v23-0006-Introduce-update_clause_relids-for-updating-Rest.patch
application/octet-stream
Filename: v23-0006-Introduce-update_clause_relids-for-updating-Rest.patch
Type: application/octet-stream
Part: 6
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v23-0006
Subject: Introduce update_clause_relids() for updating RestrictInfo->clause_relids
| File | + | − |
|---|---|---|
| src/backend/optimizer/path/equivclass.c | 120 | 0 |
| src/backend/optimizer/plan/analyzejoins.c | 52 | 29 |
| src/backend/optimizer/util/appendinfo.c | 2 | 0 |
| src/backend/optimizer/util/restrictinfo.c | 5 | 0 |
| src/include/nodes/pathnodes.h | 10 | 1 |
| src/include/optimizer/paths.h | 2 | 0 |
From 6bcce92df6dc597e050b7161e5555f3bfd7da841 Mon Sep 17 00:00:00 2001
From: Yuya Watari <watari.yuya@gmail.com>
Date: Thu, 11 Jan 2024 16:18:38 +0900
Subject: [PATCH v23 6/6] Introduce update_clause_relids() for updating
RestrictInfo->clause_relids
Originally, the update for RestrictInfo->clause_relids was done by
directly setting the field. However, this failed to update the
corresponding indexes, such as eclass_source_indexes and
eclass_derive_indexes.
This commit provides a helper function to update the field with fixing
the indexes.
---
src/backend/optimizer/path/equivclass.c | 120 ++++++++++++++++++++++
src/backend/optimizer/plan/analyzejoins.c | 81 +++++++++------
src/backend/optimizer/util/appendinfo.c | 2 +
src/backend/optimizer/util/restrictinfo.c | 5 +
src/include/nodes/pathnodes.h | 11 +-
src/include/optimizer/paths.h | 2 +
6 files changed, 191 insertions(+), 30 deletions(-)
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index d1019315ea..3f4df1a8c7 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -623,6 +623,8 @@ add_eq_source(PlannerInfo *root, EquivalenceClass *ec, RestrictInfo *rinfo)
ec->ec_source_indexes = bms_add_member(ec->ec_source_indexes, source_idx);
root->eq_sources = lappend(root->eq_sources, rinfo);
+ Assert(rinfo->eq_sources_index == -1);
+ rinfo->eq_sources_index = source_idx;
i = -1;
while ((i = bms_next_member(rinfo->clause_relids, i)) >= 0)
@@ -645,6 +647,8 @@ add_eq_derive(PlannerInfo *root, EquivalenceClass *ec, RestrictInfo *rinfo)
ec->ec_derive_indexes = bms_add_member(ec->ec_derive_indexes, derive_idx);
root->eq_derives = lappend(root->eq_derives, rinfo);
+ Assert(rinfo->eq_derives_index == -1);
+ rinfo->eq_derives_index = derive_idx;
i = -1;
while ((i = bms_next_member(rinfo->clause_relids, i)) >= 0)
@@ -656,6 +660,122 @@ add_eq_derive(PlannerInfo *root, EquivalenceClass *ec, RestrictInfo *rinfo)
}
}
+/*
+ * update_clause_relids
+ * Update RestrictInfo->clause_relids with adjusting the relevant indexes.
+ * The clause_relids field must be updated through this function, not by
+ * setting the field directly.
+ */
+void
+update_clause_relids(PlannerInfo *root, RestrictInfo *rinfo,
+ Relids new_clause_relids)
+{
+ int i;
+ Relids removing_relids;
+ Relids adding_relids;
+#ifdef USE_ASSERT_CHECKING
+ Relids common_relids;
+#endif
+
+ /*
+ * If there is nothing to do, we return immediately after setting the
+ * clause_relids field.
+ */
+ if (rinfo->eq_sources_index == -1 && rinfo->eq_derives_index == -1)
+ {
+ rinfo->clause_relids = new_clause_relids;
+ return;
+ }
+
+ /*
+ * Remove any references between this RestrictInfo and RangeTblEntries
+ * that are no longer relevant.
+ */
+ removing_relids = bms_difference(rinfo->clause_relids, new_clause_relids);
+ i = -1;
+ while ((i = bms_next_member(removing_relids, i)) >= 0)
+ {
+ RangeTblEntry *rte = root->simple_rte_array[i];
+
+ if (rinfo->eq_sources_index != -1)
+ {
+ Assert(bms_is_member(rinfo->eq_sources_index,
+ rte->eclass_source_indexes));
+ rte->eclass_source_indexes =
+ bms_del_member(rte->eclass_source_indexes,
+ rinfo->eq_sources_index);
+ }
+ if (rinfo->eq_derives_index != -1)
+ {
+ Assert(bms_is_member(rinfo->eq_derives_index,
+ rte->eclass_derive_indexes));
+ rte->eclass_derive_indexes =
+ bms_del_member(rte->eclass_derive_indexes,
+ rinfo->eq_derives_index);
+ }
+ }
+ bms_free(removing_relids);
+
+ /*
+ * Add references between this RestrictInfo and RangeTblEntries that will
+ * be relevant.
+ */
+ adding_relids = bms_difference(new_clause_relids, rinfo->clause_relids);
+ i = -1;
+ while ((i = bms_next_member(adding_relids, i)) >= 0)
+ {
+ RangeTblEntry *rte = root->simple_rte_array[i];
+
+ if (rinfo->eq_sources_index != -1)
+ {
+ Assert(!bms_is_member(rinfo->eq_sources_index,
+ rte->eclass_source_indexes));
+ rte->eclass_source_indexes =
+ bms_add_member(rte->eclass_source_indexes,
+ rinfo->eq_sources_index);
+ }
+ if (rinfo->eq_derives_index != -1)
+ {
+ Assert(!bms_is_member(rinfo->eq_derives_index,
+ rte->eclass_derive_indexes));
+ rte->eclass_derive_indexes =
+ bms_add_member(rte->eclass_derive_indexes,
+ rinfo->eq_derives_index);
+ }
+ }
+ bms_free(adding_relids);
+
+#ifdef USE_ASSERT_CHECKING
+ /*
+ * Verify that all indexes are set for common Relids.
+ */
+ common_relids = bms_intersect(rinfo->clause_relids, new_clause_relids);
+ i = -1;
+ while ((i = bms_next_member(common_relids, i)) >= 0)
+ {
+ RangeTblEntry *rte = root->simple_rte_array[i];
+
+ if (rinfo->eq_sources_index != -1)
+ {
+ Assert(bms_is_member(rinfo->eq_sources_index,
+ rte->eclass_source_indexes));
+ }
+ if (rinfo->eq_derives_index != -1)
+ {
+ Assert(bms_is_member(rinfo->eq_derives_index,
+ rte->eclass_derive_indexes));
+ }
+ }
+ bms_free(common_relids);
+#endif
+
+ /*
+ * Since we have done everything to adjust the indexes, we can set the
+ * clause_relids field.
+ */
+ rinfo->clause_relids = new_clause_relids;
+}
+
/*
* get_eclass_for_sort_expr
diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c
index 4081827e3a..2da2a6c14e 100644
--- a/src/backend/optimizer/plan/analyzejoins.c
+++ b/src/backend/optimizer/plan/analyzejoins.c
@@ -39,6 +39,7 @@
*/
typedef struct
{
+ PlannerInfo *root;
int from;
int to;
} ReplaceVarnoContext;
@@ -59,7 +60,8 @@ static bool join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo);
static void remove_leftjoinrel_from_query(PlannerInfo *root, int relid,
SpecialJoinInfo *sjinfo);
-static void remove_rel_from_restrictinfo(RestrictInfo *rinfo,
+static void remove_rel_from_restrictinfo(PlannerInfo *root,
+ RestrictInfo *rinfo,
int relid, int ojrelid);
static void remove_rel_from_eclass(PlannerInfo *root, EquivalenceClass *ec,
int relid, int ojrelid);
@@ -76,7 +78,7 @@ static bool is_innerrel_unique_for(PlannerInfo *root,
List *restrictlist,
List **extra_clauses);
static Bitmapset *replace_relid(Relids relids, int oldId, int newId);
-static void replace_varno(Node *node, int from, int to);
+static void replace_varno(PlannerInfo *root, Node *node, int from, int to);
static bool replace_varno_walker(Node *node, ReplaceVarnoContext *ctx);
static int self_join_candidates_cmp(const void *a, const void *b);
@@ -395,7 +397,7 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
}
/* Update lateral references. */
- replace_varno((Node *) otherrel->lateral_vars, relid, subst);
+ replace_varno(root, (Node *) otherrel->lateral_vars, relid, subst);
}
/*
@@ -432,7 +434,7 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
sjinf->commute_below_l = replace_relid(sjinf->commute_below_l, ojrelid, subst);
sjinf->commute_below_r = replace_relid(sjinf->commute_below_r, ojrelid, subst);
- replace_varno((Node *) sjinf->semi_rhs_exprs, relid, subst);
+ replace_varno(root, (Node *) sjinf->semi_rhs_exprs, relid, subst);
}
/*
@@ -477,7 +479,7 @@ remove_rel_from_query(PlannerInfo *root, RelOptInfo *rel,
phv->phrels = replace_relid(phv->phrels, relid, subst);
phv->phrels = replace_relid(phv->phrels, ojrelid, subst);
Assert(!bms_is_empty(phv->phrels));
- replace_varno((Node *) phv->phexpr, relid, subst);
+ replace_varno(root, (Node *) phv->phexpr, relid, subst);
Assert(phv->phnullingrels == NULL); /* no need to adjust */
}
}
@@ -551,7 +553,7 @@ remove_leftjoinrel_from_query(PlannerInfo *root, int relid,
* that any such PHV is safe (and updated its ph_eval_at), so we
* can just drop those references.
*/
- remove_rel_from_restrictinfo(rinfo, relid, ojrelid);
+ remove_rel_from_restrictinfo(root, rinfo, relid, ojrelid);
/*
* Cross-check that the clause itself does not reference the
@@ -608,16 +610,24 @@ remove_leftjoinrel_from_query(PlannerInfo *root, int relid,
* we have to also clean up the sub-clauses.
*/
static void
-remove_rel_from_restrictinfo(RestrictInfo *rinfo, int relid, int ojrelid)
+remove_rel_from_restrictinfo(PlannerInfo *root, RestrictInfo *rinfo, int relid,
+ int ojrelid)
{
+ Relids new_clause_relids;
+
+ /*
+ * The 'new_clause_relids' passed to update_clause_relids() must be a
+ * different instance from the current rinfo->clause_relids, so we make a
+ * copy of them.
+ */
+ new_clause_relids = bms_copy(rinfo->clause_relids);
+ new_clause_relids = bms_del_member(new_clause_relids, relid);
+ new_clause_relids = bms_del_member(new_clause_relids, ojrelid);
+ update_clause_relids(root, rinfo, new_clause_relids);
/*
- * The clause_relids probably aren't shared with anything else, but let's
+ * The required_relids probably aren't shared with anything else, but let's
* copy them just to be sure.
*/
- rinfo->clause_relids = bms_copy(rinfo->clause_relids);
- rinfo->clause_relids = bms_del_member(rinfo->clause_relids, relid);
- rinfo->clause_relids = bms_del_member(rinfo->clause_relids, ojrelid);
- /* Likewise for required_relids */
rinfo->required_relids = bms_copy(rinfo->required_relids);
rinfo->required_relids = bms_del_member(rinfo->required_relids, relid);
rinfo->required_relids = bms_del_member(rinfo->required_relids, ojrelid);
@@ -642,14 +652,14 @@ remove_rel_from_restrictinfo(RestrictInfo *rinfo, int relid, int ojrelid)
{
RestrictInfo *rinfo2 = lfirst_node(RestrictInfo, lc2);
- remove_rel_from_restrictinfo(rinfo2, relid, ojrelid);
+ remove_rel_from_restrictinfo(root, rinfo2, relid, ojrelid);
}
}
else
{
RestrictInfo *rinfo2 = castNode(RestrictInfo, orarg);
- remove_rel_from_restrictinfo(rinfo2, relid, ojrelid);
+ remove_rel_from_restrictinfo(root, rinfo2, relid, ojrelid);
}
}
}
@@ -708,7 +718,7 @@ remove_rel_from_eclass(PlannerInfo *root, EquivalenceClass *ec, int relid,
{
RestrictInfo *rinfo = list_nth_node(RestrictInfo, root->eq_sources, i);
- remove_rel_from_restrictinfo(rinfo, relid, ojrelid);
+ remove_rel_from_restrictinfo(root, rinfo, relid, ojrelid);
}
/*
@@ -1448,13 +1458,14 @@ is_innerrel_unique_for(PlannerInfo *root,
* Replace each occurrence of removing relid with the keeping one
*/
static void
-replace_varno(Node *node, int from, int to)
+replace_varno(PlannerInfo *root, Node *node, int from, int to)
{
ReplaceVarnoContext ctx;
if (to <= 0)
return;
+ ctx.root = root;
ctx.from = from;
ctx.to = to;
replace_varno_walker(node, &ctx);
@@ -1498,9 +1509,9 @@ replace_varno_walker(Node *node, ReplaceVarnoContext *ctx)
if (bms_is_member(ctx->from, rinfo->clause_relids))
{
- replace_varno((Node *) rinfo->clause, ctx->from, ctx->to);
- replace_varno((Node *) rinfo->orclause, ctx->from, ctx->to);
- rinfo->clause_relids = replace_relid(rinfo->clause_relids, ctx->from, ctx->to);
+ replace_varno(ctx->root, (Node *) rinfo->clause, ctx->from, ctx->to);
+ replace_varno(ctx->root, (Node *) rinfo->orclause, ctx->from, ctx->to);
+ update_clause_relids(ctx->root, rinfo, replace_relid(rinfo->clause_relids, ctx->from, ctx->to));
rinfo->left_relids = replace_relid(rinfo->left_relids, ctx->from, ctx->to);
rinfo->right_relids = replace_relid(rinfo->right_relids, ctx->from, ctx->to);
}
@@ -1613,7 +1624,7 @@ update_eclasses(PlannerInfo *root, EquivalenceClass *ec, int from, int to)
em->em_jdomain->jd_relids = replace_relid(em->em_jdomain->jd_relids, from, to);
/* We only process inner joins */
- replace_varno((Node *) em->em_expr, from, to);
+ replace_varno(root, (Node *) em->em_expr, from, to);
foreach(lc1, new_members)
{
@@ -1660,6 +1671,12 @@ update_eclasses(PlannerInfo *root, EquivalenceClass *ec, int from, int to)
* the eq_derives indexes. But set a null to detect potential problems.
*/
list_nth_cell(root->eq_derives, i)->ptr_value = NULL;
+
+ /*
+ * Since this RestrictInfo no longer exists in root->eq_derives, we
+ * must reset the stored index.
+ */
+ rinfo->eq_derives_index = -1;
}
bms_free(ec->ec_derive_indexes);
ec->ec_derive_indexes = NULL;
@@ -1677,7 +1694,7 @@ update_eclasses(PlannerInfo *root, EquivalenceClass *ec, int from, int to)
continue;
}
- replace_varno((Node *) rinfo, from, to);
+ replace_varno(root, (Node *) rinfo, from, to);
/*
* After switching the clause to the remaining relation, check it for
@@ -1720,6 +1737,12 @@ update_eclasses(PlannerInfo *root, EquivalenceClass *ec, int from, int to)
* the eq_sources indexes. But set a null to detect potential problems.
*/
list_nth_cell(root->eq_sources, i)->ptr_value = NULL;
+
+ /*
+ * Since this RestrictInfo no longer exists in root->eq_sources, we
+ * must reset the stored index.
+ */
+ rinfo->eq_sources_index = -1;
}
else
new_source_indexes = bms_add_member(new_source_indexes, i);
@@ -1782,7 +1805,7 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
int i;
List *jinfo_candidates = NIL;
List *binfo_candidates = NIL;
- ReplaceVarnoContext ctx = {.from = toRemove->relid,.to = toKeep->relid};
+ ReplaceVarnoContext ctx = {.root = root,.from = toRemove->relid,.to = toKeep->relid};
Assert(toKeep->relid != -1);
@@ -1798,7 +1821,7 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
remove_join_clause_from_rels(root, rinfo, rinfo->required_relids);
- replace_varno((Node *) rinfo, toRemove->relid, toKeep->relid);
+ replace_varno(root, (Node *) rinfo, toRemove->relid, toKeep->relid);
if (bms_membership(rinfo->required_relids) == BMS_MULTIPLE)
jinfo_candidates = lappend(jinfo_candidates, rinfo);
@@ -1818,7 +1841,7 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
{
RestrictInfo *rinfo = lfirst_node(RestrictInfo, lc);
- replace_varno((Node *) rinfo, toRemove->relid, toKeep->relid);
+ replace_varno(root, (Node *) rinfo, toRemove->relid, toKeep->relid);
if (bms_membership(rinfo->required_relids) == BMS_MULTIPLE)
jinfo_candidates = lappend(jinfo_candidates, rinfo);
@@ -1918,7 +1941,7 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
{
Node *node = lfirst(lc);
- replace_varno(node, toRemove->relid, toKeep->relid);
+ replace_varno(root, node, toRemove->relid, toKeep->relid);
if (!list_member(toKeep->reltarget->exprs, node))
toKeep->reltarget->exprs = lappend(toKeep->reltarget->exprs, node);
}
@@ -1970,9 +1993,9 @@ remove_self_join_rel(PlannerInfo *root, PlanRowMark *kmark, PlanRowMark *rmark,
remove_rel_from_query(root, toRemove, toKeep->relid, NULL, NULL);
/* At last, replace varno in root targetlist and HAVING clause */
- replace_varno((Node *) root->processed_tlist,
+ replace_varno(root, (Node *) root->processed_tlist,
toRemove->relid, toKeep->relid);
- replace_varno((Node *) root->processed_groupClause,
+ replace_varno(root, (Node *) root->processed_groupClause,
toRemove->relid, toKeep->relid);
replace_relid(root->all_result_relids, toRemove->relid, toKeep->relid);
replace_relid(root->leaf_result_relids, toRemove->relid, toKeep->relid);
@@ -2049,7 +2072,7 @@ split_selfjoin_quals(PlannerInfo *root, List *joinquals, List **selfjoinquals,
* when we have cast of the same var to different (but compatible)
* types.
*/
- replace_varno(rightexpr, bms_singleton_member(rinfo->right_relids),
+ replace_varno(root, rightexpr, bms_singleton_member(rinfo->right_relids),
bms_singleton_member(rinfo->left_relids));
if (equal(leftexpr, rightexpr))
@@ -2090,7 +2113,7 @@ match_unique_clauses(PlannerInfo *root, RelOptInfo *outer, List *uclauses,
bms_is_empty(rinfo->right_relids));
clause = (Expr *) copyObject(rinfo->clause);
- replace_varno((Node *) clause, relid, outer->relid);
+ replace_varno(root, (Node *) clause, relid, outer->relid);
iclause = bms_is_empty(rinfo->left_relids) ? get_rightop(clause) :
get_leftop(clause);
diff --git a/src/backend/optimizer/util/appendinfo.c b/src/backend/optimizer/util/appendinfo.c
index 51fdeace7d..27e4b093d7 100644
--- a/src/backend/optimizer/util/appendinfo.c
+++ b/src/backend/optimizer/util/appendinfo.c
@@ -491,6 +491,8 @@ adjust_appendrel_attrs_mutator(Node *node,
newinfo->right_bucketsize = -1;
newinfo->left_mcvfreq = -1;
newinfo->right_mcvfreq = -1;
+ newinfo->eq_sources_index = -1;
+ newinfo->eq_derives_index = -1;
return (Node *) newinfo;
}
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index 0b406e9334..59ba503ecb 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -247,6 +247,9 @@ make_restrictinfo_internal(PlannerInfo *root,
restrictinfo->left_hasheqoperator = InvalidOid;
restrictinfo->right_hasheqoperator = InvalidOid;
+ restrictinfo->eq_sources_index = -1;
+ restrictinfo->eq_derives_index = -1;
+
return restrictinfo;
}
@@ -403,6 +406,8 @@ commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op)
result->right_mcvfreq = rinfo->left_mcvfreq;
result->left_hasheqoperator = InvalidOid;
result->right_hasheqoperator = InvalidOid;
+ result->eq_sources_index = -1;
+ result->eq_derives_index = -1;
return result;
}
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 1c5d7bc0c1..b856722533 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -2622,7 +2622,12 @@ typedef struct RestrictInfo
/* 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: */
+ /*
+ * The relids (varnos+varnullingrels) actually referenced in the clause.
+ *
+ * NOTE: This field must be updated through update_clause_relids(), not by
+ * setting the field directly.
+ */
Relids clause_relids pg_node_attr(equal_ignore);
/* The set of relids required to evaluate the clause: */
@@ -2737,6 +2742,10 @@ typedef struct RestrictInfo
/* hash equality operators used for memoize nodes, else InvalidOid */
Oid left_hasheqoperator pg_node_attr(equal_ignore);
Oid right_hasheqoperator pg_node_attr(equal_ignore);
+
+ /* the index within root->eq_sources and root->eq_derives */
+ int eq_sources_index pg_node_attr(equal_ignore);
+ int eq_derives_index pg_node_attr(equal_ignore);
} RestrictInfo;
/*
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index d071f6d0fc..c23b177f65 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -128,6 +128,8 @@ extern bool process_equivalence(PlannerInfo *root,
extern Expr *canonicalize_ec_expression(Expr *expr,
Oid req_type, Oid req_collation);
extern void reconsider_outer_join_clauses(PlannerInfo *root);
+extern void update_clause_relids(PlannerInfo *root, RestrictInfo *rinfo,
+ Relids new_clause_relids);
extern EquivalenceClass *get_eclass_for_sort_expr(PlannerInfo *root,
Expr *expr,
List *opfamilies,
--
2.42.0.windows.2