aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execScan.c23
-rw-r--r--src/backend/executor/nodeCustom.c55
-rw-r--r--src/backend/executor/nodeForeignscan.c41
-rw-r--r--src/backend/executor/nodeIndexonlyscan.c6
4 files changed, 82 insertions, 43 deletions
diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c
index fa475014f13..a96e826ba42 100644
--- a/src/backend/executor/execScan.c
+++ b/src/backend/executor/execScan.c
@@ -246,19 +246,18 @@ void
ExecAssignScanProjectionInfo(ScanState *node)
{
Scan *scan = (Scan *) node->ps.plan;
- Index varno;
- /* Vars in an index-only scan's tlist should be INDEX_VAR */
- if (IsA(scan, IndexOnlyScan))
- varno = INDEX_VAR;
- /* Also foreign or custom scan on pseudo relation should be INDEX_VAR */
- else if (scan->scanrelid == 0)
- {
- Assert(IsA(scan, ForeignScan) || IsA(scan, CustomScan));
- varno = INDEX_VAR;
- }
- else
- varno = scan->scanrelid;
+ ExecAssignScanProjectionInfoWithVarno(node, scan->scanrelid);
+}
+
+/*
+ * ExecAssignScanProjectionInfoWithVarno
+ * As above, but caller can specify varno expected in Vars in the tlist.
+ */
+void
+ExecAssignScanProjectionInfoWithVarno(ScanState *node, Index varno)
+{
+ Scan *scan = (Scan *) node->ps.plan;
if (tlist_matches_tupdesc(&node->ps,
scan->plan.targetlist,
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index db1b4f2ffa4..0a022dff940 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -22,13 +22,24 @@
CustomScanState *
ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
{
- CustomScanState *css;
- Index scan_relid = cscan->scan.scanrelid;
+ CustomScanState *css;
+ Relation scan_rel = NULL;
+ Index scanrelid = cscan->scan.scanrelid;
+ Index tlistvarno;
- /* populate a CustomScanState according to the CustomScan */
+ /*
+ * Allocate the CustomScanState object. We let the custom scan provider
+ * do the palloc, in case it wants to make a larger object that embeds
+ * CustomScanState as the first field. It must set the node tag and the
+ * methods field correctly at this time. Other standard fields should be
+ * set to zero.
+ */
css = (CustomScanState *) cscan->methods->CreateCustomScanState(cscan);
Assert(IsA(css, CustomScanState));
+ /* ensure flags is filled correctly */
+ css->flags = cscan->flags;
+
/* fill up fields of ScanState */
css->ss.ps.plan = &cscan->scan.plan;
css->ss.ps.state = estate;
@@ -36,6 +47,8 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
/* create expression context for node */
ExecAssignExprContext(estate, &css->ss.ps);
+ css->ss.ps.ps_TupFromTlist = false;
+
/* initialize child expressions */
css->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) cscan->scan.plan.targetlist,
@@ -49,32 +62,40 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
ExecInitResultTupleSlot(estate, &css->ss.ps);
/*
- * open the base relation and acquire an appropriate lock on it;
- * also, get and assign the scan type
+ * open the base relation, if any, and acquire an appropriate lock on it
*/
- if (scan_relid > 0)
+ if (scanrelid > 0)
{
- Relation scan_rel;
-
- scan_rel = ExecOpenScanRelation(estate, scan_relid, eflags);
+ scan_rel = ExecOpenScanRelation(estate, scanrelid, eflags);
css->ss.ss_currentRelation = scan_rel;
- css->ss.ss_currentScanDesc = NULL; /* set by provider */
- ExecAssignScanType(&css->ss, RelationGetDescr(scan_rel));
}
- else
+
+ /*
+ * Determine the scan tuple type. If the custom scan provider provided a
+ * targetlist describing the scan tuples, use that; else use base
+ * relation's rowtype.
+ */
+ if (cscan->custom_scan_tlist != NIL || scan_rel == NULL)
{
- TupleDesc ps_tupdesc;
+ TupleDesc scan_tupdesc;
- ps_tupdesc = ExecCleanTypeFromTL(cscan->custom_ps_tlist, false);
- ExecAssignScanType(&css->ss, ps_tupdesc);
+ scan_tupdesc = ExecTypeFromTL(cscan->custom_scan_tlist, false);
+ ExecAssignScanType(&css->ss, scan_tupdesc);
+ /* Node's targetlist will contain Vars with varno = INDEX_VAR */
+ tlistvarno = INDEX_VAR;
+ }
+ else
+ {
+ ExecAssignScanType(&css->ss, RelationGetDescr(scan_rel));
+ /* Node's targetlist will contain Vars with varno = scanrelid */
+ tlistvarno = scanrelid;
}
- css->ss.ps.ps_TupFromTlist = false;
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&css->ss.ps);
- ExecAssignScanProjectionInfo(&css->ss);
+ ExecAssignScanProjectionInfoWithVarno(&css->ss, tlistvarno);
/*
* The callback of custom-scan provider applies the final initialization
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index fa553ace5d6..bb28a7372d1 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -102,7 +102,9 @@ ForeignScanState *
ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
{
ForeignScanState *scanstate;
+ Relation currentRelation = NULL;
Index scanrelid = node->scan.scanrelid;
+ Index tlistvarno;
FdwRoutine *fdwroutine;
/* check for unsupported flags */
@@ -141,40 +143,55 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
ExecInitScanTupleSlot(estate, &scanstate->ss);
/*
- * open the base relation and acquire an appropriate lock on it;
- * also, get and assign the scan type
+ * open the base relation, if any, and acquire an appropriate lock on it;
+ * also acquire function pointers from the FDW's handler
*/
if (scanrelid > 0)
{
- Relation currentRelation;
-
currentRelation = ExecOpenScanRelation(estate, scanrelid, eflags);
scanstate->ss.ss_currentRelation = currentRelation;
- ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation));
+ fdwroutine = GetFdwRoutineForRelation(currentRelation, true);
}
else
{
- TupleDesc ps_tupdesc;
+ /* We can't use the relcache, so get fdwroutine the hard way */
+ fdwroutine = GetFdwRoutineByServerId(node->fs_server);
+ }
- ps_tupdesc = ExecCleanTypeFromTL(node->fdw_ps_tlist, false);
- ExecAssignScanType(&scanstate->ss, ps_tupdesc);
+ /*
+ * Determine the scan tuple type. If the FDW provided a targetlist
+ * describing the scan tuples, use that; else use base relation's rowtype.
+ */
+ if (node->fdw_scan_tlist != NIL || currentRelation == NULL)
+ {
+ TupleDesc scan_tupdesc;
+
+ scan_tupdesc = ExecTypeFromTL(node->fdw_scan_tlist, false);
+ ExecAssignScanType(&scanstate->ss, scan_tupdesc);
+ /* Node's targetlist will contain Vars with varno = INDEX_VAR */
+ tlistvarno = INDEX_VAR;
+ }
+ else
+ {
+ ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation));
+ /* Node's targetlist will contain Vars with varno = scanrelid */
+ tlistvarno = scanrelid;
}
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&scanstate->ss.ps);
- ExecAssignScanProjectionInfo(&scanstate->ss);
+ ExecAssignScanProjectionInfoWithVarno(&scanstate->ss, tlistvarno);
/*
- * Acquire function pointers from the FDW's handler, and init fdw_state.
+ * Initialize FDW-related state.
*/
- fdwroutine = GetFdwRoutine(node->fdw_handler);
scanstate->fdwroutine = fdwroutine;
scanstate->fdw_state = NULL;
/*
- * Tell the FDW to initiate the scan.
+ * Tell the FDW to initialize the scan.
*/
fdwroutine->BeginForeignScan(scanstate, eflags);
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 06b7c3c457a..61bd644ab71 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -442,10 +442,12 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
ExecAssignScanType(&indexstate->ss, tupDesc);
/*
- * Initialize result tuple type and projection info.
+ * Initialize result tuple type and projection info. The node's
+ * targetlist will contain Vars with varno = INDEX_VAR, referencing the
+ * scan tuple.
*/
ExecAssignResultTypeFromTL(&indexstate->ss.ps);
- ExecAssignScanProjectionInfo(&indexstate->ss);
+ ExecAssignScanProjectionInfoWithVarno(&indexstate->ss, INDEX_VAR);
/*
* If we are just doing EXPLAIN (ie, aren't going to run the plan), stop