PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
prep.h File Reference
#include "nodes/pathnodes.h"
#include "nodes/plannodes.h"
Include dependency graph for prep.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void transform_MERGE_to_join (Query *parse)
 
void replace_empty_jointree (Query *parse)
 
void pull_up_sublinks (PlannerInfo *root)
 
void preprocess_function_rtes (PlannerInfo *root)
 
Queryexpand_virtual_generated_columns (PlannerInfo *root)
 
void pull_up_subqueries (PlannerInfo *root)
 
void flatten_simple_union_all (PlannerInfo *root)
 
void reduce_outer_joins (PlannerInfo *root)
 
void remove_useless_result_rtes (PlannerInfo *root)
 
Relids get_relids_in_jointree (Node *jtnode, bool include_outer_joins, bool include_inner_joins)
 
Relids get_relids_for_join (Query *query, int joinrelid)
 
void preprocess_targetlist (PlannerInfo *root)
 
Listextract_update_targetlist_colnos (List *tlist)
 
PlanRowMarkget_plan_rowmark (List *rowmarks, Index rtindex)
 
void get_agg_clause_costs (PlannerInfo *root, AggSplit aggsplit, AggClauseCosts *costs)
 
void preprocess_aggrefs (PlannerInfo *root, Node *clause)
 
RelOptInfoplan_set_operations (PlannerInfo *root)
 

Function Documentation

◆ expand_virtual_generated_columns()

Query * expand_virtual_generated_columns ( PlannerInfo root)

Definition at line 969 of file prepjointree.c.

970{
971 Query *parse = root->parse;
972 int rt_index;
973 ListCell *lc;
974
975 rt_index = 0;
976 foreach(lc, parse->rtable)
977 {
978 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
979 Relation rel;
980 TupleDesc tupdesc;
981
982 ++rt_index;
983
984 /*
985 * Only normal relations can have virtual generated columns.
986 */
987 if (rte->rtekind != RTE_RELATION)
988 continue;
989
990 rel = table_open(rte->relid, NoLock);
991
992 tupdesc = RelationGetDescr(rel);
993 if (tupdesc->constr && tupdesc->constr->has_generated_virtual)
994 {
995 List *tlist = NIL;
997
998 for (int i = 0; i < tupdesc->natts; i++)
999 {
1000 Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
1001 TargetEntry *tle;
1002
1003 if (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
1004 {
1005 Node *defexpr;
1006
1007 defexpr = build_generation_expression(rel, i + 1);
1008 ChangeVarNodes(defexpr, 1, rt_index, 0);
1009
1010 tle = makeTargetEntry((Expr *) defexpr, i + 1, 0, false);
1011 tlist = lappend(tlist, tle);
1012 }
1013 else
1014 {
1015 Var *var;
1016
1017 var = makeVar(rt_index,
1018 i + 1,
1019 attr->atttypid,
1020 attr->atttypmod,
1021 attr->attcollation,
1022 0);
1023
1024 tle = makeTargetEntry((Expr *) var, i + 1, 0, false);
1025 tlist = lappend(tlist, tle);
1026 }
1027 }
1028
1029 Assert(list_length(tlist) > 0);
1030 Assert(!rte->lateral);
1031
1032 /*
1033 * The relation's targetlist items are now in the appropriate form
1034 * to insert into the query, except that we may need to wrap them
1035 * in PlaceHolderVars. Set up required context data for
1036 * pullup_replace_vars.
1037 */
1038 rvcontext.root = root;
1039 rvcontext.targetlist = tlist;
1040 rvcontext.target_rte = rte;
1041 rvcontext.result_relation = parse->resultRelation;
1042 /* won't need these values */
1043 rvcontext.relids = NULL;
1044 rvcontext.nullinfo = NULL;
1045 /* pass NULL for outer_hasSubLinks */
1046 rvcontext.outer_hasSubLinks = NULL;
1047 rvcontext.varno = rt_index;
1048 /* this flag will be set below, if needed */
1049 rvcontext.wrap_option = REPLACE_WRAP_NONE;
1050 /* initialize cache array with indexes 0 .. length(tlist) */
1051 rvcontext.rv_cache = palloc0((list_length(tlist) + 1) *
1052 sizeof(Node *));
1053
1054 /*
1055 * If the query uses grouping sets, we need a PlaceHolderVar for
1056 * each expression of the relation's targetlist items. (See
1057 * comments in pull_up_simple_subquery().)
1058 */
1059 if (parse->groupingSets)
1060 rvcontext.wrap_option = REPLACE_WRAP_ALL;
1061
1062 /*
1063 * Apply pullup variable replacement throughout the query tree.
1064 */
1065 parse = (Query *) pullup_replace_vars((Node *) parse, &rvcontext);
1066 }
1067
1068 table_close(rel, NoLock);
1069 }
1070
1071 return parse;
1072}
Assert(PointerIsAligned(start, uint64))
int i
Definition: isn.c:77
List * lappend(List *list, void *datum)
Definition: list.c:339
#define NoLock
Definition: lockdefs.h:34
Var * makeVar(int varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:289
void * palloc0(Size size)
Definition: mcxt.c:1970
@ RTE_RELATION
Definition: parsenodes.h:1026
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
#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
@ REPLACE_WRAP_ALL
Definition: prepjointree.c:64
@ REPLACE_WRAP_NONE
Definition: prepjointree.c:63
static Node * pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
tree ctl root
Definition: radixtree.h:1857
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
#define RelationGetDescr(relation)
Definition: rel.h:542
Node * build_generation_expression(Relation rel, int attrno)
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:793
Definition: pg_list.h:54
Definition: nodes.h:135
RTEKind rtekind
Definition: parsenodes.h:1061
bool has_generated_virtual
Definition: tupdesc.h:47
TupleConstr * constr
Definition: tupdesc.h:141
Definition: primnodes.h:262
nullingrel_info * nullinfo
Definition: prepjointree.c:78
ReplaceWrapOption wrap_option
Definition: prepjointree.c:82
RangeTblEntry * target_rte
Definition: prepjointree.c:73
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160

References Assert(), build_generation_expression(), ChangeVarNodes(), TupleDescData::constr, TupleConstr::has_generated_virtual, i, lappend(), lfirst, list_length(), makeTargetEntry(), makeVar(), TupleDescData::natts, NIL, NoLock, pullup_replace_vars_context::nullinfo, pullup_replace_vars_context::outer_hasSubLinks, palloc0(), parse(), pullup_replace_vars(), RelationGetDescr, pullup_replace_vars_context::relids, REPLACE_WRAP_ALL, REPLACE_WRAP_NONE, pullup_replace_vars_context::result_relation, pullup_replace_vars_context::root, root, RTE_RELATION, RangeTblEntry::rtekind, pullup_replace_vars_context::rv_cache, table_close(), table_open(), pullup_replace_vars_context::target_rte, pullup_replace_vars_context::targetlist, TupleDescAttr(), pullup_replace_vars_context::varno, and pullup_replace_vars_context::wrap_option.

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ extract_update_targetlist_colnos()

List * extract_update_targetlist_colnos ( List tlist)

Definition at line 347 of file preptlist.c.

348{
349 List *update_colnos = NIL;
350 AttrNumber nextresno = 1;
351 ListCell *lc;
352
353 foreach(lc, tlist)
354 {
355 TargetEntry *tle = (TargetEntry *) lfirst(lc);
356
357 if (!tle->resjunk)
358 update_colnos = lappend_int(update_colnos, tle->resno);
359 tle->resno = nextresno++;
360 }
361 return update_colnos;
362}
int16 AttrNumber
Definition: attnum.h:21
List * lappend_int(List *list, int datum)
Definition: list.c:357
AttrNumber resno
Definition: primnodes.h:2221

References lappend_int(), lfirst, NIL, and TargetEntry::resno.

Referenced by make_modifytable(), and preprocess_targetlist().

◆ flatten_simple_union_all()

void flatten_simple_union_all ( PlannerInfo root)

Definition at line 2983 of file prepjointree.c.

2984{
2985 Query *parse = root->parse;
2986 SetOperationStmt *topop;
2987 Node *leftmostjtnode;
2988 int leftmostRTI;
2989 RangeTblEntry *leftmostRTE;
2990 int childRTI;
2991 RangeTblEntry *childRTE;
2992 RangeTblRef *rtr;
2993
2994 /* Shouldn't be called unless query has setops */
2995 topop = castNode(SetOperationStmt, parse->setOperations);
2996 Assert(topop);
2997
2998 /* Can't optimize away a recursive UNION */
2999 if (root->hasRecursion)
3000 return;
3001
3002 /*
3003 * Recursively check the tree of set operations. If not all UNION ALL
3004 * with identical column types, punt.
3005 */
3006 if (!is_simple_union_all_recurse((Node *) topop, parse, topop->colTypes))
3007 return;
3008
3009 /*
3010 * Locate the leftmost leaf query in the setops tree. The upper query's
3011 * Vars all refer to this RTE (see transformSetOperationStmt).
3012 */
3013 leftmostjtnode = topop->larg;
3014 while (leftmostjtnode && IsA(leftmostjtnode, SetOperationStmt))
3015 leftmostjtnode = ((SetOperationStmt *) leftmostjtnode)->larg;
3016 Assert(leftmostjtnode && IsA(leftmostjtnode, RangeTblRef));
3017 leftmostRTI = ((RangeTblRef *) leftmostjtnode)->rtindex;
3018 leftmostRTE = rt_fetch(leftmostRTI, parse->rtable);
3019 Assert(leftmostRTE->rtekind == RTE_SUBQUERY);
3020
3021 /*
3022 * Make a copy of the leftmost RTE and add it to the rtable. This copy
3023 * will represent the leftmost leaf query in its capacity as a member of
3024 * the appendrel. The original will represent the appendrel as a whole.
3025 * (We must do things this way because the upper query's Vars have to be
3026 * seen as referring to the whole appendrel.)
3027 */
3028 childRTE = copyObject(leftmostRTE);
3029 parse->rtable = lappend(parse->rtable, childRTE);
3030 childRTI = list_length(parse->rtable);
3031
3032 /* Modify the setops tree to reference the child copy */
3033 ((RangeTblRef *) leftmostjtnode)->rtindex = childRTI;
3034
3035 /* Modify the formerly-leftmost RTE to mark it as an appendrel parent */
3036 leftmostRTE->inh = true;
3037
3038 /*
3039 * Form a RangeTblRef for the appendrel, and insert it into FROM. The top
3040 * Query of a setops tree should have had an empty FromClause initially.
3041 */
3042 rtr = makeNode(RangeTblRef);
3043 rtr->rtindex = leftmostRTI;
3044 Assert(parse->jointree->fromlist == NIL);
3045 parse->jointree->fromlist = list_make1(rtr);
3046
3047 /*
3048 * Now pretend the query has no setops. We must do this before trying to
3049 * do subquery pullup, because of Assert in pull_up_simple_subquery.
3050 */
3051 parse->setOperations = NULL;
3052
3053 /*
3054 * Build AppendRelInfo information, and apply pull_up_subqueries to the
3055 * leaf queries of the UNION ALL. (We must do that now because they
3056 * weren't previously referenced by the jointree, and so were missed by
3057 * the main invocation of pull_up_subqueries.)
3058 */
3059 pull_up_union_leaf_queries((Node *) topop, root, leftmostRTI, parse, 0);
3060}
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define copyObject(obj)
Definition: nodes.h:230
#define makeNode(_type_)
Definition: nodes.h:161
#define castNode(_type_, nodeptr)
Definition: nodes.h:182
@ RTE_SUBQUERY
Definition: parsenodes.h:1027
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
#define list_make1(x1)
Definition: pg_list.h:212
static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, Query *setOpQuery, int childRToffset)
static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)

