agora inbox for pgsql-bugs@postgresql.org
help / color / mirror / Atom feedBUG #19487: Error while executing SQL query involving XML parsing
11+ messages / 3 participants
[nested] [flat]
* BUG #19487: Error while executing SQL query involving XML parsing
@ 2026-05-19 09:01 PG Bug reporting form <noreply@postgresql.org>
0 siblings, 1 reply; 11+ messages in thread
From: PG Bug reporting form @ 2026-05-19 09:01 UTC (permalink / raw)
To: pgsql-bugs@lists.postgresql.org; +Cc: i.portnov@compassplus.com
The following bug has been logged on the website:
Bug reference: 19487
Logged by: Ilya Portnov
Email address: i.portnov@compassplus.com
PostgreSQL version: 18.3
Operating system: Ubuntu 24.04 LTS
Description:
Hello.
While testing our software product for compatibility with PostgreSQL 18, we
found a problem which appears when executing particular query. Initial query
we
were executing was quite complex and involved our custom SQL functions; we
tried to simplify it as far as we could, but it's still not very simple.
Environment which we used to reproduce this:
OS: Ubuntu 24.04 LTS
Architecture: x86_64
PostgreSQL version() output:
PostgreSQL 18.3 (Ubuntu 18.3-1.pgdg22.04+1) on x86_64-pc-linux-gnu,
compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0, 64-bit
We also tried on several different Linux distributions and PostgreSQL
builds, the problem still reproduces.
So, steps to reproduce are:
1. Create function:
create or replace function xml_to_text(pXml xml) returns text
as $$
select
case when pXml is document
then (xpath('/*/text()', pXml))[1] ::text
else pXml::text
end;
$$ language sql immutable;
2. Execute query:
select xml_to_text( (xpath('ns:rq/@Day', case
when tbl.strcolumn != '' then XMLParse(document tbl.strcolumn)
when tbl.clobcolumn != '' then XMLParse(DOCUMENT
replace(replace(replace(replace(replace(tbl.clobcolumn, '',
'?'),'', '?'),'', '?'),'', '?'), '', '?'))
else XMLParse(DOCUMENT '<rq></rq>')
end,
array[array['ns', 'http://example.com/schema.xsd';]]
))[1] )
from
(
(select '<ns:rq xmlns:ns="http://example.com/schema.xsd";
Day="2019-12-16T00:00:00.000"/>' as strcolumn, null as clobcolumn)
union all
(select '<ns:rq xmlns:ns="http://example.com/schema.xsd";
Day="2019-12-16T00:00:00.000"></ns:rq>' as strcolumn, null as clobcolumn)
) tbl;
Expected result, which is what we get on PostgreSQL 17.9:
xml_to_text |
-----------------------+
2019-12-16T00:00:00.000|
2019-12-16T00:00:00.000|
Actual result on PostgreSQL 18.3:
SQL Error [2200M]: ERROR: could not parse XML document
Detail: line 1: Start tag expected, '<' not found
2019-12-16T00:00:00.000
^
Where: SQL function "xpath" statement 1
SQL function "xml_to_text" statement 1
It appears that all parts of problematic query are important for this
problem:
if I try to simplify it, for example if I try to remove one of five nested
replace() calls, the problem goes away.
This looks like a problem which was introduced somewhere between PostgreSQL
17 and 18. Any help in fixing it will be appreciated.
Best regards,
Ilya V. Portnov.
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: BUG #19487: Error while executing SQL query involving XML parsing
@ 2026-08-28 08:53 Andrey Rachitskiy <pl0h0yp1@gmail.com>
parent: PG Bug reporting form <noreply@postgresql.org>
0 siblings, 1 reply; 11+ messages in thread
From: Andrey Rachitskiy @ 2026-08-28 08:53 UTC (permalink / raw)
To: i.portnov@compassplus.com; pgsql-bugs@lists.postgresql.org; +Cc: Tom Lane <tgl@sss.pgh.pa.us>
ср, 20 мая 2026 г. в 04:30, PG Bug reporting form <noreply@postgresql.org>:
> The following bug has been logged on the website:
>
> Bug reference: 19487
> Logged by: Ilya Portnov
> Email address: i.portnov@compassplus.com
> PostgreSQL version: 18.3
> Operating system: Ubuntu 24.04 LTS
> Description:
>
> Hello.
>
> While testing our software product for compatibility with PostgreSQL 18, we
> found a problem which appears when executing particular query. Initial
> query
> we
> were executing was quite complex and involved our custom SQL functions; we
> tried to simplify it as far as we could, but it's still not very simple.
>
> Environment which we used to reproduce this:
>
> OS: Ubuntu 24.04 LTS
> Architecture: x86_64
> PostgreSQL version() output:
> PostgreSQL 18.3 (Ubuntu 18.3-1.pgdg22.04+1) on x86_64-pc-linux-gnu,
> compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0, 64-bit
>
> We also tried on several different Linux distributions and PostgreSQL
> builds, the problem still reproduces.
>
> So, steps to reproduce are:
>
> 1. Create function:
>
> create or replace function xml_to_text(pXml xml) returns text
> as $$
> select
> case when pXml is document
> then (xpath('/*/text()', pXml))[1] ::text
> else pXml::text
> end;
> $$ language sql immutable;
>
> 2. Execute query:
>
> select xml_to_text( (xpath('ns:rq/@Day', case
> when tbl.strcolumn != '' then XMLParse(document tbl.strcolumn)
> when tbl.clobcolumn != '' then XMLParse(DOCUMENT
> replace(replace(replace(replace(replace(tbl.clobcolumn, '',
> '?'),'', '?'),'', '?'),'', '?'), '', '?'))
> else XMLParse(DOCUMENT '<rq></rq>')
> end,
> array[array['ns', 'http://example.com/schema.xsd';]]
> ))[1] )
> from
> (
> (select '<ns:rq xmlns:ns="http://example.com/schema.xsd";
> Day="2019-12-16T00:00:00.000"/>' as strcolumn, null as clobcolumn)
> union all
> (select '<ns:rq xmlns:ns="http://example.com/schema.xsd";
> Day="2019-12-16T00:00:00.000"></ns:rq>' as strcolumn, null as clobcolumn)
> ) tbl;
>
> Expected result, which is what we get on PostgreSQL 17.9:
>
> xml_to_text |
> -----------------------+
> 2019-12-16T00:00:00.000|
> 2019-12-16T00:00:00.000|
>
> Actual result on PostgreSQL 18.3:
>
> SQL Error [2200M]: ERROR: could not parse XML document
> Detail: line 1: Start tag expected, '<' not found
> 2019-12-16T00:00:00.000
> ^
> Where: SQL function "xpath" statement 1
> SQL function "xml_to_text" statement 1
>
> It appears that all parts of problematic query are important for this
> problem:
> if I try to simplify it, for example if I try to remove one of five nested
> replace() calls, the problem goes away.
>
> This looks like a problem which was introduced somewhere between PostgreSQL
> 17 and 18. Any help in fixing it will be appreciated.
>
> Best regards,
> Ilya V. Portnov.
>
>
>
>
> Hi, Ilya!
Thanks for the report.
I'm sorry for the long wait with the answer.
# Guilty commit
0dca5d68d7b — Change SQL-language functions to use the plan cache.
- parent `e9e7b66044c`: query OK
- `0dca5d68d7b`: same ERROR as on master
Custom plans substitute Const arguments into the SQL function body.
`eval_const_expressions` then simplifies CASE WHEN results even when the
WHEN condition is a non-Const XmlExpr (`IS DOCUMENT`). Immutable
`xpath()` on the Const non-document content is executed at plan time and
throws.
# Proposal Fix
Fold constant `XmlExpr` in `eval_const_expressions` (same path as
`MinMaxExpr` / `ArrayExpr`), so `IS DOCUMENT` becomes a boolean Const and
CASE drops the unused arm before simplifying `xpath()`.
--
Regards,
Rachitskiy Andrey
Attachments:
[text/x-patch] 0001-Fold-constant-XmlExpr-in-eval_const_expressions.patch (3.3K, ../../CAB8bMisngV0L9L3dZkpuStTboHXkVPr0=NBhCNpDxg3r+Bheog@mail.gmail.com/3-0001-Fold-constant-XmlExpr-in-eval_const_expressions.patch)
download | inline diff:
From 8bf8719c1b908a2cae5e6bc7801e4c9c37915883 Mon Sep 17 00:00:00 2001
From: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Date: Fri, 28 Aug 2026 12:33:47 +0500
Subject: [PATCH] Fold constant XmlExpr in eval_const_expressions
IS DOCUMENT was left as XmlExpr even with a Const argument, so CASE
still simplified unused WHEN results and could execute xpath() during
planning. That started failing for SQL-language functions once they
began using custom plans.
Bug: #19487
Author: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Reported-by: Ilya Portnov <i.portnov@compassplus.com>
Discussion: https://www.postgresql.org/message-id/19487-367258bc497b923a%40postgresql.org
Backpatch-through: 18
---
src/backend/optimizer/util/clauses.c | 6 ++++++
src/test/regress/expected/xml.out | 10 ++++++++++
src/test/regress/sql/xml.sql | 5 +++++
3 files changed, 21 insertions(+)
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8da4ed617b5..0294a956fb2 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -3679,6 +3679,7 @@ eval_const_expressions_mutator(Node *node,
case T_ArrayExpr:
case T_RowExpr:
case T_MinMaxExpr:
+ case T_XmlExpr:
{
/*
* Generic handling for node types whose own processing is
@@ -3693,6 +3694,11 @@ eval_const_expressions_mutator(Node *node,
* Treating MinMaxExpr this way amounts to assuming that the
* btree comparison function it calls is immutable; see the
* reasoning in contain_mutable_functions_walker.
+ *
+ * XmlExpr is treated as immutable by that walker too, so fold
+ * it here. Otherwise a constant IS DOCUMENT left in CASE
+ * WHEN can still allow unused arms (e.g. xpath()) to be
+ * simplified and fail at plan time.
*/
/* Copy the node and const-simplify its arguments */
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index fb3e0ec41b2..fd189a8fa97 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -713,6 +713,16 @@ LINE 1: SELECT '<>' IS NOT DOCUMENT;
DETAIL: line 1: StartTag: invalid element name
<>
^
+-- Fold IS DOCUMENT constants so CASE does not run unused xpath() at plan time.
+SELECT CASE WHEN ('2019-12-16T00:00:00.000'::xml) IS DOCUMENT
+ THEN (xpath('/*/text()', '2019-12-16T00:00:00.000'::xml))[1]::text
+ ELSE ('2019-12-16T00:00:00.000'::xml)::text
+END;
+ case
+-------------------------
+ 2019-12-16T00:00:00.000
+(1 row)
+
SELECT xmlagg(data) FROM xmltest;
xmlagg
--------------------------------------
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index aafd39433a6..93a3dee92aa 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -185,6 +185,11 @@ SELECT xml '<abc/>' IS NOT DOCUMENT;
SELECT xml 'abc' IS NOT DOCUMENT;
SELECT '<>' IS NOT DOCUMENT;
+-- Fold IS DOCUMENT constants so CASE does not run unused xpath() at plan time.
+SELECT CASE WHEN ('2019-12-16T00:00:00.000'::xml) IS DOCUMENT
+ THEN (xpath('/*/text()', '2019-12-16T00:00:00.000'::xml))[1]::text
+ ELSE ('2019-12-16T00:00:00.000'::xml)::text
+END;
SELECT xmlagg(data) FROM xmltest;
SELECT xmlagg(data) FROM xmltest WHERE id > 10;
--
2.53.0
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: BUG #19487: Error while executing SQL query involving XML parsing
@ 2026-08-28 19:49 Tom Lane <tgl@sss.pgh.pa.us>
parent: Andrey Rachitskiy <pl0h0yp1@gmail.com>
0 siblings, 1 reply; 11+ messages in thread
From: Tom Lane @ 2026-08-28 19:49 UTC (permalink / raw)
To: Andrey Rachitskiy <pl0h0yp1@gmail.com>; +Cc: i.portnov@compassplus.com; pgsql-bugs@lists.postgresql.org
Andrey Rachitskiy <pl0h0yp1@gmail.com> writes:
> # Proposal Fix
> Fold constant `XmlExpr` in `eval_const_expressions` (same path as
> `MinMaxExpr` / `ArrayExpr`), so `IS DOCUMENT` becomes a boolean Const and
> CASE drops the unused arm before simplifying `xpath()`.
I don't object to simplifying XmlExpr where possible, but this patch
appears to believe that every variant of XmlExpr is immutable.
This is demonstrably false, eg
regression=# set timezone = 'America/New_York';
SET
regression=# SELECT xmlforest('2026-08-28 12:00 UTC'::timestamptz AS foo);
xmlforest
--------------------------------------
<foo>2026-08-28T08:00:00-04:00</foo>
(1 row)
regression=# set timezone = 'America/Chicago';
SET
regression=# SELECT xmlforest('2026-08-28 12:00 UTC'::timestamptz AS foo);
xmlforest
--------------------------------------
<foo>2026-08-28T07:00:00-05:00</foo>
(1 row)
So you need to take a closer look at which variants can be promised to
be immutable.
regards, tom lane
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: BUG #19487: Error while executing SQL query involving XML parsing
@ 2026-08-28 19:55 Andrey Rachitskiy <pl0h0yp1@gmail.com>
parent: Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 1 reply; 11+ messages in thread
From: Andrey Rachitskiy @ 2026-08-28 19:55 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: i.portnov@compassplus.com; pgsql-bugs@lists.postgresql.org
сб, 29 авг. 2026 г. в 00:49, Tom Lane <tgl@sss.pgh.pa.us>:
> Andrey Rachitskiy <pl0h0yp1@gmail.com> writes:
> > # Proposal Fix
> > Fold constant `XmlExpr` in `eval_const_expressions` (same path as
> > `MinMaxExpr` / `ArrayExpr`), so `IS DOCUMENT` becomes a boolean Const and
> > CASE drops the unused arm before simplifying `xpath()`.
>
> I don't object to simplifying XmlExpr where possible, but this patch
> appears to believe that every variant of XmlExpr is immutable.
> This is demonstrably false, eg
>
> regression=# set timezone = 'America/New_York';
> SET
> regression=# SELECT xmlforest('2026-08-28 12:00 UTC'::timestamptz AS foo);
> xmlforest
> --------------------------------------
> <foo>2026-08-28T08:00:00-04:00</foo>
> (1 row)
>
> regression=# set timezone = 'America/Chicago';
> SET
> regression=# SELECT xmlforest('2026-08-28 12:00 UTC'::timestamptz AS foo);
> xmlforest
> --------------------------------------
> <foo>2026-08-28T07:00:00-05:00</foo>
> (1 row)
>
> So you need to take a closer look at which variants can be promised to
> be immutable.
>
>
> Dear Tom,
Thanks for the review. I'll study it in more detail and come back with
corrections.
--
Regards,
Rachitskiy Andrey
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: BUG #19487: Error while executing SQL query involving XML parsing
@ 2026-08-29 10:54 Andrey Rachitskiy <pl0h0yp1@gmail.com>
parent: Andrey Rachitskiy <pl0h0yp1@gmail.com>
0 siblings, 1 reply; 11+ messages in thread
From: Andrey Rachitskiy @ 2026-08-29 10:54 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: i.portnov@compassplus.com; pgsql-bugs@lists.postgresql.org
сб, 29 авг. 2026 г. в 00:55, Andrey Rachitskiy <pl0h0yp1@gmail.com>:
>
>
> сб, 29 авг. 2026 г. в 00:49, Tom Lane <tgl@sss.pgh.pa.us>:
>
>> Andrey Rachitskiy <pl0h0yp1@gmail.com> writes:
>> > # Proposal Fix
>> > Fold constant `XmlExpr` in `eval_const_expressions` (same path as
>> > `MinMaxExpr` / `ArrayExpr`), so `IS DOCUMENT` becomes a boolean Const
>> and
>> > CASE drops the unused arm before simplifying `xpath()`.
>>
>> I don't object to simplifying XmlExpr where possible, but this patch
>> appears to believe that every variant of XmlExpr is immutable.
>> This is demonstrably false, eg
>>
>> regression=# set timezone = 'America/New_York';
>> SET
>> regression=# SELECT xmlforest('2026-08-28 12:00 UTC'::timestamptz AS foo);
>> xmlforest
>> --------------------------------------
>> <foo>2026-08-28T08:00:00-04:00</foo>
>> (1 row)
>>
>> regression=# set timezone = 'America/Chicago';
>> SET
>> regression=# SELECT xmlforest('2026-08-28 12:00 UTC'::timestamptz AS foo);
>> xmlforest
>> --------------------------------------
>> <foo>2026-08-28T07:00:00-05:00</foo>
>> (1 row)
>>
>> So you need to take a closer look at which variants can be promised to
>> be immutable.
>>
>>
Dear Tom, have a nice weekend!
In v2, I tried to take all the points into account and expanded the tests.
--
Regards,
Rachitskiy Andrey
Attachments:
[text/x-patch] v2-0001-Fold-immutable-XmlExpr-forms-in-eval_const_expressions.patch (9.5K, ../../CAB8bMisnPP=Ck=BX4UfHL1eTFLMFJ_RznsVXtqy3H=P+6tugjg@mail.gmail.com/3-v2-0001-Fold-immutable-XmlExpr-forms-in-eval_const_expressions.patch)
download | inline diff:
From b8ec4063aba3a790ad6ebbc0d2df950c2f160ad6 Mon Sep 17 00:00:00 2001
From: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Date: Fri, 28 Aug 2026 12:33:47 +0500
Subject: [PATCH v2] Fold immutable XmlExpr forms in eval_const_expressions
IS DOCUMENT was left as XmlExpr even with a Const argument, so CASE
still simplified unused WHEN results and could execute xpath() during
planning. That started failing for SQL-language functions once they
began using custom plans.
Not every XmlExpr is safe to fold. XMLELEMENT and XMLFOREST go through
map_sql_value_to_xml_value(), which may depend on session settings or
type output functions. Fold those only when every argument type maps
immutably. Other XmlExprOps only manipulate xml/text.
Bug: #19487
Author: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Reported-by: Ilya Portnov <i.portnov@compassplus.com>
Discussion: https://www.postgresql.org/message-id/19487-367258bc497b923a%40postgresql.org
Backpatch-through: 18
---
src/backend/optimizer/util/clauses.c | 53 ++++++++++++++++++++++
src/backend/utils/adt/xml.c | 38 ++++++++++++++++
src/include/utils/xml.h | 1 +
src/test/regress/expected/xml.out | 67 ++++++++++++++++++++++++++++
src/test/regress/sql/xml.sql | 33 ++++++++++++++
5 files changed, 192 insertions(+)
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8da4ed617b5..56f651b81f7 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -64,5 +64,6 @@
#include "utils/syscache.h"
#include "utils/typcache.h"
+#include "utils/xml.h"
typedef struct
{
@@ -115,6 +116,7 @@ static bool contain_agg_clause_walker(Node *node, void *context);
static bool find_window_functions_walker(Node *node, WindowFuncLists *lists);
static bool contain_subplans_walker(Node *node, void *context);
static bool contain_mutable_functions_walker(Node *node, void *context);
+static bool xmlexpr_is_immutable(XmlExpr *xexpr);
static bool contain_volatile_functions_walker(Node *node, void *context);
static bool contain_volatile_functions_not_nextval_walker(Node *node, void *context);
static bool max_parallel_hazard_walker(Node *node,
@@ -496,6 +498,49 @@ contain_mutable_functions_walker(Node *node, void *context)
context);
}
+/*
+ * xmlexpr_is_immutable
+ * True if this XmlExpr is immutable.
+ *
+ * XMLELEMENT and XMLFOREST go through map_sql_value_to_xml_value(), which
+ * may depend on session settings (e.g. TimeZone, xmlbinary) or on type
+ * output functions. Other XmlExprOps only manipulate xml/text.
+ */
+static bool
+xmlexpr_is_immutable(XmlExpr *xexpr)
+{
+ ListCell *lc;
+ List *arglists[2];
+ int i;
+
+ switch (xexpr->op)
+ {
+ case IS_XMLCONCAT:
+ case IS_XMLPARSE:
+ case IS_XMLPI:
+ case IS_XMLROOT:
+ case IS_XMLSERIALIZE:
+ case IS_DOCUMENT:
+ return true;
+
+ case IS_XMLELEMENT:
+ case IS_XMLFOREST:
+ arglists[0] = xexpr->named_args;
+ arglists[1] = xexpr->args;
+ for (i = 0; i < lengthof(arglists); i++)
+ {
+ foreach(lc, arglists[i])
+ {
+ if (!map_sql_value_to_xml_is_immutable(exprType(lfirst(lc))))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
/*
* contain_mutable_functions_after_planning
* Test whether given expression contains mutable functions.
@@ -3702,6 +3747,14 @@ eval_const_expressions_mutator(Node *node,
return ece_evaluate_expr(node);
return node;
}
+ case T_XmlExpr:
+ {
+ node = ece_generic_processing(node);
+ if (ece_all_arguments_const(node) &&
+ xmlexpr_is_immutable((XmlExpr *) node))
+ return ece_evaluate_expr(node);
+ return node;
+ }
case T_CoalesceExpr:
{
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 1f75ffcfd9d..2034f7b39a4 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -85,3 +85,4 @@
#include "catalog/namespace.h"
#include "catalog/pg_class.h"
+#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
@@ -2727,6 +2728,43 @@ map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
}
}
+/*
+ * map_sql_value_to_xml_is_immutable
+ * True if mapping this type to XML text is immutable.
+ *
+ * Mirrors the special cases in map_sql_value_to_xml_value(): bool/date/timestamp
+ * use fixed formatting rather than DateStyle-sensitive output, and bytea uses
+ * xmlbinary rather than byteaout (which is marked immutable).
+ */
+bool
+map_sql_value_to_xml_is_immutable(Oid type)
+{
+ Oid typeOut;
+ bool isvarlena;
+
+ if (type_is_array_domain(type))
+ return map_sql_value_to_xml_is_immutable(get_base_element_type(type));
+
+ type = getBaseType(type);
+
+ switch (type)
+ {
+ case BOOLOID:
+ case DATEOID:
+ case TIMESTAMPOID:
+ /* Fixed formatting, not type output / DateStyle */
+ return true;
+
+ case BYTEAOID:
+ /* Uses xmlbinary, not byteaout (marked immutable) */
+ return false;
+
+ default:
+ getTypeOutputInfo(type, &typeOut, &isvarlena);
+ return (func_volatile(typeOut) == PROVOLATILE_IMMUTABLE);
+ }
+}
+
/*
* Escape characters in text that have special meanings in XML.
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index ca266f448d6..daa5d96ae1d 100644
--- a/src/include/utils/xml.h
+++ b/src/include/utils/xml.h
@@ -84,6 +84,7 @@ extern char *escape_xml(const char *str);
extern char *map_sql_identifier_to_xml_name(const char *ident, bool fully_escaped, bool escape_period);
extern char *map_xml_name_to_sql_identifier(const char *name);
extern char *map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings);
+extern bool map_sql_value_to_xml_is_immutable(Oid type);
extern PGDLLIMPORT int xmlbinary; /* XmlBinaryType, but int for guc enum */
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index fb3e0ec41b2..9dd6d5a9226 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -713,6 +713,73 @@ LINE 1: SELECT '<>' IS NOT DOCUMENT;
DETAIL: line 1: StartTag: invalid element name
<>
^
+--
+-- Constant-folding of XmlExpr
+--
+-- Fold IS DOCUMENT so CASE does not simplify unused xpath() at plan time.
+SELECT CASE WHEN ('2019-12-16T00:00:00.000'::xml) IS DOCUMENT
+ THEN (xpath('/*/text()', '2019-12-16T00:00:00.000'::xml))[1]::text
+ ELSE ('2019-12-16T00:00:00.000'::xml)::text
+END;
+ case
+-------------------------
+ 2019-12-16T00:00:00.000
+(1 row)
+
+-- XMLFOREST must not fold when map_sql_value_to_xml_value() is mutable.
+-- timestamptz follows TimeZone.
+PREPARE xmlforest_tz AS SELECT xmlforest('2026-08-28 12:00 UTC'::timestamptz AS foo);
+SET timezone = 'America/New_York';
+EXECUTE xmlforest_tz;
+ xmlforest
+--------------------------------------
+ <foo>2026-08-28T08:00:00-04:00</foo>
+(1 row)
+
+SET timezone = 'America/Chicago';
+EXECUTE xmlforest_tz;
+ xmlforest
+--------------------------------------
+ <foo>2026-08-28T07:00:00-05:00</foo>
+(1 row)
+
+DEALLOCATE xmlforest_tz;
+SET timezone = 'GMT';
+-- bytea follows xmlbinary.
+PREPARE xmlforest_bin AS SELECT xmlforest(bytea 'bar' AS foo);
+SET xmlbinary TO base64;
+EXECUTE xmlforest_bin;
+ xmlforest
+-----------------
+ <foo>YmFy</foo>
+(1 row)
+
+SET xmlbinary TO hex;
+EXECUTE xmlforest_bin;
+ xmlforest
+-------------------
+ <foo>626172</foo>
+(1 row)
+
+DEALLOCATE xmlforest_bin;
+-- interval follows IntervalStyle (via type output).
+PREPARE xmlforest_iv AS SELECT xmlforest(interval '1 year 2 mons 3 days 04:05:06' AS foo);
+SET intervalstyle TO postgres;
+EXECUTE xmlforest_iv;
+ xmlforest
+------------------------------------------
+ <foo>1 year 2 mons 3 days 04:05:06</foo>
+(1 row)
+
+SET intervalstyle TO iso_8601;
+EXECUTE xmlforest_iv;
+ xmlforest
+---------------------------
+ <foo>P1Y2M3DT4H5M6S</foo>
+(1 row)
+
+DEALLOCATE xmlforest_iv;
+RESET intervalstyle;
SELECT xmlagg(data) FROM xmltest;
xmlagg
--------------------------------------
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index aafd39433a6..31fc18dd85d 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -185,6 +185,39 @@ SELECT xml '<abc/>' IS NOT DOCUMENT;
SELECT xml 'abc' IS NOT DOCUMENT;
SELECT '<>' IS NOT DOCUMENT;
+--
+-- Constant-folding of XmlExpr
+--
+-- Fold IS DOCUMENT so CASE does not simplify unused xpath() at plan time.
+SELECT CASE WHEN ('2019-12-16T00:00:00.000'::xml) IS DOCUMENT
+ THEN (xpath('/*/text()', '2019-12-16T00:00:00.000'::xml))[1]::text
+ ELSE ('2019-12-16T00:00:00.000'::xml)::text
+END;
+
+-- XMLFOREST must not fold when map_sql_value_to_xml_value() is mutable.
+-- timestamptz follows TimeZone.
+PREPARE xmlforest_tz AS SELECT xmlforest('2026-08-28 12:00 UTC'::timestamptz AS foo);
+SET timezone = 'America/New_York';
+EXECUTE xmlforest_tz;
+SET timezone = 'America/Chicago';
+EXECUTE xmlforest_tz;
+DEALLOCATE xmlforest_tz;
+SET timezone = 'GMT';
+-- bytea follows xmlbinary.
+PREPARE xmlforest_bin AS SELECT xmlforest(bytea 'bar' AS foo);
+SET xmlbinary TO base64;
+EXECUTE xmlforest_bin;
+SET xmlbinary TO hex;
+EXECUTE xmlforest_bin;
+DEALLOCATE xmlforest_bin;
+-- interval follows IntervalStyle (via type output).
+PREPARE xmlforest_iv AS SELECT xmlforest(interval '1 year 2 mons 3 days 04:05:06' AS foo);
+SET intervalstyle TO postgres;
+EXECUTE xmlforest_iv;
+SET intervalstyle TO iso_8601;
+EXECUTE xmlforest_iv;
+DEALLOCATE xmlforest_iv;
+RESET intervalstyle;
SELECT xmlagg(data) FROM xmltest;
SELECT xmlagg(data) FROM xmltest WHERE id > 10;
--
2.53.0
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: BUG #19487: Error while executing SQL query involving XML parsing
@ 2026-08-29 21:44 Tom Lane <tgl@sss.pgh.pa.us>
parent: Andrey Rachitskiy <pl0h0yp1@gmail.com>
0 siblings, 1 reply; 11+ messages in thread
From: Tom Lane @ 2026-08-29 21:44 UTC (permalink / raw)
To: Andrey Rachitskiy <pl0h0yp1@gmail.com>; +Cc: i.portnov@compassplus.com; pgsql-bugs@lists.postgresql.org
Andrey Rachitskiy <pl0h0yp1@gmail.com> writes:
> In v2, I tried to take all the points into account and expanded the tests.
Hmm, I think it might be better to drop
map_sql_value_to_xml_is_immutable and just treat XMLELEMENT and
XMLFOREST as non-immutable. Trying to be smarter adds quite a bit
of complexity to this patch as well as long-term maintenance risk
(ie, needing to keep map_sql_value_to_xml_is_immutable in step with
the actual behavior of map_sql_value_to_xml; if we mess that up, the
mistake will be very non-obvious, and these test cases are unlikely
to catch it). For my money it's not worth it.
regards, tom lane
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: BUG #19487: Error while executing SQL query involving XML parsing
@ 2026-08-30 03:08 Andrey Rachitskiy <pl0h0yp1@gmail.com>
parent: Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 1 reply; 11+ messages in thread
From: Andrey Rachitskiy @ 2026-08-30 03:08 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: i.portnov@compassplus.com; pgsql-bugs@lists.postgresql.org
вс, 30 авг. 2026 г. в 02:44, Tom Lane <tgl@sss.pgh.pa.us>:
> Andrey Rachitskiy <pl0h0yp1@gmail.com> writes:
> > In v2, I tried to take all the points into account and expanded the
> tests.
>
> Hmm, I think it might be better to drop
> map_sql_value_to_xml_is_immutable and just treat XMLELEMENT and
> XMLFOREST as non-immutable. Trying to be smarter adds quite a bit
> of complexity to this patch as well as long-term maintenance risk
> (ie, needing to keep map_sql_value_to_xml_is_immutable in step with
> the actual behavior of map_sql_value_to_xml; if we mess that up, the
> mistake will be very non-obvious, and these test cases are unlikely
> to catch it). For my money it's not worth it.
>
Dear Tom,
I think you're right. Fixed it in v3.
--
Regards,
Rachitskiy Andrey
Attachments:
[text/x-patch] v3-0001-Fold-immutable-XmlExpr-forms-in-eval_const_expressions.patch (4.4K, ../../CAB8bMivhR6_d33YFc-cAKT-Qa8Vj8MHicVUexyJSySTi+c4k_g@mail.gmail.com/3-v3-0001-Fold-immutable-XmlExpr-forms-in-eval_const_expressions.patch)
download | inline diff:
From 7dce02a462eff7492befcaa9fa27062816780e7d Mon Sep 17 00:00:00 2001
From: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Date: Fri, 28 Aug 2026 12:33:47 +0500
Subject: [PATCH v3] Fold immutable XmlExpr forms in eval_const_expressions
IS DOCUMENT was left as XmlExpr even with a Const argument, so CASE
still simplified unused WHEN results and could execute xpath() during
planning. That started failing for SQL-language functions once they
began using custom plans.
Fold XmlExpr in eval_const_expressions when all inputs are Const and
the op is immutable. Treat XMLELEMENT and XMLFOREST as non-immutable.
Other XmlExprOps only manipulate xml/text.
Bug: #19487
Author: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Reported-by: Ilya Portnov <i.portnov@compassplus.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/19487-367258bc497b923a%40postgresql.org
Backpatch-through: 18
---
src/backend/optimizer/util/clauses.c | 37 ++++++++++++++++++++++++++++
src/test/regress/expected/xml.out | 10 ++++++++
src/test/regress/sql/xml.sql | 5 ++++
3 files changed, 52 insertions(+)
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8da4ed617b5..96153179668 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -115,6 +115,7 @@ static bool contain_agg_clause_walker(Node *node, void *context);
static bool find_window_functions_walker(Node *node, WindowFuncLists *lists);
static bool contain_subplans_walker(Node *node, void *context);
static bool contain_mutable_functions_walker(Node *node, void *context);
+static bool xmlexpr_is_immutable(XmlExpr *xexpr);
static bool contain_volatile_functions_walker(Node *node, void *context);
static bool contain_volatile_functions_not_nextval_walker(Node *node, void *context);
static bool max_parallel_hazard_walker(Node *node,
@@ -496,6 +497,34 @@ contain_mutable_functions_walker(Node *node, void *context)
context);
}
+/*
+ * xmlexpr_is_immutable
+ * True if this XmlExpr is immutable.
+ *
+ * XMLELEMENT and XMLFOREST are treated as non-immutable. Other XmlExprOps
+ * only manipulate xml/text.
+ */
+static bool
+xmlexpr_is_immutable(XmlExpr *xexpr)
+{
+ switch (xexpr->op)
+ {
+ case IS_XMLCONCAT:
+ case IS_XMLPARSE:
+ case IS_XMLPI:
+ case IS_XMLROOT:
+ case IS_XMLSERIALIZE:
+ case IS_DOCUMENT:
+ return true;
+
+ case IS_XMLELEMENT:
+ case IS_XMLFOREST:
+ return false;
+ }
+
+ return false;
+}
+
/*
* contain_mutable_functions_after_planning
* Test whether given expression contains mutable functions.
@@ -3702,6 +3731,14 @@ eval_const_expressions_mutator(Node *node,
return ece_evaluate_expr(node);
return node;
}
+ case T_XmlExpr:
+ {
+ node = ece_generic_processing(node);
+ if (ece_all_arguments_const(node) &&
+ xmlexpr_is_immutable((XmlExpr *) node))
+ return ece_evaluate_expr(node);
+ return node;
+ }
case T_CoalesceExpr:
{
CoalesceExpr *coalesceexpr = (CoalesceExpr *) node;
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index fb3e0ec41b2..d60e1c4efb7 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -713,6 +713,16 @@ LINE 1: SELECT '<>' IS NOT DOCUMENT;
DETAIL: line 1: StartTag: invalid element name
<>
^
+-- Fold IS DOCUMENT so CASE does not simplify unused xpath() at plan time.
+SELECT CASE WHEN ('2019-12-16T00:00:00.000'::xml) IS DOCUMENT
+ THEN (xpath('/*/text()', '2019-12-16T00:00:00.000'::xml))[1]::text
+ ELSE ('2019-12-16T00:00:00.000'::xml)::text
+END;
+ case
+-------------------------
+ 2019-12-16T00:00:00.000
+(1 row)
+
SELECT xmlagg(data) FROM xmltest;
xmlagg
--------------------------------------
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index aafd39433a6..52e39187447 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -185,6 +185,11 @@ SELECT xml '<abc/>' IS NOT DOCUMENT;
SELECT xml 'abc' IS NOT DOCUMENT;
SELECT '<>' IS NOT DOCUMENT;
+-- Fold IS DOCUMENT so CASE does not simplify unused xpath() at plan time.
+SELECT CASE WHEN ('2019-12-16T00:00:00.000'::xml) IS DOCUMENT
+ THEN (xpath('/*/text()', '2019-12-16T00:00:00.000'::xml))[1]::text
+ ELSE ('2019-12-16T00:00:00.000'::xml)::text
+END;
SELECT xmlagg(data) FROM xmltest;
SELECT xmlagg(data) FROM xmltest WHERE id > 10;
--
2.53.0
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: BUG #19487: Error while executing SQL query involving XML parsing
@ 2026-08-30 18:03 Tom Lane <tgl@sss.pgh.pa.us>
parent: Andrey Rachitskiy <pl0h0yp1@gmail.com>
0 siblings, 1 reply; 11+ messages in thread
From: Tom Lane @ 2026-08-30 18:03 UTC (permalink / raw)
To: Andrey Rachitskiy <pl0h0yp1@gmail.com>; +Cc: i.portnov@compassplus.com; pgsql-bugs@lists.postgresql.org
Andrey Rachitskiy <pl0h0yp1@gmail.com> writes:
> I think you're right. Fixed it in v3.
I spent some time looking at this, and felt that what we really
ought to do is update clauses.c's handling of XmlExpr across the
board. In particular, contain_mutable_functions really shouldn't
allow XmlExpr in cases where we know it's not immutable. So more
or less as attached, where I also spent more effort on the comments.
I've got mixed emotions about back-patching this. It's not really
a bug fix, because we already disclaim the safety of relying on
CASE for this purpose, cf [1]. I think it might still be reasonable
to sneak into v19, but I'm unsure that putting it into 18 is a good
idea.
regards, tom lane
[1] https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-EXPRESS-EVAL
Attachments:
[text/x-diff] v4-0001-Handle-XmlExpr-more-honestly-in-clauses.c.patch (7.7K, ../../880213.1788113038@sss.pgh.pa.us/2-v4-0001-Handle-XmlExpr-more-honestly-in-clauses.c.patch)
download | inline diff:
From 1cf565ab1665c57f12047ce294700d5c17cecb7b Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sun, 30 Aug 2026 13:55:06 -0400
Subject: [PATCH v4] Handle XmlExpr more honestly in clauses.c.
eval_const_expressions() didn't constant-fold XmlExpr. In some cases
it cannot, but often it can. Failure to do so can cause visible
regressions in SQL-language function behavior compared to pre-v18,
though only in a rather narrow set of contexts: basically, if you're
trying to use a CASE to prevent evaluation of a dangerous function.
While we're at it, make contain_mutable_functions() handle XmlExpr
more precisely, and adjust some comments that justify not treating
XmlExpr explicitly.
Bug: #19487
Reported-by: Ilya Portnov <i.portnov@compassplus.com>
Author: Andrey Rachitskiy <pl0h0yp1@gmail.com>
Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/19487-367258bc497b923a@postgresql.org
Backpatch-through: ??
---
src/backend/optimizer/util/clauses.c | 83 ++++++++++++++++++++++++----
src/test/regress/expected/xml.out | 11 ++++
src/test/regress/sql/xml.sql | 7 +++
3 files changed, 90 insertions(+), 11 deletions(-)
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8da4ed617b5..737bd4a4fdf 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -115,6 +115,7 @@ static bool contain_agg_clause_walker(Node *node, void *context);
static bool find_window_functions_walker(Node *node, WindowFuncLists *lists);
static bool contain_subplans_walker(Node *node, void *context);
static bool contain_mutable_functions_walker(Node *node, void *context);
+static bool xmlexpr_is_immutable(XmlExpr *xexpr);
static bool contain_volatile_functions_walker(Node *node, void *context);
static bool contain_volatile_functions_not_nextval_walker(Node *node, void *context);
static bool max_parallel_hazard_walker(Node *node,
@@ -468,6 +469,13 @@ contain_mutable_functions_walker(Node *node, void *context)
return true;
}
+ if (IsA(node, XmlExpr))
+ {
+ /* some variants of XmlExpr are only stable */
+ if (!xmlexpr_is_immutable((XmlExpr *) node))
+ return true;
+ }
+
if (IsA(node, NextValueExpr))
{
/* NextValueExpr is volatile */
@@ -477,11 +485,10 @@ contain_mutable_functions_walker(Node *node, void *context)
/*
* It should be safe to treat MinMaxExpr as immutable, because it will
* depend on a non-cross-type btree comparison function, and those should
- * always be immutable. Treating XmlExpr as immutable is more dubious,
- * and treating CoerceToDomain as immutable is outright dangerous. But we
- * have done so historically, and changing this would probably cause more
- * problems than it would fix. In practice, if you have a non-immutable
- * domain constraint you are in for pain anyhow.
+ * always be immutable. Treating CoerceToDomain as immutable is outright
+ * dangerous, but we have done so historically, and changing this would
+ * probably cause more problems than it would fix. In practice, if you
+ * have a non-immutable domain constraint you are in for pain anyhow.
*/
/* Recurse to check arguments */
@@ -496,6 +503,44 @@ contain_mutable_functions_walker(Node *node, void *context)
context);
}
+/*
+ * xmlexpr_is_immutable
+ * True if this XmlExpr node represents immutable processing
+ * (considering just the node itself, not its arguments)
+ */
+static bool
+xmlexpr_is_immutable(XmlExpr *xexpr)
+{
+ switch (xexpr->op)
+ {
+ case IS_XMLCONCAT:
+ case IS_XMLPARSE:
+ case IS_XMLPI:
+ case IS_XMLROOT:
+ case IS_XMLSERIALIZE:
+ case IS_DOCUMENT:
+ /* These variants manipulate XML text in a self-contained way */
+ return true;
+
+ case IS_XMLELEMENT:
+ case IS_XMLFOREST:
+
+ /*
+ * These variants invoke I/O conversion functions for a wide range
+ * of data types, and have various special rules too, so in some
+ * cases they are only stable. In principle we could analyze
+ * their behavior precisely, but keeping such code in sync with
+ * the actual implementation seems like more maintenance risk than
+ * it's worth.
+ */
+ return false;
+
+ /* There is intentionally no default: case here */
+ }
+ /* We shouldn't get here, but if we do, say "not immutable" */
+ return false;
+}
+
/*
* contain_mutable_functions_after_planning
* Test whether given expression contains mutable functions.
@@ -649,8 +694,9 @@ contain_volatile_functions_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
+ * MinMaxExpr and CoerceToDomain as immutable. SQLValueFunction is
+ * stable, and XmlExpr might be immutable or stable, but it should never
+ * be volatile. Hence, none of them are of interest here.
*/
/* Recurse to check arguments */
@@ -723,10 +769,11 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
/*
* See notes in contain_mutable_functions_walker about why we treat
- * MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
- * SQLValueFunction is stable. Hence, none of them are of interest here.
- * Also, since we're intentionally ignoring nextval(), presumably we
- * should ignore NextValueExpr.
+ * MinMaxExpr and CoerceToDomain as immutable. SQLValueFunction is
+ * stable, and XmlExpr might be immutable or stable, but it should never
+ * be volatile. Hence, none of them are of interest here. Also, since
+ * we're intentionally ignoring nextval(), presumably we should ignore
+ * NextValueExpr.
*/
/* Recurse to check arguments */
@@ -3786,6 +3833,20 @@ eval_const_expressions_mutator(Node *node,
else
return copyObject((Node *) svf);
}
+ case T_XmlExpr:
+ {
+ /*
+ * Some variants of XmlExpr are immutable. Others are only
+ * stable, but in estimation mode those are still fair game to
+ * simplify.
+ */
+ node = ece_generic_processing(node);
+ if ((context->estimate ||
+ xmlexpr_is_immutable((XmlExpr *) node)) &&
+ ece_all_arguments_const(node))
+ return ece_evaluate_expr(node);
+ return node;
+ }
case T_FieldSelect:
{
/*
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index fb3e0ec41b2..350941f7172 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -713,6 +713,17 @@ LINE 1: SELECT '<>' IS NOT DOCUMENT;
DETAIL: line 1: StartTag: invalid element name
<>
^
+-- Check that IS DOCUMENT is known immutable, so that we don't reach the
+-- incorrect xpath() call at plan time.
+SELECT CASE WHEN ('2019-12-16T00:00:00.000'::xml) IS DOCUMENT
+ THEN (xpath('/*/text()', '2019-12-16T00:00:00.000'::xml))[1]
+ ELSE '2019-12-16T00:00:00.000'::xml
+END;
+ case
+-------------------------
+ 2019-12-16T00:00:00.000
+(1 row)
+
SELECT xmlagg(data) FROM xmltest;
xmlagg
--------------------------------------
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index aafd39433a6..ea0438aa45d 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -185,6 +185,13 @@ SELECT xml '<abc/>' IS NOT DOCUMENT;
SELECT xml 'abc' IS NOT DOCUMENT;
SELECT '<>' IS NOT DOCUMENT;
+-- Check that IS DOCUMENT is known immutable, so that we don't reach the
+-- incorrect xpath() call at plan time.
+SELECT CASE WHEN ('2019-12-16T00:00:00.000'::xml) IS DOCUMENT
+ THEN (xpath('/*/text()', '2019-12-16T00:00:00.000'::xml))[1]
+ ELSE '2019-12-16T00:00:00.000'::xml
+END;
+
SELECT xmlagg(data) FROM xmltest;
SELECT xmlagg(data) FROM xmltest WHERE id > 10;
--
2.52.0
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: BUG #19487: Error while executing SQL query involving XML parsing
@ 2026-08-30 18:35 Andrey Rachitskiy <pl0h0yp1@gmail.com>
parent: Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 1 reply; 11+ messages in thread
From: Andrey Rachitskiy @ 2026-08-30 18:35 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: i.portnov@compassplus.com; pgsql-bugs@lists.postgresql.org
вс, 30 авг. 2026 г. в 23:04, Tom Lane <tgl@sss.pgh.pa.us>:
> Andrey Rachitskiy <pl0h0yp1@gmail.com> writes:
> > I think you're right. Fixed it in v3.
>
> I spent some time looking at this, and felt that what we really
> ought to do is update clauses.c's handling of XmlExpr across the
> board. In particular, contain_mutable_functions really shouldn't
> allow XmlExpr in cases where we know it's not immutable. So more
> or less as attached, where I also spent more effort on the comments.
>
> I agree with handling XmlExpr more consistently. Using the
same xmlexpr_is_immutable check for both constant folding
and contain_mutable_functions looks right, including the estimate path.
LGTM
I've got mixed emotions about back-patching this. It's not really
> a bug fix, because we already disclaim the safety of relying on
> CASE for this purpose, cf [1]. I think it might still be reasonable
> to sneak into v19, but I'm unsure that putting it into 18 is a good
> idea.
>
> regards, tom lane
>
> [1]
> https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-EXPRESS-EVAL
>
> On back-patching: I share the hesitation about 18. At the same time,
SQL-language functions with this pattern did work on earlier branches and
broke for some users after the plan-cache change in 18. I would be fine
with putting it into 19 and master. If we back-patch to 18, I would treat
it as a narrow regression fix rather than a semantic promise about CASE.
Either way works for me.
Thank you for your time and for all the work you've put into this.
--
Regards,
Rachitskiy Andrey
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: BUG #19487: Error while executing SQL query involving XML parsing
@ 2026-09-01 16:21 Tom Lane <tgl@sss.pgh.pa.us>
parent: Andrey Rachitskiy <pl0h0yp1@gmail.com>
0 siblings, 1 reply; 11+ messages in thread
From: Tom Lane @ 2026-09-01 16:21 UTC (permalink / raw)
To: Andrey Rachitskiy <pl0h0yp1@gmail.com>; +Cc: i.portnov@compassplus.com; pgsql-bugs@lists.postgresql.org
Andrey Rachitskiy <pl0h0yp1@gmail.com> writes:
> вс, 30 авг. 2026 г. в 23:04, Tom Lane <tgl@sss.pgh.pa.us>:
>> I've got mixed emotions about back-patching this. It's not really
>> a bug fix, because we already disclaim the safety of relying on
>> CASE for this purpose, cf [1]. I think it might still be reasonable
>> to sneak into v19, but I'm unsure that putting it into 18 is a good
>> idea.
> On back-patching: I share the hesitation about 18. At the same time,
> SQL-language functions with this pattern did work on earlier branches and
> broke for some users after the plan-cache change in 18. I would be fine
> with putting it into 19 and master. If we back-patch to 18, I would treat
> it as a narrow regression fix rather than a semantic promise about CASE.
> Either way works for me.
After thinking about it for a day or so, I elected to push just as far
as 19. While it's true that this fixes the reported problem, it seems
possible that it de-optimizes somebody else's query. People don't
like that in minor releases...
regards, tom lane
^ permalink raw reply [nested|flat] 11+ messages in thread
* Re: BUG #19487: Error while executing SQL query involving XML parsing
@ 2026-09-01 16:37 Andrey Rachitskiy <pl0h0yp1@gmail.com>
parent: Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 0 replies; 11+ messages in thread
From: Andrey Rachitskiy @ 2026-09-01 16:37 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: i.portnov@compassplus.com; pgsql-bugs@lists.postgresql.org
вт, 1 сент. 2026 г. в 21:21, Tom Lane <tgl@sss.pgh.pa.us>:
> After thinking about it for a day or so, I elected to push just as far
> as 19. While it's true that this fixes the reported problem, it seems
> possible that it de-optimizes somebody else's query. People don't
> like that in minor releases...
>
Dear Tom,
Thank you for your thoughtful decision. Concerns about de-optimization in
minor releases are completely justified, and your caution here is very much
appreciated.
--
Regards,
Rachitskiy Andrey
^ permalink raw reply [nested|flat] 11+ messages in thread
end of thread, other threads:[~2026-09-01 16:37 UTC | newest]
Thread overview: 11+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2026-05-19 09:01 BUG #19487: Error while executing SQL query involving XML parsing PG Bug reporting form <noreply@postgresql.org>
2026-08-28 08:53 ` Andrey Rachitskiy <pl0h0yp1@gmail.com>
2026-08-28 19:49 ` Tom Lane <tgl@sss.pgh.pa.us>
2026-08-28 19:55 ` Andrey Rachitskiy <pl0h0yp1@gmail.com>
2026-08-29 10:54 ` Andrey Rachitskiy <pl0h0yp1@gmail.com>
2026-08-29 21:44 ` Tom Lane <tgl@sss.pgh.pa.us>
2026-08-30 03:08 ` Andrey Rachitskiy <pl0h0yp1@gmail.com>
2026-08-30 18:03 ` Tom Lane <tgl@sss.pgh.pa.us>
2026-08-30 18:35 ` Andrey Rachitskiy <pl0h0yp1@gmail.com>
2026-09-01 16:21 ` Tom Lane <tgl@sss.pgh.pa.us>
2026-09-01 16:37 ` Andrey Rachitskiy <pl0h0yp1@gmail.com>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox