1/*-------------------------------------------------------------------------
4 * Support routines for scanning RangeTableFunc (XMLTABLE like functions).
6 * Portions Copyright (c) 1996-2025, 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
43/* ----------------------------------------------------------------
45 * ----------------------------------------------------------------
47/* ----------------------------------------------------------------
50 * This is a workhorse for ExecTableFuncScan
51 * ----------------------------------------------------------------
61 * If first time through, read all tuples from function and put them in a
62 * tuplestore. Subsequent calls just fetch tuples from tuplestore.
68 * Get the next tuple from tuplestore.
78 * TableFuncRecheck -- access method routine to recheck a tuple in EvalPlanQual
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 * ----------------------------------------------------------------
106/* ----------------------------------------------------------------
107 * ExecInitTableFuncScan
108 * ----------------------------------------------------------------
118 /* check for unsupported flags */
122 * TableFuncscan should not have any children.
128 * create new ScanState for node
136 * Miscellaneous initialization
138 * create expression context for node
143 * initialize source tuple type
149 /* and the corresponding scan slot */
154 * Initialize result type and projection.
160 * initialize child expressions
165 /* Only XMLTABLE and JSON_TABLE are supported currently */
171 "TableFunc per value context",
173 scanstate->
opaque = NULL;
/* initialized at runtime */
194 /* these are allocated now and initialized later */
199 * Fill in the necessary fmgr infos.
201 for (
i = 0;
i < tupdesc->
natts;
i++)
213/* ----------------------------------------------------------------
214 * ExecEndTableFuncScan
216 * frees any storage allocated through C routines.
217 * ----------------------------------------------------------------
223 * Release tuplestore resources
230/* ----------------------------------------------------------------
231 * ExecReScanTableFuncScan
233 * Rescans the relation.
234 * ----------------------------------------------------------------
246 * Recompute when parameters are changed.
261/* ----------------------------------------------------------------
264 * Read rows from a TableFunc producer
265 * ----------------------------------------------------------------
277 /* build tuplestore for the result */
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
298 * If evaluating the document expression returns NULL, the table
299 * expression is empty and we return immediately.
305 /* otherwise, pass the document value to the table builder */
308 /* initialize ordinality counter */
311 /* Load all rows into the tuplestore, and we're done */
317 if (tstate->
opaque != NULL)
323 /* clean up and return to original memory context */
325 if (tstate->
opaque != NULL)
336 * Fill in namespace declarations, the row filter, and column filters in a
337 * table expression builder context.
353 * Install the document as a possibly-toasted Datum into the tablefunc
358 /* Evaluate namespace specifications */
369 (
errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
370 errmsg(
"namespace URI must not be null")));
373 /* DEFAULT is passed down to SetNamespace as NULL */
374 ns_name = ns_node ?
strVal(ns_node) : NULL;
380 * Install the row filter expression, if any, into the table builder
388 (
errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
389 errmsg(
"row filter expression must not be null")));
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.
406 if (colno != ordinalitycol)
415 (
errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
416 errmsg(
"column filter expression must not be null"),
417 errdetail(
"Filter for column \"%s\" is null.",
422 colfilter =
NameStr(att->attname);
432 * Load all the rows from the TableFunc table builder into a tuplestore.
442 int natts = tupdesc->
natts;
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
458 * Keep requesting rows from the table builder until there aren't any.
470 * Obtain the value of each column for this row, installing them into
471 * the slot; then add the tuple to the tuplestore.
473 for (colno = 0; colno < natts; colno++)
477 if (colno == ordinalitycol)
479 /* Fast path for ordinality column */
481 nulls[colno] =
false;
493 /* No value? Evaluate and apply the default, if any */
494 if (isnull && cell != NULL)
498 if (coldefexpr != NULL)
503 /* Verify a possible NOT NULL constraint */
506 (
errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
507 errmsg(
"null is not allowed in column \"%s\"",
510 nulls[colno] = isnull;
513 /* advance list of default expressions */
bool bms_is_member(int x, const Bitmapset *a)
static Datum values[MAXATTR]
#define TextDatumGetCString(d)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
ExprState * ExecInitQual(List *qual, PlanState *parent)
List * ExecInitExprList(List *nodes, PlanState *parent)
TupleTableSlot * ExecScan(ScanState *node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd)
void ExecAssignScanProjectionInfo(ScanState *node)
void ExecScanReScan(ScanState *node)
void ExecInitScanTupleSlot(EState *estate, ScanState *scanstate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
void ExecInitResultTypeTL(PlanState *planstate)
const TupleTableSlotOps TTSOpsMinimalTuple
void ExecAssignExprContext(EState *estate, PlanState *planstate)
bool(* ExecScanRecheckMtd)(ScanState *node, TupleTableSlot *slot)
TupleTableSlot *(* ExecScanAccessMtd)(ScanState *node)
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
void fmgr_info(Oid functionId, FmgrInfo *finfo)
Assert(PointerIsAligned(start, uint64))
const TableFuncRoutine JsonbTableRoutine
void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
void MemoryContextReset(MemoryContext context)
MemoryContext CurrentMemoryContext
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
#define CHECK_FOR_INTERRUPTS()
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 castNode(_type_, nodeptr)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
FormData_pg_attribute * Form_pg_attribute
#define lfirst_node(type, lc)
#define forboth(cell1, list1, cell2, list2)
static ListCell * list_head(const List *l)
static ListCell * lnext(const List *l, const ListCell *c)
static Datum Int32GetDatum(int32 X)
MemoryContext ecxt_per_tuple_memory
MemoryContext ecxt_per_query_memory
ExprContext * ps_ExprContext
TupleTableSlot * ps_ResultTupleSlot
ExecProcNodeMtd ExecProcNode
TupleTableSlot * ss_ScanTupleSlot
void(* SetNamespace)(TableFuncScanState *state, const char *name, const char *uri)
void(* SetDocument)(TableFuncScanState *state, Datum value)
void(* DestroyOpaque)(TableFuncScanState *state)
void(* SetColumnFilter)(TableFuncScanState *state, const char *path, int colnum)
void(* InitOpaque)(TableFuncScanState *state, int natts)
Datum(* GetValue)(TableFuncScanState *state, int colnum, Oid typid, int32 typmod, bool *isnull)
bool(* FetchRow)(TableFuncScanState *state)
void(* SetRowFilter)(TableFuncScanState *state, const char *path)
MemoryContext perTableCxt
Tuplestorestate * tupstore
const struct TableFuncRoutine * routine
TupleDesc tts_tupleDescriptor
TupleDesc BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
void tuplestore_rescan(Tuplestorestate *state)
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
void tuplestore_end(Tuplestorestate *state)
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
const TableFuncRoutine XmlTableRoutine