mirror of
https://github.com/postgres/postgres.git
synced 2025-08-30 06:01:21 +03:00
Support XMLTABLE query expression
XMLTABLE is defined by the SQL/XML standard as a feature that allows turning XML-formatted data into relational form, so that it can be used as a <table primary> in the FROM clause of a query. This new construct provides significant simplicity and performance benefit for XML data processing; what in a client-side custom implementation was reported to take 20 minutes can be executed in 400ms using XMLTABLE. (The same functionality was said to take 10 seconds using nested PostgreSQL XPath function calls, and 5 seconds using XMLReader under PL/Python). The implemented syntax deviates slightly from what the standard requires. First, the standard indicates that the PASSING clause is optional and that multiple XML input documents may be given to it; we make it mandatory and accept a single document only. Second, we don't currently support a default namespace to be specified. This implementation relies on a new executor node based on a hardcoded method table. (Because the grammar is fixed, there is no extensibility in the current approach; further constructs can be implemented on top of this such as JSON_TABLE, but they require changes to core code.) Author: Pavel Stehule, Álvaro Herrera Extensively reviewed by: Craig Ringer Discussion: https://postgr.es/m/CAFj8pRAgfzMD-LoSmnMGybD0WsEznLHWap8DO79+-GTRAPR4qA@mail.gmail.com
This commit is contained in:
@@ -587,6 +587,27 @@ _copyFunctionScan(const FunctionScan *from)
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyTableFuncScan
|
||||
*/
|
||||
static TableFuncScan *
|
||||
_copyTableFuncScan(const TableFuncScan *from)
|
||||
{
|
||||
TableFuncScan *newnode = makeNode(TableFuncScan);
|
||||
|
||||
/*
|
||||
* copy node superclass fields
|
||||
*/
|
||||
CopyScanFields((const Scan *) from, (Scan *) newnode);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_NODE_FIELD(tablefunc);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyValuesScan
|
||||
*/
|
||||
@@ -1138,6 +1159,31 @@ _copyRangeVar(const RangeVar *from)
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyTableFunc
|
||||
*/
|
||||
static TableFunc *
|
||||
_copyTableFunc(const TableFunc *from)
|
||||
{
|
||||
TableFunc *newnode = makeNode(TableFunc);
|
||||
|
||||
COPY_NODE_FIELD(ns_names);
|
||||
COPY_NODE_FIELD(ns_uris);
|
||||
COPY_NODE_FIELD(docexpr);
|
||||
COPY_NODE_FIELD(rowexpr);
|
||||
COPY_NODE_FIELD(colnames);
|
||||
COPY_NODE_FIELD(coltypes);
|
||||
COPY_NODE_FIELD(coltypmods);
|
||||
COPY_NODE_FIELD(colcollations);
|
||||
COPY_NODE_FIELD(colexprs);
|
||||
COPY_NODE_FIELD(coldefexprs);
|
||||
COPY_BITMAPSET_FIELD(notnulls);
|
||||
COPY_SCALAR_FIELD(ordinalitycol);
|
||||
COPY_LOCATION_FIELD(location);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* _copyIntoClause
|
||||
*/
|
||||
@@ -2169,6 +2215,7 @@ _copyRangeTblEntry(const RangeTblEntry *from)
|
||||
COPY_NODE_FIELD(joinaliasvars);
|
||||
COPY_NODE_FIELD(functions);
|
||||
COPY_SCALAR_FIELD(funcordinality);
|
||||
COPY_NODE_FIELD(tablefunc);
|
||||
COPY_NODE_FIELD(values_lists);
|
||||
COPY_STRING_FIELD(ctename);
|
||||
COPY_SCALAR_FIELD(ctelevelsup);
|
||||
@@ -2590,6 +2637,38 @@ _copyRangeTableSample(const RangeTableSample *from)
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static RangeTableFunc *
|
||||
_copyRangeTableFunc(const RangeTableFunc *from)
|
||||
{
|
||||
RangeTableFunc *newnode = makeNode(RangeTableFunc);
|
||||
|
||||
COPY_SCALAR_FIELD(lateral);
|
||||
COPY_NODE_FIELD(docexpr);
|
||||
COPY_NODE_FIELD(rowexpr);
|
||||
COPY_NODE_FIELD(namespaces);
|
||||
COPY_NODE_FIELD(columns);
|
||||
COPY_NODE_FIELD(alias);
|
||||
COPY_LOCATION_FIELD(location);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static RangeTableFuncCol *
|
||||
_copyRangeTableFuncCol(const RangeTableFuncCol *from)
|
||||
{
|
||||
RangeTableFuncCol *newnode = makeNode(RangeTableFuncCol);
|
||||
|
||||
COPY_STRING_FIELD(colname);
|
||||
COPY_NODE_FIELD(typeName);
|
||||
COPY_SCALAR_FIELD(for_ordinality);
|
||||
COPY_SCALAR_FIELD(is_not_null);
|
||||
COPY_NODE_FIELD(colexpr);
|
||||
COPY_NODE_FIELD(coldefexpr);
|
||||
COPY_LOCATION_FIELD(location);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static TypeCast *
|
||||
_copyTypeCast(const TypeCast *from)
|
||||
{
|
||||
@@ -4540,6 +4619,9 @@ copyObject(const void *from)
|
||||
case T_FunctionScan:
|
||||
retval = _copyFunctionScan(from);
|
||||
break;
|
||||
case T_TableFuncScan:
|
||||
retval = _copyTableFuncScan(from);
|
||||
break;
|
||||
case T_ValuesScan:
|
||||
retval = _copyValuesScan(from);
|
||||
break;
|
||||
@@ -4616,6 +4698,9 @@ copyObject(const void *from)
|
||||
case T_RangeVar:
|
||||
retval = _copyRangeVar(from);
|
||||
break;
|
||||
case T_TableFunc:
|
||||
retval = _copyTableFunc(from);
|
||||
break;
|
||||
case T_IntoClause:
|
||||
retval = _copyIntoClause(from);
|
||||
break;
|
||||
@@ -5210,6 +5295,12 @@ copyObject(const void *from)
|
||||
case T_RangeTableSample:
|
||||
retval = _copyRangeTableSample(from);
|
||||
break;
|
||||
case T_RangeTableFunc:
|
||||
retval = _copyRangeTableFunc(from);
|
||||
break;
|
||||
case T_RangeTableFuncCol:
|
||||
retval = _copyRangeTableFuncCol(from);
|
||||
break;
|
||||
case T_TypeName:
|
||||
retval = _copyTypeName(from);
|
||||
break;
|
||||
|
@@ -116,6 +116,26 @@ _equalRangeVar(const RangeVar *a, const RangeVar *b)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalTableFunc(const TableFunc *a, const TableFunc *b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(ns_names);
|
||||
COMPARE_NODE_FIELD(ns_uris);
|
||||
COMPARE_NODE_FIELD(docexpr);
|
||||
COMPARE_NODE_FIELD(rowexpr);
|
||||
COMPARE_NODE_FIELD(colnames);
|
||||
COMPARE_NODE_FIELD(coltypes);
|
||||
COMPARE_NODE_FIELD(coltypes);
|
||||
COMPARE_NODE_FIELD(colcollations);
|
||||
COMPARE_NODE_FIELD(colexprs);
|
||||
COMPARE_NODE_FIELD(coldefexprs);
|
||||
COMPARE_BITMAPSET_FIELD(notnulls);
|
||||
COMPARE_SCALAR_FIELD(ordinalitycol);
|
||||
COMPARE_LOCATION_FIELD(location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalIntoClause(const IntoClause *a, const IntoClause *b)
|
||||
{
|
||||
@@ -2419,6 +2439,36 @@ _equalRangeTableSample(const RangeTableSample *a, const RangeTableSample *b)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalRangeTableFunc(const RangeTableFunc *a, const RangeTableFunc *b)
|
||||
{
|
||||
COMPARE_SCALAR_FIELD(lateral);
|
||||
COMPARE_NODE_FIELD(docexpr);
|
||||
COMPARE_NODE_FIELD(rowexpr);
|
||||
COMPARE_NODE_FIELD(namespaces);
|
||||
COMPARE_NODE_FIELD(columns);
|
||||
COMPARE_NODE_FIELD(alias);
|
||||
COMPARE_LOCATION_FIELD(location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalRangeTableFuncCol(const RangeTableFuncCol *a, const RangeTableFuncCol *b)
|
||||
{
|
||||
COMPARE_STRING_FIELD(colname);
|
||||
COMPARE_NODE_FIELD(typeName);
|
||||
COMPARE_SCALAR_FIELD(for_ordinality);
|
||||
COMPARE_NODE_FIELD(typeName);
|
||||
COMPARE_SCALAR_FIELD(is_not_null);
|
||||
COMPARE_NODE_FIELD(colexpr);
|
||||
COMPARE_NODE_FIELD(coldefexpr);
|
||||
COMPARE_LOCATION_FIELD(location);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
_equalIndexElem(const IndexElem *a, const IndexElem *b)
|
||||
{
|
||||
@@ -2521,6 +2571,7 @@ _equalRangeTblEntry(const RangeTblEntry *a, const RangeTblEntry *b)
|
||||
COMPARE_SCALAR_FIELD(jointype);
|
||||
COMPARE_NODE_FIELD(joinaliasvars);
|
||||
COMPARE_NODE_FIELD(functions);
|
||||
COMPARE_NODE_FIELD(tablefunc);
|
||||
COMPARE_SCALAR_FIELD(funcordinality);
|
||||
COMPARE_NODE_FIELD(values_lists);
|
||||
COMPARE_STRING_FIELD(ctename);
|
||||
@@ -2887,6 +2938,9 @@ equal(const void *a, const void *b)
|
||||
case T_RangeVar:
|
||||
retval = _equalRangeVar(a, b);
|
||||
break;
|
||||
case T_TableFunc:
|
||||
retval = _equalTableFunc(a, b);
|
||||
break;
|
||||
case T_IntoClause:
|
||||
retval = _equalIntoClause(a, b);
|
||||
break;
|
||||
@@ -3468,6 +3522,12 @@ equal(const void *a, const void *b)
|
||||
case T_RangeTableSample:
|
||||
retval = _equalRangeTableSample(a, b);
|
||||
break;
|
||||
case T_RangeTableFunc:
|
||||
retval = _equalRangeTableFunc(a, b);
|
||||
break;
|
||||
case T_RangeTableFuncCol:
|
||||
retval = _equalRangeTableFuncCol(a, b);
|
||||
break;
|
||||
case T_TypeName:
|
||||
retval = _equalTypeName(a, b);
|
||||
break;
|
||||
|
@@ -210,10 +210,10 @@ makeWholeRowVar(RangeTblEntry *rte,
|
||||
default:
|
||||
|
||||
/*
|
||||
* RTE is a join, subselect, or VALUES. We represent this as a
|
||||
* whole-row Var of RECORD type. (Note that in most cases the Var
|
||||
* will be expanded to a RowExpr during planning, but that is not
|
||||
* our concern here.)
|
||||
* RTE is a join, subselect, tablefunc, or VALUES. We represent
|
||||
* this as a whole-row Var of RECORD type. (Note that in most
|
||||
* cases the Var will be expanded to a RowExpr during planning,
|
||||
* but that is not our concern here.)
|
||||
*/
|
||||
result = makeVar(varno,
|
||||
InvalidAttrNumber,
|
||||
|
@@ -1212,6 +1212,9 @@ exprLocation(const Node *expr)
|
||||
case T_RangeVar:
|
||||
loc = ((const RangeVar *) expr)->location;
|
||||
break;
|
||||
case T_TableFunc:
|
||||
loc = ((const TableFunc *) expr)->location;
|
||||
break;
|
||||
case T_Var:
|
||||
loc = ((const Var *) expr)->location;
|
||||
break;
|
||||
@@ -2211,6 +2214,22 @@ expression_tree_walker(Node *node,
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_TableFunc:
|
||||
{
|
||||
TableFunc *tf = (TableFunc *) node;
|
||||
|
||||
if (walker(tf->ns_uris, context))
|
||||
return true;
|
||||
if (walker(tf->docexpr, context))
|
||||
return true;
|
||||
if (walker(tf->rowexpr, context))
|
||||
return true;
|
||||
if (walker(tf->colexprs, context))
|
||||
return true;
|
||||
if (walker(tf->coldefexprs, context))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
(int) nodeTag(node));
|
||||
@@ -2318,6 +2337,10 @@ range_table_walker(List *rtable,
|
||||
if (walker(rte->functions, context))
|
||||
return true;
|
||||
break;
|
||||
case RTE_TABLEFUNC:
|
||||
if (walker(rte->tablefunc, context))
|
||||
return true;
|
||||
break;
|
||||
case RTE_VALUES:
|
||||
if (walker(rte->values_lists, context))
|
||||
return true;
|
||||
@@ -3007,6 +3030,20 @@ expression_tree_mutator(Node *node,
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_TableFunc:
|
||||
{
|
||||
TableFunc *tf = (TableFunc *) node;
|
||||
TableFunc *newnode;
|
||||
|
||||
FLATCOPY(newnode, tf, TableFunc);
|
||||
MUTATE(newnode->ns_uris, tf->ns_uris, List *);
|
||||
MUTATE(newnode->docexpr, tf->docexpr, Node *);
|
||||
MUTATE(newnode->rowexpr, tf->rowexpr, Node *);
|
||||
MUTATE(newnode->colexprs, tf->colexprs, List *);
|
||||
MUTATE(newnode->coldefexprs, tf->coldefexprs, List *);
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
(int) nodeTag(node));
|
||||
@@ -3124,6 +3161,9 @@ range_table_mutator(List *rtable,
|
||||
case RTE_FUNCTION:
|
||||
MUTATE(newrte->functions, rte->functions, List *);
|
||||
break;
|
||||
case RTE_TABLEFUNC:
|
||||
MUTATE(newrte->tablefunc, rte->tablefunc, TableFunc *);
|
||||
break;
|
||||
case RTE_VALUES:
|
||||
MUTATE(newrte->values_lists, rte->values_lists, List *);
|
||||
break;
|
||||
@@ -3548,6 +3588,32 @@ raw_expression_tree_walker(Node *node,
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_RangeTableFunc:
|
||||
{
|
||||
RangeTableFunc *rtf = (RangeTableFunc *) node;
|
||||
|
||||
if (walker(rtf->docexpr, context))
|
||||
return true;
|
||||
if (walker(rtf->rowexpr, context))
|
||||
return true;
|
||||
if (walker(rtf->namespaces, context))
|
||||
return true;
|
||||
if (walker(rtf->columns, context))
|
||||
return true;
|
||||
if (walker(rtf->alias, context))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_RangeTableFuncCol:
|
||||
{
|
||||
RangeTableFuncCol *rtfc = (RangeTableFuncCol *) node;
|
||||
|
||||
if (walker(rtfc->colexpr, context))
|
||||
return true;
|
||||
if (walker(rtfc->coldefexpr, context))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case T_TypeName:
|
||||
{
|
||||
TypeName *tn = (TypeName *) node;
|
||||
|
@@ -565,6 +565,16 @@ _outFunctionScan(StringInfo str, const FunctionScan *node)
|
||||
WRITE_BOOL_FIELD(funcordinality);
|
||||
}
|
||||
|
||||
static void
|
||||
_outTableFuncScan(StringInfo str, const TableFuncScan *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("TABLEFUNCSCAN");
|
||||
|
||||
_outScanInfo(str, (const Scan *) node);
|
||||
|
||||
WRITE_NODE_FIELD(tablefunc);
|
||||
}
|
||||
|
||||
static void
|
||||
_outValuesScan(StringInfo str, const ValuesScan *node)
|
||||
{
|
||||
@@ -955,6 +965,26 @@ _outRangeVar(StringInfo str, const RangeVar *node)
|
||||
WRITE_LOCATION_FIELD(location);
|
||||
}
|
||||
|
||||
static void
|
||||
_outTableFunc(StringInfo str, const TableFunc *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("TABLEFUNC");
|
||||
|
||||
WRITE_NODE_FIELD(ns_names);
|
||||
WRITE_NODE_FIELD(ns_uris);
|
||||
WRITE_NODE_FIELD(docexpr);
|
||||
WRITE_NODE_FIELD(rowexpr);
|
||||
WRITE_NODE_FIELD(colnames);
|
||||
WRITE_NODE_FIELD(coltypes);
|
||||
WRITE_NODE_FIELD(coltypmods);
|
||||
WRITE_NODE_FIELD(colcollations);
|
||||
WRITE_NODE_FIELD(colexprs);
|
||||
WRITE_NODE_FIELD(coldefexprs);
|
||||
WRITE_BITMAPSET_FIELD(notnulls);
|
||||
WRITE_INT_FIELD(ordinalitycol);
|
||||
WRITE_LOCATION_FIELD(location);
|
||||
}
|
||||
|
||||
static void
|
||||
_outIntoClause(StringInfo str, const IntoClause *node)
|
||||
{
|
||||
@@ -2869,6 +2899,9 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
|
||||
WRITE_NODE_FIELD(functions);
|
||||
WRITE_BOOL_FIELD(funcordinality);
|
||||
break;
|
||||
case RTE_TABLEFUNC:
|
||||
WRITE_NODE_FIELD(tablefunc);
|
||||
break;
|
||||
case RTE_VALUES:
|
||||
WRITE_NODE_FIELD(values_lists);
|
||||
WRITE_NODE_FIELD(coltypes);
|
||||
@@ -3191,6 +3224,34 @@ _outRangeTableSample(StringInfo str, const RangeTableSample *node)
|
||||
WRITE_LOCATION_FIELD(location);
|
||||
}
|
||||
|
||||
static void
|
||||
_outRangeTableFunc(StringInfo str, const RangeTableFunc *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("RANGETABLEFUNC");
|
||||
|
||||
WRITE_BOOL_FIELD(lateral);
|
||||
WRITE_NODE_FIELD(docexpr);
|
||||
WRITE_NODE_FIELD(rowexpr);
|
||||
WRITE_NODE_FIELD(namespaces);
|
||||
WRITE_NODE_FIELD(columns);
|
||||
WRITE_NODE_FIELD(alias);
|
||||
WRITE_LOCATION_FIELD(location);
|
||||
}
|
||||
|
||||
static void
|
||||
_outRangeTableFuncCol(StringInfo str, const RangeTableFuncCol *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("RANGETABLEFUNCCOL");
|
||||
|
||||
WRITE_STRING_FIELD(colname);
|
||||
WRITE_NODE_FIELD(typeName);
|
||||
WRITE_BOOL_FIELD(for_ordinality);
|
||||
WRITE_BOOL_FIELD(is_not_null);
|
||||
WRITE_NODE_FIELD(colexpr);
|
||||
WRITE_NODE_FIELD(coldefexpr);
|
||||
WRITE_LOCATION_FIELD(location);
|
||||
}
|
||||
|
||||
static void
|
||||
_outConstraint(StringInfo str, const Constraint *node)
|
||||
{
|
||||
@@ -3440,6 +3501,9 @@ outNode(StringInfo str, const void *obj)
|
||||
case T_FunctionScan:
|
||||
_outFunctionScan(str, obj);
|
||||
break;
|
||||
case T_TableFuncScan:
|
||||
_outTableFuncScan(str, obj);
|
||||
break;
|
||||
case T_ValuesScan:
|
||||
_outValuesScan(str, obj);
|
||||
break;
|
||||
@@ -3512,6 +3576,9 @@ outNode(StringInfo str, const void *obj)
|
||||
case T_RangeVar:
|
||||
_outRangeVar(str, obj);
|
||||
break;
|
||||
case T_TableFunc:
|
||||
_outTableFunc(str, obj);
|
||||
break;
|
||||
case T_IntoClause:
|
||||
_outIntoClause(str, obj);
|
||||
break;
|
||||
@@ -3922,6 +3989,12 @@ outNode(StringInfo str, const void *obj)
|
||||
case T_RangeTableSample:
|
||||
_outRangeTableSample(str, obj);
|
||||
break;
|
||||
case T_RangeTableFunc:
|
||||
_outRangeTableFunc(str, obj);
|
||||
break;
|
||||
case T_RangeTableFuncCol:
|
||||
_outRangeTableFuncCol(str, obj);
|
||||
break;
|
||||
case T_Constraint:
|
||||
_outConstraint(str, obj);
|
||||
break;
|
||||
|
@@ -279,6 +279,10 @@ print_rt(const List *rtable)
|
||||
printf("%d\t%s\t[rangefunction]",
|
||||
i, rte->eref->aliasname);
|
||||
break;
|
||||
case RTE_TABLEFUNC:
|
||||
printf("%d\t%s\t[table function]",
|
||||
i, rte->eref->aliasname);
|
||||
break;
|
||||
case RTE_VALUES:
|
||||
printf("%d\t%s\t[values list]",
|
||||
i, rte->eref->aliasname);
|
||||
|
@@ -458,6 +458,31 @@ _readRangeVar(void)
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
/*
|
||||
* _readTableFunc
|
||||
*/
|
||||
static TableFunc *
|
||||
_readTableFunc(void)
|
||||
{
|
||||
READ_LOCALS(TableFunc);
|
||||
|
||||
READ_NODE_FIELD(ns_names);
|
||||
READ_NODE_FIELD(ns_uris);
|
||||
READ_NODE_FIELD(docexpr);
|
||||
READ_NODE_FIELD(rowexpr);
|
||||
READ_NODE_FIELD(colnames);
|
||||
READ_NODE_FIELD(coltypes);
|
||||
READ_NODE_FIELD(coltypmods);
|
||||
READ_NODE_FIELD(colcollations);
|
||||
READ_NODE_FIELD(colexprs);
|
||||
READ_NODE_FIELD(coldefexprs);
|
||||
READ_BITMAPSET_FIELD(notnulls);
|
||||
READ_INT_FIELD(ordinalitycol);
|
||||
READ_LOCATION_FIELD(location);
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
static IntoClause *
|
||||
_readIntoClause(void)
|
||||
{
|
||||
@@ -1313,6 +1338,9 @@ _readRangeTblEntry(void)
|
||||
READ_NODE_FIELD(functions);
|
||||
READ_BOOL_FIELD(funcordinality);
|
||||
break;
|
||||
case RTE_TABLEFUNC:
|
||||
READ_NODE_FIELD(tablefunc);
|
||||
break;
|
||||
case RTE_VALUES:
|
||||
READ_NODE_FIELD(values_lists);
|
||||
READ_NODE_FIELD(coltypes);
|
||||
@@ -1798,6 +1826,21 @@ _readValuesScan(void)
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
/*
|
||||
* _readTableFuncScan
|
||||
*/
|
||||
static TableFuncScan *
|
||||
_readTableFuncScan(void)
|
||||
{
|
||||
READ_LOCALS(TableFuncScan);
|
||||
|
||||
ReadCommonScan(&local_node->scan);
|
||||
|
||||
READ_NODE_FIELD(tablefunc);
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
/*
|
||||
* _readCteScan
|
||||
*/
|
||||
@@ -2356,6 +2399,8 @@ parseNodeString(void)
|
||||
return_value = _readRangeVar();
|
||||
else if (MATCH("INTOCLAUSE", 10))
|
||||
return_value = _readIntoClause();
|
||||
else if (MATCH("TABLEFUNC", 9))
|
||||
return_value = _readTableFunc();
|
||||
else if (MATCH("VAR", 3))
|
||||
return_value = _readVar();
|
||||
else if (MATCH("CONST", 5))
|
||||
@@ -2498,6 +2543,8 @@ parseNodeString(void)
|
||||
return_value = _readFunctionScan();
|
||||
else if (MATCH("VALUESSCAN", 10))
|
||||
return_value = _readValuesScan();
|
||||
else if (MATCH("TABLEFUNCSCAN", 13))
|
||||
return_value = _readTableFuncScan();
|
||||
else if (MATCH("CTESCAN", 7))
|
||||
return_value = _readCteScan();
|
||||
else if (MATCH("WORKTABLESCAN", 13))
|
||||
|
Reference in New Issue
Block a user