Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commita3ca72a

Browse files
committed
Fix dumping of FUNCTION RTEs that contain non-function-call expressions.
The grammar will only accept something syntactically similar to a functioncall in a function-in-FROM expression. However, there are various waysto input something that ruleutils.c won't deparse that way, potentiallyleading to a view or rule that fails dump/reload. Fix by inserting adummy CAST around anything that isn't going to deparse as a function(which is one of the ways to get something like that in there in thefirst place).In HEAD, also make use of the infrastructure added by this to avoidemitting unnecessary parentheses in CREATE INDEX deparsing. I didnot change that in back branches, thinking that people might find itto be unexpected/unnecessary behavioral change.In HEAD, also fix incorrect logic for when to add extra parens topartition key expressions. Somebody apparently thought they couldget away with simpler logic than pg_get_indexdef_worker has, butthey were wrong --- a counterexample is PARTITION BY LIST ((a[1])).Ignoring the prettyprint flag for partition expressions isn't exactlya nice solution anyway.This has been broken all along, so back-patch to all supported branches.Discussion:https://postgr.es/m/10477.1499970459@sss.pgh.pa.us
1 parent2036f71 commita3ca72a

File tree

4 files changed

+110
-7
lines changed

4 files changed

+110
-7
lines changed

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

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,9 @@ static void get_rule_expr(Node *node, deparse_context *context,
416416
boolshowimplicit);
417417
staticvoidget_rule_expr_toplevel(Node*node,deparse_context*context,
418418
boolshowimplicit);
419+
staticvoidget_rule_expr_funccall(Node*node,deparse_context*context,
420+
boolshowimplicit);
421+
staticboollooks_like_function(Node*node);
419422
staticvoidget_oper_expr(OpExpr*expr,deparse_context*context);
420423
staticvoidget_func_expr(FuncExpr*expr,deparse_context*context,
421424
boolshowimplicit);
@@ -1308,8 +1311,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
13081311
if (!colno||colno==keyno+1)
13091312
{
13101313
/* Need parens if it's not a bare function call */
1311-
if (indexkey&&IsA(indexkey,FuncExpr)&&
1312-
((FuncExpr*)indexkey)->funcformat==COERCE_EXPLICIT_CALL)
1314+
if (looks_like_function(indexkey))
13131315
appendStringInfoString(&buf,str);
13141316
else
13151317
appendStringInfo(&buf,"(%s)",str);
@@ -1698,11 +1700,16 @@ pg_get_partkeydef_worker(Oid relid, int prettyFlags,
16981700
elog(ERROR,"too few entries in partexprs list");
16991701
partkey= (Node*)lfirst(partexpr_item);
17001702
partexpr_item=lnext(partexpr_item);
1703+
17011704
/* Deparse */
17021705
str=deparse_expression_pretty(partkey,context, false, false,
1703-
0,0);
1706+
prettyFlags,0);
1707+
/* Need parens if it's not a bare function call */
1708+
if (looks_like_function(partkey))
1709+
appendStringInfoString(&buf,str);
1710+
else
1711+
appendStringInfo(&buf,"(%s)",str);
17041712

1705-
appendStringInfoString(&buf,str);
17061713
keycoltype=exprType(partkey);
17071714
keycolcollation=exprCollation(partkey);
17081715
}
@@ -8776,6 +8783,64 @@ get_rule_expr_toplevel(Node *node, deparse_context *context,
87768783
get_rule_expr(node,context,showimplicit);
87778784
}
87788785

8786+
/*
8787+
* get_rule_expr_funccall- Parse back a function-call expression
8788+
*
8789+
* Same as get_rule_expr(), except that we guarantee that the output will
8790+
* look like a function call, or like one of the things the grammar treats as
8791+
* equivalent to a function call (see the func_expr_windowless production).
8792+
* This is needed in places where the grammar uses func_expr_windowless and
8793+
* you can't substitute a parenthesized a_expr. If what we have isn't going
8794+
* to look like a function call, wrap it in a dummy CAST() expression, which
8795+
* will satisfy the grammar --- and, indeed, is likely what the user wrote to
8796+
* produce such a thing.
8797+
*/
8798+
staticvoid
8799+
get_rule_expr_funccall(Node*node,deparse_context*context,
8800+
boolshowimplicit)
8801+
{
8802+
if (looks_like_function(node))
8803+
get_rule_expr(node,context,showimplicit);
8804+
else
8805+
{
8806+
StringInfobuf=context->buf;
8807+
8808+
appendStringInfoString(buf,"CAST(");
8809+
/* no point in showing any top-level implicit cast */
8810+
get_rule_expr(node,context, false);
8811+
appendStringInfo(buf," AS %s)",
8812+
format_type_with_typemod(exprType(node),
8813+
exprTypmod(node)));
8814+
}
8815+
}
8816+
8817+
/*
8818+
* Helper function to identify node types that satisfy func_expr_windowless.
8819+
* If in doubt, "false" is always a safe answer.
8820+
*/
8821+
staticbool
8822+
looks_like_function(Node*node)
8823+
{
8824+
if (node==NULL)
8825+
return false;/* probably shouldn't happen */
8826+
switch (nodeTag(node))
8827+
{
8828+
caseT_FuncExpr:
8829+
/* OK, unless it's going to deparse as a cast */
8830+
return (((FuncExpr*)node)->funcformat==COERCE_EXPLICIT_CALL);
8831+
caseT_NullIfExpr:
8832+
caseT_CoalesceExpr:
8833+
caseT_MinMaxExpr:
8834+
caseT_SQLValueFunction:
8835+
caseT_XmlExpr:
8836+
/* these are all accepted by func_expr_common_subexpr */
8837+
return true;
8838+
default:
8839+
break;
8840+
}
8841+
return false;
8842+
}
8843+
87798844

