+ * set_inner_join_references
+ * Handle join references appearing in an inner indexscan's quals
+ *
+ * To handle bitmap-scan plan trees, we have to be able to recurse down
+ * to the bottom BitmapIndexScan nodes; likewise, appendrel indexscans
+ * require recursing through Append nodes. This is split out as a separate
+ * function so that it can recurse.
+ *
+ * Note we do *not* apply any rtoffset for non-join Vars; this is because
+ * the quals will be processed again by fix_scan_expr when the set_plan_refs
+ * recursion reaches the inner indexscan, and so we'd have done it twice.
+ */
+static void
+set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
+ indexed_tlist *outer_itlist)
+{
+ if (IsA(inner_plan, IndexScan))
+ {
+ /*
+ * An index is being used to reduce the number of tuples scanned in
+ * the inner relation. If there are join clauses being used with the
+ * index, we must update their outer-rel var nodes to refer to the
+ * outer side of the join.
+ */
+ IndexScan *innerscan = (IndexScan *) inner_plan;
+ List *indexqualorig = innerscan->indexqualorig;
+
+ /* No work needed if indexqual refers only to its own rel... */
+ if (NumRelids((Node *) indexqualorig) > 1)
+ {
+ Index innerrel = innerscan->scan.scanrelid;
+
+ /* only refs to outer vars get changed in the inner qual */
+ innerscan->indexqualorig = fix_join_expr(glob,
+ indexqualorig,
+ outer_itlist,
+ NULL,
+ innerrel,
+ 0);
+ innerscan->indexqual = fix_join_expr(glob,
+ innerscan->indexqual,
+ outer_itlist,
+ NULL,
+ innerrel,
+ 0);
+
+ /*
+ * We must fix the inner qpqual too, if it has join clauses (this
+ * could happen if special operators are involved: some indexquals
+ * may get rechecked as qpquals).
+ */
+ if (NumRelids((Node *) inner_plan->qual) > 1)
+ inner_plan->qual = fix_join_expr(glob,
+ inner_plan->qual,
+ outer_itlist,
+ NULL,
+ innerrel,
+ 0);
+ }
+ }
+ else if (IsA(inner_plan, BitmapIndexScan))
+ {
+ /*
+ * Same, but index is being used within a bitmap plan.
+ */
+ BitmapIndexScan *innerscan = (BitmapIndexScan *) inner_plan;
+ List *indexqualorig = innerscan->indexqualorig;
+
+ /* No work needed if indexqual refers only to its own rel... */
+ if (NumRelids((Node *) indexqualorig) > 1)
+ {
+ Index innerrel = innerscan->scan.scanrelid;
+
+ /* only refs to outer vars get changed in the inner qual */
+ innerscan->indexqualorig = fix_join_expr(glob,
+ indexqualorig,
+ outer_itlist,
+ NULL,
+ innerrel,
+ 0);
+ innerscan->indexqual = fix_join_expr(glob,
+ innerscan->indexqual,
+ outer_itlist,
+ NULL,
+ innerrel,
+ 0);
+ /* no need to fix inner qpqual */
+ Assert(inner_plan->qual == NIL);
+ }
+ }
+ else if (IsA(inner_plan, BitmapHeapScan))
+ {
+ /*
+ * The inner side is a bitmap scan plan. Fix the top node, and
+ * recurse to get the lower nodes.
+ *
+ * Note: create_bitmap_scan_plan removes clauses from bitmapqualorig
+ * if they are duplicated in qpqual, so must test these independently.
+ */
+ BitmapHeapScan *innerscan = (BitmapHeapScan *) inner_plan;
+ Index innerrel = innerscan->scan.scanrelid;
+ List *bitmapqualorig = innerscan->bitmapqualorig;
+
+ /* only refs to outer vars get changed in the inner qual */
+ if (NumRelids((Node *) bitmapqualorig) > 1)
+ innerscan->bitmapqualorig = fix_join_expr(glob,
+ bitmapqualorig,
+ outer_itlist,
+ NULL,
+ innerrel,
+ 0);
+
+ /*
+ * We must fix the inner qpqual too, if it has join clauses (this
+ * could happen if special operators are involved: some indexquals may
+ * get rechecked as qpquals).
+ */
+ if (NumRelids((Node *) inner_plan->qual) > 1)
+ inner_plan->qual = fix_join_expr(glob,
+ inner_plan->qual,
+ outer_itlist,
+ NULL,
+ innerrel,
+ 0);
+
+ /* Now recurse */
+ set_inner_join_references(glob, inner_plan->lefttree, outer_itlist);
+ }
+ else if (IsA(inner_plan, BitmapAnd))
+ {
+ /* All we need do here is recurse */
+ BitmapAnd *innerscan = (BitmapAnd *) inner_plan;
+ ListCell *l;
+
+ foreach(l, innerscan->bitmapplans)
+ {
+ set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
+ }
+ }
+ else if (IsA(inner_plan, BitmapOr))
+ {
+ /* All we need do here is recurse */
+ BitmapOr *innerscan = (BitmapOr *) inner_plan;
+ ListCell *l;
+
+ foreach(l, innerscan->bitmapplans)
+ {
+ set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
+ }
+ }
+ else if (IsA(inner_plan, TidScan))
+ {
+ TidScan *innerscan = (TidScan *) inner_plan;
+ Index innerrel = innerscan->scan.scanrelid;
+
+ innerscan->tidquals = fix_join_expr(glob,
+ innerscan->tidquals,
+ outer_itlist,
+ NULL,
+ innerrel,
+ 0);
+ }
+ else if (IsA(inner_plan, Append))
+ {
+ /*
+ * The inner side is an append plan. Recurse to see if it contains
+ * indexscans that need to be fixed.
+ */
+ Append *appendplan = (Append *) inner_plan;
+ ListCell *l;
+
+ foreach(l, appendplan->appendplans)
+ {
+ set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
+ }
+ }
+ else if (IsA(inner_plan, Result))
+ {
+ /* Recurse through a gating Result node (similar to Append case) */
+ Result *result = (Result *) inner_plan;
+
+ if (result->plan.lefttree)
+ set_inner_join_references(glob, result->plan.lefttree, outer_itlist);
+ }
+}
+
+/*
+ * set_upper_references