Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7745bc3

Browse filesBrowse files
committed
Fix ruleutils.c's dumping of whole-row Vars in ROW() and VALUES() contexts.
Normally ruleutils prints a whole-row Var as "foo.*". We already knew that that doesn't work at top level of a SELECT list, because the parser would treat the "*" as a directive to expand the reference into separate columns, not a whole-row Var. However, Joshua Yanovski points out in bug #13776 that the same thing happens at top level of a ROW() construct; and some nosing around in the parser shows that the same is true in VALUES(). Hence, apply the same workaround already devised for the SELECT-list case, namely to add a forced cast to the appropriate rowtype in these cases. (The alternative of just printing "foo" was rejected because it is difficult to avoid ambiguity against plain columns named "foo".) Back-patch to all supported branches.
1 parent 7d9a473 commit 7745bc3
Copy full SHA for 7745bc3

File tree

Expand file treeCollapse file tree

3 files changed

+139
-5
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+139
-5
lines changed

‎src/backend/utils/adt/ruleutils.c

Copy file name to clipboardExpand all lines: src/backend/utils/adt/ruleutils.c
+30-5Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,8 @@ static void appendContextKeyword(deparse_context *context, const char *str,
391391
static void removeStringInfoSpaces(StringInfo str);
392392
static void get_rule_expr(Node *node, deparse_context *context,
393393
bool showimplicit);
394+
static void get_rule_expr_toplevel(Node *node, deparse_context *context,
395+
bool showimplicit);
394396
static void get_oper_expr(OpExpr *expr, deparse_context *context);
395397
static void get_func_expr(FuncExpr *expr, deparse_context *context,
396398
bool showimplicit);
@@ -4347,10 +4349,10 @@ get_values_def(List *values_lists, deparse_context *context)
43474349

43484350
/*
43494351
* Strip any top-level nodes representing indirection assignments,
4350-
* then print the result.
4352+
* then print the result. Whole-row Vars need special treatment.
43514353
*/
4352-
get_rule_expr(processIndirection(col, context, false),
4353-
context, false);
4354+
get_rule_expr_toplevel(processIndirection(col, context, false),
4355+
context, false);
43544356
}
43554357
appendStringInfoChar(buf, ')');
43564358
}
@@ -4771,7 +4773,8 @@ get_target_list(List *targetList, deparse_context *context,
47714773
* the top level of a SELECT list it's not right (the parser will
47724774
* expand that notation into multiple columns, yielding behavior
47734775
* different from a whole-row Var). We need to call get_variable
4774-
* directly so that we can tell it to do the right thing.
4776+
* directly so that we can tell it to do the right thing, and so that
4777+
* we can get the attribute name which is the default AS label.
47754778
*/
47764779
if (tle->expr && (IsA(tle->expr, Var)))
47774780
{
@@ -7515,7 +7518,8 @@ get_rule_expr(Node *node, deparse_context *context,
75157518
!tupdesc->attrs[i]->attisdropped)
75167519
{
75177520
appendStringInfoString(buf, sep);
7518-
get_rule_expr(e, context, true);
7521+
/* Whole-row Vars need special treatment here */
7522+
get_rule_expr_toplevel(e, context, true);
75197523
sep = ", ";
75207524
}
75217525
i++;
@@ -7941,6 +7945,27 @@ get_rule_expr(Node *node, deparse_context *context,
79417945
}
79427946
}
79437947

7948+
/*
7949+
* get_rule_expr_toplevel - Parse back a toplevel expression
7950+
*
7951+
* Same as get_rule_expr(), except that if the expr is just a Var, we pass
7952+
* istoplevel = true not false to get_variable(). This causes whole-row Vars
7953+
* to get printed with decoration that will prevent expansion of "*".
7954+
* We need to use this in contexts such as ROW() and VALUES(), where the
7955+
* parser would expand "foo.*" appearing at top level. (In principle we'd
7956+
* use this in get_target_list() too, but that has additional worries about
7957+
* whether to print AS, so it needs to invoke get_variable() directly anyway.)
7958+
*/
7959+
static void
7960+
get_rule_expr_toplevel(Node *node, deparse_context *context,
7961+
bool showimplicit)
7962+
{
7963+
if (node && IsA(node, Var))
7964+
(void) get_variable((Var *) node, 0, true, context);
7965+
else
7966+
get_rule_expr(node, context, showimplicit);
7967+
}
7968+
79447969

