Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 28d2420

Browse files
committed
This patch adds support for %TYPE in CREATE FUNCTION argument and return
types. This version has an elog() to remind the user the type resolution is not dynamic. Ian Lance Taylor
1 parent 0a93285 commit 28d2420

File tree

9 files changed

+170
-13
lines changed

9 files changed

+170
-13
lines changed

doc/src/sgml/ref/create_function.sgml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.23 2001/05/19 09:01:10 petere Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.24 2001/06/04 23:27:23 momjian Exp $
33
-->
44

55
<refentry id="SQL-CREATEFUNCTION">
@@ -55,10 +55,16 @@ CREATE FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceab
5555
<listitem>
5656
<para>
5757
The data type(s) of the function's arguments, if any. The
58-
input types may be base or complex types, or
59-
<literal>opaque</literal>. <literal>Opaque</literal> indicates
58+
input types may be base or complex types,
59+
<literal>opaque</literal>, or the same as the type of an
60+
existing column. <literal>Opaque</literal> indicates
6061
that the function accepts arguments of a non-SQL type such as
6162
<type>char *</type>.
63+
The type of a column is indicated using <replaceable
64+
class="parameter">tablename</replaceable>.<replaceable
65+
class="parameter">columnname</replaceable><literal>%TYPE</literal>;
66+
using this can sometimes help make a function independent from
67+
changes to the definition of a table.
6268
</para>
6369
</listitem>
6470
</varlistentry>
@@ -69,8 +75,10 @@ CREATE FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceab
6975
<listitem>
7076
<para>
7177
The return data type. The output type may be specified as a
72-
base type, complex type, <literal>setof</literal> type, or
73-
<literal>opaque</literal>. The <literal>setof</literal>
78+
base type, complex type, <literal>setof</literal> type,
79+
<literal>opaque</literal>, or the same as the type of an
80+
existing column.
81+
The <literal>setof</literal>
7482
modifier indicates that the function will return a set of
7583
items, rather than a single item. Functions with a declared
7684
return type of <literal>opaque</literal> do not return a value.

src/backend/parser/analyze.c

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.188 2001/06/04 16:17:30 tgl Exp $
9+
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.189 2001/06/04 23:27:23 momjian Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -29,6 +29,7 @@
2929
#include "parser/parse_relation.h"
3030
#include "parser/parse_target.h"
3131
#include "parser/parse_type.h"
32+
#include "parser/parse_expr.h"
3233
#include "rewrite/rewriteManip.h"
3334
#include "utils/builtins.h"
3435
#include "utils/fmgroids.h"
@@ -51,7 +52,10 @@ static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
5152
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
5253
static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
5354
static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt);
55+
static Node *transformTypeRefs(ParseState *pstate, Node *stmt);
5456

57+
static void transformTypeRefsList(ParseState *pstate, List *l);
58+
static void transformTypeRef(ParseState *pstate, TypeName *tn);
5559
static List *getSetColTypes(ParseState *pstate, Node *node);
5660
static void transformForUpdate(Query *qry, List *forUpdate);
5761
static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid);
@@ -232,6 +236,17 @@ transformStmt(ParseState *pstate, Node *parseTree)
232236
(SelectStmt *) parseTree);
233237
break;
234238

239+
/*
240+
* Convert use of %TYPE in statements where it is permitted.
241+
*/
242+
case T_ProcedureStmt:
243+
case T_CommentStmt:
244+
case T_RemoveFuncStmt:
245+
case T_DefineStmt:
246+
result = makeNode(Query);
247+
result->commandType = CMD_UTILITY;
248+
result->utilityStmt = transformTypeRefs(pstate, parseTree);
249+
break;
235250

236251
default:
237252

@@ -2701,6 +2716,107 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt)
27012716
return qry;
27022717
}
27032718

