PostgreSQL Source Code  git master
nodeTableFuncscan.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * nodeTableFuncscan.c
4  * Support routines for scanning RangeTableFunc (XMLTABLE like functions).
5  *
6  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/executor/nodeTableFuncscan.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 /*
16  * INTERFACE ROUTINES
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
22  */
23 #include "postgres.h"
24 
25 #include "executor/executor.h"
27 #include "executor/tablefunc.h"
28 #include "miscadmin.h"
29 #include "nodes/execnodes.h"
30 #include "utils/builtins.h"
31 #include "utils/lsyscache.h"
32 #include "utils/memutils.h"
33 #include "utils/xml.h"
34 
36 static bool TableFuncRecheck(TableFuncScanState *node, TupleTableSlot *slot);
37 
38 static void tfuncFetchRows(TableFuncScanState *tstate, ExprContext *econtext);
39 static void tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc);
40 static void tfuncLoadRows(TableFuncScanState *tstate, ExprContext *econtext);
41 
42 /* ----------------------------------------------------------------
43  * Scan Support
44  * ----------------------------------------------------------------
45  */
46 /* ----------------------------------------------------------------
47  * TableFuncNext
48  *
49  * This is a workhorse for ExecTableFuncScan
50  * ----------------------------------------------------------------
51  */
52 static TupleTableSlot *
54 {
55  TupleTableSlot *scanslot;
56 
57  scanslot = node->ss.ss_ScanTupleSlot;
58 
59  /*
60  * If first time through, read all tuples from function and put them in a
61  * tuplestore. Subsequent calls just fetch tuples from tuplestore.
62  */
63  if (node->tupstore == NULL)
64  tfuncFetchRows(node, node->ss.ps.ps_ExprContext);
65 
66  /*
67  * Get the next tuple from tuplestore.
68  */
69  (void) tuplestore_gettupleslot(node->tupstore,
70  true,
71  false,
72  scanslot);
73  return scanslot;
74 }
75 
76 /*
77  * TableFuncRecheck -- access method routine to recheck a tuple in EvalPlanQual
78  */
79 static bool
81 {
82  /* nothing to check */
83  return true;
84 }
85 
86 /* ----------------------------------------------------------------
87  * ExecTableFuncScan(node)
88  *
89  * Scans the function sequentially and returns the next qualifying
90  * tuple.
91  * We call the ExecScan() routine and pass it the appropriate
92  * access method functions.
93  * ----------------------------------------------------------------
94  */
95 static TupleTableSlot *
97 {
99 
100  return ExecScan(&node->ss,
103 }
104 
105 /* ----------------------------------------------------------------
106  * ExecInitTableFuncScan
107  * ----------------------------------------------------------------
108  */
110 ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
111 {
112  TableFuncScanState *scanstate;
113  TableFunc *tf = node->tablefunc;
114  TupleDesc tupdesc;
115  int i;
116 
117  /* check for unsupported flags */
118  Assert(!(eflags & EXEC_FLAG_MARK));
119 
120  /*
121  * TableFuncscan should not have any children.
122  */
123  Assert(outerPlan(node) == NULL);
124  Assert(innerPlan(node) == NULL);
125 
126  /*
127  * create new ScanState for node
128  */
129  scanstate = makeNode(TableFuncScanState);
130  scanstate->ss.ps.plan = (Plan *) node;
131  scanstate->ss.ps.state = estate;
132  scanstate->ss.ps.ExecProcNode = ExecTableFuncScan;
133 
134  /*
135  * Miscellaneous initialization
136  *
137  * create expression context for node
138  */
139  ExecAssignExprContext(estate, &scanstate->ss.ps);
140 
141  /*
142  * initialize source tuple type
143  */
144  tupdesc = BuildDescFromLists(tf->colnames,
145  tf->coltypes,
146  tf->coltypmods,
147  tf->colcollations);
148  /* and the corresponding scan slot */
149  ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc,
151 
152  /*
153  * Initialize result type and projection.
154  */
155  ExecInitResultTypeTL(&scanstate->ss.ps);
156  ExecAssignScanProjectionInfo(&scanstate->ss);
157 
158  /*
159  * initialize child expressions
160  */
161  scanstate->ss.ps.qual =
162  ExecInitQual(node->scan.plan.qual, &scanstate->ss.ps);
163 
164  /* Only XMLTABLE is supported currently */
165  scanstate->routine = &XmlTableRoutine;
166 
167  scanstate->perTableCxt =
169  "TableFunc per value context",
171  scanstate->opaque = NULL; /* initialized at runtime */
172 
173  scanstate->ns_names = tf->ns_names;
174 
175  scanstate->ns_uris =
176  ExecInitExprList(tf->ns_uris, (PlanState *) scanstate);
177  scanstate->docexpr =
178  ExecInitExpr((Expr *) tf->docexpr, (PlanState *) scanstate);
179  scanstate->rowexpr =
180  ExecInitExpr((Expr *) tf->rowexpr, (PlanState *) scanstate);
181  scanstate->colexprs =
182  ExecInitExprList(tf->colexprs, (PlanState *) scanstate);
183  scanstate->coldefexprs =
184  ExecInitExprList(tf->coldefexprs, (PlanState *) scanstate);
185 
186  scanstate->notnulls = tf->notnulls;
187 
188  /* these are allocated now and initialized later */
189  scanstate->in_functions = palloc(sizeof(FmgrInfo) * tupdesc->natts);
190  scanstate->typioparams = palloc(sizeof(Oid) * tupdesc->natts);
191 
192  /*
193  * Fill in the necessary fmgr infos.
194  */
195  for (i = 0; i < tupdesc->natts; i++)
196  {
197  Oid in_funcid;
198 
199  getTypeInputInfo(TupleDescAttr(tupdesc, i)->atttypid,
200  &in_funcid, &scanstate->typioparams[i]);
201  fmgr_info(in_funcid, &scanstate->in_functions[i]);
202  }
203 
204  return scanstate;
205 }
206 
207 /* ----------------------------------------------------------------
208  * ExecEndTableFuncScan
209  *
210  * frees any storage allocated through C routines.
211  * ----------------------------------------------------------------
212  */
213 void
215 {
216  /*
217  * Release tuplestore resources
218  */
219  if (node->tupstore != NULL)
220  tuplestore_end(node->tupstore);
221  node->tupstore = NULL;
222 }
223 
224 /* ----------------------------------------------------------------
225  * ExecReScanTableFuncScan
226  *
227  * Rescans the relation.
228  * ----------------------------------------------------------------
229  */
230 void
232 {
233  Bitmapset *chgparam = node->ss.ps.chgParam;
234 
235  if (node->ss.ps.ps_ResultTupleSlot)
237  ExecScanReScan(&node->ss);
238 
239  /*
240  * Recompute when parameters are changed.
241  */
242  if (chgparam)
243  {
244  if (node->tupstore != NULL)
245  {
246  tuplestore_end(node->tupstore);
247  node->tupstore = NULL;
248  }
249  }
250 
251  if (node->tupstore != NULL)
253 }
254 
255 /* ----------------------------------------------------------------
256  * tfuncFetchRows
257  *
258  * Read rows from a TableFunc producer
259  * ----------------------------------------------------------------
260  */
261 static void
263 {
264  const TableFuncRoutine *routine = tstate->routine;
265  MemoryContext oldcxt;
266  Datum value;
267  bool isnull;
268 
269  Assert(tstate->opaque == NULL);
270 
271  /* build tuplestore for the result */
272  oldcxt = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
273  tstate->tupstore = tuplestore_begin_heap(false, false, work_mem);
274 
275  /*
276  * Each call to fetch a new set of rows - of which there may be very many
277  * if XMLTABLE is being used in a lateral join - will allocate a possibly
278  * substantial amount of memory, so we cannot use the per-query context
279  * here. perTableCxt now serves the same function as "argcontext" does in
280  * FunctionScan - a place to store per-one-call (i.e. one result table)
281  * lifetime data (as opposed to per-query or per-result-tuple).
282  */
284 
285  PG_TRY();
286  {
287  routine->InitOpaque(tstate,
289 
290  /*
291  * If evaluating the document expression returns NULL, the table
292  * expression is empty and we return immediately.
293  */
294  value = ExecEvalExpr(tstate->docexpr, econtext, &isnull);
295 
296  if (!isnull)
297  {
298  /* otherwise, pass the document value to the table builder */
299  tfuncInitialize(tstate, econtext, value);
300 
301  /* initialize ordinality counter */
302  tstate->ordinal = 1;
303 
304  /* Load all rows into the tuplestore, and we're done */
305  tfuncLoadRows(tstate, econtext);
306  }
307  }
308  PG_CATCH();
309  {
310  if (tstate->opaque != NULL)
311  routine->DestroyOpaque(tstate);
312  PG_RE_THROW();
313  }
314  PG_END_TRY();
315 
316  /* clean up and return to original memory context */
317 
318  if (tstate->opaque != NULL)
319  {
320  routine->DestroyOpaque(tstate);
321  tstate->opaque = NULL;
322  }
323 
324  MemoryContextSwitchTo(oldcxt);
326 }
327 
328 /*
329  * Fill in namespace declarations, the row filter, and column filters in a
330  * table expression builder context.
331  */
332 static void
334 {
335  const TableFuncRoutine *routine = tstate->routine;
336  TupleDesc tupdesc;
337  ListCell *lc1,
338  *lc2;
339  bool isnull;
340  int colno;
341  Datum value;
342  int ordinalitycol =
343  ((TableFuncScan *) (tstate->ss.ps.plan))->tablefunc->ordinalitycol;
344 
345  /*
346  * Install the document as a possibly-toasted Datum into the tablefunc
347  * context.
348  */
349  routine->SetDocument(tstate, doc);
350 
351  /* Evaluate namespace specifications */
352  forboth(lc1, tstate->ns_uris, lc2, tstate->ns_names)
353  {
354  ExprState *expr = (ExprState *) lfirst(lc1);
355  String *ns_node = lfirst_node(String, lc2);
356  char *ns_uri;
357  char *ns_name;
358 
359  value = ExecEvalExpr((ExprState *) expr, econtext, &isnull);
360  if (isnull)
361  ereport(ERROR,
362  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
363  errmsg("namespace URI must not be null")));
364  ns_uri = TextDatumGetCString(value);
365 
366  /* DEFAULT is passed down to SetNamespace as NULL */
367  ns_name = ns_node ? strVal(ns_node) : NULL;
368 
369  routine->SetNamespace(tstate, ns_name, ns_uri);
370  }
371 
372  /* Install the row filter expression into the table builder context */
373  value = ExecEvalExpr(tstate->rowexpr, econtext, &isnull);
374  if (isnull)
375  ereport(ERROR,
376  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
377  errmsg("row filter expression must not be null")));
378 
379  routine->SetRowFilter(tstate, TextDatumGetCString(value));
380 
381  /*
382  * Install the column filter expressions into the table builder context.
383  * If an expression is given, use that; otherwise the column name itself
384  * is the column filter.
385  */
386  colno = 0;
387  tupdesc = tstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
388  foreach(lc1, tstate->colexprs)
389  {
390  char *colfilter;
391  Form_pg_attribute att = TupleDescAttr(tupdesc, colno);
392 
393  if (colno != ordinalitycol)
394  {
395  ExprState *colexpr = lfirst(lc1);
396 
397  if (colexpr != NULL)
398  {
399  value = ExecEvalExpr(colexpr, econtext, &isnull);
400  if (isnull)
401  ereport(ERROR,
402  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
403  errmsg("column filter expression must not be null"),
404  errdetail("Filter for column \"%s\" is null.",
405  NameStr(att->attname))));
406  colfilter = TextDatumGetCString(value);
407  }
408  else
409  colfilter = NameStr(att->attname);
410 
411  routine->SetColumnFilter(tstate, colfilter, colno);
412  }
413 
414  colno++;
415  }
416 }
417 
418 /*
419  * Load all the rows from the TableFunc table builder into a tuplestore.
420  */
421 static void
423 {
424  const TableFuncRoutine *routine = tstate->routine;
425  TupleTableSlot *slot = tstate->ss.ss_ScanTupleSlot;
426  TupleDesc tupdesc = slot->tts_tupleDescriptor;
427  Datum *values = slot->tts_values;
428  bool *nulls = slot->tts_isnull;
429  int natts = tupdesc->natts;
430  MemoryContext oldcxt;
431  int ordinalitycol;
432 
433  ordinalitycol =
434  ((TableFuncScan *) (tstate->ss.ps.plan))->tablefunc->ordinalitycol;
435 
436  /*
437  * We need a short-lived memory context that we can clean up each time
438  * around the loop, to avoid wasting space. Our default per-tuple context
439  * is fine for the job, since we won't have used it for anything yet in
440  * this tuple cycle.
441  */
442  oldcxt = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
443 
444  /*
445  * Keep requesting rows from the table builder until there aren't any.
446  */
447  while (routine->FetchRow(tstate))
448  {
449  ListCell *cell = list_head(tstate->coldefexprs);
450  int colno;
451 
453 
455 
456  /*
457  * Obtain the value of each column for this row, installing them into
458  * the slot; then add the tuple to the tuplestore.
459  */
460  for (colno = 0; colno < natts; colno++)
461  {
462  Form_pg_attribute att = TupleDescAttr(tupdesc, colno);
463 
464  if (colno == ordinalitycol)
465  {
466  /* Fast path for ordinality column */
467  values[colno] = Int32GetDatum(tstate->ordinal++);
468  nulls[colno] = false;
469  }
470  else
471  {
472  bool isnull;
473 
474  values[colno] = routine->GetValue(tstate,
475  colno,
476  att->atttypid,
477  att->atttypmod,
478  &isnull);
479 
480  /* No value? Evaluate and apply the default, if any */
481  if (isnull && cell != NULL)
482  {
483  ExprState *coldefexpr = (ExprState *) lfirst(cell);
484 
485  if (coldefexpr != NULL)
486  values[colno] = ExecEvalExpr(coldefexpr, econtext,
487  &isnull);
488  }
489 
490  /* Verify a possible NOT NULL constraint */
491  if (isnull && bms_is_member(colno, tstate->notnulls))
492  ereport(ERROR,
493  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
494  errmsg("null is not allowed in column \"%s\"",
495  NameStr(att->attname))));
496 
497  nulls[colno] = isnull;
498  }
499 
500  /* advance list of default expressions */
501  if (cell != NULL)
502  cell = lnext(tstate->coldefexprs, cell);
503  }
504 
505  tuplestore_putvalues(tstate->tupstore, tupdesc, values, nulls);
506 
508  }
509 
510  MemoryContextSwitchTo(oldcxt);
511 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:460
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define TextDatumGetCString(d)
Definition: builtins.h:95
#define NameStr(name)
Definition: c.h:735
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define PG_RE_THROW()
Definition: elog.h:411
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define ERROR
Definition: elog.h:39
#define PG_CATCH(...)
Definition: elog.h:380
#define ereport(elevel,...)
Definition: elog.h:149
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:323
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:214
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:128
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:157
void ExecAssignScanProjectionInfo(ScanState *node)
Definition: execScan.c:271
void ExecScanReScan(ScanState *node)
Definition: execScan.c:298
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1812
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1756
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:85
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:488
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:472
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:473
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:332
#define EXEC_FLAG_MARK
Definition: executor.h:69
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Definition: fmgr.c:127
int work_mem
Definition: globals.c:127
static struct @148 value
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2856
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:330
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void * palloc(Size size)
Definition: mcxt.c:1226
#define AllocSetContextCreate
Definition: memutils.h:126
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:150
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
void ExecReScanTableFuncScan(TableFuncScanState *node)
void ExecEndTableFuncScan(TableFuncScanState *node)
TableFuncScanState * ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
static bool TableFuncRecheck(TableFuncScanState *node, TupleTableSlot *slot)
static void tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc)
static TupleTableSlot * ExecTableFuncScan(PlanState *pstate)
static void tfuncLoadRows(TableFuncScanState *tstate, ExprContext *econtext)
static void tfuncFetchRows(TableFuncScanState *tstate, ExprContext *econtext)
static TupleTableSlot * TableFuncNext(TableFuncScanState *node)
#define makeNode(_type_)
Definition: nodes.h:176
#define castNode(_type_, nodeptr)
Definition: nodes.h:197
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:209
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:467
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define innerPlan(node)
Definition: plannodes.h:181
#define outerPlan(node)
Definition: plannodes.h:182
uintptr_t Datum
Definition: postgres.h:64
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:256
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:255
Definition: fmgr.h:57
ExprState * qual
Definition: execnodes.h:1057
Plan * plan
Definition: execnodes.h:1036
EState * state
Definition: execnodes.h:1038
Bitmapset * chgParam
Definition: execnodes.h:1068
ExprContext * ps_ExprContext
Definition: execnodes.h:1075
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1074
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1042
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1476
PlanState ps
Definition: execnodes.h:1473
Definition: value.h:64
void(* SetRowFilter)(struct TableFuncScanState *state, const char *path)
Definition: tablefunc.h:58
bool(* FetchRow)(struct TableFuncScanState *state)
Definition: tablefunc.h:61
void(* SetNamespace)(struct TableFuncScanState *state, const char *name, const char *uri)
Definition: tablefunc.h:56
Datum(* GetValue)(struct TableFuncScanState *state, int colnum, Oid typid, int32 typmod, bool *isnull)
Definition: tablefunc.h:62
void(* InitOpaque)(struct TableFuncScanState *state, int natts)
Definition: tablefunc.h:54
void(* SetColumnFilter)(struct TableFuncScanState *state, const char *path, int colnum)
Definition: tablefunc.h:59
void(* SetDocument)(struct TableFuncScanState *state, Datum value)
Definition: tablefunc.h:55
void(* DestroyOpaque)(struct TableFuncScanState *state)
Definition: tablefunc.h:64
MemoryContext perTableCxt
Definition: execnodes.h:1886
Tuplestorestate * tupstore
Definition: execnodes.h:1887
Bitmapset * notnulls
Definition: execnodes.h:1880
const struct TableFuncRoutine * routine
Definition: execnodes.h:1882
ExprState * rowexpr
Definition: execnodes.h:1875
FmgrInfo * in_functions
Definition: execnodes.h:1883
ExprState * docexpr
Definition: execnodes.h:1874
TableFunc * tablefunc
Definition: plannodes.h:631
Node * docexpr
Definition: primnodes.h:111
Node * rowexpr
Definition: primnodes.h:113
List * colexprs
Definition: primnodes.h:123
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:123
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
TupleDesc BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
Definition: tupdesc.c:814
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1078
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
void tuplestore_rescan(Tuplestorestate *state)
Definition: tuplestore.c:1233
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:750
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:432
#define strVal(v)
Definition: value.h:82
const TableFuncRoutine XmlTableRoutine
Definition: xml.c:214