PostgreSQL Source Code git master
planner.h File Reference
#include "nodes/pathnodes.h"
#include "nodes/plannodes.h"
Include dependency graph for planner.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef struct ExplainState ExplainState
 
typedef PlannedStmt *(* planner_hook_type) (Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams, ExplainState *es)
 
typedef void(* planner_setup_hook_type) (PlannerGlobal *glob, Query *parse, const char *query_string, double *tuple_fraction, ExplainState *es)
 
typedef void(* planner_shutdown_hook_type) (PlannerGlobal *glob, Query *parse, const char *query_string, PlannedStmt *pstmt)
 
typedef void(* create_upper_paths_hook_type) (PlannerInfo *root, UpperRelationKind stage, RelOptInfo *input_rel, RelOptInfo *output_rel, void *extra)
 

Functions

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, bool hasRecursion, double tuple_fraction, SetOperationStmt *setops)
 
RowMarkType select_rowmark_type (RangeTblEntry *rte, LockClauseStrength strength)
 
bool limit_needed (Query *parse)
 
void mark_partial_aggref (Aggref *agg, AggSplit aggsplit)
 
Pathget_cheapest_fractional_path (RelOptInfo *rel, double tuple_fraction)
 
Exprpreprocess_phv_expression (PlannerInfo *root, Expr *expr)
 
RelOptInfocreate_unique_paths (PlannerInfo *root, RelOptInfo *rel, SpecialJoinInfo *sjinfo)
 
char * choose_plan_name (PlannerGlobal *glob, const char *name, bool always_number)
 

Variables

PGDLLIMPORT planner_hook_type planner_hook
 
PGDLLIMPORT planner_setup_hook_type planner_setup_hook
 
PGDLLIMPORT planner_shutdown_hook_type planner_shutdown_hook
 
PGDLLIMPORT create_upper_paths_hook_type create_upper_paths_hook
 

Typedef Documentation

◆ create_upper_paths_hook_type

typedef void(* create_upper_paths_hook_type) (PlannerInfo *root, UpperRelationKind stage, RelOptInfo *input_rel, RelOptInfo *output_rel, void *extra)

Definition at line 49 of file planner.h.

◆ ExplainState

typedef struct ExplainState ExplainState

Definition at line 25 of file planner.h.

◆ planner_hook_type

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

Definition at line 28 of file planner.h.

◆ planner_setup_hook_type

typedef void(* planner_setup_hook_type) (PlannerGlobal *glob, Query *parse, const char *query_string, double *tuple_fraction, ExplainState *es)

Definition at line 36 of file planner.h.

◆ planner_shutdown_hook_type

typedef void(* planner_shutdown_hook_type) (PlannerGlobal *glob, Query *parse, const char *query_string, PlannedStmt *pstmt)

Definition at line 43 of file planner.h.

Function Documentation

◆ choose_plan_name()

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

Definition at line 8961 of file planner.c.

8962{
8963 unsigned n;
8964
8965 /*
8966 * If a numeric suffix is not required, then search the list of
8967 * previously-assigned names for a match. If none is found, then we can
8968 * use the provided name without modification.
8969 */
8970 if (!always_number)
8971 {
8972 bool found = false;
8973
8974 foreach_ptr(char, subplan_name, glob->subplanNames)
8975 {
8976 if (strcmp(subplan_name, name) == 0)
8977 {
8978 found = true;
8979 break;
8980 }
8981 }
8982
8983 if (!found)
8984 {
8985 /* pstrdup here is just to avoid cast-away-const */
8986 char *chosen_name = pstrdup(name);
8987
8988 glob->subplanNames = lappend(glob->subplanNames, chosen_name);
8989 return chosen_name;
8990 }
8991 }
8992
8993 /*
8994 * If a numeric suffix is required or if the un-suffixed name is already
8995 * in use, then loop until we find a positive integer that produces a
8996 * novel name.
8997 */
8998 for (n = 1; true; ++n)
8999 {
9000 char *proposed_name = psprintf("%s_%u", name, n);
9001 bool found = false;
9002
9003 foreach_ptr(char, subplan_name, glob->subplanNames)
9004 {
9005 if (strcmp(subplan_name, proposed_name) == 0)
9006 {
9007 found = true;
9008 break;
9009 }
9010 }
9011
9012 if (!found)
9013 {
9014 glob->subplanNames = lappend(glob->subplanNames, proposed_name);
9015 return proposed_name;
9016 }
9017
9018 pfree(proposed_name);
9019 }
9020}
List * lappend(List *list, void *datum)
Definition: list.c:339
char * pstrdup(const char *in)
Definition: mcxt.c:1759
void pfree(void *pointer)
Definition: mcxt.c:1594
#define foreach_ptr(type, var, lst)
Definition: pg_list.h:469
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
const char * name

References 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().

◆ create_unique_paths()

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

Definition at line 8409 of file planner.c.

