diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index ed932d35ab693cea76c196bab77ae5b5e2d248de..b85b7eb5e6532cc914928fc0f787c0a7f3b33366 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.106 2004/08/29 05:06:39 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.107 2004/10/20 16:04:47 tgl Exp $ * * NOTES * some of the executor utility code such as "ExecTypeFromTL" should be @@ -607,13 +607,13 @@ RelationNameGetTupleDesc(const char *relname) TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases) { - char functyptype = get_typtype(typeoid); + TypeFuncClass functypclass = get_type_func_class(typeoid); TupleDesc tupdesc = NULL; /* * Build a suitable tupledesc representing the output rows */ - if (functyptype == 'c') + if (functypclass == TYPEFUNC_COMPOSITE) { /* Composite data type, e.g. a table's row type */ tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(typeoid, -1)); @@ -643,9 +643,9 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases) tupdesc->tdtypmod = -1; } } - else if (functyptype == 'b' || functyptype == 'd') + else if (functypclass == TYPEFUNC_SCALAR) { - /* Must be a base data type, i.e. scalar */ + /* Base data type, i.e. scalar */ char *attname; /* the alias list is required for base types */ @@ -671,7 +671,7 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases) -1, 0); } - else if (typeoid == RECORDOID) + else if (functypclass == TYPEFUNC_RECORD) { /* XXX can't support this because typmod wasn't passed in ... */ ereport(ERROR, diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index 032235b8f3e4cf13df85e25a5d4c35ff221989c3..8407eafb9b851496345dabe1532ccc4cbc746e6c 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.27 2004/09/22 17:41:51 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.28 2004/10/20 16:04:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -132,7 +132,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate) FunctionScanState *scanstate; RangeTblEntry *rte; Oid funcrettype; - char functyptype; + TypeFuncClass functypclass; TupleDesc tupdesc = NULL; /* @@ -184,16 +184,16 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate) * Now determine if the function returns a simple or composite type, * and build an appropriate tupdesc. */ - functyptype = get_typtype(funcrettype); + functypclass = get_type_func_class(funcrettype); - if (functyptype == 'c') + if (functypclass == TYPEFUNC_COMPOSITE) { /* Composite data type, e.g. a table's row type */ tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(funcrettype, -1)); } - else if (functyptype == 'b' || functyptype == 'd') + else if (functypclass == TYPEFUNC_SCALAR) { - /* Must be a base data type, i.e. scalar */ + /* Base data type, i.e. scalar */ char *attname = strVal(linitial(rte->eref->colnames)); tupdesc = CreateTemplateTupleDesc(1, false); @@ -204,9 +204,8 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate) -1, 0); } - else if (funcrettype == RECORDOID) + else if (functypclass == TYPEFUNC_RECORD) { - /* Must be a pseudo type, i.e. record */ tupdesc = BuildDescForRelation(rte->coldeflist); } else diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 442170a2eee8cadbb7bdb3919cacaa60bd67b55a..84781f4d4aac9af2ae9f434ca3e9155ffffe3589 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.100 2004/08/29 05:06:44 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.101 2004/10/20 16:04:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -966,7 +966,7 @@ addRangeTableEntryForFunction(ParseState *pstate, { RangeTblEntry *rte = makeNode(RangeTblEntry); Oid funcrettype = exprType(funcexpr); - char functyptype; + TypeFuncClass functypclass; Alias *alias = rangefunc->alias; List *coldeflist = rangefunc->coldeflist; Alias *eref; @@ -1008,18 +1008,15 @@ addRangeTableEntryForFunction(ParseState *pstate, errmsg("a column definition list is required for functions returning \"record\""))); } - functyptype = get_typtype(funcrettype); + functypclass = get_type_func_class(funcrettype); - if (functyptype == 'c') + if (functypclass == TYPEFUNC_COMPOSITE) { - /* - * Named composite data type, i.e. a table's row type - */ + /* Composite data type, e.g. a table's row type */ Oid funcrelid = typeidTypeRelid(funcrettype); Relation rel; - if (!OidIsValid(funcrelid)) /* shouldn't happen if typtype is - * 'c' */ + if (!OidIsValid(funcrelid)) /* shouldn't happen */ elog(ERROR, "invalid typrelid for complex type %u", funcrettype); /* @@ -1038,12 +1035,10 @@ addRangeTableEntryForFunction(ParseState *pstate, */ relation_close(rel, NoLock); } - else if (functyptype == 'b' || functyptype == 'd') + else if (functypclass == TYPEFUNC_SCALAR) { - /* - * Must be a base data type, i.e. scalar. Just add one alias - * column named for the function. - */ + /* Base data type, i.e. scalar */ + /* Just add one alias column named for the function. */ if (alias && alias->colnames != NIL) { if (list_length(alias->colnames) != 1) @@ -1056,7 +1051,7 @@ addRangeTableEntryForFunction(ParseState *pstate, else eref->colnames = list_make1(makeString(eref->aliasname)); } - else if (functyptype == 'p' && funcrettype == RECORDOID) + else if (functypclass == TYPEFUNC_RECORD) { ListCell *col; @@ -1073,8 +1068,8 @@ addRangeTableEntryForFunction(ParseState *pstate, else ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("function \"%s\" in FROM has unsupported return type", - funcname))); + errmsg("function \"%s\" in FROM has unsupported return type %s", + funcname, format_type_be(funcrettype)))); /*---------- * Flags: @@ -1314,9 +1309,9 @@ expandRTE(List *rtable, int rtindex, int sublevels_up, { /* Function RTE */ Oid funcrettype = exprType(rte->funcexpr); - char functyptype = get_typtype(funcrettype); + TypeFuncClass functypclass = get_type_func_class(funcrettype); - if (functyptype == 'c') + if (functypclass == TYPEFUNC_COMPOSITE) { /* * Composite data type, i.e. a table's row type @@ -1332,11 +1327,9 @@ expandRTE(List *rtable, int rtindex, int sublevels_up, expandRelation(funcrelid, rte->eref, rtindex, sublevels_up, include_dropped, colnames, colvars); } - else if (functyptype == 'b' || functyptype == 'd') + else if (functypclass == TYPEFUNC_SCALAR) { - /* - * Must be a base data type, i.e. scalar - */ + /* Base data type, i.e. scalar */ if (colnames) *colnames = lappend(*colnames, linitial(rte->eref->colnames)); @@ -1352,7 +1345,7 @@ expandRTE(List *rtable, int rtindex, int sublevels_up, *colvars = lappend(*colvars, varnode); } } - else if (functyptype == 'p' && funcrettype == RECORDOID) + else if (functypclass == TYPEFUNC_RECORD) { List *coldeflist = rte->coldeflist; ListCell *col; @@ -1389,9 +1382,10 @@ expandRTE(List *rtable, int rtindex, int sublevels_up, } } else - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("function in FROM has unsupported return type"))); + { + /* addRangeTableEntryForFunction should've caught this */ + elog(ERROR, "function in FROM has unsupported return type"); + } } break; case RTE_JOIN: @@ -1669,14 +1663,15 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, { /* Function RTE */ Oid funcrettype = exprType(rte->funcexpr); - char functyptype = get_typtype(funcrettype); + TypeFuncClass functypclass = get_type_func_class(funcrettype); List *coldeflist = rte->coldeflist; - if (functyptype == 'c') + if (functypclass == TYPEFUNC_COMPOSITE) { /* - * Composite data type, i.e. a table's row type Same - * as ordinary relation RTE + * Composite data type, i.e. a table's row type + * + * Same as ordinary relation RTE */ Oid funcrelid = typeidTypeRelid(funcrettype); HeapTuple tp; @@ -1709,15 +1704,13 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, *vartypmod = att_tup->atttypmod; ReleaseSysCache(tp); } - else if (functyptype == 'b' || functyptype == 'd') + else if (functypclass == TYPEFUNC_SCALAR) { - /* - * Must be a base data type, i.e. scalar - */ + /* Base data type, i.e. scalar */ *vartype = funcrettype; *vartypmod = -1; } - else if (functyptype == 'p' && funcrettype == RECORDOID) + else if (functypclass == TYPEFUNC_RECORD) { ColumnDef *colDef = list_nth(coldeflist, attnum - 1); @@ -1725,9 +1718,10 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, *vartypmod = -1; } else - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("function in FROM has unsupported return type"))); + { + /* addRangeTableEntryForFunction should've caught this */ + elog(ERROR, "function in FROM has unsupported return type"); + } } break; case RTE_JOIN: diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 9dc2bbd524b08c17b5d77c51559a8e075ff60239..2e3848947c85092b849449f3ae38bffc8a33efa1 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.116 2004/08/29 05:06:50 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.117 2004/10/20 16:04:49 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -1547,6 +1547,42 @@ get_typtype(Oid typid) return '\0'; } +/* + * get_type_func_class + * + * Given the type OID, obtain its TYPEFUNC classification. + * + * This is intended to centralize a bunch of formerly ad-hoc code for + * classifying types. The categories used here are useful for deciding + * how to handle functions returning the datatype. + */ +TypeFuncClass +get_type_func_class(Oid typid) +{ + switch (get_typtype(typid)) + { + case 'c': + return TYPEFUNC_COMPOSITE; + case 'b': + case 'd': + return TYPEFUNC_SCALAR; + case 'p': + if (typid == RECORDOID) + return TYPEFUNC_RECORD; + /* + * We treat VOID and CSTRING as legitimate scalar datatypes, + * mostly for the convenience of the JDBC driver (which wants + * to be able to do "SELECT * FROM foo()" for all legitimately + * user-callable functions). + */ + if (typid == VOIDOID || typid == CSTRINGOID) + return TYPEFUNC_SCALAR; + return TYPEFUNC_OTHER; + } + /* shouldn't get here, probably */ + return TYPEFUNC_OTHER; +} + /* * get_typ_typrelid * diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index 496d2bcf11fea07d46e8f05dce5f51b025c5f917..3a016b7a52d48a40cadbce346aa0a65578a87284 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.90 2004/08/29 05:06:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.91 2004/10/20 16:04:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,6 +24,15 @@ typedef enum IOFuncSelector IOFunc_send } IOFuncSelector; +/* Type categories for get_type_func_class */ +typedef enum TypeFuncClass +{ + TYPEFUNC_SCALAR, + TYPEFUNC_COMPOSITE, + TYPEFUNC_RECORD, + TYPEFUNC_OTHER +} TypeFuncClass; + extern bool op_in_opclass(Oid opno, Oid opclass); extern void get_op_opclass_properties(Oid opno, Oid opclass, int *strategy, Oid *subtype, @@ -85,6 +94,7 @@ extern char get_typstorage(Oid typid); extern int32 get_typtypmod(Oid typid); extern Node *get_typdefault(Oid typid); extern char get_typtype(Oid typid); +extern TypeFuncClass get_type_func_class(Oid typid); extern Oid get_typ_typrelid(Oid typid); extern Oid get_element_type(Oid typid); extern Oid get_array_type(Oid typid);