 src/backend/commands/explain.c          | 10 ++++--
 src/backend/nodes/bitmapset.c           | 57 +++++++++++++++++++++++++++++++++
 src/backend/nodes/copyfuncs.c           |  2 ++
 src/backend/nodes/outfuncs.c            |  2 ++
 src/backend/optimizer/plan/createplan.c |  4 +++
 src/backend/optimizer/plan/setrefs.c    |  8 +++++
 src/include/nodes/bitmapset.h           |  1 +
 src/include/nodes/plannodes.h           |  4 +++
 8 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 9281874..8892dca 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -730,11 +730,17 @@ ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
 		case T_ValuesScan:
 		case T_CteScan:
 		case T_WorkTableScan:
-		case T_ForeignScan:
-		case T_CustomScan:
 			*rels_used = bms_add_member(*rels_used,
 										((Scan *) plan)->scanrelid);
 			break;
+		case T_ForeignScan:
+			*rels_used = bms_add_members(*rels_used,
+										 ((ForeignScan *) plan)->fdw_relids);
+			break;
+		case T_CustomScan:
+			*rels_used = bms_add_members(*rels_used,
+										 ((CustomScan *) plan)->custom_relids);
+			break;
 		case T_ModifyTable:
 			*rels_used = bms_add_member(*rels_used,
 									((ModifyTable *) plan)->nominalRelation);
diff --git a/src/backend/nodes/bitmapset.c b/src/backend/nodes/bitmapset.c
index a9c3b4b..4dc3286 100644
--- a/src/backend/nodes/bitmapset.c
+++ b/src/backend/nodes/bitmapset.c
@@ -301,6 +301,63 @@ bms_difference(const Bitmapset *a, const Bitmapset *b)
 }
 
 /*
+ * bms_shift_members - move all the bits by shift
+ */
+Bitmapset *
+bms_shift_members(const Bitmapset *a, int shift)
+{
+	Bitmapset  *b;
+	bitmapword	h_word;
+	bitmapword	l_word;
+	int			nwords;
+	int			w_shift;
+	int			b_shift;
+	int			i, j;
+
+	/* fast path if result shall be NULL obviously */
+	if (a == NULL || a->nwords * BITS_PER_BITMAPWORD + shift <= 0)
+		return NULL;
+	/* actually, not shift members */
+	if (shift == 0)
+		return bms_copy(a);
+
+	nwords = (a->nwords * BITS_PER_BITMAPWORD + shift +
+			  BITS_PER_BITMAPWORD - 1) / BITS_PER_BITMAPWORD;
+	b = palloc(BITMAPSET_SIZE(nwords));
+	b->nwords = nwords;
+
+	if (shift > 0)
+	{
+		/* Left shift */
+		w_shift = WORDNUM(shift);
+		b_shift = BITNUM(shift);
+
+		for (i=0, j=-w_shift; i < b->nwords; i++, j++)
+		{
+			h_word = (j >= 0   && j   < a->nwords ? a->words[j] : 0);
+			l_word = (j-1 >= 0 && j-1 < a->nwords ? a->words[j-1] : 0);
+			b->words[i] = ((h_word << b_shift) |
+						   (l_word >> (BITS_PER_BITMAPWORD - b_shift)));
+		}
+	}
+	else
+	{
+		/* Right shift */
+		w_shift = WORDNUM(-shift);
+		b_shift = BITNUM(-shift);
+
+		for (i=0, j=-w_shift; i < b->nwords; i++, j++)
+		{
+			h_word = (j+1 >= 0 && j+1 < a->nwords ? a->words[j+1] : 0);
+			l_word = (j >= 0 && j < a->nwords ? a->words[j] : 0);
+			b->words[i] = ((h_word >> (BITS_PER_BITMAPWORD - b_shift)) |
+						   (l_word << b_shift));
+		}
+	}
+	return b;
+}
+
+/*
  * bms_is_subset - is A a subset of B?
  */
 bool
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 9300b70..7c85943 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -596,6 +596,7 @@ _copyForeignScan(const ForeignScan *from)
 	COPY_NODE_FIELD(fdw_exprs);
 	COPY_NODE_FIELD(fdw_ps_tlist);
 	COPY_NODE_FIELD(fdw_private);
+	COPY_BITMAPSET_FIELD(fdw_relids);
 	COPY_SCALAR_FIELD(fsSystemCol);
 
 	return newnode;
@@ -621,6 +622,7 @@ _copyCustomScan(const CustomScan *from)
 	COPY_NODE_FIELD(custom_exprs);
 	COPY_NODE_FIELD(custom_ps_tlist);
 	COPY_NODE_FIELD(custom_private);
+	COPY_BITMAPSET_FIELD(custom_relids);
 
 	/*
 	 * NOTE: The method field of CustomScan is required to be a pointer to a
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index f3676ec..edeee7e 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -562,6 +562,7 @@ _outForeignScan(StringInfo str, const ForeignScan *node)
 	WRITE_NODE_FIELD(fdw_exprs);
 	WRITE_NODE_FIELD(fdw_ps_tlist);
 	WRITE_NODE_FIELD(fdw_private);
+	WRITE_BITMAPSET_FIELD(fdw_relids);
 	WRITE_BOOL_FIELD(fsSystemCol);
 }
 
@@ -576,6 +577,7 @@ _outCustomScan(StringInfo str, const CustomScan *node)
 	WRITE_NODE_FIELD(custom_exprs);
 	WRITE_NODE_FIELD(custom_ps_tlist);
 	WRITE_NODE_FIELD(custom_private);
+	WRITE_BITMAPSET_FIELD(custom_relids);
 	appendStringInfoString(str, " :methods ");
 	_outToken(str, node->methods->CustomName);
 	if (node->methods->TextOutCustomScan)
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 7a37824..514fcd9 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -2013,6 +2013,8 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path,
 				elog(ERROR, "junk TLE should not apper prior to valid one");
 		}
 	}
+	/* Set the relids that are represented by this foreign scan for Explain */
+	scan_plan->fdw_relids = best_path->path.parent->relids;
 
 	/* Copy cost data from Path to Plan; no need to make FDW do this */
 	copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
@@ -2119,6 +2121,8 @@ create_customscan_plan(PlannerInfo *root, CustomPath *best_path,
 				elog(ERROR, "junk TLE should not apper prior to valid one");
 		}
 	}
+	/* Set the relids that are represented by this custom scan for Explain */
+	cplan->custom_relids = best_path->path.parent->relids;
 
 	/*
 	 * Copy cost data from Path to Plan; no need to make custom-plan providers
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index a41c4f0..2961f44 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -568,6 +568,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 			{
 				ForeignScan *splan = (ForeignScan *) plan;
 
+				if (rtoffset > 0)
+					splan->fdw_relids =
+						bms_shift_members(splan->fdw_relids, rtoffset);
+
 				if (splan->scan.scanrelid == 0)
 				{
 					indexed_tlist *pscan_itlist =
@@ -610,6 +614,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
 			{
 				CustomScan *splan = (CustomScan *) plan;
 
+				if (rtoffset > 0)
+					splan->custom_relids =
+						bms_shift_members(splan->custom_relids, rtoffset);
+
 				if (splan->scan.scanrelid == 0)
 				{
 					indexed_tlist *pscan_itlist =
diff --git a/src/include/nodes/bitmapset.h b/src/include/nodes/bitmapset.h
index 3a556ee..3ca9791 100644
--- a/src/include/nodes/bitmapset.h
+++ b/src/include/nodes/bitmapset.h
@@ -66,6 +66,7 @@ extern void bms_free(Bitmapset *a);
 extern Bitmapset *bms_union(const Bitmapset *a, const Bitmapset *b);
 extern Bitmapset *bms_intersect(const Bitmapset *a, const Bitmapset *b);
 extern Bitmapset *bms_difference(const Bitmapset *a, const Bitmapset *b);
+extern Bitmapset *bms_shift_members(const Bitmapset *a, int shift);
 extern bool bms_is_subset(const Bitmapset *a, const Bitmapset *b);
 extern BMS_Comparison bms_subset_compare(const Bitmapset *a, const Bitmapset *b);
 extern bool bms_is_member(int x, const Bitmapset *a);
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 213034b..0f1e94c 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -490,6 +490,8 @@ typedef struct ForeignScan
 	List	   *fdw_exprs;		/* expressions that FDW may evaluate */
 	List	   *fdw_ps_tlist;	/* optional pseudo-scan tlist for FDW */
 	List	   *fdw_private;	/* private data for FDW */
+	Bitmapset  *fdw_relids;		/* set of relid (index of range-tables)
+								 * represented by this node */
 	bool		fsSystemCol;	/* true if any "system column" is needed */
 } ForeignScan;
 
@@ -523,6 +525,8 @@ typedef struct CustomScan
 	List	   *custom_exprs;	/* expressions that custom code may evaluate */
 	List	   *custom_ps_tlist;/* optional pseudo-scan target list */
 	List	   *custom_private; /* private data for custom code */
+	Bitmapset  *custom_relids;	/* set of relid (index of range-tables)
+								 * represented by this node */
 	const CustomScanMethods *methods;
 } CustomScan;
 