2719+
/*
2720+
* Transform uses of %TYPE in a statement.
2721+
*/
2722+
static Node *
2723+
transformTypeRefs(ParseState *pstate, Node *stmt)
2724+
{
2725+
switch (nodeTag(stmt))
2726+
{
2727+
case T_ProcedureStmt:
2728+
{
2729+
ProcedureStmt *ps = (ProcedureStmt *) stmt;
2730+
2731+
transformTypeRefsList(pstate, ps->argTypes);
2732+
transformTypeRef(pstate, (TypeName *) ps->returnType);
2733+
transformTypeRefsList(pstate, ps->withClause);
2734+
}
2735+
break;
2736+
2737+
case T_CommentStmt:
2738+
{
2739+
CommentStmt *cs = (CommentStmt *) stmt;
2740+
2741+
transformTypeRefsList(pstate, cs->objlist);
2742+
}
2743+
break;
2744+
2745+
case T_RemoveFuncStmt:
2746+
{
2747+
RemoveFuncStmt *rs = (RemoveFuncStmt *) stmt;
2748+
2749+
transformTypeRefsList(pstate, rs->args);
2750+
}
2751+
break;
2752+
2753+
case T_DefineStmt:
2754+
{
2755+
DefineStmt *ds = (DefineStmt *) stmt;
2756+
List *ele;
2757+
2758+
foreach(ele, ds->definition)
2759+
{
2760+
DefElem *de = (DefElem *) lfirst(ele);
2761+
2762+
if (de->arg != NULL
2763+
&& IsA(de->arg, TypeName))
2764+
{
2765+
transformTypeRef(pstate, (TypeName *) de->arg);
2766+
}
2767+
}
2768+
}
2769+
break;
2770+
2771+
default:
2772+
elog(ERROR, "Unsupported type %d in transformTypeRefs",
2773+
nodeTag(stmt));
2774+
break;
2775+
}
2776+
2777+
return stmt;
2778+
}
2779+
2780+
/*
2781+
* Transform uses of %TYPE in a list.
2782+
*/
2783+
static void
2784+
transformTypeRefsList(ParseState *pstate, List *l)
2785+
{
2786+
List *ele;
2787+
2788+
foreach(ele, l)
2789+
{
2790+
if (IsA(lfirst(ele), TypeName))
2791+
transformTypeRef(pstate, (TypeName *) lfirst(ele));
2792+
}
2793+
}
2794+
2795+
/*
2796+
* Transform a TypeName to not use %TYPE.
2797+
*/
2798+
static void
2799+
transformTypeRef(ParseState *pstate, TypeName *tn)
2800+
{
2801+
Attr *att;
2802+
Node *n;
2803+
Var *v;
2804+
char *tyn;
2805+
2806+
if (tn->attrname == NULL)
2807+
return;
2808+
att = makeAttr(tn->name, tn->attrname);
2809+
n = transformExpr(pstate, (Node *) att, EXPR_COLUMN_FIRST);
2810+
if (! IsA(n, Var))
2811+
elog(ERROR, "unsupported expression in %%TYPE");
2812+
v = (Var *) n;
2813+
tyn = typeidTypeName(v->vartype);
2814+
elog(NOTICE, "%s.%s%%TYPE converted to %s", tn->name, tn->attrname, tyn);
2815+
tn->name = tyn;
2816+
tn->typmod = v->vartypmod;
2817+
tn->attrname = NULL;
2818+
}
2819+
27042820
/* exported so planner can check again after rewriting, query pullup, etc */
27052821
void
27062822
CheckSelectForUpdate(Query *qry)

src/backend/parser/gram.y

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.227 2001/05/27 09:59:29 petere Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.228 2001/06/04 23:27:23 momjian Exp $
1515
*
1616
* HISTORY
1717
* AUTHOR DATE MAJOR EVENT
@@ -192,7 +192,7 @@ static void doNegateFloat(Value *v);
192192
def_list, opt_indirection, group_clause, TriggerFuncArgs,
193193
select_limit, opt_select_limit
194194

195-
%type <typnam> func_arg, func_return, aggr_argtype
195+
%type <typnam> func_arg, func_return, func_type, aggr_argtype
196196

197197
%type <boolean> opt_arg, TriggerForOpt, TriggerForType, OptTemp
198198

@@ -2490,15 +2490,15 @@ func_args_list: func_arg
24902490
{ $$ = lappend($1, $3); }
24912491
;
24922492

