int epqParam);
static GatherMerge *create_gather_merge_plan(PlannerInfo *root,
GatherMergePath *best_path);
+static void assert_join_preserves_scan_rtis(PlannerInfo *root, Path *best_path,
+ Plan *outer_plan,
+ Plan *inner_plan);
+#ifdef USE_ASSERT_CHECKING
+static Bitmapset *get_scanned_rtindexes(PlannerInfo *root, Plan *plan);
+static Bitmapset *remove_join_rtis(PlannerInfo *root, Bitmapset *bms);
+#endif
/*
* create_plan
copy_generic_path_info(&join_plan->join.plan, &best_path->jpath.path);
+ assert_join_preserves_scan_rtis(root, &best_path->jpath.path, outer_plan,
+ inner_plan);
+
return join_plan;
}
/* Costs of sort and material steps are included in path cost already */
copy_generic_path_info(&join_plan->join.plan, &best_path->jpath.path);
+ assert_join_preserves_scan_rtis(root, &best_path->jpath.path,
+ outer_plan, inner_plan);
+
return join_plan;
}
copy_generic_path_info(&join_plan->join.plan, &best_path->jpath.path);
+ assert_join_preserves_scan_rtis(root, &best_path->jpath.path,
+ outer_plan, inner_plan);
+
return join_plan;
}
}
return true;
}
+
+/*
+ * Check that the RTIs of the relations being joined at this level are
+ * properly reflected in the Plan tree.
+ *
+ * We expect to find every non-RTE_JOIN RTI from best_path->parent.relids
+ * mentioned in either the outer or inner subplan.
+ */
+static void
+assert_join_preserves_scan_rtis(PlannerInfo *root, Path *best_path,
+ Plan *outer_plan, Plan *inner_plan)
+{
+#ifdef USE_ASSERT_CHECKING
+ Bitmapset *outer_scanrelids;
+ Bitmapset *inner_scanrelids;
+ Bitmapset *calculated_scanrelids;
+ Bitmapset *filtered_joinrelids;
+
+ outer_scanrelids = get_scanned_rtindexes(root, outer_plan);
+ inner_scanrelids = get_scanned_rtindexes(root, inner_plan);
+ calculated_scanrelids = bms_union(outer_scanrelids, inner_scanrelids);
+ filtered_joinrelids = remove_join_rtis(root, best_path->parent->relids);
+
+ /* Any given scan RTI should appear on only one side or the other. */
+ Assert(!bms_overlap(inner_scanrelids, outer_scanrelids));
+
+ /*
+ * If this assertion fails, it means that the set of range table indexes
+ * that we found in the inner and outer path tree did not equal the set of
+ * range table indexes that we found for this joinrel, even after
+ * excluding RTE_JOIN range table indexes which are not expect to appear
+ * in the plan tree.
+ *
+ * If this assertion fails due to the addition of a new executor node
+ * type, you probably just need to update get_scanned_rtindexes to know
+ * about the new node. See the header comments for that function for other
+ * places to update at the same time.
+ */
+ Assert(bms_equal(calculated_scanrelids, filtered_joinrelids));
+#endif
+}
+
+#ifdef USE_ASSERT_CHECKING
+/*
+ * Get the set of range table indexes that are scanned by a scan or join node,
+ * or any executor node that could appear beneath a scan or join node.
+ *
+ * We are uninterested in join RTIs here; we're only interested in which RTIs
+ * are scanned at or below a particular plan node, and only if that node can
+ * appear beneath a join.
+ *
+ * When adding new cases to this function, be sure to also update
+ * ExplainPreScanNode, ExplainNode, and overexplain_per_node_hook as
+ * appropriate.
+ */
+static Bitmapset *
+get_scanned_rtindexes(PlannerInfo *root, Plan *plan)
+{
+ switch (nodeTag(plan))
+ {
+ case T_SeqScan:
+ case T_SampleScan:
+ case T_IndexScan:
+ case T_IndexOnlyScan:
+ case T_BitmapHeapScan:
+ case T_TidScan:
+ case T_TidRangeScan:
+ case T_SubqueryScan:
+ case T_FunctionScan:
+ case T_TableFuncScan:
+ case T_ValuesScan:
+ case T_CteScan:
+ case T_NamedTuplestoreScan:
+ case T_WorkTableScan:
+ return bms_make_singleton(((Scan *) plan)->scanrelid);
+ break;
+ case T_ForeignScan:
+ return ((ForeignScan *) plan)->fs_base_relids;
+ break;
+ case T_CustomScan:
+ return ((CustomScan *) plan)->custom_relids;
+ break;
+ case T_Append:
+ return ((Append *) plan)->apprelids;
+ break;
+ case T_MergeAppend:
+ return ((MergeAppend *) plan)->apprelids;
+ break;
+ case T_Result:
+ if (plan->lefttree)
+ return get_scanned_rtindexes(root, plan->lefttree);
+ else
+ return remove_join_rtis(root, ((Result *) plan)->relids);
+ break;
+ case T_HashJoin:
+ case T_MergeJoin:
+ case T_NestLoop:
+ {
+ Bitmapset *outer_scanrelids;
+ Bitmapset *inner_scanrelids;
+ Bitmapset *combined_scanrelids;
+
+ outer_scanrelids =
+ get_scanned_rtindexes(root, plan->lefttree);
+ inner_scanrelids =
+ get_scanned_rtindexes(root, plan->righttree);
+ combined_scanrelids =
+ bms_union(outer_scanrelids, inner_scanrelids);
+ inner_scanrelids = remove_join_rtis(root, inner_scanrelids);
+
+ return remove_join_rtis(root, combined_scanrelids);
+ break;
+ }
+ case T_Sort:
+ case T_IncrementalSort:
+ case T_Unique:
+ case T_Agg:
+ case T_Hash:
+ case T_Gather:
+ case T_GatherMerge:
+ case T_Material:
+ case T_Memoize:
+ return get_scanned_rtindexes(root, plan->lefttree);
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+/*
+ * Return a new Bitmapset containing only those range table indexes from the
+ * input set that do not reference an RTE where rtekind == RTE_JOIN.
+ */
+static Bitmapset *
+remove_join_rtis(PlannerInfo *root, Bitmapset *bms)
+{
+ int rti = -1;
+
+ bms = bms_copy(bms);
+
+ while ((rti = bms_next_member(bms, rti)) >= 0)
+ {
+ RangeTblEntry *rte = planner_rt_fetch(rti, root);
+
+ if (rte->rtekind == RTE_JOIN)
+ bms = bms_del_member(bms, rti);
+ }
+
+ return bms;
+}
+#endif