Index: doc/src/sgml/ref/create_domain.sgml
===================================================================
RCS file: /Users/neilc/postgres/cvs_root/pgsql/doc/src/sgml/ref/create_domain.sgml,v
retrieving revision 1.26
diff -c -r1.26 create_domain.sgml
*** doc/src/sgml/ref/create_domain.sgml	4 Nov 2005 23:14:02 -0000	1.26
--- doc/src/sgml/ref/create_domain.sgml	22 Dec 2005 22:23:00 -0000
***************
*** 20,26 ****
  
   <refsynopsisdiv>
  <synopsis>
! CREATE DOMAIN <replaceable class="parameter">name</replaceable> [AS] <replaceable class="parameter">data_type</replaceable>
      [ DEFAULT <replaceable>expression</> ]
      [ <replaceable class="PARAMETER">constraint</replaceable> [ ... ] ]
  
--- 20,26 ----
  
   <refsynopsisdiv>
  <synopsis>
! CREATE DOMAIN <replaceable class="parameter">name</replaceable> [ AS ] <replaceable class="parameter">data_type</replaceable>
      [ DEFAULT <replaceable>expression</> ]
      [ <replaceable class="PARAMETER">constraint</replaceable> [ ... ] ]
  
***************
*** 185,191 ****
  );
  
  CREATE TABLE us_snail_addy (
!   address_id SERIAL NOT NULL PRIMARY KEY
  , street1 TEXT NOT NULL
  , street2 TEXT
  , street3 TEXT
--- 185,191 ----
  );
  
  CREATE TABLE us_snail_addy (
!   address_id SERIAL PRIMARY KEY
  , street1 TEXT NOT NULL
  , street2 TEXT
  , street3 TEXT
Index: src/backend/commands/typecmds.c
===================================================================
RCS file: /Users/neilc/postgres/cvs_root/pgsql/src/backend/commands/typecmds.c,v
retrieving revision 1.85
diff -c -r1.85 typecmds.c
*** src/backend/commands/typecmds.c	22 Nov 2005 18:17:09 -0000	1.85
--- src/backend/commands/typecmds.c	22 Dec 2005 21:38:33 -0000
***************
*** 601,609 ****
  		defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum));
  
  	/*
! 	 * Pull out the typelem name of the parent OID.
! 	 *
! 	 * This is what enables us to make a domain of an array
  	 */
  	basetypelem = baseType->typelem;
  
--- 601,608 ----
  		defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum));
  
  	/*
! 	 * Pull out the typelem name of the parent OID. This is what
! 	 * enables us to make a domain of an array.
  	 */
  	basetypelem = baseType->typelem;
  
