diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index fb46e1083b08822ccad2a0a95a6828e92f53eebe..36427e2ceaa3be5cb79612d625b33dfcb1c61bcf 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -4,7 +4,7 @@
  *						  procedural language
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.53 2004/04/15 13:01:45 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.54 2004/06/03 22:56:43 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -83,7 +83,8 @@ static	void check_assignable(PLpgSQL_datum *datum);
 			int  *initvarnos;
 		}						declhdr;
 		PLpgSQL_type			*dtype;
-		PLpgSQL_datum			*variable; /* a VAR, RECFIELD, or TRIGARG */
+		PLpgSQL_datum			*scalar;	/* a VAR, RECFIELD, or TRIGARG */
+		PLpgSQL_variable		*variable;	/* a VAR, REC, or ROW */
 		PLpgSQL_var				*var;
 		PLpgSQL_row				*row;
 		PLpgSQL_rec				*rec;
@@ -100,7 +101,7 @@ static	void check_assignable(PLpgSQL_datum *datum);
 %type <ival>	decl_const decl_notnull
 %type <expr>	decl_defval decl_cursor_query
 %type <dtype>	decl_datatype
-%type <row>		decl_rowtype decl_cursor_args decl_cursor_arglist
+%type <row>		decl_cursor_args decl_cursor_arglist
 %type <nsitem>	decl_aliasitem
 %type <str>		decl_stmts decl_stmt
 
@@ -109,7 +110,8 @@ static	void check_assignable(PLpgSQL_datum *datum);
 %type <expr>	opt_exitcond
 
 %type <ival>	assign_var cursor_variable
-%type <var>		fori_var cursor_varptr decl_cursor_arg
+%type <var>		fori_var cursor_varptr
+%type <variable>	decl_cursor_arg
 %type <varname> fori_varname
 %type <forilow> fori_lower
 %type <rec>		fors_target
@@ -174,7 +176,6 @@ static	void check_assignable(PLpgSQL_datum *datum);
 %token	K_PERFORM
 %token	K_ROW_COUNT
 %token	K_RAISE
-%token	K_RECORD
 %token	K_RENAME
 %token	K_RESULT_OID
 %token	K_RETURN
@@ -195,7 +196,7 @@ static	void check_assignable(PLpgSQL_datum *datum);
 %token	T_TRIGGER
 %token	T_STRING
 %token	T_NUMBER
-%token	T_VARIABLE				/* a VAR, RECFIELD, or TRIGARG */
+%token	T_SCALAR				/* a VAR, RECFIELD, or TRIGARG */
 %token	T_ROW
 %token	T_RECORD
 %token	T_DTYPE
@@ -306,86 +307,42 @@ decl_stmt		: '<' '<' opt_lblname '>' '>'
 
 decl_statement	: decl_varname decl_const decl_datatype decl_notnull decl_defval
 					{
-						if (!OidIsValid($3->typrelid))
-						{
-							/* Ordinary scalar datatype */
-							PLpgSQL_var		*var;
-
-							var = malloc(sizeof(PLpgSQL_var));
-							memset(var, 0, sizeof(PLpgSQL_var));
-
-							var->dtype		= PLPGSQL_DTYPE_VAR;
-							var->refname	= $1.name;
-							var->lineno		= $1.lineno;
+						PLpgSQL_variable	*var;
 
-							var->datatype	= $3;
-							var->isconst	= $2;
-							var->notnull	= $4;
-							var->default_val = $5;
-
-							plpgsql_adddatum((PLpgSQL_datum *)var);
-							plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR,
-											   var->varno,
-											   $1.name);
-						}
-						else
+						var = plpgsql_build_variable($1.name, $1.lineno,
+													 $3, true);
+						if ($2)
 						{
-							/* Composite type --- treat as rowtype */
-							PLpgSQL_row	   *row;
-
-							row = plpgsql_build_rowtype($3->typrelid);
-							row->dtype		= PLPGSQL_DTYPE_ROW;
-							row->refname	= $1.name;
-							row->lineno		= $1.lineno;
-
-							if ($2)
+							if (var->dtype == PLPGSQL_DTYPE_VAR)
+								((PLpgSQL_var *) var)->isconst = $2;
+							else
 								ereport(ERROR,
 										(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-										 errmsg("rowtype variable cannot be CONSTANT")));
-							if ($4)
+										 errmsg("row or record variable cannot be CONSTANT")));
+						}
+						if ($4)
+						{
+							if (var->dtype == PLPGSQL_DTYPE_VAR)
+								((PLpgSQL_var *) var)->notnull = $4;
+							else
 								ereport(ERROR,
 										(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-										 errmsg("rowtype variable cannot be NOT NULL")));
-							if ($5 != NULL)
+										 errmsg("row or record variable cannot be NOT NULL")));
+						}
+						if ($5 != NULL)
+						{
+							if (var->dtype == PLPGSQL_DTYPE_VAR)
+								((PLpgSQL_var *) var)->default_val = $5;
+							else
 								ereport(ERROR,
 										(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-										 errmsg("default value for rowtype variable is not supported")));
-
-							plpgsql_adddatum((PLpgSQL_datum *)row);
-							plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW,
-											   row->rowno,
-											   $1.name);
-
+										 errmsg("default value for row or record variable is not supported")));
 						}
 					}
