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

Commit14f9fb5

Browse files
committed
Fix printing of whole-row Vars at top level of a SELECT targetlist.
Normally whole-row Vars are printed as "tabname.*". However, that does notwork at top level of a targetlist, because per SQL standard the parser willthink that the "*" should result in column-by-column expansion; which isnot at all what a whole-row Var implies. We used to just print the tablename in such cases, which works most of the time; but it fails if the tablename matches a column name available anywhere in the FROM clause. Thiscould lead for instance to a view being interpreted differently after dumpand reload. Adding parentheses doesn't fix it, but there is a reasonablysimple kluge we can use instead: attach a no-op cast, so that the "*" isn'tsyntactically at top level anymore. This makes the printing of suchwhole-row Vars a lot more consistent with other Vars, and may indeed fixmore cases than just the reported one; I'm suspicious that cases involvingschema qualification probably didn't work properly before, either.Per bug report and fix proposal from Abbas Butt, though this patch is quitedifferent in detail from his.Back-patch to all supported versions.
1 parenta6708e2 commit14f9fb5

File tree

1 file changed

+32
-13
lines changed

1 file changed

+32
-13
lines changed

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

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ static void get_rule_windowclause(Query *query, deparse_context *context);
184184
staticvoidget_rule_windowspec(WindowClause*wc,List*targetList,
185185
deparse_context*context);
186186
staticvoidpush_plan(deparse_namespace*dpns,Plan*subplan);
187-
staticchar*get_variable(Var*var,intlevelsup,boolshowstar,
187+
staticchar*get_variable(Var*var,intlevelsup,boolistoplevel,
188188
deparse_context*context);
189189
staticRangeTblEntry*find_rte_by_refname(constchar*refname,
190190
deparse_context*context);
@@ -2822,11 +2822,12 @@ get_target_list(List *targetList, deparse_context *context,
28222822
* "foo.*", which is the preferred notation in most contexts, but at
28232823
* the top level of a SELECT list it's not right (the parser will
28242824
* expand that notation into multiple columns, yielding behavior
2825-
* different from a whole-row Var). We want just "foo", instead.
2825+
* different from a whole-row Var). We need to call get_variable
2826+
* directly so that we can tell it to do the right thing.
28262827
*/
28272828
if (tle->expr&&IsA(tle->expr,Var))
28282829
{
2829-
attname=get_variable((Var*)tle->expr,0,false,context);
2830+
attname=get_variable((Var*)tle->expr,0,true,context);
28302831
}
28312832
else
28322833
{
@@ -3539,13 +3540,20 @@ push_plan(deparse_namespace *dpns, Plan *subplan)
35393540
* the Var's varlevelsup has to be interpreted with respect to a context
35403541
* above the current one; levelsup indicates the offset.
35413542
*
3542-
* If showstar is TRUE, whole-row Vars are displayed as "foo.*";
3543-
* if FALSE, merely as "foo".
3543+
* If istoplevel is TRUE, the Var is at the top level of a SELECT's
3544+
* targetlist, which means we need special treatment of whole-row Vars.
3545+
* Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
3546+
* dirty hack to prevent "tab.*" from being expanded into multiple columns.
3547+
* (The parser will strip the useless coercion, so no inefficiency is added in
3548+
* dump and reload.) We used to print just "tab" in such cases, but that is
3549+
* ambiguous and will yield the wrong result if "tab" is also a plain column
3550+
* name in the query.
35443551
*
3545-
* Returns the attname of the Var, or NULL if not determinable.
3552+
* Returns the attname of the Var, or NULL if the Var has no attname (because
3553+
* it is a whole-row Var).
35463554
*/
35473555
staticchar*
3548-
get_variable(Var*var,intlevelsup,boolshowstar,deparse_context*context)
3556+
get_variable(Var*var,intlevelsup,boolistoplevel,deparse_context*context)
35493557
{
35503558
StringInfobuf=context->buf;
35513559
RangeTblEntry*rte;
@@ -3724,10 +3732,16 @@ get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
37243732
if (IsA(aliasvar,Var))
37253733
{
37263734
returnget_variable(aliasvar,var->varlevelsup+levelsup,
3727-
showstar,context);
3735+
istoplevel,context);
37283736
}
37293737
}
3730-
/* Unnamed join has neither schemaname nor refname */
3738+
3739+
/*
3740+
* Unnamed join has neither schemaname nor refname. (Note: since
3741+
* it's unnamed, there is no way the user could have referenced it
3742+
* to create a whole-row Var for it. So we don't have to cover
3743+
* that case below.)
3744+
*/
37313745
refname=NULL;
37323746
}
37333747
}
@@ -3743,13 +3757,18 @@ get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
37433757
appendStringInfo(buf,"%s.",
37443758
quote_identifier(schemaname));
37453759
appendStringInfoString(buf,quote_identifier(refname));
3746-
if (attname||showstar)
3747-
appendStringInfoChar(buf,'.');
3760+
appendStringInfoChar(buf,'.');
37483761
}
37493762
if (attname)
37503763
appendStringInfoString(buf,quote_identifier(attname));
3751-
elseif (showstar)
3764+
else
3765+
{
37523766
appendStringInfoChar(buf,'*');
3767+
if (istoplevel)
3768+
appendStringInfo(buf,"::%s",
3769+
format_type_with_typemod(var->vartype,
3770+
var->vartypmod));
3771+
}
37533772

37543773
returnattname;
37553774
}
@@ -4489,7 +4508,7 @@ get_rule_expr(Node *node, deparse_context *context,
44894508
switch (nodeTag(node))
44904509
{
44914510
caseT_Var:
4492-
(void)get_variable((Var*)node,0,true,context);
4511+
(void)get_variable((Var*)node,0,false,context);
44934512
break;
44944513

44954514
caseT_Const:

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp