From 5b6ad1924392fc33e424b449d9b6edb25f0a0e18 Mon Sep 17 00:00:00 2001 From: Ilya Staroverov Date: Mon, 26 Oct 2026 12:44:29 +0300 Subject: [PATCH v1 02/11] Include SQL/XML names and DOCUMENT or CONTENT in query jumbling XmlExpr.name, XmlExpr.arg_names and XmlExpr.xmloption have not been part of the query ID since query jumbling was added to pg_stat_statements in 9.2. But they change the results: the names are those of the elements and attributes built by XMLELEMENT, XMLATTRIBUTES, XMLFOREST and XMLPI, and with DOCUMENT, XMLPARSE and XMLSERIALIZE check that the value is a document. So queries that differ only in these, like XMLELEMENT(NAME foo) and XMLELEMENT(NAME bar), were merged into a single pg_stat_statements entry. Include these fields in query jumbling. XmlExpr.type and XmlExpr.typmod are still left out: the result of XMLSERIALIZE is coerced to the target type by a separate node, the same way as for a cast. This changes the query IDs of the queries using any SQL/XML function implemented by XmlExpr, so it is for master only. Author: Ilya Staroverov --- contrib/pg_stat_statements/expected/xml.out | 24 ++++++++++++------- contrib/pg_stat_statements/expected/xml_1.out | 8 ++++--- src/include/nodes/primnodes.h | 6 ++--- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/contrib/pg_stat_statements/expected/xml.out b/contrib/pg_stat_statements/expected/xml.out index 6c4c34b2c5..f1ba8c5f4e 100644 --- a/contrib/pg_stat_statements/expected/xml.out +++ b/contrib/pg_stat_statements/expected/xml.out @@ -98,16 +98,22 @@ SELECT XMLPI(NAME foo, t) FROM pgss_xml_tab; SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C", calls; calls | query -------+------------------------------------------------------------------------- - 2 | SELECT XMLELEMENT(NAME foo) FROM pgss_xml_tab - 4 | SELECT XMLELEMENT(NAME foo, XMLATTRIBUTES(t AS a)) FROM pgss_xml_tab + 1 | SELECT XMLELEMENT(NAME bar) FROM pgss_xml_tab + 1 | SELECT XMLELEMENT(NAME foo) FROM pgss_xml_tab + 1 | SELECT XMLELEMENT(NAME foo, XMLATTRIBUTES(t AS a)) FROM pgss_xml_tab 1 | SELECT XMLELEMENT(NAME foo, XMLATTRIBUTES(t AS a), t) FROM pgss_xml_tab + 1 | SELECT XMLELEMENT(NAME foo, XMLATTRIBUTES(t AS b)) FROM pgss_xml_tab + 2 | SELECT XMLELEMENT(NAME foo, XMLATTRIBUTES(t)) FROM pgss_xml_tab 1 | SELECT XMLELEMENT(NAME foo, t) FROM pgss_xml_tab - 4 | SELECT XMLFOREST(t AS a) FROM pgss_xml_tab + 1 | SELECT XMLFOREST(t AS a) FROM pgss_xml_tab 1 | SELECT XMLFOREST(t AS a, x AS b) FROM pgss_xml_tab - 2 | SELECT XMLPI(NAME foo) FROM pgss_xml_tab + 1 | SELECT XMLFOREST(t AS b) FROM pgss_xml_tab + 2 | SELECT XMLFOREST(t) FROM pgss_xml_tab + 1 | SELECT XMLPI(NAME bar) FROM pgss_xml_tab + 1 | SELECT XMLPI(NAME foo) FROM pgss_xml_tab 1 | SELECT XMLPI(NAME foo, t) FROM pgss_xml_tab 1 | SELECT pg_stat_statements_reset() IS NOT NULL AS t -(9 rows) +(15 rows) -- XMLPARSE and XMLSERIALIZE SELECT pg_stat_statements_reset() IS NOT NULL AS t; @@ -171,12 +177,14 @@ SELECT XMLSERIALIZE(CONTENT x AS varchar(20)) FROM pgss_xml_tab; SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C", calls; calls | query -------+----------------------------------------------------------------- - 4 | SELECT XMLPARSE(DOCUMENT t) FROM pgss_xml_tab + 3 | SELECT XMLPARSE(CONTENT t) FROM pgss_xml_tab + 1 | SELECT XMLPARSE(DOCUMENT t) FROM pgss_xml_tab 1 | SELECT XMLSERIALIZE(CONTENT x AS text INDENT) FROM pgss_xml_tab + 2 | SELECT XMLSERIALIZE(CONTENT x AS text) FROM pgss_xml_tab 2 | SELECT XMLSERIALIZE(CONTENT x AS varchar(10)) FROM pgss_xml_tab - 3 | SELECT XMLSERIALIZE(DOCUMENT x AS text) FROM pgss_xml_tab + 1 | SELECT XMLSERIALIZE(DOCUMENT x AS text) FROM pgss_xml_tab 1 | SELECT pg_stat_statements_reset() IS NOT NULL AS t -(5 rows) +(7 rows) -- XMLROOT SELECT pg_stat_statements_reset() IS NOT NULL AS t; diff --git a/contrib/pg_stat_statements/expected/xml_1.out b/contrib/pg_stat_statements/expected/xml_1.out index 86152a84c8..860c875d91 100644 --- a/contrib/pg_stat_statements/expected/xml_1.out +++ b/contrib/pg_stat_statements/expected/xml_1.out @@ -131,12 +131,14 @@ SELECT XMLSERIALIZE(CONTENT x AS varchar(20)) FROM pgss_xml_tab; SELECT calls, query FROM pg_stat_statements ORDER BY query COLLATE "C", calls; calls | query -------+----------------------------------------------------------------- - 4 | SELECT XMLPARSE(DOCUMENT t) FROM pgss_xml_tab + 3 | SELECT XMLPARSE(CONTENT t) FROM pgss_xml_tab + 1 | SELECT XMLPARSE(DOCUMENT t) FROM pgss_xml_tab 1 | SELECT XMLSERIALIZE(CONTENT x AS text INDENT) FROM pgss_xml_tab + 2 | SELECT XMLSERIALIZE(CONTENT x AS text) FROM pgss_xml_tab 2 | SELECT XMLSERIALIZE(CONTENT x AS varchar(10)) FROM pgss_xml_tab - 3 | SELECT XMLSERIALIZE(DOCUMENT x AS text) FROM pgss_xml_tab + 1 | SELECT XMLSERIALIZE(DOCUMENT x AS text) FROM pgss_xml_tab 1 | SELECT pg_stat_statements_reset() IS NOT NULL AS t -(5 rows) +(7 rows) -- XMLROOT SELECT pg_stat_statements_reset() IS NOT NULL AS t; diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 726c186c7d..b14cfcdfc7 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -1611,15 +1611,15 @@ typedef struct XmlExpr /* xml function ID */ XmlExprOp op; /* name in xml(NAME foo ...) syntaxes */ - char *name pg_node_attr(query_jumble_ignore); + char *name; /* non-XML expressions for xml_attributes */ List *named_args; /* parallel list of String values */ - List *arg_names pg_node_attr(query_jumble_ignore); + List *arg_names; /* list of expressions */ List *args; /* DOCUMENT or CONTENT */ - XmlOptionType xmloption pg_node_attr(query_jumble_ignore); + XmlOptionType xmloption; /* INDENT option for XMLSERIALIZE */ bool indent; /* target type/typmod for XMLSERIALIZE */ -- 2.43.0