Header And Logo

PostgreSQL
| The world's most advanced open source database.

nodeForeignscan.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * nodeForeignscan.c
00004  *    Routines to support scans of foreign tables
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/executor/nodeForeignscan.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 /*
00016  * INTERFACE ROUTINES
00017  *
00018  *      ExecForeignScan         scans a foreign table.
00019  *      ExecInitForeignScan     creates and initializes state info.
00020  *      ExecReScanForeignScan   rescans the foreign relation.
00021  *      ExecEndForeignScan      releases any resources allocated.
00022  */
00023 #include "postgres.h"
00024 
00025 #include "executor/executor.h"
00026 #include "executor/nodeForeignscan.h"
00027 #include "foreign/fdwapi.h"
00028 #include "utils/rel.h"
00029 
00030 static TupleTableSlot *ForeignNext(ForeignScanState *node);
00031 static bool ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot);
00032 
00033 
00034 /* ----------------------------------------------------------------
00035  *      ForeignNext
00036  *
00037  *      This is a workhorse for ExecForeignScan
00038  * ----------------------------------------------------------------
00039  */
00040 static TupleTableSlot *
00041 ForeignNext(ForeignScanState *node)
00042 {
00043     TupleTableSlot *slot;
00044     ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
00045     ExprContext *econtext = node->ss.ps.ps_ExprContext;
00046     MemoryContext oldcontext;
00047 
00048     /* Call the Iterate function in short-lived context */
00049     oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
00050     slot = node->fdwroutine->IterateForeignScan(node);
00051     MemoryContextSwitchTo(oldcontext);
00052 
00053     /*
00054      * If any system columns are requested, we have to force the tuple into
00055      * physical-tuple form to avoid "cannot extract system attribute from
00056      * virtual tuple" errors later.  We also insert a valid value for
00057      * tableoid, which is the only actually-useful system column.
00058      */
00059     if (plan->fsSystemCol && !TupIsNull(slot))
00060     {
00061         HeapTuple   tup = ExecMaterializeSlot(slot);
00062 
00063         tup->t_tableOid = RelationGetRelid(node->ss.ss_currentRelation);
00064     }
00065 
00066     return slot;
00067 }
00068 
00069 /*
00070  * ForeignRecheck -- access method routine to recheck a tuple in EvalPlanQual
00071  */
00072 static bool
00073 ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
00074 {
00075     /* There are no access-method-specific conditions to recheck. */
00076     return true;
00077 }
00078 
00079 /* ----------------------------------------------------------------
00080  *      ExecForeignScan(node)
00081  *
00082  *      Fetches the next tuple from the FDW, checks local quals, and
00083  *      returns it.
00084  *      We call the ExecScan() routine and pass it the appropriate
00085  *      access method functions.
00086  * ----------------------------------------------------------------
00087  */
00088 TupleTableSlot *
00089 ExecForeignScan(ForeignScanState *node)
00090 {
00091     return ExecScan((ScanState *) node,
00092                     (ExecScanAccessMtd) ForeignNext,
00093                     (ExecScanRecheckMtd) ForeignRecheck);
00094 }
00095 
00096 
00097 /* ----------------------------------------------------------------
00098  *      ExecInitForeignScan
00099  * ----------------------------------------------------------------
00100  */
00101 ForeignScanState *
00102 ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
00103 {
00104     ForeignScanState *scanstate;
00105     Relation    currentRelation;
00106     FdwRoutine *fdwroutine;
00107 
00108     /* check for unsupported flags */
00109     Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
00110 
00111     /*
00112      * create state structure
00113      */
00114     scanstate = makeNode(ForeignScanState);
00115     scanstate->ss.ps.plan = (Plan *) node;
00116     scanstate->ss.ps.state = estate;
00117 
00118     /*
00119      * Miscellaneous initialization
00120      *
00121      * create expression context for node
00122      */
00123     ExecAssignExprContext(estate, &scanstate->ss.ps);
00124 
00125     scanstate->ss.ps.ps_TupFromTlist = false;
00126 
00127     /*
00128      * initialize child expressions
00129      */
00130     scanstate->ss.ps.targetlist = (List *)
00131         ExecInitExpr((Expr *) node->scan.plan.targetlist,
00132                      (PlanState *) scanstate);
00133     scanstate->ss.ps.qual = (List *)
00134         ExecInitExpr((Expr *) node->scan.plan.qual,
00135                      (PlanState *) scanstate);
00136 
00137     /*
00138      * tuple table initialization
00139      */
00140     ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
00141     ExecInitScanTupleSlot(estate, &scanstate->ss);
00142 
00143     /*
00144      * open the base relation and acquire appropriate lock on it.
00145      */
00146     currentRelation = ExecOpenScanRelation(estate, node->scan.scanrelid, eflags);
00147     scanstate->ss.ss_currentRelation = currentRelation;
00148 
00149     /*
00150      * get the scan type from the relation descriptor.  (XXX at some point we
00151      * might want to let the FDW editorialize on the scan tupdesc.)
00152      */
00153     ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation));
00154 
00155     /*
00156      * Initialize result tuple type and projection info.
00157      */
00158     ExecAssignResultTypeFromTL(&scanstate->ss.ps);
00159     ExecAssignScanProjectionInfo(&scanstate->ss);
00160 
00161     /*
00162      * Acquire function pointers from the FDW's handler, and init fdw_state.
00163      */
00164     fdwroutine = GetFdwRoutineForRelation(currentRelation, true);
00165     scanstate->fdwroutine = fdwroutine;
00166     scanstate->fdw_state = NULL;
00167 
00168     /*
00169      * Tell the FDW to initiate the scan.
00170      */
00171     fdwroutine->BeginForeignScan(scanstate, eflags);
00172 
00173     return scanstate;
00174 }
00175 
00176 /* ----------------------------------------------------------------
00177  *      ExecEndForeignScan
00178  *
00179  *      frees any storage allocated through C routines.
00180  * ----------------------------------------------------------------
00181  */
00182 void
00183 ExecEndForeignScan(ForeignScanState *node)
00184 {
00185     /* Let the FDW shut down */
00186     node->fdwroutine->EndForeignScan(node);
00187 
00188     /* Free the exprcontext */
00189     ExecFreeExprContext(&node->ss.ps);
00190 
00191     /* clean out the tuple table */
00192     ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
00193     ExecClearTuple(node->ss.ss_ScanTupleSlot);
00194 
00195     /* close the relation. */
00196     ExecCloseScanRelation(node->ss.ss_currentRelation);
00197 }
00198 
00199 /* ----------------------------------------------------------------
00200  *      ExecReScanForeignScan
00201  *
00202  *      Rescans the relation.
00203  * ----------------------------------------------------------------
00204  */
00205 void
00206 ExecReScanForeignScan(ForeignScanState *node)
00207 {
00208     node->fdwroutine->ReScanForeignScan(node);
00209 
00210     ExecScanReScan(&node->ss);
00211 }