References Assert(), castNode, copyObject, RangeTblEntry::inh, is_simple_union_all_recurse(), IsA, lappend(), SetOperationStmt::larg, list_length(), list_make1, makeNode, NIL, parse(), pull_up_union_leaf_queries(), root, rt_fetch, RTE_SUBQUERY, RangeTblEntry::rtekind, and RangeTblRef::rtindex.

Referenced by subquery_planner().

◆ get_agg_clause_costs()

void get_agg_clause_costs ( PlannerInfo root,
AggSplit  aggsplit,
AggClauseCosts costs 
)

Definition at line 559 of file prepagg.c.

560{
561 ListCell *lc;
562
563 foreach(lc, root->aggtransinfos)
564 {
565 AggTransInfo *transinfo = lfirst_node(AggTransInfo, lc);
566
567 /*
568 * Add the appropriate component function execution costs to
569 * appropriate totals.
570 */
571 if (DO_AGGSPLIT_COMBINE(aggsplit))
572 {
573 /* charge for combining previously aggregated states */
574 add_function_cost(root, transinfo->combinefn_oid, NULL,
575 &costs->transCost);
576 }
577 else
578 add_function_cost(root, transinfo->transfn_oid, NULL,
579 &costs->transCost);
580 if (DO_AGGSPLIT_DESERIALIZE(aggsplit) &&
581 OidIsValid(transinfo->deserialfn_oid))
582 add_function_cost(root, transinfo->deserialfn_oid, NULL,
583 &costs->transCost);
584 if (DO_AGGSPLIT_SERIALIZE(aggsplit) &&
585 OidIsValid(transinfo->serialfn_oid))
586 add_function_cost(root, transinfo->serialfn_oid, NULL,
587 &costs->finalCost);
588
589 /*
590 * These costs are incurred only by the initial aggregate node, so we
591 * mustn't include them again at upper levels.
592 */
593 if (!DO_AGGSPLIT_COMBINE(aggsplit))
594 {
595 /* add the input expressions' cost to per-input-row costs */
596 QualCost argcosts;
597
598 cost_qual_eval_node(&argcosts, (Node *) transinfo->args, root);
599 costs->transCost.startup += argcosts.startup;
600 costs->transCost.per_tuple += argcosts.per_tuple;
601
602 /*
603 * Add any filter's cost to per-input-row costs.
604 *
605 * XXX Ideally we should reduce input expression costs according
606 * to filter selectivity, but it's not clear it's worth the
607 * trouble.
608 */
609 if (transinfo->aggfilter)
610 {
611 cost_qual_eval_node(&argcosts, (Node *) transinfo->aggfilter,
612 root);
613 costs->transCost.startup += argcosts.startup;
614 costs->transCost.per_tuple += argcosts.per_tuple;
615 }
616 }
617
618 /*
619 * If the transition type is pass-by-value then it doesn't add
620 * anything to the required size of the hashtable. If it is
621 * pass-by-reference then we have to add the estimated size of the
622 * value itself, plus palloc overhead.
623 */
624 if (!transinfo->transtypeByVal)
625 {
626 int32 avgwidth;
627
628 /* Use average width if aggregate definition gave one */
629 if (transinfo->aggtransspace > 0)
630 avgwidth = transinfo->aggtransspace;
631 else if (transinfo->transfn_oid == F_ARRAY_APPEND)
632 {
633 /*
634 * If the transition function is array_append(), it'll use an
635 * expanded array as transvalue, which will occupy at least
636 * ALLOCSET_SMALL_INITSIZE and possibly more. Use that as the
637 * estimate for lack of a better idea.
638 */
639 avgwidth = ALLOCSET_SMALL_INITSIZE;
640 }
641 else
642 {
643 avgwidth = get_typavgwidth(transinfo->aggtranstype, transinfo->aggtranstypmod);
644 }
645
646 avgwidth = MAXALIGN(avgwidth);
647 costs->transitionSpace += avgwidth + 2 * sizeof(void *);
648 }
649 else if (transinfo->aggtranstype == INTERNALOID)
650 {
651 /*
652 * INTERNAL transition type is a special case: although INTERNAL
653 * is pass-by-value, it's almost certainly being used as a pointer
654 * to some large data structure. The aggregate definition can
655 * provide an estimate of the size. If it doesn't, then we assume
656 * ALLOCSET_DEFAULT_INITSIZE, which is a good guess if the data is
657 * being kept in a private memory context, as is done by
658 * array_agg() for instance.
659 */
660 if (transinfo->aggtransspace > 0)
661 costs->transitionSpace += transinfo->aggtransspace;
662 else
664 }
665 }
666
667 foreach(lc, root->agginfos)
668 {
669 AggInfo *agginfo = lfirst_node(AggInfo, lc);
670 Aggref *aggref = linitial_node(Aggref, agginfo->aggrefs);
671
672 /*
673 * Add the appropriate component function execution costs to
674 * appropriate totals.
675 */
676 if (!DO_AGGSPLIT_SKIPFINAL(aggsplit) &&
677 OidIsValid(agginfo->finalfn_oid))
678 add_function_cost(root, agginfo->finalfn_oid, NULL,
679 &costs->finalCost);
680
681 /*
682 * If there are direct arguments, treat their evaluation cost like the
683 * cost of the finalfn.
684 */
685 if (aggref->aggdirectargs)
686 {
687 QualCost argcosts;
688
689 cost_qual_eval_node(&argcosts, (Node *) aggref->aggdirectargs,
690 root);
691 costs->finalCost.startup += argcosts.startup;
692 costs->finalCost.per_tuple += argcosts.per_tuple;
693 }
694 }
695}
#define MAXALIGN(LEN)
Definition: c.h:782
int32_t int32
Definition: c.h:498
#define OidIsValid(objectId)
Definition: c.h:746
void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
Definition: costsize.c:4767
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition: lsyscache.c:2718
#define ALLOCSET_SMALL_INITSIZE
Definition: memutils.h:188
#define ALLOCSET_DEFAULT_INITSIZE
Definition: memutils.h:178
#define DO_AGGSPLIT_SKIPFINAL(as)
Definition: nodes.h:392
#define DO_AGGSPLIT_DESERIALIZE(as)
Definition: nodes.h:394
#define DO_AGGSPLIT_COMBINE(as)
Definition: nodes.h:391
#define DO_AGGSPLIT_SERIALIZE(as)
Definition: nodes.h:393
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define linitial_node(type, l)
Definition: pg_list.h:181
void add_function_cost(PlannerInfo *root, Oid funcid, Node *node, QualCost *cost)
Definition: plancat.c:2111
QualCost finalCost
Definition: pathnodes.h:61
Size transitionSpace
Definition: pathnodes.h:62
QualCost transCost
Definition: pathnodes.h:60
List * aggrefs
Definition: pathnodes.h:3512
Oid finalfn_oid
Definition: pathnodes.h:3524
List * args
Definition: pathnodes.h:3541
int32 aggtransspace
Definition: pathnodes.h:3565
bool transtypeByVal
Definition: pathnodes.h:3562
Oid combinefn_oid
Definition: pathnodes.h:3554
Oid deserialfn_oid
Definition: pathnodes.h:3551
int32 aggtranstypmod
Definition: pathnodes.h:3560
Oid serialfn_oid
Definition: pathnodes.h:3548
Oid aggtranstype
Definition: pathnodes.h:3557
Expr * aggfilter
Definition: pathnodes.h:3542
List * aggdirectargs
Definition: primnodes.h:482
Cost per_tuple
Definition: pathnodes.h:48
Cost startup
Definition: pathnodes.h:47

