PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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-2024, 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
37static bool TableFuncRecheck(TableFuncScanState *node, TupleTableSlot *slot);
38
39static void tfuncFetchRows(TableFuncScanState *tstate, ExprContext *econtext);
40static void tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc);
41static 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 */
53static 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)
66
67 /*
68 * Get the next tuple from tuplestore.
69 */
71 true,
72 false,
73 scanslot);
74 return scanslot;
75}
76
77/*
78 * TableFuncRecheck -- access method routine to recheck a tuple in EvalPlanQual
79 */
80static 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 */
96static TupleTableSlot *
98{
100
101 return ExecScan(&node->ss,
104}
105
106/* ----------------------------------------------------------------
107 * ExecInitTableFuncScan
108 * ----------------------------------------------------------------
109 */
111ExecInitTableFuncScan(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 scanstate->colvalexprs =
188 ExecInitExprList(tf->colvalexprs, (PlanState *) scanstate);
189 scanstate->passingvalexprs =
190 ExecInitExprList(tf->passingvalexprs, (PlanState *) scanstate);
191
192 scanstate->notnulls = tf->notnulls;
193
194 /* these are allocated now and initialized later */
195 scanstate->in_functions = palloc(sizeof(FmgrInfo) * tupdesc->natts);
196 scanstate->typioparams = palloc(sizeof(Oid) * tupdesc->natts);
197
198 /*
199 * Fill in the necessary fmgr infos.
200 */
201 for (i = 0; i < tupdesc->natts; i++)
202 {
203 Oid in_funcid;
204
205 getTypeInputInfo(TupleDescAttr(tupdesc, i)->atttypid,
206 &in_funcid, &scanstate->typioparams[i]);
207 fmgr_info(in_funcid, &scanstate->in_functions[i]);
208 }
209
210 return scanstate;
211}
212
213/* ----------------------------------------------------------------
214 * ExecEndTableFuncScan
215 *
216 * frees any storage allocated through C routines.
217 * ----------------------------------------------------------------
218 */
219void
221{
222 /*
223 * Release tuplestore resources
224 */
225 if (node->tupstore != NULL)
227 node->tupstore = NULL;
228}
229
230/* ----------------------------------------------------------------
231 * ExecReScanTableFuncScan
232 *
233 * Rescans the relation.
234 * ----------------------------------------------------------------
235 */
236void
238{
239 Bitmapset *chgparam = node->ss.ps.chgParam;
240
241 if (node->ss.ps.ps_ResultTupleSlot)
243 ExecScanReScan(&node->ss);
244
245 /*
246 * Recompute when parameters are changed.
247 */
248 if (chgparam)
249 {
250 if (node->tupstore != NULL)
251 {
253 node->tupstore = NULL;
254 }
255 }
256
257 if (node->tupstore != NULL)
259}
260
261/* ----------------------------------------------------------------
262 * tfuncFetchRows
263 *
264 * Read rows from a TableFunc producer
265 * ----------------------------------------------------------------
266 */
267static void
269{
270 const TableFuncRoutine *routine = tstate->routine;
271 MemoryContext oldcxt;
272 Datum value;
273 bool isnull;
274
275 Assert(tstate->opaque == NULL);
276
277 /* build tuplestore for the result */
279 tstate->tupstore = tuplestore_begin_heap(false, false, work_mem);
280
281 /*
282 * Each call to fetch a new set of rows - of which there may be very many
283 * if XMLTABLE or JSON_TABLE is being used in a lateral join - will
284 * allocate a possibly substantial amount of memory, so we cannot use the
285 * per-query context here. perTableCxt now serves the same function as
286 * "argcontext" does in FunctionScan - a place to store per-one-call (i.e.
287 * one result table) lifetime data (as opposed to per-query or
288 * per-result-tuple).
289 */
291
292 PG_TRY();
293 {
294 routine->InitOpaque(tstate,
296
297 /*
298 * If evaluating the document expression returns NULL, the table
299 * expression is empty and we return immediately.
300 */
301 value = ExecEvalExpr(tstate->docexpr, econtext, &isnull);
302
303 if (!isnull)
304 {
305 /* otherwise, pass the document value to the table builder */
306 tfuncInitialize(tstate, econtext, value);
307
308 /* initialize ordinality counter */
309 tstate->ordinal = 1;
310
311 /* Load all rows into the tuplestore, and we're done */
312 tfuncLoadRows(tstate, econtext);
313 }
314 }
315 PG_CATCH();
316 {
317 if (tstate->opaque != NULL)
318 routine->DestroyOpaque(tstate);
319 PG_RE_THROW();
320 }
321 PG_END_TRY();
322
323 /* clean up and return to original memory context */
324
325 if (tstate->opaque != NULL)
326 {
327 routine->DestroyOpaque(tstate);
328 tstate->opaque = NULL;
329 }
330
331 MemoryContextSwitchTo(oldcxt);
333}
334
335/*
336 * Fill in namespace declarations, the row filter, and column filters in a
337 * table expression builder context.
338 */
339static void
341{
342 const TableFuncRoutine *routine = tstate->routine;
343 TupleDesc tupdesc;
344 ListCell *lc1,
345 *lc2;
346 bool isnull;
347 int colno;
348 Datum value;
349 int ordinalitycol =
350 ((TableFuncScan *) (tstate->ss.ps.plan))->tablefunc->ordinalitycol;
351
352 /*
353 * Install the document as a possibly-toasted Datum into the tablefunc
354 * context.
355 */
356 routine->SetDocument(tstate, doc);
357
358 /* Evaluate namespace specifications */
359 forboth(lc1, tstate->ns_uris, lc2, tstate->ns_names)
360 {
361 ExprState *expr = (ExprState *) lfirst(lc1);
362 String *ns_node = lfirst_node(String, lc2);
363 char *ns_uri;
364 char *ns_name;
365
366 value = ExecEvalExpr((ExprState *) expr, econtext, &isnull);
367 if (isnull)
369 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
370 errmsg("namespace URI must not be null")));
371 ns_uri = TextDatumGetCString(value);
372
373 /* DEFAULT is passed down to SetNamespace as NULL */
374 ns_name = ns_node ? strVal(ns_node) : NULL;
375
376 routine->SetNamespace(tstate, ns_name, ns_uri);
377 }
378
379 /*
380 * Install the row filter expression, if any, into the table builder
381 * context.
382 */
383 if (routine->SetRowFilter)
384 {
385 value = ExecEvalExpr(tstate->rowexpr, econtext, &isnull);
386 if (isnull)
388 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
389 errmsg("row filter expression must not be null")));
390
391 routine->SetRowFilter(tstate, TextDatumGetCString(value));
392 }
393
394 /*
395 * Install the column filter expressions into the table builder context.
396 * If an expression is given, use that; otherwise the column name itself
397 * is the column filter.
398 */
399 colno = 0;
400 tupdesc = tstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
401 foreach(lc1, tstate->colexprs)
402 {
403 char *colfilter;
404 Form_pg_attribute att = TupleDescAttr(tupdesc, colno);
405
406 if (colno != ordinalitycol)
407 {
408 ExprState *colexpr = lfirst(lc1);
409
410 if (colexpr != NULL)
411 {
412 value = ExecEvalExpr(colexpr, econtext, &isnull);
413 if (isnull)
415 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
416 errmsg("column filter expression must not be null"),
417 errdetail("Filter for column \"%s\" is null.",
418 NameStr(att->attname))));
419 colfilter = TextDatumGetCString(value);
420 }
421 else
422 colfilter = NameStr(att->attname);
423
424 routine->SetColumnFilter(tstate, colfilter, colno);
425 }
426
427 colno++;
428 }
429}
430
431/*
432 * Load all the rows from the TableFunc table builder into a tuplestore.
433 */
434static void
436{
437 const TableFuncRoutine *routine = tstate->routine;
438 TupleTableSlot *slot = tstate->ss.ss_ScanTupleSlot;
439 TupleDesc tupdesc = slot->tts_tupleDescriptor;
440 Datum *values = slot->tts_values;
441 bool *nulls = slot->tts_isnull;
442 int natts = tupdesc->natts;
443 MemoryContext oldcxt;
444 int ordinalitycol;
445
446 ordinalitycol =
447 ((TableFuncScan *) (tstate->ss.ps.plan))->tablefunc->ordinalitycol;
448
449 /*
450 * We need a short-lived memory context that we can clean up each time
451 * around the loop, to avoid wasting space. Our default per-tuple context
452 * is fine for the job, since we won't have used it for anything yet in
453 * this tuple cycle.
454 */
456
457 /*
458 * Keep requesting rows from the table builder until there aren't any.
459 */
460 while (routine->FetchRow(tstate))
461 {
462 ListCell *cell = list_head(tstate->coldefexprs);
463 int colno;
464
466
468
469 /*
470 * Obtain the value of each column for this row, installing them into
471 * the slot; then add the tuple to the tuplestore.
472 */
473 for (colno = 0; colno < natts; colno++)
474 {
475 Form_pg_attribute att = TupleDescAttr(tupdesc, colno);
476
477 if (colno == ordinalitycol)
478 {
479 /* Fast path for ordinality column */
480 values[colno] = Int32GetDatum(tstate->ordinal++);
481 nulls[colno] = false;
482 }
483 else
484 {
485 bool isnull;
486
487 values[colno] = routine->GetValue(tstate,
488 colno,
489 att->atttypid,
490 att->atttypmod,
491 &isnull);
492
493 /* No value? Evaluate and apply the default, if any */
494 if (isnull && cell != NULL)
495 {
496 ExprState *coldefexpr = (ExprState *) lfirst(cell);
497
498 if (coldefexpr != NULL)
499 values[colno] = ExecEvalExpr(coldefexpr, econtext,
500 &isnull);
501 }
502
503 /* Verify a possible NOT NULL constraint */
504 if (isnull && bms_is_member(colno, tstate->notnulls))
506 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
507 errmsg("null is not allowed in column \"%s\"",
508 NameStr(att->attname))));
509
510 nulls[colno] = isnull;
511 }
512
513 /* advance list of default expressions */
514 if (cell != NULL)
515 cell = lnext(tstate->coldefexprs, cell);
516 }
517
518 tuplestore_putvalues(tstate->tupstore, tupdesc, values, nulls);
519
521 }
522
523 MemoryContextSwitchTo(oldcxt);
524}
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define TextDatumGetCString(d)
Definition: builtins.h:98
#define NameStr(name)
Definition: c.h:700
#define Assert(condition)
Definition: c.h:812
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define PG_RE_THROW()
Definition: elog.h:412
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define ERROR
Definition: elog.h:39
#define PG_CATCH(...)
Definition: elog.h:381
#define ereport(elevel,...)
Definition: elog.h:149
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:138
ExprState * ExecInitQual(List *qual, PlanState *parent)
Definition: execExpr.c:224
List * ExecInitExprList(List *nodes, PlanState *parent)
Definition: execExpr.c:330
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
Definition: execScan.c:156
void ExecAssignScanProjectionInfo(ScanState *node)
Definition: execScan.c:270
void ExecScanReScan(ScanState *node)
Definition: execScan.c:297
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1998
void ExecInitResultTypeTL(PlanState *planstate)
Definition: execTuples.c:1942
const TupleTableSlotOps TTSOpsMinimalTuple
Definition: execTuples.c:86
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:485
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
Definition: executor.h:487
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
Definition: executor.h:486
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:346
#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:130
static struct @161 value
int i
Definition: isn.c:72
const TableFuncRoutine JsonbTableRoutine
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
Definition: lsyscache.c:2874
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
void * palloc(Size size)
Definition: mcxt.c:1317
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
void ExecReScanTableFuncScan(TableFuncScanState *node)
void ExecEndTableFuncScan(TableFuncScanState *node)
static bool TableFuncRecheck(TableFuncScanState *node, TupleTableSlot *slot)
static void tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc)
TableFuncScanState * ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
static void tfuncLoadRows(TableFuncScanState *tstate, ExprContext *econtext)
static void tfuncFetchRows(TableFuncScanState *tstate, ExprContext *econtext)
static TupleTableSlot * ExecTableFuncScan(PlanState *pstate)
static TupleTableSlot * TableFuncNext(TableFuncScanState *node)
#define makeNode(_type_)
Definition: nodes.h:155
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
#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:518
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:182
#define outerPlan(node)
Definition: plannodes.h:183
uintptr_t Datum
Definition: postgres.h:64
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
unsigned int Oid
Definition: postgres_ext.h:31
@ TFT_XMLTABLE
Definition: primnodes.h:99
MemoryContextSwitchTo(old_ctx)
MemoryContext ecxt_per_tuple_memory
Definition: execnodes.h:266
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:265
Definition: fmgr.h:57
ExprState * qual
Definition: execnodes.h:1147
Plan * plan
Definition: execnodes.h:1126
EState * state
Definition: execnodes.h:1128
Bitmapset * chgParam
Definition: execnodes.h:1158
ExprContext * ps_ExprContext
Definition: execnodes.h:1165
TupleTableSlot * ps_ResultTupleSlot
Definition: execnodes.h:1164
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:1132
TupleTableSlot * ss_ScanTupleSlot
Definition: execnodes.h:1576
PlanState ps
Definition: execnodes.h:1573
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:2005
Tuplestorestate * tupstore
Definition: execnodes.h:2006
Bitmapset * notnulls
Definition: execnodes.h:1999
const struct TableFuncRoutine * routine
Definition: execnodes.h:2001
ExprState * rowexpr
Definition: execnodes.h:1992
FmgrInfo * in_functions
Definition: execnodes.h:2002
List * passingvalexprs
Definition: execnodes.h:1996
ExprState * docexpr
Definition: execnodes.h:1991
TableFunc * tablefunc
Definition: plannodes.h:634
Node * docexpr
Definition: primnodes.h:119
Node * rowexpr
Definition: primnodes.h:121
List * colexprs
Definition: primnodes.h:131
TableFuncType functype
Definition: primnodes.h:113
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:1006
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:152
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
Definition: tuplestore.c:1130
void tuplestore_rescan(Tuplestorestate *state)
Definition: tuplestore.c:1285
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:330
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:492
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
#define strVal(v)
Definition: value.h:82
const TableFuncRoutine XmlTableRoutine
Definition: xml.c:223