8410{
8411 RelOptInfo *unique_rel;
8412 List *sortPathkeys = NIL;
8413 List *groupClause = NIL;
8414 MemoryContext oldcontext;
8415
8416 /* Caller made a mistake if SpecialJoinInfo is the wrong one */
8417 Assert(sjinfo->jointype == JOIN_SEMI);
8418 Assert(bms_equal(rel->relids, sjinfo->syn_righthand));
8419
8420 /* If result already cached, return it */
8421 if (rel->unique_rel)
8422 return rel->unique_rel;
8423
8424 /* If it's not possible to unique-ify, return NULL */
8425 if (!(sjinfo->semi_can_btree || sjinfo->semi_can_hash))
8426 return NULL;
8427
8428 /*
8429 * Punt if this is a child relation and we failed to build a unique-ified
8430 * relation for its parent. This can happen if all the RHS columns were
8431 * found to be equated to constants when unique-ifying the parent table,
8432 * leaving no columns to unique-ify.
8433 */
8434 if (IS_OTHER_REL(rel) && rel->top_parent->unique_rel == NULL)
8435 return NULL;
8436
8437 /*
8438 * When called during GEQO join planning, we are in a short-lived memory
8439 * context. We must make sure that the unique rel and any subsidiary data
8440 * structures created for a baserel survive the GEQO cycle, else the
8441 * baserel is trashed for future GEQO cycles. On the other hand, when we
8442 * are creating those for a joinrel during GEQO, we don't want them to
8443 * clutter the main planning context. Upshot is that the best solution is
8444 * to explicitly allocate memory in the same context the given RelOptInfo
8445 * is in.
8446 */
8448
8449 unique_rel = makeNode(RelOptInfo);
8450 memcpy(unique_rel, rel, sizeof(RelOptInfo));
8451
8452 /*
8453 * clear path info
8454 */
8455 unique_rel->pathlist = NIL;
8456 unique_rel->ppilist = NIL;
8457 unique_rel->partial_pathlist = NIL;
8458 unique_rel->cheapest_startup_path = NULL;
8459 unique_rel->cheapest_total_path = NULL;
8460 unique_rel->cheapest_parameterized_paths = NIL;
8461
8462 /*
8463 * Build the target list for the unique rel. We also build the pathkeys
8464 * that represent the ordering requirements for the sort-based
8465 * implementation, and the list of SortGroupClause nodes that represent
8466 * the columns to be grouped on for the hash-based implementation.
8467 *
8468 * For a child rel, we can construct these fields from those of its
8469 * parent.
8470 */
8471 if (IS_OTHER_REL(rel))
8472 {
8473 PathTarget *child_unique_target;
8474 PathTarget *parent_unique_target;
8475
8476 parent_unique_target = rel->top_parent->unique_rel->reltarget;
8477
8478 child_unique_target = copy_pathtarget(parent_unique_target);
8479
8480 /* Translate the target expressions */
8481 child_unique_target->exprs = (List *)
8483 (Node *) parent_unique_target->exprs,
8484 rel,
8485 rel->top_parent);
8486
8487 unique_rel->reltarget = child_unique_target;
8488
8489 sortPathkeys = rel->top_parent->unique_pathkeys;
8490 groupClause = rel->top_parent->unique_groupclause;
8491 }
8492 else
8493 {
8494 List *newtlist;
8495 int nextresno;
8496 List *sortList = NIL;
8497 ListCell *lc1;
8498 ListCell *lc2;
8499
8500 /*
8501 * The values we are supposed to unique-ify may be expressions in the
8502 * variables of the input rel's targetlist. We have to add any such
8503 * expressions to the unique rel's targetlist.
8504 *
8505 * To complicate matters, some of the values to be unique-ified may be
8506 * known redundant by the EquivalenceClass machinery (e.g., because
8507 * they have been equated to constants). There is no need to compare
8508 * such values during unique-ification, and indeed we had better not
8509 * try because the Vars involved may not have propagated as high as
8510 * the semijoin's level. We use make_pathkeys_for_sortclauses to
8511 * detect such cases, which is a tad inefficient but it doesn't seem
8512 * worth building specialized infrastructure for this.
8513 */
8514 newtlist = make_tlist_from_pathtarget(rel->reltarget);
8515 nextresno = list_length(newtlist) + 1;
8516
8517 forboth(lc1, sjinfo->semi_rhs_exprs, lc2, sjinfo->semi_operators)
8518 {
8519 Expr *uniqexpr = lfirst(lc1);
8520 Oid in_oper = lfirst_oid(lc2);
8521 Oid sortop;
8522 TargetEntry *tle;
8523 bool made_tle = false;
8524
8525 tle = tlist_member(uniqexpr, newtlist);
8526 if (!tle)
8527 {
8528 tle = makeTargetEntry(uniqexpr,
8529 nextresno,
8530 NULL,
8531 false);
8532 newtlist = lappend(newtlist, tle);
8533 nextresno++;
8534 made_tle = true;
8535 }
8536
8537 /*
8538 * Try to build an ORDER BY list to sort the input compatibly. We
8539 * do this for each sortable clause even when the clauses are not
8540 * all sortable, so that we can detect clauses that are redundant
8541 * according to the pathkey machinery.
8542 */
8543 sortop = get_ordering_op_for_equality_op(in_oper, false);
8544 if (OidIsValid(sortop))
8545 {
8546 Oid eqop;
8547 SortGroupClause *sortcl;
8548
8549 /*
8550 * The Unique node will need equality operators. Normally
8551 * these are the same as the IN clause operators, but if those
8552 * are cross-type operators then the equality operators are
8553 * the ones for the IN clause operators' RHS datatype.
8554 */
8555 eqop = get_equality_op_for_ordering_op(sortop, NULL);
8556 if (!OidIsValid(eqop)) /* shouldn't happen */
8557 elog(ERROR, "could not find equality operator for ordering operator %u",
8558 sortop);
8559
8560 sortcl = makeNode(SortGroupClause);
8561 sortcl->tleSortGroupRef = assignSortGroupRef(tle, newtlist);
8562 sortcl->eqop = eqop;
8563 sortcl->sortop = sortop;
8564 sortcl->reverse_sort = false;
8565 sortcl->nulls_first = false;
8566 sortcl->hashable = false; /* no need to make this accurate */
8567 sortList = lappend(sortList, sortcl);
8568
8569 /*
8570 * At each step, convert the SortGroupClause list to pathkey
8571 * form. If the just-added SortGroupClause is redundant, the
8572 * result will be shorter than the SortGroupClause list.
8573 */
8574 sortPathkeys = make_pathkeys_for_sortclauses(root, sortList,
8575 newtlist);
8576 if (list_length(sortPathkeys) != list_length(sortList))
8577 {
8578 /* Drop the redundant SortGroupClause */
8579 sortList = list_delete_last(sortList);
8580 Assert(list_length(sortPathkeys) == list_length(sortList));
8581 /* Undo tlist addition, if we made one */
8582 if (made_tle)
8583 {
8584 newtlist = list_delete_last(newtlist);
8585 nextresno--;
8586 }
8587 /* We need not consider this clause for hashing, either */
8588 continue;
8589 }
8590 }
8591 else if (sjinfo->semi_can_btree) /* shouldn't happen */
8592 elog(ERROR, "could not find ordering operator for equality operator %u",
8593 in_oper);
8594
8595 if (sjinfo->semi_can_hash)
8596 {
8597 /* Create a GROUP BY list for the Agg node to use */
8598 Oid eq_oper;
8599 SortGroupClause *groupcl;
8600
8601 /*
8602 * Get the hashable equality operators for the Agg node to
8603 * use. Normally these are the same as the IN clause
8604 * operators, but if those are cross-type operators then the
8605 * equality operators are the ones for the IN clause
8606 * operators' RHS datatype.
8607 */
8608 if (!get_compatible_hash_operators(in_oper, NULL, &eq_oper))
8609 elog(ERROR, "could not find compatible hash operator for operator %u",
8610 in_oper);
8611
8612 groupcl = makeNode(SortGroupClause);
8613 groupcl->tleSortGroupRef = assignSortGroupRef(tle, newtlist);
8614 groupcl->eqop = eq_oper;
8615 groupcl->sortop = sortop;
8616 groupcl->reverse_sort = false;
8617 groupcl->nulls_first = false;
8618 groupcl->hashable = true;
8619 groupClause = lappend(groupClause, groupcl);
8620 }
8621 }
8622
8623 /*
8624 * Done building the sortPathkeys and groupClause. But the
8625 * sortPathkeys are bogus if not all the clauses were sortable.
8626 */
8627 if (!sjinfo->semi_can_btree)
8628 sortPathkeys = NIL;
8629
8630 /*
8631 * It can happen that all the RHS columns are equated to constants.
8632 * We'd have to do something special to unique-ify in that case, and
8633 * it's such an unlikely-in-the-real-world case that it's not worth
8634 * the effort. So just punt if we found no columns to unique-ify.
8635 */
8636 if (sortPathkeys == NIL && groupClause == NIL)
8637 {
8638 MemoryContextSwitchTo(oldcontext);
8639 return NULL;
8640 }
8641
8642 /* Convert the required targetlist back to PathTarget form */
8643 unique_rel->reltarget = create_pathtarget(root, newtlist);
8644 }
8645
8646 /* build unique paths based on input rel's pathlist */
8647 create_final_unique_paths(root, rel, sortPathkeys, groupClause,
8648 sjinfo, unique_rel);
8649
8650 /* build unique paths based on input rel's partial_pathlist */
8651 create_partial_unique_paths(root, rel, sortPathkeys, groupClause,
8652 sjinfo, unique_rel);
8653
8654 /* Now choose the best path(s) */
8655 set_cheapest(unique_rel);
8656
8657 /*
8658 * There shouldn't be any partial paths for the unique relation;
8659 * otherwise, we won't be able to properly guarantee uniqueness.
8660 */
8661 Assert(unique_rel->partial_pathlist == NIL);
8662
8663 /* Cache the result */
8664 rel->unique_rel = unique_rel;
8665 rel->unique_pathkeys = sortPathkeys;
8666 rel->unique_groupclause = groupClause;
8667
8668 MemoryContextSwitchTo(oldcontext);
8669
8670 return unique_rel;
8671}
Node * adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, RelOptInfo *childrel, RelOptInfo *parentrel)
Definition: appendinfo.c:592
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:142
#define OidIsValid(objectId)
Definition: c.h:777
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
Assert(PointerIsAligned(start, uint64))
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:482
Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse)
Definition: lsyscache.c:331
Oid get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
Definition: lsyscache.c:369
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:289
MemoryContext GetMemoryChunkContext(void *pointer)
Definition: mcxt.c:753
#define makeNode(_type_)
Definition: nodes.h:161
@ JOIN_SEMI
Definition: nodes.h:317
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
Index assignSortGroupRef(TargetEntry *tle, List *tlist)
List * make_pathkeys_for_sortclauses(PlannerInfo *root, List *sortclauses, List *tlist)
Definition: pathkeys.c:1336
void set_cheapest(RelOptInfo *parent_rel)
Definition: pathnode.c:270
#define IS_OTHER_REL(rel)
Definition: pathnodes.h:910
#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
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define lfirst_oid(lc)
Definition: pg_list.h:174
static void create_final_unique_paths(PlannerInfo *root, RelOptInfo *input_rel, List *sortPathkeys, List *groupClause, SpecialJoinInfo *sjinfo, RelOptInfo *unique_rel)
Definition: planner.c:8678
static void create_partial_unique_paths(PlannerInfo *root, RelOptInfo *input_rel, List *sortPathkeys, List *groupClause, SpecialJoinInfo *sjinfo, RelOptInfo *unique_rel)
Definition: planner.c:8803
unsigned int Oid
Definition: postgres_ext.h:32
tree ctl root
Definition: radixtree.h:1857
Definition: pg_list.h:54
Definition: nodes.h:135
List * exprs
Definition: pathnodes.h:1780
List * ppilist
Definition: pathnodes.h:955
Relids relids
Definition: pathnodes.h:927
struct PathTarget * reltarget
Definition: pathnodes.h:949
List * unique_pathkeys
Definition: pathnodes.h:1038
List * cheapest_parameterized_paths
Definition: pathnodes.h:959
List * pathlist
Definition: pathnodes.h:954
struct Path * cheapest_startup_path
Definition: pathnodes.h:957
struct Path * cheapest_total_path
Definition: pathnodes.h:958
List * unique_groupclause
Definition: pathnodes.h:1040
List * partial_pathlist
Definition: pathnodes.h:956
struct RelOptInfo * unique_rel
Definition: pathnodes.h:1036
Index tleSortGroupRef
Definition: parsenodes.h:1469
List * semi_rhs_exprs
Definition: pathnodes.h:3132
JoinType jointype
Definition: pathnodes.h:3121
Relids syn_righthand
Definition: pathnodes.h:3120
List * semi_operators
Definition: pathnodes.h:3131
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:79
List * make_tlist_from_pathtarget(PathTarget *target)
Definition: tlist.c:624
PathTarget * copy_pathtarget(PathTarget *src)
Definition: tlist.c:657
#define create_pathtarget(root, tlist)
Definition: tlist.h:53

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, SortGroupClause::eqop, ERROR, PathTarget::exprs, 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(), MemoryContextSwitchTo(), NIL, SortGroupClause::nulls_first, OidIsValid, RelOptInfo::partial_pathlist, RelOptInfo::pathlist, RelOptInfo::ppilist, RelOptInfo::relids, RelOptInfo::reltarget, SortGroupClause::reverse_sort, root, SpecialJoinInfo::semi_can_btree, SpecialJoinInfo::semi_can_hash, SpecialJoinInfo::semi_operators, SpecialJoinInfo::semi_rhs_exprs, set_cheapest(), SortGroupClause::sortop, SpecialJoinInfo::syn_righthand, SortGroupClause::tleSortGroupRef, tlist_member(), RelOptInfo::unique_groupclause, RelOptInfo::unique_pathkeys, and RelOptInfo::unique_rel.

Referenced by join_is_legal(), and populate_joinrel_with_paths().

◆ get_cheapest_fractional_path()

Path * get_cheapest_fractional_path ( RelOptInfo rel,
double  tuple_fraction 
)

Definition at line 6601 of file planner.c.

6602{
6603 Path *best_path = rel->cheapest_total_path;
6604 ListCell *l;
6605
6606 /* If all tuples will be retrieved, just return the cheapest-total path */
6607 if (tuple_fraction <= 0.0)
6608 return best_path;
6609
6610 /* Convert absolute # of tuples to a fraction; no need to clamp to 0..1 */
6611 if (tuple_fraction >= 1.0 && best_path->rows > 0)
6612 tuple_fraction /= best_path->rows;
6613
6614 foreach(l, rel->pathlist)
6615 {
6616 Path *path = (Path *) lfirst(l);
6617
6618 if (path->param_info)
6619 continue;
6620
6621 if (path == rel->cheapest_total_path ||
6622 compare_fractional_path_costs(best_path, path, tuple_fraction) <= 0)
6623 continue;
6624
6625 best_path = path;
6626 }
6627
6628 return best_path;
6629}
int compare_fractional_path_costs(Path *path1, Path *path2, double fraction)
Definition: pathnode.c:125
Cardinality rows
Definition: pathnodes.h:1907

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

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

◆ limit_needed()

bool limit_needed ( Query parse)

Definition at line 2790 of file planner.c.

2791{
2792 Node *node;
2793
2794 node = parse->limitCount;
2795 if (node)
2796 {
2797 if (IsA(node, Const))
2798 {
2799 /* NULL indicates LIMIT ALL, ie, no limit */
2800 if (!((Const *) node)->constisnull)
2801 return true; /* LIMIT with a constant value */
2802 }
2803 else
2804 return true; /* non-constant LIMIT */
2805 }
2806
2807 node = parse->limitOffset;
2808 if (node)
2809 {
2810 if (IsA(node, Const))
2811 {
2812 /* Treat NULL as no offset; the executor would too */
2813 if (!((Const *) node)->constisnull)
2814 {
2815 int64 offset = DatumGetInt64(((Const *) node)->constvalue);
2816
2817 if (offset != 0)
2818 return true; /* OFFSET with a nonzero value */
2819 }
2820 }
2821 else
2822 return true; /* non-constant OFFSET */
2823 }
2824
2825 return false; /* don't need a Limit plan node */
2826}
int64_t int64
Definition: c.h:538
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:393
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717

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

Referenced by grouping_planner(), and set_rel_consider_parallel().

◆ mark_partial_aggref()

void mark_partial_aggref ( Aggref agg,
AggSplit  aggsplit 
)

Definition at line 5762 of file planner.c.

5763{
5764 /* aggtranstype should be computed by this point */
5765 Assert(OidIsValid(agg->aggtranstype));
5766 /* ... but aggsplit should still be as the parser left it */
5767 Assert(agg->aggsplit == AGGSPLIT_SIMPLE);
5768
5769 /* Mark the Aggref with the intended partial-aggregation mode */
5770 agg->aggsplit = aggsplit;
5771
5772 /*
5773 * Adjust result type if needed. Normally, a partial aggregate returns
5774 * the aggregate's transition type; but if that's INTERNAL and we're
5775 * serializing, it returns BYTEA instead.
5776 */
5777 if (DO_AGGSPLIT_SKIPFINAL(aggsplit))
5778 {
5779 if (agg->aggtranstype == INTERNALOID && DO_AGGSPLIT_SERIALIZE(aggsplit))
5780 agg->aggtype = BYTEAOID;
5781 else
5782 agg->aggtype = agg->aggtranstype;
5783 }
5784}
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:396
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:397
@ AGGSPLIT_SIMPLE
Definition: nodes.h:387

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

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

◆ preprocess_phv_expression()

Expr * preprocess_phv_expression ( PlannerInfo root,
Expr expr 
)

Definition at line 1431 of file planner.c.

1432{
1433 return (Expr *) preprocess_expression(root, (Node *) expr, EXPRKIND_PHV);
1434}
#define EXPRKIND_PHV
Definition: planner.c:95
static Node * preprocess_expression(PlannerInfo *root, Node *expr, int kind)
Definition: planner.c:1285

References EXPRKIND_PHV, preprocess_expression(), and root.

Referenced by extract_lateral_references().

◆ select_rowmark_type()

RowMarkType select_rowmark_type ( RangeTblEntry rte,
LockClauseStrength  strength 
)

Definition at line 2539 of file planner.c.

2540{
2541 if (rte->rtekind != RTE_RELATION)
2542 {
2543 /* If it's not a table at all, use ROW_MARK_COPY */
2544 return ROW_MARK_COPY;
2545 }
2546 else if (rte->relkind == RELKIND_FOREIGN_TABLE)
2547 {
2548 /* Let the FDW select the rowmark type, if it wants to */
2549 FdwRoutine *fdwroutine = GetFdwRoutineByRelId(rte->relid);
2550
2551 if (fdwroutine->GetForeignRowMarkType != NULL)
2552 return fdwroutine->GetForeignRowMarkType(rte, strength);
2553 /* Otherwise, use ROW_MARK_COPY by default */
2554 return ROW_MARK_COPY;
2555 }
2556 else
2557 {
2558 /* Regular table, apply the appropriate lock type */
2559 switch (strength)
2560 {
2561 case LCS_NONE:
2562
2563 /*
2564 * We don't need a tuple lock, only the ability to re-fetch
2565 * the row.
2566 */
2567 return ROW_MARK_REFERENCE;
2568 break;
2569 case LCS_FORKEYSHARE:
2570 return ROW_MARK_KEYSHARE;
2571 break;
2572 case LCS_FORSHARE:
2573 return ROW_MARK_SHARE;
2574 break;
2575 case LCS_FORNOKEYUPDATE:
2577 break;
2578 case LCS_FORUPDATE:
2579 return ROW_MARK_EXCLUSIVE;
2580 break;
2581 }
2582 elog(ERROR, "unrecognized LockClauseStrength %d", (int) strength);
2583 return ROW_MARK_EXCLUSIVE; /* keep compiler quiet */
2584 }
2585}
FdwRoutine * GetFdwRoutineByRelId(Oid relid)
Definition: foreign.c:420
@ LCS_FORUPDATE
Definition: lockoptions.h:27
@ LCS_NONE
Definition: lockoptions.h:23
@ LCS_FORSHARE
Definition: lockoptions.h:25
@ LCS_FORKEYSHARE
Definition: lockoptions.h:24
@ LCS_FORNOKEYUPDATE
Definition: lockoptions.h:26
@ RTE_RELATION
Definition: parsenodes.h:1043
@ ROW_MARK_COPY
Definition: plannodes.h:1541
@ ROW_MARK_REFERENCE
Definition: plannodes.h:1540
@ ROW_MARK_SHARE
Definition: plannodes.h:1538
@ ROW_MARK_EXCLUSIVE
Definition: plannodes.h:1536
@ ROW_MARK_NOKEYEXCLUSIVE
Definition: plannodes.h:1537
@ ROW_MARK_KEYSHARE
Definition: plannodes.h:1539
GetForeignRowMarkType_function GetForeignRowMarkType
Definition: fdwapi.h:247
RTEKind rtekind
Definition: parsenodes.h:1078

References elog, ERROR, 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, RTE_RELATION, and RangeTblEntry::rtekind.

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 333 of file planner.c.