References add_function_cost(), Aggref::aggdirectargs, AggTransInfo::aggfilter, AggInfo::aggrefs, AggTransInfo::aggtransspace, AggTransInfo::aggtranstype, AggTransInfo::aggtranstypmod, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_SMALL_INITSIZE, AggTransInfo::args, AggTransInfo::combinefn_oid, cost_qual_eval_node(), AggTransInfo::deserialfn_oid, DO_AGGSPLIT_COMBINE, DO_AGGSPLIT_DESERIALIZE, DO_AGGSPLIT_SERIALIZE, DO_AGGSPLIT_SKIPFINAL, AggClauseCosts::finalCost, AggInfo::finalfn_oid, get_typavgwidth(), lfirst_node, linitial_node, MAXALIGN, OidIsValid, QualCost::per_tuple, root, AggTransInfo::serialfn_oid, QualCost::startup, AggClauseCosts::transCost, AggTransInfo::transfn_oid, AggClauseCosts::transitionSpace, and AggTransInfo::transtypeByVal.

Referenced by create_grouping_paths(), create_partial_grouping_paths(), and estimate_path_cost_size().

◆ get_plan_rowmark()

PlanRowMark * get_plan_rowmark ( List rowmarks,
Index  rtindex 
)

Definition at line 503 of file preptlist.c.

504{
505 ListCell *l;
506
507 foreach(l, rowmarks)
508 {
509 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
510
511 if (rc->rti == rtindex)
512 return rc;
513 }
514 return NULL;
515}

References lfirst, and PlanRowMark::rti.

Referenced by check_index_predicates(), deparseLockingClause(), and expand_inherited_rtentry().

◆ get_relids_for_join()

Relids get_relids_for_join ( Query query,
int  joinrelid 
)

Definition at line 4303 of file prepjointree.c.

4304{
4305 Node *jtnode;
4306
4307 jtnode = find_jointree_node_for_rel((Node *) query->jointree,
4308 joinrelid);
4309 if (!jtnode)
4310 elog(ERROR, "could not find join node %d", joinrelid);
4311 return get_relids_in_jointree(jtnode, true, false);
4312}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
static Node * find_jointree_node_for_rel(Node *jtnode, int relid)
Relids get_relids_in_jointree(Node *jtnode, bool include_outer_joins, bool include_inner_joins)
FromExpr * jointree
Definition: parsenodes.h:177

References elog, ERROR, find_jointree_node_for_rel(), get_relids_in_jointree(), and Query::jointree.

Referenced by add_nullingrels_if_needed(), and alias_relid_set().

◆ get_relids_in_jointree()

Relids get_relids_in_jointree ( Node jtnode,
bool  include_outer_joins,
bool  include_inner_joins 
)

Definition at line 4242 of file prepjointree.c.

4244{
4245 Relids result = NULL;
4246
4247 if (jtnode == NULL)
4248 return result;
4249 if (IsA(jtnode, RangeTblRef))
4250 {
4251 int varno = ((RangeTblRef *) jtnode)->rtindex;
4252
4253 result = bms_make_singleton(varno);
4254 }
4255 else if (IsA(jtnode, FromExpr))
4256 {
4257 FromExpr *f = (FromExpr *) jtnode;
4258 ListCell *l;
4259
4260 foreach(l, f->fromlist)
4261 {
4262 result = bms_join(result,
4264 include_outer_joins,
4265 include_inner_joins));
4266 }
4267 }
4268 else if (IsA(jtnode, JoinExpr))
4269 {
4270 JoinExpr *j = (JoinExpr *) jtnode;
4271
4272 result = get_relids_in_jointree(j->larg,
4273 include_outer_joins,
4274 include_inner_joins);
4275 result = bms_join(result,
4277 include_outer_joins,
4278 include_inner_joins));
4279 if (j->rtindex)
4280 {
4281 if (j->jointype == JOIN_INNER)
4282 {
4283 if (include_inner_joins)
4284 result = bms_add_member(result, j->rtindex);
4285 }
4286 else
4287 {
4288 if (include_outer_joins)
4289 result = bms_add_member(result, j->rtindex);
4290 }
4291 }
4292 }
4293 else
4294 elog(ERROR, "unrecognized node type: %d",
4295 (int) nodeTag(jtnode));
4296 return result;
4297}
Bitmapset * bms_make_singleton(int x)
Definition: bitmapset.c:216
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
Bitmapset * bms_join(Bitmapset *a, Bitmapset *b)
Definition: bitmapset.c:1230
int j
Definition: isn.c:78
#define nodeTag(nodeptr)
Definition: nodes.h:139
@ JOIN_INNER
Definition: nodes.h:299
List * fromlist
Definition: primnodes.h:2337

