Commit 55ca02f4 authored by Tom Lane's avatar Tom Lane

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.
parent 77a7e996
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -85,6 +85,9 @@ int plpgsql_DumpExecTree = 0; ...@@ -85,6 +85,9 @@ int plpgsql_DumpExecTree = 0;
PLpgSQL_function *plpgsql_curr_compile; 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 * 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 * is that the compiled form of a plpgsql function is allocated permanently
...@@ -234,7 +237,9 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -234,7 +237,9 @@ plpgsql_compile(Oid fn_oid, int functype)
*/ */
for (i = 0; i < procStruct->pronargs; i++) 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 * Get the parameters type
...@@ -258,13 +263,7 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -258,13 +263,7 @@ plpgsql_compile(Oid fn_oid, int functype)
* For tuple type parameters, we set up a record of * For tuple type parameters, we set up a record of
* that type * that type
*/ */
sprintf(buf, "%s%%rowtype", NameStr(typeStruct->typname)); row = build_rowtype(typeStruct->typrelid);
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->refname = strdup(buf); row->refname = strdup(buf);
...@@ -284,7 +283,6 @@ plpgsql_compile(Oid fn_oid, int functype) ...@@ -284,7 +283,6 @@ plpgsql_compile(Oid fn_oid, int functype)
var->datatype = malloc(sizeof(PLpgSQL_type)); var->datatype = malloc(sizeof(PLpgSQL_type));
memset(var->datatype, 0, sizeof(PLpgSQL_type)); memset(var->datatype, 0, sizeof(PLpgSQL_type));
sprintf(buf, "$%d", i + 1);
var->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup(buf); var->refname = strdup(buf);
var->lineno = 0; var->lineno = 0;
...@@ -1097,15 +1095,6 @@ int ...@@ -1097,15 +1095,6 @@ int
plpgsql_parse_wordrowtype(char *word) plpgsql_parse_wordrowtype(char *word)
{ {
Oid classOid; 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]; char *cp[2];
int i; int i;
...@@ -1116,25 +1105,51 @@ plpgsql_parse_wordrowtype(char *word) ...@@ -1116,25 +1105,51 @@ plpgsql_parse_wordrowtype(char *word)
word[i] = '.'; word[i] = '.';
plpgsql_convert_ident(word, cp, 2); plpgsql_convert_ident(word, cp, 2);
word[i] = '%'; 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]); 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. * Fetch the pg_class tuple.
*/ */
classOid = RelnameGetRelid(cp[0]);
if (!OidIsValid(classOid))
elog(ERROR, "%s: no such class", cp[0]);
classtup = SearchSysCache(RELOID, classtup = SearchSysCache(RELOID,
ObjectIdGetDatum(classOid), ObjectIdGetDatum(classOid),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(classtup)) 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); classStruct = (Form_pg_class) GETSTRUCT(classtup);
relname = NameStr(classStruct->relname);
/* accept relation, sequence, or view pg_class entries */ /* accept relation, sequence, or view pg_class entries */
if (classStruct->relkind != RELKIND_RELATION && if (classStruct->relkind != RELKIND_RELATION &&
classStruct->relkind != RELKIND_SEQUENCE && classStruct->relkind != RELKIND_SEQUENCE &&
classStruct->relkind != RELKIND_VIEW) 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 * Create a row datum entry and all the required variables that it
...@@ -1151,6 +1166,13 @@ plpgsql_parse_wordrowtype(char *word) ...@@ -1151,6 +1166,13 @@ plpgsql_parse_wordrowtype(char *word)
for (i = 0; i < row->nfields; i++) 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 * Get the attribute and it's type
*/ */
...@@ -1160,17 +1182,17 @@ plpgsql_parse_wordrowtype(char *word) ...@@ -1160,17 +1182,17 @@ plpgsql_parse_wordrowtype(char *word)
0, 0); 0, 0);
if (!HeapTupleIsValid(attrtup)) if (!HeapTupleIsValid(attrtup))
elog(ERROR, "cache lookup for attribute %d of class %s failed", elog(ERROR, "cache lookup for attribute %d of class %s failed",
i + 1, cp[0]); i + 1, relname);
attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup); attrStruct = (Form_pg_attribute) GETSTRUCT(attrtup);
attname = pstrdup(NameStr(attrStruct->attname)); attname = NameStr(attrStruct->attname);
typetup = SearchSysCache(TYPEOID, typetup = SearchSysCache(TYPEOID,
ObjectIdGetDatum(attrStruct->atttypid), ObjectIdGetDatum(attrStruct->atttypid),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(typetup)) if (!HeapTupleIsValid(typetup))
elog(ERROR, "cache lookup for type %u of %s.%s failed", 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); typeStruct = (Form_pg_type) GETSTRUCT(typetup);
/* /*
...@@ -1186,8 +1208,8 @@ plpgsql_parse_wordrowtype(char *word) ...@@ -1186,8 +1208,8 @@ plpgsql_parse_wordrowtype(char *word)
var = malloc(sizeof(PLpgSQL_var)); var = malloc(sizeof(PLpgSQL_var));
memset(var, 0, sizeof(PLpgSQL_var)); memset(var, 0, sizeof(PLpgSQL_var));
var->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
var->refname = malloc(strlen(cp[0]) + strlen(attname) + 2); var->refname = malloc(strlen(relname) + strlen(attname) + 2);
strcpy(var->refname, cp[0]); strcpy(var->refname, relname);
strcat(var->refname, "."); strcat(var->refname, ".");
strcat(var->refname, attname); strcat(var->refname, attname);
var->datatype = malloc(sizeof(PLpgSQL_type)); var->datatype = malloc(sizeof(PLpgSQL_type));
...@@ -1205,9 +1227,6 @@ plpgsql_parse_wordrowtype(char *word) ...@@ -1205,9 +1227,6 @@ plpgsql_parse_wordrowtype(char *word)
var->isnull = true; var->isnull = true;
var->freeval = false; var->freeval = false;
ReleaseSysCache(typetup);
ReleaseSysCache(attrtup);
plpgsql_adddatum((PLpgSQL_datum *) var); plpgsql_adddatum((PLpgSQL_datum *) var);
/* /*
...@@ -1215,16 +1234,14 @@ plpgsql_parse_wordrowtype(char *word) ...@@ -1215,16 +1234,14 @@ plpgsql_parse_wordrowtype(char *word)
*/ */
row->fieldnames[i] = strdup(attname); row->fieldnames[i] = strdup(attname);
row->varnos[i] = var->varno; row->varnos[i] = var->varno;
ReleaseSysCache(typetup);
ReleaseSysCache(attrtup);
} }
ReleaseSysCache(classtup); ReleaseSysCache(classtup);
/* return row;
* Return the complete row definition
*/
plpgsql_yylval.row = row;
return T_ROW;
} }
......
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