aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/gram.y71
-rw-r--r--src/backend/parser/parse_clause.c4
-rw-r--r--src/backend/parser/parse_relation.c336
3 files changed, 305 insertions, 106 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c794dd7d80e..53759b80296 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.354 2002/08/04 06:51:23 thomas Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.355 2002/08/04 19:48:09 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -215,7 +215,8 @@ static void doNegateFloat(Value *v);
target_list, update_target_list, insert_column_list,
insert_target_list, def_list, opt_indirection,
group_clause, TriggerFuncArgs, select_limit,
- opt_select_limit, opclass_item_list, trans_options
+ opt_select_limit, opclass_item_list, trans_options,
+ tableFuncElementList
%type <range> into_clause, OptTempTableName
@@ -256,8 +257,8 @@ static void doNegateFloat(Value *v);
%type <vsetstmt> set_rest
-%type <node> OptTableElement, ConstraintElem
-%type <node> columnDef
+%type <node> OptTableElement, ConstraintElem, tableFuncElement
+%type <node> columnDef, tableFuncColumnDef
%type <defelt> def_elem
%type <node> def_arg, columnElem, where_clause, insert_column_item,
a_expr, b_expr, c_expr, r_expr, AexprConst,
@@ -4448,6 +4449,34 @@ table_ref: relation_expr
{
RangeFunction *n = makeNode(RangeFunction);
n->funccallnode = $1;
+ n->coldeflist = NIL;
+ $$ = (Node *) n;
+ }
+ | func_table AS '(' tableFuncElementList ')'
+ {
+ RangeFunction *n = makeNode(RangeFunction);
+ n->funccallnode = $1;
+ n->coldeflist = $4;
+ $$ = (Node *) n;
+ }
+ | func_table AS ColId '(' tableFuncElementList ')'
+ {
+ RangeFunction *n = makeNode(RangeFunction);
+ Alias *a = makeNode(Alias);
+ n->funccallnode = $1;
+ a->aliasname = $3;
+ n->alias = a;
+ n->coldeflist = $5;
+ $$ = (Node *) n;
+ }
+ | func_table ColId '(' tableFuncElementList ')'
+ {
+ RangeFunction *n = makeNode(RangeFunction);
+ Alias *a = makeNode(Alias);
+ n->funccallnode = $1;
+ a->aliasname = $2;
+ n->alias = a;
+ n->coldeflist = $4;
$$ = (Node *) n;
}
| func_table alias_clause
@@ -4455,6 +4484,7 @@ table_ref: relation_expr
RangeFunction *n = makeNode(RangeFunction);
n->funccallnode = $1;
n->alias = $2;
+ n->coldeflist = NIL;
$$ = (Node *) n;
}
| select_with_parens
@@ -4703,6 +4733,39 @@ where_clause:
;
+tableFuncElementList:
+ tableFuncElementList ',' tableFuncElement
+ {
+ if ($3 != NULL)
+ $$ = lappend($1, $3);
+ else
+ $$ = $1;
+ }
+ | tableFuncElement
+ {
+ if ($1 != NULL)
+ $$ = makeList1($1);
+ else
+ $$ = NIL;
+ }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+tableFuncElement:
+ tableFuncColumnDef { $$ = $1; }
+ ;
+
+tableFuncColumnDef: ColId Typename
+ {
+ ColumnDef *n = makeNode(ColumnDef);
+ n->colname = $1;
+ n->typename = $2;
+ n->constraints = NIL;
+
+ $$ = (Node *)n;
+ }
+ ;
+
/*****************************************************************************
*
* Type syntax
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 81328798eb5..ae87b056f3e 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.94 2002/06/20 20:29:32 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.95 2002/08/04 19:48:10 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -515,7 +515,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
* OK, build an RTE for the function.
*/
rte = addRangeTableEntryForFunction(pstate, funcname, funcexpr,
- r->alias, true);
+ r, true);
/*
* We create a RangeTblRef, but we do not add it to the joinlist or
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 99b639d73e3..6a4bda5d62b 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.71 2002/08/02 18:15:07 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.72 2002/08/04 19:48:10 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -699,12 +699,14 @@ RangeTblEntry *
addRangeTableEntryForFunction(ParseState *pstate,
char *funcname,
Node *funcexpr,
- Alias *alias,
+ RangeFunction *rangefunc,
bool inFromCl)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
Oid funcrettype = exprType(funcexpr);
- Oid funcrelid;
+ char functyptype;
+ Alias *alias = rangefunc->alias;
+ List *coldeflist = rangefunc->coldeflist;
Alias *eref;
int numaliases;
int varattno;
@@ -713,6 +715,7 @@ addRangeTableEntryForFunction(ParseState *pstate,
rte->relid = InvalidOid;
rte->subquery = NULL;
rte->funcexpr = funcexpr;
+ rte->coldeflist = coldeflist;
rte->alias = alias;
eref = alias ? (Alias *) copyObject(alias) : makeAlias(funcname, NIL);
@@ -724,47 +727,56 @@ addRangeTableEntryForFunction(ParseState *pstate,
* Now determine if the function returns a simple or composite type,
* and check/add column aliases.
*/
- funcrelid = typeidTypeRelid(funcrettype);
+ functyptype = typeid_get_typtype(funcrettype);
- if (OidIsValid(funcrelid))
+ if (functyptype == 'c')
{
/*
- * Composite data type, i.e. a table's row type
- *
- * Get the rel's relcache entry. This access ensures that we have an
- * up-to-date relcache entry for the rel.
+ * Named composite data type, i.e. a table's row type
*/
- Relation rel;
- int maxattrs;
+ Oid funcrelid = typeidTypeRelid(funcrettype);
- rel = heap_open(funcrelid, AccessShareLock);
+ if (OidIsValid(funcrelid))
+ {
+ /*
+ * Get the rel's relcache entry. This access ensures that we have an
+ * up-to-date relcache entry for the rel.
+ */
+ Relation rel;
+ int maxattrs;
- /*
- * Since the rel is open anyway, let's check that the number of column
- * aliases is reasonable.
- */
- maxattrs = RelationGetNumberOfAttributes(rel);
- if (maxattrs < numaliases)
- elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
- RelationGetRelationName(rel), maxattrs, numaliases);
+ rel = heap_open(funcrelid, AccessShareLock);
- /* fill in alias columns using actual column names */
- for (varattno = numaliases; varattno < maxattrs; varattno++)
- {
- char *attrname;
+ /*
+ * Since the rel is open anyway, let's check that the number of column
+ * aliases is reasonable.
+ */
+ maxattrs = RelationGetNumberOfAttributes(rel);
+ if (maxattrs < numaliases)
+ elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
+ RelationGetRelationName(rel), maxattrs, numaliases);
- attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
- eref->colnames = lappend(eref->colnames, makeString(attrname));
- }
+ /* fill in alias columns using actual column names */
+ for (varattno = numaliases; varattno < maxattrs; varattno++)
+ {
+ char *attrname;
- /*
- * Drop the rel refcount, but keep the access lock till end of
- * transaction so that the table can't be deleted or have its schema
- * modified underneath us.
- */
- heap_close(rel, NoLock);
+ attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
+ eref->colnames = lappend(eref->colnames, makeString(attrname));
+ }
+
+ /*
+ * Drop the rel refcount, but keep the access lock till end of
+ * transaction so that the table can't be deleted or have its schema
+ * modified underneath us.
+ */
+ heap_close(rel, NoLock);
+ }
+ else
+ elog(ERROR, "Invalid return relation specified for function %s",
+ funcname);
}
- else
+ else if (functyptype == 'b')
{
/*
* Must be a base data type, i.e. scalar.
@@ -776,6 +788,22 @@ addRangeTableEntryForFunction(ParseState *pstate,
if (numaliases == 0)
eref->colnames = makeList1(makeString(funcname));
}
+ else if (functyptype == 'p' && funcrettype == RECORDOID)
+ {
+ List *col;
+
+ foreach(col, coldeflist)
+ {
+ char *attrname;
+ ColumnDef *n = lfirst(col);
+
+ attrname = pstrdup(n->colname);
+ eref->colnames = lappend(eref->colnames, makeString(attrname));
+ }
+ }
+ else
+ elog(ERROR, "Unknown kind of return type specified for function %s",
+ funcname);
/*----------
* Flags:
@@ -1051,56 +1079,70 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
case RTE_FUNCTION:
{
/* Function RTE */
- Oid funcrettype = exprType(rte->funcexpr);
- Oid funcrelid = typeidTypeRelid(funcrettype);
+ Oid funcrettype = exprType(rte->funcexpr);
+ char functyptype = typeid_get_typtype(funcrettype);
+ List *coldeflist = rte->coldeflist;
- if (OidIsValid(funcrelid))
+ /*
+ * Build a suitable tupledesc representing the output rows
+ */
+ if (functyptype == 'c')
{
- /*
- * Composite data type, i.e. a table's row type
- * Same as ordinary relation RTE
- */
- Relation rel;
- int maxattrs;
- int numaliases;
-
- rel = heap_open(funcrelid, AccessShareLock);
- maxattrs = RelationGetNumberOfAttributes(rel);
- numaliases = length(rte->eref->colnames);
-
- for (varattno = 0; varattno < maxattrs; varattno++)
+ Oid funcrelid = typeidTypeRelid(funcrettype);
+ if (OidIsValid(funcrelid))
{
- Form_pg_attribute attr = rel->rd_att->attrs[varattno];
- if (attr->attisdropped)
- continue;
+ /*
+ * Composite data type, i.e. a table's row type
+ * Same as ordinary relation RTE
+ */
+ Relation rel;
+ int maxattrs;
+ int numaliases;
- if (colnames)
- {
- char *label;
+ rel = heap_open(funcrelid, AccessShareLock);
+ maxattrs = RelationGetNumberOfAttributes(rel);
+ numaliases = length(rte->eref->colnames);
- if (varattno < numaliases)
- label = strVal(nth(varattno, rte->eref->colnames));
- else
- label = NameStr(attr->attname);
- *colnames = lappend(*colnames, makeString(pstrdup(label)));
- }
-
- if (colvars)
+ for (varattno = 0; varattno < maxattrs; varattno++)
{
- Var *varnode;
-
- varnode = makeVar(rtindex, attr->attnum,
- attr->atttypid, attr->atttypmod,
- sublevels_up);
-
- *colvars = lappend(*colvars, varnode);
+ Form_pg_attribute attr = rel->rd_att->attrs[varattno];
+
+ if (attr->attisdropped)
+ continue;
+
+ if (colnames)
+ {
+ char *label;
+
+ if (varattno < numaliases)
+ label = strVal(nth(varattno, rte->eref->colnames));
+ else
+ label = NameStr(attr->attname);
+ *colnames = lappend(*colnames, makeString(pstrdup(label)));
+ }
+
+ if (colvars)
+ {
+ Var *varnode;
+
+ varnode = makeVar(rtindex,
+ attr->attnum,
+ attr->atttypid,
+ attr->atttypmod,
+ sublevels_up);
+
+ *colvars = lappend(*colvars, varnode);
+ }
}
- }
- heap_close(rel, AccessShareLock);
+ heap_close(rel, AccessShareLock);
+ }
+ else
+ elog(ERROR, "Invalid return relation specified"
+ " for function");
}
- else
+ else if (functyptype == 'b')
{
/*
* Must be a base data type, i.e. scalar
@@ -1120,6 +1162,47 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
*colvars = lappend(*colvars, varnode);
}
}
+ else if (functyptype == 'p' && funcrettype == RECORDOID)
+ {
+ List *col;
+ int attnum = 0;
+
+ foreach(col, coldeflist)
+ {
+ ColumnDef *colDef = lfirst(col);
+
+ attnum++;
+ if (colnames)
+ {
+ char *attrname;
+
+ attrname = pstrdup(colDef->colname);
+ *colnames = lappend(*colnames, makeString(attrname));
+ }
+
+ if (colvars)
+ {
+ Var *varnode;
+ HeapTuple typeTuple;
+ Oid atttypid;
+
+ typeTuple = typenameType(colDef->typename);
+ atttypid = HeapTupleGetOid(typeTuple);
+ ReleaseSysCache(typeTuple);
+
+ varnode = makeVar(rtindex,
+ attnum,
+ atttypid,
+ -1,
+ sublevels_up);
+
+ *colvars = lappend(*colvars, varnode);
+ }
+ }
+ }
+ else
+ elog(ERROR, "Unknown kind of return type specified"
+ " for function");
}
break;
case RTE_JOIN:
@@ -1308,40 +1391,52 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
case RTE_FUNCTION:
{
/* Function RTE */
- Oid funcrettype = exprType(rte->funcexpr);
- Oid funcrelid = typeidTypeRelid(funcrettype);
+ Oid funcrettype = exprType(rte->funcexpr);
+ char functyptype = typeid_get_typtype(funcrettype);
+ List *coldeflist = rte->coldeflist;
- if (OidIsValid(funcrelid))
+ /*
+ * Build a suitable tupledesc representing the output rows
+ */
+ if (functyptype == 'c')
{
/*
* Composite data type, i.e. a table's row type
* Same as ordinary relation RTE
*/
- HeapTuple tp;
- Form_pg_attribute att_tup;
+ Oid funcrelid = typeidTypeRelid(funcrettype);
- tp = SearchSysCache(ATTNUM,
- ObjectIdGetDatum(funcrelid),
- Int16GetDatum(attnum),
- 0, 0);
- /* this shouldn't happen... */
- if (!HeapTupleIsValid(tp))
- elog(ERROR, "Relation %s does not have attribute %d",
- get_rel_name(funcrelid), attnum);
- att_tup = (Form_pg_attribute) GETSTRUCT(tp);
- /*
- * If dropped column, pretend it ain't there. See notes
- * in scanRTEForColumn.
- */
- if (att_tup->attisdropped)
- elog(ERROR, "Relation \"%s\" has no column \"%s\"",
- get_rel_name(funcrelid),
- NameStr(att_tup->attname));
- *vartype = att_tup->atttypid;
- *vartypmod = att_tup->atttypmod;
- ReleaseSysCache(tp);
+ if (OidIsValid(funcrelid))
+ {
+ HeapTuple tp;
+ Form_pg_attribute att_tup;
+
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(funcrelid),
+ Int16GetDatum(attnum),
+ 0, 0);
+ /* this shouldn't happen... */
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "Relation %s does not have attribute %d",
+ get_rel_name(funcrelid), attnum);
+ att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ /*
+ * If dropped column, pretend it ain't there. See notes
+ * in scanRTEForColumn.
+ */
+ if (att_tup->attisdropped)
+ elog(ERROR, "Relation \"%s\" has no column \"%s\"",
+ get_rel_name(funcrelid),
+ NameStr(att_tup->attname));
+ *vartype = att_tup->atttypid;
+ *vartypmod = att_tup->atttypmod;
+ ReleaseSysCache(tp);
+ }
+ else
+ elog(ERROR, "Invalid return relation specified"
+ " for function");
}
- else
+ else if (functyptype == 'b')
{
/*
* Must be a base data type, i.e. scalar
@@ -1349,6 +1444,22 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
*vartype = funcrettype;
*vartypmod = -1;
}
+ else if (functyptype == 'p' && funcrettype == RECORDOID)
+ {
+ ColumnDef *colDef = nth(attnum - 1, coldeflist);
+ HeapTuple typeTuple;
+ Oid atttypid;
+
+ typeTuple = typenameType(colDef->typename);
+ atttypid = HeapTupleGetOid(typeTuple);
+ ReleaseSysCache(typeTuple);
+
+ *vartype = atttypid;
+ *vartypmod = -1;
+ }
+ else
+ elog(ERROR, "Unknown kind of return type specified"
+ " for function");
}
break;
case RTE_JOIN:
@@ -1576,3 +1687,28 @@ warnAutoRange(ParseState *pstate, RangeVar *relation)
pstate->parentParseState != NULL ? " in subquery" : "",
relation->relname);
}
+
+char
+typeid_get_typtype(Oid typeid)
+{
+ HeapTuple typeTuple;
+ Form_pg_type typeStruct;
+ char result;
+
+ /*
+ * determine if the function returns a simple, named composite,
+ * or anonymous composite type
+ */
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typeid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup for type %u failed", typeid);
+ typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ result = typeStruct->typtype;
+
+ ReleaseSysCache(typeTuple);
+
+ return result;
+}