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

Commit08bc189

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 parent1869f00 commit08bc189

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
@@ -203,7 +203,7 @@ static void get_rule_orderby(List *orderList, List *targetList,
203203
staticvoidget_rule_windowclause(Query*query,deparse_context*context);
204204
staticvoidget_rule_windowspec(WindowClause*wc,List*targetList,
205205
deparse_context*context);
206-
staticchar*get_variable(Var*var,intlevelsup,boolshowstar,
206+
staticchar*get_variable(Var*var,intlevelsup,boolistoplevel,
207207
deparse_context*context);
208208
staticRangeTblEntry*find_rte_by_refname(constchar*refname,
209209
deparse_context*context);
@@ -3013,11 +3013,12 @@ get_target_list(List *targetList, deparse_context *context,
30133013
* "foo.*", which is the preferred notation in most contexts, but at
30143014
* the top level of a SELECT list it's not right (the parser will
30153015
* expand that notation into multiple columns, yielding behavior
3016-
* different from a whole-row Var). We want just "foo", instead.
3016+
* different from a whole-row Var). We need to call get_variable
3017+
* directly so that we can tell it to do the right thing.
30173018
*/
30183019
if (tle->expr&&IsA(tle->expr,Var))
30193020
{
3020-
attname=get_variable((Var*)tle->expr,0,false,context);
3021+
attname=get_variable((Var*)tle->expr,0,true,context);
30213022
}
30223023
else
30233024
{
@@ -3684,13 +3685,20 @@ get_utility_query_def(Query *query, deparse_context *context)
36843685
* the Var's varlevelsup has to be interpreted with respect to a context
36853686
* above the current one; levelsup indicates the offset.
36863687
*
3687-
* If showstar is TRUE, whole-row Vars are displayed as "foo.*";
3688-
* if FALSE, merely as "foo".
3688+
* If istoplevel is TRUE, the Var is at the top level of a SELECT's
3689+
* targetlist, which means we need special treatment of whole-row Vars.
3690+
* Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
3691+
* dirty hack to prevent "tab.*" from being expanded into multiple columns.
3692+
* (The parser will strip the useless coercion, so no inefficiency is added in
3693+
* dump and reload.) We used to print just "tab" in such cases, but that is
3694+
* ambiguous and will yield the wrong result if "tab" is also a plain column
3695+
* name in the query.
36893696
*
3690-
* Returns the attname of the Var, or NULL if not determinable.
3697+
* Returns the attname of the Var, or NULL if the Var has no attname (because
3698+
* it is a whole-row Var).
36913699
*/
36923700
staticchar*
3693-
get_variable(Var*var,intlevelsup,boolshowstar,deparse_context*context)
3701+
get_variable(Var*var,intlevelsup,boolistoplevel,deparse_context*context)
36943702
{
36953703
StringInfobuf=context->buf;
36963704
RangeTblEntry*rte;
@@ -3857,10 +3865,16 @@ get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
38573865
if (IsA(aliasvar,Var))
38583866
{
38593867
returnget_variable(aliasvar,var->varlevelsup+levelsup,
3860-
showstar,context);
3868+
istoplevel,context);
38613869
}
38623870
}
3863-
/* Unnamed join has neither schemaname nor refname */
3871+
3872+
/*
3873+
* Unnamed join has neither schemaname nor refname. (Note: since
3874+
* it's unnamed, there is no way the user could have referenced it
3875+
* to create a whole-row Var for it. So we don't have to cover
3876+
* that case below.)
3877+
*/
38643878
refname=NULL;
38653879
}
38663880
}
@@ -3876,13 +3890,18 @@ get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
38763890
appendStringInfo(buf,"%s.",
38773891
quote_identifier(schemaname));
38783892
appendStringInfoString(buf,quote_identifier(refname));
3879-
if (attname||showstar)
3880-
appendStringInfoChar(buf,'.');
3893+
appendStringInfoChar(buf,'.');
38813894
}
38823895
if (attname)
38833896
appendStringInfoString(buf,quote_identifier(attname));
3884-
elseif (showstar)
3897+
else
3898+
{
38853899
appendStringInfoChar(buf,'*');
3900+
if (istoplevel)
3901+
appendStringInfo(buf,"::%s",
3902+
format_type_with_typemod(var->vartype,
3903+
var->vartypmod));
3904+
}
38863905

38873906
returnattname;
38883907
}
@@ -4819,7 +4838,7 @@ get_rule_expr(Node *node, deparse_context *context,
48194838
switch (nodeTag(node))
48204839
{
48214840
caseT_Var:
4822-
(void)get_variable((Var*)node,0,true,context);
4841+
(void)get_variable((Var*)node,0,false,context);
48234842
break;
48244843

48254844
caseT_Const:

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp