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