OSDN Git Service

Fix plpgsql so that variables of composite types (rowtypes) can be
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 27 Apr 2003 22:21:22 +0000 (22:21 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 27 Apr 2003 22:21:22 +0000 (22:21 +0000)
declared without having to write %ROWTYPE.  If the declared type of
a variable is a composite type, it'll be taken to be a row variable
automatically.

doc/src/sgml/plpgsql.sgml
src/pl/plpgsql/src/gram.y
src/pl/plpgsql/src/pl_comp.c
src/pl/plpgsql/src/plpgsql.h

index 38306e1..2aa0c07 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v 1.17 2003/04/07 01:29:25 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v 1.18 2003/04/27 22:21:22 tgl Exp $
 -->
 
 <chapter id="plpgsql"> 
@@ -541,7 +541,8 @@ user_id users.user_id%TYPE;
      <title>Row Types</title>
 
 <synopsis>
-<replaceable>name</replaceable> <replaceable>tablename</replaceable><literal>%ROWTYPE</literal>;
+<replaceable>name</replaceable> <replaceable>table_name</replaceable><literal>%ROWTYPE</literal>;
+<replaceable>name</replaceable> <replaceable>composite_type_name</replaceable>;
 </synopsis>
 
    <para>
@@ -550,17 +551,20 @@ user_id users.user_id%TYPE;
     can hold a whole row of a <command>SELECT</> or <command>FOR</>
     query result, so long as that query's column set matches the
     declared type of the variable.
-    <replaceable>tablename</replaceable> must be an existing table or
-    view name in the database. The individual fields of the row value
+    The individual fields of the row value
     are accessed using the usual dot notation, for example
     <literal>rowvar.field</literal>.
    </para>
 
    <para>
-    Presently, a row variable can only be declared using the
-    <literal>%ROWTYPE</literal> notation; although one might expect a
-    bare table name to work as a type declaration, it won't be accepted
-    within <application>PL/pgSQL</application> functions.
+    A row variable can be declared to have the same type as the rows of
+    an existing table or view, by using the
+    <replaceable>table_name</replaceable><literal>%ROWTYPE</literal>
+    notation; or it can be declared by giving a composite type's name.
+    (Since every table has an associated datatype of the same name,
+    it actually does not matter in <productname>PostgreSQL</> whether you
+    write <literal>%ROWTYPE</literal> or not.  But the form with
+    <literal>%ROWTYPE</literal> is more portable.)
    </para>
 
    <para>
index 23dc894..dd15cf8 100644 (file)
@@ -4,7 +4,7 @@
  *                                               procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.41 2003/03/25 03:16:40 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.42 2003/04/27 22:21:22 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -307,36 +307,64 @@ decl_stmt         : '<' '<' opt_lblname '>' '>'
 
 decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval
                                        {
-                                               PLpgSQL_var             *new;
+                                               if (!OidIsValid($3->typrelid))
+                                               {
+                                                       /* Ordinary scalar datatype */
+                                                       PLpgSQL_var             *var;
 
-                                               new = malloc(sizeof(PLpgSQL_var));
-                                               memset(new, 0, sizeof(PLpgSQL_var));
+                                                       var = malloc(sizeof(PLpgSQL_var));
+                                                       memset(var, 0, sizeof(PLpgSQL_var));
 
-                                               new->dtype              = PLPGSQL_DTYPE_VAR;
-                                               new->refname    = $1.name;
-                                               new->lineno             = $1.lineno;
+                                                       var->dtype              = PLPGSQL_DTYPE_VAR;
+                                                       var->refname    = $1.name;
+                                                       var->lineno             = $1.lineno;
 
-                                               new->datatype   = $3;
-                                               new->isconst    = $2;
-                                               new->notnull    = $4;
-                                               new->default_val = $5;
+                                                       var->datatype   = $3;
+                                                       var->isconst    = $2;
+                                                       var->notnull    = $4;
+                                                       var->default_val = $5;
 
-                                               plpgsql_adddatum((PLpgSQL_datum *)new);
-                                               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
-                                                                                               $1.name);
+                                                       plpgsql_adddatum((PLpgSQL_datum *)var);
+                                                       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR,
+                                                                                          var->varno,
+                                                                                          $1.name);
+                                               }
+                                               else
+                                               {
+                                                       /* Composite type --- treat as rowtype */
+                                                       PLpgSQL_row        *row;
+
+                                                       row = build_rowtype($3->typrelid);
+                                                       row->dtype              = PLPGSQL_DTYPE_ROW;
+                                                       row->refname    = $1.name;
+                                                       row->lineno             = $1.lineno;
+
+                                                       if ($2)
+                                                               elog(ERROR, "Rowtype variable cannot be CONSTANT");
+                                                       if ($4)
+                                                               elog(ERROR, "Rowtype variable cannot be NOT NULL");
+                                                       if ($5 != NULL)
+                                                               elog(ERROR, "Default value for rowtype variable is not supported");
+
+                                                       plpgsql_adddatum((PLpgSQL_datum *)row);
+                                                       plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW,
+                                                                                          row->rowno,
+                                                                                          $1.name);
+
+                                               }
                                        }
                                | decl_varname K_RECORD ';'
                                        {
-                                               PLpgSQL_rec             *new;
+                                               PLpgSQL_rec             *var;
 
-                                               new = malloc(sizeof(PLpgSQL_rec));
+                                               var = malloc(sizeof(PLpgSQL_rec));
 
-                                               new->dtype              = PLPGSQL_DTYPE_REC;
-                                               new->refname    = $1.name;
-                                               new->lineno             = $1.lineno;
+                                               var->dtype              = PLPGSQL_DTYPE_REC;
+                                               var->refname    = $1.name;
+                                               var->lineno             = $1.lineno;
 
-                                               plpgsql_adddatum((PLpgSQL_datum *)new);
-                                               plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, new->recno,
+                                               plpgsql_adddatum((PLpgSQL_datum *)var);
+                                               plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, var->recno,
                                                                                                $1.name);
                                        }
                                | decl_varname decl_rowtype ';'
