<!--
-$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">
<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>
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>
* 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.
*
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 ';'
* 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.
*
static void plpgsql_compile_error_callback(void *arg);
-static PLpgSQL_row *build_rowtype(Oid classOid);
+static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod);
/*
*/
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;
if (HeapTupleIsValid(typeTup))
{
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
- PLpgSQL_type *typ;
if (!typeStruct->typisdefined ||
typeStruct->typrelid != InvalidOid)
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]);
HeapTuple attrtup;
Form_pg_attribute attrStruct;
HeapTuple typetup;
- Form_pg_type typeStruct;
- PLpgSQL_type *typ;
char *cp[3];
int i;
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);
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;
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);
/*
* Build a rowtype data structure given the pg_class OID.
*/
-static PLpgSQL_row *
+PLpgSQL_row *
build_rowtype(Oid classOid)
{
PLpgSQL_row *row;
HeapTuple attrtup;
Form_pg_attribute attrStruct;
HeapTuple typetup;
- Form_pg_type typeStruct;
const char *attname;
PLpgSQL_var *var;
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
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;
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 */
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;
}