References bms_add_member(), bms_join(), bms_make_singleton(), elog, ERROR, FromExpr::fromlist, get_relids_in_jointree(), IsA, j, JOIN_INNER, lfirst, and nodeTag.

Referenced by find_dependent_phvs_in_jointree(), get_relids_for_join(), get_relids_in_jointree(), is_simple_subquery(), mark_nullable_by_grouping(), preprocess_rowmarks(), pull_up_simple_subquery(), and remove_result_refs().

◆ plan_set_operations()

RelOptInfo * plan_set_operations ( PlannerInfo root)

Definition at line 93 of file prepunion.c.

94{
95 Query *parse = root->parse;
96 SetOperationStmt *topop = castNode(SetOperationStmt, parse->setOperations);
97 Node *node;
98 RangeTblEntry *leftmostRTE;
99 Query *leftmostQuery;
100 RelOptInfo *setop_rel;
101 List *top_tlist;
102
103 Assert(topop);
104
105 /* check for unsupported stuff */
106 Assert(parse->jointree->fromlist == NIL);
107 Assert(parse->jointree->quals == NULL);
108 Assert(parse->groupClause == NIL);
109 Assert(parse->havingQual == NULL);
110 Assert(parse->windowClause == NIL);
111 Assert(parse->distinctClause == NIL);
112
113 /*
114 * In the outer query level, equivalence classes are limited to classes
115 * which define that the top-level target entry is equivalent to the
116 * corresponding child target entry. There won't be any equivalence class
117 * merging. Mark that merging is complete to allow us to make pathkeys.
118 */
119 Assert(root->eq_classes == NIL);
120 root->ec_merging_done = true;
121
122 /*
123 * We'll need to build RelOptInfos for each of the leaf subqueries, which
124 * are RTE_SUBQUERY rangetable entries in this Query. Prepare the index
125 * arrays for those, and for AppendRelInfos in case they're needed.
126 */
128
129 /*
130 * Find the leftmost component Query. We need to use its column names for
131 * all generated tlists (else SELECT INTO won't work right).
132 */
133 node = topop->larg;
134 while (node && IsA(node, SetOperationStmt))
135 node = ((SetOperationStmt *) node)->larg;
136 Assert(node && IsA(node, RangeTblRef));
137 leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
138 leftmostQuery = leftmostRTE->subquery;
139 Assert(leftmostQuery != NULL);
140
141 /*
142 * If the topmost node is a recursive union, it needs special processing.
143 */
144 if (root->hasRecursion)
145 {
146 setop_rel = generate_recursion_path(topop, root,
147 leftmostQuery->targetList,
148 &top_tlist);
149 }
150 else
151 {
152 bool trivial_tlist;
153
154 /*
155 * Recurse on setOperations tree to generate paths for set ops. The
156 * final output paths should have just the column types shown as the
157 * output from the top-level node.
158 */
159 setop_rel = recurse_set_operations((Node *) topop, root,
160 NULL, /* no parent */
161 topop->colTypes, topop->colCollations,
162 leftmostQuery->targetList,
163 &top_tlist,
164 &trivial_tlist);
165 }
166
167 /* Must return the built tlist into root->processed_tlist. */
168 root->processed_tlist = top_tlist;
169
170 return setop_rel;
171}
static RelOptInfo * recurse_set_operations(Node *setOp, PlannerInfo *root, SetOperationStmt *parentOp, List *colTypes, List *colCollations, List *refnames_tlist, List **pTargetList, bool *istrivial_tlist)
Definition: prepunion.c:209
static RelOptInfo * generate_recursion_path(SetOperationStmt *setOp, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:357
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:94
List * targetList
Definition: parsenodes.h:193
Query * subquery
Definition: parsenodes.h:1118

References Assert(), castNode, generate_recursion_path(), IsA, SetOperationStmt::larg, NIL, parse(), recurse_set_operations(), root, setup_simple_rel_arrays(), RangeTblEntry::subquery, and Query::targetList.

Referenced by grouping_planner().

◆ preprocess_aggrefs()

void preprocess_aggrefs ( PlannerInfo root,
Node clause 
)

Definition at line 110 of file prepagg.c.

111{
112 (void) preprocess_aggrefs_walker(clause, root);
113}
static bool preprocess_aggrefs_walker(Node *node, PlannerInfo *root)
Definition: prepagg.c:344

References preprocess_aggrefs_walker(), and root.

Referenced by grouping_planner().

◆ preprocess_function_rtes()

void preprocess_function_rtes ( PlannerInfo root)

Definition at line 914 of file prepjointree.c.

915{
916 ListCell *rt;
917
918 foreach(rt, root->parse->rtable)
919 {
920 RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
921
922 if (rte->rtekind == RTE_FUNCTION)
923 {
924 Query *funcquery;
925
926 /* Apply const-simplification */
927 rte->functions = (List *)
929
930 /* Check safety of expansion, and expand if possible */
931 funcquery = inline_set_returning_function(root, rte);
932 if (funcquery)
933 {
934 /* Successful expansion, convert the RTE to a subquery */
935 rte->rtekind = RTE_SUBQUERY;
936 rte->subquery = funcquery;
937 rte->security_barrier = false;
938
939 /*
940 * Clear fields that should not be set in a subquery RTE.
941 * However, we leave rte->functions filled in for the moment,
942 * in case makeWholeRowVar needs to consult it. We'll clear
943 * it in setrefs.c (see add_rte_to_flat_rtable) so that this
944 * abuse of the data structure doesn't escape the planner.
945 */
946 rte->funcordinality = false;
947 }
948 }
949 }
950}
Query * inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
Definition: clauses.c:5068
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2256
@ RTE_FUNCTION
Definition: parsenodes.h:1029
bool funcordinality
Definition: parsenodes.h:1193
List * functions
Definition: parsenodes.h:1191

References eval_const_expressions(), RangeTblEntry::funcordinality, RangeTblEntry::functions, inline_set_returning_function(), lfirst, root, RTE_FUNCTION, RTE_SUBQUERY, RangeTblEntry::rtekind, and RangeTblEntry::subquery.

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ preprocess_targetlist()

void preprocess_targetlist ( PlannerInfo root)

Definition at line 63 of file preptlist.c.

64{
65 Query *parse = root->parse;
66 int result_relation = parse->resultRelation;
67 List *range_table = parse->rtable;
68 CmdType command_type = parse->commandType;
69 RangeTblEntry *target_rte = NULL;
70 Relation target_relation = NULL;
71 List *tlist;
72 ListCell *lc;
73
74 /*
75 * If there is a result relation, open it so we can look for missing
76 * columns and so on. We assume that previous code already acquired at
77 * least AccessShareLock on the relation, so we need no lock here.
78 */
79 if (result_relation)
80 {
81 target_rte = rt_fetch(result_relation, range_table);
82
83 /*
84 * Sanity check: it'd better be a real relation not, say, a subquery.
85 * Else parser or rewriter messed up.
86 */
87 if (target_rte->rtekind != RTE_RELATION)
88 elog(ERROR, "result relation must be a regular relation");
89
90 target_relation = table_open(target_rte->relid, NoLock);
91 }
92 else
93 Assert(command_type == CMD_SELECT);
94
95 /*
96 * In an INSERT, the executor expects the targetlist to match the exact
97 * order of the target table's attributes, including entries for
98 * attributes not mentioned in the source query.
99 *
100 * In an UPDATE, we don't rearrange the tlist order, but we need to make a
101 * separate list of the target attribute numbers, in tlist order, and then
102 * renumber the processed_tlist entries to be consecutive.
103 */
104 tlist = parse->targetList;
105 if (command_type == CMD_INSERT)
106 tlist = expand_insert_targetlist(root, tlist, target_relation);
107 else if (command_type == CMD_UPDATE)
108 root->update_colnos = extract_update_targetlist_colnos(tlist);
109
110 /*
111 * For non-inherited UPDATE/DELETE/MERGE, register any junk column(s)
112 * needed to allow the executor to identify the rows to be updated or
113 * deleted. In the inheritance case, we do nothing now, leaving this to
114 * be dealt with when expand_inherited_rtentry() makes the leaf target
115 * relations. (But there might not be any leaf target relations, in which
116 * case we must do this in distribute_row_identity_vars().)
117 */
118 if ((command_type == CMD_UPDATE || command_type == CMD_DELETE ||
119 command_type == CMD_MERGE) &&
120 !target_rte->inh)
121 {
122 /* row-identity logic expects to add stuff to processed_tlist */
123 root->processed_tlist = tlist;
124 add_row_identity_columns(root, result_relation,
125 target_rte, target_relation);
126 tlist = root->processed_tlist;
127 }
128
129 /*
130 * For MERGE we also need to handle the target list for each INSERT and
131 * UPDATE action separately. In addition, we examine the qual of each
132 * action and add any Vars there (other than those of the target rel) to
133 * the subplan targetlist.
134 */
135 if (command_type == CMD_MERGE)
136 {
137 ListCell *l;
138 List *vars;
139
140 /*
141 * For MERGE, handle targetlist of each MergeAction separately. Give
142 * the same treatment to MergeAction->targetList as we would have
143 * given to a regular INSERT. For UPDATE, collect the column numbers
144 * being modified.
145 */
146 foreach(l, parse->mergeActionList)
147 {
149 ListCell *l2;
150
151 if (action->commandType == CMD_INSERT)
153 action->targetList,
154 target_relation);
155 else if (action->commandType == CMD_UPDATE)
156 action->updateColnos =
158
159 /*
160 * Add resjunk entries for any Vars and PlaceHolderVars used in
161 * each action's targetlist and WHEN condition that belong to
162 * relations other than the target. We don't expect to see any
163 * aggregates or window functions here.
164 */
166 list_concat_copy((List *) action->qual,
167 action->targetList),
169 foreach(l2, vars)
170 {
171 Var *var = (Var *) lfirst(l2);
172 TargetEntry *tle;
173
174 if (IsA(var, Var) && var->varno == result_relation)
175 continue; /* don't need it */
176
177 if (tlist_member((Expr *) var, tlist))
178 continue; /* already got it */
179
180 tle = makeTargetEntry((Expr *) var,
181 list_length(tlist) + 1,
182 NULL, true);
183 tlist = lappend(tlist, tle);
184 }
186 }
187
188 /*
189 * Add resjunk entries for any Vars and PlaceHolderVars used in the
190 * join condition that belong to relations other than the target. We
191 * don't expect to see any aggregates or window functions here.
192 */
193 vars = pull_var_clause(parse->mergeJoinCondition,
195 foreach(l, vars)
196 {
197 Var *var = (Var *) lfirst(l);
198 TargetEntry *tle;
199
200 if (IsA(var, Var) && var->varno == result_relation)
201 continue; /* don't need it */
202
203 if (tlist_member((Expr *) var, tlist))
204 continue; /* already got it */
205
206 tle = makeTargetEntry((Expr *) var,
207 list_length(tlist) + 1,
208 NULL, true);
209 tlist = lappend(tlist, tle);
210 }
211 }
212
213 /*
214 * Add necessary junk columns for rowmarked rels. These values are needed
215 * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
216 * rechecking. See comments for PlanRowMark in plannodes.h. If you
217 * change this stanza, see also expand_inherited_rtentry(), which has to
218 * be able to add on junk columns equivalent to these.
219 *
220 * (Someday it might be useful to fold these resjunk columns into the
221 * row-identity-column management used for UPDATE/DELETE. Today is not
222 * that day, however. One notable issue is that it seems important that
223 * the whole-row Vars made here use the real table rowtype, not RECORD, so
224 * that conversion to/from child relations' rowtypes will happen. Also,
225 * since these entries don't potentially bloat with more and more child
226 * relations, there's not really much need for column sharing.)
227 */
228 foreach(lc, root->rowMarks)
229 {
230 PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
231 Var *var;
232 char resname[32];
233 TargetEntry *tle;
234
235 /* child rels use the same junk attrs as their parents */
236 if (rc->rti != rc->prti)
237 continue;
238
239 if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
240 {
241 /* Need to fetch TID */
242 var = makeVar(rc->rti,
244 TIDOID,
245 -1,
247 0);
248 snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
249 tle = makeTargetEntry((Expr *) var,
250 list_length(tlist) + 1,
251 pstrdup(resname),
252 true);
253 tlist = lappend(tlist, tle);
254 }
255 if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
256 {
257 /* Need the whole row as a junk var */
258 var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
259 rc->rti,
260 0,
261 false);
262 snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
263 tle = makeTargetEntry((Expr *) var,
264 list_length(tlist) + 1,
265 pstrdup(resname),
266 true);
267 tlist = lappend(tlist, tle);
268 }
269
270 /* If parent of inheritance tree, always fetch the tableoid too. */
271 if (rc->isParent)
272 {
273 var = makeVar(rc->rti,
275 OIDOID,
276 -1,
278 0);
279 snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
280 tle = makeTargetEntry((Expr *) var,
281 list_length(tlist) + 1,
282 pstrdup(resname),
283 true);
284 tlist = lappend(tlist, tle);
285 }
286 }
287
288 /*
289 * If the query has a RETURNING list, add resjunk entries for any Vars
290 * used in RETURNING that belong to other relations. We need to do this
291 * to make these Vars available for the RETURNING calculation. Vars that
292 * belong to the result rel don't need to be added, because they will be
293 * made to refer to the actual heap tuple.
294 */
295 if (parse->returningList && list_length(parse->rtable) > 1)
296 {
297 List *vars;
298 ListCell *l;
299
300 vars = pull_var_clause((Node *) parse->returningList,
304 foreach(l, vars)
305 {
306 Var *var = (Var *) lfirst(l);
307 TargetEntry *tle;
308
309 if (IsA(var, Var) &&
310 var->varno == result_relation)
311 continue; /* don't need it */
312
313 if (tlist_member((Expr *) var, tlist))
314 continue; /* already got it */
315
316 tle = makeTargetEntry((Expr *) var,
317 list_length(tlist) + 1,
318 NULL,
319 true);
320
321 tlist = lappend(tlist, tle);
322 }
324 }
325
326 root->processed_tlist = tlist;
327
328 if (target_relation)
329 table_close(target_relation, NoLock);
330}
void add_row_identity_columns(PlannerInfo *root, Index rtindex, RangeTblEntry *target_rte, Relation target_relation)
Definition: appendinfo.c:904
List * list_concat_copy(const List *list1, const List *list2)
Definition: list.c:598
void list_free(List *list)
Definition: list.c:1546
Var * makeWholeRowVar(RangeTblEntry *rte, int varno, Index varlevelsup, bool allowScalar)
Definition: makefuncs.c:137
char * pstrdup(const char *in)
Definition: mcxt.c:2322
CmdType
Definition: nodes.h:269
@ CMD_MERGE
Definition: nodes.h:275
@ CMD_INSERT
Definition: nodes.h:273
@ CMD_DELETE
Definition: nodes.h:274
@ CMD_UPDATE
Definition: nodes.h:272
@ CMD_SELECT
Definition: nodes.h:271
#define PVC_RECURSE_AGGREGATES
Definition: optimizer.h:193
#define PVC_RECURSE_WINDOWFUNCS
Definition: optimizer.h:195
#define PVC_INCLUDE_PLACEHOLDERS
Definition: optimizer.h:196
@ ROW_MARK_COPY
Definition: plannodes.h:1491
#define snprintf
Definition: port.h:239
#define InvalidOid
Definition: postgres_ext.h:35
List * extract_update_targetlist_colnos(List *tlist)
Definition: preptlist.c:347
static List * expand_insert_targetlist(PlannerInfo *root, List *tlist, Relation rel)
Definition: preptlist.c:381
Index prti
Definition: plannodes.h:1542
bool isParent
Definition: plannodes.h:1554
Index rowmarkId
Definition: plannodes.h:1544
int allMarkTypes
Definition: plannodes.h:1548
int varno
Definition: primnodes.h:269
Definition: regcomp.c:282
#define TableOidAttributeNumber
Definition: sysattr.h:26
#define SelfItemPointerAttributeNumber
Definition: sysattr.h:21
TargetEntry * tlist_member(Expr *node, List *targetlist)
Definition: tlist.c:79
List * pull_var_clause(Node *node, int flags)
Definition: var.c:653

References generate_unaccent_rules::action, add_row_identity_columns(), PlanRowMark::allMarkTypes, Assert(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_SELECT, CMD_UPDATE, elog, ERROR, expand_insert_targetlist(), extract_update_targetlist_colnos(), RangeTblEntry::inh, InvalidOid, IsA, PlanRowMark::isParent, lappend(), lfirst, list_concat_copy(), list_free(), list_length(), makeTargetEntry(), makeVar(), makeWholeRowVar(), NoLock, parse(), PlanRowMark::prti, pstrdup(), pull_var_clause(), PVC_INCLUDE_PLACEHOLDERS, PVC_RECURSE_AGGREGATES, PVC_RECURSE_WINDOWFUNCS, root, ROW_MARK_COPY, PlanRowMark::rowmarkId, rt_fetch, RTE_RELATION, RangeTblEntry::rtekind, PlanRowMark::rti, SelfItemPointerAttributeNumber, snprintf, table_close(), table_open(), TableOidAttributeNumber, tlist_member(), and Var::varno.

Referenced by grouping_planner().

◆ pull_up_sublinks()

void pull_up_sublinks ( PlannerInfo root)

Definition at line 468 of file prepjointree.c.

469{
470 Node *jtnode;
471 Relids relids;
472
473 /* Begin recursion through the jointree */
475 (Node *) root->parse->jointree,
476 &relids);
477
478 /*
479 * root->parse->jointree must always be a FromExpr, so insert a dummy one
480 * if we got a bare RangeTblRef or JoinExpr out of the recursion.
481 */
482 if (IsA(jtnode, FromExpr))
483 root->parse->jointree = (FromExpr *) jtnode;
484 else
485 root->parse->jointree = makeFromExpr(list_make1(jtnode), NULL);
486}
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:336
static Node * pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, Relids *relids)
Definition: prepjointree.c:495