-				| decl_varname K_RECORD ';'
-					{
-						PLpgSQL_rec		*var;
-
-						var = malloc(sizeof(PLpgSQL_rec));
-
-						var->dtype		= PLPGSQL_DTYPE_REC;
-						var->refname	= $1.name;
-						var->lineno		= $1.lineno;
-
-						plpgsql_adddatum((PLpgSQL_datum *)var);
-						plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, var->recno,
-												$1.name);
-					}
-				| decl_varname decl_rowtype ';'
-					{
-						$2->dtype		= PLPGSQL_DTYPE_ROW;
-						$2->refname		= $1.name;
-						$2->lineno		= $1.lineno;
-
-						plpgsql_adddatum((PLpgSQL_datum *)$2);
-						plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, $2->rowno,
-												$1.name);
-					}
 				| decl_varname K_ALIAS K_FOR decl_aliasitem ';'
 					{
 						plpgsql_ns_additem($4->itemtype,
-										$4->itemno, $1.name);
+										   $4->itemno, $1.name);
 					}
 				| K_RENAME decl_renname K_TO decl_renname ';'
 					{
@@ -404,16 +361,15 @@ decl_statement	: decl_varname decl_const decl_datatype decl_notnull decl_defval
 						/* pop local namespace for cursor args */
 						plpgsql_ns_pop();
 
-						new = malloc(sizeof(PLpgSQL_var));
-						memset(new, 0, sizeof(PLpgSQL_var));
+						new = (PLpgSQL_var *)
+							plpgsql_build_variable($1.name, $1.lineno,
+												   plpgsql_build_datatype(REFCURSOROID,
+																		  -1),
+												   true);
 
 						curname_def = malloc(sizeof(PLpgSQL_expr));
 						memset(curname_def, 0, sizeof(PLpgSQL_expr));
 
-						new->dtype		= PLPGSQL_DTYPE_VAR;
-						new->refname	= $1.name;
-						new->lineno		= $1.lineno;
-
 						curname_def->dtype = PLPGSQL_DTYPE_EXPR;
 						strcpy(buf, "SELECT '");
 						cp1 = new->refname;
@@ -428,17 +384,11 @@ decl_statement	: decl_varname decl_const decl_datatype decl_notnull decl_defval
 						curname_def->query = strdup(buf);
 						new->default_val = curname_def;
 
-						new->datatype = plpgsql_parse_datatype("refcursor");
-
 						new->cursor_explicit_expr = $6;
 						if ($4 == NULL)
 							new->cursor_explicit_argrow = -1;
 						else
 							new->cursor_explicit_argrow = $4->rowno;
-
-						plpgsql_adddatum((PLpgSQL_datum *)new);
-						plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
-										   $1.name);
 					}
 				;
 
@@ -504,7 +454,7 @@ decl_cursor_arglist : decl_cursor_arg
 						new->nfields = 1;
 
 						new->fieldnames[0] = $1->refname;
-						new->varnos[0] = $1->varno;
+						new->varnos[0] = $1->dno;
 
 						$$ = new;
 					}
@@ -513,7 +463,7 @@ decl_cursor_arglist : decl_cursor_arg
 						int i = $1->nfields++;
 
 						$1->fieldnames[i] = $3->refname;
-						$1->varnos[i] = $3->varno;
+						$1->varnos[i] = $3->dno;
 
 						$$ = $1;
 					}
@@ -521,24 +471,8 @@ decl_cursor_arglist : decl_cursor_arg
 
 decl_cursor_arg : decl_varname decl_datatype
 					{
-						PLpgSQL_var *new;
-
-						new = malloc(sizeof(PLpgSQL_var));
-						memset(new, 0, sizeof(PLpgSQL_var));
-
-						new->dtype		= PLPGSQL_DTYPE_VAR;
-						new->refname	= $1.name;
-						new->lineno		= $1.lineno;
-
-						new->datatype	= $2;
-						new->isconst	= false;
-						new->notnull	= false;
-
-						plpgsql_adddatum((PLpgSQL_datum *)new);
-						plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
-										   $1.name);
-						
-						$$ = new;
+						$$ = plpgsql_build_variable($1.name, $1.lineno,
+													$2, true);
 					}
 				;
 
@@ -573,12 +507,6 @@ decl_aliasitem	: T_WORD
 					}
 				;
 
-decl_rowtype	: T_ROW
-					{
-						$$ = yylval.row;
-					}
-				;
-
 decl_varname	: T_WORD
 					{
 						char	*name;
@@ -803,18 +731,18 @@ getdiag_item : K_ROW_COUNT
 					}
 				;
 
-getdiag_target	: T_VARIABLE
+getdiag_target	: T_SCALAR
 					{
-						check_assignable(yylval.variable);
-						$$ = yylval.variable->dno;
+						check_assignable(yylval.scalar);
+						$$ = yylval.scalar->dno;
 					}
 				;
 
 
-assign_var		: T_VARIABLE
+assign_var		: T_SCALAR
 					{
-						check_assignable(yylval.variable);
-						$$ = yylval.variable->dno;
+						check_assignable(yylval.scalar);
+						$$ = yylval.scalar->dno;
 					}
 				| assign_var '[' expr_until_rightbracket
 					{
@@ -970,21 +898,11 @@ fori_var		: fori_varname
 					{
 						PLpgSQL_var		*new;
 
-						new = malloc(sizeof(PLpgSQL_var));
-						memset(new, 0, sizeof(PLpgSQL_var));
-
-						new->dtype		= PLPGSQL_DTYPE_VAR;
-						new->refname	= $1.name;
-						new->lineno		= $1.lineno;
-
-						new->datatype	= plpgsql_parse_datatype("integer");
-						new->isconst	= false;
-						new->notnull	= false;
-						new->default_val = NULL;
-
-						plpgsql_adddatum((PLpgSQL_datum *)new);
-						plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, new->varno,
-												$1.name);
+						new = (PLpgSQL_var *)
+							plpgsql_build_variable($1.name, $1.lineno,
+												   plpgsql_build_datatype(INT4OID,
+																		  -1),
+												   true);
 
 						plpgsql_add_initdatums(NULL);
 
@@ -992,7 +910,7 @@ fori_var		: fori_varname
 					}
 				;
 
-fori_varname	: T_VARIABLE
+fori_varname	: T_SCALAR
 					{
 						char	*name;
 
@@ -1297,9 +1215,9 @@ raise_params	: raise_params raise_param
 					}
 				;
 
-raise_param		: ',' T_VARIABLE
+raise_param		: ',' T_SCALAR
 					{
-						$$ = yylval.variable->dno;
+						$$ = yylval.scalar->dno;
 					}
 				;
 
@@ -1491,37 +1409,37 @@ stmt_close		: K_CLOSE lno cursor_variable ';'
 					}
 				;
 
