diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/Makefile | 2 | ||||
-rw-r--r-- | src/backend/executor/execAmi.c | 5 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 7 | ||||
-rw-r--r-- | src/backend/executor/execProcnode.c | 14 | ||||
-rw-r--r-- | src/backend/executor/nodeForeignscan.c | 209 |
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); +} |