References IsA, list_make1, makeFromExpr(), pull_up_sublinks_jointree_recurse(), and root.

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ pull_up_subqueries()

void pull_up_subqueries ( PlannerInfo root)

Definition at line 1083 of file prepjointree.c.

1084{
1085 /* Top level of jointree must always be a FromExpr */
1086 Assert(IsA(root->parse->jointree, FromExpr));
1087 /* Recursion starts with no containing join nor appendrel */
1088 root->parse->jointree = (FromExpr *)
1089 pull_up_subqueries_recurse(root, (Node *) root->parse->jointree,
1090 NULL, NULL);
1091 /* We should still have a FromExpr */
1092 Assert(IsA(root->parse->jointree, FromExpr));
1093}
static Node * pull_up_subqueries_recurse(PlannerInfo *root, Node *jtnode, JoinExpr *lowest_outer_join, AppendRelInfo *containing_appendrel)

References Assert(), IsA, pull_up_subqueries_recurse(), and root.

Referenced by pull_up_simple_subquery(), and subquery_planner().

◆ reduce_outer_joins()

void reduce_outer_joins ( PlannerInfo root)

Definition at line 3102 of file prepjointree.c.

3103{
3106 ListCell *lc;
3107
3108 /*
3109 * To avoid doing strictness checks on more quals than necessary, we want
3110 * to stop descending the jointree as soon as there are no outer joins
3111 * below our current point. This consideration forces a two-pass process.
3112 * The first pass gathers information about which base rels appear below
3113 * each side of each join clause, and about whether there are outer
3114 * join(s) below each side of each join clause. The second pass examines
3115 * qual clauses and changes join types as it descends the tree.
3116 */
3117 state1 = reduce_outer_joins_pass1((Node *) root->parse->jointree);
3118
3119 /* planner.c shouldn't have called me if no outer joins */
3120 if (state1 == NULL || !state1->contains_outer)
3121 elog(ERROR, "so where are the outer joins?");
3122
3123 state2.inner_reduced = NULL;
3124 state2.partial_reduced = NIL;
3125
3126 reduce_outer_joins_pass2((Node *) root->parse->jointree,
3127 state1, &state2,
3128 root, NULL, NIL);
3129
3130 /*
3131 * If we successfully reduced the strength of any outer joins, we must
3132 * remove references to those joins as nulling rels. This is handled as
3133 * an additional pass, for simplicity and because we can handle all
3134 * fully-reduced joins in a single pass over the parse tree.
3135 */
3136 if (!bms_is_empty(state2.inner_reduced))
3137 {
3138 root->parse = (Query *)
3139 remove_nulling_relids((Node *) root->parse,
3140 state2.inner_reduced,
3141 NULL);
3142 /* There could be references in the append_rel_list, too */
3143 root->append_rel_list = (List *)
3144 remove_nulling_relids((Node *) root->append_rel_list,
3145 state2.inner_reduced,
3146 NULL);
3147 }
3148
3149 /*
3150 * Partially-reduced full joins have to be done one at a time, since
3151 * they'll each need a different setting of except_relids.
3152 */
3153 foreach(lc, state2.partial_reduced)
3154 {
3156 Relids full_join_relids = bms_make_singleton(statep->full_join_rti);
3157
3158 root->parse = (Query *)
3159 remove_nulling_relids((Node *) root->parse,
3160 full_join_relids,
3161 statep->unreduced_side);
3162 root->append_rel_list = (List *)
3163 remove_nulling_relids((Node *) root->append_rel_list,
3164 full_join_relids,
3165 statep->unreduced_side);
3166 }
3167}
#define bms_is_empty(a)
Definition: bitmapset.h:118
static void reduce_outer_joins_pass2(Node *jtnode, reduce_outer_joins_pass1_state *state1, reduce_outer_joins_pass2_state *state2, PlannerInfo *root, Relids nonnullable_rels, List *forced_null_vars)
static reduce_outer_joins_pass1_state * reduce_outer_joins_pass1(Node *jtnode)
Node * remove_nulling_relids(Node *node, const Bitmapset *removable_relids, const Bitmapset *except_relids)

