Commit 4089d251 authored by Tom Lane's avatar Tom Lane

Fix plpgsql so that variables of composite types (rowtypes) can be

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.
parent 982430f8
<!-- <!--
$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"> <chapter id="plpgsql">
...@@ -541,7 +541,8 @@ user_id users.user_id%TYPE; ...@@ -541,7 +541,8 @@ user_id users.user_id%TYPE;
<title>Row Types</title> <title>Row Types</title>
<synopsis> <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> </synopsis>
<para> <para>
...@@ -550,17 +551,20 @@ user_id users.user_id%TYPE; ...@@ -550,17 +551,20 @@ user_id users.user_id%TYPE;
can hold a whole row of a <command>SELECT</> or <command>FOR</> can hold a whole row of a <command>SELECT</> or <command>FOR</>
query result, so long as that query's column set matches the query result, so long as that query's column set matches the
declared type of the variable. declared type of the variable.
<replaceable>tablename</replaceable> must be an existing table or The individual fields of the row value
view name in the database. The individual fields of the row value
are accessed using the usual dot notation, for example are accessed using the usual dot notation, for example
<literal>rowvar.field</literal>. <literal>rowvar.field</literal>.
</para> </para>
<para> <para>
Presently, a row variable can only be declared using the A row variable can be declared to have the same type as the rows of
<literal>%ROWTYPE</literal> notation; although one might expect a an existing table or view, by using the
bare table name to work as a type declaration, it won't be accepted <replaceable>table_name</replaceable><literal>%ROWTYPE</literal>
within <application>PL/pgSQL</application> functions. 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>
<para> <para>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -307,36 +307,64 @@ decl_stmt : '<' '<' opt_lblname '>' '>' ...@@ -307,36 +307,64 @@ decl_stmt : '<' '<' opt_lblname '>' '>'
decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval 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)); var = malloc(sizeof(PLpgSQL_var));
memset(new, 0, sizeof(PLpgSQL_var)); memset(var, 0, sizeof(PLpgSQL_var));
new->dtype = PLPGSQL_DTYPE_VAR; var->dtype = PLPGSQL_DTYPE_VAR;
new->refname = $1.name; var->refname = $1.name;
new->lineno = $1.lineno; var->lineno = $1.lineno;
new->datatype = $3; var->datatype = $3;
new->isconst = $2; var->isconst = $2;
new->notnull = $4; var->notnull = $4;
new->default_val = $5; var->default_val = $5;
plpgsql_adddatum((PLpgSQL_datum *)new); plpgsql_adddatum((PLpgSQL_datum *)var);
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno, plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR,
$1.name); 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 ';' | 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; var->dtype = PLPGSQL_DTYPE_REC;
new->refname = $1.name; var->refname = $1.name;
new->lineno = $1.lineno; var->lineno = $1.lineno;
plpgsql_adddatum((PLpgSQL_datum *)new); plpgsql_adddatum((PLpgSQL_datum *)var);
plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, new->recno, plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, var->recno,
$1.name); $1.name);
} }
| decl_varname decl_rowtype ';' | decl_varname decl_rowtype ';'
......
...@@ -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.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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -81,7 +81,7 @@ PLpgSQL_function *plpgsql_curr_compile; ...@@ -81,7 +81,7 @@ PLpgSQL_function *plpgsql_curr_compile;
static void plpgsql_compile_error_callback(void *arg); 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) ...@@ -275,19 +275,11 @@ plpgsql_compile(Oid fn_oid, int functype)
*/ */
var = malloc(sizeof(PLpgSQL_var)); var = malloc(sizeof(PLpgSQL_var));
memset(var, 0, 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->dtype = PLPGSQL_DTYPE_VAR;
var->refname = strdup(buf); var->refname = strdup(buf);
var->lineno = 0; var->lineno = 0;
var->datatype->typname = strdup(NameStr(typeStruct->typname)); var->datatype = build_datatype(typeTup, -1);
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->isconst = true; var->isconst = true;
var->notnull = false; var->notnull = false;
var->default_val = NULL; var->default_val = NULL;
...@@ -908,7 +900,6 @@ plpgsql_parse_wordtype(char *word) ...@@ -908,7 +900,6 @@ plpgsql_parse_wordtype(char *word)
if (HeapTupleIsValid(typeTup)) if (HeapTupleIsValid(typeTup))
{ {
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup); Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
PLpgSQL_type *typ;
if (!typeStruct->typisdefined || if (!typeStruct->typisdefined ||
typeStruct->typrelid != InvalidOid) typeStruct->typrelid != InvalidOid)
...@@ -918,17 +909,7 @@ plpgsql_parse_wordtype(char *word) ...@@ -918,17 +909,7 @@ plpgsql_parse_wordtype(char *word)
return T_ERROR; return T_ERROR;
} }
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); plpgsql_yylval.dtype = build_datatype(typeTup, -1);
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;
ReleaseSysCache(typeTup); ReleaseSysCache(typeTup);
pfree(cp[0]); pfree(cp[0]);
...@@ -960,8 +941,6 @@ plpgsql_parse_dblwordtype(char *word) ...@@ -960,8 +941,6 @@ plpgsql_parse_dblwordtype(char *word)
HeapTuple attrtup; HeapTuple attrtup;
Form_pg_attribute attrStruct; Form_pg_attribute attrStruct;
HeapTuple typetup; HeapTuple typetup;
Form_pg_type typeStruct;
PLpgSQL_type *typ;
char *cp[3]; char *cp[3];
int i; int i;
...@@ -1067,22 +1046,11 @@ plpgsql_parse_dblwordtype(char *word) ...@@ -1067,22 +1046,11 @@ plpgsql_parse_dblwordtype(char *word)
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], cp[1]); attrStruct->atttypid, cp[0], cp[1]);
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
/* /*
* Found that - build a compiler type struct and return it * Found that - build a compiler type struct and return it
*/ */
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);
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;
ReleaseSysCache(classtup); ReleaseSysCache(classtup);
ReleaseSysCache(attrtup); ReleaseSysCache(attrtup);
...@@ -1107,8 +1075,6 @@ plpgsql_parse_tripwordtype(char *word) ...@@ -1107,8 +1075,6 @@ plpgsql_parse_tripwordtype(char *word)
HeapTuple attrtup; HeapTuple attrtup;
Form_pg_attribute attrStruct; Form_pg_attribute attrStruct;
HeapTuple typetup; HeapTuple typetup;
Form_pg_type typeStruct;
PLpgSQL_type *typ;
char *cp[2]; char *cp[2];
char *colname[1]; char *colname[1];
int qualified_att_len; int qualified_att_len;
...@@ -1192,22 +1158,11 @@ plpgsql_parse_tripwordtype(char *word) ...@@ -1192,22 +1158,11 @@ plpgsql_parse_tripwordtype(char *word)
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], cp[1]); attrStruct->atttypid, cp[0], cp[1]);
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
/* /*
* Found that - build a compiler type struct and return it * Found that - build a compiler type struct and return it
*/ */
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type)); plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);
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;
ReleaseSysCache(classtup); ReleaseSysCache(classtup);
ReleaseSysCache(attrtup); ReleaseSysCache(attrtup);
...@@ -1296,7 +1251,7 @@ plpgsql_parse_dblwordrowtype(char *word) ...@@ -1296,7 +1251,7 @@ plpgsql_parse_dblwordrowtype(char *word)
/* /*
* Build a rowtype data structure given the pg_class OID. * Build a rowtype data structure given the pg_class OID.
*/ */
static PLpgSQL_row * PLpgSQL_row *
build_rowtype(Oid classOid) build_rowtype(Oid classOid)
{ {
PLpgSQL_row *row; PLpgSQL_row *row;
...@@ -1341,7 +1296,6 @@ build_rowtype(Oid classOid) ...@@ -1341,7 +1296,6 @@ build_rowtype(Oid classOid)
HeapTuple attrtup; HeapTuple attrtup;
Form_pg_attribute attrStruct; Form_pg_attribute attrStruct;
HeapTuple typetup; HeapTuple typetup;
Form_pg_type typeStruct;
const char *attname; const char *attname;
PLpgSQL_var *var; PLpgSQL_var *var;
...@@ -1365,7 +1319,6 @@ build_rowtype(Oid classOid) ...@@ -1365,7 +1319,6 @@ build_rowtype(Oid classOid)
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, relname, attname); attrStruct->atttypid, relname, attname);
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
/* /*
* Create the internal variable * Create the internal variable
...@@ -1384,14 +1337,7 @@ build_rowtype(Oid classOid) ...@@ -1384,14 +1337,7 @@ build_rowtype(Oid classOid)
strcpy(var->refname, relname); 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 = build_datatype(typetup, attrStruct->atttypmod);
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->isconst = false; var->isconst = false;
var->notnull = false; var->notnull = false;
var->default_val = NULL; var->default_val = NULL;
...@@ -1428,7 +1374,6 @@ plpgsql_parse_datatype(char *string) ...@@ -1428,7 +1374,6 @@ plpgsql_parse_datatype(char *string)
Oid type_id; Oid type_id;
int32 typmod; int32 typmod;
HeapTuple typeTup; HeapTuple typeTup;
Form_pg_type typeStruct;
PLpgSQL_type *typ; PLpgSQL_type *typ;
/* Let the main parser try to parse it under standard SQL rules */ /* Let the main parser try to parse it under standard SQL rules */
...@@ -1440,20 +1385,34 @@ plpgsql_parse_datatype(char *string) ...@@ -1440,20 +1385,34 @@ plpgsql_parse_datatype(char *string)
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(typeTup)) if (!HeapTupleIsValid(typeTup))
elog(ERROR, "cache lookup failed for type %u", type_id); 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 = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
typ->typname = strdup(NameStr(typeStruct->typname)); typ->typname = strdup(NameStr(typeStruct->typname));
typ->typoid = type_id; typ->typoid = HeapTupleGetOid(typeTup);
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
typ->typelem = typeStruct->typelem;
typ->typbyval = typeStruct->typbyval;
typ->typlen = typeStruct->typlen; 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; typ->atttypmod = typmod;
ReleaseSysCache(typeTup);
return typ; return typ;
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* procedural language * procedural language
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -142,14 +142,15 @@ typedef struct ...@@ -142,14 +142,15 @@ typedef struct
typedef struct typedef struct
{ /* Postgres base data type */ { /* Postgres data type */
char *typname; char *typname;
Oid typoid; Oid typoid; /* OID of the data type */
FmgrInfo typinput; int16 typlen; /* stuff copied from its pg_type entry */
Oid typelem;
int16 typlen;
bool typbyval; bool typbyval;
int32 atttypmod; Oid typrelid;
Oid typelem;
FmgrInfo typinput; /* lookup info for typinput function */
int32 atttypmod; /* typmod (taken from someplace else) */
} PLpgSQL_type; } PLpgSQL_type;
...@@ -600,6 +601,7 @@ extern int plpgsql_parse_tripwordtype(char *word); ...@@ -600,6 +601,7 @@ extern int plpgsql_parse_tripwordtype(char *word);
extern int plpgsql_parse_wordrowtype(char *word); extern int plpgsql_parse_wordrowtype(char *word);
extern int plpgsql_parse_dblwordrowtype(char *word); extern int plpgsql_parse_dblwordrowtype(char *word);
extern PLpgSQL_type *plpgsql_parse_datatype(char *string); extern PLpgSQL_type *plpgsql_parse_datatype(char *string);
extern PLpgSQL_row *build_rowtype(Oid classOid);
extern void plpgsql_adddatum(PLpgSQL_datum * new); extern void plpgsql_adddatum(PLpgSQL_datum * new);
extern int plpgsql_add_initdatums(int **varnos); extern int plpgsql_add_initdatums(int **varnos);
extern void plpgsql_yyerror(const char *s); extern void plpgsql_yyerror(const char *s);
......
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