summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/analyze.c9
-rw-r--r--src/backend/parser/gram.y189
-rw-r--r--src/backend/parser/parse_clause.c245
-rw-r--r--src/backend/parser/parse_coerce.c33
-rw-r--r--src/backend/parser/parse_relation.c79
-rw-r--r--src/backend/parser/parse_target.c7
6 files changed, 547 insertions, 15 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 796b5c9a5f9..3571e50aea4 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -2772,6 +2772,15 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
LCS_asString(lc->strength)),
parser_errposition(pstate, thisrel->location)));
break;
+ case RTE_TABLEFUNC:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ /*------
+ translator: %s is a SQL row locking clause such as FOR UPDATE */
+ errmsg("%s cannot be applied to a table function",
+ LCS_asString(lc->strength)),
+ parser_errposition(pstate, thisrel->location)));
+ break;
case RTE_VALUES:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index bb55e1c95cc..e7acc2d9a23 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -464,7 +464,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <defelt> def_elem reloption_elem old_aggr_elem operator_def_elem
%type <node> def_arg columnElem where_clause where_or_current_clause
a_expr b_expr c_expr AexprConst indirection_el opt_slice_bound
- columnref in_expr having_clause func_table array_expr
+ columnref in_expr having_clause func_table xmltable array_expr
ExclusionWhereClause
%type <list> rowsfrom_item rowsfrom_list opt_col_def_list
%type <boolean> opt_ordinality
@@ -550,6 +550,11 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <node> xmlexists_argument
%type <ival> document_or_content
%type <boolean> xml_whitespace_option
+%type <list> xmltable_column_list xmltable_column_option_list
+%type <node> xmltable_column_el
+%type <defelt> xmltable_column_option_el
+%type <list> xml_namespace_list
+%type <target> xml_namespace_el
%type <node> func_application func_expr_common_subexpr
%type <node> func_expr func_expr_windowless
@@ -607,7 +612,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
CACHE CALLED CASCADE CASCADED CASE CAST CATALOG_P CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
- CLUSTER COALESCE COLLATE COLLATION COLUMN COMMENT COMMENTS COMMIT
+ CLUSTER COALESCE COLLATE COLLATION COLUMN COLUMNS COMMENT COMMENTS COMMIT
COMMITTED CONCURRENTLY CONFIGURATION CONFLICT CONNECTION CONSTRAINT
CONSTRAINTS CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE
CROSS CSV CUBE CURRENT_P
@@ -681,8 +686,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
WHEN WHERE WHITESPACE_P WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITE
- XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLEXISTS XMLFOREST XMLPARSE
- XMLPI XMLROOT XMLSERIALIZE
+ XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLEXISTS XMLFOREST XMLNAMESPACES
+ XMLPARSE XMLPI XMLROOT XMLSERIALIZE XMLTABLE
YEAR_P YES_P
@@ -11187,6 +11192,19 @@ table_ref: relation_expr opt_alias_clause
n->coldeflist = lsecond($3);
$$ = (Node *) n;
}
+ | xmltable opt_alias_clause
+ {
+ RangeTableFunc *n = (RangeTableFunc *) $1;
+ n->alias = $2;
+ $$ = (Node *) n;
+ }
+ | LATERAL_P xmltable opt_alias_clause
+ {
+ RangeTableFunc *n = (RangeTableFunc *) $2;
+ n->lateral = true;
+ n->alias = $3;
+ $$ = (Node *) n;
+ }
| select_with_parens opt_alias_clause
{
RangeSubselect *n = makeNode(RangeSubselect);
@@ -11626,6 +11644,166 @@ TableFuncElement: ColId Typename opt_collate_clause
}
;
+/*
+ * XMLTABLE
+ */
+xmltable:
+ XMLTABLE '(' c_expr xmlexists_argument COLUMNS xmltable_column_list ')'
+ {
+ RangeTableFunc *n = makeNode(RangeTableFunc);
+ n->rowexpr = $3;
+ n->docexpr = $4;
+ n->columns = $6;
+ n->namespaces = NIL;
+ n->location = @1;
+ $$ = (Node *)n;
+ }
+ | XMLTABLE '(' XMLNAMESPACES '(' xml_namespace_list ')' ','
+ c_expr xmlexists_argument COLUMNS xmltable_column_list ')'
+ {
+ RangeTableFunc *n = makeNode(RangeTableFunc);
+ n->rowexpr = $8;
+ n->docexpr = $9;
+ n->columns = $11;
+ n->namespaces = $5;
+ n->location = @1;
+ $$ = (Node *)n;
+ }
+ ;
+
+xmltable_column_list: xmltable_column_el { $$ = list_make1($1); }
+ | xmltable_column_list ',' xmltable_column_el { $$ = lappend($1, $3); }
+ ;
+
+xmltable_column_el:
+ ColId Typename
+ {
+ RangeTableFuncCol *fc = makeNode(RangeTableFuncCol);
+
+ fc->colname = $1;
+ fc->for_ordinality = false;
+ fc->typeName = $2;
+ fc->is_not_null = false;
+ fc->colexpr = NULL;
+ fc->coldefexpr = NULL;
+ fc->location = @1;
+
+ $$ = (Node *) fc;
+ }
+ | ColId Typename xmltable_column_option_list
+ {
+ RangeTableFuncCol *fc = makeNode(RangeTableFuncCol);
+ ListCell *option;
+ bool nullability_seen = false;
+
+ fc->colname = $1;
+ fc->typeName = $2;
+ fc->for_ordinality = false;
+ fc->is_not_null = false;
+ fc->colexpr = NULL;
+ fc->coldefexpr = NULL;
+ fc->location = @1;
+
+ foreach(option, $3)
+ {
+ DefElem *defel = (DefElem *) lfirst(option);
+
+ if (strcmp(defel->defname, "default") == 0)
+ {
+ if (fc->coldefexpr != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("only one DEFAULT value is allowed"),
+ parser_errposition(defel->location)));
+ fc->coldefexpr = defel->arg;
+ }
+ else if (strcmp(defel->defname, "path") == 0)
+ {
+ if (fc->colexpr != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("only one PATH value per column is allowed"),
+ parser_errposition(defel->location)));
+ fc->colexpr = defel->arg;
+ }
+ else if (strcmp(defel->defname, "is_not_null") == 0)
+ {
+ if (nullability_seen)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant NULL / NOT NULL declarations for column \"%s\"", fc->colname),
+ parser_errposition(defel->location)));
+ fc->is_not_null = intVal(defel->arg);
+ nullability_seen = true;
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("unrecognized column option \"%s\"",
+ defel->defname),
+ parser_errposition(defel->location)));
+ }
+ }
+ $$ = (Node *) fc;
+ }
+ | ColId FOR ORDINALITY
+ {
+ RangeTableFuncCol *fc = makeNode(RangeTableFuncCol);
+
+ fc->colname = $1;
+ fc->for_ordinality = true;
+ /* other fields are ignored, initialized by makeNode */
+ fc->location = @1;
+
+ $$ = (Node *) fc;
+ }
+ ;
+
+xmltable_column_option_list:
+ xmltable_column_option_el
+ { $$ = list_make1($1); }
+ | xmltable_column_option_list xmltable_column_option_el
+ { $$ = lappend($1, $2); }
+ ;
+
+xmltable_column_option_el:
+ IDENT b_expr
+ { $$ = makeDefElem($1, $2, @1); }
+ | DEFAULT b_expr
+ { $$ = makeDefElem("default", $2, @1); }
+ | NOT NULL_P
+ { $$ = makeDefElem("is_not_null", (Node *) makeInteger(true), @1); }
+ | NULL_P
+ { $$ = makeDefElem("is_not_null", (Node *) makeInteger(false), @1); }
+ ;
+
+xml_namespace_list:
+ xml_namespace_el
+ { $$ = list_make1($1); }
+ | xml_namespace_list ',' xml_namespace_el
+ { $$ = lappend($1, $3); }
+ ;
+
+xml_namespace_el:
+ b_expr AS ColLabel
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = $3;
+ $$->indirection = NIL;
+ $$->val = $1;
+ $$->location = @1;
+ }
+ | DEFAULT b_expr
+ {
+ $$ = makeNode(ResTarget);
+ $$->name = NULL;
+ $$->indirection = NIL;
+ $$->val = $2;
+ $$->location = @1;
+ }
+ ;
+
/*****************************************************************************
*
* Type syntax
@@ -14205,6 +14383,7 @@ unreserved_keyword:
| CLASS
| CLOSE
| CLUSTER
+ | COLUMNS
| COMMENT
| COMMENTS
| COMMIT
@@ -14510,10 +14689,12 @@ col_name_keyword:
| XMLELEMENT
| XMLEXISTS
| XMLFOREST
+ | XMLNAMESPACES
| XMLPARSE
| XMLPI
| XMLROOT
| XMLSERIALIZE
+ | XMLTABLE
;
/* Type/function identifier --- keywords that can be type or function names.
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index b5eae56006d..47ca685b568 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -22,6 +22,7 @@
#include "catalog/catalog.h"
#include "catalog/heap.h"
#include "catalog/pg_am.h"
+#include "catalog/pg_collation.h"
#include "catalog/pg_constraint_fn.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
@@ -65,6 +66,8 @@ static RangeTblEntry *transformRangeSubselect(ParseState *pstate,
RangeSubselect *r);
static RangeTblEntry *transformRangeFunction(ParseState *pstate,
RangeFunction *r);
+static RangeTblEntry *transformRangeTableFunc(ParseState *pstate,
+ RangeTableFunc *t);
static TableSampleClause *transformRangeTableSample(ParseState *pstate,
RangeTableSample *rts);
static Node *transformFromClauseItem(ParseState *pstate, Node *n,
@@ -693,6 +696,229 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
}
/*
+ * transformRangeTableFunc -
+ * Transform a raw RangeTableFunc into TableFunc.
+ *
+ * Transform the namespace clauses, the document-generating expression, the
+ * row-generating expression, the column-generating expressions, and the
+ * default value expressions.
+ */
+static RangeTblEntry *
+transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
+{
+ TableFunc *tf = makeNode(TableFunc);
+ const char *constructName;
+ Oid docType;
+ RangeTblEntry *rte;
+ bool is_lateral;
+ ListCell *col;
+ char **names;
+ int colno;
+
+ /* Currently only XMLTABLE is supported */
+ constructName = "XMLTABLE";
+ docType = XMLOID;
+
+ /*
+ * We make lateral_only names of this level visible, whether or not the
+ * RangeTableFunc is explicitly marked LATERAL. This is needed for SQL
+ * spec compliance and seems useful on convenience grounds for all
+ * functions in FROM.
+ *
+ * (LATERAL can't nest within a single pstate level, so we don't need
+ * save/restore logic here.)
+ */
+ Assert(!pstate->p_lateral_active);
+ pstate->p_lateral_active = true;
+
+ /* Transform and apply typecast to the row-generating expression ... */
+ Assert(rtf->rowexpr != NULL);
+ tf->rowexpr = coerce_to_specific_type(pstate,
+ transformExpr(pstate, rtf->rowexpr, EXPR_KIND_FROM_FUNCTION),
+ TEXTOID,
+ constructName);
+ assign_expr_collations(pstate, tf->rowexpr);
+
+ /* ... and to the document itself */
+ Assert(rtf->docexpr != NULL);
+ tf->docexpr = coerce_to_specific_type(pstate,
+ transformExpr(pstate, rtf->docexpr, EXPR_KIND_FROM_FUNCTION),
+ docType,
+ constructName);
+ assign_expr_collations(pstate, tf->docexpr);
+
+ /* undef ordinality column number */
+ tf->ordinalitycol = -1;
+
+
+ names = palloc(sizeof(char *) * list_length(rtf->columns));
+
+ colno = 0;
+ foreach(col, rtf->columns)
+ {
+ RangeTableFuncCol *rawc = (RangeTableFuncCol *) lfirst(col);
+ Oid typid;
+ int32 typmod;
+ Node *colexpr;
+ Node *coldefexpr;
+ int j;
+
+ tf->colnames = lappend(tf->colnames,
+ makeString(pstrdup(rawc->colname)));
+
+ /*
+ * Determine the type and typmod for the new column. FOR
+ * ORDINALITY columns are INTEGER per spec; the others are
+ * user-specified.
+ */
+ if (rawc->for_ordinality)
+ {
+ if (tf->ordinalitycol != -1)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("only one FOR ORDINALITY column is allowed"),
+ parser_errposition(pstate, rawc->location)));
+
+ typid = INT4OID;
+ typmod = -1;
+ tf->ordinalitycol = colno;
+ }
+ else
+ {
+ if (rawc->typeName->setof)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ errmsg("column \"%s\" cannot be declared SETOF",
+ rawc->colname),
+ parser_errposition(pstate, rawc->location)));
+
+ typenameTypeIdAndMod(pstate, rawc->typeName,
+ &typid, &typmod);
+ }
+
+ tf->coltypes = lappend_oid(tf->coltypes, typid);
+ tf->coltypmods = lappend_int(tf->coltypmods, typmod);
+ tf->colcollations = lappend_oid(tf->colcollations,
+ type_is_collatable(typid) ? DEFAULT_COLLATION_OID : InvalidOid);
+
+ /* Transform the PATH and DEFAULT expressions */
+ if (rawc->colexpr)
+ {
+ colexpr = coerce_to_specific_type(pstate,
+ transformExpr(pstate, rawc->colexpr,
+ EXPR_KIND_FROM_FUNCTION),
+ TEXTOID,
+ constructName);
+ assign_expr_collations(pstate, colexpr);
+ }
+ else
+ colexpr = NULL;
+
+ if (rawc->coldefexpr)
+ {
+ coldefexpr = coerce_to_specific_type_typmod(pstate,
+ transformExpr(pstate, rawc->coldefexpr,
+ EXPR_KIND_FROM_FUNCTION),
+ typid, typmod,
+ constructName);
+ assign_expr_collations(pstate, coldefexpr);
+ }
+ else
+ coldefexpr = NULL;
+
+ tf->colexprs = lappend(tf->colexprs, colexpr);
+ tf->coldefexprs = lappend(tf->coldefexprs, coldefexpr);
+
+ if (rawc->is_not_null)
+ tf->notnulls = bms_add_member(tf->notnulls, colno);
+
+ /* make sure column names are unique */
+ for (j = 0; j < colno; j++)
+ if (strcmp(names[j], rawc->colname) == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("column name \"%s\" is not unique",
+ rawc->colname),
+ parser_errposition(pstate, rawc->location)));
+ names[colno] = rawc->colname;
+
+ colno++;
+ }
+ pfree(names);
+
+ /* Namespaces, if any, also need to be transformed */
+ if (rtf->namespaces != NIL)
+ {
+ ListCell *ns;
+ ListCell *lc2;
+ List *ns_uris = NIL;
+ List *ns_names = NIL;
+ bool default_ns_seen = false;
+
+ foreach(ns, rtf->namespaces)
+ {
+ ResTarget *r = (ResTarget *) lfirst(ns);
+ Node *ns_uri;
+
+ Assert(IsA(r, ResTarget));
+ ns_uri = transformExpr(pstate, r->val, EXPR_KIND_FROM_FUNCTION);
+ ns_uri = coerce_to_specific_type(pstate, ns_uri,
+ TEXTOID, constructName);
+ assign_expr_collations(pstate, ns_uri);
+ ns_uris = lappend(ns_uris, ns_uri);
+
+ /* Verify consistency of name list: no dupes, only one DEFAULT */
+ if (r->name != NULL)
+ {
+ foreach(lc2, ns_names)
+ {
+ char *name = strVal(lfirst(lc2));
+
+ if (name == NULL)
+ continue;
+ if (strcmp(name, r->name) == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("namespace name \"%s\" is not unique",
+ name),
+ parser_errposition(pstate, r->location)));
+ }
+ }
+ else
+ {
+ if (default_ns_seen)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("only one default namespace is allowed"),
+ parser_errposition(pstate, r->location)));
+ default_ns_seen = true;
+ }
+
+ /* Note the string may be NULL */
+ ns_names = lappend(ns_names, makeString(r->name));
+ }
+
+ tf->ns_uris = ns_uris;
+ tf->ns_names = ns_names;
+ }
+
+ tf->location = rtf->location;
+
+ pstate->p_lateral_active = false;
+
+ /*
+ * Mark the RTE as LATERAL if the user said LATERAL explicitly, or if
+ * there are any lateral cross-references in it.
+ */
+ is_lateral = rtf->lateral || contain_vars_of_level((Node *) tf, 0);
+
+ rte = addRangeTableEntryForTableFunc(pstate,
+ tf, rtf->alias, is_lateral, true);
+
+ return rte;
+}
+
+/*
* transformRangeTableSample --- transform a TABLESAMPLE clause
*
* Caller has already transformed rts->relation, we just have to validate
@@ -795,7 +1021,6 @@ transformRangeTableSample(ParseState *pstate, RangeTableSample *rts)
return tablesample;
}
-
/*
* transformFromClauseItem -
* Transform a FROM-clause item, adding any required entries to the
@@ -891,6 +1116,24 @@ transformFromClauseItem(ParseState *pstate, Node *n,
rtr->rtindex = rtindex;
return (Node *) rtr;
}
+ else if (IsA(n, RangeTableFunc))
+ {
+ /* table function is like a plain relation */
+ RangeTblRef *rtr;
+ RangeTblEntry *rte;
+ int rtindex;
+
+ rte = transformRangeTableFunc(pstate, (RangeTableFunc *) n);
+ /* assume new rte is at end */
+ rtindex = list_length(pstate->p_rtable);
+ Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
+ *top_rte = rte;
+ *top_rti = rtindex;
+ *namespace = list_make1(makeDefaultNSItem(rte));
+ rtr = makeNode(RangeTblRef);
+ rtr->rtindex = rtindex;
+ return (Node *) rtr;
+ }
else if (IsA(n, RangeTableSample))
{
/* TABLESAMPLE clause (wrapping some other valid FROM node) */
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 2a2ac321573..2c3f3cd9ce7 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -1096,9 +1096,9 @@ coerce_to_boolean(ParseState *pstate, Node *node,
}
/*
- * coerce_to_specific_type()
- * Coerce an argument of a construct that requires a specific data type.
- * Also check that input is not a set.
+ * coerce_to_specific_type_typmod()
+ * Coerce an argument of a construct that requires a specific data type,
+ * with a specific typmod. Also check that input is not a set.
*
* Returns the possibly-transformed node tree.
*
@@ -1106,9 +1106,9 @@ coerce_to_boolean(ParseState *pstate, Node *node,
* processing is wanted.
*/
Node *
-coerce_to_specific_type(ParseState *pstate, Node *node,
- Oid targetTypeId,
- const char *constructName)
+coerce_to_specific_type_typmod(ParseState *pstate, Node *node,
+ Oid targetTypeId, int32 targetTypmod,
+ const char *constructName)
{
Oid inputTypeId = exprType(node);
@@ -1117,7 +1117,7 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
Node *newnode;
newnode = coerce_to_target_type(pstate, node, inputTypeId,
- targetTypeId, -1,
+ targetTypeId, targetTypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
-1);
@@ -1144,6 +1144,25 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
return node;
}
+/*
+ * coerce_to_specific_type()
+ * Coerce an argument of a construct that requires a specific data type.
+ * Also check that input is not a set.
+ *
+ * Returns the possibly-transformed node tree.
+ *
+ * As with coerce_type, pstate may be NULL if no special unknown-Param
+ * processing is wanted.
+ */
+Node *
+coerce_to_specific_type(ParseState *pstate, Node *node,
+ Oid targetTypeId,
+ const char *constructName)
+{
+ return coerce_to_specific_type_typmod(pstate, node,
+ targetTypeId, -1,
+ constructName);
+}
/*
* parser_coercion_errposition - report coercion error location, if possible
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index cf69533b53d..2eea258d28d 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -1628,6 +1628,69 @@ addRangeTableEntryForFunction(ParseState *pstate,
}
/*
+ * Add an entry for a table function to the pstate's range table (p_rtable).
+ *
+ * This is much like addRangeTableEntry() except that it makes a tablefunc RTE.
+ */
+RangeTblEntry *
+addRangeTableEntryForTableFunc(ParseState *pstate,
+ TableFunc *tf,
+ Alias *alias,
+ bool lateral,
+ bool inFromCl)
+{
+ RangeTblEntry *rte = makeNode(RangeTblEntry);
+ char *refname = alias ? alias->aliasname : pstrdup("xmltable");
+ Alias *eref;
+ int numaliases;
+
+ Assert(pstate != NULL);
+
+ rte->rtekind = RTE_TABLEFUNC;
+ rte->relid = InvalidOid;
+ rte->subquery = NULL;
+ rte->tablefunc = tf;
+ rte->coltypes = tf->coltypes;
+ rte->coltypmods = tf->coltypmods;
+ rte->colcollations = tf->colcollations;
+ rte->alias = alias;
+
+ eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
+ numaliases = list_length(eref->colnames);
+
+ /* fill in any unspecified alias columns */
+ if (numaliases < list_length(tf->colnames))
+ eref->colnames = list_concat(eref->colnames,
+ list_copy_tail(tf->colnames, numaliases));
+
+ rte->eref = eref;
+
+ /*
+ * Set flags and access permissions.
+ *
+ * Tablefuncs are never checked for access rights (at least, not by the
+ * RTE permissions mechanism).
+ */
+ rte->lateral = lateral;
+ rte->inh = false; /* never true for tablefunc RTEs */
+ rte->inFromCl = inFromCl;
+
+ rte->requiredPerms = 0;
+ rte->checkAsUser = InvalidOid;
+ rte->selectedCols = NULL;
+ rte->insertedCols = NULL;
+ rte->updatedCols = NULL;
+
+ /*
+ * Add completed RTE to pstate's range table list, but not to join list
+ * nor namespace --- caller must do that if appropriate.
+ */
+ pstate->p_rtable = lappend(pstate->p_rtable, rte);
+
+ return rte;
+}
+
+/*
* Add an entry for a VALUES list to the pstate's range table (p_rtable).
*
* This is much like addRangeTableEntry() except that it makes a values RTE.
@@ -2226,10 +2289,11 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
}
}
break;
+ case RTE_TABLEFUNC:
case RTE_VALUES:
case RTE_CTE:
{
- /* Values or CTE RTE */
+ /* Tablefunc, Values or CTE RTE */
ListCell *aliasp_item = list_head(rte->eref->colnames);
ListCell *lct;
ListCell *lcm;
@@ -2638,10 +2702,14 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
*varcollid = exprCollation(aliasvar);
}
break;
+ case RTE_TABLEFUNC:
case RTE_VALUES:
case RTE_CTE:
{
- /* VALUES or CTE RTE --- get type info from lists in the RTE */
+ /*
+ * tablefunc, VALUES or CTE RTE --- get type info from lists
+ * in the RTE
+ */
Assert(attnum > 0 && attnum <= list_length(rte->coltypes));
*vartype = list_nth_oid(rte->coltypes, attnum - 1);
*vartypmod = list_nth_int(rte->coltypmods, attnum - 1);
@@ -2684,9 +2752,14 @@ get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum)
}
break;
case RTE_SUBQUERY:
+ case RTE_TABLEFUNC:
case RTE_VALUES:
case RTE_CTE:
- /* Subselect, Values, CTE RTEs never have dropped columns */
+
+ /*
+ * Subselect, Table Functions, Values, CTE RTEs never have dropped
+ * columns
+ */
result = false;
break;
case RTE_JOIN:
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 2576e312390..3b84140a9be 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -396,6 +396,7 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
break;
case RTE_FUNCTION:
case RTE_VALUES:
+ case RTE_TABLEFUNC:
/* not a simple relation, leave it unmarked */
break;
case RTE_CTE:
@@ -1557,6 +1558,12 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
* its result columns as RECORD, which is not allowed.
*/
break;
+ case RTE_TABLEFUNC:
+
+ /*
+ * Table function cannot have columns with RECORD type.
+ */
+ break;
case RTE_CTE:
/* CTE reference: examine subquery's output expr */
if (!rte->self_reference)