-cursor_varptr	: T_VARIABLE
+cursor_varptr	: T_SCALAR
 					{
-						if (yylval.variable->dtype != PLPGSQL_DTYPE_VAR)
+						if (yylval.scalar->dtype != PLPGSQL_DTYPE_VAR)
 							yyerror("cursor variable must be a simple variable");
 
-						if (((PLpgSQL_var *) yylval.variable)->datatype->typoid != REFCURSOROID)
+						if (((PLpgSQL_var *) yylval.scalar)->datatype->typoid != REFCURSOROID)
 						{
 							plpgsql_error_lineno = plpgsql_scanner_lineno();
 							ereport(ERROR,
 									(errcode(ERRCODE_DATATYPE_MISMATCH),
 									 errmsg("\"%s\" must be of type cursor or refcursor",
-											((PLpgSQL_var *) yylval.variable)->refname)));
+											((PLpgSQL_var *) yylval.scalar)->refname)));
 						}
-						$$ = (PLpgSQL_var *) yylval.variable;
+						$$ = (PLpgSQL_var *) yylval.scalar;
 					}
 				;
 
-cursor_variable	: T_VARIABLE
+cursor_variable	: T_SCALAR
 					{
-						if (yylval.variable->dtype != PLPGSQL_DTYPE_VAR)
+						if (yylval.scalar->dtype != PLPGSQL_DTYPE_VAR)
 							yyerror("cursor variable must be a simple variable");
 
-						if (((PLpgSQL_var *) yylval.variable)->datatype->typoid != REFCURSOROID)
+						if (((PLpgSQL_var *) yylval.scalar)->datatype->typoid != REFCURSOROID)
 						{
 							plpgsql_error_lineno = plpgsql_scanner_lineno();
 							ereport(ERROR,
 									(errcode(ERRCODE_DATATYPE_MISMATCH),
 									 errmsg("\"%s\" must be of type refcursor",
-											((PLpgSQL_var *) yylval.variable)->refname)));
+											((PLpgSQL_var *) yylval.scalar)->refname)));
 						}
-						$$ = yylval.variable->dno;
+						$$ = yylval.scalar->dno;
 					}
 				;
 
