提交 4089d251 编写于 作者: T 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.
上级 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">
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册