1 /*-------------------------------------------------------------------------
4 * Routines to support scans of foreign tables
6 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/executor/nodeForeignscan.c
13 *-------------------------------------------------------------------------
18 * ExecForeignScan scans a foreign table.
19 * ExecInitForeignScan creates and initializes state info.
20 * ExecReScanForeignScan rescans the foreign relation.
21 * ExecEndForeignScan releases any resources allocated.
25 #include "executor/executor.h"
26 #include "executor/nodeForeignscan.h"
27 #include "foreign/fdwapi.h"
28 #include "utils/memutils.h"
29 #include "utils/rel.h"
31 static TupleTableSlot *ForeignNext(ForeignScanState *node);
32 static bool ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot);
35 /* ----------------------------------------------------------------
38 * This is a workhorse for ExecForeignScan
39 * ----------------------------------------------------------------
41 static TupleTableSlot *
42 ForeignNext(ForeignScanState *node)
45 ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
46 ExprContext *econtext = node->ss.ps.ps_ExprContext;
47 MemoryContext oldcontext;
49 /* Call the Iterate function in short-lived context */
50 oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
51 slot = node->fdwroutine->IterateForeignScan(node);
52 MemoryContextSwitchTo(oldcontext);
55 * If any system columns are requested, we have to force the tuple into
56 * physical-tuple form to avoid "cannot extract system attribute from
57 * virtual tuple" errors later. We also insert a valid value for
58 * tableoid, which is the only actually-useful system column.
60 if (plan->fsSystemCol && !TupIsNull(slot))
62 HeapTuple tup = ExecMaterializeSlot(slot);
64 tup->t_tableOid = RelationGetRelid(node->ss.ss_currentRelation);
71 * ForeignRecheck -- access method routine to recheck a tuple in EvalPlanQual
74 ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
76 FdwRoutine *fdwroutine = node->fdwroutine;
77 ExprContext *econtext;
80 * extract necessary information from foreign scan node
82 econtext = node->ss.ps.ps_ExprContext;
84 /* Does the tuple meet the remote qual condition? */
85 econtext->ecxt_scantuple = slot;
87 ResetExprContext(econtext);
90 * If an outer join is pushed down, RecheckForeignScan may need to store a
91 * different tuple in the slot, because a different set of columns may go
92 * to NULL upon recheck. Otherwise, it shouldn't need to change the slot
93 * contents, just return true or false to indicate whether the quals still
94 * pass. For simple cases, setting fdw_recheck_quals may be easier than
95 * providing this callback.
97 if (fdwroutine->RecheckForeignScan &&
98 !fdwroutine->RecheckForeignScan(node, slot))
101 return ExecQual(node->fdw_recheck_quals, econtext, false);
104 /* ----------------------------------------------------------------
105 * ExecForeignScan(node)
107 * Fetches the next tuple from the FDW, checks local quals, and
109 * We call the ExecScan() routine and pass it the appropriate
110 * access method functions.
111 * ----------------------------------------------------------------
114 ExecForeignScan(ForeignScanState *node)
116 return ExecScan((ScanState *) node,
117 (ExecScanAccessMtd) ForeignNext,
118 (ExecScanRecheckMtd) ForeignRecheck);
122 /* ----------------------------------------------------------------
123 * ExecInitForeignScan
124 * ----------------------------------------------------------------
127 ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
129 ForeignScanState *scanstate;
130 Relation currentRelation = NULL;
131 Index scanrelid = node->scan.scanrelid;
133 FdwRoutine *fdwroutine;
135 /* check for unsupported flags */
136 Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
139 * create state structure
141 scanstate = makeNode(ForeignScanState);
142 scanstate->ss.ps.plan = (Plan *) node;
143 scanstate->ss.ps.state = estate;
146 * Miscellaneous initialization
148 * create expression context for node
150 ExecAssignExprContext(estate, &scanstate->ss.ps);
152 scanstate->ss.ps.ps_TupFromTlist = false;
155 * initialize child expressions
157 scanstate->ss.ps.targetlist = (List *)
158 ExecInitExpr((Expr *) node->scan.plan.targetlist,
159 (PlanState *) scanstate);
160 scanstate->ss.ps.qual = (List *)
161 ExecInitExpr((Expr *) node->scan.plan.qual,
162 (PlanState *) scanstate);
163 scanstate->fdw_recheck_quals = (List *)
164 ExecInitExpr((Expr *) node->fdw_recheck_quals,
165 (PlanState *) scanstate);
168 * tuple table initialization
170 ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
171 ExecInitScanTupleSlot(estate, &scanstate->ss);
174 * open the base relation, if any, and acquire an appropriate lock on it;
175 * also acquire function pointers from the FDW's handler
179 currentRelation = ExecOpenScanRelation(estate, scanrelid, eflags);
180 scanstate->ss.ss_currentRelation = currentRelation;
181 fdwroutine = GetFdwRoutineForRelation(currentRelation, true);
185 /* We can't use the relcache, so get fdwroutine the hard way */
186 fdwroutine = GetFdwRoutineByServerId(node->fs_server);
190 * Determine the scan tuple type. If the FDW provided a targetlist
191 * describing the scan tuples, use that; else use base relation's rowtype.
193 if (node->fdw_scan_tlist != NIL || currentRelation == NULL)
195 TupleDesc scan_tupdesc;
197 scan_tupdesc = ExecTypeFromTL(node->fdw_scan_tlist, false);
198 ExecAssignScanType(&scanstate->ss, scan_tupdesc);
199 /* Node's targetlist will contain Vars with varno = INDEX_VAR */
200 tlistvarno = INDEX_VAR;
204 ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation));
205 /* Node's targetlist will contain Vars with varno = scanrelid */
206 tlistvarno = scanrelid;
210 * Initialize result tuple type and projection info.
212 ExecAssignResultTypeFromTL(&scanstate->ss.ps);
213 ExecAssignScanProjectionInfoWithVarno(&scanstate->ss, tlistvarno);
216 * Initialize FDW-related state.
218 scanstate->fdwroutine = fdwroutine;
219 scanstate->fdw_state = NULL;
221 /* Initialize any outer plan. */
223 outerPlanState(scanstate) =
224 ExecInitNode(outerPlan(node), estate, eflags);
227 * Tell the FDW to initialize the scan.
229 fdwroutine->BeginForeignScan(scanstate, eflags);
234 /* ----------------------------------------------------------------
237 * frees any storage allocated through C routines.
238 * ----------------------------------------------------------------
241 ExecEndForeignScan(ForeignScanState *node)
243 /* Let the FDW shut down */
244 node->fdwroutine->EndForeignScan(node);
246 /* Shut down any outer plan. */
247 if (outerPlanState(node))
248 ExecEndNode(outerPlanState(node));
250 /* Free the exprcontext */
251 ExecFreeExprContext(&node->ss.ps);
253 /* clean out the tuple table */
254 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
255 ExecClearTuple(node->ss.ss_ScanTupleSlot);
257 /* close the relation. */
258 if (node->ss.ss_currentRelation)
259 ExecCloseScanRelation(node->ss.ss_currentRelation);
262 /* ----------------------------------------------------------------
263 * ExecReScanForeignScan
265 * Rescans the relation.
266 * ----------------------------------------------------------------
269 ExecReScanForeignScan(ForeignScanState *node)
271 PlanState *outerPlan = outerPlanState(node);
273 node->fdwroutine->ReScanForeignScan(node);
276 * If chgParam of subnode is not null then plan will be re-scanned by
277 * first ExecProcNode. outerPlan may also be NULL, in which case there
278 * is nothing to rescan at all.
280 if (outerPlan != NULL && outerPlan->chgParam == NULL)
281 ExecReScan(outerPlan);
283 ExecScanReScan(&node->ss);