@@ -1664,8 +1582,8 @@ read_sql_construct(int until,
 			plpgsql_dstring_append(&ds, " ");
 		switch (tok)
 		{
-			case T_VARIABLE:
-				params[nparams] = yylval.variable->dno;
+			case T_SCALAR:
+				params[nparams] = yylval.scalar->dno;
 				snprintf(buf, sizeof(buf), " $%d ", ++nparams);
 				plpgsql_dstring_append(&ds, buf);
 				break;
@@ -1821,25 +1739,25 @@ make_select_stmt(void)
 					have_into = 1;
 					break;
 
-				case T_VARIABLE:
+				case T_SCALAR:
 				{
 					int				nfields = 1;
 					char			*fieldnames[1024];
 					int				varnos[1024];
 
-					check_assignable(yylval.variable);
+					check_assignable(yylval.scalar);
 					fieldnames[0] = strdup(yytext);
-					varnos[0]	  = yylval.variable->dno;
+					varnos[0]	  = yylval.scalar->dno;
 
 					while ((tok = yylex()) == ',')
 					{
 						tok = yylex();
 						switch(tok)
 						{
-							case T_VARIABLE:
-								check_assignable(yylval.variable);
+							case T_SCALAR:
+								check_assignable(yylval.scalar);
 								fieldnames[nfields] = strdup(yytext);
-								varnos[nfields++]	= yylval.variable->dno;
+								varnos[nfields++]	= yylval.scalar->dno;
 								break;
 
 							default:
@@ -1885,8 +1803,8 @@ make_select_stmt(void)
 			plpgsql_dstring_append(&ds, " ");
 		switch (tok)
 		{
-			case T_VARIABLE:
-				params[nparams] = yylval.variable->dno;
+			case T_SCALAR:
+				params[nparams] = yylval.scalar->dno;
 				snprintf(buf, sizeof(buf), " $%d ", ++nparams);
 				plpgsql_dstring_append(&ds, buf);
 				break;
@@ -1968,25 +1886,25 @@ make_fetch_stmt(void)
 			rec = yylval.rec;
 			break;
 
-		case T_VARIABLE:
+		case T_SCALAR:
 			{
 				int				nfields = 1;
 				char			*fieldnames[1024];
 				int				varnos[1024];
 
-				check_assignable(yylval.variable);
+				check_assignable(yylval.scalar);
 				fieldnames[0] = strdup(yytext);
-				varnos[0]	  = yylval.variable->dno;
+				varnos[0]	  = yylval.scalar->dno;
 
 				while ((tok = yylex()) == ',')
 				{
 					tok = yylex();
 					switch(tok)
 					{
-						case T_VARIABLE:
-							check_assignable(yylval.variable);
+						case T_SCALAR:
+							check_assignable(yylval.scalar);
 							fieldnames[nfields] = strdup(yytext);
-							varnos[nfields++]	= yylval.variable->dno;
+							varnos[nfields++]	= yylval.scalar->dno;
 							break;
 
 						default:
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 8c930de9c237ec01b3f4a015b455cc11a857e902..1c0fe6f8cc4a44c698f52654ad0141fefda40f1d 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -3,7 +3,7 @@
  *			  procedural language
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.75 2004/03/21 22:29:11 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.76 2004/06/03 22:56:43 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -56,6 +56,7 @@
 #include "tcop/tcopprot.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 
@@ -105,6 +106,7 @@ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo,
 		   bool forValidator);
 static void plpgsql_compile_error_callback(void *arg);
 static char **fetchArgNames(HeapTuple procTup, int nargs);
+static PLpgSQL_row *build_row_var(Oid classOid);
 static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod);
 static void compute_function_hashkey(FunctionCallInfo fcinfo,
 						 Form_pg_proc procStruct,
@@ -249,8 +251,7 @@ do_compile(FunctionCallInfo fcinfo,
 	char	   *proc_source;
 	HeapTuple	typeTup;
 	Form_pg_type typeStruct;
-	PLpgSQL_var *var;
-	PLpgSQL_row *row;
+	PLpgSQL_variable *var;
 	PLpgSQL_rec *rec;
 	int			i;
 	int			arg_varnos[FUNC_MAX_ARGS];
@@ -392,33 +393,9 @@ do_compile(FunctionCallInfo fcinfo,
 				if (procStruct->prorettype == ANYARRAYOID ||
 					procStruct->prorettype == ANYELEMENTOID)
 				{
-					char		buf[32];
-
-					/* name for variable */
-					snprintf(buf, sizeof(buf), "$%d", 0);
-
-					/*
-					 * Normal return values get a var node
-					 */
-					var = malloc(sizeof(PLpgSQL_var));
-					memset(var, 0, sizeof(PLpgSQL_var));
-
-					var->dtype = PLPGSQL_DTYPE_VAR;
-					var->refname = strdup(buf);
-					var->lineno = 0;
-					var->datatype = build_datatype(typeTup, -1);
-					var->isconst = false;
-					var->notnull = false;
-					var->default_val = NULL;
-
-					/* preset to NULL */
-					var->value = 0;
-					var->isnull = true;
-					var->freeval = false;
-
-					plpgsql_adddatum((PLpgSQL_datum *) var);
-					plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno,
-									   var->refname);
+					(void) plpgsql_build_variable(strdup("$0"), 0,
+												  build_datatype(typeTup, -1),
+												  true);
 				}
 			}
 			ReleaseSysCache(typeTup);
@@ -432,7 +409,8 @@ do_compile(FunctionCallInfo fcinfo,
 			{
 				char		buf[32];
 				Oid			argtypeid;
-				PLpgSQL_datum *argdatum;
+				PLpgSQL_type *argdtype;
+				PLpgSQL_variable *argvariable;
 				int			argitemtype;
 
 				/* Create $n name for variable */
@@ -444,70 +422,44 @@ do_compile(FunctionCallInfo fcinfo,
 				 * the hashkey, we can just use those results.
 				 */
 				argtypeid = hashkey->argtypes[i];
-
-				/*
-				 * Get the parameter type
-				 */
-				typeTup = SearchSysCache(TYPEOID,
-										 ObjectIdGetDatum(argtypeid),
-										 0, 0, 0);
-				if (!HeapTupleIsValid(typeTup))
-					elog(ERROR, "cache lookup failed for type %u", argtypeid);
-				typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
+				argdtype = plpgsql_build_datatype(argtypeid, -1);
 
 				/* Disallow pseudotype argument */
 				/* (note we already replaced ANYARRAY/ANYELEMENT) */
-				if (typeStruct->typtype == 'p')
+				/* (build_variable would do this, but wrong message) */
+				if (argdtype->ttype != PLPGSQL_TTYPE_SCALAR &&
+					argdtype->ttype != PLPGSQL_TTYPE_ROW)
 					ereport(ERROR,
 							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						  errmsg("plpgsql functions cannot take type %s",
-								 format_type_be(argtypeid))));
+							 errmsg("plpgsql functions cannot take type %s",
+									format_type_be(argtypeid))));
+
+				/* Build variable and add to datum list */
+				argvariable = plpgsql_build_variable(strdup(buf), 0,
+													 argdtype, false);
 
-				if (typeStruct->typrelid != InvalidOid)
+				if (argvariable->dtype == PLPGSQL_DTYPE_VAR)
 				{
-					/*
-					 * For tuple type parameters, we set up a record of
-					 * that type
-					 */
-					row = plpgsql_build_rowtype(typeStruct->typrelid);
-					row->refname = strdup(buf);
-
-					argdatum = (PLpgSQL_datum *) row;
-					argitemtype = PLPGSQL_NSTYPE_ROW;
+					/* argument vars are forced to be CONSTANT (why?) */
+					((PLpgSQL_var *) argvariable)->isconst = true;
+					argitemtype = PLPGSQL_NSTYPE_VAR;
 				}
 				else
 				{
-					/*
-					 * Normal parameters get a var node
-					 */
-					var = malloc(sizeof(PLpgSQL_var));
-					memset(var, 0, sizeof(PLpgSQL_var));
-
-					var->dtype = PLPGSQL_DTYPE_VAR;
-					var->refname = strdup(buf);
-					var->lineno = 0;
-					var->datatype = build_datatype(typeTup, -1);
-					var->isconst = true;
-					var->notnull = false;
-					var->default_val = NULL;
-
-					argdatum = (PLpgSQL_datum *) var;
-					argitemtype = PLPGSQL_NSTYPE_VAR;
+					Assert(argvariable->dtype == PLPGSQL_DTYPE_ROW);
+					argitemtype = PLPGSQL_NSTYPE_ROW;
 				}
 
-				/* Add it to datum list, and remember datum number */
-				plpgsql_adddatum(argdatum);
-				arg_varnos[i] = argdatum->dno;
+				/* Remember datum number */
+				arg_varnos[i] = argvariable->dno;
 
 				/* Add to namespace under the $n name */
-				plpgsql_ns_additem(argitemtype, argdatum->dno, buf);
+				plpgsql_ns_additem(argitemtype, argvariable->dno, buf);
 
 				/* If there's a name for the argument, make an alias */
 				if (argnames && argnames[i] && argnames[i][0])
-					plpgsql_ns_additem(argitemtype, argdatum->dno,
+					plpgsql_ns_additem(argitemtype, argvariable->dno,
 									   argnames[i]);
-
-				ReleaseSysCache(typeTup);
 			}
 			break;
 
@@ -552,128 +504,58 @@ do_compile(FunctionCallInfo fcinfo,
 			/*
 			 * Add the variable tg_name
 			 */
-			var = malloc(sizeof(PLpgSQL_var));
-			memset(var, 0, sizeof(PLpgSQL_var));
-
-			var->dtype = PLPGSQL_DTYPE_VAR;
-			var->refname = strdup("tg_name");
-			var->lineno = 0;
-			var->datatype = plpgsql_parse_datatype("name");
-			var->isconst = false;
-			var->notnull = false;
-			var->default_val = NULL;
-
-			plpgsql_adddatum((PLpgSQL_datum *) var);
-			plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
-			function->tg_name_varno = var->varno;
+			var = plpgsql_build_variable(strdup("tg_name"), 0,
+										 plpgsql_build_datatype(NAMEOID, -1),
+										 true);
+			function->tg_name_varno = var->dno;
 
 			/*
 			 * Add the variable tg_when
 			 */
-			var = malloc(sizeof(PLpgSQL_var));
-			memset(var, 0, sizeof(PLpgSQL_var));
-
-			var->dtype = PLPGSQL_DTYPE_VAR;
-			var->refname = strdup("tg_when");
-			var->lineno = 0;
-			var->datatype = plpgsql_parse_datatype("text");
-			var->isconst = false;
-			var->notnull = false;
-			var->default_val = NULL;
-
-			plpgsql_adddatum((PLpgSQL_datum *) var);
-			plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
-			function->tg_when_varno = var->varno;
+			var = plpgsql_build_variable(strdup("tg_when"), 0,
+										 plpgsql_build_datatype(TEXTOID, -1),
+										 true);
+			function->tg_when_varno = var->dno;
 
 			/*
 			 * Add the variable tg_level
 			 */
-			var = malloc(sizeof(PLpgSQL_var));
-			memset(var, 0, sizeof(PLpgSQL_var));
-
-			var->dtype = PLPGSQL_DTYPE_VAR;
-			var->refname = strdup("tg_level");
-			var->lineno = 0;
-			var->datatype = plpgsql_parse_datatype("text");
-			var->isconst = false;
-			var->notnull = false;
-			var->default_val = NULL;
-
-			plpgsql_adddatum((PLpgSQL_datum *) var);
-			plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
-			function->tg_level_varno = var->varno;
+			var = plpgsql_build_variable(strdup("tg_level"), 0,
+										 plpgsql_build_datatype(TEXTOID, -1),
+										 true);
+			function->tg_level_varno = var->dno;
 
 			/*
 			 * Add the variable tg_op
 			 */
-			var = malloc(sizeof(PLpgSQL_var));
-			memset(var, 0, sizeof(PLpgSQL_var));
-
-			var->dtype = PLPGSQL_DTYPE_VAR;
-			var->refname = strdup("tg_op");
-			var->lineno = 0;
-			var->datatype = plpgsql_parse_datatype("text");
-			var->isconst = false;
-			var->notnull = false;
-			var->default_val = NULL;
-
-			plpgsql_adddatum((PLpgSQL_datum *) var);
-			plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
-			function->tg_op_varno = var->varno;
+			var = plpgsql_build_variable(strdup("tg_op"), 0,
+										 plpgsql_build_datatype(TEXTOID, -1),
+										 true);
+			function->tg_op_varno = var->dno;
 
 			/*
 			 * Add the variable tg_relid
 			 */
-			var = malloc(sizeof(PLpgSQL_var));
-			memset(var, 0, sizeof(PLpgSQL_var));
-
-			var->dtype = PLPGSQL_DTYPE_VAR;
-			var->refname = strdup("tg_relid");
-			var->lineno = 0;
-			var->datatype = plpgsql_parse_datatype("oid");
-			var->isconst = false;
-			var->notnull = false;
-			var->default_val = NULL;
-
-			plpgsql_adddatum((PLpgSQL_datum *) var);
-			plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
-			function->tg_relid_varno = var->varno;
+			var = plpgsql_build_variable(strdup("tg_relid"), 0,
+										 plpgsql_build_datatype(OIDOID, -1),
+										 true);
+			function->tg_relid_varno = var->dno;
 
 			/*
 			 * Add the variable tg_relname
 			 */
-			var = malloc(sizeof(PLpgSQL_var));
-			memset(var, 0, sizeof(PLpgSQL_var));
-
-			var->dtype = PLPGSQL_DTYPE_VAR;
-			var->refname = strdup("tg_relname");
-			var->lineno = 0;
-			var->datatype = plpgsql_parse_datatype("name");
-			var->isconst = false;
-			var->notnull = false;
-			var->default_val = NULL;
-
-			plpgsql_adddatum((PLpgSQL_datum *) var);
-			plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
-			function->tg_relname_varno = var->varno;
+			var = plpgsql_build_variable(strdup("tg_relname"), 0,
+										 plpgsql_build_datatype(NAMEOID, -1),
+										 true);
+			function->tg_relname_varno = var->dno;
 
 			/*
 			 * Add the variable tg_nargs
 			 */
-			var = malloc(sizeof(PLpgSQL_var));
-			memset(var, 0, sizeof(PLpgSQL_var));
-
-			var->dtype = PLPGSQL_DTYPE_VAR;
-			var->refname = strdup("tg_nargs");
-			var->lineno = 0;
-			var->datatype = plpgsql_parse_datatype("int4");
-			var->isconst = false;
-			var->notnull = false;
-			var->default_val = NULL;
-
-			plpgsql_adddatum((PLpgSQL_datum *) var);
-			plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
-			function->tg_nargs_varno = var->varno;
+			var = plpgsql_build_variable(strdup("tg_nargs"), 0,
+										 plpgsql_build_datatype(INT4OID, -1),
+										 true);
+			function->tg_nargs_varno = var->dno;
 
 			break;
 
@@ -685,20 +567,10 @@ do_compile(FunctionCallInfo fcinfo,
 	/*
 	 * Create the magic FOUND variable.
 	 */
-	var = malloc(sizeof(PLpgSQL_var));
-	memset(var, 0, sizeof(PLpgSQL_var));
-
-	var->dtype = PLPGSQL_DTYPE_VAR;
-	var->refname = strdup("found");
-	var->lineno = 0;
-	var->datatype = plpgsql_parse_datatype("bool");
-	var->isconst = false;
-	var->notnull = false;
-	var->default_val = NULL;
-
-	plpgsql_adddatum((PLpgSQL_datum *) var);
-	plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
-	function->found_varno = var->varno;
+	var = plpgsql_build_variable(strdup("found"), 0,
+								 plpgsql_build_datatype(BOOLOID, -1),
+								 true);
+	function->found_varno = var->dno;
 
 	/*
 	 * Forget about the above created variables
@@ -848,11 +720,11 @@ plpgsql_parse_word(char *word)
 			trigarg->argnum = plpgsql_read_expression(']', "]");
 
 			plpgsql_adddatum((PLpgSQL_datum *) trigarg);
-			plpgsql_yylval.variable = (PLpgSQL_datum *) trigarg;
+			plpgsql_yylval.scalar = (PLpgSQL_datum *) trigarg;
 
 			plpgsql_SpaceScanned = save_spacescanned;
 			pfree(cp[0]);
-			return T_VARIABLE;
+			return T_SCALAR;
 		}
 	}
 
@@ -869,8 +741,8 @@ plpgsql_parse_word(char *word)
 				return T_LABEL;
 
 			case PLPGSQL_NSTYPE_VAR:
-				plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[nse->itemno]);
-				return T_VARIABLE;
+				plpgsql_yylval.scalar = plpgsql_Datums[nse->itemno];
+				return T_SCALAR;
 
 			case PLPGSQL_NSTYPE_REC:
 				plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[nse->itemno]);
@@ -937,8 +809,8 @@ plpgsql_parse_dblword(char *word)
 			switch (ns->itemtype)
 			{
 				case PLPGSQL_NSTYPE_VAR:
-					plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[ns->itemno]);
-					return T_VARIABLE;
+					plpgsql_yylval.scalar = plpgsql_Datums[ns->itemno];
+					return T_SCALAR;
 
 				case PLPGSQL_NSTYPE_REC:
 					plpgsql_yylval.rec = (PLpgSQL_rec *) (plpgsql_Datums[ns->itemno]);
@@ -968,11 +840,11 @@ plpgsql_parse_dblword(char *word)
 
 				plpgsql_adddatum((PLpgSQL_datum *) new);
 
-				plpgsql_yylval.variable = (PLpgSQL_datum *) new;
+				plpgsql_yylval.scalar = (PLpgSQL_datum *) new;
 
 				pfree(cp[0]);
 				pfree(cp[1]);
-				return T_VARIABLE;
+				return T_SCALAR;
 			}
 
 		case PLPGSQL_NSTYPE_ROW:
@@ -990,10 +862,10 @@ plpgsql_parse_dblword(char *word)
 					if (row->fieldnames[i] &&
 						strcmp(row->fieldnames[i], cp[1]) == 0)
 					{
-						plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[row->varnos[i]]);
+						plpgsql_yylval.scalar = plpgsql_Datums[row->varnos[i]];
 						pfree(cp[0]);
 						pfree(cp[1]);
-						return T_VARIABLE;
+						return T_SCALAR;
 					}
 				}
 				ereport(ERROR,
@@ -1074,12 +946,13 @@ plpgsql_parse_tripword(char *word)
 
 				plpgsql_adddatum((PLpgSQL_datum *) new);
 
-				plpgsql_yylval.variable = (PLpgSQL_datum *) new;
+				plpgsql_yylval.scalar = (PLpgSQL_datum *) new;
 
 				pfree(cp[0]);
 				pfree(cp[1]);
 				pfree(cp[2]);
-				return T_VARIABLE;
+
+				return T_SCALAR;
 			}
 
 		case PLPGSQL_NSTYPE_ROW:
@@ -1097,11 +970,13 @@ plpgsql_parse_tripword(char *word)
 					if (row->fieldnames[i] &&
 						strcmp(row->fieldnames[i], cp[2]) == 0)
 					{
-						plpgsql_yylval.var = (PLpgSQL_var *) (plpgsql_Datums[row->varnos[i]]);
+						plpgsql_yylval.scalar = plpgsql_Datums[row->varnos[i]];
+
 						pfree(cp[0]);
 						pfree(cp[1]);
 						pfree(cp[2]);
-						return T_VARIABLE;
+
+						return T_SCALAR;
 					}
 				}
 				ereport(ERROR,
@@ -1161,6 +1036,8 @@ plpgsql_parse_wordtype(char *word)
 				plpgsql_yylval.dtype = ((PLpgSQL_var *) (plpgsql_Datums[nse->itemno]))->datatype;
 				return T_DTYPE;
 
+			/* XXX perhaps allow REC here? */
+
 			default:
 				return T_ERROR;
 		}
@@ -1451,6 +1328,7 @@ plpgsql_parse_tripwordtype(char *word)
 	ReleaseSysCache(typetup);
 	pfree(cp[0]);
 	pfree(cp[1]);
+
 	return T_DTYPE;
 }
 
@@ -1482,21 +1360,20 @@ plpgsql_parse_wordrowtype(char *word)
 				 errmsg("relation \"%s\" does not exist", cp[0])));
 
 	/*
-	 * Build and return the complete row definition
+	 * Build and return the row type struct
 	 */
-	plpgsql_yylval.row = plpgsql_build_rowtype(classOid);
-
-	plpgsql_adddatum((PLpgSQL_datum *) plpgsql_yylval.row);
+	plpgsql_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid),
+												  -1);
 
 	pfree(cp[0]);
 	pfree(cp[1]);
 
-	return T_ROW;
+	return T_DTYPE;
 }
 
 /* ----------
  * plpgsql_parse_dblwordrowtype		Scanner found word.word%ROWTYPE.
- *			So word must be namespace qualified a table name.
+ *			So word must be a namespace qualified table name.
  * ----------
  */
 #define ROWTYPE_JUNK_LEN	8
@@ -1527,22 +1404,120 @@ plpgsql_parse_dblwordrowtype(char *word)
 				 errmsg("relation \"%s\" does not exist", cp)));
 
 	/*
-	 * Build and return the complete row definition
+	 * Build and return the row type struct
 	 */
-	plpgsql_yylval.row = plpgsql_build_rowtype(classOid);
-
-	plpgsql_adddatum((PLpgSQL_datum *) plpgsql_yylval.row);
+	plpgsql_yylval.dtype = plpgsql_build_datatype(get_rel_type_id(classOid),
+												  -1);
 
 	pfree(cp);
 
-	return T_ROW;
+	return T_DTYPE;
 }
 
 /*
- * Build a rowtype data structure given the pg_class OID.
+ * plpgsql_build_variable - build a datum-array entry of a given datatype
+ *
+ * The returned struct may be a PLpgSQL_var, PLpgSQL_row, or PLpgSQL_rec
+ * depending on the given datatype.  The struct is automatically added
+ * to the current datum array, and optionally to the current namespace.
  */
