Commit 28d2420e authored by Bruce Momjian's avatar Bruce Momjian

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
parent 0a93285d
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.23 2001/05/19 09:01:10 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.24 2001/06/04 23:27:23 momjian Exp $
-->
<refentry id="SQL-CREATEFUNCTION">
......@@ -55,10 +55,16 @@ CREATE FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceab
<listitem>
<para>
The data type(s) of the function's arguments, if any. The
input types may be base or complex types, or
<literal>opaque</literal>. <literal>Opaque</literal> indicates
input types may be base or complex types,
<literal>opaque</literal>, or the same as the type of an
existing column. <literal>Opaque</literal> indicates
that the function accepts arguments of a non-SQL type such as
<type>char *</type>.
The type of a column is indicated using <replaceable
class="parameter">tablename</replaceable>.<replaceable
class="parameter">columnname</replaceable><literal>%TYPE</literal>;
using this can sometimes help make a function independent from
changes to the definition of a table.
</para>
</listitem>
</varlistentry>
......@@ -69,8 +75,10 @@ CREATE FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceab
<listitem>
<para>
The return data type. The output type may be specified as a
base type, complex type, <literal>setof</literal> type, or
<literal>opaque</literal>. The <literal>setof</literal>
base type, complex type, <literal>setof</literal> type,
<literal>opaque</literal>, or the same as the type of an
existing column.
The <literal>setof</literal>
modifier indicates that the function will return a set of
items, rather than a single item. Functions with a declared
return type of <literal>opaque</literal> do not return a value.
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.188 2001/06/04 16:17:30 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.189 2001/06/04 23:27:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -29,6 +29,7 @@
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "parser/parse_type.h"
#include "parser/parse_expr.h"
#include "rewrite/rewriteManip.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
......@@ -51,7 +52,10 @@ static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt);
static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt);
static Node *transformTypeRefs(ParseState *pstate, Node *stmt);
static void transformTypeRefsList(ParseState *pstate, List *l);
static void transformTypeRef(ParseState *pstate, TypeName *tn);
static List *getSetColTypes(ParseState *pstate, Node *node);
static void transformForUpdate(Query *qry, List *forUpdate);
static void transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid);
......@@ -232,6 +236,17 @@ transformStmt(ParseState *pstate, Node *parseTree)
(SelectStmt *) parseTree);
break;
/*
* Convert use of %TYPE in statements where it is permitted.
*/
case T_ProcedureStmt:
case T_CommentStmt:
case T_RemoveFuncStmt:
case T_DefineStmt:
result = makeNode(Query);
result->commandType = CMD_UTILITY;
result->utilityStmt = transformTypeRefs(pstate, parseTree);
break;
default:
......@@ -2701,6 +2716,107 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt)
return qry;
}
/*
* Transform uses of %TYPE in a statement.
*/
static Node *
transformTypeRefs(ParseState *pstate, Node *stmt)
{
switch (nodeTag(stmt))
{
case T_ProcedureStmt:
{
ProcedureStmt *ps = (ProcedureStmt *) stmt;
transformTypeRefsList(pstate, ps->argTypes);
transformTypeRef(pstate, (TypeName *) ps->returnType);
transformTypeRefsList(pstate, ps->withClause);
}
break;
case T_CommentStmt:
{
CommentStmt *cs = (CommentStmt *) stmt;
transformTypeRefsList(pstate, cs->objlist);
}
break;
case T_RemoveFuncStmt:
{
RemoveFuncStmt *rs = (RemoveFuncStmt *) stmt;
transformTypeRefsList(pstate, rs->args);
}
break;
case T_DefineStmt:
{
DefineStmt *ds = (DefineStmt *) stmt;
List *ele;
foreach(ele, ds->definition)
{
DefElem *de = (DefElem *) lfirst(ele);
if (de->arg != NULL
&& IsA(de->arg, TypeName))
{
transformTypeRef(pstate, (TypeName *) de->arg);
}
}
}
break;
default:
elog(ERROR, "Unsupported type %d in transformTypeRefs",
nodeTag(stmt));
break;
}
return stmt;
}
/*
* Transform uses of %TYPE in a list.
*/
static void
transformTypeRefsList(ParseState *pstate, List *l)
{
List *ele;
foreach(ele, l)
{
if (IsA(lfirst(ele), TypeName))
transformTypeRef(pstate, (TypeName *) lfirst(ele));
}
}
/*
* Transform a TypeName to not use %TYPE.
*/
static void
transformTypeRef(ParseState *pstate, TypeName *tn)
{
Attr *att;
Node *n;
Var *v;
char *tyn;
if (tn->attrname == NULL)
return;
att = makeAttr(tn->name, tn->attrname);
n = transformExpr(pstate, (Node *) att, EXPR_COLUMN_FIRST);
if (! IsA(n, Var))
elog(ERROR, "unsupported expression in %%TYPE");
v = (Var *) n;
tyn = typeidTypeName(v->vartype);
elog(NOTICE, "%s.%s%%TYPE converted to %s", tn->name, tn->attrname, tyn);
tn->name = tyn;
tn->typmod = v->vartypmod;
tn->attrname = NULL;
}
/* exported so planner can check again after rewriting, query pullup, etc */
void
CheckSelectForUpdate(Query *qry)
......
......@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.227 2001/05/27 09:59:29 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.228 2001/06/04 23:27:23 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -192,7 +192,7 @@ static void doNegateFloat(Value *v);
def_list, opt_indirection, group_clause, TriggerFuncArgs,
select_limit, opt_select_limit
%type <typnam> func_arg, func_return, aggr_argtype
%type <typnam> func_arg, func_return, func_type, aggr_argtype
%type <boolean> opt_arg, TriggerForOpt, TriggerForType, OptTemp
......@@ -2490,7 +2490,7 @@ func_args_list: func_arg
{ $$ = lappend($1, $3); }
;
func_arg: opt_arg Typename
func_arg: opt_arg func_type
{
/* We can catch over-specified arguments here if we want to,
* but for now better to silently swallow typmod, etc.
......@@ -2498,7 +2498,7 @@ func_arg: opt_arg Typename
*/
$$ = $2;
}
| Typename
| func_type
{
$$ = $1;
}
......@@ -2526,7 +2526,7 @@ func_as: Sconst
{ $$ = makeList2(makeString($1), makeString($3)); }
;
func_return: Typename
func_return: func_type
{
/* We can catch over-specified arguments here if we want to,
* but for now better to silently swallow typmod, etc.
......@@ -2536,6 +2536,18 @@ func_return: Typename
}
;
func_type: Typename
{
$$ = $1;
}
| IDENT '.' ColId '%' TYPE_P
{
$$ = makeNode(TypeName);
$$->name = $1;
$$->typmod = -1;
$$->attrname = $3;
}
;
/*****************************************************************************
*
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.96 2001/05/21 18:42:08 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.97 2001/06/04 23:27:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -942,6 +942,7 @@ parser_typecast_expression(ParseState *pstate,
char *
TypeNameToInternalName(TypeName *typename)
{
Assert(typename->attrname == NULL);
if (typename->arrayBounds != NIL)
{
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.129 2001/05/21 18:42:08 momjian Exp $
* $Id: parsenodes.h,v 1.130 2001/06/04 23:27:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -951,6 +951,7 @@ typedef struct TypeName
bool setof; /* is a set? */
int32 typmod; /* type modifier */
List *arrayBounds; /* array bounds */
char *attrname; /* field name when using %TYPE */
} TypeName;
/*
......
......@@ -13,6 +13,12 @@ CREATE FUNCTION hobby_construct(text, text)
LANGUAGE 'sql';
CREATE FUNCTION hobbies_by_name(hobbies_r.name%TYPE)
RETURNS hobbies_r.person%TYPE
AS 'select person from hobbies_r where name = $1'
LANGUAGE 'sql';
CREATE FUNCTION equipment(hobbies_r)
RETURNS setof equipment_r
AS 'select * from equipment_r where hobby = $1.name'
......
......@@ -214,6 +214,7 @@ SELECT user_relns() AS user_relns
--SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name;
SELECT hobbies_by_name('basketball');
--
-- check that old-style C functions work properly with TOASTed values
......
......@@ -9,6 +9,12 @@ CREATE FUNCTION hobby_construct(text, text)
RETURNS hobbies_r
AS 'select $1 as name, $2 as hobby'
LANGUAGE 'sql';
CREATE FUNCTION hobbies_by_name(hobbies_r.name%TYPE)
RETURNS hobbies_r.person%TYPE
AS 'select person from hobbies_r where name = $1'
LANGUAGE 'sql';
NOTICE: hobbies_r.name%TYPE converted to text
NOTICE: hobbies_r.person%TYPE converted to text
CREATE FUNCTION equipment(hobbies_r)
RETURNS setof equipment_r
AS 'select * from equipment_r where hobby = $1.name'
......
......@@ -656,6 +656,12 @@ SELECT user_relns() AS user_relns
(90 rows)
--SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name;
SELECT hobbies_by_name('basketball');
hobbies_by_name
-----------------
joe
(1 row)
--
-- check that old-style C functions work properly with TOASTed values
--
......
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