References bms_is_empty, bms_make_singleton(), reduce_outer_joins_pass1_state::contains_outer, elog, ERROR, reduce_outer_joins_partial_state::full_join_rti, reduce_outer_joins_pass2_state::inner_reduced, lfirst, NIL, reduce_outer_joins_pass2_state::partial_reduced, reduce_outer_joins_pass1(), reduce_outer_joins_pass2(), remove_nulling_relids(), root, and reduce_outer_joins_partial_state::unreduced_side.

Referenced by subquery_planner().

◆ remove_useless_result_rtes()

void remove_useless_result_rtes ( PlannerInfo root)

Definition at line 3596 of file prepjointree.c.

3597{
3598 Relids dropped_outer_joins = NULL;
3599 ListCell *cell;
3600
3601 /* Top level of jointree must always be a FromExpr */
3602 Assert(IsA(root->parse->jointree, FromExpr));
3603 /* Recurse ... */
3604 root->parse->jointree = (FromExpr *)
3606 (Node *) root->parse->jointree,
3607 NULL,
3608 &dropped_outer_joins);
3609 /* We should still have a FromExpr */
3610 Assert(IsA(root->parse->jointree, FromExpr));
3611
3612 /*
3613 * If we removed any outer-join nodes from the jointree, run around and
3614 * remove references to those joins as nulling rels. (There could be such
3615 * references in PHVs that we pulled up out of the original subquery that
3616 * the RESULT rel replaced. This is kosher on the grounds that we now
3617 * know that such an outer join wouldn't really have nulled anything.) We
3618 * don't do this during the main recursion, for simplicity and because we
3619 * can handle all such joins in a single pass over the parse tree.
3620 */
3621 if (!bms_is_empty(dropped_outer_joins))
3622 {
3623 root->parse = (Query *)
3624 remove_nulling_relids((Node *) root->parse,
3625 dropped_outer_joins,
3626 NULL);
3627 /* There could be references in the append_rel_list, too */
3628 root->append_rel_list = (List *)
3629 remove_nulling_relids((Node *) root->append_rel_list,
3630 dropped_outer_joins,
3631 NULL);
3632 }
3633
3634 /*
3635 * Remove any PlanRowMark referencing an RTE_RESULT RTE. We obviously
3636 * must do that for any RTE_RESULT that we just removed. But one for a
3637 * RTE that we did not remove can be dropped anyway: since the RTE has
3638 * only one possible output row, there is no need for EPQ to mark and
3639 * restore that row.
3640 *
3641 * It's necessary, not optional, to remove the PlanRowMark for a surviving
3642 * RTE_RESULT RTE; otherwise we'll generate a whole-row Var for the
3643 * RTE_RESULT, which the executor has no support for.
3644 */
3645 foreach(cell, root->rowMarks)
3646 {
3647 PlanRowMark *rc = (PlanRowMark *) lfirst(cell);
3648
3649 if (rt_fetch(rc->rti, root->parse->rtable)->rtekind == RTE_RESULT)
3650 root->rowMarks = foreach_delete_current(root->rowMarks, cell);
3651 }
3652}
@ RTE_RESULT
Definition: parsenodes.h:1034
#define foreach_delete_current(lst, var_or_cell)
Definition: pg_list.h:391
static Node * remove_useless_results_recurse(PlannerInfo *root, Node *jtnode, Node **parent_quals, Relids *dropped_outer_joins)