-PLpgSQL_row *
-plpgsql_build_rowtype(Oid classOid)
+PLpgSQL_variable *
+plpgsql_build_variable(char *refname, int lineno, PLpgSQL_type *dtype,
+					bool add2namespace)
+{
+	PLpgSQL_variable *result;
+
+	switch (dtype->ttype)
+	{
+		case PLPGSQL_TTYPE_SCALAR:
+		{
+			/* Ordinary scalar datatype */
+			PLpgSQL_var		*var;
+
+			var = malloc(sizeof(PLpgSQL_var));
+			memset(var, 0, sizeof(PLpgSQL_var));
+
+			var->dtype		= PLPGSQL_DTYPE_VAR;
+			var->refname	= refname;
+			var->lineno		= lineno;
+			var->datatype	= dtype;
+			/* other fields might be filled by caller */
+
+			/* preset to NULL */
+			var->value = 0;
+			var->isnull = true;
+			var->freeval = false;
+
+			plpgsql_adddatum((PLpgSQL_datum *) var);
+			if (add2namespace)
+				plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR,
+								   var->varno,
+								   refname);
+			result = (PLpgSQL_variable *) var;
+			break;
+		}
+		case PLPGSQL_TTYPE_ROW:
+		{
+			/* Composite type -- build a row variable */
+			PLpgSQL_row	   *row;
+
+			row = build_row_var(dtype->typrelid);
+
+			row->dtype		= PLPGSQL_DTYPE_ROW;
+			row->refname	= refname;
+			row->lineno		= lineno;
+
+			plpgsql_adddatum((PLpgSQL_datum *) row);
+			if (add2namespace)
+				plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW,
+								   row->rowno,
+								   refname);
+			result = (PLpgSQL_variable *) row;
+			break;
+		}
+		case PLPGSQL_TTYPE_REC:
+		{
+			/* "record" type -- build a variable-contents record variable */
+			PLpgSQL_rec		*rec;
+
+			rec = malloc(sizeof(PLpgSQL_rec));
+			memset(rec, 0, sizeof(PLpgSQL_rec));
+
+			rec->dtype		= PLPGSQL_DTYPE_REC;
+			rec->refname	= refname;
+			rec->lineno		= lineno;
+
+			plpgsql_adddatum((PLpgSQL_datum *) rec);
+			if (add2namespace)
+				plpgsql_ns_additem(PLPGSQL_NSTYPE_REC,
+								   rec->recno,
+								   refname);
+			result = (PLpgSQL_variable *) rec;
+			break;
+		}
+		case PLPGSQL_TTYPE_PSEUDO:
+		{
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("variable \"%s\" has pseudo-type %s",
+							refname, format_type_be(dtype->typoid))));
+			result = NULL;		/* keep compiler quiet */
+			break;
+		}
+		default:
+			elog(ERROR, "unrecognized ttype: %d", dtype->ttype);
+			result = NULL;		/* keep compiler quiet */
+			break;
+	}
+
+	return result;
+}
+
+/*
+ * Build a row-variable data structure given the pg_class OID.
+ */
+static PLpgSQL_row *
+build_row_var(Oid classOid)
 {
 	PLpgSQL_row *row;
 	Relation	rel;
@@ -1601,17 +1576,14 @@ plpgsql_build_rowtype(Oid classOid)
 		if (!attrStruct->attisdropped)
 		{
 			const char *attname;
-			HeapTuple	typetup;
-			PLpgSQL_var *var;
+			char	*refname;
+			PLpgSQL_variable *var;
 
 			attname = NameStr(attrStruct->attname);
-
-			typetup = SearchSysCache(TYPEOID,
-									 ObjectIdGetDatum(attrStruct->atttypid),
-									 0, 0, 0);
-			if (!HeapTupleIsValid(typetup))
-				elog(ERROR, "cache lookup failed for type %u",
-					 attrStruct->atttypid);
+			refname = malloc(strlen(relname) + strlen(attname) + 2);
+			strcpy(refname, relname);
+			strcat(refname, ".");
+			strcat(refname, attname);
 
 			/*
 			 * Create the internal variable for the field
@@ -1623,30 +1595,16 @@ plpgsql_build_rowtype(Oid classOid)
 			 * the variables due to entering a block at execution time. Thus
 			 * we ignore this information for now.
 			 */
-			var = malloc(sizeof(PLpgSQL_var));
-			MemSet(var, 0, sizeof(PLpgSQL_var));
-			var->dtype = PLPGSQL_DTYPE_VAR;
-			var->refname = malloc(strlen(relname) + strlen(attname) + 2);
-			strcpy(var->refname, relname);
-			strcat(var->refname, ".");
-			strcat(var->refname, attname);
-			var->datatype = build_datatype(typetup, attrStruct->atttypmod);
-			var->isconst = false;
-			var->notnull = false;
-			var->default_val = NULL;
-			var->value = (Datum) 0;
-			var->isnull = true;
-			var->freeval = false;
-
-			plpgsql_adddatum((PLpgSQL_datum *) var);
+			var = plpgsql_build_variable(refname, 0,
+							  plpgsql_build_datatype(attrStruct->atttypid,
+													 attrStruct->atttypmod),
+										 false);
 
 			/*
 			 * Add the variable to the row.
 			 */
 			row->fieldnames[i] = strdup(attname);
-			row->varnos[i] = var->varno;
-
-			ReleaseSysCache(typetup);
+			row->varnos[i] = var->dno;
 		}
 		else
 		{
@@ -1668,22 +1626,33 @@ plpgsql_build_rowtype(Oid classOid)
  * ----------
  */
 PLpgSQL_type *
-plpgsql_parse_datatype(char *string)
+plpgsql_parse_datatype(const char *string)
 {
 	Oid			type_id;
 	int32		typmod;
-	HeapTuple	typeTup;
-	PLpgSQL_type *typ;
 
 	/* Let the main parser try to parse it under standard SQL rules */
 	parseTypeString(string, &type_id, &typmod);
 
 	/* Okay, build a PLpgSQL_type data structure for it */
+	return plpgsql_build_datatype(type_id, typmod);
+}
+
+/*
+ * plpgsql_build_datatype
+ *		Build PLpgSQL_type struct given type OID and typmod.
+ */
+PLpgSQL_type *
+plpgsql_build_datatype(Oid typeOid, int32 typmod)
+{
+	HeapTuple	typeTup;
+	PLpgSQL_type *typ;
+
 	typeTup = SearchSysCache(TYPEOID,
-							 ObjectIdGetDatum(type_id),
+							 ObjectIdGetDatum(typeOid),
 							 0, 0, 0);
 	if (!HeapTupleIsValid(typeTup))
-		elog(ERROR, "cache lookup failed for type %u", type_id);
+		elog(ERROR, "cache lookup failed for type %u", typeOid);
 
 	typ = build_datatype(typeTup, typmod);
 
@@ -1701,10 +1670,37 @@ build_datatype(HeapTuple typeTup, int32 typmod)
 	Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
 	PLpgSQL_type *typ;
 
+	if (!typeStruct->typisdefined)
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("type \"%s\" is only a shell",
+						NameStr(typeStruct->typname))));
+
 	typ = (PLpgSQL_type *) malloc(sizeof(PLpgSQL_type));
 
 	typ->typname = strdup(NameStr(typeStruct->typname));
 	typ->typoid = HeapTupleGetOid(typeTup);
+	switch (typeStruct->typtype)
+	{
+		case 'b':				/* base type */
+		case 'd':				/* domain */
+			typ->ttype = PLPGSQL_TTYPE_SCALAR;
+			break;
+		case 'c':				/* composite, ie, rowtype */
+			Assert(OidIsValid(typeStruct->typrelid));
+			typ->ttype = PLPGSQL_TTYPE_ROW;
+			break;
+		case 'p':				/* pseudo */
+			if (typ->typoid == RECORDOID)
+				typ->ttype = PLPGSQL_TTYPE_REC;
+			else
+				typ->ttype = PLPGSQL_TTYPE_PSEUDO;
+			break;
+		default:
+			elog(ERROR, "unrecognized typtype: %d",
+				 (int) typeStruct->typtype);
+			break;
+	}
 	typ->typlen = typeStruct->typlen;
 	typ->typbyval = typeStruct->typbyval;
 	typ->typrelid = typeStruct->typrelid;
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index cb3c4c2944feb013785fa1b72079e8fb2b4757f6..90ed37ada2003ccc27333a38b8deca68d1c63829 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -3,7 +3,7 @@
  *			  procedural language
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.45 2004/03/19 18:58:07 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.46 2004/06/03 22:56:43 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -58,8 +58,7 @@ enum
 	PLPGSQL_NSTYPE_LABEL,
 	PLPGSQL_NSTYPE_VAR,
 	PLPGSQL_NSTYPE_ROW,
-	PLPGSQL_NSTYPE_REC,
-	PLPGSQL_NSTYPE_RECFIELD
+	PLPGSQL_NSTYPE_REC
 };
 
 /* ----------
@@ -77,6 +76,18 @@ enum
 	PLPGSQL_DTYPE_TRIGARG
 };
 
+/* ----------
+ * Variants distinguished in PLpgSQL_type structs
+ * ----------
+ */
+enum
+{
+	PLPGSQL_TTYPE_SCALAR,		/* scalar types and domains */
+	PLPGSQL_TTYPE_ROW,			/* composite types */
+	PLPGSQL_TTYPE_REC,			/* RECORD pseudotype */
+	PLPGSQL_TTYPE_PSEUDO		/* other pseudotypes */
+};
+
 /* ----------
  * Execution tree node types
  * ----------
@@ -142,9 +153,10 @@ typedef struct
 
 
 typedef struct
-{								/* Postgres data type		*/
-	char	   *typname;
+{								/* Postgres data type */
+	char	   *typname;		/* (simple) name of the type */
 	Oid			typoid;			/* OID of the data type */
+	int			ttype;			/* PLPGSQL_TTYPE_ code */
 	int16		typlen;			/* stuff copied from its pg_type entry */
 	bool		typbyval;
 	Oid			typrelid;
@@ -165,6 +177,17 @@ typedef struct
 	int			dno;
 }	PLpgSQL_datum;
 