87808845
/*
87818846
* get_oper_expr- Parse back an OpExpr node
@@ -9749,7 +9814,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
97499814
if (list_length(rte->functions)==1&&
97509815
(rtfunc1->funccolnames==NIL|| !rte->funcordinality))
97519816
{
9752-
get_rule_expr(rtfunc1->funcexpr,context, true);
9817+
get_rule_expr_funccall(rtfunc1->funcexpr,context, true);
97539818
/* we'll print the coldeflist below, if it has one */
97549819
}
97559820
else
@@ -9812,7 +9877,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
98129877

98139878
if (funcno>0)
98149879
appendStringInfoString(buf,", ");
9815-
get_rule_expr(rtfunc->funcexpr,context, true);
9880+
get_rule_expr_funccall(rtfunc->funcexpr,context, true);
98169881
if (rtfunc->funccolnames!=NIL)
98179882
{
98189883
/* Reconstruct the column definition list */

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ Partition key: RANGE (a oid_ops, plusone(b), c, d COLLATE "C")
434434
Column | Type | Collation | Nullable | Default
435435
--------+---------+-----------+----------+---------
436436
a | integer | | |
437-
Partition key: LIST ((a + 1))
437+
Partition key: LIST (((a + 1)))
438438

439439
DROP TABLE partitioned, partitioned2;
440440
--

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,6 +1622,32 @@ select pg_get_viewdef('tt19v', true);
16221622
'foo'::text = ANY ((( SELECT ARRAY['abc'::text, 'def'::text, 'foo'::text] AS "array"))::text[]) AS c2;
16231623
(1 row)
16241624

1625+
-- check display of assorted RTE_FUNCTION expressions
1626+
create view tt20v as
1627+
select * from
1628+
coalesce(1,2) as c,
1629+
collation for ('x'::text) col,
1630+
current_date as d,
1631+
localtimestamp(3) as t,
1632+
cast(1+2 as int4) as i4,
1633+
cast(1+2 as int8) as i8;
1634+
select pg_get_viewdef('tt20v', true);
1635+
pg_get_viewdef
1636+
---------------------------------------------
1637+
SELECT c.c, +
1638+
col.col, +
1639+
d.d, +
1640+
t.t, +
1641+
i4.i4, +
1642+
i8.i8 +
1643+
FROM COALESCE(1, 2) c(c), +
1644+
pg_collation_for('x'::text) col(col), +
1645+
CURRENT_DATE d(d), +
1646+
LOCALTIMESTAMP(3) t(t), +
1647+
CAST(1 + 2 AS integer) i4(i4), +
1648+
CAST((1 + 2)::bigint AS bigint) i8(i8);
1649+
(1 row)
1650+
16251651
-- clean up all the random objects we made above
16261652
set client_min_messages = warning;
16271653
DROP SCHEMA temp_view_test CASCADE;

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,18 @@ select 'foo'::text = any(array['abc','def','foo']::text[]) c1,
547547
'foo'::text= any((select array['abc','def','foo']::text[])::text[]) c2;
548548
select pg_get_viewdef('tt19v', true);
549549

550+
-- check display of assorted RTE_FUNCTION expressions
551+
552+
createviewtt20vas
553+
select*from
554+
coalesce(1,2)as c,
555+
collation for ('x'::text) col,
556+
current_dateas d,
557+
localtimestamp(3)as t,
558+
cast(1+2as int4)as i4,
559+
cast(1+2as int8)as i8;
560+
select pg_get_viewdef('tt20v', true);
561+
550562
-- clean up all the random objects we made above
551563
set client_min_messages= warning;
552564
DROPSCHEMA temp_view_test CASCADE;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp