Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4089d25

Browse files
committed
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.
1 parent 982430f commit 4089d25

File tree

4 files changed

+99
-106
lines changed

4 files changed

+99
-106
lines changed

doc/src/sgml/plpgsql.sgml

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v 1.17 2003/04/07 01:29:25 petere Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v 1.18 2003/04/27 22:21:22 tgl Exp $
33
-->
44

55
<chapter id="plpgsql">
@@ -541,7 +541,8 @@ user_id users.user_id%TYPE;
541541
<title>Row Types</title>
542542

543543
<synopsis>
544-
<replaceable>name</replaceable> <replaceable>tablename</replaceable><literal>%ROWTYPE</literal>;
544+
<replaceable>name</replaceable> <replaceable>table_name</replaceable><literal>%ROWTYPE</literal>;
545+
<replaceable>name</replaceable> <replaceable>composite_type_name</replaceable>;
545546
</synopsis>
546547

547548
<para>
@@ -550,17 +551,20 @@ user_id users.user_id%TYPE;
550551
can hold a whole row of a <command>SELECT</> or <command>FOR</>
551552
query result, so long as that query's column set matches the
552553
declared type of the variable.
553-
<replaceable>tablename</replaceable> must be an existing table or
554-
view name in the database. The individual fields of the row value
554+
The individual fields of the row value
555555
are accessed using the usual dot notation, for example
556556
<literal>rowvar.field</literal>.
557557
</para>
558558

559559
<para>
560-
Presently, a row variable can only be declared using the
561-
<literal>%ROWTYPE</literal> notation; although one might expect a
562-
bare table name to work as a type declaration, it won't be accepted
563-
within <application>PL/pgSQL</application> functions.
560+
A row variable can be declared to have the same type as the rows of
561+
an existing table or view, by using the
562+
<replaceable>table_name</replaceable><literal>%ROWTYPE</literal>
563+
notation; or it can be declared by giving a composite type's name.
564+
(Since every table has an associated datatype of the same name,
565+
it actually does not matter in <productname>PostgreSQL</> whether you
566+
write <literal>%ROWTYPE</literal> or not. But the form with
567+
<literal>%ROWTYPE</literal> is more portable.)
564568
</para>
565569

566570
<para>

src/pl/plpgsql/src/gram.y

Lines changed: 49 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* procedural language
55
*
66
* IDENTIFICATION
7-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.41 2003/03/25 03:16:40 tgl Exp $
7+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.42 2003/04/27 22:21:22 tgl Exp $
88
*
99
* This software is copyrighted by Jan Wieck - Hamburg.
1010
*
@@ -307,36 +307,64 @@ decl_stmt : '<' '<' opt_lblname '>' '>'
307307

308308
decl_statement : decl_varname decl_const decl_datatype decl_notnull decl_defval
309309
{
310-
PLpgSQL_var *new;
310+
if (!OidIsValid($3->typrelid))
311+
{
312+
/* Ordinary scalar datatype */
313+
PLpgSQL_var *var;
311314

312-
new = malloc(sizeof(PLpgSQL_var));
313-
memset(new, 0, sizeof(PLpgSQL_var));
315+
var = malloc(sizeof(PLpgSQL_var));
316+
memset(var, 0, sizeof(PLpgSQL_var));
314317

315-
new->dtype = PLPGSQL_DTYPE_VAR;
316-
new->refname = $1.name;
317-
new->lineno = $1.lineno;
318+
var->dtype = PLPGSQL_DTYPE_VAR;
319+
var->refname = $1.name;
320+
var->lineno = $1.lineno;
318321

319-
new->datatype = $3;
320-
new->isconst = $2;
321-
new->notnull = $4;
322-
new->default_val = $5;
322+
var->datatype = $3;
323+
var->isconst = $2;
324+
var->notnull = $4;
325+
var->default_val = $5;
323326

324-
plpgsql_adddatum((PLpgSQL_datum *)new);
325-
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
326-
$1.name);
327+
plpgsql_adddatum((PLpgSQL_datum *)var);
328+
plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR,
329+
var->varno,
330+
$1.name);
331+
}
332+
else
333+
{
334+
/* Composite type --- treat as rowtype */
335+
PLpgSQL_row *row;
336+
337+
row = build_rowtype($3->typrelid);
338+
row->dtype = PLPGSQL_DTYPE_ROW;
339+
row->refname = $1.name;
340+
row->lineno = $1.lineno;
341+
342+
if ($2)
343+
elog(ERROR, "Rowtype variable cannot be CONSTANT");
344+
if ($4)
345+
elog(ERROR, "Rowtype variable cannot be NOT NULL");
346+
if ($5 != NULL)
347+
elog(ERROR, "Default value for rowtype variable is not supported");
348+
349+
plpgsql_adddatum((PLpgSQL_datum *)row);
350+
plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW,
351+
row->rowno,
352+
$1.name);
353+
354+
}
327355
}
328356
| decl_varname K_RECORD ';'
329357
{
330-
PLpgSQL_rec *new;
358+
PLpgSQL_rec *var;
331359

332-
new = malloc(sizeof(PLpgSQL_rec));
360+
var = malloc(sizeof(PLpgSQL_rec));
333361

334-
new->dtype = PLPGSQL_DTYPE_REC;
335-
new->refname = $1.name;
336-
new->lineno = $1.lineno;
362+
var->dtype = PLPGSQL_DTYPE_REC;
363+
var->refname = $1.name;
364+
var->lineno = $1.lineno;
337365

338-
plpgsql_adddatum((PLpgSQL_datum *)new);
339-
plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, new->recno,
366+
plpgsql_adddatum((PLpgSQL_datum *)var);
367+
plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, var->recno,
340368
$1.name);
341369
}
342370
| decl_varname decl_rowtype ';'

src/pl/plpgsql/src/pl_comp.c

Lines changed: 29 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.56 2003/04/24 21:16:44 tgl Exp $
6+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.57 2003/04/27 22:21:22 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -81,7 +81,7 @@ PLpgSQL_function *plpgsql_curr_compile;
8181

8282

8383
static void plpgsql_compile_error_callback(void *arg);
84-
static PLpgSQL_row *build_rowtype(Oid classOid);
84+
static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod);
8585

8686

8787
/*
@@ -275,19 +275,11 @@ plpgsql_compile(Oid fn_oid, int functype)
275275
*/
276276
var = malloc(sizeof(PLpgSQL_var));
277277
memset(var, 0, sizeof(PLpgSQL_var));
278-
var->datatype = malloc(sizeof(PLpgSQL_type));
279-
memset(var->datatype, 0, sizeof(PLpgSQL_type));
280278

281279
var->dtype = PLPGSQL_DTYPE_VAR;
282280
var->refname = strdup(buf);
283281
var->lineno = 0;
284-
var->datatype->typname = strdup(NameStr(typeStruct->typname));
285-
var->datatype->typoid = procStruct->proargtypes[i];
286-
perm_fmgr_info(typeStruct->typinput, &(var->datatype->typinput));
287-
var->datatype->typelem = typeStruct->typelem;
288-
var->datatype->typbyval = typeStruct->typbyval;
289-
var->datatype->typlen = typeStruct->typlen;
290-
var->datatype->atttypmod = -1;
282+
var->datatype = build_datatype(typeTup, -1);
291283
var->isconst = true;
292284
var->notnull = false;
293285
var->default_val = NULL;
@@ -908,7 +900,6 @@ plpgsql_parse_wordtype(char *word)
908900
if (HeapTupleIsValid(typeTup))
909901
{
910902
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
911-
PLpgSQL_type *typ;
912903

913904
if (!typeStruct->typisdefined ||
914905
typeStruct->typrelid != InvalidOid)
@@ -918,17 +909,7 @@ plpgsql_parse_wordtype(char *word)
918909
return T_ERROR;
919910
}
920911

921-
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
922-
923-
typ->typname = strdup(NameStr(typeStruct->typname));
924-
typ->typoid = typeOid;
925-
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
926-
typ->typelem = typeStruct->typelem;
927-
typ->typbyval = typeStruct->typbyval;
928-
typ->typlen = typeStruct->typlen;
929-
typ->atttypmod = -1;
930-
931-
plpgsql_yylval.dtype = typ;
912+
plpgsql_yylval.dtype = build_datatype(typeTup, -1);
932913

933914
ReleaseSysCache(typeTup);
934915
pfree(cp[0]);
@@ -960,8 +941,6 @@ plpgsql_parse_dblwordtype(char *word)
960941
HeapTuple attrtup;
961942
Form_pg_attribute attrStruct;
962943
HeapTuple typetup;
963-
Form_pg_type typeStruct;
964-
PLpgSQL_type *typ;
965944
char *cp[3];
966945
int i;
967946

@@ -1067,22 +1046,11 @@ plpgsql_parse_dblwordtype(char *word)
10671046
if (!HeapTupleIsValid(typetup))
10681047
elog(ERROR, "cache lookup for type %u of %s.%s failed",
10691048
attrStruct->atttypid, cp[0], cp[1]);
1070-
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
10711049

10721050
/*
10731051
* Found that - build a compiler type struct and return it
10741052
*/
1075-
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
1076-
1077-
typ->typname = strdup(NameStr(typeStruct->typname));
1078-
typ->typoid = attrStruct->atttypid;
1079-
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
1080-
typ->typelem = typeStruct->typelem;
1081-
typ->typbyval = typeStruct->typbyval;
1082-
typ->typlen = typeStruct->typlen;
1083-
typ->atttypmod = attrStruct->atttypmod;
1084-
1085-
plpgsql_yylval.dtype = typ;
1053+
plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);
10861054

10871055
ReleaseSysCache(classtup);
10881056
ReleaseSysCache(attrtup);
@@ -1107,8 +1075,6 @@ plpgsql_parse_tripwordtype(char *word)
11071075
HeapTuple attrtup;
11081076
Form_pg_attribute attrStruct;
11091077
HeapTuple typetup;
1110-
Form_pg_type typeStruct;
1111-
PLpgSQL_type *typ;
11121078
char *cp[2];
11131079
char *colname[1];
11141080
int qualified_att_len;
@@ -1192,22 +1158,11 @@ plpgsql_parse_tripwordtype(char *word)
11921158
if (!HeapTupleIsValid(typetup))
11931159
elog(ERROR, "cache lookup for type %u of %s.%s failed",
11941160
attrStruct->atttypid, cp[0], cp[1]);
1195-
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
11961161

11971162
/*
11981163
* Found that - build a compiler type struct and return it
11991164
*/
1200-
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
1201-
1202-
typ->typname = strdup(NameStr(typeStruct->typname));
1203-
typ->typoid = attrStruct->atttypid;
1204-
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
1205-
typ->typelem = typeStruct->typelem;
1206-
typ->typbyval = typeStruct->typbyval;
1207-
typ->typlen = typeStruct->typlen;
1208-
typ->atttypmod = attrStruct->atttypmod;
1209-
1210-
plpgsql_yylval.dtype = typ;
1165+
plpgsql_yylval.dtype = build_datatype(typetup, attrStruct->atttypmod);
12111166

12121167
ReleaseSysCache(classtup);
12131168
ReleaseSysCache(attrtup);
@@ -1296,7 +1251,7 @@ plpgsql_parse_dblwordrowtype(char *word)
12961251
/*
12971252
* Build a rowtype data structure given the pg_class OID.
12981253
*/
1299-
static PLpgSQL_row *
1254+
PLpgSQL_row *
13001255
build_rowtype(Oid classOid)
13011256
{
13021257
PLpgSQL_row *row;
@@ -1341,7 +1296,6 @@ build_rowtype(Oid classOid)
13411296
HeapTuple attrtup;
13421297
Form_pg_attribute attrStruct;
13431298
HeapTuple typetup;
1344-
Form_pg_type typeStruct;
13451299
const char *attname;
13461300
PLpgSQL_var *var;
13471301

@@ -1365,7 +1319,6 @@ build_rowtype(Oid classOid)
13651319
if (!HeapTupleIsValid(typetup))
13661320
elog(ERROR, "cache lookup for type %u of %s.%s failed",
13671321
attrStruct->atttypid, relname, attname);
1368-
typeStruct = (Form_pg_type) GETSTRUCT(typetup);
13691322

13701323
/*
13711324
* Create the internal variable
@@ -1384,14 +1337,7 @@ build_rowtype(Oid classOid)
13841337
strcpy(var->refname, relname);
13851338
strcat(var->refname, ".");
13861339
strcat(var->refname, attname);
1387-
var->datatype = malloc(sizeof(PLpgSQL_type));
1388-
var->datatype->typname = strdup(NameStr(typeStruct->typname));
1389-
var->datatype->typoid = attrStruct->atttypid;
1390-
perm_fmgr_info(typeStruct->typinput, &(var->datatype->typinput));
1391-
var->datatype->typelem = typeStruct->typelem;
1392-
var->datatype->typbyval = typeStruct->typbyval;
1393-
var->datatype->typlen = typeStruct->typlen;
1394-
var->datatype->atttypmod = attrStruct->atttypmod;
1340+
var->datatype = build_datatype(typetup, attrStruct->atttypmod);
13951341
var->isconst = false;
13961342
var->notnull = false;
13971343
var->default_val = NULL;
@@ -1428,7 +1374,6 @@ plpgsql_parse_datatype(char *string)
14281374
Oid type_id;
14291375
int32 typmod;
14301376
HeapTuple typeTup;
1431-
Form_pg_type typeStruct;
14321377
PLpgSQL_type *typ;
14331378

14341379
/* Let the main parser try to parse it under standard SQL rules */
@@ -1440,20 +1385,34 @@ plpgsql_parse_datatype(char *string)
14401385
0, 0, 0);
14411386
if (!HeapTupleIsValid(typeTup))
14421387
elog(ERROR, "cache lookup failed for type %u", type_id);
1443-
typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
1388+
1389+
typ = build_datatype(typeTup, typmod);
1390+
1391+
ReleaseSysCache(typeTup);
1392+
1393+
return typ;
1394+
}
1395+
1396+
/*
1397+
* Utility subroutine to make a PLpgSQL_type struct given a pg_type entry
1398+
*/
1399+
static PLpgSQL_type *
1400+
build_datatype(HeapTuple typeTup, int32 typmod)
1401+
{
1402+
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
1403+
PLpgSQL_type *typ;
14441404

14451405
typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
14461406

14471407
typ->typname = strdup(NameStr(typeStruct->typname));
1448-
typ->typoid = type_id;
1449-
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
1450-
typ->typelem = typeStruct->typelem;
1451-
typ->typbyval = typeStruct->typbyval;
1408+
typ->typoid = HeapTupleGetOid(typeTup);
14521409
typ->typlen = typeStruct->typlen;
1410+
typ->typbyval = typeStruct->typbyval;
1411+
typ->typrelid = typeStruct->typrelid;
1412+
typ->typelem = typeStruct->typelem;
1413+
perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
14531414
typ->atttypmod = typmod;
14541415

1455-
ReleaseSysCache(typeTup);
1456-
14571416
return typ;
14581417
}
14591418

src/pl/plpgsql/src/plpgsql.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.34 2003/04/24 21:16:44 tgl Exp $
6+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.35 2003/04/27 22:21:22 tgl Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -142,14 +142,15 @@ typedef struct
142142

143143

144144
typedef struct
145-
{ /* Postgres base data type */
145+
{ /* Postgres data type */
146146
char *typname;
147-
Oid typoid;
148-
FmgrInfo typinput;
149-
Oid typelem;
150-
int16 typlen;
147+
Oid typoid; /* OID of the data type */
148+
int16 typlen; /* stuff copied from its pg_type entry */
151149
bool typbyval;
152-
int32 atttypmod;
150+
Oid typrelid;
151+
Oid typelem;
152+
FmgrInfo typinput; /* lookup info for typinput function */
153+
int32 atttypmod; /* typmod (taken from someplace else) */
153154
} PLpgSQL_type;
154155

155156

@@ -600,6 +601,7 @@ extern int plpgsql_parse_tripwordtype(char *word);
600601
extern int plpgsql_parse_wordrowtype(char *word);
601602
extern int plpgsql_parse_dblwordrowtype(char *word);
602603
extern PLpgSQL_type *plpgsql_parse_datatype(char *string);
604+
extern PLpgSQL_row *build_rowtype(Oid classOid);
603605
extern void plpgsql_adddatum(PLpgSQL_datum * new);
604606
extern int plpgsql_add_initdatums(int **varnos);
605607
extern void plpgsql_yyerror(const char *s);

0 commit comments

Comments
 (0)