References Assert(), bms_is_empty, foreach_delete_current, IsA, lfirst, remove_nulling_relids(), remove_useless_results_recurse(), root, rt_fetch, RTE_RESULT, and PlanRowMark::rti.

Referenced by subquery_planner().

◆ replace_empty_jointree()

void replace_empty_jointree ( Query parse)

Definition at line 410 of file prepjointree.c.

411{
412 RangeTblEntry *rte;
413 Index rti;
414 RangeTblRef *rtr;
415
416 /* Nothing to do if jointree is already nonempty */
417 if (parse->jointree->fromlist != NIL)
418 return;
419
420 /* We mustn't change it in the top level of a setop tree, either */
421 if (parse->setOperations)
422 return;
423
424 /* Create suitable RTE */
425 rte = makeNode(RangeTblEntry);
426 rte->rtekind = RTE_RESULT;
427 rte->eref = makeAlias("*RESULT*", NIL);
428
429 /* Add it to rangetable */
430 parse->rtable = lappend(parse->rtable, rte);
431 rti = list_length(parse->rtable);
432
433 /* And jam a reference into the jointree */
434 rtr = makeNode(RangeTblRef);
435 rtr->rtindex = rti;
436 parse->jointree->fromlist = list_make1(rtr);
437}
unsigned int Index
Definition: c.h:585
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:438

References lappend(), list_length(), list_make1, makeAlias(), makeNode, NIL, parse(), RTE_RESULT, RangeTblEntry::rtekind, and RangeTblRef::rtindex.

Referenced by convert_EXISTS_sublink_to_join(), pull_up_simple_subquery(), and subquery_planner().

◆ transform_MERGE_to_join()

void transform_MERGE_to_join ( Query parse)

Definition at line 183 of file prepjointree.c.

