Skip to content

Commit fb22b32

Browse files
committed
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.
1 parent 857e210 commit fb22b32

File tree

5 files changed

+94
-55
lines changed

5 files changed

+94
-55
lines changed

src/backend/access/common/tupdesc.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.106 2004/08/29 05:06:39 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.107 2004/10/20 16:04:47 tgl Exp $
1212
*
1313
* NOTES
1414
* some of the executor utility code such as "ExecTypeFromTL" should be
@@ -607,13 +607,13 @@ RelationNameGetTupleDesc(const char *relname)
607607
TupleDesc
608608
TypeGetTupleDesc(Oid typeoid, List *colaliases)
609609
{
610-
char functyptype = get_typtype(typeoid);
610+
TypeFuncClass functypclass = get_type_func_class(typeoid);
611611
TupleDesc tupdesc = NULL;
612612

613613
/*
614614
* Build a suitable tupledesc representing the output rows
615615
*/
616-
if (functyptype == 'c')
616+
if (functypclass == TYPEFUNC_COMPOSITE)
617617
{
618618
/* Composite data type, e.g. a table's row type */
619619
tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(typeoid, -1));
@@ -643,9 +643,9 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases)
643643
tupdesc->tdtypmod = -1;
644644
}
645645
}
646-
else if (functyptype == 'b' || functyptype == 'd')
646+
else if (functypclass == TYPEFUNC_SCALAR)
647647
{
648-
/* Must be a base data type, i.e. scalar */
648+
/* Base data type, i.e. scalar */
649649
char *attname;
650650

651651
/* the alias list is required for base types */
@@ -671,7 +671,7 @@ TypeGetTupleDesc(Oid typeoid, List *colaliases)
671671
-1,
672672
0);
673673
}
674-
else if (typeoid == RECORDOID)
674+
else if (functypclass == TYPEFUNC_RECORD)
675675
{
676676
/* XXX can't support this because typmod wasn't passed in ... */
677677
ereport(ERROR,

src/backend/executor/nodeFunctionscan.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.27 2004/09/22 17:41:51 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.28 2004/10/20 16:04:48 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -132,7 +132,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate)
132132
FunctionScanState *scanstate;
133133
RangeTblEntry *rte;
134134
Oid funcrettype;
135-
char functyptype;
135+
TypeFuncClass functypclass;
136136
TupleDesc tupdesc = NULL;
137137

138138
/*
@@ -184,16 +184,16 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate)
184184
* Now determine if the function returns a simple or composite type,
185185
* and build an appropriate tupdesc.
186186
*/
187-
functyptype = get_typtype(funcrettype);
187+
functypclass = get_type_func_class(funcrettype);
188188

189-
if (functyptype == 'c')
189+
if (functypclass == TYPEFUNC_COMPOSITE)
190190
{
191191
/* Composite data type, e.g. a table's row type */
192192
tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(funcrettype, -1));
193193
}
194-
else if (functyptype == 'b' || functyptype == 'd')
194+
else if (functypclass == TYPEFUNC_SCALAR)
195195
{
196-
/* Must be a base data type, i.e. scalar */
196+
/* Base data type, i.e. scalar */
197197
char *attname = strVal(linitial(rte->eref->colnames));
198198

199199
tupdesc = CreateTemplateTupleDesc(1, false);
@@ -204,9 +204,8 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate)
204204
-1,
205205
0);
206206
}
207-
else if (funcrettype == RECORDOID)
207+
else if (functypclass == TYPEFUNC_RECORD)
208208
{
209-
/* Must be a pseudo type, i.e. record */
210209
tupdesc = BuildDescForRelation(rte->coldeflist);
211210
}
212211
else

src/backend/parser/parse_relation.c

Lines changed: 33 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.100 2004/08/29 05:06:44 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.101 2004/10/20 16:04:48 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -966,7 +966,7 @@ addRangeTableEntryForFunction(ParseState *pstate,
966966
{
967967
RangeTblEntry *rte = makeNode(RangeTblEntry);
968968
Oid funcrettype = exprType(funcexpr);
969-
char functyptype;
969+
TypeFuncClass functypclass;
970970
Alias *alias = rangefunc->alias;
971971
List *coldeflist = rangefunc->coldeflist;
972972
Alias *eref;
@@ -1008,18 +1008,15 @@ addRangeTableEntryForFunction(ParseState *pstate,
10081008
errmsg("a column definition list is required for functions returning \"record\"")));
10091009
}
10101010

1011-
functyptype = get_typtype(funcrettype);
1011+
functypclass = get_type_func_class(funcrettype);
10121012

