mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-18 18:44:06 +08:00
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.
This commit is contained in:
parent
77a7e9968b
commit
55ca02f447
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user