This patch adds support for %TYPE in CREATE FUNCTION argument and return
authorBruce Momjian
Mon, 4 Jun 2001 23:27:23 +0000 (23:27 +0000)
committerBruce Momjian
Mon, 4 Jun 2001 23:27:23 +0000 (23:27 +0000)
types.  This version has an elog() to remind the user the type
resolution is not dynamic.

Ian Lance Taylor

doc/src/sgml/ref/create_function.sgml
src/backend/parser/analyze.c
src/backend/parser/gram.y
src/backend/parser/parse_expr.c
src/include/nodes/parsenodes.h
src/test/regress/input/create_function_2.source
src/test/regress/input/misc.source
src/test/regress/output/create_function_2.source
src/test/regress/output/misc.source

index b95c2fd24e60ec3343170b4d6118569c5e22ced4..2a28925dff5c8f79d0848143c21190a0c8e33399 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -55,10 +55,16 @@ CREATE FUNCTION name ( [ 
      
       
        The data type(s) of the function's arguments, if any.  The
-       input types may be base or complex types, or
-       opaque.  Opaque indicates
+       input types may be base or complex types,
+       opaque, or the same as the type of an
+       existing column.  Opaque indicates
        that the function accepts arguments of a non-SQL type such as
        char *.
+   The type of a column is indicated using 
+   class="parameter">tablename.
+   class="parameter">columnname%TYPE;
+   using this can sometimes help make a function independent from
+   changes to the definition of a table.
       
      
     
@@ -69,8 +75,10 @@ CREATE FUNCTION name ( [ 
      
       
        The return data type.  The output type may be specified as a
-       base type, complex type, setof type, or
-       opaque.  The setof
+       base type, complex type, setof type,
+       opaque, or the same as the type of an
+       existing column.
+       The setof
        modifier indicates that the function will return a set of
        items, rather than a single item.  Functions with a declared
        return type of opaque do not return a value.
index 2bef065b11aff35da922d2225c6d7ba28cae8d12..c6f21e77b03be983c556726fa3c271b407c4b9e4 100644 (file)
@@ -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)
index 37c28495e546f0115282421c32d8e69df8151bdb..6cf2adcb5ba852e8366ecbf5a620a406b2b5398e 100644 (file)
@@ -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  func_arg, func_return, aggr_argtype
+%type  func_arg, func_return, func_type, aggr_argtype
 
 %type     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;
+               }
+       ;
 
 /*****************************************************************************
  *
index 4cbbc1c980c805001fe2b682d44dd016633fa10d..a196779f44c190f474d51ef91b7a00781f4106fb 100644 (file)
@@ -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)
    {
 
index ff4cc278312204af65879b3a96d7320785df2dc6..31aadb449d598251dfe95fb64ed3849f66b4dc18 100644 (file)
@@ -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;
 
 /*
index b1c0eab138608bf17232ed586a0b40a3a458a721..4bcf24c6011d70f4c8dca76fe6e4f91810590610 100644 (file)
@@ -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'
index dbb8df847090ba1185eba934c84fe9fd610546c4..0fa63839e6051ef1e4e141b97a069503a4a66093 100644 (file)
@@ -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
index a5f39a00bb00f2f7ae6174dc2977305181008cea..137242da70573cd0634aaf5ba5e11fe3685841f4 100644 (file)
@@ -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'
index 768dba5c3c7789af4804bbdfffe292f9d16fa9bc..57dc0fb4a4284ee26c945d55bec2c325aa3fda68 100644 (file)
@@ -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
 --