335{
336 PlannedStmt *result;
337 PlannerGlobal *glob;
338 double tuple_fraction;
340 RelOptInfo *final_rel;
341 Path *best_path;
342 Plan *top_plan;
343 ListCell *lp,
344 *lr;
345
346 /*
347 * Set up global state for this planner invocation. This data is needed
348 * across all levels of sub-Query that might exist in the given command,
349 * so we keep it in a separate struct that's linked to by each per-Query
350 * PlannerInfo.
351 */
352 glob = makeNode(PlannerGlobal);
353
354 glob->boundParams = boundParams;
355 glob->subplans = NIL;
356 glob->subpaths = NIL;
357 glob->subroots = NIL;
358 glob->rewindPlanIDs = NULL;
359 glob->finalrtable = NIL;
360 glob->allRelids = NULL;
361 glob->prunableRelids = NULL;
362 glob->finalrteperminfos = NIL;
363 glob->finalrowmarks = NIL;
364 glob->resultRelations = NIL;
365 glob->appendRelations = NIL;
366 glob->partPruneInfos = NIL;
367 glob->relationOids = NIL;
368 glob->invalItems = NIL;
369 glob->paramExecTypes = NIL;
370 glob->lastPHId = 0;
371 glob->lastRowMarkId = 0;
372 glob->lastPlanNodeId = 0;
373 glob->transientPlan = false;
374 glob->dependsOnRole = false;
375 glob->partition_directory = NULL;
376 glob->rel_notnullatts_hash = NULL;
377
378 /*
379 * Assess whether it's feasible to use parallel mode for this query. We
380 * can't do this in a standalone backend, or if the command will try to
381 * modify any data, or if this is a cursor operation, or if GUCs are set
382 * to values that don't permit parallelism, or if parallel-unsafe
383 * functions are present in the query tree.
384 *
385 * (Note that we do allow CREATE TABLE AS, SELECT INTO, and CREATE
386 * MATERIALIZED VIEW to use parallel plans, but this is safe only because
387 * the command is writing into a completely new table which workers won't
388 * be able to see. If the workers could see the table, the fact that
389 * group locking would cause them to ignore the leader's heavyweight GIN
390 * page locks would make this unsafe. We'll have to fix that somehow if
391 * we want to allow parallel inserts in general; updates and deletes have
392 * additional problems especially around combo CIDs.)
393 *
394 * For now, we don't try to use parallel mode if we're running inside a
395 * parallel worker. We might eventually be able to relax this
396 * restriction, but for now it seems best not to have parallel workers
397 * trying to create their own parallel workers.
398 */
399 if ((cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 &&
401 parse->commandType == CMD_SELECT &&
402 !parse->hasModifyingCTE &&
405 {
406 /* all the cheap tests pass, so scan the query tree */
408 glob->parallelModeOK = (glob->maxParallelHazard != PROPARALLEL_UNSAFE);
409 }
410 else
411 {
412 /* skip the query tree scan, just assume it's unsafe */
413 glob->maxParallelHazard = PROPARALLEL_UNSAFE;
414 glob->parallelModeOK = false;
415 }
416
417 /*
418 * glob->parallelModeNeeded is normally set to false here and changed to
419 * true during plan creation if a Gather or Gather Merge plan is actually
420 * created (cf. create_gather_plan, create_gather_merge_plan).
421 *
422 * However, if debug_parallel_query = on or debug_parallel_query =
423 * regress, then we impose parallel mode whenever it's safe to do so, even
424 * if the final plan doesn't use parallelism. It's not safe to do so if
425 * the query contains anything parallel-unsafe; parallelModeOK will be
426 * false in that case. Note that parallelModeOK can't change after this
427 * point. Otherwise, everything in the query is either parallel-safe or
428 * parallel-restricted, and in either case it should be OK to impose
429 * parallel-mode restrictions. If that ends up breaking something, then
430 * either some function the user included in the query is incorrectly
431 * labeled as parallel-safe or parallel-restricted when in reality it's
432 * parallel-unsafe, or else the query planner itself has a bug.
433 */
434 glob->parallelModeNeeded = glob->parallelModeOK &&
436
437 /* Determine what fraction of the plan is likely to be scanned */
438 if (cursorOptions & CURSOR_OPT_FAST_PLAN)
439 {
440 /*
441 * We have no real idea how many tuples the user will ultimately FETCH
442 * from a cursor, but it is often the case that he doesn't want 'em
443 * all, or would prefer a fast-start plan anyway so that he can
444 * process some of the tuples sooner. Use a GUC parameter to decide
445 * what fraction to optimize for.
446 */
447 tuple_fraction = cursor_tuple_fraction;
448
449 /*
450 * We document cursor_tuple_fraction as simply being a fraction, which
451 * means the edge cases 0 and 1 have to be treated specially here. We
452 * convert 1 to 0 ("all the tuples") and 0 to a very small fraction.
453 */
454 if (tuple_fraction >= 1.0)
455 tuple_fraction = 0.0;
456 else if (tuple_fraction <= 0.0)
457 tuple_fraction = 1e-10;
458 }
459 else
460 {
461 /* Default assumption is we need all the tuples */
462 tuple_fraction = 0.0;
463 }
464
465 /* Allow plugins to take control after we've initialized "glob" */
467 (*planner_setup_hook) (glob, parse, query_string, &tuple_fraction, es);
468
469 /* primary planning entry point (may recurse for subqueries) */
470 root = subquery_planner(glob, parse, NULL, NULL, false, tuple_fraction,
471 NULL);
472
473 /* Select best Path and turn it into a Plan */
474 final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
475 best_path = get_cheapest_fractional_path(final_rel, tuple_fraction);
476
477 top_plan = create_plan(root, best_path);
478
479 /*
480 * If creating a plan for a scrollable cursor, make sure it can run
481 * backwards on demand. Add a Material node at the top at need.
482 */
483 if (cursorOptions & CURSOR_OPT_SCROLL)
484 {
485 if (!ExecSupportsBackwardScan(top_plan))
486 top_plan = materialize_finished_plan(top_plan);
487 }
488
489 /*
490 * Optionally add a Gather node for testing purposes, provided this is
491 * actually a safe thing to do.
492 *
493 * We can add Gather even when top_plan has parallel-safe initPlans, but
494 * then we have to move the initPlans to the Gather node because of
495 * SS_finalize_plan's limitations. That would cause cosmetic breakage of
496 * regression tests when debug_parallel_query = regress, because initPlans
497 * that would normally appear on the top_plan move to the Gather, causing
498 * them to disappear from EXPLAIN output. That doesn't seem worth kluging
499 * EXPLAIN to hide, so skip it when debug_parallel_query = regress.
500 */
502 top_plan->parallel_safe &&
503 (top_plan->initPlan == NIL ||
505 {
506 Gather *gather = makeNode(Gather);
507 Cost initplan_cost;
508 bool unsafe_initplans;
509
510 gather->plan.targetlist = top_plan->targetlist;
511 gather->plan.qual = NIL;
512 gather->plan.lefttree = top_plan;
513 gather->plan.righttree = NULL;
514 gather->num_workers = 1;
515 gather->single_copy = true;
517
518 /* Transfer any initPlans to the new top node */
519 gather->plan.initPlan = top_plan->initPlan;
520 top_plan->initPlan = NIL;
521
522 /*
523 * Since this Gather has no parallel-aware descendants to signal to,
524 * we don't need a rescan Param.
525 */
526 gather->rescan_param = -1;
527
528 /*
529 * Ideally we'd use cost_gather here, but setting up dummy path data
530 * to satisfy it doesn't seem much cleaner than knowing what it does.
531 */
532 gather->plan.startup_cost = top_plan->startup_cost +
534 gather->plan.total_cost = top_plan->total_cost +
536 gather->plan.plan_rows = top_plan->plan_rows;
537 gather->plan.plan_width = top_plan->plan_width;
538 gather->plan.parallel_aware = false;
539 gather->plan.parallel_safe = false;
540
541 /*
542 * Delete the initplans' cost from top_plan. We needn't add it to the
543 * Gather node, since the above coding already included it there.
544 */
546 &initplan_cost, &unsafe_initplans);
547 top_plan->startup_cost -= initplan_cost;
548 top_plan->total_cost -= initplan_cost;
549
550 /* use parallel mode for parallel plans. */
551 root->glob->parallelModeNeeded = true;
552
553 top_plan = &gather->plan;
554 }
555
556 /*
557 * If any Params were generated, run through the plan tree and compute
558 * each plan node's extParam/allParam sets. Ideally we'd merge this into
559 * set_plan_references' tree traversal, but for now it has to be separate
560 * because we need to visit subplans before not after main plan.
561 */
562 if (glob->paramExecTypes != NIL)
563 {
564 Assert(list_length(glob->subplans) == list_length(glob->subroots));
565 forboth(lp, glob->subplans, lr, glob->subroots)
566 {
567 Plan *subplan = (Plan *) lfirst(lp);
568 PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
569
570 SS_finalize_plan(subroot, subplan);
571 }
572 SS_finalize_plan(root, top_plan);
573 }
574
575 /* final cleanup of the plan */
576 Assert(glob->finalrtable == NIL);
577 Assert(glob->finalrteperminfos == NIL);
578 Assert(glob->finalrowmarks == NIL);
579 Assert(glob->resultRelations == NIL);
580 Assert(glob->appendRelations == NIL);
581 top_plan = set_plan_references(root, top_plan);
582 /* ... and the subplans (both regular subplans and initplans) */
583 Assert(list_length(glob->subplans) == list_length(glob->subroots));
584 forboth(lp, glob->subplans, lr, glob->subroots)
585 {
586 Plan *subplan = (Plan *) lfirst(lp);
587 PlannerInfo *subroot = lfirst_node(PlannerInfo, lr);
588
589 lfirst(lp) = set_plan_references(subroot, subplan);
590 }
591
592 /* build the PlannedStmt result */
593 result = makeNode(PlannedStmt);
594
595 result->commandType = parse->commandType;
596 result->queryId = parse->queryId;
598 result->hasReturning = (parse->returningList != NIL);
599 result->hasModifyingCTE = parse->hasModifyingCTE;
600 result->canSetTag = parse->canSetTag;
601 result->transientPlan = glob->transientPlan;
602 result->dependsOnRole = glob->dependsOnRole;
603 result->parallelModeNeeded = glob->parallelModeNeeded;
604 result->planTree = top_plan;
605 result->partPruneInfos = glob->partPruneInfos;
606 result->rtable = glob->finalrtable;
607 result->unprunableRelids = bms_difference(glob->allRelids,
608 glob->prunableRelids);
609 result->permInfos = glob->finalrteperminfos;
610 result->resultRelations = glob->resultRelations;
611 result->appendRelations = glob->appendRelations;
612 result->subplans = glob->subplans;
613 result->rewindPlanIDs = glob->rewindPlanIDs;
614 result->rowMarks = glob->finalrowmarks;
615 result->relationOids = glob->relationOids;
616 result->invalItems = glob->invalItems;
617 result->paramExecTypes = glob->paramExecTypes;
618 /* utilityStmt should be null, but we might as well copy it */
619 result->utilityStmt = parse->utilityStmt;
620 result->stmt_location = parse->stmt_location;
621 result->stmt_len = parse->stmt_len;
622
623 result->jitFlags = PGJIT_NONE;
624 if (jit_enabled && jit_above_cost >= 0 &&
625 top_plan->total_cost > jit_above_cost)
626 {
627 result->jitFlags |= PGJIT_PERFORM;
628
629 /*
630 * Decide how much effort should be put into generating better code.
631 */
632 if (jit_optimize_above_cost >= 0 &&
634 result->jitFlags |= PGJIT_OPT3;
635 if (jit_inline_above_cost >= 0 &&
637 result->jitFlags |= PGJIT_INLINE;
638
639 /*
640 * Decide which operations should be JITed.
641 */
642 if (jit_expressions)
643 result->jitFlags |= PGJIT_EXPR;
645 result->jitFlags |= PGJIT_DEFORM;
646 }
647
648 /* Allow plugins to take control before we discard "glob" */
650 (*planner_shutdown_hook) (glob, parse, query_string, result);
651
652 if (glob->partition_directory != NULL)
653 DestroyPartitionDirectory(glob->partition_directory);
654
655 return result;
656}
Bitmapset * bms_difference(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:346
char max_parallel_hazard(Query *parse)
Definition: clauses.c:746
int max_parallel_workers_per_gather
Definition: costsize.c:143
double parallel_setup_cost
Definition: costsize.c:136
double parallel_tuple_cost
Definition: costsize.c:135
Plan * materialize_finished_plan(Plan *subplan)
Definition: createplan.c:6501
Plan * create_plan(PlannerInfo *root, Path *best_path)
Definition: createplan.c:340
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:511
bool IsUnderPostmaster
Definition: globals.c:120
#define IsParallelWorker()
Definition: parallel.h:60
double jit_optimize_above_cost
Definition: jit.c:41
bool jit_enabled
Definition: jit.c:32
bool jit_expressions
Definition: jit.c:36
bool jit_tuple_deforming
Definition: jit.c:38
double jit_above_cost
Definition: jit.c:39
double jit_inline_above_cost
Definition: jit.c:40
#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
double Cost
Definition: nodes.h:261
@ CMD_SELECT
Definition: nodes.h:275
@ DEBUG_PARALLEL_REGRESS
Definition: optimizer.h:98
@ DEBUG_PARALLEL_OFF
Definition: optimizer.h:96
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:3387
#define CURSOR_OPT_FAST_PLAN
Definition: parsenodes.h:3393
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3396
void DestroyPartitionDirectory(PartitionDirectory pdir)
Definition: partdesc.c:484
@ UPPERREL_FINAL
Definition: pathnodes.h:79
#define lfirst_node(type, lc)
Definition: pg_list.h:176
double cursor_tuple_fraction
Definition: planner.c:68
planner_shutdown_hook_type planner_shutdown_hook
Definition: planner.c:80
PlannerInfo * subquery_planner(PlannerGlobal *glob, Query *parse, char *plan_name, PlannerInfo *parent_root, bool hasRecursion, double tuple_fraction, SetOperationStmt *setops)
Definition: planner.c:693
Path * get_cheapest_fractional_path(RelOptInfo *rel, double tuple_fraction)
Definition: planner.c:6601
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:41
e
Definition: preproc-init.c:82
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1581
Plan * set_plan_references(PlannerInfo *root, Plan *plan)
Definition: setrefs.c:288
int num_workers
Definition: plannodes.h:1339
bool invisible
Definition: plannodes.h:1345
bool single_copy
Definition: plannodes.h:1343
Plan plan
Definition: plannodes.h:1337
int rescan_param
Definition: plannodes.h:1341
struct Plan * lefttree
Definition: plannodes.h:233
Cost total_cost
Definition: plannodes.h:199
struct Plan * righttree
Definition: plannodes.h:234
bool parallel_aware
Definition: plannodes.h:213
Cost startup_cost
Definition: plannodes.h:197
List * qual
Definition: plannodes.h:231
int plan_width
Definition: plannodes.h:207
bool parallel_safe
Definition: plannodes.h:215
Cardinality plan_rows
Definition: plannodes.h:205
List * targetlist
Definition: plannodes.h:229
List * initPlan
Definition: plannodes.h:236
struct Plan * planTree
Definition: plannodes.h:101
bool hasModifyingCTE
Definition: plannodes.h:83
List * appendRelations
Definition: plannodes.h:127
List * permInfos
Definition: plannodes.h:120
bool canSetTag
Definition: plannodes.h:86
List * rowMarks
Definition: plannodes.h:138
int jitFlags
Definition: plannodes.h:98
Bitmapset * rewindPlanIDs
Definition: plannodes.h:135
int64 queryId
Definition: plannodes.h:71
ParseLoc stmt_len
Definition: plannodes.h:165
PlannedStmtOrigin planOrigin
Definition: plannodes.h:77
bool hasReturning
Definition: plannodes.h:80
ParseLoc stmt_location
Definition: plannodes.h:163
List * invalItems
Definition: plannodes.h:144
bool transientPlan
Definition: plannodes.h:89
List * resultRelations
Definition: plannodes.h:124
List * subplans
Definition: plannodes.h:132
List * relationOids
Definition: plannodes.h:141
bool dependsOnRole
Definition: plannodes.h:92
Bitmapset * unprunableRelids
Definition: plannodes.h:115
CmdType commandType
Definition: plannodes.h:68
Node * utilityStmt
Definition: plannodes.h:150
List * rtable
Definition: plannodes.h:109
List * partPruneInfos
Definition: plannodes.h:106
List * paramExecTypes
Definition: plannodes.h:147
bool parallelModeNeeded
Definition: plannodes.h:95
Bitmapset * prunableRelids
Definition: pathnodes.h:133
int lastPlanNodeId
Definition: pathnodes.h:166
char maxParallelHazard
Definition: pathnodes.h:181
List * subplans
Definition: pathnodes.h:105
bool dependsOnRole
Definition: pathnodes.h:172
Bitmapset * allRelids
Definition: pathnodes.h:126
List * appendRelations
Definition: pathnodes.h:145
List * finalrowmarks
Definition: pathnodes.h:139
List * invalItems
Definition: pathnodes.h:154
List * relationOids
Definition: pathnodes.h:151
List * paramExecTypes
Definition: pathnodes.h:157
bool parallelModeOK
Definition: pathnodes.h:175
bool transientPlan
Definition: pathnodes.h:169
Bitmapset * rewindPlanIDs
Definition: pathnodes.h:117
List * finalrteperminfos
Definition: pathnodes.h:136
List * subpaths
Definition: pathnodes.h:108
Index lastPHId
Definition: pathnodes.h:160
Index lastRowMarkId
Definition: pathnodes.h:163
List * resultRelations
Definition: pathnodes.h:142
List * partPruneInfos
Definition: pathnodes.h:148
List * finalrtable
Definition: pathnodes.h:120
bool parallelModeNeeded
Definition: pathnodes.h:178
void SS_finalize_plan(PlannerInfo *root, Plan *plan)
Definition: subselect.c:2404
void SS_compute_initplan_cost(List *init_plans, Cost *initplan_cost_p, bool *unsafe_initplans_p)
Definition: subselect.c:2348

References PlannerGlobal::allRelids, PlannerGlobal::appendRelations, PlannedStmt::appendRelations, Assert(), bms_difference(), PlannedStmt::canSetTag, CMD_SELECT, PlannedStmt::commandType, 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::dependsOnRole, PlannedStmt::dependsOnRole, DestroyPartitionDirectory(), ExecSupportsBackwardScan(), fetch_upper_rel(), PlannerGlobal::finalrowmarks, PlannerGlobal::finalrtable, PlannerGlobal::finalrteperminfos, forboth, get_cheapest_fractional_path(), PlannedStmt::hasModifyingCTE, PlannedStmt::hasReturning, Plan::initPlan, PlannerGlobal::invalItems, PlannedStmt::invalItems, Gather::invisible, IsParallelWorker, IsUnderPostmaster, jit_above_cost, jit_enabled, jit_expressions, jit_inline_above_cost, jit_optimize_above_cost, jit_tuple_deforming, PlannedStmt::jitFlags, PlannerGlobal::lastPHId, PlannerGlobal::lastPlanNodeId, PlannerGlobal::lastRowMarkId, Plan::lefttree, lfirst, lfirst_node, list_length(), makeNode, materialize_finished_plan(), max_parallel_hazard(), max_parallel_workers_per_gather, PlannerGlobal::maxParallelHazard, NIL, Gather::num_workers, Plan::parallel_aware, Plan::parallel_safe, parallel_setup_cost, parallel_tuple_cost, PlannerGlobal::parallelModeNeeded, PlannedStmt::parallelModeNeeded, PlannerGlobal::parallelModeOK, PlannerGlobal::paramExecTypes, PlannedStmt::paramExecTypes, parse(), PlannerGlobal::partPruneInfos, PlannedStmt::partPruneInfos, PlannedStmt::permInfos, PGJIT_DEFORM, PGJIT_EXPR, PGJIT_INLINE, PGJIT_NONE, PGJIT_OPT3, PGJIT_PERFORM, Gather::plan, Plan::plan_rows, PLAN_STMT_STANDARD, Plan::plan_width, planner_setup_hook, planner_shutdown_hook, PlannedStmt::planOrigin, PlannedStmt::planTree, PlannerGlobal::prunableRelids, Plan::qual, PlannedStmt::queryId, PlannerGlobal::relationOids, PlannedStmt::relationOids, Gather::rescan_param, PlannerGlobal::resultRelations, PlannedStmt::resultRelations, PlannerGlobal::rewindPlanIDs, PlannedStmt::rewindPlanIDs, Plan::righttree, root, PlannedStmt::rowMarks, PlannedStmt::rtable, set_plan_references(), Gather::single_copy, SS_compute_initplan_cost(), SS_finalize_plan(), Plan::startup_cost, PlannedStmt::stmt_len, PlannedStmt::stmt_location, PlannerGlobal::subpaths, PlannerGlobal::subplans, PlannedStmt::subplans, subquery_planner(), Plan::targetlist, Plan::total_cost, PlannerGlobal::transientPlan, PlannedStmt::transientPlan, PlannedStmt::unprunableRelids, UPPERREL_FINAL, and PlannedStmt::utilityStmt.

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

◆ subquery_planner()

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

Definition at line 693 of file planner.c.

696{
698 List *newWithCheckOptions;
699 List *newHaving;
700 bool hasOuterJoins;
701 bool hasResultRTEs;
702 RelOptInfo *final_rel;
703 ListCell *l;
704
705 /* Create a PlannerInfo data structure for this subquery */
707 root->parse = parse;
708 root->glob = glob;
709 root->query_level = parent_root ? parent_root->query_level + 1 : 1;
710 root->plan_name = plan_name;
711 root->parent_root = parent_root;
712 root->plan_params = NIL;
713 root->outer_params = NULL;
714 root->planner_cxt = CurrentMemoryContext;
715 root->init_plans = NIL;
716 root->cte_plan_ids = NIL;
717 root->multiexpr_params = NIL;
718 root->join_domains = NIL;
719 root->eq_classes = NIL;
720 root->ec_merging_done = false;
721 root->last_rinfo_serial = 0;
722 root->all_result_relids =
723 parse->resultRelation ? bms_make_singleton(parse->resultRelation) : NULL;
724 root->leaf_result_relids = NULL; /* we'll find out leaf-ness later */
725 root->append_rel_list = NIL;
726 root->row_identity_vars = NIL;
727 root->rowMarks = NIL;
728 memset(root->upper_rels, 0, sizeof(root->upper_rels));
729 memset(root->upper_targets, 0, sizeof(root->upper_targets));
730 root->processed_groupClause = NIL;
731 root->processed_distinctClause = NIL;
732 root->processed_tlist = NIL;
733 root->update_colnos = NIL;
734 root->grouping_map = NULL;
735 root->minmax_aggs = NIL;
736 root->qual_security_level = 0;
737 root->hasPseudoConstantQuals = false;
738 root->hasAlternativeSubPlans = false;
739 root->placeholdersFrozen = false;
740 root->hasRecursion = hasRecursion;
741 root->assumeReplanning = false;
742 if (hasRecursion)
743 root->wt_param_id = assign_special_exec_param(root);
744 else
745 root->wt_param_id = -1;
746 root->non_recursive_path = NULL;
747
748 /*
749 * Create the top-level join domain. This won't have valid contents until
750 * deconstruct_jointree fills it in, but the node needs to exist before
751 * that so we can build EquivalenceClasses referencing it.
752 */
753 root->join_domains = list_make1(makeNode(JoinDomain));
754
755 /*
756 * If there is a WITH list, process each WITH query and either convert it
757 * to RTE_SUBQUERY RTE(s) or build an initplan SubPlan structure for it.
758 */
759 if (parse->cteList)
761
762 /*
763 * If it's a MERGE command, transform the joinlist as appropriate.
764 */
766
767 /*
768 * Scan the rangetable for relation RTEs and retrieve the necessary
769 * catalog information for each relation. Using this information, clear
770 * the inh flag for any relation that has no children, collect not-null
771 * attribute numbers for any relation that has column not-null
772 * constraints, and expand virtual generated columns for any relation that
773 * contains them. Note that this step does not descend into sublinks and
774 * subqueries; if we pull up any sublinks or subqueries below, their
775 * relation RTEs are processed just before pulling them up.
776 */
778
779 /*
780 * If the FROM clause is empty, replace it with a dummy RTE_RESULT RTE, so
781 * that we don't need so many special cases to deal with that situation.
782 */
784
785 /*
786 * Look for ANY and EXISTS SubLinks in WHERE and JOIN/ON clauses, and try
787 * to transform them into joins. Note that this step does not descend
788 * into subqueries; if we pull up any subqueries below, their SubLinks are
789 * processed just before pulling them up.
790 */
791 if (parse->hasSubLinks)
793
794 /*
795 * Scan the rangetable for function RTEs, do const-simplification on them,
796 * and then inline them if possible (producing subqueries that might get
797 * pulled up next). Recursion issues here are handled in the same way as
798 * for SubLinks.
799 */
801
802 /*
803 * Check to see if any subqueries in the jointree can be merged into this
804 * query.
805 */
807
808 /*
809 * If this is a simple UNION ALL query, flatten it into an appendrel. We
810 * do this now because it requires applying pull_up_subqueries to the leaf
811 * queries of the UNION ALL, which weren't touched above because they
812 * weren't referenced by the jointree (they will be after we do this).
813 */
814 if (parse->setOperations)
816
817 /*
818 * Survey the rangetable to see what kinds of entries are present. We can
819 * skip some later processing if relevant SQL features are not used; for
820 * example if there are no JOIN RTEs we can avoid the expense of doing
821 * flatten_join_alias_vars(). This must be done after we have finished
822 * adding rangetable entries, of course. (Note: actually, processing of
823 * inherited or partitioned rels can cause RTEs for their child tables to
824 * get added later; but those must all be RTE_RELATION entries, so they
825 * don't invalidate the conclusions drawn here.)
826 */
827 root->hasJoinRTEs = false;
828 root->hasLateralRTEs = false;
829 root->group_rtindex = 0;
830 hasOuterJoins = false;
831 hasResultRTEs = false;
832 foreach(l, parse->rtable)
833 {
835
836 switch (rte->rtekind)
837 {
838 case RTE_JOIN:
839 root->hasJoinRTEs = true;
840 if (IS_OUTER_JOIN(rte->jointype))
841 hasOuterJoins = true;
842 break;
843 case RTE_RESULT:
844 hasResultRTEs = true;
845 break;
846 case RTE_GROUP:
847 Assert(parse->hasGroupRTE);
848 root->group_rtindex = list_cell_number(parse->rtable, l) + 1;
849 break;
850 default:
851 /* No work here for other RTE types */
852 break;
853 }
854
855 if (rte->lateral)
856 root->hasLateralRTEs = true;
857
858 /*
859 * We can also determine the maximum security level required for any
860 * securityQuals now. Addition of inheritance-child RTEs won't affect
861 * this, because child tables don't have their own securityQuals; see
862 * expand_single_inheritance_child().
863 */
864 if (rte->securityQuals)
865 root->qual_security_level = Max(root->qual_security_level,
866 list_length(rte->securityQuals));
867 }
868
869 /*
870 * If we have now verified that the query target relation is
871 * non-inheriting, mark it as a leaf target.
872 */
873 if (parse->resultRelation)
874 {
875 RangeTblEntry *rte = rt_fetch(parse->resultRelation, parse->rtable);
876
877 if (!rte->inh)
878 root->leaf_result_relids =
879 bms_make_singleton(parse->resultRelation);
880 }
881
882 /*
883 * This would be a convenient time to check access permissions for all
884 * relations mentioned in the query, since it would be better to fail now,
885 * before doing any detailed planning. However, for historical reasons,
886 * we leave this to be done at executor startup.
887 *
888 * Note, however, that we do need to check access permissions for any view
889 * relations mentioned in the query, in order to prevent information being
890 * leaked by selectivity estimation functions, which only check view owner
891 * permissions on underlying tables (see all_rows_selectable() and its
892 * callers). This is a little ugly, because it means that access
893 * permissions for views will be checked twice, which is another reason
894 * why it would be better to do all the ACL checks here.
895 */
896 foreach(l, parse->rtable)
897 {
899
900 if (rte->perminfoindex != 0 &&
901 rte->relkind == RELKIND_VIEW)
902 {
903 RTEPermissionInfo *perminfo;
904 bool result;
905
906 perminfo = getRTEPermissionInfo(parse->rteperminfos, rte);
907 result = ExecCheckOneRelPerms(perminfo);
908 if (!result)
910 get_rel_name(perminfo->relid));
911 }
912 }
913
914 /*
915 * Preprocess RowMark information. We need to do this after subquery
916 * pullup, so that all base relations are present.
917 */
919
920 /*
921 * Set hasHavingQual to remember if HAVING clause is present. Needed
922 * because preprocess_expression will reduce a constant-true condition to
923 * an empty qual list ... but "HAVING TRUE" is not a semantic no-op.
924 */
925 root->hasHavingQual = (parse->havingQual != NULL);
926
927 /*
928 * Do expression preprocessing on targetlist and quals, as well as other
929 * random expressions in the querytree. Note that we do not need to
930 * handle sort/group expressions explicitly, because they are actually
931 * part of the targetlist.
932 */
933 parse->targetList = (List *)
934 preprocess_expression(root, (Node *) parse->targetList,
936
937 newWithCheckOptions = NIL;
938 foreach(l, parse->withCheckOptions)
939 {
941
942 wco->qual = preprocess_expression(root, wco->qual,
944 if (wco->qual != NULL)
945 newWithCheckOptions = lappend(newWithCheckOptions, wco);
946 }
947 parse->withCheckOptions = newWithCheckOptions;
948
949 parse->returningList = (List *)
950 preprocess_expression(root, (Node *) parse->returningList,
952
954
955 parse->havingQual = preprocess_expression(root, parse->havingQual,
957
958 foreach(l, parse->windowClause)
959 {
961
962 /* partitionClause/orderClause are sort/group expressions */
967 }
968
969 parse->limitOffset = preprocess_expression(root, parse->limitOffset,
971 parse->limitCount = preprocess_expression(root, parse->limitCount,
973
974 if (parse->onConflict)
975 {
976 parse->onConflict->arbiterElems = (List *)
978 (Node *) parse->onConflict->arbiterElems,
980 parse->onConflict->arbiterWhere =
982 parse->onConflict->arbiterWhere,
984 parse->onConflict->onConflictSet = (List *)
986 (Node *) parse->onConflict->onConflictSet,
988 parse->onConflict->onConflictWhere =
990 parse->onConflict->onConflictWhere,
992 /* exclRelTlist contains only Vars, so no preprocessing needed */
993 }
994
995 foreach(l, parse->mergeActionList)
996 {
998
999 action->targetList = (List *)
1001 (Node *) action->targetList,
1003 action->qual =
1005 (Node *) action->qual,
1007 }
1008
1009 parse->mergeJoinCondition =
1010 preprocess_expression(root, parse->mergeJoinCondition, EXPRKIND_QUAL);
1011
1012 root->append_rel_list = (List *)
1013 preprocess_expression(root, (Node *) root->append_rel_list,
1015
1016 /* Also need to preprocess expressions within RTEs */
1017 foreach(l, parse->rtable)
1018 {
1020 int kind;
1021 ListCell *lcsq;
1022
1023 if (rte->rtekind == RTE_RELATION)
1024 {
1025 if (rte->tablesample)
1028 (Node *) rte->tablesample,
1030 }
1031 else if (rte->rtekind == RTE_SUBQUERY)
1032 {
1033 /*
1034 * We don't want to do all preprocessing yet on the subquery's
1035 * expressions, since that will happen when we plan it. But if it
1036 * contains any join aliases of our level, those have to get
1037 * expanded now, because planning of the subquery won't do it.
1038 * That's only possible if the subquery is LATERAL.
1039 */
1040 if (rte->lateral && root->hasJoinRTEs)
1041 rte->subquery = (Query *)
1043 (Node *) rte->subquery);
1044 }
1045 else if (rte->rtekind == RTE_FUNCTION)
1046 {
1047 /* Preprocess the function expression(s) fully */
1048 kind = rte->lateral ? EXPRKIND_RTFUNC_LATERAL : EXPRKIND_RTFUNC;
1049 rte->functions = (List *)
1050 preprocess_expression(root, (Node *) rte->functions, kind);
1051 }
1052 else if (rte->rtekind == RTE_TABLEFUNC)
1053 {
1054 /* Preprocess the function expression(s) fully */
1055 kind = rte->lateral ? EXPRKIND_TABLEFUNC_LATERAL : EXPRKIND_TABLEFUNC;
1056 rte->tablefunc = (TableFunc *)
1057 preprocess_expression(root, (Node *) rte->tablefunc, kind);
1058 }
1059 else if (rte->rtekind == RTE_VALUES)
1060 {
1061 /* Preprocess the values lists fully */
1062 kind = rte->lateral ? EXPRKIND_VALUES_LATERAL : EXPRKIND_VALUES;
1063 rte->values_lists = (List *)
1065 }
1066 else if (rte->rtekind == RTE_GROUP)
1067 {
1068 /* Preprocess the groupexprs list fully */
1069 rte->groupexprs = (List *)
1070 preprocess_expression(root, (Node *) rte->groupexprs,
1072 }
1073
1074 /*
1075 * Process each element of the securityQuals list as if it were a
1076 * separate qual expression (as indeed it is). We need to do it this
1077 * way to get proper canonicalization of AND/OR structure. Note that
1078 * this converts each element into an implicit-AND sublist.
1079 */
1080 foreach(lcsq, rte->securityQuals)
1081 {
1083 (Node *) lfirst(lcsq),
1085 }
1086 }
1087
1088 /*
1089 * Now that we are done preprocessing expressions, and in particular done
1090 * flattening join alias variables, get rid of the joinaliasvars lists.
1091 * They no longer match what expressions in the rest of the tree look
1092 * like, because we have not preprocessed expressions in those lists (and
1093 * do not want to; for example, expanding a SubLink there would result in
1094 * a useless unreferenced subplan). Leaving them in place simply creates
1095 * a hazard for later scans of the tree. We could try to prevent that by
1096 * using QTW_IGNORE_JOINALIASES in every tree scan done after this point,
1097 * but that doesn't sound very reliable.
1098 */
1099 if (root->hasJoinRTEs)
1100 {
1101 foreach(l, parse->rtable)
1102 {
1104
1105 rte->joinaliasvars = NIL;
1106 }
1107 }
1108
1109 /*
1110 * Replace any Vars in the subquery's targetlist and havingQual that
1111 * reference GROUP outputs with the underlying grouping expressions.
1112 *
1113 * Note that we need to perform this replacement after we've preprocessed
1114 * the grouping expressions. This is to ensure that there is only one
1115 * instance of SubPlan for each SubLink contained within the grouping
1116 * expressions.
1117 */
1118 if (parse->hasGroupRTE)
1119 {
1120 parse->targetList = (List *)
1121 flatten_group_exprs(root, root->parse, (Node *) parse->targetList);
1122 parse->havingQual =
1123 flatten_group_exprs(root, root->parse, parse->havingQual);
1124 }
1125
1126 /* Constant-folding might have removed all set-returning functions */
1127 if (parse->hasTargetSRFs)
1128 parse->hasTargetSRFs = expression_returns_set((Node *) parse->targetList);
1129
1130 /*
1131 * If we have grouping sets, expand the groupingSets tree of this query to
1132 * a flat list of grouping sets. We need to do this before optimizing
1133 * HAVING, since we can't easily tell if there's an empty grouping set
1134 * until we have this representation.
1135 */
1136 if (parse->groupingSets)
1137 {
1138 parse->groupingSets =
1139 expand_grouping_sets(parse->groupingSets, parse->groupDistinct, -1);
1140 }
1141
1142 /*
1143 * In some cases we may want to transfer a HAVING clause into WHERE. We
1144 * cannot do so if the HAVING clause contains aggregates (obviously) or
1145 * volatile functions (since a HAVING clause is supposed to be executed
1146 * only once per group). We also can't do this if there are any grouping
1147 * sets and the clause references any columns that are nullable by the
1148 * grouping sets; the nulled values of those columns are not available
1149 * before the grouping step. (The test on groupClause might seem wrong,
1150 * but it's okay: it's just an optimization to avoid running pull_varnos
1151 * when there cannot be any Vars in the HAVING clause.)
1152 *
1153 * Also, it may be that the clause is so expensive to execute that we're
1154 * better off doing it only once per group, despite the loss of
1155 * selectivity. This is hard to estimate short of doing the entire
1156 * planning process twice, so we use a heuristic: clauses containing
1157 * subplans are left in HAVING. Otherwise, we move or copy the HAVING
1158 * clause into WHERE, in hopes of eliminating tuples before aggregation
1159 * instead of after.
1160 *
1161 * If the query has no empty grouping set then we can simply move such a
1162 * clause into WHERE; any group that fails the clause will not be in the
1163 * output because none of its tuples will reach the grouping or
1164 * aggregation stage. Otherwise we have to keep the clause in HAVING to
1165 * ensure that we don't emit a bogus aggregated row. But then the HAVING
1166 * clause must be degenerate (variable-free), so we can copy it into WHERE
1167 * so that query_planner() can use it in a gating Result node. (This could
1168 * be done better, but it seems not worth optimizing.)
1169 *
1170 * Note that a HAVING clause may contain expressions that are not fully
1171 * preprocessed. This can happen if these expressions are part of
1172 * grouping items. In such cases, they are replaced with GROUP Vars in
1173 * the parser and then replaced back after we're done with expression
1174 * preprocessing on havingQual. This is not an issue if the clause
1175 * remains in HAVING, because these expressions will be matched to lower
1176 * target items in setrefs.c. However, if the clause is moved or copied
1177 * into WHERE, we need to ensure that these expressions are fully
1178 * preprocessed.
1179 *
1180 * Note that both havingQual and parse->jointree->quals are in
1181 * implicitly-ANDed-list form at this point, even though they are declared
1182 * as Node *.
1183 */
1184 newHaving = NIL;
1185 foreach(l, (List *) parse->havingQual)
1186 {
1187 Node *havingclause = (Node *) lfirst(l);
1188
1189 if (contain_agg_clause(havingclause) ||
1190 contain_volatile_functions(havingclause) ||
1191 contain_subplans(havingclause) ||
1192 (parse->groupClause && parse->groupingSets &&
1193 bms_is_member(root->group_rtindex, pull_varnos(root, havingclause))))
1194 {
1195 /* keep it in HAVING */
1196 newHaving = lappend(newHaving, havingclause);
1197 }
1198 else if (parse->groupClause &&
1199 (parse->groupingSets == NIL ||
1200 (List *) linitial(parse->groupingSets) != NIL))
1201 {
1202 /* There is GROUP BY, but no empty grouping set */
1203 Node *whereclause;
1204
1205 /* Preprocess the HAVING clause fully */
1206 whereclause = preprocess_expression(root, havingclause,
1208 /* ... and move it to WHERE */
1209 parse->jointree->quals = (Node *)
1210 list_concat((List *) parse->jointree->quals,
1211 (List *) whereclause);
1212 }
1213 else
1214 {
1215 /* There is an empty grouping set (perhaps implicitly) */
1216 Node *whereclause;
1217
1218 /* Preprocess the HAVING clause fully */
1219 whereclause = preprocess_expression(root, copyObject(havingclause),
1221 /* ... and put a copy in WHERE */
1222 parse->jointree->quals = (Node *)
1223 list_concat((List *) parse->jointree->quals,
1224 (List *) whereclause);
1225 /* ... and also keep it in HAVING */
1226 newHaving = lappend(newHaving, havingclause);
1227 }
1228 }
1229 parse->havingQual = (Node *) newHaving;
1230
1231 /*
1232 * If we have any outer joins, try to reduce them to plain inner joins.
1233 * This step is most easily done after we've done expression
1234 * preprocessing.
1235 */
1236 if (hasOuterJoins)
1238
1239 /*
1240 * If we have any RTE_RESULT relations, see if they can be deleted from
1241 * the jointree. We also rely on this processing to flatten single-child
1242 * FromExprs underneath outer joins. This step is most effectively done
1243 * after we've done expression preprocessing and outer join reduction.
1244 */
1245 if (hasResultRTEs || hasOuterJoins)
1247
1248 /*
1249 * Do the main planning.
1250 */
1251 grouping_planner(root, tuple_fraction, setops);
1252
1253 /*
1254 * Capture the set of outer-level param IDs we have access to, for use in
1255 * extParam/allParam calculations later.
1256 */
1258
1259 /*
1260 * If any initPlans were created in this query level, adjust the surviving
1261 * Paths' costs and parallel-safety flags to account for them. The
1262 * initPlans won't actually get attached to the plan tree till
1263 * create_plan() runs, but we must include their effects now.
1264 */
1265 final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
1266 SS_charge_for_initplans(root, final_rel);
1267
1268 /*
1269 * Make sure we've identified the cheapest Path for the final rel. (By
1270 * doing this here not in grouping_planner, we include initPlan costs in
1271 * the decision, though it's unlikely that will change anything.)
1272 */
1273 set_cheapest(final_rel);
1274
1275 return root;
1276}
@ ACLCHECK_NO_PRIV
Definition: acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2652
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
#define Max(x, y)
Definition: c.h:1000
bool contain_agg_clause(Node *clause)
Definition: clauses.c:190
bool contain_subplans(Node *clause)
Definition: clauses.c:342
bool contain_volatile_functions(Node *clause)
Definition: clauses.c:550
bool ExecCheckOneRelPerms(RTEPermissionInfo *perminfo)
Definition: execMain.c:646
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2095
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
bool expression_returns_set(Node *clause)
Definition: nodeFuncs.c:763
#define copyObject(obj)
Definition: nodes.h:232
#define IS_OUTER_JOIN(jointype)
Definition: nodes.h:348
int assign_special_exec_param(PlannerInfo *root)
Definition: paramassign.c:754
List * expand_grouping_sets(List *groupingSets, bool groupDistinct, int limit)
Definition: parse_agg.c:1947
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
@ RTE_JOIN
Definition: parsenodes.h:1045
@ RTE_VALUES
Definition: parsenodes.h:1048
@ RTE_SUBQUERY
Definition: parsenodes.h:1044
@ RTE_RESULT
Definition: parsenodes.h:1051
@ RTE_FUNCTION
Definition: parsenodes.h:1046
@ RTE_TABLEFUNC
Definition: parsenodes.h:1047
@ RTE_GROUP
Definition: parsenodes.h:1054
@ OBJECT_VIEW
Definition: parsenodes.h:2376
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define list_make1(x1)
Definition: pg_list.h:212
#define linitial(l)
Definition: pg_list.h:178
static int list_cell_number(const List *l, const ListCell *c)
Definition: pg_list.h:333
#define EXPRKIND_TABLEFUNC_LATERAL
Definition: planner.c:99
#define EXPRKIND_TARGET
Definition: planner.c:88
#define EXPRKIND_APPINFO
Definition: planner.c:94
static void preprocess_rowmarks(PlannerInfo *root)
Definition: planner.c:2427
#define EXPRKIND_TABLESAMPLE
Definition: planner.c:96
#define EXPRKIND_GROUPEXPR
Definition: planner.c:100
static void preprocess_qual_conditions(PlannerInfo *root, Node *jtnode)
Definition: planner.c:1387
#define EXPRKIND_RTFUNC_LATERAL
Definition: planner.c:90
#define EXPRKIND_VALUES_LATERAL
Definition: planner.c:92
#define EXPRKIND_LIMIT
Definition: planner.c:93
#define EXPRKIND_VALUES
Definition: planner.c:91
#define EXPRKIND_QUAL
Definition: planner.c:87
static void grouping_planner(PlannerInfo *root, double tuple_fraction, SetOperationStmt *setops)
Definition: planner.c:1464
#define EXPRKIND_TABLEFUNC
Definition: planner.c:98
#define EXPRKIND_RTFUNC
Definition: planner.c:89
#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)
Definition: prepjointree.c:187
void remove_useless_result_rtes(PlannerInfo *root)
void pull_up_sublinks(PlannerInfo *root)
Definition: prepjointree.c:647
void replace_empty_jointree(Query *parse)
Definition: prepjointree.c:589
void pull_up_subqueries(PlannerInfo *root)
Query * preprocess_relation_rtes(PlannerInfo *root)
Definition: prepjointree.c:417
void reduce_outer_joins(PlannerInfo *root)
Index query_level
Definition: pathnodes.h:233
TableFunc * tablefunc
Definition: parsenodes.h:1215
struct TableSampleClause * tablesample
Definition: parsenodes.h:1129
Query * subquery
Definition: parsenodes.h:1135
List * values_lists
Definition: parsenodes.h:1221
JoinType jointype
Definition: parsenodes.h:1182
List * functions
Definition: parsenodes.h:1208
Node * startOffset
Definition: parsenodes.h:1578
Node * endOffset
Definition: parsenodes.h:1579
void SS_process_ctes(PlannerInfo *root)
Definition: subselect.c:883
void SS_identify_outer_params(PlannerInfo *root)
Definition: subselect.c:2220
void SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel)
Definition: subselect.c:2284
Node * flatten_group_exprs(PlannerInfo *root, Query *query, Node *node)
Definition: var.c:968
Relids pull_varnos(PlannerInfo *root, Node *node)
Definition: var.c:114
Node * flatten_join_alias_vars(PlannerInfo *root, Query *query, Node *node)
Definition: var.c:789

References aclcheck_error(), ACLCHECK_NO_PRIV, generate_unaccent_rules::action, Assert(), assign_special_exec_param(), bms_is_member(), bms_make_singleton(), contain_agg_clause(), contain_subplans(), contain_volatile_functions(), copyObject, CurrentMemoryContext, WindowClause::endOffset, 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, fetch_upper_rel(), flatten_group_exprs(), flatten_join_alias_vars(), flatten_simple_union_all(), RangeTblEntry::functions, get_rel_name(), getRTEPermissionInfo(), grouping_planner(), RangeTblEntry::inh, IS_OUTER_JOIN, RangeTblEntry::jointype, 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(), WithCheckOption::qual, PlannerInfo::query_level, reduce_outer_joins(), RTEPermissionInfo::relid, remove_useless_result_rtes(), replace_empty_jointree(), root, rt_fetch, RTE_FUNCTION, RTE_GROUP, RTE_JOIN, RTE_RELATION, RTE_RESULT, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, set_cheapest(), SS_charge_for_initplans(), SS_identify_outer_params(), SS_process_ctes(), WindowClause::startOffset, RangeTblEntry::subquery, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, transform_MERGE_to_join(), UPPERREL_FINAL, and RangeTblEntry::values_lists.

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

Variable Documentation

◆ create_upper_paths_hook

◆ planner_hook

PGDLLIMPORT planner_hook_type planner_hook
extern

Definition at line 74 of file planner.c.

Referenced by _PG_init(), and planner().

◆ planner_setup_hook

PGDLLIMPORT planner_setup_hook_type planner_setup_hook
extern

Definition at line 77 of file planner.c.

Referenced by standard_planner().

◆ planner_shutdown_hook

PGDLLIMPORT planner_shutdown_hook_type planner_shutdown_hook
extern

Definition at line 80 of file planner.c.

Referenced by standard_planner().