diff options
Diffstat (limited to 'src/backend/parser/parse_relation.c')
-rw-r--r-- | src/backend/parser/parse_relation.c | 336 |
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; +} |