1013-
if (functyptype == 'c')
1013+
if (functypclass == TYPEFUNC_COMPOSITE)
10141014
{
1015-
/*
1016-
* Named composite data type, i.e. a table's row type
1017-
*/
1015+
/* Composite data type, e.g. a table's row type */
10181016
Oid funcrelid = typeidTypeRelid(funcrettype);
10191017
Relation rel;
10201018

1021-
if (!OidIsValid(funcrelid)) /* shouldn't happen if typtype is
1022-
* 'c' */
1019+
if (!OidIsValid(funcrelid)) /* shouldn't happen */
10231020
elog(ERROR, "invalid typrelid for complex type %u", funcrettype);
10241021

10251022
/*
@@ -1038,12 +1035,10 @@ addRangeTableEntryForFunction(ParseState *pstate,
10381035
*/
10391036
relation_close(rel, NoLock);
10401037
}
1041-
else if (functyptype == 'b' || functyptype == 'd')
1038+
else if (functypclass == TYPEFUNC_SCALAR)
10421039
{
1043-
/*
1044-
* Must be a base data type, i.e. scalar. Just add one alias
1045-
* column named for the function.
1046-
*/
1040+
/* Base data type, i.e. scalar */
1041+
/* Just add one alias column named for the function. */
10471042
if (alias && alias->colnames != NIL)
10481043
{
10491044
if (list_length(alias->colnames) != 1)
@@ -1056,7 +1051,7 @@ addRangeTableEntryForFunction(ParseState *pstate,
10561051
else
10571052
eref->colnames = list_make1(makeString(eref->aliasname));
10581053
}
1059-
else if (functyptype == 'p' && funcrettype == RECORDOID)
1054+
else if (functypclass == TYPEFUNC_RECORD)
10601055
{
10611056
ListCell *col;
10621057

@@ -1073,8 +1068,8 @@ addRangeTableEntryForFunction(ParseState *pstate,
10731068
else
10741069
ereport(ERROR,
10751070
(errcode(ERRCODE_DATATYPE_MISMATCH),
1076-
errmsg("function \"%s\" in FROM has unsupported return type",
1077-
funcname)));
1071+
errmsg("function \"%s\" in FROM has unsupported return type %s",
1072+
funcname, format_type_be(funcrettype))));
10781073

10791074
/*----------
10801075
* Flags:
@@ -1314,9 +1309,9 @@ expandRTE(List *rtable, int rtindex, int sublevels_up,
13141309
{
13151310
/* Function RTE */
13161311
Oid funcrettype = exprType(rte->funcexpr);
1317-
char functyptype = get_typtype(funcrettype);
1312+
TypeFuncClass functypclass = get_type_func_class(funcrettype);
13181313

1319-
if (functyptype == 'c')
1314+
if (functypclass == TYPEFUNC_COMPOSITE)
13201315
{
13211316
/*
13221317
* Composite data type, i.e. a table's row type
@@ -1332,11 +1327,9 @@ expandRTE(List *rtable, int rtindex, int sublevels_up,
13321327
expandRelation(funcrelid, rte->eref, rtindex, sublevels_up,
13331328
include_dropped, colnames, colvars);
13341329
}
1335-
else if (functyptype == 'b' || functyptype == 'd')
1330+
else if (functypclass == TYPEFUNC_SCALAR)
13361331
{
1337-
/*
1338-
* Must be a base data type, i.e. scalar
1339-
*/
1332+
/* Base data type, i.e. scalar */
13401333
if (colnames)
13411334
*colnames = lappend(*colnames,
13421335
linitial(rte->eref->colnames));
@@ -1352,7 +1345,7 @@ expandRTE(List *rtable, int rtindex, int sublevels_up,
13521345
*colvars = lappend(*colvars, varnode);
13531346
}
13541347
}
1355-
else if (functyptype == 'p' && funcrettype == RECORDOID)
1348+
else if (functypclass == TYPEFUNC_RECORD)
13561349
{
13571350
List *coldeflist = rte->coldeflist;
13581351
ListCell *col;
@@ -1389,9 +1382,10 @@ expandRTE(List *rtable, int rtindex, int sublevels_up,
13891382
}
13901383
}
13911384
else
1392-
ereport(ERROR,
1393-
(errcode(ERRCODE_DATATYPE_MISMATCH),
1394-
errmsg("function in FROM has unsupported return type")));
1385+
{
1386+
/* addRangeTableEntryForFunction should've caught this */
1387+
elog(ERROR, "function in FROM has unsupported return type");
1388+
}
13951389
}
13961390
break;
13971391
case RTE_JOIN:
@@ -1669,14 +1663,15 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
16691663
{
16701664
/* Function RTE */
16711665
Oid funcrettype = exprType(rte->funcexpr);
1672-
char functyptype = get_typtype(funcrettype);
1666+
TypeFuncClass functypclass = get_type_func_class(funcrettype);
16731667
List *coldeflist = rte->coldeflist;
16741668

1675-
if (functyptype == 'c')
1669+
if (functypclass == TYPEFUNC_COMPOSITE)
16761670
{
16771671
/*
1678-
* Composite data type, i.e. a table's row type Same
1679-
* as ordinary relation RTE
1672+
* Composite data type, i.e. a table's row type
1673+
*
1674+
* Same as ordinary relation RTE
16801675
*/
16811676
Oid funcrelid = typeidTypeRelid(funcrettype);
16821677
HeapTuple tp;
@@ -1709,25 +1704,24 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
17091704
*vartypmod = att_tup->atttypmod;
17101705
ReleaseSysCache(tp);
17111706
}
1712-
else if (functyptype == 'b' || functyptype == 'd')
1707+
else if (functypclass == TYPEFUNC_SCALAR)
17131708
{
1714-
/*
1715-
* Must be a base data type, i.e. scalar
1716-
*/
1709+
/* Base data type, i.e. scalar */
17171710
*vartype = funcrettype;
17181711
*vartypmod = -1;
17191712
}
1720-
else if (functyptype == 'p' && funcrettype == RECORDOID)
1713+
else if (functypclass == TYPEFUNC_RECORD)
17211714
{
17221715
ColumnDef *colDef = list_nth(coldeflist, attnum - 1);
17231716

17241717
*vartype = typenameTypeId(colDef->typename);
17251718
*vartypmod = -1;
17261719
}
17271720
else
1728-
ereport(ERROR,
1729-
(errcode(ERRCODE_DATATYPE_MISMATCH),
1730-
errmsg("function in FROM has unsupported return type")));
1721+
{
1722+
/* addRangeTableEntryForFunction should've caught this */
1723+
elog(ERROR, "function in FROM has unsupported return type");
1724+
}
17311725
}
17321726
break;
17331727
case RTE_JOIN:

src/backend/utils/cache/lsyscache.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.116 2004/08/29 05:06:50 momjian Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.117 2004/10/20 16:04:49 tgl Exp $
1111
*
1212
* NOTES
1313
* Eventually, the index information should go through here, too.
@@ -1547,6 +1547,42 @@ get_typtype(Oid typid)
15471547
return '\0';
15481548
}
15491549