index feb80f9..5c88761 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.56 2003/04/24 21:16:44 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.57 2003/04/27 22:21:22 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -81,7 +81,7 @@ PLpgSQL_function *plpgsql_curr_compile;
 
 
 static void plpgsql_compile_error_callback(void *arg);
-static PLpgSQL_row *build_rowtype(Oid classOid);
+static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod);
 
 
 /*
@@ -275,19 +275,11 @@ plpgsql_compile(Oid fn_oid, int functype)
                                         */
                                        var = malloc(sizeof(PLpgSQL_var));
                                        memset(var, 0, sizeof(PLpgSQL_var));
-                                       var->datatype = malloc(sizeof(PLpgSQL_type));
-                                       memset(var->datatype, 0, sizeof(PLpgSQL_type));
 
                                        var->dtype = PLPGSQL_DTYPE_VAR;
                                        var->refname = strdup(buf);
                                        var->lineno = 0;
-                                       var->datatype->typname = strdup(NameStr(typeStruct->typname));
-                                       var->datatype->typoid = procStruct->proargtypes[i];
-                                       perm_fmgr_info(typeStruct->typinput, &(var->datatype->typinput));
-                                       var->datatype->typelem = typeStruct->typelem;
-                                       var->datatype->typbyval = typeStruct->typbyval;
-                                       var->datatype->typlen = typeStruct->typlen;
-                                       var->datatype->atttypmod = -1;
+                                       var->datatype = build_datatype(typeTup, -1);
                                        var->isconst = true;
                                        var->notnull = false;
                                        var->default_val = NULL;
@@ -908,7 +900,6 @@ plpgsql_parse_wordtype(char *word)
                if (HeapTupleIsValid(typeTup))
                {
                        Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
-                       PLpgSQL_type *typ;
 
                        if (!typeStruct->typisdefined ||
                                typeStruct->typrelid != InvalidOid)
@@ -918,17 +909,7 @@ plpgsql_parse_wordtype(char *word)
                                return T_ERROR;
                        }
 