+/*
+ * The variants PLpgSQL_var, PLpgSQL_row, and PLpgSQL_rec share these
+ * fields
+ */
+typedef struct
+{								/* Scalar or composite variable */
+	int			dtype;
+	int			dno;
+	char	   *refname;
+	int			lineno;
+}	PLpgSQL_variable;
 
 typedef struct PLpgSQL_expr
 {								/* SQL Query to plan and execute	*/
@@ -186,7 +209,7 @@ typedef struct PLpgSQL_expr
 
 
 typedef struct
-{								/* Local variable			*/
+{								/* Scalar variable */
 	int			dtype;
 	int			varno;
 	char	   *refname;
@@ -206,11 +229,12 @@ typedef struct
 
 
 typedef struct
-{								/* Rowtype				*/
+{								/* Row variable */
 	int			dtype;
 	int			rowno;
 	char	   *refname;
 	int			lineno;
+
 	TupleDesc	rowtupdesc;
 
 	/*
@@ -227,7 +251,7 @@ typedef struct
 
 
 typedef struct
-{								/* Record of non-fixed structure */
+{								/* Record variable (non-fixed structure) */
 	int			dtype;
 	int			recno;
 	char	   *refname;
@@ -630,9 +654,12 @@ extern int	plpgsql_parse_dblwordtype(char *word);
 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 *plpgsql_build_rowtype(Oid classOid);
-extern void plpgsql_adddatum(PLpgSQL_datum * new);
+extern PLpgSQL_type *plpgsql_parse_datatype(const char *string);
+extern PLpgSQL_type *plpgsql_build_datatype(Oid typeOid, int32 typmod);
+extern PLpgSQL_variable *plpgsql_build_variable(char *refname, int lineno,
+												PLpgSQL_type *dtype,
+												bool add2namespace);
+extern void plpgsql_adddatum(PLpgSQL_datum *new);
 extern int	plpgsql_add_initdatums(int **varnos);
 extern void plpgsql_HashTableInit(void);
 
diff --git a/src/pl/plpgsql/src/scan.l b/src/pl/plpgsql/src/scan.l
index 077efe6671e440dad4a4b2fadc07e65c75b27099..d369170cf3eafd9365e5bae212dcf1720785b68c 100644
--- a/src/pl/plpgsql/src/scan.l
+++ b/src/pl/plpgsql/src/scan.l
@@ -4,7 +4,7 @@
  *			  procedural language
  *
  * IDENTIFICATION
- *    $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.34 2004/03/21 22:29:11 tgl Exp $
+ *    $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.35 2004/06/03 22:56:43 tgl Exp $
  *
  *    This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -167,7 +167,6 @@ null			{ return K_NULL;			}
 open			{ return K_OPEN;			}
 perform			{ return K_PERFORM;			}
 raise			{ return K_RAISE;			}
-record			{ return K_RECORD;			}
 rename			{ return K_RENAME;			}
 result_oid		{ return K_RESULT_OID;		}
 return			{ return K_RETURN;			}