OSDN Git Service

Restructure rowtype-parameter handling to eliminate need for possibly-
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 12 Aug 2002 14:25:07 +0000 (14:25 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 12 Aug 2002 14:25:07 +0000 (14:25 +0000)
overflowable buffer for 'name%rowtype'; not to mention avoid problems
with mixed-case type names and other special cases.

src/pl/plpgsql/src/pl_comp.c

index d3c7cb0..00edb1a 100644 (file)
@@ -3,7 +3,7 @@
  *                       procedural language
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.44 2002/08/08 01:36:04 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.45 2002/08/12 14:25:07 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -85,6 +85,9 @@ int                   plpgsql_DumpExecTree = 0;
 PLpgSQL_function *plpgsql_curr_compile;
 
 
+static PLpgSQL_row *build_rowtype(Oid classOid);
+
+
 /*
  * This routine is a crock, and so is everyplace that calls it.  The problem
  * is that the compiled form of a plpgsql function is allocated permanently
@@ -234,7 +237,9 @@ plpgsql_compile(Oid fn_oid, int functype)
                         */
                        for (i = 0; i < procStruct->pronargs; i++)
                        {
-                               char            buf[256];
+                               char            buf[32];
+
+                               sprintf(buf, "$%d", i + 1);     /* name for variable */
 
                                /*
                                 * Get the parameters type
@@ -258,13 +263,7 @@ plpgsql_compile(Oid fn_oid, int functype)
                                         * For tuple type parameters, we set up a record of
                                         * that type
                                         */
-                                       sprintf(buf, "%s%%rowtype", NameStr(typeStruct->typname));
-                                       if (plpgsql_parse_wordrowtype(buf) != T_ROW)
-                                               elog(ERROR, "cannot get tuple struct of argument %d",
-                                                        i + 1);
-
-                                       row = plpgsql_yylval.row;
-                                       sprintf(buf, "$%d", i + 1);
+                                       row = build_rowtype(typeStruct->typrelid);
 
                                        row->refname = strdup(buf);
 
@@ -284,7 +283,6 @@ plpgsql_compile(Oid fn_oid, int functype)
                                        var->datatype = malloc(sizeof(PLpgSQL_type));
                                        memset(var->datatype, 0, sizeof(PLpgSQL_type));
 
-                                       sprintf(buf, "$%d", i + 1);
                                        var->dtype = PLPGSQL_DTYPE_VAR;
                                        var->refname = strdup(buf);
                                        var->lineno = 0;
@@ -1097,15 +1095,6 @@ int
 plpgsql_parse_wordrowtype(char *word)
 {
        Oid                     classOid;
-       HeapTuple       classtup;
-       Form_pg_class classStruct;
-       HeapTuple       typetup;
-       Form_pg_type typeStruct;
-       HeapTuple       attrtup;
-       Form_pg_attribute attrStruct;
-       PLpgSQL_row *row;
-       PLpgSQL_var *var;
-       char       *attname;
        char       *cp[2];
        int                     i;
 
@@ -1116,25 +1105,51 @@ plpgsql_parse_wordrowtype(char *word)
        word[i] = '.';
        plpgsql_convert_ident(word, cp, 2);
        word[i] = '%';
+
+       /* Lookup the relation */
+       classOid = RelnameGetRelid(cp[0]);
+       if (!OidIsValid(classOid))
+               elog(ERROR, "%s: no such class", cp[0]);
+
+       /*
+        * Build and return the complete row definition
+        */
+       plpgsql_yylval.row = build_rowtype(classOid);
+
+       pfree(cp[0]);
        pfree(cp[1]);
 
+       return T_ROW;
+}
+
+/*
+ * Build a rowtype data structure given the pg_class OID.
+ */
+static PLpgSQL_row *
+build_rowtype(Oid classOid)
+{
+       PLpgSQL_row *row;
+       HeapTuple       classtup;
+       Form_pg_class classStruct;
+       const char  *relname;
+       int                     i;
+
        /*
         * Fetch the pg_class tuple.
         */
-       classOid = RelnameGetRelid(cp[0]);
-       if (!OidIsValid(classOid))
-               elog(ERROR, "%s: no such class", cp[0]);
        classtup = SearchSysCache(RELOID,
                                                          ObjectIdGetDatum(classOid),
                                                          0, 0, 0);
        if (!HeapTupleIsValid(classtup))
-               elog(ERROR, "%s: no such class", cp[0]);
+               elog(ERROR, "cache lookup failed for relation %u", classOid);
        classStruct = (Form_pg_class) GETSTRUCT(classtup);
+       relname = NameStr(classStruct->relname);
+
        /* accept relation, sequence, or view pg_class entries */
        if (classStruct->relkind != RELKIND_RELATION &&
                classStruct->relkind != RELKIND_SEQUENCE &&
                classStruct->relkind != RELKIND_VIEW)
-               elog(ERROR, "%s isn't a table", cp[0]);
+               elog(ERROR, "%s isn't a table", relname);
 
        /*
         * Create a row datum entry and all the required variables that it
@@ -1151,6 +1166,13 @@ plpgsql_parse_wordrowtype(char *word)
 
        for (i = 0; i < row->nfields; i++)
        {
+               HeapTuple       attrtup;
+               Form_pg_attribute attrStruct;
+               HeapTuple       typetup;
+               Form_pg_type typeStruct;
+               const char         *attname;
+               PLpgSQL_var *var;
+
                /*
                 * Get the attribute and it's type
                 */
@@ -1160,17 +1182,17 @@ plpgsql_parse_wordrowtype(char *word)
                                                                 0, 0);
                if (!HeapTupleIsValid(attrtup))
                        elog(ERROR, "cache lookup for attribute %d of class %s failed",
-                                i + 1, cp[0]);
+                                i + 1, relname);
                attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
 
-               attname = pstrdup(NameStr(attrStruct->attname));
+               attname = NameStr(attrStruct->attname);
 
                typetup = SearchSysCache(TYPEOID,
                                                                 ObjectIdGetDatum(attrStruct->atttypid),
                                                                 0, 0, 0);
                if (!HeapTupleIsValid(typetup))
                        elog(ERROR, "cache lookup for type %u of %s.%s failed",
-                                attrStruct->atttypid, cp[0], attname);
+                                attrStruct->atttypid, relname, attname);
                typeStruct = (Form_pg_type) GETSTRUCT(typetup);
 
                /*
@@ -1186,8 +1208,8 @@ plpgsql_parse_wordrowtype(char *word)
                var = malloc(sizeof(PLpgSQL_var));
                memset(var, 0, sizeof(PLpgSQL_var));
                var->dtype = PLPGSQL_DTYPE_VAR;
-               var->refname = malloc(strlen(cp[0]) + strlen(attname) + 2);
-               strcpy(var->refname, cp[0]);
+               var->refname = malloc(strlen(relname) + strlen(attname) + 2);
+               strcpy(var->refname, relname);
                strcat(var->refname, ".");
                strcat(var->refname, attname);
                var->datatype = malloc(sizeof(PLpgSQL_type));
@@ -1205,9 +1227,6 @@ plpgsql_parse_wordrowtype(char *word)
                var->isnull = true;
                var->freeval = false;
 
-               ReleaseSysCache(typetup);
-               ReleaseSysCache(attrtup);
-
                plpgsql_adddatum((PLpgSQL_datum *) var);
 
                /*
@@ -1215,16 +1234,14 @@ plpgsql_parse_wordrowtype(char *word)
                 */
                row->fieldnames[i] = strdup(attname);
                row->varnos[i] = var->varno;
+
+               ReleaseSysCache(typetup);
+               ReleaseSysCache(attrtup);
        }
 
        ReleaseSysCache(classtup);
 
-       /*
-        * Return the complete row definition
-        */
-       plpgsql_yylval.row = row;
-
-       return T_ROW;
+       return row;
 }