-                       typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
-
-                       typ->typname = strdup(NameStr(typeStruct->typname));
-                       typ->typoid = typeOid;
-                       perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
-                       typ->typelem = typeStruct->typelem;
-                       typ->typbyval = typeStruct->typbyval;
-                       typ->typlen = typeStruct->typlen;
-                       typ->atttypmod = -1;
-
-                       plpgsql_yylval.dtype = typ;
+                       plpgsql_yylval.dtype = build_datatype(typeTup, -1);
 
                        ReleaseSysCache(typeTup);
                        pfree(cp[0]);
@@ -960,8 +941,6 @@ plpgsql_parse_dblwordtype(char *word)
        HeapTuple       attrtup;
        Form_pg_attribute attrStruct;
        HeapTuple       typetup;
-       Form_pg_type typeStruct;
-       PLpgSQL_type *typ;
        char       *cp[3];
        int                     i;
 
@@ -1067,22 +1046,11 @@ plpgsql_parse_dblwordtype(char *word)
        if (!HeapTupleIsValid(typetup))
                elog(ERROR, "cache lookup for type %u of %s.%s failed",
                         attrStruct->atttypid, cp[0], cp[1]);
-       typeStruct = (Form_pg_type) GETSTRUCT(typetup);
 
        /*
         * Found that - build a compiler type struct and return it
         */
-       typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
-
-       typ->typname = strdup(NameStr(typeStruct->typname));
-       typ->typoid = attrStruct->atttypid;
-       perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
-       typ->typelem = typeStruct->typelem;
-       typ->typbyval = typeStruct->typbyval;
-       typ->typlen = typeStruct->typlen;
-       typ->atttypmod = attrStruct->atttypmod;
-
-       plpgsql_yylval.dtype = typ;
+       plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);
 
        ReleaseSysCache(classtup);
        ReleaseSysCache(attrtup);
@@ -1107,8 +1075,6 @@ plpgsql_parse_tripwordtype(char *word)
        HeapTuple       attrtup;
        Form_pg_attribute attrStruct;
        HeapTuple       typetup;
-       Form_pg_type typeStruct;
-       PLpgSQL_type *typ;
        char       *cp[2];
        char       *colname[1];
        int                     qualified_att_len;
@@ -1192,22 +1158,11 @@ plpgsql_parse_tripwordtype(char *word)
        if (!HeapTupleIsValid(typetup))
                elog(ERROR, "cache lookup for type %u of %s.%s failed",
                         attrStruct->atttypid, cp[0], cp[1]);
-       typeStruct = (Form_pg_type) GETSTRUCT(typetup);
 
        /*
         * Found that - build a compiler type struct and return it
         */
-       typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
-
-       typ->typname = strdup(NameStr(typeStruct->typname));
-       typ->typoid = attrStruct->atttypid;
-       perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
-       typ->typelem = typeStruct->typelem;
-       typ->typbyval = typeStruct->typbyval;
-       typ->typlen = typeStruct->typlen;
-       typ->atttypmod = attrStruct->atttypmod;
-
-       plpgsql_yylval.dtype = typ;
+       plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);
 
        ReleaseSysCache(classtup);
        ReleaseSysCache(attrtup);
@@ -1296,7 +1251,7 @@ plpgsql_parse_dblwordrowtype(char *word)
 /*
  * Build a rowtype data structure given the pg_class OID.
  */
-static PLpgSQL_row *
+PLpgSQL_row *
 build_rowtype(Oid classOid)
 {
        PLpgSQL_row *row;
@@ -1341,7 +1296,6 @@ build_rowtype(Oid classOid)
                HeapTuple       attrtup;
                Form_pg_attribute attrStruct;
                HeapTuple       typetup;
-               Form_pg_type typeStruct;
                const char *attname;
                PLpgSQL_var *var;
 
@@ -1365,7 +1319,6 @@ build_rowtype(Oid classOid)
                if (!HeapTupleIsValid(typetup))
                        elog(ERROR, "cache lookup for type %u of %s.%s failed",
                                 attrStruct->atttypid, relname, attname);
-               typeStruct = (Form_pg_type) GETSTRUCT(typetup);
 
                /*
                 * Create the internal variable
@@ -1384,14 +1337,7 @@ build_rowtype(Oid classOid)
                strcpy(var->refname, relname);
                strcat(var->refname, ".");
                strcat(var->refname, attname);
-               var->datatype = malloc(sizeof(PLpgSQL_type));
-               var->datatype->typname = strdup(NameStr(typeStruct->typname));
-               var->datatype->typoid = attrStruct->atttypid;
-               perm_fmgr_info(typeStruct->typinput, &(var->datatype->typinput));
-               var->datatype->typelem = typeStruct->typelem;
-               var->datatype->typbyval = typeStruct->typbyval;
-               var->datatype->typlen = typeStruct->typlen;
-               var->datatype->atttypmod = attrStruct->atttypmod;
+               var->datatype = build_datatype(typetup, attrStruct->atttypmod);
                var->isconst = false;
                var->notnull = false;
                var->default_val = NULL;
@@ -1428,7 +1374,6 @@ plpgsql_parse_datatype(char *string)
        Oid                     type_id;
        int32           typmod;
        HeapTuple       typeTup;
-       Form_pg_type typeStruct;
        PLpgSQL_type *typ;
 
        /* Let the main parser try to parse it under standard SQL rules */
@@ -1440,20 +1385,34 @@ plpgsql_parse_datatype(char *string)
                                                         0, 0, 0);
        if (!HeapTupleIsValid(typeTup))
                elog(ERROR, "cache lookup failed for type %u", type_id);
-       typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
+
+       typ = build_datatype(typeTup, typmod);
+
+       ReleaseSysCache(typeTup);
+
+       return typ;
+}
+
+/*
+ * Utility subroutine to make a PLpgSQL_type struct given a pg_type entry
+ */
+static PLpgSQL_type *
+build_datatype(HeapTuple typeTup, int32 typmod)
+{
+       Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
+       PLpgSQL_type *typ;
 
        typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
 
        typ->typname = strdup(NameStr(typeStruct->typname));
-       typ->typoid = type_id;
-       perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
-       typ->typelem = typeStruct->typelem;
-       typ->typbyval = typeStruct->typbyval;
+       typ->typoid = HeapTupleGetOid(typeTup);
        typ->typlen = typeStruct->typlen;
+       typ->typbyval = typeStruct->typbyval;
+       typ->typrelid = typeStruct->typrelid;
+       typ->typelem = typeStruct->typelem;
+       perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
        typ->atttypmod = typmod;
 
-       ReleaseSysCache(typeTup);
-
        return typ;
 }
 
index 3756d94..1140ceb 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.34 2003/04/24 21:16:44 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.35 2003/04/27 22:21:22 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -142,14 +142,15 @@ typedef struct
 
 
 typedef struct
-{                                                              /* Postgres base data type              */
+{                                                              /* Postgres data type           */
        char       *typname;
-       Oid                     typoid;
-       FmgrInfo        typinput;
-       Oid                     typelem;
-       int16           typlen;
+       Oid                     typoid;                 /* OID of the data type */
+       int16           typlen;                 /* stuff copied from its pg_type entry */
        bool            typbyval;
-       int32           atttypmod;
+       Oid                     typrelid;
+       Oid                     typelem;
+       FmgrInfo        typinput;               /* lookup info for typinput function */
+       int32           atttypmod;              /* typmod (taken from someplace else) */
 }      PLpgSQL_type;
 
 
@@ -600,6 +601,7 @@ extern int  plpgsql_parse_tripwordtype(char *word);
 extern int     plpgsql_parse_wordrowtype(char *word);
 extern int     plpgsql_parse_dblwordrowtype(char *word);
 extern PLpgSQL_type *plpgsql_parse_datatype(char *string);
+extern PLpgSQL_row *build_rowtype(Oid classOid);
 extern void plpgsql_adddatum(PLpgSQL_datum * new);
 extern int     plpgsql_add_initdatums(int **varnos);
 extern void plpgsql_yyerror(const char *s);