summaryrefslogtreecommitdiffstats
path: root/src/backend/optimizer/util/joininfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/joininfo.c')
-rw-r--r--src/backend/optimizer/util/joininfo.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/backend/optimizer/util/joininfo.c b/src/backend/optimizer/util/joininfo.c
new file mode 100644
index 0000000..d4cffdb
--- /dev/null
+++ b/src/backend/optimizer/util/joininfo.c
@@ -0,0 +1,140 @@
+/*-------------------------------------------------------------------------
+ *
+ * joininfo.c
+ * joininfo list manipulation routines
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/optimizer/util/joininfo.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "optimizer/joininfo.h"
+#include "optimizer/pathnode.h"
+#include "optimizer/paths.h"
+
+
+/*
+ * have_relevant_joinclause
+ * Detect whether there is a joinclause that involves
+ * the two given relations.
+ *
+ * Note: the joinclause does not have to be evaluable with only these two
+ * relations. This is intentional. For example consider
+ * SELECT * FROM a, b, c WHERE a.x = (b.y + c.z)
+ * If a is much larger than the other tables, it may be worthwhile to
+ * cross-join b and c and then use an inner indexscan on a.x. Therefore
+ * we should consider this joinclause as reason to join b to c, even though
+ * it can't be applied at that join step.
+ */
+bool
+have_relevant_joinclause(PlannerInfo *root,
+ RelOptInfo *rel1, RelOptInfo *rel2)
+{
+ bool result = false;
+ List *joininfo;
+ Relids other_relids;
+ ListCell *l;
+
+ /*
+ * We could scan either relation's joininfo list; may as well use the
+ * shorter one.
+ */
+ if (list_length(rel1->joininfo) <= list_length(rel2->joininfo))
+ {
+ joininfo = rel1->joininfo;
+ other_relids = rel2->relids;
+ }
+ else
+ {
+ joininfo = rel2->joininfo;
+ other_relids = rel1->relids;
+ }
+
+ foreach(l, joininfo)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
+
+ if (bms_overlap(other_relids, rinfo->required_relids))
+ {
+ result = true;
+ break;
+ }
+ }
+
+ /*
+ * We also need to check the EquivalenceClass data structure, which might
+ * contain relationships not emitted into the joininfo lists.
+ */
+ if (!result && rel1->has_eclass_joins && rel2->has_eclass_joins)
+ result = have_relevant_eclass_joinclause(root, rel1, rel2);
+
+ return result;
+}
+
+
+/*
+ * add_join_clause_to_rels
+ * Add 'restrictinfo' to the joininfo list of each relation it requires.
+ *
+ * Note that the same copy of the restrictinfo node is linked to by all the
+ * lists it is in. This allows us to exploit caching of information about
+ * the restriction clause (but we must be careful that the information does
+ * not depend on context).
+ *
+ * 'restrictinfo' describes the join clause
+ * 'join_relids' is the list of relations participating in the join clause
+ * (there must be more than one)
+ */
+void
+add_join_clause_to_rels(PlannerInfo *root,
+ RestrictInfo *restrictinfo,
+ Relids join_relids)
+{
+ int cur_relid;
+
+ cur_relid = -1;
+ while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
+ {
+ RelOptInfo *rel = find_base_rel(root, cur_relid);
+
+ rel->joininfo = lappend(rel->joininfo, restrictinfo);
+ }
+}
+
+/*
+ * remove_join_clause_from_rels
+ * Delete 'restrictinfo' from all the joininfo lists it is in
+ *
+ * This reverses the effect of add_join_clause_to_rels. It's used when we
+ * discover that a relation need not be joined at all.
+ *
+ * 'restrictinfo' describes the join clause
+ * 'join_relids' is the list of relations participating in the join clause
+ * (there must be more than one)
+ */
+void
+remove_join_clause_from_rels(PlannerInfo *root,
+ RestrictInfo *restrictinfo,
+ Relids join_relids)
+{
+ int cur_relid;
+
+ cur_relid = -1;
+ while ((cur_relid = bms_next_member(join_relids, cur_relid)) >= 0)
+ {
+ RelOptInfo *rel = find_base_rel(root, cur_relid);
+
+ /*
+ * Remove the restrictinfo from the list. Pointer comparison is
+ * sufficient.
+ */
+ Assert(list_member_ptr(rel->joininfo, restrictinfo));
+ rel->joininfo = list_delete_ptr(rel->joininfo, restrictinfo);
+ }
+}