Skip to content

Commit ca14c41

Browse files
committed
Fix ruleutils.c's dumping of whole-row Vars in more contexts.
Commit 7745bc3 intended to ensure that whole-row Vars would be printed with "::type" decoration in all contexts where plain "var.*" notation would result in star-expansion, notably in ROW() and VALUES() constructs. However, it missed the case of INSERT with a single-row VALUES, as reported by Timur Khanjanov. Nosing around ruleutils.c, I found a second oversight: the code for RowCompareExpr generates ROW() notation without benefit of an actual RowExpr, and naturally it wasn't in sync :-(. (The code for FieldStore also does this, but we don't expect that to generate strictly parsable SQL anyway, so I left it alone.) Back-patch to all supported branches. Discussion: https://postgr.es/m/efaba6f9-4190-56be-8ff2-7a1674f9194f@intrans.baku.az
1 parent 2180833 commit ca14c41

File tree

3 files changed

+57
-23
lines changed

3 files changed

+57
-23
lines changed

src/backend/utils/adt/ruleutils.c

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,8 @@ static void get_rule_expr(Node *node, deparse_context *context,
432432
bool showimplicit);
433433
static void get_rule_expr_toplevel(Node *node, deparse_context *context,
434434
bool showimplicit);
435+
static void get_rule_list_toplevel(List *lst, deparse_context *context,
436+
bool showimplicit);
435437
static void get_rule_expr_funccall(Node *node, deparse_context *context,
436438
bool showimplicit);
437439
static bool looks_like_function(Node *node);
@@ -6229,7 +6231,7 @@ get_insert_query_def(Query *query, deparse_context *context)
62296231
/* Add the single-VALUES expression list */
62306232
appendContextKeyword(context, "VALUES (",
62316233
-PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
6232-
get_rule_expr((Node *) strippedexprs, context, false);
6234+
get_rule_list_toplevel(strippedexprs, context, false);
62336235
appendStringInfoChar(buf, ')');
62346236
}
62356237
else
@@ -8539,23 +8541,15 @@ get_rule_expr(Node *node, deparse_context *context,
85398541
case T_RowCompareExpr:
85408542
{
85418543
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
8542-
ListCell *arg;
8543-
char *sep;
85448544

85458545
/*
85468546
* SQL99 allows "ROW" to be omitted when there is more than
8547-
* one column, but for simplicity we always print it.
8547+
* one column, but for simplicity we always print it. Within
8548+
* a ROW expression, whole-row Vars need special treatment, so
8549+
* use get_rule_list_toplevel.
85488550
*/
85498551
appendStringInfoString(buf, "(ROW(");
8550-
sep = "";
8551-
foreach(arg, rcexpr->largs)
8552-
{
8553-
Node *e = (Node *) lfirst(arg);
8554-
8555-
appendStringInfoString(buf, sep);
8556-
get_rule_expr(e, context, true);
8557-
sep = ", ";
8558-
}
8552+
get_rule_list_toplevel(rcexpr->largs, context, true);
85598553

85608554
/*
85618555
* We assume that the name of the first-column operator will
@@ -8568,15 +8562,7 @@ get_rule_expr(Node *node, deparse_context *context,
85688562
generate_operator_name(linitial_oid(rcexpr->opnos),
85698563
exprType(linitial(rcexpr->largs)),
85708564
exprType(linitial(rcexpr->rargs))));
8571-
sep = "";
8572-
foreach(arg, rcexpr->rargs)
8573-
{
8574-
Node *e = (Node *) lfirst(arg);
8575-
8576-
appendStringInfoString(buf, sep);
8577-
get_rule_expr(e, context, true);
8578-
sep = ", ";
8579-
}
8565+
get_rule_list_toplevel(rcexpr->rargs, context, true);
85808566
appendStringInfoString(buf, "))");
85818567
}
85828568
break;
@@ -9121,6 +9107,32 @@ get_rule_expr_toplevel(Node *node, deparse_context *context,
91219107
get_rule_expr(node, context, showimplicit);
91229108
}
91239109

9110+
/*
9111+
* get_rule_list_toplevel - Parse back a list of toplevel expressions
9112+
*
9113+
* Apply get_rule_expr_toplevel() to each element of a List.
9114+
*
9115+
* This adds commas between the expressions, but caller is responsible
9116+
* for printing surrounding decoration.
9117+
*/
9118+
static void
9119+
get_rule_list_toplevel(List *lst, deparse_context *context,
9120+
bool showimplicit)
9121+
{
9122+
const char *sep;
9123+
ListCell *lc;
9124+
9125+
sep = "";
9126+
foreach(lc, lst)
9127+
{
9128+
Node *e = (Node *) lfirst(lc);
9129+
9130+
appendStringInfoString(context->buf, sep);
9131+
get_rule_expr_toplevel(e, context, showimplicit);
9132+
sep = ", ";
9133+
}
9134+
}
9135+
91249136
/*
91259137
* get_rule_expr_funccall - Parse back a function-call expression
91269138
*

src/test/regress/expected/create_view.out

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,22 @@ select * from int8_tbl i where i.* in (values(i.*::int8_tbl));
16361636
4567890123456789 | -4567890123456789
16371637
(5 rows)
16381638

1639+
create table tt15v_log(o tt15v, n tt15v, incr bool);
1640+
create rule updlog as on update to tt15v do also
1641+
insert into tt15v_log values(old, new, row(old,old) < row(new,new));
1642+
\d+ tt15v
1643+
View "testviewschm2.tt15v"
1644+
Column | Type | Collation | Nullable | Default | Storage | Description
1645+
--------+-----------------+-----------+----------+---------+----------+-------------
1646+
row | nestedcomposite | | | | extended |
1647+
View definition:
1648+
SELECT ROW(i.*::int8_tbl)::nestedcomposite AS "row"
1649+
FROM int8_tbl i;
1650+
Rules:
1651+
updlog AS
1652+
ON UPDATE TO tt15v DO INSERT INTO tt15v_log (o, n, incr)
1653+
VALUES (old.*::tt15v, new.*::tt15v, (ROW(old.*::tt15v, old.*::tt15v) < ROW(new.*::tt15v, new.*::tt15v)))
1654+
16391655
-- check unique-ification of overlength names
16401656
create view tt18v as
16411657
select * from int8_tbl xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy
@@ -1904,7 +1920,7 @@ drop cascades to view aliased_view_2
19041920
drop cascades to view aliased_view_3
19051921
drop cascades to view aliased_view_4
19061922
DROP SCHEMA testviewschm2 CASCADE;
1907-
NOTICE: drop cascades to 67 other objects
1923+
NOTICE: drop cascades to 68 other objects
19081924
DETAIL: drop cascades to table t1
19091925
drop cascades to view temporal1
19101926
drop cascades to view temporal2
@@ -1963,6 +1979,7 @@ drop cascades to type nestedcomposite
19631979
drop cascades to view tt15v
19641980
drop cascades to view tt16v
19651981
drop cascades to view tt17v
1982+
drop cascades to table tt15v_log
19661983
drop cascades to view tt18v
19671984
drop cascades to view tt19v
19681985
drop cascades to view tt20v

src/test/regress/sql/create_view.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,11 @@ select * from tt17v;
554554
select pg_get_viewdef('tt17v', true);
555555
select * from int8_tbl i where i.* in (values(i.*::int8_tbl));
556556

557+
create table tt15v_log(o tt15v, n tt15v, incr bool);
558+
create rule updlog as on update to tt15v do also
559+
insert into tt15v_log values(old, new, row(old,old) < row(new,new));
560+
\d+ tt15v
561+
557562
-- check unique-ification of overlength names
558563

559564
create view tt18v as

0 commit comments

Comments
 (0)