diff options
Diffstat (limited to 'src/include/nodes/pathnodes.h')
-rw-r--r-- | src/include/nodes/pathnodes.h | 216 |
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 |