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

Commitaa8a2c3

Browse files
committed
Fix generation of MergeAppend plans for optimized min/max on expressions.
Before jamming a desired targetlist into a plan node, one really ought tomake sure the plan node can handle projections, and insert a bufferingResult plan node if not. planagg.c forgot to do this, which is a hangoverfrom the days when it only dealt with IndexScan plan types. MergeAppenddoesn't project though, not to mention that it gets unhappy if you removeits possibly-resjunk sort columns. The code accidentally failed to failfor cases in which the min/max argument was a simple Var, because the newtargetlist would be equivalent to the original "flat" tlist anyway.For any more complex case, it's been broken since 9.1 where we introducedthe ability to optimize min/max using MergeAppend, as reported by RaphaelBauduin. Fix by duplicating the logic from grouping_planner that decideswhether we need a Result node.In 9.2 and 9.1, this requires back-porting the tlist_same_exprs() functionintroduced in commit4387cf9, else we'duselessly add a Result node in cases that worked before. It's rathertempting to back-patch that whole commit so that we can avoid extra Resultnodes in mainline cases too; but I'll refrain, since that code hasn'treally seen all that much field testing yet.
1 parent74aea2a commitaa8a2c3

File tree

5 files changed

+124
-1
lines changed

5 files changed

+124
-1
lines changed

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

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include"optimizer/planmain.h"
3939
#include"optimizer/planner.h"
4040
#include"optimizer/subselect.h"
41+
#include"optimizer/tlist.h"
4142
#include"parser/parsetree.h"
4243
#include"parser/parse_clause.h"
4344
#include"utils/lsyscache.h"
@@ -525,7 +526,27 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *mminfo)
525526
*/
526527
plan=create_plan(subroot,mminfo->path);
527528

528-
plan->targetlist=subparse->targetList;
529+
/*
530+
* If the top-level plan node is one that cannot do expression evaluation
531+
* and its existing target list isn't already what we need, we must insert
532+
* a Result node to project the desired tlist.
533+
*/
534+
if (!is_projection_capable_plan(plan)&&
535+
!tlist_same_exprs(subparse->targetList,plan->targetlist))
536+
{
537+
plan= (Plan*)make_result(subroot,
538+
subparse->targetList,
539+
NULL,
540+
plan);
541+
}
542+
else
543+
{
544+
/*
545+
* Otherwise, just replace the subplan's flat tlist with the desired
546+
* tlist.
547+
*/
548+
plan->targetlist=subparse->targetList;
549+
}
529550

530551
plan= (Plan*)make_limit(plan,
531552
subparse->limitOffset,

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,43 @@ get_tlist_exprs(List *tlist, bool includeJunk)
187187
}
188188

189189

