mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
In deparsing, parenthesize IS DOCUMENT where it is an operand.
isSimpleNode() and related code treated every XmlExpr as self-delimiting. Most of them are, because they look like function calls with some extra decoration. But "x IS DOCUMENT" is not: it is a postfix test, like IS NULL. Printed as the operand of another operator, or as the operand of a postfix test, it was therefore not parenthesized and could not be parsed back, or was parsed as something unintended. Under-parenthesization occurred even in non-pretty-print cases, so that this could break dump/restore workflows. To fix, treat IS DOCUMENT as neither simple nor function-like, and give it the same treatment as other postfix tests. Also pass the single argument of IS DOCUMENT, not the argument list, to get_rule_expr_paren(). This avoids unnecessary parenthesization of the argument. Author: Henson Choi <assam258@gmail.com> Reviewed-by: Prashant Chinnam <crprashant@hotmail.com> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/CAAAe_zDuPSkc8ihCctV67Lxbqock+S4wqCHHo8xxZ1t4teXo0g@mail.gmail.com Backpatch-through: 14
This commit is contained in:
@@ -8913,7 +8913,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
|
|||||||
case T_CoalesceExpr:
|
case T_CoalesceExpr:
|
||||||
case T_MinMaxExpr:
|
case T_MinMaxExpr:
|
||||||
case T_SQLValueFunction:
|
case T_SQLValueFunction:
|
||||||
case T_XmlExpr:
|
|
||||||
case T_NextValueExpr:
|
case T_NextValueExpr:
|
||||||
case T_NullIfExpr:
|
case T_NullIfExpr:
|
||||||
case T_Aggref:
|
case T_Aggref:
|
||||||
@@ -9015,6 +9014,17 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
|
|||||||
}
|
}
|
||||||
pg_fallthrough;
|
pg_fallthrough;
|
||||||
|
|
||||||
|
case T_XmlExpr:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Function-like (name(..)), except "x IS DOCUMENT", which is a
|
||||||
|
* postfix test like IS NULL. (The IsA check is needed because
|
||||||
|
* T_OpExpr falls through to here.)
|
||||||
|
*/
|
||||||
|
if (IsA(node, XmlExpr) && ((XmlExpr *) node)->op != IS_DOCUMENT)
|
||||||
|
return true;
|
||||||
|
pg_fallthrough;
|
||||||
|
|
||||||
case T_SubLink:
|
case T_SubLink:
|
||||||
case T_NullTest:
|
case T_NullTest:
|
||||||
case T_BooleanTest:
|
case T_BooleanTest:
|
||||||
@@ -9039,13 +9049,14 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
|
|||||||
case T_RowExpr: /* other separators */
|
case T_RowExpr: /* other separators */
|
||||||
case T_CoalesceExpr: /* own parentheses */
|
case T_CoalesceExpr: /* own parentheses */
|
||||||
case T_MinMaxExpr: /* own parentheses */
|
case T_MinMaxExpr: /* own parentheses */
|
||||||
case T_XmlExpr: /* own parentheses */
|
|
||||||
case T_NullIfExpr: /* other separators */
|
case T_NullIfExpr: /* other separators */
|
||||||
case T_Aggref: /* own parentheses */
|
case T_Aggref: /* own parentheses */
|
||||||
case T_GroupingFunc: /* own parentheses */
|
case T_GroupingFunc: /* own parentheses */
|
||||||
case T_WindowFunc: /* own parentheses */
|
case T_WindowFunc: /* own parentheses */
|
||||||
case T_CaseExpr: /* other separators */
|
case T_CaseExpr: /* other separators */
|
||||||
return true;
|
return true;
|
||||||
|
case T_XmlExpr: /* own parentheses, except IS DOCUMENT */
|
||||||
|
return ((XmlExpr *) parentNode)->op != IS_DOCUMENT;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -9091,7 +9102,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
|
|||||||
case T_RowExpr: /* other separators */
|
case T_RowExpr: /* other separators */
|
||||||
case T_CoalesceExpr: /* own parentheses */
|
case T_CoalesceExpr: /* own parentheses */
|
||||||
case T_MinMaxExpr: /* own parentheses */
|
case T_MinMaxExpr: /* own parentheses */
|
||||||
case T_XmlExpr: /* own parentheses */
|
|
||||||
case T_NullIfExpr: /* other separators */
|
case T_NullIfExpr: /* other separators */
|
||||||
case T_Aggref: /* own parentheses */
|
case T_Aggref: /* own parentheses */
|
||||||
case T_GroupingFunc: /* own parentheses */
|
case T_GroupingFunc: /* own parentheses */
|
||||||
@@ -9099,6 +9109,8 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
|
|||||||
case T_CaseExpr: /* other separators */
|
case T_CaseExpr: /* other separators */
|
||||||
case T_JsonExpr: /* own parentheses */
|
case T_JsonExpr: /* own parentheses */
|
||||||
return true;
|
return true;
|
||||||
|
case T_XmlExpr: /* own parentheses, except IS DOCUMENT */
|
||||||
|
return ((XmlExpr *) parentNode)->op != IS_DOCUMENT;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -10151,6 +10163,9 @@ get_rule_expr(Node *node, deparse_context *context,
|
|||||||
appendStringInfoString(buf, "XMLSERIALIZE(");
|
appendStringInfoString(buf, "XMLSERIALIZE(");
|
||||||
break;
|
break;
|
||||||
case IS_DOCUMENT:
|
case IS_DOCUMENT:
|
||||||
|
/* postfix test, like IS NULL: not self-delimiting */
|
||||||
|
if (!PRETTY_PAREN(context))
|
||||||
|
appendStringInfoChar(buf, '(');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
|
if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
|
||||||
@@ -10258,7 +10273,9 @@ get_rule_expr(Node *node, deparse_context *context,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IS_DOCUMENT:
|
case IS_DOCUMENT:
|
||||||
get_rule_expr_paren((Node *) xexpr->args, context, false, node);
|
Assert(list_length(xexpr->args) == 1);
|
||||||
|
get_rule_expr_paren((Node *) linitial(xexpr->args),
|
||||||
|
context, false, node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10274,7 +10291,11 @@ get_rule_expr(Node *node, deparse_context *context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (xexpr->op == IS_DOCUMENT)
|
if (xexpr->op == IS_DOCUMENT)
|
||||||
|
{
|
||||||
appendStringInfoString(buf, " IS DOCUMENT");
|
appendStringInfoString(buf, " IS DOCUMENT");
|
||||||
|
if (!PRETTY_PAREN(context))
|
||||||
|
appendStringInfoChar(buf, ')');
|
||||||
|
}
|
||||||
else
|
else
|
||||||
appendStringInfoChar(buf, ')');
|
appendStringInfoChar(buf, ')');
|
||||||
}
|
}
|
||||||
@@ -10776,10 +10797,12 @@ looks_like_function(Node *node)
|
|||||||
case T_CoalesceExpr:
|
case T_CoalesceExpr:
|
||||||
case T_MinMaxExpr:
|
case T_MinMaxExpr:
|
||||||
case T_SQLValueFunction:
|
case T_SQLValueFunction:
|
||||||
case T_XmlExpr:
|
|
||||||
case T_JsonExpr:
|
case T_JsonExpr:
|
||||||
/* these are all accepted by func_expr_common_subexpr */
|
/* these are all accepted by func_expr_common_subexpr */
|
||||||
return true;
|
return true;
|
||||||
|
case T_XmlExpr:
|
||||||
|
/* all but IS DOCUMENT, which is a postfix test */
|
||||||
|
return ((XmlExpr *) node)->op != IS_DOCUMENT;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2276,6 +2276,23 @@ select pg_get_viewdef('tt26v', true);
|
|||||||
FROM ( VALUES (1,2,3)) v(x, y, z);
|
FROM ( VALUES (1,2,3)) v(x, y, z);
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- xml IS DOCUMENT needs to be treated specially
|
||||||
|
create operator ||
|
||||||
|
(function = xmlconcat2, leftarg=xml, rightarg=xml);
|
||||||
|
create view tt261v as
|
||||||
|
select x is document as c1,
|
||||||
|
(x || x) is document as c2,
|
||||||
|
f = (x is document) as c3
|
||||||
|
from (values(false,null::xml)) v(f,x);
|
||||||
|
select pg_get_viewdef('tt261v', true);
|
||||||
|
pg_get_viewdef
|
||||||
|
----------------------------------------------
|
||||||
|
SELECT x IS DOCUMENT AS c1, +
|
||||||
|
(x || x) IS DOCUMENT AS c2, +
|
||||||
|
f = (x IS DOCUMENT) AS c3 +
|
||||||
|
FROM ( VALUES (false,NULL::xml)) v(f, x);
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- test restriction on non-system view expansion.
|
-- test restriction on non-system view expansion.
|
||||||
create table tt27v_tbl (a int);
|
create table tt27v_tbl (a int);
|
||||||
create view tt27v as select a from tt27v_tbl;
|
create view tt27v as select a from tt27v_tbl;
|
||||||
@@ -2322,7 +2339,7 @@ drop cascades to view aliased_view_2
|
|||||||
drop cascades to view aliased_view_3
|
drop cascades to view aliased_view_3
|
||||||
drop cascades to view aliased_view_4
|
drop cascades to view aliased_view_4
|
||||||
DROP SCHEMA testviewschm2 CASCADE;
|
DROP SCHEMA testviewschm2 CASCADE;
|
||||||
NOTICE: drop cascades to 80 other objects
|
NOTICE: drop cascades to 82 other objects
|
||||||
DETAIL: drop cascades to table t1
|
DETAIL: drop cascades to table t1
|
||||||
drop cascades to view temporal1
|
drop cascades to view temporal1
|
||||||
drop cascades to view temporal2
|
drop cascades to view temporal2
|
||||||
@@ -2401,5 +2418,7 @@ drop cascades to view tt23v
|
|||||||
drop cascades to view tt24v
|
drop cascades to view tt24v
|
||||||
drop cascades to view tt25v
|
drop cascades to view tt25v
|
||||||
drop cascades to view tt26v
|
drop cascades to view tt26v
|
||||||
|
drop cascades to operator ||(xml,xml)
|
||||||
|
drop cascades to view tt261v
|
||||||
drop cascades to table tt27v_tbl
|
drop cascades to table tt27v_tbl
|
||||||
drop cascades to view tt27v
|
drop cascades to view tt27v
|
||||||
|
|||||||
@@ -832,6 +832,16 @@ select x + y + z as c1,
|
|||||||
from (values(1,2,3)) v(x,y,z);
|
from (values(1,2,3)) v(x,y,z);
|
||||||
select pg_get_viewdef('tt26v', true);
|
select pg_get_viewdef('tt26v', true);
|
||||||
|
|
||||||
|
-- xml IS DOCUMENT needs to be treated specially
|
||||||
|
create operator ||
|
||||||
|
(function = xmlconcat2, leftarg=xml, rightarg=xml);
|
||||||
|
create view tt261v as
|
||||||
|
select x is document as c1,
|
||||||
|
(x || x) is document as c2,
|
||||||
|
f = (x is document) as c3
|
||||||
|
from (values(false,null::xml)) v(f,x);
|
||||||
|
select pg_get_viewdef('tt261v', true);
|
||||||
|
|
||||||
-- test restriction on non-system view expansion.
|
-- test restriction on non-system view expansion.
|
||||||
create table tt27v_tbl (a int);
|
create table tt27v_tbl (a int);
|
||||||
create view tt27v as select a from tt27v_tbl;
|
create view tt27v as select a from tt27v_tbl;
|
||||||
|
|||||||
Reference in New Issue
Block a user