aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/initsplan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/initsplan.c')
-rw-r--r--src/backend/optimizer/plan/initsplan.c184
1 files changed, 121 insertions, 63 deletions
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6c..aae5df09f9b 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -62,14 +62,12 @@ static SpecialJoinInfo *make_outerjoininfo(PlannerInfo *root,
JoinType jointype, List *clause);
static void compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause);
static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,
- bool is_deduced,
bool below_outer_join,
JoinType jointype,
Index security_level,
Relids qualscope,
Relids ojscope,
Relids outerjoin_nonnullable,
- Relids deduced_nullable_relids,
List **postponed_qual_list);
static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
Relids *nullable_relids_p, bool is_pushed_down);
@@ -815,9 +813,9 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
if (bms_is_subset(pq->relids, *qualscope))
distribute_qual_to_rels(root, pq->qual,
- false, below_outer_join, JOIN_INNER,
+ below_outer_join, JOIN_INNER,
root->qual_security_level,
- *qualscope, NULL, NULL, NULL,
+ *qualscope, NULL, NULL,
NULL);
else
*postponed_qual_list = lappend(*postponed_qual_list, pq);
@@ -831,9 +829,9 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
Node *qual = (Node *) lfirst(l);
distribute_qual_to_rels(root, qual,
- false, below_outer_join, JOIN_INNER,
+ below_outer_join, JOIN_INNER,
root->qual_security_level,
- *qualscope, NULL, NULL, NULL,
+ *qualscope, NULL, NULL,
postponed_qual_list);
}
}
@@ -1008,10 +1006,10 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
Node *qual = (Node *) lfirst(l);
distribute_qual_to_rels(root, qual,
- false, below_outer_join, j->jointype,
+ below_outer_join, j->jointype,
root->qual_security_level,
*qualscope,
- ojscope, nonnullable_rels, NULL,
+ ojscope, nonnullable_rels,
postponed_qual_list);
}
@@ -1110,14 +1108,12 @@ process_security_barrier_quals(PlannerInfo *root,
* than being pushed up to top of tree, which we don't want.
*/
distribute_qual_to_rels(root, qual,
- false,
below_outer_join,
JOIN_INNER,
security_level,
qualscope,
qualscope,
NULL,
- NULL,
NULL);
}
security_level++;
@@ -1581,7 +1577,6 @@ compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause)
* as belonging to a higher join level, just add it to postponed_qual_list.
*
* 'clause': the qual clause to be distributed
- * 'is_deduced': true if the qual came from implied-equality deduction
* 'below_outer_join': true if the qual is from a JOIN/ON that is below the
* nullable side of a higher-level outer join
* 'jointype': type of join the qual is from (JOIN_INNER for a WHERE clause)
@@ -1593,8 +1588,6 @@ compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause)
* baserels appearing on the outer (nonnullable) side of the join
* (for FULL JOIN this includes both sides of the join, and must in fact
* equal qualscope)
- * 'deduced_nullable_relids': if is_deduced is true, the nullable relids to
- * impute to the clause; otherwise NULL
* 'postponed_qual_list': list of PostponedQual structs, which we can add
* this qual to if it turns out to belong to a higher join level.
* Can be NULL if caller knows postponement is impossible.
@@ -1603,23 +1596,17 @@ compute_semijoin_info(SpecialJoinInfo *sjinfo, List *clause)
* 'ojscope' is needed if we decide to force the qual up to the outer-join
* level, which will be ojscope not necessarily qualscope.
*
- * In normal use (when is_deduced is false), at the time this is called,
- * root->join_info_list must contain entries for all and only those special
- * joins that are syntactically below this qual. But when is_deduced is true,
- * we are adding new deduced clauses after completion of deconstruct_jointree,
- * so it cannot be assumed that root->join_info_list has anything to do with
- * qual placement.
+ * At the time this is called, root->join_info_list must contain entries for
+ * all and only those special joins that are syntactically below this qual.
*/
static void
distribute_qual_to_rels(PlannerInfo *root, Node *clause,
- bool is_deduced,
bool below_outer_join,
JoinType jointype,
Index security_level,
Relids qualscope,
Relids ojscope,
Relids outerjoin_nonnullable,
- Relids deduced_nullable_relids,
List **postponed_qual_list)
{
Relids relids;
@@ -1653,7 +1640,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
Assert(root->hasLateralRTEs); /* shouldn't happen otherwise */
Assert(jointype == JOIN_INNER); /* mustn't postpone past outer join */
- Assert(!is_deduced); /* shouldn't be deduced, either */
pq->qual = clause;
pq->relids = relids;
*postponed_qual_list = lappend(*postponed_qual_list, pq);
@@ -1754,24 +1740,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
* This seems like another reason why it should perhaps be rethought.
*----------
*/
- if (is_deduced)
- {
- /*
- * If the qual came from implied-equality deduction, it should not be
- * outerjoin-delayed, else deducer blew it. But we can't check this
- * because the join_info_list may now contain OJs above where the qual
- * belongs. For the same reason, we must rely on caller to supply the
- * correct nullable_relids set.
- */
- Assert(!ojscope);
- is_pushed_down = true;
- outerjoin_delayed = false;
- nullable_relids = deduced_nullable_relids;
- /* Don't feed it back for more deductions */
- maybe_equivalence = false;
- maybe_outer_join = false;
- }
- else if (bms_overlap(relids, outerjoin_nonnullable))
+ if (bms_overlap(relids, outerjoin_nonnullable))
{
/*
* The qual is attached to an outer join and mentions (some of the)
@@ -2277,14 +2246,18 @@ distribute_restrictinfo_to_rels(PlannerInfo *root,
* can produce constant TRUE or constant FALSE. (Otherwise it's not,
* because the expressions went through eval_const_expressions already.)
*
+ * Returns the generated RestrictInfo, if any. The result will be NULL
+ * if both_const is true and we successfully reduced the clause to
+ * constant TRUE.
+ *
* Note: this function will copy item1 and item2, but it is caller's
* responsibility to make sure that the Relids parameters are fresh copies
* not shared with other uses.
*
- * This is currently used only when an EquivalenceClass is found to
- * contain pseudoconstants. See path/pathkeys.c for more details.
+ * Note: we do not do initialize_mergeclause_eclasses() here. It is
+ * caller's responsibility that left_ec/right_ec be set as necessary.
*/
-void
+RestrictInfo *
process_implied_equality(PlannerInfo *root,
Oid opno,
Oid collation,
@@ -2296,24 +2269,27 @@ process_implied_equality(PlannerInfo *root,
bool below_outer_join,
bool both_const)
{
- Expr *clause;
+ RestrictInfo *restrictinfo;
+ Node *clause;
+ Relids relids;
+ bool pseudoconstant = false;
/*
* Build the new clause. Copy to ensure it shares no substructure with
* original (this is necessary in case there are subselects in there...)
*/
- clause = make_opclause(opno,
- BOOLOID, /* opresulttype */
- false, /* opretset */
- copyObject(item1),
- copyObject(item2),
- InvalidOid,
- collation);
+ clause = (Node *) make_opclause(opno,
+ BOOLOID, /* opresulttype */
+ false, /* opretset */
+ copyObject(item1),
+ copyObject(item2),
+ InvalidOid,
+ collation);
/* If both constant, try to reduce to a boolean constant. */
if (both_const)
{
- clause = (Expr *) eval_const_expressions(root, (Node *) clause);
+ clause = eval_const_expressions(root, clause);
/* If we produced const TRUE, just drop the clause */
if (clause && IsA(clause, Const))
@@ -2322,25 +2298,106 @@ process_implied_equality(PlannerInfo *root,
Assert(cclause->consttype == BOOLOID);
if (!cclause->constisnull && DatumGetBool(cclause->constvalue))
- return;
+ return NULL;
+ }
+ }
+
+ /*
+ * The rest of this is a very cut-down version of distribute_qual_to_rels.
+ * We can skip most of the work therein, but there are a couple of special
+ * cases we still have to handle.
+ *
+ * Retrieve all relids mentioned within the possibly-simplified clause.
+ */
+ relids = pull_varnos(clause);
+ Assert(bms_is_subset(relids, qualscope));
+
+ /*
+ * If the clause is variable-free, our normal heuristic for pushing it
+ * down to just the mentioned rels doesn't work, because there are none.
+ * Apply at the given qualscope, or at the top of tree if it's nonvolatile
+ * (which it very likely is, but we'll check, just to be sure).
+ */
+ if (bms_is_empty(relids))
+ {
+ /* eval at original syntactic level */
+ relids = bms_copy(qualscope);
+ if (!contain_volatile_functions(clause))
+ {
+ /* mark as gating qual */
+ pseudoconstant = true;
+ /* tell createplan.c to check for gating quals */
+ root->hasPseudoConstantQuals = true;
+ /* if not below outer join, push it to top of tree */
+ if (!below_outer_join)
+ {
+ relids =
+ get_relids_in_jointree((Node *) root->parse->jointree,
+ false);
+ }
}
}
/*
+ * Build the RestrictInfo node itself.
+ */
+ restrictinfo = make_restrictinfo((Expr *) clause,
+ true, /* is_pushed_down */
+ false, /* outerjoin_delayed */
+ pseudoconstant,
+ security_level,
+ relids,
+ NULL, /* outer_relids */
+ nullable_relids);
+
+ /*
+ * If it's a join clause, add vars used in the clause to targetlists of
+ * their relations, so that they will be emitted by the plan nodes that
+ * scan those relations (else they won't be available at the join node!).
+ *
+ * Typically, we'd have already done this when the component expressions
+ * were first seen by distribute_qual_to_rels; but it is possible that
+ * some of the Vars could have missed having that done because they only
+ * appeared in single-relation clauses originally. So do it here for
+ * safety.
+ */
+ if (bms_membership(relids) == BMS_MULTIPLE)
+ {
+ List *vars = pull_var_clause(clause,
+ PVC_RECURSE_AGGREGATES |
+ PVC_RECURSE_WINDOWFUNCS |
+ PVC_INCLUDE_PLACEHOLDERS);
+
+ add_vars_to_targetlist(root, vars, relids, false);
+ list_free(vars);
+ }
+
+ /*
+ * Check mergejoinability. This will usually succeed, since the op came
+ * from an EquivalenceClass; but we could have reduced the original clause
+ * to a constant.
+ */
+ check_mergejoinable(restrictinfo);
+
+ /*
+ * Note we don't do initialize_mergeclause_eclasses(); the caller can
+ * handle that much more cheaply than we can. It's okay to call
+ * distribute_restrictinfo_to_rels() before that happens.
+ */
+
+ /*
* Push the new clause into all the appropriate restrictinfo lists.
*/
- distribute_qual_to_rels(root, (Node *) clause,
- true, below_outer_join, JOIN_INNER,
- security_level,
- qualscope, NULL, NULL, nullable_relids,
- NULL);
+ distribute_restrictinfo_to_rels(root, restrictinfo);
+
+ return restrictinfo;
}
/*
* build_implied_join_equality --- build a RestrictInfo for a derived equality
*
* This overlaps the functionality of process_implied_equality(), but we
- * must return the RestrictInfo, not push it into the joininfo tree.
+ * must not push the RestrictInfo into the joininfo tree.
*
* Note: this function will copy item1 and item2, but it is caller's
* responsibility to make sure that the Relids parameters are fresh copies
@@ -2455,18 +2512,19 @@ match_foreign_keys_to_quals(PlannerInfo *root)
*/
for (colno = 0; colno < fkinfo->nkeys; colno++)
{
+ EquivalenceClass *ec;
AttrNumber con_attno,
ref_attno;
Oid fpeqop;
ListCell *lc2;
- fkinfo->eclass[colno] = match_eclasses_to_foreign_key_col(root,
- fkinfo,
- colno);
+ ec = match_eclasses_to_foreign_key_col(root, fkinfo, colno);
/* Don't bother looking for loose quals if we got an EC match */
- if (fkinfo->eclass[colno] != NULL)
+ if (ec != NULL)
{
fkinfo->nmatched_ec++;
+ if (ec->ec_has_const)
+ fkinfo->nconst_ec++;
continue;
}