Commit fb22b320 authored by Tom Lane's avatar Tom Lane

Allow functions returning void or cstring to appear in FROM clause,

to make life cushy for the JDBC driver.  Centralize the decision-making
that affects this by inventing a get_type_func_class() function, rather
than adding special cases in half a dozen places.
parent 857e210e
......@@ -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,
......
......@@ -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
......
......@@ -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:
......
......@@ -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
*
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment