Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * planner.c
4 : : * The query optimizer external interface.
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/optimizer/plan/planner.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : :
16 : : #include "postgres.h"
17 : :
18 : : #include <limits.h>
19 : : #include <math.h>
20 : :
21 : : #include "access/genam.h"
22 : : #include "access/parallel.h"
23 : : #include "access/sysattr.h"
24 : : #include "access/table.h"
25 : : #include "catalog/pg_aggregate.h"
26 : : #include "catalog/pg_constraint.h"
27 : : #include "catalog/pg_inherits.h"
28 : : #include "catalog/pg_proc.h"
29 : : #include "catalog/pg_type.h"
30 : : #include "executor/executor.h"
31 : : #include "foreign/fdwapi.h"
32 : : #include "jit/jit.h"
33 : : #include "lib/bipartite_match.h"
34 : : #include "lib/knapsack.h"
35 : : #include "miscadmin.h"
36 : : #include "nodes/makefuncs.h"
37 : : #include "nodes/nodeFuncs.h"
38 : : #ifdef OPTIMIZER_DEBUG
39 : : #include "nodes/print.h"
40 : : #endif
41 : : #include "nodes/supportnodes.h"
42 : : #include "optimizer/appendinfo.h"
43 : : #include "optimizer/clauses.h"
44 : : #include "optimizer/cost.h"
45 : : #include "optimizer/optimizer.h"
46 : : #include "optimizer/paramassign.h"
47 : : #include "optimizer/pathnode.h"
48 : : #include "optimizer/paths.h"
49 : : #include "optimizer/plancat.h"
50 : : #include "optimizer/planmain.h"
51 : : #include "optimizer/planner.h"
52 : : #include "optimizer/prep.h"
53 : : #include "optimizer/subselect.h"
54 : : #include "optimizer/tlist.h"
55 : : #include "parser/analyze.h"
56 : : #include "parser/parse_agg.h"
57 : : #include "parser/parse_clause.h"
58 : : #include "parser/parse_relation.h"
59 : : #include "parser/parsetree.h"
60 : : #include "partitioning/partdesc.h"
61 : : #include "utils/lsyscache.h"
62 : : #include "utils/rel.h"
63 : : #include "utils/selfuncs.h"
64 : :
65 : : /* GUC parameters */
66 : : double cursor_tuple_fraction = DEFAULT_CURSOR_TUPLE_FRACTION;
67 : : int debug_parallel_query = DEBUG_PARALLEL_OFF;
68 : : bool parallel_leader_participation = true;
69 : :
70 : : /* Hook for plugins to get control in planner() */
71 : : planner_hook_type planner_hook = NULL;
72 : :
73 : : /* Hook for plugins to get control when grouping_planner() plans upper rels */
74 : : create_upper_paths_hook_type create_upper_paths_hook = NULL;
75 : :
76 : :
77 : : /* Expression kind codes for preprocess_expression */
78 : : #define EXPRKIND_QUAL 0
79 : : #define EXPRKIND_TARGET 1
80 : : #define EXPRKIND_RTFUNC 2
81 : : #define EXPRKIND_RTFUNC_LATERAL 3
82 : : #define EXPRKIND_VALUES 4
83 : : #define EXPRKIND_VALUES_LATERAL 5
84 : : #define EXPRKIND_LIMIT 6
85 : : #define EXPRKIND_APPINFO 7
86 : : #define EXPRKIND_PHV 8
87 : : #define EXPRKIND_TABLESAMPLE 9
88 : : #define EXPRKIND_ARBITER_ELEM 10
89 : : #define EXPRKIND_TABLEFUNC 11
90 : : #define EXPRKIND_TABLEFUNC_LATERAL 12
91 : :
92 : : /*
93 : : * Data specific to grouping sets
94 : : */
95 : : typedef struct
96 : : {
97 : : List *rollups;
98 : : List *hash_sets_idx;
99 : : double dNumHashGroups;
100 : : bool any_hashable;
101 : : Bitmapset *unsortable_refs;
102 : : Bitmapset *unhashable_refs;
103 : : List *unsortable_sets;
104 : : int *tleref_to_colnum_map;
105 : : } grouping_sets_data;
106 : :
107 : : /*
108 : : * Temporary structure for use during WindowClause reordering in order to be
109 : : * able to sort WindowClauses on partitioning/ordering prefix.
110 : : */
111 : : typedef struct
112 : : {
113 : : WindowClause *wc;
114 : : List *uniqueOrder; /* A List of unique ordering/partitioning
115 : : * clauses per Window */
116 : : } WindowClauseSortData;
117 : :
118 : : /* Passthrough data for standard_qp_callback */
119 : : typedef struct
120 : : {
121 : : List *activeWindows; /* active windows, if any */
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 */
125 : : } standard_qp_extra;
126 : :
127 : : /* Local functions */
128 : : static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind);
129 : : static void preprocess_qual_conditions(PlannerInfo *root, Node *jtnode);
130 : : static void grouping_planner(PlannerInfo *root, double tuple_fraction,
131 : : SetOperationStmt *setops);
132 : : static grouping_sets_data *preprocess_grouping_sets(PlannerInfo *root);
133 : : static List *remap_to_groupclause_idx(List *groupClause, List *gsets,
134 : : int *tleref_to_colnum_map);
135 : : static void preprocess_rowmarks(PlannerInfo *root);
136 : : static double preprocess_limit(PlannerInfo *root,
137 : : double tuple_fraction,
138 : : int64 *offset_est, int64 *count_est);
139 : : static void remove_useless_groupby_columns(PlannerInfo *root);
140 : : static List *groupclause_apply_groupingset(PlannerInfo *root, List *force);
141 : : static List *extract_rollup_sets(List *groupingSets);
142 : : static List *reorder_grouping_sets(List *groupingSets, List *sortclause);
143 : : static void standard_qp_callback(PlannerInfo *root, void *extra);
144 : : static double get_number_of_groups(PlannerInfo *root,
145 : : double path_rows,
146 : : grouping_sets_data *gd,
147 : : List *target_list);
148 : : static RelOptInfo *create_grouping_paths(PlannerInfo *root,
149 : : RelOptInfo *input_rel,
150 : : PathTarget *target,
151 : : bool target_parallel_safe,
152 : : grouping_sets_data *gd);
153 : : static bool is_degenerate_grouping(PlannerInfo *root);
154 : : static void create_degenerate_grouping_paths(PlannerInfo *root,
155 : : RelOptInfo *input_rel,
156 : : RelOptInfo *grouped_rel);
157 : : static RelOptInfo *make_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
158 : : PathTarget *target, bool target_parallel_safe,
159 : : Node *havingQual);
160 : : static void create_ordinary_grouping_paths(PlannerInfo *root,
161 : : RelOptInfo *input_rel,
162 : : RelOptInfo *grouped_rel,
163 : : const AggClauseCosts *agg_costs,
164 : : grouping_sets_data *gd,
165 : : GroupPathExtraData *extra,
166 : : RelOptInfo **partially_grouped_rel_p);
167 : : static void consider_groupingsets_paths(PlannerInfo *root,
168 : : RelOptInfo *grouped_rel,
169 : : Path *path,
170 : : bool is_sorted,
171 : : bool can_hash,
172 : : grouping_sets_data *gd,
173 : : const AggClauseCosts *agg_costs,
174 : : double dNumGroups);
175 : : static RelOptInfo *create_window_paths(PlannerInfo *root,
176 : : RelOptInfo *input_rel,
177 : : PathTarget *input_target,
178 : : PathTarget *output_target,
179 : : bool output_target_parallel_safe,
180 : : WindowFuncLists *wflists,
181 : : List *activeWindows);
182 : : static void create_one_window_path(PlannerInfo *root,
183 : : RelOptInfo *window_rel,
184 : : Path *path,
185 : : PathTarget *input_target,
186 : : PathTarget *output_target,
187 : : WindowFuncLists *wflists,
188 : : List *activeWindows);
189 : : static RelOptInfo *create_distinct_paths(PlannerInfo *root,
190 : : RelOptInfo *input_rel,
191 : : PathTarget *target);
192 : : static void create_partial_distinct_paths(PlannerInfo *root,
193 : : RelOptInfo *input_rel,
194 : : RelOptInfo *final_distinct_rel,
195 : : PathTarget *target);
196 : : static RelOptInfo *create_final_distinct_paths(PlannerInfo *root,
197 : : RelOptInfo *input_rel,
198 : : RelOptInfo *distinct_rel);
199 : : static RelOptInfo *create_ordered_paths(PlannerInfo *root,
200 : : RelOptInfo *input_rel,
201 : : PathTarget *target,
202 : : bool target_parallel_safe,
203 : : double limit_tuples);
204 : : static PathTarget *make_group_input_target(PlannerInfo *root,
205 : : PathTarget *final_target);
206 : : static PathTarget *make_partial_grouping_target(PlannerInfo *root,
207 : : PathTarget *grouping_target,
208 : : Node *havingQual);
209 : : static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
210 : : static void optimize_window_clauses(PlannerInfo *root,
211 : : WindowFuncLists *wflists);
212 : : static List *select_active_windows(PlannerInfo *root, WindowFuncLists *wflists);
213 : : static PathTarget *make_window_input_target(PlannerInfo *root,
214 : : PathTarget *final_target,
215 : : List *activeWindows);
216 : : static List *make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc,
217 : : List *tlist);
218 : : static PathTarget *make_sort_input_target(PlannerInfo *root,
219 : : PathTarget *final_target,
220 : : bool *have_postponed_srfs);
221 : : static void adjust_paths_for_srfs(PlannerInfo *root, RelOptInfo *rel,
222 : : List *targets, List *targets_contain_srfs);
223 : : static void add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
224 : : RelOptInfo *grouped_rel,
225 : : RelOptInfo *partially_grouped_rel,
226 : : const AggClauseCosts *agg_costs,
227 : : grouping_sets_data *gd,
228 : : double dNumGroups,
229 : : GroupPathExtraData *extra);
230 : : static RelOptInfo *create_partial_grouping_paths(PlannerInfo *root,
231 : : RelOptInfo *grouped_rel,
232 : : RelOptInfo *input_rel,
233 : : grouping_sets_data *gd,
234 : : GroupPathExtraData *extra,
235 : : bool force_rel_creation);
236 : : static void gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel);
237 : : static bool can_partial_agg(PlannerInfo *root);
238 : : static void apply_scanjoin_target_to_paths(PlannerInfo *root,
239 : : RelOptInfo *rel,
240 : : List *scanjoin_targets,
241 : : List *scanjoin_targets_contain_srfs,
242 : : bool scanjoin_target_parallel_safe,
243 : : bool tlist_same_exprs);
244 : : static void create_partitionwise_grouping_paths(PlannerInfo *root,
245 : : RelOptInfo *input_rel,
246 : : RelOptInfo *grouped_rel,
247 : : RelOptInfo *partially_grouped_rel,
248 : : const AggClauseCosts *agg_costs,
249 : : grouping_sets_data *gd,
250 : : PartitionwiseAggregateType patype,
251 : : GroupPathExtraData *extra);
252 : : static bool group_by_has_partkey(RelOptInfo *input_rel,
253 : : List *targetList,
254 : : List *groupClause);
255 : : static int common_prefix_cmp(const void *a, const void *b);
256 : : static List *generate_setop_child_grouplist(SetOperationStmt *op,
257 : : List *targetlist);
258 : :
259 : :
260 : : /*****************************************************************************
261 : : *
262 : : * Query optimizer entry point
263 : : *
264 : : * To support loadable plugins that monitor or modify planner behavior,
265 : : * we provide a hook variable that lets a plugin get control before and
266 : : * after the standard planning process. The plugin would normally call
267 : : * standard_planner().
268 : : *
269 : : * Note to plugin authors: standard_planner() scribbles on its Query input,
270 : : * so you'd better copy that data structure if you want to plan more than once.
271 : : *
272 : : *****************************************************************************/
273 : : PlannedStmt *
1476 fujii@postgresql.org 274 :CBC 218728 : planner(Query *parse, const char *query_string, int cursorOptions,
275 : : ParamListInfo boundParams)
276 : : {
277 : : PlannedStmt *result;
278 : :
6169 tgl@sss.pgh.pa.us 279 [ + + ]: 218728 : if (planner_hook)
1476 fujii@postgresql.org 280 : 40484 : result = (*planner_hook) (parse, query_string, cursorOptions, boundParams);
281 : : else
282 : 178244 : result = standard_planner(parse, query_string, cursorOptions, boundParams);
6169 tgl@sss.pgh.pa.us 283 : 216792 : return result;
284 : : }
285 : :
286 : : PlannedStmt *
1476 fujii@postgresql.org 287 : 218728 : standard_planner(Query *parse, const char *query_string, int cursorOptions,
288 : : ParamListInfo boundParams)
289 : : {
290 : : PlannedStmt *result;
291 : : PlannerGlobal *glob;
292 : : double tuple_fraction;
293 : : PlannerInfo *root;
294 : : RelOptInfo *final_rel;
295 : : Path *best_path;
296 : : Plan *top_plan;
297 : : ListCell *lp,
298 : : *lr;
299 : :
300 : : /*
301 : : * Set up global state for this planner invocation. This data is needed
302 : : * across all levels of sub-Query that might exist in the given command,
303 : : * so we keep it in a separate struct that's linked to by each per-Query
304 : : * PlannerInfo.
305 : : */
6264 tgl@sss.pgh.pa.us 306 : 218728 : glob = makeNode(PlannerGlobal);
307 : :
308 : 218728 : glob->boundParams = boundParams;
6261 309 : 218728 : glob->subplans = NIL;
19 tgl@sss.pgh.pa.us 310 :GNC 218728 : glob->subpaths = NIL;
4607 tgl@sss.pgh.pa.us 311 :CBC 218728 : glob->subroots = NIL;
6256 312 : 218728 : glob->rewindPlanIDs = NULL;
6261 313 : 218728 : glob->finalrtable = NIL;
495 alvherre@alvh.no-ip. 314 : 218728 : glob->finalrteperminfos = NIL;
5298 tgl@sss.pgh.pa.us 315 : 218728 : glob->finalrowmarks = NIL;
4797 316 : 218728 : glob->resultRelations = NIL;
1586 317 : 218728 : glob->appendRelations = NIL;
6030 318 : 218728 : glob->relationOids = NIL;
5696 319 : 218728 : glob->invalItems = NIL;
2344 rhaas@postgresql.org 320 : 218728 : glob->paramExecTypes = NIL;
5654 tgl@sss.pgh.pa.us 321 : 218728 : glob->lastPHId = 0;
4813 322 : 218728 : glob->lastRowMarkId = 0;
3121 rhaas@postgresql.org 323 : 218728 : glob->lastPlanNodeId = 0;
6051 tgl@sss.pgh.pa.us 324 : 218728 : glob->transientPlan = false;
2830 325 : 218728 : glob->dependsOnRole = false;
326 : :
327 : : /*
328 : : * Assess whether it's feasible to use parallel mode for this query. We
329 : : * can't do this in a standalone backend, or if the command will try to
330 : : * modify any data, or if this is a cursor operation, or if GUCs are set
331 : : * to values that don't permit parallelism, or if parallel-unsafe
332 : : * functions are present in the query tree.
333 : : *
334 : : * (Note that we do allow CREATE TABLE AS, SELECT INTO, and CREATE
335 : : * MATERIALIZED VIEW to use parallel plans, but this is safe only because
336 : : * the command is writing into a completely new table which workers won't
337 : : * be able to see. If the workers could see the table, the fact that
338 : : * group locking would cause them to ignore the leader's heavyweight GIN
339 : : * page locks would make this unsafe. We'll have to fix that somehow if
340 : : * we want to allow parallel inserts in general; updates and deletes have
341 : : * additional problems especially around combo CIDs.)
342 : : *
343 : : * For now, we don't try to use parallel mode if we're running inside a
344 : : * parallel worker. We might eventually be able to relax this
345 : : * restriction, but for now it seems best not to have parallel workers
346 : : * trying to create their own parallel workers.
347 : : */
2795 348 [ + + + + ]: 218728 : if ((cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 &&
349 : 205949 : IsUnderPostmaster &&
1117 akapila@postgresql.o 350 [ + + ]: 205949 : parse->commandType == CMD_SELECT &&
2795 tgl@sss.pgh.pa.us 351 [ + + ]: 164868 : !parse->hasModifyingCTE &&
352 [ + + ]: 164798 : max_parallel_workers_per_gather > 0 &&
1857 tmunro@postgresql.or 353 [ + + ]: 164564 : !IsParallelWorker())
354 : : {
355 : : /* all the cheap tests pass, so scan the query tree */
1117 akapila@postgresql.o 356 : 164538 : glob->maxParallelHazard = max_parallel_hazard(parse);
2795 tgl@sss.pgh.pa.us 357 : 164538 : glob->parallelModeOK = (glob->maxParallelHazard != PROPARALLEL_UNSAFE);
358 : : }
359 : : else
360 : : {
361 : : /* skip the query tree scan, just assume it's unsafe */
362 : 54190 : glob->maxParallelHazard = PROPARALLEL_UNSAFE;
363 : 54190 : glob->parallelModeOK = false;
364 : : }
365 : :
366 : : /*
367 : : * glob->parallelModeNeeded is normally set to false here and changed to
368 : : * true during plan creation if a Gather or Gather Merge plan is actually
369 : : * created (cf. create_gather_plan, create_gather_merge_plan).
370 : : *
371 : : * However, if debug_parallel_query = on or debug_parallel_query =
372 : : * regress, then we impose parallel mode whenever it's safe to do so, even
373 : : * if the final plan doesn't use parallelism. It's not safe to do so if
374 : : * the query contains anything parallel-unsafe; parallelModeOK will be
375 : : * false in that case. Note that parallelModeOK can't change after this
376 : : * point. Otherwise, everything in the query is either parallel-safe or
377 : : * parallel-restricted, and in either case it should be OK to impose
378 : : * parallel-mode restrictions. If that ends up breaking something, then
379 : : * either some function the user included in the query is incorrectly
380 : : * labeled as parallel-safe or parallel-restricted when in reality it's
381 : : * parallel-unsafe, or else the query planner itself has a bug.
382 : : */
2844 rhaas@postgresql.org 383 [ + + ]: 355726 : glob->parallelModeNeeded = glob->parallelModeOK &&
424 drowley@postgresql.o 384 [ + + ]: 136998 : (debug_parallel_query != DEBUG_PARALLEL_OFF);
385 : :
386 : : /* Determine what fraction of the plan is likely to be scanned */
6208 tgl@sss.pgh.pa.us 387 [ + + ]: 218728 : if (cursorOptions & CURSOR_OPT_FAST_PLAN)
388 : : {
389 : : /*
390 : : * We have no real idea how many tuples the user will ultimately FETCH
391 : : * from a cursor, but it is often the case that he doesn't want 'em
392 : : * all, or would prefer a fast-start plan anyway so that he can
393 : : * process some of the tuples sooner. Use a GUC parameter to decide
394 : : * what fraction to optimize for.
395 : : */
5826 396 : 1369 : tuple_fraction = cursor_tuple_fraction;
397 : :
398 : : /*
399 : : * We document cursor_tuple_fraction as simply being a fraction, which
400 : : * means the edge cases 0 and 1 have to be treated specially here. We
401 : : * convert 1 to 0 ("all the tuples") and 0 to a very small fraction.
402 : : */
403 [ - + ]: 1369 : if (tuple_fraction >= 1.0)
5826 tgl@sss.pgh.pa.us 404 :UBC 0 : tuple_fraction = 0.0;
5826 tgl@sss.pgh.pa.us 405 [ - + ]:CBC 1369 : else if (tuple_fraction <= 0.0)
5826 tgl@sss.pgh.pa.us 406 :UBC 0 : tuple_fraction = 1e-10;
407 : : }
408 : : else
409 : : {
410 : : /* Default assumption is we need all the tuples */
7706 tgl@sss.pgh.pa.us 411 :CBC 217359 : tuple_fraction = 0.0;
412 : : }
413 : :
414 : : /* primary planning entry point (may recurse for subqueries) */
12 drowley@postgresql.o 415 :GNC 218728 : root = subquery_planner(glob, parse, NULL, false, tuple_fraction, NULL);
416 : :
417 : : /* Select best Path and turn it into a Plan */
2960 tgl@sss.pgh.pa.us 418 :CBC 216881 : final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
419 : 216881 : best_path = get_cheapest_fractional_path(final_rel, tuple_fraction);
420 : :
421 : 216881 : top_plan = create_plan(root, best_path);
422 : :
423 : : /*
424 : : * If creating a plan for a scrollable cursor, make sure it can run
425 : : * backwards on demand. Add a Material node at the top at need.
426 : : */
6208 427 [ + + ]: 216792 : if (cursorOptions & CURSOR_OPT_SCROLL)
428 : : {
6263 429 [ + + ]: 132 : if (!ExecSupportsBackwardScan(top_plan))
2628 430 : 15 : top_plan = materialize_finished_plan(top_plan);
431 : : }
432 : :
433 : : /*
434 : : * Optionally add a Gather node for testing purposes, provided this is
435 : : * actually a safe thing to do.
436 : : *
437 : : * We can add Gather even when top_plan has parallel-safe initPlans, but
438 : : * then we have to move the initPlans to the Gather node because of
439 : : * SS_finalize_plan's limitations. That would cause cosmetic breakage of
440 : : * regression tests when debug_parallel_query = regress, because initPlans
441 : : * that would normally appear on the top_plan move to the Gather, causing
442 : : * them to disappear from EXPLAIN output. That doesn't seem worth kluging
443 : : * EXPLAIN to hide, so skip it when debug_parallel_query = regress.
444 : : */
276 tgl@sss.pgh.pa.us 445 [ + + ]:GNC 216792 : if (debug_parallel_query != DEBUG_PARALLEL_OFF &&
446 [ + + ]: 58 : top_plan->parallel_safe &&
447 [ - + ]: 18 : (top_plan->initPlan == NIL ||
276 tgl@sss.pgh.pa.us 448 [ # # ]:UNC 0 : debug_parallel_query != DEBUG_PARALLEL_REGRESS))
449 : : {
2989 rhaas@postgresql.org 450 :CBC 18 : Gather *gather = makeNode(Gather);
451 : : Cost initplan_cost;
452 : : bool unsafe_initplans;
453 : :
454 : 18 : gather->plan.targetlist = top_plan->targetlist;
455 : 18 : gather->plan.qual = NIL;
456 : 18 : gather->plan.lefttree = top_plan;
457 : 18 : gather->plan.righttree = NULL;
458 : 18 : gather->num_workers = 1;
459 : 18 : gather->single_copy = true;
424 drowley@postgresql.o 460 : 18 : gather->invisible = (debug_parallel_query == DEBUG_PARALLEL_REGRESS);
461 : :
462 : : /* Transfer any initPlans to the new top node */
276 tgl@sss.pgh.pa.us 463 :GNC 18 : gather->plan.initPlan = top_plan->initPlan;
464 : 18 : top_plan->initPlan = NIL;
465 : :
466 : : /*
467 : : * Since this Gather has no parallel-aware descendants to signal to,
468 : : * we don't need a rescan Param.
469 : : */
2419 tgl@sss.pgh.pa.us 470 :CBC 18 : gather->rescan_param = -1;
471 : :
472 : : /*
473 : : * Ideally we'd use cost_gather here, but setting up dummy path data
474 : : * to satisfy it doesn't seem much cleaner than knowing what it does.
475 : : */
2842 476 : 18 : gather->plan.startup_cost = top_plan->startup_cost +
477 : : parallel_setup_cost;
478 : 18 : gather->plan.total_cost = top_plan->total_cost +
479 : 18 : parallel_setup_cost + parallel_tuple_cost * top_plan->plan_rows;
480 : 18 : gather->plan.plan_rows = top_plan->plan_rows;
481 : 18 : gather->plan.plan_width = top_plan->plan_width;
482 : 18 : gather->plan.parallel_aware = false;
2559 483 : 18 : gather->plan.parallel_safe = false;
484 : :
485 : : /*
486 : : * Delete the initplans' cost from top_plan. We needn't add it to the
487 : : * Gather node, since the above coding already included it there.
488 : : */
276 tgl@sss.pgh.pa.us 489 :GNC 18 : SS_compute_initplan_cost(gather->plan.initPlan,
490 : : &initplan_cost, &unsafe_initplans);
491 : 18 : top_plan->startup_cost -= initplan_cost;
492 : 18 : top_plan->total_cost -= initplan_cost;
493 : :
494 : : /* use parallel mode for parallel plans. */
2989 rhaas@postgresql.org 495 :CBC 18 : root->glob->parallelModeNeeded = true;
496 : :
497 : 18 : top_plan = &gather->plan;
498 : : }
499 : :
500 : : /*
501 : : * If any Params were generated, run through the plan tree and compute
502 : : * each plan node's extParam/allParam sets. Ideally we'd merge this into
503 : : * set_plan_references' tree traversal, but for now it has to be separate
504 : : * because we need to visit subplans before not after main plan.
505 : : */
2344 506 [ + + ]: 216792 : if (glob->paramExecTypes != NIL)
507 : : {
3169 tgl@sss.pgh.pa.us 508 [ - + ]: 72244 : Assert(list_length(glob->subplans) == list_length(glob->subroots));
509 [ + + + + : 90719 : forboth(lp, glob->subplans, lr, glob->subroots)
+ + + + +
+ + - +
+ ]
510 : : {
511 : 18475 : Plan *subplan = (Plan *) lfirst(lp);
2413 512 : 18475 : PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
513 : :
3169 514 : 18475 : SS_finalize_plan(subroot, subplan);
515 : : }
516 : 72244 : SS_finalize_plan(root, top_plan);
517 : : }
518 : :
519 : : /* final cleanup of the plan */
6261 520 [ - + ]: 216792 : Assert(glob->finalrtable == NIL);
495 alvherre@alvh.no-ip. 521 [ - + ]: 216792 : Assert(glob->finalrteperminfos == NIL);
5298 tgl@sss.pgh.pa.us 522 [ - + ]: 216792 : Assert(glob->finalrowmarks == NIL);
4797 523 [ - + ]: 216792 : Assert(glob->resultRelations == NIL);
1586 524 [ - + ]: 216792 : Assert(glob->appendRelations == NIL);
4607 525 : 216792 : top_plan = set_plan_references(root, top_plan);
526 : : /* ... and the subplans (both regular subplans and initplans) */
527 [ - + ]: 216792 : Assert(list_length(glob->subplans) == list_length(glob->subroots));
528 [ + + + + : 235267 : forboth(lp, glob->subplans, lr, glob->subroots)
+ + + + +
+ + - +
+ ]
529 : : {
5995 bruce@momjian.us 530 : 18475 : Plan *subplan = (Plan *) lfirst(lp);
2413 tgl@sss.pgh.pa.us 531 : 18475 : PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
532 : :
4607 533 : 18475 : lfirst(lp) = set_plan_references(subroot, subplan);
534 : : }
535 : :
536 : : /* build the PlannedStmt result */
6263 537 : 216792 : result = makeNode(PlannedStmt);
538 : :
539 : 216792 : result->commandType = parse->commandType;
4401 540 : 216792 : result->queryId = parse->queryId;
5300 541 : 216792 : result->hasReturning = (parse->returningList != NIL);
4797 542 : 216792 : result->hasModifyingCTE = parse->hasModifyingCTE;
6263 543 : 216792 : result->canSetTag = parse->canSetTag;
6051 544 : 216792 : result->transientPlan = glob->transientPlan;
2830 545 : 216792 : result->dependsOnRole = glob->dependsOnRole;
546 : 216792 : result->parallelModeNeeded = glob->parallelModeNeeded;
6263 547 : 216792 : result->planTree = top_plan;
6261 548 : 216792 : result->rtable = glob->finalrtable;
495 alvherre@alvh.no-ip. 549 : 216792 : result->permInfos = glob->finalrteperminfos;
4797 tgl@sss.pgh.pa.us 550 : 216792 : result->resultRelations = glob->resultRelations;
1586 551 : 216792 : result->appendRelations = glob->appendRelations;
6261 552 : 216792 : result->subplans = glob->subplans;
6256 553 : 216792 : result->rewindPlanIDs = glob->rewindPlanIDs;
5298 554 : 216792 : result->rowMarks = glob->finalrowmarks;
6030 555 : 216792 : result->relationOids = glob->relationOids;
5696 556 : 216792 : result->invalItems = glob->invalItems;
2344 rhaas@postgresql.org 557 : 216792 : result->paramExecTypes = glob->paramExecTypes;
558 : : /* utilityStmt should be null, but we might as well copy it */
2647 tgl@sss.pgh.pa.us 559 : 216792 : result->utilityStmt = parse->utilityStmt;
560 : 216792 : result->stmt_location = parse->stmt_location;
561 : 216792 : result->stmt_len = parse->stmt_len;
562 : :
2215 andres@anarazel.de 563 : 216792 : result->jitFlags = PGJIT_NONE;
564 [ + + + - ]: 216792 : if (jit_enabled && jit_above_cost >= 0 &&
565 [ + + ]: 216589 : top_plan->total_cost > jit_above_cost)
566 : : {
567 : 694 : result->jitFlags |= PGJIT_PERFORM;
568 : :
569 : : /*
570 : : * Decide how much effort should be put into generating better code.
571 : : */
572 [ + - ]: 694 : if (jit_optimize_above_cost >= 0 &&
573 [ + + ]: 694 : top_plan->total_cost > jit_optimize_above_cost)
574 : 506 : result->jitFlags |= PGJIT_OPT3;
2209 575 [ + - ]: 694 : if (jit_inline_above_cost >= 0 &&
576 [ + + ]: 694 : top_plan->total_cost > jit_inline_above_cost)
577 : 506 : result->jitFlags |= PGJIT_INLINE;
578 : :
579 : : /*
580 : : * Decide which operations should be JITed.
581 : : */
2217 582 [ + - ]: 694 : if (jit_expressions)
583 : 694 : result->jitFlags |= PGJIT_EXPR;
2211 584 [ + - ]: 694 : if (jit_tuple_deforming)
585 : 694 : result->jitFlags |= PGJIT_DEFORM;
586 : : }
587 : :
1865 rhaas@postgresql.org 588 [ + + ]: 216792 : if (glob->partition_directory != NULL)
589 : 5578 : DestroyPartitionDirectory(glob->partition_directory);
590 : :
6263 tgl@sss.pgh.pa.us 591 : 216792 : return result;
592 : : }
593 : :
594 : :
595 : : /*--------------------
596 : : * subquery_planner
597 : : * Invokes the planner on a subquery. We recurse to here for each
598 : : * sub-SELECT found in the query tree.
599 : : *
600 : : * glob is the global state for the current planner run.
601 : : * parse is the querytree produced by the parser & rewriter.
602 : : * parent_root is the immediate parent Query's info (NULL at the top level).
603 : : * hasRecursion is true if this is a recursive WITH query.
604 : : * tuple_fraction is the fraction of tuples we expect will be retrieved.
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.
610 : : *
611 : : * Basically, this routine does the stuff that should only be done once
612 : : * per Query object. It then calls grouping_planner. At one time,
613 : : * grouping_planner could be invoked recursively on the same Query object;
614 : : * that's not currently true, but we keep the separation between the two
615 : : * routines anyway, in case we need it again someday.
616 : : *
617 : : * subquery_planner will be called recursively to handle sub-Query nodes
618 : : * found within the query's expressions and rangetable.
619 : : *
620 : : * Returns the PlannerInfo struct ("root") that contains all data generated
621 : : * while planning the subquery. In particular, the Path(s) attached to
622 : : * the (UPPERREL_FINAL, NULL) upperrel represent our conclusions about the
623 : : * cheapest way(s) to implement the query. The top level will select the
624 : : * best Path and pass it through createplan.c to produce a finished Plan.
625 : : *--------------------
626 : : */
627 : : PlannerInfo *
12 drowley@postgresql.o 628 :GNC 247671 : subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root,
629 : : bool hasRecursion, double tuple_fraction,
630 : : SetOperationStmt *setops)
631 : : {
632 : : PlannerInfo *root;
633 : : List *newWithCheckOptions;
634 : : List *newHaving;
635 : : bool hasOuterJoins;
636 : : bool hasResultRTEs;
637 : : RelOptInfo *final_rel;
638 : : ListCell *l;
639 : :
640 : : /* Create a PlannerInfo data structure for this subquery */
6888 tgl@sss.pgh.pa.us 641 :CBC 247671 : root = makeNode(PlannerInfo);
642 : 247671 : root->parse = parse;
6264 643 : 247671 : root->glob = glob;
5671 644 [ + + ]: 247671 : root->query_level = parent_root ? parent_root->query_level + 1 : 1;
645 : 247671 : root->parent_root = parent_root;
4239 646 : 247671 : root->plan_params = NIL;
3169 647 : 247671 : root->outer_params = NULL;
6294 648 : 247671 : root->planner_cxt = CurrentMemoryContext;
6264 649 : 247671 : root->init_plans = NIL;
5671 650 : 247671 : root->cte_plan_ids = NIL;
3588 651 : 247671 : root->multiexpr_params = NIL;
440 652 : 247671 : root->join_domains = NIL;
6294 653 : 247671 : root->eq_classes = NIL;
1729 drowley@postgresql.o 654 : 247671 : root->ec_merging_done = false;
440 tgl@sss.pgh.pa.us 655 : 247671 : root->last_rinfo_serial = 0;
1110 656 : 247671 : root->all_result_relids =
657 [ + + ]: 247671 : parse->resultRelation ? bms_make_singleton(parse->resultRelation) : NULL;
658 : 247671 : root->leaf_result_relids = NULL; /* we'll find out leaf-ness later */
6648 659 : 247671 : root->append_rel_list = NIL;
1110 660 : 247671 : root->row_identity_vars = NIL;
5284 661 : 247671 : root->rowMarks = NIL;
2960 662 : 247671 : memset(root->upper_rels, 0, sizeof(root->upper_rels));
2953 663 : 247671 : memset(root->upper_targets, 0, sizeof(root->upper_targets));
452 664 : 247671 : root->processed_groupClause = NIL;
665 : 247671 : root->processed_distinctClause = NIL;
2960 666 : 247671 : root->processed_tlist = NIL;
1110 667 : 247671 : root->update_colnos = NIL;
3256 andres@anarazel.de 668 : 247671 : root->grouping_map = NULL;
2960 tgl@sss.pgh.pa.us 669 : 247671 : root->minmax_aggs = NIL;
2643 670 : 247671 : root->qual_security_level = 0;
1295 671 : 247671 : root->hasPseudoConstantQuals = false;
672 : 247671 : root->hasAlternativeSubPlans = false;
606 673 : 247671 : root->placeholdersFrozen = false;
5671 674 : 247671 : root->hasRecursion = hasRecursion;
675 [ + + ]: 247671 : if (hasRecursion)
1920 676 : 406 : root->wt_param_id = assign_special_exec_param(root);
677 : : else
5671 678 : 247265 : root->wt_param_id = -1;
2960 679 : 247671 : root->non_recursive_path = NULL;
2200 alvherre@alvh.no-ip. 680 : 247671 : root->partColsUpdated = false;
681 : :
682 : : /*
683 : : * Create the top-level join domain. This won't have valid contents until
684 : : * deconstruct_jointree fills it in, but the node needs to exist before
685 : : * that so we can build EquivalenceClasses referencing it.
686 : : */
440 tgl@sss.pgh.pa.us 687 : 247671 : root->join_domains = list_make1(makeNode(JoinDomain));
688 : :
689 : : /*
690 : : * If there is a WITH list, process each WITH query and either convert it
691 : : * to RTE_SUBQUERY RTE(s) or build an initplan SubPlan structure for it.
692 : : */
5671 693 [ + + ]: 247671 : if (parse->cteList)
694 : 1205 : SS_process_ctes(root);
695 : :
696 : : /*
697 : : * If it's a MERGE command, transform the joinlist as appropriate.
698 : : */
748 alvherre@alvh.no-ip. 699 : 247668 : transform_MERGE_to_join(parse);
700 : :
701 : : /*
702 : : * If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so
703 : : * that we don't need so many special cases to deal with that situation.
704 : : */
1903 tgl@sss.pgh.pa.us 705 : 247668 : replace_empty_jointree(parse);
706 : :
707 : : /*
708 : : * Look for ANY and EXISTS SubLinks in WHERE and JOIN/ON clauses, and try
709 : : * to transform them into joins. Note that this step does not descend
710 : : * into subqueries; if we pull up any subqueries below, their SubLinks are
711 : : * processed just before pulling them up.
712 : : */
7755 713 [ + + ]: 247668 : if (parse->hasSubLinks)
5719 714 : 14486 : pull_up_sublinks(root);
715 : :
716 : : /*
717 : : * Scan the rangetable for function RTEs, do const-simplification on them,
718 : : * and then inline them if possible (producing subqueries that might get
719 : : * pulled up next). Recursion issues here are handled in the same way as
720 : : * for SubLinks.
721 : : */
1718 722 : 247668 : preprocess_function_rtes(root);
723 : :
724 : : /*
725 : : * Check to see if any subqueries in the jointree can be merged into this
726 : : * query.
727 : : */
3322 728 : 247665 : pull_up_subqueries(root);
729 : :
730 : : /*
731 : : * If this is a simple UNION ALL query, flatten it into an appendrel. We
732 : : * do this now because it requires applying pull_up_subqueries to the leaf
733 : : * queries of the UNION ALL, which weren't touched above because they
734 : : * weren't referenced by the jointree (they will be after we do this).
735 : : */
4906 736 [ + + ]: 247662 : if (parse->setOperations)
737 : 2752 : flatten_simple_union_all(root);
738 : :
739 : : /*
740 : : * Survey the rangetable to see what kinds of entries are present. We can
741 : : * skip some later processing if relevant SQL features are not used; for
742 : : * example if there are no JOIN RTEs we can avoid the expense of doing
743 : : * flatten_join_alias_vars(). This must be done after we have finished
744 : : * adding rangetable entries, of course. (Note: actually, processing of
745 : : * inherited or partitioned rels can cause RTEs for their child tables to
746 : : * get added later; but those must all be RTE_RELATION entries, so they
747 : : * don't invalidate the conclusions drawn here.)
748 : : */
6888 749 : 247662 : root->hasJoinRTEs = false;
4249 750 : 247662 : root->hasLateralRTEs = false;
5722 751 : 247662 : hasOuterJoins = false;
1903 752 : 247662 : hasResultRTEs = false;
7263 neilc@samurai.com 753 [ + - + + : 655214 : foreach(l, parse->rtable)
+ + ]
754 : : {
2413 tgl@sss.pgh.pa.us 755 : 407552 : RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
756 : :
1842 757 [ + + + + ]: 407552 : switch (rte->rtekind)
758 : : {
759 : 207661 : case RTE_RELATION:
760 [ + + ]: 207661 : if (rte->inh)
761 : : {
762 : : /*
763 : : * Check to see if the relation actually has any children;
764 : : * if not, clear the inh flag so we can treat it as a
765 : : * plain base relation.
766 : : *
767 : : * Note: this could give a false-positive result, if the
768 : : * rel once had children but no longer does. We used to
769 : : * be able to clear rte->inh later on when we discovered
770 : : * that, but no more; we have to handle such cases as
771 : : * full-fledged inheritance.
772 : : */
773 : 166834 : rte->inh = has_subclass(rte->relid);
774 : : }
775 : 207661 : break;
776 : 38056 : case RTE_JOIN:
777 : 38056 : root->hasJoinRTEs = true;
778 [ + + ]: 38056 : if (IS_OUTER_JOIN(rte->jointype))
779 : 22457 : hasOuterJoins = true;
780 : 38056 : break;
781 : 107325 : case RTE_RESULT:
782 : 107325 : hasResultRTEs = true;
783 : 107325 : break;
784 : 54510 : default:
785 : : /* No work here for other RTE types */
786 : 54510 : break;
787 : : }
788 : :
4249 789 [ + + ]: 407552 : if (rte->lateral)
790 : 4763 : root->hasLateralRTEs = true;
791 : :
792 : : /*
793 : : * We can also determine the maximum security level required for any
794 : : * securityQuals now. Addition of inheritance-child RTEs won't affect
795 : : * this, because child tables don't have their own securityQuals; see
796 : : * expand_single_inheritance_child().
797 : : */
1841 798 [ + + ]: 407552 : if (rte->securityQuals)
799 [ - + ]: 1182 : root->qual_security_level = Max(root->qual_security_level,
800 : : list_length(rte->securityQuals));
801 : : }
802 : :
803 : : /*
804 : : * If we have now verified that the query target relation is
805 : : * non-inheriting, mark it as a leaf target.
806 : : */
1110 807 [ + + ]: 247662 : if (parse->resultRelation)
808 : : {
809 : 43864 : RangeTblEntry *rte = rt_fetch(parse->resultRelation, parse->rtable);
810 : :
811 [ + + ]: 43864 : if (!rte->inh)
812 : 42592 : root->leaf_result_relids =
813 : 42592 : bms_make_singleton(parse->resultRelation);
814 : : }
815 : :
816 : : /*
817 : : * Preprocess RowMark information. We need to do this after subquery
818 : : * pullup, so that all base relations are present.
819 : : */
5284 820 : 247662 : preprocess_rowmarks(root);
821 : :
822 : : /*
823 : : * Set hasHavingQual to remember if HAVING clause is present. Needed
824 : : * because preprocess_expression will reduce a constant-true condition to
825 : : * an empty qual list ... but "HAVING TRUE" is not a semantic no-op.
826 : : */
6888 827 : 247662 : root->hasHavingQual = (parse->havingQual != NULL);
828 : :
829 : : /*
830 : : * Do expression preprocessing on targetlist and quals, as well as other
831 : : * random expressions in the querytree. Note that we do not need to
832 : : * handle sort/group expressions explicitly, because they are actually
833 : : * part of the targetlist.
834 : : */
8790 835 : 245853 : parse->targetList = (List *)
6888 836 : 247662 : preprocess_expression(root, (Node *) parse->targetList,
837 : : EXPRKIND_TARGET);
838 : :
839 : : /* Constant-folding might have removed all set-returning functions */
2770 840 [ + + ]: 245853 : if (parse->hasTargetSRFs)
841 : 4202 : parse->hasTargetSRFs = expression_returns_set((Node *) parse->targetList);
842 : :
3923 sfrost@snowman.net 843 : 245853 : newWithCheckOptions = NIL;
844 [ + + + + : 247013 : foreach(l, parse->withCheckOptions)
+ + ]
845 : : {
2413 tgl@sss.pgh.pa.us 846 : 1160 : WithCheckOption *wco = lfirst_node(WithCheckOption, l);
847 : :
3923 sfrost@snowman.net 848 : 1160 : wco->qual = preprocess_expression(root, wco->qual,
849 : : EXPRKIND_QUAL);
850 [ + + ]: 1160 : if (wco->qual != NULL)
851 : 960 : newWithCheckOptions = lappend(newWithCheckOptions, wco);
852 : : }
853 : 245853 : parse->withCheckOptions = newWithCheckOptions;
854 : :
6455 tgl@sss.pgh.pa.us 855 : 245853 : parse->returningList = (List *)
856 : 245853 : preprocess_expression(root, (Node *) parse->returningList,
857 : : EXPRKIND_TARGET);
858 : :
6888 859 : 245853 : preprocess_qual_conditions(root, (Node *) parse->jointree);
860 : :
861 : 245853 : parse->havingQual = preprocess_expression(root, parse->havingQual,
862 : : EXPRKIND_QUAL);
863 : :
5175 864 [ + + + + : 247111 : foreach(l, parse->windowClause)
+ + ]
865 : : {
2413 866 : 1258 : WindowClause *wc = lfirst_node(WindowClause, l);
867 : :
868 : : /* partitionClause/orderClause are sort/group expressions */
5175 869 : 1258 : wc->startOffset = preprocess_expression(root, wc->startOffset,
870 : : EXPRKIND_LIMIT);
871 : 1258 : wc->endOffset = preprocess_expression(root, wc->endOffset,
872 : : EXPRKIND_LIMIT);
491 drowley@postgresql.o 873 : 1258 : wc->runCondition = (List *) preprocess_expression(root,
874 : 1258 : (Node *) wc->runCondition,
875 : : EXPRKIND_TARGET);
876 : : }
877 : :
6888 tgl@sss.pgh.pa.us 878 : 245853 : parse->limitOffset = preprocess_expression(root, parse->limitOffset,
879 : : EXPRKIND_LIMIT);
880 : 245853 : parse->limitCount = preprocess_expression(root, parse->limitCount,
881 : : EXPRKIND_LIMIT);
882 : :
3264 andres@anarazel.de 883 [ + + ]: 245853 : if (parse->onConflict)
884 : : {
2895 tgl@sss.pgh.pa.us 885 : 1430 : parse->onConflict->arbiterElems = (List *)
886 : 715 : preprocess_expression(root,
887 : 715 : (Node *) parse->onConflict->arbiterElems,
888 : : EXPRKIND_ARBITER_ELEM);
889 : 1430 : parse->onConflict->arbiterWhere =
890 : 715 : preprocess_expression(root,
891 : 715 : parse->onConflict->arbiterWhere,
892 : : EXPRKIND_QUAL);
3264 andres@anarazel.de 893 : 1430 : parse->onConflict->onConflictSet = (List *)
2895 tgl@sss.pgh.pa.us 894 : 715 : preprocess_expression(root,
895 : 715 : (Node *) parse->onConflict->onConflictSet,
896 : : EXPRKIND_TARGET);
3264 andres@anarazel.de 897 : 715 : parse->onConflict->onConflictWhere =
2895 tgl@sss.pgh.pa.us 898 : 715 : preprocess_expression(root,
899 : 715 : parse->onConflict->onConflictWhere,
900 : : EXPRKIND_QUAL);
901 : : /* exclRelTlist contains only Vars, so no preprocessing needed */
902 : : }
903 : :
748 alvherre@alvh.no-ip. 904 [ + + + + : 247156 : foreach(l, parse->mergeActionList)
+ + ]
905 : : {
906 : 1303 : MergeAction *action = (MergeAction *) lfirst(l);
907 : :
908 : 1303 : action->targetList = (List *)
909 : 1303 : preprocess_expression(root,
910 : 1303 : (Node *) action->targetList,
911 : : EXPRKIND_TARGET);
912 : 1303 : action->qual =
913 : 1303 : preprocess_expression(root,
914 : : (Node *) action->qual,
915 : : EXPRKIND_QUAL);
916 : : }
917 : :
15 dean.a.rasheed@gmail 918 :GNC 245853 : parse->mergeJoinCondition =
919 : 245853 : preprocess_expression(root, parse->mergeJoinCondition, EXPRKIND_QUAL);
920 : :
6648 tgl@sss.pgh.pa.us 921 :CBC 245853 : root->append_rel_list = (List *)
922 : 245853 : preprocess_expression(root, (Node *) root->append_rel_list,
923 : : EXPRKIND_APPINFO);
924 : :
925 : : /* Also need to preprocess expressions within RTEs */
7263 neilc@samurai.com 926 [ + - + + : 651463 : foreach(l, parse->rtable)
+ + ]
927 : : {
2413 tgl@sss.pgh.pa.us 928 : 405610 : RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
929 : : int kind;
930 : : ListCell *lcsq;
931 : :
3257 simon@2ndQuadrant.co 932 [ + + ]: 405610 : if (rte->rtekind == RTE_RELATION)
933 : : {
934 [ + + ]: 207534 : if (rte->tablesample)
3186 tgl@sss.pgh.pa.us 935 : 111 : rte->tablesample = (TableSampleClause *)
936 : 111 : preprocess_expression(root,
937 : 111 : (Node *) rte->tablesample,
938 : : EXPRKIND_TABLESAMPLE);
939 : : }
3257 simon@2ndQuadrant.co 940 [ + + ]: 198076 : else if (rte->rtekind == RTE_SUBQUERY)
941 : : {
942 : : /*
943 : : * We don't want to do all preprocessing yet on the subquery's
944 : : * expressions, since that will happen when we plan it. But if it
945 : : * contains any join aliases of our level, those have to get
946 : : * expanded now, because planning of the subquery won't do it.
947 : : * That's only possible if the subquery is LATERAL.
948 : : */
4244 tgl@sss.pgh.pa.us 949 [ + + + + ]: 26623 : if (rte->lateral && root->hasJoinRTEs)
950 : 427 : rte->subquery = (Query *)
440 951 : 427 : flatten_join_alias_vars(root, root->parse,
1902 952 : 427 : (Node *) rte->subquery);
953 : : }
4244 954 [ + + ]: 171453 : else if (rte->rtekind == RTE_FUNCTION)
955 : : {
956 : : /* Preprocess the function expression(s) fully */
957 [ + + ]: 21525 : kind = rte->lateral ? EXPRKIND_RTFUNC_LATERAL : EXPRKIND_RTFUNC;
2594 alvherre@alvh.no-ip. 958 : 21525 : rte->functions = (List *)
959 : 21525 : preprocess_expression(root, (Node *) rte->functions, kind);
960 : : }
961 [ + + ]: 149928 : else if (rte->rtekind == RTE_TABLEFUNC)
962 : : {
963 : : /* Preprocess the function expression(s) fully */
964 [ + + ]: 254 : kind = rte->lateral ? EXPRKIND_TABLEFUNC_LATERAL : EXPRKIND_TABLEFUNC;
965 : 254 : rte->tablefunc = (TableFunc *)
966 : 254 : preprocess_expression(root, (Node *) rte->tablefunc, kind);
967 : : }
6465 mail@joeconway.com 968 [ + + ]: 149674 : else if (rte->rtekind == RTE_VALUES)
969 : : {
970 : : /* Preprocess the values lists fully */
4244 tgl@sss.pgh.pa.us 971 [ + + ]: 3864 : kind = rte->lateral ? EXPRKIND_VALUES_LATERAL : EXPRKIND_VALUES;
6465 mail@joeconway.com 972 : 3864 : rte->values_lists = (List *)
4244 tgl@sss.pgh.pa.us 973 : 3864 : preprocess_expression(root, (Node *) rte->values_lists, kind);
974 : : }
975 : :
976 : : /*
977 : : * Process each element of the securityQuals list as if it were a
978 : : * separate qual expression (as indeed it is). We need to do it this
979 : : * way to get proper canonicalization of AND/OR structure. Note that
980 : : * this converts each element into an implicit-AND sublist.
981 : : */
2643 982 [ + + + + : 406965 : foreach(lcsq, rte->securityQuals)
+ + ]
983 : : {
984 : 1355 : lfirst(lcsq) = preprocess_expression(root,
985 : 1355 : (Node *) lfirst(lcsq),
986 : : EXPRKIND_QUAL);
987 : : }
988 : : }
989 : :
990 : : /*
991 : : * Now that we are done preprocessing expressions, and in particular done
992 : : * flattening join alias variables, get rid of the joinaliasvars lists.
993 : : * They no longer match what expressions in the rest of the tree look
994 : : * like, because we have not preprocessed expressions in those lists (and
995 : : * do not want to; for example, expanding a SubLink there would result in
996 : : * a useless unreferenced subplan). Leaving them in place simply creates
997 : : * a hazard for later scans of the tree. We could try to prevent that by
998 : : * using QTW_IGNORE_JOINALIASES in every tree scan done after this point,
999 : : * but that doesn't sound very reliable.
1000 : : */
2364 1001 [ + + ]: 245853 : if (root->hasJoinRTEs)
1002 : : {
1003 [ + - + + : 130420 : foreach(l, parse->rtable)
+ + ]
1004 : : {
1005 : 107661 : RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
1006 : :
1007 : 107661 : rte->joinaliasvars = NIL;
1008 : : }
1009 : : }
1010 : :
1011 : : /*
1012 : : * In some cases we may want to transfer a HAVING clause into WHERE. We
1013 : : * cannot do so if the HAVING clause contains aggregates (obviously) or
1014 : : * volatile functions (since a HAVING clause is supposed to be executed
1015 : : * only once per group). We also can't do this if there are any nonempty
1016 : : * grouping sets; moving such a clause into WHERE would potentially change
1017 : : * the results, if any referenced column isn't present in all the grouping
1018 : : * sets. (If there are only empty grouping sets, then the HAVING clause
1019 : : * must be degenerate as discussed below.)
1020 : : *
1021 : : * Also, it may be that the clause is so expensive to execute that we're
1022 : : * better off doing it only once per group, despite the loss of
1023 : : * selectivity. This is hard to estimate short of doing the entire
1024 : : * planning process twice, so we use a heuristic: clauses containing
1025 : : * subplans are left in HAVING. Otherwise, we move or copy the HAVING
1026 : : * clause into WHERE, in hopes of eliminating tuples before aggregation
1027 : : * instead of after.
1028 : : *
1029 : : * If the query has explicit grouping then we can simply move such a
1030 : : * clause into WHERE; any group that fails the clause will not be in the
1031 : : * output because none of its tuples will reach the grouping or
1032 : : * aggregation stage. Otherwise we must have a degenerate (variable-free)
1033 : : * HAVING clause, which we put in WHERE so that query_planner() can use it
1034 : : * in a gating Result node, but also keep in HAVING to ensure that we
1035 : : * don't emit a bogus aggregated row. (This could be done better, but it
1036 : : * seems not worth optimizing.)
1037 : : *
1038 : : * Note that both havingQual and parse->jointree->quals are in
1039 : : * implicitly-ANDed-list form at this point, even though they are declared
1040 : : * as Node *.
1041 : : */
8487 1042 : 245853 : newHaving = NIL;
7263 neilc@samurai.com 1043 [ + + + + : 246423 : foreach(l, (List *) parse->havingQual)
+ + ]
1044 : : {
1045 : 570 : Node *havingclause = (Node *) lfirst(l);
1046 : :
2988 andres@anarazel.de 1047 [ + + + + : 1119 : if ((parse->groupClause && parse->groupingSets) ||
+ + ]
1048 [ + - ]: 620 : contain_agg_clause(havingclause) ||
6975 tgl@sss.pgh.pa.us 1049 [ - + ]: 142 : contain_volatile_functions(havingclause) ||
3185 andres@anarazel.de 1050 : 71 : contain_subplans(havingclause))
1051 : : {
1052 : : /* keep it in HAVING */
8487 tgl@sss.pgh.pa.us 1053 : 499 : newHaving = lappend(newHaving, havingclause);
1054 : : }
3185 andres@anarazel.de 1055 [ + + + - ]: 71 : else if (parse->groupClause && !parse->groupingSets)
1056 : : {
1057 : : /* move it to WHERE */
8487 tgl@sss.pgh.pa.us 1058 : 62 : parse->jointree->quals = (Node *)
1059 : 62 : lappend((List *) parse->jointree->quals, havingclause);
1060 : : }
1061 : : else
1062 : : {
1063 : : /* put a copy in WHERE, keep it in HAVING */
6975 1064 : 18 : parse->jointree->quals = (Node *)
1065 : 9 : lappend((List *) parse->jointree->quals,
1066 : : copyObject(havingclause));
1067 : 9 : newHaving = lappend(newHaving, havingclause);
1068 : : }
1069 : : }
8487 1070 : 245853 : parse->havingQual = (Node *) newHaving;
1071 : :
1072 : : /*
1073 : : * If we have any outer joins, try to reduce them to plain inner joins.
1074 : : * This step is most easily done after we've done expression
1075 : : * preprocessing.
1076 : : */
5722 1077 [ + + ]: 245853 : if (hasOuterJoins)
6888 1078 : 14860 : reduce_outer_joins(root);
1079 : :
1080 : : /*
1081 : : * If we have any RTE_RESULT relations, see if they can be deleted from
1082 : : * the jointree. We also rely on this processing to flatten single-child
1083 : : * FromExprs underneath outer joins. This step is most effectively done
1084 : : * after we've done expression preprocessing and outer join reduction.
1085 : : */
440 1086 [ + + + + ]: 245853 : if (hasResultRTEs || hasOuterJoins)
1903 1087 : 119867 : remove_useless_result_rtes(root);
1088 : :
1089 : : /*
1090 : : * Do the main planning.
1091 : : */
12 drowley@postgresql.o 1092 :GNC 245853 : grouping_planner(root, tuple_fraction, setops);
1093 : :
1094 : : /*
1095 : : * Capture the set of outer-level param IDs we have access to, for use in
1096 : : * extParam/allParam calculations later.
1097 : : */
3169 tgl@sss.pgh.pa.us 1098 :CBC 245821 : SS_identify_outer_params(root);
1099 : :
1100 : : /*
1101 : : * If any initPlans were created in this query level, adjust the surviving
1102 : : * Paths' costs and parallel-safety flags to account for them. The
1103 : : * initPlans won't actually get attached to the plan tree till
1104 : : * create_plan() runs, but we must include their effects now.
1105 : : */
2960 1106 : 245821 : final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
1107 : 245821 : SS_charge_for_initplans(root, final_rel);
1108 : :
1109 : : /*
1110 : : * Make sure we've identified the cheapest Path for the final rel. (By
1111 : : * doing this here not in grouping_planner, we include initPlan costs in
1112 : : * the decision, though it's unlikely that will change anything.)
1113 : : */
1114 : 245821 : set_cheapest(final_rel);
1115 : :
1116 : 245821 : return root;
1117 : : }
1118 : :
1119 : : /*
1120 : : * preprocess_expression
1121 : : * Do subquery_planner's preprocessing work for an expression,
1122 : : * which can be a targetlist, a WHERE clause (including JOIN/ON
1123 : : * conditions), a HAVING clause, or a few other things.
1124 : : */
1125 : : static Node *
6888 1126 : 2052452 : preprocess_expression(PlannerInfo *root, Node *expr, int kind)
1127 : : {
1128 : : /*
1129 : : * Fall out quickly if expression is empty. This occurs often enough to
1130 : : * be worth checking. Note that null->null is the correct conversion for
1131 : : * implicit-AND result format, too.
1132 : : */
6894 1133 [ + + ]: 2052452 : if (expr == NULL)
1134 : 1640294 : return NULL;
1135 : :
1136 : : /*
1137 : : * If the query has any join RTEs, replace join alias variables with
1138 : : * base-relation variables. We must do this first, since any expressions
1139 : : * we may extract from the joinaliasvars lists have not been preprocessed.
1140 : : * For example, if we did this after sublink processing, sublinks expanded
1141 : : * out from join aliases would not get processed. But we can skip this in
1142 : : * non-lateral RTE functions, VALUES lists, and TABLESAMPLE clauses, since
1143 : : * they can't contain any Vars of the current query level.
1144 : : */
4244 1145 [ + + + + ]: 412158 : if (root->hasJoinRTEs &&
3186 1146 [ + + + - ]: 164629 : !(kind == EXPRKIND_RTFUNC ||
1147 [ + + ]: 82216 : kind == EXPRKIND_VALUES ||
1148 : : kind == EXPRKIND_TABLESAMPLE ||
1149 : : kind == EXPRKIND_TABLEFUNC))
440 1150 : 82210 : expr = flatten_join_alias_vars(root, root->parse, expr);
1151 : :
1152 : : /*
1153 : : * Simplify constant expressions. For function RTEs, this was already
1154 : : * done by preprocess_function_rtes. (But note we must do it again for
1155 : : * EXPRKIND_RTFUNC_LATERAL, because those might by now contain
1156 : : * un-simplified subexpressions inserted by flattening of subqueries or
1157 : : * join alias variables.)
1158 : : *
1159 : : * Note: an essential effect of this is to convert named-argument function
1160 : : * calls to positional notation and insert the current actual values of
1161 : : * any default arguments for functions. To ensure that happens, we *must*
1162 : : * process all expressions here. Previous PG versions sometimes skipped
1163 : : * const-simplification if it didn't seem worth the trouble, but we can't
1164 : : * do that anymore.
1165 : : *
1166 : : * Note: this also flattens nested AND and OR expressions into N-argument
1167 : : * form. All processing of a qual expression after this point must be
1168 : : * careful to maintain AND/OR flatness --- that is, do not generate a tree
1169 : : * with AND directly under AND, nor OR directly under OR.
1170 : : */
913 1171 [ + + ]: 412158 : if (kind != EXPRKIND_RTFUNC)
1718 1172 : 394537 : expr = eval_const_expressions(root, expr);
1173 : :
1174 : : /*
1175 : : * If it's a qual or havingQual, canonicalize it.
1176 : : */
7755 1177 [ + + ]: 410349 : if (kind == EXPRKIND_QUAL)
1178 : : {
2226 1179 : 140137 : expr = (Node *) canonicalize_qual((Expr *) expr, false);
1180 : :
1181 : : #ifdef OPTIMIZER_DEBUG
1182 : : printf("After canonicalize_qual()\n");
1183 : : pprint(expr);
1184 : : #endif
1185 : : }
1186 : :
1187 : : /*
1188 : : * Check for ANY ScalarArrayOpExpr with Const arrays and set the
1189 : : * hashfuncid of any that might execute more quickly by using hash lookups
1190 : : * instead of a linear search.
1191 : : */
1102 drowley@postgresql.o 1192 [ + + + + ]: 410349 : if (kind == EXPRKIND_QUAL || kind == EXPRKIND_TARGET)
1193 : : {
1194 : 379729 : convert_saop_to_hashed_saop(expr);
1195 : : }
1196 : :
1197 : : /* Expand SubLinks to SubPlans */
6888 tgl@sss.pgh.pa.us 1198 [ + + ]: 410349 : if (root->parse->hasSubLinks)
6264 1199 : 39097 : expr = SS_process_sublinks(root, expr, (kind == EXPRKIND_QUAL));
1200 : :
1201 : : /*
1202 : : * XXX do not insert anything here unless you have grokked the comments in
1203 : : * SS_replace_correlation_vars ...
1204 : : */
1205 : :
1206 : : /* Replace uplevel vars with Param nodes (this IS possible in VALUES) */
1207 [ + + ]: 410349 : if (root->query_level > 1)
1208 : 64898 : expr = SS_replace_correlation_vars(root, expr);
1209 : :
1210 : : /*
1211 : : * If it's a qual or havingQual, convert it to implicit-AND format. (We
1212 : : * don't want to do this before eval_const_expressions, since the latter
1213 : : * would be unable to simplify a top-level AND correctly. Also,
1214 : : * SS_process_sublinks expects explicit-AND format.)
1215 : : */
7398 1216 [ + + ]: 410349 : if (kind == EXPRKIND_QUAL)
1217 : 140137 : expr = (Node *) make_ands_implicit((Expr *) expr);
1218 : :
8598 1219 : 410349 : return expr;
1220 : : }
1221 : :
1222 : : /*
1223 : : * preprocess_qual_conditions
1224 : : * Recursively scan the query's jointree and do subquery_planner's
1225 : : * preprocessing work on each qual condition found therein.
1226 : : */
1227 : : static void
6888 1228 : 597500 : preprocess_qual_conditions(PlannerInfo *root, Node *jtnode)
1229 : : {
8598 1230 [ - + ]: 597500 : if (jtnode == NULL)
8598 tgl@sss.pgh.pa.us 1231 :UBC 0 : return;
8598 tgl@sss.pgh.pa.us 1232 [ + + ]:CBC 597500 : if (IsA(jtnode, RangeTblRef))
1233 : : {
1234 : : /* nothing to do here */
1235 : : }
1236 [ + + ]: 292127 : else if (IsA(jtnode, FromExpr))
1237 : : {
1238 : 251858 : FromExpr *f = (FromExpr *) jtnode;
1239 : : ListCell *l;
1240 : :
1241 [ + + + + : 522967 : foreach(l, f->fromlist)
+ + ]
6888 1242 : 271109 : preprocess_qual_conditions(root, lfirst(l));
1243 : :
1244 : 251858 : f->quals = preprocess_expression(root, f->quals, EXPRKIND_QUAL);
1245 : : }
8598 1246 [ + - ]: 40269 : else if (IsA(jtnode, JoinExpr))
1247 : : {
1248 : 40269 : JoinExpr *j = (JoinExpr *) jtnode;
1249 : :
6888 1250 : 40269 : preprocess_qual_conditions(root, j->larg);
1251 : 40269 : preprocess_qual_conditions(root, j->rarg);
1252 : :
1253 : 40269 : j->quals = preprocess_expression(root, j->quals, EXPRKIND_QUAL);
1254 : : }
1255 : : else
7569 tgl@sss.pgh.pa.us 1256 [ # # ]:UBC 0 : elog(ERROR, "unrecognized node type: %d",
1257 : : (int) nodeTag(jtnode));
1258 : : }
1259 : :
1260 : : /*
1261 : : * preprocess_phv_expression
1262 : : * Do preprocessing on a PlaceHolderVar expression that's been pulled up.
1263 : : *
1264 : : * If a LATERAL subquery references an output of another subquery, and that
1265 : : * output must be wrapped in a PlaceHolderVar because of an intermediate outer
1266 : : * join, then we'll push the PlaceHolderVar expression down into the subquery
1267 : : * and later pull it back up during find_lateral_references, which runs after
1268 : : * subquery_planner has preprocessed all the expressions that were in the
1269 : : * current query level to start with. So we need to preprocess it then.
1270 : : */
1271 : : Expr *
4249 tgl@sss.pgh.pa.us 1272 :CBC 36 : preprocess_phv_expression(PlannerInfo *root, Expr *expr)
1273 : : {
1274 : 36 : return (Expr *) preprocess_expression(root, (Node *) expr, EXPRKIND_PHV);
1275 : : }
1276 : :
1277 : : /*--------------------
1278 : : * grouping_planner
1279 : : * Perform planning steps related to grouping, aggregation, etc.
1280 : : *
1281 : : * This function adds all required top-level processing to the scan/join
1282 : : * Path(s) produced by query_planner.
1283 : : *
1284 : : * tuple_fraction is the fraction of tuples we expect will be retrieved.
1285 : : * tuple_fraction is interpreted as follows:
1286 : : * 0: expect all tuples to be retrieved (normal case)
1287 : : * 0 < tuple_fraction < 1: expect the given fraction of tuples available
1288 : : * from the plan to be retrieved
1289 : : * tuple_fraction >= 1: tuple_fraction is the absolute number of tuples
1290 : : * expected to be retrieved (ie, a LIMIT specification).
1291 : : * setops is used for set operation subqueries to provide the subquery with
1292 : : * the context in which it's being used so that Paths correctly sorted for the
1293 : : * set operation can be generated. NULL when not planning a set operation
1294 : : * child.
1295 : : *
1296 : : * Returns nothing; the useful output is in the Paths we attach to the
1297 : : * (UPPERREL_FINAL, NULL) upperrel in *root. In addition,
1298 : : * root->processed_tlist contains the final processed targetlist.
1299 : : *
1300 : : * Note that we have not done set_cheapest() on the final rel; it's convenient
1301 : : * to leave this to the caller.
1302 : : *--------------------
1303 : : */
1304 : : static void
12 drowley@postgresql.o 1305 :GNC 245853 : grouping_planner(PlannerInfo *root, double tuple_fraction,
1306 : : SetOperationStmt *setops)
1307 : : {
6888 tgl@sss.pgh.pa.us 1308 :CBC 245853 : Query *parse = root->parse;
6472 bruce@momjian.us 1309 : 245853 : int64 offset_est = 0;
1310 : 245853 : int64 count_est = 0;
6190 tgl@sss.pgh.pa.us 1311 : 245853 : double limit_tuples = -1.0;
2956 1312 : 245853 : bool have_postponed_srfs = false;
1313 : : PathTarget *final_target;
1314 : : List *final_targets;
1315 : : List *final_targets_contain_srfs;
1316 : : bool final_target_parallel_safe;
1317 : : RelOptInfo *current_rel;
1318 : : RelOptInfo *final_rel;
1319 : : FinalPathExtraData extra;
1320 : : ListCell *lc;
1321 : :
1322 : : /* Tweak caller-supplied tuple_fraction if have LIMIT/OFFSET */
6814 1323 [ + + + + ]: 245853 : if (parse->limitCount || parse->limitOffset)
1324 : : {
1325 : 2314 : tuple_fraction = preprocess_limit(root, tuple_fraction,
1326 : : &offset_est, &count_est);
1327 : :
1328 : : /*
1329 : : * If we have a known LIMIT, and don't have an unknown OFFSET, we can
1330 : : * estimate the effects of using a bounded sort.
1331 : : */
6190 1332 [ + + + + ]: 2314 : if (count_est > 0 && offset_est >= 0)
1333 : 2070 : limit_tuples = (double) count_est + (double) offset_est;
1334 : : }
1335 : :
1336 : : /* Make tuple_fraction accessible to lower-level routines */
2960 1337 : 245853 : root->tuple_fraction = tuple_fraction;
1338 : :
8592 1339 [ + + ]: 245853 : if (parse->setOperations)
1340 : : {
1341 : : /*
1342 : : * Construct Paths for set operations. The results will not need any
1343 : : * work except perhaps a top-level sort and/or LIMIT. Note that any
1344 : : * special work for recursive unions is the responsibility of
1345 : : * plan_set_operations.
1346 : : */
2960 1347 : 2590 : current_rel = plan_set_operations(root);
1348 : :
1349 : : /*
1350 : : * We should not need to call preprocess_targetlist, since we must be
1351 : : * in a SELECT query node. Instead, use the processed_tlist returned
1352 : : * by plan_set_operations (since this tells whether it returned any
1353 : : * resjunk columns!), and transfer any sort key information from the
1354 : : * original tlist.
1355 : : */
8592 1356 [ - + ]: 2587 : Assert(parse->commandType == CMD_SELECT);
1357 : :
1358 : : /* for safety, copy processed_tlist instead of modifying in-place */
1845 1359 : 2587 : root->processed_tlist =
1360 : 2587 : postprocess_setop_tlist(copyObject(root->processed_tlist),
1361 : : parse->targetList);
1362 : :
1363 : : /* Also extract the PathTarget form of the setop result tlist */
2956 1364 : 2587 : final_target = current_rel->cheapest_total_path->pathtarget;
1365 : :
1366 : : /* And check whether it's parallel safe */
1367 : : final_target_parallel_safe =
2229 rhaas@postgresql.org 1368 : 2587 : is_parallel_safe(root, (Node *) final_target->exprs);
1369 : :
1370 : : /* The setop result tlist couldn't contain any SRFs */
2643 andres@anarazel.de 1371 [ - + ]: 2587 : Assert(!parse->hasTargetSRFs);
1372 : 2587 : final_targets = final_targets_contain_srfs = NIL;
1373 : :
1374 : : /*
1375 : : * Can't handle FOR [KEY] UPDATE/SHARE here (parser should have
1376 : : * checked already, but let's make sure).
1377 : : */
8530 tgl@sss.pgh.pa.us 1378 [ - + ]: 2587 : if (parse->rowMarks)
7569 tgl@sss.pgh.pa.us 1379 [ # # ]:UBC 0 : ereport(ERROR,
1380 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1381 : : /*------
1382 : : translator: %s is a SQL row locking clause such as FOR UPDATE */
1383 : : errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
1384 : : LCS_asString(linitial_node(RowMarkClause,
1385 : : parse->rowMarks)->strength))));
1386 : :
1387 : : /*
1388 : : * Calculate pathkeys that represent result ordering requirements
1389 : : */
5736 tgl@sss.pgh.pa.us 1390 [ - + ]:CBC 2587 : Assert(parse->distinctClause == NIL);
5731 1391 : 2587 : root->sort_pathkeys = make_pathkeys_for_sortclauses(root,
1392 : : parse->sortClause,
1393 : : root->processed_tlist);
1394 : : }
1395 : : else
1396 : : {
1397 : : /* No set operations, do regular planning */
1398 : : PathTarget *sort_input_target;
1399 : : List *sort_input_targets;
1400 : : List *sort_input_targets_contain_srfs;
1401 : : bool sort_input_target_parallel_safe;
1402 : : PathTarget *grouping_target;
1403 : : List *grouping_targets;
1404 : : List *grouping_targets_contain_srfs;
1405 : : bool grouping_target_parallel_safe;
1406 : : PathTarget *scanjoin_target;
1407 : : List *scanjoin_targets;
1408 : : List *scanjoin_targets_contain_srfs;
1409 : : bool scanjoin_target_parallel_safe;
1410 : : bool scanjoin_target_same_exprs;
1411 : : bool have_grouping;
5586 1412 : 243263 : WindowFuncLists *wflists = NULL;
1413 : 243263 : List *activeWindows = NIL;
2575 rhodiumtoad@postgres 1414 : 243263 : grouping_sets_data *gset_data = NULL;
1415 : : standard_qp_extra qp_extra;
1416 : :
1417 : : /* A recursive query should always have setOperations */
5671 tgl@sss.pgh.pa.us 1418 [ - + ]: 243263 : Assert(!root->hasRecursion);
1419 : :
1420 : : /* Preprocess grouping sets and GROUP BY clause, if any */
3256 andres@anarazel.de 1421 [ + + ]: 243263 : if (parse->groupingSets)
1422 : : {
2575 rhodiumtoad@postgres 1423 : 367 : gset_data = preprocess_grouping_sets(root);
1424 : : }
452 tgl@sss.pgh.pa.us 1425 [ + + ]: 242896 : else if (parse->groupClause)
1426 : : {
1427 : : /* Preprocess regular GROUP BY clause, if any */
39 drowley@postgresql.o 1428 :GNC 1683 : root->processed_groupClause = list_copy(parse->groupClause);
1429 : : /* Remove any redundant GROUP BY columns */
452 tgl@sss.pgh.pa.us 1430 :CBC 1683 : remove_useless_groupby_columns(root);
1431 : : }
1432 : :
1433 : : /*
1434 : : * Preprocess targetlist. Note that much of the remaining planning
1435 : : * work will be done with the PathTarget representation of tlists, but
1436 : : * we must also maintain the full representation of the final tlist so
1437 : : * that we can transfer its decoration (resnames etc) to the topmost
1438 : : * tlist of the finished Plan. This is kept in processed_tlist.
1439 : : */
1110 1440 : 243260 : preprocess_targetlist(root);
1441 : :
1442 : : /*
1443 : : * Mark all the aggregates with resolved aggtranstypes, and detect
1444 : : * aggregates that are duplicates or can share transition state. We
1445 : : * must do this before slicing and dicing the tlist into various
1446 : : * pathtargets, else some copies of the Aggref nodes might escape
1447 : : * being marked.
1448 : : */
2843 1449 [ + + ]: 243260 : if (parse->hasAggs)
1450 : : {
1237 heikki.linnakangas@i 1451 : 17756 : preprocess_aggrefs(root, (Node *) root->processed_tlist);
1452 : 17756 : preprocess_aggrefs(root, (Node *) parse->havingQual);
1453 : : }
1454 : :
1455 : : /*
1456 : : * Locate any window functions in the tlist. (We don't need to look
1457 : : * anywhere else, since expressions used in ORDER BY will be in there
1458 : : * too.) Note that they could all have been eliminated by constant
1459 : : * folding, in which case we don't need to do any more work.
1460 : : */
5586 tgl@sss.pgh.pa.us 1461 [ + + ]: 243260 : if (parse->hasWindowFuncs)
1462 : : {
1845 1463 : 1150 : wflists = find_window_functions((Node *) root->processed_tlist,
5586 1464 : 1150 : list_length(parse->windowClause));
1465 [ + + ]: 1150 : if (wflists->numWindowFuncs > 0)
1466 : : {
1467 : : /*
1468 : : * See if any modifications can be made to each WindowClause
1469 : : * to allow the executor to execute the WindowFuncs more
1470 : : * quickly.
1471 : : */
478 drowley@postgresql.o 1472 : 1147 : optimize_window_clauses(root, wflists);
1473 : :
5586 tgl@sss.pgh.pa.us 1474 : 1147 : activeWindows = select_active_windows(root, wflists);
1475 : : }
1476 : : else
1477 : 3 : parse->hasWindowFuncs = false;
1478 : : }
1479 : :
1480 : : /*
1481 : : * Preprocess MIN/MAX aggregates, if any. Note: be careful about
1482 : : * adding logic between here and the query_planner() call. Anything
1483 : : * that is needed in MIN/MAX-optimizable cases will have to be
1484 : : * duplicated in planagg.c.
1485 : : */
4910 1486 [ + + ]: 243260 : if (parse->hasAggs)
1845 1487 : 17756 : preprocess_minmax_aggregates(root);
1488 : :
1489 : : /*
1490 : : * Figure out whether there's a hard limit on the number of rows that
1491 : : * query_planner's result subplan needs to return. Even if we know a
1492 : : * hard limit overall, it doesn't apply if the query has any
1493 : : * grouping/aggregation operations, or SRFs in the tlist.
1494 : : */
4896 1495 [ + + ]: 243260 : if (parse->groupClause ||
3256 andres@anarazel.de 1496 [ + + ]: 241234 : parse->groupingSets ||
4896 tgl@sss.pgh.pa.us 1497 [ + + ]: 241213 : parse->distinctClause ||
1498 [ + + ]: 240120 : parse->hasAggs ||
1499 [ + + ]: 224192 : parse->hasWindowFuncs ||
2770 1500 [ + + ]: 223108 : parse->hasTargetSRFs ||
4896 1501 [ + + ]: 219118 : root->hasHavingQual)
3905 1502 : 24151 : root->limit_tuples = -1.0;
1503 : : else
1504 : 219109 : root->limit_tuples = limit_tuples;
1505 : :
1506 : : /* Set up data needed by standard_qp_callback */
4003 1507 : 243260 : qp_extra.activeWindows = activeWindows;
452 1508 : 243260 : qp_extra.gset_data = gset_data;
1509 : :
1510 : : /*
1511 : : * If we're a subquery for a set operation, store the SetOperationStmt
1512 : : * in qp_extra.
1513 : : */
12 drowley@postgresql.o 1514 :GNC 243260 : qp_extra.setop = setops;
1515 : :
1516 : : /*
1517 : : * Generate the best unsorted and presorted paths for the scan/join
1518 : : * portion of this Query, ie the processing represented by the
1519 : : * FROM/WHERE clauses. (Note there may not be any presorted paths.)
1520 : : * We also generate (in standard_qp_callback) pathkey representations
1521 : : * of the query's sort clause, distinct clause, etc.
1522 : : */
1845 tgl@sss.pgh.pa.us 1523 :CBC 243260 : current_rel = query_planner(root, standard_qp_callback, &qp_extra);
1524 : :
1525 : : /*
1526 : : * Convert the query's result tlist into PathTarget format.
1527 : : *
1528 : : * Note: this cannot be done before query_planner() has performed
1529 : : * appendrel expansion, because that might add resjunk entries to
1530 : : * root->processed_tlist. Waiting till afterwards is also helpful
1531 : : * because the target width estimates can use per-Var width numbers
1532 : : * that were obtained within query_planner().
1533 : : */
1534 : 243237 : final_target = create_pathtarget(root, root->processed_tlist);
1535 : : final_target_parallel_safe =
2229 rhaas@postgresql.org 1536 : 243237 : is_parallel_safe(root, (Node *) final_target->exprs);
1537 : :
1538 : : /*
1539 : : * If ORDER BY was given, consider whether we should use a post-sort
1540 : : * projection, and compute the adjusted target for preceding steps if
1541 : : * so.
1542 : : */
2956 tgl@sss.pgh.pa.us 1543 [ + + ]: 243237 : if (parse->sortClause)
1544 : : {
1545 : 26978 : sort_input_target = make_sort_input_target(root,
1546 : : final_target,
1547 : : &have_postponed_srfs);
1548 : : sort_input_target_parallel_safe =
2229 rhaas@postgresql.org 1549 : 26978 : is_parallel_safe(root, (Node *) sort_input_target->exprs);
1550 : : }
1551 : : else
1552 : : {
2956 tgl@sss.pgh.pa.us 1553 : 216259 : sort_input_target = final_target;
2229 rhaas@postgresql.org 1554 : 216259 : sort_input_target_parallel_safe = final_target_parallel_safe;
1555 : : }
1556 : :
1557 : : /*
1558 : : * If we have window functions to deal with, the output from any
1559 : : * grouping step needs to be what the window functions want;
1560 : : * otherwise, it should be sort_input_target.
1561 : : */
2958 tgl@sss.pgh.pa.us 1562 [ + + ]: 243237 : if (activeWindows)
1563 : : {
1564 : 1147 : grouping_target = make_window_input_target(root,
1565 : : final_target,
1566 : : activeWindows);
1567 : : grouping_target_parallel_safe =
2229 rhaas@postgresql.org 1568 : 1147 : is_parallel_safe(root, (Node *) grouping_target->exprs);
1569 : : }
1570 : : else
1571 : : {
2956 tgl@sss.pgh.pa.us 1572 : 242090 : grouping_target = sort_input_target;
2229 rhaas@postgresql.org 1573 : 242090 : grouping_target_parallel_safe = sort_input_target_parallel_safe;
1574 : : }
1575 : :
1576 : : /*
1577 : : * If we have grouping or aggregation to do, the topmost scan/join
1578 : : * plan node must emit what the grouping step wants; otherwise, it
1579 : : * should emit grouping_target.
1580 : : */
2958 tgl@sss.pgh.pa.us 1581 [ + + ]: 241211 : have_grouping = (parse->groupClause || parse->groupingSets ||
1582 [ + + + + : 484448 : parse->hasAggs || root->hasHavingQual);
+ + ]
1583 [ + + ]: 243237 : if (have_grouping)
1584 : : {
2956 1585 : 17996 : scanjoin_target = make_group_input_target(root, final_target);
1586 : : scanjoin_target_parallel_safe =
1860 efujita@postgresql.o 1587 : 17996 : is_parallel_safe(root, (Node *) scanjoin_target->exprs);
1588 : : }
1589 : : else
1590 : : {
2958 tgl@sss.pgh.pa.us 1591 : 225241 : scanjoin_target = grouping_target;
2229 rhaas@postgresql.org 1592 : 225241 : scanjoin_target_parallel_safe = grouping_target_parallel_safe;
1593 : : }
1594 : :
1595 : : /*
1596 : : * If there are any SRFs in the targetlist, we must separate each of
1597 : : * these PathTargets into SRF-computing and SRF-free targets. Replace
1598 : : * each of the named targets with a SRF-free version, and remember the
1599 : : * list of additional projection steps we need to add afterwards.
1600 : : */
2643 andres@anarazel.de 1601 [ + + ]: 243237 : if (parse->hasTargetSRFs)
1602 : : {
1603 : : /* final_target doesn't recompute any SRFs in sort_input_target */
1604 : 4202 : split_pathtarget_at_srfs(root, final_target, sort_input_target,
1605 : : &final_targets,
1606 : : &final_targets_contain_srfs);
2413 tgl@sss.pgh.pa.us 1607 : 4202 : final_target = linitial_node(PathTarget, final_targets);
2643 andres@anarazel.de 1608 [ - + ]: 4202 : Assert(!linitial_int(final_targets_contain_srfs));
1609 : : /* likewise for sort_input_target vs. grouping_target */
1610 : 4202 : split_pathtarget_at_srfs(root, sort_input_target, grouping_target,
1611 : : &sort_input_targets,
1612 : : &sort_input_targets_contain_srfs);
2413 tgl@sss.pgh.pa.us 1613 : 4202 : sort_input_target = linitial_node(PathTarget, sort_input_targets);
2643 andres@anarazel.de 1614 [ - + ]: 4202 : Assert(!linitial_int(sort_input_targets_contain_srfs));
1615 : : /* likewise for grouping_target vs. scanjoin_target */
1616 : 4202 : split_pathtarget_at_srfs(root, grouping_target, scanjoin_target,
1617 : : &grouping_targets,
1618 : : &grouping_targets_contain_srfs);
2413 tgl@sss.pgh.pa.us 1619 : 4202 : grouping_target = linitial_node(PathTarget, grouping_targets);
2643 andres@anarazel.de 1620 [ - + ]: 4202 : Assert(!linitial_int(grouping_targets_contain_srfs));
1621 : : /* scanjoin_target will not have any SRFs precomputed for it */
1622 : 4202 : split_pathtarget_at_srfs(root, scanjoin_target, NULL,
1623 : : &scanjoin_targets,
1624 : : &scanjoin_targets_contain_srfs);
2413 tgl@sss.pgh.pa.us 1625 : 4202 : scanjoin_target = linitial_node(PathTarget, scanjoin_targets);
2643 andres@anarazel.de 1626 [ - + ]: 4202 : Assert(!linitial_int(scanjoin_targets_contain_srfs));
1627 : : }
1628 : : else
1629 : : {
1630 : : /* initialize lists; for most of these, dummy values are OK */
1631 : 239035 : final_targets = final_targets_contain_srfs = NIL;
1632 : 239035 : sort_input_targets = sort_input_targets_contain_srfs = NIL;
1633 : 239035 : grouping_targets = grouping_targets_contain_srfs = NIL;
2208 rhaas@postgresql.org 1634 : 239035 : scanjoin_targets = list_make1(scanjoin_target);
1635 : 239035 : scanjoin_targets_contain_srfs = NIL;
1636 : : }
1637 : :
1638 : : /* Apply scan/join target. */
1639 : 243237 : scanjoin_target_same_exprs = list_length(scanjoin_targets) == 1
1640 [ + + + + ]: 243237 : && equal(scanjoin_target->exprs, current_rel->reltarget->exprs);
1641 : 243237 : apply_scanjoin_target_to_paths(root, current_rel, scanjoin_targets,
1642 : : scanjoin_targets_contain_srfs,
1643 : : scanjoin_target_parallel_safe,
1644 : : scanjoin_target_same_exprs);
1645 : :
1646 : : /*
1647 : : * Save the various upper-rel PathTargets we just computed into
1648 : : * root->upper_targets[]. The core code doesn't use this, but it
1649 : : * provides a convenient place for extensions to get at the info. For
1650 : : * consistency, we save all the intermediate targets, even though some
1651 : : * of the corresponding upperrels might not be needed for this query.
1652 : : */
2953 tgl@sss.pgh.pa.us 1653 : 243237 : root->upper_targets[UPPERREL_FINAL] = final_target;
1882 efujita@postgresql.o 1654 : 243237 : root->upper_targets[UPPERREL_ORDERED] = final_target;
1655 : 243237 : root->upper_targets[UPPERREL_DISTINCT] = sort_input_target;
67 drowley@postgresql.o 1656 :GNC 243237 : root->upper_targets[UPPERREL_PARTIAL_DISTINCT] = sort_input_target;
2953 tgl@sss.pgh.pa.us 1657 :CBC 243237 : root->upper_targets[UPPERREL_WINDOW] = sort_input_target;
1658 : 243237 : root->upper_targets[UPPERREL_GROUP_AGG] = grouping_target;
1659 : :
1660 : : /*
1661 : : * If we have grouping and/or aggregation, consider ways to implement
1662 : : * that. We build a new upperrel representing the output of this
1663 : : * phase.
1664 : : */
2958 1665 [ + + ]: 243237 : if (have_grouping)
1666 : : {
2960 1667 : 17996 : current_rel = create_grouping_paths(root,
1668 : : current_rel,
1669 : : grouping_target,
1670 : : grouping_target_parallel_safe,
1671 : : gset_data);
1672 : : /* Fix things up if grouping_target contains SRFs */
2643 andres@anarazel.de 1673 [ + + ]: 17993 : if (parse->hasTargetSRFs)
1674 : 191 : adjust_paths_for_srfs(root, current_rel,
1675 : : grouping_targets,
1676 : : grouping_targets_contain_srfs);
1677 : : }
1678 : :
1679 : : /*
1680 : : * If we have window functions, consider ways to implement those. We
1681 : : * build a new upperrel representing the output of this phase.
1682 : : */
2960 tgl@sss.pgh.pa.us 1683 [ + + ]: 243234 : if (activeWindows)
1684 : : {
1685 : 1147 : current_rel = create_window_paths(root,
1686 : : current_rel,
1687 : : grouping_target,
1688 : : sort_input_target,
1689 : : sort_input_target_parallel_safe,
1690 : : wflists,
1691 : : activeWindows);
1692 : : /* Fix things up if sort_input_target contains SRFs */
2643 andres@anarazel.de 1693 [ + + ]: 1147 : if (parse->hasTargetSRFs)
1694 : 6 : adjust_paths_for_srfs(root, current_rel,
1695 : : sort_input_targets,
1696 : : sort_input_targets_contain_srfs);
1697 : : }
1698 : :
1699 : : /*
1700 : : * If there is a DISTINCT clause, consider ways to implement that. We
1701 : : * build a new upperrel representing the output of this phase.
1702 : : */
2960 tgl@sss.pgh.pa.us 1703 [ + + ]: 243234 : if (parse->distinctClause)
1704 : : {
1705 : 1098 : current_rel = create_distinct_paths(root,
1706 : : current_rel,
1707 : : sort_input_target);
1708 : : }
1709 : : } /* end of if (setOperations) */
1710 : :
1711 : : /*
1712 : : * If ORDER BY was given, consider ways to implement that, and generate a
1713 : : * new upperrel containing only paths that emit the correct ordering and
1714 : : * project the correct final_target. We can apply the original
1715 : : * limit_tuples limit in sort costing here, but only if there are no
1716 : : * postponed SRFs.
1717 : : */
1718 [ + + ]: 245821 : if (parse->sortClause)
1719 : : {
1720 [ + + ]: 28656 : current_rel = create_ordered_paths(root,
1721 : : current_rel,
1722 : : final_target,
1723 : : final_target_parallel_safe,
1724 : : have_postponed_srfs ? -1.0 :
1725 : : limit_tuples);
1726 : : /* Fix things up if final_target contains SRFs */
2643 andres@anarazel.de 1727 [ + + ]: 28656 : if (parse->hasTargetSRFs)
1728 : 98 : adjust_paths_for_srfs(root, current_rel,
1729 : : final_targets,
1730 : : final_targets_contain_srfs);
1731 : : }
1732 : :
1733 : : /*
1734 : : * Now we are prepared to build the final-output upperrel.
1735 : : */
2960 tgl@sss.pgh.pa.us 1736 : 245821 : final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
1737 : :
1738 : : /*
1739 : : * If the input rel is marked consider_parallel and there's nothing that's
1740 : : * not parallel-safe in the LIMIT clause, then the final_rel can be marked
1741 : : * consider_parallel as well. Note that if the query has rowMarks or is
1742 : : * not a SELECT, consider_parallel will be false for every relation in the
1743 : : * query.
1744 : : */
2844 rhaas@postgresql.org 1745 [ + + + + ]: 319376 : if (current_rel->consider_parallel &&
2795 tgl@sss.pgh.pa.us 1746 [ + + ]: 147098 : is_parallel_safe(root, parse->limitOffset) &&
1747 : 73543 : is_parallel_safe(root, parse->limitCount))
2844 rhaas@postgresql.org 1748 : 73540 : final_rel->consider_parallel = true;
1749 : :
1750 : : /*
1751 : : * If the current_rel belongs to a single FDW, so does the final_rel.
1752 : : */
tgl@sss.pgh.pa.us 1753 : 245821 : final_rel->serverid = current_rel->serverid;
2830 1754 : 245821 : final_rel->userid = current_rel->userid;
1755 : 245821 : final_rel->useridiscurrent = current_rel->useridiscurrent;
2844 1756 : 245821 : final_rel->fdwroutine = current_rel->fdwroutine;
1757 : :
1758 : : /*
1759 : : * Generate paths for the final_rel. Insert all surviving paths, with
1760 : : * LockRows, Limit, and/or ModifyTable steps added if needed.
1761 : : */
2960 1762 [ + - + + : 499803 : foreach(lc, current_rel->pathlist)
+ + ]
1763 : : {
1764 : 253982 : Path *path = (Path *) lfirst(lc);
1765 : :
1766 : : /*
1767 : : * If there is a FOR [KEY] UPDATE/SHARE clause, add the LockRows node.
1768 : : * (Note: we intentionally test parse->rowMarks not root->rowMarks
1769 : : * here. If there are only non-locking rowmarks, they should be
1770 : : * handled by the ModifyTable node instead. However, root->rowMarks
1771 : : * is what goes into the LockRows node.)
1772 : : */
1773 [ + + ]: 253982 : if (parse->rowMarks)
1774 : : {
1775 : 4041 : path = (Path *) create_lockrows_path(root, final_rel, path,
1776 : : root->rowMarks,
1777 : : assign_special_exec_param(root));
1778 : : }
1779 : :
1780 : : /*
1781 : : * If there is a LIMIT/OFFSET clause, add the LIMIT node.
1782 : : */
1783 [ + + ]: 253982 : if (limit_needed(parse))
1784 : : {
1785 : 2747 : path = (Path *) create_limit_path(root, final_rel, path,
1786 : : parse->limitOffset,
1787 : : parse->limitCount,
1788 : : parse->limitOption,
1789 : : offset_est, count_est);
1790 : : }
1791 : :
1792 : : /*
1793 : : * If this is an INSERT/UPDATE/DELETE/MERGE, add the ModifyTable node.
1794 : : */
1110 1795 [ + + ]: 253982 : if (parse->commandType != CMD_SELECT)
1796 : : {
1797 : : Index rootRelation;
1798 : 43745 : List *resultRelations = NIL;
1799 : 43745 : List *updateColnosLists = NIL;
1800 : 43745 : List *withCheckOptionLists = NIL;
1801 : 43745 : List *returningLists = NIL;
748 alvherre@alvh.no-ip. 1802 : 43745 : List *mergeActionLists = NIL;
15 dean.a.rasheed@gmail 1803 :GNC 43745 : List *mergeJoinConditions = NIL;
1804 : : List *rowMarks;
1805 : :
1110 tgl@sss.pgh.pa.us 1806 [ + + ]:CBC 43745 : if (bms_membership(root->all_result_relids) == BMS_MULTIPLE)
1807 : : {
1808 : : /* Inherited UPDATE/DELETE/MERGE */
1809 : 1257 : RelOptInfo *top_result_rel = find_base_rel(root,
1810 : : parse->resultRelation);
1811 : 1257 : int resultRelation = -1;
1812 : :
1813 : : /* Pass the root result rel forward to the executor. */
173 1814 : 1257 : rootRelation = parse->resultRelation;
1815 : :
1816 : : /* Add only leaf children to ModifyTable. */
1110 1817 : 3696 : while ((resultRelation = bms_next_member(root->leaf_result_relids,
1818 [ + + ]: 3696 : resultRelation)) >= 0)
1819 : : {
1820 : 2439 : RelOptInfo *this_result_rel = find_base_rel(root,
1821 : : resultRelation);
1822 : :
1823 : : /*
1824 : : * Also exclude any leaf rels that have turned dummy since
1825 : : * being added to the list, for example, by being excluded
1826 : : * by constraint exclusion.
1827 : : */
1828 [ + + ]: 2439 : if (IS_DUMMY_REL(this_result_rel))
1829 : 42 : continue;
1830 : :
1831 : : /* Build per-target-rel lists needed by ModifyTable */
1832 : 2397 : resultRelations = lappend_int(resultRelations,
1833 : : resultRelation);
1834 [ + + ]: 2397 : if (parse->commandType == CMD_UPDATE)
1835 : : {
1836 : 1718 : List *update_colnos = root->update_colnos;
1837 : :
1838 [ + - ]: 1718 : if (this_result_rel != top_result_rel)
1839 : : update_colnos =
1840 : 1718 : adjust_inherited_attnums_multilevel(root,
1841 : : update_colnos,
1842 : : this_result_rel->relid,
1843 : : top_result_rel->relid);
1844 : 1718 : updateColnosLists = lappend(updateColnosLists,
1845 : : update_colnos);
1846 : : }
1847 [ + + ]: 2397 : if (parse->withCheckOptions)
1848 : : {
1849 : 213 : List *withCheckOptions = parse->withCheckOptions;
1850 : :
1851 [ + - ]: 213 : if (this_result_rel != top_result_rel)
1852 : : withCheckOptions = (List *)
1853 : 213 : adjust_appendrel_attrs_multilevel(root,
1854 : : (Node *) withCheckOptions,
1855 : : this_result_rel,
1856 : : top_result_rel);
1857 : 213 : withCheckOptionLists = lappend(withCheckOptionLists,
1858 : : withCheckOptions);
1859 : : }
1860 [ + + ]: 2397 : if (parse->returningList)
1861 : : {
1862 : 276 : List *returningList = parse->returningList;
1863 : :
1864 [ + - ]: 276 : if (this_result_rel != top_result_rel)
1865 : : returningList = (List *)
1866 : 276 : adjust_appendrel_attrs_multilevel(root,
1867 : : (Node *) returningList,
1868 : : this_result_rel,
1869 : : top_result_rel);
1870 : 276 : returningLists = lappend(returningLists,
1871 : : returningList);
1872 : : }
748 alvherre@alvh.no-ip. 1873 [ + + ]: 2397 : if (parse->mergeActionList)
1874 : : {
1875 : : ListCell *l;
1876 : 195 : List *mergeActionList = NIL;
1877 : :
1878 : : /*
1879 : : * Copy MergeActions and translate stuff that
1880 : : * references attribute numbers.
1881 : : */
1882 [ + - + + : 672 : foreach(l, parse->mergeActionList)
+ + ]
1883 : : {
1884 : 477 : MergeAction *action = lfirst(l),
1885 : 477 : *leaf_action = copyObject(action);
1886 : :
1887 : 477 : leaf_action->qual =
1888 : 477 : adjust_appendrel_attrs_multilevel(root,
1889 : : (Node *) action->qual,
1890 : : this_result_rel,
1891 : : top_result_rel);
1892 : 477 : leaf_action->targetList = (List *)
1893 : 477 : adjust_appendrel_attrs_multilevel(root,
1894 : 477 : (Node *) action->targetList,
1895 : : this_result_rel,
1896 : : top_result_rel);
1897 [ + + ]: 477 : if (leaf_action->commandType == CMD_UPDATE)
1898 : 296 : leaf_action->updateColnos =
1899 : 296 : adjust_inherited_attnums_multilevel(root,
1900 : : action->updateColnos,
1901 : : this_result_rel->relid,
1902 : : top_result_rel->relid);
1903 : 477 : mergeActionList = lappend(mergeActionList,
1904 : : leaf_action);
1905 : : }
1906 : :
1907 : 195 : mergeActionLists = lappend(mergeActionLists,
1908 : : mergeActionList);
1909 : : }
15 dean.a.rasheed@gmail 1910 [ + + ]:GNC 2397 : if (parse->commandType == CMD_MERGE)
1911 : : {
1912 : 195 : Node *mergeJoinCondition = parse->mergeJoinCondition;
1913 : :
1914 [ + - ]: 195 : if (this_result_rel != top_result_rel)
1915 : : mergeJoinCondition =
1916 : 195 : adjust_appendrel_attrs_multilevel(root,
1917 : : mergeJoinCondition,
1918 : : this_result_rel,
1919 : : top_result_rel);
1920 : 195 : mergeJoinConditions = lappend(mergeJoinConditions,
1921 : : mergeJoinCondition);
1922 : : }
1923 : : }
1924 : :
1110 tgl@sss.pgh.pa.us 1925 [ + + ]:CBC 1257 : if (resultRelations == NIL)
1926 : : {
1927 : : /*
1928 : : * We managed to exclude every child rel, so generate a
1929 : : * dummy one-relation plan using info for the top target
1930 : : * rel (even though that may not be a leaf target).
1931 : : * Although it's clear that no data will be updated or
1932 : : * deleted, we still need to have a ModifyTable node so
1933 : : * that any statement triggers will be executed. (This
1934 : : * could be cleaner if we fixed nodeModifyTable.c to allow
1935 : : * zero target relations, but that probably wouldn't be a
1936 : : * net win.)
1937 : : */
1938 : 15 : resultRelations = list_make1_int(parse->resultRelation);
1939 [ + - ]: 15 : if (parse->commandType == CMD_UPDATE)
1940 : 15 : updateColnosLists = list_make1(root->update_colnos);
1941 [ - + ]: 15 : if (parse->withCheckOptions)
1110 tgl@sss.pgh.pa.us 1942 :UBC 0 : withCheckOptionLists = list_make1(parse->withCheckOptions);
1110 tgl@sss.pgh.pa.us 1943 [ + + ]:CBC 15 : if (parse->returningList)
1944 : 9 : returningLists = list_make1(parse->returningList);
748 alvherre@alvh.no-ip. 1945 [ - + ]: 15 : if (parse->mergeActionList)
748 alvherre@alvh.no-ip. 1946 :UBC 0 : mergeActionLists = list_make1(parse->mergeActionList);
15 dean.a.rasheed@gmail 1947 [ - + ]:GNC 15 : if (parse->commandType == CMD_MERGE)
15 dean.a.rasheed@gmail 1948 :UNC 0 : mergeJoinConditions = list_make1(parse->mergeJoinCondition);
1949 : : }
1950 : : }
1951 : : else
1952 : : {
1953 : : /* Single-relation INSERT/UPDATE/DELETE/MERGE. */
173 tgl@sss.pgh.pa.us 1954 :CBC 42488 : rootRelation = 0; /* there's no separate root rel */
1110 1955 : 42488 : resultRelations = list_make1_int(parse->resultRelation);
1956 [ + + ]: 42488 : if (parse->commandType == CMD_UPDATE)
1957 : 5759 : updateColnosLists = list_make1(root->update_colnos);
1958 [ + + ]: 42488 : if (parse->withCheckOptions)
1959 : 448 : withCheckOptionLists = list_make1(parse->withCheckOptions);
1960 [ + + ]: 42488 : if (parse->returningList)
1961 : 1102 : returningLists = list_make1(parse->returningList);
748 alvherre@alvh.no-ip. 1962 [ + + ]: 42488 : if (parse->mergeActionList)
1963 : 774 : mergeActionLists = list_make1(parse->mergeActionList);
15 dean.a.rasheed@gmail 1964 [ + + ]:GNC 42488 : if (parse->commandType == CMD_MERGE)
1965 : 774 : mergeJoinConditions = list_make1(parse->mergeJoinCondition);
1966 : : }
1967 : :
1968 : : /*
1969 : : * If there was a FOR [KEY] UPDATE/SHARE clause, the LockRows node
1970 : : * will have dealt with fetching non-locked marked rows, else we
1971 : : * need to have ModifyTable do that.
1972 : : */
2960 tgl@sss.pgh.pa.us 1973 [ - + ]:CBC 43745 : if (parse->rowMarks)
2960 tgl@sss.pgh.pa.us 1974 :UBC 0 : rowMarks = NIL;
1975 : : else
2960 tgl@sss.pgh.pa.us 1976 :CBC 43745 : rowMarks = root->rowMarks;
1977 : :
1978 : : path = (Path *)
1979 : 43745 : create_modifytable_path(root, final_rel,
1980 : : path,
1981 : : parse->commandType,
1982 : 43745 : parse->canSetTag,
1983 : 43745 : parse->resultRelation,
1984 : : rootRelation,
1110 1985 : 43745 : root->partColsUpdated,
1986 : : resultRelations,
1987 : : updateColnosLists,
1988 : : withCheckOptionLists,
1989 : : returningLists,
1990 : : rowMarks,
1991 : : parse->onConflict,
1992 : : mergeActionLists,
1993 : : mergeJoinConditions,
1994 : : assign_special_exec_param(root));
1995 : : }
1996 : :
1997 : : /* And shove it into final_rel */
2960 1998 : 253982 : add_path(final_rel, path);
1999 : : }
2000 : :
2001 : : /*
2002 : : * Generate partial paths for final_rel, too, if outer query levels might
2003 : : * be able to make use of them.
2004 : : */
2224 rhaas@postgresql.org 2005 [ + + + + ]: 245821 : if (final_rel->consider_parallel && root->query_level > 1 &&
2006 [ + + ]: 9243 : !limit_needed(parse))
2007 : : {
2008 [ + - - + ]: 9166 : Assert(!parse->rowMarks && parse->commandType == CMD_SELECT);
2009 [ + + + + : 9217 : foreach(lc, current_rel->partial_pathlist)
+ + ]
2010 : : {
2011 : 51 : Path *partial_path = (Path *) lfirst(lc);
2012 : :
2013 : 51 : add_partial_path(final_rel, partial_path);
2014 : : }
2015 : : }
2016 : :
1839 efujita@postgresql.o 2017 : 245821 : extra.limit_needed = limit_needed(parse);
2018 : 245821 : extra.limit_tuples = limit_tuples;
2019 : 245821 : extra.count_est = count_est;
2020 : 245821 : extra.offset_est = offset_est;
2021 : :
2022 : : /*
2023 : : * If there is an FDW that's responsible for all baserels of the query,
2024 : : * let it consider adding ForeignPaths.
2025 : : */
2844 tgl@sss.pgh.pa.us 2026 [ + + ]: 245821 : if (final_rel->fdwroutine &&
2027 [ + + ]: 612 : final_rel->fdwroutine->GetForeignUpperPaths)
2028 : 582 : final_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_FINAL,
2029 : : current_rel, final_rel,
2030 : : &extra);
2031 : :
2032 : : /* Let extensions possibly add some more paths */
2924 2033 [ - + ]: 245821 : if (create_upper_paths_hook)
2924 tgl@sss.pgh.pa.us 2034 :UBC 0 : (*create_upper_paths_hook) (root, UPPERREL_FINAL,
2035 : : current_rel, final_rel, &extra);
2036 : :
2037 : : /* Note: currently, we leave it to callers to do set_cheapest() */
2960 tgl@sss.pgh.pa.us 2038 :CBC 245821 : }
2039 : :
2040 : : /*
2041 : : * Do preprocessing for groupingSets clause and related data. This handles the
2042 : : * preliminary steps of expanding the grouping sets, organizing them into lists
2043 : : * of rollups, and preparing annotations which will later be filled in with
2044 : : * size estimates.
2045 : : */
2046 : : static grouping_sets_data *
2575 rhodiumtoad@postgres 2047 : 367 : preprocess_grouping_sets(PlannerInfo *root)
2048 : : {
2049 : 367 : Query *parse = root->parse;
2050 : : List *sets;
2051 : 367 : int maxref = 0;
2052 : : ListCell *lc_set;
2053 : 367 : grouping_sets_data *gd = palloc0(sizeof(grouping_sets_data));
2054 : :
1123 tomas.vondra@postgre 2055 : 367 : parse->groupingSets = expand_grouping_sets(parse->groupingSets, parse->groupDistinct, -1);
2056 : :
2575 rhodiumtoad@postgres 2057 : 367 : gd->any_hashable = false;
2058 : 367 : gd->unhashable_refs = NULL;
2059 : 367 : gd->unsortable_refs = NULL;
2060 : 367 : gd->unsortable_sets = NIL;
2061 : :
2062 : : /*
2063 : : * We don't currently make any attempt to optimize the groupClause when
2064 : : * there are grouping sets, so just duplicate it in processed_groupClause.
2065 : : */
452 tgl@sss.pgh.pa.us 2066 : 367 : root->processed_groupClause = parse->groupClause;
2067 : :
2575 rhodiumtoad@postgres 2068 [ + + ]: 367 : if (parse->groupClause)
2069 : : {
2070 : : ListCell *lc;
2071 : :
2072 [ + - + + : 1126 : foreach(lc, parse->groupClause)
+ + ]
2073 : : {
2413 tgl@sss.pgh.pa.us 2074 : 780 : SortGroupClause *gc = lfirst_node(SortGroupClause, lc);
2575 rhodiumtoad@postgres 2075 : 780 : Index ref = gc->tleSortGroupRef;
2076 : :
2077 [ + + ]: 780 : if (ref > maxref)
2078 : 762 : maxref = ref;
2079 : :
2080 [ + + ]: 780 : if (!gc->hashable)
2081 : 15 : gd->unhashable_refs = bms_add_member(gd->unhashable_refs, ref);
2082 : :
2083 [ + + ]: 780 : if (!OidIsValid(gc->sortop))
2084 : 21 : gd->unsortable_refs = bms_add_member(gd->unsortable_refs, ref);
2085 : : }
2086 : : }
2087 : :
2088 : : /* Allocate workspace array for remapping */
2089 : 367 : gd->tleref_to_colnum_map = (int *) palloc((maxref + 1) * sizeof(int));
2090 : :
2091 : : /*
2092 : : * If we have any unsortable sets, we must extract them before trying to
2093 : : * prepare rollups. Unsortable sets don't go through
2094 : : * reorder_grouping_sets, so we must apply the GroupingSetData annotation
2095 : : * here.
2096 : : */
2097 [ + + ]: 367 : if (!bms_is_empty(gd->unsortable_refs))
2098 : : {
2099 : 21 : List *sortable_sets = NIL;
2100 : : ListCell *lc;
2101 : :
2102 [ + - + + : 63 : foreach(lc, parse->groupingSets)
+ + ]
2103 : : {
2413 tgl@sss.pgh.pa.us 2104 : 45 : List *gset = (List *) lfirst(lc);
2105 : :
2575 rhodiumtoad@postgres 2106 [ + + ]: 45 : if (bms_overlap_list(gd->unsortable_refs, gset))
2107 : : {
2108 : 24 : GroupingSetData *gs = makeNode(GroupingSetData);
2109 : :
2110 : 24 : gs->set = gset;
2111 : 24 : gd->unsortable_sets = lappend(gd->unsortable_sets, gs);
2112 : :
2113 : : /*
2114 : : * We must enforce here that an unsortable set is hashable;
2115 : : * later code assumes this. Parse analysis only checks that
2116 : : * every individual column is either hashable or sortable.
2117 : : *
2118 : : * Note that passing this test doesn't guarantee we can
2119 : : * generate a plan; there might be other showstoppers.
2120 : : */
2121 [ + + ]: 24 : if (bms_overlap_list(gd->unhashable_refs, gset))
2122 [ + - ]: 3 : ereport(ERROR,
2123 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2124 : : errmsg("could not implement GROUP BY"),
2125 : : errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
2126 : : }
2127 : : else
2128 : 21 : sortable_sets = lappend(sortable_sets, gset);
2129 : : }
2130 : :
2131 [ + + ]: 18 : if (sortable_sets)
2132 : 15 : sets = extract_rollup_sets(sortable_sets);
2133 : : else
2134 : 3 : sets = NIL;
2135 : : }
2136 : : else
2137 : 346 : sets = extract_rollup_sets(parse->groupingSets);
2138 : :
2139 [ + + + + : 969 : foreach(lc_set, sets)
+ + ]
2140 : : {
2141 : 605 : List *current_sets = (List *) lfirst(lc_set);
2142 : 605 : RollupData *rollup = makeNode(RollupData);
2143 : : GroupingSetData *gs;
2144 : :
2145 : : /*
2146 : : * Reorder the current list of grouping sets into correct prefix
2147 : : * order. If only one aggregation pass is needed, try to make the
2148 : : * list match the ORDER BY clause; if more than one pass is needed, we
2149 : : * don't bother with that.
2150 : : *
2151 : : * Note that this reorders the sets from smallest-member-first to
2152 : : * largest-member-first, and applies the GroupingSetData annotations,
2153 : : * though the data will be filled in later.
2154 : : */
2155 [ + + ]: 605 : current_sets = reorder_grouping_sets(current_sets,
2156 : 605 : (list_length(sets) == 1
2157 : : ? parse->sortClause
2158 : : : NIL));
2159 : :
2160 : : /*
2161 : : * Get the initial (and therefore largest) grouping set.
2162 : : */
2413 tgl@sss.pgh.pa.us 2163 : 605 : gs = linitial_node(GroupingSetData, current_sets);
2164 : :
2165 : : /*
2166 : : * Order the groupClause appropriately. If the first grouping set is
2167 : : * empty, then the groupClause must also be empty; otherwise we have
2168 : : * to force the groupClause to match that grouping set's order.
2169 : : *
2170 : : * (The first grouping set can be empty even though parse->groupClause
2171 : : * is not empty only if all non-empty grouping sets are unsortable.
2172 : : * The groupClauses for hashed grouping sets are built later on.)
2173 : : */
2575 rhodiumtoad@postgres 2174 [ + + ]: 605 : if (gs->set)
84 akorotkov@postgresql 2175 :GNC 584 : rollup->groupClause = groupclause_apply_groupingset(root, gs->set);
2176 : : else
2575 rhodiumtoad@postgres 2177 :CBC 21 : rollup->groupClause = NIL;
2178 : :
2179 : : /*
2180 : : * Is it hashable? We pretend empty sets are hashable even though we
2181 : : * actually force them not to be hashed later. But don't bother if
2182 : : * there's nothing but empty sets (since in that case we can't hash
2183 : : * anything).
2184 : : */
2185 [ + + ]: 605 : if (gs->set &&
2186 [ + + ]: 584 : !bms_overlap_list(gd->unhashable_refs, gs->set))
2187 : : {
2188 : 572 : rollup->hashable = true;
2189 : 572 : gd->any_hashable = true;
2190 : : }
2191 : :
2192 : : /*
2193 : : * Now that we've pinned down an order for the groupClause for this
2194 : : * list of grouping sets, we need to remap the entries in the grouping
2195 : : * sets from sortgrouprefs to plain indices (0-based) into the
2196 : : * groupClause for this collection of grouping sets. We keep the
2197 : : * original form for later use, though.
2198 : : */
2199 : 605 : rollup->gsets = remap_to_groupclause_idx(rollup->groupClause,
2200 : : current_sets,
2201 : : gd->tleref_to_colnum_map);
2202 : 605 : rollup->gsets_data = current_sets;
2203 : :
2204 : 605 : gd->rollups = lappend(gd->rollups, rollup);
2205 : : }
2206 : :
2207 [ + + ]: 364 : if (gd->unsortable_sets)
2208 : : {
2209 : : /*
2210 : : * We have not yet pinned down a groupclause for this, but we will
2211 : : * need index-based lists for estimation purposes. Construct
2212 : : * hash_sets_idx based on the entire original groupclause for now.
2213 : : */
2214 : 18 : gd->hash_sets_idx = remap_to_groupclause_idx(parse->groupClause,
2215 : : gd->unsortable_sets,
2216 : : gd->tleref_to_colnum_map);
2217 : 18 : gd->any_hashable = true;
2218 : : }
2219 : :
2220 : 364 : return gd;
2221 : : }
2222 : :
2223 : : /*
2224 : : * Given a groupclause and a list of GroupingSetData, return equivalent sets
2225 : : * (without annotation) mapped to indexes into the given groupclause.
2226 : : */
2227 : : static List *
2228 : 1794 : remap_to_groupclause_idx(List *groupClause,
2229 : : List *gsets,
2230 : : int *tleref_to_colnum_map)
2231 : : {
2232 : 1794 : int ref = 0;
2233 : 1794 : List *result = NIL;
2234 : : ListCell *lc;
2235 : :
2236 [ + + + + : 4460 : foreach(lc, groupClause)
+ + ]
2237 : : {
2413 tgl@sss.pgh.pa.us 2238 : 2666 : SortGroupClause *gc = lfirst_node(SortGroupClause, lc);
2239 : :
2575 rhodiumtoad@postgres 2240 : 2666 : tleref_to_colnum_map[gc->tleSortGroupRef] = ref++;
2241 : : }
2242 : :
2243 [ + - + + : 4191 : foreach(lc, gsets)
+ + ]
2244 : : {
2245 : 2397 : List *set = NIL;
2246 : : ListCell *lc2;
2413 tgl@sss.pgh.pa.us 2247 : 2397 : GroupingSetData *gs = lfirst_node(GroupingSetData, lc);
2248 : :
2575 rhodiumtoad@postgres 2249 [ + + + + : 5452 : foreach(lc2, gs->set)
+ + ]
2250 : : {
2251 : 3055 : set = lappend_int(set, tleref_to_colnum_map[lfirst_int(lc2)]);
2252 : : }
2253 : :
2254 : 2397 : result = lappend(result, set);
2255 : : }
2256 : :
2257 : 1794 : return result;
2258 : : }
2259 : :
2260 : :
2261 : : /*
2262 : : * preprocess_rowmarks - set up PlanRowMarks if needed
2263 : : */
2264 : : static void
5284 tgl@sss.pgh.pa.us 2265 : 247662 : preprocess_rowmarks(PlannerInfo *root)
2266 : : {
2267 : 247662 : Query *parse = root->parse;
2268 : : Bitmapset *rels;
2269 : : List *prowmarks;
2270 : : ListCell *l;
2271 : : int i;
2272 : :
2273 [ + + ]: 247662 : if (parse->rowMarks)
2274 : : {
2275 : : /*
2276 : : * We've got trouble if FOR [KEY] UPDATE/SHARE appears inside
2277 : : * grouping, since grouping renders a reference to individual tuple
2278 : : * CTIDs invalid. This is also checked at parse time, but that's
2279 : : * insufficient because of rule substitution, query pullup, etc.
2280 : : */
2413 2281 : 3812 : CheckSelectLocking(parse, linitial_node(RowMarkClause,
2282 : : parse->rowMarks)->strength);
2283 : : }
2284 : : else
2285 : : {
2286 : : /*
2287 : : * We only need rowmarks for UPDATE, DELETE, MERGE, or FOR [KEY]
2288 : : * UPDATE/SHARE.
2289 : : */
5284 2290 [ + + ]: 243850 : if (parse->commandType != CMD_UPDATE &&
197 dean.a.rasheed@gmail 2291 [ + + ]: 237173 : parse->commandType != CMD_DELETE &&
2292 [ + + ]: 235056 : parse->commandType != CMD_MERGE)
5284 tgl@sss.pgh.pa.us 2293 : 234204 : return;
2294 : : }
2295 : :
2296 : : /*
2297 : : * We need to have rowmarks for all base relations except the target. We
2298 : : * make a bitmapset of all base rels and then remove the items we don't
2299 : : * need or have FOR [KEY] UPDATE/SHARE marks for.
2300 : : */
440 2301 : 13458 : rels = get_relids_in_jointree((Node *) parse->jointree, false, false);
5284 2302 [ + + ]: 13458 : if (parse->resultRelation)
2303 : 9646 : rels = bms_del_member(rels, parse->resultRelation);
2304 : :
2305 : : /*
2306 : : * Convert RowMarkClauses to PlanRowMark representation.
2307 : : */
2308 : 13458 : prowmarks = NIL;
2309 [ + + + + : 17401 : foreach(l, parse->rowMarks)
+ + ]
2310 : : {
2413 2311 : 3943 : RowMarkClause *rc = lfirst_node(RowMarkClause, l);
5282 2312 : 3943 : RangeTblEntry *rte = rt_fetch(rc->rti, parse->rtable);
2313 : : PlanRowMark *newrc;
2314 : :
2315 : : /*
2316 : : * Currently, it is syntactically impossible to have FOR UPDATE et al
2317 : : * applied to an update/delete target rel. If that ever becomes
2318 : : * possible, we should drop the target from the PlanRowMark list.
2319 : : */
5284 2320 [ - + ]: 3943 : Assert(rc->rti != parse->resultRelation);
2321 : :
2322 : : /*
2323 : : * Ignore RowMarkClauses for subqueries; they aren't real tables and
2324 : : * can't support true locking. Subqueries that got flattened into the
2325 : : * main query should be ignored completely. Any that didn't will get
2326 : : * ROW_MARK_COPY items in the next loop.
2327 : : */
5282 2328 [ + + ]: 3943 : if (rte->rtekind != RTE_RELATION)
2329 : 54 : continue;
2330 : :
5284 2331 : 3889 : rels = bms_del_member(rels, rc->rti);
2332 : :
5282 2333 : 3889 : newrc = makeNode(PlanRowMark);
5284 2334 : 3889 : newrc->rti = newrc->prti = rc->rti;
4813 2335 : 3889 : newrc->rowmarkId = ++(root->glob->lastRowMarkId);
3311 2336 : 3889 : newrc->markType = select_rowmark_type(rte, rc->strength);
3318 2337 : 3889 : newrc->allMarkTypes = (1 << newrc->markType);
2338 : 3889 : newrc->strength = rc->strength;
3477 alvherre@alvh.no-ip. 2339 : 3889 : newrc->waitPolicy = rc->waitPolicy;
5284 tgl@sss.pgh.pa.us 2340 : 3889 : newrc->isParent = false;
2341 : :
2342 : 3889 : prowmarks = lappend(prowmarks, newrc);
2343 : : }
2344 : :
2345 : : /*
2346 : : * Now, add rowmarks for any non-target, non-locked base relations.
2347 : : */
2348 : 13458 : i = 0;
2349 [ + - + + : 32044 : foreach(l, parse->rtable)
+ + ]
2350 : : {
2413 2351 : 18586 : RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
2352 : : PlanRowMark *newrc;
2353 : :
5284 2354 : 18586 : i++;
2355 [ + + ]: 18586 : if (!bms_is_member(i, rels))
2356 : 16928 : continue;
2357 : :
2358 : 1658 : newrc = makeNode(PlanRowMark);
2359 : 1658 : newrc->rti = newrc->prti = i;
4813 2360 : 1658 : newrc->rowmarkId = ++(root->glob->lastRowMarkId);
3311 2361 : 1658 : newrc->markType = select_rowmark_type(rte, LCS_NONE);
3318 2362 : 1658 : newrc->allMarkTypes = (1 << newrc->markType);
2363 : 1658 : newrc->strength = LCS_NONE;
2489 2364 : 1658 : newrc->waitPolicy = LockWaitBlock; /* doesn't matter */
5284 2365 : 1658 : newrc->isParent = false;
2366 : :
2367 : 1658 : prowmarks = lappend(prowmarks, newrc);
2368 : : }
2369 : :
2370 : 13458 : root->rowMarks = prowmarks;
2371 : : }
2372 : :
2373 : : /*
2374 : : * Select RowMarkType to use for a given table
2375 : : */
2376 : : RowMarkType
3311 2377 : 6611 : select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength)
2378 : : {
2379 [ + + ]: 6611 : if (rte->rtekind != RTE_RELATION)
2380 : : {
2381 : : /* If it's not a table at all, use ROW_MARK_COPY */
2382 : 640 : return ROW_MARK_COPY;
2383 : : }
2384 [ + + ]: 5971 : else if (rte->relkind == RELKIND_FOREIGN_TABLE)
2385 : : {
2386 : : /* Let the FDW select the rowmark type, if it wants to */
3260 2387 : 96 : FdwRoutine *fdwroutine = GetFdwRoutineByRelId(rte->relid);
2388 : :
2389 [ - + ]: 96 : if (fdwroutine->GetForeignRowMarkType != NULL)
3260 tgl@sss.pgh.pa.us 2390 :UBC 0 : return fdwroutine->GetForeignRowMarkType(rte, strength);
2391 : : /* Otherwise, use ROW_MARK_COPY by default */
3311 tgl@sss.pgh.pa.us 2392 :CBC 96 : return ROW_MARK_COPY;
2393 : : }
2394 : : else
2395 : : {
2396 : : /* Regular table, apply the appropriate lock type */
2397 [ + + + + : 5875 : switch (strength)
+ - ]
2398 : : {
2399 : 1116 : case LCS_NONE:
2400 : :
2401 : : /*
2402 : : * We don't need a tuple lock, only the ability to re-fetch
2403 : : * the row.
2404 : : */
2405 : 1116 : return ROW_MARK_REFERENCE;
2406 : : break;
2407 : 3851 : case LCS_FORKEYSHARE:
2408 : 3851 : return ROW_MARK_KEYSHARE;
2409 : : break;
2410 : 150 : case LCS_FORSHARE:
2411 : 150 : return ROW_MARK_SHARE;
2412 : : break;
2413 : 31 : case LCS_FORNOKEYUPDATE:
2414 : 31 : return ROW_MARK_NOKEYEXCLUSIVE;
2415 : : break;
2416 : 727 : case LCS_FORUPDATE:
2417 : 727 : return ROW_MARK_EXCLUSIVE;
2418 : : break;
2419 : : }
3311 tgl@sss.pgh.pa.us 2420 [ # # ]:UBC 0 : elog(ERROR, "unrecognized LockClauseStrength %d", (int) strength);
2421 : : return ROW_MARK_EXCLUSIVE; /* keep compiler quiet */
2422 : : }
2423 : : }
2424 : :
2425 : : /*
2426 : : * preprocess_limit - do pre-estimation for LIMIT and/or OFFSET clauses
2427 : : *
2428 : : * We try to estimate the values of the LIMIT/OFFSET clauses, and pass the
2429 : : * results back in *count_est and *offset_est. These variables are set to
2430 : : * 0 if the corresponding clause is not present, and -1 if it's present
2431 : : * but we couldn't estimate the value for it. (The "0" convention is OK
2432 : : * for OFFSET but a little bit bogus for LIMIT: effectively we estimate
2433 : : * LIMIT 0 as though it were LIMIT 1. But this is in line with the planner's
2434 : : * usual practice of never estimating less than one row.) These values will
2435 : : * be passed to create_limit_path, which see if you change this code.
2436 : : *
2437 : : * The return value is the suitably adjusted tuple_fraction to use for
2438 : : * planning the query. This adjustment is not overridable, since it reflects
2439 : : * plan actions that grouping_planner() will certainly take, not assumptions
2440 : : * about context.
2441 : : */
2442 : : static double
6814 tgl@sss.pgh.pa.us 2443 :CBC 2314 : preprocess_limit(PlannerInfo *root, double tuple_fraction,
2444 : : int64 *offset_est, int64 *count_est)
2445 : : {
6883 2446 : 2314 : Query *parse = root->parse;
2447 : : Node *est;
2448 : : double limit_fraction;
2449 : :
2450 : : /* Should not be called unless LIMIT or OFFSET */
6814 2451 [ + + - + ]: 2314 : Assert(parse->limitCount || parse->limitOffset);
2452 : :
2453 : : /*
2454 : : * Try to obtain the clause values. We use estimate_expression_value
2455 : : * primarily because it can sometimes do something useful with Params.
2456 : : */
2457 [ + + ]: 2314 : if (parse->limitCount)
2458 : : {
6264 2459 : 2082 : est = estimate_expression_value(root, parse->limitCount);
6814 2460 [ + - + + ]: 2082 : if (est && IsA(est, Const))
2461 : : {
2462 [ - + ]: 2079 : if (((Const *) est)->constisnull)
2463 : : {
2464 : : /* NULL indicates LIMIT ALL, ie, no limit */
6756 bruce@momjian.us 2465 :UBC 0 : *count_est = 0; /* treat as not present */
2466 : : }
2467 : : else
2468 : : {
6472 bruce@momjian.us 2469 :CBC 2079 : *count_est = DatumGetInt64(((Const *) est)->constvalue);
6814 tgl@sss.pgh.pa.us 2470 [ + + ]: 2079 : if (*count_est <= 0)
2489 2471 : 75 : *count_est = 1; /* force to at least 1 */
2472 : : }
2473 : : }
2474 : : else
6814 2475 : 3 : *count_est = -1; /* can't estimate */
2476 : : }
2477 : : else
2478 : 232 : *count_est = 0; /* not present */
2479 : :
2480 [ + + ]: 2314 : if (parse->limitOffset)
2481 : : {
6264 2482 : 412 : est = estimate_expression_value(root, parse->limitOffset);
6814 2483 [ + - + + ]: 412 : if (est && IsA(est, Const))
2484 : : {
2485 [ - + ]: 400 : if (((Const *) est)->constisnull)
2486 : : {
2487 : : /* Treat NULL as no offset; the executor will too */
6756 bruce@momjian.us 2488 :UBC 0 : *offset_est = 0; /* treat as not present */
2489 : : }
2490 : : else
2491 : : {
6472 bruce@momjian.us 2492 :CBC 400 : *offset_est = DatumGetInt64(((Const *) est)->constvalue);
6814 tgl@sss.pgh.pa.us 2493 [ - + ]: 400 : if (*offset_est < 0)
3554 tgl@sss.pgh.pa.us 2494 :UBC 0 : *offset_est = 0; /* treat as not present */
2495 : : }
2496 : : }
2497 : : else
6814 tgl@sss.pgh.pa.us 2498 :CBC 12 : *offset_est = -1; /* can't estimate */
2499 : : }
2500 : : else
2501 : 1902 : *offset_est = 0; /* not present */
2502 : :
2503 [ + + ]: 2314 : if (*count_est != 0)
2504 : : {
2505 : : /*
2506 : : * A LIMIT clause limits the absolute number of tuples returned.
2507 : : * However, if it's not a constant LIMIT then we have to guess; for
2508 : : * lack of a better idea, assume 10% of the plan's result is wanted.
2509 : : */
2510 [ + + + + ]: 2082 : if (*count_est < 0 || *offset_est < 0)
2511 : : {
2512 : : /* LIMIT or OFFSET is an expression ... punt ... */
2513 : 12 : limit_fraction = 0.10;
2514 : : }
2515 : : else
2516 : : {
2517 : : /* LIMIT (plus OFFSET, if any) is max number of tuples needed */
2518 : 2070 : limit_fraction = (double) *count_est + (double) *offset_est;
2519 : : }
2520 : :
2521 : : /*
2522 : : * If we have absolute limits from both caller and LIMIT, use the
2523 : : * smaller value; likewise if they are both fractional. If one is
2524 : : * fractional and the other absolute, we can't easily determine which
2525 : : * is smaller, but we use the heuristic that the absolute will usually
2526 : : * be smaller.
2527 : : */
6883 2528 [ + + ]: 2082 : if (tuple_fraction >= 1.0)
2529 : : {
2530 [ + - ]: 3 : if (limit_fraction >= 1.0)
2531 : : {
2532 : : /* both absolute */
2533 [ - + ]: 3 : tuple_fraction = Min(tuple_fraction, limit_fraction);
2534 : : }
2535 : : else
2536 : : {
2537 : : /* caller absolute, limit fractional; use caller's value */
2538 : : }
2539 : : }
2540 [ + + ]: 2079 : else if (tuple_fraction > 0.0)
2541 : : {
2542 [ + - ]: 72 : if (limit_fraction >= 1.0)
2543 : : {
2544 : : /* caller fractional, limit absolute; use limit */
6814 2545 : 72 : tuple_fraction = limit_fraction;
2546 : : }
2547 : : else
2548 : : {
2549 : : /* both fractional */
6814 tgl@sss.pgh.pa.us 2550 [ # # ]:UBC 0 : tuple_fraction = Min(tuple_fraction, limit_fraction);
2551 : : }
2552 : : }
2553 : : else
2554 : : {
2555 : : /* no info from caller, just use limit */
6883 tgl@sss.pgh.pa.us 2556 :CBC 2007 : tuple_fraction = limit_fraction;
2557 : : }
2558 : : }
6814 2559 [ + + + + ]: 232 : else if (*offset_est != 0 && tuple_fraction > 0.0)
2560 : : {
2561 : : /*
2562 : : * We have an OFFSET but no LIMIT. This acts entirely differently
2563 : : * from the LIMIT case: here, we need to increase rather than decrease
2564 : : * the caller's tuple_fraction, because the OFFSET acts to cause more
2565 : : * tuples to be fetched instead of fewer. This only matters if we got
2566 : : * a tuple_fraction > 0, however.
2567 : : *
2568 : : * As above, use 10% if OFFSET is present but unestimatable.
2569 : : */
2570 [ - + ]: 6 : if (*offset_est < 0)
6814 tgl@sss.pgh.pa.us 2571 :UBC 0 : limit_fraction = 0.10;
2572 : : else
6814 tgl@sss.pgh.pa.us 2573 :CBC 6 : limit_fraction = (double) *offset_est;
2574 : :
2575 : : /*
2576 : : * If we have absolute counts from both caller and OFFSET, add them
2577 : : * together; likewise if they are both fractional. If one is
2578 : : * fractional and the other absolute, we want to take the larger, and
2579 : : * we heuristically assume that's the fractional one.
2580 : : */
2581 [ - + ]: 6 : if (tuple_fraction >= 1.0)
2582 : : {
6814 tgl@sss.pgh.pa.us 2583 [ # # ]:UBC 0 : if (limit_fraction >= 1.0)
2584 : : {
2585 : : /* both absolute, so add them together */
2586 : 0 : tuple_fraction += limit_fraction;
2587 : : }
2588 : : else
2589 : : {
2590 : : /* caller absolute, limit fractional; use limit */
2591 : 0 : tuple_fraction = limit_fraction;
2592 : : }
2593 : : }
2594 : : else
2595 : : {
6814 tgl@sss.pgh.pa.us 2596 [ - + ]:CBC 6 : if (limit_fraction >= 1.0)
2597 : : {
2598 : : /* caller fractional, limit absolute; use caller's value */
2599 : : }
2600 : : else
2601 : : {
2602 : : /* both fractional, so add them together */
6814 tgl@sss.pgh.pa.us 2603 :UBC 0 : tuple_fraction += limit_fraction;
2604 [ # # ]: 0 : if (tuple_fraction >= 1.0)
2489 2605 : 0 : tuple_fraction = 0.0; /* assume fetch all */
2606 : : }
2607 : : }
2608 : : }
2609 : :
6883 tgl@sss.pgh.pa.us 2610 :CBC 2314 : return tuple_fraction;
2611 : : }
2612 : :
2613 : : /*
2614 : : * limit_needed - do we actually need a Limit plan node?
2615 : : *
2616 : : * If we have constant-zero OFFSET and constant-null LIMIT, we can skip adding
2617 : : * a Limit node. This is worth checking for because "OFFSET 0" is a common
2618 : : * locution for an optimization fence. (Because other places in the planner
2619 : : * merely check whether parse->limitOffset isn't NULL, it will still work as
2620 : : * an optimization fence --- we're just suppressing unnecessary run-time
2621 : : * overhead.)
2622 : : *
2623 : : * This might look like it could be merged into preprocess_limit, but there's
2624 : : * a key distinction: here we need hard constants in OFFSET/LIMIT, whereas
2625 : : * in preprocess_limit it's good enough to consider estimated values.
2626 : : */
2627 : : bool
4049 2628 : 512158 : limit_needed(Query *parse)
2629 : : {
2630 : : Node *node;
2631 : :
2632 : 512158 : node = parse->limitCount;
2633 [ + + ]: 512158 : if (node)
2634 : : {
2635 [ + + ]: 4966 : if (IsA(node, Const))
2636 : : {
2637 : : /* NULL indicates LIMIT ALL, ie, no limit */
2638 [ + - ]: 4870 : if (!((Const *) node)->constisnull)
2639 : 4870 : return true; /* LIMIT with a constant value */
2640 : : }
2641 : : else
2642 : 96 : return true; /* non-constant LIMIT */
2643 : : }
2644 : :
2645 : 507192 : node = parse->limitOffset;
2646 [ + + ]: 507192 : if (node)
2647 : : {
2648 [ + + ]: 688 : if (IsA(node, Const))
2649 : : {
2650 : : /* Treat NULL as no offset; the executor would too */
2651 [ + - ]: 543 : if (!((Const *) node)->constisnull)
2652 : : {
3973 bruce@momjian.us 2653 : 543 : int64 offset = DatumGetInt64(((Const *) node)->constvalue);
2654 : :
3554 tgl@sss.pgh.pa.us 2655 [ + + ]: 543 : if (offset != 0)
2656 : 42 : return true; /* OFFSET with a nonzero value */
2657 : : }
2658 : : }
2659 : : else
4049 2660 : 145 : return true; /* non-constant OFFSET */
2661 : : }
2662 : :
2663 : 507005 : return false; /* don't need a Limit plan node */
2664 : : }
2665 : :
2666 : :
2667 : : /*
2668 : : * remove_useless_groupby_columns
2669 : : * Remove any columns in the GROUP BY clause that are redundant due to
2670 : : * being functionally dependent on other GROUP BY columns.
2671 : : *
2672 : : * Since some other DBMSes do not allow references to ungrouped columns, it's
2673 : : * not unusual to find all columns listed in GROUP BY even though listing the
2674 : : * primary-key columns would be sufficient. Deleting such excess columns
2675 : : * avoids redundant sorting work, so it's worth doing.
2676 : : *
2677 : : * Relcache invalidations will ensure that cached plans become invalidated
2678 : : * when the underlying index of the pkey constraint is dropped.
2679 : : *
2680 : : * Currently, we only make use of pkey constraints for this, however, we may
2681 : : * wish to take this further in the future and also use unique constraints
2682 : : * which have NOT NULL columns. In that case, plan invalidation will still
2683 : : * work since relations will receive a relcache invalidation when a NOT NULL
2684 : : * constraint is dropped.
2685 : : */
2686 : : static void
2985 2687 : 1683 : remove_useless_groupby_columns(PlannerInfo *root)
2688 : : {
2689 : 1683 : Query *parse = root->parse;
2690 : : Bitmapset **groupbyattnos;
2691 : : Bitmapset **surplusvars;
2692 : : ListCell *lc;
2693 : : int relid;
2694 : :
2695 : : /* No chance to do anything if there are less than two GROUP BY items */
452 2696 [ + + ]: 1683 : if (list_length(root->processed_groupClause) < 2)
2985 2697 : 1045 : return;
2698 : :
2699 : : /* Don't fiddle with the GROUP BY clause if the query has grouping sets */
2700 [ - + ]: 638 : if (parse->groupingSets)
2985 tgl@sss.pgh.pa.us 2701 :UBC 0 : return;
2702 : :
2703 : : /*
2704 : : * Scan the GROUP BY clause to find GROUP BY items that are simple Vars.
2705 : : * Fill groupbyattnos[k] with a bitmapset of the column attnos of RTE k
2706 : : * that are GROUP BY items.
2707 : : */
2985 tgl@sss.pgh.pa.us 2708 :CBC 638 : groupbyattnos = (Bitmapset **) palloc0(sizeof(Bitmapset *) *
2709 : 638 : (list_length(parse->rtable) + 1));
452 2710 [ + - + + : 2281 : foreach(lc, root->processed_groupClause)
+ + ]
2711 : : {
2413 2712 : 1643 : SortGroupClause *sgc = lfirst_node(SortGroupClause, lc);
2985 2713 : 1643 : TargetEntry *tle = get_sortgroupclause_tle(sgc, parse->targetList);
2714 : 1643 : Var *var = (Var *) tle->expr;
2715 : :
2716 : : /*
2717 : : * Ignore non-Vars and Vars from other query levels.
2718 : : *
2719 : : * XXX in principle, stable expressions containing Vars could also be
2720 : : * removed, if all the Vars are functionally dependent on other GROUP
2721 : : * BY items. But it's not clear that such cases occur often enough to
2722 : : * be worth troubling over.
2723 : : */
2724 [ + + ]: 1643 : if (!IsA(var, Var) ||
2725 [ - + ]: 1207 : var->varlevelsup > 0)
2726 : 436 : continue;
2727 : :
2728 : : /* OK, remember we have this Var */
2729 : 1207 : relid = var->varno;
2730 [ - + ]: 1207 : Assert(relid <= list_length(parse->rtable));
2731 : 1207 : groupbyattnos[relid] = bms_add_member(groupbyattnos[relid],
2489 2732 : 1207 : var->varattno - FirstLowInvalidHeapAttributeNumber);
2733 : : }
2734 : :
2735 : : /*
2736 : : * Consider each relation and see if it is possible to remove some of its
2737 : : * Vars from GROUP BY. For simplicity and speed, we do the actual removal
2738 : : * in a separate pass. Here, we just fill surplusvars[k] with a bitmapset
2739 : : * of the column attnos of RTE k that are removable GROUP BY items.
2740 : : */
2985 2741 : 638 : surplusvars = NULL; /* don't allocate array unless required */
2742 : 638 : relid = 0;
2743 [ + - + + : 1751 : foreach(lc, parse->rtable)
+ + ]
2744 : : {
2413 2745 : 1113 : RangeTblEntry *rte = lfirst_node(RangeTblEntry, lc);
2746 : : Bitmapset *relattnos;
2747 : : Bitmapset *pkattnos;
2748 : : Oid constraintOid;
2749 : :
2985 2750 : 1113 : relid++;
2751 : :
2752 : : /* Only plain relations could have primary-key constraints */
2753 [ + + ]: 1113 : if (rte->rtekind != RTE_RELATION)
2754 : 1022 : continue;
2755 : :
2756 : : /*
2757 : : * We must skip inheritance parent tables as some of the child rels
2758 : : * may cause duplicate rows. This cannot happen with partitioned
2759 : : * tables, however.
2760 : : */
1747 drowley@postgresql.o 2761 [ + + + + ]: 826 : if (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE)
2762 : 9 : continue;
2763 : :
2764 : : /* Nothing to do unless this rel has multiple Vars in GROUP BY */
2985 tgl@sss.pgh.pa.us 2765 : 817 : relattnos = groupbyattnos[relid];
2766 [ + + ]: 817 : if (bms_membership(relattnos) != BMS_MULTIPLE)
2767 : 437 : continue;
2768 : :
2769 : : /*
2770 : : * Can't remove any columns for this rel if there is no suitable
2771 : : * (i.e., nondeferrable) primary key constraint.
2772 : : */
2773 : 380 : pkattnos = get_primary_key_attnos(rte->relid, false, &constraintOid);
2774 [ + + ]: 380 : if (pkattnos == NULL)
2775 : 289 : continue;
2776 : :
2777 : : /*
2778 : : * If the primary key is a proper subset of relattnos then we have
2779 : : * some items in the GROUP BY that can be removed.
2780 : : */
2781 [ + + ]: 91 : if (bms_subset_compare(pkattnos, relattnos) == BMS_SUBSET1)
2782 : : {
2783 : : /*
2784 : : * To easily remember whether we've found anything to do, we don't
2785 : : * allocate the surplusvars[] array until we find something.
2786 : : */
2787 [ + + ]: 82 : if (surplusvars == NULL)
2788 : 79 : surplusvars = (Bitmapset **) palloc0(sizeof(Bitmapset *) *
2489 2789 : 79 : (list_length(parse->rtable) + 1));
2790 : :
2791 : : /* Remember the attnos of the removable columns */
2985 2792 : 82 : surplusvars[relid] = bms_difference(relattnos, pkattnos);
2793 : : }
2794 : : }
2795 : :
2796 : : /*
2797 : : * If we found any surplus Vars, build a new GROUP BY clause without them.
2798 : : * (Note: this may leave some TLEs with unreferenced ressortgroupref
2799 : : * markings, but that's harmless.)
2800 : : */
2801 [ + + ]: 638 : if (surplusvars != NULL)
2802 : : {
2803 : 79 : List *new_groupby = NIL;
2804 : :
452 2805 [ + - + + : 339 : foreach(lc, root->processed_groupClause)
+ + ]
2806 : : {
2413 2807 : 260 : SortGroupClause *sgc = lfirst_node(SortGroupClause, lc);
2985 2808 : 260 : TargetEntry *tle = get_sortgroupclause_tle(sgc, parse->targetList);
2809 : 260 : Var *var = (Var *) tle->expr;
2810 : :
2811 : : /*
2812 : : * New list must include non-Vars, outer Vars, and anything not
2813 : : * marked as surplus.
2814 : : */
2815 [ + - ]: 260 : if (!IsA(var, Var) ||
2816 [ + - ]: 260 : var->varlevelsup > 0 ||
2489 2817 [ + + ]: 260 : !bms_is_member(var->varattno - FirstLowInvalidHeapAttributeNumber,
2818 : 260 : surplusvars[var->varno]))
2985 2819 : 163 : new_groupby = lappend(new_groupby, sgc);
2820 : : }
2821 : :
452 2822 : 79 : root->processed_groupClause = new_groupby;
2823 : : }
2824 : : }
2825 : :
2826 : : /*
2827 : : * groupclause_apply_groupingset
2828 : : * Apply the order of GROUP BY clauses defined by grouping sets. Items
2829 : : * not in the grouping set are skipped.
2830 : : */
2831 : : static List *
84 akorotkov@postgresql 2832 :GNC 1755 : groupclause_apply_groupingset(PlannerInfo *root, List *gset)
2833 : : {
5734 tgl@sss.pgh.pa.us 2834 :CBC 1755 : Query *parse = root->parse;
3256 andres@anarazel.de 2835 : 1755 : List *new_groupclause = NIL;
2836 : : ListCell *sl;
2837 : :
84 akorotkov@postgresql 2838 [ + - + + :GNC 4382 : foreach(sl, gset)
+ + ]
2839 : : {
2840 : 2627 : Index ref = lfirst_int(sl);
2841 : 2627 : SortGroupClause *cl = get_sortgroupref_clause(ref, parse->groupClause);
2842 : :
2843 : 2627 : new_groupclause = lappend(new_groupclause, cl);
2844 : : }
3256 andres@anarazel.de 2845 :CBC 1755 : return new_groupclause;
2846 : : }
2847 : :
2848 : : /*
2849 : : * Extract lists of grouping sets that can be implemented using a single
2850 : : * rollup-type aggregate pass each. Returns a list of lists of grouping sets.
2851 : : *
2852 : : * Input must be sorted with smallest sets first. Result has each sublist
2853 : : * sorted with smallest sets first.
2854 : : *
2855 : : * We want to produce the absolute minimum possible number of lists here to
2856 : : * avoid excess sorts. Fortunately, there is an algorithm for this; the problem
2857 : : * of finding the minimal partition of a partially-ordered set into chains
2858 : : * (which is what we need, taking the list of grouping sets as a poset ordered
2859 : : * by set inclusion) can be mapped to the problem of finding the maximum
2860 : : * cardinality matching on a bipartite graph, which is solvable in polynomial
2861 : : * time with a worst case of no worse than O(n^2.5) and usually much
2862 : : * better. Since our N is at most 4096, we don't need to consider fallbacks to
2863 : : * heuristic or approximate methods. (Planning time for a 12-d cube is under
2864 : : * half a second on my modest system even with optimization off and assertions
2865 : : * on.)
2866 : : */
2867 : : static List *
2868 : 361 : extract_rollup_sets(List *groupingSets)
2869 : : {
2870 : 361 : int num_sets_raw = list_length(groupingSets);
2871 : 361 : int num_empty = 0;
3249 bruce@momjian.us 2872 : 361 : int num_sets = 0; /* distinct sets */
3256 andres@anarazel.de 2873 : 361 : int num_chains = 0;
2874 : 361 : List *result = NIL;
2875 : : List **results;
2876 : : List **orig_sets;
2877 : : Bitmapset **set_masks;
2878 : : int *chains;
2879 : : short **adjacency;
2880 : : short *adjacency_buf;
2881 : : BipartiteMatchState *state;
2882 : : int i;
2883 : : int j;
2884 : : int j_size;
2885 : 361 : ListCell *lc1 = list_head(groupingSets);
2886 : : ListCell *lc;
2887 : :
2888 : : /*
2889 : : * Start by stripping out empty sets. The algorithm doesn't require this,
2890 : : * but the planner currently needs all empty sets to be returned in the
2891 : : * first list, so we strip them here and add them back after.
2892 : : */
2893 [ + + + + ]: 648 : while (lc1 && lfirst(lc1) == NIL)
2894 : : {
2895 : 287 : ++num_empty;
1735 tgl@sss.pgh.pa.us 2896 : 287 : lc1 = lnext(groupingSets, lc1);
2897 : : }
2898 : :
2899 : : /* bail out now if it turns out that all we had were empty sets. */
3256 andres@anarazel.de 2900 [ + + ]: 361 : if (!lc1)
2901 : 21 : return list_make1(groupingSets);
2902 : :
2903 : : /*----------
2904 : : * We don't strictly need to remove duplicate sets here, but if we don't,
2905 : : * they tend to become scattered through the result, which is a bit
2906 : : * confusing (and irritating if we ever decide to optimize them out).
2907 : : * So we remove them here and add them back after.
2908 : : *
2909 : : * For each non-duplicate set, we fill in the following:
2910 : : *
2911 : : * orig_sets[i] = list of the original set lists
2912 : : * set_masks[i] = bitmapset for testing inclusion
2913 : : * adjacency[i] = array [n, v1, v2, ... vn] of adjacency indices
2914 : : *
2915 : : * chains[i] will be the result group this set is assigned to.
2916 : : *
2917 : : * We index all of these from 1 rather than 0 because it is convenient
2918 : : * to leave 0 free for the NIL node in the graph algorithm.
2919 : : *----------
2920 : : */
3249 bruce@momjian.us 2921 : 340 : orig_sets = palloc0((num_sets_raw + 1) * sizeof(List *));
3256 andres@anarazel.de 2922 : 340 : set_masks = palloc0((num_sets_raw + 1) * sizeof(Bitmapset *));
2923 : 340 : adjacency = palloc0((num_sets_raw + 1) * sizeof(short *));
2924 : 340 : adjacency_buf = palloc((num_sets_raw + 1) * sizeof(short));
2925 : :
2926 : 340 : j_size = 0;
2927 : 340 : j = 0;
2928 : 340 : i = 1;
2929 : :
1735 tgl@sss.pgh.pa.us 2930 [ + - + + : 1258 : for_each_cell(lc, groupingSets, lc1)
+ + ]
2931 : : {
2413 2932 : 918 : List *candidate = (List *) lfirst(lc);
3256 andres@anarazel.de 2933 : 918 : Bitmapset *candidate_set = NULL;
2934 : : ListCell *lc2;
2935 : 918 : int dup_of = 0;
2936 : :
2937 [ + - + + : 2253 : foreach(lc2, candidate)
+ + ]
2938 : : {
2939 : 1335 : candidate_set = bms_add_member(candidate_set, lfirst_int(lc2));
2940 : : }
2941 : :
2942 : : /* we can only be a dup if we're the same length as a previous set */
2943 [ + + ]: 918 : if (j_size == list_length(candidate))
2944 : : {
2945 : : int k;
2946 : :
2947 [ + + ]: 832 : for (k = j; k < i; ++k)
2948 : : {
2949 [ + + ]: 540 : if (bms_equal(set_masks[k], candidate_set))
2950 : : {
2951 : 79 : dup_of = k;
2952 : 79 : break;
2953 : : }
2954 : : }
2955 : : }
2956 [ + - ]: 547 : else if (j_size < list_length(candidate))
2957 : : {
2958 : 547 : j_size = list_length(candidate);
2959 : 547 : j = i;
2960 : : }
2961 : :
2962 [ + + ]: 918 : if (dup_of > 0)
2963 : : {
2964 : 79 : orig_sets[dup_of] = lappend(orig_sets[dup_of], candidate);
2965 : 79 : bms_free(candidate_set);
2966 : : }
2967 : : else
2968 : : {
2969 : : int k;
3249 bruce@momjian.us 2970 : 839 : int n_adj = 0;
2971 : :
3256 andres@anarazel.de 2972 : 839 : orig_sets[i] = list_make1(candidate);
2973 : 839 : set_masks[i] = candidate_set;
2974 : :
2975 : : /* fill in adjacency list; no need to compare equal-size sets */
2976 : :
2977 [ + + ]: 1445 : for (k = j - 1; k > 0; --k)
2978 : : {
2979 [ + + ]: 606 : if (bms_is_subset(set_masks[k], candidate_set))
2980 : 525 : adjacency_buf[++n_adj] = k;
2981 : : }
2982 : :
2983 [ + + ]: 839 : if (n_adj > 0)
2984 : : {
2985 : 269 : adjacency_buf[0] = n_adj;
2986 : 269 : adjacency[i] = palloc((n_adj + 1) * sizeof(short));
2987 : 269 : memcpy(adjacency[i], adjacency_buf, (n_adj + 1) * sizeof(short));
2988 : : }
2989 : : else
2990 : 570 : adjacency[i] = NULL;
2991 : :
2992 : 839 : ++i;
2993 : : }
2994 : : }
2995 : :
2996 : 340 : num_sets = i - 1;
2997 : :
2998 : : /*
2999 : : * Apply the graph matching algorithm to do the work.
3000 : : */
3001 : 340 : state = BipartiteMatch(num_sets, num_sets, adjacency);
3002 : :
3003 : : /*
3004 : : * Now, the state->pair* fields have the info we need to assign sets to
3005 : : * chains. Two sets (u,v) belong to the same chain if pair_uv[u] = v or
3006 : : * pair_vu[v] = u (both will be true, but we check both so that we can do
3007 : : * it in one pass)
3008 : : */
3009 : 340 : chains = palloc0((num_sets + 1) * sizeof(int));
3010 : :
3011 [ + + ]: 1179 : for (i = 1; i <= num_sets; ++i)
3012 : : {
3249 bruce@momjian.us 3013 : 839 : int u = state->pair_vu[i];
3014 : 839 : int v = state->pair_uv[i];
3015 : :
3256 andres@anarazel.de 3016 [ + + - + ]: 839 : if (u > 0 && u < i)
3256 andres@anarazel.de 3017 :UBC 0 : chains[i] = chains[u];
3256 andres@anarazel.de 3018 [ + + + - ]:CBC 839 : else if (v > 0 && v < i)
3019 : 255 : chains[i] = chains[v];
3020 : : else
3021 : 584 : chains[i] = ++num_chains;
3022 : : }
3023 : :
3024 : : /* build result lists. */
3249 bruce@momjian.us 3025 : 340 : results = palloc0((num_chains + 1) * sizeof(List *));
3026 : :
3256 andres@anarazel.de 3027 [ + + ]: 1179 : for (i = 1; i <= num_sets; ++i)
3028 : : {
3249 bruce@momjian.us 3029 : 839 : int c = chains[i];
3030 : :
3256 andres@anarazel.de 3031 [ - + ]: 839 : Assert(c > 0);
3032 : :
3033 : 839 : results[c] = list_concat(results[c], orig_sets[i]);
3034 : : }
3035 : :
3036 : : /* push any empty sets back on the first list. */
3037 [ + + ]: 582 : while (num_empty-- > 0)
3038 : 242 : results[1] = lcons(NIL, results[1]);
3039 : :
3040 : : /* make result list */
3041 [ + + ]: 924 : for (i = 1; i <= num_chains; ++i)
3042 : 584 : result = lappend(result, results[i]);
3043 : :
3044 : : /*
3045 : : * Free all the things.
3046 : : *
3047 : : * (This is over-fussy for small sets but for large sets we could have
3048 : : * tied up a nontrivial amount of memory.)
3049 : : */
3050 : 340 : BipartiteMatchFree(state);
3051 : 340 : pfree(results);
3052 : 340 : pfree(chains);
3053 [ + + ]: 1179 : for (i = 1; i <= num_sets; ++i)
3054 [ + + ]: 839 : if (adjacency[i])
3055 : 269 : pfree(adjacency[i]);
3056 : 340 : pfree(adjacency);
3057 : 340 : pfree(adjacency_buf);
3058 : 340 : pfree(orig_sets);
3059 [ + + ]: 1179 : for (i = 1; i <= num_sets; ++i)
3060 : 839 : bms_free(set_masks[i]);
3061 : 340 : pfree(set_masks);
3062 : :
3063 : 340 : return result;
3064 : : }
3065 : :
3066 : : /*
3067 : : * Reorder the elements of a list of grouping sets such that they have correct
3068 : : * prefix relationships. Also inserts the GroupingSetData annotations.
3069 : : *
3070 : : * The input must be ordered with smallest sets first; the result is returned
3071 : : * with largest sets first. Note that the result shares no list substructure
3072 : : * with the input, so it's safe for the caller to modify it later.
3073 : : *
3074 : : * If we're passed in a sortclause, we follow its order of columns to the
3075 : : * extent possible, to minimize the chance that we add unnecessary sorts.
3076 : : * (We're trying here to ensure that GROUPING SETS ((a,b,c),(c)) ORDER BY c,b,a
3077 : : * gets implemented in one pass.)
3078 : : */
3079 : : static List *
572 pg@bowt.ie 3080 : 605 : reorder_grouping_sets(List *groupingSets, List *sortclause)
3081 : : {
3082 : : ListCell *lc;
3256 andres@anarazel.de 3083 : 605 : List *previous = NIL;
3084 : 605 : List *result = NIL;
3085 : :
572 pg@bowt.ie 3086 [ + - + + : 1810 : foreach(lc, groupingSets)
+ + ]
3087 : : {
2413 tgl@sss.pgh.pa.us 3088 : 1205 : List *candidate = (List *) lfirst(lc);
3249 bruce@momjian.us 3089 : 1205 : List *new_elems = list_difference_int(candidate, previous);
2575 rhodiumtoad@postgres 3090 : 1205 : GroupingSetData *gs = makeNode(GroupingSetData);
3091 : :
1750 3092 [ + + + + ]: 1245 : while (list_length(sortclause) > list_length(previous) &&
3093 : : new_elems != NIL)
3094 : : {
3095 : 94 : SortGroupClause *sc = list_nth(sortclause, list_length(previous));
3096 : 94 : int ref = sc->tleSortGroupRef;
3097 : :
3098 [ + + ]: 94 : if (list_member_int(new_elems, ref))
3099 : : {
3100 : 40 : previous = lappend_int(previous, ref);
3101 : 40 : new_elems = list_delete_int(new_elems, ref);
3102 : : }
3103 : : else
3104 : : {
3105 : : /* diverged from the sortclause; give up on it */
3106 : 54 : sortclause = NIL;
3107 : 54 : break;
3108 : : }
3109 : : }
3110 : :
3111 : 1205 : previous = list_concat(previous, new_elems);
3112 : :
2575 3113 : 1205 : gs->set = list_copy(previous);
3114 : 1205 : result = lcons(gs, result);
3115 : : }
3116 : :
3256 andres@anarazel.de 3117 : 605 : list_free(previous);
3118 : :
3119 : 605 : return result;
3120 : : }
3121 : :
3122 : : /*
3123 : : * has_volatile_pathkey
3124 : : * Returns true if any PathKey in 'keys' has an EquivalenceClass
3125 : : * containing a volatile function. Otherwise returns false.
3126 : : */
3127 : : static bool
453 drowley@postgresql.o 3128 : 1110 : has_volatile_pathkey(List *keys)
3129 : : {
3130 : : ListCell *lc;
3131 : :
3132 [ + + + + : 2298 : foreach(lc, keys)
+ + ]
3133 : : {
3134 : 1197 : PathKey *pathkey = lfirst_node(PathKey, lc);
3135 : :
3136 [ + + ]: 1197 : if (pathkey->pk_eclass->ec_has_volatile)
3137 : 9 : return true;
3138 : : }
3139 : :
3140 : 1101 : return false;
3141 : : }
3142 : :
3143 : : /*
3144 : : * adjust_group_pathkeys_for_groupagg
3145 : : * Add pathkeys to root->group_pathkeys to reflect the best set of
3146 : : * pre-ordered input for ordered aggregates.
3147 : : *
3148 : : * We define "best" as the pathkeys that suit the largest number of
3149 : : * aggregate functions. We find these by looking at the first ORDER BY /
3150 : : * DISTINCT aggregate and take the pathkeys for that before searching for
3151 : : * other aggregates that require the same or a more strict variation of the
3152 : : * same pathkeys. We then repeat that process for any remaining aggregates
3153 : : * with different pathkeys and if we find another set of pathkeys that suits a
3154 : : * larger number of aggregates then we select those pathkeys instead.
3155 : : *
3156 : : * When the best pathkeys are found we also mark each Aggref that can use
3157 : : * those pathkeys as aggpresorted = true.
3158 : : *
3159 : : * Note: When an aggregate function's ORDER BY / DISTINCT clause contains any
3160 : : * volatile functions, we never make use of these pathkeys. We want to ensure
3161 : : * that sorts using volatile functions are done independently in each Aggref
3162 : : * rather than once at the query level. If we were to allow this then Aggrefs
3163 : : * with compatible sort orders would all transition their rows in the same
3164 : : * order if those pathkeys were deemed to be the best pathkeys to sort on.
3165 : : * Whereas, if some other set of Aggref's pathkeys happened to be deemed
3166 : : * better pathkeys to sort on, then the volatile function Aggrefs would be
3167 : : * left to perform their sorts individually. To avoid this inconsistent
3168 : : * behavior which could make Aggref results depend on what other Aggrefs the
3169 : : * query contains, we always force Aggrefs with volatile functions to perform
3170 : : * their own sorts.
3171 : : */
3172 : : static void
452 tgl@sss.pgh.pa.us 3173 : 900 : adjust_group_pathkeys_for_groupagg(PlannerInfo *root)
3174 : : {
3175 : 900 : List *grouppathkeys = root->group_pathkeys;
3176 : : List *bestpathkeys;
3177 : : Bitmapset *bestaggs;
3178 : : Bitmapset *unprocessed_aggs;
3179 : : ListCell *lc;
3180 : : int i;
3181 : :
3182 : : /* Shouldn't be here if there are grouping sets */
3183 [ - + ]: 900 : Assert(root->parse->groupingSets == NIL);
3184 : : /* Shouldn't be here unless there are some ordered aggregates */
3185 [ - + ]: 900 : Assert(root->numOrderedAggs > 0);
3186 : :
3187 : : /* Do nothing if disabled */
3188 [ + + ]: 900 : if (!enable_presorted_aggregate)
3189 : 3 : return;
3190 : :
3191 : : /*
3192 : : * Make a first pass over all AggInfos to collect a Bitmapset containing
3193 : : * the indexes of all AggInfos to be processed below.
3194 : : */
621 drowley@postgresql.o 3195 : 897 : unprocessed_aggs = NULL;
3196 [ + - + + : 2136 : foreach(lc, root->agginfos)
+ + ]
3197 : : {
3198 : 1239 : AggInfo *agginfo = lfirst_node(AggInfo, lc);
3199 : 1239 : Aggref *aggref = linitial_node(Aggref, agginfo->aggrefs);
3200 : :
3201 [ + + ]: 1239 : if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3202 : 132 : continue;
3203 : :
3204 : : /* only add aggregates with a DISTINCT or ORDER BY */
3205 [ + + + + ]: 1107 : if (aggref->aggdistinct != NIL || aggref->aggorder != NIL)
3206 : 957 : unprocessed_aggs = bms_add_member(unprocessed_aggs,
3207 : : foreach_current_index(lc));
3208 : : }
3209 : :
3210 : : /*
3211 : : * Now process all the unprocessed_aggs to find the best set of pathkeys
3212 : : * for the given set of aggregates.
3213 : : *
3214 : : * On the first outer loop here 'bestaggs' will be empty. We'll populate
3215 : : * this during the first loop using the pathkeys for the very first
3216 : : * AggInfo then taking any stronger pathkeys from any other AggInfos with
3217 : : * a more strict set of compatible pathkeys. Once the outer loop is
3218 : : * complete, we mark off all the aggregates with compatible pathkeys then
3219 : : * remove those from the unprocessed_aggs and repeat the process to try to
3220 : : * find another set of pathkeys that are suitable for a larger number of
3221 : : * aggregates. The outer loop will stop when there are not enough
3222 : : * unprocessed aggregates for it to be possible to find a set of pathkeys
3223 : : * to suit a larger number of aggregates.
3224 : : */
3225 : 897 : bestpathkeys = NIL;
3226 : 897 : bestaggs = NULL;
3227 [ + + ]: 1770 : while (bms_num_members(unprocessed_aggs) > bms_num_members(bestaggs))
3228 : : {
3229 : 873 : Bitmapset *aggindexes = NULL;
3230 : 873 : List *currpathkeys = NIL;
3231 : :
3232 : 873 : i = -1;
3233 [ + + ]: 1983 : while ((i = bms_next_member(unprocessed_aggs, i)) >= 0)
3234 : : {
3235 : 1110 : AggInfo *agginfo = list_nth_node(AggInfo, root->agginfos, i);
3236 : 1110 : Aggref *aggref = linitial_node(Aggref, agginfo->aggrefs);
3237 : : List *sortlist;
3238 : : List *pathkeys;
3239 : :
3240 [ + + ]: 1110 : if (aggref->aggdistinct != NIL)
3241 : 353 : sortlist = aggref->aggdistinct;
3242 : : else
3243 : 757 : sortlist = aggref->aggorder;
3244 : :
453 3245 : 1110 : pathkeys = make_pathkeys_for_sortclauses(root, sortlist,
3246 : : aggref->args);
3247 : :
3248 : : /*
3249 : : * Ignore Aggrefs which have volatile functions in their ORDER BY
3250 : : * or DISTINCT clause.
3251 : : */
3252 [ + + ]: 1110 : if (has_volatile_pathkey(pathkeys))
3253 : : {
3254 : 9 : unprocessed_aggs = bms_del_member(unprocessed_aggs, i);
3255 : 9 : continue;
3256 : : }
3257 : :
3258 : : /*
3259 : : * When not set yet, take the pathkeys from the first unprocessed
3260 : : * aggregate.
3261 : : */
621 3262 [ + + ]: 1101 : if (currpathkeys == NIL)
3263 : : {
453 3264 : 870 : currpathkeys = pathkeys;
3265 : :
3266 : : /* include the GROUP BY pathkeys, if they exist */
621 3267 [ + + ]: 870 : if (grouppathkeys != NIL)
3268 : 135 : currpathkeys = append_pathkeys(list_copy(grouppathkeys),
3269 : : currpathkeys);
3270 : :
3271 : : /* record that we found pathkeys for this aggregate */
3272 : 870 : aggindexes = bms_add_member(aggindexes, i);
3273 : : }
3274 : : else
3275 : : {
3276 : : /* now look for a stronger set of matching pathkeys */
3277 : :
3278 : : /* include the GROUP BY pathkeys, if they exist */
3279 [ + + ]: 231 : if (grouppathkeys != NIL)
3280 : 144 : pathkeys = append_pathkeys(list_copy(grouppathkeys),
3281 : : pathkeys);
3282 : :
3283 : : /* are 'pathkeys' compatible or better than 'currpathkeys'? */
3284 [ + + + - ]: 231 : switch (compare_pathkeys(currpathkeys, pathkeys))
3285 : : {
3286 : 6 : case PATHKEYS_BETTER2:
3287 : : /* 'pathkeys' are stronger, use these ones instead */
3288 : 6 : currpathkeys = pathkeys;
3289 : : /* FALLTHROUGH */
3290 : :
3291 : 36 : case PATHKEYS_BETTER1:
3292 : : /* 'pathkeys' are less strict */
3293 : : /* FALLTHROUGH */
3294 : :
3295 : : case PATHKEYS_EQUAL:
3296 : : /* mark this aggregate as covered by 'currpathkeys' */
3297 : 36 : aggindexes = bms_add_member(aggindexes, i);
3298 : 36 : break;
3299 : :
3300 : 195 : case PATHKEYS_DIFFERENT:
3301 : 195 : break;
3302 : : }
3303 : : }
3304 : : }
3305 : :
3306 : : /* remove the aggregates that we've just processed */
3307 : 873 : unprocessed_aggs = bms_del_members(unprocessed_aggs, aggindexes);
3308 : :
3309 : : /*
3310 : : * If this pass included more aggregates than the previous best then
3311 : : * use these ones as the best set.
3312 : : */
3313 [ + + ]: 873 : if (bms_num_members(aggindexes) > bms_num_members(bestaggs))
3314 : : {
3315 : 819 : bestaggs = aggindexes;
3316 : 819 : bestpathkeys = currpathkeys;
3317 : : }
3318 : : }
3319 : :
3320 : : /*
3321 : : * If we found any ordered aggregates, update root->group_pathkeys to add
3322 : : * the best set of aggregate pathkeys. Note that bestpathkeys includes
3323 : : * the original GROUP BY pathkeys already.
3324 : : */
452 tgl@sss.pgh.pa.us 3325 [ + + ]: 897 : if (bestpathkeys != NIL)
3326 : 795 : root->group_pathkeys = bestpathkeys;
3327 : :
3328 : : /*
3329 : : * Now that we've found the best set of aggregates we can set the
3330 : : * presorted flag to indicate to the executor that it needn't bother
3331 : : * performing a sort for these Aggrefs. We're able to do this now as
3332 : : * there's no chance of a Hash Aggregate plan as create_grouping_paths
3333 : : * will not mark the GROUP BY as GROUPING_CAN_USE_HASH due to the presence
3334 : : * of ordered aggregates.
3335 : : */
621 drowley@postgresql.o 3336 : 897 : i = -1;
3337 [ + + ]: 1737 : while ((i = bms_next_member(bestaggs, i)) >= 0)
3338 : : {
3339 : 840 : AggInfo *agginfo = list_nth_node(AggInfo, root->agginfos, i);
3340 : :
3341 [ + - + + : 1689 : foreach(lc, agginfo->aggrefs)
+ + ]
3342 : : {
3343 : 849 : Aggref *aggref = lfirst_node(Aggref, lc);
3344 : :
3345 : 849 : aggref->aggpresorted = true;
3346 : : }
3347 : : }
3348 : : }
3349 : :
3350 : : /*
3351 : : * Compute query_pathkeys and other pathkeys during plan generation
3352 : : */
3353 : : static void
4003 tgl@sss.pgh.pa.us 3354 : 243253 : standard_qp_callback(PlannerInfo *root, void *extra)
3355 : : {
3356 : 243253 : Query *parse = root->parse;
3357 : 243253 : standard_qp_extra *qp_extra = (standard_qp_extra *) extra;
1845 3358 : 243253 : List *tlist = root->processed_tlist;
4003 3359 : 243253 : List *activeWindows = qp_extra->activeWindows;
3360 : :
3361 : : /*
3362 : : * Calculate pathkeys that represent grouping/ordering and/or ordered
3363 : : * aggregate requirements.
3364 : : */
452 3365 [ + + ]: 243253 : if (qp_extra->gset_data)
3366 : : {
3367 : : /*
3368 : : * With grouping sets, just use the first RollupData's groupClause. We
3369 : : * don't make any effort to optimize grouping clauses when there are
3370 : : * grouping sets, nor can we combine aggregate ordering keys with
3371 : : * grouping.
3372 : : */
3373 : 364 : List *rollups = qp_extra->gset_data->rollups;
3374 [ + + ]: 364 : List *groupClause = (rollups ? linitial_node(RollupData, rollups)->groupClause : NIL);
3375 : :
3376 [ + - ]: 364 : if (grouping_is_sortable(groupClause))
3377 : : {
3378 : 364 : root->group_pathkeys = make_pathkeys_for_sortclauses(root,
3379 : : groupClause,
3380 : : tlist);
3381 : 364 : root->num_groupby_pathkeys = list_length(root->group_pathkeys);
3382 : : }
3383 : : else
3384 : : {
452 tgl@sss.pgh.pa.us 3385 :UBC 0 : root->group_pathkeys = NIL;
3386 : 0 : root->num_groupby_pathkeys = 0;
3387 : : }
3388 : : }
452 tgl@sss.pgh.pa.us 3389 [ + + + + ]:CBC 242889 : else if (parse->groupClause || root->numOrderedAggs > 0)
3390 : 2464 : {
3391 : : /*
3392 : : * With a plain GROUP BY list, we can remove any grouping items that
3393 : : * are proven redundant by EquivalenceClass processing. For example,
3394 : : * we can remove y given "WHERE x = y GROUP BY x, y". These aren't
3395 : : * especially common cases, but they're nearly free to detect. Note
3396 : : * that we remove redundant items from processed_groupClause but not
3397 : : * the original parse->groupClause.
3398 : : */
3399 : : bool sortable;
3400 : :
3401 : 2464 : root->group_pathkeys =
3402 : 2464 : make_pathkeys_for_sortclauses_extended(root,
3403 : : &root->processed_groupClause,
3404 : : tlist,
3405 : : true,
3406 : : &sortable);
3407 [ - + ]: 2464 : if (!sortable)
3408 : : {
3409 : : /* Can't sort; no point in considering aggregate ordering either */
452 tgl@sss.pgh.pa.us 3410 :UBC 0 : root->group_pathkeys = NIL;
3411 : 0 : root->num_groupby_pathkeys = 0;
3412 : : }
3413 : : else
3414 : : {
452 tgl@sss.pgh.pa.us 3415 :CBC 2464 : root->num_groupby_pathkeys = list_length(root->group_pathkeys);
3416 : : /* If we have ordered aggs, consider adding onto group_pathkeys */
3417 [ + + ]: 2464 : if (root->numOrderedAggs > 0)
3418 : 900 : adjust_group_pathkeys_for_groupagg(root);
3419 : : }
3420 : : }
3421 : : else
3422 : : {
4003 3423 : 240425 : root->group_pathkeys = NIL;
621 drowley@postgresql.o 3424 : 240425 : root->num_groupby_pathkeys = 0;
3425 : : }
3426 : :
3427 : : /* We consider only the first (bottom) window in pathkeys logic */
4003 tgl@sss.pgh.pa.us 3428 [ + + ]: 243253 : if (activeWindows != NIL)
3429 : : {
2413 3430 : 1147 : WindowClause *wc = linitial_node(WindowClause, activeWindows);
3431 : :
4003 3432 : 1147 : root->window_pathkeys = make_pathkeys_for_window(root,
3433 : : wc,
3434 : : tlist);
3435 : : }
3436 : : else
3437 : 242106 : root->window_pathkeys = NIL;
3438 : :
3439 : : /*
3440 : : * As with GROUP BY, we can discard any DISTINCT items that are proven
3441 : : * redundant by EquivalenceClass processing. The non-redundant list is
3442 : : * kept in root->processed_distinctClause, leaving the original
3443 : : * parse->distinctClause alone.
3444 : : */
452 3445 [ + + ]: 243253 : if (parse->distinctClause)
3446 : : {
3447 : : bool sortable;
3448 : :
3449 : : /* Make a copy since pathkey processing can modify the list */
3450 : 1098 : root->processed_distinctClause = list_copy(parse->distinctClause);
4003 3451 : 1098 : root->distinct_pathkeys =
452 3452 : 1098 : make_pathkeys_for_sortclauses_extended(root,
3453 : : &root->processed_distinctClause,
3454 : : tlist,
3455 : : true,
3456 : : &sortable);
3457 [ + + ]: 1098 : if (!sortable)
3458 : 3 : root->distinct_pathkeys = NIL;
3459 : : }
3460 : : else
4003 3461 : 242155 : root->distinct_pathkeys = NIL;
3462 : :
3463 : 243253 : root->sort_pathkeys =
3464 : 243253 : make_pathkeys_for_sortclauses(root,
3465 : : parse->sortClause,
3466 : : tlist);
3467 : :
3468 : : /* setting setop_pathkeys might be useful to the union planner */
20 drowley@postgresql.o 3469 [ + + + + ]:GNC 250102 : if (qp_extra->setop != NULL &&
3470 : 6849 : set_operation_ordered_results_useful(qp_extra->setop))
3471 : 5119 : {
3472 : : List *groupClauses;
3473 : : bool sortable;
3474 : :
3475 : 5119 : groupClauses = generate_setop_child_grouplist(qp_extra->setop, tlist);
3476 : :
3477 : 5119 : root->setop_pathkeys =
3478 : 5119 : make_pathkeys_for_sortclauses_extended(root,
3479 : : &groupClauses,
3480 : : tlist,
3481 : : false,
3482 : : &sortable);
3483 [ + + ]: 5119 : if (!sortable)
3484 : 74 : root->setop_pathkeys = NIL;
3485 : : }
3486 : : else
3487 : 238134 : root->setop_pathkeys = NIL;
3488 : :
3489 : : /*
3490 : : * Figure out whether we want a sorted result from query_planner.
3491 : : *
3492 : : * If we have a sortable GROUP BY clause, then we want a result sorted
3493 : : * properly for grouping. Otherwise, if we have window functions to
3494 : : * evaluate, we try to sort for the first window. Otherwise, if there's a
3495 : : * sortable DISTINCT clause that's more rigorous than the ORDER BY clause,
3496 : : * we try to produce output that's sufficiently well sorted for the
3497 : : * DISTINCT. Otherwise, if there is an ORDER BY clause, we want to sort
3498 : : * by the ORDER BY clause. Otherwise, if we're a subquery being planned
3499 : : * for a set operation which can benefit from presorted results and have a
3500 : : * sortable targetlist, we want to sort by the target list.
3501 : : *
3502 : : * Note: if we have both ORDER BY and GROUP BY, and ORDER BY is a superset
3503 : : * of GROUP BY, it would be tempting to request sort by ORDER BY --- but
3504 : : * that might just leave us failing to exploit an available sort order at
3505 : : * all. Needs more thought. The choice for DISTINCT versus ORDER BY is
3506 : : * much easier, since we know that the parser ensured that one is a
3507 : : * superset of the other.
3508 : : */
4003 tgl@sss.pgh.pa.us 3509 [ + + ]:CBC 243253 : if (root->group_pathkeys)
3510 : 2659 : root->query_pathkeys = root->group_pathkeys;
3511 [ + + ]: 240594 : else if (root->window_pathkeys)
3512 : 991 : root->query_pathkeys = root->window_pathkeys;
3513 [ + + ]: 479206 : else if (list_length(root->distinct_pathkeys) >
3514 : 239603 : list_length(root->sort_pathkeys))
3515 : 896 : root->query_pathkeys = root->distinct_pathkeys;
3516 [ + + ]: 238707 : else if (root->sort_pathkeys)
3517 : 25896 : root->query_pathkeys = root->sort_pathkeys;
20 drowley@postgresql.o 3518 [ + + ]:GNC 212811 : else if (root->setop_pathkeys != NIL)
3519 : 4760 : root->query_pathkeys = root->setop_pathkeys;
3520 : : else
4003 tgl@sss.pgh.pa.us 3521 :CBC 208051 : root->query_pathkeys = NIL;
3522 : 243253 : }
3523 : :
3524 : : /*
3525 : : * Estimate number of groups produced by grouping clauses (1 if not grouping)
3526 : : *
3527 : : * path_rows: number of output rows from scan/join step
3528 : : * gd: grouping sets data including list of grouping sets and their clauses
3529 : : * target_list: target list containing group clause references
3530 : : *
3531 : : * If doing grouping sets, we also annotate the gsets data with the estimates
3532 : : * for each set and each individual rollup list, with a view to later
3533 : : * determining whether some combination of them could be hashed instead.
3534 : : */
3535 : : static double
2960 3536 : 19594 : get_number_of_groups(PlannerInfo *root,
3537 : : double path_rows,
3538 : : grouping_sets_data *gd,
3539 : : List *target_list)
3540 : : {
5177 3541 : 19594 : Query *parse = root->parse;
3542 : : double dNumGroups;
3543 : :
2960 3544 [ + + ]: 19594 : if (parse->groupClause)
3545 : : {
3546 : : List *groupExprs;
3547 : :
3548 [ + + ]: 3233 : if (parse->groupingSets)
3549 : : {
3550 : : /* Add up the estimates for each grouping set */
3551 : : ListCell *lc;
3552 : :
2524 bruce@momjian.us 3553 [ - + ]: 343 : Assert(gd); /* keep Coverity happy */
3554 : :
2960 tgl@sss.pgh.pa.us 3555 : 343 : dNumGroups = 0;
3556 : :
2575 rhodiumtoad@postgres 3557 [ + + + + : 927 : foreach(lc, gd->rollups)
+ + ]
3558 : : {
2413 tgl@sss.pgh.pa.us 3559 : 584 : RollupData *rollup = lfirst_node(RollupData, lc);
3560 : : ListCell *lc2;
3561 : : ListCell *lc3;
3562 : :
2575 rhodiumtoad@postgres 3563 : 584 : groupExprs = get_sortgrouplist_exprs(rollup->groupClause,
3564 : : target_list);
3565 : :
3566 : 584 : rollup->numGroups = 0.0;
3567 : :
557 drowley@postgresql.o 3568 [ + - + + : 1744 : forboth(lc2, rollup->gsets, lc3, rollup->gsets_data)
+ - + + +
+ + - +
+ ]
3569 : : {
3570 : 1160 : List *gset = (List *) lfirst(lc2);
3571 : 1160 : GroupingSetData *gs = lfirst_node(GroupingSetData, lc3);
2575 rhodiumtoad@postgres 3572 : 1160 : double numGroups = estimate_num_groups(root,
3573 : : groupExprs,
3574 : : path_rows,
3575 : : &gset,
3576 : : NULL);
3577 : :
3578 : 1160 : gs->numGroups = numGroups;
3579 : 1160 : rollup->numGroups += numGroups;
3580 : : }
3581 : :
3582 : 584 : dNumGroups += rollup->numGroups;
3583 : : }
3584 : :
3585 [ + + ]: 343 : if (gd->hash_sets_idx)
3586 : : {
3587 : : ListCell *lc2;
3588 : :
3589 : 18 : gd->dNumHashGroups = 0;
3590 : :
3591 : 18 : groupExprs = get_sortgrouplist_exprs(parse->groupClause,
3592 : : target_list);
3593 : :
3594 [ + - + + : 39 : forboth(lc, gd->hash_sets_idx, lc2, gd->unsortable_sets)
+ - + + +
+ + - +
+ ]
3595 : : {
3596 : 21 : List *gset = (List *) lfirst(lc);
2413 tgl@sss.pgh.pa.us 3597 : 21 : GroupingSetData *gs = lfirst_node(GroupingSetData, lc2);
2575 rhodiumtoad@postgres 3598 : 21 : double numGroups = estimate_num_groups(root,
3599 : : groupExprs,
3600 : : path_rows,
3601 : : &gset,
3602 : : NULL);
3603 : :
3604 : 21 : gs->numGroups = numGroups;
3605 : 21 : gd->dNumHashGroups += numGroups;
3606 : : }
3607 : :
3608 : 18 : dNumGroups += gd->dNumHashGroups;
3609 : : }
3610 : : }
3611 : : else
3612 : : {
3613 : : /* Plain GROUP BY -- estimate based on optimized groupClause */
452 tgl@sss.pgh.pa.us 3614 : 2890 : groupExprs = get_sortgrouplist_exprs(root->processed_groupClause,
3615 : : target_list);
3616 : :
2960 3617 : 2890 : dNumGroups = estimate_num_groups(root, groupExprs, path_rows,
3618 : : NULL, NULL);
3619 : : }
3620 : : }
3621 [ + + ]: 16361 : else if (parse->groupingSets)
3622 : : {
3623 : : /* Empty grouping sets ... one result row for each one */
3624 : 21 : dNumGroups = list_length(parse->groupingSets);
3625 : : }
3626 [ - + - - ]: 16340 : else if (parse->hasAggs || root->hasHavingQual)
3627 : : {
3628 : : /* Plain aggregation, one result row */
3629 : 16340 : dNumGroups = 1;
3630 : : }
3631 : : else
3632 : : {
3633 : : /* Not grouping */
2960 tgl@sss.pgh.pa.us 3634 :UBC 0 : dNumGroups = 1;
3635 : : }
3636 : :
2960 tgl@sss.pgh.pa.us 3637 :CBC 19594 : return dNumGroups;
3638 : : }
3639 : :
3640 : : /*
3641 : : * create_grouping_paths
3642 : : *
3643 : : * Build a new upperrel containing Paths for grouping and/or aggregation.
3644 : : * Along the way, we also build an upperrel for Paths which are partially
3645 : : * grouped and/or aggregated. A partially grouped and/or aggregated path
3646 : : * needs a FinalizeAggregate node to complete the aggregation. Currently,
3647 : : * the only partially grouped paths we build are also partial paths; that
3648 : : * is, they need a Gather and then a FinalizeAggregate.
3649 : : *
3650 : : * input_rel: contains the source-data Paths
3651 : : * target: the pathtarget for the result Paths to compute
3652 : : * gd: grouping sets data including list of grouping sets and their clauses
3653 : : *
3654 : : * Note: all Paths in input_rel are expected to return the target computed
3655 : : * by make_group_input_target.
3656 : : */
3657 : : static RelOptInfo *
3658 : 17996 : create_grouping_paths(PlannerInfo *root,
3659 : : RelOptInfo *input_rel,
3660 : : PathTarget *target,
3661 : : bool target_parallel_safe,
3662 : : grouping_sets_data *gd)
3663 : : {
3664 : 17996 : Query *parse = root->parse;
3665 : : RelOptInfo *grouped_rel;
3666 : : RelOptInfo *partially_grouped_rel;
3667 : : AggClauseCosts agg_costs;
3668 : :
1237 heikki.linnakangas@i 3669 [ + - + - : 107976 : MemSet(&agg_costs, 0, sizeof(AggClauseCosts));
+ - + - +
+ ]
3670 : 17996 : get_agg_clause_costs(root, AGGSPLIT_SIMPLE, &agg_costs);
3671 : :
3672 : : /*
3673 : : * Create grouping relation to hold fully aggregated grouping and/or
3674 : : * aggregation paths.
3675 : : */
2215 rhaas@postgresql.org 3676 : 17996 : grouped_rel = make_grouping_rel(root, input_rel, target,
3677 : : target_parallel_safe, parse->havingQual);
3678 : :
3679 : : /*
3680 : : * Create either paths for a degenerate grouping or paths for ordinary
3681 : : * grouping, as appropriate.
3682 : : */
2222 3683 [ + + ]: 17996 : if (is_degenerate_grouping(root))
2217 3684 : 9 : create_degenerate_grouping_paths(root, input_rel, grouped_rel);
3685 : : else
3686 : : {
3687 : 17987 : int flags = 0;
3688 : : GroupPathExtraData extra;
3689 : :
3690 : : /*
3691 : : * Determine whether it's possible to perform sort-based
3692 : : * implementations of grouping. (Note that if processed_groupClause
3693 : : * is empty, grouping_is_sortable() is trivially true, and all the
3694 : : * pathkeys_contained_in() tests will succeed too, so that we'll
3695 : : * consider every surviving input path.)
3696 : : *
3697 : : * If we have grouping sets, we might be able to sort some but not all
3698 : : * of them; in this case, we need can_sort to be true as long as we
3699 : : * must consider any sorted-input plan.
3700 : : */
3701 [ + + + + ]: 17987 : if ((gd && gd->rollups != NIL)
452 tgl@sss.pgh.pa.us 3702 [ + + ]: 17626 : || grouping_is_sortable(root->processed_groupClause))
2217 rhaas@postgresql.org 3703 : 17984 : flags |= GROUPING_CAN_USE_SORT;
3704 : :
3705 : : /*
3706 : : * Determine whether we should consider hash-based implementations of
3707 : : * grouping.
3708 : : *
3709 : : * Hashed aggregation only applies if we're grouping. If we have
3710 : : * grouping sets, some groups might be hashable but others not; in
3711 : : * this case we set can_hash true as long as there is nothing globally
3712 : : * preventing us from hashing (and we should therefore consider plans
3713 : : * with hashes).
3714 : : *
3715 : : * Executor doesn't support hashed aggregation with DISTINCT or ORDER
3716 : : * BY aggregates. (Doing so would imply storing *all* the input
3717 : : * values in the hash table, and/or running many sorts in parallel,
3718 : : * either of which seems like a certain loser.) We similarly don't
3719 : : * support ordered-set aggregates in hashed aggregation, but that case
3720 : : * is also included in the numOrderedAggs count.
3721 : : *
3722 : : * Note: grouping_is_hashable() is much more expensive to check than
3723 : : * the other gating conditions, so we want to do it last.
3724 : : */
3725 [ + + ]: 17987 : if ((parse->groupClause != NIL &&
1237 heikki.linnakangas@i 3726 [ + + + + : 3915 : root->numOrderedAggs == 0 &&
+ + ]
452 tgl@sss.pgh.pa.us 3727 : 1889 : (gd ? gd->any_hashable : grouping_is_hashable(root->processed_groupClause))))
2217 rhaas@postgresql.org 3728 : 1887 : flags |= GROUPING_CAN_USE_HASH;
3729 : :
3730 : : /*
3731 : : * Determine whether partial aggregation is possible.
3732 : : */
1237 heikki.linnakangas@i 3733 [ + + ]: 17987 : if (can_partial_agg(root))
2217 rhaas@postgresql.org 3734 : 16130 : flags |= GROUPING_CAN_PARTIAL_AGG;
3735 : :
2215 3736 : 17987 : extra.flags = flags;
3737 : 17987 : extra.target_parallel_safe = target_parallel_safe;
3738 : 17987 : extra.havingQual = parse->havingQual;
3739 : 17987 : extra.targetList = parse->targetList;
3740 : 17987 : extra.partial_costs_set = false;
3741 : :
3742 : : /*
3743 : : * Determine whether partitionwise aggregation is in theory possible.
3744 : : * It can be disabled by the user, and for now, we don't try to
3745 : : * support grouping sets. create_ordinary_grouping_paths() will check
3746 : : * additional conditions, such as whether input_rel is partitioned.
3747 : : */
3748 [ + + + + ]: 17987 : if (enable_partitionwise_aggregate && !parse->groupingSets)
3749 : 224 : extra.patype = PARTITIONWISE_AGGREGATE_FULL;
3750 : : else
3751 : 17763 : extra.patype = PARTITIONWISE_AGGREGATE_NONE;
3752 : :
2217 3753 : 17987 : create_ordinary_grouping_paths(root, input_rel, grouped_rel,
3754 : : &agg_costs, gd, &extra,
3755 : : &partially_grouped_rel);
3756 : : }
3757 : :
2222 3758 : 17993 : set_cheapest(grouped_rel);
3759 : 17993 : return grouped_rel;
3760 : : }
3761 : :
3762 : : /*
3763 : : * make_grouping_rel
3764 : : *
3765 : : * Create a new grouping rel and set basic properties.
3766 : : *
3767 : : * input_rel represents the underlying scan/join relation.
3768 : : * target is the output expected from the grouping relation.
3769 : : */
3770 : : static RelOptInfo *
2215 3771 : 18695 : make_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
3772 : : PathTarget *target, bool target_parallel_safe,
3773 : : Node *havingQual)
3774 : : {
3775 : : RelOptInfo *grouped_rel;
3776 : :
3777 [ + + + + : 18695 : if (IS_OTHER_REL(input_rel))
- + ]
3778 : : {
3779 : 699 : grouped_rel = fetch_upper_rel(root, UPPERREL_GROUP_AGG,
3780 : : input_rel->relids);
3781 : 699 : grouped_rel->reloptkind = RELOPT_OTHER_UPPER_REL;
3782 : : }
3783 : : else
3784 : : {
3785 : : /*
3786 : : * By tradition, the relids set for the main grouping relation is
3787 : : * NULL. (This could be changed, but might require adjustments
3788 : : * elsewhere.)
3789 : : */
3790 : 17996 : grouped_rel = fetch_upper_rel(root, UPPERREL_GROUP_AGG, NULL);
3791 : : }
3792 : :
3793 : : /* Set target. */
3794 : 18695 : grouped_rel->reltarget = target;
3795 : :
3796 : : /*
3797 : : * If the input relation is not parallel-safe, then the grouped relation
3798 : : * can't be parallel-safe, either. Otherwise, it's parallel-safe if the
3799 : : * target list and HAVING quals are parallel-safe.
3800 : : */
3801 [ + + + + : 32322 : if (input_rel->consider_parallel && target_parallel_safe &&
+ + ]
3802 : 13627 : is_parallel_safe(root, (Node *) havingQual))
3803 : 13618 : grouped_rel->consider_parallel = true;
3804 : :
3805 : : /*
3806 : : * If the input rel belongs to a single FDW, so does the grouped rel.
3807 : : */
3808 : 18695 : grouped_rel->serverid = input_rel->serverid;
3809 : 18695 : grouped_rel->userid = input_rel->userid;
3810 : 18695 : grouped_rel->useridiscurrent = input_rel->useridiscurrent;
3811 : 18695 : grouped_rel->fdwroutine = input_rel->fdwroutine;
3812 : :
3813 : 18695 : return grouped_rel;
3814 : : }
3815 : :
3816 : : /*
3817 : : * is_degenerate_grouping
3818 : : *
3819 : : * A degenerate grouping is one in which the query has a HAVING qual and/or
3820 : : * grouping sets, but no aggregates and no GROUP BY (which implies that the
3821 : : * grouping sets are all empty).
3822 : : */
3823 : : static bool
2222 3824 : 17996 : is_degenerate_grouping(PlannerInfo *root)
3825 : : {
3826 : 17996 : Query *parse = root->parse;
3827 : :
3828 [ + + ]: 17453 : return (root->hasHavingQual || parse->groupingSets) &&
3829 [ + + + + : 35449 : !parse->hasAggs && parse->groupClause == NIL;
+ + ]
3830 : : }
3831 : :
3832 : : /*
3833 : : * create_degenerate_grouping_paths
3834 : : *
3835 : : * When the grouping is degenerate (see is_degenerate_grouping), we are
3836 : : * supposed to emit either zero or one row for each grouping set depending on
3837 : : * whether HAVING succeeds. Furthermore, there cannot be any variables in
3838 : : * either HAVING or the targetlist, so we actually do not need the FROM table
3839 : : * at all! We can just throw away the plan-so-far and generate a Result node.
3840 : : * This is a sufficiently unusual corner case that it's not worth contorting
3841 : : * the structure of this module to avoid having to generate the earlier paths
3842 : : * in the first place.
3843 : : */
3844 : : static void
3845 : 9 : create_degenerate_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
3846 : : RelOptInfo *grouped_rel)
3847 : : {
3848 : 9 : Query *parse = root->parse;
3849 : : int nrows;
3850 : : Path *path;
3851 : :
3852 : 9 : nrows = list_length(parse->groupingSets);
3853 [ - + ]: 9 : if (nrows > 1)
3854 : : {
3855 : : /*
3856 : : * Doesn't seem worthwhile writing code to cons up a generate_series
3857 : : * or a values scan to emit multiple rows. Instead just make N clones
3858 : : * and append them. (With a volatile HAVING clause, this means you
3859 : : * might get between 0 and N output rows. Offhand I think that's
3860 : : * desired.)
3861 : : */
2222 rhaas@postgresql.org 3862 :UBC 0 : List *paths = NIL;
3863 : :
3864 [ # # ]: 0 : while (--nrows >= 0)
3865 : : {
3866 : : path = (Path *)
1903 tgl@sss.pgh.pa.us 3867 : 0 : create_group_result_path(root, grouped_rel,
3868 : 0 : grouped_rel->reltarget,
3869 : 0 : (List *) parse->havingQual);
2222 rhaas@postgresql.org 3870 : 0 : paths = lappend(paths, path);
3871 : : }
3872 : : path = (Path *)
2199 alvherre@alvh.no-ip. 3873 : 0 : create_append_path(root,
3874 : : grouped_rel,
3875 : : paths,
3876 : : NIL,
3877 : : NIL,
3878 : : NULL,
3879 : : 0,
3880 : : false,
3881 : : -1);
3882 : : }
3883 : : else
3884 : : {
3885 : : /* No grouping sets, or just one, so one output row */
3886 : : path = (Path *)
1903 tgl@sss.pgh.pa.us 3887 :CBC 9 : create_group_result_path(root, grouped_rel,
3888 : 9 : grouped_rel->reltarget,
3889 : 9 : (List *) parse->havingQual);
3890 : : }
3891 : :
2222 rhaas@postgresql.org 3892 : 9 : add_path(grouped_rel, path);
3893 : 9 : }
3894 : :
3895 : : /*
3896 : : * create_ordinary_grouping_paths
3897 : : *
3898 : : * Create grouping paths for the ordinary (that is, non-degenerate) case.
3899 : : *
3900 : : * We need to consider sorted and hashed aggregation in the same function,
3901 : : * because otherwise (1) it would be harder to throw an appropriate error
3902 : : * message if neither way works, and (2) we should not allow hashtable size
3903 : : * considerations to dissuade us from using hashing if sorting is not possible.
3904 : : *
3905 : : * *partially_grouped_rel_p will be set to the partially grouped rel which this
3906 : : * function creates, or to NULL if it doesn't create one.
3907 : : */
3908 : : static void
3909 : 18686 : create_ordinary_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
3910 : : RelOptInfo *grouped_rel,
3911 : : const AggClauseCosts *agg_costs,
3912 : : grouping_sets_data *gd,
3913 : : GroupPathExtraData *extra,
3914 : : RelOptInfo **partially_grouped_rel_p)
3915 : : {
3916 : 18686 : Path *cheapest_path = input_rel->cheapest_total_path;
2217 3917 : 18686 : RelOptInfo *partially_grouped_rel = NULL;
3918 : : double dNumGroups;
2215 3919 : 18686 : PartitionwiseAggregateType patype = PARTITIONWISE_AGGREGATE_NONE;
3920 : :
3921 : : /*
3922 : : * If this is the topmost grouping relation or if the parent relation is
3923 : : * doing some form of partitionwise aggregation, then we may be able to do
3924 : : * it at this level also. However, if the input relation is not
3925 : : * partitioned, partitionwise aggregate is impossible.
3926 : : */
3927 [ + + ]: 18686 : if (extra->patype != PARTITIONWISE_AGGREGATE_NONE &&
1865 tgl@sss.pgh.pa.us 3928 [ + + + - : 923 : IS_PARTITIONED_REL(input_rel))
+ + + - +
+ ]
3929 : : {
3930 : : /*
3931 : : * If this is the topmost relation or if the parent relation is doing
3932 : : * full partitionwise aggregation, then we can do full partitionwise
3933 : : * aggregation provided that the GROUP BY clause contains all of the
3934 : : * partitioning columns at this level. Otherwise, we can do at most
3935 : : * partial partitionwise aggregation. But if partial aggregation is
3936 : : * not supported in general then we can't use it for partitionwise
3937 : : * aggregation either.
3938 : : *
3939 : : * Check parse->groupClause not processed_groupClause, because it's
3940 : : * okay if some of the partitioning columns were proved redundant.
3941 : : */
2215 rhaas@postgresql.org 3942 [ + + + + ]: 532 : if (extra->patype == PARTITIONWISE_AGGREGATE_FULL &&
3943 : 254 : group_by_has_partkey(input_rel, extra->targetList,
3944 : 254 : root->parse->groupClause))
3945 : 142 : patype = PARTITIONWISE_AGGREGATE_FULL;
3946 [ + + ]: 136 : else if ((extra->flags & GROUPING_CAN_PARTIAL_AGG) != 0)
3947 : 115 : patype = PARTITIONWISE_AGGREGATE_PARTIAL;
3948 : : else
3949 : 21 : patype = PARTITIONWISE_AGGREGATE_NONE;
3950 : : }
3951 : :
3952 : : /*
3953 : : * Before generating paths for grouped_rel, we first generate any possible
3954 : : * partially grouped paths; that way, later code can easily consider both
3955 : : * parallel and non-parallel approaches to grouping.
3956 : : */
3957 [ + + ]: 18686 : if ((extra->flags & GROUPING_CAN_PARTIAL_AGG) != 0)
3958 : : {
3959 : : bool force_rel_creation;
3960 : :
3961 : : /*
3962 : : * If we're doing partitionwise aggregation at this level, force
3963 : : * creation of a partially_grouped_rel so we can add partitionwise
3964 : : * paths to it.
3965 : : */
3966 : 16793 : force_rel_creation = (patype == PARTITIONWISE_AGGREGATE_PARTIAL);
3967 : :
3968 : : partially_grouped_rel =
2217 3969 : 16793 : create_partial_grouping_paths(root,
3970 : : grouped_rel,
3971 : : input_rel,
3972 : : gd,
3973 : : extra,
3974 : : force_rel_creation);
3975 : : }
3976 : :
3977 : : /* Set out parameter. */
2215 3978 : 18686 : *partially_grouped_rel_p = partially_grouped_rel;
3979 : :
3980 : : /* Apply partitionwise aggregation technique, if possible. */
3981 [ + + ]: 18686 : if (patype != PARTITIONWISE_AGGREGATE_NONE)
3982 : 257 : create_partitionwise_grouping_paths(root, input_rel, grouped_rel,
3983 : : partially_grouped_rel, agg_costs,
3984 : : gd, patype, extra);
3985 : :
3986 : : /* If we are doing partial aggregation only, return. */
3987 [ + + ]: 18686 : if (extra->patype == PARTITIONWISE_AGGREGATE_PARTIAL)
3988 : : {
3989 [ - + ]: 297 : Assert(partially_grouped_rel);
3990 : :
3991 [ + - ]: 297 : if (partially_grouped_rel->pathlist)
3992 : 297 : set_cheapest(partially_grouped_rel);
3993 : :
3994 : 297 : return;
3995 : : }
3996 : :
3997 : : /* Gather any partially grouped partial paths. */
3998 [ + + + + ]: 18389 : if (partially_grouped_rel && partially_grouped_rel->partial_pathlist)
3999 : : {
2217 4000 : 740 : gather_grouping_paths(root, partially_grouped_rel);
4001 : 740 : set_cheapest(partially_grouped_rel);
4002 : : }
4003 : :
4004 : : /*
4005 : : * Estimate number of groups.
4006 : : */
2215 4007 : 18389 : dNumGroups = get_number_of_groups(root,
4008 : : cheapest_path->rows,
4009 : : gd,
4010 : : extra->targetList);
4011 : :
4012 : : /* Build final grouping paths */
2217 4013 : 18389 : add_paths_to_grouping_rel(root, input_rel, grouped_rel,
4014 : : partially_grouped_rel, agg_costs, gd,
4015 : : dNumGroups, extra);
4016 : :
4017 : : /* Give a helpful error if we failed to find any implementation */
2270 4018 [ + + ]: 18389 : if (grouped_rel->pathlist == NIL)
4019 [ + - ]: 3 : ereport(ERROR,
4020 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4021 : : errmsg("could not implement GROUP BY"),
4022 : : errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
4023 : :
4024 : : /*
4025 : : * If there is an FDW that's responsible for all baserels of the query,
4026 : : * let it consider adding ForeignPaths.
4027 : : */
4028 [ + + ]: 18386 : if (grouped_rel->fdwroutine &&
4029 [ + - ]: 162 : grouped_rel->fdwroutine->GetForeignUpperPaths)
4030 : 162 : grouped_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_GROUP_AGG,
4031 : : input_rel, grouped_rel,
4032 : : extra);
4033 : :
4034 : : /* Let extensions possibly add some more paths */
4035 [ - + ]: 18386 : if (create_upper_paths_hook)
2270 rhaas@postgresql.org 4036 :UBC 0 : (*create_upper_paths_hook) (root, UPPERREL_GROUP_AGG,
4037 : : input_rel, grouped_rel,
4038 : : extra);
4039 : : }
4040 : :
4041 : : /*
4042 : : * For a given input path, consider the possible ways of doing grouping sets on
4043 : : * it, by combinations of hashing and sorting. This can be called multiple
4044 : : * times, so it's important that it not scribble on input. No result is
4045 : : * returned, but any generated paths are added to grouped_rel.
4046 : : */
4047 : : static void
2270 rhaas@postgresql.org 4048 :CBC 722 : consider_groupingsets_paths(PlannerInfo *root,
4049 : : RelOptInfo *grouped_rel,
4050 : : Path *path,
4051 : : bool is_sorted,
4052 : : bool can_hash,
4053 : : grouping_sets_data *gd,
4054 : : const AggClauseCosts *agg_costs,
4055 : : double dNumGroups)
4056 : : {
4057 : 722 : Query *parse = root->parse;
994 tgl@sss.pgh.pa.us 4058 : 722 : Size hash_mem_limit = get_hash_memory_limit();
4059 : :
4060 : : /*
4061 : : * If we're not being offered sorted input, then only consider plans that
4062 : : * can be done entirely by hashing.
4063 : : *
4064 : : * We can hash everything if it looks like it'll fit in hash_mem. But if
4065 : : * the input is actually sorted despite not being advertised as such, we
4066 : : * prefer to make use of that in order to use less memory.
4067 : : *
4068 : : * If none of the grouping sets are sortable, then ignore the hash_mem
4069 : : * limit and generate a path anyway, since otherwise we'll just fail.
4070 : : */
2270 rhaas@postgresql.org 4071 [ + + ]: 722 : if (!is_sorted)
4072 : : {
4073 : 325 : List *new_rollups = NIL;
4074 : 325 : RollupData *unhashed_rollup = NULL;
4075 : : List *sets_data;
4076 : 325 : List *empty_sets_data = NIL;
4077 : 325 : List *empty_sets = NIL;
4078 : : ListCell *lc;
4079 : 325 : ListCell *l_start = list_head(gd->rollups);
4080 : 325 : AggStrategy strat = AGG_HASHED;
4081 : : double hashsize;
4082 : 325 : double exclude_groups = 0.0;
4083 : :
4084 [ - + ]: 325 : Assert(can_hash);
4085 : :
4086 : : /*
4087 : : * If the input is coincidentally sorted usefully (which can happen
4088 : : * even if is_sorted is false, since that only means that our caller
4089 : : * has set up the sorting for us), then save some hashtable space by
4090 : : * making use of that. But we need to watch out for degenerate cases:
4091 : : *
4092 : : * 1) If there are any empty grouping sets, then group_pathkeys might
4093 : : * be NIL if all non-empty grouping sets are unsortable. In this case,
4094 : : * there will be a rollup containing only empty groups, and the
4095 : : * pathkeys_contained_in test is vacuously true; this is ok.
4096 : : *
4097 : : * XXX: the above relies on the fact that group_pathkeys is generated
4098 : : * from the first rollup. If we add the ability to consider multiple
4099 : : * sort orders for grouping input, this assumption might fail.
4100 : : *
4101 : : * 2) If there are no empty sets and only unsortable sets, then the
4102 : : * rollups list will be empty (and thus l_start == NULL), and
4103 : : * group_pathkeys will be NIL; we must ensure that the vacuously-true
4104 : : * pathkeys_contained_in test doesn't cause us to crash.
4105 : : */
2216 rhodiumtoad@postgres 4106 [ + + + + ]: 647 : if (l_start != NULL &&
4107 : 322 : pathkeys_contained_in(root->group_pathkeys, path->pathkeys))
4108 : : {
2270 rhaas@postgresql.org 4109 : 12 : unhashed_rollup = lfirst_node(RollupData, l_start);
4110 : 12 : exclude_groups = unhashed_rollup->numGroups;
1735 tgl@sss.pgh.pa.us 4111 : 12 : l_start = lnext(gd->rollups, l_start);
4112 : : }
4113 : :
1237 heikki.linnakangas@i 4114 : 325 : hashsize = estimate_hashagg_tablesize(root,
4115 : : path,
4116 : : agg_costs,
4117 : : dNumGroups - exclude_groups);
4118 : :
4119 : : /*
4120 : : * gd->rollups is empty if we have only unsortable columns to work
4121 : : * with. Override hash_mem in that case; otherwise, we'll rely on the
4122 : : * sorted-input case to generate usable mixed paths.
4123 : : */
994 tgl@sss.pgh.pa.us 4124 [ + + + - ]: 325 : if (hashsize > hash_mem_limit && gd->rollups)
2270 rhaas@postgresql.org 4125 : 9 : return; /* nope, won't fit */
4126 : :
4127 : : /*
4128 : : * We need to burst the existing rollups list into individual grouping
4129 : : * sets and recompute a groupClause for each set.
4130 : : */
4131 : 316 : sets_data = list_copy(gd->unsortable_sets);
4132 : :
1735 tgl@sss.pgh.pa.us 4133 [ + + + + : 798 : for_each_cell(lc, gd->rollups, l_start)
+ + ]
4134 : : {
2270 rhaas@postgresql.org 4135 : 494 : RollupData *rollup = lfirst_node(RollupData, lc);
4136 : :
4137 : : /*
4138 : : * If we find an unhashable rollup that's not been skipped by the
4139 : : * "actually sorted" check above, we can't cope; we'd need sorted
4140 : : * input (with a different sort order) but we can't get that here.
4141 : : * So bail out; we'll get a valid path from the is_sorted case
4142 : : * instead.
4143 : : *
4144 : : * The mere presence of empty grouping sets doesn't make a rollup
4145 : : * unhashable (see preprocess_grouping_sets), we handle those
4146 : : * specially below.
4147 : : */
2575 rhodiumtoad@postgres 4148 [ + + ]: 494 : if (!rollup->hashable)
4149 : 12 : return;
4150 : :
1707 tgl@sss.pgh.pa.us 4151 : 482 : sets_data = list_concat(sets_data, rollup->gsets_data);
4152 : : }
2575 rhodiumtoad@postgres 4153 [ + - + + : 1341 : foreach(lc, sets_data)
+ + ]
4154 : : {
2413 tgl@sss.pgh.pa.us 4155 : 1037 : GroupingSetData *gs = lfirst_node(GroupingSetData, lc);
2575 rhodiumtoad@postgres 4156 : 1037 : List *gset = gs->set;
4157 : : RollupData *rollup;
4158 : :
4159 [ + + ]: 1037 : if (gset == NIL)
4160 : : {
4161 : : /* Empty grouping sets can't be hashed. */
4162 : 224 : empty_sets_data = lappend(empty_sets_data, gs);
4163 : 224 : empty_sets = lappend(empty_sets, NIL);
4164 : : }
4165 : : else
4166 : : {
4167 : 813 : rollup = makeNode(RollupData);
4168 : :
84 akorotkov@postgresql 4169 :GNC 813 : rollup->groupClause = groupclause_apply_groupingset(root, gset);
2575 rhodiumtoad@postgres 4170 :CBC 813 : rollup->gsets_data = list_make1(gs);
4171 : 813 : rollup->gsets = remap_to_groupclause_idx(rollup->groupClause,
4172 : : rollup->gsets_data,
4173 : : gd->tleref_to_colnum_map);
4174 : 813 : rollup->numGroups = gs->numGroups;
4175 : 813 : rollup->hashable = true;
4176 : 813 : rollup->is_hashed = true;
4177 : 813 : new_rollups = lappend(new_rollups, rollup);
4178 : : }
4179 : : }
4180 : :
4181 : : /*
4182 : : * If we didn't find anything nonempty to hash, then bail. We'll
4183 : : * generate a path from the is_sorted case.
4184 : : */
4185 [ - + ]: 304 : if (new_rollups == NIL)
2575 rhodiumtoad@postgres 4186 :UBC 0 : return;
4187 : :
4188 : : /*
4189 : : * If there were empty grouping sets they should have been in the
4190 : : * first rollup.
4191 : : */
2575 rhodiumtoad@postgres 4192 [ + + - + ]:CBC 304 : Assert(!unhashed_rollup || !empty_sets);
4193 : :
4194 [ + + ]: 304 : if (unhashed_rollup)
4195 : : {
4196 : 12 : new_rollups = lappend(new_rollups, unhashed_rollup);
4197 : 12 : strat = AGG_MIXED;
4198 : : }
4199 [ + + ]: 292 : else if (empty_sets)
4200 : : {
4201 : 200 : RollupData *rollup = makeNode(RollupData);
4202 : :
4203 : 200 : rollup->groupClause = NIL;
4204 : 200 : rollup->gsets_data = empty_sets_data;
4205 : 200 : rollup->gsets = empty_sets;
4206 : 200 : rollup->numGroups = list_length(empty_sets);
4207 : 200 : rollup->hashable = false;
4208 : 200 : rollup->is_hashed = false;
4209 : 200 : new_rollups = lappend(new_rollups, rollup);
4210 : 200 : strat = AGG_MIXED;
4211 : : }
4212 : :
4213 : 304 : add_path(grouped_rel, (Path *)
4214 : 304 : create_groupingsets_path(root,
4215 : : grouped_rel,
4216 : : path,
4217 : 304 : (List *) parse->havingQual,
4218 : : strat,
4219 : : new_rollups,
4220 : : agg_costs));
4221 : 304 : return;
4222 : : }
4223 : :
4224 : : /*
4225 : : * If we have sorted input but nothing we can do with it, bail.
4226 : : */
606 tgl@sss.pgh.pa.us 4227 [ - + ]: 397 : if (gd->rollups == NIL)
2575 rhodiumtoad@postgres 4228 :UBC 0 : return;
4229 : :
4230 : : /*
4231 : : * Given sorted input, we try and make two paths: one sorted and one mixed
4232 : : * sort/hash. (We need to try both because hashagg might be disabled, or
4233 : : * some columns might not be sortable.)
4234 : : *
4235 : : * can_hash is passed in as false if some obstacle elsewhere (such as
4236 : : * ordered aggs) means that we shouldn't consider hashing at all.
4237 : : */
2575 rhodiumtoad@postgres 4238 [ + + + - ]:CBC 397 : if (can_hash && gd->any_hashable)
4239 : : {
4240 : 358 : List *rollups = NIL;
4241 : 358 : List *hash_sets = list_copy(gd->unsortable_sets);
994 tgl@sss.pgh.pa.us 4242 : 358 : double availspace = hash_mem_limit;
4243 : : ListCell *lc;
4244 : :
4245 : : /*
4246 : : * Account first for space needed for groups we can't sort at all.
4247 : : */
1237 heikki.linnakangas@i 4248 : 358 : availspace -= estimate_hashagg_tablesize(root,
4249 : : path,
4250 : : agg_costs,
4251 : : gd->dNumHashGroups);
4252 : :
2575 rhodiumtoad@postgres 4253 [ + - + + ]: 358 : if (availspace > 0 && list_length(gd->rollups) > 1)
4254 : : {
4255 : : double scale;
4256 : 198 : int num_rollups = list_length(gd->rollups);
4257 : : int k_capacity;
4258 : 198 : int *k_weights = palloc(num_rollups * sizeof(int));
4259 : 198 : Bitmapset *hash_items = NULL;
4260 : : int i;
4261 : :
4262 : : /*
4263 : : * We treat this as a knapsack problem: the knapsack capacity
4264 : : * represents hash_mem, the item weights are the estimated memory
4265 : : * usage of the hashtables needed to implement a single rollup,
4266 : : * and we really ought to use the cost saving as the item value;
4267 : : * however, currently the costs assigned to sort nodes don't
4268 : : * reflect the comparison costs well, and so we treat all items as
4269 : : * of equal value (each rollup we hash instead saves us one sort).
4270 : : *
4271 : : * To use the discrete knapsack, we need to scale the values to a
4272 : : * reasonably small bounded range. We choose to allow a 5% error
4273 : : * margin; we have no more than 4096 rollups in the worst possible
4274 : : * case, which with a 5% error margin will require a bit over 42MB
4275 : : * of workspace. (Anyone wanting to plan queries that complex had
4276 : : * better have the memory for it. In more reasonable cases, with
4277 : : * no more than a couple of dozen rollups, the memory usage will
4278 : : * be negligible.)
4279 : : *
4280 : : * k_capacity is naturally bounded, but we clamp the values for
4281 : : * scale and weight (below) to avoid overflows or underflows (or
4282 : : * uselessly trying to use a scale factor less than 1 byte).
4283 : : */
4284 [ + - ]: 198 : scale = Max(availspace / (20.0 * num_rollups), 1.0);
4285 : 198 : k_capacity = (int) floor(availspace / scale);
4286 : :
4287 : : /*
4288 : : * We leave the first rollup out of consideration since it's the
4289 : : * one that matches the input sort order. We assign indexes "i"
4290 : : * to only those entries considered for hashing; the second loop,
4291 : : * below, must use the same condition.
4292 : : */
4293 : 198 : i = 0;
1294 tgl@sss.pgh.pa.us 4294 [ + - + + : 504 : for_each_from(lc, gd->rollups, 1)
+ + ]
4295 : : {
2413 4296 : 306 : RollupData *rollup = lfirst_node(RollupData, lc);
4297 : :
2575 rhodiumtoad@postgres 4298 [ + - ]: 306 : if (rollup->hashable)
4299 : : {
1237 heikki.linnakangas@i 4300 : 306 : double sz = estimate_hashagg_tablesize(root,
4301 : : path,
4302 : : agg_costs,
4303 : : rollup->numGroups);
4304 : :
4305 : : /*
4306 : : * If sz is enormous, but hash_mem (and hence scale) is
4307 : : * small, avoid integer overflow here.
4308 : : */
2575 rhodiumtoad@postgres 4309 [ + + ]: 306 : k_weights[i] = (int) Min(floor(sz / scale),
4310 : : k_capacity + 1.0);
4311 : 306 : ++i;
4312 : : }
4313 : : }
4314 : :
4315 : : /*
4316 : : * Apply knapsack algorithm; compute the set of items which
4317 : : * maximizes the value stored (in this case the number of sorts
4318 : : * saved) while keeping the total size (approximately) within
4319 : : * capacity.
4320 : : */
4321 [ + - ]: 198 : if (i > 0)
4322 : 198 : hash_items = DiscreteKnapsack(k_capacity, i, k_weights, NULL);
4323 : :
4324 [ + - ]: 198 : if (!bms_is_empty(hash_items))
4325 : : {
4326 : 198 : rollups = list_make1(linitial(gd->rollups));
4327 : :
4328 : 198 : i = 0;
1294 tgl@sss.pgh.pa.us 4329 [ + - + + : 504 : for_each_from(lc, gd->rollups, 1)
+ + ]
4330 : : {
2413 4331 : 306 : RollupData *rollup = lfirst_node(RollupData, lc);
4332 : :
2575 rhodiumtoad@postgres 4333 [ + - ]: 306 : if (rollup->hashable)
4334 : : {
4335 [ + + ]: 306 : if (bms_is_member(i, hash_items))
4336 : 288 : hash_sets = list_concat(hash_sets,
1707 tgl@sss.pgh.pa.us 4337 : 288 : rollup->gsets_data);
4338 : : else
2575 rhodiumtoad@postgres 4339 : 18 : rollups = lappend(rollups, rollup);
4340 : 306 : ++i;
4341 : : }
4342 : : else
2575 rhodiumtoad@postgres 4343 :UBC 0 : rollups = lappend(rollups, rollup);
4344 : : }
4345 : : }
4346 : : }
4347 : :
2575 rhodiumtoad@postgres 4348 [ + + + + ]:CBC 358 : if (!rollups && hash_sets)
4349 : 12 : rollups = list_copy(gd->rollups);
4350 : :
4351 [ + + + + : 716 : foreach(lc, hash_sets)
+ + ]
4352 : : {
2413 tgl@sss.pgh.pa.us 4353 : 358 : GroupingSetData *gs = lfirst_node(GroupingSetData, lc);
2575 rhodiumtoad@postgres 4354 : 358 : RollupData *rollup = makeNode(RollupData);
4355 : :
4356 [ - + ]: 358 : Assert(gs->set != NIL);
4357 : :
84 akorotkov@postgresql 4358 :GNC 358 : rollup->groupClause = groupclause_apply_groupingset(root, gs->set);
2575 rhodiumtoad@postgres 4359 :CBC 358 : rollup->gsets_data = list_make1(gs);
4360 : 358 : rollup->gsets = remap_to_groupclause_idx(rollup->groupClause,
4361 : : rollup->gsets_data,
4362 : : gd->tleref_to_colnum_map);
4363 : 358 : rollup->numGroups = gs->numGroups;
4364 : 358 : rollup->hashable = true;
4365 : 358 : rollup->is_hashed = true;
4366 : 358 : rollups = lcons(rollup, rollups);
4367 : : }
4368 : :
4369 [ + + ]: 358 : if (rollups)
4370 : : {
4371 : 210 : add_path(grouped_rel, (Path *)
4372 : 210 : create_groupingsets_path(root,
4373 : : grouped_rel,
4374 : : path,
4375 : 210 : (List *) parse->havingQual,
4376 : : AGG_MIXED,
4377 : : rollups,
4378 : : agg_costs));
4379 : : }
4380 : : }
4381 : :
4382 : : /*
4383 : : * Now try the simple sorted case.
4384 : : */
4385 [ + + ]: 397 : if (!gd->unsortable_sets)
4386 : 382 : add_path(grouped_rel, (Path *)
4387 : 382 : create_groupingsets_path(root,
4388 : : grouped_rel,
4389 : : path,
4390 : 382 : (List *) parse->havingQual,
4391 : : AGG_SORTED,
4392 : : gd->rollups,
4393 : : agg_costs));
4394 : : }
4395 : :
4396 : : /*
4397 : : * create_window_paths
4398 : : *
4399 : : * Build a new upperrel containing Paths for window-function evaluation.
4400 : : *
4401 : : * input_rel: contains the source-data Paths
4402 : : * input_target: result of make_window_input_target
4403 : : * output_target: what the topmost WindowAggPath should return
4404 : : * wflists: result of find_window_functions
4405 : : * activeWindows: result of select_active_windows
4406 : : *
4407 : : * Note: all Paths in input_rel are expected to return input_target.
4408 : : */
4409 : : static RelOptInfo *
2960 tgl@sss.pgh.pa.us 4410 : 1147 : create_window_paths(PlannerInfo *root,
4411 : : RelOptInfo *input_rel,
4412 : : PathTarget *input_target,
4413 : : PathTarget *output_target,
4414 : : bool output_target_parallel_safe,
4415 : : WindowFuncLists *wflists,
4416 : : List *activeWindows)
4417 : : {
4418 : : RelOptInfo *window_rel;
4419 : : ListCell *lc;
4420 : :
4421 : : /* For now, do all work in the (WINDOW, NULL) upperrel */
4422 : 1147 : window_rel = fetch_upper_rel(root, UPPERREL_WINDOW, NULL);
4423 : :
4424 : : /*
4425 : : * If the input relation is not parallel-safe, then the window relation
4426 : : * can't be parallel-safe, either. Otherwise, we need to examine the
4427 : : * target list and active windows for non-parallel-safe constructs.
4428 : : */
2229 rhaas@postgresql.org 4429 [ + + - + : 1147 : if (input_rel->consider_parallel && output_target_parallel_safe &&
- - ]
2795 tgl@sss.pgh.pa.us 4430 :UBC 0 : is_parallel_safe(root, (Node *) activeWindows))
2844 rhaas@postgresql.org 4431 : 0 : window_rel->consider_parallel = true;
4432 : :
4433 : : /*
4434 : : * If the input rel belongs to a single FDW, so does the window rel.
4435 : : */
2844 tgl@sss.pgh.pa.us 4436 :CBC 1147 : window_rel->serverid = input_rel->serverid;
2830 4437 : 1147 : window_rel->userid = input_rel->userid;
4438 : 1147 : window_rel->useridiscurrent = input_rel->useridiscurrent;
2844 4439 : 1147 : window_rel->fdwroutine = input_rel->fdwroutine;
4440 : :
4441 : : /*
4442 : : * Consider computing window functions starting from the existing
4443 : : * cheapest-total path (which will likely require a sort) as well as any
4444 : : * existing paths that satisfy or partially satisfy root->window_pathkeys.
4445 : : */
2960 4446 [ + - + + : 2444 : foreach(lc, input_rel->pathlist)
+ + ]
4447 : : {
4448 : 1297 : Path *path = (Path *) lfirst(lc);
4449 : : int presorted_keys;
4450 : :
4451 [ + + + + ]: 1447 : if (path == input_rel->cheapest_total_path ||
1307 drowley@postgresql.o 4452 : 150 : pathkeys_count_contained_in(root->window_pathkeys, path->pathkeys,
4453 : 66 : &presorted_keys) ||
4454 [ + + ]: 66 : presorted_keys > 0)
2960 tgl@sss.pgh.pa.us 4455 : 1240 : create_one_window_path(root,
4456 : : window_rel,
4457 : : path,
4458 : : input_target,
4459 : : output_target,
4460 : : wflists,
4461 : : activeWindows);
4462 : : }
4463 : :
4464 : : /*
4465 : : * If there is an FDW that's responsible for all baserels of the query,
4466 : : * let it consider adding ForeignPaths.
4467 : : */
2844 4468 [ + + ]: 1147 : if (window_rel->fdwroutine &&
4469 [ + - ]: 6 : window_rel->fdwroutine->GetForeignUpperPaths)
4470 : 6 : window_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_WINDOW,
4471 : : input_rel, window_rel,
4472 : : NULL);
4473 : :
4474 : : /* Let extensions possibly add some more paths */
2924 4475 [ - + ]: 1147 : if (create_upper_paths_hook)
2924 tgl@sss.pgh.pa.us 4476 :UBC 0 : (*create_upper_paths_hook) (root, UPPERREL_WINDOW,
4477 : : input_rel, window_rel, NULL);
4478 : :
4479 : : /* Now choose the best path(s) */
2960 tgl@sss.pgh.pa.us 4480 :CBC 1147 : set_cheapest(window_rel);
4481 : :
4482 : 1147 : return window_rel;
4483 : : }
4484 : :
4485 : : /*
4486 : : * Stack window-function implementation steps atop the given Path, and
4487 : : * add the result to window_rel.
4488 : : *
4489 : : * window_rel: upperrel to contain result
4490 : : * path: input Path to use (must return input_target)
4491 : : * input_target: result of make_window_input_target
4492 : : * output_target: what the topmost WindowAggPath should return
4493 : : * wflists: result of find_window_functions
4494 : : * activeWindows: result of select_active_windows
4495 : : */
4496 : : static void
4497 : 1240 : create_one_window_path(PlannerInfo *root,
4498 : : RelOptInfo *window_rel,
4499 : : Path *path,
4500 : : PathTarget *input_target,
4501 : : PathTarget *output_target,
4502 : : WindowFuncLists *wflists,
4503 : : List *activeWindows)
4504 : : {
4505 : : PathTarget *window_target;
4506 : : ListCell *l;
737 drowley@postgresql.o 4507 : 1240 : List *topqual = NIL;
4508 : :
4509 : : /*
4510 : : * Since each window clause could require a different sort order, we stack
4511 : : * up a WindowAgg node for each clause, with sort steps between them as
4512 : : * needed. (We assume that select_active_windows chose a good order for
4513 : : * executing the clauses in.)
4514 : : *
4515 : : * input_target should contain all Vars and Aggs needed for the result.
4516 : : * (In some cases we wouldn't need to propagate all of these all the way
4517 : : * to the top, since they might only be needed as inputs to WindowFuncs.
4518 : : * It's probably not worth trying to optimize that though.) It must also
4519 : : * contain all window partitioning and sorting expressions, to ensure
4520 : : * they're computed only once at the bottom of the stack (that's critical
4521 : : * for volatile functions). As we climb up the stack, we'll add outputs
4522 : : * for the WindowFuncs computed at each level.
4523 : : */
2958 tgl@sss.pgh.pa.us 4524 : 1240 : window_target = input_target;
4525 : :
2960 4526 [ + - + + : 2555 : foreach(l, activeWindows)
+ + ]
4527 : : {
2413 4528 : 1315 : WindowClause *wc = lfirst_node(WindowClause, l);
4529 : : List *window_pathkeys;
4530 : : int presorted_keys;
4531 : : bool is_sorted;
4532 : : bool topwindow;
4533 : :
2960 4534 : 1315 : window_pathkeys = make_pathkeys_for_window(root,
4535 : : wc,
4536 : : root->processed_tlist);
4537 : :
1307 drowley@postgresql.o 4538 : 1315 : is_sorted = pathkeys_count_contained_in(window_pathkeys,
4539 : : path->pathkeys,
4540 : : &presorted_keys);
4541 : :
4542 : : /* Sort if necessary */
4543 [ + + ]: 1315 : if (!is_sorted)
4544 : : {
4545 : : /*
4546 : : * No presorted keys or incremental sort disabled, just perform a
4547 : : * complete sort.
4548 : : */
4549 [ + + - + ]: 1015 : if (presorted_keys == 0 || !enable_incremental_sort)
4550 : 988 : path = (Path *) create_sort_path(root, window_rel,
4551 : : path,
4552 : : window_pathkeys,
4553 : : -1.0);
4554 : : else
4555 : : {
4556 : : /*
4557 : : * Since we have presorted keys and incremental sort is
4558 : : * enabled, just use incremental sort.
4559 : : */
4560 : 27 : path = (Path *) create_incremental_sort_path(root,
4561 : : window_rel,
4562 : : path,
4563 : : window_pathkeys,
4564 : : presorted_keys,
4565 : : -1.0);
4566 : : }
4567 : : }
4568 : :
1735 tgl@sss.pgh.pa.us 4569 [ + + ]: 1315 : if (lnext(activeWindows, l))
4570 : : {
4571 : : /*
4572 : : * Add the current WindowFuncs to the output target for this
4573 : : * intermediate WindowAggPath. We must copy window_target to
4574 : : * avoid changing the previous path's target.
4575 : : *
4576 : : * Note: a WindowFunc adds nothing to the target's eval costs; but
4577 : : * we do need to account for the increase in tlist width.
4578 : : */
117 tgl@sss.pgh.pa.us 4579 :GNC 75 : int64 tuple_width = window_target->width;
4580 : : ListCell *lc2;
4581 : :
2958 tgl@sss.pgh.pa.us 4582 :CBC 75 : window_target = copy_pathtarget(window_target);
4583 [ + - + + : 171 : foreach(lc2, wflists->windowFuncs[wc->winref])
+ + ]
4584 : : {
2561 4585 : 96 : WindowFunc *wfunc = lfirst_node(WindowFunc, lc2);
4586 : :
2958 4587 : 96 : add_column_to_pathtarget(window_target, (Expr *) wfunc, 0);
117 tgl@sss.pgh.pa.us 4588 :GNC 96 : tuple_width += get_typavgwidth(wfunc->wintype, -1);
4589 : : }
4590 : 75 : window_target->width = clamp_width_est(tuple_width);
4591 : : }
4592 : : else
4593 : : {
4594 : : /* Install the goal target in the topmost WindowAgg */
2958 tgl@sss.pgh.pa.us 4595 :CBC 1240 : window_target = output_target;
4596 : : }
4597 : :
4598 : : /* mark the final item in the list as the top-level window */
737 drowley@postgresql.o 4599 : 1315 : topwindow = foreach_current_index(l) == list_length(activeWindows) - 1;
4600 : :
4601 : : /*
4602 : : * Accumulate all of the runConditions from each intermediate
4603 : : * WindowClause. The top-level WindowAgg must pass these as a qual so
4604 : : * that it filters out unwanted tuples correctly.
4605 : : */
4606 [ + + ]: 1315 : if (!topwindow)
4607 : 75 : topqual = list_concat(topqual, wc->runCondition);
4608 : :
4609 : : path = (Path *)
2958 tgl@sss.pgh.pa.us 4610 [ + + ]: 1315 : create_windowagg_path(root, window_rel, path, window_target,
2960 4611 : 1315 : wflists->windowFuncs[wc->winref],
4612 : : wc, topwindow ? topqual : NIL, topwindow);
4613 : : }
4614 : :
4615 : 1240 : add_path(window_rel, path);
6944 4616 : 1240 : }
4617 : :
4618 : : /*
4619 : : * create_distinct_paths
4620 : : *
4621 : : * Build a new upperrel containing Paths for SELECT DISTINCT evaluation.
4622 : : *
4623 : : * input_rel: contains the source-data Paths
4624 : : * target: the pathtarget for the result Paths to compute
4625 : : *
4626 : : * Note: input paths should already compute the desired pathtarget, since
4627 : : * Sort/Unique won't project anything.
4628 : : */
4629 : : static RelOptInfo *
67 drowley@postgresql.o 4630 :GNC 1098 : create_distinct_paths(PlannerInfo *root, RelOptInfo *input_rel,
4631 : : PathTarget *target)
4632 : : {
4633 : : RelOptInfo *distinct_rel;
4634 : :
4635 : : /* For now, do all work in the (DISTINCT, NULL) upperrel */
2960 tgl@sss.pgh.pa.us 4636 :CBC 1098 : distinct_rel = fetch_upper_rel(root, UPPERREL_DISTINCT, NULL);
4637 : :
4638 : : /*
4639 : : * We don't compute anything at this level, so distinct_rel will be
4640 : : * parallel-safe if the input rel is parallel-safe. In particular, if
4641 : : * there is a DISTINCT ON (...) clause, any path for the input_rel will
4642 : : * output those expressions, and will not be parallel-safe unless those
4643 : : * expressions are parallel-safe.
4644 : : */
2844 rhaas@postgresql.org 4645 : 1098 : distinct_rel->consider_parallel = input_rel->consider_parallel;
4646 : :
4647 : : /*
4648 : : * If the input rel belongs to a single FDW, so does the distinct_rel.
4649 : : */
tgl@sss.pgh.pa.us 4650 : 1098 : distinct_rel->serverid = input_rel->serverid;
2830 4651 : 1098 : distinct_rel->userid = input_rel->userid;
4652 : 1098 : distinct_rel->useridiscurrent = input_rel->useridiscurrent;
2844 4653 : 1098 : distinct_rel->fdwroutine = input_rel->fdwroutine;
4654 : :
4655 : : /* build distinct paths based on input_rel's pathlist */
966 drowley@postgresql.o 4656 : 1098 : create_final_distinct_paths(root, input_rel, distinct_rel);
4657 : :
4658 : : /* now build distinct paths based on input_rel's partial_pathlist */
67 drowley@postgresql.o 4659 :GNC 1098 : create_partial_distinct_paths(root, input_rel, distinct_rel, target);
4660 : :
4661 : : /* Give a helpful error if we failed to create any paths */
966 drowley@postgresql.o 4662 [ - + ]:CBC 1098 : if (distinct_rel->pathlist == NIL)
966 drowley@postgresql.o 4663 [ # # ]:UBC 0 : ereport(ERROR,
4664 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4665 : : errmsg("could not implement DISTINCT"),
4666 : : errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
4667 : :
4668 : : /*
4669 : : * If there is an FDW that's responsible for all baserels of the query,
4670 : : * let it consider adding ForeignPaths.
4671 : : */
966 drowley@postgresql.o 4672 [ + + ]:CBC 1098 : if (distinct_rel->fdwroutine &&
4673 [ + - ]: 8 : distinct_rel->fdwroutine->GetForeignUpperPaths)
4674 : 8 : distinct_rel->fdwroutine->GetForeignUpperPaths(root,
4675 : : UPPERREL_DISTINCT,
4676 : : input_rel,
4677 : : distinct_rel,
4678 : : NULL);
4679 : :
4680 : : /* Let extensions possibly add some more paths */
4681 [ - + ]: 1098 : if (create_upper_paths_hook)
966 drowley@postgresql.o 4682 :UBC 0 : (*create_upper_paths_hook) (root, UPPERREL_DISTINCT, input_rel,
4683 : : distinct_rel, NULL);
4684 : :
4685 : : /* Now choose the best path(s) */
966 drowley@postgresql.o 4686 :CBC 1098 : set_cheapest(distinct_rel);
4687 : :
4688 : 1098 : return distinct_rel;
4689 : : }
4690 : :
4691 : : /*
4692 : : * create_partial_distinct_paths
4693 : : *
4694 : : * Process 'input_rel' partial paths and add unique/aggregate paths to the
4695 : : * UPPERREL_PARTIAL_DISTINCT rel. For paths created, add Gather/GatherMerge
4696 : : * paths on top and add a final unique/aggregate path to remove any duplicate
4697 : : * produced from combining rows from parallel workers.
4698 : : */
4699 : : static void
4700 : 1098 : create_partial_distinct_paths(PlannerInfo *root, RelOptInfo *input_rel,
4701 : : RelOptInfo *final_distinct_rel,
4702 : : PathTarget *target)
4703 : : {
4704 : : RelOptInfo *partial_distinct_rel;
4705 : : Query *parse;
4706 : : List *distinctExprs;
4707 : : double numDistinctRows;
4708 : : Path *cheapest_partial_path;
4709 : : ListCell *lc;
4710 : :
4711 : : /* nothing to do when there are no partial paths in the input rel */
4712 [ + + + + ]: 1098 : if (!input_rel->consider_parallel || input_rel->partial_pathlist == NIL)
4713 : 1050 : return;
4714 : :
4715 : 48 : parse = root->parse;
4716 : :
4717 : : /* can't do parallel DISTINCT ON */
4718 [ - + ]: 48 : if (parse->hasDistinctOn)
966 drowley@postgresql.o 4719 :UBC 0 : return;
4720 : :
966 drowley@postgresql.o 4721 :CBC 48 : partial_distinct_rel = fetch_upper_rel(root, UPPERREL_PARTIAL_DISTINCT,
4722 : : NULL);
67 drowley@postgresql.o 4723 :GNC 48 : partial_distinct_rel->reltarget = target;
966 drowley@postgresql.o 4724 :CBC 48 : partial_distinct_rel->consider_parallel = input_rel->consider_parallel;
4725 : :
4726 : : /*
4727 : : * If input_rel belongs to a single FDW, so does the partial_distinct_rel.
4728 : : */
4729 : 48 : partial_distinct_rel->serverid = input_rel->serverid;
4730 : 48 : partial_distinct_rel->userid = input_rel->userid;
4731 : 48 : partial_distinct_rel->useridiscurrent = input_rel->useridiscurrent;
4732 : 48 : partial_distinct_rel->fdwroutine = input_rel->fdwroutine;
4733 : :
4734 : 48 : cheapest_partial_path = linitial(input_rel->partial_pathlist);
4735 : :
452 tgl@sss.pgh.pa.us 4736 : 48 : distinctExprs = get_sortgrouplist_exprs(root->processed_distinctClause,
4737 : : parse->targetList);
4738 : :
4739 : : /* estimate how many distinct rows we'll get from each worker */
966 drowley@postgresql.o 4740 : 48 : numDistinctRows = estimate_num_groups(root, distinctExprs,
4741 : : cheapest_partial_path->rows,
4742 : : NULL, NULL);
4743 : :
4744 : : /*
4745 : : * Try sorting the cheapest path and incrementally sorting any paths with
4746 : : * presorted keys and put a unique paths atop of those.
4747 : : */
452 tgl@sss.pgh.pa.us 4748 [ + - ]: 48 : if (grouping_is_sortable(root->processed_distinctClause))
4749 : : {
966 drowley@postgresql.o 4750 [ + - + + : 99 : foreach(lc, input_rel->partial_pathlist)
+ + ]
4751 : : {
459 4752 : 51 : Path *input_path = (Path *) lfirst(lc);
4753 : : Path *sorted_path;
4754 : : bool is_sorted;
4755 : : int presorted_keys;
4756 : :
4757 : 51 : is_sorted = pathkeys_count_contained_in(root->distinct_pathkeys,
4758 : : input_path->pathkeys,
4759 : : &presorted_keys);
4760 : :
4761 [ + + ]: 51 : if (is_sorted)
459 drowley@postgresql.o 4762 :GBC 3 : sorted_path = input_path;
4763 : : else
4764 : : {
4765 : : /*
4766 : : * Try at least sorting the cheapest path and also try
4767 : : * incrementally sorting any path which is partially sorted
4768 : : * already (no need to deal with paths which have presorted
4769 : : * keys when incremental sort is disabled unless it's the
4770 : : * cheapest partial path).
4771 : : */
459 drowley@postgresql.o 4772 [ + + ]:CBC 48 : if (input_path != cheapest_partial_path &&
4773 [ + - - + ]: 3 : (presorted_keys == 0 || !enable_incremental_sort))
459 drowley@postgresql.o 4774 :UBC 0 : continue;
4775 : :
4776 : : /*
4777 : : * We've no need to consider both a sort and incremental sort.
4778 : : * We'll just do a sort if there are no presorted keys and an
4779 : : * incremental sort when there are presorted keys.
4780 : : */
459 drowley@postgresql.o 4781 [ + + + + ]:CBC 48 : if (presorted_keys == 0 || !enable_incremental_sort)
4782 : 45 : sorted_path = (Path *) create_sort_path(root,
4783 : : partial_distinct_rel,
4784 : : input_path,
4785 : : root->distinct_pathkeys,
4786 : : -1.0);
4787 : : else
4788 : 3 : sorted_path = (Path *) create_incremental_sort_path(root,
4789 : : partial_distinct_rel,
4790 : : input_path,
4791 : : root->distinct_pathkeys,
4792 : : presorted_keys,
4793 : : -1.0);
4794 : : }
4795 : :
4796 : : /*
4797 : : * An empty distinct_pathkeys means all tuples have the same value
4798 : : * for the DISTINCT clause. See create_final_distinct_paths()
4799 : : */
74 drowley@postgresql.o 4800 [ + + ]:GNC 51 : if (root->distinct_pathkeys == NIL)
4801 : : {
4802 : : Node *limitCount;
4803 : :
4804 : 3 : limitCount = (Node *) makeConst(INT8OID, -1, InvalidOid,
4805 : : sizeof(int64),
4806 : : Int64GetDatum(1), false,
4807 : : FLOAT8PASSBYVAL);
4808 : :
4809 : : /*
4810 : : * Apply a LimitPath onto the partial path to restrict the
4811 : : * tuples from each worker to 1. create_final_distinct_paths
4812 : : * will need to apply an additional LimitPath to restrict this
4813 : : * to a single row after the Gather node. If the query
4814 : : * already has a LIMIT clause, then we could end up with three
4815 : : * Limit nodes in the final plan. Consolidating the top two
4816 : : * of these could be done, but does not seem worth troubling
4817 : : * over.
4818 : : */
4819 : 3 : add_partial_path(partial_distinct_rel, (Path *)
4820 : 3 : create_limit_path(root, partial_distinct_rel,
4821 : : sorted_path,
4822 : : NULL,
4823 : : limitCount,
4824 : : LIMIT_OPTION_COUNT,
4825 : : 0, 1));
4826 : : }
4827 : : else
4828 : : {
4829 : 48 : add_partial_path(partial_distinct_rel, (Path *)
4830 : 48 : create_upper_unique_path(root, partial_distinct_rel,
4831 : : sorted_path,
4832 : 48 : list_length(root->distinct_pathkeys),
4833 : : numDistinctRows));
4834 : : }
4835 : : }
4836 : : }
4837 : :
4838 : : /*
4839 : : * Now try hash aggregate paths, if enabled and hashing is possible. Since
4840 : : * we're not on the hook to ensure we do our best to create at least one
4841 : : * path here, we treat enable_hashagg as a hard off-switch rather than the
4842 : : * slightly softer variant in create_final_distinct_paths.
4843 : : */
452 tgl@sss.pgh.pa.us 4844 [ + + + - ]:CBC 48 : if (enable_hashagg && grouping_is_hashable(root->processed_distinctClause))
4845 : : {
966 drowley@postgresql.o 4846 : 39 : add_partial_path(partial_distinct_rel, (Path *)
4847 : 39 : create_agg_path(root,
4848 : : partial_distinct_rel,
4849 : : cheapest_partial_path,
4850 : : cheapest_partial_path->pathtarget,
4851 : : AGG_HASHED,
4852 : : AGGSPLIT_SIMPLE,
4853 : : root->processed_distinctClause,
4854 : : NIL,
4855 : : NULL,
4856 : : numDistinctRows));
4857 : : }
4858 : :
4859 : : /*
4860 : : * If there is an FDW that's responsible for all baserels of the query,
4861 : : * let it consider adding ForeignPaths.
4862 : : */
4863 [ - + ]: 48 : if (partial_distinct_rel->fdwroutine &&
966 drowley@postgresql.o 4864 [ # # ]:UBC 0 : partial_distinct_rel->fdwroutine->GetForeignUpperPaths)
4865 : 0 : partial_distinct_rel->fdwroutine->GetForeignUpperPaths(root,
4866 : : UPPERREL_PARTIAL_DISTINCT,
4867 : : input_rel,
4868 : : partial_distinct_rel,
4869 : : NULL);
4870 : :
4871 : : /* Let extensions possibly add some more partial paths */
966 drowley@postgresql.o 4872 [ - + ]:CBC 48 : if (create_upper_paths_hook)
966 drowley@postgresql.o 4873 :UBC 0 : (*create_upper_paths_hook) (root, UPPERREL_PARTIAL_DISTINCT,
4874 : : input_rel, partial_distinct_rel, NULL);
4875 : :
966 drowley@postgresql.o 4876 [ + - ]:CBC 48 : if (partial_distinct_rel->partial_pathlist != NIL)
4877 : : {
71 drowley@postgresql.o 4878 :GNC 48 : generate_useful_gather_paths(root, partial_distinct_rel, true);
966 drowley@postgresql.o 4879 :CBC 48 : set_cheapest(partial_distinct_rel);
4880 : :
4881 : : /*
4882 : : * Finally, create paths to distinctify the final result. This step
4883 : : * is needed to remove any duplicates due to combining rows from
4884 : : * parallel workers.
4885 : : */
4886 : 48 : create_final_distinct_paths(root, partial_distinct_rel,
4887 : : final_distinct_rel);
4888 : : }
4889 : : }
4890 : :
4891 : : /*
4892 : : * create_final_distinct_paths
4893 : : * Create distinct paths in 'distinct_rel' based on 'input_rel' pathlist
4894 : : *
4895 : : * input_rel: contains the source-data paths
4896 : : * distinct_rel: destination relation for storing created paths
4897 : : */
4898 : : static RelOptInfo *
4899 : 1146 : create_final_distinct_paths(PlannerInfo *root, RelOptInfo *input_rel,
4900 : : RelOptInfo *distinct_rel)
4901 : : {
4902 : 1146 : Query *parse = root->parse;
4903 : 1146 : Path *cheapest_input_path = input_rel->cheapest_total_path;
4904 : : double numDistinctRows;
4905 : : bool allow_hash;
4906 : :
4907 : : /* Estimate number of distinct rows there will be */
2960 tgl@sss.pgh.pa.us 4908 [ + + + - : 1146 : if (parse->groupClause || parse->groupingSets || parse->hasAggs ||
+ + ]
4909 [ - + ]: 1127 : root->hasHavingQual)
4910 : : {
4911 : : /*
4912 : : * If there was grouping or aggregation, use the number of input rows
4913 : : * as the estimated number of DISTINCT rows (ie, assume the input is
4914 : : * already mostly unique).
4915 : : */
4916 : 19 : numDistinctRows = cheapest_input_path->rows;
4917 : : }
4918 : : else
4919 : : {
4920 : : /*
4921 : : * Otherwise, the UNIQUE filter has effects comparable to GROUP BY.
4922 : : */
4923 : : List *distinctExprs;
4924 : :
452 4925 : 1127 : distinctExprs = get_sortgrouplist_exprs(root->processed_distinctClause,
4926 : : parse->targetList);
2960 4927 : 1127 : numDistinctRows = estimate_num_groups(root, distinctExprs,
4928 : : cheapest_input_path->rows,
4929 : : NULL, NULL);
4930 : : }
4931 : :
4932 : : /*
4933 : : * Consider sort-based implementations of DISTINCT, if possible.
4934 : : */
452 4935 [ + + ]: 1146 : if (grouping_is_sortable(root->processed_distinctClause))
4936 : : {
4937 : : /*
4938 : : * Firstly, if we have any adequately-presorted paths, just stick a
4939 : : * Unique node on those. We also, consider doing an explicit sort of
4940 : : * the cheapest input path and Unique'ing that. If any paths have
4941 : : * presorted keys then we'll create an incremental sort atop of those
4942 : : * before adding a unique node on the top.
4943 : : *
4944 : : * When we have DISTINCT ON, we must sort by the more rigorous of
4945 : : * DISTINCT and ORDER BY, else it won't have the desired behavior.
4946 : : * Also, if we do have to do an explicit sort, we might as well use
4947 : : * the more rigorous ordering to avoid a second sort later. (Note
4948 : : * that the parser will have ensured that one clause is a prefix of
4949 : : * the other.)
4950 : : */
4951 : : List *needed_pathkeys;
4952 : : ListCell *lc;
459 drowley@postgresql.o 4953 [ + + ]: 1143 : double limittuples = root->distinct_pathkeys == NIL ? 1.0 : -1.0;
4954 : :
2960 tgl@sss.pgh.pa.us 4955 [ + + + + ]: 1225 : if (parse->hasDistinctOn &&
4956 : 82 : list_length(root->distinct_pathkeys) <
4957 : 82 : list_length(root->sort_pathkeys))
4958 : 21 : needed_pathkeys = root->sort_pathkeys;
4959 : : else
4960 : 1122 : needed_pathkeys = root->distinct_pathkeys;
4961 : :
4962 [ + - + + : 2731 : foreach(lc, input_rel->pathlist)
+ + ]
4963 : : {
459 drowley@postgresql.o 4964 : 1588 : Path *input_path = (Path *) lfirst(lc);
4965 : : Path *sorted_path;
4966 : : bool is_sorted;
4967 : : int presorted_keys;
4968 : :
4969 : 1588 : is_sorted = pathkeys_count_contained_in(needed_pathkeys,
4970 : : input_path->pathkeys,
4971 : : &presorted_keys);
4972 : :
4973 [ + + ]: 1588 : if (is_sorted)
4974 : 335 : sorted_path = input_path;
4975 : : else
4976 : : {
4977 : : /*
4978 : : * Try at least sorting the cheapest path and also try
4979 : : * incrementally sorting any path which is partially sorted
4980 : : * already (no need to deal with paths which have presorted
4981 : : * keys when incremental sort is disabled unless it's the
4982 : : * cheapest input path).
4983 : : */
4984 [ + + ]: 1253 : if (input_path != cheapest_input_path &&
4985 [ + + + + ]: 204 : (presorted_keys == 0 || !enable_incremental_sort))
4986 : 41 : continue;
4987 : :
4988 : : /*
4989 : : * We've no need to consider both a sort and incremental sort.
4990 : : * We'll just do a sort if there are no presorted keys and an
4991 : : * incremental sort when there are presorted keys.
4992 : : */
4993 [ + + - + ]: 1212 : if (presorted_keys == 0 || !enable_incremental_sort)
4994 : 1040 : sorted_path = (Path *) create_sort_path(root,
4995 : : distinct_rel,
4996 : : input_path,
4997 : : needed_pathkeys,
4998 : : limittuples);
4999 : : else
5000 : 172 : sorted_path = (Path *) create_incremental_sort_path(root,
5001 : : distinct_rel,
5002 : : input_path,
5003 : : needed_pathkeys,
5004 : : presorted_keys,
5005 : : limittuples);
5006 : : }
5007 : :
5008 : : /*
5009 : : * distinct_pathkeys may have become empty if all of the pathkeys
5010 : : * were determined to be redundant. If all of the pathkeys are
5011 : : * redundant then each DISTINCT target must only allow a single
5012 : : * value, therefore all resulting tuples must be identical (or at
5013 : : * least indistinguishable by an equality check). We can uniquify
5014 : : * these tuples simply by just taking the first tuple. All we do
5015 : : * here is add a path to do "LIMIT 1" atop of 'sorted_path'. When
5016 : : * doing a DISTINCT ON we may still have a non-NIL sort_pathkeys
5017 : : * list, so we must still only do this with paths which are
5018 : : * correctly sorted by sort_pathkeys.
5019 : : */
5020 [ + + ]: 1547 : if (root->distinct_pathkeys == NIL)
5021 : : {
5022 : : Node *limitCount;
5023 : :
5024 : 49 : limitCount = (Node *) makeConst(INT8OID, -1, InvalidOid,
5025 : : sizeof(int64),
5026 : : Int64GetDatum(1), false,
5027 : : FLOAT8PASSBYVAL);
5028 : :
5029 : : /*
5030 : : * If the query already has a LIMIT clause, then we could end
5031 : : * up with a duplicate LimitPath in the final plan. That does
5032 : : * not seem worth troubling over too much.
5033 : : */
5034 : 49 : add_path(distinct_rel, (Path *)
5035 : 49 : create_limit_path(root, distinct_rel, sorted_path,
5036 : : NULL, limitCount,
5037 : : LIMIT_OPTION_COUNT, 0, 1));
5038 : : }
5039 : : else
5040 : : {
5041 : 1498 : add_path(distinct_rel, (Path *)
5042 : 1498 : create_upper_unique_path(root, distinct_rel,
5043 : : sorted_path,
5044 : 1498 : list_length(root->distinct_pathkeys),
5045 : : numDistinctRows));
5046 : : }
5047 : : }
5048 : : }
5049 : :
5050 : : /*
5051 : : * Consider hash-based implementations of DISTINCT, if possible.
5052 : : *
5053 : : * If we were not able to make any other types of path, we *must* hash or
5054 : : * die trying. If we do have other choices, there are two things that
5055 : : * should prevent selection of hashing: if the query uses DISTINCT ON
5056 : : * (because it won't really have the expected behavior if we hash), or if
5057 : : * enable_hashagg is off.
5058 : : *
5059 : : * Note: grouping_is_hashable() is much more expensive to check than the
5060 : : * other gating conditions, so we want to do it last.
5061 : : */
2960 tgl@sss.pgh.pa.us 5062 [ + + ]: 1146 : if (distinct_rel->pathlist == NIL)
5063 : 3 : allow_hash = true; /* we have no alternatives */
5064 [ + + + + ]: 1143 : else if (parse->hasDistinctOn || !enable_hashagg)
5065 : 127 : allow_hash = false; /* policy-based decision not to hash */
5066 : : else
1357 pg@bowt.ie 5067 : 1016 : allow_hash = true; /* default */
5068 : :
452 tgl@sss.pgh.pa.us 5069 [ + + + - ]: 1146 : if (allow_hash && grouping_is_hashable(root->processed_distinctClause))
5070 : : {
5071 : : /* Generate hashed aggregate path --- no sort needed */
2960 5072 : 1019 : add_path(distinct_rel, (Path *)
5073 : 1019 : create_agg_path(root,
5074 : : distinct_rel,
5075 : : cheapest_input_path,
5076 : : cheapest_input_path->pathtarget,
5077 : : AGG_HASHED,
5078 : : AGGSPLIT_SIMPLE,
5079 : : root->processed_distinctClause,
5080 : : NIL,
5081 : : NULL,
5082 : : numDistinctRows));
5083 : : }
5084 : :
5085 : 1146 : return distinct_rel;
5086 : : }
5087 : :
5088 : : /*
5089 : : * create_ordered_paths
5090 : : *
5091 : : * Build a new upperrel containing Paths for ORDER BY evaluation.
5092 : : *
5093 : : * All paths in the result must satisfy the ORDER BY ordering.
5094 : : * The only new paths we need consider are an explicit full sort
5095 : : * and incremental sort on the cheapest-total existing path.
5096 : : *
5097 : : * input_rel: contains the source-data Paths
5098 : : * target: the output tlist the result Paths must emit
5099 : : * limit_tuples: estimated bound on the number of output tuples,
5100 : : * or -1 if no LIMIT or couldn't estimate
5101 : : *
5102 : : * XXX This only looks at sort_pathkeys. I wonder if it needs to look at the
5103 : : * other pathkeys (grouping, ...) like generate_useful_gather_paths.
5104 : : */
5105 : : static RelOptInfo *
5106 : 28656 : create_ordered_paths(PlannerInfo *root,
5107 : : RelOptInfo *input_rel,
5108 : : PathTarget *target,
5109 : : bool target_parallel_safe,
5110 : : double limit_tuples)
5111 : : {
5112 : 28656 : Path *cheapest_input_path = input_rel->cheapest_total_path;
5113 : : RelOptInfo *ordered_rel;
5114 : : ListCell *lc;
5115 : :
5116 : : /* For now, do all work in the (ORDERED, NULL) upperrel */
5117 : 28656 : ordered_rel = fetch_upper_rel(root, UPPERREL_ORDERED, NULL);
5118 : :
5119 : : /*
5120 : : * If the input relation is not parallel-safe, then the ordered relation
5121 : : * can't be parallel-safe, either. Otherwise, it's parallel-safe if the
5122 : : * target list is parallel-safe.
5123 : : */
2229 rhaas@postgresql.org 5124 [ + + + + ]: 28656 : if (input_rel->consider_parallel && target_parallel_safe)
2844 5125 : 19009 : ordered_rel->consider_parallel = true;
5126 : :
5127 : : /*
5128 : : * If the input rel belongs to a single FDW, so does the ordered_rel.
5129 : : */
tgl@sss.pgh.pa.us 5130 : 28656 : ordered_rel->serverid = input_rel->serverid;
2830 5131 : 28656 : ordered_rel->userid = input_rel->userid;
5132 : 28656 : ordered_rel->useridiscurrent = input_rel->useridiscurrent;
2844 5133 : 28656 : ordered_rel->fdwroutine = input_rel->fdwroutine;
5134 : :
2960 5135 [ + - + + : 71783 : foreach(lc, input_rel->pathlist)
+ + ]
5136 : : {
1469 tomas.vondra@postgre 5137 : 43127 : Path *input_path = (Path *) lfirst(lc);
5138 : : Path *sorted_path;
5139 : : bool is_sorted;
5140 : : int presorted_keys;
5141 : :
5142 : 43127 : is_sorted = pathkeys_count_contained_in(root->sort_pathkeys,
5143 : : input_path->pathkeys, &presorted_keys);
5144 : :
5145 [ + + ]: 43127 : if (is_sorted)
485 drowley@postgresql.o 5146 : 15965 : sorted_path = input_path;
5147 : : else
5148 : : {
5149 : : /*
5150 : : * Try at least sorting the cheapest path and also try
5151 : : * incrementally sorting any path which is partially sorted
5152 : : * already (no need to deal with paths which have presorted keys
5153 : : * when incremental sort is disabled unless it's the cheapest
5154 : : * input path).
5155 : : */
5156 [ + + ]: 27162 : if (input_path != cheapest_input_path &&
5157 [ + + + + ]: 2599 : (presorted_keys == 0 || !enable_incremental_sort))
5158 : 827 : continue;
5159 : :
5160 : : /*
5161 : : * We've no need to consider both a sort and incremental sort.
5162 : : * We'll just do a sort if there are no presorted keys and an
5163 : : * incremental sort when there are presorted keys.
5164 : : */
5165 [ + + + + ]: 26335 : if (presorted_keys == 0 || !enable_incremental_sort)
1469 tomas.vondra@postgre 5166 : 24347 : sorted_path = (Path *) create_sort_path(root,
5167 : : ordered_rel,
5168 : : input_path,
5169 : : root->sort_pathkeys,
5170 : : limit_tuples);
5171 : : else
485 drowley@postgresql.o 5172 : 1988 : sorted_path = (Path *) create_incremental_sort_path(root,
5173 : : ordered_rel,
5174 : : input_path,
5175 : : root->sort_pathkeys,
5176 : : presorted_keys,
5177 : : limit_tuples);
5178 : : }
5179 : :
5180 : : /* Add projection step if needed */
5181 [ + + ]: 42300 : if (sorted_path->pathtarget != target)
5182 : 8617 : sorted_path = apply_projection_to_path(root, ordered_rel,
5183 : : sorted_path, target);
5184 : :
5185 : 42300 : add_path(ordered_rel, sorted_path);
5186 : : }
5187 : :
5188 : : /*
5189 : : * generate_gather_paths() will have already generated a simple Gather
5190 : : * path for the best parallel path, if any, and the loop above will have
5191 : : * considered sorting it. Similarly, generate_gather_paths() will also
5192 : : * have generated order-preserving Gather Merge plans which can be used
5193 : : * without sorting if they happen to match the sort_pathkeys, and the loop
5194 : : * above will have handled those as well. However, there's one more
5195 : : * possibility: it may make sense to sort the cheapest partial path or
5196 : : * incrementally sort any partial path that is partially sorted according
5197 : : * to the required output order and then use Gather Merge.
5198 : : */
2593 rhaas@postgresql.org 5199 [ + + + + ]: 28656 : if (ordered_rel->consider_parallel && root->sort_pathkeys != NIL &&
5200 [ + + ]: 18940 : input_rel->partial_pathlist != NIL)
5201 : : {
5202 : : Path *cheapest_partial_path;
5203 : :
5204 : 1057 : cheapest_partial_path = linitial(input_rel->partial_pathlist);
5205 : :
74 drowley@postgresql.o 5206 [ + - + + :GNC 2223 : foreach(lc, input_rel->partial_pathlist)
+ + ]
5207 : : {
5208 : 1166 : Path *input_path = (Path *) lfirst(lc);
5209 : : Path *sorted_path;
5210 : : bool is_sorted;
5211 : : int presorted_keys;
5212 : : double total_groups;
5213 : :
5214 : 1166 : is_sorted = pathkeys_count_contained_in(root->sort_pathkeys,
5215 : : input_path->pathkeys,
5216 : : &presorted_keys);
5217 : :
5218 [ + + ]: 1166 : if (is_sorted)
5219 : 97 : continue;
5220 : :
5221 : : /*
5222 : : * Try at least sorting the cheapest path and also try
5223 : : * incrementally sorting any path which is partially sorted
5224 : : * already (no need to deal with paths which have presorted keys
5225 : : * when incremental sort is disabled unless it's the cheapest
5226 : : * partial path).
5227 : : */
5228 [ + + ]: 1069 : if (input_path != cheapest_partial_path &&
5229 [ + - - + ]: 21 : (presorted_keys == 0 || !enable_incremental_sort))
74 drowley@postgresql.o 5230 :UNC 0 : continue;
5231 : :
5232 : : /*
5233 : : * We've no need to consider both a sort and incremental sort.
5234 : : * We'll just do a sort if there are no presorted keys and an
5235 : : * incremental sort when there are presorted keys.
5236 : : */
74 drowley@postgresql.o 5237 [ + + + + ]:GNC 1069 : if (presorted_keys == 0 || !enable_incremental_sort)
5238 : 1039 : sorted_path = (Path *) create_sort_path(root,
5239 : : ordered_rel,
5240 : : input_path,
5241 : : root->sort_pathkeys,
5242 : : limit_tuples);
5243 : : else
1468 tomas.vondra@postgre 5244 :CBC 30 : sorted_path = (Path *) create_incremental_sort_path(root,
5245 : : ordered_rel,
5246 : : input_path,
5247 : : root->sort_pathkeys,
5248 : : presorted_keys,
5249 : : limit_tuples);
74 drowley@postgresql.o 5250 :GNC 1069 : total_groups = input_path->rows *
5251 : 1069 : input_path->parallel_workers;
5252 : : sorted_path = (Path *)
5253 : 1069 : create_gather_merge_path(root, ordered_rel,
5254 : : sorted_path,
5255 : : sorted_path->pathtarget,
5256 : : root->sort_pathkeys, NULL,
5257 : : &total_groups);
5258 : :
5259 : : /* Add projection step if needed */
5260 [ + + ]: 1069 : if (sorted_path->pathtarget != target)
5261 : 218 : sorted_path = apply_projection_to_path(root, ordered_rel,
5262 : : sorted_path, target);
5263 : :
5264 : 1069 : add_path(ordered_rel, sorted_path);
5265 : : }
5266 : : }
5267 : :
5268 : : /*
5269 : : * If there is an FDW that's responsible for all baserels of the query,
5270 : : * let it consider adding ForeignPaths.
5271 : : */
2844 tgl@sss.pgh.pa.us 5272 [ + + ]:CBC 28656 : if (ordered_rel->fdwroutine &&
5273 [ + + ]: 188 : ordered_rel->fdwroutine->GetForeignUpperPaths)
5274 : 181 : ordered_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_ORDERED,
5275 : : input_rel, ordered_rel,
5276 : : NULL);
5277 : :
5278 : : /* Let extensions possibly add some more paths */
2924 5279 [ - + ]: 28656 : if (create_upper_paths_hook)
2924 tgl@sss.pgh.pa.us 5280 :UBC 0 : (*create_upper_paths_hook) (root, UPPERREL_ORDERED,
5281 : : input_rel, ordered_rel, NULL);
5282 : :
5283 : : /*
5284 : : * No need to bother with set_cheapest here; grouping_planner does not
5285 : : * need us to do it.
5286 : : */
2960 tgl@sss.pgh.pa.us 5287 [ - + ]:CBC 28656 : Assert(ordered_rel->pathlist != NIL);
5288 : :
5289 : 28656 : return ordered_rel;
5290 : : }
5291 : :
5292 : :
5293 : : /*
5294 : : * make_group_input_target
5295 : : * Generate appropriate PathTarget for initial input to grouping nodes.
5296 : : *
5297 : : * If there is grouping or aggregation, the scan/join subplan cannot emit
5298 : : * the query's final targetlist; for example, it certainly can't emit any
5299 : : * aggregate function calls. This routine generates the correct target
5300 : : * for the scan/join subplan.
5301 : : *
5302 : : * The query target list passed from the parser already contains entries
5303 : : * for all ORDER BY and GROUP BY expressions, but it will not have entries
5304 : : * for variables used only in HAVING clauses; so we need to add those
5305 : : * variables to the subplan target list. Also, we flatten all expressions
5306 : : * except GROUP BY items into their component variables; other expressions
5307 : : * will be computed by the upper plan nodes rather than by the subplan.
5308 : : * For example, given a query like
5309 : : * SELECT a+b,SUM(c+d) FROM table GROUP BY a+b;
5310 : : * we want to pass this targetlist to the subplan:
5311 : : * a+b,c,d
5312 : : * where the a+b target will be used by the Sort/Group steps, and the
5313 : : * other targets will be used for computing the final results.
5314 : : *
5315 : : * 'final_target' is the query's final target list (in PathTarget form)
5316 : : *
5317 : : * The result is the PathTarget to be computed by the Paths returned from
5318 : : * query_planner().
5319 : : */
5320 : : static PathTarget *
2956 5321 : 17996 : make_group_input_target(PlannerInfo *root, PathTarget *final_target)
5322 : : {
6888 5323 : 17996 : Query *parse = root->parse;
5324 : : PathTarget *input_target;
5325 : : List *non_group_cols;
5326 : : List *non_group_vars;
5327 : : int i;
5328 : : ListCell *lc;
5329 : :
5330 : : /*
5331 : : * We must build a target containing all grouping columns, plus any other
5332 : : * Vars mentioned in the query's targetlist and HAVING qual.
5333 : : */
2956 5334 : 17996 : input_target = create_empty_pathtarget();
4656 5335 : 17996 : non_group_cols = NIL;
5336 : :
2956 5337 : 17996 : i = 0;
5338 [ + - + + : 43439 : foreach(lc, final_target->exprs)
+ + ]
5339 : : {
5340 : 25443 : Expr *expr = (Expr *) lfirst(lc);
2862 5341 [ + - ]: 25443 : Index sgref = get_pathtarget_sortgroupref(final_target, i);
5342 : :
452 5343 [ + + + + : 29429 : if (sgref && root->processed_groupClause &&
+ + ]
5344 : 3986 : get_sortgroupref_clause_noerr(sgref,
5345 : : root->processed_groupClause) != NULL)
5346 : : {
5347 : : /*
5348 : : * It's a grouping column, so add it to the input target as-is.
5349 : : */
2956 5350 : 3208 : add_column_to_pathtarget(input_target, expr, sgref);
5351 : : }
5352 : : else
5353 : : {
5354 : : /*
5355 : : * Non-grouping column, so just remember the expression for later
5356 : : * call to pull_var_clause.
5357 : : */
5358 : 22235 : non_group_cols = lappend(non_group_cols, expr);
5359 : : }
5360 : :
5361 : 25443 : i++;
5362 : : }
5363 : :
5364 : : /*
5365 : : * If there's a HAVING clause, we'll need the Vars it uses, too.
5366 : : */
4656 5367 [ + + ]: 17996 : if (parse->havingQual)
5368 : 493 : non_group_cols = lappend(non_group_cols, parse->havingQual);
5369 : :
5370 : : /*
5371 : : * Pull out all the Vars mentioned in non-group cols (plus HAVING), and
5372 : : * add them to the input target if not already present. (A Var used
5373 : : * directly as a GROUP BY item will be present already.) Note this
5374 : : * includes Vars used in resjunk items, so we are covering the needs of
5375 : : * ORDER BY and window specifications. Vars used within Aggrefs and
5376 : : * WindowFuncs will be pulled out here, too.
5377 : : */
5378 : 17996 : non_group_vars = pull_var_clause((Node *) non_group_cols,
5379 : : PVC_RECURSE_AGGREGATES |
5380 : : PVC_RECURSE_WINDOWFUNCS |
5381 : : PVC_INCLUDE_PLACEHOLDERS);
2956 5382 : 17996 : add_new_columns_to_pathtarget(input_target, non_group_vars);
5383 : :
5384 : : /* clean up cruft */
4656 5385 : 17996 : list_free(non_group_vars);
5386 : 17996 : list_free(non_group_cols);
5387 : :
5388 : : /* XXX this causes some redundant cost calculation ... */
2956 5389 : 17996 : return set_pathtarget_cost_width(root, input_target);
5390 : : }
5391 : :
5392 : : /*
5393 : : * make_partial_grouping_target
5394 : : * Generate appropriate PathTarget for output of partial aggregate
5395 : : * (or partial grouping, if there are no aggregates) nodes.
5396 : : *
5397 : : * A partial aggregation node needs to emit all the same aggregates that
5398 : : * a regular aggregation node would, plus any aggregates used in HAVING;
5399 : : * except that the Aggref nodes should be marked as partial aggregates.
5400 : : *
5401 : : * In addition, we'd better emit any Vars and PlaceHolderVars that are
5402 : : * used outside of Aggrefs in the aggregation tlist and HAVING. (Presumably,
5403 : : * these would be Vars that are grouped by or used in grouping expressions.)
5404 : : *
5405 : : * grouping_target is the tlist to be emitted by the topmost aggregation step.
5406 : : * havingQual represents the HAVING clause.
5407 : : */
5408 : : static PathTarget *
2222 rhaas@postgresql.org 5409 : 1080 : make_partial_grouping_target(PlannerInfo *root,
5410 : : PathTarget *grouping_target,
5411 : : Node *havingQual)
5412 : : {
5413 : : PathTarget *partial_target;
5414 : : List *non_group_cols;
5415 : : List *non_group_exprs;
5416 : : int i;
5417 : : ListCell *lc;
5418 : :
2849 tgl@sss.pgh.pa.us 5419 : 1080 : partial_target = create_empty_pathtarget();
2946 rhaas@postgresql.org 5420 : 1080 : non_group_cols = NIL;
5421 : :
5422 : 1080 : i = 0;
2849 tgl@sss.pgh.pa.us 5423 [ + - + + : 3833 : foreach(lc, grouping_target->exprs)
+ + ]
5424 : : {
2946 rhaas@postgresql.org 5425 : 2753 : Expr *expr = (Expr *) lfirst(lc);
2849 tgl@sss.pgh.pa.us 5426 [ + - ]: 2753 : Index sgref = get_pathtarget_sortgroupref(grouping_target, i);
5427 : :
452 5428 [ + + + + : 4624 : if (sgref && root->processed_groupClause &&
+ + ]
5429 : 1871 : get_sortgroupref_clause_noerr(sgref,
5430 : : root->processed_groupClause) != NULL)
5431 : : {
5432 : : /*
5433 : : * It's a grouping column, so add it to the partial_target as-is.
5434 : : * (This allows the upper agg step to repeat the grouping calcs.)
5435 : : */
2849 5436 : 932 : add_column_to_pathtarget(partial_target, expr, sgref);
5437 : : }
5438 : : else
5439 : : {
5440 : : /*
5441 : : * Non-grouping column, so just remember the expression for later
5442 : : * call to pull_var_clause.
5443 : : */
2946 rhaas@postgresql.org 5444 : 1821 : non_group_cols = lappend(non_group_cols, expr);
5445 : : }
5446 : :
5447 : 2753 : i++;
5448 : : }
5449 : :
5450 : : /*
5451 : : * If there's a HAVING clause, we'll need the Vars/Aggrefs it uses, too.
5452 : : */
2222 5453 [ + + ]: 1080 : if (havingQual)
5454 : 412 : non_group_cols = lappend(non_group_cols, havingQual);
5455 : :
5456 : : /*
5457 : : * Pull out all the Vars, PlaceHolderVars, and Aggrefs mentioned in
5458 : : * non-group cols (plus HAVING), and add them to the partial_target if not
5459 : : * already present. (An expression used directly as a GROUP BY item will
5460 : : * be present already.) Note this includes Vars used in resjunk items, so
5461 : : * we are covering the needs of ORDER BY and window specifications.
5462 : : */
2946 5463 : 1080 : non_group_exprs = pull_var_clause((Node *) non_group_cols,
5464 : : PVC_INCLUDE_AGGREGATES |
5465 : : PVC_RECURSE_WINDOWFUNCS |
5466 : : PVC_INCLUDE_PLACEHOLDERS);
5467 : :
2849 tgl@sss.pgh.pa.us 5468 : 1080 : add_new_columns_to_pathtarget(partial_target, non_group_exprs);
5469 : :
5470 : : /*
5471 : : * Adjust Aggrefs to put them in partial mode. At this point all Aggrefs
5472 : : * are at the top level of the target list, so we can just scan the list
5473 : : * rather than recursing through the expression trees.
5474 : : */
5475 [ + - + + : 4137 : foreach(lc, partial_target->exprs)
+ + ]
5476 : : {
5477 : 3057 : Aggref *aggref = (Aggref *) lfirst(lc);
5478 : :
5479 [ + + ]: 3057 : if (IsA(aggref, Aggref))
5480 : : {
5481 : : Aggref *newaggref;
5482 : :
5483 : : /*
5484 : : * We shouldn't need to copy the substructure of the Aggref node,
5485 : : * but flat-copy the node itself to avoid damaging other trees.
5486 : : */
5487 : 2110 : newaggref = makeNode(Aggref);
5488 : 2110 : memcpy(newaggref, aggref, sizeof(Aggref));
5489 : :
5490 : : /* For now, assume serialization is required */
5491 : 2110 : mark_partial_aggref(newaggref, AGGSPLIT_INITIAL_SERIAL);
5492 : :
5493 : 2110 : lfirst(lc) = newaggref;
5494 : : }
5495 : : }
5496 : :
5497 : : /* clean up cruft */
2946 rhaas@postgresql.org 5498 : 1080 : list_free(non_group_exprs);
5499 : 1080 : list_free(non_group_cols);
5500 : :
5501 : : /* XXX this causes some redundant cost calculation ... */
2849 tgl@sss.pgh.pa.us 5502 : 1080 : return set_pathtarget_cost_width(root, partial_target);
5503 : : }
5504 : :
5505 : : /*
5506 : : * mark_partial_aggref
5507 : : * Adjust an Aggref to make it represent a partial-aggregation step.
5508 : : *
5509 : : * The Aggref node is modified in-place; caller must do any copying required.
5510 : : */
5511 : : void
5512 : 3518 : mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
5513 : : {
5514 : : /* aggtranstype should be computed by this point */
5515 [ - + ]: 3518 : Assert(OidIsValid(agg->aggtranstype));
5516 : : /* ... but aggsplit should still be as the parser left it */
5517 [ - + ]: 3518 : Assert(agg->aggsplit == AGGSPLIT_SIMPLE);
5518 : :
5519 : : /* Mark the Aggref with the intended partial-aggregation mode */
5520 : 3518 : agg->aggsplit = aggsplit;
5521 : :
5522 : : /*
5523 : : * Adjust result type if needed. Normally, a partial aggregate returns
5524 : : * the aggregate's transition type; but if that's INTERNAL and we're
5525 : : * serializing, it returns BYTEA instead.
5526 : : */
5527 [ + + ]: 3518 : if (DO_AGGSPLIT_SKIPFINAL(aggsplit))
5528 : : {
5529 [ + + + - ]: 2814 : if (agg->aggtranstype == INTERNALOID && DO_AGGSPLIT_SERIALIZE(aggsplit))
5530 : 121 : agg->aggtype = BYTEAOID;
5531 : : else
5532 : 2693 : agg->aggtype = agg->aggtranstype;
5533 : : }
2946 rhaas@postgresql.org 5534 : 3518 : }
5535 : :
5536 : : /*
5537 : : * postprocess_setop_tlist
5538 : : * Fix up targetlist returned by plan_set_operations().
5539 : : *
5540 : : * We need to transpose sort key info from the orig_tlist into new_tlist.
5541 : : * NOTE: this would not be good enough if we supported resjunk sort keys
5542 : : * for results of set operations --- then, we'd need to project a whole
5543 : : * new tlist to evaluate the resjunk columns. For now, just ereport if we
5544 : : * find any resjunk columns in orig_tlist.
5545 : : */
5546 : : static List *
8557 tgl@sss.pgh.pa.us 5547 : 2587 : postprocess_setop_tlist(List *new_tlist, List *orig_tlist)
5548 : : {
5549 : : ListCell *l;
7263 neilc@samurai.com 5550 : 2587 : ListCell *orig_tlist_item = list_head(orig_tlist);
5551 : :
8557 tgl@sss.pgh.pa.us 5552 [ + + + + : 9975 : foreach(l, new_tlist)
+ + ]
5553 : : {
2413 5554 : 7388 : TargetEntry *new_tle = lfirst_node(TargetEntry, l);
5555 : : TargetEntry *orig_tle;
5556 : :
5557 : : /* ignore resjunk columns in setop result */
6948 5558 [ + + ]: 7388 : if (new_tle->resjunk)
8557 5559 : 259 : continue;
5560 : :
7263 neilc@samurai.com 5561 [ - + ]: 7129 : Assert(orig_tlist_item != NULL);
2413 tgl@sss.pgh.pa.us 5562 : 7129 : orig_tle = lfirst_node(TargetEntry, orig_tlist_item);
1735 5563 : 7129 : orig_tlist_item = lnext(orig_tlist, orig_tlist_item);
6756 bruce@momjian.us 5564 [ - + ]: 7129 : if (orig_tle->resjunk) /* should not happen */
7569 tgl@sss.pgh.pa.us 5565 [ # # ]:UBC 0 : elog(ERROR, "resjunk output columns are not implemented");
6948 tgl@sss.pgh.pa.us 5566 [ - + ]:CBC 7129 : Assert(new_tle->resno == orig_tle->resno);
5567 : 7129 : new_tle->ressortgroupref = orig_tle->ressortgroupref;
5568 : : }
7263 neilc@samurai.com 5569 [ - + ]: 2587 : if (orig_tlist_item != NULL)
7569 tgl@sss.pgh.pa.us 5570 [ # # ]:UBC 0 : elog(ERROR, "resjunk output columns are not implemented");
8557 tgl@sss.pgh.pa.us 5571 :CBC 2587 : return new_tlist;
5572 : : }
5573 : :
5574 : : /*
5575 : : * optimize_window_clauses
5576 : : * Call each WindowFunc's prosupport function to see if we're able to
5577 : : * make any adjustments to any of the WindowClause's so that the executor
5578 : : * can execute the window functions in a more optimal way.
5579 : : *
5580 : : * Currently we only allow adjustments to the WindowClause's frameOptions. We
5581 : : * may allow more things to be done here in the future.
5582 : : */
5583 : : static void
478 drowley@postgresql.o 5584 : 1147 : optimize_window_clauses(PlannerInfo *root, WindowFuncLists *wflists)
5585 : : {
5586 : 1147 : List *windowClause = root->parse->windowClause;
5587 : : ListCell *lc;
5588 : :
5589 [ + - + + : 2399 : foreach(lc, windowClause)
+ + ]
5590 : : {
5591 : 1252 : WindowClause *wc = lfirst_node(WindowClause, lc);
5592 : : ListCell *lc2;
5593 : 1252 : int optimizedFrameOptions = 0;
5594 : :
5595 [ - + ]: 1252 : Assert(wc->winref <= wflists->maxWinRef);
5596 : :
5597 : : /* skip any WindowClauses that have no WindowFuncs */
5598 [ + + ]: 1252 : if (wflists->windowFuncs[wc->winref] == NIL)
5599 : 12 : continue;
5600 : :
5601 [ + - + + : 1498 : foreach(lc2, wflists->windowFuncs[wc->winref])
+ + ]
5602 : : {
5603 : : SupportRequestOptimizeWindowClause req;
5604 : : SupportRequestOptimizeWindowClause *res;
5605 : 1258 : WindowFunc *wfunc = lfirst_node(WindowFunc, lc2);
5606 : : Oid prosupport;
5607 : :
5608 : 1258 : prosupport = get_func_support(wfunc->winfnoid);
5609 : :
5610 : : /* Check if there's a support function for 'wfunc' */
5611 [ + + ]: 1258 : if (!OidIsValid(prosupport))
5612 : 1000 : break; /* can't optimize this WindowClause */
5613 : :
5614 : 368 : req.type = T_SupportRequestOptimizeWindowClause;
5615 : 368 : req.window_clause = wc;
5616 : 368 : req.window_func = wfunc;
5617 : 368 : req.frameOptions = wc->frameOptions;
5618 : :
5619 : : /* call the support function */
5620 : : res = (SupportRequestOptimizeWindowClause *)
5621 : 368 : DatumGetPointer(OidFunctionCall1(prosupport,
5622 : : PointerGetDatum(&req)));
5623 : :
5624 : : /*
5625 : : * Skip to next WindowClause if the support function does not
5626 : : * support this request type.
5627 : : */
5628 [ + + ]: 368 : if (res == NULL)
5629 : 110 : break;
5630 : :
5631 : : /*
5632 : : * Save these frameOptions for the first WindowFunc for this
5633 : : * WindowClause.
5634 : : */
5635 [ + + ]: 258 : if (foreach_current_index(lc2) == 0)
5636 : 246 : optimizedFrameOptions = res->frameOptions;
5637 : :
5638 : : /*
5639 : : * On subsequent WindowFuncs, if the frameOptions are not the same
5640 : : * then we're unable to optimize the frameOptions for this
5641 : : * WindowClause.
5642 : : */
5643 [ - + ]: 12 : else if (optimizedFrameOptions != res->frameOptions)
478 drowley@postgresql.o 5644 :UBC 0 : break; /* skip to the next WindowClause, if any */
5645 : : }
5646 : :
5647 : : /* adjust the frameOptions if all WindowFunc's agree that it's ok */
478 drowley@postgresql.o 5648 [ + + + - ]:CBC 1240 : if (lc2 == NULL && wc->frameOptions != optimizedFrameOptions)
5649 : : {
5650 : : ListCell *lc3;
5651 : :
5652 : : /* apply the new frame options */
5653 : 240 : wc->frameOptions = optimizedFrameOptions;
5654 : :
5655 : : /*
5656 : : * We now check to see if changing the frameOptions has caused
5657 : : * this WindowClause to be a duplicate of some other WindowClause.
5658 : : * This can only happen if we have multiple WindowClauses, so
5659 : : * don't bother if there's only 1.
5660 : : */
5661 [ + + ]: 240 : if (list_length(windowClause) == 1)
5662 : 195 : continue;
5663 : :
5664 : : /*
5665 : : * Do the duplicate check and reuse the existing WindowClause if
5666 : : * we find a duplicate.
5667 : : */
5668 [ + - + + : 114 : foreach(lc3, windowClause)
+ + ]
5669 : : {
5670 : 87 : WindowClause *existing_wc = lfirst_node(WindowClause, lc3);
5671 : :
5672 : : /* skip over the WindowClause we're currently editing */
5673 [ + + ]: 87 : if (existing_wc == wc)
5674 : 27 : continue;
5675 : :
5676 : : /*
5677 : : * Perform the same duplicate check that is done in
5678 : : * transformWindowFuncCall.
5679 : : */
5680 [ + - + + ]: 120 : if (equal(wc->partitionClause, existing_wc->partitionClause) &&
5681 : 60 : equal(wc->orderClause, existing_wc->orderClause) &&
5682 [ + + + - ]: 60 : wc->frameOptions == existing_wc->frameOptions &&
5683 [ + - ]: 36 : equal(wc->startOffset, existing_wc->startOffset) &&
5684 : 18 : equal(wc->endOffset, existing_wc->endOffset))
5685 : : {
5686 : : ListCell *lc4;
5687 : :
5688 : : /*
5689 : : * Now move each WindowFunc in 'wc' into 'existing_wc'.
5690 : : * This required adjusting each WindowFunc's winref and
5691 : : * moving the WindowFuncs in 'wc' to the list of
5692 : : * WindowFuncs in 'existing_wc'.
5693 : : */
5694 [ + - + + : 39 : foreach(lc4, wflists->windowFuncs[wc->winref])
+ + ]
5695 : : {
5696 : 21 : WindowFunc *wfunc = lfirst_node(WindowFunc, lc4);
5697 : :
5698 : 21 : wfunc->winref = existing_wc->winref;
5699 : : }
5700 : :
5701 : : /* move list items */
5702 : 36 : wflists->windowFuncs[existing_wc->winref] = list_concat(wflists->windowFuncs[existing_wc->winref],
5703 : 18 : wflists->windowFuncs[wc->winref]);
5704 : 18 : wflists->windowFuncs[wc->winref] = NIL;
5705 : :
5706 : : /*
5707 : : * transformWindowFuncCall() should have made sure there
5708 : : * are no other duplicates, so we needn't bother looking
5709 : : * any further.
5710 : : */
5711 : 18 : break;
5712 : : }
5713 : : }
5714 : : }
5715 : : }
5716 : 1147 : }
5717 : :
5718 : : /*
5719 : : * select_active_windows
5720 : : * Create a list of the "active" window clauses (ie, those referenced
5721 : : * by non-deleted WindowFuncs) in the order they are to be executed.
5722 : : */
5723 : : static List *
5586 tgl@sss.pgh.pa.us 5724 : 1147 : select_active_windows(PlannerInfo *root, WindowFuncLists *wflists)
5725 : : {
2039 rhodiumtoad@postgres 5726 : 1147 : List *windowClause = root->parse->windowClause;
5727 : 1147 : List *result = NIL;
5728 : : ListCell *lc;
5729 : 1147 : int nActive = 0;
5730 : 1147 : WindowClauseSortData *actives = palloc(sizeof(WindowClauseSortData)
5731 : 1147 : * list_length(windowClause));
5732 : :
5733 : : /* First, construct an array of the active windows */
5734 [ + - + + : 2399 : foreach(lc, windowClause)
+ + ]
5735 : : {
2413 tgl@sss.pgh.pa.us 5736 : 1252 : WindowClause *wc = lfirst_node(WindowClause, lc);
5737 : :
5738 : : /* It's only active if wflists shows some related WindowFuncs */
5586 5739 [ - + ]: 1252 : Assert(wc->winref <= wflists->maxWinRef);
2039 rhodiumtoad@postgres 5740 [ + + ]: 1252 : if (wflists->windowFuncs[wc->winref] == NIL)
5741 : 30 : continue;
5742 : :
5743 : 1222 : actives[nActive].wc = wc; /* original clause */
5744 : :
5745 : : /*
5746 : : * For sorting, we want the list of partition keys followed by the
5747 : : * list of sort keys. But pathkeys construction will remove duplicates
5748 : : * between the two, so we can as well (even though we can't detect all
5749 : : * of the duplicates, since some may come from ECs - that might mean
5750 : : * we miss optimization chances here). We must, however, ensure that
5751 : : * the order of entries is preserved with respect to the ones we do
5752 : : * keep.
5753 : : *
5754 : : * partitionClause and orderClause had their own duplicates removed in
5755 : : * parse analysis, so we're only concerned here with removing
5756 : : * orderClause entries that also appear in partitionClause.
5757 : : */
5758 : 2444 : actives[nActive].uniqueOrder =
5759 : 1222 : list_concat_unique(list_copy(wc->partitionClause),
5760 : 1222 : wc->orderClause);
5761 : 1222 : nActive++;
5762 : : }
5763 : :
5764 : : /*
5765 : : * Sort active windows by their partitioning/ordering clauses, ignoring
5766 : : * any framing clauses, so that the windows that need the same sorting are
5767 : : * adjacent in the list. When we come to generate paths, this will avoid
5768 : : * inserting additional Sort nodes.
5769 : : *
5770 : : * This is how we implement a specific requirement from the SQL standard,
5771 : : * which says that when two or more windows are order-equivalent (i.e.
5772 : : * have matching partition and order clauses, even if their names or
5773 : : * framing clauses differ), then all peer rows must be presented in the
5774 : : * same order in all of them. If we allowed multiple sort nodes for such
5775 : : * cases, we'd risk having the peer rows end up in different orders in
5776 : : * equivalent windows due to sort instability. (See General Rule 4 of
5777 : : * <window clause> in SQL2008 - SQL2016.)
5778 : : *
5779 : : * Additionally, if the entire list of clauses of one window is a prefix
5780 : : * of another, put first the window with stronger sorting requirements.
5781 : : * This way we will first sort for stronger window, and won't have to sort
5782 : : * again for the weaker one.
5783 : : */
5784 : 1147 : qsort(actives, nActive, sizeof(WindowClauseSortData), common_prefix_cmp);
5785 : :
5786 : : /* build ordered list of the original WindowClause nodes */
5787 [ + + ]: 2369 : for (int i = 0; i < nActive; i++)
5788 : 1222 : result = lappend(result, actives[i].wc);
5789 : :
5790 : 1147 : pfree(actives);
5791 : :
5792 : 1147 : return result;
5793 : : }
5794 : :
5795 : : /*
5796 : : * common_prefix_cmp
5797 : : * QSort comparison function for WindowClauseSortData
5798 : : *
5799 : : * Sort the windows by the required sorting clauses. First, compare the sort
5800 : : * clauses themselves. Second, if one window's clauses are a prefix of another
5801 : : * one's clauses, put the window with more sort clauses first.
5802 : : *
5803 : : * We purposefully sort by the highest tleSortGroupRef first. Since
5804 : : * tleSortGroupRefs are assigned for the query's DISTINCT and ORDER BY first
5805 : : * and because here we sort the lowest tleSortGroupRefs last, if a
5806 : : * WindowClause is sharing a tleSortGroupRef with the query's DISTINCT or
5807 : : * ORDER BY clause, this makes it more likely that the final WindowAgg will
5808 : : * provide presorted input for the query's DISTINCT or ORDER BY clause, thus
5809 : : * reducing the total number of sorts required for the query.
5810 : : */
5811 : : static int
5812 : 81 : common_prefix_cmp(const void *a, const void *b)
5813 : : {
5814 : 81 : const WindowClauseSortData *wcsa = a;
5815 : 81 : const WindowClauseSortData *wcsb = b;
5816 : : ListCell *item_a;
5817 : : ListCell *item_b;
5818 : :
5819 [ + + + + : 138 : forboth(item_a, wcsa->uniqueOrder, item_b, wcsb->uniqueOrder)
+ + + + +
+ + + +
+ ]
5820 : : {
5821 : 108 : SortGroupClause *sca = lfirst_node(SortGroupClause, item_a);
5822 : 108 : SortGroupClause *scb = lfirst_node(SortGroupClause, item_b);
5823 : :
5824 [ + + ]: 108 : if (sca->tleSortGroupRef > scb->tleSortGroupRef)
5825 : 51 : return -1;
5826 [ + + ]: 102 : else if (sca->tleSortGroupRef < scb->tleSortGroupRef)
5827 : 33 : return 1;
5828 [ - + ]: 69 : else if (sca->sortop > scb->sortop)
2039 rhodiumtoad@postgres 5829 :UBC 0 : return -1;
2039 rhodiumtoad@postgres 5830 [ + + ]:CBC 69 : else if (sca->sortop < scb->sortop)
5831 : 12 : return 1;
5832 [ - + - - ]: 57 : else if (sca->nulls_first && !scb->nulls_first)
2039 rhodiumtoad@postgres 5833 :UBC 0 : return -1;
2039 rhodiumtoad@postgres 5834 [ + - - + ]:CBC 57 : else if (!sca->nulls_first && scb->nulls_first)
2039 rhodiumtoad@postgres 5835 :UBC 0 : return 1;
5836 : : /* no need to compare eqop, since it is fully determined by sortop */
5837 : : }
5838 : :
2039 rhodiumtoad@postgres 5839 [ + + ]:CBC 30 : if (list_length(wcsa->uniqueOrder) > list_length(wcsb->uniqueOrder))
5840 : 3 : return -1;
5841 [ + + ]: 27 : else if (list_length(wcsa->uniqueOrder) < list_length(wcsb->uniqueOrder))
5842 : 6 : return 1;
5843 : :
5844 : 21 : return 0;
5845 : : }
5846 : :
5847 : : /*
5848 : : * make_window_input_target
5849 : : * Generate appropriate PathTarget for initial input to WindowAgg nodes.
5850 : : *
5851 : : * When the query has window functions, this function computes the desired
5852 : : * target to be computed by the node just below the first WindowAgg.
5853 : : * This tlist must contain all values needed to evaluate the window functions,
5854 : : * compute the final target list, and perform any required final sort step.
5855 : : * If multiple WindowAggs are needed, each intermediate one adds its window
5856 : : * function results onto this base tlist; only the topmost WindowAgg computes
5857 : : * the actual desired target list.
5858 : : *
5859 : : * This function is much like make_group_input_target, though not quite enough
5860 : : * like it to share code. As in that function, we flatten most expressions
5861 : : * into their component variables. But we do not want to flatten window
5862 : : * PARTITION BY/ORDER BY clauses, since that might result in multiple
5863 : : * evaluations of them, which would be bad (possibly even resulting in
5864 : : * inconsistent answers, if they contain volatile functions).
5865 : : * Also, we must not flatten GROUP BY clauses that were left unflattened by
5866 : : * make_group_input_target, because we may no longer have access to the
5867 : : * individual Vars in them.
5868 : : *
5869 : : * Another key difference from make_group_input_target is that we don't
5870 : : * flatten Aggref expressions, since those are to be computed below the
5871 : : * window functions and just referenced like Vars above that.
5872 : : *
5873 : : * 'final_target' is the query's final target list (in PathTarget form)
5874 : : * 'activeWindows' is the list of active windows previously identified by
5875 : : * select_active_windows.
5876 : : *
5877 : : * The result is the PathTarget to be computed by the plan node immediately
5878 : : * below the first WindowAgg node.
5879 : : */
5880 : : static PathTarget *
2958 tgl@sss.pgh.pa.us 5881 : 1147 : make_window_input_target(PlannerInfo *root,
5882 : : PathTarget *final_target,
5883 : : List *activeWindows)
5884 : : {
5885 : : PathTarget *input_target;
5886 : : Bitmapset *sgrefs;
5887 : : List *flattenable_cols;
5888 : : List *flattenable_vars;
5889 : : int i;
5890 : : ListCell *lc;
5891 : :
452 5892 [ - + ]: 1147 : Assert(root->parse->hasWindowFuncs);
5893 : :
5894 : : /*
5895 : : * Collect the sortgroupref numbers of window PARTITION/ORDER BY clauses
5896 : : * into a bitmapset for convenient reference below.
5897 : : */
4231 5898 : 1147 : sgrefs = NULL;
5494 5899 [ + - + + : 2369 : foreach(lc, activeWindows)
+ + ]
5900 : : {
2413 5901 : 1222 : WindowClause *wc = lfirst_node(WindowClause, lc);
5902 : : ListCell *lc2;
5903 : :
5494 5904 [ + + + + : 1572 : foreach(lc2, wc->partitionClause)
+ + ]
5905 : : {
2413 5906 : 350 : SortGroupClause *sortcl = lfirst_node(SortGroupClause, lc2);
5907 : :
5494 5908 : 350 : sgrefs = bms_add_member(sgrefs, sortcl->tleSortGroupRef);
5909 : : }
5910 [ + + + + : 2282 : foreach(lc2, wc->orderClause)
+ + ]
5911 : : {
2413 5912 : 1060 : SortGroupClause *sortcl = lfirst_node(SortGroupClause, lc2);
5913 : :
5494 5914 : 1060 : sgrefs = bms_add_member(sgrefs, sortcl->tleSortGroupRef);
5915 : : }
5916 : : }
5917 : :
5918 : : /* Add in sortgroupref numbers of GROUP BY clauses, too */
452 5919 [ + + + + : 1228 : foreach(lc, root->processed_groupClause)
+ + ]
5920 : : {
2413 5921 : 81 : SortGroupClause *grpcl = lfirst_node(SortGroupClause, lc);
5922 : :
4231 5923 : 81 : sgrefs = bms_add_member(sgrefs, grpcl->tleSortGroupRef);
5924 : : }
5925 : :
5926 : : /*
5927 : : * Construct a target containing all the non-flattenable targetlist items,
5928 : : * and save aside the others for a moment.
5929 : : */
2956 5930 : 1147 : input_target = create_empty_pathtarget();
4231 5931 : 1147 : flattenable_cols = NIL;
5932 : :
2956 5933 : 1147 : i = 0;
5934 [ + - + + : 4994 : foreach(lc, final_target->exprs)
+ + ]
5935 : : {
5936 : 3847 : Expr *expr = (Expr *) lfirst(lc);
2862 5937 [ + - ]: 3847 : Index sgref = get_pathtarget_sortgroupref(final_target, i);
5938 : :
5939 : : /*
5940 : : * Don't want to deconstruct window clauses or GROUP BY items. (Note
5941 : : * that such items can't contain window functions, so it's okay to
5942 : : * compute them below the WindowAgg nodes.)
5943 : : */
2956 5944 [ + + + + ]: 3847 : if (sgref != 0 && bms_is_member(sgref, sgrefs))
5945 : : {
5946 : : /*
5947 : : * Don't want to deconstruct this value, so add it to the input
5948 : : * target as-is.
5949 : : */
5950 : 1355 : add_column_to_pathtarget(input_target, expr, sgref);
5951 : : }
5952 : : else
5953 : : {
5954 : : /*
5955 : : * Column is to be flattened, so just remember the expression for
5956 : : * later call to pull_var_clause.
5957 : : */
5958 : 2492 : flattenable_cols = lappend(flattenable_cols, expr);
5959 : : }
5960 : :
5961 : 3847 : i++;
5962 : : }
5963 : :
5964 : : /*
5965 : : * Pull out all the Vars and Aggrefs mentioned in flattenable columns, and
5966 : : * add them to the input target if not already present. (Some might be
5967 : : * there already because they're used directly as window/group clauses.)
5968 : : *
5969 : : * Note: it's essential to use PVC_INCLUDE_AGGREGATES here, so that any
5970 : : * Aggrefs are placed in the Agg node's tlist and not left to be computed
5971 : : * at higher levels. On the other hand, we should recurse into
5972 : : * WindowFuncs to make sure their input expressions are available.
5973 : : */
4231 5974 : 1147 : flattenable_vars = pull_var_clause((Node *) flattenable_cols,
5975 : : PVC_INCLUDE_AGGREGATES |
5976 : : PVC_RECURSE_WINDOWFUNCS |
5977 : : PVC_INCLUDE_PLACEHOLDERS);
2956 5978 : 1147 : add_new_columns_to_pathtarget(input_target, flattenable_vars);
5979 : :
5980 : : /* clean up cruft */
4231 5981 : 1147 : list_free(flattenable_vars);
5982 : 1147 : list_free(flattenable_cols);
5983 : :
5984 : : /* XXX this causes some redundant cost calculation ... */
2956 5985 : 1147 : return set_pathtarget_cost_width(root, input_target);
5986 : : }
5987 : :
5988 : : /*
5989 : : * make_pathkeys_for_window
5990 : : * Create a pathkeys list describing the required input ordering
5991 : : * for the given WindowClause.
5992 : : *
5993 : : * Modifies wc's partitionClause to remove any clauses which are deemed
5994 : : * redundant by the pathkey logic.
5995 : : *
5996 : : * The required ordering is first the PARTITION keys, then the ORDER keys.
5997 : : * In the future we might try to implement windowing using hashing, in which
5998 : : * case the ordering could be relaxed, but for now we always sort.
5999 : : */
6000 : : static List *
5586 6001 : 2462 : make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc,
6002 : : List *tlist)
6003 : : {
286 drowley@postgresql.o 6004 :GNC 2462 : List *window_pathkeys = NIL;
6005 : :
6006 : : /* Throw error if can't sort */
5586 tgl@sss.pgh.pa.us 6007 [ - + ]:CBC 2462 : if (!grouping_is_sortable(wc->partitionClause))
5586 tgl@sss.pgh.pa.us 6008 [ # # ]:UBC 0 : ereport(ERROR,
6009 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6010 : : errmsg("could not implement window PARTITION BY"),
6011 : : errdetail("Window partitioning columns must be of sortable datatypes.")));
5586 tgl@sss.pgh.pa.us 6012 [ - + ]:CBC 2462 : if (!grouping_is_sortable(wc->orderClause))
5586 tgl@sss.pgh.pa.us 6013 [ # # ]:UBC 0 : ereport(ERROR,
6014 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6015 : : errmsg("could not implement window ORDER BY"),
6016 : : errdetail("Window ordering columns must be of sortable datatypes.")));
6017 : :
6018 : : /*
6019 : : * First fetch the pathkeys for the PARTITION BY clause. We can safely
6020 : : * remove any clauses from the wc->partitionClause for redundant pathkeys.
6021 : : */
286 drowley@postgresql.o 6022 [ + + ]:GNC 2462 : if (wc->partitionClause != NIL)
6023 : : {
6024 : : bool sortable;
6025 : :
6026 : 587 : window_pathkeys = make_pathkeys_for_sortclauses_extended(root,
6027 : : &wc->partitionClause,
6028 : : tlist,
6029 : : true,
6030 : : &sortable);
6031 : :
6032 [ - + ]: 587 : Assert(sortable);
6033 : : }
6034 : :
6035 : : /*
6036 : : * In principle, we could also consider removing redundant ORDER BY items
6037 : : * too as doing so does not alter the result of peer row checks done by
6038 : : * the executor. However, we must *not* remove the ordering column for
6039 : : * RANGE OFFSET cases, as the executor needs that for in_range tests even
6040 : : * if it's known to be equal to some partitioning column.
6041 : : */
6042 [ + + ]: 2462 : if (wc->orderClause != NIL)
6043 : : {
6044 : : List *orderby_pathkeys;
6045 : :
6046 : 2087 : orderby_pathkeys = make_pathkeys_for_sortclauses(root,
6047 : : wc->orderClause,
6048 : : tlist);
6049 : :
6050 : : /* Okay, make the combined pathkeys */
6051 [ + + ]: 2087 : if (window_pathkeys != NIL)
6052 : 440 : window_pathkeys = append_pathkeys(window_pathkeys, orderby_pathkeys);
6053 : : else
6054 : 1647 : window_pathkeys = orderby_pathkeys;
6055 : : }
6056 : :
5586 tgl@sss.pgh.pa.us 6057 :CBC 2462 : return window_pathkeys;
6058 : : }
6059 : :
6060 : : /*
6061 : : * make_sort_input_target
6062 : : * Generate appropriate PathTarget for initial input to Sort step.
6063 : : *
6064 : : * If the query has ORDER BY, this function chooses the target to be computed
6065 : : * by the node just below the Sort (and DISTINCT, if any, since Unique can't
6066 : : * project) steps. This might or might not be identical to the query's final
6067 : : * output target.
6068 : : *
6069 : : * The main argument for keeping the sort-input tlist the same as the final
6070 : : * is that we avoid a separate projection node (which will be needed if
6071 : : * they're different, because Sort can't project). However, there are also
6072 : : * advantages to postponing tlist evaluation till after the Sort: it ensures
6073 : : * a consistent order of evaluation for any volatile functions in the tlist,
6074 : : * and if there's also a LIMIT, we can stop the query without ever computing
6075 : : * tlist functions for later rows, which is beneficial for both volatile and
6076 : : * expensive functions.
6077 : : *
6078 : : * Our current policy is to postpone volatile expressions till after the sort
6079 : : * unconditionally (assuming that that's possible, ie they are in plain tlist
6080 : : * columns and not ORDER BY/GROUP BY/DISTINCT columns). We also prefer to
6081 : : * postpone set-returning expressions, because running them beforehand would
6082 : : * bloat the sort dataset, and because it might cause unexpected output order
6083 : : * if the sort isn't stable. However there's a constraint on that: all SRFs
6084 : : * in the tlist should be evaluated at the same plan step, so that they can
6085 : : * run in sync in nodeProjectSet. So if any SRFs are in sort columns, we
6086 : : * mustn't postpone any SRFs. (Note that in principle that policy should
6087 : : * probably get applied to the group/window input targetlists too, but we
6088 : : * have not done that historically.) Lastly, expensive expressions are
6089 : : * postponed if there is a LIMIT, or if root->tuple_fraction shows that
6090 : : * partial evaluation of the query is possible (if neither is true, we expect
6091 : : * to have to evaluate the expressions for every row anyway), or if there are
6092 : : * any volatile or set-returning expressions (since once we've put in a
6093 : : * projection at all, it won't cost any more to postpone more stuff).
6094 : : *
6095 : : * Another issue that could potentially be considered here is that
6096 : : * evaluating tlist expressions could result in data that's either wider
6097 : : * or narrower than the input Vars, thus changing the volume of data that
6098 : : * has to go through the Sort. However, we usually have only a very bad
6099 : : * idea of the output width of any expression more complex than a Var,
6100 : : * so for now it seems too risky to try to optimize on that basis.
6101 : : *
6102 : : * Note that if we do produce a modified sort-input target, and then the
6103 : : * query ends up not using an explicit Sort, no particular harm is done:
6104 : : * we'll initially use the modified target for the preceding path nodes,
6105 : : * but then change them to the final target with apply_projection_to_path.
6106 : : * Moreover, in such a case the guarantees about evaluation order of
6107 : : * volatile functions still hold, since the rows are sorted already.
6108 : : *
6109 : : * This function has some things in common with make_group_input_target and
6110 : : * make_window_input_target, though the detailed rules for what to do are
6111 : : * different. We never flatten/postpone any grouping or ordering columns;
6112 : : * those are needed before the sort. If we do flatten a particular
6113 : : * expression, we leave Aggref and WindowFunc nodes alone, since those were
6114 : : * computed earlier.
6115 : : *
6116 : : * 'final_target' is the query's final target list (in PathTarget form)
6117 : : * 'have_postponed_srfs' is an output argument, see below
6118 : : *
6119 : : * The result is the PathTarget to be computed by the plan node immediately
6120 : : * below the Sort step (and the Distinct step, if any). This will be
6121 : : * exactly final_target if we decide a projection step wouldn't be helpful.
6122 : : *
6123 : : * In addition, *have_postponed_srfs is set to true if we choose to postpone
6124 : : * any set-returning functions to after the Sort.
6125 : : */
6126 : : static PathTarget *
2956 6127 : 26978 : make_sort_input_target(PlannerInfo *root,
6128 : : PathTarget *final_target,
6129 : : bool *have_postponed_srfs)
6130 : : {
6131 : 26978 : Query *parse = root->parse;
6132 : : PathTarget *input_target;
6133 : : int ncols;
6134 : : bool *col_is_srf;
6135 : : bool *postpone_col;
6136 : : bool have_srf;
6137 : : bool have_volatile;
6138 : : bool have_expensive;
6139 : : bool have_srf_sortcols;
6140 : : bool postpone_srfs;
6141 : : List *postponable_cols;
6142 : : List *postponable_vars;
6143 : : int i;
6144 : : ListCell *lc;
6145 : :
6146 : : /* Shouldn't get here unless query has ORDER BY */
6147 [ - + ]: 26978 : Assert(parse->sortClause);
6148 : :
2489 6149 : 26978 : *have_postponed_srfs = false; /* default result */
6150 : :
6151 : : /* Inspect tlist and collect per-column information */
2956 6152 : 26978 : ncols = list_length(final_target->exprs);
2942 6153 : 26978 : col_is_srf = (bool *) palloc0(ncols * sizeof(bool));
2956 6154 : 26978 : postpone_col = (bool *) palloc0(ncols * sizeof(bool));
2942 6155 : 26978 : have_srf = have_volatile = have_expensive = have_srf_sortcols = false;
6156 : :
2956 6157 : 26978 : i = 0;
6158 [ + - + + : 162411 : foreach(lc, final_target->exprs)
+ + ]
6159 : : {
6160 : 135433 : Expr *expr = (Expr *) lfirst(lc);
6161 : :
6162 : : /*
6163 : : * If the column has a sortgroupref, assume it has to be evaluated
6164 : : * before sorting. Generally such columns would be ORDER BY, GROUP
6165 : : * BY, etc targets. One exception is columns that were removed from
6166 : : * GROUP BY by remove_useless_groupby_columns() ... but those would
6167 : : * only be Vars anyway. There don't seem to be any cases where it
6168 : : * would be worth the trouble to double-check.
6169 : : */
2862 6170 [ + - + + ]: 135433 : if (get_pathtarget_sortgroupref(final_target, i) == 0)
6171 : : {
6172 : : /*
6173 : : * Check for SRF or volatile functions. Check the SRF case first
6174 : : * because we must know whether we have any postponed SRFs.
6175 : : */
2770 6176 [ + + + + ]: 96457 : if (parse->hasTargetSRFs &&
6177 : 108 : expression_returns_set((Node *) expr))
6178 : : {
6179 : : /* We'll decide below whether these are postponable */
2942 6180 : 48 : col_is_srf[i] = true;
2956 6181 : 48 : have_srf = true;
6182 : : }
6183 [ + + ]: 96301 : else if (contain_volatile_functions((Node *) expr))
6184 : : {
6185 : : /* Unconditionally postpone */
6186 : 71 : postpone_col[i] = true;
6187 : 71 : have_volatile = true;
6188 : : }
6189 : : else
6190 : : {
6191 : : /*
6192 : : * Else check the cost. XXX it's annoying to have to do this
6193 : : * when set_pathtarget_cost_width() just did it. Refactor to
6194 : : * allow sharing the work?
6195 : : */
6196 : : QualCost cost;
6197 : :
6198 : 96230 : cost_qual_eval_node(&cost, (Node *) expr, root);
6199 : :
6200 : : /*
6201 : : * We arbitrarily define "expensive" as "more than 10X
6202 : : * cpu_operator_cost". Note this will take in any PL function
6203 : : * with default cost.
6204 : : */
6205 [ + + ]: 96230 : if (cost.per_tuple > 10 * cpu_operator_cost)
6206 : : {
6207 : 7036 : postpone_col[i] = true;
6208 : 7036 : have_expensive = true;
6209 : : }
6210 : : }
6211 : : }
6212 : : else
6213 : : {
6214 : : /* For sortgroupref cols, just check if any contain SRFs */
2942 6215 [ + - ]: 39084 : if (!have_srf_sortcols &&
2770 6216 [ + + + + ]: 39239 : parse->hasTargetSRFs &&
2942 6217 : 155 : expression_returns_set((Node *) expr))
6218 : 62 : have_srf_sortcols = true;
6219 : : }
6220 : :
2956 6221 : 135433 : i++;
6222 : : }
6223 : :
6224 : : /*
6225 : : * We can postpone SRFs if we have some but none are in sortgroupref cols.
6226 : : */
2942 6227 [ + + + + ]: 26978 : postpone_srfs = (have_srf && !have_srf_sortcols);
6228 : :
6229 : : /*
6230 : : * If we don't need a post-sort projection, just return final_target.
6231 : : */
6232 [ + + + + ]: 26978 : if (!(postpone_srfs || have_volatile ||
2956 6233 [ + + ]: 26879 : (have_expensive &&
6234 [ + + + - ]: 4240 : (parse->limitCount || root->tuple_fraction > 0))))
6235 : 26861 : return final_target;
6236 : :
6237 : : /*
6238 : : * Report whether the post-sort projection will contain set-returning
6239 : : * functions. This is important because it affects whether the Sort can
6240 : : * rely on the query's LIMIT (if any) to bound the number of rows it needs
6241 : : * to return.
6242 : : */
2942 6243 : 117 : *have_postponed_srfs = postpone_srfs;
6244 : :
6245 : : /*
6246 : : * Construct the sort-input target, taking all non-postponable columns and
6247 : : * then adding Vars, PlaceHolderVars, Aggrefs, and WindowFuncs found in
6248 : : * the postponable ones.
6249 : : */
2956 6250 : 117 : input_target = create_empty_pathtarget();
6251 : 117 : postponable_cols = NIL;
6252 : :
6253 : 117 : i = 0;
6254 [ + - + + : 971 : foreach(lc, final_target->exprs)
+ + ]
6255 : : {
6256 : 854 : Expr *expr = (Expr *) lfirst(lc);
6257 : :
2942 6258 [ + + + + : 854 : if (postpone_col[i] || (postpone_srfs && col_is_srf[i]))
+ + ]
2956 6259 : 143 : postponable_cols = lappend(postponable_cols, expr);
6260 : : else
2956 tgl@sss.pgh.pa.us 6261 :UBC 0 : add_column_to_pathtarget(input_target, expr,
2489 tgl@sss.pgh.pa.us 6262 [ + - ]:CBC 711 : get_pathtarget_sortgroupref(final_target, i));
6263 : :
2956 6264 : 854 : i++;
6265 : : }
6266 : :
6267 : : /*
6268 : : * Pull out all the Vars, Aggrefs, and WindowFuncs mentioned in
6269 : : * postponable columns, and add them to the sort-input target if not
6270 : : * already present. (Some might be there already.) We mustn't
6271 : : * deconstruct Aggrefs or WindowFuncs here, since the projection node
6272 : : * would be unable to recompute them.
6273 : : */
6274 : 117 : postponable_vars = pull_var_clause((Node *) postponable_cols,
6275 : : PVC_INCLUDE_AGGREGATES |
6276 : : PVC_INCLUDE_WINDOWFUNCS |
6277 : : PVC_INCLUDE_PLACEHOLDERS);
6278 : 117 : add_new_columns_to_pathtarget(input_target, postponable_vars);
6279 : :
6280 : : /* clean up cruft */
6281 : 117 : list_free(postponable_vars);
6282 : 117 : list_free(postponable_cols);
6283 : :
6284 : : /* XXX this represents even more redundant cost calculation ... */
6285 : 117 : return set_pathtarget_cost_width(root, input_target);
6286 : : }
6287 : :
6288 : : /*
6289 : : * get_cheapest_fractional_path
6290 : : * Find the cheapest path for retrieving a specified fraction of all
6291 : : * the tuples expected to be returned by the given relation.
6292 : : *
6293 : : * We interpret tuple_fraction the same way as grouping_planner.
6294 : : *
6295 : : * We assume set_cheapest() has been run on the given rel.
6296 : : */
6297 : : Path *
2960 6298 : 233398 : get_cheapest_fractional_path(RelOptInfo *rel, double tuple_fraction)
6299 : : {
6300 : 233398 : Path *best_path = rel->cheapest_total_path;
6301 : : ListCell *l;
6302 : :
6303 : : /* If all tuples will be retrieved, just return the cheapest-total path */
6304 [ + + ]: 233398 : if (tuple_fraction <= 0.0)
6305 : 230751 : return best_path;
6306 : :
6307 : : /* Convert absolute # of tuples to a fraction; no need to clamp to 0..1 */
2941 6308 [ + + + - ]: 2647 : if (tuple_fraction >= 1.0 && best_path->rows > 0)
2960 6309 : 1032 : tuple_fraction /= best_path->rows;
6310 : :
6311 [ + - + + : 6359 : foreach(l, rel->pathlist)
+ + ]
6312 : : {
6313 : 3712 : Path *path = (Path *) lfirst(l);
6314 : :
6315 [ + + + + ]: 4777 : if (path == rel->cheapest_total_path ||
2489 6316 : 1065 : compare_fractional_path_costs(best_path, path, tuple_fraction) <= 0)
2960 6317 : 3606 : continue;
6318 : :
6319 : 106 : best_path = path;
6320 : : }
6321 : :
6322 : 2647 : return best_path;
6323 : : }
6324 : :
6325 : : /*
6326 : : * adjust_paths_for_srfs
6327 : : * Fix up the Paths of the given upperrel to handle tSRFs properly.
6328 : : *
6329 : : * The executor can only handle set-returning functions that appear at the
6330 : : * top level of the targetlist of a ProjectSet plan node. If we have any SRFs
6331 : : * that are not at top level, we need to split up the evaluation into multiple
6332 : : * plan levels in which each level satisfies this constraint. This function
6333 : : * modifies each Path of an upperrel that (might) compute any SRFs in its
6334 : : * output tlist to insert appropriate projection steps.
6335 : : *
6336 : : * The given targets and targets_contain_srfs lists are from
6337 : : * split_pathtarget_at_srfs(). We assume the existing Paths emit the first
6338 : : * target in targets.
6339 : : */
6340 : : static void
2643 andres@anarazel.de 6341 : 4497 : adjust_paths_for_srfs(PlannerInfo *root, RelOptInfo *rel,
6342 : : List *targets, List *targets_contain_srfs)
6343 : : {
6344 : : ListCell *lc;
6345 : :
6346 [ - + ]: 4497 : Assert(list_length(targets) == list_length(targets_contain_srfs));
6347 [ - + ]: 4497 : Assert(!linitial_int(targets_contain_srfs));
6348 : :
6349 : : /* If no SRFs appear at this plan level, nothing to do */
6350 [ + + ]: 4497 : if (list_length(targets) == 1)
6351 : 295 : return;
6352 : :
6353 : : /*
6354 : : * Stack SRF-evaluation nodes atop each path for the rel.
6355 : : *
6356 : : * In principle we should re-run set_cheapest() here to identify the
6357 : : * cheapest path, but it seems unlikely that adding the same tlist eval
6358 : : * costs to all the paths would change that, so we don't bother. Instead,
6359 : : * just assume that the cheapest-startup and cheapest-total paths remain
6360 : : * so. (There should be no parameterized paths anymore, so we needn't
6361 : : * worry about updating cheapest_parameterized_paths.)
6362 : : */
6363 [ + - + + : 8416 : foreach(lc, rel->pathlist)
+ + ]
6364 : : {
6365 : 4214 : Path *subpath = (Path *) lfirst(lc);
6366 : 4214 : Path *newpath = subpath;
6367 : : ListCell *lc1,
6368 : : *lc2;
6369 : :
6370 [ - + ]: 4214 : Assert(subpath->param_info == NULL);
6371 [ + - + + : 13195 : forboth(lc1, targets, lc2, targets_contain_srfs)
+ - + + +
+ + - +
+ ]
6372 : : {
2413 tgl@sss.pgh.pa.us 6373 : 8981 : PathTarget *thistarget = lfirst_node(PathTarget, lc1);
2643 andres@anarazel.de 6374 : 8981 : bool contains_srfs = (bool) lfirst_int(lc2);
6375 : :
6376 : : /* If this level doesn't contain SRFs, do regular projection */
6377 [ + + ]: 8981 : if (contains_srfs)
6378 : 4244 : newpath = (Path *) create_set_projection_path(root,
6379 : : rel,
6380 : : newpath,
6381 : : thistarget);
6382 : : else
6383 : 4737 : newpath = (Path *) apply_projection_to_path(root,
6384 : : rel,
6385 : : newpath,
6386 : : thistarget);
6387 : : }
6388 : 4214 : lfirst(lc) = newpath;
6389 [ + + ]: 4214 : if (subpath == rel->cheapest_startup_path)
6390 : 167 : rel->cheapest_startup_path = newpath;
6391 [ + + ]: 4214 : if (subpath == rel->cheapest_total_path)
6392 : 167 : rel->cheapest_total_path = newpath;
6393 : : }
6394 : :
6395 : : /* Likewise for partial paths, if any */
2270 rhaas@postgresql.org 6396 [ + + + + : 4205 : foreach(lc, rel->partial_pathlist)
+ + ]
6397 : : {
6398 : 3 : Path *subpath = (Path *) lfirst(lc);
6399 : 3 : Path *newpath = subpath;
6400 : : ListCell *lc1,
6401 : : *lc2;
6402 : :
6403 [ - + ]: 3 : Assert(subpath->param_info == NULL);
6404 [ + - + + : 12 : forboth(lc1, targets, lc2, targets_contain_srfs)
+ - + + +
+ + - +
+ ]
6405 : : {
6406 : 9 : PathTarget *thistarget = lfirst_node(PathTarget, lc1);
6407 : 9 : bool contains_srfs = (bool) lfirst_int(lc2);
6408 : :
6409 : : /* If this level doesn't contain SRFs, do regular projection */
6410 [ + + ]: 9 : if (contains_srfs)
6411 : 3 : newpath = (Path *) create_set_projection_path(root,
6412 : : rel,
6413 : : newpath,
6414 : : thistarget);
6415 : : else
6416 : : {
6417 : : /* avoid apply_projection_to_path, in case of multiple refs */
6418 : 6 : newpath = (Path *) create_projection_path(root,
6419 : : rel,
6420 : : newpath,
6421 : : thistarget);
6422 : : }
6423 : : }
6424 : 3 : lfirst(lc) = newpath;
6425 : : }
6426 : : }
6427 : :
6428 : : /*
6429 : : * expression_planner
6430 : : * Perform planner's transformations on a standalone expression.
6431 : : *
6432 : : * Various utility commands need to evaluate expressions that are not part
6433 : : * of a plannable query. They can do so using the executor's regular
6434 : : * expression-execution machinery, but first the expression has to be fed
6435 : : * through here to transform it from parser output to something executable.
6436 : : *
6437 : : * Currently, we disallow sublinks in standalone expressions, so there's no
6438 : : * real "planning" involved here. (That might not always be true though.)
6439 : : * What we must do is run eval_const_expressions to ensure that any function
6440 : : * calls are converted to positional notation and function default arguments
6441 : : * get inserted. The fact that constant subexpressions get simplified is a
6442 : : * side-effect that is useful when the expression will get evaluated more than
6443 : : * once. Also, we must fix operator function IDs.
6444 : : *
6445 : : * This does not return any information about dependencies of the expression.
6446 : : * Hence callers should use the results only for the duration of the current
6447 : : * query. Callers that would like to cache the results for longer should use
6448 : : * expression_planner_with_deps, probably via the plancache.
6449 : : *
6450 : : * Note: this must not make any damaging changes to the passed-in expression
6451 : : * tree. (It would actually be okay to apply fix_opfuncids to it, but since
6452 : : * we first do an expression_tree_mutator-based walk, what is returned will
6453 : : * be a new node tree.) The result is constructed in the current memory
6454 : : * context; beware that this can leak a lot of additional stuff there, too.
6455 : : */
6456 : : Expr *
6457 : 115054 : expression_planner(Expr *expr)
6458 : : {
6459 : : Node *result;
6460 : :
6461 : : /*
6462 : : * Convert named-argument function calls, insert default arguments and
6463 : : * simplify constant subexprs
6464 : : */
6465 : 115054 : result = eval_const_expressions(NULL, (Node *) expr);
6466 : :
6467 : : /* Fill in opfuncid values if missing */
6468 : 115045 : fix_opfuncids(result);
6469 : :
6470 : 115045 : return (Expr *) result;
6471 : : }
6472 : :
6473 : : /*
6474 : : * expression_planner_with_deps
6475 : : * Perform planner's transformations on a standalone expression,
6476 : : * returning expression dependency information along with the result.
6477 : : *
6478 : : * This is identical to expression_planner() except that it also returns
6479 : : * information about possible dependencies of the expression, ie identities of
6480 : : * objects whose definitions affect the result. As in a PlannedStmt, these
6481 : : * are expressed as a list of relation Oids and a list of PlanInvalItems.
6482 : : */
6483 : : Expr *
1949 tgl@sss.pgh.pa.us 6484 : 182 : expression_planner_with_deps(Expr *expr,
6485 : : List **relationOids,
6486 : : List **invalItems)
6487 : : {
6488 : : Node *result;
6489 : : PlannerGlobal glob;
6490 : : PlannerInfo root;
6491 : :
6492 : : /* Make up dummy planner state so we can use setrefs machinery */
6493 [ + - + - : 3458 : MemSet(&glob, 0, sizeof(glob));
+ - + - +
+ ]
6494 : 182 : glob.type = T_PlannerGlobal;
6495 : 182 : glob.relationOids = NIL;
6496 : 182 : glob.invalItems = NIL;
6497 : :
6498 [ + - + - : 16016 : MemSet(&root, 0, sizeof(root));
+ - + - +
+ ]
6499 : 182 : root.type = T_PlannerInfo;
6500 : 182 : root.glob = &glob;
6501 : :
6502 : : /*
6503 : : * Convert named-argument function calls, insert default arguments and
6504 : : * simplify constant subexprs. Collect identities of inlined functions
6505 : : * and elided domains, too.
6506 : : */
6507 : 182 : result = eval_const_expressions(&root, (Node *) expr);
6508 : :
6509 : : /* Fill in opfuncid values if missing */
6510 : 182 : fix_opfuncids(result);
6511 : :
6512 : : /*
6513 : : * Now walk the finished expression to find anything else we ought to
6514 : : * record as an expression dependency.
6515 : : */
6516 : 182 : (void) extract_query_dependencies_walker(result, &root);
6517 : :
6518 : 182 : *relationOids = glob.relationOids;
6519 : 182 : *invalItems = glob.invalItems;
6520 : :
6521 : 182 : return (Expr *) result;
6522 : : }
6523 : :
6524 : :
6525 : : /*
6526 : : * plan_cluster_use_sort
6527 : : * Use the planner to decide how CLUSTER should implement sorting
6528 : : *
6529 : : * tableOid is the OID of a table to be clustered on its index indexOid
6530 : : * (which is already known to be a btree index). Decide whether it's
6531 : : * cheaper to do an indexscan or a seqscan-plus-sort to execute the CLUSTER.
6532 : : * Return true to use sorting, false to use an indexscan.
6533 : : *
6534 : : * Note: caller had better already hold some type of lock on the table.
6535 : : */
6536 : : bool
2270 rhaas@postgresql.org 6537 : 94 : plan_cluster_use_sort(Oid tableOid, Oid indexOid)
6538 : : {
6539 : : PlannerInfo *root;
6540 : : Query *query;
6541 : : PlannerGlobal *glob;
6542 : : RangeTblEntry *rte;
6543 : : RelOptInfo *rel;
6544 : : IndexOptInfo *indexInfo;
6545 : : QualCost indexExprCost;
6546 : : Cost comparisonCost;
6547 : : Path *seqScanPath;
6548 : : Path seqScanAndSortPath;
6549 : : IndexPath *indexScanPath;
6550 : : ListCell *lc;
6551 : :
6552 : : /* We can short-circuit the cost comparison if indexscans are disabled */
6553 [ + + ]: 94 : if (!enable_indexscan)
6554 : 15 : return true; /* use sort */
6555 : :
6556 : : /* Set up mostly-dummy planner state */
6557 : 79 : query = makeNode(Query);
6558 : 79 : query->commandType = CMD_SELECT;
6559 : :
6560 : 79 : glob = makeNode(PlannerGlobal);
6561 : :
6562 : 79 : root = makeNode(PlannerInfo);
6563 : 79 : root->parse = query;
6564 : 79 : root->glob = glob;
6565 : 79 : root->query_level = 1;
6566 : 79 : root->planner_cxt = CurrentMemoryContext;
6567 : 79 : root->wt_param_id = -1;
440 tgl@sss.pgh.pa.us 6568 : 79 : root->join_domains = list_make1(makeNode(JoinDomain));
6569 : :
6570 : : /* Build a minimal RTE for the rel */
2270 rhaas@postgresql.org 6571 : 79 : rte = makeNode(RangeTblEntry);
6572 : 79 : rte->rtekind = RTE_RELATION;
6573 : 79 : rte->relid = tableOid;
6574 : 79 : rte->relkind = RELKIND_RELATION; /* Don't be too picky. */
2023 tgl@sss.pgh.pa.us 6575 : 79 : rte->rellockmode = AccessShareLock;
2270 rhaas@postgresql.org 6576 : 79 : rte->lateral = false;
6577 : 79 : rte->inh = false;
6578 : 79 : rte->inFromCl = true;
6579 : 79 : query->rtable = list_make1(rte);
495 alvherre@alvh.no-ip. 6580 : 79 : addRTEPermissionInfo(&query->rteperminfos, rte);
6581 : :
6582 : : /* Set up RTE/RelOptInfo arrays */
2270 rhaas@postgresql.org 6583 : 79 : setup_simple_rel_arrays(root);
6584 : :
6585 : : /* Build RelOptInfo */
6586 : 79 : rel = build_simple_rel(root, 1, NULL);
6587 : :
6588 : : /* Locate IndexOptInfo for the target index */
6589 : 79 : indexInfo = NULL;
6590 [ + - + - : 98 : foreach(lc, rel->indexlist)
+ - ]
6591 : : {
6592 : 98 : indexInfo = lfirst_node(IndexOptInfo, lc);
6593 [ + + ]: 98 : if (indexInfo->indexoid == indexOid)
6594 : 79 : break;
6595 : : }
6596 : :
6597 : : /*
6598 : : * It's possible that get_relation_info did not generate an IndexOptInfo
6599 : : * for the desired index; this could happen if it's not yet reached its
6600 : : * indcheckxmin usability horizon, or if it's a system index and we're
6601 : : * ignoring system indexes. In such cases we should tell CLUSTER to not
6602 : : * trust the index contents but use seqscan-and-sort.
6603 : : */
6604 [ - + ]: 79 : if (lc == NULL) /* not in the list? */
2270 rhaas@postgresql.org 6605 :UBC 0 : return true; /* use sort */
6606 : :
6607 : : /*
6608 : : * Rather than doing all the pushups that would be needed to use
6609 : : * set_baserel_size_estimates, just do a quick hack for rows and width.
6610 : : */
2270 rhaas@postgresql.org 6611 :CBC 79 : rel->rows = rel->tuples;
6612 : 79 : rel->reltarget->width = get_relation_data_width(tableOid, NULL);
6613 : :
6614 : 79 : root->total_table_pages = rel->pages;
6615 : :
6616 : : /*
6617 : : * Determine eval cost of the index expressions, if any. We need to
6618 : : * charge twice that amount for each tuple comparison that happens during
6619 : : * the sort, since tuplesort.c will have to re-evaluate the index
6620 : : * expressions each time. (XXX that's pretty inefficient...)
6621 : : */
6622 : 79 : cost_qual_eval(&indexExprCost, indexInfo->indexprs, root);
6623 : 79 : comparisonCost = 2.0 * (indexExprCost.startup + indexExprCost.per_tuple);
6624 : :
6625 : : /* Estimate the cost of seq scan + sort */
6626 : 79 : seqScanPath = create_seqscan_path(root, rel, NULL, 0);
6627 : 79 : cost_sort(&seqScanAndSortPath, root, NIL,
6628 : 79 : seqScanPath->total_cost, rel->tuples, rel->reltarget->width,
6629 : : comparisonCost, maintenance_work_mem, -1.0);
6630 : :
6631 : : /* Estimate the cost of index scan */
6632 : 79 : indexScanPath = create_index_path(root, indexInfo,
6633 : : NIL, NIL, NIL, NIL,
6634 : : ForwardScanDirection, false,
6635 : : NULL, 1.0, false);
6636 : :
6637 : 79 : return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost);
6638 : : }
6639 : :
6640 : : /*
6641 : : * plan_create_index_workers
6642 : : * Use the planner to decide how many parallel worker processes
6643 : : * CREATE INDEX should request for use
6644 : : *
6645 : : * tableOid is the table on which the index is to be built. indexOid is the
6646 : : * OID of an index to be created or reindexed (which must be a btree index).
6647 : : *
6648 : : * Return value is the number of parallel worker processes to request. It
6649 : : * may be unsafe to proceed if this is 0. Note that this does not include the
6650 : : * leader participating as a worker (value is always a number of parallel
6651 : : * worker processes).
6652 : : *
6653 : : * Note: caller had better already hold some type of lock on the table and
6654 : : * index.
6655 : : */
6656 : : int
2263 6657 : 16464 : plan_create_index_workers(Oid tableOid, Oid indexOid)
6658 : : {
6659 : : PlannerInfo *root;
6660 : : Query *query;
6661 : : PlannerGlobal *glob;
6662 : : RangeTblEntry *rte;
6663 : : Relation heap;
6664 : : Relation index;
6665 : : RelOptInfo *rel;
6666 : : int parallel_workers;
6667 : : BlockNumber heap_blocks;
6668 : : double reltuples;
6669 : : double allvisfrac;
6670 : :
6671 : : /*
6672 : : * We don't allow performing parallel operation in standalone backend or
6673 : : * when parallelism is disabled.
6674 : : */
1231 tgl@sss.pgh.pa.us 6675 [ + + + + ]: 16464 : if (!IsUnderPostmaster || max_parallel_maintenance_workers == 0)
2263 rhaas@postgresql.org 6676 : 209 : return 0;
6677 : :
6678 : : /* Set up largely-dummy planner state */
6679 : 16255 : query = makeNode(Query);
6680 : 16255 : query->commandType = CMD_SELECT;
6681 : :
6682 : 16255 : glob = makeNode(PlannerGlobal);
6683 : :
6684 : 16255 : root = makeNode(PlannerInfo);
6685 : 16255 : root->parse = query;
6686 : 16255 : root->glob = glob;
6687 : 16255 : root->query_level = 1;
6688 : 16255 : root->planner_cxt = CurrentMemoryContext;
6689 : 16255 : root->wt_param_id = -1;
440 tgl@sss.pgh.pa.us 6690 : 16255 : root->join_domains = list_make1(makeNode(JoinDomain));
6691 : :
6692 : : /*
6693 : : * Build a minimal RTE.
6694 : : *
6695 : : * Mark the RTE with inh = true. This is a kludge to prevent
6696 : : * get_relation_info() from fetching index info, which is necessary
6697 : : * because it does not expect that any IndexOptInfo is currently
6698 : : * undergoing REINDEX.
6699 : : */
2263 rhaas@postgresql.org 6700 : 16255 : rte = makeNode(RangeTblEntry);
6701 : 16255 : rte->rtekind = RTE_RELATION;
6702 : 16255 : rte->relid = tableOid;
6703 : 16255 : rte->relkind = RELKIND_RELATION; /* Don't be too picky. */
2023 tgl@sss.pgh.pa.us 6704 : 16255 : rte->rellockmode = AccessShareLock;
2263 rhaas@postgresql.org 6705 : 16255 : rte->lateral = false;
6706 : 16255 : rte->inh = true;
6707 : 16255 : rte->inFromCl = true;
6708 : 16255 : query->rtable = list_make1(rte);
495 alvherre@alvh.no-ip. 6709 : 16255 : addRTEPermissionInfo(&query->rteperminfos, rte);
6710 : :
6711 : : /* Set up RTE/RelOptInfo arrays */
2263 rhaas@postgresql.org 6712 : 16255 : setup_simple_rel_arrays(root);
6713 : :
6714 : : /* Build RelOptInfo */
6715 : 16255 : rel = build_simple_rel(root, 1, NULL);
6716 : :
6717 : : /* Rels are assumed already locked by the caller */
1910 andres@anarazel.de 6718 : 16255 : heap = table_open(tableOid, NoLock);
2263 rhaas@postgresql.org 6719 : 16255 : index = index_open(indexOid, NoLock);
6720 : :
6721 : : /*
6722 : : * Determine if it's safe to proceed.
6723 : : *
6724 : : * Currently, parallel workers can't access the leader's temporary tables.
6725 : : * Furthermore, any index predicate or index expressions must be parallel
6726 : : * safe.
6727 : : */
6728 [ + + ]: 16255 : if (heap->rd_rel->relpersistence == RELPERSISTENCE_TEMP ||
38 michael@paquier.xyz 6729 [ + + ]: 15331 : !is_parallel_safe(root, (Node *) RelationGetIndexExpressions(index)) ||
6730 [ - + ]: 15271 : !is_parallel_safe(root, (Node *) RelationGetIndexPredicate(index)))
6731 : : {
2263 rhaas@postgresql.org 6732 : 984 : parallel_workers = 0;
6733 : 984 : goto done;
6734 : : }
6735 : :
6736 : : /*
6737 : : * If parallel_workers storage parameter is set for the table, accept that
6738 : : * as the number of parallel worker processes to launch (though still cap
6739 : : * at max_parallel_maintenance_workers). Note that we deliberately do not
6740 : : * consider any other factor when parallel_workers is set. (e.g., memory
6741 : : * use by workers.)
6742 : : */
6743 [ + + ]: 15271 : if (rel->rel_parallel_workers != -1)
6744 : : {
6745 : 7 : parallel_workers = Min(rel->rel_parallel_workers,
6746 : : max_parallel_maintenance_workers);
6747 : 7 : goto done;
6748 : : }
6749 : :
6750 : : /*
6751 : : * Estimate heap relation size ourselves, since rel->pages cannot be
6752 : : * trusted (heap RTE was marked as inheritance parent)
6753 : : */
6754 : 15264 : estimate_rel_size(heap, NULL, &heap_blocks, &reltuples, &allvisfrac);
6755 : :
6756 : : /*
6757 : : * Determine number of workers to scan the heap relation using generic
6758 : : * model
6759 : : */
6760 : 15264 : parallel_workers = compute_parallel_worker(rel, heap_blocks, -1,
6761 : : max_parallel_maintenance_workers);
6762 : :
6763 : : /*
6764 : : * Cap workers based on available maintenance_work_mem as needed.
6765 : : *
6766 : : * Note that each tuplesort participant receives an even share of the
6767 : : * total maintenance_work_mem budget. Aim to leave participants
6768 : : * (including the leader as a participant) with no less than 32MB of
6769 : : * memory. This leaves cases where maintenance_work_mem is set to 64MB
6770 : : * immediately past the threshold of being capable of launching a single
6771 : : * parallel worker to sort.
6772 : : */
6773 [ + + ]: 15330 : while (parallel_workers > 0 &&
6774 [ + + ]: 139 : maintenance_work_mem / (parallel_workers + 1) < 32768L)
6775 : 66 : parallel_workers--;
6776 : :
6777 : 15264 : done:
6778 : 16255 : index_close(index, NoLock);
1910 andres@anarazel.de 6779 : 16255 : table_close(heap, NoLock);
6780 : :
2263 rhaas@postgresql.org 6781 : 16255 : return parallel_workers;
6782 : : }
6783 : :
6784 : : /*
6785 : : * make_ordered_path
6786 : : * Return a path ordered by 'pathkeys' based on the given 'path'. May
6787 : : * return NULL if it doesn't make sense to generate an ordered path in
6788 : : * this case.
6789 : : */
6790 : : static Path *
84 akorotkov@postgresql 6791 :GNC 22043 : make_ordered_path(PlannerInfo *root, RelOptInfo *rel, Path *path,
6792 : : Path *cheapest_path, List *pathkeys)
6793 : : {
6794 : : bool is_sorted;
6795 : : int presorted_keys;
6796 : :
6797 : 22043 : is_sorted = pathkeys_count_contained_in(pathkeys,
6798 : : path->pathkeys,
6799 : : &presorted_keys);
6800 : :
6801 [ + + ]: 22043 : if (!is_sorted)
6802 : : {
6803 : : /*
6804 : : * Try at least sorting the cheapest path and also try incrementally
6805 : : * sorting any path which is partially sorted already (no need to deal
6806 : : * with paths which have presorted keys when incremental sort is
6807 : : * disabled unless it's the cheapest input path).
6808 : : */
6809 [ + + ]: 4095 : if (path != cheapest_path &&
6810 [ + + + + ]: 316 : (presorted_keys == 0 || !enable_incremental_sort))
6811 : 214 : return NULL;
6812 : :
6813 : : /*
6814 : : * We've no need to consider both a sort and incremental sort. We'll
6815 : : * just do a sort if there are no presorted keys and an incremental
6816 : : * sort when there are presorted keys.
6817 : : */
6818 [ + + - + ]: 3881 : if (presorted_keys == 0 || !enable_incremental_sort)
6819 : 3743 : path = (Path *) create_sort_path(root,
6820 : : rel,
6821 : : path,
6822 : : pathkeys,
6823 : : -1.0);
6824 : : else
6825 : 138 : path = (Path *) create_incremental_sort_path(root,
6826 : : rel,
6827 : : path,
6828 : : pathkeys,
6829 : : presorted_keys,
6830 : : -1.0);
6831 : : }
6832 : :
6833 : 21829 : return path;
6834 : : }
6835 : :
6836 : : /*
6837 : : * add_paths_to_grouping_rel
6838 : : *
6839 : : * Add non-partial paths to grouping relation.
6840 : : */
6841 : : static void
2270 rhaas@postgresql.org 6842 :CBC 18389 : add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
6843 : : RelOptInfo *grouped_rel,
6844 : : RelOptInfo *partially_grouped_rel,
6845 : : const AggClauseCosts *agg_costs,
6846 : : grouping_sets_data *gd, double dNumGroups,
6847 : : GroupPathExtraData *extra)
6848 : : {
6849 : 18389 : Query *parse = root->parse;
6850 : 18389 : Path *cheapest_path = input_rel->cheapest_total_path;
6851 : : ListCell *lc;
2215 6852 : 18389 : bool can_hash = (extra->flags & GROUPING_CAN_USE_HASH) != 0;
6853 : 18389 : bool can_sort = (extra->flags & GROUPING_CAN_USE_SORT) != 0;
6854 : 18389 : List *havingQual = (List *) extra->havingQual;
6855 : 18389 : AggClauseCosts *agg_final_costs = &extra->agg_final_costs;
6856 : :
2270 6857 [ + + ]: 18389 : if (can_sort)
6858 : : {
6859 : : /*
6860 : : * Use any available suitably-sorted path as input, and also consider
6861 : : * sorting the cheapest-total path and incremental sort on any paths
6862 : : * with presorted keys.
6863 : : */
6864 [ + - + + : 37993 : foreach(lc, input_rel->pathlist)
+ + ]
6865 : : {
6866 : : ListCell *lc2;
6867 : 19607 : Path *path = (Path *) lfirst(lc);
84 akorotkov@postgresql 6868 :GNC 19607 : Path *path_save = path;
6869 : 19607 : List *pathkey_orderings = NIL;
6870 : :
6871 : : /* generate alternative group orderings that might be useful */
6872 : 19607 : pathkey_orderings = get_useful_group_keys_orderings(root, path);
6873 : :
6874 [ - + ]: 19607 : Assert(list_length(pathkey_orderings) > 0);
6875 : :
6876 [ + - + + : 39277 : foreach(lc2, pathkey_orderings)
+ + ]
6877 : : {
6878 : 19670 : PathKeyInfo *info = (PathKeyInfo *) lfirst(lc2);
6879 : :
6880 : : /* restore the path (we replace it in the loop) */
6881 : 19670 : path = path_save;
6882 : :
6883 : 19670 : path = make_ordered_path(root,
6884 : : grouped_rel,
6885 : : path,
6886 : : cheapest_path,
6887 : : info->pathkeys);
6888 [ + + ]: 19670 : if (path == NULL)
6889 : 163 : continue;
6890 : :
6891 : : /* Now decide what to stick atop it */
6892 [ + + ]: 19507 : if (parse->groupingSets)
6893 : : {
6894 : 397 : consider_groupingsets_paths(root, grouped_rel,
6895 : : path, true, can_hash,
6896 : : gd, agg_costs, dNumGroups);
6897 : : }
6898 [ + + ]: 19110 : else if (parse->hasAggs)
6899 : : {
6900 : : /*
6901 : : * We have aggregation, possibly with plain GROUP BY. Make
6902 : : * an AggPath.
6903 : : */
559 tgl@sss.pgh.pa.us 6904 : 18787 : add_path(grouped_rel, (Path *)
6905 : 18787 : create_agg_path(root,
6906 : : grouped_rel,
6907 : : path,
6908 : 18787 : grouped_rel->reltarget,
6909 : 18787 : parse->groupClause ? AGG_SORTED : AGG_PLAIN,
6910 : : AGGSPLIT_SIMPLE,
6911 : : info->clauses,
6912 : : havingQual,
6913 : : agg_costs,
6914 : : dNumGroups));
6915 : : }
84 akorotkov@postgresql 6916 [ + - ]: 323 : else if (parse->groupClause)
6917 : : {
6918 : : /*
6919 : : * We have GROUP BY without aggregation or grouping sets.
6920 : : * Make a GroupPath.
6921 : : */
559 tgl@sss.pgh.pa.us 6922 : 323 : add_path(grouped_rel, (Path *)
6923 : 323 : create_group_path(root,
6924 : : grouped_rel,
6925 : : path,
6926 : : info->clauses,
6927 : : havingQual,
6928 : : dNumGroups));
6929 : : }
6930 : : else
6931 : : {
6932 : : /* Other cases should have been handled above */
84 akorotkov@postgresql 6933 :UNC 0 : Assert(false);
6934 : : }
6935 : : }
6936 : : }
6937 : :
6938 : : /*
6939 : : * Instead of operating directly on the input relation, we can
6940 : : * consider finalizing a partially aggregated path.
6941 : : */
84 akorotkov@postgresql 6942 [ + + ]:CBC 18386 : if (partially_grouped_rel != NULL)
6943 : : {
6944 [ + - + + : 1945 : foreach(lc, partially_grouped_rel->pathlist)
+ + ]
6945 : : {
6946 : : ListCell *lc2;
6947 : 1162 : Path *path = (Path *) lfirst(lc);
84 akorotkov@postgresql 6948 :GNC 1162 : Path *path_save = path;
6949 : 1162 : List *pathkey_orderings = NIL;
6950 : :
6951 : : /* generate alternative group orderings that might be useful */
6952 : 1162 : pathkey_orderings = get_useful_group_keys_orderings(root, path);
6953 : :
6954 [ - + ]: 1162 : Assert(list_length(pathkey_orderings) > 0);
6955 : :
6956 : : /* process all potentially interesting grouping reorderings */
6957 [ + - + + : 2324 : foreach(lc2, pathkey_orderings)
+ + ]
6958 : : {
6959 : 1162 : PathKeyInfo *info = (PathKeyInfo *) lfirst(lc2);
6960 : :
6961 : : /* restore the path (we replace it in the loop) */
6962 : 1162 : path = path_save;
6963 : :
6964 : 1162 : path = make_ordered_path(root,
6965 : : grouped_rel,
6966 : : path,
6967 : 1162 : partially_grouped_rel->cheapest_total_path,
6968 : : info->pathkeys);
6969 : :
6970 [ + + ]: 1162 : if (path == NULL)
6971 : 48 : continue;
6972 : :
6973 [ + + ]: 1114 : if (parse->hasAggs)
6974 : 990 : add_path(grouped_rel, (Path *)
6975 : 990 : create_agg_path(root,
6976 : : grouped_rel,
6977 : : path,
6978 : 990 : grouped_rel->reltarget,
6979 : 990 : parse->groupClause ? AGG_SORTED : AGG_PLAIN,
6980 : : AGGSPLIT_FINAL_DESERIAL,
6981 : : info->clauses,
6982 : : havingQual,
6983 : : agg_final_costs,
6984 : : dNumGroups));
6985 : : else
6986 : 124 : add_path(grouped_rel, (Path *)
6987 : 124 : create_group_path(root,
6988 : : grouped_rel,
6989 : : path,
6990 : : info->clauses,
6991 : : havingQual,
6992 : : dNumGroups));
6993 : :
6994 : : }
6995 : : }
6996 : : }
6997 : : }
6998 : :
2270 rhaas@postgresql.org 6999 [ + + ]:CBC 18389 : if (can_hash)
7000 : : {
7001 [ + + ]: 2253 : if (parse->groupingSets)
7002 : : {
7003 : : /*
7004 : : * Try for a hash-only groupingsets path over unsorted input.
7005 : : */
7006 : 325 : consider_groupingsets_paths(root, grouped_rel,
7007 : : cheapest_path, false, true,
7008 : : gd, agg_costs, dNumGroups);
7009 : : }
7010 : : else
7011 : : {
7012 : : /*
7013 : : * Generate a HashAgg Path. We just need an Agg over the
7014 : : * cheapest-total input path, since input order won't matter.
7015 : : */
1357 pg@bowt.ie 7016 : 1928 : add_path(grouped_rel, (Path *)
7017 : 1928 : create_agg_path(root, grouped_rel,
7018 : : cheapest_path,
7019 : 1928 : grouped_rel->reltarget,
7020 : : AGG_HASHED,
7021 : : AGGSPLIT_SIMPLE,
7022 : : root->processed_groupClause,
7023 : : havingQual,
7024 : : agg_costs,
7025 : : dNumGroups));
7026 : : }
7027 : :
7028 : : /*
7029 : : * Generate a Finalize HashAgg Path atop of the cheapest partially
7030 : : * grouped path, assuming there is one
7031 : : */
2217 rhaas@postgresql.org 7032 [ + + + - ]: 2253 : if (partially_grouped_rel && partially_grouped_rel->pathlist)
7033 : : {
2239 7034 : 383 : Path *path = partially_grouped_rel->cheapest_total_path;
7035 : :
1357 pg@bowt.ie 7036 : 383 : add_path(grouped_rel, (Path *)
7037 : 383 : create_agg_path(root,
7038 : : grouped_rel,
7039 : : path,
7040 : 383 : grouped_rel->reltarget,
7041 : : AGG_HASHED,
7042 : : AGGSPLIT_FINAL_DESERIAL,
7043 : : root->processed_groupClause,
7044 : : havingQual,
7045 : : agg_final_costs,
7046 : : dNumGroups));
7047 : : }
7048 : : }
7049 : :
7050 : : /*
7051 : : * When partitionwise aggregate is used, we might have fully aggregated
7052 : : * paths in the partial pathlist, because add_paths_to_append_rel() will
7053 : : * consider a path for grouped_rel consisting of a Parallel Append of
7054 : : * non-partial paths from each child.
7055 : : */
2215 rhaas@postgresql.org 7056 [ + + ]: 18389 : if (grouped_rel->partial_pathlist != NIL)
7057 : 81 : gather_grouping_paths(root, grouped_rel);
4938 tgl@sss.pgh.pa.us 7058 : 18389 : }
7059 : :
7060 : : /*
7061 : : * create_partial_grouping_paths
7062 : : *
7063 : : * Create a new upper relation representing the result of partial aggregation
7064 : : * and populate it with appropriate paths. Note that we don't finalize the
7065 : : * lists of paths here, so the caller can add additional partial or non-partial
7066 : : * paths and must afterward call gather_grouping_paths and set_cheapest on
7067 : : * the returned upper relation.
7068 : : *
7069 : : * All paths for this new upper relation -- both partial and non-partial --
7070 : : * have been partially aggregated but require a subsequent FinalizeAggregate
7071 : : * step.
7072 : : *
7073 : : * NB: This function is allowed to return NULL if it determines that there is
7074 : : * no real need to create a new RelOptInfo.
7075 : : */
7076 : : static RelOptInfo *
2217 rhaas@postgresql.org 7077 : 16793 : create_partial_grouping_paths(PlannerInfo *root,
7078 : : RelOptInfo *grouped_rel,
7079 : : RelOptInfo *input_rel,
7080 : : grouping_sets_data *gd,
7081 : : GroupPathExtraData *extra,
7082 : : bool force_rel_creation)
7083 : : {
2270 7084 : 16793 : Query *parse = root->parse;
7085 : : RelOptInfo *partially_grouped_rel;
2215 7086 : 16793 : AggClauseCosts *agg_partial_costs = &extra->agg_partial_costs;
7087 : 16793 : AggClauseCosts *agg_final_costs = &extra->agg_final_costs;
7088 : 16793 : Path *cheapest_partial_path = NULL;
7089 : 16793 : Path *cheapest_total_path = NULL;
2270 7090 : 16793 : double dNumPartialGroups = 0;
2215 7091 : 16793 : double dNumPartialPartialGroups = 0;
7092 : : ListCell *lc;
7093 : 16793 : bool can_hash = (extra->flags & GROUPING_CAN_USE_HASH) != 0;
7094 : 16793 : bool can_sort = (extra->flags & GROUPING_CAN_USE_SORT) != 0;
7095 : :
7096 : : /*
7097 : : * Consider whether we should generate partially aggregated non-partial
7098 : : * paths. We can only do this if we have a non-partial path, and only if
7099 : : * the parent of the input rel is performing partial partitionwise
7100 : : * aggregation. (Note that extra->patype is the type of partitionwise
7101 : : * aggregation being used at the parent level, not this level.)
7102 : : */
7103 [ + - ]: 16793 : if (input_rel->pathlist != NIL &&
7104 [ + + ]: 16793 : extra->patype == PARTITIONWISE_AGGREGATE_PARTIAL)
7105 : 297 : cheapest_total_path = input_rel->cheapest_total_path;
7106 : :
7107 : : /*
7108 : : * If parallelism is possible for grouped_rel, then we should consider
7109 : : * generating partially-grouped partial paths. However, if the input rel
7110 : : * has no partial paths, then we can't.
7111 : : */
7112 [ + + + + ]: 16793 : if (grouped_rel->consider_parallel && input_rel->partial_pathlist != NIL)
7113 : 908 : cheapest_partial_path = linitial(input_rel->partial_pathlist);
7114 : :
7115 : : /*
7116 : : * If we can't partially aggregate partial paths, and we can't partially
7117 : : * aggregate non-partial paths, then don't bother creating the new
7118 : : * RelOptInfo at all, unless the caller specified force_rel_creation.
7119 : : */
7120 [ + + + + ]: 16793 : if (cheapest_total_path == NULL &&
7121 : 15756 : cheapest_partial_path == NULL &&
7122 [ + + ]: 15756 : !force_rel_creation)
7123 : 15713 : return NULL;
7124 : :
7125 : : /*
7126 : : * Build a new upper relation to represent the result of partially
7127 : : * aggregating the rows from the input relation.
7128 : : */
2217 7129 : 1080 : partially_grouped_rel = fetch_upper_rel(root,
7130 : : UPPERREL_PARTIAL_GROUP_AGG,
7131 : : grouped_rel->relids);
7132 : 1080 : partially_grouped_rel->consider_parallel =
7133 : 1080 : grouped_rel->consider_parallel;
2215 7134 : 1080 : partially_grouped_rel->reloptkind = grouped_rel->reloptkind;
2217 7135 : 1080 : partially_grouped_rel->serverid = grouped_rel->serverid;
7136 : 1080 : partially_grouped_rel->userid = grouped_rel->userid;
7137 : 1080 : partially_grouped_rel->useridiscurrent = grouped_rel->useridiscurrent;
7138 : 1080 : partially_grouped_rel->fdwroutine = grouped_rel->fdwroutine;
7139 : :
7140 : : /*
7141 : : * Build target list for partial aggregate paths. These paths cannot just
7142 : : * emit the same tlist as regular aggregate paths, because (1) we must
7143 : : * include Vars and Aggrefs needed in HAVING, which might not appear in
7144 : : * the result tlist, and (2) the Aggrefs must be set in partial mode.
7145 : : */
7146 : 1080 : partially_grouped_rel->reltarget =
7147 : 1080 : make_partial_grouping_target(root, grouped_rel->reltarget,
7148 : : extra->havingQual);
7149 : :
2215 7150 [ + + ]: 1080 : if (!extra->partial_costs_set)
7151 : : {
7152 : : /*
7153 : : * Collect statistics about aggregates for estimating costs of
7154 : : * performing aggregation in parallel.
7155 : : */
7156 [ + - + - : 3834 : MemSet(agg_partial_costs, 0, sizeof(AggClauseCosts));
+ - + - +
+ ]
7157 [ + - + - : 3834 : MemSet(agg_final_costs, 0, sizeof(AggClauseCosts));
+ - + - +
+ ]
7158 [ + + ]: 639 : if (parse->hasAggs)
7159 : : {
7160 : : /* partial phase */
1237 heikki.linnakangas@i 7161 : 575 : get_agg_clause_costs(root, AGGSPLIT_INITIAL_SERIAL,
7162 : : agg_partial_costs);
7163 : :
7164 : : /* final phase */
7165 : 575 : get_agg_clause_costs(root, AGGSPLIT_FINAL_DESERIAL,
7166 : : agg_final_costs);
7167 : : }
7168 : :
2215 rhaas@postgresql.org 7169 : 639 : extra->partial_costs_set = true;
7170 : : }
7171 : :
7172 : : /* Estimate number of partial groups. */
7173 [ + + ]: 1080 : if (cheapest_total_path != NULL)
7174 : : dNumPartialGroups =
7175 : 297 : get_number_of_groups(root,
7176 : : cheapest_total_path->rows,
7177 : : gd,
7178 : : extra->targetList);
7179 [ + + ]: 1080 : if (cheapest_partial_path != NULL)
7180 : : dNumPartialPartialGroups =
7181 : 908 : get_number_of_groups(root,
7182 : : cheapest_partial_path->rows,
7183 : : gd,
7184 : : extra->targetList);
7185 : :
7186 [ + - + + ]: 1080 : if (can_sort && cheapest_total_path != NULL)
7187 : : {
7188 : : /* This should have been checked previously */
2270 7189 [ + + - + ]: 297 : Assert(parse->hasAggs || parse->groupClause);
7190 : :
7191 : : /*
7192 : : * Use any available suitably-sorted path as input, and also consider
7193 : : * sorting the cheapest partial path.
7194 : : */
2215 7195 [ + - + + : 594 : foreach(lc, input_rel->pathlist)
+ + ]
7196 : : {
7197 : : ListCell *lc2;
7198 : 297 : Path *path = (Path *) lfirst(lc);
84 akorotkov@postgresql 7199 :GNC 297 : Path *path_save = path;
7200 : 297 : List *pathkey_orderings = NIL;
7201 : :
7202 : : /* generate alternative group orderings that might be useful */
7203 : 297 : pathkey_orderings = get_useful_group_keys_orderings(root, path);
7204 : :
7205 [ - + ]: 297 : Assert(list_length(pathkey_orderings) > 0);
7206 : :
7207 : : /* process all potentially interesting grouping reorderings */
7208 [ + - + + : 594 : foreach(lc2, pathkey_orderings)
+ + ]
7209 : : {
7210 : 297 : PathKeyInfo *info = (PathKeyInfo *) lfirst(lc2);
7211 : :
7212 : : /* restore the path (we replace it in the loop) */
7213 : 297 : path = path_save;
7214 : :
7215 : 297 : path = make_ordered_path(root,
7216 : : partially_grouped_rel,
7217 : : path,
7218 : : cheapest_total_path,
7219 : : info->pathkeys);
7220 : :
7221 [ - + ]: 297 : if (path == NULL)
84 akorotkov@postgresql 7222 :UNC 0 : continue;
7223 : :
84 akorotkov@postgresql 7224 [ + + ]:GNC 297 : if (parse->hasAggs)
7225 : 261 : add_path(partially_grouped_rel, (Path *)
7226 : 261 : create_agg_path(root,
7227 : : partially_grouped_rel,
7228 : : path,
7229 : 261 : partially_grouped_rel->reltarget,
7230 : 261 : parse->groupClause ? AGG_SORTED : AGG_PLAIN,
7231 : : AGGSPLIT_INITIAL_SERIAL,
7232 : : info->clauses,
7233 : : NIL,
7234 : : agg_partial_costs,
7235 : : dNumPartialGroups));
7236 : : else
7237 : 36 : add_path(partially_grouped_rel, (Path *)
7238 : 36 : create_group_path(root,
7239 : : partially_grouped_rel,
7240 : : path,
7241 : : info->clauses,
7242 : : NIL,
7243 : : dNumPartialGroups));
7244 : : }
7245 : : }
7246 : : }
7247 : :
2215 rhaas@postgresql.org 7248 [ + - + + ]:CBC 1080 : if (can_sort && cheapest_partial_path != NULL)
7249 : : {
7250 : : /* Similar to above logic, but for partial paths. */
2270 7251 [ + - + + : 1822 : foreach(lc, input_rel->partial_pathlist)
+ + ]
7252 : : {
7253 : : ListCell *lc2;
7254 : 914 : Path *path = (Path *) lfirst(lc);
84 akorotkov@postgresql 7255 :GNC 914 : Path *path_save = path;
7256 : 914 : List *pathkey_orderings = NIL;
7257 : :
7258 : : /* generate alternative group orderings that might be useful */
7259 : 914 : pathkey_orderings = get_useful_group_keys_orderings(root, path);
7260 : :
7261 [ - + ]: 914 : Assert(list_length(pathkey_orderings) > 0);
7262 : :
7263 : : /* process all potentially interesting grouping reorderings */
7264 [ + - + + : 1828 : foreach(lc2, pathkey_orderings)
+ + ]
7265 : : {
7266 : 914 : PathKeyInfo *info = (PathKeyInfo *) lfirst(lc2);
7267 : :
7268 : :
7269 : : /* restore the path (we replace it in the loop) */
7270 : 914 : path = path_save;
7271 : :
7272 : 914 : path = make_ordered_path(root,
7273 : : partially_grouped_rel,
7274 : : path,
7275 : : cheapest_partial_path,
7276 : : info->pathkeys);
7277 : :
7278 [ + + ]: 914 : if (path == NULL)
84 akorotkov@postgresql 7279 :CBC 3 : continue;
7280 : :
84 akorotkov@postgresql 7281 [ + + ]:GNC 911 : if (parse->hasAggs)
7282 : 835 : add_partial_path(partially_grouped_rel, (Path *)
7283 : 835 : create_agg_path(root,
7284 : : partially_grouped_rel,
7285 : : path,
7286 : 835 : partially_grouped_rel->reltarget,
7287 : 835 : parse->groupClause ? AGG_SORTED : AGG_PLAIN,
7288 : : AGGSPLIT_INITIAL_SERIAL,
7289 : : info->clauses,
7290 : : NIL,
7291 : : agg_partial_costs,
7292 : : dNumPartialPartialGroups));
7293 : : else
7294 : 76 : add_partial_path(partially_grouped_rel, (Path *)
7295 : 76 : create_group_path(root,
7296 : : partially_grouped_rel,
7297 : : path,
7298 : : info->clauses,
7299 : : NIL,
7300 : : dNumPartialPartialGroups));
7301 : : }
7302 : : }
7303 : : }
7304 : :
7305 : : /*
7306 : : * Add a partially-grouped HashAgg Path where possible
7307 : : */
2215 rhaas@postgresql.org 7308 [ + + + + ]:CBC 1080 : if (can_hash && cheapest_total_path != NULL)
7309 : : {
7310 : : /* Checked above */
2270 7311 [ + + - + ]: 297 : Assert(parse->hasAggs || parse->groupClause);
7312 : :
1357 pg@bowt.ie 7313 : 297 : add_path(partially_grouped_rel, (Path *)
7314 : 297 : create_agg_path(root,
7315 : : partially_grouped_rel,
7316 : : cheapest_total_path,
7317 : 297 : partially_grouped_rel->reltarget,
7318 : : AGG_HASHED,
7319 : : AGGSPLIT_INITIAL_SERIAL,
7320 : : root->processed_groupClause,
7321 : : NIL,
7322 : : agg_partial_costs,
7323 : : dNumPartialGroups));
7324 : : }
7325 : :
7326 : : /*
7327 : : * Now add a partially-grouped HashAgg partial Path where possible
7328 : : */
2215 rhaas@postgresql.org 7329 [ + + + + ]: 1080 : if (can_hash && cheapest_partial_path != NULL)
7330 : : {
1357 pg@bowt.ie 7331 : 508 : add_partial_path(partially_grouped_rel, (Path *)
7332 : 508 : create_agg_path(root,
7333 : : partially_grouped_rel,
7334 : : cheapest_partial_path,
7335 : 508 : partially_grouped_rel->reltarget,
7336 : : AGG_HASHED,
7337 : : AGGSPLIT_INITIAL_SERIAL,
7338 : : root->processed_groupClause,
7339 : : NIL,
7340 : : agg_partial_costs,
7341 : : dNumPartialPartialGroups));
7342 : : }
7343 : :
7344 : : /*
7345 : : * If there is an FDW that's responsible for all baserels of the query,
7346 : : * let it consider adding partially grouped ForeignPaths.
7347 : : */
2239 rhaas@postgresql.org 7348 [ + + ]: 1080 : if (partially_grouped_rel->fdwroutine &&
7349 [ + - ]: 3 : partially_grouped_rel->fdwroutine->GetForeignUpperPaths)
7350 : : {
7351 : 3 : FdwRoutine *fdwroutine = partially_grouped_rel->fdwroutine;
7352 : :
7353 : 3 : fdwroutine->GetForeignUpperPaths(root,
7354 : : UPPERREL_PARTIAL_GROUP_AGG,
7355 : : input_rel, partially_grouped_rel,
7356 : : extra);
7357 : : }
7358 : :
2217 7359 : 1080 : return partially_grouped_rel;
7360 : : }
7361 : :
7362 : : /*
7363 : : * Generate Gather and Gather Merge paths for a grouping relation or partial
7364 : : * grouping relation.
7365 : : *
7366 : : * generate_useful_gather_paths does most of the work, but we also consider a
7367 : : * special case: we could try sorting the data by the group_pathkeys and then
7368 : : * applying Gather Merge.
7369 : : *
7370 : : * NB: This function shouldn't be used for anything other than a grouped or
7371 : : * partially grouped relation not only because of the fact that it explicitly
7372 : : * references group_pathkeys but we pass "true" as the third argument to
7373 : : * generate_useful_gather_paths().
7374 : : */
7375 : : static void
7376 : 821 : gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel)
7377 : : {
7378 : : ListCell *lc;
7379 : : Path *cheapest_partial_path;
7380 : : List *groupby_pathkeys;
7381 : :
7382 : : /*
7383 : : * This occurs after any partial aggregation has taken place, so trim off
7384 : : * any pathkeys added for ORDER BY / DISTINCT aggregates.
7385 : : */
30 drowley@postgresql.o 7386 [ + + ]: 821 : if (list_length(root->group_pathkeys) > root->num_groupby_pathkeys)
7387 : 9 : groupby_pathkeys = list_copy_head(root->group_pathkeys,
7388 : : root->num_groupby_pathkeys);
7389 : : else
7390 : 812 : groupby_pathkeys = root->group_pathkeys;
7391 : :
7392 : : /* Try Gather for unordered paths and Gather Merge for ordered ones. */
1468 tomas.vondra@postgre 7393 : 821 : generate_useful_gather_paths(root, rel, true);
7394 : :
2217 rhaas@postgresql.org 7395 : 821 : cheapest_partial_path = linitial(rel->partial_pathlist);
7396 : :
7397 : : /* XXX Shouldn't this also consider the group-key-reordering? */
1468 tomas.vondra@postgre 7398 [ + - + + : 1948 : foreach(lc, rel->partial_pathlist)
+ + ]
7399 : : {
7400 : 1127 : Path *path = (Path *) lfirst(lc);
7401 : : bool is_sorted;
7402 : : int presorted_keys;
7403 : : double total_groups;
7404 : :
30 drowley@postgresql.o 7405 : 1127 : is_sorted = pathkeys_count_contained_in(groupby_pathkeys,
7406 : : path->pathkeys,
7407 : : &presorted_keys);
7408 : :
1468 tomas.vondra@postgre 7409 [ + + ]: 1127 : if (is_sorted)
7410 : 740 : continue;
7411 : :
7412 : : /*
7413 : : * Try at least sorting the cheapest path and also try incrementally
7414 : : * sorting any path which is partially sorted already (no need to deal
7415 : : * with paths which have presorted keys when incremental sort is
7416 : : * disabled unless it's the cheapest input path).
7417 : : */
74 drowley@postgresql.o 7418 [ - + ]:GNC 387 : if (path != cheapest_partial_path &&
74 drowley@postgresql.o 7419 [ # # # # ]:UNC 0 : (presorted_keys == 0 || !enable_incremental_sort))
1468 tomas.vondra@postgre 7420 :LBC (30) : continue;
7421 : :
74 drowley@postgresql.o 7422 :GNC 387 : total_groups = path->rows * path->parallel_workers;
7423 : :
7424 : : /*
7425 : : * We've no need to consider both a sort and incremental sort. We'll
7426 : : * just do a sort if there are no presorted keys and an incremental
7427 : : * sort when there are presorted keys.
7428 : : */
7429 [ - + - - ]: 387 : if (presorted_keys == 0 || !enable_incremental_sort)
7430 : 387 : path = (Path *) create_sort_path(root, rel, path,
7431 : : groupby_pathkeys,
7432 : : -1.0);
7433 : : else
74 drowley@postgresql.o 7434 :UNC 0 : path = (Path *) create_incremental_sort_path(root,
7435 : : rel,
7436 : : path,
7437 : : groupby_pathkeys,
7438 : : presorted_keys,
7439 : : -1.0);
7440 : :
7441 : : path = (Path *)
1468 tomas.vondra@postgre 7442 :GBC 387 : create_gather_merge_path(root,
7443 : : rel,
7444 : : path,
7445 : 387 : rel->reltarget,
7446 : : groupby_pathkeys,
7447 : : NULL,
7448 : : &total_groups);
7449 : :
7450 : 387 : add_path(rel, path);
7451 : : }
2581 rhaas@postgresql.org 7452 :GIC 821 : }
7453 : :
7454 : : /*
7455 : : * can_partial_agg
7456 : : *
7457 : : * Determines whether or not partial grouping and/or aggregation is possible.
7458 : : * Returns true when possible, false otherwise.
7459 : : */
7460 : : static bool
1237 heikki.linnakangas@i 7461 :CBC 17987 : can_partial_agg(PlannerInfo *root)
7462 : : {
2270 rhaas@postgresql.org 7463 : 17987 : Query *parse = root->parse;
7464 : :
2217 7465 [ + + - + ]: 17987 : if (!parse->hasAggs && parse->groupClause == NIL)
7466 : : {
7467 : : /*
7468 : : * We don't know how to do parallel aggregation unless we have either
7469 : : * some aggregates or a grouping clause.
7470 : : */
2270 rhaas@postgresql.org 7471 :UBC 0 : return false;
7472 : : }
2270 rhaas@postgresql.org 7473 [ + + ]:CBC 17987 : else if (parse->groupingSets)
7474 : : {
7475 : : /* We don't know how to do grouping sets in parallel. */
7476 : 364 : return false;
7477 : : }
1237 heikki.linnakangas@i 7478 [ + + + + ]: 17623 : else if (root->hasNonPartialAggs || root->hasNonSerialAggs)
7479 : : {
7480 : : /* Insufficient support for partial mode. */
2270 rhaas@postgresql.org 7481 : 1493 : return false;
7482 : : }
7483 : :
7484 : : /* Everything looks good. */
7485 : 16130 : return true;
7486 : : }
7487 : :
7488 : : /*
7489 : : * apply_scanjoin_target_to_paths
7490 : : *
7491 : : * Adjust the final scan/join relation, and recursively all of its children,
7492 : : * to generate the final scan/join target. It would be more correct to model
7493 : : * this as a separate planning step with a new RelOptInfo at the toplevel and
7494 : : * for each child relation, but doing it this way is noticeably cheaper.
7495 : : * Maybe that problem can be solved at some point, but for now we do this.
7496 : : *
7497 : : * If tlist_same_exprs is true, then the scan/join target to be applied has
7498 : : * the same expressions as the existing reltarget, so we need only insert the
7499 : : * appropriate sortgroupref information. By avoiding the creation of
7500 : : * projection paths we save effort both immediately and at plan creation time.
7501 : : */
7502 : : static void
2215 7503 : 254510 : apply_scanjoin_target_to_paths(PlannerInfo *root,
7504 : : RelOptInfo *rel,
7505 : : List *scanjoin_targets,
7506 : : List *scanjoin_targets_contain_srfs,
7507 : : bool scanjoin_target_parallel_safe,
7508 : : bool tlist_same_exprs)
7509 : : {
1865 tgl@sss.pgh.pa.us 7510 [ + + + + : 254510 : bool rel_is_partitioned = IS_PARTITIONED_REL(rel);
+ + + - +
+ ]
7511 : : PathTarget *scanjoin_target;
7512 : : ListCell *lc;
7513 : :
7514 : : /* This recurses, so be paranoid. */
2208 rhaas@postgresql.org 7515 : 254510 : check_stack_depth();
7516 : :
7517 : : /*
7518 : : * If the rel is partitioned, we want to drop its existing paths and
7519 : : * generate new ones. This function would still be correct if we kept the
7520 : : * existing paths: we'd modify them to generate the correct target above
7521 : : * the partitioning Append, and then they'd compete on cost with paths
7522 : : * generating the target below the Append. However, in our current cost
7523 : : * model the latter way is always the same or cheaper cost, so modifying
7524 : : * the existing paths would just be useless work. Moreover, when the cost
7525 : : * is the same, varying roundoff errors might sometimes allow an existing
7526 : : * path to be picked, resulting in undesirable cross-platform plan
7527 : : * variations. So we drop old paths and thereby force the work to be done
7528 : : * below the Append, except in the case of a non-parallel-safe target.
7529 : : *
7530 : : * Some care is needed, because we have to allow
7531 : : * generate_useful_gather_paths to see the old partial paths in the next
7532 : : * stanza. Hence, zap the main pathlist here, then allow
7533 : : * generate_useful_gather_paths to add path(s) to the main list, and
7534 : : * finally zap the partial pathlist.
7535 : : */
1865 tgl@sss.pgh.pa.us 7536 [ + + ]: 254510 : if (rel_is_partitioned)
7537 : 6142 : rel->pathlist = NIL;
7538 : :
7539 : : /*
7540 : : * If the scan/join target is not parallel-safe, partial paths cannot
7541 : : * generate it.
7542 : : */
2208 rhaas@postgresql.org 7543 [ + + ]: 254510 : if (!scanjoin_target_parallel_safe)
7544 : : {
7545 : : /*
7546 : : * Since we can't generate the final scan/join target in parallel
7547 : : * workers, this is our last opportunity to use any partial paths that
7548 : : * exist; so build Gather path(s) that use them and emit whatever the
7549 : : * current reltarget is. We don't do this in the case where the
7550 : : * target is parallel-safe, since we will be able to generate superior
7551 : : * paths by doing it after the final scan/join target has been
7552 : : * applied.
7553 : : */
1468 tomas.vondra@postgre 7554 : 37927 : generate_useful_gather_paths(root, rel, false);
7555 : :
7556 : : /* Can't use parallel query above this level. */
2208 rhaas@postgresql.org 7557 : 37927 : rel->partial_pathlist = NIL;
7558 : 37927 : rel->consider_parallel = false;
7559 : : }
7560 : :
7561 : : /* Finish dropping old paths for a partitioned rel, per comment above */
1865 tgl@sss.pgh.pa.us 7562 [ + + ]: 254510 : if (rel_is_partitioned)
2208 rhaas@postgresql.org 7563 : 6142 : rel->partial_pathlist = NIL;
7564 : :
7565 : : /* Extract SRF-free scan/join target. */
7566 : 254510 : scanjoin_target = linitial_node(PathTarget, scanjoin_targets);
7567 : :
7568 : : /*
7569 : : * Apply the SRF-free scan/join target to each existing path.
7570 : : *
7571 : : * If the tlist exprs are the same, we can just inject the sortgroupref
7572 : : * information into the existing pathtargets. Otherwise, replace each
7573 : : * path with a projection path that generates the SRF-free scan/join
7574 : : * target. This can't change the ordering of paths within rel->pathlist,
7575 : : * so we just modify the list in place.
7576 : : */
2215 7577 [ + + + + : 522501 : foreach(lc, rel->pathlist)
+ + ]
7578 : : {
7579 : 267991 : Path *subpath = (Path *) lfirst(lc);
7580 : :
7581 : : /* Shouldn't have any parameterized paths anymore */
7582 [ - + ]: 267991 : Assert(subpath->param_info == NULL);
7583 : :
2208 7584 [ + + ]: 267991 : if (tlist_same_exprs)
7585 : 90383 : subpath->pathtarget->sortgrouprefs =
7586 : 90383 : scanjoin_target->sortgrouprefs;
7587 : : else
7588 : : {
7589 : : Path *newpath;
7590 : :
2215 7591 : 177608 : newpath = (Path *) create_projection_path(root, rel, subpath,
7592 : : scanjoin_target);
7593 : 177608 : lfirst(lc) = newpath;
7594 : : }
7595 : : }
7596 : :
7597 : : /* Likewise adjust the targets for any partial paths. */
2208 7598 [ + + + + : 264383 : foreach(lc, rel->partial_pathlist)
+ + ]
7599 : : {
7600 : 9873 : Path *subpath = (Path *) lfirst(lc);
7601 : :
7602 : : /* Shouldn't have any parameterized paths anymore */
7603 [ - + ]: 9873 : Assert(subpath->param_info == NULL);
7604 : :
7605 [ + + ]: 9873 : if (tlist_same_exprs)
7606 : 8110 : subpath->pathtarget->sortgrouprefs =
7607 : 8110 : scanjoin_target->sortgrouprefs;
7608 : : else
7609 : : {
7610 : : Path *newpath;
7611 : :
1865 tgl@sss.pgh.pa.us 7612 : 1763 : newpath = (Path *) create_projection_path(root, rel, subpath,
7613 : : scanjoin_target);
2215 rhaas@postgresql.org 7614 : 1763 : lfirst(lc) = newpath;
7615 : : }
7616 : : }
7617 : :
7618 : : /*
7619 : : * Now, if final scan/join target contains SRFs, insert ProjectSetPath(s)
7620 : : * atop each existing path. (Note that this function doesn't look at the
7621 : : * cheapest-path fields, which is a good thing because they're bogus right
7622 : : * now.)
7623 : : */
2208 7624 [ + + ]: 254510 : if (root->parse->hasTargetSRFs)
7625 : 4202 : adjust_paths_for_srfs(root, rel,
7626 : : scanjoin_targets,
7627 : : scanjoin_targets_contain_srfs);
7628 : :
7629 : : /*
7630 : : * Update the rel's target to be the final (with SRFs) scan/join target.
7631 : : * This now matches the actual output of all the paths, and we might get
7632 : : * confused in createplan.c if they don't agree. We must do this now so
7633 : : * that any append paths made in the next part will use the correct
7634 : : * pathtarget (cf. create_append_path).
7635 : : *
7636 : : * Note that this is also necessary if GetForeignUpperPaths() gets called
7637 : : * on the final scan/join relation or on any of its children, since the
7638 : : * FDW might look at the rel's target to create ForeignPaths.
7639 : : */
1865 tgl@sss.pgh.pa.us 7640 : 254510 : rel->reltarget = llast_node(PathTarget, scanjoin_targets);
7641 : :
7642 : : /*
7643 : : * If the relation is partitioned, recursively apply the scan/join target
7644 : : * to all partitions, and generate brand-new Append paths in which the
7645 : : * scan/join target is computed below the Append rather than above it.
7646 : : * Since Append is not projection-capable, that might save a separate
7647 : : * Result node, and it also is important for partitionwise aggregate.
7648 : : */
7649 [ + + ]: 254510 : if (rel_is_partitioned)
7650 : : {
2208 rhaas@postgresql.org 7651 : 6142 : List *live_children = NIL;
7652 : : int i;
7653 : :
7654 : : /* Adjust each partition. */
985 drowley@postgresql.o 7655 : 6142 : i = -1;
7656 [ + + ]: 17436 : while ((i = bms_next_member(rel->live_parts, i)) >= 0)
7657 : : {
7658 : 11294 : RelOptInfo *child_rel = rel->part_rels[i];
7659 : : AppendRelInfo **appinfos;
7660 : : int nappinfos;
2208 rhaas@postgresql.org 7661 : 11294 : List *child_scanjoin_targets = NIL;
7662 : :
985 drowley@postgresql.o 7663 [ - + ]: 11294 : Assert(child_rel != NULL);
7664 : :
7665 : : /* Dummy children can be ignored. */
7666 [ + + ]: 11294 : if (IS_DUMMY_REL(child_rel))
1842 tgl@sss.pgh.pa.us 7667 : 21 : continue;
7668 : :
7669 : : /* Translate scan/join targets for this child. */
2208 rhaas@postgresql.org 7670 : 11273 : appinfos = find_appinfos_by_relids(root, child_rel->relids,
7671 : : &nappinfos);
7672 [ + - + + : 22546 : foreach(lc, scanjoin_targets)
+ + ]
7673 : : {
7674 : 11273 : PathTarget *target = lfirst_node(PathTarget, lc);
7675 : :
7676 : 11273 : target = copy_pathtarget(target);
7677 : 11273 : target->exprs = (List *)
7678 : 11273 : adjust_appendrel_attrs(root,
7679 : 11273 : (Node *) target->exprs,
7680 : : nappinfos, appinfos);
7681 : 11273 : child_scanjoin_targets = lappend(child_scanjoin_targets,
7682 : : target);
7683 : : }
7684 : 11273 : pfree(appinfos);
7685 : :
7686 : : /* Recursion does the real work. */
7687 : 11273 : apply_scanjoin_target_to_paths(root, child_rel,
7688 : : child_scanjoin_targets,
7689 : : scanjoin_targets_contain_srfs,
7690 : : scanjoin_target_parallel_safe,
7691 : : tlist_same_exprs);
7692 : :
7693 : : /* Save non-dummy children for Append paths. */
7694 [ + - ]: 11273 : if (!IS_DUMMY_REL(child_rel))
7695 : 11273 : live_children = lappend(live_children, child_rel);
7696 : : }
7697 : :
7698 : : /* Build new paths for this relation by appending child paths. */
1865 tgl@sss.pgh.pa.us 7699 : 6142 : add_paths_to_append_rel(root, rel, live_children);
7700 : : }
7701 : :
7702 : : /*
7703 : : * Consider generating Gather or Gather Merge paths. We must only do this
7704 : : * if the relation is parallel safe, and we don't do it for child rels to
7705 : : * avoid creating multiple Gather nodes within the same plan. We must do
7706 : : * this after all paths have been generated and before set_cheapest, since
7707 : : * one of the generated paths may turn out to be the cheapest one.
7708 : : */
2208 rhaas@postgresql.org 7709 [ + + + + : 254510 : if (rel->consider_parallel && !IS_OTHER_REL(rel))
+ + + - ]
1468 tomas.vondra@postgre 7710 : 73885 : generate_useful_gather_paths(root, rel, false);
7711 : :
7712 : : /*
7713 : : * Reassess which paths are the cheapest, now that we've potentially added
7714 : : * new Gather (or Gather Merge) and/or Append (or MergeAppend) paths to
7715 : : * this relation.
7716 : : */
2208 rhaas@postgresql.org 7717 : 254510 : set_cheapest(rel);
2215 7718 : 254510 : }
7719 : :
7720 : : /*
7721 : : * create_partitionwise_grouping_paths
7722 : : *
7723 : : * If the partition keys of input relation are part of the GROUP BY clause, all
7724 : : * the rows belonging to a given group come from a single partition. This
7725 : : * allows aggregation/grouping over a partitioned relation to be broken down
7726 : : * into aggregation/grouping on each partition. This should be no worse, and
7727 : : * often better, than the normal approach.
7728 : : *
7729 : : * However, if the GROUP BY clause does not contain all the partition keys,
7730 : : * rows from a given group may be spread across multiple partitions. In that
7731 : : * case, we perform partial aggregation for each group, append the results,
7732 : : * and then finalize aggregation. This is less certain to win than the
7733 : : * previous case. It may win if the PartialAggregate stage greatly reduces
7734 : : * the number of groups, because fewer rows will pass through the Append node.
7735 : : * It may lose if we have lots of small groups.
7736 : : */
7737 : : static void
7738 : 257 : create_partitionwise_grouping_paths(PlannerInfo *root,
7739 : : RelOptInfo *input_rel,
7740 : : RelOptInfo *grouped_rel,
7741 : : RelOptInfo *partially_grouped_rel,
7742 : : const AggClauseCosts *agg_costs,
7743 : : grouping_sets_data *gd,
7744 : : PartitionwiseAggregateType patype,
7745 : : GroupPathExtraData *extra)
7746 : : {
7747 : 257 : List *grouped_live_children = NIL;
7748 : 257 : List *partially_grouped_live_children = NIL;
2208 7749 : 257 : PathTarget *target = grouped_rel->reltarget;
2123 7750 : 257 : bool partial_grouping_valid = true;
7751 : : int i;
7752 : :
2215 7753 [ - + ]: 257 : Assert(patype != PARTITIONWISE_AGGREGATE_NONE);
7754 [ + + - + ]: 257 : Assert(patype != PARTITIONWISE_AGGREGATE_PARTIAL ||
7755 : : partially_grouped_rel != NULL);
7756 : :
7757 : : /* Add paths for partitionwise aggregation/grouping. */
985 drowley@postgresql.o 7758 : 257 : i = -1;
7759 [ + + ]: 956 : while ((i = bms_next_member(input_rel->live_parts, i)) >= 0)
7760 : : {
7761 : 699 : RelOptInfo *child_input_rel = input_rel->part_rels[i];
7762 : : PathTarget *child_target;
7763 : : AppendRelInfo **appinfos;
7764 : : int nappinfos;
7765 : : GroupPathExtraData child_extra;
7766 : : RelOptInfo *child_grouped_rel;
7767 : : RelOptInfo *child_partially_grouped_rel;
7768 : :
7769 [ - + ]: 699 : Assert(child_input_rel != NULL);
7770 : :
7771 : : /* Dummy children can be ignored. */
7772 [ - + ]: 699 : if (IS_DUMMY_REL(child_input_rel))
1842 tgl@sss.pgh.pa.us 7773 :UBC 0 : continue;
7774 : :
985 drowley@postgresql.o 7775 :CBC 699 : child_target = copy_pathtarget(target);
7776 : :
7777 : : /*
7778 : : * Copy the given "extra" structure as is and then override the
7779 : : * members specific to this child.
7780 : : */
2215 rhaas@postgresql.org 7781 : 699 : memcpy(&child_extra, extra, sizeof(child_extra));
7782 : :
7783 : 699 : appinfos = find_appinfos_by_relids(root, child_input_rel->relids,
7784 : : &nappinfos);
7785 : :
7786 : 699 : child_target->exprs = (List *)
7787 : 699 : adjust_appendrel_attrs(root,
7788 : 699 : (Node *) target->exprs,
7789 : : nappinfos, appinfos);
7790 : :
7791 : : /* Translate havingQual and targetList. */
7792 : 699 : child_extra.havingQual = (Node *)
7793 : : adjust_appendrel_attrs(root,
7794 : : extra->havingQual,
7795 : : nappinfos, appinfos);
7796 : 699 : child_extra.targetList = (List *)
7797 : 699 : adjust_appendrel_attrs(root,
7798 : 699 : (Node *) extra->targetList,
7799 : : nappinfos, appinfos);
7800 : :
7801 : : /*
7802 : : * extra->patype was the value computed for our parent rel; patype is
7803 : : * the value for this relation. For the child, our value is its
7804 : : * parent rel's value.
7805 : : */
7806 : 699 : child_extra.patype = patype;
7807 : :
7808 : : /*
7809 : : * Create grouping relation to hold fully aggregated grouping and/or
7810 : : * aggregation paths for the child.
7811 : : */
7812 : 699 : child_grouped_rel = make_grouping_rel(root, child_input_rel,
7813 : : child_target,
7814 : 699 : extra->target_parallel_safe,
7815 : : child_extra.havingQual);
7816 : :
7817 : : /* Create grouping paths for this child relation. */
7818 : 699 : create_ordinary_grouping_paths(root, child_input_rel,
7819 : : child_grouped_rel,
7820 : : agg_costs, gd, &child_extra,
7821 : : &child_partially_grouped_rel);
7822 : :
7823 [ + + ]: 699 : if (child_partially_grouped_rel)
7824 : : {
7825 : : partially_grouped_live_children =
7826 : 441 : lappend(partially_grouped_live_children,
7827 : : child_partially_grouped_rel);
7828 : : }
7829 : : else
2123 7830 : 258 : partial_grouping_valid = false;
7831 : :
2215 7832 [ + + ]: 699 : if (patype == PARTITIONWISE_AGGREGATE_FULL)
7833 : : {
7834 : 402 : set_cheapest(child_grouped_rel);
7835 : 402 : grouped_live_children = lappend(grouped_live_children,
7836 : : child_grouped_rel);
7837 : : }
7838 : :
7839 : 699 : pfree(appinfos);
7840 : : }
7841 : :
7842 : : /*
7843 : : * Try to create append paths for partially grouped children. For full
7844 : : * partitionwise aggregation, we might have paths in the partial_pathlist
7845 : : * if parallel aggregation is possible. For partial partitionwise
7846 : : * aggregation, we may have paths in both pathlist and partial_pathlist.
7847 : : *
7848 : : * NB: We must have a partially grouped path for every child in order to
7849 : : * generate a partially grouped path for this relation.
7850 : : */
2123 7851 [ + + + + ]: 257 : if (partially_grouped_rel && partial_grouping_valid)
7852 : : {
7853 [ - + ]: 169 : Assert(partially_grouped_live_children != NIL);
7854 : :
2215 7855 : 169 : add_paths_to_append_rel(root, partially_grouped_rel,
7856 : : partially_grouped_live_children);
7857 : :
7858 : : /*
7859 : : * We need call set_cheapest, since the finalization step will use the
7860 : : * cheapest path from the rel.
7861 : : */
7862 [ + - ]: 169 : if (partially_grouped_rel->pathlist)
7863 : 169 : set_cheapest(partially_grouped_rel);
7864 : : }
7865 : :
7866 : : /* If possible, create append paths for fully grouped children. */
7867 [ + + ]: 257 : if (patype == PARTITIONWISE_AGGREGATE_FULL)
7868 : : {
2123 7869 [ - + ]: 142 : Assert(grouped_live_children != NIL);
7870 : :
2215 7871 : 142 : add_paths_to_append_rel(root, grouped_rel, grouped_live_children);
7872 : : }
7873 : 257 : }
7874 : :
7875 : : /*
7876 : : * group_by_has_partkey
7877 : : *
7878 : : * Returns true, if all the partition keys of the given relation are part of
7879 : : * the GROUP BY clauses, false otherwise.
7880 : : */
7881 : : static bool
7882 : 254 : group_by_has_partkey(RelOptInfo *input_rel,
7883 : : List *targetList,
7884 : : List *groupClause)
7885 : : {
7886 : 254 : List *groupexprs = get_sortgrouplist_exprs(groupClause, targetList);
7887 : 254 : int cnt = 0;
7888 : : int partnatts;
7889 : :
7890 : : /* Input relation should be partitioned. */
7891 [ - + ]: 254 : Assert(input_rel->part_scheme);
7892 : :
7893 : : /* Rule out early, if there are no partition keys present. */
7894 [ - + ]: 254 : if (!input_rel->partexprs)
2215 rhaas@postgresql.org 7895 :UBC 0 : return false;
7896 : :
2215 rhaas@postgresql.org 7897 :CBC 254 : partnatts = input_rel->part_scheme->partnatts;
7898 : :
7899 [ + + ]: 414 : for (cnt = 0; cnt < partnatts; cnt++)
7900 : : {
7901 : 272 : List *partexprs = input_rel->partexprs[cnt];
7902 : : ListCell *lc;
7903 : 272 : bool found = false;
7904 : :
7905 [ + + + + : 381 : foreach(lc, partexprs)
+ + ]
7906 : : {
7907 : 269 : Expr *partexpr = lfirst(lc);
7908 : :
7909 [ + + ]: 269 : if (list_member(groupexprs, partexpr))
7910 : : {
7911 : 160 : found = true;
7912 : 160 : break;
7913 : : }
7914 : : }
7915 : :
7916 : : /*
7917 : : * If none of the partition key expressions match with any of the
7918 : : * GROUP BY expression, return false.
7919 : : */
7920 [ + + ]: 272 : if (!found)
7921 : 112 : return false;
7922 : : }
7923 : :
7924 : 142 : return true;
7925 : : }
7926 : :
7927 : : /*
7928 : : * generate_setop_child_grouplist
7929 : : * Build a SortGroupClause list defining the sort/grouping properties
7930 : : * of the child of a set operation.
7931 : : *
7932 : : * This is similar to generate_setop_grouplist() but differs as the setop
7933 : : * child query's targetlist entries may already have a tleSortGroupRef
7934 : : * assigned for other purposes, such as GROUP BYs. Here we keep the
7935 : : * SortGroupClause list in the same order as 'op' groupClauses and just adjust
7936 : : * the tleSortGroupRef to reference the TargetEntry's 'ressortgroupref'.
7937 : : */
7938 : : static List *
20 drowley@postgresql.o 7939 :GNC 5119 : generate_setop_child_grouplist(SetOperationStmt *op, List *targetlist)
7940 : : {
7941 : 5119 : List *grouplist = copyObject(op->groupClauses);
7942 : : ListCell *lg;
7943 : : ListCell *lt;
7944 : :
7945 : 5119 : lg = list_head(grouplist);
7946 [ + + + + : 20096 : foreach(lt, targetlist)
+ + ]
7947 : : {
7948 : 14977 : TargetEntry *tle = (TargetEntry *) lfirst(lt);
7949 : : SortGroupClause *sgc;
7950 : :
7951 : : /* resjunk columns could have sortgrouprefs. Leave these alone */
7952 [ - + ]: 14977 : if (tle->resjunk)
20 drowley@postgresql.o 7953 :UNC 0 : continue;
7954 : :
7955 : : /* we expect every non-resjunk target to have a SortGroupClause */
20 drowley@postgresql.o 7956 [ - + ]:GNC 14977 : Assert(lg != NULL);
7957 : 14977 : sgc = (SortGroupClause *) lfirst(lg);
7958 : 14977 : lg = lnext(grouplist, lg);
7959 : :
7960 : : /* assign a tleSortGroupRef, or reuse the existing one */
7961 : 14977 : sgc->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
7962 : : }
7963 [ - + ]: 5119 : Assert(lg == NULL);
7964 : 5119 : return grouplist;
7965 : : }
|