mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Implement an API to let foreign-data wrappers actually be functional.
This commit provides the core code and documentation needed. A contrib module test case will follow shortly. Shigeru Hanada, Jan Urbanski, Heikki Linnakangas
This commit is contained in:
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
209
src/backend/executor/nodeForeignscan.c
Normal file
209
src/backend/executor/nodeForeignscan.c
Normal file
@ -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);
|
||||
}
|
Reference in New Issue
Block a user