From 55ca02f447947416e66ef5355a0e4bf007c230c7 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 12 Aug 2002 14:25:07 +0000 Subject: [PATCH] Restructure rowtype-parameter handling to eliminate need for possibly- 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 | 93 +++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index d3c7cb0ef0..00edb1abf9 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -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; } -- 2.40.0