aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_relation.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_relation.c')
-rw-r--r--src/backend/parser/parse_relation.c336
1 files changed, 236 insertions, 100 deletions
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;
+}