]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Allow functions returning void or cstring to appear in FROM clause,
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 20 Oct 2004 16:04:50 +0000 (16:04 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 20 Oct 2004 16:04:50 +0000 (16:04 +0000)
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.

src/backend/access/common/tupdesc.c
src/backend/executor/nodeFunctionscan.c
src/backend/parser/parse_relation.c
src/backend/utils/cache/lsyscache.c
src/include/utils/lsyscache.h

index ed932d35ab693cea76c196bab77ae5b5e2d248de..b85b7eb5e6532cc914928fc0f787c0a7f3b33366 100644 (file)
@@ -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,
index 032235b8f3e4cf13df85e25a5d4c35ff221989c3..8407eafb9b851496345dabe1532ccc4cbc746e6c 100644 (file)
@@ -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
index 442170a2eee8cadbb7bdb3919cacaa60bd67b55a..84781f4d4aac9af2ae9f434ca3e9155ffffe3589 100644 (file)
@@ -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:
index 9dc2bbd524b08c17b5d77c51559a8e075ff60239..2e3848947c85092b849449f3ae38bffc8a33efa1 100644 (file)
@@ -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
  *
index 496d2bcf11fea07d46e8f05dce5f51b025c5f917..3a016b7a52d48a40cadbce346aa0a65578a87284 100644 (file)
@@ -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);