Skip to content

Commit 45a3cef

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 850c704 commit 45a3cef

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
@@ -421,6 +421,8 @@ static void get_rule_expr(Node *node, deparse_context *context,
421421
bool showimplicit);
422422
static void get_rule_expr_toplevel(Node *node, deparse_context *context,
423423
bool showimplicit);
424+
static void get_rule_list_toplevel(List *lst, deparse_context *context,
425+
bool showimplicit);
424426
static void get_rule_expr_funccall(Node *node, deparse_context *context,
425427
bool showimplicit);
426428
static bool looks_like_function(Node *node);
@@ -6278,7 +6280,7 @@ get_insert_query_def(Query *query, deparse_context *context)
62786280
/* Add the single-VALUES expression list */
62796281
appendContextKeyword(context, "VALUES (",
62806282
-PRETTYINDENT_STD, PRETTYINDENT_STD, 2);
6281-
get_rule_expr((Node *) strippedexprs, context, false);
6283+
get_rule_list_toplevel(strippedexprs, context, false);
62826284
appendStringInfoChar(buf, ')');
62836285
}
62846286
else
@@ -8466,23 +8468,15 @@ get_rule_expr(Node *node, deparse_context *context,
84668468
case T_RowCompareExpr:
84678469
{
84688470
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
8469-
ListCell *arg;
8470-
char *sep;
84718471

84728472
/*
84738473
* SQL99 allows "ROW" to be omitted when there is more than
8474-
* one column, but for simplicity we always print it.
8474+
* one column, but for simplicity we always print it. Within
8475+
* a ROW expression, whole-row Vars need special treatment, so
8476+
* use get_rule_list_toplevel.
84758477
*/
84768478
appendStringInfoString(buf, "(ROW(");
8477-
sep = "";
8478-
foreach(arg, rcexpr->largs)
8479-
{
8480-
Node *e = (Node *) lfirst(arg);
8481-
8482-
appendStringInfoString(buf, sep);
8483-
get_rule_expr(e, context, true);
8484-
sep = ", ";
8485-
}
8479+
get_rule_list_toplevel(rcexpr->largs, context, true);
84868480

84878481
/*
84888482
* We assume that the name of the first-column operator will
@@ -8495,15 +8489,7 @@ get_rule_expr(Node *node, deparse_context *context,
84958489
generate_operator_name(linitial_oid(rcexpr->opnos),
84968490
exprType(linitial(rcexpr->largs)),
84978491
exprType(linitial(rcexpr->rargs))));
8498-
sep = "";
8499-
foreach(arg, rcexpr->rargs)
8500-
{
8501-
Node *e = (Node *) lfirst(arg);
8502-
8503-
appendStringInfoString(buf, sep);
8504-
get_rule_expr(e, context, true);
8505-
sep = ", ";
8506-
}
8492+
get_rule_list_toplevel(rcexpr->rargs, context, true);
85078493
appendStringInfoString(buf, "))");
85088494
}
85098495
break;
@@ -9048,6 +9034,32 @@ get_rule_expr_toplevel(Node *node, deparse_context *context,
90489034
get_rule_expr(node, context, showimplicit);
90499035
}
90509036

9037+
/*
9038+
* get_rule_list_toplevel - Parse back a list of toplevel expressions
9039+
*
9040+
* Apply get_rule_expr_toplevel() to each element of a List.
9041+
*
9042+
* This adds commas between the expressions, but caller is responsible
9043+
* for printing surrounding decoration.
9044+
*/
9045+
static void
9046+
get_rule_list_toplevel(List *lst, deparse_context *context,
9047+
bool showimplicit)
9048+
{
9049+
const char *sep;
9050+
ListCell *lc;
9051+
9052+
sep = "";
9053+
foreach(lc, lst)
9054+
{
9055+
Node *e = (Node *) lfirst(lc);
9056+
9057+
appendStringInfoString(context->buf, sep);
9058+
get_rule_expr_toplevel(e, context, showimplicit);
9059+
sep = ", ";
9060+
}
9061+
}
9062+
90519063
/*
90529064
* get_rule_expr_funccall - Parse back a function-call expression
90539065
*

src/test/regress/expected/create_view.out

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

1615+
create table tt15v_log(o tt15v, n tt15v, incr bool);
1616+
create rule updlog as on update to tt15v do also
1617+
insert into tt15v_log values(old, new, row(old,old) < row(new,new));
1618+
\d+ tt15v
1619+
View "testviewschm2.tt15v"
1620+
Column | Type | Collation | Nullable | Default | Storage | Description
1621+
--------+-----------------+-----------+----------+---------+----------+-------------
1622+
row | nestedcomposite | | | | extended |
1623+
View definition:
1624+
SELECT ROW(i.*::int8_tbl)::nestedcomposite AS "row"
1625+
FROM int8_tbl i;
1626+
Rules:
1627+
updlog AS
1628+
ON UPDATE TO tt15v DO INSERT INTO tt15v_log (o, n, incr)
1629+
VALUES (old.*::tt15v, new.*::tt15v, (ROW(old.*::tt15v, old.*::tt15v) < ROW(new.*::tt15v, new.*::tt15v)))
1630+
16151631
-- check unique-ification of overlength names
16161632
create view tt18v as
16171633
select * from int8_tbl xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy
@@ -1782,7 +1798,7 @@ drop cascades to view aliased_view_2
17821798
drop cascades to view aliased_view_3
17831799
drop cascades to view aliased_view_4
17841800
DROP SCHEMA testviewschm2 CASCADE;
1785-
NOTICE: drop cascades to 63 other objects
1801+
NOTICE: drop cascades to 64 other objects
17861802
DETAIL: drop cascades to table t1
17871803
drop cascades to view temporal1
17881804
drop cascades to view temporal2
@@ -1840,6 +1856,7 @@ drop cascades to type nestedcomposite
18401856
drop cascades to view tt15v
18411857
drop cascades to view tt16v
18421858
drop cascades to view tt17v
1859+
drop cascades to table tt15v_log
18431860
drop cascades to view tt18v
18441861
drop cascades to view tt19v
18451862
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
@@ -548,6 +548,11 @@ select * from tt17v;
548548
select pg_get_viewdef('tt17v', true);
549549
select * from int8_tbl i where i.* in (values(i.*::int8_tbl));
550550

551+
create table tt15v_log(o tt15v, n tt15v, incr bool);
552+
create rule updlog as on update to tt15v do also
553+
insert into tt15v_log values(old, new, row(old,old) < row(new,new));
554+
\d+ tt15v
555+
551556
-- check unique-ification of overlength names
552557

553558
create view tt18v as

0 commit comments

Comments
 (0)