mirror of
https://github.com/postgres/postgres.git
synced 2025-05-09 18:21:05 +03:00
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.
This commit is contained in:
parent
a37ab812c7
commit
7d0e872086
@ -378,6 +378,8 @@ static void appendContextKeyword(deparse_context *context, const char *str,
|
|||||||
static void removeStringInfoSpaces(StringInfo str);
|
static void removeStringInfoSpaces(StringInfo str);
|
||||||
static void get_rule_expr(Node *node, deparse_context *context,
|
static void get_rule_expr(Node *node, deparse_context *context,
|
||||||
bool showimplicit);
|
bool showimplicit);
|
||||||
|
static void get_rule_expr_toplevel(Node *node, deparse_context *context,
|
||||||
|
bool showimplicit);
|
||||||
static void get_oper_expr(OpExpr *expr, deparse_context *context);
|
static void get_oper_expr(OpExpr *expr, deparse_context *context);
|
||||||
static void get_func_expr(FuncExpr *expr, deparse_context *context,
|
static void get_func_expr(FuncExpr *expr, deparse_context *context,
|
||||||
bool showimplicit);
|
bool showimplicit);
|
||||||
@ -4162,10 +4164,10 @@ get_values_def(List *values_lists, deparse_context *context)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Strip any top-level nodes representing indirection assignments,
|
* Strip any top-level nodes representing indirection assignments,
|
||||||
* then print the result.
|
* then print the result. Whole-row Vars need special treatment.
|
||||||
*/
|
*/
|
||||||
get_rule_expr(processIndirection(col, context, false),
|
get_rule_expr_toplevel(processIndirection(col, context, false),
|
||||||
context, false);
|
context, false);
|
||||||
}
|
}
|
||||||
appendStringInfoChar(buf, ')');
|
appendStringInfoChar(buf, ')');
|
||||||
}
|
}
|
||||||
@ -4556,7 +4558,8 @@ get_target_list(List *targetList, deparse_context *context,
|
|||||||
* the top level of a SELECT list it's not right (the parser will
|
* the top level of a SELECT list it's not right (the parser will
|
||||||
* expand that notation into multiple columns, yielding behavior
|
* expand that notation into multiple columns, yielding behavior
|
||||||
* different from a whole-row Var). We need to call get_variable
|
* different from a whole-row Var). We need to call get_variable
|
||||||
* directly so that we can tell it to do the right thing.
|
* directly so that we can tell it to do the right thing, and so that
|
||||||
|
* we can get the attribute name which is the default AS label.
|
||||||
*/
|
*/
|
||||||
if (tle->expr && IsA(tle->expr, Var))
|
if (tle->expr && IsA(tle->expr, Var))
|
||||||
{
|
{
|
||||||
@ -7045,7 +7048,8 @@ get_rule_expr(Node *node, deparse_context *context,
|
|||||||
!tupdesc->attrs[i]->attisdropped)
|
!tupdesc->attrs[i]->attisdropped)
|
||||||
{
|
{
|
||||||
appendStringInfoString(buf, sep);
|
appendStringInfoString(buf, sep);
|
||||||
get_rule_expr(e, context, true);
|
/* Whole-row Vars need special treatment here */
|
||||||
|
get_rule_expr_toplevel(e, context, true);
|
||||||
sep = ", ";
|
sep = ", ";
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
@ -7425,6 +7429,27 @@ get_rule_expr(Node *node, deparse_context *context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_rule_expr_toplevel - Parse back a toplevel expression
|
||||||
|
*
|
||||||
|
* Same as get_rule_expr(), except that if the expr is just a Var, we pass
|
||||||
|
* istoplevel = true not false to get_variable(). This causes whole-row Vars
|
||||||
|
* to get printed with decoration that will prevent expansion of "*".
|
||||||
|
* We need to use this in contexts such as ROW() and VALUES(), where the
|
||||||
|
* parser would expand "foo.*" appearing at top level. (In principle we'd
|
||||||
|
* use this in get_target_list() too, but that has additional worries about
|
||||||
|
* whether to print AS, so it needs to invoke get_variable() directly anyway.)
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
get_rule_expr_toplevel(Node *node, deparse_context *context,
|
||||||
|
bool showimplicit)
|
||||||
|
{
|
||||||
|
if (node && IsA(node, Var))
|
||||||
|
(void) get_variable((Var *) node, 0, true, context);
|
||||||
|
else
|
||||||
|
get_rule_expr(node, context, showimplicit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get_oper_expr - Parse back an OpExpr node
|
* get_oper_expr - Parse back an OpExpr node
|
||||||
|
@ -1384,6 +1384,97 @@ select * from tt14v;
|
|||||||
foo | | quux
|
foo | | quux
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- check display of whole-row variables in some corner cases
|
||||||
|
create type nestedcomposite as (x int8_tbl);
|
||||||
|
create view tt15v as select row(i)::nestedcomposite from int8_tbl i;
|
||||||
|
select * from tt15v;
|
||||||
|
row
|
||||||
|
------------------------------------------
|
||||||
|
("(123,456)")
|
||||||
|
("(123,4567890123456789)")
|
||||||
|
("(4567890123456789,123)")
|
||||||
|
("(4567890123456789,4567890123456789)")
|
||||||
|
("(4567890123456789,-4567890123456789)")
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
select pg_get_viewdef('tt15v', true);
|
||||||
|
pg_get_viewdef
|
||||||
|
------------------------------------------------------
|
||||||
|
SELECT ROW(i.*::int8_tbl)::nestedcomposite AS "row"+
|
||||||
|
FROM int8_tbl i;
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
select row(i.*::int8_tbl)::nestedcomposite from int8_tbl i;
|
||||||
|
row
|
||||||
|
------------------------------------------
|
||||||
|
("(123,456)")
|
||||||
|
("(123,4567890123456789)")
|
||||||
|
("(4567890123456789,123)")
|
||||||
|
("(4567890123456789,4567890123456789)")
|
||||||
|
("(4567890123456789,-4567890123456789)")
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
create view tt16v as select * from int8_tbl i, lateral(values(i)) ss;
|
||||||
|
select * from tt16v;
|
||||||
|
q1 | q2 | column1
|
||||||
|
------------------+-------------------+--------------------------------------
|
||||||
|
123 | 456 | (123,456)
|
||||||
|
123 | 4567890123456789 | (123,4567890123456789)
|
||||||
|
4567890123456789 | 123 | (4567890123456789,123)
|
||||||
|
4567890123456789 | 4567890123456789 | (4567890123456789,4567890123456789)
|
||||||
|
4567890123456789 | -4567890123456789 | (4567890123456789,-4567890123456789)
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
select pg_get_viewdef('tt16v', true);
|
||||||
|
pg_get_viewdef
|
||||||
|
-------------------------------------------
|
||||||
|
SELECT i.q1, +
|
||||||
|
i.q2, +
|
||||||
|
ss.column1 +
|
||||||
|
FROM int8_tbl i, +
|
||||||
|
LATERAL ( VALUES (i.*::int8_tbl)) ss;
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
select * from int8_tbl i, lateral(values(i.*::int8_tbl)) ss;
|
||||||
|
q1 | q2 | column1
|
||||||
|
------------------+-------------------+--------------------------------------
|
||||||
|
123 | 456 | (123,456)
|
||||||
|
123 | 4567890123456789 | (123,4567890123456789)
|
||||||
|
4567890123456789 | 123 | (4567890123456789,123)
|
||||||
|
4567890123456789 | 4567890123456789 | (4567890123456789,4567890123456789)
|
||||||
|
4567890123456789 | -4567890123456789 | (4567890123456789,-4567890123456789)
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
create view tt17v as select * from int8_tbl i where i in (values(i));
|
||||||
|
select * from tt17v;
|
||||||
|
q1 | q2
|
||||||
|
------------------+-------------------
|
||||||
|
123 | 456
|
||||||
|
123 | 4567890123456789
|
||||||
|
4567890123456789 | 123
|
||||||
|
4567890123456789 | 4567890123456789
|
||||||
|
4567890123456789 | -4567890123456789
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
select pg_get_viewdef('tt17v', true);
|
||||||
|
pg_get_viewdef
|
||||||
|
---------------------------------------------
|
||||||
|
SELECT i.q1, +
|
||||||
|
i.q2 +
|
||||||
|
FROM int8_tbl i +
|
||||||
|
WHERE (i.* IN ( VALUES (i.*::int8_tbl)));
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
select * from int8_tbl i where i.* in (values(i.*::int8_tbl));
|
||||||
|
q1 | q2
|
||||||
|
------------------+-------------------
|
||||||
|
123 | 456
|
||||||
|
123 | 4567890123456789
|
||||||
|
4567890123456789 | 123
|
||||||
|
4567890123456789 | 4567890123456789
|
||||||
|
4567890123456789 | -4567890123456789
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
-- clean up all the random objects we made above
|
-- clean up all the random objects we made above
|
||||||
set client_min_messages = warning;
|
set client_min_messages = warning;
|
||||||
DROP SCHEMA temp_view_test CASCADE;
|
DROP SCHEMA temp_view_test CASCADE;
|
||||||
|
@ -469,6 +469,24 @@ alter table tt14t drop column f3;
|
|||||||
select pg_get_viewdef('tt14v', true);
|
select pg_get_viewdef('tt14v', true);
|
||||||
select * from tt14v;
|
select * from tt14v;
|
||||||
|
|
||||||
|
-- check display of whole-row variables in some corner cases
|
||||||
|
|
||||||
|
create type nestedcomposite as (x int8_tbl);
|
||||||
|
create view tt15v as select row(i)::nestedcomposite from int8_tbl i;
|
||||||
|
select * from tt15v;
|
||||||
|
select pg_get_viewdef('tt15v', true);
|
||||||
|
select row(i.*::int8_tbl)::nestedcomposite from int8_tbl i;
|
||||||
|
|
||||||
|
create view tt16v as select * from int8_tbl i, lateral(values(i)) ss;
|
||||||
|
select * from tt16v;
|
||||||
|
select pg_get_viewdef('tt16v', true);
|
||||||
|
select * from int8_tbl i, lateral(values(i.*::int8_tbl)) ss;
|
||||||
|
|
||||||
|
create view tt17v as select * from int8_tbl i where i in (values(i));
|
||||||
|
select * from tt17v;
|
||||||
|
select pg_get_viewdef('tt17v', true);
|
||||||
|
select * from int8_tbl i where i.* in (values(i.*::int8_tbl));
|
||||||
|
|
||||||
-- clean up all the random objects we made above
|
-- clean up all the random objects we made above
|
||||||
set client_min_messages = warning;
|
set client_min_messages = warning;
|
||||||
DROP SCHEMA temp_view_test CASCADE;
|
DROP SCHEMA temp_view_test CASCADE;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user