54
54
#include "optimizer/tlist.h"
55
55
#include "parser/analyze.h"
56
56
#include "parser/parse_agg.h"
57
+ #include "parser/parse_clause.h"
57
58
#include "parser/parse_relation.h"
58
59
#include "parser/parsetree.h"
59
60
#include "partitioning/partdesc.h"
@@ -119,12 +120,15 @@ typedef struct
119
120
{
120
121
List * activeWindows ; /* active windows, if any */
121
122
grouping_sets_data * gset_data ; /* grouping sets data, if any */
123
+ SetOperationStmt * setop ; /* parent set operation or NULL if not a
124
+ * subquery belonging to a set operation */
122
125
} standard_qp_extra ;
123
126
124
127
/* Local functions */
125
128
static Node * preprocess_expression (PlannerInfo * root , Node * expr , int kind );
126
129
static void preprocess_qual_conditions (PlannerInfo * root , Node * jtnode );
127
- static void grouping_planner (PlannerInfo * root , double tuple_fraction );
130
+ static void grouping_planner (PlannerInfo * root , double tuple_fraction ,
131
+ SetOperationStmt * setops );
128
132
static grouping_sets_data * preprocess_grouping_sets (PlannerInfo * root );
129
133
static List * remap_to_groupclause_idx (List * groupClause , List * gsets ,
130
134
int * tleref_to_colnum_map );
@@ -249,6 +253,8 @@ static bool group_by_has_partkey(RelOptInfo *input_rel,
249
253
List * targetList ,
250
254
List * groupClause );
251
255
static int common_prefix_cmp (const void * a , const void * b );
256
+ static List * generate_setop_child_grouplist (SetOperationStmt * op ,
257
+ List * targetlist );
252
258
253
259
254
260
/*****************************************************************************
@@ -406,8 +412,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
406
412
}
407
413
408
414
/* primary planning entry point (may recurse for subqueries) */
409
- root = subquery_planner (glob , parse , NULL ,
410
- false, tuple_fraction );
415
+ root = subquery_planner (glob , parse , NULL , false, tuple_fraction , NULL );
411
416
412
417
/* Select best Path and turn it into a Plan */
413
418
final_rel = fetch_upper_rel (root , UPPERREL_FINAL , NULL );
@@ -598,6 +603,10 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
598
603
* hasRecursion is true if this is a recursive WITH query.
599
604
* tuple_fraction is the fraction of tuples we expect will be retrieved.
600
605
* tuple_fraction is interpreted as explained for grouping_planner, below.
606
+ * setops is used for set operation subqueries to provide the subquery with
607
+ * the context in which it's being used so that Paths correctly sorted for the
608
+ * set operation can be generated. NULL when not planning a set operation
609
+ * child.
601
610
*
602
611
* Basically, this routine does the stuff that should only be done once
603
612
* per Query object. It then calls grouping_planner. At one time,
@@ -616,9 +625,9 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
616
625
*--------------------
617
626
*/
618
627
PlannerInfo *
619
- subquery_planner (PlannerGlobal * glob , Query * parse ,
620
- PlannerInfo * parent_root ,
621
- bool hasRecursion , double tuple_fraction )
628
+ subquery_planner (PlannerGlobal * glob , Query * parse , PlannerInfo * parent_root ,
629
+ bool hasRecursion , double tuple_fraction ,
630
+ SetOperationStmt * setops )
622
631
{
623
632
PlannerInfo * root ;
624
633
List * newWithCheckOptions ;
@@ -1077,7 +1086,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
1077
1086
/*
1078
1087
* Do the main planning.
1079
1088
*/
1080
- grouping_planner (root , tuple_fraction );
1089
+ grouping_planner (root , tuple_fraction , setops );
1081
1090
1082
1091
/*
1083
1092
* Capture the set of outer-level param IDs we have access to, for use in
@@ -1275,7 +1284,11 @@ preprocess_phv_expression(PlannerInfo *root, Expr *expr)
1275
1284
* 0 < tuple_fraction < 1: expect the given fraction of tuples available
1276
1285
* from the plan to be retrieved
1277
1286
* tuple_fraction >= 1: tuple_fraction is the absolute number of tuples
1278
- * expected to be retrieved (ie, a LIMIT specification)
1287
+ * expected to be retrieved (ie, a LIMIT specification).
1288
+ * setops is used for set operation subqueries to provide the subquery with
1289
+ * the context in which it's being used so that Paths correctly sorted for the
1290
+ * set operation can be generated. NULL when not planning a set operation
1291
+ * child.
1279
1292
*
1280
1293
* Returns nothing; the useful output is in the Paths we attach to the
1281
1294
* (UPPERREL_FINAL, NULL) upperrel in *root. In addition,
@@ -1286,7 +1299,8 @@ preprocess_phv_expression(PlannerInfo *root, Expr *expr)
1286
1299
*--------------------
1287
1300
*/
1288
1301
static void
1289
- grouping_planner (PlannerInfo * root , double tuple_fraction )
1302
+ grouping_planner (PlannerInfo * root , double tuple_fraction ,
1303
+ SetOperationStmt * setops )
1290
1304
{
1291
1305
Query * parse = root -> parse ;
1292
1306
int64 offset_est = 0 ;
@@ -1321,17 +1335,6 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
1321
1335
1322
1336
if (parse -> setOperations )
1323
1337
{
1324
- /*
1325
- * If there's a top-level ORDER BY, assume we have to fetch all the
1326
- * tuples. This might be too simplistic given all the hackery below
1327
- * to possibly avoid the sort; but the odds of accurate estimates here
1328
- * are pretty low anyway. XXX try to get rid of this in favor of
1329
- * letting plan_set_operations generate both fast-start and
1330
- * cheapest-total paths.
1331
- */
1332
- if (parse -> sortClause )
1333
- root -> tuple_fraction = 0.0 ;
1334
-
1335
1338
/*
1336
1339
* Construct Paths for set operations. The results will not need any
1337
1340
* work except perhaps a top-level sort and/or LIMIT. Note that any
@@ -1501,6 +1504,12 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
1501
1504
qp_extra .activeWindows = activeWindows ;
1502
1505
qp_extra .gset_data = gset_data ;
1503
1506
1507
+ /*
1508
+ * If we're a subquery for a set operation, store the SetOperationStmt
1509
+ * in qp_extra.
1510
+ */
1511
+ qp_extra .setop = setops ;
1512
+
1504
1513
/*
1505
1514
* Generate the best unsorted and presorted paths for the scan/join
1506
1515
* portion of this Query, ie the processing represented by the
@@ -3453,6 +3462,27 @@ standard_qp_callback(PlannerInfo *root, void *extra)
3453
3462
parse -> sortClause ,
3454
3463
tlist );
3455
3464
3465
+ /* setting setop_pathkeys might be useful to the union planner */
3466
+ if (qp_extra -> setop != NULL &&
3467
+ set_operation_ordered_results_useful (qp_extra -> setop ))
3468
+ {
3469
+ List * groupClauses ;
3470
+ bool sortable ;
3471
+
3472
+ groupClauses = generate_setop_child_grouplist (qp_extra -> setop , tlist );
3473
+
3474
+ root -> setop_pathkeys =
3475
+ make_pathkeys_for_sortclauses_extended (root ,
3476
+ & groupClauses ,
3477
+ tlist ,
3478
+ false,
3479
+ & sortable );
3480
+ if (!sortable )
3481
+ root -> setop_pathkeys = NIL ;
3482
+ }
3483
+ else
3484
+ root -> setop_pathkeys = NIL ;
3485
+
3456
3486
/*
3457
3487
* Figure out whether we want a sorted result from query_planner.
3458
3488
*
@@ -3462,7 +3492,9 @@ standard_qp_callback(PlannerInfo *root, void *extra)
3462
3492
* sortable DISTINCT clause that's more rigorous than the ORDER BY clause,
3463
3493
* we try to produce output that's sufficiently well sorted for the
3464
3494
* DISTINCT. Otherwise, if there is an ORDER BY clause, we want to sort
3465
- * by the ORDER BY clause.
3495
+ * by the ORDER BY clause. Otherwise, if we're a subquery being planned
3496
+ * for a set operation which can benefit from presorted results and have a
3497
+ * sortable targetlist, we want to sort by the target list.
3466
3498
*
3467
3499
* Note: if we have both ORDER BY and GROUP BY, and ORDER BY is a superset
3468
3500
* of GROUP BY, it would be tempting to request sort by ORDER BY --- but
@@ -3480,6 +3512,8 @@ standard_qp_callback(PlannerInfo *root, void *extra)
3480
3512
root -> query_pathkeys = root -> distinct_pathkeys ;
3481
3513
else if (root -> sort_pathkeys )
3482
3514
root -> query_pathkeys = root -> sort_pathkeys ;
3515
+ else if (root -> setop_pathkeys != NIL )
3516
+ root -> query_pathkeys = root -> setop_pathkeys ;
3483
3517
else
3484
3518
root -> query_pathkeys = NIL ;
3485
3519
}
@@ -7923,3 +7957,43 @@ group_by_has_partkey(RelOptInfo *input_rel,
7923
7957
7924
7958
return true;
7925
7959
}
7960
+
7961
+ /*
7962
+ * generate_setop_child_grouplist
7963
+ * Build a SortGroupClause list defining the sort/grouping properties
7964
+ * of the child of a set operation.
7965
+ *
7966
+ * This is similar to generate_setop_grouplist() but differs as the setop
7967
+ * child query's targetlist entries may already have a tleSortGroupRef
7968
+ * assigned for other purposes, such as GROUP BYs. Here we keep the
7969
+ * SortGroupClause list in the same order as 'op' groupClauses and just adjust
7970
+ * the tleSortGroupRef to reference the TargetEntry's 'ressortgroupref'.
7971
+ */
7972
+ static List *
7973
+ generate_setop_child_grouplist (SetOperationStmt * op , List * targetlist )
7974
+ {
7975
+ List * grouplist = copyObject (op -> groupClauses );
7976
+ ListCell * lg ;
7977
+ ListCell * lt ;
7978
+
7979
+ lg = list_head (grouplist );
7980
+ foreach (lt , targetlist )
7981
+ {
7982
+ TargetEntry * tle = (TargetEntry * ) lfirst (lt );
7983
+ SortGroupClause * sgc ;
7984
+
7985
+ /* resjunk columns could have sortgrouprefs. Leave these alone */
7986
+ if (tle -> resjunk )
7987
+ continue ;
7988
+
7989
+ /* we expect every non-resjunk target to have a SortGroupClause */
7990
+ Assert (lg != NULL );
7991
+ sgc = (SortGroupClause * ) lfirst (lg );
7992
+ lg = lnext (grouplist , lg );
7993
+
7994
+ /* assign a tleSortGroupRef, or reuse the existing one */
7995
+ sgc -> tleSortGroupRef = assignSortGroupRef (tle , targetlist );
7996
+ }
7997
+ Assert (lg == NULL );
7998
+ return grouplist ;
7999
+ }
0 commit comments