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