***************
*** 633,639 ****
  		switch (constr->contype)
  		{
  			case CONSTR_DEFAULT:
- 
  				/*
  				 * The inherited default value may be overridden by the user
  				 * with the DEFAULT <expr> statement.
--- 632,637 ----
***************
*** 686,692 ****
  				break;
  
  			case CONSTR_CHECK:
- 
  				/*
  				 * Check constraints are handled after domain creation, as
  				 * they require the Oid of the domain
--- 684,689 ----
***************
*** 758,764 ****
  	{
  		Constraint *constr = lfirst(listptr);
  
! 		/* it must be a Constraint, per check above */
  
  		switch (constr->contype)
  		{
--- 755,761 ----
  	{
  		Constraint *constr = lfirst(listptr);
  
! 		/* it must be a plain Constraint, per check above */
  
  		switch (constr->contype)
  		{
***************
*** 1772,1779 ****
   */
  static char *
  domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
! 					int typMod, Constraint *constr,
! 					char *domainName)
  {
  	Node	   *expr;
  	char	   *ccsrc;
--- 1769,1775 ----
   */
  static char *
  domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
! 					int typMod, Constraint *constr, char *domainName)
  {
  	Node	   *expr;
  	char	   *ccsrc;
***************
*** 1811,1817 ****
  	 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
  	 * the expression.	Note that it will appear to have the type of the base
  	 * type, not the domain.  This seems correct since within the check
! 	 * expression, we should not assume the input value can be considered a
  	 * member of the domain.
  	 */
  	domVal = makeNode(CoerceToDomainValue);
--- 1807,1813 ----
  	 * Set up a CoerceToDomainValue to represent the occurrence of VALUE in
  	 * the expression.	Note that it will appear to have the type of the base
  	 * type, not the domain.  This seems correct since within the check
! 	 * expression, we should not assume that the input value can be considered a
  	 * member of the domain.
  	 */
  	domVal = makeNode(CoerceToDomainValue);
Index: src/backend/executor/execQual.c
===================================================================
RCS file: /Users/neilc/postgres/cvs_root/pgsql/src/backend/executor/execQual.c,v
retrieving revision 1.186
diff -c -r1.186 execQual.c
*** src/backend/executor/execQual.c	14 Dec 2005 16:28:32 -0000	1.186
--- src/backend/executor/execQual.c	22 Dec 2005 23:10:50 -0000
***************
*** 2599,2623 ****
  {
  	CoerceToDomain *ctest = (CoerceToDomain *) cstate->xprstate.expr;
  	Datum		result;
- 	ListCell   *l;
  
  	result = ExecEvalExpr(cstate->arg, econtext, isNull, isDone);
  
  	if (isDone && *isDone == ExprEndResult)
  		return result;			/* nothing to check */
  
! 	foreach(l, cstate->constraints)
  	{
  		DomainConstraintState *con = (DomainConstraintState *) lfirst(l);
  
  		switch (con->constrainttype)
  		{
  			case DOM_CONSTRAINT_NOTNULL:
! 				if (*isNull)
  					ereport(ERROR,
  							(errcode(ERRCODE_NOT_NULL_VIOLATION),
  							 errmsg("domain %s does not allow null values",
! 									format_type_be(ctest->resulttype))));
  				break;
  			case DOM_CONSTRAINT_CHECK:
  				{
--- 2599,2639 ----
  {
  	CoerceToDomain *ctest = (CoerceToDomain *) cstate->xprstate.expr;
  	Datum		result;
  
  	result = ExecEvalExpr(cstate->arg, econtext, isNull, isDone);
  
  	if (isDone && *isDone == ExprEndResult)
  		return result;			/* nothing to check */
  
! 	/*
! 	 * Check any constraints associated with the domain. If any of the
! 	 * constraints fails, an error is reported via ereport.
! 	 */
! 	ExecCheckDomainConstraints(result, *isNull, ctest->resulttype,
! 							   econtext, cstate->constraints);
! 
! 	/* No constraints failed, so return the datum */
! 	return result;
! }
! 
! void
! ExecCheckDomainConstraints(Datum value, bool isnull, Oid valtype,
! 						   ExprContext *econtext, List *constraints)
! {
! 	ListCell   *l;
! 
! 	foreach(l, constraints)
  	{
  		DomainConstraintState *con = (DomainConstraintState *) lfirst(l);
  
  		switch (con->constrainttype)
  		{
  			case DOM_CONSTRAINT_NOTNULL:
! 				if (isnull)
  					ereport(ERROR,
  							(errcode(ERRCODE_NOT_NULL_VIOLATION),
  							 errmsg("domain %s does not allow null values",
! 									format_type_be(valtype))));
  				break;
  			case DOM_CONSTRAINT_CHECK:
  				{
***************
*** 2635,2652 ****
  					save_datum = econtext->domainValue_datum;
  					save_isNull = econtext->domainValue_isNull;
  
! 					econtext->domainValue_datum = result;
! 					econtext->domainValue_isNull = *isNull;
  
  					conResult = ExecEvalExpr(con->check_expr,
  											 econtext, &conIsNull, NULL);
  
! 					if (!conIsNull &&
! 						!DatumGetBool(conResult))
  						ereport(ERROR,
  								(errcode(ERRCODE_CHECK_VIOLATION),
  								 errmsg("value for domain %s violates check constraint \"%s\"",
! 										format_type_be(ctest->resulttype),
  										con->name)));
  					econtext->domainValue_datum = save_datum;
  					econtext->domainValue_isNull = save_isNull;
--- 2651,2667 ----
  					save_datum = econtext->domainValue_datum;
  					save_isNull = econtext->domainValue_isNull;
  
! 					econtext->domainValue_datum = value;
! 					econtext->domainValue_isNull = isnull;
  
  					conResult = ExecEvalExpr(con->check_expr,
  											 econtext, &conIsNull, NULL);
  
! 					if (!conIsNull && !DatumGetBool(conResult))
  						ereport(ERROR,
  								(errcode(ERRCODE_CHECK_VIOLATION),
  								 errmsg("value for domain %s violates check constraint \"%s\"",
! 										format_type_be(valtype),
  										con->name)));
  					econtext->domainValue_datum = save_datum;
  					econtext->domainValue_isNull = save_isNull;
***************
*** 2659,2667 ****
  				break;
  		}
  	}
- 
- 	/* If all has gone well (constraints did not fail) return the datum */
- 	return result;
  }
  
  /*
--- 2674,2679 ----
Index: src/include/executor/executor.h
===================================================================
RCS file: /Users/neilc/postgres/cvs_root/pgsql/src/include/executor/executor.h,v
retrieving revision 1.123
diff -c -r1.123 executor.h
*** src/include/executor/executor.h	3 Dec 2005 05:51:03 -0000	1.123
--- src/include/executor/executor.h	22 Dec 2005 23:09:22 -0000
***************
*** 136,141 ****
--- 136,144 ----
  extern int	ExecCleanTargetListLength(List *targetlist);
  extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo,
  			ExprDoneCond *isDone);
+ extern void ExecCheckDomainConstraints(Datum value, bool isnull,
+ 									   Oid valtype, ExprContext *econtext,
+ 									   List *constraints);
  
  /*
   * prototypes from functions in execScan.c
Index: src/pl/plpgsql/src/pl_comp.c
===================================================================
RCS file: /Users/neilc/postgres/cvs_root/pgsql/src/pl/plpgsql/src/pl_comp.c,v
retrieving revision 1.97
diff -c -r1.97 pl_comp.c
*** src/pl/plpgsql/src/pl_comp.c	9 Dec 2005 17:08:49 -0000	1.97
--- src/pl/plpgsql/src/pl_comp.c	22 Dec 2005 22:33:59 -0000
***************
*** 1875,1880 ****
--- 1875,1881 ----
  			break;
  	}
  	typ->typlen = typeStruct->typlen;
+ 	typ->typtype = typeStruct->typtype;
  	typ->typbyval = typeStruct->typbyval;
  	typ->typrelid = typeStruct->typrelid;
  	typ->typioparam = getTypeIOParam(typeTup);
Index: src/pl/plpgsql/src/pl_exec.c
===================================================================
RCS file: /Users/neilc/postgres/cvs_root/pgsql/src/pl/plpgsql/src/pl_exec.c,v
retrieving revision 1.157
diff -c -r1.157 pl_exec.c
*** src/pl/plpgsql/src/pl_exec.c	22 Nov 2005 18:17:33 -0000	1.157
--- src/pl/plpgsql/src/pl_exec.c	23 Dec 2005 19:06:32 -0000
***************
*** 43,48 ****
--- 43,49 ----
  #include "access/heapam.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_type.h"
+ #include "commands/typecmds.h"
  #include "executor/spi_priv.h"
  #include "funcapi.h"
  #include "optimizer/clauses.h"
***************
*** 168,182 ****
  					PLpgSQL_row *row,
  					TupleDesc tupdesc);
  static char *convert_value_to_string(Datum value, Oid valtype);
  static Datum exec_cast_value(Datum value, Oid valtype,
! 				Oid reqtype,
! 				FmgrInfo *reqinput,
! 				Oid reqtypioparam,
! 				int32 reqtypmod,
! 				bool isnull);
  static Datum exec_simple_cast_value(Datum value, Oid valtype,
! 					   Oid reqtype, int32 reqtypmod,
! 					   bool isnull);
  static void exec_init_tuple_store(PLpgSQL_execstate *estate);
  static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2);
  static void exec_set_found(PLpgSQL_execstate *estate, bool state);
--- 169,188 ----
  					PLpgSQL_row *row,
  					TupleDesc tupdesc);
  static char *convert_value_to_string(Datum value, Oid valtype);
+ static Datum exec_cast_to_type(Datum value, Oid value_type,
+ 							   PLpgSQL_type *reqtype, bool isnull,
+ 							   ExprContext *econtext);
  static Datum exec_cast_value(Datum value, Oid valtype,
! 							 Oid reqtype,
! 							 FmgrInfo *reqinput,
! 							 Oid reqtypioparam,
! 							 int32 reqtypmod,
! 							 int16 reqtyptype,
! 							 bool isnull,
! 							 ExprContext *econtext);
  static Datum exec_simple_cast_value(Datum value, Oid valtype,
! 									Oid reqtype, int32 reqtypmod,
! 									bool isnull, ExprContext *econtext);
  static void exec_init_tuple_store(PLpgSQL_execstate *estate);
  static bool compatible_tupdesc(TupleDesc td1, TupleDesc td2);
  static void exec_set_found(PLpgSQL_execstate *estate, bool state);
***************
*** 356,362 ****
  											&(func->fn_retinput),
  											func->fn_rettypioparam,
  											-1,
! 											fcinfo->isnull);
  
  			/*
  			 * If the function's return type isn't by value, copy the value
--- 362,370 ----
  											&(func->fn_retinput),
  											func->fn_rettypioparam,
  											-1,
! 											'\0',
! 											fcinfo->isnull,
! 											NULL);
  
  			/*
  			 * If the function's return type isn't by value, copy the value
***************
*** 1356,1365 ****
  	 * Get the value of the lower bound into the loop var
  	 */
  	value = exec_eval_expr(estate, stmt->lower, &isnull, &valtype);
! 	value = exec_cast_value(value, valtype, var->datatype->typoid,
! 							&(var->datatype->typinput),
! 							var->datatype->typioparam,
! 							var->datatype->atttypmod, isnull);
  	if (isnull)
  		ereport(ERROR,
  				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
--- 1364,1371 ----
  	 * Get the value of the lower bound into the loop var
  	 */
  	value = exec_eval_expr(estate, stmt->lower, &isnull, &valtype);
! 	value = exec_cast_to_type(value, valtype, var->datatype, isnull,
! 							  estate->eval_econtext);
  	if (isnull)
  		ereport(ERROR,
  				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
***************
*** 1372,1381 ****
  	 * Get the value of the upper bound
  	 */
  	value = exec_eval_expr(estate, stmt->upper, &isnull, &valtype);
! 	value = exec_cast_value(value, valtype, var->datatype->typoid,
! 							&(var->datatype->typinput),
! 							var->datatype->typioparam,
! 							var->datatype->atttypmod, isnull);
  	if (isnull)
  		ereport(ERROR,
  				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
--- 1378,1385 ----
  	 * Get the value of the upper bound
  	 */
  	value = exec_eval_expr(estate, stmt->upper, &isnull, &valtype);
! 	value = exec_cast_to_type(value, valtype, var->datatype, isnull,
! 							  estate->eval_econtext);
  	if (isnull)
  		ereport(ERROR,
  				(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
***************
*** 1876,1882 ****
  													var->datatype->typoid,
  												 tupdesc->attrs[0]->atttypid,
  												tupdesc->attrs[0]->atttypmod,
! 													isNull);
  
  					tuple = heap_form_tuple(tupdesc, &retval, &isNull);
  
--- 1880,1887 ----
  													var->datatype->typoid,
  												 tupdesc->attrs[0]->atttypid,
  												tupdesc->attrs[0]->atttypmod,
! 													isNull,
! 													estate->eval_econtext);
  
  					tuple = heap_form_tuple(tupdesc, &retval, &isNull);
  
***************
*** 1942,1948 ****
  										rettype,
  										tupdesc->attrs[0]->atttypid,
  										tupdesc->attrs[0]->atttypmod,
! 										isNull);
  
  		tuple = heap_form_tuple(tupdesc, &retval, &isNull);
  
--- 1947,1954 ----
  										rettype,
  										tupdesc->attrs[0]->atttypid,
  										tupdesc->attrs[0]->atttypmod,
! 										isNull,
! 										estate->eval_econtext);
  
  		tuple = heap_form_tuple(tupdesc, &retval, &isNull);
  
***************
*** 2997,3007 ****
  				PLpgSQL_var *var = (PLpgSQL_var *) target;
  				Datum		newvalue;
  
! 				newvalue = exec_cast_value(value, valtype, var->datatype->typoid,
! 										   &(var->datatype->typinput),
! 										   var->datatype->typioparam,
! 										   var->datatype->atttypmod,
! 										   *isNull);
  
  				if (*isNull && var->notnull)
  					ereport(ERROR,
--- 3003,3011 ----
  				PLpgSQL_var *var = (PLpgSQL_var *) target;
  				Datum		newvalue;
  
! 				newvalue = exec_cast_to_type(value, valtype,
! 											 var->datatype, *isNull,
! 											 estate->eval_econtext);
  
  				if (*isNull && var->notnull)
  					ereport(ERROR,
***************
*** 3157,3163 ****
  						   errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
  
  				/*
! 				 * Get the number of the records field to change and the
  				 * number of attributes in the tuple.
  				 */
  				fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
--- 3161,3167 ----
  						   errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
  
  				/*
! 				 * Get the number of the record's field to change and the
  				 * number of attributes in the tuple.
  				 */
  				fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
***************
*** 3200,3206 ****
  													 valtype,
  													 atttype,
  													 atttypmod,
! 													 attisnull);
  				if (attisnull)
  					nulls[fno] = 'n';
  				else
--- 3204,3211 ----
  													 valtype,
  													 atttype,
  													 atttypmod,
! 													 attisnull,
! 													 estate->eval_econtext);
  				if (attisnull)
  					nulls[fno] = 'n';
  				else
***************
*** 3316,3322 ****
  													   valtype,
  													   arrayelemtypeid,
  													   -1,
! 													   *isNull);
  
  				/*
  				 * If the original array is null, cons up an empty array so
--- 3321,3328 ----
  													   valtype,
  													   arrayelemtypeid,
  													   -1,
! 													   *isNull,
! 													   estate->eval_econtext);
  
  				/*
  				 * If the original array is null, cons up an empty array so
***************
*** 3561,3567 ****
  	exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid);
  	exprdatum = exec_simple_cast_value(exprdatum, exprtypeid,
  									   INT4OID, -1,
! 									   *isNull);
  	return DatumGetInt32(exprdatum);
  }
  
--- 3567,3574 ----
  	exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid);
  	exprdatum = exec_simple_cast_value(exprdatum, exprtypeid,
  									   INT4OID, -1,
! 									   *isNull,
! 									   estate->eval_econtext);
  	return DatumGetInt32(exprdatum);
  }
  
***************
*** 3583,3589 ****
  	exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid);
  	exprdatum = exec_simple_cast_value(exprdatum, exprtypeid,
  									   BOOLOID, -1,
! 									   *isNull);
  	return DatumGetBool(exprdatum);
  }
  
--- 3590,3597 ----
  	exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid);
  	exprdatum = exec_simple_cast_value(exprdatum, exprtypeid,
  									   BOOLOID, -1,
! 									   *isNull,
! 									   estate->eval_econtext);
  	return DatumGetBool(exprdatum);
  }
  
***************
*** 4048,4053 ****
--- 4056,4083 ----
  }
  
  /* ----------
+  * exec_cast_to_type	   Cast a value to the specified type
+  *
+  * This is just syntax sugar for exec_cast_value, for the common case
+  * where we have a PLpgSQL_type representing the cast's target type.
+  * ----------
+  */
+ static Datum
+ exec_cast_to_type(Datum value, Oid value_type,
+ 				  PLpgSQL_type *reqtype, bool isnull,
+ 				  ExprContext *econtext)
+ {
+ 	return exec_cast_value(value, value_type,
+ 						   reqtype->typoid,
+ 						   &(reqtype->typinput),
+ 						   reqtype->typioparam,
+ 						   reqtype->atttypmod,
+ 						   reqtype->typtype,
+ 						   isnull,
+ 						   econtext);
+ }
+ 
+ /* ----------
   * exec_cast_value			Cast a value if required
   * ----------
   */
***************
*** 4057,4068 ****
  				FmgrInfo *reqinput,
  				Oid reqtypioparam,
  				int32 reqtypmod,
! 				bool isnull)
  {
  	if (!isnull)
  	{
  		/*
! 		 * If the type of the queries return value isn't that of the variable,
  		 * convert it.
  		 */
  		if (valtype != reqtype || reqtypmod != -1)
--- 4087,4100 ----
  				FmgrInfo *reqinput,
  				Oid reqtypioparam,
  				int32 reqtypmod,
! 				int16 reqtyptype,
! 				bool isnull,
! 				ExprContext *econtext)
  {
  	if (!isnull)
  	{
  		/*
! 		 * If the type of the query's return value isn't that of the variable,
  		 * convert it.
  		 */
  		if (valtype != reqtype || reqtypmod != -1)
***************
*** 4075,4080 ****
--- 4107,4124 ----
  								  ObjectIdGetDatum(reqtypioparam),
  								  Int32GetDatum(reqtypmod));
  			pfree(extval);
+ 
+ 			/*
+ 			 * If the required type is a domain type, we need to
+ 			 * manually check any applicable domain constraints.
+ 			 */
+ 			if (reqtyptype == 'd')
+ 			{
+ 				List *constraints = GetDomainConstraints(reqtype);
+ 
+ 				ExecCheckDomainConstraints(value, isnull, reqtype,
+ 										   econtext, constraints);
+ 			}
  		}
  	}
  
***************
*** 4092,4098 ****
  static Datum
  exec_simple_cast_value(Datum value, Oid valtype,
  					   Oid reqtype, int32 reqtypmod,
! 					   bool isnull)
  {
  	if (!isnull)
  	{
--- 4136,4142 ----
  static Datum
  exec_simple_cast_value(Datum value, Oid valtype,
  					   Oid reqtype, int32 reqtypmod,
! 					   bool isnull, ExprContext *econtext)
  {
  	if (!isnull)
  	{
***************
*** 4100,4118 ****
  		{
  			Oid			typinput;
  			Oid			typioparam;
  			FmgrInfo	finfo_input;
  
  			getTypeInputInfo(reqtype, &typinput, &typioparam);
- 
  			fmgr_info(typinput, &finfo_input);
  
  			value = exec_cast_value(value,
  									valtype,
  									reqtype,
  									&finfo_input,
  									typioparam,
  									reqtypmod,
! 									isnull);
  		}
  	}
  
--- 4144,4168 ----
  		{
  			Oid			typinput;
  			Oid			typioparam;
+ 			char		typtype;
  			FmgrInfo	finfo_input;
  
  			getTypeInputInfo(reqtype, &typinput, &typioparam);
  			fmgr_info(typinput, &finfo_input);
  
+ 			typtype = get_typtype(reqtype);
+ 			if (typtype == '\0')
+ 				elog(ERROR, "cache lookup failed for type %u", reqtype);
+ 
  			value = exec_cast_value(value,
  									valtype,
  									reqtype,
  									&finfo_input,
  									typioparam,
  									reqtypmod,
! 									typtype,
! 									isnull,
! 									econtext);
  		}
  	}
  
Index: src/pl/plpgsql/src/plpgsql.h
===================================================================
RCS file: /Users/neilc/postgres/cvs_root/pgsql/src/pl/plpgsql/src/plpgsql.h,v
retrieving revision 1.66
diff -c -r1.66 plpgsql.h
*** src/pl/plpgsql/src/plpgsql.h	22 Nov 2005 18:17:33 -0000	1.66
--- src/pl/plpgsql/src/plpgsql.h	22 Dec 2005 22:32:38 -0000
***************
*** 159,164 ****
--- 159,165 ----
  	Oid			typoid;			/* OID of the data type */
  	int			ttype;			/* PLPGSQL_TTYPE_ code */
  	int16		typlen;			/* stuff copied from its pg_type entry */
+ 	int16		typtype;
  	bool		typbyval;
  	Oid			typrelid;
  	Oid			typioparam;