79457970
/*
79467971
* get_oper_expr - Parse back an OpExpr node

‎src/test/regress/expected/create_view.out

Copy file name to clipboardExpand all lines: src/test/regress/expected/create_view.out
+91Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,6 +1384,97 @@ select * from tt14v;
13841384
foo | | quux
13851385
(1 row)
13861386

1387+
-- check display of whole-row variables in some corner cases
1388+
create type nestedcomposite as (x int8_tbl);
1389+
create view tt15v as select row(i)::nestedcomposite from int8_tbl i;
1390+
select * from tt15v;
1391+
row
1392+
------------------------------------------
1393+
("(123,456)")
1394+
("(123,4567890123456789)")
1395+
("(4567890123456789,123)")
1396+
("(4567890123456789,4567890123456789)")
1397+
("(4567890123456789,-4567890123456789)")
1398+
(5 rows)
1399+
1400+
select pg_get_viewdef('tt15v', true);
1401+
pg_get_viewdef
1402+
------------------------------------------------------
1403+
SELECT ROW(i.*::int8_tbl)::nestedcomposite AS "row"+
1404+
FROM int8_tbl i;
1405+
(1 row)
1406+
1407+
select row(i.*::int8_tbl)::nestedcomposite from int8_tbl i;
1408+
row
1409+
------------------------------------------
1410+
("(123,456)")
1411+
("(123,4567890123456789)")
1412+
("(4567890123456789,123)")
1413+
("(4567890123456789,4567890123456789)")
1414+
("(4567890123456789,-4567890123456789)")
1415+
(5 rows)
1416+
1417+
create view tt16v as select * from int8_tbl i, lateral(values(i)) ss;
1418+
select * from tt16v;
1419+
q1 | q2 | column1
1420+
------------------+-------------------+--------------------------------------
1421+
123 | 456 | (123,456)
1422+
123 | 4567890123456789 | (123,4567890123456789)
1423+
4567890123456789 | 123 | (4567890123456789,123)
1424+
4567890123456789 | 4567890123456789 | (4567890123456789,4567890123456789)
1425+
4567890123456789 | -4567890123456789 | (4567890123456789,-4567890123456789)
1426+
(5 rows)
1427+
1428+
select pg_get_viewdef('tt16v', true);
1429+
pg_get_viewdef
1430+
-------------------------------------------
1431+
SELECT i.q1, +
1432+
i.q2, +
1433+
ss.column1 +
1434+
FROM int8_tbl i, +
1435+
LATERAL ( VALUES (i.*::int8_tbl)) ss;
1436+
(1 row)
1437+
1438+
select * from int8_tbl i, lateral(values(i.*::int8_tbl)) ss;
1439+
q1 | q2 | column1
1440+
------------------+-------------------+--------------------------------------
1441+
123 | 456 | (123,456)
1442+
123 | 4567890123456789 | (123,4567890123456789)
1443+
4567890123456789 | 123 | (4567890123456789,123)
1444+
4567890123456789 | 4567890123456789 | (4567890123456789,4567890123456789)
1445+
4567890123456789 | -4567890123456789 | (4567890123456789,-4567890123456789)
1446+
(5 rows)
1447+
1448+
create view tt17v as select * from int8_tbl i where i in (values(i));
1449+
select * from tt17v;
1450+
q1 | q2
1451+
------------------+-------------------
1452+
123 | 456
1453+
123 | 4567890123456789
1454+
4567890123456789 | 123
1455+
4567890123456789 | 4567890123456789
1456+
4567890123456789 | -4567890123456789
1457+
(5 rows)
1458+
1459+
select pg_get_viewdef('tt17v', true);
1460+
pg_get_viewdef
1461+
---------------------------------------------
1462+
SELECT i.q1, +
1463+
i.q2 +
1464+
FROM int8_tbl i +
1465+
WHERE (i.* IN ( VALUES (i.*::int8_tbl)));
1466+
(1 row)
1467+
1468+
select * from int8_tbl i where i.* in (values(i.*::int8_tbl));
1469+
q1 | q2
1470+
------------------+-------------------
1471+
123 | 456
1472+
123 | 4567890123456789
1473+
4567890123456789 | 123
1474+
4567890123456789 | 4567890123456789
1475+
4567890123456789 | -4567890123456789
1476+
(5 rows)
1477+
13871478
-- clean up all the random objects we made above
13881479
set client_min_messages = warning;
13891480
DROP SCHEMA temp_view_test CASCADE;

‎src/test/regress/sql/create_view.sql

Copy file name to clipboardExpand all lines: src/test/regress/sql/create_view.sql
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,24 @@ alter table tt14t drop column f3;
469469
select pg_get_viewdef('tt14v', true);
470470
select * from tt14v;
471471

472+
-- check display of whole-row variables in some corner cases
473+
474+
create type nestedcomposite as (x int8_tbl);
475+
create view tt15v as select row(i)::nestedcomposite from int8_tbl i;
476+
select * from tt15v;
477+
select pg_get_viewdef('tt15v', true);
478+
select row(i.*::int8_tbl)::nestedcomposite from int8_tbl i;
479+
480+
create view tt16v as select * from int8_tbl i, lateral(values(i)) ss;
481+
select * from tt16v;
482+
select pg_get_viewdef('tt16v', true);
483+
select * from int8_tbl i, lateral(values(i.*::int8_tbl)) ss;
484+
485+
create view tt17v as select * from int8_tbl i where i in (values(i));
486+
select * from tt17v;
487+
select pg_get_viewdef('tt17v', true);
488+
select * from int8_tbl i where i.* in (values(i.*::int8_tbl));
489+
472490
-- clean up all the random objects we made above
473491
set client_min_messages = warning;
474492
DROP SCHEMA temp_view_test CASCADE;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.