1 /*-------------------------------------------------------------------------
4 * Support routines for scanning RangeTableFunc (XMLTABLE like functions).
6 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/executor/nodeTableFuncscan.c
13 *-------------------------------------------------------------------------
17 * ExecTableFuncscan scans a function.
18 * ExecFunctionNext retrieve next tuple in sequential order.
19 * ExecInitTableFuncscan creates and initializes a TableFuncscan node.
20 * ExecEndTableFuncscan releases any storage allocated.
21 * ExecReScanTableFuncscan rescans the function
25 #include "nodes/execnodes.h"
26 #include "executor/executor.h"
27 #include "executor/nodeTableFuncscan.h"
28 #include "executor/tablefunc.h"
29 #include "miscadmin.h"
30 #include "utils/builtins.h"
31 #include "utils/lsyscache.h"
32 #include "utils/memutils.h"
33 #include "utils/xml.h"
36 static TupleTableSlot *TableFuncNext(TableFuncScanState *node);
37 static bool TableFuncRecheck(TableFuncScanState *node, TupleTableSlot *slot);
39 static void tfuncFetchRows(TableFuncScanState *tstate, ExprContext *econtext);
40 static void tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc);
41 static void tfuncLoadRows(TableFuncScanState *tstate, ExprContext *econtext);
43 /* ----------------------------------------------------------------
45 * ----------------------------------------------------------------
47 /* ----------------------------------------------------------------
50 * This is a workhorse for ExecTableFuncscan
51 * ----------------------------------------------------------------
53 static TupleTableSlot *
54 TableFuncNext(TableFuncScanState *node)
56 TupleTableSlot *scanslot;
58 scanslot = node->ss.ss_ScanTupleSlot;
61 * If first time through, read all tuples from function and put them in a
62 * tuplestore. Subsequent calls just fetch tuples from tuplestore.
64 if (node->tupstore == NULL)
65 tfuncFetchRows(node, node->ss.ps.ps_ExprContext);
68 * Get the next tuple from tuplestore.
70 (void) tuplestore_gettupleslot(node->tupstore,
78 * TableFuncRecheck -- access method routine to recheck a tuple in EvalPlanQual
81 TableFuncRecheck(TableFuncScanState *node, TupleTableSlot *slot)
83 /* nothing to check */
87 /* ----------------------------------------------------------------
88 * ExecTableFuncscan(node)
90 * Scans the function sequentially and returns the next qualifying
92 * We call the ExecScan() routine and pass it the appropriate
93 * access method functions.
94 * ----------------------------------------------------------------
97 ExecTableFuncScan(TableFuncScanState *node)
99 return ExecScan(&node->ss,
100 (ExecScanAccessMtd) TableFuncNext,
101 (ExecScanRecheckMtd) TableFuncRecheck);
104 /* ----------------------------------------------------------------
105 * ExecInitTableFuncscan
106 * ----------------------------------------------------------------
109 ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
111 TableFuncScanState *scanstate;
112 TableFunc *tf = node->tablefunc;
116 /* check for unsupported flags */
117 Assert(!(eflags & EXEC_FLAG_MARK));
120 * TableFuncscan should not have any children.
122 Assert(outerPlan(node) == NULL);
123 Assert(innerPlan(node) == NULL);
126 * create new ScanState for node
128 scanstate = makeNode(TableFuncScanState);
129 scanstate->ss.ps.plan = (Plan *) node;
130 scanstate->ss.ps.state = estate;
133 * Miscellaneous initialization
135 * create expression context for node
137 ExecAssignExprContext(estate, &scanstate->ss.ps);
140 * initialize child expressions
142 scanstate->ss.ps.qual =
143 ExecInitQual(node->scan.plan.qual, &scanstate->ss.ps);
146 * tuple table initialization
148 ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
149 ExecInitScanTupleSlot(estate, &scanstate->ss);
152 * initialize source tuple type
154 tupdesc = BuildDescFromLists(tf->colnames,
159 ExecAssignScanType(&scanstate->ss, tupdesc);
162 * Initialize result tuple type and projection info.
164 ExecAssignResultTypeFromTL(&scanstate->ss.ps);
165 ExecAssignScanProjectionInfo(&scanstate->ss);
167 /* Only XMLTABLE is supported currently */
168 scanstate->routine = &XmlTableRoutine;
170 scanstate->perValueCxt =
171 AllocSetContextCreate(CurrentMemoryContext,
172 "TableFunc per value context",
173 ALLOCSET_DEFAULT_SIZES);
174 scanstate->opaque = NULL; /* initialized at runtime */
176 scanstate->ns_names = tf->ns_names;
179 ExecInitExprList(tf->ns_uris, (PlanState *) scanstate);
181 ExecInitExpr((Expr *) tf->docexpr, (PlanState *) scanstate);
183 ExecInitExpr((Expr *) tf->rowexpr, (PlanState *) scanstate);
184 scanstate->colexprs =
185 ExecInitExprList(tf->colexprs, (PlanState *) scanstate);
186 scanstate->coldefexprs =
187 ExecInitExprList(tf->coldefexprs, (PlanState *) scanstate);
189 scanstate->notnulls = tf->notnulls;
191 /* these are allocated now and initialized later */
192 scanstate->in_functions = palloc(sizeof(FmgrInfo) * tupdesc->natts);
193 scanstate->typioparams = palloc(sizeof(Oid) * tupdesc->natts);
196 * Fill in the necessary fmgr infos.
198 for (i = 0; i < tupdesc->natts; i++)
202 getTypeInputInfo(tupdesc->attrs[i]->atttypid,
203 &in_funcid, &scanstate->typioparams[i]);
204 fmgr_info(in_funcid, &scanstate->in_functions[i]);
210 /* ----------------------------------------------------------------
211 * ExecEndTableFuncscan
213 * frees any storage allocated through C routines.
214 * ----------------------------------------------------------------
217 ExecEndTableFuncScan(TableFuncScanState *node)
220 * Free the exprcontext
222 ExecFreeExprContext(&node->ss.ps);
225 * clean out the tuple table
227 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
228 ExecClearTuple(node->ss.ss_ScanTupleSlot);
231 * Release tuplestore resources
233 if (node->tupstore != NULL)
234 tuplestore_end(node->tupstore);
235 node->tupstore = NULL;
238 /* ----------------------------------------------------------------
239 * ExecReScanTableFuncscan
241 * Rescans the relation.
242 * ----------------------------------------------------------------
245 ExecReScanTableFuncScan(TableFuncScanState *node)
247 Bitmapset *chgparam = node->ss.ps.chgParam;
249 ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
250 ExecScanReScan(&node->ss);
253 * Recompute when parameters are changed.
257 if (node->tupstore != NULL)
259 tuplestore_end(node->tupstore);
260 node->tupstore = NULL;
264 if (node->tupstore != NULL)
265 tuplestore_rescan(node->tupstore);
268 /* ----------------------------------------------------------------
271 * Read rows from a TableFunc producer
272 * ----------------------------------------------------------------
275 tfuncFetchRows(TableFuncScanState *tstate, ExprContext *econtext)
277 const TableFuncRoutine *routine = tstate->routine;
278 MemoryContext oldcxt;
282 Assert(tstate->opaque == NULL);
284 /* build tuplestore for the result */
285 oldcxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
286 tstate->tupstore = tuplestore_begin_heap(false, false, work_mem);
290 routine->InitOpaque(tstate,
291 tstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor->natts);
294 * If evaluating the document expression returns NULL, the table
295 * expression is empty and we return immediately.
297 value = ExecEvalExpr(tstate->docexpr, econtext, &isnull);
301 /* otherwise, pass the document value to the table builder */
302 tfuncInitialize(tstate, econtext, value);
304 /* initialize ordinality counter */
307 /* Load all rows into the tuplestore, and we're done */
308 tfuncLoadRows(tstate, econtext);
313 if (tstate->opaque != NULL)
314 routine->DestroyOpaque(tstate);
319 /* return to original memory context, and clean up */
320 MemoryContextSwitchTo(oldcxt);
322 if (tstate->opaque != NULL)
324 routine->DestroyOpaque(tstate);
325 tstate->opaque = NULL;
332 * Fill in namespace declarations, the row filter, and column filters in a
333 * table expression builder context.
336 tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc)
338 const TableFuncRoutine *routine = tstate->routine;
346 ((TableFuncScan *) (tstate->ss.ps.plan))->tablefunc->ordinalitycol;
349 * Install the document as a possibly-toasted Datum into the tablefunc
352 routine->SetDocument(tstate, doc);
354 /* Evaluate namespace specifications */
355 forboth(lc1, tstate->ns_uris, lc2, tstate->ns_names)
357 ExprState *expr = (ExprState *) lfirst(lc1);
358 char *ns_name = strVal(lfirst(lc2));
361 value = ExecEvalExpr((ExprState *) expr, econtext, &isnull);
364 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
365 errmsg("namespace URI must not be null")));
366 ns_uri = TextDatumGetCString(value);
368 routine->SetNamespace(tstate, ns_name, ns_uri);
371 /* Install the row filter expression into the table builder context */
372 value = ExecEvalExpr(tstate->rowexpr, econtext, &isnull);
375 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
376 errmsg("row filter expression must not be null")));
378 routine->SetRowFilter(tstate, TextDatumGetCString(value));
381 * Install the column filter expressions into the table builder context.
382 * If an expression is given, use that; otherwise the column name itself
383 * is the column filter.
386 tupdesc = tstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
387 foreach(lc1, tstate->colexprs)
391 if (colno != ordinalitycol)
393 ExprState *colexpr = lfirst(lc1);
397 value = ExecEvalExpr(colexpr, econtext, &isnull);
400 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
401 errmsg("column filter expression must not be null"),
402 errdetail("Filter for column \"%s\" is null.",
403 NameStr(tupdesc->attrs[colno]->attname))));
404 colfilter = TextDatumGetCString(value);
407 colfilter = NameStr(tupdesc->attrs[colno]->attname);
409 routine->SetColumnFilter(tstate, colfilter, colno);
417 * Load all the rows from the TableFunc table builder into a tuplestore.
420 tfuncLoadRows(TableFuncScanState *tstate, ExprContext *econtext)
422 const TableFuncRoutine *routine = tstate->routine;
423 TupleTableSlot *slot = tstate->ss.ss_ScanTupleSlot;
424 TupleDesc tupdesc = slot->tts_tupleDescriptor;
425 Datum *values = slot->tts_values;
426 bool *nulls = slot->tts_isnull;
427 int natts = tupdesc->natts;
428 MemoryContext oldcxt;
432 ((TableFuncScan *) (tstate->ss.ps.plan))->tablefunc->ordinalitycol;
433 oldcxt = MemoryContextSwitchTo(tstate->perValueCxt);
436 * Keep requesting rows from the table builder until there aren't any.
438 while (routine->FetchRow(tstate))
440 ListCell *cell = list_head(tstate->coldefexprs);
443 ExecClearTuple(tstate->ss.ss_ScanTupleSlot);
446 * Obtain the value of each column for this row, installing them into the
447 * slot; then add the tuple to the tuplestore.
449 for (colno = 0; colno < natts; colno++)
451 if (colno == ordinalitycol)
453 /* Fast path for ordinality column */
454 values[colno] = Int32GetDatum(tstate->ordinal++);
455 nulls[colno] = false;
461 values[colno] = routine->GetValue(tstate,
463 tupdesc->attrs[colno]->atttypid,
464 tupdesc->attrs[colno]->atttypmod,
467 /* No value? Evaluate and apply the default, if any */
468 if (isnull && cell != NULL)
470 ExprState *coldefexpr = (ExprState *) lfirst(cell);
472 if (coldefexpr != NULL)
473 values[colno] = ExecEvalExpr(coldefexpr, econtext,
477 /* Verify a possible NOT NULL constraint */
478 if (isnull && bms_is_member(colno, tstate->notnulls))
480 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
481 errmsg("null is not allowed in column \"%s\"",
482 NameStr(tupdesc->attrs[colno]->attname))));
484 nulls[colno] = isnull;
487 /* advance list of default expressions */
492 tuplestore_putvalues(tstate->tupstore, tupdesc, values, nulls);
494 MemoryContextReset(tstate->perValueCxt);
497 MemoryContextSwitchTo(oldcxt);