Thanks to visit codestin.com
Credit goes to github.com

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)