184{
185 RangeTblEntry *joinrte;
186 JoinExpr *joinexpr;
187 bool have_action[NUM_MERGE_MATCH_KINDS];
188 JoinType jointype;
189 int joinrti;
190 List *vars;
191 RangeTblRef *rtr;
192 FromExpr *target;
193 Node *source;
194 int sourcerti;
195
196 if (parse->commandType != CMD_MERGE)
197 return;
198
199 /* XXX probably bogus */
200 vars = NIL;
201
202 /*
203 * Work out what kind of join is required. If there any WHEN NOT MATCHED
204 * BY SOURCE/TARGET actions, an outer join is required so that we process
205 * all unmatched tuples from the source and/or target relations.
206 * Otherwise, we can use an inner join.
207 */
208 have_action[MERGE_WHEN_MATCHED] = false;
209 have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE] = false;
210 have_action[MERGE_WHEN_NOT_MATCHED_BY_TARGET] = false;
211
212 foreach_node(MergeAction, action, parse->mergeActionList)
213 {
214 if (action->commandType != CMD_NOTHING)
215 have_action[action->matchKind] = true;
216 }
217
218 if (have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE] &&
220 jointype = JOIN_FULL;
221 else if (have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE])
222 jointype = JOIN_LEFT;
223 else if (have_action[MERGE_WHEN_NOT_MATCHED_BY_TARGET])
224 jointype = JOIN_RIGHT;
225 else
226 jointype = JOIN_INNER;
227
228 /* Manufacture a join RTE to use. */
229 joinrte = makeNode(RangeTblEntry);
230 joinrte->rtekind = RTE_JOIN;
231 joinrte->jointype = jointype;
232 joinrte->joinmergedcols = 0;
233 joinrte->joinaliasvars = vars;
234 joinrte->joinleftcols = NIL; /* MERGE does not allow JOIN USING */
235 joinrte->joinrightcols = NIL; /* ditto */
236 joinrte->join_using_alias = NULL;
237
238 joinrte->alias = NULL;
239 joinrte->eref = makeAlias("*MERGE*", NIL);
240 joinrte->lateral = false;
241 joinrte->inh = false;
242 joinrte->inFromCl = true;
243
244 /*
245 * Add completed RTE to pstate's range table list, so that we know its
246 * index.
247 */
248 parse->rtable = lappend(parse->rtable, joinrte);
249 joinrti = list_length(parse->rtable);
250
251 /*
252 * Create a JOIN between the target and the source relation.
253 *
254 * Here the target is identified by parse->mergeTargetRelation. For a
255 * regular table, this will equal parse->resultRelation, but for a
256 * trigger-updatable view, it will be the expanded view subquery that we
257 * need to pull data from.
258 *
259 * The source relation is in parse->jointree->fromlist, but any quals in
260 * parse->jointree->quals are restrictions on the target relation (if the
261 * target relation is an auto-updatable view).
262 */
263 /* target rel, with any quals */
264 rtr = makeNode(RangeTblRef);
265 rtr->rtindex = parse->mergeTargetRelation;
266 target = makeFromExpr(list_make1(rtr), parse->jointree->quals);
267
268 /* source rel (expect exactly one -- see transformMergeStmt()) */
269 Assert(list_length(parse->jointree->fromlist) == 1);
270 source = linitial(parse->jointree->fromlist);
271
272 /*
273 * index of source rel (expect either a RangeTblRef or a JoinExpr -- see
274 * transformFromClauseItem()).
275 */
276 if (IsA(source, RangeTblRef))
277 sourcerti = ((RangeTblRef *) source)->rtindex;
278 else if (IsA(source, JoinExpr))
279 sourcerti = ((JoinExpr *) source)->rtindex;
280 else
281 {
282 elog(ERROR, "unrecognized source node type: %d",
283 (int) nodeTag(source));
284 sourcerti = 0; /* keep compiler quiet */
285 }
286
287 /* Join the source and target */
288 joinexpr = makeNode(JoinExpr);
289 joinexpr->jointype = jointype;
290 joinexpr->isNatural = false;
291 joinexpr->larg = (Node *) target;
292 joinexpr->rarg = source;
293 joinexpr->usingClause = NIL;
294 joinexpr->join_using_alias = NULL;
295 joinexpr->quals = parse->mergeJoinCondition;
296 joinexpr->alias = NULL;
297 joinexpr->rtindex = joinrti;
298
299 /* Make the new join be the sole entry in the query's jointree */
300 parse->jointree->fromlist = list_make1(joinexpr);
301 parse->jointree->quals = NULL;
302
303 /*
304 * If necessary, mark parse->targetlist entries that refer to the target
305 * as nullable by the join. Normally the targetlist will be empty for a
306 * MERGE, but if the target is a trigger-updatable view, it will contain a
307 * whole-row Var referring to the expanded view query.
308 */
309 if (parse->targetList != NIL &&
310 (jointype == JOIN_RIGHT || jointype == JOIN_FULL))
311 parse->targetList = (List *)
312 add_nulling_relids((Node *) parse->targetList,
313 bms_make_singleton(parse->mergeTargetRelation),
314 bms_make_singleton(joinrti));
315
316 /*
317 * If the source relation is on the outer side of the join, mark any
318 * source relation Vars in the join condition, actions, and RETURNING list
319 * as nullable by the join. These Vars will be added to the targetlist by
320 * preprocess_targetlist(), so it's important to mark them correctly here.
321 *
322 * It might seem that this is not necessary for Vars in the join
323 * condition, since it is inside the join, but it is also needed above the
324 * join (in the ModifyTable node) to distinguish between the MATCHED and
325 * NOT MATCHED BY SOURCE cases -- see ExecMergeMatched(). Note that this
326 * creates a modified copy of the join condition, for use above the join,
327 * without modifying the original join condition, inside the join.
328 */
329 if (jointype == JOIN_LEFT || jointype == JOIN_FULL)
330 {
331 parse->mergeJoinCondition =
332 add_nulling_relids(parse->mergeJoinCondition,
333 bms_make_singleton(sourcerti),
334 bms_make_singleton(joinrti));
335
336 foreach_node(MergeAction, action, parse->mergeActionList)
337 {
338 action->qual =
340 bms_make_singleton(sourcerti),
341 bms_make_singleton(joinrti));
342
343 action->targetList = (List *)
344 add_nulling_relids((Node *) action->targetList,
345 bms_make_singleton(sourcerti),
346 bms_make_singleton(joinrti));
347 }
348
349 parse->returningList = (List *)
350 add_nulling_relids((Node *) parse->returningList,
351 bms_make_singleton(sourcerti),
352 bms_make_singleton(joinrti));
353 }
354
355 /*
356 * If there are any WHEN NOT MATCHED BY SOURCE actions, the executor will
357 * use the join condition to distinguish between MATCHED and NOT MATCHED
358 * BY SOURCE cases. Otherwise, it's no longer needed, and we set it to
359 * NULL, saving cycles during planning and execution.
360 *
361 * We need to be careful though: the executor evaluates this condition
362 * using the output of the join subplan node, which nulls the output from
363 * the source relation when the join condition doesn't match. That risks
364 * producing incorrect results when rechecking using a "non-strict" join
365 * condition, such as "src.col IS NOT DISTINCT FROM tgt.col". To guard
366 * against that, we add an additional "src IS NOT NULL" check to the join
367 * condition, so that it does the right thing when performing a recheck
368 * based on the output of the join subplan.
369 */
370 if (have_action[MERGE_WHEN_NOT_MATCHED_BY_SOURCE])
371 {
372 Var *var;
373 NullTest *ntest;
374
375 /* source wholerow Var (nullable by the new join) */
376 var = makeWholeRowVar(rt_fetch(sourcerti, parse->rtable),
377 sourcerti, 0, false);
378 var->varnullingrels = bms_make_singleton(joinrti);
379
380 /* "src IS NOT NULL" check */
381 ntest = makeNode(NullTest);
382 ntest->arg = (Expr *) var;
383 ntest->nulltesttype = IS_NOT_NULL;
384 ntest->argisrow = false;
385 ntest->location = -1;
386
387 /* combine it with the original join condition */
388 parse->mergeJoinCondition =
389 (Node *) make_and_qual((Node *) ntest, parse->mergeJoinCondition);
390 }
391 else
392 parse->mergeJoinCondition = NULL; /* join condition not needed */
393}
Node * make_and_qual(Node *qual1, Node *qual2)
Definition: makefuncs.c:780
@ CMD_NOTHING
Definition: nodes.h:278
JoinType
Definition: nodes.h:294
@ JOIN_FULL
Definition: nodes.h:301
@ JOIN_RIGHT
Definition: nodes.h:302
@ JOIN_LEFT
Definition: nodes.h:300
@ RTE_JOIN
Definition: parsenodes.h:1028
#define linitial(l)
Definition: pg_list.h:178
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
static rewind_source * source
Definition: pg_rewind.c:89
#define NUM_MERGE_MATCH_KINDS
Definition: primnodes.h:2006
@ IS_NOT_NULL
Definition: primnodes.h:1957
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
Definition: primnodes.h:2003
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition: primnodes.h:2002
@ MERGE_WHEN_MATCHED
Definition: primnodes.h:2001
Node * add_nulling_relids(Node *node, const Bitmapset *target_relids, const Bitmapset *added_relids)
Node * quals
Definition: primnodes.h:2318
JoinType jointype
Definition: primnodes.h:2309
int rtindex
Definition: primnodes.h:2322
Node * larg
Definition: primnodes.h:2311
bool isNatural
Definition: primnodes.h:2310
Node * rarg
Definition: primnodes.h:2312
NullTestType nulltesttype
Definition: primnodes.h:1964
ParseLoc location
Definition: primnodes.h:1967
Expr * arg
Definition: primnodes.h:1963
JoinType jointype
Definition: parsenodes.h:1165

References generate_unaccent_rules::action, add_nulling_relids(), NullTest::arg, Assert(), bms_make_singleton(), CMD_MERGE, CMD_NOTHING, elog, ERROR, foreach_node, RangeTblEntry::inh, IS_NOT_NULL, IsA, JoinExpr::isNatural, JOIN_FULL, JOIN_INNER, JOIN_LEFT, JOIN_RIGHT, RangeTblEntry::jointype, JoinExpr::jointype, lappend(), JoinExpr::larg, linitial, list_length(), list_make1, NullTest::location, make_and_qual(), makeAlias(), makeFromExpr(), makeNode, makeWholeRowVar(), MERGE_WHEN_MATCHED, MERGE_WHEN_NOT_MATCHED_BY_SOURCE, MERGE_WHEN_NOT_MATCHED_BY_TARGET, NIL, nodeTag, NullTest::nulltesttype, NUM_MERGE_MATCH_KINDS, parse(), JoinExpr::quals, JoinExpr::rarg, rt_fetch, RTE_JOIN, RangeTblEntry::rtekind, RangeTblRef::rtindex, JoinExpr::rtindex, and source.

Referenced by subquery_planner().