]> granicus.if.org Git - postgresql/blob - src/backend/executor/nodeForeignscan.c
64a07bcc7713773b1d7cfca9527ccbad75a909ce
[postgresql] / src / backend / executor / nodeForeignscan.c
1 /*-------------------------------------------------------------------------
2  *
3  * nodeForeignscan.c
4  *        Routines to support scans of foreign tables
5  *
6  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        src/backend/executor/nodeForeignscan.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
17  *
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.
22  */
23 #include "postgres.h"
24
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"
30
31 static TupleTableSlot *ForeignNext(ForeignScanState *node);
32 static bool ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot);
33
34
35 /* ----------------------------------------------------------------
36  *              ForeignNext
37  *
38  *              This is a workhorse for ExecForeignScan
39  * ----------------------------------------------------------------
40  */
41 static TupleTableSlot *
42 ForeignNext(ForeignScanState *node)
43 {
44         TupleTableSlot *slot;
45         ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
46         ExprContext *econtext = node->ss.ps.ps_ExprContext;
47         MemoryContext oldcontext;
48
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);
53
54         /*
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.
59          */
60         if (plan->fsSystemCol && !TupIsNull(slot))
61         {
62                 HeapTuple       tup = ExecMaterializeSlot(slot);
63
64                 tup->t_tableOid = RelationGetRelid(node->ss.ss_currentRelation);
65         }
66
67         return slot;
68 }
69
70 /*
71  * ForeignRecheck -- access method routine to recheck a tuple in EvalPlanQual
72  */
73 static bool
74 ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
75 {
76         FdwRoutine *fdwroutine = node->fdwroutine;
77         ExprContext *econtext;
78
79         /*
80          * extract necessary information from foreign scan node
81          */
82         econtext = node->ss.ps.ps_ExprContext;
83
84         /* Does the tuple meet the remote qual condition? */
85         econtext->ecxt_scantuple = slot;
86
87         ResetExprContext(econtext);
88
89         /*
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.
96          */
97         if (fdwroutine->RecheckForeignScan &&
98                 !fdwroutine->RecheckForeignScan(node, slot))
99                 return false;
100
101         return ExecQual(node->fdw_recheck_quals, econtext, false);
102 }
103
104 /* ----------------------------------------------------------------
105  *              ExecForeignScan(node)
106  *
107  *              Fetches the next tuple from the FDW, checks local quals, and
108  *              returns it.
109  *              We call the ExecScan() routine and pass it the appropriate
110  *              access method functions.
111  * ----------------------------------------------------------------
112  */
113 TupleTableSlot *
114 ExecForeignScan(ForeignScanState *node)
115 {
116         return ExecScan((ScanState *) node,
117                                         (ExecScanAccessMtd) ForeignNext,
118                                         (ExecScanRecheckMtd) ForeignRecheck);
119 }
120
121
122 /* ----------------------------------------------------------------
123  *              ExecInitForeignScan
124  * ----------------------------------------------------------------
125  */
126 ForeignScanState *
127 ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
128 {
129         ForeignScanState *scanstate;
130         Relation        currentRelation = NULL;
131         Index           scanrelid = node->scan.scanrelid;
132         Index           tlistvarno;
133         FdwRoutine *fdwroutine;
134
135         /* check for unsupported flags */
136         Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
137
138         /*
139          * create state structure
140          */
141         scanstate = makeNode(ForeignScanState);
142         scanstate->ss.ps.plan = (Plan *) node;
143         scanstate->ss.ps.state = estate;
144
145         /*
146          * Miscellaneous initialization
147          *
148          * create expression context for node
149          */
150         ExecAssignExprContext(estate, &scanstate->ss.ps);
151
152         scanstate->ss.ps.ps_TupFromTlist = false;
153
154         /*
155          * initialize child expressions
156          */
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);
166
167         /*
168          * tuple table initialization
169          */
170         ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
171         ExecInitScanTupleSlot(estate, &scanstate->ss);
172
173         /*
174          * open the base relation, if any, and acquire an appropriate lock on it;
175          * also acquire function pointers from the FDW's handler
176          */
177         if (scanrelid > 0)
178         {
179                 currentRelation = ExecOpenScanRelation(estate, scanrelid, eflags);
180                 scanstate->ss.ss_currentRelation = currentRelation;
181                 fdwroutine = GetFdwRoutineForRelation(currentRelation, true);
182         }
183         else
184         {
185                 /* We can't use the relcache, so get fdwroutine the hard way */
186                 fdwroutine = GetFdwRoutineByServerId(node->fs_server);
187         }
188
189         /*
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.
192          */
193         if (node->fdw_scan_tlist != NIL || currentRelation == NULL)
194         {
195                 TupleDesc       scan_tupdesc;
196
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;
201         }
202         else
203         {
204                 ExecAssignScanType(&scanstate->ss, RelationGetDescr(currentRelation));
205                 /* Node's targetlist will contain Vars with varno = scanrelid */
206                 tlistvarno = scanrelid;
207         }
208
209         /*
210          * Initialize result tuple type and projection info.
211          */
212         ExecAssignResultTypeFromTL(&scanstate->ss.ps);
213         ExecAssignScanProjectionInfoWithVarno(&scanstate->ss, tlistvarno);
214
215         /*
216          * Initialize FDW-related state.
217          */
218         scanstate->fdwroutine = fdwroutine;
219         scanstate->fdw_state = NULL;
220
221         /* Initialize any outer plan. */
222         if (outerPlan(node))
223                 outerPlanState(scanstate) =
224                         ExecInitNode(outerPlan(node), estate, eflags);
225
226         /*
227          * Tell the FDW to initialize the scan.
228          */
229         fdwroutine->BeginForeignScan(scanstate, eflags);
230
231         return scanstate;
232 }
233
234 /* ----------------------------------------------------------------
235  *              ExecEndForeignScan
236  *
237  *              frees any storage allocated through C routines.
238  * ----------------------------------------------------------------
239  */
240 void
241 ExecEndForeignScan(ForeignScanState *node)
242 {
243         /* Let the FDW shut down */
244         node->fdwroutine->EndForeignScan(node);
245
246         /* Shut down any outer plan. */
247         if (outerPlanState(node))
248                 ExecEndNode(outerPlanState(node));
249
250         /* Free the exprcontext */
251         ExecFreeExprContext(&node->ss.ps);
252
253         /* clean out the tuple table */
254         ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
255         ExecClearTuple(node->ss.ss_ScanTupleSlot);
256
257         /* close the relation. */
258         if (node->ss.ss_currentRelation)
259                 ExecCloseScanRelation(node->ss.ss_currentRelation);
260 }
261
262 /* ----------------------------------------------------------------
263  *              ExecReScanForeignScan
264  *
265  *              Rescans the relation.
266  * ----------------------------------------------------------------
267  */
268 void
269 ExecReScanForeignScan(ForeignScanState *node)
270 {
271         PlanState  *outerPlan = outerPlanState(node);
272
273         node->fdwroutine->ReScanForeignScan(node);
274
275         /*
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.
279          */
280         if (outerPlan != NULL && outerPlan->chgParam == NULL)
281                 ExecReScan(outerPlan);
282
283         ExecScanReScan(&node->ss);
284 }