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

Commitfcf9eca

Browse files
committed
In locate_grouping_columns(), don't expect an exact match of Var typmods.
It's possible that inlining of SQL functions (or perhaps other changes?)has exposed typmod information not known at parse time. In such cases,Vars generated by query_planner might have valid typmod values while theoriginal grouping columns only have typmod -1. This isn't a semanticproblem since the behavior of grouping only depends on type not typmod,but it breaks locate_grouping_columns' use of tlist_member to locate thematching entry in query_planner's result tlist.We can fix this without an excessive amount of new code or complexity byrelying on the fact that locate_grouping_columns only gets called whenmake_subplanTargetList has set need_tlist_eval == false, and that can onlyhappen if all the grouping columns are simple Vars. Therefore we only needto search the sub_tlist for a matching Var, and we can reasonably define a"match" as being a match of the Var identity fieldsvarno/varattno/varlevelsup. The code still Asserts that vartype matches,but ignores vartypmod.Per bug #8393 from Evan Martin. The added regression test case isbasically the same as his example. This has been broken for a very longtime, so back-patch to all supported branches.
1 parent3454876 commitfcf9eca

File tree

5 files changed

+66
-3
lines changed

5 files changed

+66
-3
lines changed

‎src/backend/optimizer/plan/planner.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2964,7 +2964,8 @@ choose_hashed_distinct(PlannerInfo *root,
29642964
* 'groupColIdx' receives an array of column numbers for the GROUP BY
29652965
*expressions (if there are any) in the returned target list.
29662966
* 'need_tlist_eval' is set true if we really need to evaluate the
2967-
*returned tlist as-is.
2967+
*returned tlist as-is. (Note: locate_grouping_columns assumes
2968+
*that if this is FALSE, all grouping columns are simple Vars.)
29682969
*
29692970
* The result is the targetlist to be passed to query_planner.
29702971
*/
@@ -3127,6 +3128,7 @@ get_grouping_column_index(Query *parse, TargetEntry *tle)
31273128
* This is only needed if we don't use the sub_tlist chosen by
31283129
* make_subplanTargetList.We have to forget the column indexes found
31293130
* by that routine and re-locate the grouping exprs in the real sub_tlist.
3131+
* We assume the grouping exprs are just Vars (see make_subplanTargetList).
31303132
*/
31313133
staticvoid
31323134
locate_grouping_columns(PlannerInfo*root,
@@ -3150,11 +3152,24 @@ locate_grouping_columns(PlannerInfo *root,
31503152
foreach(gl,root->parse->groupClause)
31513153
{
31523154
SortGroupClause*grpcl= (SortGroupClause*)lfirst(gl);
3153-
Node*groupexpr=get_sortgroupclause_expr(grpcl,tlist);
3154-
TargetEntry*te=tlist_member(groupexpr,sub_tlist);
3155+
Var*groupexpr= (Var*)get_sortgroupclause_expr(grpcl,tlist);
3156+
TargetEntry*te;
31553157

3158+
/*
3159+
* The grouping column returned by create_plan might not have the same
3160+
* typmod as the original Var.(This can happen in cases where a
3161+
* set-returning function has been inlined, so that we now have more
3162+
* knowledge about what it returns than we did when the original Var
3163+
* was created.) So we can't use tlist_member() to search the tlist;
3164+
* instead use tlist_member_match_var.For safety, still check that
3165+
* the vartype matches.
3166+
*/
3167+
if (!(groupexpr&&IsA(groupexpr,Var)))
3168+
elog(ERROR,"grouping column is not a Var as expected");
3169+
te=tlist_member_match_var(groupexpr,sub_tlist);
31563170
if (!te)
31573171
elog(ERROR,"failed to locate grouping columns");
3172+
Assert(((Var*)te->expr)->vartype==groupexpr->vartype);
31583173
groupColIdx[keyno++]=te->resno;
31593174
}
31603175
}

‎src/backend/optimizer/util/tlist.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,35 @@ tlist_member_ignore_relabel(Node *node, List *targetlist)
7171
returnNULL;
7272
}
7373

74+
/*
75+
* tlist_member_match_var
76+
* Same as above, except that we match the provided Var on the basis
77+
* of varno/varattno/varlevelsup only, rather than using full equal().
78+
*
79+
* This is needed in some cases where we can't be sure of an exact typmod
80+
* match. It's probably a good idea to check the vartype anyway, but
81+
* we leave it to the caller to apply any suitable sanity checks.
82+
*/
83+
TargetEntry*
84+
tlist_member_match_var(Var*var,List*targetlist)
85+
{
86+
ListCell*temp;
87+
88+
foreach(temp,targetlist)
89+
{
90+
TargetEntry*tlentry= (TargetEntry*)lfirst(temp);
91+
Var*tlvar= (Var*)tlentry->expr;
92+
93+
if (!tlvar|| !IsA(tlvar,Var))
94+
continue;
95+
if (var->varno==tlvar->varno&&
96+
var->varattno==tlvar->varattno&&
97+
var->varlevelsup==tlvar->varlevelsup)
98+
returntlentry;
99+
}
100+
returnNULL;
101+
}
102+
74103
/*
75104
* flatten_tlist
76105
* Create a target list that only contains unique variables.

‎src/include/optimizer/tlist.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
externTargetEntry*tlist_member(Node*node,List*targetlist);
2121
externTargetEntry*tlist_member_ignore_relabel(Node*node,List*targetlist);
22+
externTargetEntry*tlist_member_match_var(Var*var,List*targetlist);
2223

2324
externList*flatten_tlist(List*tlist,PVCAggregateBehavioraggbehavior,
2425
PVCPlaceHolderBehaviorphbehavior);

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,17 @@ SELECT * FROM foo(3);
12471247
(9 rows)
12481248

12491249
DROP FUNCTION foo(int);
1250+
-- case that causes change of typmod knowledge during inlining
1251+
CREATE OR REPLACE FUNCTION foo()
1252+
RETURNS TABLE(a varchar(5))
1253+
AS $$ SELECT 'hello'::varchar(5) $$ LANGUAGE sql STABLE;
1254+
SELECT * FROM foo() GROUP BY 1;
1255+
a
1256+
-------
1257+
hello
1258+
(1 row)
1259+
1260+
DROP FUNCTION foo();
12501261
--
12511262
-- some tests on SQL functions with RETURNING
12521263
--

‎src/test/regress/sql/rangefuncs.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,13 @@ AS $$ SELECT a, b
330330
SELECT*FROM foo(3);
331331
DROPFUNCTION foo(int);
332332

333+
-- case that causes change of typmod knowledge during inlining
334+
CREATE OR REPLACEFUNCTIONfoo()
335+
RETURNS TABLE(avarchar(5))
336+
AS $$SELECT'hello'::varchar(5) $$ LANGUAGE sql STABLE;
337+
SELECT*FROM foo()GROUP BY1;
338+
DROPFUNCTION foo();
339+
333340
--
334341
-- some tests on SQL functions with RETURNING
335342
--

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp