1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Fix two issues in deparsing.

If the target relation of UPDATE, DELETE, or MERGE has an alias,
we printed that "bare" (without AS or forced quoting), the same
as we do in FROM.  However, if that alias is "set", there's an
ambiguity with the SET keyword that must follow the relation
specification.  The parser would choose the wrong interpretation,
so that the dumped query would fail to reload.  The least surprising
and most future-proof fix seems to be to always print AS in these
contexts, as we already did in INSERT.

Also, we were insufficiently careful about parenthesizing the
left-hand argument of a SubLink (IN, op ANY/ALL, or row comparison),
so that the printed expression might not parse back with the intended
meaning depending on operator precedence.  This is only a problem in
"pretty-print" mode, since non-pretty mode fully parenthesizes every
operator.  So it isn't a hazard for pg_dump, but it still seems like
something to fix.  To do so, switch to using get_rule_expr_paren.
Presently that will add parens in some cases where it wouldn't really
be necessary, but that's better than the reverse, and it arguably
is helpful for readability anyway.

Author: Henson Choi <assam258@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAAAe_zDqXin5NeB5atRCbZqUdcMOeyXRqhan+tVp0F30OCURnw@mail.gmail.com
Discussion: https://postgr.es/m/CAAAe_zCy+D45Qd_br484F+V34y0BVA=hp_7cb=u6HysyMkE3UQ@mail.gmail.com
Backpatch-through: 14
This commit is contained in:
Tom Lane
2026-10-19 17:51:09 -04:00
parent 5eaf77b56e
commit f0595c3d83
4 changed files with 35 additions and 15 deletions

View File

@@ -6865,8 +6865,11 @@ get_update_query_def(Query *query, deparse_context *context)
only_marker(rte),
generate_relation_name(rte->relid, NIL));
/* Print the relation alias, if needed */
get_rte_alias(rte, query->resultRelation, false, context);
/*
* Print the relation alias, if needed. Always write AS, since a bare
* alias named "set" would be read as the SET keyword.
*/
get_rte_alias(rte, query->resultRelation, true, context);
appendStringInfoString(buf, " SET ");
@@ -7073,8 +7076,11 @@ get_delete_query_def(Query *query, deparse_context *context)
only_marker(rte),
generate_relation_name(rte->relid, NIL));
/* Print the relation alias, if needed */
get_rte_alias(rte, query->resultRelation, false, context);
/*
* Print the relation alias, if needed. Always write AS, since a bare
* alias named "set" would be read as the SET keyword.
*/
get_rte_alias(rte, query->resultRelation, true, context);
/* Add the USING clause if given */
get_from_clause(query, " USING ", context);
@@ -7125,8 +7131,11 @@ get_merge_query_def(Query *query, deparse_context *context)
only_marker(rte),
generate_relation_name(rte->relid, NIL));
/* Print the relation alias, if needed */
get_rte_alias(rte, query->resultRelation, false, context);
/*
* Print the relation alias, if needed. Always write AS, since a bare
* alias named "set" would be read as the SET keyword.
*/
get_rte_alias(rte, query->resultRelation, true, context);
/* Print the source relation and join clause */
get_from_clause(query, " USING ", context);
@@ -11104,7 +11113,9 @@ get_sublink_expr(SubLink *sublink, deparse_context *context)
/* single combining operator */
OpExpr *opexpr = (OpExpr *) sublink->testexpr;
get_rule_expr(linitial(opexpr->args), context, true);
/* Use get_rule_expr_paren to add parens if needed */
get_rule_expr_paren(linitial(opexpr->args), context, true,
(Node *) sublink);
opname = generate_operator_name(opexpr->opno,
exprType(linitial(opexpr->args)),
exprType(lsecond(opexpr->args)));

View File

@@ -2231,7 +2231,10 @@ select x + y + z as c1,
(x > y) AND (y > z OR x > z) as c8,
(x > y) OR (y > z AND NOT (x > z)) as c9,
(x,y) <> ALL (values(1,2),(3,4)) as c10,
(x,y) <= ANY (values(1,2),(3,4)) as c11
(x,y) <= ANY (values(1,2),(3,4)) as c11,
(x>0 OR y>0) IN (SELECT false) AS c12,
(x < y) <> ALL (SELECT false) AS c13,
true = (y = ANY (SELECT 1)) AS c14
from (values(1,2,3)) v(x,y,z);
select pg_get_viewdef('tt26v', true);
pg_get_viewdef
@@ -2246,7 +2249,10 @@ select pg_get_viewdef('tt26v', true);
x > y AND (y > z OR x > z) AS c8, +
x > y OR y > z AND NOT x > z AS c9, +
((x, y) <> ALL ( VALUES (1,2), (3,4))) AS c10,+
((x, y) <= ANY ( VALUES (1,2), (3,4))) AS c11 +
((x, y) <= ANY ( VALUES (1,2), (3,4))) AS c11,+
((x > 0 OR y > 0) IN ( SELECT false)) AS c12, +
((x < y) <> ALL ( SELECT false)) AS c13, +
true = ((y IN ( SELECT 1))) AS c14 +
FROM ( VALUES (1,2,3)) v(x, y, z);
(1 row)

View File

@@ -3049,7 +3049,7 @@ Rules:
RETURNING trgt.f1,
trgt.f2
r6 AS
ON UPDATE TO rules_src DO INSTEAD UPDATE rules_log trgt SET tag = 'updated'::text
ON UPDATE TO rules_src DO INSTEAD UPDATE rules_log AS trgt SET tag = 'updated'::text
WHERE trgt.f1 = new.f1
r7 AS
ON DELETE TO rules_src DO INSTEAD WITH wins AS (
@@ -3057,10 +3057,10 @@ Rules:
VALUES (0)
RETURNING trgt_1.f1
), wupd AS (
UPDATE int4_tbl trgt_1 SET f1 = trgt_1.f1 + 1
UPDATE int4_tbl AS trgt_1 SET f1 = trgt_1.f1 + 1
RETURNING trgt_1.f1
), wdel AS (
DELETE FROM int4_tbl trgt_1
DELETE FROM int4_tbl AS trgt_1
WHERE trgt_1.f1 = 0
RETURNING trgt_1.f1
)
@@ -3088,7 +3088,7 @@ create rule rr as on update to rule_t1 do instead UPDATE rule_dest trgt
f2 | integer | | | | plain | |
Rules:
rr AS
ON UPDATE TO rule_t1 DO INSTEAD UPDATE rule_dest trgt SET (f2[1], f1, tag) = ( SELECT new.f2,
ON UPDATE TO rule_t1 DO INSTEAD UPDATE rule_dest AS trgt SET (f2[1], f1, tag) = ( SELECT new.f2,
new.f1,
'updated'::character varying AS "varchar")
WHERE trgt.f1 = new.f1
@@ -3634,7 +3634,7 @@ CREATE OR REPLACE FUNCTION public.merge_sf_test()
RETURNS void
LANGUAGE sql
BEGIN ATOMIC
MERGE INTO sf_target t
MERGE INTO sf_target AS t
USING rule_merge1 s
ON (s.a = t.id)
WHEN MATCHED

View File

@@ -825,7 +825,10 @@ select x + y + z as c1,
(x > y) AND (y > z OR x > z) as c8,
(x > y) OR (y > z AND NOT (x > z)) as c9,
(x,y) <> ALL (values(1,2),(3,4)) as c10,
(x,y) <= ANY (values(1,2),(3,4)) as c11
(x,y) <= ANY (values(1,2),(3,4)) as c11,
(x>0 OR y>0) IN (SELECT false) AS c12,
(x < y) <> ALL (SELECT false) AS c13,
true = (y = ANY (SELECT 1)) AS c14
from (values(1,2,3)) v(x,y,z);
select pg_get_viewdef('tt26v', true);