aboutsummaryrefslogtreecommitdiff
path: root/src/include/nodes/pathnodes.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/include/nodes/pathnodes.h')
-rw-r--r--src/include/nodes/pathnodes.h216
1 files changed, 164 insertions, 52 deletions
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 2d1d8f4bcdf..630a0440895 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -249,14 +249,26 @@ struct PlannerInfo
struct AppendRelInfo **append_rel_array pg_node_attr(read_write_ignore);
/*
- * all_baserels is a Relids set of all base relids (but not "other"
- * relids) in the query; that is, the Relids identifier of the final join
- * we need to form. This is computed in make_one_rel, just before we
- * start making Paths.
+ * all_baserels is a Relids set of all base relids (but not joins or
+ * "other" rels) in the query. This is computed in deconstruct_jointree.
*/
Relids all_baserels;
/*
+ * outer_join_rels is a Relids set of all outer-join relids in the query.
+ * This is computed in deconstruct_jointree.
+ */
+ Relids outer_join_rels;
+
+ /*
+ * all_query_rels is a Relids set of all base relids and outer join relids
+ * (but not "other" relids) in the query. This is the Relids identifier
+ * of the final join we need to form. This is computed in
+ * deconstruct_jointree.
+ */
+ Relids all_query_rels;
+
+ /*
* nullable_baserels is a Relids set of base relids that are nullable by
* some outer join in the jointree; these are rels that are potentially
* nullable below the WHERE clause, SELECT targetlist, etc. This is
@@ -313,25 +325,28 @@ struct PlannerInfo
List *canon_pathkeys;
/*
- * list of RestrictInfos for mergejoinable outer join clauses
+ * list of OuterJoinClauseInfos for mergejoinable outer join clauses
* w/nonnullable var on left
*/
List *left_join_clauses;
/*
- * list of RestrictInfos for mergejoinable outer join clauses
+ * list of OuterJoinClauseInfos for mergejoinable outer join clauses
* w/nonnullable var on right
*/
List *right_join_clauses;
/*
- * list of RestrictInfos for mergejoinable full join clauses
+ * list of OuterJoinClauseInfos for mergejoinable full join clauses
*/
List *full_join_clauses;
/* list of SpecialJoinInfos */
List *join_info_list;
+ /* counter for assigning RestrictInfo serial numbers */
+ int last_rinfo_serial;
+
/*
* all_result_relids is empty for SELECT, otherwise it contains at least
* parse->resultRelation. For UPDATE/DELETE/MERGE across an inheritance
@@ -592,9 +607,10 @@ typedef struct PartitionSchemeData *PartitionScheme;
* or the output of a sub-SELECT or function that appears in the range table.
* In either case it is uniquely identified by an RT index. A "joinrel"
* is the joining of two or more base rels. A joinrel is identified by
- * the set of RT indexes for its component baserels. We create RelOptInfo
- * nodes for each baserel and joinrel, and store them in the PlannerInfo's
- * simple_rel_array and join_rel_list respectively.
+ * the set of RT indexes for its component baserels, along with RT indexes
+ * for any outer joins it has computed. We create RelOptInfo nodes for each
+ * baserel and joinrel, and store them in the PlannerInfo's simple_rel_array
+ * and join_rel_list respectively.
*
* Note that there is only one joinrel for any given set of component
* baserels, no matter what order we assemble them in; so an unordered
@@ -633,8 +649,10 @@ typedef struct PartitionSchemeData *PartitionScheme;
* Parts of this data structure are specific to various scan and join
* mechanisms. It didn't seem worth creating new node types for them.
*
- * relids - Set of base-relation identifiers; it is a base relation
- * if there is just one, a join relation if more than one
+ * relids - Set of relation identifiers (RT indexes). This is a base
+ * relation if there is just one, a join relation if more;
+ * in the join case, RT indexes of any outer joins formed
+ * at or below this join are included along with baserels
* rows - estimated number of tuples in the relation after restriction
* clauses have been applied (ie, output rows of a plan for it)
* consider_startup - true if there is any value in keeping plain paths for
@@ -846,7 +864,7 @@ typedef struct RelOptInfo
RelOptKind reloptkind;
/*
- * all relations included in this RelOptInfo; set of base relids
+ * all relations included in this RelOptInfo; set of base + OJ relids
* (rangetable indexes)
*/
Relids relids;
@@ -911,7 +929,7 @@ typedef struct RelOptInfo
int32 *attr_widths pg_node_attr(read_write_ignore);
/* LATERAL Vars and PHVs referenced by rel */
List *lateral_vars;
- /* rels that reference me laterally */
+ /* rels that reference this baserel laterally */
Relids lateral_referencers;
/* list of IndexOptInfo */
List *indexlist;
@@ -921,10 +939,7 @@ typedef struct RelOptInfo
BlockNumber pages;
Cardinality tuples;
double allvisfrac;
-
- /*
- * Indexes in PlannerInfo's eq_classes list of ECs that mention this rel
- */
+ /* indexes in PlannerInfo's eq_classes list of ECs that mention this rel */
Bitmapset *eclass_indexes;
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
@@ -1378,6 +1393,8 @@ typedef struct EquivalenceMember
bool em_is_const; /* expression is pseudoconstant? */
bool em_is_child; /* derived version for a child relation? */
Oid em_datatype; /* the "nominal type" used by the opfamily */
+ /* if em_is_child is true, this links to corresponding EM for top parent */
+ struct EquivalenceMember *em_parent pg_node_attr(read_write_ignore);
} EquivalenceMember;
/*
@@ -1484,7 +1501,13 @@ typedef struct PathTarget
* Note: ppi_clauses is only used in ParamPathInfos for base relation paths;
* in join cases it's NIL because the set of relevant clauses varies depending
* on how the join is formed. The relevant clauses will appear in each
- * parameterized join path's joinrestrictinfo list, instead.
+ * parameterized join path's joinrestrictinfo list, instead. ParamPathInfos
+ * for append relations don't bother with this, either.
+ *
+ * ppi_serials is the set of rinfo_serial numbers for quals that are enforced
+ * by this path. As with ppi_clauses, it's only maintained for baserels.
+ * (We could construct it on-the-fly from ppi_clauses, but it seems better
+ * to materialize a copy.)
*/
typedef struct ParamPathInfo
{
@@ -1495,6 +1518,7 @@ typedef struct ParamPathInfo
Relids ppi_req_outer; /* rels supplying parameters used by path */
Cardinality ppi_rows; /* estimated number of result tuples */
List *ppi_clauses; /* join clauses available from outer rels */
+ Bitmapset *ppi_serials; /* set of rinfo_serial for enforced quals */
} ParamPathInfo;
@@ -2319,17 +2343,17 @@ typedef struct LimitPath
* If a restriction clause references a single base relation, it will appear
* in the baserestrictinfo list of the RelOptInfo for that base rel.
*
- * If a restriction clause references more than one base rel, it will
+ * If a restriction clause references more than one base+OJ relation, it will
* appear in the joininfo list of every RelOptInfo that describes a strict
- * subset of the base rels mentioned in the clause. The joininfo lists are
+ * subset of the relations mentioned in the clause. The joininfo lists are
* used to drive join tree building by selecting plausible join candidates.
* The clause cannot actually be applied until we have built a join rel
- * containing all the base rels it references, however.
+ * containing all the relations it references, however.
*
- * When we construct a join rel that includes all the base rels referenced
+ * When we construct a join rel that includes all the relations referenced
* in a multi-relation restriction clause, we place that clause into the
* joinrestrictinfo lists of paths for the join rel, if neither left nor
- * right sub-path includes all base rels referenced in the clause. The clause
+ * right sub-path includes all relations referenced in the clause. The clause
* will be applied at that join level, and will not propagate any further up
* the join tree. (Note: the "predicate migration" code was once intended to
* push restriction clauses up and down the plan tree based on evaluation
@@ -2350,12 +2374,14 @@ typedef struct LimitPath
* or join to enforce that all members of each EquivalenceClass are in fact
* equal in all rows emitted by the scan or join.
*
- * When dealing with outer joins we have to be very careful about pushing qual
- * clauses up and down the tree. An outer join's own JOIN/ON conditions must
- * be evaluated exactly at that join node, unless they are "degenerate"
- * conditions that reference only Vars from the nullable side of the join.
- * Quals appearing in WHERE or in a JOIN above the outer join cannot be pushed
- * down below the outer join, if they reference any nullable Vars.
+ * The clause_relids field lists the base plus outer-join RT indexes that
+ * actually appear in the clause. required_relids lists the minimum set of
+ * relids needed to evaluate the clause; while this is often equal to
+ * clause_relids, it can be more. We will add relids to required_relids when
+ * we need to force an outer join ON clause to be evaluated exactly at the
+ * level of the outer join, which is true except when it is a "degenerate"
+ * condition that references only Vars from the nullable side of the join.
+ *
* RestrictInfo nodes contain a flag to indicate whether a qual has been
* pushed down to a lower level than its original syntactic placement in the
* join tree would suggest. If an outer join prevents us from pushing a qual
@@ -2440,6 +2466,12 @@ typedef struct LimitPath
* or merge or hash join clause, so it's of no interest to large parts of
* the planner.
*
+ * When we generate multiple versions of a clause so as to have versions
+ * that will work after commuting some left joins per outer join identity 3,
+ * we mark the one with the fewest nullingrels bits with has_clone = true,
+ * and the rest with is_clone = true. This allows proper filtering of
+ * these redundant clauses, so that we apply only one version of them.
+ *
* When join clauses are generated from EquivalenceClasses, there may be
* several equally valid ways to enforce join equivalence, of which we need
* apply only one. We mark clauses of this kind by setting parent_ec to
@@ -2474,16 +2506,23 @@ typedef struct RestrictInfo
/* see comment above */
bool pseudoconstant pg_node_attr(equal_ignore);
+ /* see comment above */
+ bool has_clone;
+ bool is_clone;
+
/* true if known to contain no leaked Vars */
bool leakproof pg_node_attr(equal_ignore);
- /* to indicate if clause contains any volatile functions. */
+ /* indicates if clause contains any volatile functions */
VolatileFunctionStatus has_volatile pg_node_attr(equal_ignore);
/* see comment above */
Index security_level;
- /* The set of relids (varnos) actually referenced in the clause: */
+ /* number of base rels in clause_relids */
+ int num_base_rels pg_node_attr(equal_ignore);
+
+ /* The relids (varnos+varnullingrels) actually referenced in the clause: */
Relids clause_relids pg_node_attr(equal_ignore);
/* The set of relids required to evaluate the clause: */
@@ -2508,6 +2547,25 @@ typedef struct RestrictInfo
*/
Expr *orclause pg_node_attr(equal_ignore);
+ /*----------
+ * Serial number of this RestrictInfo. This is unique within the current
+ * PlannerInfo context, with a few critical exceptions:
+ * 1. When we generate multiple clones of the same qual condition to
+ * cope with outer join identity 3, all the clones get the same serial
+ * number. This reflects that we only want to apply one of them in any
+ * given plan.
+ * 2. If we manufacture a commuted version of a qual to use as an index
+ * condition, it copies the original's rinfo_serial, since it is in
+ * practice the same condition.
+ * 3. RestrictInfos made for a child relation copy their parent's
+ * rinfo_serial. Likewise, when an EquivalenceClass makes a derived
+ * equality clause for a child relation, it copies the rinfo_serial of
+ * the matching equality clause for the parent. This allows detection
+ * of redundant pushed-down equality clauses.
+ *----------
+ */
+ int rinfo_serial;
+
/*
* Generating EquivalenceClass. This field is NULL unless clause is
* potentially redundant.
@@ -2624,10 +2682,15 @@ typedef struct MergeScanSelCache
* of a plan tree. This is used during planning to represent the contained
* expression. At the end of the planning process it is replaced by either
* the contained expression or a Var referring to a lower-level evaluation of
- * the contained expression. Typically the evaluation occurs below an outer
+ * the contained expression. Generally the evaluation occurs below an outer
* join, and Var references above the outer join might thereby yield NULL
* instead of the expression value.
*
+ * phrels and phlevelsup correspond to the varno/varlevelsup fields of a
+ * plain Var, except that phrels has to be a relid set since the evaluation
+ * level of a PlaceHolderVar might be a join rather than a base relation.
+ * Likewise, phnullingrels corresponds to varnullingrels.
+ *
* Although the planner treats this as an expression node type, it is not
* recognized by the parser or executor, so we declare it here rather than
* in primnodes.h.
@@ -2640,8 +2703,10 @@ typedef struct MergeScanSelCache
* PHV. Another way in which it can happen is that initplan sublinks
* could get replaced by differently-numbered Params when sublink folding
* is done. (The end result of such a situation would be some
- * unreferenced initplans, which is annoying but not really a problem.) On
- * the same reasoning, there is no need to examine phrels.
+ * unreferenced initplans, which is annoying but not really a problem.)
+ * On the same reasoning, there is no need to examine phrels. But we do
+ * need to compare phnullingrels, as that represents effects that are
+ * external to the original value of the PHV.
*/
typedef struct PlaceHolderVar
@@ -2651,9 +2716,12 @@ typedef struct PlaceHolderVar
/* the represented expression */
Expr *phexpr pg_node_attr(equal_ignore);
- /* base relids syntactically within expr src */
+ /* base+OJ relids syntactically within expr src */
Relids phrels pg_node_attr(equal_ignore);
+ /* RT indexes of outer joins that can null PHV's value */
+ Relids phnullingrels;
+
/* ID for PHV (unique within planner run) */
Index phid;
@@ -2677,20 +2745,49 @@ typedef struct PlaceHolderVar
* We make SpecialJoinInfos for FULL JOINs even though there is no flexibility
* of planning for them, because this simplifies make_join_rel()'s API.
*
- * min_lefthand and min_righthand are the sets of base relids that must be
- * available on each side when performing the special join. lhs_strict is
- * true if the special join's condition cannot succeed when the LHS variables
- * are all NULL (this means that an outer join can commute with upper-level
- * outer joins even if it appears in their RHS). We don't bother to set
- * lhs_strict for FULL JOINs, however.
- *
+ * min_lefthand and min_righthand are the sets of base+OJ relids that must be
+ * available on each side when performing the special join.
* It is not valid for either min_lefthand or min_righthand to be empty sets;
* if they were, this would break the logic that enforces join order.
*
- * syn_lefthand and syn_righthand are the sets of base relids that are
+ * syn_lefthand and syn_righthand are the sets of base+OJ relids that are
* syntactically below this special join. (These are needed to help compute
* min_lefthand and min_righthand for higher joins.)
*
+ * jointype is never JOIN_RIGHT; a RIGHT JOIN is handled by switching
+ * the inputs to make it a LEFT JOIN. So the allowed values of jointype
+ * in a join_info_list member are only LEFT, FULL, SEMI, or ANTI.
+ *
+ * ojrelid is the RT index of the join RTE representing this outer join,
+ * if there is one. It is zero when jointype is INNER or SEMI, and can be
+ * zero for jointype ANTI (if the join was transformed from a SEMI join).
+ * One use for this field is that when constructing the output targetlist of a
+ * join relation that implements this OJ, we add ojrelid to the varnullingrels
+ * and phnullingrels fields of nullable (RHS) output columns, so that the
+ * output Vars and PlaceHolderVars correctly reflect the nulling that has
+ * potentially happened to them.
+ *
+ * commute_above_l is filled with the relids of syntactically-higher outer
+ * joins that have been found to commute with this one per outer join identity
+ * 3 (see optimizer/README), when this join is in the LHS of the upper join
+ * (so, this is the lower join in the first form of the identity).
+ *
+ * commute_above_r is filled with the relids of syntactically-higher outer
+ * joins that have been found to commute with this one per outer join identity
+ * 3, when this join is in the RHS of the upper join (so, this is the lower
+ * join in the second form of the identity).
+ *
+ * commute_below is filled with the relids of syntactically-lower outer joins
+ * that have been found to commute with this one per outer join identity 3.
+ * (We need not record which side they are on, since that can be determined
+ * by seeing whether the lower join's relid appears in syn_lefthand or
+ * syn_righthand.)
+ *
+ * lhs_strict is true if the special join's condition cannot succeed when the
+ * LHS variables are all NULL (this means that an outer join can commute with
+ * upper-level outer joins even if it appears in their RHS). We don't bother
+ * to set lhs_strict for FULL JOINs, however.
+ *
* delay_upper_joins is set true if we detect a pushed-down clause that has
* to be evaluated after this join is formed (because it references the RHS).
* Any outer joins that have such a clause and this join in their RHS cannot
@@ -2705,10 +2802,6 @@ typedef struct PlaceHolderVar
* join planning; but it's helpful to have it available during planning of
* parameterized table scans, so we store it in the SpecialJoinInfo structs.)
*
- * jointype is never JOIN_RIGHT; a RIGHT JOIN is handled by switching
- * the inputs to make it a LEFT JOIN. So the allowed values of jointype
- * in a join_info_list member are only LEFT, FULL, SEMI, or ANTI.
- *
* For purposes of join selectivity estimation, we create transient
* SpecialJoinInfo structures for regular inner joins; so it is possible
* to have jointype == JOIN_INNER in such a structure, even though this is
@@ -2728,11 +2821,15 @@ struct SpecialJoinInfo
pg_node_attr(no_read)
NodeTag type;
- Relids min_lefthand; /* base relids in minimum LHS for join */
- Relids min_righthand; /* base relids in minimum RHS for join */
- Relids syn_lefthand; /* base relids syntactically within LHS */
- Relids syn_righthand; /* base relids syntactically within RHS */
+ Relids min_lefthand; /* base+OJ relids in minimum LHS for join */
+ Relids min_righthand; /* base+OJ relids in minimum RHS for join */
+ Relids syn_lefthand; /* base+OJ relids syntactically within LHS */
+ Relids syn_righthand; /* base+OJ relids syntactically within RHS */
JoinType jointype; /* always INNER, LEFT, FULL, SEMI, or ANTI */
+ Index ojrelid; /* outer join's RT index; 0 if none */
+ Relids commute_above_l; /* commuting OJs above this one, if LHS */
+ Relids commute_above_r; /* commuting OJs above this one, if RHS */
+ Relids commute_below; /* commuting OJs below this one */
bool lhs_strict; /* joinclause is strict for some LHS rel */
bool delay_upper_joins; /* can't commute with upper RHS */
/* Remaining fields are set only for JOIN_SEMI jointype: */
@@ -2743,6 +2840,21 @@ struct SpecialJoinInfo
};
/*
+ * Transient outer-join clause info.
+ *
+ * We set aside every outer join ON clause that looks mergejoinable,
+ * and process it specially at the end of qual distribution.
+ */
+typedef struct OuterJoinClauseInfo
+{
+ pg_node_attr(no_copy_equal, no_read)
+
+ NodeTag type;
+ RestrictInfo *rinfo; /* a mergejoinable outer-join clause */
+ SpecialJoinInfo *sjinfo; /* the outer join's SpecialJoinInfo */
+} OuterJoinClauseInfo;
+
+/*
* Append-relation info.
*
* When we expand an inheritable table or a UNION-ALL subselect into an