5454#include "optimizer/tlist.h"
5555#include "parser/analyze.h"
5656#include "parser/parse_agg.h"
57+ #include "parser/parse_clause.h"
5758#include "parser/parse_relation.h"
5859#include "parser/parsetree.h"
5960#include "partitioning/partdesc.h"
@@ -119,12 +120,15 @@ typedef struct
119120{
120121 List * activeWindows ; /* active windows, if any */
121122 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 */
122125} standard_qp_extra ;
123126
124127/* Local functions */
125128static Node * preprocess_expression (PlannerInfo * root , Node * expr , int kind );
126129static 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 );
128132static grouping_sets_data * preprocess_grouping_sets (PlannerInfo * root );
129133static List * remap_to_groupclause_idx (List * groupClause , List * gsets ,
130134 int * tleref_to_colnum_map );
@@ -249,6 +253,8 @@ static bool group_by_has_partkey(RelOptInfo *input_rel,
249253 List * targetList ,
250254 List * groupClause );
251255static int common_prefix_cmp (const void * a , const void * b );
256+ static List * generate_setop_child_grouplist (SetOperationStmt * op ,
257+ List * targetlist );
252258
253259
254260/*****************************************************************************
@@ -406,8 +412,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
406412 }
407413
408414 /* 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 );
411416
412417 /* Select best Path and turn it into a Plan */
413418 final_rel = fetch_upper_rel (root , UPPERREL_FINAL , NULL );
@@ -598,6 +603,10 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
598603 * hasRecursion is true if this is a recursive WITH query.
599604 * tuple_fraction is the fraction of tuples we expect will be retrieved.
600605 * 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.
601610 *
602611 * Basically, this routine does the stuff that should only be done once
603612 * 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,
616625 *--------------------
617626 */
618627PlannerInfo *
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 )
622631{
623632 PlannerInfo * root ;
624633 List * newWithCheckOptions ;
@@ -1077,7 +1086,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
10771086 /*
10781087 * Do the main planning.
10791088 */
1080- grouping_planner (root , tuple_fraction );
1089+ grouping_planner (root , tuple_fraction , setops );
10811090
10821091 /*
10831092 * 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)
12751284 * 0 < tuple_fraction < 1: expect the given fraction of tuples available
12761285 * from the plan to be retrieved
12771286 * 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.
12791292 *
12801293 * Returns nothing; the useful output is in the Paths we attach to the
12811294 * (UPPERREL_FINAL, NULL) upperrel in *root. In addition,
@@ -1286,7 +1299,8 @@ preprocess_phv_expression(PlannerInfo *root, Expr *expr)
12861299 *--------------------
12871300 */
12881301static void
1289- grouping_planner (PlannerInfo * root , double tuple_fraction )
1302+ grouping_planner (PlannerInfo * root , double tuple_fraction ,
1303+ SetOperationStmt * setops )
12901304{
12911305 Query * parse = root -> parse ;
12921306 int64 offset_est = 0 ;
@@ -1321,17 +1335,6 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
13211335
13221336 if (parse -> setOperations )
13231337 {
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-
13351338 /*
13361339 * Construct Paths for set operations. The results will not need any
13371340 * work except perhaps a top-level sort and/or LIMIT. Note that any
@@ -1501,6 +1504,12 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
15011504 qp_extra .activeWindows = activeWindows ;
15021505 qp_extra .gset_data = gset_data ;
15031506
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+
15041513 /*
15051514 * Generate the best unsorted and presorted paths for the scan/join
15061515 * portion of this Query, ie the processing represented by the
@@ -3453,6 +3462,27 @@ standard_qp_callback(PlannerInfo *root, void *extra)
34533462 parse -> sortClause ,
34543463 tlist );
34553464
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+
34563486 /*
34573487 * Figure out whether we want a sorted result from query_planner.
34583488 *
@@ -3462,7 +3492,9 @@ standard_qp_callback(PlannerInfo *root, void *extra)
34623492 * sortable DISTINCT clause that's more rigorous than the ORDER BY clause,
34633493 * we try to produce output that's sufficiently well sorted for the
34643494 * 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.
34663498 *
34673499 * Note: if we have both ORDER BY and GROUP BY, and ORDER BY is a superset
34683500 * 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)
34803512 root -> query_pathkeys = root -> distinct_pathkeys ;
34813513 else if (root -> sort_pathkeys )
34823514 root -> query_pathkeys = root -> sort_pathkeys ;
3515+ else if (root -> setop_pathkeys != NIL )
3516+ root -> query_pathkeys = root -> setop_pathkeys ;
34833517 else
34843518 root -> query_pathkeys = NIL ;
34853519}
@@ -7923,3 +7957,43 @@ group_by_has_partkey(RelOptInfo *input_rel,
79237957
79247958 return true;
79257959}
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