2493-
func_arg: opt_arg Typename
2493+
func_arg: opt_arg func_type
24942494
{
24952495
/* We can catch over-specified arguments here if we want to,
24962496
* but for now better to silently swallow typmod, etc.
24972497
* - thomas 2000-03-22
24982498
*/
24992499
$$ = $2;
25002500
}
2501-
| Typename
2501+
| func_type
25022502
{
25032503
$$ = $1;
25042504
}
@@ -2526,7 +2526,7 @@ func_as: Sconst
25262526
{ $$ = makeList2(makeString($1), makeString($3)); }
25272527
;
25282528

2529-
func_return: Typename
2529+
func_return: func_type
25302530
{
25312531
/* We can catch over-specified arguments here if we want to,
25322532
* but for now better to silently swallow typmod, etc.
@@ -2536,6 +2536,18 @@ func_return: Typename
25362536
}
25372537
;
25382538

2539+
func_type: Typename
2540+
{
2541+
$$ = $1;
2542+
}
2543+
| IDENT '.' ColId '%' TYPE_P
2544+
{
2545+
$$ = makeNode(TypeName);
2546+
$$->name = $1;
2547+
$$->typmod = -1;
2548+
$$->attrname = $3;
2549+
}
2550+
;
25392551

25402552
/*****************************************************************************
25412553
*

src/backend/parser/parse_expr.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.96 2001/05/21 18:42:08 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.97 2001/06/04 23:27:23 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -942,6 +942,7 @@ parser_typecast_expression(ParseState *pstate,
942942
char *
943943
TypeNameToInternalName(TypeName *typename)
944944
{
945+
Assert(typename->attrname == NULL);
945946
if (typename->arrayBounds != NIL)
946947
{
947948

src/include/nodes/parsenodes.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: parsenodes.h,v 1.129 2001/05/21 18:42:08 momjian Exp $
10+
* $Id: parsenodes.h,v 1.130 2001/06/04 23:27:23 momjian Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -951,6 +951,7 @@ typedef struct TypeName
951951
bool setof; /* is a set? */
952952
int32 typmod; /* type modifier */
953953
List *arrayBounds; /* array bounds */
954+
char *attrname; /* field name when using %TYPE */
954955
} TypeName;
955956

956957
/*

src/test/regress/input/create_function_2.source

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ CREATE FUNCTION hobby_construct(text, text)
1313
LANGUAGE 'sql';
1414

1515

16+
CREATE FUNCTION hobbies_by_name(hobbies_r.name%TYPE)
17+
RETURNS hobbies_r.person%TYPE
18+
AS 'select person from hobbies_r where name = $1'
19+
LANGUAGE 'sql';
20+
21+
1622
CREATE FUNCTION equipment(hobbies_r)
1723
RETURNS setof equipment_r
1824
AS 'select * from equipment_r where hobby = $1.name'

src/test/regress/input/misc.source

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ SELECT user_relns() AS user_relns
214214

215215
--SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name;
216216

217+
SELECT hobbies_by_name('basketball');
217218

218219
--
219220
-- check that old-style C functions work properly with TOASTed values

src/test/regress/output/create_function_2.source

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ CREATE FUNCTION hobby_construct(text, text)
99
RETURNS hobbies_r
1010
AS 'select $1 as name, $2 as hobby'
1111
LANGUAGE 'sql';
12+
CREATE FUNCTION hobbies_by_name(hobbies_r.name%TYPE)
13+
RETURNS hobbies_r.person%TYPE
14+
AS 'select person from hobbies_r where name = $1'
15+
LANGUAGE 'sql';
16+
NOTICE: hobbies_r.name%TYPE converted to text
17+
NOTICE: hobbies_r.person%TYPE converted to text
1218
CREATE FUNCTION equipment(hobbies_r)
1319
RETURNS setof equipment_r
1420
AS 'select * from equipment_r where hobby = $1.name'

src/test/regress/output/misc.source

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,12 @@ SELECT user_relns() AS user_relns
656656
(90 rows)
657657

658658
--SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name;
659+
SELECT hobbies_by_name('basketball');
660+
hobbies_by_name
661+
-----------------
662+
joe
663+
(1 row)
664+
659665
--
660666
-- check that old-style C functions work properly with TOASTed values
661667
--

0 commit comments

Comments
 (0)