1550+
/*
1551+
* get_type_func_class
1552+
*
1553+
* Given the type OID, obtain its TYPEFUNC classification.
1554+
*
1555+
* This is intended to centralize a bunch of formerly ad-hoc code for
1556+
* classifying types. The categories used here are useful for deciding
1557+
* how to handle functions returning the datatype.
1558+
*/
1559+
TypeFuncClass
1560+
get_type_func_class(Oid typid)
1561+
{
1562+
switch (get_typtype(typid))
1563+
{
1564+
case 'c':
1565+
return TYPEFUNC_COMPOSITE;
1566+
case 'b':
1567+
case 'd':
1568+
return TYPEFUNC_SCALAR;
1569+
case 'p':
1570+
if (typid == RECORDOID)
1571+
return TYPEFUNC_RECORD;
1572+
/*
1573+
* We treat VOID and CSTRING as legitimate scalar datatypes,
1574+
* mostly for the convenience of the JDBC driver (which wants
1575+
* to be able to do "SELECT * FROM foo()" for all legitimately
1576+
* user-callable functions).
1577+
*/
1578+
if (typid == VOIDOID || typid == CSTRINGOID)
1579+
return TYPEFUNC_SCALAR;
1580+
return TYPEFUNC_OTHER;
1581+
}
1582+
/* shouldn't get here, probably */
1583+
return TYPEFUNC_OTHER;
1584+
}
1585+
15501586
/*
15511587
* get_typ_typrelid
15521588
*

src/include/utils/lsyscache.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.90 2004/08/29 05:06:59 momjian Exp $
9+
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.91 2004/10/20 16:04:50 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -24,6 +24,15 @@ typedef enum IOFuncSelector
2424
IOFunc_send
2525
} IOFuncSelector;
2626

27+
/* Type categories for get_type_func_class */
28+
typedef enum TypeFuncClass
29+
{
30+
TYPEFUNC_SCALAR,
31+
TYPEFUNC_COMPOSITE,
32+
TYPEFUNC_RECORD,
33+
TYPEFUNC_OTHER
34+
} TypeFuncClass;
35+
2736
extern bool op_in_opclass(Oid opno, Oid opclass);
2837
extern void get_op_opclass_properties(Oid opno, Oid opclass,
2938
int *strategy, Oid *subtype,
@@ -85,6 +94,7 @@ extern char get_typstorage(Oid typid);
8594
extern int32 get_typtypmod(Oid typid);
8695
extern Node *get_typdefault(Oid typid);
8796
extern char get_typtype(Oid typid);
97+
extern TypeFuncClass get_type_func_class(Oid typid);
8898
extern Oid get_typ_typrelid(Oid typid);
8999
extern Oid get_element_type(Oid typid);
90100
extern Oid get_array_type(Oid typid);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy