aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/Makefile2
-rw-r--r--src/backend/executor/execAmi.c5
-rw-r--r--src/backend/executor/execMain.c7
-rw-r--r--src/backend/executor/execProcnode.c14
-rw-r--r--src/backend/executor/nodeForeignscan.c209
5 files changed, 236 insertions, 1 deletions
diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile
index da4fbb440bc..a854c9a5dc6 100644
--- a/src/backend/executor/Makefile
+++ b/src/backend/executor/Makefile
@@ -23,6 +23,6 @@ OBJS = execAmi.o execCurrent.o execGrouping.o execJunk.o execMain.o \
nodeSeqscan.o nodeSetOp.o nodeSort.o nodeUnique.o \
nodeValuesscan.o nodeCtescan.o nodeWorktablescan.o \
nodeGroup.o nodeSubplan.o nodeSubqueryscan.o nodeTidscan.o \
- nodeWindowAgg.o tstoreReceiver.o spi.o
+ nodeForeignscan.o nodeWindowAgg.o tstoreReceiver.o spi.o
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index 6bdc60c352d..01775ce4494 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -21,6 +21,7 @@
#include "executor/nodeBitmapIndexscan.h"
#include "executor/nodeBitmapOr.h"
#include "executor/nodeCtescan.h"
+#include "executor/nodeForeignscan.h"
#include "executor/nodeFunctionscan.h"
#include "executor/nodeGroup.h"
#include "executor/nodeGroup.h"
@@ -186,6 +187,10 @@ ExecReScan(PlanState *node)
ExecReScanWorkTableScan((WorkTableScanState *) node);
break;
+ case T_ForeignScanState:
+ ExecReScanForeignScan((ForeignScanState *) node);
+ break;
+
case T_NestLoopState:
ExecReScanNestLoop((NestLoopState *) node);
break;
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 7df7f5cdf0d..68509fbfc6e 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -738,6 +738,13 @@ InitPlan(QueryDesc *queryDesc, int eflags)
break;
}
+ /* if foreign table, tuples can't be locked */
+ if (relation && relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("SELECT FOR UPDATE/SHARE cannot be used with foreign table \"%s\"",
+ RelationGetRelationName(relation))));
+
erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
erm->relation = relation;
erm->rti = rc->rti;
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index e8ebec12343..17788761d7f 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -85,6 +85,7 @@
#include "executor/nodeBitmapIndexscan.h"
#include "executor/nodeBitmapOr.h"
#include "executor/nodeCtescan.h"
+#include "executor/nodeForeignscan.h"
#include "executor/nodeFunctionscan.h"
#include "executor/nodeGroup.h"
#include "executor/nodeHash.h"
@@ -232,6 +233,11 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
estate, eflags);
break;
+ case T_ForeignScan:
+ result = (PlanState *) ExecInitForeignScan((ForeignScan *) node,
+ estate, eflags);
+ break;
+
/*
* join nodes
*/
@@ -422,6 +428,10 @@ ExecProcNode(PlanState *node)
result = ExecWorkTableScan((WorkTableScanState *) node);
break;
+ case T_ForeignScanState:
+ result = ExecForeignScan((ForeignScanState *) node);
+ break;
+
/*
* join nodes
*/
@@ -650,6 +660,10 @@ ExecEndNode(PlanState *node)
ExecEndWorkTableScan((WorkTableScanState *) node);
break;
+ case T_ForeignScanState:
+ ExecEndForeignScan((ForeignScanState *) node);
+ break;
+
/*
* join nodes
*/
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
new file mode 100644
index 00000000000..c4309a981e2
--- /dev/null
+++ b/src/backend/executor/nodeForeignscan.c
@@ -0,0 +1,209 @@
+/*-------------------------------------------------------------------------
+ *
+ * nodeForeignscan.c
+ * Routines to support scans of foreign tables
+ *
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/executor/nodeForeignscan.c
+ *
+ *-------------------------------------------------------------------------
+ */
+/*
+ * INTERFACE ROUTINES
+ *
+ * ExecForeignScan scans a foreign table.
+ * ExecInitForeignScan creates and initializes state info.
+ * ExecReScanForeignScan rescans the foreign relation.
+ * ExecEndForeignScan releases any resources allocated.
+ */
+#include "postgres.h"
+
+#include "executor/executor.h"
+#include "executor/nodeForeignscan.h"
+#include "foreign/fdwapi.h"
+
+static TupleTableSlot *ForeignNext(ForeignScanState *node);
+static bool ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot);
+
+
+/* ----------------------------------------------------------------
+ * ForeignNext
+ *
+ * This is a workhorse for ExecForeignScan
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+ForeignNext(ForeignScanState *node)
+{
+ TupleTableSlot *slot;
+ ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
+ ExprContext *econtext = node->ss.ps.ps_ExprContext;
+ MemoryContext oldcontext;
+
+ /* Call the Iterate function in short-lived context */
+ oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
+ slot = node->fdwroutine->IterateForeignScan(node);
+ MemoryContextSwitchTo(oldcontext);
+
+ /*
+ * If any system columns are requested, we have to force the tuple into
+ * physical-tuple form to avoid "cannot extract system attribute from
+ * virtual tuple" errors later. We also insert a valid value for
+ * tableoid, which is the only actually-useful system column.
+ */
+ if (plan->fsSystemCol && !TupIsNull(slot))
+ {
+ HeapTuple tup = ExecMaterializeSlot(slot);
+
+ tup->t_tableOid = RelationGetRelid(node->ss.ss_currentRelation);
+ }
+
+ return slot;
+}
+
+/*
+ * ForeignRecheck -- access method routine to recheck a tuple in EvalPlanQual
+ */
+static bool
+ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
+{
+ /* There are no access-method-specific conditions to recheck. */
+ return true;
+}
+
+/* ----------------------------------------------------------------
+ * ExecForeignScan(node)
+ *
+ * Fetches the next tuple from the FDW, checks local quals, and
+ * returns it.
+ * We call the ExecScan() routine and pass it the appropriate
+ * access method functions.
+ * ----------------------------------------------------------------
+ */
+TupleTableSlot *
+ExecForeignScan(ForeignScanState *node)
+{
+ return ExecScan((ScanState *) node,
+ (ExecScanAccessMtd) ForeignNext,
+ (ExecScanRecheckMtd) ForeignRecheck);
+}
+
+
+/* ----------------------------------------------------------------
+ * ExecInitForeignScan
+ * ----------------------------------------------------------------
+ */
+ForeignScanState *
+ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
+{
+ ForeignScanState *scanstate;
+ Relation currentRelation;
+ FdwRoutine *fdwroutine;
+
+ /* check for unsupported flags */
+ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
+
+ /*
+ * create state structure
+ */
+ scanstate = makeNode(ForeignScanState);
+ scanstate->ss.ps.plan = (Plan *) node;
+ scanstate->ss.ps.state = estate;
+
+ /*
+ * Miscellaneous initialization
+ *
+ * create expression context for node
+ */
+ ExecAssignExprContext(estate, &scanstate->ss.ps);
+
+ scanstate->ss.ps.ps_TupFromTlist = false;
+
+ /*
+ * initialize child expressions
+ */
+ scanstate->ss.ps.targetlist = (List *)
+ ExecInitExpr((Expr *) node->scan.plan.targetlist,
+ (PlanState *) scanstate);
+ scanstate->ss.ps.qual = (List *)
+ ExecInitExpr((Expr *) node->scan.plan.qual,
+ (PlanState *) scanstate);
+
+ /*
+ * tuple table initialization
+ */
+ ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
+ ExecInitScanTupleSlot(estate, &scanstate->ss);
+
+ /*
+ * open the base relation and acquire appropriate lock on it.
+ */
+ currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid);
+ scanstate->ss.ss_currentRelation = currentRelation;
+
+ /*
+ * get the scan type from the relation descriptor.
+ */
+ ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation));
+
+ /*
+ * Initialize result tuple type and projection info.
+ */
+ ExecAssignResultTypeFromTL(&scanstate->ss.ps);
+ ExecAssignScanProjectionInfo(&scanstate->ss);
+
+ /*
+ * Acquire function pointers from the FDW's handler, and init fdw_state.
+ */
+ fdwroutine = GetFdwRoutineByRelId(RelationGetRelid(currentRelation));
+ scanstate->fdwroutine = fdwroutine;
+ scanstate->fdw_state = NULL;
+
+ /*
+ * Tell the FDW to initiate the scan.
+ */
+ fdwroutine->BeginForeignScan(scanstate, eflags);
+
+ return scanstate;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEndForeignScan
+ *
+ * frees any storage allocated through C routines.
+ * ----------------------------------------------------------------
+ */
+void
+ExecEndForeignScan(ForeignScanState *node)
+{
+ /* Let the FDW shut down */
+ node->fdwroutine->EndForeignScan(node);
+
+ /* Free the exprcontext */
+ ExecFreeExprContext(&node->ss.ps);
+
+ /* clean out the tuple table */
+ ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
+ ExecClearTuple(node->ss.ss_ScanTupleSlot);
+
+ /* close the relation. */
+ ExecCloseScanRelation(node->ss.ss_currentRelation);
+}
+
+/* ----------------------------------------------------------------
+ * ExecReScanForeignScan
+ *
+ * Rescans the relation.
+ * ----------------------------------------------------------------
+ */
+void
+ExecReScanForeignScan(ForeignScanState *node)
+{
+ node->fdwroutine->ReScanForeignScan(node);
+
+ ExecScanReScan(&node->ss);
+}