PostgreSQL Source Code git master
Loading...
Searching...
No Matches
planner.c File Reference
#include "postgres.h"
#include <limits.h>
#include <math.h>
#include "access/genam.h"
#include "access/parallel.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "foreign/fdwapi.h"
#include "jit/jit.h"
#include "lib/bipartite_match.h"
#include "lib/knapsack.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "nodes/supportnodes.h"
#include "optimizer/appendinfo.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/paramassign.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/plancat.h"
#include "optimizer/planmain.h"
#include "optimizer/planner.h"
#include "optimizer/prep.h"
#include "optimizer/subselect.h"
#include "optimizer/tlist.h"
#include "parser/analyze.h"
#include "parser/parse_agg.h"
#include "parser/parse_clause.h"
#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "partitioning/partdesc.h"
#include "rewrite/rewriteManip.h"
#include "utils/acl.h"
#include "utils/backend_status.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/selfuncs.h"
Include dependency graph for planner.c:

Go to the source code of this file.

Data Structures

struct  grouping_sets_data
 
struct  WindowClauseSortData
 
struct  standard_qp_extra
 
struct  having_grouping_ctx
 

Macros

#define EXPRKIND_QUAL   0
 
#define EXPRKIND_TARGET   1
 
#define EXPRKIND_RTFUNC   2
 
#define EXPRKIND_RTFUNC_LATERAL   3
 
#define EXPRKIND_VALUES   4
 
#define EXPRKIND_VALUES_LATERAL   5
 
#define EXPRKIND_LIMIT   6
 
#define EXPRKIND_APPINFO   7
 
#define EXPRKIND_PHV   8
 
#define EXPRKIND_TABLESAMPLE   9
 
#define EXPRKIND_ARBITER_ELEM   10
 
#define EXPRKIND_TABLEFUNC   11
 
#define EXPRKIND_TABLEFUNC_LATERAL   12
 
#define EXPRKIND_GROUPEXPR   13
 

Functions

static Nodepreprocess_expression (PlannerInfo *root, Node *expr, int kind)
 
static void preprocess_qual_conditions (PlannerInfo *root, Node *jtnode)
 
static Bitmapsetfind_having_conflicts (Query *parse, Index group_rtindex)
 
static Oid having_var_grouping_eqop (Var *var, void *context)
 
static Oid group_var_eqop (Query *parse, Var *var)
 
static void grouping_planner (PlannerInfo *root, double tuple_fraction, SetOperationStmt *setops)
 
static grouping_sets_datapreprocess_grouping_sets (PlannerInfo *root)
 
static Listremap_to_groupclause_idx (List *groupClause, List *gsets, int *tleref_to_colnum_map)
 
static void preprocess_rowmarks (PlannerInfo *root)
 
static double preprocess_limit (PlannerInfo *root, double tuple_fraction, int64 *offset_est, int64 *count_est)
 
static Listpreprocess_groupclause (PlannerInfo *root, List *force)
 
static Listextract_rollup_sets (List *groupingSets)
 
static Listreorder_grouping_sets (List *groupingSets, List *sortclause)
 
static void standard_qp_callback (PlannerInfo *root, void *extra)
 
static double get_number_of_groups (PlannerInfo *root, double path_rows, grouping_sets_data *gd, List *target_list)
 
static RelOptInfocreate_grouping_paths (PlannerInfo *root, RelOptInfo *input_rel, PathTarget *target, bool target_parallel_safe, grouping_sets_data *gd)
 
static bool is_degenerate_grouping (PlannerInfo *root)
 
static void create_degenerate_grouping_paths (PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *grouped_rel)
 
static RelOptInfomake_grouping_rel (PlannerInfo *root, RelOptInfo *input_rel, PathTarget *target, bool target_parallel_safe, Node *havingQual)
 
static void create_ordinary_grouping_paths (PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *grouped_rel, const AggClauseCosts *agg_costs, grouping_sets_data *gd, GroupPathExtraData *extra, RelOptInfo **partially_grouped_rel_p)
 
static void consider_groupingsets_paths (PlannerInfo *root, RelOptInfo *grouped_rel, Path *path, bool is_sorted, bool can_hash, grouping_sets_data *gd, const AggClauseCosts *agg_costs, double dNumGroups)
 
static RelOptInfocreate_window_paths (PlannerInfo *root, RelOptInfo *input_rel, PathTarget *input_target, PathTarget *output_target, bool output_target_parallel_safe, WindowFuncLists *wflists, List *activeWindows)
 
static void create_one_window_path (PlannerInfo *root, RelOptInfo *window_rel, Path *path, PathTarget *input_target, PathTarget *output_target, WindowFuncLists *wflists, List *activeWindows)
 
static RelOptInfocreate_distinct_paths (PlannerInfo *root, RelOptInfo *input_rel, PathTarget *target)
 
static void create_partial_distinct_paths (PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *final_distinct_rel, PathTarget *target)
 
static RelOptInfocreate_final_distinct_paths (PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *distinct_rel)
 
static Listget_useful_pathkeys_for_distinct (PlannerInfo *root, List *needed_pathkeys, List *path_pathkeys)
 
static RelOptInfocreate_ordered_paths (PlannerInfo *root, RelOptInfo *input_rel, PathTarget *target, bool target_parallel_safe, double limit_tuples)
 
static PathTargetmake_group_input_target (PlannerInfo *root, PathTarget *final_target)
 
static PathTargetmake_partial_grouping_target (PlannerInfo *root, PathTarget *grouping_target, Node *havingQual)
 
static Listpostprocess_setop_tlist (List *new_tlist, List *orig_tlist)
 
static void optimize_window_clauses (PlannerInfo *root, WindowFuncLists *wflists)
 
static Listselect_active_windows (PlannerInfo *root, WindowFuncLists *wflists)
 
static void name_active_windows (List *activeWindows)
 
static PathTargetmake_window_input_target (PlannerInfo *root, PathTarget *final_target, List *activeWindows)
 
static Listmake_pathkeys_for_window (PlannerInfo *root, WindowClause *wc, List *tlist)
 
static PathTargetmake_sort_input_target (PlannerInfo *root, PathTarget *final_target, bool *have_postponed_srfs)
 
static void adjust_paths_for_srfs (PlannerInfo *root, RelOptInfo *rel, List *targets, List *targets_contain_srfs)
 
static void add_paths_to_grouping_rel (PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *grouped_rel, RelOptInfo *partially_grouped_rel, const AggClauseCosts *agg_costs, grouping_sets_data *gd, GroupPathExtraData *extra)
 
static RelOptInfocreate_partial_grouping_paths (PlannerInfo *root, RelOptInfo *grouped_rel, RelOptInfo *input_rel, grouping_sets_data *gd, GroupPathExtraData *extra, bool force_rel_creation)
 
static Pathmake_ordered_path (PlannerInfo *root, RelOptInfo *rel, Path *path, Path *cheapest_path, List *pathkeys, double limit_tuples)
 
static void gather_grouping_paths (PlannerInfo *root, RelOptInfo *rel)
 
static bool can_partial_agg (PlannerInfo *root)
 
static void apply_scanjoin_target_to_paths (PlannerInfo *root, RelOptInfo *rel, List *scanjoin_targets, List *scanjoin_targets_contain_srfs, bool scanjoin_target_parallel_safe, bool tlist_same_exprs)
 
static void create_partitionwise_grouping_paths (PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *grouped_rel, RelOptInfo *partially_grouped_rel, const AggClauseCosts *agg_costs, grouping_sets_data *gd, PartitionwiseAggregateType patype, GroupPathExtraData *extra)
 
static bool group_by_has_partkey (RelOptInfo *input_rel, List *targetList, List *groupClause)
 
static int common_prefix_cmp (const void *a, const void *b)
 
static Listgenerate_setop_child_grouplist (SetOperationStmt *op, List *targetlist)
 
static void create_final_unique_paths (PlannerInfo *root, RelOptInfo *input_rel, List *sortPathkeys, List *groupClause, SpecialJoinInfo *sjinfo, RelOptInfo *unique_rel)
 
static void create_partial_unique_paths (PlannerInfo *root, RelOptInfo *input_rel, List *sortPathkeys, List *groupClause, SpecialJoinInfo *sjinfo, RelOptInfo *unique_rel)
 
PlannedStmtplanner (Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams, ExplainState *es)
 
PlannedStmtstandard_planner (Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams, ExplainState *es)
 
PlannerInfosubquery_planner (PlannerGlobal *glob, Query *parse, char *plan_name, PlannerInfo *parent_root, PlannerInfo *alternative_root, bool hasRecursion, double tuple_fraction, SetOperationStmt *setops)
 
Exprpreprocess_phv_expression (PlannerInfo *root, Expr *expr)
 
RowMarkType select_rowmark_type (RangeTblEntry *rte, LockClauseStrength strength)
 
bool limit_needed (Query *parse)
 
static bool has_volatile_pathkey (List *keys)
 
static void adjust_group_pathkeys_for_groupagg (PlannerInfo *root)
 
void mark_partial_aggref (Aggref *agg, AggSplit aggsplit)
 
Pathget_cheapest_fractional_path (RelOptInfo *rel, double tuple_fraction)
 
Exprexpression_planner (Expr *expr)
 
Exprexpression_planner_with_deps (Expr *expr, List **relationOids, List **invalItems)
 
bool plan_cluster_use_sort (Oid tableOid, Oid indexOid)
 
int plan_create_index_workers (Oid tableOid, Oid indexOid)
 
RelOptInfocreate_unique_paths (PlannerInfo *root, RelOptInfo *rel, SpecialJoinInfo *sjinfo)
 
charchoose_plan_name (PlannerGlobal *glob, const char *name, bool always_number)
 

Variables

double cursor_tuple_fraction = DEFAULT_CURSOR_TUPLE_FRACTION
 
int debug_parallel_query = DEBUG_PARALLEL_OFF
 
bool parallel_leader_participation = true
 
bool enable_distinct_reordering = true
 
planner_hook_type planner_hook = NULL
 
planner_setup_hook_type planner_setup_hook = NULL
 
planner_shutdown_hook_type planner_shutdown_hook = NULL
 
create_upper_paths_hook_type create_upper_paths_hook = NULL
 

Macro Definition Documentation

◆ EXPRKIND_APPINFO

#define EXPRKIND_APPINFO   7

Definition at line 94 of file planner.c.

◆ EXPRKIND_ARBITER_ELEM

#define EXPRKIND_ARBITER_ELEM   10

Definition at line 97 of file planner.c.

◆ EXPRKIND_GROUPEXPR

#define EXPRKIND_GROUPEXPR   13

Definition at line 100 of file planner.c.

◆ EXPRKIND_LIMIT

#define EXPRKIND_LIMIT   6

Definition at line 93 of file planner.c.

◆ EXPRKIND_PHV

#define EXPRKIND_PHV   8

Definition at line 95 of file planner.c.

◆ EXPRKIND_QUAL

#define EXPRKIND_QUAL   0

Definition at line 87 of file planner.c.

◆ EXPRKIND_RTFUNC

#define EXPRKIND_RTFUNC   2

Definition at line 89 of file planner.c.

◆ EXPRKIND_RTFUNC_LATERAL

#define EXPRKIND_RTFUNC_LATERAL   3

Definition at line 90 of file planner.c.

◆ EXPRKIND_TABLEFUNC

#define EXPRKIND_TABLEFUNC   11

Definition at line 98 of file planner.c.

◆ EXPRKIND_TABLEFUNC_LATERAL

#define EXPRKIND_TABLEFUNC_LATERAL   12

Definition at line 99 of file planner.c.

◆ EXPRKIND_TABLESAMPLE

#define EXPRKIND_TABLESAMPLE   9

Definition at line 96 of file planner.c.

◆ EXPRKIND_TARGET

#define EXPRKIND_TARGET   1

Definition at line 88 of file planner.c.

◆ EXPRKIND_VALUES

#define EXPRKIND_VALUES   4

Definition at line 91 of file planner.c.

◆ EXPRKIND_VALUES_LATERAL

#define EXPRKIND_VALUES_LATERAL   5

Definition at line 92 of file planner.c.

Function Documentation

◆ add_paths_to_grouping_rel()

static void add_paths_to_grouping_rel ( PlannerInfo root,
RelOptInfo input_rel,
RelOptInfo grouped_rel,
RelOptInfo partially_grouped_rel,
const AggClauseCosts agg_costs,
grouping_sets_data gd,
GroupPathExtraData extra 
)
static

Definition at line 7345 of file planner.c.

7351{
7352 Query *parse = root->parse;
7353 Path *cheapest_path = input_rel->cheapest_total_path;
7355 ListCell *lc;
7356 bool can_hash = (extra->flags & GROUPING_CAN_USE_HASH) != 0;
7357 bool can_sort = (extra->flags & GROUPING_CAN_USE_SORT) != 0;
7358 List *havingQual = (List *) extra->havingQual;
7359 AggClauseCosts *agg_final_costs = &extra->agg_final_costs;
7360 double dNumGroups = 0;
7361 double dNumFinalGroups = 0;
7362
7363 /*
7364 * Estimate number of groups for non-split aggregation.
7365 */
7367 cheapest_path->rows,
7368 gd,
7369 extra->targetList);
7370
7372 {
7374 partially_grouped_rel->cheapest_total_path;
7375
7376 /*
7377 * Estimate number of groups for final phase of partial aggregation.
7378 */
7382 gd,
7383 extra->targetList);
7384 }
7385
7386 if (can_sort)
7387 {
7388 /*
7389 * Use any available suitably-sorted path as input, and also consider
7390 * sorting the cheapest-total path and incremental sort on any paths
7391 * with presorted keys.
7392 */
7393 foreach(lc, input_rel->pathlist)
7394 {
7395 ListCell *lc2;
7396 Path *path = (Path *) lfirst(lc);
7397 Path *path_save = path;
7399
7400 /* generate alternative group orderings that might be useful */
7402
7404
7405 foreach(lc2, pathkey_orderings)
7406 {
7408
7409 /* restore the path (we replace it in the loop) */
7410 path = path_save;
7411
7412 path = make_ordered_path(root,
7413 grouped_rel,
7414 path,
7416 info->pathkeys,
7417 -1.0);
7418 if (path == NULL)
7419 continue;
7420
7421 /* Now decide what to stick atop it */
7422 if (parse->groupingSets)
7423 {
7424 consider_groupingsets_paths(root, grouped_rel,
7425 path, true, can_hash,
7427 }
7428 else if (parse->hasAggs)
7429 {
7430 /*
7431 * We have aggregation, possibly with plain GROUP BY. Make
7432 * an AggPath.
7433 */
7434 add_path(grouped_rel, (Path *)
7436 grouped_rel,
7437 path,
7438 grouped_rel->reltarget,
7439 parse->groupClause ? AGG_SORTED : AGG_PLAIN,
7441 info->clauses,
7442 havingQual,
7443 agg_costs,
7444 dNumGroups));
7445 }
7446 else if (parse->groupClause)
7447 {
7448 /*
7449 * We have GROUP BY without aggregation or grouping sets.
7450 * Make a GroupPath.
7451 */
7452 add_path(grouped_rel, (Path *)
7454 grouped_rel,
7455 path,
7456 info->clauses,
7457 havingQual,
7458 dNumGroups));
7459 }
7460 else
7461 {
7462 /* Other cases should have been handled above */
7463 Assert(false);
7464 }
7465 }
7466 }
7467
7468 /*
7469 * Instead of operating directly on the input relation, we can
7470 * consider finalizing a partially aggregated path.
7471 */
7473 {
7474 foreach(lc, partially_grouped_rel->pathlist)
7475 {
7476 ListCell *lc2;
7477 Path *path = (Path *) lfirst(lc);
7478 Path *path_save = path;
7480
7481 /* generate alternative group orderings that might be useful */
7483
7485
7486 /* process all potentially interesting grouping reorderings */
7487 foreach(lc2, pathkey_orderings)
7488 {
7490
7491 /* restore the path (we replace it in the loop) */
7492 path = path_save;
7493
7494 path = make_ordered_path(root,
7495 grouped_rel,
7496 path,
7498 info->pathkeys,
7499 -1.0);
7500
7501 if (path == NULL)
7502 continue;
7503
7504 if (parse->hasAggs)
7505 add_path(grouped_rel, (Path *)
7507 grouped_rel,
7508 path,
7509 grouped_rel->reltarget,
7510 parse->groupClause ? AGG_SORTED : AGG_PLAIN,
7512 info->clauses,
7513 havingQual,
7514 agg_final_costs,
7516 else
7517 add_path(grouped_rel, (Path *)
7519 grouped_rel,
7520 path,
7521 info->clauses,
7522 havingQual,
7524
7525 }
7526 }
7527 }
7528 }
7529
7530 if (can_hash)
7531 {
7532 if (parse->groupingSets)
7533 {
7534 /*
7535 * Try for a hash-only groupingsets path over unsorted input.
7536 */
7537 consider_groupingsets_paths(root, grouped_rel,
7538 cheapest_path, false, true,
7540 }
7541 else
7542 {
7543 /*
7544 * Generate a HashAgg Path. We just need an Agg over the
7545 * cheapest-total input path, since input order won't matter.
7546 */
7547 add_path(grouped_rel, (Path *)
7548 create_agg_path(root, grouped_rel,
7550 grouped_rel->reltarget,
7551 AGG_HASHED,
7553 root->processed_groupClause,
7554 havingQual,
7555 agg_costs,
7556 dNumGroups));
7557 }
7558
7559 /*
7560 * Generate a Finalize HashAgg Path atop of the cheapest partially
7561 * grouped path, assuming there is one
7562 */
7564 {
7565 add_path(grouped_rel, (Path *)
7567 grouped_rel,
7569 grouped_rel->reltarget,
7570 AGG_HASHED,
7572 root->processed_groupClause,
7573 havingQual,
7574 agg_final_costs,
7576 }
7577 }
7578
7579 /*
7580 * When partitionwise aggregate is used, we might have fully aggregated
7581 * paths in the partial pathlist, because add_paths_to_append_rel() will
7582 * consider a path for grouped_rel consisting of a Parallel Append of
7583 * non-partial paths from each child.
7584 */
7585 if (grouped_rel->partial_pathlist != NIL)
7586 gather_grouping_paths(root, grouped_rel);
7587}
#define Assert(condition)
Definition c.h:1002
void parse(int)
Definition parse.c:49
@ AGG_SORTED
Definition nodes.h:363
@ AGG_HASHED
Definition nodes.h:364
@ AGG_PLAIN
Definition nodes.h:362
@ AGGSPLIT_FINAL_DESERIAL
Definition nodes.h:389
@ AGGSPLIT_SIMPLE
Definition nodes.h:385
List * get_useful_group_keys_orderings(PlannerInfo *root, Path *path)
Definition pathkeys.c:467
GroupPath * create_group_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *groupClause, List *qual, double numGroups)
Definition pathnode.c:2948
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition pathnode.c:459
AggPath * create_agg_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, AggStrategy aggstrategy, AggSplit aggsplit, List *groupClause, List *qual, const AggClauseCosts *aggcosts, double numGroups)
Definition pathnode.c:3057
#define GROUPING_CAN_USE_HASH
Definition pathnodes.h:3645
#define GROUPING_CAN_USE_SORT
Definition pathnodes.h:3644
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
static void gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel)
Definition planner.c:8017
static Path * make_ordered_path(PlannerInfo *root, RelOptInfo *rel, Path *path, Path *cheapest_path, List *pathkeys, double limit_tuples)
Definition planner.c:7958
static void consider_groupingsets_paths(PlannerInfo *root, RelOptInfo *grouped_rel, Path *path, bool is_sorted, bool can_hash, grouping_sets_data *gd, const AggClauseCosts *agg_costs, double dNumGroups)
Definition planner.c:4434
static double get_number_of_groups(PlannerInfo *root, double path_rows, grouping_sets_data *gd, List *target_list)
Definition planner.c:3928
static int fb(int x)
tree ctl root
Definition radixtree.h:1857
AggClauseCosts agg_final_costs
Definition pathnodes.h:3685
Definition pg_list.h:54
struct PathTarget * reltarget
Definition pathnodes.h:1045
List * partial_pathlist
Definition pathnodes.h:1052

References add_path(), GroupPathExtraData::agg_final_costs, AGG_HASHED, AGG_PLAIN, AGG_SORTED, AGGSPLIT_FINAL_DESERIAL, AGGSPLIT_SIMPLE, Assert, GroupByOrdering::clauses, consider_groupingsets_paths(), create_agg_path(), create_group_path(), fb(), GroupPathExtraData::flags, gather_grouping_paths(), get_number_of_groups(), get_useful_group_keys_orderings(), GROUPING_CAN_USE_HASH, GROUPING_CAN_USE_SORT, GroupPathExtraData::havingQual, lfirst, list_length(), make_ordered_path(), NIL, parse(), RelOptInfo::partial_pathlist, GroupByOrdering::pathkeys, RelOptInfo::reltarget, root, and GroupPathExtraData::targetList.

Referenced by create_ordinary_grouping_paths().

◆ adjust_group_pathkeys_for_groupagg()

static void adjust_group_pathkeys_for_groupagg ( PlannerInfo root)
static

Definition at line 3499 of file planner.c.

3500{
3501 List *grouppathkeys = root->group_pathkeys;
3505 ListCell *lc;
3506 int i;
3507
3508 /* Shouldn't be here if there are grouping sets */
3509 Assert(root->parse->groupingSets == NIL);
3510 /* Shouldn't be here unless there are some ordered aggregates */
3511 Assert(root->numOrderedAggs > 0);
3512
3513 /* Do nothing if disabled */
3515 return;
3516
3517 /*
3518 * Make a first pass over all AggInfos to collect a Bitmapset containing
3519 * the indexes of all AggInfos to be processed below.
3520 */
3522 foreach(lc, root->agginfos)
3523 {
3525 Aggref *aggref = linitial_node(Aggref, agginfo->aggrefs);
3526
3527 if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
3528 continue;
3529
3530 /* Skip unless there's a DISTINCT or ORDER BY clause */
3531 if (aggref->aggdistinct == NIL && aggref->aggorder == NIL)
3532 continue;
3533
3534 /* Additional safety checks are needed if there's a FILTER clause */
3535 if (aggref->aggfilter != NULL)
3536 {
3537 ListCell *lc2;
3538 bool allow_presort = true;
3539
3540 /*
3541 * When the Aggref has a FILTER clause, it's possible that the
3542 * filter removes rows that cannot be sorted because the
3543 * expression to sort by results in an error during its
3544 * evaluation. This is a problem for presorting as that happens
3545 * before the FILTER, whereas without presorting, the Aggregate
3546 * node will apply the FILTER *before* sorting. So that we never
3547 * try to sort anything that might error, here we aim to skip over
3548 * any Aggrefs with arguments with expressions which, when
3549 * evaluated, could cause an ERROR. Vars and Consts are ok. There
3550 * may be more cases that should be allowed, but more thought
3551 * needs to be given. Err on the side of caution.
3552 */
3553 foreach(lc2, aggref->args)
3554 {
3556 Expr *expr = tle->expr;
3557
3558 while (IsA(expr, RelabelType))
3559 expr = (Expr *) (castNode(RelabelType, expr))->arg;
3560
3561 /* Common case, Vars and Consts are ok */
3562 if (IsA(expr, Var) || IsA(expr, Const))
3563 continue;
3564
3565 /* Unsupported. Don't try to presort for this Aggref */
3566 allow_presort = false;
3567 break;
3568 }
3569
3570 /* Skip unsupported Aggrefs */
3571 if (!allow_presort)
3572 continue;
3573 }
3574
3577 }
3578
3579 /*
3580 * Now process all the unprocessed_aggs to find the best set of pathkeys
3581 * for the given set of aggregates.
3582 *
3583 * On the first outer loop here 'bestaggs' will be empty. We'll populate
3584 * this during the first loop using the pathkeys for the very first
3585 * AggInfo then taking any stronger pathkeys from any other AggInfos with
3586 * a more strict set of compatible pathkeys. Once the outer loop is
3587 * complete, we mark off all the aggregates with compatible pathkeys then
3588 * remove those from the unprocessed_aggs and repeat the process to try to
3589 * find another set of pathkeys that are suitable for a larger number of
3590 * aggregates. The outer loop will stop when there are not enough
3591 * unprocessed aggregates for it to be possible to find a set of pathkeys
3592 * to suit a larger number of aggregates.
3593 */
3594 bestpathkeys = NIL;
3595 bestaggs = NULL;
3597 {
3600
3601 i = -1;
3602 while ((i = bms_next_member(unprocessed_aggs, i)) >= 0)
3603 {
3604 AggInfo *agginfo = list_nth_node(AggInfo, root->agginfos, i);
3605 Aggref *aggref = linitial_node(Aggref, agginfo->aggrefs);
3606 List *sortlist;
3607 List *pathkeys;
3608
3609 if (aggref->aggdistinct != NIL)
3610 sortlist = aggref->aggdistinct;
3611 else
3612 sortlist = aggref->aggorder;
3613
3615 aggref->args);
3616
3617 /*
3618 * Ignore Aggrefs which have volatile functions in their ORDER BY
3619 * or DISTINCT clause.
3620 */
3621 if (has_volatile_pathkey(pathkeys))
3622 {
3624 continue;
3625 }
3626
3627 /*
3628 * When not set yet, take the pathkeys from the first unprocessed
3629 * aggregate.
3630 */
3631 if (currpathkeys == NIL)
3632 {
3633 currpathkeys = pathkeys;
3634
3635 /* include the GROUP BY pathkeys, if they exist */
3636 if (grouppathkeys != NIL)
3638 currpathkeys);
3639
3640 /* record that we found pathkeys for this aggregate */
3642 }
3643 else
3644 {
3645 /* now look for a stronger set of matching pathkeys */
3646
3647 /* include the GROUP BY pathkeys, if they exist */
3648 if (grouppathkeys != NIL)
3650 pathkeys);
3651
3652 /* are 'pathkeys' compatible or better than 'currpathkeys'? */
3653 switch (compare_pathkeys(currpathkeys, pathkeys))
3654 {
3655 case PATHKEYS_BETTER2:
3656 /* 'pathkeys' are stronger, use these ones instead */
3657 currpathkeys = pathkeys;
3659
3660 case PATHKEYS_BETTER1:
3661 /* 'pathkeys' are less strict */
3663
3664 case PATHKEYS_EQUAL:
3665 /* mark this aggregate as covered by 'currpathkeys' */
3667 break;
3668
3669 case PATHKEYS_DIFFERENT:
3670 break;
3671 }
3672 }
3673 }
3674
3675 /* remove the aggregates that we've just processed */
3677
3678 /*
3679 * If this pass included more aggregates than the previous best then
3680 * use these ones as the best set.
3681 */
3683 {
3686 }
3687 }
3688
3689 /*
3690 * If we found any ordered aggregates, update root->group_pathkeys to add
3691 * the best set of aggregate pathkeys. Note that bestpathkeys includes
3692 * the original GROUP BY pathkeys already.
3693 */
3694 if (bestpathkeys != NIL)
3695 root->group_pathkeys = bestpathkeys;
3696
3697 /*
3698 * Now that we've found the best set of aggregates we can set the
3699 * presorted flag to indicate to the executor that it needn't bother
3700 * performing a sort for these Aggrefs. We're able to do this now as
3701 * there's no chance of a Hash Aggregate plan as create_grouping_paths
3702 * will not mark the GROUP BY as GROUPING_CAN_USE_HASH due to the presence
3703 * of ordered aggregates.
3704 */
3705 i = -1;
3706 while ((i = bms_next_member(bestaggs, i)) >= 0)
3707 {
3708 AggInfo *agginfo = list_nth_node(AggInfo, root->agginfos, i);
3709
3710 foreach(lc, agginfo->aggrefs)
3711 {
3712 Aggref *aggref = lfirst_node(Aggref, lc);
3713
3714 aggref->aggpresorted = true;
3715 }
3716 }
3717}
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1290
Bitmapset * bms_del_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1145
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition bitmapset.c:852
int bms_num_members(const Bitmapset *a)
Definition bitmapset.c:744
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
#define pg_fallthrough
Definition c.h:220
bool enable_presorted_aggregate
Definition costsize.c:165
Datum arg
Definition elog.c:1323
int i
Definition isn.c:77
List * list_copy(const List *oldlist)
Definition list.c:1573
#define IsA(nodeptr, _type_)
Definition nodes.h:162
#define castNode(_type_, nodeptr)
Definition nodes.h:180
List * append_pathkeys(List *target, List *source)
Definition pathkeys.c:107
List * make_pathkeys_for_sortclauses(PlannerInfo *root, List *sortclauses, List *tlist)
Definition pathkeys.c:1336
PathKeysComparison compare_pathkeys(List *keys1, List *keys2)
Definition pathkeys.c:304
@ PATHKEYS_BETTER2
Definition paths.h:221
@ PATHKEYS_BETTER1
Definition paths.h:220
@ PATHKEYS_DIFFERENT
Definition paths.h:222
@ PATHKEYS_EQUAL
Definition paths.h:219
#define lfirst_node(type, lc)
Definition pg_list.h:176
#define linitial_node(type, l)
Definition pg_list.h:181
#define foreach_current_index(var_or_cell)
Definition pg_list.h:435
#define list_nth_node(type, list, n)
Definition pg_list.h:359
static bool has_volatile_pathkey(List *keys)
Definition planner.c:3454
List * aggdistinct
Definition primnodes.h:491
List * args
Definition primnodes.h:485
Expr * aggfilter
Definition primnodes.h:494
List * aggorder
Definition primnodes.h:488

References Aggref::aggdistinct, Aggref::aggfilter, Aggref::aggorder, append_pathkeys(), arg, Aggref::args, Assert, bms_add_member(), bms_del_member(), bms_del_members(), bms_next_member(), bms_num_members(), castNode, compare_pathkeys(), enable_presorted_aggregate, fb(), foreach_current_index, has_volatile_pathkey(), i, IsA, lfirst, lfirst_node, linitial_node, list_copy(), list_nth_node, make_pathkeys_for_sortclauses(), NIL, PATHKEYS_BETTER1, PATHKEYS_BETTER2, PATHKEYS_DIFFERENT, PATHKEYS_EQUAL, pg_fallthrough, and root.

Referenced by standard_qp_callback().

◆ adjust_paths_for_srfs()

static void adjust_paths_for_srfs ( PlannerInfo root,
RelOptInfo rel,
List targets,
List targets_contain_srfs 
)
static

Definition at line 6894 of file planner.c.

6896{
6897 ListCell *lc;
6898
6901
6902 /* If no SRFs appear at this plan level, nothing to do */
6903 if (list_length(targets) == 1)
6904 return;
6905
6906 /*
6907 * Stack SRF-evaluation nodes atop each path for the rel.
6908 *
6909 * In principle we should re-run set_cheapest() here to identify the
6910 * cheapest path, but it seems unlikely that adding the same tlist eval
6911 * costs to all the paths would change that, so we don't bother. Instead,
6912 * just assume that the cheapest-startup and cheapest-total paths remain
6913 * so. (There should be no parameterized paths anymore, so we needn't
6914 * worry about updating cheapest_parameterized_paths.)
6915 */
6916 foreach(lc, rel->pathlist)
6917 {
6918 Path *subpath = (Path *) lfirst(lc);
6919 Path *newpath = subpath;
6920 ListCell *lc1,
6921 *lc2;
6922
6923 Assert(subpath->param_info == NULL);
6925 {
6927 bool contains_srfs = (bool) lfirst_int(lc2);
6928
6929 /* If this level doesn't contain SRFs, do regular projection */
6930 if (contains_srfs)
6932 rel,
6933 newpath,
6934 thistarget);
6935 else
6937 rel,
6938 newpath,
6939 thistarget);
6940 }
6941 lfirst(lc) = newpath;
6942 if (subpath == rel->cheapest_startup_path)
6944 if (subpath == rel->cheapest_total_path)
6946 }
6947
6948 /* Likewise for partial paths, if any */
6949 foreach(lc, rel->partial_pathlist)
6950 {
6951 Path *subpath = (Path *) lfirst(lc);
6952 Path *newpath = subpath;
6953 ListCell *lc1,
6954 *lc2;
6955
6956 Assert(subpath->param_info == NULL);
6958 {
6960 bool contains_srfs = (bool) lfirst_int(lc2);
6961
6962 /* If this level doesn't contain SRFs, do regular projection */
6963 if (contains_srfs)
6965 rel,
6966 newpath,
6967 thistarget);
6968 else
6969 {
6970 /* avoid apply_projection_to_path, in case of multiple refs */
6972 rel,
6973 newpath,
6974 thistarget);
6975 }
6976 }
6977 lfirst(lc) = newpath;
6978 }
6979}
Datum subpath(PG_FUNCTION_ARGS)
Definition ltree_op.c:348
ProjectSetPath * create_set_projection_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
Definition pathnode.c:2785
ProjectionPath * create_projection_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target)
Definition pathnode.c:2587
Path * apply_projection_to_path(PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target)
Definition pathnode.c:2696
#define forboth(cell1, list1, cell2, list2)
Definition pg_list.h:550
#define lfirst_int(lc)
Definition pg_list.h:173
#define linitial_int(l)
Definition pg_list.h:179
List * pathlist
Definition pathnodes.h:1050
struct Path * cheapest_startup_path
Definition pathnodes.h:1053
struct Path * cheapest_total_path
Definition pathnodes.h:1054

References apply_projection_to_path(), Assert, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, create_projection_path(), create_set_projection_path(), fb(), forboth, lfirst, lfirst_int, lfirst_node, linitial_int, list_length(), RelOptInfo::partial_pathlist, RelOptInfo::pathlist, root, and subpath().

Referenced by apply_scanjoin_target_to_paths(), and grouping_planner().

◆ apply_scanjoin_target_to_paths()

static void apply_scanjoin_target_to_paths ( PlannerInfo root,
RelOptInfo rel,
List scanjoin_targets,
List scanjoin_targets_contain_srfs,
bool  scanjoin_target_parallel_safe,
bool  tlist_same_exprs 
)
static

Definition at line 8142 of file planner.c.

8148{
8151 ListCell *lc;
8152
8153 /* This recurses, so be paranoid. */
8155
8156 /*
8157 * If the rel only has Append and MergeAppend paths, we want to drop its
8158 * existing paths and generate new ones. This function would still be
8159 * correct if we kept the existing paths: we'd modify them to generate the
8160 * correct target above the partitioning Append, and then they'd compete
8161 * on cost with paths generating the target below the Append. However, in
8162 * our current cost model the latter way is always the same or cheaper
8163 * cost, so modifying the existing paths would just be useless work.
8164 * Moreover, when the cost is the same, varying roundoff errors might
8165 * sometimes allow an existing path to be picked, resulting in undesirable
8166 * cross-platform plan variations. So we drop old paths and thereby force
8167 * the work to be done below the Append.
8168 *
8169 * However, there are several cases when this optimization is not safe. If
8170 * the rel isn't partitioned, then none of the paths will be Append or
8171 * MergeAppend paths, so we should definitely not do this. If it is
8172 * partitioned but is a joinrel, it may have Append and MergeAppend paths,
8173 * but it can also have join paths that we can't afford to discard.
8174 *
8175 * Some care is needed, because we have to allow
8176 * generate_useful_gather_paths to see the old partial paths in the next
8177 * stanza. Hence, zap the main pathlist here, then allow
8178 * generate_useful_gather_paths to add path(s) to the main list, and
8179 * finally zap the partial pathlist.
8180 */
8182 rel->pathlist = NIL;
8183
8184 /*
8185 * If the scan/join target is not parallel-safe, partial paths cannot
8186 * generate it.
8187 */
8189 {
8190 /*
8191 * Since we can't generate the final scan/join target in parallel
8192 * workers, this is our last opportunity to use any partial paths that
8193 * exist; so build Gather path(s) that use them and emit whatever the
8194 * current reltarget is. We don't do this in the case where the
8195 * target is parallel-safe, since we will be able to generate superior
8196 * paths by doing it after the final scan/join target has been
8197 * applied.
8198 */
8200
8201 /* Can't use parallel query above this level. */
8202 rel->partial_pathlist = NIL;
8203 rel->consider_parallel = false;
8204 }
8205
8206 /* Finish dropping old paths for a partitioned rel, per comment above */
8208 rel->partial_pathlist = NIL;
8209
8210 /* Extract SRF-free scan/join target. */
8212
8213 /*
8214 * Apply the SRF-free scan/join target to each existing path.
8215 *
8216 * If the tlist exprs are the same, we can just inject the sortgroupref
8217 * information into the existing pathtargets. Otherwise, replace each
8218 * path with a projection path that generates the SRF-free scan/join
8219 * target. This can't change the ordering of paths within rel->pathlist,
8220 * so we just modify the list in place.
8221 */
8222 foreach(lc, rel->pathlist)
8223 {
8224 Path *subpath = (Path *) lfirst(lc);
8225
8226 /* Shouldn't have any parameterized paths anymore */
8227 Assert(subpath->param_info == NULL);
8228
8229 if (tlist_same_exprs)
8230 subpath->pathtarget->sortgrouprefs =
8231 scanjoin_target->sortgrouprefs;
8232 else
8233 {
8234 Path *newpath;
8235
8238 lfirst(lc) = newpath;
8239 }
8240 }
8241
8242 /* Likewise adjust the targets for any partial paths. */
8243 foreach(lc, rel->partial_pathlist)
8244 {
8245 Path *subpath = (Path *) lfirst(lc);
8246
8247 /* Shouldn't have any parameterized paths anymore */
8248 Assert(subpath->param_info == NULL);
8249
8250 if (tlist_same_exprs)
8251 subpath->pathtarget->sortgrouprefs =
8252 scanjoin_target->sortgrouprefs;
8253 else
8254 {
8255 Path *newpath;
8256
8259 lfirst(lc) = newpath;
8260 }
8261 }
8262
8263 /*
8264 * Now, if final scan/join target contains SRFs, insert ProjectSetPath(s)
8265 * atop each existing path. (Note that this function doesn't look at the
8266 * cheapest-path fields, which is a good thing because they're bogus right
8267 * now.)
8268 */
8269 if (root->parse->hasTargetSRFs)
8273
8274 /*
8275 * Update the rel's target to be the final (with SRFs) scan/join target.
8276 * This now matches the actual output of all the paths, and we might get
8277 * confused in createplan.c if they don't agree. We must do this now so
8278 * that any append paths made in the next part will use the correct
8279 * pathtarget (cf. create_append_path).
8280 *
8281 * Note that this is also necessary if GetForeignUpperPaths() gets called
8282 * on the final scan/join relation or on any of its children, since the
8283 * FDW might look at the rel's target to create ForeignPaths.
8284 */
8286
8287 /*
8288 * If the relation is partitioned, recursively apply the scan/join target
8289 * to all partitions, and generate brand-new Append paths in which the
8290 * scan/join target is computed below the Append rather than above it.
8291 * Since Append is not projection-capable, that might save a separate
8292 * Result node, and it also is important for partitionwise aggregate.
8293 */
8295 {
8297 int i;
8298
8299 /* Adjust each partition. */
8300 i = -1;
8301 while ((i = bms_next_member(rel->live_parts, i)) >= 0)
8302 {
8303 RelOptInfo *child_rel = rel->part_rels[i];
8304 AppendRelInfo **appinfos;
8305 int nappinfos;
8307
8308 Assert(child_rel != NULL);
8309
8310 /* Dummy children can be ignored. */
8312 continue;
8313
8314 /* Translate scan/join targets for this child. */
8315 appinfos = find_appinfos_by_relids(root, child_rel->relids,
8316 &nappinfos);
8317 foreach(lc, scanjoin_targets)
8318 {
8319 PathTarget *target = lfirst_node(PathTarget, lc);
8320
8321 target = copy_pathtarget(target);
8322 target->exprs = (List *)
8324 (Node *) target->exprs,
8325 nappinfos, appinfos);
8327 target);
8328 }
8329 pfree(appinfos);
8330
8331 /* Recursion does the real work. */
8337
8338 /* Save non-dummy children for Append paths. */
8339 if (!IS_DUMMY_REL(child_rel))
8341 }
8342
8343 /* Build new paths for this relation by appending child paths. */
8345 }
8346
8347 /*
8348 * Consider generating Gather or Gather Merge paths. We must only do this
8349 * if the relation is parallel safe, and we don't do it for child rels to
8350 * avoid creating multiple Gather nodes within the same plan. We must do
8351 * this after all paths have been generated and before set_cheapest, since
8352 * one of the generated paths may turn out to be the cheapest one.
8353 */
8354 if (rel->consider_parallel && !IS_OTHER_REL(rel))
8356
8357 /*
8358 * Reassess which paths are the cheapest, now that we've potentially added
8359 * new Gather (or Gather Merge) and/or Append (or MergeAppend) paths to
8360 * this relation.
8361 */
8362 set_cheapest(rel);
8363}
void generate_useful_gather_paths(PlannerInfo *root, RelOptInfo *rel, bool override_rows)
Definition allpaths.c:3392
void add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, List *live_childrels)
Definition allpaths.c:1420
AppendRelInfo ** find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
Definition appendinfo.c:809
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
Definition appendinfo.c:201
List * lappend(List *list, void *datum)
Definition list.c:339
void pfree(void *pointer)
Definition mcxt.c:1619
void set_cheapest(RelOptInfo *parent_rel)
Definition pathnode.c:268
#define IS_SIMPLE_REL(rel)
Definition pathnodes.h:989
#define IS_DUMMY_REL(r)
Definition pathnodes.h:2299
#define IS_PARTITIONED_REL(rel)
Definition pathnodes.h:1231
#define IS_OTHER_REL(rel)
Definition pathnodes.h:1004
#define llast_node(type, l)
Definition pg_list.h:202
static void apply_scanjoin_target_to_paths(PlannerInfo *root, RelOptInfo *rel, List *scanjoin_targets, List *scanjoin_targets_contain_srfs, bool scanjoin_target_parallel_safe, bool tlist_same_exprs)
Definition planner.c:8142
static void adjust_paths_for_srfs(PlannerInfo *root, RelOptInfo *rel, List *targets, List *targets_contain_srfs)
Definition planner.c:6894
void check_stack_depth(void)
Definition stack_depth.c:96
Definition nodes.h:133
List * exprs
Definition pathnodes.h:1878
bool consider_parallel
Definition pathnodes.h:1037
Bitmapset * live_parts
Definition pathnodes.h:1204
bool tlist_same_exprs(List *tlist1, List *tlist2)
Definition tlist.c:227
PathTarget * copy_pathtarget(PathTarget *src)
Definition tlist.c:666

References add_paths_to_append_rel(), adjust_appendrel_attrs(), adjust_paths_for_srfs(), apply_scanjoin_target_to_paths(), Assert, bms_next_member(), check_stack_depth(), RelOptInfo::consider_parallel, copy_pathtarget(), create_projection_path(), PathTarget::exprs, fb(), find_appinfos_by_relids(), generate_useful_gather_paths(), i, IS_DUMMY_REL, IS_OTHER_REL, IS_PARTITIONED_REL, IS_SIMPLE_REL, lappend(), lfirst, lfirst_node, linitial_node, RelOptInfo::live_parts, llast_node, NIL, RelOptInfo::partial_pathlist, RelOptInfo::pathlist, pfree(), RelOptInfo::reltarget, root, set_cheapest(), subpath(), and tlist_same_exprs().

Referenced by apply_scanjoin_target_to_paths(), and grouping_planner().

◆ can_partial_agg()

static bool can_partial_agg ( PlannerInfo root)
static

Definition at line 8100 of file planner.c.

8101{
8102 Query *parse = root->parse;
8103
8104 if (!parse->hasAggs && parse->groupClause == NIL)
8105 {
8106 /*
8107 * We don't know how to do parallel aggregation unless we have either
8108 * some aggregates or a grouping clause.
8109 */
8110 return false;
8111 }
8112 else if (parse->groupingSets)
8113 {
8114 /* We don't know how to do grouping sets in parallel. */
8115 return false;
8116 }
8117 else if (root->hasNonPartialAggs || root->hasNonSerialAggs)
8118 {
8119 /* Insufficient support for partial mode. */
8120 return false;
8121 }
8122
8123 /* Everything looks good. */
8124 return true;
8125}

References NIL, parse(), and root.

Referenced by create_grouping_paths().

◆ choose_plan_name()

char * choose_plan_name ( PlannerGlobal glob,
const char name,
bool  always_number 
)

Definition at line 9215 of file planner.c.

9216{
9217 unsigned n;
9218
9219 /*
9220 * If a numeric suffix is not required, then search the list of
9221 * previously-assigned names for a match. If none is found, then we can
9222 * use the provided name without modification.
9223 */
9224 if (!always_number)
9225 {
9226 bool found = false;
9227
9228 foreach_ptr(char, subplan_name, glob->subplanNames)
9229 {
9230 if (strcmp(subplan_name, name) == 0)
9231 {
9232 found = true;
9233 break;
9234 }
9235 }
9236
9237 if (!found)
9238 {
9239 /* pstrdup here is just to avoid cast-away-const */
9240 char *chosen_name = pstrdup(name);
9241
9242 glob->subplanNames = lappend(glob->subplanNames, chosen_name);
9243 return chosen_name;
9244 }
9245 }
9246
9247 /*
9248 * If a numeric suffix is required or if the un-suffixed name is already
9249 * in use, then loop until we find a positive integer that produces a
9250 * novel name.
9251 */
9252 for (n = 1; true; ++n)
9253 {
9254 char *proposed_name = psprintf("%s_%u", name, n);
9255 bool found = false;
9256
9257 foreach_ptr(char, subplan_name, glob->subplanNames)
9258 {
9260 {
9261 found = true;
9262 break;
9263 }
9264 }
9265
9266 if (!found)
9267 {
9268 glob->subplanNames = lappend(glob->subplanNames, proposed_name);
9269 return proposed_name;
9270 }
9271
9273 }
9274}
char * pstrdup(const char *in)
Definition mcxt.c:1910
#define foreach_ptr(type, var, lst)
Definition pg_list.h:501
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
const char * name

References fb(), foreach_ptr, lappend(), name, pfree(), psprintf(), and pstrdup().

Referenced by build_minmax_path(), make_subplan(), recurse_set_operations(), set_subquery_pathlist(), and SS_process_ctes().

◆ common_prefix_cmp()

static int common_prefix_cmp ( const void a,
const void b 
)
static

Definition at line 6355 of file planner.c.

6356{
6357 const WindowClauseSortData *wcsa = a;
6358 const WindowClauseSortData *wcsb = b;
6361
6362 forboth(item_a, wcsa->uniqueOrder, item_b, wcsb->uniqueOrder)
6363 {
6366
6367 if (sca->tleSortGroupRef > scb->tleSortGroupRef)
6368 return -1;
6369 else if (sca->tleSortGroupRef < scb->tleSortGroupRef)
6370 return 1;
6371 else if (sca->sortop > scb->sortop)
6372 return -1;
6373 else if (sca->sortop < scb->sortop)
6374 return 1;
6375 else if (sca->nulls_first && !scb->nulls_first)
6376 return -1;
6377 else if (!sca->nulls_first && scb->nulls_first)
6378 return 1;
6379 /* no need to compare eqop, since it is fully determined by sortop */
6380 }
6381
6382 if (list_length(wcsa->uniqueOrder) > list_length(wcsb->uniqueOrder))
6383 return -1;
6384 else if (list_length(wcsa->uniqueOrder) < list_length(wcsb->uniqueOrder))
6385 return 1;
6386
6387 return 0;
6388}
int b
Definition isn.c:74
int a
Definition isn.c:73

References a, b, fb(), forboth, lfirst_node, and list_length().

Referenced by select_active_windows().

◆ consider_groupingsets_paths()

static void consider_groupingsets_paths ( PlannerInfo root,
RelOptInfo grouped_rel,
Path path,
bool  is_sorted,
bool  can_hash,
grouping_sets_data gd,
const AggClauseCosts agg_costs,
double  dNumGroups 
)
static

Definition at line 4434 of file planner.c.

4442{
4443 Query *parse = root->parse;
4444 Size hash_mem_limit = get_hash_memory_limit();
4445
4446 /*
4447 * If we're not being offered sorted input, then only consider plans that
4448 * can be done entirely by hashing.
4449 *
4450 * We can hash everything if it looks like it'll fit in hash_mem. But if
4451 * the input is actually sorted despite not being advertised as such, we
4452 * prefer to make use of that in order to use less memory.
4453 *
4454 * If none of the grouping sets are sortable, then ignore the hash_mem
4455 * limit and generate a path anyway, since otherwise we'll just fail.
4456 */
4457 if (!is_sorted)
4458 {
4459 List *new_rollups = NIL;
4461 List *sets_data;
4463 List *empty_sets = NIL;
4464 ListCell *lc;
4465 ListCell *l_start = list_head(gd->rollups);
4467 double hashsize;
4468 double exclude_groups = 0.0;
4469
4471
4472 /*
4473 * If the input is coincidentally sorted usefully (which can happen
4474 * even if is_sorted is false, since that only means that our caller
4475 * has set up the sorting for us), then save some hashtable space by
4476 * making use of that. But we need to watch out for degenerate cases:
4477 *
4478 * 1) If there are any empty grouping sets, then group_pathkeys might
4479 * be NIL if all non-empty grouping sets are unsortable. In this case,
4480 * there will be a rollup containing only empty groups, and the
4481 * pathkeys_contained_in test is vacuously true; this is ok.
4482 *
4483 * XXX: the above relies on the fact that group_pathkeys is generated
4484 * from the first rollup. If we add the ability to consider multiple
4485 * sort orders for grouping input, this assumption might fail.
4486 *
4487 * 2) If there are no empty sets and only unsortable sets, then the
4488 * rollups list will be empty (and thus l_start == NULL), and
4489 * group_pathkeys will be NIL; we must ensure that the vacuously-true
4490 * pathkeys_contained_in test doesn't cause us to crash.
4491 */
4492 if (l_start != NULL &&
4493 pathkeys_contained_in(root->group_pathkeys, path->pathkeys))
4494 {
4496 exclude_groups = unhashed_rollup->numGroups;
4497 l_start = lnext(gd->rollups, l_start);
4498 }
4499
4501 path,
4502 agg_costs,
4504
4505 /*
4506 * gd->rollups is empty if we have only unsortable columns to work
4507 * with. Override hash_mem in that case; otherwise, we'll rely on the
4508 * sorted-input case to generate usable mixed paths.
4509 */
4510 if (hashsize > hash_mem_limit && gd->rollups)
4511 return; /* nope, won't fit */
4512
4513 /*
4514 * We need to burst the existing rollups list into individual grouping
4515 * sets and recompute a groupClause for each set.
4516 */
4517 sets_data = list_copy(gd->unsortable_sets);
4518
4519 for_each_cell(lc, gd->rollups, l_start)
4520 {
4522
4523 /*
4524 * If we find an unhashable rollup that's not been skipped by the
4525 * "actually sorted" check above, we can't cope; we'd need sorted
4526 * input (with a different sort order) but we can't get that here.
4527 * So bail out; we'll get a valid path from the is_sorted case
4528 * instead.
4529 *
4530 * The mere presence of empty grouping sets doesn't make a rollup
4531 * unhashable (see preprocess_grouping_sets), we handle those
4532 * specially below.
4533 */
4534 if (!rollup->hashable)
4535 return;
4536
4537 sets_data = list_concat(sets_data, rollup->gsets_data);
4538 }
4539 foreach(lc, sets_data)
4540 {
4542 List *gset = gs->set;
4544
4545 if (gset == NIL)
4546 {
4547 /* Empty grouping sets can't be hashed. */
4550 }
4551 else
4552 {
4554
4555 rollup->groupClause = preprocess_groupclause(root, gset);
4556 rollup->gsets_data = list_make1(gs);
4557 rollup->gsets = remap_to_groupclause_idx(rollup->groupClause,
4558 rollup->gsets_data,
4559 gd->tleref_to_colnum_map);
4560 rollup->numGroups = gs->numGroups;
4561 rollup->hashable = true;
4562 rollup->is_hashed = true;
4564 }
4565 }
4566
4567 /*
4568 * If we didn't find anything nonempty to hash, then bail. We'll
4569 * generate a path from the is_sorted case.
4570 */
4571 if (new_rollups == NIL)
4572 return;
4573
4574 /*
4575 * If there were empty grouping sets they should have been in the
4576 * first rollup.
4577 */
4579
4580 if (unhashed_rollup)
4581 {
4583 strat = AGG_MIXED;
4584 }
4585 else if (empty_sets)
4586 {
4588
4589 rollup->groupClause = NIL;
4590 rollup->gsets_data = empty_sets_data;
4591 rollup->gsets = empty_sets;
4592 rollup->numGroups = list_length(empty_sets);
4593 rollup->hashable = false;
4594 rollup->is_hashed = false;
4596 strat = AGG_MIXED;
4597 }
4598
4599 add_path(grouped_rel, (Path *)
4601 grouped_rel,
4602 path,
4603 (List *) parse->havingQual,
4604 strat,
4606 agg_costs));
4607 return;
4608 }
4609
4610 /*
4611 * If we have sorted input but nothing we can do with it, bail.
4612 */
4613 if (gd->rollups == NIL)
4614 return;
4615
4616 /*
4617 * Given sorted input, we try and make two paths: one sorted and one mixed
4618 * sort/hash. (We need to try both because hashagg might be disabled, or
4619 * some columns might not be sortable.)
4620 *
4621 * can_hash is passed in as false if some obstacle elsewhere (such as
4622 * ordered aggs) means that we shouldn't consider hashing at all.
4623 */
4624 if (can_hash && gd->any_hashable)
4625 {
4626 List *rollups = NIL;
4627 List *hash_sets = list_copy(gd->unsortable_sets);
4628 double availspace = hash_mem_limit;
4629 ListCell *lc;
4630
4631 /*
4632 * Account first for space needed for groups we can't sort at all.
4633 */
4635 path,
4636 agg_costs,
4637 gd->dNumHashGroups);
4638
4639 if (availspace > 0 && list_length(gd->rollups) > 1)
4640 {
4641 double scale;
4642 int num_rollups = list_length(gd->rollups);
4643 int k_capacity;
4644 int *k_weights = palloc(num_rollups * sizeof(int));
4646 int i;
4647
4648 /*
4649 * We treat this as a knapsack problem: the knapsack capacity
4650 * represents hash_mem, the item weights are the estimated memory
4651 * usage of the hashtables needed to implement a single rollup,
4652 * and we really ought to use the cost saving as the item value;
4653 * however, currently the costs assigned to sort nodes don't
4654 * reflect the comparison costs well, and so we treat all items as
4655 * of equal value (each rollup we hash instead saves us one sort).
4656 *
4657 * To use the discrete knapsack, we need to scale the values to a
4658 * reasonably small bounded range. We choose to allow a 5% error
4659 * margin; we have no more than 4096 rollups in the worst possible
4660 * case, which with a 5% error margin will require a bit over 42MB
4661 * of workspace. (Anyone wanting to plan queries that complex had
4662 * better have the memory for it. In more reasonable cases, with
4663 * no more than a couple of dozen rollups, the memory usage will
4664 * be negligible.)
4665 *
4666 * k_capacity is naturally bounded, but we clamp the values for
4667 * scale and weight (below) to avoid overflows or underflows (or
4668 * uselessly trying to use a scale factor less than 1 byte).
4669 */
4670 scale = Max(availspace / (20.0 * num_rollups), 1.0);
4672
4673 /*
4674 * We leave the first rollup out of consideration since it's the
4675 * one that matches the input sort order. We assign indexes "i"
4676 * to only those entries considered for hashing; the second loop,
4677 * below, must use the same condition.
4678 */
4679 i = 0;
4680 for_each_from(lc, gd->rollups, 1)
4681 {
4683
4684 if (rollup->hashable)
4685 {
4687 path,
4688 agg_costs,
4689 rollup->numGroups);
4690
4691 /*
4692 * If sz is enormous, but hash_mem (and hence scale) is
4693 * small, avoid integer overflow here.
4694 */
4695 k_weights[i] = (int) Min(floor(sz / scale),
4696 k_capacity + 1.0);
4697 ++i;
4698 }
4699 }
4700
4701 /*
4702 * Apply knapsack algorithm; compute the set of items which
4703 * maximizes the value stored (in this case the number of sorts
4704 * saved) while keeping the total size (approximately) within
4705 * capacity.
4706 */
4707 if (i > 0)
4709
4711 {
4712 rollups = list_make1(linitial(gd->rollups));
4713
4714 i = 0;
4715 for_each_from(lc, gd->rollups, 1)
4716 {
4718
4719 if (rollup->hashable)
4720 {
4723 rollup->gsets_data);
4724 else
4725 rollups = lappend(rollups, rollup);
4726 ++i;
4727 }
4728 else
4729 rollups = lappend(rollups, rollup);
4730 }
4731 }
4732 }
4733
4734 if (!rollups && hash_sets)
4735 rollups = list_copy(gd->rollups);
4736
4737 foreach(lc, hash_sets)
4738 {
4741
4742 Assert(gs->set != NIL);
4743
4744 rollup->groupClause = preprocess_groupclause(root, gs->set);
4745 rollup->gsets_data = list_make1(gs);
4746 rollup->gsets = remap_to_groupclause_idx(rollup->groupClause,
4747 rollup->gsets_data,
4748 gd->tleref_to_colnum_map);
4749 rollup->numGroups = gs->numGroups;
4750 rollup->hashable = true;
4751 rollup->is_hashed = true;
4752 rollups = lcons(rollup, rollups);
4753 }
4754
4755 if (rollups)
4756 {
4757 add_path(grouped_rel, (Path *)
4759 grouped_rel,
4760 path,
4761 (List *) parse->havingQual,
4762 AGG_MIXED,
4763 rollups,
4764 agg_costs));
4765 }
4766 }
4767
4768 /*
4769 * Now try the simple sorted case.
4770 */
4771 if (!gd->unsortable_sets)
4772 add_path(grouped_rel, (Path *)
4774 grouped_rel,
4775 path,
4776 (List *) parse->havingQual,
4777 AGG_SORTED,
4778 gd->rollups,
4779 agg_costs));
4780}
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
#define bms_is_empty(a)
Definition bitmapset.h:118
#define Min(x, y)
Definition c.h:1150
#define Max(x, y)
Definition c.h:1144
size_t Size
Definition c.h:748
Bitmapset * DiscreteKnapsack(int max_weight, int num_items, int *item_weights, double *item_values)
Definition knapsack.c:51
List * list_concat(List *list1, const List *list2)
Definition list.c:561
List * lcons(void *datum, List *list)
Definition list.c:495
void * palloc(Size size)
Definition mcxt.c:1390
size_t get_hash_memory_limit(void)
Definition nodeHash.c:3680
AggStrategy
Definition nodes.h:361
@ AGG_MIXED
Definition nodes.h:365
#define makeNode(_type_)
Definition nodes.h:159
bool pathkeys_contained_in(List *keys1, List *keys2)
Definition pathkeys.c:343
GroupingSetsPath * create_groupingsets_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *having_qual, AggStrategy aggstrategy, List *rollups, const AggClauseCosts *agg_costs)
Definition pathnode.c:3139
#define list_make1(x1)
Definition pg_list.h:244
#define for_each_cell(cell, lst, initcell)
Definition pg_list.h:470
#define for_each_from(cell, lst, N)
Definition pg_list.h:446
#define linitial(l)
Definition pg_list.h:178
static ListCell * list_head(const List *l)
Definition pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition pg_list.h:375
static int scale
Definition pgbench.c:182
static List * preprocess_groupclause(PlannerInfo *root, List *force)
Definition planner.c:3098
static List * remap_to_groupclause_idx(List *groupClause, List *gsets, int *tleref_to_colnum_map)
Definition planner.c:2632
double estimate_hashagg_tablesize(PlannerInfo *root, Path *path, const AggClauseCosts *agg_costs, double dNumGroups)
Definition selfuncs.c:4528
List * pathkeys
Definition pathnodes.h:2011

References add_path(), AGG_HASHED, AGG_MIXED, AGG_SORTED, Assert, bms_is_empty, bms_is_member(), create_groupingsets_path(), DiscreteKnapsack(), estimate_hashagg_tablesize(), fb(), for_each_cell, for_each_from, get_hash_memory_limit(), i, lappend(), lcons(), lfirst_node, linitial, list_concat(), list_copy(), list_head(), list_length(), list_make1, lnext(), makeNode, Max, Min, NIL, palloc(), parse(), Path::pathkeys, pathkeys_contained_in(), preprocess_groupclause(), remap_to_groupclause_idx(), root, and scale.

Referenced by add_paths_to_grouping_rel().

◆ create_degenerate_grouping_paths()

static void create_degenerate_grouping_paths ( PlannerInfo root,
RelOptInfo input_rel,
RelOptInfo grouped_rel 
)
static

Definition at line 4240 of file planner.c.

4242{
4243 Query *parse = root->parse;
4244 int nrows;
4245 Path *path;
4246
4247 nrows = list_length(parse->groupingSets);
4248 if (nrows > 1)
4249 {
4250 /*
4251 * Doesn't seem worthwhile writing code to cons up a generate_series
4252 * or a values scan to emit multiple rows. Instead just make N clones
4253 * and append them. (With a volatile HAVING clause, this means you
4254 * might get between 0 and N output rows. Offhand I think that's
4255 * desired.)
4256 */
4257 AppendPathInput append = {0};
4258
4259 while (--nrows >= 0)
4260 {
4261 path = (Path *)
4262 create_group_result_path(root, grouped_rel,
4263 grouped_rel->reltarget,
4264 (List *) parse->havingQual);
4265 append.subpaths = lappend(append.subpaths, path);
4266 }
4267 path = (Path *)
4269 grouped_rel,
4270 append,
4271 NIL,
4272 NULL,
4273 0,
4274 false,
4275 -1);
4276 }
4277 else
4278 {
4279 /* No grouping sets, or just one, so one output row */
4280 path = (Path *)
4281 create_group_result_path(root, grouped_rel,
4282 grouped_rel->reltarget,
4283 (List *) parse->havingQual);
4284 }
4285
4286 add_path(grouped_rel, path);
4287}
AppendPath * create_append_path(PlannerInfo *root, RelOptInfo *rel, AppendPathInput input, List *pathkeys, Relids required_outer, int parallel_workers, bool parallel_aware, double rows)
Definition pathnode.c:1352
GroupResultPath * create_group_result_path(PlannerInfo *root, RelOptInfo *rel, PathTarget *target, List *havingqual)
Definition pathnode.c:1664

References add_path(), create_append_path(), create_group_result_path(), fb(), lappend(), list_length(), NIL, parse(), RelOptInfo::reltarget, and root.

Referenced by create_grouping_paths().

◆ create_distinct_paths()

static RelOptInfo * create_distinct_paths ( PlannerInfo root,
RelOptInfo input_rel,
PathTarget target 
)
static

Definition at line 5053 of file planner.c.

5055{
5057
5058 /* For now, do all work in the (DISTINCT, NULL) upperrel */
5060
5061 /*
5062 * We don't compute anything at this level, so distinct_rel will be
5063 * parallel-safe if the input rel is parallel-safe. In particular, if
5064 * there is a DISTINCT ON (...) clause, any path for the input_rel will
5065 * output those expressions, and will not be parallel-safe unless those
5066 * expressions are parallel-safe.
5067 */
5068 distinct_rel->consider_parallel = input_rel->consider_parallel;
5069
5070 /*
5071 * If the input rel belongs to a single FDW, so does the distinct_rel.
5072 */
5073 distinct_rel->serverid = input_rel->serverid;
5074 distinct_rel->userid = input_rel->userid;
5075 distinct_rel->useridiscurrent = input_rel->useridiscurrent;
5076 distinct_rel->fdwroutine = input_rel->fdwroutine;
5077
5078 /* build distinct paths based on input_rel's pathlist */
5080
5081 /* now build distinct paths based on input_rel's partial_pathlist */
5083
5084 /* Give a helpful error if we failed to create any paths */
5085 if (distinct_rel->pathlist == NIL)
5086 ereport(ERROR,
5088 errmsg("could not implement DISTINCT"),
5089 errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
5090
5091 /*
5092 * If there is an FDW that's responsible for all baserels of the query,
5093 * let it consider adding ForeignPaths.
5094 */
5095 if (distinct_rel->fdwroutine &&
5096 distinct_rel->fdwroutine->GetForeignUpperPaths)
5097 distinct_rel->fdwroutine->GetForeignUpperPaths(root,
5099 input_rel,
5101 NULL);
5102
5103 /* Let extensions possibly add some more paths */
5105 (*create_upper_paths_hook) (root, UPPERREL_DISTINCT, input_rel,
5107
5108 /* Now choose the best path(s) */
5110
5111 return distinct_rel;
5112}
int errcode(int sqlerrcode)
Definition elog.c:875
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
static char * errmsg
@ UPPERREL_DISTINCT
Definition pathnodes.h:150
static RelOptInfo * create_final_distinct_paths(PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *distinct_rel)
Definition planner.c:5306
static void create_partial_distinct_paths(PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *final_distinct_rel, PathTarget *target)
Definition planner.c:5123
create_upper_paths_hook_type create_upper_paths_hook
Definition planner.c:83
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition relnode.c:1617

References create_final_distinct_paths(), create_partial_distinct_paths(), create_upper_paths_hook, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), fetch_upper_rel(), NIL, root, set_cheapest(), and UPPERREL_DISTINCT.

Referenced by grouping_planner().

◆ create_final_distinct_paths()

static RelOptInfo * create_final_distinct_paths ( PlannerInfo root,
RelOptInfo input_rel,
RelOptInfo distinct_rel 
)
static

Definition at line 5306 of file planner.c.

5308{
5309 Query *parse = root->parse;
5310 Path *cheapest_input_path = input_rel->cheapest_total_path;
5311 double numDistinctRows;
5312 bool allow_hash;
5313
5314 /* Estimate number of distinct rows there will be */
5315 if (parse->groupClause || parse->groupingSets || parse->hasAggs ||
5316 root->hasHavingQual)
5317 {
5318 /*
5319 * If there was grouping or aggregation, use the number of input rows
5320 * as the estimated number of DISTINCT rows (ie, assume the input is
5321 * already mostly unique).
5322 */
5324 }
5325 else
5326 {
5327 /*
5328 * Otherwise, the UNIQUE filter has effects comparable to GROUP BY.
5329 */
5331
5332 distinctExprs = get_sortgrouplist_exprs(root->processed_distinctClause,
5333 parse->targetList);
5335 cheapest_input_path->rows,
5336 NULL, NULL);
5337 }
5338
5339 /*
5340 * Consider sort-based implementations of DISTINCT, if possible.
5341 */
5342 if (grouping_is_sortable(root->processed_distinctClause))
5343 {
5344 /*
5345 * Firstly, if we have any adequately-presorted paths, just stick a
5346 * Unique node on those. We also, consider doing an explicit sort of
5347 * the cheapest input path and Unique'ing that. If any paths have
5348 * presorted keys then we'll create an incremental sort atop of those
5349 * before adding a unique node on the top. We'll also attempt to
5350 * reorder the required pathkeys to match the input path's pathkeys as
5351 * much as possible, in hopes of avoiding a possible need to re-sort.
5352 *
5353 * When we have DISTINCT ON, we must sort by the more rigorous of
5354 * DISTINCT and ORDER BY, else it won't have the desired behavior.
5355 * Also, if we do have to do an explicit sort, we might as well use
5356 * the more rigorous ordering to avoid a second sort later. (Note
5357 * that the parser will have ensured that one clause is a prefix of
5358 * the other.)
5359 */
5361 ListCell *lc;
5362 double limittuples = root->distinct_pathkeys == NIL ? 1.0 : -1.0;
5363
5364 if (parse->hasDistinctOn &&
5365 list_length(root->distinct_pathkeys) <
5366 list_length(root->sort_pathkeys))
5367 needed_pathkeys = root->sort_pathkeys;
5368 else
5369 needed_pathkeys = root->distinct_pathkeys;
5370
5371 foreach(lc, input_rel->pathlist)
5372 {
5373 Path *input_path = (Path *) lfirst(lc);
5376
5380 input_path->pathkeys);
5382
5384 {
5387 input_path,
5390 limittuples);
5391
5392 if (sorted_path == NULL)
5393 continue;
5394
5395 /*
5396 * distinct_pathkeys may have become empty if all of the
5397 * pathkeys were determined to be redundant. If all of the
5398 * pathkeys are redundant then each DISTINCT target must only
5399 * allow a single value, therefore all resulting tuples must
5400 * be identical (or at least indistinguishable by an equality
5401 * check). We can uniquify these tuples simply by just taking
5402 * the first tuple. All we do here is add a path to do "LIMIT
5403 * 1" atop of 'sorted_path'. When doing a DISTINCT ON we may
5404 * still have a non-NIL sort_pathkeys list, so we must still
5405 * only do this with paths which are correctly sorted by
5406 * sort_pathkeys.
5407 */
5408 if (root->distinct_pathkeys == NIL)
5409 {
5410 Node *limitCount;
5411
5412 limitCount = (Node *) makeConst(INT8OID, -1, InvalidOid,
5413 sizeof(int64),
5414 Int64GetDatum(1), false,
5415 true);
5416
5417 /*
5418 * If the query already has a LIMIT clause, then we could
5419 * end up with a duplicate LimitPath in the final plan.
5420 * That does not seem worth troubling over too much.
5421 */
5424 NULL, limitCount,
5425 LIMIT_OPTION_COUNT, 0, 1));
5426 }
5427 else
5428 {
5432 list_length(root->distinct_pathkeys),
5434 }
5435 }
5436 }
5437 }
5438
5439 /*
5440 * Consider hash-based implementations of DISTINCT, if possible.
5441 *
5442 * If we were not able to make any other types of path, we *must* hash or
5443 * die trying. If we do have other choices, there are two things that
5444 * should prevent selection of hashing: if the query uses DISTINCT ON
5445 * (because it won't really have the expected behavior if we hash), or if
5446 * enable_hashagg is off.
5447 *
5448 * Note: grouping_is_hashable() is much more expensive to check than the
5449 * other gating conditions, so we want to do it last.
5450 */
5451 if (distinct_rel->pathlist == NIL)
5452 allow_hash = true; /* we have no alternatives */
5453 else if (parse->hasDistinctOn || !enable_hashagg)
5454 allow_hash = false; /* policy-based decision not to hash */
5455 else
5456 allow_hash = true; /* default */
5457
5458 if (allow_hash && grouping_is_hashable(root->processed_distinctClause))
5459 {
5460 /* Generate hashed aggregate path --- no sort needed */
5465 cheapest_input_path->pathtarget,
5466 AGG_HASHED,
5468 root->processed_distinctClause,
5469 NIL,
5470 NULL,
5472 }
5473
5474 return distinct_rel;
5475}
int64_t int64
Definition c.h:680
bool enable_hashagg
Definition costsize.c:153
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition makefuncs.c:350
@ LIMIT_OPTION_COUNT
Definition nodes.h:440
LimitPath * create_limit_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, Node *limitOffset, Node *limitCount, LimitOption limitOption, int64 offset_est, int64 count_est)
Definition pathnode.c:3793
UniquePath * create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, int numCols, double numGroups)
Definition pathnode.c:3005
#define foreach_node(type, var, lst)
Definition pg_list.h:528
static List * get_useful_pathkeys_for_distinct(PlannerInfo *root, List *needed_pathkeys, List *path_pathkeys)
Definition planner.c:5486
static Datum Int64GetDatum(int64 X)
Definition postgres.h:426
#define InvalidOid
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset, EstimationInfo *estinfo)
Definition selfuncs.c:3802
Cardinality rows
Definition pathnodes.h:2005
bool grouping_is_sortable(List *groupClause)
Definition tlist.c:549
List * get_sortgrouplist_exprs(List *sgClauses, List *targetList)
Definition tlist.c:401
bool grouping_is_hashable(List *groupClause)
Definition tlist.c:569

References add_path(), AGG_HASHED, AGGSPLIT_SIMPLE, Assert, create_agg_path(), create_limit_path(), create_unique_path(), enable_hashagg, estimate_num_groups(), fb(), foreach_node, get_sortgrouplist_exprs(), get_useful_pathkeys_for_distinct(), grouping_is_hashable(), grouping_is_sortable(), Int64GetDatum(), InvalidOid, lfirst, LIMIT_OPTION_COUNT, list_length(), make_ordered_path(), makeConst(), NIL, parse(), root, and Path::rows.

Referenced by create_distinct_paths(), and create_partial_distinct_paths().

◆ create_final_unique_paths()

static void create_final_unique_paths ( PlannerInfo root,
RelOptInfo input_rel,
List sortPathkeys,
List groupClause,
SpecialJoinInfo sjinfo,
RelOptInfo unique_rel 
)
static

Definition at line 8932 of file planner.c.

8935{
8936 Path *cheapest_input_path = input_rel->cheapest_total_path;
8937
8938 /* Estimate number of output rows */
8939 unique_rel->rows = estimate_num_groups(root,
8940 sjinfo->semi_rhs_exprs,
8941 cheapest_input_path->rows,
8942 NULL,
8943 NULL);
8944
8945 /* Consider sort-based implementations, if possible. */
8946 if (sjinfo->semi_can_btree)
8947 {
8948 ListCell *lc;
8949
8950 /*
8951 * Use any available suitably-sorted path as input, and also consider
8952 * sorting the cheapest-total path and incremental sort on any paths
8953 * with presorted keys.
8954 *
8955 * To save planning time, we ignore parameterized input paths unless
8956 * they are the cheapest-total path.
8957 */
8958 foreach(lc, input_rel->pathlist)
8959 {
8960 Path *input_path = (Path *) lfirst(lc);
8961 Path *path;
8962 bool is_sorted;
8963 int presorted_keys;
8964
8965 /*
8966 * Ignore parameterized paths that are not the cheapest-total
8967 * path.
8968 */
8969 if (input_path->param_info &&
8971 continue;
8972
8974 input_path->pathkeys,
8975 &presorted_keys);
8976
8977 /*
8978 * Ignore paths that are not suitably or partially sorted, unless
8979 * they are the cheapest total path (no need to deal with paths
8980 * which have presorted keys when incremental sort is disabled).
8981 */
8983 (presorted_keys == 0 || !enable_incremental_sort))
8984 continue;
8985
8986 /*
8987 * Make a separate ProjectionPath in case we need a Result node.
8988 */
8989 path = (Path *) create_projection_path(root,
8990 unique_rel,
8991 input_path,
8992 unique_rel->reltarget);
8993
8994 if (!is_sorted)
8995 {
8996 /*
8997 * We've no need to consider both a sort and incremental sort.
8998 * We'll just do a sort if there are no presorted keys and an
8999 * incremental sort when there are presorted keys.
9000 */
9001 if (presorted_keys == 0 || !enable_incremental_sort)
9002 path = (Path *) create_sort_path(root,
9003 unique_rel,
9004 path,
9006 -1.0);
9007 else
9009 unique_rel,
9010 path,
9012 presorted_keys,
9013 -1.0);
9014 }
9015
9016 path = (Path *) create_unique_path(root, unique_rel, path,
9018 unique_rel->rows);
9019
9020 add_path(unique_rel, path);
9021 }
9022 }
9023
9024 /* Consider hash-based implementation, if possible. */
9025 if (sjinfo->semi_can_hash)
9026 {
9027 Path *path;
9028
9029 /*
9030 * Make a separate ProjectionPath in case we need a Result node.
9031 */
9032 path = (Path *) create_projection_path(root,
9033 unique_rel,
9035 unique_rel->reltarget);
9036
9037 path = (Path *) create_agg_path(root,
9038 unique_rel,
9039 path,
9040 cheapest_input_path->pathtarget,
9041 AGG_HASHED,
9043 groupClause,
9044 NIL,
9045 NULL,
9046 unique_rel->rows);
9047
9048 add_path(unique_rel, path);
9049 }
9050}
bool enable_incremental_sort
Definition costsize.c:152
bool pathkeys_count_contained_in(List *keys1, List *keys2, int *n_common)
Definition pathkeys.c:558
IncrementalSortPath * create_incremental_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, int presorted_keys, double limit_tuples)
Definition pathnode.c:2855
SortPath * create_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
Definition pathnode.c:2904
Cardinality rows
Definition pathnodes.h:1027
List * semi_rhs_exprs
Definition pathnodes.h:3241

References add_path(), AGG_HASHED, AGGSPLIT_SIMPLE, create_agg_path(), create_incremental_sort_path(), create_projection_path(), create_sort_path(), create_unique_path(), enable_incremental_sort, estimate_num_groups(), fb(), lfirst, list_length(), NIL, pathkeys_count_contained_in(), RelOptInfo::reltarget, root, RelOptInfo::rows, SpecialJoinInfo::semi_can_btree, SpecialJoinInfo::semi_can_hash, and SpecialJoinInfo::semi_rhs_exprs.

Referenced by create_partial_unique_paths(), and create_unique_paths().

◆ create_grouping_paths()

static RelOptInfo * create_grouping_paths ( PlannerInfo root,
RelOptInfo input_rel,
PathTarget target,
bool  target_parallel_safe,
grouping_sets_data gd 
)
static

Definition at line 4050 of file planner.c.

4055{
4056 Query *parse = root->parse;
4057 RelOptInfo *grouped_rel;
4060
4061 MemSet(&agg_costs, 0, sizeof(AggClauseCosts));
4063
4064 /*
4065 * Create grouping relation to hold fully aggregated grouping and/or
4066 * aggregation paths.
4067 */
4068 grouped_rel = make_grouping_rel(root, input_rel, target,
4069 target_parallel_safe, parse->havingQual);
4070
4071 /*
4072 * Create either paths for a degenerate grouping or paths for ordinary
4073 * grouping, as appropriate.
4074 */
4077 else
4078 {
4079 int flags = 0;
4080 GroupPathExtraData extra;
4081
4082 /*
4083 * Determine whether it's possible to perform sort-based
4084 * implementations of grouping. (Note that if processed_groupClause
4085 * is empty, grouping_is_sortable() is trivially true, and all the
4086 * pathkeys_contained_in() tests will succeed too, so that we'll
4087 * consider every surviving input path.)
4088 *
4089 * If we have grouping sets, we might be able to sort some but not all
4090 * of them; in this case, we need can_sort to be true as long as we
4091 * must consider any sorted-input plan.
4092 */
4093 if ((gd && gd->rollups != NIL)
4094 || grouping_is_sortable(root->processed_groupClause))
4095 flags |= GROUPING_CAN_USE_SORT;
4096
4097 /*
4098 * Determine whether we should consider hash-based implementations of
4099 * grouping.
4100 *
4101 * Hashed aggregation only applies if we're grouping. If we have
4102 * grouping sets, some groups might be hashable but others not; in
4103 * this case we set can_hash true as long as there is nothing globally
4104 * preventing us from hashing (and we should therefore consider plans
4105 * with hashes).
4106 *
4107 * Executor doesn't support hashed aggregation with DISTINCT or ORDER
4108 * BY aggregates. (Doing so would imply storing *all* the input
4109 * values in the hash table, and/or running many sorts in parallel,
4110 * either of which seems like a certain loser.) We similarly don't
4111 * support ordered-set aggregates in hashed aggregation, but that case
4112 * is also included in the numOrderedAggs count.
4113 *
4114 * Note: grouping_is_hashable() is much more expensive to check than
4115 * the other gating conditions, so we want to do it last.
4116 */
4117 if ((parse->groupClause != NIL &&
4118 root->numOrderedAggs == 0 &&
4119 (gd ? gd->any_hashable : grouping_is_hashable(root->processed_groupClause))))
4120 flags |= GROUPING_CAN_USE_HASH;
4121
4122 /*
4123 * Determine whether partial aggregation is possible.
4124 */
4125 if (can_partial_agg(root))
4126 flags |= GROUPING_CAN_PARTIAL_AGG;
4127
4128 extra.flags = flags;
4129 extra.target_parallel_safe = target_parallel_safe;
4130 extra.havingQual = parse->havingQual;
4131 extra.targetList = parse->targetList;
4132 extra.partial_costs_set = false;
4133
4134 /*
4135 * Determine whether partitionwise aggregation is in theory possible.
4136 * It can be disabled by the user, and for now, we don't try to
4137 * support grouping sets. create_ordinary_grouping_paths() will check
4138 * additional conditions, such as whether input_rel is partitioned.
4139 */
4140 if (enable_partitionwise_aggregate && !parse->groupingSets)
4142 else
4144
4146 &agg_costs, gd, &extra,
4148 }
4149
4150 set_cheapest(grouped_rel);
4151 return grouped_rel;
4152}
#define MemSet(start, val, len)
Definition c.h:1166
bool enable_partitionwise_aggregate
Definition costsize.c:161
@ PARTITIONWISE_AGGREGATE_FULL
Definition pathnodes.h:3662
@ PARTITIONWISE_AGGREGATE_NONE
Definition pathnodes.h:3661
#define GROUPING_CAN_PARTIAL_AGG
Definition pathnodes.h:3646
static void create_degenerate_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *grouped_rel)
Definition planner.c:4240
static bool is_degenerate_grouping(PlannerInfo *root)
Definition planner.c:4219
static void create_ordinary_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *grouped_rel, const AggClauseCosts *agg_costs, grouping_sets_data *gd, GroupPathExtraData *extra, RelOptInfo **partially_grouped_rel_p)
Definition planner.c:4303
static bool can_partial_agg(PlannerInfo *root)
Definition planner.c:8100
static RelOptInfo * make_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel, PathTarget *target, bool target_parallel_safe, Node *havingQual)
Definition planner.c:4163
void get_agg_clause_costs(PlannerInfo *root, AggSplit aggsplit, AggClauseCosts *costs)
Definition prepagg.c:559
PartitionwiseAggregateType patype
Definition pathnodes.h:3691

References AGGSPLIT_SIMPLE, can_partial_agg(), create_degenerate_grouping_paths(), create_ordinary_grouping_paths(), enable_partitionwise_aggregate, fb(), GroupPathExtraData::flags, get_agg_clause_costs(), GROUPING_CAN_PARTIAL_AGG, GROUPING_CAN_USE_HASH, GROUPING_CAN_USE_SORT, grouping_is_hashable(), grouping_is_sortable(), GroupPathExtraData::havingQual, is_degenerate_grouping(), make_grouping_rel(), MemSet, NIL, parse(), GroupPathExtraData::partial_costs_set, PARTITIONWISE_AGGREGATE_FULL, PARTITIONWISE_AGGREGATE_NONE, GroupPathExtraData::patype, root, set_cheapest(), GroupPathExtraData::target_parallel_safe, and GroupPathExtraData::targetList.

Referenced by grouping_planner().

◆ create_one_window_path()

static void create_one_window_path ( PlannerInfo root,
RelOptInfo window_rel,
Path path,
PathTarget input_target,
PathTarget output_target,
WindowFuncLists wflists,
List activeWindows 
)
static

Definition at line 4883 of file planner.c.

4890{
4892 ListCell *l;
4893 List *topqual = NIL;
4894
4895 /*
4896 * Since each window clause could require a different sort order, we stack
4897 * up a WindowAgg node for each clause, with sort steps between them as
4898 * needed. (We assume that select_active_windows chose a good order for
4899 * executing the clauses in.)
4900 *
4901 * input_target should contain all Vars and Aggs needed for the result.
4902 * (In some cases we wouldn't need to propagate all of these all the way
4903 * to the top, since they might only be needed as inputs to WindowFuncs.
4904 * It's probably not worth trying to optimize that though.) It must also
4905 * contain all window partitioning and sorting expressions, to ensure
4906 * they're computed only once at the bottom of the stack (that's critical
4907 * for volatile functions). As we climb up the stack, we'll add outputs
4908 * for the WindowFuncs computed at each level.
4909 */
4911
4912 foreach(l, activeWindows)
4913 {
4915 List *window_pathkeys;
4916 List *runcondition = NIL;
4917 int presorted_keys;
4918 bool is_sorted;
4919 bool topwindow;
4920 ListCell *lc2;
4921
4922 window_pathkeys = make_pathkeys_for_window(root,
4923 wc,
4924 root->processed_tlist);
4925
4926 is_sorted = pathkeys_count_contained_in(window_pathkeys,
4927 path->pathkeys,
4928 &presorted_keys);
4929
4930 /* Sort if necessary */
4931 if (!is_sorted)
4932 {
4933 /*
4934 * No presorted keys or incremental sort disabled, just perform a
4935 * complete sort.
4936 */
4937 if (presorted_keys == 0 || !enable_incremental_sort)
4939 path,
4940 window_pathkeys,
4941 -1.0);
4942 else
4943 {
4944 /*
4945 * Since we have presorted keys and incremental sort is
4946 * enabled, just use incremental sort.
4947 */
4949 window_rel,
4950 path,
4951 window_pathkeys,
4952 presorted_keys,
4953 -1.0);
4954 }
4955 }
4956
4957 if (lnext(activeWindows, l))
4958 {
4959 /*
4960 * Add the current WindowFuncs to the output target for this
4961 * intermediate WindowAggPath. We must copy window_target to
4962 * avoid changing the previous path's target.
4963 *
4964 * Note: a WindowFunc adds nothing to the target's eval costs; but
4965 * we do need to account for the increase in tlist width.
4966 */
4968
4970 foreach(lc2, wflists->windowFuncs[wc->winref])
4971 {
4973
4975 tuple_width += get_typavgwidth(wfunc->wintype, -1);
4976 }
4978 }
4979 else
4980 {
4981 /* Install the goal target in the topmost WindowAgg */
4983 }
4984
4985 /* mark the final item in the list as the top-level window */
4986 topwindow = foreach_current_index(l) == list_length(activeWindows) - 1;
4987
4988 /*
4989 * Collect the WindowFuncRunConditions from each WindowFunc and
4990 * convert them into OpExprs
4991 */
4992 foreach(lc2, wflists->windowFuncs[wc->winref])
4993 {
4994 ListCell *lc3;
4996
4997 foreach(lc3, wfunc->runCondition)
4998 {
5001 Expr *opexpr;
5002 Expr *leftop;
5003 Expr *rightop;
5004
5005 if (wfuncrc->wfunc_left)
5006 {
5007 leftop = (Expr *) copyObject(wfunc);
5008 rightop = copyObject(wfuncrc->arg);
5009 }
5010 else
5011 {
5012 leftop = copyObject(wfuncrc->arg);
5013 rightop = (Expr *) copyObject(wfunc);
5014 }
5015
5016 opexpr = make_opclause(wfuncrc->opno,
5017 BOOLOID,
5018 false,
5019 leftop,
5020 rightop,
5021 InvalidOid,
5022 wfuncrc->inputcollid);
5023
5024 runcondition = lappend(runcondition, opexpr);
5025
5026 if (!topwindow)
5027 topqual = lappend(topqual, opexpr);
5028 }
5029 }
5030
5031 path = (Path *)
5033 wflists->windowFuncs[wc->winref],
5034 runcondition, wc,
5035 topwindow ? topqual : NIL, topwindow);
5036 }
5037
5038 add_path(window_rel, path);
5039}
int32 clamp_width_est(int64 tuple_width)
Definition costsize.c:243
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition lsyscache.c:2894
Expr * make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop, Oid opcollid, Oid inputcollid)
Definition makefuncs.c:701
#define copyObject(obj)
Definition nodes.h:230
WindowAggPath * create_windowagg_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, List *windowFuncs, List *runCondition, WindowClause *winclause, List *qual, bool topwindow)
Definition pathnode.c:3393
static List * make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc, List *tlist)
Definition planner.c:6544
void add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
Definition tlist.c:704

References add_column_to_pathtarget(), add_path(), clamp_width_est(), copy_pathtarget(), copyObject, create_incremental_sort_path(), create_sort_path(), create_windowagg_path(), enable_incremental_sort, fb(), foreach_current_index, get_typavgwidth(), InvalidOid, lappend(), lfirst_node, list_length(), lnext(), make_opclause(), make_pathkeys_for_window(), NIL, Path::pathkeys, pathkeys_count_contained_in(), root, and WindowClause::winref.

Referenced by create_window_paths().

◆ create_ordered_paths()

static RelOptInfo * create_ordered_paths ( PlannerInfo root,
RelOptInfo input_rel,
PathTarget target,
bool  target_parallel_safe,
double  limit_tuples 
)
static

Definition at line 5571 of file planner.c.

5576{
5577 Path *cheapest_input_path = input_rel->cheapest_total_path;
5579 ListCell *lc;
5580
5581 /* For now, do all work in the (ORDERED, NULL) upperrel */
5583
5584 /*
5585 * If the input relation is not parallel-safe, then the ordered relation
5586 * can't be parallel-safe, either. Otherwise, it's parallel-safe if the
5587 * target list is parallel-safe.
5588 */
5589 if (input_rel->consider_parallel && target_parallel_safe)
5590 ordered_rel->consider_parallel = true;
5591
5592 /* Assume that the same path generation strategies are allowed. */
5593 ordered_rel->pgs_mask = input_rel->pgs_mask;
5594
5595 /*
5596 * If the input rel belongs to a single FDW, so does the ordered_rel.
5597 */
5598 ordered_rel->serverid = input_rel->serverid;
5599 ordered_rel->userid = input_rel->userid;
5600 ordered_rel->useridiscurrent = input_rel->useridiscurrent;
5601 ordered_rel->fdwroutine = input_rel->fdwroutine;
5602
5603 foreach(lc, input_rel->pathlist)
5604 {
5605 Path *input_path = (Path *) lfirst(lc);
5607 bool is_sorted;
5608 int presorted_keys;
5609
5611 input_path->pathkeys, &presorted_keys);
5612
5613 if (is_sorted)
5615 else
5616 {
5617 /*
5618 * Try at least sorting the cheapest path and also try
5619 * incrementally sorting any path which is partially sorted
5620 * already (no need to deal with paths which have presorted keys
5621 * when incremental sort is disabled unless it's the cheapest
5622 * input path).
5623 */
5625 (presorted_keys == 0 || !enable_incremental_sort))
5626 continue;
5627
5628 /*
5629 * We've no need to consider both a sort and incremental sort.
5630 * We'll just do a sort if there are no presorted keys and an
5631 * incremental sort when there are presorted keys.
5632 */
5633 if (presorted_keys == 0 || !enable_incremental_sort)
5636 input_path,
5637 root->sort_pathkeys,
5638 limit_tuples);
5639 else
5642 input_path,
5643 root->sort_pathkeys,
5644 presorted_keys,
5645 limit_tuples);
5646 }
5647
5648 /*
5649 * If the pathtarget of the result path has different expressions from
5650 * the target to be applied, a projection step is needed.
5651 */
5652 if (!equal(sorted_path->pathtarget->exprs, target->exprs))
5654 sorted_path, target);
5655
5657 }
5658
5659 /*
5660 * generate_gather_paths() will have already generated a simple Gather
5661 * path for the best parallel path, if any, and the loop above will have
5662 * considered sorting it. Similarly, generate_gather_paths() will also
5663 * have generated order-preserving Gather Merge plans which can be used
5664 * without sorting if they happen to match the sort_pathkeys, and the loop
5665 * above will have handled those as well. However, there's one more
5666 * possibility: it may make sense to sort the cheapest partial path or
5667 * incrementally sort any partial path that is partially sorted according
5668 * to the required output order and then use Gather Merge.
5669 */
5670 if (ordered_rel->consider_parallel && root->sort_pathkeys != NIL &&
5671 input_rel->partial_pathlist != NIL)
5672 {
5674
5675 cheapest_partial_path = linitial(input_rel->partial_pathlist);
5676
5677 foreach(lc, input_rel->partial_pathlist)
5678 {
5679 Path *input_path = (Path *) lfirst(lc);
5681 bool is_sorted;
5682 int presorted_keys;
5683 double total_groups;
5684
5686 input_path->pathkeys,
5687 &presorted_keys);
5688
5689 if (is_sorted)
5690 continue;
5691
5692 /*
5693 * Try at least sorting the cheapest path and also try
5694 * incrementally sorting any path which is partially sorted
5695 * already (no need to deal with paths which have presorted keys
5696 * when incremental sort is disabled unless it's the cheapest
5697 * partial path).
5698 */
5700 (presorted_keys == 0 || !enable_incremental_sort))
5701 continue;
5702
5703 /*
5704 * We've no need to consider both a sort and incremental sort.
5705 * We'll just do a sort if there are no presorted keys and an
5706 * incremental sort when there are presorted keys.
5707 */
5708 if (presorted_keys == 0 || !enable_incremental_sort)
5711 input_path,
5712 root->sort_pathkeys,
5713 limit_tuples);
5714 else
5717 input_path,
5718 root->sort_pathkeys,
5719 presorted_keys,
5720 limit_tuples);
5722 sorted_path = (Path *)
5725 sorted_path->pathtarget,
5726 root->sort_pathkeys, NULL,
5727 &total_groups);
5728
5729 /*
5730 * If the pathtarget of the result path has different expressions
5731 * from the target to be applied, a projection step is needed.
5732 */
5733 if (!equal(sorted_path->pathtarget->exprs, target->exprs))
5735 sorted_path, target);
5736
5738 }
5739 }
5740
5741 /*
5742 * If there is an FDW that's responsible for all baserels of the query,
5743 * let it consider adding ForeignPaths.
5744 */
5745 if (ordered_rel->fdwroutine &&
5746 ordered_rel->fdwroutine->GetForeignUpperPaths)
5747 ordered_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_ORDERED,
5749 NULL);
5750
5751 /* Let extensions possibly add some more paths */
5753 (*create_upper_paths_hook) (root, UPPERREL_ORDERED,
5755
5756 /*
5757 * No need to bother with set_cheapest here; grouping_planner does not
5758 * need us to do it.
5759 */
5760 Assert(ordered_rel->pathlist != NIL);
5761
5762 return ordered_rel;
5763}
double compute_gather_rows(Path *path)
Definition costsize.c:6769
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
GatherMergePath * create_gather_merge_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, List *pathkeys, Relids required_outer, double *rows)
Definition pathnode.c:1813
@ UPPERREL_ORDERED
Definition pathnodes.h:151

References add_path(), apply_projection_to_path(), Assert, compute_gather_rows(), create_gather_merge_path(), create_incremental_sort_path(), create_sort_path(), create_upper_paths_hook, enable_incremental_sort, equal(), PathTarget::exprs, fb(), fetch_upper_rel(), lfirst, linitial, NIL, pathkeys_count_contained_in(), root, and UPPERREL_ORDERED.

Referenced by grouping_planner().

◆ create_ordinary_grouping_paths()

static void create_ordinary_grouping_paths ( PlannerInfo root,
RelOptInfo input_rel,
RelOptInfo grouped_rel,
const AggClauseCosts agg_costs,
grouping_sets_data gd,
GroupPathExtraData extra,
RelOptInfo **  partially_grouped_rel_p 
)
static

Definition at line 4303 of file planner.c.

4309{
4312
4313 /*
4314 * If this is the topmost grouping relation or if the parent relation is
4315 * doing some form of partitionwise aggregation, then we may be able to do
4316 * it at this level also. However, if the input relation is not
4317 * partitioned, partitionwise aggregate is impossible.
4318 */
4319 if (extra->patype != PARTITIONWISE_AGGREGATE_NONE &&
4321 {
4322 /*
4323 * If this is the topmost relation or if the parent relation is doing
4324 * full partitionwise aggregation, then we can do full partitionwise
4325 * aggregation provided that the GROUP BY clause contains all of the
4326 * partitioning columns at this level and the collation used by GROUP
4327 * BY matches the partitioning collation. Otherwise, we can do at
4328 * most partial partitionwise aggregation. But if partial aggregation
4329 * is not supported in general then we can't use it for partitionwise
4330 * aggregation either.
4331 *
4332 * Check parse->groupClause not processed_groupClause, because it's
4333 * okay if some of the partitioning columns were proved redundant.
4334 */
4335 if (extra->patype == PARTITIONWISE_AGGREGATE_FULL &&
4337 root->parse->groupClause))
4339 else if ((extra->flags & GROUPING_CAN_PARTIAL_AGG) != 0)
4341 else
4343 }
4344
4345 /*
4346 * Before generating paths for grouped_rel, we first generate any possible
4347 * partially grouped paths; that way, later code can easily consider both
4348 * parallel and non-parallel approaches to grouping.
4349 */
4350 if ((extra->flags & GROUPING_CAN_PARTIAL_AGG) != 0)
4351 {
4352 bool force_rel_creation;
4353
4354 /*
4355 * If we're doing partitionwise aggregation at this level, force
4356 * creation of a partially_grouped_rel so we can add partitionwise
4357 * paths to it.
4358 */
4360
4363 grouped_rel,
4364 input_rel,
4365 gd,
4366 extra,
4368 }
4369
4370 /* Set out parameter. */
4372
4373 /* Apply partitionwise aggregation technique, if possible. */
4374 if (patype != PARTITIONWISE_AGGREGATE_NONE)
4377 gd, patype, extra);
4378
4379 /* If we are doing partial aggregation only, return. */
4381 {
4383
4384 if (partially_grouped_rel->pathlist)
4386
4387 return;
4388 }
4389
4390 /* Gather any partially grouped partial paths. */
4391 if (partially_grouped_rel && partially_grouped_rel->partial_pathlist)
4393
4394 /* Now choose the best path(s) for partially_grouped_rel. */
4397
4398 /* Build final grouping paths */
4401 extra);
4402
4403 /* Give a helpful error if we failed to find any implementation */
4404 if (grouped_rel->pathlist == NIL)
4405 ereport(ERROR,
4407 errmsg("could not implement GROUP BY"),
4408 errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
4409
4410 /*
4411 * If there is an FDW that's responsible for all baserels of the query,
4412 * let it consider adding ForeignPaths.
4413 */
4414 if (grouped_rel->fdwroutine &&
4415 grouped_rel->fdwroutine->GetForeignUpperPaths)
4416 grouped_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_GROUP_AGG,
4417 input_rel, grouped_rel,
4418 extra);
4419
4420 /* Let extensions possibly add some more paths */
4422 (*create_upper_paths_hook) (root, UPPERREL_GROUP_AGG,
4423 input_rel, grouped_rel,
4424 extra);
4425}
PartitionwiseAggregateType
Definition pathnodes.h:3660
@ PARTITIONWISE_AGGREGATE_PARTIAL
Definition pathnodes.h:3663
@ UPPERREL_GROUP_AGG
Definition pathnodes.h:147
static void add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *grouped_rel, RelOptInfo *partially_grouped_rel, const AggClauseCosts *agg_costs, grouping_sets_data *gd, GroupPathExtraData *extra)
Definition planner.c:7345
static RelOptInfo * create_partial_grouping_paths(PlannerInfo *root, RelOptInfo *grouped_rel, RelOptInfo *input_rel, grouping_sets_data *gd, GroupPathExtraData *extra, bool force_rel_creation)
Definition planner.c:7606
static void create_partitionwise_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel, RelOptInfo *grouped_rel, RelOptInfo *partially_grouped_rel, const AggClauseCosts *agg_costs, grouping_sets_data *gd, PartitionwiseAggregateType patype, GroupPathExtraData *extra)
Definition planner.c:8383
static bool group_by_has_partkey(RelOptInfo *input_rel, List *targetList, List *groupClause)
Definition planner.c:8520

References add_paths_to_grouping_rel(), Assert, create_partial_grouping_paths(), create_partitionwise_grouping_paths(), create_upper_paths_hook, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), GroupPathExtraData::flags, gather_grouping_paths(), group_by_has_partkey(), GROUPING_CAN_PARTIAL_AGG, IS_PARTITIONED_REL, NIL, PARTITIONWISE_AGGREGATE_FULL, PARTITIONWISE_AGGREGATE_NONE, PARTITIONWISE_AGGREGATE_PARTIAL, RelOptInfo::pathlist, GroupPathExtraData::patype, root, set_cheapest(), GroupPathExtraData::targetList, and UPPERREL_GROUP_AGG.

Referenced by create_grouping_paths(), and create_partitionwise_grouping_paths().

◆ create_partial_distinct_paths()

static void create_partial_distinct_paths ( PlannerInfo root,
RelOptInfo input_rel,
RelOptInfo final_distinct_rel,
PathTarget target 
)
static

Definition at line 5123 of file planner.c.

5126{
5128 Query *parse;
5130 double numDistinctRows;
5132 ListCell *lc;
5133
5134 /* nothing to do when there are no partial paths in the input rel */
5135 if (!input_rel->consider_parallel || input_rel->partial_pathlist == NIL)
5136 return;
5137
5138 parse = root->parse;
5139
5140 /* can't do parallel DISTINCT ON */
5141 if (parse->hasDistinctOn)
5142 return;
5143
5145 NULL);
5146 partial_distinct_rel->reltarget = target;
5147 partial_distinct_rel->consider_parallel = input_rel->consider_parallel;
5148
5149 /*
5150 * If input_rel belongs to a single FDW, so does the partial_distinct_rel.
5151 */
5152 partial_distinct_rel->serverid = input_rel->serverid;
5153 partial_distinct_rel->userid = input_rel->userid;
5154 partial_distinct_rel->useridiscurrent = input_rel->useridiscurrent;
5155 partial_distinct_rel->fdwroutine = input_rel->fdwroutine;
5156
5157 cheapest_partial_path = linitial(input_rel->partial_pathlist);
5158
5159 distinctExprs = get_sortgrouplist_exprs(root->processed_distinctClause,
5160 parse->targetList);
5161
5162 /* estimate how many distinct rows we'll get from each worker */
5165 NULL, NULL);
5166
5167 /*
5168 * Try sorting the cheapest path and incrementally sorting any paths with
5169 * presorted keys and put a unique paths atop of those. We'll also
5170 * attempt to reorder the required pathkeys to match the input path's
5171 * pathkeys as much as possible, in hopes of avoiding a possible need to
5172 * re-sort.
5173 */
5174 if (grouping_is_sortable(root->processed_distinctClause))
5175 {
5176 foreach(lc, input_rel->partial_pathlist)
5177 {
5178 Path *input_path = (Path *) lfirst(lc);
5181
5184 root->distinct_pathkeys,
5185 input_path->pathkeys);
5187
5189 {
5192 input_path,
5195 -1.0);
5196
5197 if (sorted_path == NULL)
5198 continue;
5199
5200 /*
5201 * An empty distinct_pathkeys means all tuples have the same
5202 * value for the DISTINCT clause. See
5203 * create_final_distinct_paths()
5204 */
5205 if (root->distinct_pathkeys == NIL)
5206 {
5207 Node *limitCount;
5208
5209 limitCount = (Node *) makeConst(INT8OID, -1, InvalidOid,
5210 sizeof(int64),
5211 Int64GetDatum(1), false,
5212 true);
5213
5214 /*
5215 * Apply a LimitPath onto the partial path to restrict the
5216 * tuples from each worker to 1.
5217 * create_final_distinct_paths will need to apply an
5218 * additional LimitPath to restrict this to a single row
5219 * after the Gather node. If the query already has a
5220 * LIMIT clause, then we could end up with three Limit
5221 * nodes in the final plan. Consolidating the top two of
5222 * these could be done, but does not seem worth troubling
5223 * over.
5224 */
5228 NULL,
5229 limitCount,
5231 0, 1));
5232 }
5233 else
5234 {
5238 list_length(root->distinct_pathkeys),
5240 }
5241 }
5242 }
5243 }
5244
5245 /*
5246 * Now try hash aggregate paths, if enabled and hashing is possible. Since
5247 * we're not on the hook to ensure we do our best to create at least one
5248 * path here, we treat enable_hashagg as a hard off-switch rather than the
5249 * slightly softer variant in create_final_distinct_paths.
5250 */
5251 if (enable_hashagg && grouping_is_hashable(root->processed_distinctClause))
5252 {
5257 cheapest_partial_path->pathtarget,
5258 AGG_HASHED,
5260 root->processed_distinctClause,
5261 NIL,
5262 NULL,
5264 }
5265
5266 /*
5267 * If there is an FDW that's responsible for all baserels of the query,
5268 * let it consider adding ForeignPaths.
5269 */
5270 if (partial_distinct_rel->fdwroutine &&
5271 partial_distinct_rel->fdwroutine->GetForeignUpperPaths)
5272 partial_distinct_rel->fdwroutine->GetForeignUpperPaths(root,
5274 input_rel,
5276 NULL);
5277
5278 /* Let extensions possibly add some more partial paths */
5280 (*create_upper_paths_hook) (root, UPPERREL_PARTIAL_DISTINCT,
5282
5283 if (partial_distinct_rel->partial_pathlist != NIL)
5284 {
5287
5288 /*
5289 * Finally, create paths to distinctify the final result. This step
5290 * is needed to remove any duplicates due to combining rows from
5291 * parallel workers.
5292 */
5295 }
5296}
void add_partial_path(RelOptInfo *parent_rel, Path *new_path)
Definition pathnode.c:793
@ UPPERREL_PARTIAL_DISTINCT
Definition pathnodes.h:149

References add_partial_path(), AGG_HASHED, AGGSPLIT_SIMPLE, Assert, create_agg_path(), create_final_distinct_paths(), create_limit_path(), create_unique_path(), create_upper_paths_hook, enable_hashagg, estimate_num_groups(), fb(), fetch_upper_rel(), foreach_node, generate_useful_gather_paths(), get_sortgrouplist_exprs(), get_useful_pathkeys_for_distinct(), grouping_is_hashable(), grouping_is_sortable(), Int64GetDatum(), InvalidOid, lfirst, LIMIT_OPTION_COUNT, linitial, list_length(), make_ordered_path(), makeConst(), NIL, parse(), root, set_cheapest(), and UPPERREL_PARTIAL_DISTINCT.

Referenced by create_distinct_paths().

◆ create_partial_grouping_paths()

static RelOptInfo * create_partial_grouping_paths ( PlannerInfo root,
RelOptInfo grouped_rel,
RelOptInfo input_rel,
grouping_sets_data gd,
GroupPathExtraData extra,
bool  force_rel_creation 
)
static

Definition at line 7606 of file planner.c.

7612{
7613 Query *parse = root->parse;
7616 AggClauseCosts *agg_partial_costs = &extra->agg_partial_costs;
7617 AggClauseCosts *agg_final_costs = &extra->agg_final_costs;
7619 Path *cheapest_total_path = NULL;
7620 double dNumPartialGroups = 0;
7621 double dNumPartialPartialGroups = 0;
7622 ListCell *lc;
7623 bool can_hash = (extra->flags & GROUPING_CAN_USE_HASH) != 0;
7624 bool can_sort = (extra->flags & GROUPING_CAN_USE_SORT) != 0;
7625
7626 /*
7627 * Check whether any partially aggregated paths have been generated
7628 * through eager aggregation.
7629 */
7630 if (input_rel->grouped_rel &&
7631 !IS_DUMMY_REL(input_rel->grouped_rel) &&
7632 input_rel->grouped_rel->pathlist != NIL)
7633 eager_agg_rel = input_rel->grouped_rel;
7634
7635 /*
7636 * Consider whether we should generate partially aggregated non-partial
7637 * paths. We can only do this if we have a non-partial path, and only if
7638 * the parent of the input rel is performing partial partitionwise
7639 * aggregation. (Note that extra->patype is the type of partitionwise
7640 * aggregation being used at the parent level, not this level.)
7641 */
7642 if (input_rel->pathlist != NIL &&
7644 cheapest_total_path = input_rel->cheapest_total_path;
7645
7646 /*
7647 * If parallelism is possible for grouped_rel, then we should consider
7648 * generating partially-grouped partial paths. However, if the input rel
7649 * has no partial paths, then we can't.
7650 */
7651 if (grouped_rel->consider_parallel && input_rel->partial_pathlist != NIL)
7652 cheapest_partial_path = linitial(input_rel->partial_pathlist);
7653
7654 /*
7655 * If we can't partially aggregate partial paths, and we can't partially
7656 * aggregate non-partial paths, and no partially aggregated paths were
7657 * generated by eager aggregation, then don't bother creating the new
7658 * RelOptInfo at all, unless the caller specified force_rel_creation.
7659 */
7660 if (cheapest_total_path == NULL &&
7662 eager_agg_rel == NULL &&
7664 return NULL;
7665
7666 /*
7667 * Build a new upper relation to represent the result of partially
7668 * aggregating the rows from the input relation.
7669 */
7672 grouped_rel->relids);
7673 partially_grouped_rel->consider_parallel =
7674 grouped_rel->consider_parallel;
7675 partially_grouped_rel->pgs_mask = grouped_rel->pgs_mask;
7676 partially_grouped_rel->reloptkind = grouped_rel->reloptkind;
7677 partially_grouped_rel->serverid = grouped_rel->serverid;
7678 partially_grouped_rel->userid = grouped_rel->userid;
7679 partially_grouped_rel->useridiscurrent = grouped_rel->useridiscurrent;
7680 partially_grouped_rel->fdwroutine = grouped_rel->fdwroutine;
7681
7682 /*
7683 * Build target list for partial aggregate paths. These paths cannot just
7684 * emit the same tlist as regular aggregate paths, because (1) we must
7685 * include Vars and Aggrefs needed in HAVING, which might not appear in
7686 * the result tlist, and (2) the Aggrefs must be set in partial mode.
7687 */
7690 extra->havingQual);
7691
7692 if (!extra->partial_costs_set)
7693 {
7694 /*
7695 * Collect statistics about aggregates for estimating costs of
7696 * performing aggregation in parallel.
7697 */
7698 MemSet(agg_partial_costs, 0, sizeof(AggClauseCosts));
7699 MemSet(agg_final_costs, 0, sizeof(AggClauseCosts));
7700 if (parse->hasAggs)
7701 {
7702 /* partial phase */
7704 agg_partial_costs);
7705
7706 /* final phase */
7708 agg_final_costs);
7709 }
7710
7711 extra->partial_costs_set = true;
7712 }
7713
7714 /* Estimate number of partial groups. */
7715 if (cheapest_total_path != NULL)
7718 cheapest_total_path->rows,
7719 gd,
7720 extra->targetList);
7725 gd,
7726 extra->targetList);
7727
7728 if (can_sort && cheapest_total_path != NULL)
7729 {
7730 /* This should have been checked previously */
7731 Assert(parse->hasAggs || parse->groupClause);
7732
7733 /*
7734 * Use any available suitably-sorted path as input, and also consider
7735 * sorting the cheapest partial path.
7736 */
7737 foreach(lc, input_rel->pathlist)
7738 {
7739 ListCell *lc2;
7740 Path *path = (Path *) lfirst(lc);
7741 Path *path_save = path;
7743
7744 /* generate alternative group orderings that might be useful */
7746
7748
7749 /* process all potentially interesting grouping reorderings */
7750 foreach(lc2, pathkey_orderings)
7751 {
7753
7754 /* restore the path (we replace it in the loop) */
7755 path = path_save;
7756
7757 path = make_ordered_path(root,
7759 path,
7760 cheapest_total_path,
7761 info->pathkeys,
7762 -1.0);
7763
7764 if (path == NULL)
7765 continue;
7766
7767 if (parse->hasAggs)
7771 path,
7772 partially_grouped_rel->reltarget,
7773 parse->groupClause ? AGG_SORTED : AGG_PLAIN,
7775 info->clauses,
7776 NIL,
7777 agg_partial_costs,
7779 else
7783 path,
7784 info->clauses,
7785 NIL,
7787 }
7788 }
7789 }
7790
7792 {
7793 /* Similar to above logic, but for partial paths. */
7794 foreach(lc, input_rel->partial_pathlist)
7795 {
7796 ListCell *lc2;
7797 Path *path = (Path *) lfirst(lc);
7798 Path *path_save = path;
7800
7801 /* generate alternative group orderings that might be useful */
7803
7805
7806 /* process all potentially interesting grouping reorderings */
7807 foreach(lc2, pathkey_orderings)
7808 {
7810
7811
7812 /* restore the path (we replace it in the loop) */
7813 path = path_save;
7814
7815 path = make_ordered_path(root,
7817 path,
7819 info->pathkeys,
7820 -1.0);
7821
7822 if (path == NULL)
7823 continue;
7824
7825 if (parse->hasAggs)
7829 path,
7830 partially_grouped_rel->reltarget,
7831 parse->groupClause ? AGG_SORTED : AGG_PLAIN,
7833 info->clauses,
7834 NIL,
7835 agg_partial_costs,
7837 else
7841 path,
7842 info->clauses,
7843 NIL,
7845 }
7846 }
7847 }
7848
7849 /*
7850 * Add a partially-grouped HashAgg Path where possible
7851 */
7852 if (can_hash && cheapest_total_path != NULL)
7853 {
7854 /* Checked above */
7855 Assert(parse->hasAggs || parse->groupClause);
7856
7860 cheapest_total_path,
7861 partially_grouped_rel->reltarget,
7862 AGG_HASHED,
7864 root->processed_groupClause,
7865 NIL,
7866 agg_partial_costs,
7868 }
7869
7870 /*
7871 * Now add a partially-grouped HashAgg partial Path where possible
7872 */
7874 {
7879 partially_grouped_rel->reltarget,
7880 AGG_HASHED,
7882 root->processed_groupClause,
7883 NIL,
7884 agg_partial_costs,
7886 }
7887
7888 /*
7889 * Add any partially aggregated paths generated by eager aggregation to
7890 * the new upper relation after applying projection steps as needed.
7891 */
7892 if (eager_agg_rel)
7893 {
7894 /* Add the paths */
7895 foreach(lc, eager_agg_rel->pathlist)
7896 {
7897 Path *path = (Path *) lfirst(lc);
7898
7899 /* Shouldn't have any parameterized paths anymore */
7900 Assert(path->param_info == NULL);
7901
7902 path = (Path *) create_projection_path(root,
7904 path,
7905 partially_grouped_rel->reltarget);
7906
7908 }
7909
7910 /*
7911 * Likewise add the partial paths, but only if parallelism is possible
7912 * for partially_grouped_rel.
7913 */
7914 if (partially_grouped_rel->consider_parallel)
7915 {
7916 foreach(lc, eager_agg_rel->partial_pathlist)
7917 {
7918 Path *path = (Path *) lfirst(lc);
7919
7920 /* Shouldn't have any parameterized paths anymore */
7921 Assert(path->param_info == NULL);
7922
7923 path = (Path *) create_projection_path(root,
7925 path,
7926 partially_grouped_rel->reltarget);
7927
7929 }
7930 }
7931 }
7932
7933 /*
7934 * If there is an FDW that's responsible for all baserels of the query,
7935 * let it consider adding partially grouped ForeignPaths.
7936 */
7937 if (partially_grouped_rel->fdwroutine &&
7938 partially_grouped_rel->fdwroutine->GetForeignUpperPaths)
7939 {
7940 FdwRoutine *fdwroutine = partially_grouped_rel->fdwroutine;
7941
7942 fdwroutine->GetForeignUpperPaths(root,
7945 extra);
7946 }
7947
7948 return partially_grouped_rel;
7949}
@ AGGSPLIT_INITIAL_SERIAL
Definition nodes.h:387
@ UPPERREL_PARTIAL_GROUP_AGG
Definition pathnodes.h:145
static PathTarget * make_partial_grouping_target(PlannerInfo *root, PathTarget *grouping_target, Node *havingQual)
Definition planner.c:5906
GetForeignUpperPaths_function GetForeignUpperPaths
Definition fdwapi.h:230
AggClauseCosts agg_partial_costs
Definition pathnodes.h:3684
bool useridiscurrent
Definition pathnodes.h:1115
Relids relids
Definition pathnodes.h:1021
uint64 pgs_mask
Definition pathnodes.h:1039
RelOptKind reloptkind
Definition pathnodes.h:1015

References add_partial_path(), add_path(), GroupPathExtraData::agg_final_costs, AGG_HASHED, GroupPathExtraData::agg_partial_costs, AGG_PLAIN, AGG_SORTED, AGGSPLIT_FINAL_DESERIAL, AGGSPLIT_INITIAL_SERIAL, Assert, GroupByOrdering::clauses, RelOptInfo::consider_parallel, create_agg_path(), create_group_path(), create_projection_path(), fb(), fetch_upper_rel(), GroupPathExtraData::flags, get_agg_clause_costs(), get_number_of_groups(), get_useful_group_keys_orderings(), FdwRoutine::GetForeignUpperPaths, GROUPING_CAN_USE_HASH, GROUPING_CAN_USE_SORT, GroupPathExtraData::havingQual, IS_DUMMY_REL, lfirst, linitial, list_length(), make_ordered_path(), make_partial_grouping_target(), MemSet, NIL, parse(), GroupPathExtraData::partial_costs_set, PARTITIONWISE_AGGREGATE_PARTIAL, GroupByOrdering::pathkeys, GroupPathExtraData::patype, RelOptInfo::pgs_mask, RelOptInfo::relids, RelOptInfo::reloptkind, RelOptInfo::reltarget, root, Path::rows, RelOptInfo::serverid, GroupPathExtraData::targetList, UPPERREL_PARTIAL_GROUP_AGG, RelOptInfo::userid, and RelOptInfo::useridiscurrent.

Referenced by create_ordinary_grouping_paths().

◆ create_partial_unique_paths()

static void create_partial_unique_paths ( PlannerInfo root,
RelOptInfo input_rel,
List sortPathkeys,
List groupClause,
SpecialJoinInfo sjinfo,
RelOptInfo unique_rel 
)
static

Definition at line 9057 of file planner.c.

9060{
9063
9064 /* nothing to do when there are no partial paths in the input rel */
9065 if (!input_rel->consider_parallel || input_rel->partial_pathlist == NIL)
9066 return;
9067
9068 /*
9069 * nothing to do if there's anything in the targetlist that's
9070 * parallel-restricted.
9071 */
9072 if (!is_parallel_safe(root, (Node *) unique_rel->reltarget->exprs))
9073 return;
9074
9075 cheapest_partial_path = linitial(input_rel->partial_pathlist);
9076
9079
9080 /*
9081 * clear path info
9082 */
9083 partial_unique_rel->pathlist = NIL;
9084 partial_unique_rel->ppilist = NIL;
9085 partial_unique_rel->partial_pathlist = NIL;
9086 partial_unique_rel->cheapest_startup_path = NULL;
9087 partial_unique_rel->cheapest_total_path = NULL;
9088 partial_unique_rel->cheapest_parameterized_paths = NIL;
9089
9090 /* Estimate number of output rows */
9092 sjinfo->semi_rhs_exprs,
9094 NULL,
9095 NULL);
9096 partial_unique_rel->reltarget = unique_rel->reltarget;
9097
9098 /* Consider sort-based implementations, if possible. */
9099 if (sjinfo->semi_can_btree)
9100 {
9101 ListCell *lc;
9102
9103 /*
9104 * Use any available suitably-sorted path as input, and also consider
9105 * sorting the cheapest partial path and incremental sort on any paths
9106 * with presorted keys.
9107 */
9108 foreach(lc, input_rel->partial_pathlist)
9109 {
9110 Path *input_path = (Path *) lfirst(lc);
9111 Path *path;
9112 bool is_sorted;
9113 int presorted_keys;
9114
9116 input_path->pathkeys,
9117 &presorted_keys);
9118
9119 /*
9120 * Ignore paths that are not suitably or partially sorted, unless
9121 * they are the cheapest partial path (no need to deal with paths
9122 * which have presorted keys when incremental sort is disabled).
9123 */
9125 (presorted_keys == 0 || !enable_incremental_sort))
9126 continue;
9127
9128 /*
9129 * Make a separate ProjectionPath in case we need a Result node.
9130 */
9131 path = (Path *) create_projection_path(root,
9133 input_path,
9134 partial_unique_rel->reltarget);
9135
9136 if (!is_sorted)
9137 {
9138 /*
9139 * We've no need to consider both a sort and incremental sort.
9140 * We'll just do a sort if there are no presorted keys and an
9141 * incremental sort when there are presorted keys.
9142 */
9143 if (presorted_keys == 0 || !enable_incremental_sort)
9144 path = (Path *) create_sort_path(root,
9146 path,
9148 -1.0);
9149 else
9152 path,
9154 presorted_keys,
9155 -1.0);
9156 }
9157
9160 partial_unique_rel->rows);
9161
9163 }
9164 }
9165
9166 /* Consider hash-based implementation, if possible. */
9167 if (sjinfo->semi_can_hash)
9168 {
9169 Path *path;
9170
9171 /*
9172 * Make a separate ProjectionPath in case we need a Result node.
9173 */
9174 path = (Path *) create_projection_path(root,
9177 partial_unique_rel->reltarget);
9178
9179 path = (Path *) create_agg_path(root,
9181 path,
9182 cheapest_partial_path->pathtarget,
9183 AGG_HASHED,
9185 groupClause,
9186 NIL,
9187 NULL,
9188 partial_unique_rel->rows);
9189
9191 }
9192
9193 if (partial_unique_rel->partial_pathlist != NIL)
9194 {
9197
9198 /*
9199 * Finally, create paths to unique-ify the final result. This step is
9200 * needed to remove any duplicates due to combining rows from parallel
9201 * workers.
9202 */
9204 sortPathkeys, groupClause,
9205 sjinfo, unique_rel);
9206 }
9207}
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
bool is_parallel_safe(PlannerInfo *root, Node *node)
Definition clauses.c:782
static void create_final_unique_paths(PlannerInfo *root, RelOptInfo *input_rel, List *sortPathkeys, List *groupClause, SpecialJoinInfo *sjinfo, RelOptInfo *unique_rel)
Definition planner.c:8932

References add_partial_path(), AGG_HASHED, AGGSPLIT_SIMPLE, create_agg_path(), create_final_unique_paths(), create_incremental_sort_path(), create_projection_path(), create_sort_path(), create_unique_path(), enable_incremental_sort, estimate_num_groups(), PathTarget::exprs, fb(), generate_useful_gather_paths(), is_parallel_safe(), lfirst, linitial, list_length(), makeNode, memcpy(), NIL, pathkeys_count_contained_in(), RelOptInfo::reltarget, root, Path::rows, SpecialJoinInfo::semi_can_btree, SpecialJoinInfo::semi_can_hash, SpecialJoinInfo::semi_rhs_exprs, and set_cheapest().

Referenced by create_unique_paths().

◆ create_partitionwise_grouping_paths()

static void create_partitionwise_grouping_paths ( PlannerInfo root,
RelOptInfo input_rel,
RelOptInfo grouped_rel,
RelOptInfo partially_grouped_rel,
const AggClauseCosts agg_costs,
grouping_sets_data gd,
PartitionwiseAggregateType  patype,
GroupPathExtraData extra 
)
static

Definition at line 8383 of file planner.c.

8391{
8394 PathTarget *target = grouped_rel->reltarget;
8395 bool partial_grouping_valid = true;
8396 int i;
8397
8401
8402 /* Add paths for partitionwise aggregation/grouping. */
8403 i = -1;
8404 while ((i = bms_next_member(input_rel->live_parts, i)) >= 0)
8405 {
8406 RelOptInfo *child_input_rel = input_rel->part_rels[i];
8408 AppendRelInfo **appinfos;
8409 int nappinfos;
8413
8415
8416 /* Dummy children can be ignored. */
8418 continue;
8419
8420 child_target = copy_pathtarget(target);
8421
8422 /*
8423 * Copy the given "extra" structure as is and then override the
8424 * members specific to this child.
8425 */
8426 memcpy(&child_extra, extra, sizeof(child_extra));
8427
8428 appinfos = find_appinfos_by_relids(root, child_input_rel->relids,
8429 &nappinfos);
8430
8431 child_target->exprs = (List *)
8433 (Node *) target->exprs,
8434 nappinfos, appinfos);
8435
8436 /* Translate havingQual and targetList. */
8437 child_extra.havingQual = (Node *)
8439 extra->havingQual,
8440 nappinfos, appinfos);
8441 child_extra.targetList = (List *)
8443 (Node *) extra->targetList,
8444 nappinfos, appinfos);
8445
8446 /*
8447 * extra->patype was the value computed for our parent rel; patype is
8448 * the value for this relation. For the child, our value is its
8449 * parent rel's value.
8450 */
8451 child_extra.patype = patype;
8452
8453 /*
8454 * Create grouping relation to hold fully aggregated grouping and/or
8455 * aggregation paths for the child.
8456 */
8459 extra->target_parallel_safe,
8460 child_extra.havingQual);
8461
8462 /* Create grouping paths for this child relation. */
8467
8469 {
8473 }
8474 else
8475 partial_grouping_valid = false;
8476
8477 if (patype == PARTITIONWISE_AGGREGATE_FULL)
8478 {
8482 }
8483
8484 pfree(appinfos);
8485 }
8486
8487 /*
8488 * Try to create append paths for partially grouped children. For full
8489 * partitionwise aggregation, we might have paths in the partial_pathlist
8490 * if parallel aggregation is possible. For partial partitionwise
8491 * aggregation, we may have paths in both pathlist and partial_pathlist.
8492 *
8493 * NB: We must have a partially grouped path for every child in order to
8494 * generate a partially grouped path for this relation.
8495 */
8497 {
8499
8502 }
8503
8504 /* If possible, create append paths for fully grouped children. */
8505 if (patype == PARTITIONWISE_AGGREGATE_FULL)
8506 {
8508
8510 }
8511}

References add_paths_to_append_rel(), adjust_appendrel_attrs(), Assert, bms_next_member(), copy_pathtarget(), create_ordinary_grouping_paths(), PathTarget::exprs, fb(), find_appinfos_by_relids(), GroupPathExtraData::havingQual, i, IS_DUMMY_REL, lappend(), make_grouping_rel(), memcpy(), NIL, PARTITIONWISE_AGGREGATE_FULL, PARTITIONWISE_AGGREGATE_NONE, PARTITIONWISE_AGGREGATE_PARTIAL, pfree(), RelOptInfo::reltarget, root, set_cheapest(), GroupPathExtraData::target_parallel_safe, and GroupPathExtraData::targetList.

Referenced by create_ordinary_grouping_paths().

◆ create_unique_paths()

RelOptInfo * create_unique_paths ( PlannerInfo root,
RelOptInfo rel,
SpecialJoinInfo sjinfo 
)

Definition at line 8663 of file planner.c.

8664{
8665 RelOptInfo *unique_rel;
8667 List *groupClause = NIL;
8668 MemoryContext oldcontext;
8669
8670 /* Caller made a mistake if SpecialJoinInfo is the wrong one */
8671 Assert(sjinfo->jointype == JOIN_SEMI);
8672 Assert(bms_equal(rel->relids, sjinfo->syn_righthand));
8673
8674 /* If result already cached, return it */
8675 if (rel->unique_rel)
8676 return rel->unique_rel;
8677
8678 /* If it's not possible to unique-ify, return NULL */
8679 if (!(sjinfo->semi_can_btree || sjinfo->semi_can_hash))
8680 return NULL;
8681
8682 /*
8683 * Punt if this is a child relation and we failed to build a unique-ified
8684 * relation for its parent. This can happen if all the RHS columns were
8685 * found to be equated to constants when unique-ifying the parent table,
8686 * leaving no columns to unique-ify.
8687 */
8688 if (IS_OTHER_REL(rel) && rel->top_parent->unique_rel == NULL)
8689 return NULL;
8690
8691 /*
8692 * When called during GEQO join planning, we are in a short-lived memory
8693 * context. We must make sure that the unique rel and any subsidiary data
8694 * structures created for a baserel survive the GEQO cycle, else the
8695 * baserel is trashed for future GEQO cycles. On the other hand, when we
8696 * are creating those for a joinrel during GEQO, we don't want them to
8697 * clutter the main planning context. Upshot is that the best solution is
8698 * to explicitly allocate memory in the same context the given RelOptInfo
8699 * is in.
8700 */
8702
8703 unique_rel = makeNode(RelOptInfo);
8704 memcpy(unique_rel, rel, sizeof(RelOptInfo));
8705
8706 /*
8707 * clear path info
8708 */
8709 unique_rel->pathlist = NIL;
8710 unique_rel->ppilist = NIL;
8711 unique_rel->partial_pathlist = NIL;
8712 unique_rel->cheapest_startup_path = NULL;
8713 unique_rel->cheapest_total_path = NULL;
8714 unique_rel->cheapest_parameterized_paths = NIL;
8715
8716 /*
8717 * Build the target list for the unique rel. We also build the pathkeys
8718 * that represent the ordering requirements for the sort-based
8719 * implementation, and the list of SortGroupClause nodes that represent
8720 * the columns to be grouped on for the hash-based implementation.
8721 *
8722 * For a child rel, we can construct these fields from those of its
8723 * parent.
8724 */
8725 if (IS_OTHER_REL(rel))
8726 {
8729
8730 parent_unique_target = rel->top_parent->unique_rel->reltarget;
8731
8733
8734 /* Translate the target expressions */
8735 child_unique_target->exprs = (List *)
8737 (Node *) parent_unique_target->exprs,
8738 rel,
8739 rel->top_parent);
8740
8741 unique_rel->reltarget = child_unique_target;
8742
8743 sortPathkeys = rel->top_parent->unique_pathkeys;
8744 groupClause = rel->top_parent->unique_groupclause;
8745 }
8746 else
8747 {
8748 List *newtlist;
8749 int nextresno;
8750 List *sortList = NIL;
8751 ListCell *lc1;
8752 ListCell *lc2;
8753
8754 /*
8755 * The values we are supposed to unique-ify may be expressions in the
8756 * variables of the input rel's targetlist. We have to add any such
8757 * expressions to the unique rel's targetlist.
8758 *
8759 * To complicate matters, some of the values to be unique-ified may be
8760 * known redundant by the EquivalenceClass machinery (e.g., because
8761 * they have been equated to constants). There is no need to compare
8762 * such values during unique-ification, and indeed we had better not
8763 * try because the Vars involved may not have propagated as high as
8764 * the semijoin's level. We use make_pathkeys_for_sortclauses to
8765 * detect such cases, which is a tad inefficient but it doesn't seem
8766 * worth building specialized infrastructure for this.
8767 */
8770
8771 forboth(lc1, sjinfo->semi_rhs_exprs, lc2, sjinfo->semi_operators)
8772 {
8773 Expr *uniqexpr = lfirst(lc1);
8775 Oid sortop;
8777 bool made_tle = false;
8778
8780 if (!tle)
8781 {
8783 nextresno,
8784 NULL,
8785 false);
8787 nextresno++;
8788 made_tle = true;
8789 }
8790
8791 /*
8792 * Try to build an ORDER BY list to sort the input compatibly. We
8793 * do this for each sortable clause even when the clauses are not
8794 * all sortable, so that we can detect clauses that are redundant
8795 * according to the pathkey machinery.
8796 */
8798 if (OidIsValid(sortop))
8799 {
8800 Oid eqop;
8802
8803 /*
8804 * The Unique node will need equality operators. Normally
8805 * these are the same as the IN clause operators, but if those
8806 * are cross-type operators then the equality operators are
8807 * the ones for the IN clause operators' RHS datatype.
8808 */
8809 eqop = get_equality_op_for_ordering_op(sortop, NULL);
8810 if (!OidIsValid(eqop)) /* shouldn't happen */
8811 elog(ERROR, "could not find equality operator for ordering operator %u",
8812 sortop);
8813
8815 sortcl->tleSortGroupRef = assignSortGroupRef(tle, newtlist);
8816 sortcl->eqop = eqop;
8817 sortcl->sortop = sortop;
8818 sortcl->reverse_sort = false;
8819 sortcl->nulls_first = false;
8820 sortcl->hashable = false; /* no need to make this accurate */
8822
8823 /*
8824 * At each step, convert the SortGroupClause list to pathkey
8825 * form. If the just-added SortGroupClause is redundant, the
8826 * result will be shorter than the SortGroupClause list.
8827 */
8829 newtlist);
8831 {
8832 /* Drop the redundant SortGroupClause */
8835 /* Undo tlist addition, if we made one */
8836 if (made_tle)
8837 {
8839 nextresno--;
8840 }
8841 /* We need not consider this clause for hashing, either */
8842 continue;
8843 }
8844 }
8845 else if (sjinfo->semi_can_btree) /* shouldn't happen */
8846 elog(ERROR, "could not find ordering operator for equality operator %u",
8847 in_oper);
8848
8849 if (sjinfo->semi_can_hash)
8850 {
8851 /* Create a GROUP BY list for the Agg node to use */
8852 Oid eq_oper;
8854
8855 /*
8856 * Get the hashable equality operators for the Agg node to
8857 * use. Normally these are the same as the IN clause
8858 * operators, but if those are cross-type operators then the
8859 * equality operators are the ones for the IN clause
8860 * operators' RHS datatype.
8861 */
8863 elog(ERROR, "could not find compatible hash operator for operator %u",
8864 in_oper);
8865
8867 groupcl->tleSortGroupRef = assignSortGroupRef(tle, newtlist);
8868 groupcl->eqop = eq_oper;
8869 groupcl->sortop = sortop;
8870 groupcl->reverse_sort = false;
8871 groupcl->nulls_first = false;
8872 groupcl->hashable = true;
8873 groupClause = lappend(groupClause, groupcl);
8874 }
8875 }
8876
8877 /*
8878 * Done building the sortPathkeys and groupClause. But the
8879 * sortPathkeys are bogus if not all the clauses were sortable.
8880 */
8881 if (!sjinfo->semi_can_btree)
8882 sortPathkeys = NIL;
8883
8884 /*
8885 * It can happen that all the RHS columns are equated to constants.
8886 * We'd have to do something special to unique-ify in that case, and
8887 * it's such an unlikely-in-the-real-world case that it's not worth
8888 * the effort. So just punt if we found no columns to unique-ify.
8889 */
8890 if (sortPathkeys == NIL && groupClause == NIL)
8891 {
8892 MemoryContextSwitchTo(oldcontext);
8893 return NULL;
8894 }
8895
8896 /* Convert the required targetlist back to PathTarget form */
8897 unique_rel->reltarget = create_pathtarget(root, newtlist);
8898 }
8899
8900 /* build unique paths based on input rel's pathlist */
8901 create_final_unique_paths(root, rel, sortPathkeys, groupClause,
8902 sjinfo, unique_rel);
8903
8904 /* build unique paths based on input rel's partial_pathlist */
8906 sjinfo, unique_rel);
8907
8908 /* Now choose the best path(s) */
8909 set_cheapest(unique_rel);
8910
8911 /*
8912 * There shouldn't be any partial paths for the unique relation;
8913 * otherwise, we won't be able to properly guarantee uniqueness.
8914 */
8915 Assert(unique_rel->partial_pathlist == NIL);
8916
8917 /* Cache the result */
8918 rel->unique_rel = unique_rel;
8920 rel->unique_groupclause = groupClause;
8921
8922 MemoryContextSwitchTo(oldcontext);
8923
8924 return unique_rel;
8925}
Node * adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition appendinfo.c:597
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:142
#define OidIsValid(objectId)
Definition c.h:917
#define elog(elevel,...)
Definition elog.h:228
List * list_delete_last(List *list)
Definition list.c:957
bool get_compatible_hash_operators(Oid opno, Oid *lhs_opno, Oid *rhs_opno)
Definition lsyscache.c:483
Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse)
Definition lsyscache.c:326
Oid get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
Definition lsyscache.c:364
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition makefuncs.c:289
MemoryContext GetMemoryChunkContext(void *pointer)
Definition mcxt.c:759
@ JOIN_SEMI
Definition nodes.h:315
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
Index assignSortGroupRef(TargetEntry *tle, List *tlist)
#define lfirst_oid(lc)
Definition pg_list.h:174
static void create_partial_unique_paths(PlannerInfo *root, RelOptInfo *input_rel, List *sortPathkeys, List *groupClause, SpecialJoinInfo *sjinfo, RelOptInfo *unique_rel)
Definition planner.c:9057
unsigned int Oid
List * ppilist
Definition pathnodes.h:1051
List * unique_pathkeys
Definition pathnodes.h:1134
List * cheapest_parameterized_paths
Definition pathnodes.h:1055
List * unique_groupclause
Definition pathnodes.h:1136
struct RelOptInfo * unique_rel
Definition pathnodes.h:1132
JoinType jointype
Definition pathnodes.h:3230
Relids syn_righthand
Definition pathnodes.h:3229
List * semi_operators
Definition pathnodes.h:3240
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition tlist.c:88
List * make_tlist_from_pathtarget(PathTarget *target)
Definition tlist.c:633
#define create_pathtarget(root, tlist)
Definition tlist.h:58

References adjust_appendrel_attrs_multilevel(), Assert, assignSortGroupRef(), bms_equal(), RelOptInfo::cheapest_parameterized_paths, RelOptInfo::cheapest_startup_path, RelOptInfo::cheapest_total_path, copy_pathtarget(), create_final_unique_paths(), create_partial_unique_paths(), create_pathtarget, elog, ERROR, fb(), forboth, get_compatible_hash_operators(), get_equality_op_for_ordering_op(), get_ordering_op_for_equality_op(), GetMemoryChunkContext(), IS_OTHER_REL, JOIN_SEMI, SpecialJoinInfo::jointype, lappend(), lfirst, lfirst_oid, list_delete_last(), list_length(), make_pathkeys_for_sortclauses(), make_tlist_from_pathtarget(), makeNode, makeTargetEntry(), memcpy(), MemoryContextSwitchTo(), NIL, OidIsValid, RelOptInfo::partial_pathlist, RelOptInfo::pathlist, RelOptInfo::ppilist, RelOptInfo::relids, RelOptInfo::reltarget, root, SpecialJoinInfo::semi_can_btree, SpecialJoinInfo::semi_can_hash, SpecialJoinInfo::semi_operators, SpecialJoinInfo::semi_rhs_exprs, set_cheapest(), SpecialJoinInfo::syn_righthand, tlist_member(), RelOptInfo::unique_groupclause, RelOptInfo::unique_pathkeys, and RelOptInfo::unique_rel.

Referenced by join_is_legal(), and populate_joinrel_with_paths().

◆ create_window_paths()

static RelOptInfo * create_window_paths ( PlannerInfo root,
RelOptInfo input_rel,
PathTarget input_target,
PathTarget output_target,
bool  output_target_parallel_safe,
WindowFuncLists wflists,
List activeWindows 
)
static

Definition at line 4796 of file planner.c.

4803{
4805 ListCell *lc;
4806
4807 /* For now, do all work in the (WINDOW, NULL) upperrel */
4809
4810 /*
4811 * If the input relation is not parallel-safe, then the window relation
4812 * can't be parallel-safe, either. Otherwise, we need to examine the
4813 * target list and active windows for non-parallel-safe constructs.
4814 */
4815 if (input_rel->consider_parallel && output_target_parallel_safe &&
4816 is_parallel_safe(root, (Node *) activeWindows))
4817 window_rel->consider_parallel = true;
4818
4819 /*
4820 * If the input rel belongs to a single FDW, so does the window rel.
4821 */
4822 window_rel->serverid = input_rel->serverid;
4823 window_rel->userid = input_rel->userid;
4824 window_rel->useridiscurrent = input_rel->useridiscurrent;
4825 window_rel->fdwroutine = input_rel->fdwroutine;
4826
4827 /*
4828 * Consider computing window functions starting from the existing
4829 * cheapest-total path (which will likely require a sort) as well as any
4830 * existing paths that satisfy or partially satisfy root->window_pathkeys.
4831 */
4832 foreach(lc, input_rel->pathlist)
4833 {
4834 Path *path = (Path *) lfirst(lc);
4835 int presorted_keys;
4836
4837 if (path == input_rel->cheapest_total_path ||
4838 pathkeys_count_contained_in(root->window_pathkeys, path->pathkeys,
4839 &presorted_keys) ||
4840 presorted_keys > 0)
4842 window_rel,
4843 path,
4846 wflists,
4847 activeWindows);
4848 }
4849
4850 /*
4851 * If there is an FDW that's responsible for all baserels of the query,
4852 * let it consider adding ForeignPaths.
4853 */
4854 if (window_rel->fdwroutine &&
4855 window_rel->fdwroutine->GetForeignUpperPaths)
4856 window_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_WINDOW,
4858 NULL);
4859
4860 /* Let extensions possibly add some more paths */
4862 (*create_upper_paths_hook) (root, UPPERREL_WINDOW,
4864
4865 /* Now choose the best path(s) */
4867
4868 return window_rel;
4869}
@ UPPERREL_WINDOW
Definition pathnodes.h:148
static void create_one_window_path(PlannerInfo *root, RelOptInfo *window_rel, Path *path, PathTarget *input_target, PathTarget *output_target, WindowFuncLists *wflists, List *activeWindows)
Definition planner.c:4883

References create_one_window_path(), create_upper_paths_hook, fb(), fetch_upper_rel(), is_parallel_safe(), lfirst, Path::pathkeys, pathkeys_count_contained_in(), root, set_cheapest(), and UPPERREL_WINDOW.

Referenced by grouping_planner().

◆ expression_planner()

Expr * expression_planner ( Expr expr)

Definition at line 7010 of file planner.c.

7011{
7012 Node *result;
7013
7014 /*
7015 * Convert named-argument function calls, insert default arguments and
7016 * simplify constant subexprs
7017 */
7019
7020 /* Fill in opfuncid values if missing */
7022
7023 return (Expr *) result;
7024}
uint32 result
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition clauses.c:2516
void fix_opfuncids(Node *node)
Definition nodeFuncs.c:1859

References eval_const_expressions(), fb(), fix_opfuncids(), and result.

Referenced by ATExecAddColumn(), ATExecSetExpression(), ATPrepAlterColumnType(), BeginCopyFrom(), ComputePartitionAttrs(), contain_mutable_functions_after_planning(), contain_volatile_functions_after_planning(), createTableConstraints(), ExecPrepareCheck(), ExecPrepareExpr(), ExecPrepareQual(), load_domaintype_info(), set_baserel_partition_constraint(), slot_fill_defaults(), and transformPartitionBoundValue().

◆ expression_planner_with_deps()

Expr * expression_planner_with_deps ( Expr expr,
List **  relationOids,
List **  invalItems 
)

Definition at line 7037 of file planner.c.

7040{
7041 Node *result;
7042 PlannerGlobal glob;
7044
7045 /* Make up dummy planner state so we can use setrefs machinery */
7046 MemSet(&glob, 0, sizeof(glob));
7047 glob.type = T_PlannerGlobal;
7048 glob.relationOids = NIL;
7049 glob.invalItems = NIL;
7050
7051 MemSet(&root, 0, sizeof(root));
7052 root.type = T_PlannerInfo;
7053 root.glob = &glob;
7054
7055 /*
7056 * Convert named-argument function calls, insert default arguments and
7057 * simplify constant subexprs. Collect identities of inlined functions
7058 * and elided domains, too.
7059 */
7060 result = eval_const_expressions(&root, (Node *) expr);
7061
7062 /* Fill in opfuncid values if missing */
7064
7065 /*
7066 * Now walk the finished expression to find anything else we ought to
7067 * record as an expression dependency.
7068 */
7070
7071 *relationOids = glob.relationOids;
7072 *invalItems = glob.invalItems;
7073
7074 return (Expr *) result;
7075}
bool extract_query_dependencies_walker(Node *node, PlannerInfo *context)
Definition setrefs.c:3749
List * invalItems
Definition pathnodes.h:230
List * relationOids
Definition pathnodes.h:227

References eval_const_expressions(), extract_query_dependencies_walker(), fb(), fix_opfuncids(), PlannerGlobal::invalItems, MemSet, NIL, PlannerGlobal::relationOids, result, and root.

Referenced by GetCachedExpression().

◆ extract_rollup_sets()

static List * extract_rollup_sets ( List groupingSets)
static

Definition at line 3194 of file planner.c.

3195{
3196 int num_sets_raw = list_length(groupingSets);
3197 int num_empty = 0;
3198 int num_sets = 0; /* distinct sets */
3199 int num_chains = 0;
3200 List *result = NIL;
3201 List **results;
3202 List **orig_sets;
3204 int *chains;
3205 short **adjacency;
3206 short *adjacency_buf;
3208 int i;
3209 int j;
3210 int j_size;
3211 ListCell *lc1 = list_head(groupingSets);
3212 ListCell *lc;
3213
3214 /*
3215 * Start by stripping out empty sets. The algorithm doesn't require this,
3216 * but the planner currently needs all empty sets to be returned in the
3217 * first list, so we strip them here and add them back after.
3218 */
3219 while (lc1 && lfirst(lc1) == NIL)
3220 {
3221 ++num_empty;
3222 lc1 = lnext(groupingSets, lc1);
3223 }
3224
3225 /* bail out now if it turns out that all we had were empty sets. */
3226 if (!lc1)
3227 return list_make1(groupingSets);
3228
3229 /*----------
3230 * We don't strictly need to remove duplicate sets here, but if we don't,
3231 * they tend to become scattered through the result, which is a bit
3232 * confusing (and irritating if we ever decide to optimize them out).
3233 * So we remove them here and add them back after.
3234 *
3235 * For each non-duplicate set, we fill in the following:
3236 *
3237 * orig_sets[i] = list of the original set lists
3238 * set_masks[i] = bitmapset for testing inclusion
3239 * adjacency[i] = array [n, v1, v2, ... vn] of adjacency indices
3240 *
3241 * chains[i] will be the result group this set is assigned to.
3242 *
3243 * We index all of these from 1 rather than 0 because it is convenient
3244 * to leave 0 free for the NIL node in the graph algorithm.
3245 *----------
3246 */
3247 orig_sets = palloc0((num_sets_raw + 1) * sizeof(List *));
3248 set_masks = palloc0((num_sets_raw + 1) * sizeof(Bitmapset *));
3249 adjacency = palloc0((num_sets_raw + 1) * sizeof(short *));
3250 adjacency_buf = palloc((num_sets_raw + 1) * sizeof(short));
3251
3252 j_size = 0;
3253 j = 0;
3254 i = 1;
3255
3256 for_each_cell(lc, groupingSets, lc1)
3257 {
3258 List *candidate = (List *) lfirst(lc);
3260 ListCell *lc2;
3261 int dup_of = 0;
3262
3263 foreach(lc2, candidate)
3264 {
3266 }
3267
3268 /* we can only be a dup if we're the same length as a previous set */
3270 {
3271 int k;
3272
3273 for (k = j; k < i; ++k)
3274 {
3276 {
3277 dup_of = k;
3278 break;
3279 }
3280 }
3281 }
3282 else if (j_size < list_length(candidate))
3283 {
3285 j = i;
3286 }
3287
3288 if (dup_of > 0)
3289 {
3292 }
3293 else
3294 {
3295 int k;
3296 int n_adj = 0;
3297
3300
3301 /* fill in adjacency list; no need to compare equal-size sets */
3302
3303 for (k = j - 1; k > 0; --k)
3304 {
3306 adjacency_buf[++n_adj] = k;
3307 }
3308
3309 if (n_adj > 0)
3310 {
3311 adjacency_buf[0] = n_adj;
3312 adjacency[i] = palloc((n_adj + 1) * sizeof(short));
3313 memcpy(adjacency[i], adjacency_buf, (n_adj + 1) * sizeof(short));
3314 }
3315 else
3316 adjacency[i] = NULL;
3317
3318 ++i;
3319 }
3320 }
3321
3322 num_sets = i - 1;
3323
3324 /*
3325 * Apply the graph matching algorithm to do the work.
3326 */
3327 state = BipartiteMatch(num_sets, num_sets, adjacency);
3328
3329 /*
3330 * Now, the state->pair* fields have the info we need to assign sets to
3331 * chains. Two sets (u,v) belong to the same chain if pair_uv[u] = v or
3332 * pair_vu[v] = u (both will be true, but we check both so that we can do
3333 * it in one pass)
3334 */
3335 chains = palloc0((num_sets + 1) * sizeof(int));
3336
3337 for (i = 1; i <= num_sets; ++i)
3338 {
3339 int u = state->pair_vu[i];
3340 int v = state->pair_uv[i];
3341
3342 if (u > 0 && u < i)
3343 chains[i] = chains[u];
3344 else if (v > 0 && v < i)
3345 chains[i] = chains[v];
3346 else
3347 chains[i] = ++num_chains;
3348 }
3349
3350 /* build result lists. */
3351 results = palloc0((num_chains + 1) * sizeof(List *));
3352
3353 for (i = 1; i <= num_sets; ++i)
3354 {
3355 int c = chains[i];
3356
3357 Assert(c > 0);
3358
3359 results[c] = list_concat(results[c], orig_sets[i]);
3360 }
3361
3362 /* push any empty sets back on the first list. */
3363 while (num_empty-- > 0)
3364 results[1] = lcons(NIL, results[1]);
3365
3366 /* make result list */
3367 for (i = 1; i <= num_chains; ++i)
3368 result = lappend(result, results[i]);
3369
3370 /*
3371 * Free all the things.
3372 *
3373 * (This is over-fussy for small sets but for large sets we could have
3374 * tied up a nontrivial amount of memory.)
3375 */
3377 pfree(results);
3378 pfree(chains);
3379 for (i = 1; i <= num_sets; ++i)
3380 if (adjacency[i])
3381 pfree(adjacency[i]);
3382 pfree(adjacency);
3385 for (i = 1; i <= num_sets; ++i)
3388
3389 return result;
3390}
BipartiteMatchState * BipartiteMatch(int u_size, int v_size, short **adjacency)
void BipartiteMatchFree(BipartiteMatchState *state)
bool bms_is_subset(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:412
void bms_free(Bitmapset *a)
Definition bitmapset.c:239
int j
Definition isn.c:78
void * palloc0(Size size)
Definition mcxt.c:1420
char * c

References Assert, BipartiteMatch(), BipartiteMatchFree(), bms_add_member(), bms_equal(), bms_free(), bms_is_subset(), fb(), for_each_cell, i, j, lappend(), lcons(), lfirst, lfirst_int, list_concat(), list_head(), list_length(), list_make1, lnext(), memcpy(), NIL, palloc(), palloc0(), pfree(), and result.

Referenced by preprocess_grouping_sets().

◆ find_having_conflicts()

static Bitmapset * find_having_conflicts ( Query parse,
Index  group_rtindex 
)
static

Definition at line 1587 of file planner.c.

1588{
1591 int idx;
1592
1593 if (parse->havingQual == NULL)
1594 return NULL;
1595
1596 ctx.parse = parse;
1597 ctx.group_rtindex = group_rtindex;
1598
1599 idx = 0;
1600 foreach_ptr(Node, clause, (List *) parse->havingQual)
1601 {
1603 &ctx))
1605 idx++;
1606 }
1607
1608 return result;
1609}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:263
bool expression_has_grouping_conflict(Node *expr, grouping_eqop_callback get_eqop, void *context)
Definition clauses.c:6318
static Oid having_var_grouping_eqop(Var *var, void *context)
Definition planner.c:1619

References bms_add_member(), expression_has_grouping_conflict(), fb(), foreach_ptr, having_grouping_ctx::group_rtindex, having_var_grouping_eqop(), idx(), having_grouping_ctx::parse, parse(), and result.

Referenced by subquery_planner().

◆ gather_grouping_paths()

static void gather_grouping_paths ( PlannerInfo root,
RelOptInfo rel 
)
static

Definition at line 8017 of file planner.c.

8018{
8019 ListCell *lc;
8022
8023 /*
8024 * This occurs after any partial aggregation has taken place, so trim off
8025 * any pathkeys added for ORDER BY / DISTINCT aggregates.
8026 */
8027 if (list_length(root->group_pathkeys) > root->num_groupby_pathkeys)
8028 groupby_pathkeys = list_copy_head(root->group_pathkeys,
8029 root->num_groupby_pathkeys);
8030 else
8031 groupby_pathkeys = root->group_pathkeys;
8032
8033 /* Try Gather for unordered paths and Gather Merge for ordered ones. */
8035
8037
8038 /* XXX Shouldn't this also consider the group-key-reordering? */
8039 foreach(lc, rel->partial_pathlist)
8040 {
8041 Path *path = (Path *) lfirst(lc);
8042 bool is_sorted;
8043 int presorted_keys;
8044 double total_groups;
8045
8047 path->pathkeys,
8048 &presorted_keys);
8049
8050 if (is_sorted)
8051 continue;
8052
8053 /*
8054 * Try at least sorting the cheapest path and also try incrementally
8055 * sorting any path which is partially sorted already (no need to deal
8056 * with paths which have presorted keys when incremental sort is
8057 * disabled unless it's the cheapest input path).
8058 */
8059 if (path != cheapest_partial_path &&
8060 (presorted_keys == 0 || !enable_incremental_sort))
8061 continue;
8062
8063 /*
8064 * We've no need to consider both a sort and incremental sort. We'll
8065 * just do a sort if there are no presorted keys and an incremental
8066 * sort when there are presorted keys.
8067 */
8068 if (presorted_keys == 0 || !enable_incremental_sort)
8069 path = (Path *) create_sort_path(root, rel, path,
8071 -1.0);
8072 else
8074 rel,
8075 path,
8077 presorted_keys,
8078 -1.0);
8080 path = (Path *)
8082 rel,
8083 path,
8084 rel->reltarget,
8086 NULL,
8087 &total_groups);
8088
8089 add_path(rel, path);
8090 }
8091}
List * list_copy_head(const List *oldlist, int len)
Definition list.c:1593

References add_path(), compute_gather_rows(), create_gather_merge_path(), create_incremental_sort_path(), create_sort_path(), enable_incremental_sort, fb(), generate_useful_gather_paths(), lfirst, linitial, list_copy_head(), list_length(), RelOptInfo::partial_pathlist, Path::pathkeys, pathkeys_count_contained_in(), RelOptInfo::reltarget, and root.

Referenced by add_paths_to_grouping_rel(), and create_ordinary_grouping_paths().

◆ generate_setop_child_grouplist()

static List * generate_setop_child_grouplist ( SetOperationStmt op,
List targetlist 
)
static

Definition at line 8607 of file planner.c.

8608{
8609 List *grouplist = copyObject(op->groupClauses);
8610 ListCell *lg;
8611 ListCell *lt;
8612 ListCell *ct;
8613
8615 ct = list_head(op->colTypes);
8616 foreach(lt, targetlist)
8617 {
8618 TargetEntry *tle = (TargetEntry *) lfirst(lt);
8620 Oid coltype;
8621
8622 /* resjunk columns could have sortgrouprefs. Leave these alone */
8623 if (tle->resjunk)
8624 continue;
8625
8626 /*
8627 * We expect every non-resjunk target to have a SortGroupClause and
8628 * colTypes.
8629 */
8630 Assert(lg != NULL);
8631 Assert(ct != NULL);
8633 coltype = lfirst_oid(ct);
8634
8635 /* reject if target type isn't the same as the setop target type */
8636 if (coltype != exprType((Node *) tle->expr))
8637 return NIL;
8638
8639 lg = lnext(grouplist, lg);
8640 ct = lnext(op->colTypes, ct);
8641
8642 /* assign a tleSortGroupRef, or reuse the existing one */
8643 sgc->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
8644 }
8645
8646 Assert(lg == NULL);
8647 Assert(ct == NULL);
8648
8649 return grouplist;
8650}
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42

References Assert, assignSortGroupRef(), copyObject, exprType(), fb(), lfirst, lfirst_oid, list_head(), lnext(), and NIL.

Referenced by standard_qp_callback().

◆ get_cheapest_fractional_path()

Path * get_cheapest_fractional_path ( RelOptInfo rel,
double  tuple_fraction 
)

Definition at line 6848 of file planner.c.

6849{
6851 ListCell *l;
6852
6853 /* If all tuples will be retrieved, just return the cheapest-total path */
6854 if (tuple_fraction <= 0.0)
6855 return best_path;
6856
6857 /* Convert absolute # of tuples to a fraction; no need to clamp to 0..1 */
6858 if (tuple_fraction >= 1.0 && best_path->rows > 0)
6859 tuple_fraction /= best_path->rows;
6860
6861 foreach(l, rel->pathlist)
6862 {
6863 Path *path = (Path *) lfirst(l);
6864
6865 if (path->param_info)
6866 continue;
6867
6868 if (path == rel->cheapest_total_path ||
6869 compare_fractional_path_costs(best_path, path, tuple_fraction) <= 0)
6870 continue;
6871
6872 best_path = path;
6873 }
6874
6875 return best_path;
6876}
int compare_fractional_path_costs(Path *path1, Path *path2, double fraction)
Definition pathnode.c:123

References RelOptInfo::cheapest_total_path, compare_fractional_path_costs(), fb(), lfirst, and RelOptInfo::pathlist.

Referenced by add_paths_to_append_rel(), make_subplan(), and standard_planner().

◆ get_number_of_groups()

static double get_number_of_groups ( PlannerInfo root,
double  path_rows,
grouping_sets_data gd,
List target_list 
)
static

Definition at line 3928 of file planner.c.

3932{
3933 Query *parse = root->parse;
3934 double dNumGroups;
3935
3936 if (parse->groupClause)
3937 {
3939
3940 if (parse->groupingSets)
3941 {
3942 /* Add up the estimates for each grouping set */
3943 ListCell *lc;
3944
3945 Assert(gd); /* keep Coverity happy */
3946
3947 dNumGroups = 0;
3948
3949 foreach(lc, gd->rollups)
3950 {
3952 ListCell *lc2;
3953 ListCell *lc3;
3954
3956 target_list);
3957
3958 rollup->numGroups = 0.0;
3959
3960 forboth(lc2, rollup->gsets, lc3, rollup->gsets_data)
3961 {
3962 List *gset = (List *) lfirst(lc2);
3964 double numGroups = estimate_num_groups(root,
3965 groupExprs,
3966 path_rows,
3967 &gset,
3968 NULL);
3969
3970 gs->numGroups = numGroups;
3971 rollup->numGroups += numGroups;
3972 }
3973
3974 dNumGroups += rollup->numGroups;
3975 }
3976
3977 if (gd->hash_sets_idx)
3978 {
3979 ListCell *lc2;
3980
3981 gd->dNumHashGroups = 0;
3982
3984 target_list);
3985
3986 forboth(lc, gd->hash_sets_idx, lc2, gd->unsortable_sets)
3987 {
3988 List *gset = (List *) lfirst(lc);
3990 double numGroups = estimate_num_groups(root,
3991 groupExprs,
3992 path_rows,
3993 &gset,
3994 NULL);
3995
3996 gs->numGroups = numGroups;
3997 gd->dNumHashGroups += numGroups;
3998 }
3999
4000 dNumGroups += gd->dNumHashGroups;
4001 }
4002 }
4003 else
4004 {
4005 /* Plain GROUP BY -- estimate based on optimized groupClause */
4006 groupExprs = get_sortgrouplist_exprs(root->processed_groupClause,
4007 target_list);
4008
4010 NULL, NULL);
4011 }
4012 }
4013 else if (parse->groupingSets)
4014 {
4015 /* Empty grouping sets ... one result row for each one */
4016 dNumGroups = list_length(parse->groupingSets);
4017 }
4018 else if (parse->hasAggs || root->hasHavingQual)
4019 {
4020 /* Plain aggregation, one result row */
4021 dNumGroups = 1;
4022 }
4023 else
4024 {
4025 /* Not grouping */
4026 dNumGroups = 1;
4027 }
4028
4029 return dNumGroups;
4030}

References Assert, estimate_num_groups(), fb(), forboth, get_sortgrouplist_exprs(), lfirst, lfirst_node, list_length(), parse(), and root.

Referenced by add_paths_to_grouping_rel(), and create_partial_grouping_paths().

◆ get_useful_pathkeys_for_distinct()

static List * get_useful_pathkeys_for_distinct ( PlannerInfo root,
List needed_pathkeys,
List path_pathkeys 
)
static

Definition at line 5486 of file planner.c.

5488{
5491
5492 /* always include the given 'needed_pathkeys' */
5495
5497 return useful_pathkeys_list;
5498
5499 /*
5500 * Scan the given 'path_pathkeys' and construct a list of PathKey nodes
5501 * that match 'needed_pathkeys', but only up to the longest matching
5502 * prefix.
5503 *
5504 * When we have DISTINCT ON, we must ensure that the resulting pathkey
5505 * list matches initial distinctClause pathkeys; otherwise, it won't have
5506 * the desired behavior.
5507 */
5509 {
5510 /*
5511 * The PathKey nodes are canonical, so they can be checked for
5512 * equality by simple pointer comparison.
5513 */
5515 break;
5516 if (root->parse->hasDistinctOn &&
5517 !list_member_ptr(root->distinct_pathkeys, pathkey))
5518 break;
5519
5521 }
5522
5523 /* If no match at all, no point in reordering needed_pathkeys */
5524 if (useful_pathkeys == NIL)
5525 return useful_pathkeys_list;
5526
5527 /*
5528 * If not full match, the resulting pathkey list is not useful without
5529 * incremental sort.
5530 */
5533 return useful_pathkeys_list;
5534
5535 /* Append the remaining PathKey nodes in needed_pathkeys */
5538
5539 /*
5540 * If the resulting pathkey list is the same as the 'needed_pathkeys',
5541 * just drop it.
5542 */
5545 return useful_pathkeys_list;
5546
5549
5550 return useful_pathkeys_list;
5551}
List * list_concat_unique_ptr(List *list1, const List *list2)
Definition list.c:1427
bool list_member_ptr(const List *list, const void *datum)
Definition list.c:682
bool enable_distinct_reordering
Definition planner.c:71

References compare_pathkeys(), enable_distinct_reordering, enable_incremental_sort, fb(), foreach_node, lappend(), list_concat_unique_ptr(), list_length(), list_member_ptr(), NIL, PATHKEYS_EQUAL, and root.

Referenced by create_final_distinct_paths(), and create_partial_distinct_paths().

◆ group_by_has_partkey()

static bool group_by_has_partkey ( RelOptInfo input_rel,
List targetList,
List groupClause 
)
static

Definition at line 8520 of file planner.c.

8523{
8524 List *groupexprs = get_sortgrouplist_exprs(groupClause, targetList);
8525 int cnt = 0;
8526 int partnatts;
8527
8528 /* Input relation should be partitioned. */
8529 Assert(input_rel->part_scheme);
8530
8531 /* Rule out early, if there are no partition keys present. */
8532 if (!input_rel->partexprs)
8533 return false;
8534
8535 partnatts = input_rel->part_scheme->partnatts;
8536
8537 for (cnt = 0; cnt < partnatts; cnt++)
8538 {
8539 List *partexprs = input_rel->partexprs[cnt];
8540 ListCell *lc;
8541 bool found = false;
8542
8543 foreach(lc, partexprs)
8544 {
8545 ListCell *lg;
8546 Expr *partexpr = lfirst(lc);
8547 Oid partcoll = input_rel->part_scheme->partcollation[cnt];
8548
8549 foreach(lg, groupexprs)
8550 {
8551 Expr *groupexpr = lfirst(lg);
8553
8554 /*
8555 * Note: we can assume there is at most one RelabelType node;
8556 * eval_const_expressions() will have simplified if more than
8557 * one.
8558 */
8560 groupexpr = ((RelabelType *) groupexpr)->arg;
8561
8562 if (equal(groupexpr, partexpr))
8563 {
8564 /*
8565 * Reject a match if the grouping collation does not match
8566 * the partitioning collation.
8567 */
8570 return false;
8571
8572 found = true;
8573 break;
8574 }
8575 }
8576
8577 if (found)
8578 break;
8579 }
8580
8581 /*
8582 * If none of the partition key expressions match with any of the
8583 * GROUP BY expression, return false.
8584 */
8585 if (!found)
8586 return false;
8587 }
8588
8589 return true;
8590}
Oid exprCollation(const Node *expr)
Definition nodeFuncs.c:826

References Assert, equal(), exprCollation(), fb(), get_sortgrouplist_exprs(), IsA, lfirst, and OidIsValid.

Referenced by create_ordinary_grouping_paths().

◆ group_var_eqop()

static Oid group_var_eqop ( Query parse,
Var var 
)
static

Definition at line 1640 of file planner.c.

1641{
1642 int counter = 0;
1643
1644 Assert(var->varlevelsup == 0);
1645
1646 foreach_node(SortGroupClause, sgc, parse->groupClause)
1647 {
1648 if (get_sortgroupclause_tle(sgc, parse->targetList) == NULL)
1649 continue;
1650 if (++counter == var->varattno)
1651 return sgc->eqop;
1652 }
1653
1654 elog(ERROR, "could not find GROUP clause for GROUP Var attno %d",
1655 var->varattno);
1656 return InvalidOid; /* keep compiler quiet */
1657}
AttrNumber varattno
Definition primnodes.h:275
Index varlevelsup
Definition primnodes.h:295
TargetEntry * get_sortgroupclause_tle(SortGroupClause *sgClause, List *targetList)
Definition tlist.c:376

References Assert, elog, ERROR, fb(), foreach_node, get_sortgroupclause_tle(), InvalidOid, parse(), Var::varattno, and Var::varlevelsup.

Referenced by having_var_grouping_eqop().

◆ grouping_planner()

static void grouping_planner ( PlannerInfo root,
double  tuple_fraction,
SetOperationStmt setops 
)
static

Definition at line 1704 of file planner.c.

1706{
1707 Query *parse = root->parse;
1708 int64 offset_est = 0;
1709 int64 count_est = 0;
1710 double limit_tuples = -1.0;
1711 bool have_postponed_srfs = false;
1718 FinalPathExtraData extra;
1719 ListCell *lc;
1720
1721 /* Tweak caller-supplied tuple_fraction if have LIMIT/OFFSET */
1722 if (parse->limitCount || parse->limitOffset)
1723 {
1724 tuple_fraction = preprocess_limit(root, tuple_fraction,
1725 &offset_est, &count_est);
1726
1727 /*
1728 * If we have a known LIMIT, and don't have an unknown OFFSET, we can
1729 * estimate the effects of using a bounded sort.
1730 */
1731 if (count_est > 0 && offset_est >= 0)
1732 limit_tuples = (double) count_est + (double) offset_est;
1733 }
1734
1735 /* Make tuple_fraction accessible to lower-level routines */
1736 root->tuple_fraction = tuple_fraction;
1737
1738 if (parse->setOperations)
1739 {
1740 /*
1741 * Construct Paths for set operations. The results will not need any
1742 * work except perhaps a top-level sort and/or LIMIT. Note that any
1743 * special work for recursive unions is the responsibility of
1744 * plan_set_operations.
1745 */
1747
1748 /*
1749 * We should not need to call preprocess_targetlist, since we must be
1750 * in a SELECT query node. Instead, use the processed_tlist returned
1751 * by plan_set_operations (since this tells whether it returned any
1752 * resjunk columns!), and transfer any sort key information from the
1753 * original tlist.
1754 */
1755 Assert(parse->commandType == CMD_SELECT);
1756
1757 /* for safety, copy processed_tlist instead of modifying in-place */
1758 root->processed_tlist =
1759 postprocess_setop_tlist(copyObject(root->processed_tlist),
1760 parse->targetList);
1761
1762 /* Also extract the PathTarget form of the setop result tlist */
1763 final_target = current_rel->cheapest_total_path->pathtarget;
1764
1765 /* And check whether it's parallel safe */
1768
1769 /* The setop result tlist couldn't contain any SRFs */
1770 Assert(!parse->hasTargetSRFs);
1772
1773 /*
1774 * Can't handle FOR [KEY] UPDATE/SHARE here (parser should have
1775 * checked already, but let's make sure).
1776 */
1777 if (parse->rowMarks)
1778 ereport(ERROR,
1780 /*------
1781 translator: %s is a SQL row locking clause such as FOR UPDATE */
1782 errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT",
1784 parse->rowMarks)->strength))));
1785
1786 /*
1787 * Calculate pathkeys that represent result ordering requirements
1788 */
1789 Assert(parse->distinctClause == NIL);
1790 root->sort_pathkeys = make_pathkeys_for_sortclauses(root,
1791 parse->sortClause,
1792 root->processed_tlist);
1793 }
1794 else
1795 {
1796 /* No set operations, do regular planning */
1810 bool have_grouping;
1812 List *activeWindows = NIL;
1813 grouping_sets_data *gset_data = NULL;
1815
1816 /* A recursive query should always have setOperations */
1817 Assert(!root->hasRecursion);
1818
1819 /* Preprocess grouping sets and GROUP BY clause, if any */
1820 if (parse->groupingSets)
1821 {
1822 gset_data = preprocess_grouping_sets(root);
1823 }
1824 else if (parse->groupClause)
1825 {
1826 /* Preprocess regular GROUP BY clause, if any */
1827 root->processed_groupClause = preprocess_groupclause(root, NIL);
1828 }
1829
1830 /*
1831 * Preprocess targetlist. Note that much of the remaining planning
1832 * work will be done with the PathTarget representation of tlists, but
1833 * we must also maintain the full representation of the final tlist so
1834 * that we can transfer its decoration (resnames etc) to the topmost
1835 * tlist of the finished Plan. This is kept in processed_tlist.
1836 */
1838
1839 /*
1840 * Mark all the aggregates with resolved aggtranstypes, and detect
1841 * aggregates that are duplicates or can share transition state. We
1842 * must do this before slicing and dicing the tlist into various
1843 * pathtargets, else some copies of the Aggref nodes might escape
1844 * being marked.
1845 */
1846 if (parse->hasAggs)
1847 {
1848 preprocess_aggrefs(root, (Node *) root->processed_tlist);
1849 preprocess_aggrefs(root, (Node *) parse->havingQual);
1850 }
1851
1852 /*
1853 * Locate any window functions in the tlist. (We don't need to look
1854 * anywhere else, since expressions used in ORDER BY will be in there
1855 * too.) Note that they could all have been eliminated by constant
1856 * folding, in which case we don't need to do any more work.
1857 */
1858 if (parse->hasWindowFuncs)
1859 {
1860 wflists = find_window_functions((Node *) root->processed_tlist,
1861 list_length(parse->windowClause));
1862 if (wflists->numWindowFuncs > 0)
1863 {
1864 /*
1865 * See if any modifications can be made to each WindowClause
1866 * to allow the executor to execute the WindowFuncs more
1867 * quickly.
1868 */
1870
1871 /* Extract the list of windows actually in use. */
1872 activeWindows = select_active_windows(root, wflists);
1873
1874 /* Make sure they all have names, for EXPLAIN's use. */
1875 name_active_windows(activeWindows);
1876 }
1877 else
1878 parse->hasWindowFuncs = false;
1879 }
1880
1881 /*
1882 * Preprocess MIN/MAX aggregates, if any. Note: be careful about
1883 * adding logic between here and the query_planner() call. Anything
1884 * that is needed in MIN/MAX-optimizable cases will have to be
1885 * duplicated in planagg.c.
1886 */
1887 if (parse->hasAggs)
1889
1890 /*
1891 * Figure out whether there's a hard limit on the number of rows that
1892 * query_planner's result subplan needs to return. Even if we know a
1893 * hard limit overall, it doesn't apply if the query has any
1894 * grouping/aggregation operations, or SRFs in the tlist.
1895 */
1896 if (parse->groupClause ||
1897 parse->groupingSets ||
1898 parse->distinctClause ||
1899 parse->hasAggs ||
1900 parse->hasWindowFuncs ||
1901 parse->hasTargetSRFs ||
1902 root->hasHavingQual)
1903 root->limit_tuples = -1.0;
1904 else
1905 root->limit_tuples = limit_tuples;
1906
1907 /* Set up data needed by standard_qp_callback */
1908 qp_extra.activeWindows = activeWindows;
1909 qp_extra.gset_data = gset_data;
1910
1911 /*
1912 * If we're a subquery for a set operation, store the SetOperationStmt
1913 * in qp_extra.
1914 */
1915 qp_extra.setop = setops;
1916
1917 /*
1918 * Generate the best unsorted and presorted paths for the scan/join
1919 * portion of this Query, ie the processing represented by the
1920 * FROM/WHERE clauses. (Note there may not be any presorted paths.)
1921 * We also generate (in standard_qp_callback) pathkey representations
1922 * of the query's sort clause, distinct clause, etc.
1923 */
1925
1926 /*
1927 * Convert the query's result tlist into PathTarget format.
1928 *
1929 * Note: this cannot be done before query_planner() has performed
1930 * appendrel expansion, because that might add resjunk entries to
1931 * root->processed_tlist. Waiting till afterwards is also helpful
1932 * because the target width estimates can use per-Var width numbers
1933 * that were obtained within query_planner().
1934 */
1935 final_target = create_pathtarget(root, root->processed_tlist);
1938
1939 /*
1940 * If ORDER BY was given, consider whether we should use a post-sort
1941 * projection, and compute the adjusted target for preceding steps if
1942 * so.
1943 */
1944 if (parse->sortClause)
1945 {
1951 }
1952 else
1953 {
1956 }
1957
1958 /*
1959 * If we have window functions to deal with, the output from any
1960 * grouping step needs to be what the window functions want;
1961 * otherwise, it should be sort_input_target.
1962 */
1963 if (activeWindows)
1964 {
1967 activeWindows);
1970 }
1971 else
1972 {
1975 }
1976
1977 /*
1978 * If we have grouping or aggregation to do, the topmost scan/join
1979 * plan node must emit what the grouping step wants; otherwise, it
1980 * should emit grouping_target.
1981 */
1982 have_grouping = (parse->groupClause || parse->groupingSets ||
1983 parse->hasAggs || root->hasHavingQual);
1984 if (have_grouping)
1985 {
1989 }
1990 else
1991 {
1994 }
1995
1996 /*
1997 * If there are any SRFs in the targetlist, we must separate each of
1998 * these PathTargets into SRF-computing and SRF-free targets. Replace
1999 * each of the named targets with a SRF-free version, and remember the
2000 * list of additional projection steps we need to add afterwards.
2001 */
2002 if (parse->hasTargetSRFs)
2003 {
2004 /* final_target doesn't recompute any SRFs in sort_input_target */
2010 /* likewise for sort_input_target vs. grouping_target */
2016 /* likewise for grouping_target vs. scanjoin_target */
2023 /* scanjoin_target will not have any SRFs precomputed for it */
2029 }
2030 else
2031 {
2032 /* initialize lists; for most of these, dummy values are OK */
2038 }
2039
2040 /* Apply scan/join target. */
2042 && equal(scanjoin_target->exprs, current_rel->reltarget->exprs);
2047
2048 /*
2049 * Save the various upper-rel PathTargets we just computed into
2050 * root->upper_targets[]. The core code doesn't use this, but it
2051 * provides a convenient place for extensions to get at the info. For
2052 * consistency, we save all the intermediate targets, even though some
2053 * of the corresponding upperrels might not be needed for this query.
2054 */
2055 root->upper_targets[UPPERREL_FINAL] = final_target;
2056 root->upper_targets[UPPERREL_ORDERED] = final_target;
2057 root->upper_targets[UPPERREL_DISTINCT] = sort_input_target;
2059 root->upper_targets[UPPERREL_WINDOW] = sort_input_target;
2060 root->upper_targets[UPPERREL_GROUP_AGG] = grouping_target;
2061
2062 /*
2063 * If we have grouping and/or aggregation, consider ways to implement
2064 * that. We build a new upperrel representing the output of this
2065 * phase.
2066 */
2067 if (have_grouping)
2068 {
2073 gset_data);
2074 /* Fix things up if grouping_target contains SRFs */
2075 if (parse->hasTargetSRFs)
2079 }
2080
2081 /*
2082 * If we have window functions, consider ways to implement those. We
2083 * build a new upperrel representing the output of this phase.
2084 */
2085 if (activeWindows)
2086 {
2092 wflists,
2093 activeWindows);
2094 /* Fix things up if sort_input_target contains SRFs */
2095 if (parse->hasTargetSRFs)
2099 }
2100
2101 /*
2102 * If there is a DISTINCT clause, consider ways to implement that. We
2103 * build a new upperrel representing the output of this phase.
2104 */
2105 if (parse->distinctClause)
2106 {
2110 }
2111 } /* end of if (setOperations) */
2112
2113 /*
2114 * If ORDER BY was given, consider ways to implement that, and generate a
2115 * new upperrel containing only paths that emit the correct ordering and
2116 * project the correct final_target. We can apply the original
2117 * limit_tuples limit in sort costing here, but only if there are no
2118 * postponed SRFs.
2119 */
2120 if (parse->sortClause)
2121 {
2126 have_postponed_srfs ? -1.0 :
2127 limit_tuples);
2128 /* Fix things up if final_target contains SRFs */
2129 if (parse->hasTargetSRFs)
2133 }
2134
2135 /*
2136 * Now we are prepared to build the final-output upperrel.
2137 */
2139
2140 /*
2141 * If the input rel is marked consider_parallel and there's nothing that's
2142 * not parallel-safe in the LIMIT clause, then the final_rel can be marked
2143 * consider_parallel as well. Note that if the query has rowMarks or is
2144 * not a SELECT, consider_parallel will be false for every relation in the
2145 * query.
2146 */
2147 if (current_rel->consider_parallel &&
2148 is_parallel_safe(root, parse->limitOffset) &&
2149 is_parallel_safe(root, parse->limitCount))
2150 final_rel->consider_parallel = true;
2151
2152 /*
2153 * If the current_rel belongs to a single FDW, so does the final_rel.
2154 */
2155 final_rel->serverid = current_rel->serverid;
2156 final_rel->userid = current_rel->userid;
2157 final_rel->useridiscurrent = current_rel->useridiscurrent;
2158 final_rel->fdwroutine = current_rel->fdwroutine;
2159
2160 /*
2161 * Generate paths for the final_rel. Insert all surviving paths, with
2162 * LockRows, Limit, and/or ModifyTable steps added if needed.
2163 */
2164 foreach(lc, current_rel->pathlist)
2165 {
2166 Path *path = (Path *) lfirst(lc);
2167
2168 /*
2169 * If there is a FOR [KEY] UPDATE/SHARE clause, add the LockRows node.
2170 * (Note: we intentionally test parse->rowMarks not root->rowMarks
2171 * here. If there are only non-locking rowmarks, they should be
2172 * handled by the ModifyTable node instead. However, root->rowMarks
2173 * is what goes into the LockRows node.)
2174 */
2175 if (parse->rowMarks)
2176 {
2177 path = (Path *) create_lockrows_path(root, final_rel, path,
2178 root->rowMarks,
2180 }
2181
2182 /*
2183 * If there is a LIMIT/OFFSET clause, add the LIMIT node.
2184 */
2185 if (limit_needed(parse))
2186 {
2187 path = (Path *) create_limit_path(root, final_rel, path,
2188 parse->limitOffset,
2189 parse->limitCount,
2190 parse->limitOption,
2191 offset_est, count_est);
2192 }
2193
2194 /*
2195 * If this is an INSERT/UPDATE/DELETE/MERGE, add the ModifyTable node.
2196 */
2197 if (parse->commandType != CMD_SELECT)
2198 {
2199 Index rootRelation;
2200 List *resultRelations = NIL;
2201 List *updateColnosLists = NIL;
2202 List *withCheckOptionLists = NIL;
2203 List *returningLists = NIL;
2204 List *mergeActionLists = NIL;
2205 List *mergeJoinConditions = NIL;
2206 List *rowMarks;
2207
2208 if (bms_membership(root->all_result_relids) == BMS_MULTIPLE)
2209 {
2210 /* Inherited UPDATE/DELETE/MERGE */
2212 parse->resultRelation);
2213 int resultRelation = -1;
2214
2215 /* Pass the root result rel forward to the executor. */
2216 rootRelation = parse->resultRelation;
2217
2218 /* Add only leaf children to ModifyTable. */
2219 while ((resultRelation = bms_next_member(root->leaf_result_relids,
2220 resultRelation)) >= 0)
2221 {
2223 resultRelation);
2224
2225 /*
2226 * Also exclude any leaf rels that have turned dummy since
2227 * being added to the list, for example, by being excluded
2228 * by constraint exclusion.
2229 */
2231 continue;
2232
2233 /* Build per-target-rel lists needed by ModifyTable */
2234 resultRelations = lappend_int(resultRelations,
2235 resultRelation);
2236 if (parse->commandType == CMD_UPDATE)
2237 {
2238 List *update_colnos = root->update_colnos;
2239
2241 update_colnos =
2243 update_colnos,
2244 this_result_rel->relid,
2245 top_result_rel->relid);
2246 updateColnosLists = lappend(updateColnosLists,
2247 update_colnos);
2248 }
2249 if (parse->withCheckOptions)
2250 {
2251 List *withCheckOptions = parse->withCheckOptions;
2252
2259 withCheckOptionLists = lappend(withCheckOptionLists,
2261 }
2262 if (parse->returningList)
2263 {
2264 List *returningList = parse->returningList;
2265
2267 returningList = (List *)
2269 (Node *) returningList,
2272 returningLists = lappend(returningLists,
2273 returningList);
2274 }
2275 if (parse->mergeActionList)
2276 {
2277 ListCell *l;
2278 List *mergeActionList = NIL;
2279
2280 /*
2281 * Copy MergeActions and translate stuff that
2282 * references attribute numbers.
2283 */
2284 foreach(l, parse->mergeActionList)
2285 {
2287 *leaf_action = copyObject(action);
2288
2289 leaf_action->qual =
2291 (Node *) action->qual,
2294 leaf_action->targetList = (List *)
2296 (Node *) action->targetList,
2299 if (leaf_action->commandType == CMD_UPDATE)
2300 leaf_action->updateColnos =
2302 action->updateColnos,
2303 this_result_rel->relid,
2304 top_result_rel->relid);
2305 mergeActionList = lappend(mergeActionList,
2306 leaf_action);
2307 }
2308
2309 mergeActionLists = lappend(mergeActionLists,
2310 mergeActionList);
2311 }
2312 if (parse->commandType == CMD_MERGE)
2313 {
2314 Node *mergeJoinCondition = parse->mergeJoinCondition;
2315
2317 mergeJoinCondition =
2319 mergeJoinCondition,
2322 mergeJoinConditions = lappend(mergeJoinConditions,
2323 mergeJoinCondition);
2324 }
2325 }
2326
2327 if (resultRelations == NIL)
2328 {
2329 /*
2330 * We managed to exclude every child rel, so generate a
2331 * dummy one-relation plan using info for the top target
2332 * rel (even though that may not be a leaf target).
2333 * Although it's clear that no data will be updated or
2334 * deleted, we still need to have a ModifyTable node so
2335 * that any statement triggers will be executed. (This
2336 * could be cleaner if we fixed nodeModifyTable.c to allow
2337 * zero target relations, but that probably wouldn't be a
2338 * net win.)
2339 */
2340 resultRelations = list_make1_int(parse->resultRelation);
2341 if (parse->commandType == CMD_UPDATE)
2342 updateColnosLists = list_make1(root->update_colnos);
2343 if (parse->withCheckOptions)
2344 withCheckOptionLists = list_make1(parse->withCheckOptions);
2345 if (parse->returningList)
2346 returningLists = list_make1(parse->returningList);
2347 if (parse->mergeActionList)
2348 mergeActionLists = list_make1(parse->mergeActionList);
2349 if (parse->commandType == CMD_MERGE)
2350 mergeJoinConditions = list_make1(parse->mergeJoinCondition);
2351 }
2352 }
2353 else
2354 {
2355 /* Single-relation INSERT/UPDATE/DELETE/MERGE. */
2356 rootRelation = 0; /* there's no separate root rel */
2357 resultRelations = list_make1_int(parse->resultRelation);
2358 if (parse->commandType == CMD_UPDATE)
2359 updateColnosLists = list_make1(root->update_colnos);
2360 if (parse->withCheckOptions)
2361 withCheckOptionLists = list_make1(parse->withCheckOptions);
2362 if (parse->returningList)
2363 returningLists = list_make1(parse->returningList);
2364 if (parse->mergeActionList)
2365 mergeActionLists = list_make1(parse->mergeActionList);
2366 if (parse->commandType == CMD_MERGE)
2367 mergeJoinConditions = list_make1(parse->mergeJoinCondition);
2368 }
2369
2370 /*
2371 * If there was a FOR [KEY] UPDATE/SHARE clause, the LockRows node
2372 * will have dealt with fetching non-locked marked rows, else we
2373 * need to have ModifyTable do that.
2374 */
2375 if (parse->rowMarks)
2376 rowMarks = NIL;
2377 else
2378 rowMarks = root->rowMarks;
2379
2380 path = (Path *)
2382 path,
2383 parse->commandType,
2384 parse->canSetTag,
2385 parse->resultRelation,
2386 rootRelation,
2387 resultRelations,
2388 updateColnosLists,
2389 withCheckOptionLists,
2390 returningLists,
2391 rowMarks,
2392 parse->onConflict,
2393 mergeActionLists,
2394 mergeJoinConditions,
2395 parse->forPortionOf,
2397 }
2398
2399 /* And shove it into final_rel */
2400 add_path(final_rel, path);
2401 }
2402
2403 /*
2404 * Generate partial paths for final_rel, too, if outer query levels might
2405 * be able to make use of them.
2406 */
2407 if (final_rel->consider_parallel && root->query_level > 1 &&
2408 !limit_needed(parse))
2409 {
2410 Assert(!parse->rowMarks && parse->commandType == CMD_SELECT);
2411 foreach(lc, current_rel->partial_pathlist)
2412 {
2413 Path *partial_path = (Path *) lfirst(lc);
2414
2416 }
2417 }
2418
2419 extra.limit_needed = limit_needed(parse);
2420 extra.limit_tuples = limit_tuples;
2421 extra.count_est = count_est;
2422 extra.offset_est = offset_est;
2423
2424 /*
2425 * If there is an FDW that's responsible for all baserels of the query,
2426 * let it consider adding ForeignPaths.
2427 */
2428 if (final_rel->fdwroutine &&
2429 final_rel->fdwroutine->GetForeignUpperPaths)
2430 final_rel->fdwroutine->GetForeignUpperPaths(root, UPPERREL_FINAL,
2432 &extra);
2433
2434 /* Let extensions possibly add some more paths */
2436 (*create_upper_paths_hook) (root, UPPERREL_FINAL,
2437 current_rel, final_rel, &extra);
2438
2439 /* Note: currently, we leave it to callers to do set_cheapest() */
2440}
List * adjust_inherited_attnums_multilevel(PlannerInfo *root, List *attnums, Index child_relid, Index top_parent_relid)
Definition appendinfo.c:738
BMS_Membership bms_membership(const Bitmapset *a)
Definition bitmapset.c:765
@ BMS_MULTIPLE
Definition bitmapset.h:73
unsigned int Index
Definition c.h:757
WindowFuncLists * find_window_functions(Node *clause, Index maxWinRef)
Definition clauses.c:260
List * lappend_int(List *list, int datum)
Definition list.c:357
@ CMD_MERGE
Definition nodes.h:277
@ CMD_UPDATE
Definition nodes.h:274
@ CMD_SELECT
Definition nodes.h:273
int assign_special_exec_param(PlannerInfo *root)
const char * LCS_asString(LockClauseStrength strength)
Definition analyze.c:3717
LockRowsPath * create_lockrows_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *rowMarks, int epqParam)
Definition pathnode.c:3630
ModifyTablePath * create_modifytable_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, CmdType operation, bool canSetTag, Index nominalRelation, Index rootRelation, List *resultRelations, List *updateColnosLists, List *withCheckOptionLists, List *returningLists, List *rowMarks, OnConflictExpr *onconflict, List *mergeActionLists, List *mergeJoinConditions, ForPortionOfExpr *forPortionOf, int epqParam)
Definition pathnode.c:3692
@ UPPERREL_FINAL
Definition pathnodes.h:152
#define list_make1_int(x1)
Definition pg_list.h:259
void preprocess_minmax_aggregates(PlannerInfo *root)
Definition planagg.c:74
RelOptInfo * query_planner(PlannerInfo *root, query_pathkeys_callback qp_callback, void *qp_extra)
Definition planmain.c:54
static List * postprocess_setop_tlist(List *new_tlist, List *orig_tlist)
Definition planner.c:6044
static double preprocess_limit(PlannerInfo *root, double tuple_fraction, int64 *offset_est, int64 *count_est)
Definition planner.c:2847
static PathTarget * make_window_input_target(PlannerInfo *root, PathTarget *final_target, List *activeWindows)
Definition planner.c:6424
static RelOptInfo * create_distinct_paths(PlannerInfo *root, RelOptInfo *input_rel, PathTarget *target)
Definition planner.c:5053
static void optimize_window_clauses(PlannerInfo *root, WindowFuncLists *wflists)
Definition planner.c:6081
static void name_active_windows(List *activeWindows)
Definition planner.c:6304
static PathTarget * make_sort_input_target(PlannerInfo *root, PathTarget *final_target, bool *have_postponed_srfs)
Definition planner.c:6672
static grouping_sets_data * preprocess_grouping_sets(PlannerInfo *root)
Definition planner.c:2452
static PathTarget * make_group_input_target(PlannerInfo *root, PathTarget *final_target)
Definition planner.c:5794
static List * select_active_windows(PlannerInfo *root, WindowFuncLists *wflists)
Definition planner.c:6221
bool limit_needed(Query *parse)
Definition planner.c:3032
static RelOptInfo * create_ordered_paths(PlannerInfo *root, RelOptInfo *input_rel, PathTarget *target, bool target_parallel_safe, double limit_tuples)
Definition planner.c:5571
static RelOptInfo * create_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel, PathTarget *target, bool target_parallel_safe, grouping_sets_data *gd)
Definition planner.c:4050
static void standard_qp_callback(PlannerInfo *root, void *extra)
Definition planner.c:3723
static RelOptInfo * create_window_paths(PlannerInfo *root, RelOptInfo *input_rel, PathTarget *input_target, PathTarget *output_target, bool output_target_parallel_safe, WindowFuncLists *wflists, List *activeWindows)
Definition planner.c:4796
void preprocess_aggrefs(PlannerInfo *root, Node *clause)
Definition prepagg.c:110
void preprocess_targetlist(PlannerInfo *root)
Definition preptlist.c:66
RelOptInfo * plan_set_operations(PlannerInfo *root)
Definition prepunion.c:98
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition relnode.c:544
Cardinality limit_tuples
Definition pathnodes.h:3707
void split_pathtarget_at_srfs_grouping(PlannerInfo *root, PathTarget *target, PathTarget *input_target, List **targets, List **targets_contain_srfs)
Definition tlist.c:868
void split_pathtarget_at_srfs(PlannerInfo *root, PathTarget *target, PathTarget *input_target, List **targets, List **targets_contain_srfs)
Definition tlist.c:845

References add_partial_path(), add_path(), adjust_appendrel_attrs_multilevel(), adjust_inherited_attnums_multilevel(), adjust_paths_for_srfs(), apply_scanjoin_target_to_paths(), Assert, assign_special_exec_param(), bms_membership(), BMS_MULTIPLE, bms_next_member(), CMD_MERGE, CMD_SELECT, CMD_UPDATE, copyObject, FinalPathExtraData::count_est, create_distinct_paths(), create_grouping_paths(), create_limit_path(), create_lockrows_path(), create_modifytable_path(), create_ordered_paths(), create_pathtarget, create_upper_paths_hook, create_window_paths(), equal(), ereport, errcode(), errmsg, ERROR, fb(), fetch_upper_rel(), find_base_rel(), find_window_functions(), IS_DUMMY_REL, is_parallel_safe(), lappend(), lappend_int(), LCS_asString(), lfirst, limit_needed(), FinalPathExtraData::limit_needed, FinalPathExtraData::limit_tuples, linitial_int, linitial_node, list_length(), list_make1, list_make1_int, make_group_input_target(), make_pathkeys_for_sortclauses(), make_sort_input_target(), make_window_input_target(), name_active_windows(), NIL, FinalPathExtraData::offset_est, optimize_window_clauses(), parse(), plan_set_operations(), postprocess_setop_tlist(), preprocess_aggrefs(), preprocess_groupclause(), preprocess_grouping_sets(), preprocess_limit(), preprocess_minmax_aggregates(), preprocess_targetlist(), query_planner(), root, select_active_windows(), split_pathtarget_at_srfs(), split_pathtarget_at_srfs_grouping(), standard_qp_callback(), UPPERREL_DISTINCT, UPPERREL_FINAL, UPPERREL_GROUP_AGG, UPPERREL_ORDERED, UPPERREL_PARTIAL_DISTINCT, and UPPERREL_WINDOW.

Referenced by subquery_planner().

◆ has_volatile_pathkey()

static bool has_volatile_pathkey ( List keys)
static

Definition at line 3454 of file planner.c.

3455{
3456 ListCell *lc;
3457
3458 foreach(lc, keys)
3459 {
3461
3462 if (pathkey->pk_eclass->ec_has_volatile)
3463 return true;
3464 }
3465
3466 return false;
3467}

References fb(), and lfirst_node.

Referenced by adjust_group_pathkeys_for_groupagg().

◆ having_var_grouping_eqop()

static Oid having_var_grouping_eqop ( Var var,
void context 
)
static

Definition at line 1619 of file planner.c.

1620{
1621 having_grouping_ctx *ctx = (having_grouping_ctx *) context;
1622
1623 if (var->varno != ctx->group_rtindex || var->varlevelsup != 0)
1624 return InvalidOid;
1625
1626 return group_var_eqop(ctx->parse, var);
1627}
static Oid group_var_eqop(Query *parse, Var *var)
Definition planner.c:1640
int varno
Definition primnodes.h:270

References having_grouping_ctx::group_rtindex, group_var_eqop(), InvalidOid, having_grouping_ctx::parse, Var::varlevelsup, and Var::varno.

Referenced by find_having_conflicts().

◆ is_degenerate_grouping()

static bool is_degenerate_grouping ( PlannerInfo root)
static

Definition at line 4219 of file planner.c.

4220{
4221 Query *parse = root->parse;
4222
4223 return (root->hasHavingQual || parse->groupingSets) &&
4224 !parse->hasAggs && parse->groupClause == NIL;
4225}

References NIL, parse(), and root.

Referenced by create_grouping_paths().

◆ limit_needed()

bool limit_needed ( Query parse)

Definition at line 3032 of file planner.c.

3033{
3034 Node *node;
3035
3036 node = parse->limitCount;
3037 if (node)
3038 {
3039 if (IsA(node, Const))
3040 {
3041 /* NULL indicates LIMIT ALL, ie, no limit */
3042 if (!((Const *) node)->constisnull)
3043 return true; /* LIMIT with a constant value */
3044 }
3045 else
3046 return true; /* non-constant LIMIT */
3047 }
3048
3049 node = parse->limitOffset;
3050 if (node)
3051 {
3052 if (IsA(node, Const))
3053 {
3054 /* Treat NULL as no offset; the executor would too */
3055 if (!((Const *) node)->constisnull)
3056 {
3057 int64 offset = DatumGetInt64(((Const *) node)->constvalue);
3058
3059 if (offset != 0)
3060 return true; /* OFFSET with a nonzero value */
3061 }
3062 }
3063 else
3064 return true; /* non-constant OFFSET */
3065 }
3066
3067 return false; /* don't need a Limit plan node */
3068}
static int64 DatumGetInt64(Datum X)
Definition postgres.h:416

References DatumGetInt64(), fb(), IsA, and parse().

Referenced by grouping_planner(), and set_rel_consider_parallel().

◆ make_group_input_target()

static PathTarget * make_group_input_target ( PlannerInfo root,
PathTarget final_target 
)
static

Definition at line 5794 of file planner.c.

5795{
5796 Query *parse = root->parse;
5800 int i;
5801 ListCell *lc;
5802
5803 /*
5804 * We must build a target containing all grouping columns, plus any other
5805 * Vars mentioned in the query's targetlist and HAVING qual.
5806 */
5809
5810 i = 0;
5811 foreach(lc, final_target->exprs)
5812 {
5813 Expr *expr = (Expr *) lfirst(lc);
5815
5816 if (sgref && root->processed_groupClause &&
5818 root->processed_groupClause) != NULL)
5819 {
5820 /*
5821 * It's a grouping column, so add it to the input target as-is.
5822 *
5823 * Note that the target is logically below the grouping step. So
5824 * with grouping sets we need to remove the RT index of the
5825 * grouping step if there is any from the target expression.
5826 */
5827 if (parse->hasGroupRTE && parse->groupingSets != NIL)
5828 {
5829 Assert(root->group_rtindex > 0);
5830 expr = (Expr *)
5831 remove_nulling_relids((Node *) expr,
5832 bms_make_singleton(root->group_rtindex),
5833 NULL);
5834 }
5836 }
5837 else
5838 {
5839 /*
5840 * Non-grouping column, so just remember the expression for later
5841 * call to pull_var_clause.
5842 */
5844 }
5845
5846 i++;
5847 }
5848
5849 /*
5850 * If there's a HAVING clause, we'll need the Vars it uses, too.
5851 */
5852 if (parse->havingQual)
5854
5855 /*
5856 * Pull out all the Vars mentioned in non-group cols (plus HAVING), and
5857 * add them to the input target if not already present. (A Var used
5858 * directly as a GROUP BY item will be present already.) Note this
5859 * includes Vars used in resjunk items, so we are covering the needs of
5860 * ORDER BY and window specifications. Vars used within Aggrefs and
5861 * WindowFuncs will be pulled out here, too.
5862 *
5863 * Note that the target is logically below the grouping step. So with
5864 * grouping sets we need to remove the RT index of the grouping step if
5865 * there is any from the non-group Vars.
5866 */
5871 if (parse->hasGroupRTE && parse->groupingSets != NIL)
5872 {
5873 Assert(root->group_rtindex > 0);
5874 non_group_vars = (List *)
5876 bms_make_singleton(root->group_rtindex),
5877 NULL);
5878 }
5880
5881 /* clean up cruft */
5884
5885 /* XXX this causes some redundant cost calculation ... */
5887}
Bitmapset * bms_make_singleton(int x)
Definition bitmapset.c:216
PathTarget * set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target)
Definition costsize.c:6511
void list_free(List *list)
Definition list.c:1546
#define PVC_RECURSE_AGGREGATES
Definition optimizer.h:198
#define PVC_RECURSE_WINDOWFUNCS
Definition optimizer.h:200
#define PVC_INCLUDE_PLACEHOLDERS
Definition optimizer.h:201
#define get_pathtarget_sortgroupref(target, colno)
Definition pathnodes.h:1894
Node * remove_nulling_relids(Node *node, const Bitmapset *removable_relids, const Bitmapset *except_relids)
SortGroupClause * get_sortgroupref_clause_noerr(Index sortref, List *clauses)
Definition tlist.c:452
void add_new_columns_to_pathtarget(PathTarget *target, List *exprs)
Definition tlist.c:761
PathTarget * create_empty_pathtarget(void)
Definition tlist.c:690
List * pull_var_clause(Node *node, int flags)
Definition var.c:653

References add_column_to_pathtarget(), add_new_columns_to_pathtarget(), Assert, bms_make_singleton(), create_empty_pathtarget(), fb(), get_pathtarget_sortgroupref, get_sortgroupref_clause_noerr(), i, lappend(), lfirst, list_free(), NIL, parse(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, remove_nulling_relids(), root, and set_pathtarget_cost_width().

Referenced by grouping_planner().

◆ make_grouping_rel()

static RelOptInfo * make_grouping_rel ( PlannerInfo root,
RelOptInfo input_rel,
PathTarget target,
bool  target_parallel_safe,
Node havingQual 
)
static

Definition at line 4163 of file planner.c.

4166{
4167 RelOptInfo *grouped_rel;
4168
4170 {
4172 input_rel->relids);
4173 grouped_rel->reloptkind = RELOPT_OTHER_UPPER_REL;
4174 }
4175 else
4176 {
4177 /*
4178 * By tradition, the relids set for the main grouping relation is
4179 * NULL. (This could be changed, but might require adjustments
4180 * elsewhere.)
4181 */
4183 }
4184
4185 /* Set target. */
4186 grouped_rel->reltarget = target;
4187
4188 /*
4189 * If the input relation is not parallel-safe, then the grouped relation
4190 * can't be parallel-safe, either. Otherwise, it's parallel-safe if the
4191 * target list and HAVING quals are parallel-safe.
4192 */
4193 if (input_rel->consider_parallel && target_parallel_safe &&
4194 is_parallel_safe(root, havingQual))
4195 grouped_rel->consider_parallel = true;
4196
4197 /* Assume that the same path generation strategies are allowed */
4198 grouped_rel->pgs_mask = input_rel->pgs_mask;
4199
4200 /*
4201 * If the input rel belongs to a single FDW, so does the grouped rel.
4202 */
4203 grouped_rel->serverid = input_rel->serverid;
4204 grouped_rel->userid = input_rel->userid;
4205 grouped_rel->useridiscurrent = input_rel->useridiscurrent;
4206 grouped_rel->fdwroutine = input_rel->fdwroutine;
4207
4208 return grouped_rel;
4209}
@ RELOPT_OTHER_UPPER_REL
Definition pathnodes.h:982

References RelOptInfo::consider_parallel, fb(), fetch_upper_rel(), IS_OTHER_REL, is_parallel_safe(), RelOptInfo::pgs_mask, RELOPT_OTHER_UPPER_REL, RelOptInfo::reloptkind, RelOptInfo::reltarget, root, RelOptInfo::serverid, UPPERREL_GROUP_AGG, RelOptInfo::userid, and RelOptInfo::useridiscurrent.

Referenced by create_grouping_paths(), and create_partitionwise_grouping_paths().

◆ make_ordered_path()

static Path * make_ordered_path ( PlannerInfo root,
RelOptInfo rel,
Path path,
Path cheapest_path,
List pathkeys,
double  limit_tuples 
)
static

Definition at line 7958 of file planner.c.

7960{
7961 bool is_sorted;
7962 int presorted_keys;
7963
7965 path->pathkeys,
7966 &presorted_keys);
7967
7968 if (!is_sorted)
7969 {
7970 /*
7971 * Try at least sorting the cheapest path and also try incrementally
7972 * sorting any path which is partially sorted already (no need to deal
7973 * with paths which have presorted keys when incremental sort is
7974 * disabled unless it's the cheapest input path).
7975 */
7976 if (path != cheapest_path &&
7977 (presorted_keys == 0 || !enable_incremental_sort))
7978 return NULL;
7979
7980 /*
7981 * We've no need to consider both a sort and incremental sort. We'll
7982 * just do a sort if there are no presorted keys and an incremental
7983 * sort when there are presorted keys.
7984 */
7985 if (presorted_keys == 0 || !enable_incremental_sort)
7986 path = (Path *) create_sort_path(root,
7987 rel,
7988 path,
7989 pathkeys,
7990 limit_tuples);
7991 else
7993 rel,
7994 path,
7995 pathkeys,
7996 presorted_keys,
7997 limit_tuples);
7998 }
7999
8000 return path;
8001}

References create_incremental_sort_path(), create_sort_path(), enable_incremental_sort, fb(), Path::pathkeys, pathkeys_count_contained_in(), and root.

Referenced by add_paths_to_grouping_rel(), create_final_distinct_paths(), create_partial_distinct_paths(), and create_partial_grouping_paths().

◆ make_partial_grouping_target()

static PathTarget * make_partial_grouping_target ( PlannerInfo root,
PathTarget grouping_target,
Node havingQual 
)
static

Definition at line 5906 of file planner.c.

5909{
5913 int i;
5914 ListCell *lc;
5915
5918
5919 i = 0;
5920 foreach(lc, grouping_target->exprs)
5921 {
5922 Expr *expr = (Expr *) lfirst(lc);
5924
5925 if (sgref && root->processed_groupClause &&
5927 root->processed_groupClause) != NULL)
5928 {
5929 /*
5930 * It's a grouping column, so add it to the partial_target as-is.
5931 * (This allows the upper agg step to repeat the grouping calcs.)
5932 */
5934 }
5935 else
5936 {
5937 /*
5938 * Non-grouping column, so just remember the expression for later
5939 * call to pull_var_clause.
5940 */
5942 }
5943
5944 i++;
5945 }
5946
5947 /*
5948 * If there's a HAVING clause, we'll need the Vars/Aggrefs it uses, too.
5949 */
5950 if (havingQual)
5951 non_group_cols = lappend(non_group_cols, havingQual);
5952
5953 /*
5954 * Pull out all the Vars, PlaceHolderVars, and Aggrefs mentioned in
5955 * non-group cols (plus HAVING), and add them to the partial_target if not
5956 * already present. (An expression used directly as a GROUP BY item will
5957 * be present already.) Note this includes Vars used in resjunk items, so
5958 * we are covering the needs of ORDER BY and window specifications.
5959 */
5964
5966
5967 /*
5968 * Adjust Aggrefs to put them in partial mode. At this point all Aggrefs
5969 * are at the top level of the target list, so we can just scan the list
5970 * rather than recursing through the expression trees.
5971 */
5972 foreach(lc, partial_target->exprs)
5973 {
5974 Aggref *aggref = (Aggref *) lfirst(lc);
5975
5976 if (IsA(aggref, Aggref))
5977 {
5979
5980 /*
5981 * We shouldn't need to copy the substructure of the Aggref node,
5982 * but flat-copy the node itself to avoid damaging other trees.
5983 */
5985 memcpy(newaggref, aggref, sizeof(Aggref));
5986
5987 /* For now, assume serialization is required */
5989
5990 lfirst(lc) = newaggref;
5991 }
5992 }
5993
5994 /* clean up cruft */
5997
5998 /* XXX this causes some redundant cost calculation ... */
6000}
#define PVC_INCLUDE_AGGREGATES
Definition optimizer.h:197
void mark_partial_aggref(Aggref *agg, AggSplit aggsplit)
Definition planner.c:6009

References add_column_to_pathtarget(), add_new_columns_to_pathtarget(), AGGSPLIT_INITIAL_SERIAL, create_empty_pathtarget(), fb(), get_pathtarget_sortgroupref, get_sortgroupref_clause_noerr(), i, IsA, lappend(), lfirst, list_free(), makeNode, mark_partial_aggref(), memcpy(), NIL, pull_var_clause(), PVC_INCLUDE_AGGREGATES, PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_WINDOWFUNCS, root, and set_pathtarget_cost_width().

Referenced by create_partial_grouping_paths().

◆ make_pathkeys_for_window()

static List * make_pathkeys_for_window ( PlannerInfo root,
WindowClause wc,
List tlist 
)
static

Definition at line 6544 of file planner.c.

6546{
6547 List *window_pathkeys = NIL;
6548
6549 /* Throw error if can't sort */
6551 ereport(ERROR,
6553 errmsg("could not implement window PARTITION BY"),
6554 errdetail("Window partitioning columns must be of sortable datatypes.")));
6556 ereport(ERROR,
6558 errmsg("could not implement window ORDER BY"),
6559 errdetail("Window ordering columns must be of sortable datatypes.")));
6560
6561 /*
6562 * First fetch the pathkeys for the PARTITION BY clause. We can safely
6563 * remove any clauses from the wc->partitionClause for redundant pathkeys.
6564 */
6565 if (wc->partitionClause != NIL)
6566 {
6567 bool sortable;
6568
6570 &wc->partitionClause,
6571 tlist,
6572 true,
6573 false,
6574 &sortable,
6575 false);
6576
6578 }
6579
6580 /*
6581 * In principle, we could also consider removing redundant ORDER BY items
6582 * too as doing so does not alter the result of peer row checks done by
6583 * the executor. However, we must *not* remove the ordering column for
6584 * RANGE OFFSET cases, as the executor needs that for in_range tests even
6585 * if it's known to be equal to some partitioning column.
6586 */
6587 if (wc->orderClause != NIL)
6588 {
6590
6592 wc->orderClause,
6593 tlist);
6594
6595 /* Okay, make the combined pathkeys */
6596 if (window_pathkeys != NIL)
6597 window_pathkeys = append_pathkeys(window_pathkeys, orderby_pathkeys);
6598 else
6599 window_pathkeys = orderby_pathkeys;
6600 }
6601
6602 return window_pathkeys;
6603}
List * make_pathkeys_for_sortclauses_extended(PlannerInfo *root, List **sortclauses, List *tlist, bool remove_redundant, bool remove_group_rtindex, bool *sortable, bool set_ec_sortref)
Definition pathkeys.c:1381
List * partitionClause
List * orderClause

References append_pathkeys(), Assert, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), grouping_is_sortable(), make_pathkeys_for_sortclauses(), make_pathkeys_for_sortclauses_extended(), NIL, WindowClause::orderClause, WindowClause::partitionClause, and root.

Referenced by create_one_window_path(), and standard_qp_callback().

◆ make_sort_input_target()

static PathTarget * make_sort_input_target ( PlannerInfo root,
PathTarget final_target,
bool have_postponed_srfs 
)
static

Definition at line 6672 of file planner.c.

6675{
6676 Query *parse = root->parse;
6678 int ncols;
6679 bool *col_is_srf;
6680 bool *postpone_col;
6681 bool have_srf;
6682 bool have_volatile;
6683 bool have_expensive;
6684 bool have_srf_sortcols;
6685 bool postpone_srfs;
6688 int i;
6689 ListCell *lc;
6690
6691 /* Shouldn't get here unless query has ORDER BY */
6692 Assert(parse->sortClause);
6693
6694 *have_postponed_srfs = false; /* default result */
6695
6696 /* Inspect tlist and collect per-column information */
6697 ncols = list_length(final_target->exprs);
6698 col_is_srf = (bool *) palloc0(ncols * sizeof(bool));
6699 postpone_col = (bool *) palloc0(ncols * sizeof(bool));
6701
6702 i = 0;
6703 foreach(lc, final_target->exprs)
6704 {
6705 Expr *expr = (Expr *) lfirst(lc);
6706
6707 /*
6708 * If the column has a sortgroupref, assume it has to be evaluated
6709 * before sorting. Generally such columns would be ORDER BY, GROUP
6710 * BY, etc targets. One exception is columns that were removed from
6711 * GROUP BY by remove_useless_groupby_columns() ... but those would
6712 * only be Vars anyway. There don't seem to be any cases where it
6713 * would be worth the trouble to double-check.
6714 */
6716 {
6717 /*
6718 * Check for SRF or volatile functions. Check the SRF case first
6719 * because we must know whether we have any postponed SRFs.
6720 */
6721 if (parse->hasTargetSRFs &&
6722 expression_returns_set((Node *) expr))
6723 {
6724 /* We'll decide below whether these are postponable */
6725 col_is_srf[i] = true;
6726 have_srf = true;
6727 }
6728 else if (contain_volatile_functions((Node *) expr))
6729 {
6730 /* Unconditionally postpone */
6731 postpone_col[i] = true;
6732 have_volatile = true;
6733 }
6734 else
6735 {
6736 /*
6737 * Else check the cost. XXX it's annoying to have to do this
6738 * when set_pathtarget_cost_width() just did it. Refactor to
6739 * allow sharing the work?
6740 */
6741 QualCost cost;
6742
6743 cost_qual_eval_node(&cost, (Node *) expr, root);
6744
6745 /*
6746 * We arbitrarily define "expensive" as "more than 10X
6747 * cpu_operator_cost". Note this will take in any PL function
6748 * with default cost.
6749 */
6750 if (cost.per_tuple > 10 * cpu_operator_cost)
6751 {
6752 postpone_col[i] = true;
6753 have_expensive = true;
6754 }
6755 }
6756 }
6757 else
6758 {
6759 /* For sortgroupref cols, just check if any contain SRFs */
6760 if (!have_srf_sortcols &&
6761 parse->hasTargetSRFs &&
6762 expression_returns_set((Node *) expr))
6763 have_srf_sortcols = true;
6764 }
6765
6766 i++;
6767 }
6768
6769 /*
6770 * We can postpone SRFs if we have some but none are in sortgroupref cols.
6771 */
6773
6774 /*
6775 * If we don't need a post-sort projection, just return final_target.
6776 */
6777 if (!(postpone_srfs || have_volatile ||
6778 (have_expensive &&
6779 (parse->limitCount || root->tuple_fraction > 0))))
6780 return final_target;
6781
6782 /*
6783 * Report whether the post-sort projection will contain set-returning
6784 * functions. This is important because it affects whether the Sort can
6785 * rely on the query's LIMIT (if any) to bound the number of rows it needs
6786 * to return.
6787 */
6789
6790 /*
6791 * Construct the sort-input target, taking all non-postponable columns and
6792 * then adding Vars, PlaceHolderVars, Aggrefs, and WindowFuncs found in
6793 * the postponable ones.
6794 */
6797
6798 i = 0;
6799 foreach(lc, final_target->exprs)
6800 {
6801 Expr *expr = (Expr *) lfirst(lc);
6802
6803 if (postpone_col[i] || (postpone_srfs && col_is_srf[i]))
6805 else
6808
6809 i++;
6810 }
6811
6812 /*
6813 * Pull out all the Vars, Aggrefs, and WindowFuncs mentioned in
6814 * postponable columns, and add them to the sort-input target if not
6815 * already present. (Some might be there already.) We mustn't
6816 * deconstruct Aggrefs or WindowFuncs here, since the projection node
6817 * would be unable to recompute them.
6818 */
6824
6825 /* clean up cruft */
6828
6829 /* XXX this represents even more redundant cost calculation ... */
6831}
bool contain_volatile_functions(Node *clause)
Definition clauses.c:567
double cpu_operator_cost
Definition costsize.c:135
void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
Definition costsize.c:4926
bool expression_returns_set(Node *clause)
Definition nodeFuncs.c:768
#define PVC_INCLUDE_WINDOWFUNCS
Definition optimizer.h:199
Cost per_tuple
Definition pathnodes.h:121

References add_column_to_pathtarget(), add_new_columns_to_pathtarget(), Assert, contain_volatile_functions(), cost_qual_eval_node(), cpu_operator_cost, create_empty_pathtarget(), expression_returns_set(), fb(), get_pathtarget_sortgroupref, i, lappend(), lfirst, list_free(), list_length(), NIL, palloc0(), parse(), QualCost::per_tuple, pull_var_clause(), PVC_INCLUDE_AGGREGATES, PVC_INCLUDE_PLACEHOLDERS, PVC_INCLUDE_WINDOWFUNCS, root, and set_pathtarget_cost_width().

Referenced by grouping_planner().

◆ make_window_input_target()

static PathTarget * make_window_input_target ( PlannerInfo root,
PathTarget final_target,
List activeWindows 
)
static

Definition at line 6424 of file planner.c.

6427{
6432 int i;
6433 ListCell *lc;
6434
6435 Assert(root->parse->hasWindowFuncs);
6436
6437 /*
6438 * Collect the sortgroupref numbers of window PARTITION/ORDER BY clauses
6439 * into a bitmapset for convenient reference below.
6440 */
6441 sgrefs = NULL;
6442 foreach(lc, activeWindows)
6443 {
6445 ListCell *lc2;
6446
6447 foreach(lc2, wc->partitionClause)
6448 {
6450
6451 sgrefs = bms_add_member(sgrefs, sortcl->tleSortGroupRef);
6452 }
6453 foreach(lc2, wc->orderClause)
6454 {
6456
6457 sgrefs = bms_add_member(sgrefs, sortcl->tleSortGroupRef);
6458 }
6459 }
6460
6461 /* Add in sortgroupref numbers of GROUP BY clauses, too */
6462 foreach(lc, root->processed_groupClause)
6463 {
6465
6466 sgrefs = bms_add_member(sgrefs, grpcl->tleSortGroupRef);
6467 }
6468
6469 /*
6470 * Construct a target containing all the non-flattenable targetlist items,
6471 * and save aside the others for a moment.
6472 */
6475
6476 i = 0;
6477 foreach(lc, final_target->exprs)
6478 {
6479 Expr *expr = (Expr *) lfirst(lc);
6481
6482 /*
6483 * Don't want to deconstruct window clauses or GROUP BY items. (Note
6484 * that such items can't contain window functions, so it's okay to
6485 * compute them below the WindowAgg nodes.)
6486 */
6487 if (sgref != 0 && bms_is_member(sgref, sgrefs))
6488 {
6489 /*
6490 * Don't want to deconstruct this value, so add it to the input
6491 * target as-is.
6492 */
6494 }
6495 else
6496 {
6497 /*
6498 * Column is to be flattened, so just remember the expression for
6499 * later call to pull_var_clause.
6500 */
6502 }
6503
6504 i++;
6505 }
6506
6507 /*
6508 * Pull out all the Vars and Aggrefs mentioned in flattenable columns, and
6509 * add them to the input target if not already present. (Some might be
6510 * there already because they're used directly as window/group clauses.)
6511 *
6512 * Note: it's essential to use PVC_INCLUDE_AGGREGATES here, so that any
6513 * Aggrefs are placed in the Agg node's tlist and not left to be computed
6514 * at higher levels. On the other hand, we should recurse into
6515 * WindowFuncs to make sure their input expressions are available.
6516 */
6522
6523 /* clean up cruft */
6526
6527 /* XXX this causes some redundant cost calculation ... */
6529}

References add_column_to_pathtarget(), add_new_columns_to_pathtarget(), Assert, bms_add_member(), bms_is_member(), create_empty_pathtarget(), fb(), get_pathtarget_sortgroupref, i, lappend(), lfirst, lfirst_node, list_free(), NIL, WindowClause::orderClause, WindowClause::partitionClause, pull_var_clause(), PVC_INCLUDE_AGGREGATES, PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_WINDOWFUNCS, root, and set_pathtarget_cost_width().

Referenced by grouping_planner().

◆ mark_partial_aggref()

void mark_partial_aggref ( Aggref agg,
AggSplit  aggsplit 
)

Definition at line 6009 of file planner.c.

6010{
6011 /* aggtranstype should be computed by this point */
6012 Assert(OidIsValid(agg->aggtranstype));
6013 /* ... but aggsplit should still be as the parser left it */
6014 Assert(agg->aggsplit == AGGSPLIT_SIMPLE);
6015
6016 /* Mark the Aggref with the intended partial-aggregation mode */
6017 agg->aggsplit = aggsplit;
6018
6019 /*
6020 * Adjust result type if needed. Normally, a partial aggregate returns
6021 * the aggregate's transition type; but if that's INTERNAL and we're
6022 * serializing, it returns BYTEA instead.
6023 */
6024 if (DO_AGGSPLIT_SKIPFINAL(aggsplit))
6025 {
6026 if (agg->aggtranstype == INTERNALOID && DO_AGGSPLIT_SERIALIZE(aggsplit))
6027 agg->aggtype = BYTEAOID;
6028 else
6029 agg->aggtype = agg->aggtranstype;
6030 }
6031}
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition nodes.h:394
#define DO_AGGSPLIT_SERIALIZE(as)
Definition nodes.h:395

References AGGSPLIT_SIMPLE, Assert, DO_AGGSPLIT_SERIALIZE, DO_AGGSPLIT_SKIPFINAL, fb(), and OidIsValid.

Referenced by convert_combining_aggrefs(), create_rel_agg_info(), and make_partial_grouping_target().

◆ name_active_windows()

static void name_active_windows ( List activeWindows)
static

Definition at line 6304 of file planner.c.

6305{
6306 int next_n = 1;
6307 char newname[16];
6308 ListCell *lc;
6309
6310 foreach(lc, activeWindows)
6311 {
6313
6314 /* Nothing to do if it has a name already. */
6315 if (wc->name)
6316 continue;
6317
6318 /* Select a name not currently present in the list. */
6319 for (;;)
6320 {
6321 ListCell *lc2;
6322
6323 snprintf(newname, sizeof(newname), "w%d", next_n++);
6324 foreach(lc2, activeWindows)
6325 {
6327
6328 if (wc2->name && strcmp(wc2->name, newname) == 0)
6329 break; /* matched */
6330 }
6331 if (lc2 == NULL)
6332 break; /* reached the end with no match */
6333 }
6334 wc->name = pstrdup(newname);
6335 }
6336}
#define snprintf
Definition port.h:261

References fb(), lfirst_node, pstrdup(), and snprintf.

Referenced by grouping_planner().

◆ optimize_window_clauses()

static void optimize_window_clauses ( PlannerInfo root,
WindowFuncLists wflists 
)
static

Definition at line 6081 of file planner.c.

6082{
6083 List *windowClause = root->parse->windowClause;
6084 ListCell *lc;
6085
6086 foreach(lc, windowClause)
6087 {
6089 ListCell *lc2;
6090 int optimizedFrameOptions = 0;
6091
6092 Assert(wc->winref <= wflists->maxWinRef);
6093
6094 /* skip any WindowClauses that have no WindowFuncs */
6095 if (wflists->windowFuncs[wc->winref] == NIL)
6096 continue;
6097
6098 foreach(lc2, wflists->windowFuncs[wc->winref])
6099 {
6104
6106
6107 /* Check if there's a support function for 'wfunc' */
6108 if (!OidIsValid(prosupport))
6109 break; /* can't optimize this WindowClause */
6110
6112 req.window_clause = wc;
6113 req.window_func = wfunc;
6114 req.frameOptions = wc->frameOptions;
6115
6116 /* call the support function */
6119 PointerGetDatum(&req)));
6120
6121 /*
6122 * Skip to next WindowClause if the support function does not
6123 * support this request type.
6124 */
6125 if (res == NULL)
6126 break;
6127
6128 /*
6129 * Save these frameOptions for the first WindowFunc for this
6130 * WindowClause.
6131 */
6132 if (foreach_current_index(lc2) == 0)
6134
6135 /*
6136 * On subsequent WindowFuncs, if the frameOptions are not the same
6137 * then we're unable to optimize the frameOptions for this
6138 * WindowClause.
6139 */
6140 else if (optimizedFrameOptions != res->frameOptions)
6141 break; /* skip to the next WindowClause, if any */
6142 }
6143
6144 /* adjust the frameOptions if all WindowFunc's agree that it's ok */
6145 if (lc2 == NULL && wc->frameOptions != optimizedFrameOptions)
6146 {
6147 ListCell *lc3;
6148
6149 /* apply the new frame options */
6151
6152 /*
6153 * We now check to see if changing the frameOptions has caused
6154 * this WindowClause to be a duplicate of some other WindowClause.
6155 * This can only happen if we have multiple WindowClauses, so
6156 * don't bother if there's only 1.
6157 */
6158 if (list_length(windowClause) == 1)
6159 continue;
6160
6161 /*
6162 * Do the duplicate check and reuse the existing WindowClause if
6163 * we find a duplicate.
6164 */
6165 foreach(lc3, windowClause)
6166 {
6168
6169 /* skip over the WindowClause we're currently editing */
6170 if (existing_wc == wc)
6171 continue;
6172
6173 /*
6174 * Perform the same duplicate check that is done in
6175 * transformWindowFuncCall.
6176 */
6177 if (equal(wc->partitionClause, existing_wc->partitionClause) &&
6178 equal(wc->orderClause, existing_wc->orderClause) &&
6179 wc->frameOptions == existing_wc->frameOptions &&
6180 equal(wc->startOffset, existing_wc->startOffset) &&
6181 equal(wc->endOffset, existing_wc->endOffset))
6182 {
6183 ListCell *lc4;
6184
6185 /*
6186 * Now move each WindowFunc in 'wc' into 'existing_wc'.
6187 * This required adjusting each WindowFunc's winref and
6188 * moving the WindowFuncs in 'wc' to the list of
6189 * WindowFuncs in 'existing_wc'.
6190 */
6191 foreach(lc4, wflists->windowFuncs[wc->winref])
6192 {
6194
6195 wfunc->winref = existing_wc->winref;
6196 }
6197
6198 /* move list items */
6199 wflists->windowFuncs[existing_wc->winref] = list_concat(wflists->windowFuncs[existing_wc->winref],
6200 wflists->windowFuncs[wc->winref]);
6201 wflists->windowFuncs[wc->winref] = NIL;
6202
6203 /*
6204 * transformWindowFuncCall() should have made sure there
6205 * are no other duplicates, so we needn't bother looking
6206 * any further.
6207 */
6208 break;
6209 }
6210 }
6211 }
6212 }
6213}
#define OidFunctionCall1(functionId, arg1)
Definition fmgr.h:726
RegProcedure get_func_support(Oid funcid)
Definition lsyscache.c:2172
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
#define PointerGetDatum(X)
Definition postgres.h:354
Node * startOffset
Node * endOffset
Index winref
Definition primnodes.h:604

References Assert, DatumGetPointer(), WindowClause::endOffset, equal(), fb(), foreach_current_index, WindowClause::frameOptions, SupportRequestOptimizeWindowClause::frameOptions, get_func_support(), lfirst_node, list_concat(), list_length(), NIL, OidFunctionCall1, OidIsValid, WindowClause::orderClause, WindowClause::partitionClause, PointerGetDatum, root, WindowClause::startOffset, WindowFunc::winfnoid, WindowClause::winref, and WindowFunc::winref.

Referenced by grouping_planner().

◆ plan_cluster_use_sort()

bool plan_cluster_use_sort ( Oid  tableOid,
Oid  indexOid 
)

Definition at line 7090 of file planner.c.

7091{
7093 Query *query;
7094 PlannerGlobal *glob;
7096 RelOptInfo *rel;
7097 IndexOptInfo *indexInfo;
7103 ListCell *lc;
7104
7105 /* We can short-circuit the cost comparison if indexscans are disabled */
7106 if (!enable_indexscan)
7107 return true; /* use sort */
7108
7109 /* Set up mostly-dummy planner state */
7110 query = makeNode(Query);
7111 query->commandType = CMD_SELECT;
7112
7113 glob = makeNode(PlannerGlobal);
7114
7116 root->parse = query;
7117 root->glob = glob;
7118 root->query_level = 1;
7119 root->planner_cxt = CurrentMemoryContext;
7120 root->wt_param_id = -1;
7121 root->join_domains = list_make1(makeNode(JoinDomain));
7122
7123 /* Build a minimal RTE for the rel */
7125 rte->rtekind = RTE_RELATION;
7126 rte->relid = tableOid;
7127 rte->relkind = RELKIND_RELATION; /* Don't be too picky. */
7128 rte->rellockmode = AccessShareLock;
7129 rte->lateral = false;
7130 rte->inh = false;
7131 rte->inFromCl = true;
7132 query->rtable = list_make1(rte);
7133 addRTEPermissionInfo(&query->rteperminfos, rte);
7134
7135 /* Set up RTE/RelOptInfo arrays */
7137
7138 /* Build RelOptInfo */
7139 rel = build_simple_rel(root, 1, NULL);
7140
7141 /* Locate IndexOptInfo for the target index */
7142 indexInfo = NULL;
7143 foreach(lc, rel->indexlist)
7144 {
7145 indexInfo = lfirst_node(IndexOptInfo, lc);
7146 if (indexInfo->indexoid == indexOid)
7147 break;
7148 }
7149
7150 /*
7151 * It's possible that get_relation_info did not generate an IndexOptInfo
7152 * for the desired index; this could happen if it's not yet reached its
7153 * indcheckxmin usability horizon, or if it's a system index and we're
7154 * ignoring system indexes. In such cases we should tell CLUSTER to not
7155 * trust the index contents but use seqscan-and-sort.
7156 */
7157 if (lc == NULL) /* not in the list? */
7158 return true; /* use sort */
7159
7160 /*
7161 * Rather than doing all the pushups that would be needed to use
7162 * set_baserel_size_estimates, just do a quick hack for rows and width.
7163 */
7164 rel->rows = rel->tuples;
7165 rel->reltarget->width = get_relation_data_width(tableOid, NULL);
7166
7167 root->total_table_pages = rel->pages;
7168
7169 /*
7170 * Determine eval cost of the index expressions, if any. We need to
7171 * charge twice that amount for each tuple comparison that happens during
7172 * the sort, since tuplesort.c will have to re-evaluate the index
7173 * expressions each time. (XXX that's pretty inefficient...)
7174 */
7175 cost_qual_eval(&indexExprCost, indexInfo->indexprs, root);
7176 comparisonCost = 2.0 * (indexExprCost.startup + indexExprCost.per_tuple);
7177
7178 /* Estimate the cost of seq scan + sort */
7181 seqScanPath->disabled_nodes,
7182 seqScanPath->total_cost, rel->tuples, rel->reltarget->width,
7184
7185 /* Estimate the cost of index scan */
7187 NIL, NIL, NIL, NIL,
7188 ForwardScanDirection, false,
7189 NULL, 1.0, false);
7190
7191 return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost);
7192}
void cost_sort(Path *path, PlannerInfo *root, List *pathkeys, int input_disabled_nodes, Cost input_cost, double tuples, int width, Cost comparison_cost, int sort_mem, double limit_tuples)
Definition costsize.c:2201
void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
Definition costsize.c:4900
bool enable_indexscan
Definition costsize.c:147
int maintenance_work_mem
Definition globals.c:135
#define AccessShareLock
Definition lockdefs.h:36
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
double Cost
Definition nodes.h:259
RTEPermissionInfo * addRTEPermissionInfo(List **rteperminfos, RangeTblEntry *rte)
@ RTE_RELATION
IndexPath * create_index_path(PlannerInfo *root, IndexOptInfo *index, List *indexclauses, List *indexorderbys, List *indexorderbycols, List *pathkeys, ScanDirection indexscandir, bool indexonly, Relids required_outer, double loop_count, bool partial_path)
Definition pathnode.c:1092
Path * create_seqscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer, int parallel_workers)
Definition pathnode.c:1026
int32 get_relation_data_width(Oid relid, int32 *attr_widths)
Definition plancat.c:1472
void setup_simple_rel_arrays(PlannerInfo *root)
Definition relnode.c:114
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition relnode.c:212
@ ForwardScanDirection
Definition sdir.h:28
List * rtable
Definition parsenodes.h:180
CmdType commandType
Definition parsenodes.h:124
Cardinality tuples
Definition pathnodes.h:1096
BlockNumber pages
Definition pathnodes.h:1095
List * indexlist
Definition pathnodes.h:1091

References AccessShareLock, addRTEPermissionInfo(), build_simple_rel(), CMD_SELECT, Query::commandType, cost_qual_eval(), cost_sort(), create_index_path(), create_seqscan_path(), CurrentMemoryContext, enable_indexscan, fb(), ForwardScanDirection, get_relation_data_width(), RelOptInfo::indexlist, IndexOptInfo::indexoid, lfirst_node, list_make1, maintenance_work_mem, makeNode, NIL, RelOptInfo::pages, RelOptInfo::reltarget, root, RelOptInfo::rows, Query::rtable, RTE_RELATION, setup_simple_rel_arrays(), RelOptInfo::tuples, and PathTarget::width.

Referenced by copy_table_data().

◆ plan_create_index_workers()

int plan_create_index_workers ( Oid  tableOid,
Oid  indexOid 
)

Definition at line 7212 of file planner.c.

7213{
7215 Query *query;
7216 PlannerGlobal *glob;
7218 Relation heap;
7220 RelOptInfo *rel;
7221 int parallel_workers;
7223 double reltuples;
7224 double allvisfrac;
7225
7226 /*
7227 * We don't allow performing parallel operation in standalone backend or
7228 * when parallelism is disabled.
7229 */
7231 return 0;
7232
7233 /* Set up largely-dummy planner state */
7234 query = makeNode(Query);
7235 query->commandType = CMD_SELECT;
7236
7237 glob = makeNode(PlannerGlobal);
7238
7240 root->parse = query;
7241 root->glob = glob;
7242 root->query_level = 1;
7243 root->planner_cxt = CurrentMemoryContext;
7244 root->wt_param_id = -1;
7245 root->join_domains = list_make1(makeNode(JoinDomain));
7246
7247 /*
7248 * Build a minimal RTE.
7249 *
7250 * Mark the RTE with inh = true. This is a kludge to prevent
7251 * get_relation_info() from fetching index info, which is necessary
7252 * because it does not expect that any IndexOptInfo is currently
7253 * undergoing REINDEX.
7254 */
7256 rte->rtekind = RTE_RELATION;
7257 rte->relid = tableOid;
7258 rte->relkind = RELKIND_RELATION; /* Don't be too picky. */
7259 rte->rellockmode = AccessShareLock;
7260 rte->lateral = false;
7261 rte->inh = true;
7262 rte->inFromCl = true;
7263 query->rtable = list_make1(rte);
7264 addRTEPermissionInfo(&query->rteperminfos, rte);
7265
7266 /* Set up RTE/RelOptInfo arrays */
7268
7269 /* Build RelOptInfo */
7270 rel = build_simple_rel(root, 1, NULL);
7271
7272 /* Rels are assumed already locked by the caller */
7273 heap = table_open(tableOid, NoLock);
7274 index = index_open(indexOid, NoLock);
7275
7276 /*
7277 * Determine if it's safe to proceed.
7278 *
7279 * Currently, parallel workers can't access the leader's temporary tables.
7280 * Furthermore, any index predicate or index expressions must be parallel
7281 * safe.
7282 */
7283 if (heap->rd_rel->relpersistence == RELPERSISTENCE_TEMP ||
7286 {
7287 parallel_workers = 0;
7288 goto done;
7289 }
7290
7291 /*
7292 * If parallel_workers storage parameter is set for the table, accept that
7293 * as the number of parallel worker processes to launch (though still cap
7294 * at max_parallel_maintenance_workers). Note that we deliberately do not
7295 * consider any other factor when parallel_workers is set. (e.g., memory
7296 * use by workers.)
7297 */
7298 if (rel->rel_parallel_workers != -1)
7299 {
7300 parallel_workers = Min(rel->rel_parallel_workers,
7302 goto done;
7303 }
7304
7305 /*
7306 * Estimate heap relation size ourselves, since rel->pages cannot be
7307 * trusted (heap RTE was marked as inheritance parent)
7308 */
7309 estimate_rel_size(heap, NULL, &heap_blocks, &reltuples, &allvisfrac);
7310
7311 /*
7312 * Determine number of workers to scan the heap relation using generic
7313 * model
7314 */
7315 parallel_workers = compute_parallel_worker(rel, heap_blocks, -1,
7317
7318 /*
7319 * Cap workers based on available maintenance_work_mem as needed.
7320 *
7321 * Note that each tuplesort participant receives an even share of the
7322 * total maintenance_work_mem budget. Aim to leave participants
7323 * (including the leader as a participant) with no less than 32MB of
7324 * memory. This leaves cases where maintenance_work_mem is set to 64MB
7325 * immediately past the threshold of being capable of launching a single
7326 * parallel worker to sort.
7327 */
7328 while (parallel_workers > 0 &&
7329 maintenance_work_mem / (parallel_workers + 1) < 32 * 1024)
7330 parallel_workers--;
7331
7332done:
7334 table_close(heap, NoLock);
7335
7336 return parallel_workers;
7337}
int compute_parallel_worker(RelOptInfo *rel, double heap_pages, double index_pages, int max_workers)
Definition allpaths.c:4973
uint32 BlockNumber
Definition block.h:31
int max_parallel_maintenance_workers
Definition globals.c:136
bool IsUnderPostmaster
Definition globals.c:122
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:178
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:134
#define NoLock
Definition lockdefs.h:34
void estimate_rel_size(Relation rel, int32 *attr_widths, BlockNumber *pages, double *tuples, double *allvisfrac)
Definition plancat.c:1305
List * RelationGetIndexPredicate(Relation relation)
Definition relcache.c:5220
List * RelationGetIndexExpressions(Relation relation)
Definition relcache.c:5107
int rel_parallel_workers
Definition pathnodes.h:1103
Form_pg_class rd_rel
Definition rel.h:111
Definition type.h:97
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40

References AccessShareLock, addRTEPermissionInfo(), build_simple_rel(), CMD_SELECT, Query::commandType, compute_parallel_worker(), CurrentMemoryContext, estimate_rel_size(), fb(), index_close(), index_open(), is_parallel_safe(), IsUnderPostmaster, list_make1, maintenance_work_mem, makeNode, max_parallel_maintenance_workers, Min, NoLock, RelationData::rd_rel, RelOptInfo::rel_parallel_workers, RelationGetIndexExpressions(), RelationGetIndexPredicate(), root, Query::rtable, RTE_RELATION, setup_simple_rel_arrays(), table_close(), and table_open().

Referenced by index_build().

◆ planner()

PlannedStmt * planner ( Query parse,
const char query_string,
int  cursorOptions,
ParamListInfo  boundParams,
ExplainState es 
)

Definition at line 328 of file planner.c.

330{
332
333 if (planner_hook)
334 result = (*planner_hook) (parse, query_string, cursorOptions,
335 boundParams, es);
336 else
337 result = standard_planner(parse, query_string, cursorOptions,
338 boundParams, es);
339
340 pgstat_report_plan_id(result->planId, false);
341
342 return result;
343}
void pgstat_report_plan_id(int64 plan_id, bool force)
planner_hook_type planner_hook
Definition planner.c:74
PlannedStmt * standard_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams, ExplainState *es)
Definition planner.c:346

References parse(), pgstat_report_plan_id(), planner_hook, result, and standard_planner().

Referenced by pg_plan_query(), and test_plan_advice_advisor().

◆ postprocess_setop_tlist()

static List * postprocess_setop_tlist ( List new_tlist,
List orig_tlist 
)
static

Definition at line 6044 of file planner.c.

6045{
6046 ListCell *l;
6048
6049 foreach(l, new_tlist)
6050 {
6053
6054 /* ignore resjunk columns in setop result */
6055 if (new_tle->resjunk)
6056 continue;
6057
6061 if (orig_tle->resjunk) /* should not happen */
6062 elog(ERROR, "resjunk output columns are not implemented");
6063 Assert(new_tle->resno == orig_tle->resno);
6064 new_tle->ressortgroupref = orig_tle->ressortgroupref;
6065 }
6066 if (orig_tlist_item != NULL)
6067 elog(ERROR, "resjunk output columns are not implemented");
6068 return new_tlist;
6069}

References Assert, elog, ERROR, fb(), lfirst_node, list_head(), and lnext().

Referenced by grouping_planner().

◆ preprocess_expression()

static Node * preprocess_expression ( PlannerInfo root,
Node expr,
int  kind 
)
static

Definition at line 1429 of file planner.c.

1430{
1431 /*
1432 * Fall out quickly if expression is empty. This occurs often enough to
1433 * be worth checking. Note that null->null is the correct conversion for
1434 * implicit-AND result format, too.
1435 */
1436 if (expr == NULL)
1437 return NULL;
1438
1439 /*
1440 * If the query has any join RTEs, replace join alias variables with
1441 * base-relation variables. We must do this first, since any expressions
1442 * we may extract from the joinaliasvars lists have not been preprocessed.
1443 * For example, if we did this after sublink processing, sublinks expanded
1444 * out from join aliases would not get processed. But we can skip this in
1445 * non-lateral RTE functions, VALUES lists, and TABLESAMPLE clauses, since
1446 * they can't contain any Vars of the current query level.
1447 */
1448 if (root->hasJoinRTEs &&
1449 !(kind == EXPRKIND_RTFUNC ||
1450 kind == EXPRKIND_VALUES ||
1451 kind == EXPRKIND_TABLESAMPLE ||
1452 kind == EXPRKIND_TABLEFUNC))
1453 expr = flatten_join_alias_vars(root, root->parse, expr);
1454
1455 /*
1456 * Simplify constant expressions. For function RTEs, this was already
1457 * done by preprocess_function_rtes. (But note we must do it again for
1458 * EXPRKIND_RTFUNC_LATERAL, because those might by now contain
1459 * un-simplified subexpressions inserted by flattening of subqueries or
1460 * join alias variables.)
1461 *
1462 * Note: an essential effect of this is to convert named-argument function
1463 * calls to positional notation and insert the current actual values of
1464 * any default arguments for functions. To ensure that happens, we *must*
1465 * process all expressions here. Previous PG versions sometimes skipped
1466 * const-simplification if it didn't seem worth the trouble, but we can't
1467 * do that anymore.
1468 *
1469 * Note: this also flattens nested AND and OR expressions into N-argument
1470 * form. All processing of a qual expression after this point must be
1471 * careful to maintain AND/OR flatness --- that is, do not generate a tree
1472 * with AND directly under AND, nor OR directly under OR.
1473 */
1474 if (kind != EXPRKIND_RTFUNC)
1475 expr = eval_const_expressions(root, expr);
1476
1477 /*
1478 * If it's a qual or havingQual, canonicalize it.
1479 */
1480 if (kind == EXPRKIND_QUAL)
1481 {
1482 expr = (Node *) canonicalize_qual((Expr *) expr, false);
1483
1484#ifdef OPTIMIZER_DEBUG
1485 printf("After canonicalize_qual()\n");
1486 pprint(expr);
1487#endif
1488 }
1489
1490 /*
1491 * Check for ANY ScalarArrayOpExpr with Const arrays and set the
1492 * hashfuncid of any that might execute more quickly by using hash lookups
1493 * instead of a linear search.
1494 */
1495 if (kind == EXPRKIND_QUAL || kind == EXPRKIND_TARGET)
1496 {
1498 }
1499
1500 /* Expand SubLinks to SubPlans */
1501 if (root->parse->hasSubLinks)
1502 expr = SS_process_sublinks(root, expr, (kind == EXPRKIND_QUAL));
1503
1504 /*
1505 * XXX do not insert anything here unless you have grokked the comments in
1506 * SS_replace_correlation_vars ...
1507 */
1508
1509 /* Replace uplevel vars with Param nodes (this IS possible in VALUES) */
1510 if (root->query_level > 1)
1511 expr = SS_replace_correlation_vars(root, expr);
1512
1513 /*
1514 * If it's a qual or havingQual, convert it to implicit-AND format. (We
1515 * don't want to do this before eval_const_expressions, since the latter
1516 * would be unable to simplify a top-level AND correctly. Also,
1517 * SS_process_sublinks expects explicit-AND format.)
1518 */
1519 if (kind == EXPRKIND_QUAL)
1520 expr = (Node *) make_ands_implicit((Expr *) expr);
1521
1522 return expr;
1523}
void pprint(const void *obj)
Definition print.c:54
void convert_saop_to_hashed_saop(Node *node)
Definition clauses.c:2549
List * make_ands_implicit(Expr *clause)
Definition makefuncs.c:810
#define EXPRKIND_TARGET
Definition planner.c:88
#define EXPRKIND_TABLESAMPLE
Definition planner.c:96
#define EXPRKIND_VALUES
Definition planner.c:91
#define EXPRKIND_QUAL
Definition planner.c:87
#define EXPRKIND_TABLEFUNC
Definition planner.c:98
#define EXPRKIND_RTFUNC
Definition planner.c:89
#define printf(...)
Definition port.h:267
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition prepqual.c:293
Node * SS_process_sublinks(PlannerInfo *root, Node *expr, bool isQual)
Definition subselect.c:2209
Node * SS_replace_correlation_vars(PlannerInfo *root, Node *expr)
Definition subselect.c:2154
Node * flatten_join_alias_vars(PlannerInfo *root, Query *query, Node *node)
Definition var.c:781

References canonicalize_qual(), convert_saop_to_hashed_saop(), eval_const_expressions(), EXPRKIND_QUAL, EXPRKIND_RTFUNC, EXPRKIND_TABLEFUNC, EXPRKIND_TABLESAMPLE, EXPRKIND_TARGET, EXPRKIND_VALUES, fb(), flatten_join_alias_vars(), make_ands_implicit(), pprint(), printf, root, SS_process_sublinks(), and SS_replace_correlation_vars().

Referenced by preprocess_phv_expression(), preprocess_qual_conditions(), and subquery_planner().

◆ preprocess_groupclause()

static List * preprocess_groupclause ( PlannerInfo root,
List force 
)
static

Definition at line 3098 of file planner.c.

3099{
3100 Query *parse = root->parse;
3102 ListCell *sl;
3103 ListCell *gl;
3104
3105 /* For grouping sets, we need to force the ordering */
3106 if (force)
3107 {
3108 foreach(sl, force)
3109 {
3112
3114 }
3115
3116 return new_groupclause;
3117 }
3118
3119 /* If no ORDER BY, nothing useful to do here */
3120 if (parse->sortClause == NIL)
3121 return list_copy(parse->groupClause);
3122
3123 /*
3124 * Scan the ORDER BY clause and construct a list of matching GROUP BY
3125 * items, but only as far as we can make a matching prefix.
3126 *
3127 * This code assumes that the sortClause contains no duplicate items.
3128 */
3129 foreach(sl, parse->sortClause)
3130 {
3132
3133 foreach(gl, parse->groupClause)
3134 {
3136
3137 if (equal(gc, sc))
3138 {
3140 break;
3141 }
3142 }
3143 if (gl == NULL)
3144 break; /* no match, so stop scanning */
3145 }
3146
3147
3148 /* If no match at all, no point in reordering GROUP BY */
3149 if (new_groupclause == NIL)
3150 return list_copy(parse->groupClause);
3151
3152 /*
3153 * Add any remaining GROUP BY items to the new list. We don't require a
3154 * complete match, because even partial match allows ORDER BY to be
3155 * implemented using incremental sort. Also, give up if there are any
3156 * non-sortable GROUP BY items, since then there's no hope anyway.
3157 */
3158 foreach(gl, parse->groupClause)
3159 {
3161
3163 continue; /* it matched an ORDER BY item */
3164 if (!OidIsValid(gc->sortop)) /* give up, GROUP BY can't be sorted */
3165 return list_copy(parse->groupClause);
3167 }
3168
3169 /* Success --- install the rearranged GROUP BY list */
3171 return new_groupclause;
3172}
SortGroupClause * get_sortgroupref_clause(Index sortref, List *clauses)
Definition tlist.c:431

References Assert, equal(), fb(), get_sortgroupref_clause(), lappend(), lfirst_int, lfirst_node, list_copy(), list_length(), list_member_ptr(), NIL, OidIsValid, parse(), and root.

Referenced by consider_groupingsets_paths(), grouping_planner(), and preprocess_grouping_sets().

◆ preprocess_grouping_sets()

static grouping_sets_data * preprocess_grouping_sets ( PlannerInfo root)
static

Definition at line 2452 of file planner.c.

2453{
2454 Query *parse = root->parse;
2455 List *sets;
2456 int maxref = 0;
2459
2460 /*
2461 * We don't currently make any attempt to optimize the groupClause when
2462 * there are grouping sets, so just duplicate it in processed_groupClause.
2463 */
2464 root->processed_groupClause = parse->groupClause;
2465
2466 /* Detect unhashable and unsortable grouping expressions */
2467 gd->any_hashable = false;
2468 gd->unhashable_refs = NULL;
2469 gd->unsortable_refs = NULL;
2470 gd->unsortable_sets = NIL;
2471
2472 if (parse->groupClause)
2473 {
2474 ListCell *lc;
2475
2476 foreach(lc, parse->groupClause)
2477 {
2479 Index ref = gc->tleSortGroupRef;
2480
2481 if (ref > maxref)
2482 maxref = ref;
2483
2484 if (!gc->hashable)
2485 gd->unhashable_refs = bms_add_member(gd->unhashable_refs, ref);
2486
2487 if (!OidIsValid(gc->sortop))
2488 gd->unsortable_refs = bms_add_member(gd->unsortable_refs, ref);
2489 }
2490 }
2491
2492 /* Allocate workspace array for remapping */
2493 gd->tleref_to_colnum_map = (int *) palloc((maxref + 1) * sizeof(int));
2494
2495 /*
2496 * If we have any unsortable sets, we must extract them before trying to
2497 * prepare rollups. Unsortable sets don't go through
2498 * reorder_grouping_sets, so we must apply the GroupingSetData annotation
2499 * here.
2500 */
2501 if (!bms_is_empty(gd->unsortable_refs))
2502 {
2504 ListCell *lc;
2505
2506 foreach(lc, parse->groupingSets)
2507 {
2508 List *gset = (List *) lfirst(lc);
2509
2510 if (bms_overlap_list(gd->unsortable_refs, gset))
2511 {
2513
2514 gs->set = gset;
2515 gd->unsortable_sets = lappend(gd->unsortable_sets, gs);
2516
2517 /*
2518 * We must enforce here that an unsortable set is hashable;
2519 * later code assumes this. Parse analysis only checks that
2520 * every individual column is either hashable or sortable.
2521 *
2522 * Note that passing this test doesn't guarantee we can
2523 * generate a plan; there might be other showstoppers.
2524 */
2525 if (bms_overlap_list(gd->unhashable_refs, gset))
2526 ereport(ERROR,
2528 errmsg("could not implement GROUP BY"),
2529 errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
2530 }
2531 else
2533 }
2534
2535 if (sortable_sets)
2537 else
2538 sets = NIL;
2539 }
2540 else
2541 sets = extract_rollup_sets(parse->groupingSets);
2542
2543 foreach(lc_set, sets)
2544 {
2548
2549 /*
2550 * Reorder the current list of grouping sets into correct prefix
2551 * order. If only one aggregation pass is needed, try to make the
2552 * list match the ORDER BY clause; if more than one pass is needed, we
2553 * don't bother with that.
2554 *
2555 * Note that this reorders the sets from smallest-member-first to
2556 * largest-member-first, and applies the GroupingSetData annotations,
2557 * though the data will be filled in later.
2558 */
2560 (list_length(sets) == 1
2561 ? parse->sortClause
2562 : NIL));
2563
2564 /*
2565 * Get the initial (and therefore largest) grouping set.
2566 */
2568
2569 /*
2570 * Order the groupClause appropriately. If the first grouping set is
2571 * empty, then the groupClause must also be empty; otherwise we have
2572 * to force the groupClause to match that grouping set's order.
2573 *
2574 * (The first grouping set can be empty even though parse->groupClause
2575 * is not empty only if all non-empty grouping sets are unsortable.
2576 * The groupClauses for hashed grouping sets are built later on.)
2577 */
2578 if (gs->set)
2579 rollup->groupClause = preprocess_groupclause(root, gs->set);
2580 else
2581 rollup->groupClause = NIL;
2582
2583 /*
2584 * Is it hashable? We pretend empty sets are hashable even though we
2585 * actually force them not to be hashed later. But don't bother if
2586 * there's nothing but empty sets (since in that case we can't hash
2587 * anything).
2588 */
2589 if (gs->set &&
2590 !bms_overlap_list(gd->unhashable_refs, gs->set))
2591 {
2592 rollup->hashable = true;
2593 gd->any_hashable = true;
2594 }
2595
2596 /*
2597 * Now that we've pinned down an order for the groupClause for this
2598 * list of grouping sets, we need to remap the entries in the grouping
2599 * sets from sortgrouprefs to plain indices (0-based) into the
2600 * groupClause for this collection of grouping sets. We keep the
2601 * original form for later use, though.
2602 */
2603 rollup->gsets = remap_to_groupclause_idx(rollup->groupClause,
2605 gd->tleref_to_colnum_map);
2606 rollup->gsets_data = current_sets;
2607
2608 gd->rollups = lappend(gd->rollups, rollup);
2609 }
2610
2611 if (gd->unsortable_sets)
2612 {
2613 /*
2614 * We have not yet pinned down a groupclause for this, but we will
2615 * need index-based lists for estimation purposes. Construct
2616 * hash_sets_idx based on the entire original groupclause for now.
2617 */
2618 gd->hash_sets_idx = remap_to_groupclause_idx(parse->groupClause,
2619 gd->unsortable_sets,
2620 gd->tleref_to_colnum_map);
2621 gd->any_hashable = true;
2622 }
2623
2624 return gd;
2625}
bool bms_overlap_list(const Bitmapset *a, const List *b)
Definition bitmapset.c:601
#define palloc0_object(type)
Definition fe_memutils.h:90
static List * reorder_grouping_sets(List *groupingSets, List *sortclause)
Definition planner.c:3406
static List * extract_rollup_sets(List *groupingSets)
Definition planner.c:3194

References bms_add_member(), bms_is_empty, bms_overlap_list(), ereport, errcode(), errdetail(), errmsg, ERROR, extract_rollup_sets(), fb(), lappend(), lfirst, lfirst_node, linitial_node, list_length(), makeNode, NIL, OidIsValid, palloc(), palloc0_object, parse(), preprocess_groupclause(), remap_to_groupclause_idx(), reorder_grouping_sets(), and root.

Referenced by grouping_planner().

◆ preprocess_limit()

static double preprocess_limit ( PlannerInfo root,
double  tuple_fraction,
int64 offset_est,
int64 count_est 
)
static

Definition at line 2847 of file planner.c.

2849{
2850 Query *parse = root->parse;
2851 Node *est;
2852 double limit_fraction;
2853
2854 /* Should not be called unless LIMIT or OFFSET */
2855 Assert(parse->limitCount || parse->limitOffset);
2856
2857 /*
2858 * Try to obtain the clause values. We use estimate_expression_value
2859 * primarily because it can sometimes do something useful with Params.
2860 */
2861 if (parse->limitCount)
2862 {
2863 est = estimate_expression_value(root, parse->limitCount);
2864 if (est && IsA(est, Const))
2865 {
2866 if (((Const *) est)->constisnull)
2867 {
2868 /* NULL indicates LIMIT ALL, ie, no limit */
2869 *count_est = 0; /* treat as not present */
2870 }
2871 else
2872 {
2873 *count_est = DatumGetInt64(((Const *) est)->constvalue);
2874 if (*count_est <= 0)
2875 *count_est = 1; /* force to at least 1 */
2876 }
2877 }
2878 else
2879 *count_est = -1; /* can't estimate */
2880 }
2881 else
2882 *count_est = 0; /* not present */
2883
2884 if (parse->limitOffset)
2885 {
2886 est = estimate_expression_value(root, parse->limitOffset);
2887 if (est && IsA(est, Const))
2888 {
2889 if (((Const *) est)->constisnull)
2890 {
2891 /* Treat NULL as no offset; the executor will too */
2892 *offset_est = 0; /* treat as not present */
2893 }
2894 else
2895 {
2896 *offset_est = DatumGetInt64(((Const *) est)->constvalue);
2897 if (*offset_est < 0)
2898 *offset_est = 0; /* treat as not present */
2899 }
2900 }
2901 else
2902 *offset_est = -1; /* can't estimate */
2903 }
2904 else
2905 *offset_est = 0; /* not present */
2906
2907 if (*count_est != 0)
2908 {
2909 /*
2910 * A LIMIT clause limits the absolute number of tuples returned.
2911 * However, if it's not a constant LIMIT then we have to guess; for
2912 * lack of a better idea, assume 10% of the plan's result is wanted.
2913 */
2914 if (*count_est < 0 || *offset_est < 0)
2915 {
2916 /* LIMIT or OFFSET is an expression ... punt ... */
2917 limit_fraction = 0.10;
2918 }
2919 else
2920 {
2921 /* LIMIT (plus OFFSET, if any) is max number of tuples needed */
2922 limit_fraction = (double) *count_est + (double) *offset_est;
2923 }
2924
2925 /*
2926 * If we have absolute limits from both caller and LIMIT, use the
2927 * smaller value; likewise if they are both fractional. If one is
2928 * fractional and the other absolute, we can't easily determine which
2929 * is smaller, but we use the heuristic that the absolute will usually
2930 * be smaller.
2931 */
2932 if (tuple_fraction >= 1.0)
2933 {
2934 if (limit_fraction >= 1.0)
2935 {
2936 /* both absolute */
2937 tuple_fraction = Min(tuple_fraction, limit_fraction);
2938 }
2939 else
2940 {
2941 /* caller absolute, limit fractional; use caller's value */
2942 }
2943 }
2944 else if (tuple_fraction > 0.0)
2945 {
2946 if (limit_fraction >= 1.0)
2947 {
2948 /* caller fractional, limit absolute; use limit */
2949 tuple_fraction = limit_fraction;
2950 }
2951 else
2952 {
2953 /* both fractional */
2954 tuple_fraction = Min(tuple_fraction, limit_fraction);
2955 }
2956 }
2957 else
2958 {
2959 /* no info from caller, just use limit */
2960 tuple_fraction = limit_fraction;
2961 }
2962 }
2963 else if (*offset_est != 0 && tuple_fraction > 0.0)
2964 {
2965 /*
2966 * We have an OFFSET but no LIMIT. This acts entirely differently
2967 * from the LIMIT case: here, we need to increase rather than decrease
2968 * the caller's tuple_fraction, because the OFFSET acts to cause more
2969 * tuples to be fetched instead of fewer. This only matters if we got
2970 * a tuple_fraction > 0, however.
2971 *
2972 * As above, use 10% if OFFSET is present but unestimatable.
2973 */
2974 if (*offset_est < 0)
2975 limit_fraction = 0.10;
2976 else
2977 limit_fraction = (double) *offset_est;
2978
2979 /*
2980 * If we have absolute counts from both caller and OFFSET, add them
2981 * together; likewise if they are both fractional. If one is
2982 * fractional and the other absolute, we want to take the larger, and
2983 * we heuristically assume that's the fractional one.
2984 */
2985 if (tuple_fraction >= 1.0)
2986 {
2987 if (limit_fraction >= 1.0)
2988 {
2989 /* both absolute, so add them together */
2990 tuple_fraction += limit_fraction;
2991 }
2992 else
2993 {
2994 /* caller absolute, limit fractional; use limit */
2995 tuple_fraction = limit_fraction;
2996 }
2997 }
2998 else
2999 {
3000 if (limit_fraction >= 1.0)
3001 {
3002 /* caller fractional, limit absolute; use caller's value */
3003 }
3004 else
3005 {
3006 /* both fractional, so add them together */
3007 tuple_fraction += limit_fraction;
3008 if (tuple_fraction >= 1.0)
3009 tuple_fraction = 0.0; /* assume fetch all */
3010 }
3011 }
3012 }
3013
3014 return tuple_fraction;
3015}
Node * estimate_expression_value(PlannerInfo *root, Node *node)
Definition clauses.c:2660

References Assert, DatumGetInt64(), estimate_expression_value(), fb(), IsA, Min, parse(), and root.

Referenced by grouping_planner().

◆ preprocess_phv_expression()

Expr * preprocess_phv_expression ( PlannerInfo root,
Expr expr 
)

Definition at line 1671 of file planner.c.

1672{
1673 return (Expr *) preprocess_expression(root, (Node *) expr, EXPRKIND_PHV);
1674}
#define EXPRKIND_PHV
Definition planner.c:95
static Node * preprocess_expression(PlannerInfo *root, Node *expr, int kind)
Definition planner.c:1429

References EXPRKIND_PHV, preprocess_expression(), and root.

Referenced by extract_lateral_references().

◆ preprocess_qual_conditions()

static void preprocess_qual_conditions ( PlannerInfo root,
Node jtnode 
)
static

Definition at line 1531 of file planner.c.

1532{
1533 if (jtnode == NULL)
1534 return;
1535 if (IsA(jtnode, RangeTblRef))
1536 {
1537 /* nothing to do here */
1538 }
1539 else if (IsA(jtnode, FromExpr))
1540 {
1541 FromExpr *f = (FromExpr *) jtnode;
1542 ListCell *l;
1543
1544 foreach(l, f->fromlist)
1546
1548 }
1549 else if (IsA(jtnode, JoinExpr))
1550 {
1551 JoinExpr *j = (JoinExpr *) jtnode;
1552
1555
1556 j->quals = preprocess_expression(root, j->quals, EXPRKIND_QUAL);
1557 }
1558 else
1559 elog(ERROR, "unrecognized node type: %d",
1560 (int) nodeTag(jtnode));
1561}
#define nodeTag(nodeptr)
Definition nodes.h:137
static void preprocess_qual_conditions(PlannerInfo *root, Node *jtnode)
Definition planner.c:1531
Node * quals
Definition primnodes.h:2378
List * fromlist
Definition primnodes.h:2377

References elog, ERROR, EXPRKIND_QUAL, fb(), FromExpr::fromlist, IsA, j, lfirst, nodeTag, preprocess_expression(), preprocess_qual_conditions(), FromExpr::quals, and root.

Referenced by preprocess_qual_conditions(), and subquery_planner().

◆ preprocess_rowmarks()

static void preprocess_rowmarks ( PlannerInfo root)
static

Definition at line 2669 of file planner.c.

2670{
2671 Query *parse = root->parse;
2672 Bitmapset *rels;
2673 List *prowmarks;
2674 ListCell *l;
2675 int i;
2676
2677 if (parse->rowMarks)
2678 {
2679 /*
2680 * We've got trouble if FOR [KEY] UPDATE/SHARE appears inside
2681 * grouping, since grouping renders a reference to individual tuple
2682 * CTIDs invalid. This is also checked at parse time, but that's
2683 * insufficient because of rule substitution, query pullup, etc.
2684 */
2686 parse->rowMarks)->strength);
2687 }
2688 else
2689 {
2690 /*
2691 * We only need rowmarks for UPDATE, DELETE, MERGE, or FOR [KEY]
2692 * UPDATE/SHARE.
2693 */
2694 if (parse->commandType != CMD_UPDATE &&
2695 parse->commandType != CMD_DELETE &&
2696 parse->commandType != CMD_MERGE)
2697 return;
2698 }
2699
2700 /*
2701 * We need to have rowmarks for all base relations except the target. We
2702 * make a bitmapset of all base rels and then remove the items we don't
2703 * need or have FOR [KEY] UPDATE/SHARE marks for.
2704 */
2705 rels = get_relids_in_jointree((Node *) parse->jointree, false, false);
2706 if (parse->resultRelation)
2707 rels = bms_del_member(rels, parse->resultRelation);
2708
2709 /*
2710 * Convert RowMarkClauses to PlanRowMark representation.
2711 */
2712 prowmarks = NIL;
2713 foreach(l, parse->rowMarks)
2714 {
2716 RangeTblEntry *rte = rt_fetch(rc->rti, parse->rtable);
2718
2719 /*
2720 * Currently, it is syntactically impossible to have FOR UPDATE et al
2721 * applied to an update/delete target rel. If that ever becomes
2722 * possible, we should drop the target from the PlanRowMark list.
2723 */
2724 Assert(rc->rti != parse->resultRelation);
2725
2726 /*
2727 * Ignore RowMarkClauses for subqueries; they aren't real tables and
2728 * can't support true locking. Subqueries that got flattened into the
2729 * main query should be ignored completely. Any that didn't will get
2730 * ROW_MARK_COPY items in the next loop.
2731 */
2732 if (rte->rtekind != RTE_RELATION)
2733 continue;
2734
2735 rels = bms_del_member(rels, rc->rti);
2736
2738 newrc->rti = newrc->prti = rc->rti;
2739 newrc->rowmarkId = ++(root->glob->lastRowMarkId);
2740 newrc->markType = select_rowmark_type(rte, rc->strength);
2741 newrc->allMarkTypes = (1 << newrc->markType);
2742 newrc->strength = rc->strength;
2743 newrc->waitPolicy = rc->waitPolicy;
2744 newrc->isParent = false;
2745
2747 }
2748
2749 /*
2750 * Now, add rowmarks for any non-target, non-locked base relations.
2751 */
2752 i = 0;
2753 foreach(l, parse->rtable)
2754 {
2757
2758 i++;
2759 if (!bms_is_member(i, rels))
2760 continue;
2761
2763 newrc->rti = newrc->prti = i;
2764 newrc->rowmarkId = ++(root->glob->lastRowMarkId);
2765 newrc->markType = select_rowmark_type(rte, LCS_NONE);
2766 newrc->allMarkTypes = (1 << newrc->markType);
2767 newrc->strength = LCS_NONE;
2768 newrc->waitPolicy = LockWaitBlock; /* doesn't matter */
2769 newrc->isParent = false;
2770
2772 }
2773
2774 root->rowMarks = prowmarks;
2775}
@ LockWaitBlock
Definition lockoptions.h:40
@ LCS_NONE
Definition lockoptions.h:23
@ CMD_DELETE
Definition nodes.h:276
void CheckSelectLocking(Query *qry, LockClauseStrength strength)
Definition analyze.c:3742
#define rt_fetch(rangetable_index, rangetable)
Definition parsetree.h:31
RowMarkType select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength)
Definition planner.c:2781
Relids get_relids_in_jointree(Node *jtnode, bool include_outer_joins, bool include_inner_joins)
LockClauseStrength strength
LockWaitPolicy waitPolicy

References Assert, bms_del_member(), bms_is_member(), CheckSelectLocking(), CMD_DELETE, CMD_MERGE, CMD_UPDATE, fb(), get_relids_in_jointree(), i, lappend(), LCS_NONE, lfirst_node, linitial_node, LockWaitBlock, makeNode, NIL, parse(), root, rt_fetch, RTE_RELATION, RowMarkClause::rti, select_rowmark_type(), RowMarkClause::strength, and RowMarkClause::waitPolicy.

Referenced by subquery_planner().

◆ remap_to_groupclause_idx()

static List * remap_to_groupclause_idx ( List groupClause,
List gsets,
int tleref_to_colnum_map 
)
static

Definition at line 2632 of file planner.c.

2635{
2636 int ref = 0;
2637 List *result = NIL;
2638 ListCell *lc;
2639
2640 foreach(lc, groupClause)
2641 {
2643
2644 tleref_to_colnum_map[gc->tleSortGroupRef] = ref++;
2645 }
2646
2647 foreach(lc, gsets)
2648 {
2649 List *set = NIL;
2650 ListCell *lc2;
2652
2653 foreach(lc2, gs->set)
2654 {
2655 set = lappend_int(set, tleref_to_colnum_map[lfirst_int(lc2)]);
2656 }
2657
2658 result = lappend(result, set);
2659 }
2660
2661 return result;
2662}

References fb(), lappend(), lappend_int(), lfirst_int, lfirst_node, NIL, and result.

Referenced by consider_groupingsets_paths(), and preprocess_grouping_sets().

◆ reorder_grouping_sets()

static List * reorder_grouping_sets ( List groupingSets,
List sortclause 
)
static

Definition at line 3406 of file planner.c.

3407{
3408 ListCell *lc;
3409 List *previous = NIL;
3410 List *result = NIL;
3411
3412 foreach(lc, groupingSets)
3413 {
3414 List *candidate = (List *) lfirst(lc);
3417
3418 while (list_length(sortclause) > list_length(previous) &&
3419 new_elems != NIL)
3420 {
3422 int ref = sc->tleSortGroupRef;
3423
3425 {
3426 previous = lappend_int(previous, ref);
3428 }
3429 else
3430 {
3431 /* diverged from the sortclause; give up on it */
3432 sortclause = NIL;
3433 break;
3434 }
3435 }
3436
3437 previous = list_concat(previous, new_elems);
3438
3439 gs->set = list_copy(previous);
3440 result = lcons(gs, result);
3441 }
3442
3443 list_free(previous);
3444
3445 return result;
3446}
List * list_difference_int(const List *list1, const List *list2)
Definition list.c:1288
List * list_delete_int(List *list, int datum)
Definition list.c:891
bool list_member_int(const List *list, int datum)
Definition list.c:702
static void * list_nth(const List *list, int n)
Definition pg_list.h:331

References fb(), lappend_int(), lcons(), lfirst, list_concat(), list_copy(), list_delete_int(), list_difference_int(), list_free(), list_length(), list_member_int(), list_nth(), makeNode, NIL, and result.

Referenced by preprocess_grouping_sets().

◆ select_active_windows()

static List * select_active_windows ( PlannerInfo root,
WindowFuncLists wflists 
)
static

Definition at line 6221 of file planner.c.

6222{
6223 List *windowClause = root->parse->windowClause;
6224 List *result = NIL;
6225 ListCell *lc;
6226 int nActive = 0;
6228 list_length(windowClause));
6229
6230 /* First, construct an array of the active windows */
6231 foreach(lc, windowClause)
6232 {
6234
6235 /* It's only active if wflists shows some related WindowFuncs */
6236 Assert(wc->winref <= wflists->maxWinRef);
6237 if (wflists->windowFuncs[wc->winref] == NIL)
6238 continue;
6239
6240 actives[nActive].wc = wc; /* original clause */
6241
6242 /*
6243 * For sorting, we want the list of partition keys followed by the
6244 * list of sort keys. But pathkeys construction will remove duplicates
6245 * between the two, so we can as well (even though we can't detect all
6246 * of the duplicates, since some may come from ECs - that might mean
6247 * we miss optimization chances here). We must, however, ensure that
6248 * the order of entries is preserved with respect to the ones we do
6249 * keep.
6250 *
6251 * partitionClause and orderClause had their own duplicates removed in
6252 * parse analysis, so we're only concerned here with removing
6253 * orderClause entries that also appear in partitionClause.
6254 */
6255 actives[nActive].uniqueOrder =
6257 wc->orderClause);
6258 nActive++;
6259 }
6260
6261 /*
6262 * Sort active windows by their partitioning/ordering clauses, ignoring
6263 * any framing clauses, so that the windows that need the same sorting are
6264 * adjacent in the list. When we come to generate paths, this will avoid
6265 * inserting additional Sort nodes.
6266 *
6267 * This is how we implement a specific requirement from the SQL standard,
6268 * which says that when two or more windows are order-equivalent (i.e.
6269 * have matching partition and order clauses, even if their names or
6270 * framing clauses differ), then all peer rows must be presented in the
6271 * same order in all of them. If we allowed multiple sort nodes for such
6272 * cases, we'd risk having the peer rows end up in different orders in
6273 * equivalent windows due to sort instability. (See General Rule 4 of
6274 * <window clause> in SQL2008 - SQL2016.)
6275 *
6276 * Additionally, if the entire list of clauses of one window is a prefix
6277 * of another, put first the window with stronger sorting requirements.
6278 * This way we will first sort for stronger window, and won't have to sort
6279 * again for the weaker one.
6280 */
6282
6283 /* build ordered list of the original WindowClause nodes */
6284 for (int i = 0; i < nActive; i++)
6285 result = lappend(result, actives[i].wc);
6286
6287 pfree(actives);
6288
6289 return result;
6290}
#define palloc_array(type, count)
Definition fe_memutils.h:91
List * list_concat_unique(List *list1, const List *list2)
Definition list.c:1405
static int common_prefix_cmp(const void *a, const void *b)
Definition planner.c:6355
#define qsort(a, b, c, d)
Definition port.h:496

References Assert, common_prefix_cmp(), fb(), i, lappend(), lfirst_node, list_concat_unique(), list_copy(), list_length(), NIL, WindowClause::orderClause, palloc_array, WindowClause::partitionClause, pfree(), qsort, result, root, and WindowClause::winref.

Referenced by grouping_planner().

◆ select_rowmark_type()

RowMarkType select_rowmark_type ( RangeTblEntry rte,
LockClauseStrength  strength 
)

Definition at line 2781 of file planner.c.

2782{
2783 if (rte->rtekind != RTE_RELATION)
2784 {
2785 /* If it's not a table at all, use ROW_MARK_COPY */
2786 return ROW_MARK_COPY;
2787 }
2788 else if (rte->relkind == RELKIND_FOREIGN_TABLE)
2789 {
2790 /* Let the FDW select the rowmark type, if it wants to */
2791 FdwRoutine *fdwroutine = GetFdwRoutineByRelId(rte->relid);
2792
2793 if (fdwroutine->GetForeignRowMarkType != NULL)
2794 return fdwroutine->GetForeignRowMarkType(rte, strength);
2795 /* Otherwise, use ROW_MARK_COPY by default */
2796 return ROW_MARK_COPY;
2797 }
2798 else
2799 {
2800 /* Regular table, apply the appropriate lock type */
2801 switch (strength)
2802 {
2803 case LCS_NONE:
2804
2805 /*
2806 * We don't need a tuple lock, only the ability to re-fetch
2807 * the row.
2808 */
2809 return ROW_MARK_REFERENCE;
2810 break;
2811 case LCS_FORKEYSHARE:
2812 return ROW_MARK_KEYSHARE;
2813 break;
2814 case LCS_FORSHARE:
2815 return ROW_MARK_SHARE;
2816 break;
2817 case LCS_FORNOKEYUPDATE:
2819 break;
2820 case LCS_FORUPDATE:
2821 return ROW_MARK_EXCLUSIVE;
2822 break;
2823 }
2824 elog(ERROR, "unrecognized LockClauseStrength %d", (int) strength);
2825 return ROW_MARK_EXCLUSIVE; /* keep compiler quiet */
2826 }
2827}
FdwRoutine * GetFdwRoutineByRelId(Oid relid)
Definition foreign.c:451
@ LCS_FORUPDATE
Definition lockoptions.h:28
@ LCS_FORSHARE
Definition lockoptions.h:26
@ LCS_FORKEYSHARE
Definition lockoptions.h:25
@ LCS_FORNOKEYUPDATE
Definition lockoptions.h:27
@ ROW_MARK_COPY
Definition plannodes.h:1562
@ ROW_MARK_REFERENCE
Definition plannodes.h:1561
@ ROW_MARK_SHARE
Definition plannodes.h:1559
@ ROW_MARK_EXCLUSIVE
Definition plannodes.h:1557
@ ROW_MARK_NOKEYEXCLUSIVE
Definition plannodes.h:1558
@ ROW_MARK_KEYSHARE
Definition plannodes.h:1560
GetForeignRowMarkType_function GetForeignRowMarkType
Definition fdwapi.h:251

References elog, ERROR, fb(), GetFdwRoutineByRelId(), FdwRoutine::GetForeignRowMarkType, LCS_FORKEYSHARE, LCS_FORNOKEYUPDATE, LCS_FORSHARE, LCS_FORUPDATE, LCS_NONE, ROW_MARK_COPY, ROW_MARK_EXCLUSIVE, ROW_MARK_KEYSHARE, ROW_MARK_NOKEYEXCLUSIVE, ROW_MARK_REFERENCE, ROW_MARK_SHARE, and RTE_RELATION.

Referenced by expand_single_inheritance_child(), and preprocess_rowmarks().

◆ standard_planner()

PlannedStmt * standard_planner ( Query parse,
const char query_string,
int  cursorOptions,
ParamListInfo  boundParams,
ExplainState es 
)

Definition at line 346 of file planner.c.

348{
350 PlannerGlobal *glob;
351 double tuple_fraction;
355 Plan *top_plan;
356 ListCell *lp,
357 *lr,
358 *lc;
359
360 /*
361 * Set up global state for this planner invocation. This data is needed
362 * across all levels of sub-Query that might exist in the given command,
363 * so we keep it in a separate struct that's linked to by each per-Query
364 * PlannerInfo.
365 */
366 glob = makeNode(PlannerGlobal);
367
368 glob->boundParams = boundParams;
369 glob->subplans = NIL;
370 glob->subpaths = NIL;
371 glob->subroots = NIL;
372 glob->rewindPlanIDs = NULL;
373 glob->finalrtable = NIL;
374 glob->allRelids = NULL;
375 glob->prunableRelids = NULL;
376 glob->finalrteperminfos = NIL;
377 glob->finalrowmarks = NIL;
378 glob->resultRelations = NIL;
379 glob->appendRelations = NIL;
380 glob->partPruneInfos = NIL;
381 glob->relationOids = NIL;
382 glob->invalItems = NIL;
383 glob->paramExecTypes = NIL;
384 glob->lastPHId = 0;
385 glob->lastRowMarkId = 0;
386 glob->lastPlanNodeId = 0;
387 glob->transientPlan = false;
388 glob->dependsOnRole = false;
389 glob->partition_directory = NULL;
390 glob->rel_notnullatts_hash = NULL;
391
392 /*
393 * Assess whether it's feasible to use parallel mode for this query. We
394 * can't do this in a standalone backend, or if the command will try to
395 * modify any data, or if this is a cursor operation, or if GUCs are set
396 * to values that don't permit parallelism, or if parallel-unsafe
397 * functions are present in the query tree.
398 *
399 * (Note that we do allow CREATE TABLE AS, SELECT INTO, and CREATE
400 * MATERIALIZED VIEW to use parallel plans, but this is safe only because
401 * the command is writing into a completely new table which workers won't
402 * be able to see. If the workers could see the table, the fact that
403 * group locking would cause them to ignore the leader's heavyweight GIN
404 * page locks would make this unsafe. We'll have to fix that somehow if
405 * we want to allow parallel inserts in general; updates and deletes have
406 * additional problems especially around combo CIDs.)
407 *
408 * For now, we don't try to use parallel mode if we're running inside a
409 * parallel worker. We might eventually be able to relax this
410 * restriction, but for now it seems best not to have parallel workers
411 * trying to create their own parallel workers.
412 */
413 if ((cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 &&
415 parse->commandType == CMD_SELECT &&
416 !parse->hasModifyingCTE &&
419 {
420 /* all the cheap tests pass, so scan the query tree */
423 }
424 else
425 {
426 /* skip the query tree scan, just assume it's unsafe */
428 glob->parallelModeOK = false;
429 }
430
431 /*
432 * glob->parallelModeNeeded is normally set to false here and changed to
433 * true during plan creation if a Gather or Gather Merge plan is actually
434 * created (cf. create_gather_plan, create_gather_merge_plan).
435 *
436 * However, if debug_parallel_query = on or debug_parallel_query =
437 * regress, then we impose parallel mode whenever it's safe to do so, even
438 * if the final plan doesn't use parallelism. It's not safe to do so if
439 * the query contains anything parallel-unsafe; parallelModeOK will be
440 * false in that case. Note that parallelModeOK can't change after this
441 * point. Otherwise, everything in the query is either parallel-safe or
442 * parallel-restricted, and in either case it should be OK to impose
443 * parallel-mode restrictions. If that ends up breaking something, then
444 * either some function the user included in the query is incorrectly
445 * labeled as parallel-safe or parallel-restricted when in reality it's
446 * parallel-unsafe, or else the query planner itself has a bug.
447 */
448 glob->parallelModeNeeded = glob->parallelModeOK &&
450
451 /* Determine what fraction of the plan is likely to be scanned */
452 if (cursorOptions & CURSOR_OPT_FAST_PLAN)
453 {
454 /*
455 * We have no real idea how many tuples the user will ultimately FETCH
456 * from a cursor, but it is often the case that he doesn't want 'em
457 * all, or would prefer a fast-start plan anyway so that he can
458 * process some of the tuples sooner. Use a GUC parameter to decide
459 * what fraction to optimize for.
460 */
461 tuple_fraction = cursor_tuple_fraction;
462
463 /*
464 * We document cursor_tuple_fraction as simply being a fraction, which
465 * means the edge cases 0 and 1 have to be treated specially here. We
466 * convert 1 to 0 ("all the tuples") and 0 to a very small fraction.
467 */
468 if (tuple_fraction >= 1.0)
469 tuple_fraction = 0.0;
470 else if (tuple_fraction <= 0.0)
471 tuple_fraction = 1e-10;
472 }
473 else
474 {
475 /* Default assumption is we need all the tuples */
476 tuple_fraction = 0.0;
477 }
478
479 /*
480 * Compute the initial path generation strategy mask.
481 *
482 * Some strategies, such as PGS_FOREIGNJOIN, have no corresponding enable_*
483 * GUC, and so the corresponding bits are always set in the default
484 * strategy mask.
485 *
486 * It may seem surprising that enable_indexscan sets both PGS_INDEXSCAN
487 * and PGS_INDEXONLYSCAN. However, the historical behavior of this GUC
488 * corresponds to this exactly: enable_indexscan=off disables both
489 * index-scan and index-only scan paths, whereas enable_indexonlyscan=off
490 * converts the index-only scan paths that we would have considered into
491 * index scan paths.
492 */
495 if (enable_tidscan)
497 if (enable_seqscan)
506 {
508 if (enable_material)
510 }
511 if (enable_nestloop)
512 {
514 if (enable_material)
516 if (enable_memoize)
518 }
519 if (enable_hashjoin)
525
526 /* Allow plugins to take control after we've initialized "glob" */
528 (*planner_setup_hook) (glob, parse, query_string, cursorOptions,
529 &tuple_fraction, es);
530
531 /* primary planning entry point (may recurse for subqueries) */
532 root = subquery_planner(glob, parse, NULL, NULL, NULL, false,
533 tuple_fraction, NULL);
534
535 /* Select best Path and turn it into a Plan */
538
540
541 /*
542 * If creating a plan for a scrollable cursor, make sure it can run
543 * backwards on demand. Add a Material node at the top at need.
544 */
545 if (cursorOptions & CURSOR_OPT_SCROLL)
546 {
549 }
550
551 /*
552 * Optionally add a Gather node for testing purposes, provided this is
553 * actually a safe thing to do.
554 *
555 * We can add Gather even when top_plan has parallel-safe initPlans, but
556 * then we have to move the initPlans to the Gather node because of
557 * SS_finalize_plan's limitations. That would cause cosmetic breakage of
558 * regression tests when debug_parallel_query = regress, because initPlans
559 * that would normally appear on the top_plan move to the Gather, causing
560 * them to disappear from EXPLAIN output. That doesn't seem worth kluging
561 * EXPLAIN to hide, so skip it when debug_parallel_query = regress.
562 */
564 top_plan->parallel_safe &&
565 (top_plan->initPlan == NIL ||
567 {
570 bool unsafe_initplans;
571
572 gather->plan.targetlist = top_plan->targetlist;
573 gather->plan.qual = NIL;
574 gather->plan.lefttree = top_plan;
575 gather->plan.righttree = NULL;
576 gather->num_workers = 1;
577 gather->single_copy = true;
579
580 /* Transfer any initPlans to the new top node */
581 gather->plan.initPlan = top_plan->initPlan;
582 top_plan->initPlan = NIL;
583
584 /*
585 * Since this Gather has no parallel-aware descendants to signal to,
586 * we don't need a rescan Param.
587 */
588 gather->rescan_param = -1;
589
590 /*
591 * Ideally we'd use cost_gather here, but setting up dummy path data
592 * to satisfy it doesn't seem much cleaner than knowing what it does.
593 */
594 gather->plan.startup_cost = top_plan->startup_cost +
596 gather->plan.total_cost = top_plan->total_cost +
598 gather->plan.plan_rows = top_plan->plan_rows;
599 gather->plan.plan_width = top_plan->plan_width;
600 gather->plan.parallel_aware = false;
601 gather->plan.parallel_safe = false;
602
603 /*
604 * Delete the initplans' cost from top_plan. We needn't add it to the
605 * Gather node, since the above coding already included it there.
606 */
607 SS_compute_initplan_cost(gather->plan.initPlan,
609 top_plan->startup_cost -= initplan_cost;
610 top_plan->total_cost -= initplan_cost;
611
612 /* use parallel mode for parallel plans. */
613 root->glob->parallelModeNeeded = true;
614
615 top_plan = &gather->plan;
616 }
617
618 /*
619 * If any Params were generated, run through the plan tree and compute
620 * each plan node's extParam/allParam sets. Ideally we'd merge this into
621 * set_plan_references' tree traversal, but for now it has to be separate
622 * because we need to visit subplans before not after main plan.
623 */
624 if (glob->paramExecTypes != NIL)
625 {
626 Assert(list_length(glob->subplans) == list_length(glob->subroots));
627 forboth(lp, glob->subplans, lr, glob->subroots)
628 {
629 Plan *subplan = (Plan *) lfirst(lp);
631
632 SS_finalize_plan(subroot, subplan);
633 }
635 }
636
637 /* final cleanup of the plan */
638 Assert(glob->finalrtable == NIL);
639 Assert(glob->finalrteperminfos == NIL);
640 Assert(glob->finalrowmarks == NIL);
641 Assert(glob->resultRelations == NIL);
642 Assert(glob->appendRelations == NIL);
644 /* ... and the subplans (both regular subplans and initplans) */
645 Assert(list_length(glob->subplans) == list_length(glob->subroots));
646 forboth(lp, glob->subplans, lr, glob->subroots)
647 {
648 Plan *subplan = (Plan *) lfirst(lp);
650
651 lfirst(lp) = set_plan_references(subroot, subplan);
652 }
653
654 /* build the PlannedStmt result */
656
657 result->commandType = parse->commandType;
658 result->queryId = parse->queryId;
659 result->planOrigin = PLAN_STMT_STANDARD;
660 result->hasReturning = (parse->returningList != NIL);
661 result->hasModifyingCTE = parse->hasModifyingCTE;
662 result->canSetTag = parse->canSetTag;
663 result->transientPlan = glob->transientPlan;
664 result->dependsOnRole = glob->dependsOnRole;
665 result->parallelModeNeeded = glob->parallelModeNeeded;
666 result->planTree = top_plan;
667 result->partPruneInfos = glob->partPruneInfos;
668 result->rtable = glob->finalrtable;
669 result->unprunableRelids = bms_difference(glob->allRelids,
670 glob->prunableRelids);
671 result->permInfos = glob->finalrteperminfos;
672 result->subrtinfos = glob->subrtinfos;
673 result->appendRelations = glob->appendRelations;
674 result->subplans = glob->subplans;
675 result->rewindPlanIDs = glob->rewindPlanIDs;
676 result->rowMarks = glob->finalrowmarks;
677
678 /*
679 * Compute resultRelationRelids and rowMarkRelids from resultRelations and
680 * rowMarks. These can be used for cheap membership checks.
681 */
682 foreach(lc, glob->resultRelations)
683 result->resultRelationRelids = bms_add_member(result->resultRelationRelids,
684 lfirst_int(lc));
685 foreach(lc, glob->finalrowmarks)
686 result->rowMarkRelids = bms_add_member(result->rowMarkRelids,
687 ((PlanRowMark *) lfirst(lc))->rti);
688
689 result->relationOids = glob->relationOids;
690 result->invalItems = glob->invalItems;
691 result->paramExecTypes = glob->paramExecTypes;
692 /* utilityStmt should be null, but we might as well copy it */
693 result->utilityStmt = parse->utilityStmt;
694 result->elidedNodes = glob->elidedNodes;
695 result->stmt_location = parse->stmt_location;
696 result->stmt_len = parse->stmt_len;
697
698 result->jitFlags = PGJIT_NONE;
699 if (jit_enabled && jit_above_cost >= 0 &&
700 top_plan->total_cost > jit_above_cost)
701 {
702 result->jitFlags |= PGJIT_PERFORM;
703
704 /*
705 * Decide how much effort should be put into generating better code.
706 */
707 if (jit_optimize_above_cost >= 0 &&
708 top_plan->total_cost > jit_optimize_above_cost)
709 result->jitFlags |= PGJIT_OPT3;
710 if (jit_inline_above_cost >= 0 &&
711 top_plan->total_cost > jit_inline_above_cost)
712 result->jitFlags |= PGJIT_INLINE;
713
714 /*
715 * Decide which operations should be JITed.
716 */
717 if (jit_expressions)
718 result->jitFlags |= PGJIT_EXPR;
720 result->jitFlags |= PGJIT_DEFORM;
721 }
722
723 /* Allow plugins to take control before we discard "glob" */
725 (*planner_shutdown_hook) (glob, parse, query_string, result);
726
727 if (glob->partition_directory != NULL)
728 DestroyPartitionDirectory(glob->partition_directory);
729
730 return result;
731}
Bitmapset * bms_difference(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:346
char max_parallel_hazard(Query *parse)
Definition clauses.c:763
bool enable_seqscan
Definition costsize.c:146
int max_parallel_workers_per_gather
Definition costsize.c:144
bool enable_memoize
Definition costsize.c:156
double parallel_setup_cost
Definition costsize.c:137
bool enable_gathermerge
Definition costsize.c:159
double parallel_tuple_cost
Definition costsize.c:136
bool enable_indexonlyscan
Definition costsize.c:148
bool enable_tidscan
Definition costsize.c:150
bool enable_material
Definition costsize.c:155
bool enable_hashjoin
Definition costsize.c:158
bool enable_mergejoin
Definition costsize.c:157
bool enable_partitionwise_join
Definition costsize.c:160
bool enable_nestloop
Definition costsize.c:154
bool enable_bitmapscan
Definition costsize.c:149
Plan * materialize_finished_plan(Plan *subplan)
Plan * create_plan(PlannerInfo *root, Path *best_path)
Definition createplan.c:339
bool ExecSupportsBackwardScan(Plan *node)
Definition execAmi.c:512
#define IsParallelWorker()
Definition parallel.h:62
double jit_optimize_above_cost
Definition jit.c:42
bool jit_enabled
Definition jit.c:33
bool jit_expressions
Definition jit.c:37
bool jit_tuple_deforming
Definition jit.c:39
double jit_above_cost
Definition jit.c:40
double jit_inline_above_cost
Definition jit.c:41
#define PGJIT_OPT3
Definition jit.h:21
#define PGJIT_NONE
Definition jit.h:19
#define PGJIT_EXPR
Definition jit.h:23
#define PGJIT_DEFORM
Definition jit.h:24
#define PGJIT_INLINE
Definition jit.h:22
#define PGJIT_PERFORM
Definition jit.h:20
@ DEBUG_PARALLEL_REGRESS
Definition optimizer.h:98
@ DEBUG_PARALLEL_OFF
Definition optimizer.h:96
#define CURSOR_OPT_SCROLL
#define CURSOR_OPT_FAST_PLAN
#define CURSOR_OPT_PARALLEL_OK
void DestroyPartitionDirectory(PartitionDirectory pdir)
Definition partdesc.c:484
#define PGS_NESTLOOP_MEMOIZE
Definition pathnodes.h:76
#define PGS_TIDSCAN
Definition pathnodes.h:70
#define PGS_FOREIGNJOIN
Definition pathnodes.h:71
#define PGS_APPEND
Definition pathnodes.h:78
#define PGS_MERGE_APPEND
Definition pathnodes.h:79
#define PGS_SEQSCAN
Definition pathnodes.h:66
#define PGS_CONSIDER_INDEXONLY
Definition pathnodes.h:82
#define PGS_NESTLOOP_MATERIALIZE
Definition pathnodes.h:75
#define PGS_MERGEJOIN_PLAIN
Definition pathnodes.h:72
#define PGS_MERGEJOIN_MATERIALIZE
Definition pathnodes.h:73
#define PGS_HASHJOIN
Definition pathnodes.h:77
#define PGS_CONSIDER_NONPARTIAL
Definition pathnodes.h:84
#define PGS_BITMAPSCAN
Definition pathnodes.h:69
#define PGS_GATHER
Definition pathnodes.h:80
#define PGS_CONSIDER_PARTITIONWISE
Definition pathnodes.h:83
#define PGS_GATHER_MERGE
Definition pathnodes.h:81
#define PGS_INDEXONLYSCAN
Definition pathnodes.h:68
#define PGS_INDEXSCAN
Definition pathnodes.h:67
#define PGS_NESTLOOP_PLAIN
Definition pathnodes.h:74
PlannerInfo * subquery_planner(PlannerGlobal *glob, Query *parse, char *plan_name, PlannerInfo *parent_root, PlannerInfo *alternative_root, bool hasRecursion, double tuple_fraction, SetOperationStmt *setops)
Definition planner.c:770
double cursor_tuple_fraction
Definition planner.c:68
planner_shutdown_hook_type planner_shutdown_hook
Definition planner.c:80
Path * get_cheapest_fractional_path(RelOptInfo *rel, double tuple_fraction)
Definition planner.c:6848
planner_setup_hook_type planner_setup_hook
Definition planner.c:77
int debug_parallel_query
Definition planner.c:69
@ PLAN_STMT_STANDARD
Definition plannodes.h:39
e
Plan * set_plan_references(PlannerInfo *root, Plan *plan)
Definition setrefs.c:291
Bitmapset * prunableRelids
Definition pathnodes.h:206
char maxParallelHazard
Definition pathnodes.h:260
List * subplans
Definition pathnodes.h:178
bool dependsOnRole
Definition pathnodes.h:251
Bitmapset * allRelids
Definition pathnodes.h:199
List * appendRelations
Definition pathnodes.h:221
List * finalrowmarks
Definition pathnodes.h:215
List * paramExecTypes
Definition pathnodes.h:233
bool parallelModeOK
Definition pathnodes.h:254
bool transientPlan
Definition pathnodes.h:248
Bitmapset * rewindPlanIDs
Definition pathnodes.h:190
List * finalrteperminfos
Definition pathnodes.h:209
List * subpaths
Definition pathnodes.h:181
Index lastRowMarkId
Definition pathnodes.h:242
List * resultRelations
Definition pathnodes.h:218
List * partPruneInfos
Definition pathnodes.h:224
List * finalrtable
Definition pathnodes.h:193
uint64 default_pgs_mask
Definition pathnodes.h:263
bool parallelModeNeeded
Definition pathnodes.h:257
void SS_finalize_plan(PlannerInfo *root, Plan *plan)
Definition subselect.c:2551
void SS_compute_initplan_cost(List *init_plans, Cost *initplan_cost_p, bool *unsafe_initplans_p)
Definition subselect.c:2495

References PlannerGlobal::allRelids, PlannerGlobal::appendRelations, Assert, bms_add_member(), bms_difference(), CMD_SELECT, create_plan(), CURSOR_OPT_FAST_PLAN, CURSOR_OPT_PARALLEL_OK, CURSOR_OPT_SCROLL, cursor_tuple_fraction, DEBUG_PARALLEL_OFF, debug_parallel_query, DEBUG_PARALLEL_REGRESS, PlannerGlobal::default_pgs_mask, PlannerGlobal::dependsOnRole, DestroyPartitionDirectory(), PlannerGlobal::elidedNodes, enable_bitmapscan, enable_gathermerge, enable_hashjoin, enable_indexonlyscan, enable_indexscan, enable_material, enable_memoize, enable_mergejoin, enable_nestloop, enable_partitionwise_join, enable_seqscan, enable_tidscan, ExecSupportsBackwardScan(), fb(), fetch_upper_rel(), PlannerGlobal::finalrowmarks, PlannerGlobal::finalrtable, PlannerGlobal::finalrteperminfos, forboth, get_cheapest_fractional_path(), PlannerGlobal::invalItems, IsParallelWorker, IsUnderPostmaster, jit_above_cost, jit_enabled, jit_expressions, jit_inline_above_cost, jit_optimize_above_cost, jit_tuple_deforming, PlannerGlobal::lastPHId, PlannerGlobal::lastPlanNodeId, PlannerGlobal::lastRowMarkId, lfirst, lfirst_int, lfirst_node, list_length(), makeNode, materialize_finished_plan(), max_parallel_hazard(), max_parallel_workers_per_gather, PlannerGlobal::maxParallelHazard, NIL, parallel_setup_cost, parallel_tuple_cost, PlannerGlobal::parallelModeNeeded, PlannerGlobal::parallelModeOK, PlannerGlobal::paramExecTypes, parse(), PlannerGlobal::partPruneInfos, PGJIT_DEFORM, PGJIT_EXPR, PGJIT_INLINE, PGJIT_NONE, PGJIT_OPT3, PGJIT_PERFORM, PGS_APPEND, PGS_BITMAPSCAN, PGS_CONSIDER_INDEXONLY, PGS_CONSIDER_NONPARTIAL, PGS_CONSIDER_PARTITIONWISE, PGS_FOREIGNJOIN, PGS_GATHER, PGS_GATHER_MERGE, PGS_HASHJOIN, PGS_INDEXONLYSCAN, PGS_INDEXSCAN, PGS_MERGE_APPEND, PGS_MERGEJOIN_MATERIALIZE, PGS_MERGEJOIN_PLAIN, PGS_NESTLOOP_MATERIALIZE, PGS_NESTLOOP_MEMOIZE, PGS_NESTLOOP_PLAIN, PGS_SEQSCAN, PGS_TIDSCAN, PLAN_STMT_STANDARD, planner_setup_hook, planner_shutdown_hook, PlannerGlobal::prunableRelids, PlannerGlobal::relationOids, result, PlannerGlobal::resultRelations, PlannerGlobal::rewindPlanIDs, root, set_plan_references(), SS_compute_initplan_cost(), SS_finalize_plan(), PlannerGlobal::subpaths, PlannerGlobal::subplans, subquery_planner(), PlannerGlobal::subrtinfos, PlannerGlobal::transientPlan, and UPPERREL_FINAL.

Referenced by delay_execution_planner(), pgss_planner(), and planner().

◆ standard_qp_callback()

static void standard_qp_callback ( PlannerInfo root,
void extra 
)
static

Definition at line 3723 of file planner.c.

3724{
3725 Query *parse = root->parse;
3727 List *tlist = root->processed_tlist;
3728 List *activeWindows = qp_extra->activeWindows;
3729
3730 /*
3731 * Calculate pathkeys that represent grouping/ordering and/or ordered
3732 * aggregate requirements.
3733 */
3734 if (qp_extra->gset_data)
3735 {
3736 /*
3737 * With grouping sets, just use the first RollupData's groupClause. We
3738 * don't make any effort to optimize grouping clauses when there are
3739 * grouping sets, nor can we combine aggregate ordering keys with
3740 * grouping.
3741 */
3742 List *rollups = qp_extra->gset_data->rollups;
3743 List *groupClause = (rollups ? linitial_node(RollupData, rollups)->groupClause : NIL);
3744
3745 if (grouping_is_sortable(groupClause))
3746 {
3747 bool sortable;
3748
3749 /*
3750 * The groupClause is logically below the grouping step. So if
3751 * there is an RTE entry for the grouping step, we need to remove
3752 * its RT index from the sort expressions before we make PathKeys
3753 * for them.
3754 */
3755 root->group_pathkeys =
3757 &groupClause,
3758 tlist,
3759 false,
3760 parse->hasGroupRTE,
3761 &sortable,
3762 false);
3764 root->num_groupby_pathkeys = list_length(root->group_pathkeys);
3765 }
3766 else
3767 {
3768 root->group_pathkeys = NIL;
3769 root->num_groupby_pathkeys = 0;
3770 }
3771 }
3772 else if (parse->groupClause || root->numOrderedAggs > 0)
3773 {
3774 /*
3775 * With a plain GROUP BY list, we can remove any grouping items that
3776 * are proven redundant by EquivalenceClass processing. For example,
3777 * we can remove y given "WHERE x = y GROUP BY x, y". These aren't
3778 * especially common cases, but they're nearly free to detect. Note
3779 * that we remove redundant items from processed_groupClause but not
3780 * the original parse->groupClause.
3781 */
3782 bool sortable;
3783
3784 /*
3785 * Convert group clauses into pathkeys. Set the ec_sortref field of
3786 * EquivalenceClass'es if it's not set yet.
3787 */
3788 root->group_pathkeys =
3790 &root->processed_groupClause,
3791 tlist,
3792 true,
3793 false,
3794 &sortable,
3795 true);
3796 if (!sortable)
3797 {
3798 /* Can't sort; no point in considering aggregate ordering either */
3799 root->group_pathkeys = NIL;
3800 root->num_groupby_pathkeys = 0;
3801 }
3802 else
3803 {
3804 root->num_groupby_pathkeys = list_length(root->group_pathkeys);
3805 /* If we have ordered aggs, consider adding onto group_pathkeys */
3806 if (root->numOrderedAggs > 0)
3808 }
3809 }
3810 else
3811 {
3812 root->group_pathkeys = NIL;
3813 root->num_groupby_pathkeys = 0;
3814 }
3815
3816 /* We consider only the first (bottom) window in pathkeys logic */
3817 if (activeWindows != NIL)
3818 {
3819 WindowClause *wc = linitial_node(WindowClause, activeWindows);
3820
3821 root->window_pathkeys = make_pathkeys_for_window(root,
3822 wc,
3823 tlist);
3824 }
3825 else
3826 root->window_pathkeys = NIL;
3827
3828 /*
3829 * As with GROUP BY, we can discard any DISTINCT items that are proven
3830 * redundant by EquivalenceClass processing. The non-redundant list is
3831 * kept in root->processed_distinctClause, leaving the original
3832 * parse->distinctClause alone.
3833 */
3834 if (parse->distinctClause)
3835 {
3836 bool sortable;
3837
3838 /* Make a copy since pathkey processing can modify the list */
3839 root->processed_distinctClause = list_copy(parse->distinctClause);
3840 root->distinct_pathkeys =
3842 &root->processed_distinctClause,
3843 tlist,
3844 true,
3845 false,
3846 &sortable,
3847 false);
3848 if (!sortable)
3849 root->distinct_pathkeys = NIL;
3850 }
3851 else
3852 root->distinct_pathkeys = NIL;
3853
3854 root->sort_pathkeys =
3856 parse->sortClause,
3857 tlist);
3858
3859 /* setting setop_pathkeys might be useful to the union planner */
3860 if (qp_extra->setop != NULL)
3861 {
3862 List *groupClauses;
3863 bool sortable;
3864
3865 groupClauses = generate_setop_child_grouplist(qp_extra->setop, tlist);
3866
3867 root->setop_pathkeys =
3869 &groupClauses,
3870 tlist,
3871 false,
3872 false,
3873 &sortable,
3874 false);
3875 if (!sortable)
3876 root->setop_pathkeys = NIL;
3877 }
3878 else
3879 root->setop_pathkeys = NIL;
3880
3881 /*
3882 * Figure out whether we want a sorted result from query_planner.
3883 *
3884 * If we have a sortable GROUP BY clause, then we want a result sorted
3885 * properly for grouping. Otherwise, if we have window functions to
3886 * evaluate, we try to sort for the first window. Otherwise, if there's a
3887 * sortable DISTINCT clause that's more rigorous than the ORDER BY clause,
3888 * we try to produce output that's sufficiently well sorted for the
3889 * DISTINCT. Otherwise, if there is an ORDER BY clause, we want to sort
3890 * by the ORDER BY clause. Otherwise, if we're a subquery being planned
3891 * for a set operation which can benefit from presorted results and have a
3892 * sortable targetlist, we want to sort by the target list.
3893 *
3894 * Note: if we have both ORDER BY and GROUP BY, and ORDER BY is a superset
3895 * of GROUP BY, it would be tempting to request sort by ORDER BY --- but
3896 * that might just leave us failing to exploit an available sort order at
3897 * all. Needs more thought. The choice for DISTINCT versus ORDER BY is
3898 * much easier, since we know that the parser ensured that one is a
3899 * superset of the other.
3900 */
3901 if (root->group_pathkeys)
3902 root->query_pathkeys = root->group_pathkeys;
3903 else if (root->window_pathkeys)
3904 root->query_pathkeys = root->window_pathkeys;
3905 else if (list_length(root->distinct_pathkeys) >
3906 list_length(root->sort_pathkeys))
3907 root->query_pathkeys = root->distinct_pathkeys;
3908 else if (root->sort_pathkeys)
3909 root->query_pathkeys = root->sort_pathkeys;
3910 else if (root->setop_pathkeys != NIL)
3911 root->query_pathkeys = root->setop_pathkeys;
3912 else
3913 root->query_pathkeys = NIL;
3914}
static void adjust_group_pathkeys_for_groupagg(PlannerInfo *root)
Definition planner.c:3499
static List * generate_setop_child_grouplist(SetOperationStmt *op, List *targetlist)
Definition planner.c:8607

References adjust_group_pathkeys_for_groupagg(), Assert, fb(), generate_setop_child_grouplist(), grouping_is_sortable(), linitial_node, list_copy(), list_length(), make_pathkeys_for_sortclauses(), make_pathkeys_for_sortclauses_extended(), make_pathkeys_for_window(), NIL, parse(), and root.

Referenced by grouping_planner().

◆ subquery_planner()

PlannerInfo * subquery_planner ( PlannerGlobal glob,
Query parse,
char plan_name,
PlannerInfo parent_root,
PlannerInfo alternative_root,
bool  hasRecursion,
double  tuple_fraction,
SetOperationStmt setops 
)

Definition at line 770 of file planner.c.

774{
779 int havingIdx;
780 bool hasOuterJoins;
781 bool hasResultRTEs;
783 ListCell *l;
784
785 /* Create a PlannerInfo data structure for this subquery */
787 root->parse = parse;
788 root->glob = glob;
789 root->query_level = parent_root ? parent_root->query_level + 1 : 1;
790 root->plan_name = plan_name;
791 if (alternative_root != NULL)
792 root->alternative_plan_name = alternative_root->plan_name;
793 else
794 root->alternative_plan_name = plan_name;
795 root->parent_root = parent_root;
796 root->plan_params = NIL;
797 root->outer_params = NULL;
798 root->planner_cxt = CurrentMemoryContext;
799 root->init_plans = NIL;
800 root->cte_plan_ids = NIL;
801 root->multiexpr_params = NIL;
802 root->join_domains = NIL;
803 root->eq_classes = NIL;
804 root->ec_merging_done = false;
805 root->last_rinfo_serial = 0;
806 root->all_result_relids =
807 parse->resultRelation ? bms_make_singleton(parse->resultRelation) : NULL;
808 root->leaf_result_relids = NULL; /* we'll find out leaf-ness later */
809 root->append_rel_list = NIL;
810 root->row_identity_vars = NIL;
811 root->rowMarks = NIL;
812 memset(root->upper_rels, 0, sizeof(root->upper_rels));
813 memset(root->upper_targets, 0, sizeof(root->upper_targets));
814 root->processed_groupClause = NIL;
815 root->processed_distinctClause = NIL;
816 root->processed_tlist = NIL;
817 root->update_colnos = NIL;
818 root->grouping_map = NULL;
819 root->minmax_aggs = NIL;
820 root->qual_security_level = 0;
821 root->hasPseudoConstantQuals = false;
822 root->hasAlternativeSubPlans = false;
823 root->placeholdersFrozen = false;
824 root->hasRecursion = hasRecursion;
825 root->assumeReplanning = false;
826 if (hasRecursion)
827 root->wt_param_id = assign_special_exec_param(root);
828 else
829 root->wt_param_id = -1;
830 root->non_recursive_path = NULL;
831
832 /*
833 * Create the top-level join domain. This won't have valid contents until
834 * deconstruct_jointree fills it in, but the node needs to exist before
835 * that so we can build EquivalenceClasses referencing it.
836 */
837 root->join_domains = list_make1(makeNode(JoinDomain));
838
839 /*
840 * If there is a WITH list, process each WITH query and either convert it
841 * to RTE_SUBQUERY RTE(s) or build an initplan SubPlan structure for it.
842 */
843 if (parse->cteList)
845
846 /*
847 * If it's a MERGE command, transform the joinlist as appropriate.
848 */
850
851 /*
852 * Reject FOR PORTION OF on a generated column. We can't write to a
853 * virtual generated column, and a stored generated column should be
854 * written by its own expression.
855 *
856 * We do this in the planner rather than parse analysis so that updatable
857 * views have been rewritten; otherwise they would mask which columns are
858 * generated. We need to check before preprocess_relation_rtes(), so that
859 * for virtual generated columns we still have the rangeVar. After that
860 * it is replaced by the column's expression.
861 *
862 * XXX: We plan to implement PERIODs as stored generated columns, so later
863 * we will loosen this restriction if the column belongs to a PERIOD.
864 */
865 if (parse->forPortionOf)
866 {
867 ForPortionOfExpr *forPortionOf = parse->forPortionOf;
868 RangeTblEntry *rte = rt_fetch(parse->resultRelation, parse->rtable);
869
870 if (get_attgenerated(rte->relid, forPortionOf->rangeVar->varattno))
873 errmsg("cannot use generated column \"%s\" in FOR PORTION OF",
874 forPortionOf->range_name)));
875 }
876
877 /*
878 * Scan the rangetable for relation RTEs and retrieve the necessary
879 * catalog information for each relation. Using this information, clear
880 * the inh flag for any relation that has no children, collect not-null
881 * attribute numbers for any relation that has column not-null
882 * constraints, and expand virtual generated columns for any relation that
883 * contains them. Note that this step does not descend into sublinks and
884 * subqueries; if we pull up any sublinks or subqueries below, their
885 * relation RTEs are processed just before pulling them up.
886 */
888
889 /*
890 * If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so
891 * that we don't need so many special cases to deal with that situation.
892 */
894
895 /*
896 * Look for ANY and EXISTS SubLinks in WHERE and JOIN/ON clauses, and try
897 * to transform them into joins. Note that this step does not descend
898 * into subqueries; if we pull up any subqueries below, their SubLinks are
899 * processed just before pulling them up.
900 */
901 if (parse->hasSubLinks)
903
904 /*
905 * Scan the rangetable for function RTEs, do const-simplification on them,
906 * and then inline them if possible (producing subqueries that might get
907 * pulled up next). Recursion issues here are handled in the same way as
908 * for SubLinks.
909 */
911
912 /*
913 * Check to see if any subqueries in the jointree can be merged into this
914 * query.
915 */
917
918 /*
919 * If this is a simple UNION ALL query, flatten it into an appendrel. We
920 * do this now because it requires applying pull_up_subqueries to the leaf
921 * queries of the UNION ALL, which weren't touched above because they
922 * weren't referenced by the jointree (they will be after we do this).
923 */
924 if (parse->setOperations)
926
927 /*
928 * Survey the rangetable to see what kinds of entries are present. We can
929 * skip some later processing if relevant SQL features are not used; for
930 * example if there are no JOIN RTEs we can avoid the expense of doing
931 * flatten_join_alias_vars(). This must be done after we have finished
932 * adding rangetable entries, of course. (Note: actually, processing of
933 * inherited or partitioned rels can cause RTEs for their child tables to
934 * get added later; but those must all be RTE_RELATION entries, so they
935 * don't invalidate the conclusions drawn here.)
936 */
937 root->hasJoinRTEs = false;
938 root->hasLateralRTEs = false;
939 root->group_rtindex = 0;
940 hasOuterJoins = false;
941 hasResultRTEs = false;
942 foreach(l, parse->rtable)
943 {
945
946 switch (rte->rtekind)
947 {
948 case RTE_JOIN:
949 root->hasJoinRTEs = true;
950 if (IS_OUTER_JOIN(rte->jointype))
951 hasOuterJoins = true;
952 break;
953 case RTE_RESULT:
954 hasResultRTEs = true;
955 break;
956 case RTE_GROUP:
957 Assert(parse->hasGroupRTE);
958 root->group_rtindex = list_cell_number(parse->rtable, l) + 1;
959 break;
960 default:
961 /* No work here for other RTE types */
962 break;
963 }
964
965 if (rte->lateral)
966 root->hasLateralRTEs = true;
967
968 /*
969 * We can also determine the maximum security level required for any
970 * securityQuals now. Addition of inheritance-child RTEs won't affect
971 * this, because child tables don't have their own securityQuals; see
972 * expand_single_inheritance_child().
973 */
974 if (rte->securityQuals)
975 root->qual_security_level = Max(root->qual_security_level,
976 list_length(rte->securityQuals));
977 }
978
979 /*
980 * If we have now verified that the query target relation is
981 * non-inheriting, mark it as a leaf target.
982 */
983 if (parse->resultRelation)
984 {
985 RangeTblEntry *rte = rt_fetch(parse->resultRelation, parse->rtable);
986
987 if (!rte->inh)
988 root->leaf_result_relids =
989 bms_make_singleton(parse->resultRelation);
990 }
991
992 /*
993 * This would be a convenient time to check access permissions for all
994 * relations mentioned in the query, since it would be better to fail now,
995 * before doing any detailed planning. However, for historical reasons,
996 * we leave this to be done at executor startup.
997 *
998 * Note, however, that we do need to check access permissions for any view
999 * relations mentioned in the query, in order to prevent information being
1000 * leaked by selectivity estimation functions, which only check view owner
1001 * permissions on underlying tables (see all_rows_selectable() and its
1002 * callers). This is a little ugly, because it means that access
1003 * permissions for views will be checked twice, which is another reason
1004 * why it would be better to do all the ACL checks here.
1005 */
1006 foreach(l, parse->rtable)
1007 {
1009
1010 if (rte->perminfoindex != 0 &&
1011 rte->relkind == RELKIND_VIEW)
1012 {
1014 bool result;
1015
1016 perminfo = getRTEPermissionInfo(parse->rteperminfos, rte);
1018 if (!result)
1020 get_rel_name(perminfo->relid));
1021 }
1022 }
1023
1024 /*
1025 * Preprocess RowMark information. We need to do this after subquery
1026 * pullup, so that all base relations are present.
1027 */
1029
1030 /*
1031 * Set hasHavingQual to remember if HAVING clause is present. Needed
1032 * because preprocess_expression will reduce a constant-true condition to
1033 * an empty qual list ... but "HAVING TRUE" is not a semantic no-op.
1034 */
1035 root->hasHavingQual = (parse->havingQual != NULL);
1036
1037 /*
1038 * Do expression preprocessing on targetlist and quals, as well as other
1039 * random expressions in the querytree. Note that we do not need to
1040 * handle sort/group expressions explicitly, because they are actually
1041 * part of the targetlist.
1042 */
1043 parse->targetList = (List *)
1044 preprocess_expression(root, (Node *) parse->targetList,
1046
1048 foreach(l, parse->withCheckOptions)
1049 {
1051
1052 wco->qual = preprocess_expression(root, wco->qual,
1054 if (wco->qual != NULL)
1056 }
1057 parse->withCheckOptions = newWithCheckOptions;
1058
1059 parse->returningList = (List *)
1060 preprocess_expression(root, (Node *) parse->returningList,
1062
1063 preprocess_qual_conditions(root, (Node *) parse->jointree);
1064
1065 parse->havingQual = preprocess_expression(root, parse->havingQual,
1067
1068 foreach(l, parse->windowClause)
1069 {
1071
1072 /* partitionClause/orderClause are sort/group expressions */
1077 }
1078
1079 parse->limitOffset = preprocess_expression(root, parse->limitOffset,
1081 parse->limitCount = preprocess_expression(root, parse->limitCount,
1083
1084 if (parse->onConflict)
1085 {
1086 parse->onConflict->arbiterElems = (List *)
1088 (Node *) parse->onConflict->arbiterElems,
1090 parse->onConflict->arbiterWhere =
1092 parse->onConflict->arbiterWhere,
1094 parse->onConflict->onConflictSet = (List *)
1096 (Node *) parse->onConflict->onConflictSet,
1098 parse->onConflict->onConflictWhere =
1100 parse->onConflict->onConflictWhere,
1102 /* exclRelTlist contains only Vars, so no preprocessing needed */
1103 }
1104
1105 if (parse->forPortionOf)
1106 {
1107 parse->forPortionOf->targetRange =
1109 parse->forPortionOf->targetRange,
1111 if (contain_volatile_functions(parse->forPortionOf->targetRange))
1112 ereport(ERROR,
1114 errmsg("FOR PORTION OF bounds cannot contain volatile functions")));
1115 }
1116
1117 foreach(l, parse->mergeActionList)
1118 {
1120
1121 action->targetList = (List *)
1123 (Node *) action->targetList,
1125 action->qual =
1127 (Node *) action->qual,
1129 }
1130
1131 parse->mergeJoinCondition =
1132 preprocess_expression(root, parse->mergeJoinCondition, EXPRKIND_QUAL);
1133
1134 root->append_rel_list = (List *)
1135 preprocess_expression(root, (Node *) root->append_rel_list,
1137
1138 /* Also need to preprocess expressions within RTEs */
1139 foreach(l, parse->rtable)
1140 {
1142 int kind;
1143 ListCell *lcsq;
1144
1145 if (rte->rtekind == RTE_RELATION)
1146 {
1147 if (rte->tablesample)
1148 rte->tablesample = (TableSampleClause *)
1150 (Node *) rte->tablesample,
1152 }
1153 else if (rte->rtekind == RTE_SUBQUERY)
1154 {
1155 /*
1156 * We don't want to do all preprocessing yet on the subquery's
1157 * expressions, since that will happen when we plan it. But if it
1158 * contains any join aliases of our level, those have to get
1159 * expanded now, because planning of the subquery won't do it.
1160 * That's only possible if the subquery is LATERAL.
1161 */
1162 if (rte->lateral && root->hasJoinRTEs)
1163 rte->subquery = (Query *)
1165 (Node *) rte->subquery);
1166 }
1167 else if (rte->rtekind == RTE_FUNCTION)
1168 {
1169 /* Preprocess the function expression(s) fully */
1170 kind = rte->lateral ? EXPRKIND_RTFUNC_LATERAL : EXPRKIND_RTFUNC;
1171 rte->functions = (List *)
1172 preprocess_expression(root, (Node *) rte->functions, kind);
1173 }
1174 else if (rte->rtekind == RTE_TABLEFUNC)
1175 {
1176 /* Preprocess the function expression(s) fully */
1178 rte->tablefunc = (TableFunc *)
1179 preprocess_expression(root, (Node *) rte->tablefunc, kind);
1180 }
1181 else if (rte->rtekind == RTE_VALUES)
1182 {
1183 /* Preprocess the values lists fully */
1184 kind = rte->lateral ? EXPRKIND_VALUES_LATERAL : EXPRKIND_VALUES;
1185 rte->values_lists = (List *)
1186 preprocess_expression(root, (Node *) rte->values_lists, kind);
1187 }
1188 else if (rte->rtekind == RTE_GROUP)
1189 {
1190 /* Preprocess the groupexprs list fully */
1191 rte->groupexprs = (List *)
1192 preprocess_expression(root, (Node *) rte->groupexprs,
1194 }
1195
1196 /*
1197 * Process each element of the securityQuals list as if it were a
1198 * separate qual expression (as indeed it is). We need to do it this
1199 * way to get proper canonicalization of AND/OR structure. Note that
1200 * this converts each element into an implicit-AND sublist.
1201 */
1202 foreach(lcsq, rte->securityQuals)
1203 {
1205 (Node *) lfirst(lcsq),
1207 }
1208 }
1209
1210 /*
1211 * Now that we are done preprocessing expressions, and in particular done
1212 * flattening join alias variables, get rid of the joinaliasvars lists.
1213 * They no longer match what expressions in the rest of the tree look
1214 * like, because we have not preprocessed expressions in those lists (and
1215 * do not want to; for example, expanding a SubLink there would result in
1216 * a useless unreferenced subplan). Leaving them in place simply creates
1217 * a hazard for later scans of the tree. We could try to prevent that by
1218 * using QTW_IGNORE_JOINALIASES in every tree scan done after this point,
1219 * but that doesn't sound very reliable.
1220 */
1221 if (root->hasJoinRTEs)
1222 {
1223 foreach(l, parse->rtable)
1224 {
1226
1227 rte->joinaliasvars = NIL;
1228 }
1229 }
1230
1231 /*
1232 * Before we flatten GROUP Vars, identify HAVING clauses whose equality
1233 * semantics disagree with the GROUP BY's. See find_having_conflicts.
1234 */
1235 if (parse->hasGroupRTE)
1237 root->group_rtindex);
1238 else
1240
1241 /*
1242 * Replace any Vars in the subquery's targetlist and havingQual that
1243 * reference GROUP outputs with the underlying grouping expressions.
1244 *
1245 * Note that we need to perform this replacement after we've preprocessed
1246 * the grouping expressions. This is to ensure that there is only one
1247 * instance of SubPlan for each SubLink contained within the grouping
1248 * expressions.
1249 */
1250 if (parse->hasGroupRTE)
1251 {
1252 parse->targetList = (List *)
1253 flatten_group_exprs(root, root->parse, (Node *) parse->targetList);
1254 parse->havingQual =
1255 flatten_group_exprs(root, root->parse, parse->havingQual);
1256 }
1257
1258 /* Constant-folding might have removed all set-returning functions */
1259 if (parse->hasTargetSRFs)
1260 parse->hasTargetSRFs = expression_returns_set((Node *) parse->targetList);
1261
1262 /*
1263 * If we have grouping sets, expand the groupingSets tree of this query to
1264 * a flat list of grouping sets. We need to do this before optimizing
1265 * HAVING, since we can't easily tell if there's an empty grouping set
1266 * until we have this representation.
1267 */
1268 if (parse->groupingSets)
1269 {
1270 parse->groupingSets =
1271 expand_grouping_sets(parse->groupingSets, parse->groupDistinct, -1);
1272 }
1273
1274 /*
1275 * In some cases we may want to transfer a HAVING clause into WHERE. We
1276 * cannot do so if the HAVING clause contains aggregates (obviously) or
1277 * volatile functions (since a HAVING clause is supposed to be executed
1278 * only once per group). We also can't do this if there are any grouping
1279 * sets and the clause references any columns that are nullable by the
1280 * grouping sets; the nulled values of those columns are not available
1281 * before the grouping step. (The test on groupClause might seem wrong,
1282 * but it's okay: it's just an optimization to avoid running pull_varnos
1283 * when there cannot be any Vars in the HAVING clause.)
1284 *
1285 * We also cannot do this for HAVING clauses that conflict with GROUP BY
1286 * on collation or operator family. Both kinds of conflict are detected
1287 * before flatten_group_exprs (see find_having_conflicts above) and
1288 * recorded in the havingPushdownConflicts bitmapset. The bitmapset
1289 * indexes remain valid here because flatten_group_exprs uses
1290 * expression_tree_mutator, which preserves the list length and ordering
1291 * of havingQual.
1292 *
1293 * Also, it may be that the clause is so expensive to execute that we're
1294 * better off doing it only once per group, despite the loss of
1295 * selectivity. This is hard to estimate short of doing the entire
1296 * planning process twice, so we use a heuristic: clauses containing
1297 * subplans are left in HAVING. Otherwise, we move or copy the HAVING
1298 * clause into WHERE, in hopes of eliminating tuples before aggregation
1299 * instead of after.
1300 *
1301 * If the query has no empty grouping set then we can simply move such a
1302 * clause into WHERE; any group that fails the clause will not be in the
1303 * output because none of its tuples will reach the grouping or
1304 * aggregation stage. Otherwise we have to keep the clause in HAVING to
1305 * ensure that we don't emit a bogus aggregated row. But then the HAVING
1306 * clause must be degenerate (variable-free), so we can copy it into WHERE
1307 * so that query_planner() can use it in a gating Result node. (This could
1308 * be done better, but it seems not worth optimizing.)
1309 *
1310 * Note that a HAVING clause may contain expressions that are not fully
1311 * preprocessed. This can happen if these expressions are part of
1312 * grouping items. In such cases, they are replaced with GROUP Vars in
1313 * the parser and then replaced back after we're done with expression
1314 * preprocessing on havingQual. This is not an issue if the clause
1315 * remains in HAVING, because these expressions will be matched to lower
1316 * target items in setrefs.c. However, if the clause is moved or copied
1317 * into WHERE, we need to ensure that these expressions are fully
1318 * preprocessed.
1319 *
1320 * Note that both havingQual and parse->jointree->quals are in
1321 * implicitly-ANDed-list form at this point, even though they are declared
1322 * as Node *.
1323 */
1324 newHaving = NIL;
1325 havingIdx = 0;
1326 foreach(l, (List *) parse->havingQual)
1327 {
1328 Node *havingclause = (Node *) lfirst(l);
1329
1334 (parse->groupClause && parse->groupingSets &&
1335 bms_is_member(root->group_rtindex, pull_varnos(root, havingclause))))
1336 {
1337 /* keep it in HAVING */
1339 }
1340 else if (parse->groupClause &&
1341 (parse->groupingSets == NIL ||
1342 (List *) linitial(parse->groupingSets) != NIL))
1343 {
1344 /* There is GROUP BY, but no empty grouping set */
1346
1347 /* Preprocess the HAVING clause fully */
1350 /* ... and move it to WHERE */
1351 parse->jointree->quals = (Node *)
1352 list_concat((List *) parse->jointree->quals,
1353 (List *) whereclause);
1354 }
1355 else
1356 {
1357 /* There is an empty grouping set (perhaps implicitly) */
1359
1360 /* Preprocess the HAVING clause fully */
1363 /* ... and put a copy in WHERE */
1364 parse->jointree->quals = (Node *)
1365 list_concat((List *) parse->jointree->quals,
1366 (List *) whereclause);
1367 /* ... and also keep it in HAVING */
1369 }
1370
1371 havingIdx++;
1372 }
1373 parse->havingQual = (Node *) newHaving;
1374
1375 /*
1376 * If we have any outer joins, try to reduce them to plain inner joins.
1377 * This step is most easily done after we've done expression
1378 * preprocessing.
1379 */
1380 if (hasOuterJoins)
1382
1383 /*
1384 * If we have any RTE_RESULT relations, see if they can be deleted from
1385 * the jointree. We also rely on this processing to flatten single-child
1386 * FromExprs underneath outer joins. This step is most effectively done
1387 * after we've done expression preprocessing and outer join reduction.
1388 */
1391
1392 /*
1393 * Do the main planning.
1394 */
1395 grouping_planner(root, tuple_fraction, setops);
1396
1397 /*
1398 * Capture the set of outer-level param IDs we have access to, for use in
1399 * extParam/allParam calculations later.
1400 */
1402
1403 /*
1404 * If any initPlans were created in this query level, adjust the surviving
1405 * Paths' costs and parallel-safety flags to account for them. The
1406 * initPlans won't actually get attached to the plan tree till
1407 * create_plan() runs, but we must include their effects now.
1408 */
1411
1412 /*
1413 * Make sure we've identified the cheapest Path for the final rel. (By
1414 * doing this here not in grouping_planner, we include initPlan costs in
1415 * the decision, though it's unlikely that will change anything.)
1416 */
1418
1419 return root;
1420}
@ ACLCHECK_NO_PRIV
Definition acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
bool contain_agg_clause(Node *clause)
Definition clauses.c:210
bool contain_subplans(Node *clause)
Definition clauses.c:359
bool ExecCheckOneRelPerms(RTEPermissionInfo *perminfo)
Definition execMain.c:657
char * get_rel_name(Oid relid)
Definition lsyscache.c:2242
char get_attgenerated(Oid relid, AttrNumber attnum)
Definition lsyscache.c:1114
#define IS_OUTER_JOIN(jointype)
Definition nodes.h:346
List * expand_grouping_sets(List *groupingSets, bool groupDistinct, int limit)
Definition parse_agg.c:2019
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
@ RTE_JOIN
@ RTE_VALUES
@ RTE_SUBQUERY
@ RTE_RESULT
@ RTE_FUNCTION
@ RTE_TABLEFUNC
@ RTE_GROUP
@ OBJECT_VIEW
static int list_cell_number(const List *l, const ListCell *c)
Definition pg_list.h:365
#define EXPRKIND_TABLEFUNC_LATERAL
Definition planner.c:99
#define EXPRKIND_APPINFO
Definition planner.c:94
static void preprocess_rowmarks(PlannerInfo *root)
Definition planner.c:2669
#define EXPRKIND_GROUPEXPR
Definition planner.c:100
static Bitmapset * find_having_conflicts(Query *parse, Index group_rtindex)
Definition planner.c:1587
#define EXPRKIND_RTFUNC_LATERAL
Definition planner.c:90
#define EXPRKIND_VALUES_LATERAL
Definition planner.c:92
#define EXPRKIND_LIMIT
Definition planner.c:93
static void grouping_planner(PlannerInfo *root, double tuple_fraction, SetOperationStmt *setops)
Definition planner.c:1704
#define EXPRKIND_ARBITER_ELEM
Definition planner.c:97
void preprocess_function_rtes(PlannerInfo *root)
void flatten_simple_union_all(PlannerInfo *root)
void transform_MERGE_to_join(Query *parse)
void remove_useless_result_rtes(PlannerInfo *root)
void pull_up_sublinks(PlannerInfo *root)
void replace_empty_jointree(Query *parse)
void pull_up_subqueries(PlannerInfo *root)
Query * preprocess_relation_rtes(PlannerInfo *root)
void reduce_outer_joins(PlannerInfo *root)
void SS_process_ctes(PlannerInfo *root)
Definition subselect.c:886
void SS_identify_outer_params(PlannerInfo *root)
Definition subselect.c:2367
void SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
Definition subselect.c:2431
Node * flatten_group_exprs(PlannerInfo *root, Query *query, Node *node)
Definition var.c:999
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition var.c:114

References aclcheck_error(), ACLCHECK_NO_PRIV, Assert, assign_special_exec_param(), bms_is_member(), bms_make_singleton(), contain_agg_clause(), contain_subplans(), contain_volatile_functions(), copyObject, CurrentMemoryContext, WindowClause::endOffset, ereport, errcode(), errmsg, ERROR, ExecCheckOneRelPerms(), expand_grouping_sets(), expression_returns_set(), EXPRKIND_APPINFO, EXPRKIND_ARBITER_ELEM, EXPRKIND_GROUPEXPR, EXPRKIND_LIMIT, EXPRKIND_QUAL, EXPRKIND_RTFUNC, EXPRKIND_RTFUNC_LATERAL, EXPRKIND_TABLEFUNC, EXPRKIND_TABLEFUNC_LATERAL, EXPRKIND_TABLESAMPLE, EXPRKIND_TARGET, EXPRKIND_VALUES, EXPRKIND_VALUES_LATERAL, fb(), fetch_upper_rel(), find_having_conflicts(), flatten_group_exprs(), flatten_join_alias_vars(), flatten_simple_union_all(), get_attgenerated(), get_rel_name(), getRTEPermissionInfo(), grouping_planner(), IS_OUTER_JOIN, lappend(), lfirst, lfirst_node, linitial, list_cell_number(), list_concat(), list_length(), list_make1, makeNode, Max, NIL, OBJECT_VIEW, parse(), preprocess_expression(), preprocess_function_rtes(), preprocess_qual_conditions(), preprocess_relation_rtes(), preprocess_rowmarks(), pull_up_sublinks(), pull_up_subqueries(), pull_varnos(), ForPortionOfExpr::range_name, ForPortionOfExpr::rangeVar, reduce_outer_joins(), remove_useless_result_rtes(), replace_empty_jointree(), result, root, rt_fetch, RTE_FUNCTION, RTE_GROUP, RTE_JOIN, RTE_RELATION, RTE_RESULT, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, set_cheapest(), SS_charge_for_initplans(), SS_identify_outer_params(), SS_process_ctes(), WindowClause::startOffset, transform_MERGE_to_join(), UPPERREL_FINAL, and Var::varattno.

Referenced by make_subplan(), recurse_set_operations(), set_subquery_pathlist(), SS_process_ctes(), and standard_planner().

Variable Documentation

◆ create_upper_paths_hook

◆ cursor_tuple_fraction

double cursor_tuple_fraction = DEFAULT_CURSOR_TUPLE_FRACTION

Definition at line 68 of file planner.c.

Referenced by standard_planner().

◆ debug_parallel_query

int debug_parallel_query = DEBUG_PARALLEL_OFF

Definition at line 69 of file planner.c.

Referenced by ProcessParallelMessage(), query_planner(), and standard_planner().

◆ enable_distinct_reordering

bool enable_distinct_reordering = true

Definition at line 71 of file planner.c.

Referenced by get_useful_pathkeys_for_distinct().

◆ parallel_leader_participation

bool parallel_leader_participation = true

Definition at line 70 of file planner.c.

Referenced by ExecGather(), ExecGatherMerge(), ExecInitGather(), and get_parallel_divisor().

◆ planner_hook

planner_hook_type planner_hook = NULL

Definition at line 74 of file planner.c.

Referenced by _PG_init(), and planner().

◆ planner_setup_hook

planner_setup_hook_type planner_setup_hook = NULL

Definition at line 77 of file planner.c.

Referenced by pgpa_planner_install_hooks(), and standard_planner().

◆ planner_shutdown_hook

planner_shutdown_hook_type planner_shutdown_hook = NULL

Definition at line 80 of file planner.c.

Referenced by pgpa_planner_install_hooks(), and standard_planner().