190+
/*
191+
* tlist_same_exprs
192+
*Check whether two target lists contain the same expressions
193+
*
194+
* Note: this function is used to decide whether it's safe to jam a new tlist
195+
* into a non-projection-capable plan node. Obviously we can't do that unless
196+
* the node's tlist shows it already returns the column values we want.
197+
* However, we can ignore the TargetEntry attributes resname, ressortgroupref,
198+
* resorigtbl, resorigcol, and resjunk, because those are only labelings that
199+
* don't affect the row values computed by the node. (Moreover, if we didn't
200+
* ignore them, we'd frequently fail to make the desired optimization, since
201+
* the planner tends to not bother to make resname etc. valid in intermediate
202+
* plan nodes.) Note that on success, the caller must still jam the desired
203+
* tlist into the plan node, else it won't have the desired labeling fields.
204+
*/
205+
bool
206+
tlist_same_exprs(List*tlist1,List*tlist2)
207+
{
208+
ListCell*lc1,
209+
*lc2;
210+
211+
if (list_length(tlist1)!=list_length(tlist2))
212+
return false;/* not same length, so can't match */
213+
214+
forboth(lc1,tlist1,lc2,tlist2)
215+
{
216+
TargetEntry*tle1= (TargetEntry*)lfirst(lc1);
217+
TargetEntry*tle2= (TargetEntry*)lfirst(lc2);
218+
219+
if (!equal(tle1->expr,tle2->expr))
220+
return false;
221+
}
222+
223+
return true;
224+
}
225+
226+
190227
/*
191228
* Does tlist have same output datatypes as listed in colTypes?
192229
*

‎src/include/optimizer/tlist.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ extern List *flatten_tlist(List *tlist, PVCAggregateBehavior aggbehavior,
2626
externList*add_to_flat_tlist(List*tlist,List*exprs);
2727

2828
externList*get_tlist_exprs(List*tlist,boolincludeJunk);
29+
30+
externbooltlist_same_exprs(List*tlist1,List*tlist2);
31+
2932
externbooltlist_same_datatypes(List*tlist,List*colTypes,booljunkOK);
3033
externbooltlist_same_collations(List*tlist,List*colCollations,booljunkOK);
3134

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

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,28 @@ select * from matest0 order by 1-id;
12161216
1 | Test 1
12171217
(6 rows)
12181218

1219+
explain (verbose, costs off) select min(1-id) from matest0;
1220+
QUERY PLAN
1221+
------------------------------------------------
1222+
Aggregate
1223+
Output: min((1 - public.matest0.id))
1224+
-> Append
1225+
-> Seq Scan on public.matest0
1226+
Output: public.matest0.id
1227+
-> Seq Scan on public.matest1 matest0
1228+
Output: public.matest0.id
1229+
-> Seq Scan on public.matest2 matest0
1230+
Output: public.matest0.id
1231+
-> Seq Scan on public.matest3 matest0
1232+
Output: public.matest0.id
1233+
(11 rows)
1234+
1235+
select min(1-id) from matest0;
1236+
min
1237+
-----
1238+
-5
1239+
(1 row)
1240+
12191241
reset enable_indexscan;
12201242
set enable_seqscan = off; -- plan with fewest seqscans should be merge
12211243
explain (verbose, costs off) select * from matest0 order by 1-id;
@@ -1249,6 +1271,42 @@ select * from matest0 order by 1-id;
12491271
1 | Test 1
12501272
(6 rows)
12511273

1274+
explain (verbose, costs off) select min(1-id) from matest0;
1275+
QUERY PLAN
1276+
--------------------------------------------------------------------------------------
1277+
Result
1278+
Output: $0
1279+
InitPlan 1 (returns $0)
1280+
-> Limit
1281+
Output: ((1 - public.matest0.id))
1282+
-> Result
1283+
Output: ((1 - public.matest0.id))
1284+
-> Merge Append
1285+
Sort Key: ((1 - public.matest0.id))
1286+
-> Index Scan using matest0i on public.matest0
1287+
Output: public.matest0.id, (1 - public.matest0.id)
1288+
Index Cond: ((1 - public.matest0.id) IS NOT NULL)
1289+
-> Index Scan using matest1i on public.matest1 matest0
1290+
Output: public.matest0.id, (1 - public.matest0.id)
1291+
Index Cond: ((1 - public.matest0.id) IS NOT NULL)
1292+
-> Sort
1293+
Output: public.matest0.id, ((1 - public.matest0.id))
1294+
Sort Key: ((1 - public.matest0.id))
1295+
-> Bitmap Heap Scan on public.matest2 matest0
1296+
Output: public.matest0.id, (1 - public.matest0.id)
1297+
Filter: ((1 - public.matest0.id) IS NOT NULL)
1298+
-> Bitmap Index Scan on matest2_pkey
1299+
-> Index Scan using matest3i on public.matest3 matest0
1300+
Output: public.matest0.id, (1 - public.matest0.id)
1301+
Index Cond: ((1 - public.matest0.id) IS NOT NULL)
1302+
(25 rows)
1303+
1304+
select min(1-id) from matest0;
1305+
min
1306+
-----
1307+
-5
1308+
(1 row)
1309+
12521310
reset enable_seqscan;
12531311
drop table matest0 cascade;
12541312
NOTICE: drop cascades to 3 other objects

‎src/test/regress/sql/inherit.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,11 +382,15 @@ insert into matest3 (name) values ('Test 6');
382382
set enable_indexscan= off;-- force use of seqscan/sort, so no merge
383383
explain (verbose, costs off)select*from matest0order by1-id;
384384
select*from matest0order by1-id;
385+
explain (verbose, costs off)selectmin(1-id)from matest0;
386+
selectmin(1-id)from matest0;
385387
reset enable_indexscan;
386388

387389
set enable_seqscan= off;-- plan with fewest seqscans should be merge
388390
explain (verbose, costs off)select*from matest0order by1-id;
389391
select*from matest0order by1-id;
392+
explain (verbose, costs off)selectmin(1-id)from matest0;
393+
selectmin(1-id)from matest0;
390394
reset enable_seqscan;
391395

392396
droptable matest0 cascade;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp