diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 348d267380..b35a1805ca 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.50 2004/05/16 23:22:07 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_type.sgml,v 1.51 2004/06/06 00:41:25 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -102,13 +102,15 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
    or as taking three arguments of types
    <type>cstring</type>, <type>oid</type>, <type>integer</type>.
    The first argument is the input text as a C string, the second
-   argument is the element type in case this is an array type,
+   argument is the element type's OID in case this is an array type
+   (or the type's own OID for a composite type),
    and the third is the <literal>typmod</> of the destination column, if known.
    The input function should return a value of the data type itself.
    The output function may be
    declared as taking one argument of the new data type,  or as taking
    two arguments of which the second is type <type>oid</type>.
-   The second argument is again the array element type for array types.
+   The second argument is again the array element type OID for array types
+   or the type OID for composite types.
    The output function should return type <type>cstring</type>.
   </para>
 
@@ -128,14 +130,16 @@ CREATE TYPE <replaceable class="parameter">name</replaceable> (
    and <type>oid</type>.  It must return a value of the data type itself.
    (The first argument is a pointer to a <type>StringInfo</type> buffer
    holding the received byte string; the optional second argument is the
-   element type in case this is an array type.)  Similarly, the optional
+   element type OID in case this is an array type, or the type's own OID for a
+   composite type.)  Similarly, the optional
    <replaceable class="parameter">send_function</replaceable> converts
    from the internal representation to the external binary representation.
    If this function is not supplied, the type cannot participate in binary
    output.  The send function may be
    declared as taking one argument of the new data type,  or as taking
    two arguments of which the second is type <type>oid</type>.
-   The second argument is again the array element type for array types.
+   The second argument is again the array element type OID for array types
+   or the type OID for composite types.
    The send function must return type <type>bytea</type>.
   </para>
 
diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c
index fc0b8d9e7a..e5e74eca23 100644
--- a/src/backend/access/common/printtup.c
+++ b/src/backend/access/common/printtup.c
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.82 2004/06/04 20:35:21 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.83 2004/06/06 00:41:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,7 +51,7 @@ typedef struct
 {								/* Per-attribute information */
 	Oid			typoutput;		/* Oid for the type's text output fn */
 	Oid			typsend;		/* Oid for the type's binary output fn */
-	Oid			typelem;		/* typelem value to pass to the output fn */
+	Oid			typioparam;		/* param to pass to the output fn */
 	bool		typisvarlena;	/* is it varlena (ie possibly toastable)? */
 	int16		format;			/* format code for this column */
 	FmgrInfo	finfo;			/* Precomputed call info for output fn */
@@ -278,7 +278,7 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
 		{
 			getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
 							  &thisState->typoutput,
-							  &thisState->typelem,
+							  &thisState->typioparam,
 							  &thisState->typisvarlena);
 			fmgr_info(thisState->typoutput, &thisState->finfo);
 		}
@@ -286,7 +286,7 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs)
 		{
 			getTypeBinaryOutputInfo(typeinfo->attrs[i]->atttypid,
 									&thisState->typsend,
-									&thisState->typelem,
+									&thisState->typioparam,
 									&thisState->typisvarlena);
 			fmgr_info(thisState->typsend, &thisState->finfo);
 		}
@@ -356,7 +356,7 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
 
 			outputstr = DatumGetCString(FunctionCall3(&thisState->finfo,
 													  attr,
-									ObjectIdGetDatum(thisState->typelem),
+									ObjectIdGetDatum(thisState->typioparam),
 						  Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
 			pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
 			pfree(outputstr);
@@ -368,7 +368,7 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
 
 			outputbytes = DatumGetByteaP(FunctionCall2(&thisState->finfo,
 													   attr,
-								  ObjectIdGetDatum(thisState->typelem)));
+								  ObjectIdGetDatum(thisState->typioparam)));
 			/* We assume the result will not have been toasted */
 			pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
 			pq_sendbytes(&buf, VARDATA(outputbytes),
@@ -458,7 +458,7 @@ printtup_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
 
 		outputstr = DatumGetCString(FunctionCall3(&thisState->finfo,
 												  attr,
-									ObjectIdGetDatum(thisState->typelem),
+									ObjectIdGetDatum(thisState->typioparam),
 						  Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
 		pq_sendcountedtext(&buf, outputstr, strlen(outputstr), true);
 		pfree(outputstr);
@@ -557,7 +557,7 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
 	char	   *value;
 	bool		isnull;
 	Oid			typoutput,
-				typelem;
+				typioparam;
 	bool		typisvarlena;
 
 	for (i = 0; i < natts; ++i)
@@ -566,7 +566,7 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
 		if (isnull)
 			continue;
 		getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
-						  &typoutput, &typelem, &typisvarlena);
+						  &typoutput, &typioparam, &typisvarlena);
 
 		/*
 		 * If we have a toasted datum, forcibly detoast it here to avoid
@@ -579,7 +579,7 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
 
 		value = DatumGetCString(OidFunctionCall3(typoutput,
 												 attr,
-											   ObjectIdGetDatum(typelem),
+											   ObjectIdGetDatum(typioparam),
 						  Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
 
 		printatt((unsigned) i + 1, typeinfo->attrs[i], value);
@@ -672,7 +672,7 @@ printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
 
 		outputbytes = DatumGetByteaP(FunctionCall2(&thisState->finfo,
 												   attr,
-								  ObjectIdGetDatum(thisState->typelem)));
+								  ObjectIdGetDatum(thisState->typioparam)));
 		/* We assume the result will not have been toasted */
 		pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
 		pq_sendbytes(&buf, VARDATA(outputbytes),
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 02f67339b1..553cf79dd0 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.183 2004/06/03 02:08:02 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.184 2004/06/06 00:41:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -803,9 +803,11 @@ InsertOneTuple(Oid objectid)
 void
 InsertOneValue(char *value, int i)
 {
-	int			typeindex;
+	Oid			typoid;
+	Oid			typioparam;
+	Oid			typinput;
+	Oid			typoutput;
 	char	   *prt;
-	struct typmap **app;
 
 	AssertArg(i >= 0 || i < MAXATTR);
 
@@ -813,51 +815,59 @@ InsertOneValue(char *value, int i)
 
 	if (Typ != NULL)
 	{
+		struct typmap **app;
 		struct typmap *ap;
 
-		elog(DEBUG4, "Typ != NULL");
+		elog(DEBUG5, "Typ != NULL");
+		typoid = boot_reldesc->rd_att->attrs[i]->atttypid;
 		app = Typ;
-		while (*app && (*app)->am_oid != boot_reldesc->rd_att->attrs[i]->atttypid)
+		while (*app && (*app)->am_oid != typoid)
 			++app;
 		ap = *app;
 		if (ap == NULL)
-		{
-			elog(FATAL, "could not find atttypid %u in Typ list",
-				 boot_reldesc->rd_att->attrs[i]->atttypid);
-		}
-		values[i] = OidFunctionCall3(ap->am_typ.typinput,
-									 CStringGetDatum(value),
-									 ObjectIdGetDatum(ap->am_typ.typelem),
-									 Int32GetDatum(-1));
-		prt = DatumGetCString(OidFunctionCall3(ap->am_typ.typoutput,
-											   values[i],
-									ObjectIdGetDatum(ap->am_typ.typelem),
-											   Int32GetDatum(-1)));
-		elog(DEBUG4, " -> %s", prt);
-		pfree(prt);
+			elog(ERROR, "could not find atttypid %u in Typ list", typoid);
+
+		/* XXX this should match getTypeIOParam() */
+		if (ap->am_typ.typtype == 'c')
+			typioparam = typoid;
+		else
+			typioparam = ap->am_typ.typelem;
+
+		typinput = ap->am_typ.typinput;
+		typoutput = ap->am_typ.typoutput;
 	}
 	else
 	{
+		int			typeindex;
+
+		/* XXX why is typoid determined differently in this path? */
+		typoid = attrtypes[i]->atttypid;
 		for (typeindex = 0; typeindex < n_types; typeindex++)
 		{
-			if (TypInfo[typeindex].oid == attrtypes[i]->atttypid)
+			if (TypInfo[typeindex].oid == typoid)
 				break;
 		}
 		if (typeindex >= n_types)
-			elog(ERROR, "type oid %u not found", attrtypes[i]->atttypid);
-		elog(DEBUG4, "Typ == NULL, typeindex = %u", typeindex);
-		values[i] = OidFunctionCall3(TypInfo[typeindex].inproc,
-									 CStringGetDatum(value),
-								ObjectIdGetDatum(TypInfo[typeindex].elem),
-									 Int32GetDatum(-1));
-		prt = DatumGetCString(OidFunctionCall3(TypInfo[typeindex].outproc,
-											   values[i],
-								ObjectIdGetDatum(TypInfo[typeindex].elem),
-											   Int32GetDatum(-1)));
-		elog(DEBUG4, " -> %s", prt);
-		pfree(prt);
+			elog(ERROR, "type oid %u not found", typoid);
+		elog(DEBUG5, "Typ == NULL, typeindex = %u", typeindex);
+
+		/* XXX there are no composite types in TypInfo */
+		typioparam = TypInfo[typeindex].elem;
+
+		typinput = TypInfo[typeindex].inproc;
+		typoutput = TypInfo[typeindex].outproc;
 	}
-	elog(DEBUG4, "inserted");
+
+	values[i] = OidFunctionCall3(typinput,
+								 CStringGetDatum(value),
+								 ObjectIdGetDatum(typioparam),
+								 Int32GetDatum(-1));
+	prt = DatumGetCString(OidFunctionCall3(typoutput,
+										   values[i],
+										   ObjectIdGetDatum(typioparam),
+										   Int32GetDatum(-1)));
+	elog(DEBUG4, "inserted -> %s", prt);
+	pfree(prt);
 }
 
 /* ----------------
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 13ed62b8df..77e7d1b185 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.225 2004/06/05 19:48:07 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.226 2004/06/06 00:41:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -143,7 +143,7 @@ static char *CopyReadAttributeCSV(const char *delim, const char *null_print,
 							   char *quote, char *escape,
 							   CopyReadResult *result, bool *isnull);
 static Datum CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo,
-						Oid typelem, bool *isnull);
+						Oid typioparam, bool *isnull);
 static void CopyAttributeOut(char *string, char *delim);
 static void CopyAttributeOutCSV(char *string, char *delim, char *quote,
 								char *escape, bool force_quote);
@@ -1143,7 +1143,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
 	Form_pg_attribute *attr;
 	FmgrInfo   *out_functions;
 	bool	   *force_quote;
-	Oid		   *elements;
+	Oid		   *typioparams;
 	bool	   *isvarlena;
 	char	   *string;
 	Snapshot	mySnapshot;
@@ -1160,7 +1160,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
 	 * Get info about the columns we need to process.
 	 */
 	out_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo));
-	elements = (Oid *) palloc(num_phys_attrs * sizeof(Oid));
+	typioparams = (Oid *) palloc(num_phys_attrs * sizeof(Oid));
 	isvarlena = (bool *) palloc(num_phys_attrs * sizeof(bool));
 	force_quote = (bool *) palloc(num_phys_attrs * sizeof(bool));
 	foreach(cur, attnumlist)
@@ -1170,11 +1170,11 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
 		
 		if (binary)
 			getTypeBinaryOutputInfo(attr[attnum - 1]->atttypid,
-									&out_func_oid, &elements[attnum - 1],
+									&out_func_oid, &typioparams[attnum - 1],
 									&isvarlena[attnum - 1]);
 		else
 			getTypeOutputInfo(attr[attnum - 1]->atttypid,
-							  &out_func_oid, &elements[attnum - 1],
+							  &out_func_oid, &typioparams[attnum - 1],
 							  &isvarlena[attnum - 1]);
 		fmgr_info(out_func_oid, &out_functions[attnum - 1]);
 
@@ -1290,7 +1290,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
 				{
 					string = DatumGetCString(FunctionCall3(&out_functions[attnum - 1],
 														   value,
-								  ObjectIdGetDatum(elements[attnum - 1]),
+								  ObjectIdGetDatum(typioparams[attnum - 1]),
 							Int32GetDatum(attr[attnum - 1]->atttypmod)));
 					if (csv_mode)
 					{
@@ -1308,7 +1308,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
 
 					outputbytes = DatumGetByteaP(FunctionCall2(&out_functions[attnum - 1],
 															   value,
-								ObjectIdGetDatum(elements[attnum - 1])));
+								ObjectIdGetDatum(typioparams[attnum - 1])));
 					/* We assume the result will not have been toasted */
 					CopySendInt32(VARSIZE(outputbytes) - VARHDRSZ);
 					CopySendData(VARDATA(outputbytes),
@@ -1333,7 +1333,7 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
 	MemoryContextDelete(mycontext);
 
 	pfree(out_functions);
-	pfree(elements);
+	pfree(typioparams);
 	pfree(isvarlena);
 	pfree(force_quote);
 }
@@ -1442,8 +1442,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 				num_defaults;
 	FmgrInfo   *in_functions;
 	FmgrInfo	oid_in_function;
-	Oid		   *elements;
-	Oid			oid_in_element;
+	Oid		   *typioparams;
+	Oid			oid_typioparam;
 	ExprState **constraintexprs;
 	bool	   *force_notnull;
 	bool		hasConstraints = false;
@@ -1501,7 +1501,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 	 * (Which input function we use depends on text/binary format choice.)
 	 */
 	in_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo));
-	elements = (Oid *) palloc(num_phys_attrs * sizeof(Oid));
+	typioparams = (Oid *) palloc(num_phys_attrs * sizeof(Oid));
 	defmap = (int *) palloc(num_phys_attrs * sizeof(int));
 	defexprs = (ExprState **) palloc(num_phys_attrs * sizeof(ExprState *));
 	constraintexprs = (ExprState **) palloc0(num_phys_attrs * sizeof(ExprState *));
@@ -1513,13 +1513,13 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 		if (attr[attnum - 1]->attisdropped)
 			continue;
 
-		/* Fetch the input function and typelem info */
+		/* Fetch the input function and typioparam info */
 		if (binary)
 			getTypeBinaryInputInfo(attr[attnum - 1]->atttypid,
-								   &in_func_oid, &elements[attnum - 1]);
+								   &in_func_oid, &typioparams[attnum - 1]);
 		else
 			getTypeInputInfo(attr[attnum - 1]->atttypid,
-							 &in_func_oid, &elements[attnum - 1]);
+							 &in_func_oid, &typioparams[attnum - 1]);
 		fmgr_info(in_func_oid, &in_functions[attnum - 1]);
 
 		if (list_member_int(force_notnull_atts, attnum))
@@ -1628,7 +1628,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 	if (file_has_oids && binary)
 	{
 		getTypeBinaryInputInfo(OIDOID,
-							   &in_func_oid, &oid_in_element);
+							   &in_func_oid, &oid_typioparam);
 		fmgr_info(in_func_oid, &oid_in_function);
 	}
 
@@ -1757,7 +1757,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 					copy_attname = NameStr(attr[m]->attname);
 					values[m] = FunctionCall3(&in_functions[m],
 											  CStringGetDatum(string),
-										   ObjectIdGetDatum(elements[m]),
+										   ObjectIdGetDatum(typioparams[m]),
 									  Int32GetDatum(attr[m]->atttypmod));
 					nulls[m] = ' ';
 					copy_attname = NULL;
@@ -1800,8 +1800,8 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 				copy_attname = "oid";
 				loaded_oid =
 					DatumGetObjectId(CopyReadBinaryAttribute(0,
-														&oid_in_function,
-														  oid_in_element,
+															 &oid_in_function,
+															 oid_typioparam,
 															 &isnull));
 				if (isnull || loaded_oid == InvalidOid)
 					ereport(ERROR,
@@ -1820,7 +1820,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 				i++;
 				values[m] = CopyReadBinaryAttribute(i,
 													&in_functions[m],
-													elements[m],
+													typioparams[m],
 													&isnull);
 				nulls[m] = isnull ? 'n' : ' ';
 				copy_attname = NULL;
@@ -1941,7 +1941,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
 	pfree(nulls);
 
 	pfree(in_functions);
-	pfree(elements);
+	pfree(typioparams);
 	pfree(defmap);
 	pfree(defexprs);
 	pfree(constraintexprs);
@@ -2429,7 +2429,7 @@ CopyReadAttributeCSV(const char *delim, const char *null_print, char *quote,
  * Read a binary attribute
  */
 static Datum
-CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typelem,
+CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typioparam,
 						bool *isnull)
 {
 	int32		fld_size;
@@ -2469,7 +2469,7 @@ CopyReadBinaryAttribute(int column_no, FmgrInfo *flinfo, Oid typelem,
 	/* Call the column type's binary input converter */
 	result = FunctionCall2(flinfo,
 						   PointerGetDatum(&attribute_buf),
-						   ObjectIdGetDatum(typelem));
+						   ObjectIdGetDatum(typioparam));
 
 	/* Trouble if it didn't eat the whole buffer */
 	if (attribute_buf.cursor != attribute_buf.len)
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index 8dd8cfc394..950d9d7f3b 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.79 2004/05/30 23:40:26 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.80 2004/06/06 00:41:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -685,7 +685,7 @@ TupleDescGetAttInMetadata(TupleDesc tupdesc)
 	Oid			atttypeid;
 	Oid			attinfuncid;
 	FmgrInfo   *attinfuncinfo;
-	Oid		   *attelems;
+	Oid		   *attioparams;
 	int32	   *atttypmods;
 	AttInMetadata *attinmeta;
 
@@ -699,7 +699,7 @@ TupleDescGetAttInMetadata(TupleDesc tupdesc)
 	 * attribute
 	 */
 	attinfuncinfo = (FmgrInfo *) palloc0(natts * sizeof(FmgrInfo));
-	attelems = (Oid *) palloc0(natts * sizeof(Oid));
+	attioparams = (Oid *) palloc0(natts * sizeof(Oid));
 	atttypmods = (int32 *) palloc0(natts * sizeof(int32));
 
 	for (i = 0; i < natts; i++)
@@ -708,13 +708,13 @@ TupleDescGetAttInMetadata(TupleDesc tupdesc)
 		if (!tupdesc->attrs[i]->attisdropped)
 		{
 			atttypeid = tupdesc->attrs[i]->atttypid;
-			getTypeInputInfo(atttypeid, &attinfuncid, &attelems[i]);
+			getTypeInputInfo(atttypeid, &attinfuncid, &attioparams[i]);
 			fmgr_info(attinfuncid, &attinfuncinfo[i]);
 			atttypmods[i] = tupdesc->attrs[i]->atttypmod;
 		}
 	}
 	attinmeta->attinfuncs = attinfuncinfo;
-	attinmeta->attelems = attelems;
+	attinmeta->attioparams = attioparams;
 	attinmeta->atttypmods = atttypmods;
 
 	return attinmeta;
@@ -732,7 +732,7 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
 	Datum	   *dvalues;
 	char	   *nulls;
 	int			i;
-	Oid			attelem;
+	Oid			attioparam;
 	int32		atttypmod;
 	HeapTuple	tuple;
 
@@ -747,12 +747,12 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
 			/* Non-dropped attributes */
 			if (values[i] != NULL)
 			{
-				attelem = attinmeta->attelems[i];
+				attioparam = attinmeta->attioparams[i];
 				atttypmod = attinmeta->atttypmods[i];
 
 				dvalues[i] = FunctionCall3(&attinmeta->attinfuncs[i],
 										   CStringGetDatum(values[i]),
-										   ObjectIdGetDatum(attelem),
+										   ObjectIdGetDatum(attioparam),
 										   Int32GetDatum(atttypmod));
 				nulls[i] = ' ';
 			}
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 265828f4c1..119f5da346 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -45,7 +45,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.121 2004/05/30 23:40:26 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.122 2004/06/06 00:41:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1357,29 +1357,17 @@ ExecInitAgg(Agg *node, EState *estate)
 static Datum
 GetAggInitVal(Datum textInitVal, Oid transtype)
 {
-	char	   *strInitVal;
-	HeapTuple	tup;
 	Oid			typinput,
-				typelem;
+				typioparam;
+	char	   *strInitVal;
 	Datum		initVal;
 
+	getTypeInputInfo(transtype, &typinput, &typioparam);
 	strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
-
-	tup = SearchSysCache(TYPEOID,
-						 ObjectIdGetDatum(transtype),
-						 0, 0, 0);
-	if (!HeapTupleIsValid(tup))
-		elog(ERROR, "cache lookup failed for type %u", transtype);
-
-	typinput = ((Form_pg_type) GETSTRUCT(tup))->typinput;
-	typelem = ((Form_pg_type) GETSTRUCT(tup))->typelem;
-	ReleaseSysCache(tup);
-
 	initVal = OidFunctionCall3(typinput,
 							   CStringGetDatum(strInitVal),
-							   ObjectIdGetDatum(typelem),
+							   ObjectIdGetDatum(typioparam),
 							   Int32GetDatum(-1));
-
 	pfree(strInitVal);
 	return initVal;
 }
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 047b8fa2aa..f5f2850b98 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.116 2004/06/04 20:35:21 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.117 2004/06/06 00:41:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -538,7 +538,7 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
 	bool		isnull;
 	Oid			typoid,
 				foutoid,
-				typelem;
+				typioparam;
 	int32		typmod;
 	bool		typisvarlena;
 
@@ -566,7 +566,7 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
 		typmod = -1;
 	}
 
-	getTypeOutputInfo(typoid, &foutoid, &typelem, &typisvarlena);
+	getTypeOutputInfo(typoid, &foutoid, &typioparam, &typisvarlena);
 
 	/*
 	 * If we have a toasted datum, forcibly detoast it here to avoid
@@ -579,7 +579,7 @@ SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
 
 	result = OidFunctionCall3(foutoid,
 							  val,
-							  ObjectIdGetDatum(typelem),
+							  ObjectIdGetDatum(typioparam),
 							  Int32GetDatum(typmod));
 
 	/* Clean up detoasted copy, if any */
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 4934c09e2b..035bb7aa65 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.68 2004/05/30 23:40:27 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.69 2004/06/06 00:41:26 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -20,7 +20,6 @@
 #include "postgres.h"
 
 #include "access/printtup.h"
-#include "catalog/pg_type.h"
 #include "lib/stringinfo.h"
 #include "nodes/print.h"
 #include "optimizer/clauses.h"
@@ -345,9 +344,9 @@ print_expr(Node *expr, List *rtable)
 	else if (IsA(expr, Const))
 	{
 		Const	   *c = (Const *) expr;
-		HeapTuple	typeTup;
 		Oid			typoutput;
-		Oid			typelem;
+		Oid			typioparam;
+		bool		typIsVarlena;
 		char	   *outputstr;
 
 		if (c->constisnull)
@@ -356,18 +355,12 @@ print_expr(Node *expr, List *rtable)
 			return;
 		}
 
-		typeTup = SearchSysCache(TYPEOID,
-								 ObjectIdGetDatum(c->consttype),
-								 0, 0, 0);
-		if (!HeapTupleIsValid(typeTup))
-			elog(ERROR, "cache lookup failed for type %u", c->consttype);
-		typoutput = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
-		typelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
-		ReleaseSysCache(typeTup);
+		getTypeOutputInfo(c->consttype,
+						  &typoutput, &typioparam, &typIsVarlena);
 
 		outputstr = DatumGetCString(OidFunctionCall3(typoutput,
 													 c->constvalue,
-											   ObjectIdGetDatum(typelem),
+											   ObjectIdGetDatum(typioparam),
 													 Int32GetDatum(-1)));
 		printf("%s", outputstr);
 		pfree(outputstr);
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 9ba0bdc90f..b12d1854aa 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.117 2004/05/30 23:40:35 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.118 2004/06/06 00:41:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -356,14 +356,10 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
 
 		/*
 		 * If input is an untyped string constant, assume we can convert
-		 * it to anything except a class type.
+		 * it to anything.
 		 */
 		if (inputTypeId == UNKNOWNOID)
-		{
-			if (ISCOMPLEX(targetTypeId))
-				return false;
 			continue;
-		}
 
 		/*
 		 * If pg_cast shows that we can coerce, accept.  This test now
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index be4877909f..79cc9d8bf4 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.68 2004/06/03 19:41:46 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.69 2004/06/06 00:41:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -323,83 +323,24 @@ typeTypeRelid(Type typ)
 	return typtup->typrelid;
 }
 
-#ifdef NOT_USED
-Oid
-typeTypElem(Type typ)
-{
-	Form_pg_type typtup;
-
-	typtup = (Form_pg_type) GETSTRUCT(typ);
-
-	return typtup->typelem;
-}
-#endif
-
-#ifdef NOT_USED
-/* Given a type structure, return the in-conversion function of the type */
-Oid
-typeInfunc(Type typ)
-{
-	Form_pg_type typtup;
-
-	typtup = (Form_pg_type) GETSTRUCT(typ);
-
-	return typtup->typinput;
-}
-#endif
-
-#ifdef NOT_USED
-/* Given a type structure, return the out-conversion function of the type */
-Oid
-typeOutfunc(Type typ)
-{
-	Form_pg_type typtup;
-
-	typtup = (Form_pg_type) GETSTRUCT(typ);
-
-	return typtup->typoutput;
-}
-#endif
-
-/* Given a type structure and a string, returns the internal form of
-   that string */
+/*
+ * Given a type structure and a string, returns the internal representation
+ * of that string
+ */
 Datum
 stringTypeDatum(Type tp, char *string, int32 atttypmod)
 {
-	Oid			op;
-	Oid			typelem;
+	Oid			typinput;
+	Oid			typioparam;
 
-	op = ((Form_pg_type) GETSTRUCT(tp))->typinput;
-	typelem = ((Form_pg_type) GETSTRUCT(tp))->typelem;	/* XXX - used for
-														 * array_in */
-	return OidFunctionCall3(op,
+	typinput = ((Form_pg_type) GETSTRUCT(tp))->typinput;
+	typioparam = getTypeIOParam(tp);
+	return OidFunctionCall3(typinput,
 							CStringGetDatum(string),
-							ObjectIdGetDatum(typelem),
+							ObjectIdGetDatum(typioparam),
 							Int32GetDatum(atttypmod));
 }
 
-/* Given a type id, returns the out-conversion function of the type */
-#ifdef NOT_USED
-Oid
-typeidOutfunc(Oid type_id)
-{
-	HeapTuple	typeTuple;
-	Form_pg_type type;
-	Oid			outfunc;
-
-	typeTuple = SearchSysCache(TYPEOID,
-							   ObjectIdGetDatum(type_id),
-							   0, 0, 0);
-	if (!HeapTupleIsValid(typeTuple))
-		elog(ERROR, "cache lookup failed for type %u", type_id);
-
-	type = (Form_pg_type) GETSTRUCT(typeTuple);
-	outfunc = type->typoutput;
-	ReleaseSysCache(typeTuple);
-	return outfunc;
-}
-#endif
-
 /* given a typeid, return the type's typrelid (associated relation, if any) */
 Oid
 typeidTypeRelid(Oid type_id)
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index a0eda360c4..9a467a9ba0 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tcop/fastpath.c,v 1.72 2004/04/19 17:22:31 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tcop/fastpath.c,v 1.73 2004/06/06 00:41:27 tgl Exp $
  *
  * NOTES
  *	  This cruft is the server side of PQfn.
@@ -150,14 +150,14 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
 		if (format == 0)
 		{
 			Oid			typoutput,
-						typelem;
+						typioparam;
 			bool		typisvarlena;
 			char	   *outputstr;
 
-			getTypeOutputInfo(rettype, &typoutput, &typelem, &typisvarlena);
+			getTypeOutputInfo(rettype, &typoutput, &typioparam, &typisvarlena);
 			outputstr = DatumGetCString(OidFunctionCall3(typoutput,
 														 retval,
-											   ObjectIdGetDatum(typelem),
+											   ObjectIdGetDatum(typioparam),
 													 Int32GetDatum(-1)));
 			pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
 			pfree(outputstr);
@@ -165,15 +165,15 @@ SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
 		else if (format == 1)
 		{
 			Oid			typsend,
-						typelem;
+						typioparam;
 			bool		typisvarlena;
 			bytea	   *outputbytes;
 
 			getTypeBinaryOutputInfo(rettype,
-									&typsend, &typelem, &typisvarlena);
+									&typsend, &typioparam, &typisvarlena);
 			outputbytes = DatumGetByteaP(OidFunctionCall2(typsend,
 														  retval,
-											 ObjectIdGetDatum(typelem)));
+											 ObjectIdGetDatum(typioparam)));
 			/* We assume the result will not have been toasted */
 			pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
 			pq_sendbytes(&buf, VARDATA(outputbytes),
@@ -467,11 +467,11 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
 
 		if (aformat == 0)
 		{
-			Oid			typInput;
-			Oid			typElem;
+			Oid			typinput;
+			Oid			typioparam;
 			char	   *pstring;
 
-			getTypeInputInfo(fip->argtypes[i], &typInput, &typElem);
+			getTypeInputInfo(fip->argtypes[i], &typinput, &typioparam);
 
 			/*
 			 * Since stringinfo.c keeps a trailing null in place even for
@@ -483,9 +483,9 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
 				pg_client_to_server((unsigned char *) abuf.data,
 									argsize);
 			fcinfo->arg[i] =
-				OidFunctionCall3(typInput,
+				OidFunctionCall3(typinput,
 								 CStringGetDatum(pstring),
-								 ObjectIdGetDatum(typElem),
+								 ObjectIdGetDatum(typioparam),
 								 Int32GetDatum(-1));
 			/* Free result of encoding conversion, if any */
 			if (pstring != abuf.data)
@@ -493,15 +493,15 @@ parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
 		}
 		else if (aformat == 1)
 		{
-			Oid			typReceive;
-			Oid			typElem;
+			Oid			typreceive;
+			Oid			typioparam;
 
 			/* Call the argument type's binary input converter */
-			getTypeBinaryInputInfo(fip->argtypes[i], &typReceive, &typElem);
+			getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
 
-			fcinfo->arg[i] = OidFunctionCall2(typReceive,
+			fcinfo->arg[i] = OidFunctionCall2(typreceive,
 											  PointerGetDatum(&abuf),
-											  ObjectIdGetDatum(typElem));
+											  ObjectIdGetDatum(typioparam));
 
 			/* Trouble if it didn't eat the whole buffer */
 			if (abuf.cursor != abuf.len)
@@ -557,8 +557,8 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip,
 	for (i = 0; i < nargs; ++i)
 	{
 		int			argsize;
-		Oid			typReceive;
-		Oid			typElem;
+		Oid			typreceive;
+		Oid			typioparam;
 
 		argsize = pq_getmsgint(msgBuf, 4);
 		if (argsize == -1)
@@ -582,11 +582,11 @@ parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip,
 							   argsize);
 
 		/* Call the argument type's binary input converter */
-		getTypeBinaryInputInfo(fip->argtypes[i], &typReceive, &typElem);
+		getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
 
-		fcinfo->arg[i] = OidFunctionCall2(typReceive,
+		fcinfo->arg[i] = OidFunctionCall2(typreceive,
 										  PointerGetDatum(&abuf),
-										  ObjectIdGetDatum(typElem));
+										  ObjectIdGetDatum(typioparam));
 
 		/* Trouble if it didn't eat the whole buffer */
 		if (abuf.cursor != abuf.len)
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 29d457e94e..07b60969a4 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.418 2004/06/03 02:08:03 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.419 2004/06/06 00:41:27 tgl Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -1432,11 +1432,11 @@ exec_bind_message(StringInfo input_message)
 
 					if (pformat == 0)
 					{
-						Oid			typInput;
-						Oid			typElem;
+						Oid			typinput;
+						Oid			typioparam;
 						char	   *pstring;
 
-						getTypeInputInfo(ptype, &typInput, &typElem);
+						getTypeInputInfo(ptype, &typinput, &typioparam);
 
 						/*
 						 * We have to do encoding conversion before
@@ -1446,9 +1446,9 @@ exec_bind_message(StringInfo input_message)
 							pg_client_to_server((unsigned char *) pbuf.data,
 												plength);
 						params[i].value =
-							OidFunctionCall3(typInput,
+							OidFunctionCall3(typinput,
 											 CStringGetDatum(pstring),
-											 ObjectIdGetDatum(typElem),
+											 ObjectIdGetDatum(typioparam),
 											 Int32GetDatum(-1));
 						/* Free result of encoding conversion, if any */
 						if (pstring != pbuf.data)
@@ -1456,19 +1456,19 @@ exec_bind_message(StringInfo input_message)
 					}
 					else if (pformat == 1)
 					{
-						Oid			typReceive;
-						Oid			typElem;
+						Oid			typreceive;
+						Oid			typioparam;
 
 						/*
 						 * Call the parameter type's binary input
 						 * converter
 						 */
-						getTypeBinaryInputInfo(ptype, &typReceive, &typElem);
+						getTypeBinaryInputInfo(ptype, &typreceive, &typioparam);
 
 						params[i].value =
-							OidFunctionCall2(typReceive,
+							OidFunctionCall2(typreceive,
 											 PointerGetDatum(&pbuf),
-											 ObjectIdGetDatum(typElem));
+											 ObjectIdGetDatum(typioparam));
 
 						/* Trouble if it didn't eat the whole buffer */
 						if (pbuf.cursor != pbuf.len)
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index ba734a0975..6511efb356 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.102 2004/01/07 18:56:28 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.103 2004/06/06 00:41:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -75,12 +75,12 @@
 
 static int	ArrayCount(char *str, int *dim, char typdelim);
 static Datum *ReadArrayStr(char *arrayStr, int nitems, int ndim, int *dim,
-			 FmgrInfo *inputproc, Oid typelem, int32 typmod,
+			 FmgrInfo *inputproc, Oid typioparam, int32 typmod,
 			 char typdelim,
 			 int typlen, bool typbyval, char typalign,
 			 int *nbytes);
 static Datum *ReadArrayBinary(StringInfo buf, int nitems,
-				FmgrInfo *receiveproc, Oid typelem,
+				FmgrInfo *receiveproc, Oid typioparam,
 				int typlen, bool typbyval, char typalign,
 				int *nbytes);
 static void CopyArrayEls(char *p, Datum *values, int nitems,
@@ -130,7 +130,7 @@ array_in(PG_FUNCTION_ARGS)
 	bool		typbyval;
 	char		typalign;
 	char		typdelim;
-	Oid			typelem;
+	Oid			typioparam;
 	char	   *string_save,
 			   *p;
 	int			i,
@@ -166,7 +166,7 @@ array_in(PG_FUNCTION_ARGS)
 		get_type_io_data(element_type, IOFunc_input,
 						 &my_extra->typlen, &my_extra->typbyval,
 						 &my_extra->typalign, &my_extra->typdelim,
-						 &my_extra->typelem, &my_extra->typiofunc);
+						 &my_extra->typioparam, &my_extra->typiofunc);
 		fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
 					  fcinfo->flinfo->fn_mcxt);
 		my_extra->element_type = element_type;
@@ -175,7 +175,7 @@ array_in(PG_FUNCTION_ARGS)
 	typbyval = my_extra->typbyval;
 	typalign = my_extra->typalign;
 	typdelim = my_extra->typdelim;
-	typelem = my_extra->typelem;
+	typioparam = my_extra->typioparam;
 
 	/* Make a modifiable copy of the input */
 	/* XXX why are we allocating an extra 2 bytes here? */
@@ -299,7 +299,7 @@ array_in(PG_FUNCTION_ARGS)
 				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 				 errmsg("missing left brace")));
 
-	dataPtr = ReadArrayStr(p, nitems, ndim, dim, &my_extra->proc, typelem,
+	dataPtr = ReadArrayStr(p, nitems, ndim, dim, &my_extra->proc, typioparam,
 						   typmod, typdelim, typlen, typbyval, typalign,
 						   &nbytes);
 	nbytes += ARR_OVERHEAD(ndim);
@@ -439,7 +439,7 @@ ReadArrayStr(char *arrayStr,
 			 int ndim,
 			 int *dim,
 			 FmgrInfo *inputproc,
-			 Oid typelem,
+			 Oid typioparam,
 			 int32 typmod,
 			 char typdelim,
 			 int typlen,
@@ -571,7 +571,7 @@ ReadArrayStr(char *arrayStr,
 
 		values[i] = FunctionCall3(inputproc,
 								  CStringGetDatum(itemstart),
-								  ObjectIdGetDatum(typelem),
+								  ObjectIdGetDatum(typioparam),
 								  Int32GetDatum(typmod));
 	}
 
@@ -675,7 +675,7 @@ array_out(PG_FUNCTION_ARGS)
 	bool		typbyval;
 	char		typalign;
 	char		typdelim;
-	Oid			typelem;
+	Oid			typioparam;
 	char	   *p,
 			   *tmp,
 			   *retval,
@@ -716,7 +716,7 @@ array_out(PG_FUNCTION_ARGS)
 		get_type_io_data(element_type, IOFunc_output,
 						 &my_extra->typlen, &my_extra->typbyval,
 						 &my_extra->typalign, &my_extra->typdelim,
-						 &my_extra->typelem, &my_extra->typiofunc);
+						 &my_extra->typioparam, &my_extra->typiofunc);
 		fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
 					  fcinfo->flinfo->fn_mcxt);
 		my_extra->element_type = element_type;
@@ -725,7 +725,7 @@ array_out(PG_FUNCTION_ARGS)
 	typbyval = my_extra->typbyval;
 	typalign = my_extra->typalign;
 	typdelim = my_extra->typdelim;
-	typelem = my_extra->typelem;
+	typioparam = my_extra->typioparam;
 
 	ndim = ARR_NDIM(v);
 	dim = ARR_DIMS(v);
@@ -754,7 +754,7 @@ array_out(PG_FUNCTION_ARGS)
 		itemvalue = fetch_att(p, typbyval, typlen);
 		values[i] = DatumGetCString(FunctionCall3(&my_extra->proc,
 												  itemvalue,
-											   ObjectIdGetDatum(typelem),
+											   ObjectIdGetDatum(typioparam),
 												  Int32GetDatum(-1)));
 		p = att_addlength(p, typlen, PointerGetDatum(p));
 		p = (char *) att_align(p, typalign);
@@ -871,7 +871,7 @@ array_recv(PG_FUNCTION_ARGS)
 	int			typlen;
 	bool		typbyval;
 	char		typalign;
-	Oid			typelem;
+	Oid			typioparam;
 	int			i,
 				nitems;
 	int32		nbytes;
@@ -946,7 +946,7 @@ array_recv(PG_FUNCTION_ARGS)
 		get_type_io_data(element_type, IOFunc_receive,
 						 &my_extra->typlen, &my_extra->typbyval,
 						 &my_extra->typalign, &my_extra->typdelim,
-						 &my_extra->typelem, &my_extra->typiofunc);
+						 &my_extra->typioparam, &my_extra->typiofunc);
 		if (!OidIsValid(my_extra->typiofunc))
 			ereport(ERROR,
 					(errcode(ERRCODE_UNDEFINED_FUNCTION),
@@ -959,9 +959,9 @@ array_recv(PG_FUNCTION_ARGS)
 	typlen = my_extra->typlen;
 	typbyval = my_extra->typbyval;
 	typalign = my_extra->typalign;
-	typelem = my_extra->typelem;
+	typioparam = my_extra->typioparam;
 
-	dataPtr = ReadArrayBinary(buf, nitems, &my_extra->proc, typelem,
+	dataPtr = ReadArrayBinary(buf, nitems, &my_extra->proc, typioparam,
 							  typlen, typbyval, typalign,
 							  &nbytes);
 	nbytes += ARR_OVERHEAD(ndim);
@@ -994,7 +994,7 @@ static Datum *
 ReadArrayBinary(StringInfo buf,
 				int nitems,
 				FmgrInfo *receiveproc,
-				Oid typelem,
+				Oid typioparam,
 				int typlen,
 				bool typbyval,
 				char typalign,
@@ -1037,7 +1037,7 @@ ReadArrayBinary(StringInfo buf,
 		/* Now call the element's receiveproc */
 		values[i] = FunctionCall2(receiveproc,
 								  PointerGetDatum(&elem_buf),
-								  ObjectIdGetDatum(typelem));
+								  ObjectIdGetDatum(typioparam));
 
 		/* Trouble if it didn't eat the whole buffer */
 		if (elem_buf.cursor != itemlen)
@@ -1086,7 +1086,7 @@ array_send(PG_FUNCTION_ARGS)
 	int			typlen;
 	bool		typbyval;
 	char		typalign;
-	Oid			typelem;
+	Oid			typioparam;
 	char	   *p;
 	int			nitems,
 				i;
@@ -1118,7 +1118,7 @@ array_send(PG_FUNCTION_ARGS)
 		get_type_io_data(element_type, IOFunc_send,
 						 &my_extra->typlen, &my_extra->typbyval,
 						 &my_extra->typalign, &my_extra->typdelim,
-						 &my_extra->typelem, &my_extra->typiofunc);
+						 &my_extra->typioparam, &my_extra->typiofunc);
 		if (!OidIsValid(my_extra->typiofunc))
 			ereport(ERROR,
 					(errcode(ERRCODE_UNDEFINED_FUNCTION),
@@ -1131,7 +1131,7 @@ array_send(PG_FUNCTION_ARGS)
 	typlen = my_extra->typlen;
 	typbyval = my_extra->typbyval;
 	typalign = my_extra->typalign;
-	typelem = my_extra->typelem;
+	typioparam = my_extra->typioparam;
 
 	ndim = ARR_NDIM(v);
 	dim = ARR_DIMS(v);
@@ -1160,7 +1160,7 @@ array_send(PG_FUNCTION_ARGS)
 
 		outputbytes = DatumGetByteaP(FunctionCall2(&my_extra->proc,
 												   itemvalue,
-											 ObjectIdGetDatum(typelem)));
+											 ObjectIdGetDatum(typioparam)));
 		/* We assume the result will not have been toasted */
 		pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
 		pq_sendbytes(&buf, VARDATA(outputbytes),
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 8614e73d53..ef58e99dac 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
  *				back to source text
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.169 2004/05/30 23:40:36 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.170 2004/06/06 00:41:27 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -3445,8 +3445,9 @@ static void
 get_const_expr(Const *constval, deparse_context *context)
 {
 	StringInfo	buf = context->buf;
-	HeapTuple	typetup;
-	Form_pg_type typeStruct;
+	Oid			typoutput;
+	Oid			typioparam;
+	bool		typIsVarlena;
 	char	   *extval;
 	char	   *valptr;
 	bool		isfloat = false;
@@ -3463,17 +3464,12 @@ get_const_expr(Const *constval, deparse_context *context)
 		return;
 	}
 
-	typetup = SearchSysCache(TYPEOID,
-							 ObjectIdGetDatum(constval->consttype),
-							 0, 0, 0);
-	if (!HeapTupleIsValid(typetup))
-		elog(ERROR, "cache lookup failed for type %u", constval->consttype);
+	getTypeOutputInfo(constval->consttype,
+					  &typoutput, &typioparam, &typIsVarlena);
 
-	typeStruct = (Form_pg_type) GETSTRUCT(typetup);
-
-	extval = DatumGetCString(OidFunctionCall3(typeStruct->typoutput,
+	extval = DatumGetCString(OidFunctionCall3(typoutput,
 											  constval->constvalue,
-								   ObjectIdGetDatum(typeStruct->typelem),
+											  ObjectIdGetDatum(typioparam),
 											  Int32GetDatum(-1)));
 
 	switch (constval->consttype)
@@ -3570,8 +3566,6 @@ get_const_expr(Const *constval, deparse_context *context)
 	if (needlabel)
 		appendStringInfo(buf, "::%s",
 					  format_type_with_typemod(constval->consttype, -1));
-
-	ReleaseSysCache(typetup);
 }
 
 
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index b1dc69ee90..53ac27ddf2 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.114 2004/05/30 23:40:36 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.115 2004/06/06 00:41:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2172,7 +2172,7 @@ array_to_text(PG_FUNCTION_ARGS)
 	int			typlen;
 	bool		typbyval;
 	char		typalign;
-	Oid			typelem;
+	Oid			typioparam;
 	StringInfo	result_str = makeStringInfo();
 	int			i;
 	ArrayMetaState *my_extra;
@@ -2211,7 +2211,7 @@ array_to_text(PG_FUNCTION_ARGS)
 		get_type_io_data(element_type, IOFunc_output,
 						 &my_extra->typlen, &my_extra->typbyval,
 						 &my_extra->typalign, &my_extra->typdelim,
-						 &my_extra->typelem, &my_extra->typiofunc);
+						 &my_extra->typioparam, &my_extra->typiofunc);
 		fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc,
 					  fcinfo->flinfo->fn_mcxt);
 		my_extra->element_type = element_type;
@@ -2219,7 +2219,7 @@ array_to_text(PG_FUNCTION_ARGS)
 	typlen = my_extra->typlen;
 	typbyval = my_extra->typbyval;
 	typalign = my_extra->typalign;
-	typelem = my_extra->typelem;
+	typioparam = my_extra->typioparam;
 
 	for (i = 0; i < nitems; i++)
 	{
@@ -2230,7 +2230,7 @@ array_to_text(PG_FUNCTION_ARGS)
 
 		value = DatumGetCString(FunctionCall3(&my_extra->proc,
 											  itemvalue,
-											  ObjectIdGetDatum(typelem),
+											  ObjectIdGetDatum(typioparam),
 											  Int32GetDatum(-1)));
 
 		if (i > 0)
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 237cf97e6c..d51d1c1892 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.112 2003/12/03 17:45:09 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.113 2004/06/06 00:41:27 tgl Exp $
  *
  * NOTES
  *	  Eventually, the index information should go through here, too.
@@ -1174,11 +1174,37 @@ get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
 	ReleaseSysCache(tp);
 }
 
+/*
+ * getTypeIOParam
+ *		Given a pg_type row, select the type OID to pass to I/O functions
+ *
+ * Formerly, all I/O functions were passed pg_type.typelem as their second
+ * parameter, but we now have a more complex rule about what to pass.
+ * This knowledge is intended to be centralized here --- direct references
+ * to typelem elsewhere in the code are wrong, if they are associated with
+ * I/O calls and not with actual subscripting operations!  (But see
+ * bootstrap.c, which can't conveniently use this routine.)
+ */
+Oid
+getTypeIOParam(HeapTuple typeTuple)
+{
+	Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
+
+	/*
+	 * Composite types get their own OID as parameter; array types get
+	 * their typelem as parameter; everybody else gets zero.
+	 */
+	if (typeStruct->typtype == 'c')
+		return HeapTupleGetOid(typeTuple);
+	else
+		return typeStruct->typelem;
+}
+
 /*
  * get_type_io_data
  *
  *		A six-fer:	given the type OID, return typlen, typbyval, typalign,
- *					typdelim, typelem, and IO function OID. The IO function
+ *					typdelim, typioparam, and IO function OID. The IO function
  *					returned is controlled by IOFuncSelector
  */
 void
@@ -1188,7 +1214,7 @@ get_type_io_data(Oid typid,
 				 bool *typbyval,
 				 char *typalign,
 				 char *typdelim,
-				 Oid *typelem,
+				 Oid *typioparam,
 				 Oid *func)
 {
 	HeapTuple	typeTuple;
@@ -1205,7 +1231,7 @@ get_type_io_data(Oid typid,
 	*typbyval = typeStruct->typbyval;
 	*typalign = typeStruct->typalign;
 	*typdelim = typeStruct->typdelim;
-	*typelem = typeStruct->typelem;
+	*typioparam = getTypeIOParam(typeTuple);
 	switch (which_func)
 	{
 		case IOFunc_input:
@@ -1355,7 +1381,7 @@ get_typdefault(Oid typid)
 			/* Convert C string to a value of the given type */
 			datum = OidFunctionCall3(type->typinput,
 									 CStringGetDatum(strDefaultVal),
-									 ObjectIdGetDatum(type->typelem),
+									 ObjectIdGetDatum(getTypeIOParam(typeTuple)),
 									 Int32GetDatum(-1));
 			/* Build a Const node containing the value */
 			expr = (Node *) makeConst(typid,
@@ -1607,7 +1633,7 @@ get_array_type(Oid typid)
  *		Get info needed for converting values of a type to internal form
  */
 void
-getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem)
+getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
 {
 	HeapTuple	typeTuple;
 	Form_pg_type pt;
@@ -1631,7 +1657,7 @@ getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem)
 						format_type_be(type))));
 
 	*typInput = pt->typinput;
-	*typElem = pt->typelem;
+	*typIOParam = getTypeIOParam(typeTuple);
 
 	ReleaseSysCache(typeTuple);
 }
@@ -1642,7 +1668,7 @@ getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem)
  *		Get info needed for printing values of a type
  */
 void
-getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
+getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typIOParam,
 				  bool *typIsVarlena)
 {
 	HeapTuple	typeTuple;
@@ -1667,7 +1693,7 @@ getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
 						format_type_be(type))));
 
 	*typOutput = pt->typoutput;
-	*typElem = pt->typelem;
+	*typIOParam = getTypeIOParam(typeTuple);
 	*typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
 
 	ReleaseSysCache(typeTuple);
@@ -1679,7 +1705,7 @@ getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
  *		Get info needed for binary input of values of a type
  */
 void
-getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typElem)
+getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
 {
 	HeapTuple	typeTuple;
 	Form_pg_type pt;
@@ -1703,7 +1729,7 @@ getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typElem)
 						format_type_be(type))));
 
 	*typReceive = pt->typreceive;
-	*typElem = pt->typelem;
+	*typIOParam = getTypeIOParam(typeTuple);
 
 	ReleaseSysCache(typeTuple);
 }
@@ -1714,7 +1740,7 @@ getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typElem)
  *		Get info needed for binary output of values of a type
  */
 void
-getTypeBinaryOutputInfo(Oid type, Oid *typSend, Oid *typElem,
+getTypeBinaryOutputInfo(Oid type, Oid *typSend, Oid *typIOParam,
 						bool *typIsVarlena)
 {
 	HeapTuple	typeTuple;
@@ -1739,7 +1765,7 @@ getTypeBinaryOutputInfo(Oid type, Oid *typSend, Oid *typElem,
 						format_type_be(type))));
 
 	*typSend = pt->typsend;
-	*typElem = pt->typelem;
+	*typIOParam = getTypeIOParam(typeTuple);
 	*typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
 
 	ReleaseSysCache(typeTuple);
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index fd1660423e..77b410c3fb 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -9,7 +9,7 @@
  *
  * Copyright (c) 2002-2003, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/funcapi.h,v 1.11 2004/04/01 21:28:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/funcapi.h,v 1.12 2004/06/06 00:41:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,8 +40,8 @@ typedef struct AttInMetadata
 	/* array of attribute type input function finfo */
 	FmgrInfo   *attinfuncs;
 
-	/* array of attribute type typelem */
-	Oid		   *attelems;
+	/* array of attribute type i/o parameter OIDs */
+	Oid		   *attioparams;
 
 	/* array of attribute typmod */
 	int32	   *atttypmods;
diff --git a/src/include/utils/array.h b/src/include/utils/array.h
index af976a54e2..596cf79d4d 100644
--- a/src/include/utils/array.h
+++ b/src/include/utils/array.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/array.h,v 1.46 2003/11/29 22:41:15 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/utils/array.h,v 1.47 2004/06/06 00:41:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,7 +59,7 @@ typedef struct ArrayMetaState
 	bool		typbyval;
 	char		typalign;
 	char		typdelim;
-	Oid			typelem;
+	Oid			typioparam;
 	Oid			typiofunc;
 	FmgrInfo	proc;
 } ArrayMetaState;
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index bd02e132d0..68fab871bd 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.86 2003/12/03 17:45:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.87 2004/06/06 00:41:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -71,13 +71,14 @@ extern bool get_typbyval(Oid typid);
 extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
 extern void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
 					 char *typalign);
+extern Oid	getTypeIOParam(HeapTuple typeTuple);
 extern void get_type_io_data(Oid typid,
 				 IOFuncSelector which_func,
 				 int16 *typlen,
 				 bool *typbyval,
 				 char *typalign,
 				 char *typdelim,
-				 Oid *typelem,
+				 Oid *typioparam,
 				 Oid *func);
 extern char get_typstorage(Oid typid);
 extern int32 get_typtypmod(Oid typid);
@@ -86,11 +87,11 @@ extern char get_typtype(Oid typid);
 extern Oid	get_typ_typrelid(Oid typid);
 extern Oid	get_element_type(Oid typid);
 extern Oid	get_array_type(Oid typid);
-extern void getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem);
-extern void getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
+extern void getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam);
+extern void getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typIOParam,
 				  bool *typIsVarlena);
-extern void getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typElem);
-extern void getTypeBinaryOutputInfo(Oid type, Oid *typSend, Oid *typElem,
+extern void getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam);
+extern void getTypeBinaryOutputInfo(Oid type, Oid *typSend, Oid *typIOParam,
 						bool *typIsVarlena);
 extern Oid	getBaseType(Oid typid);
 extern int32 get_typavgwidth(Oid typid, int32 typmod);
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 8c3680ae19..7bb2ac3433 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -33,7 +33,7 @@
  *	  ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.43 2004/04/01 21:28:46 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.44 2004/06/06 00:41:28 tgl Exp $
  *
  **********************************************************************/
 
@@ -79,10 +79,10 @@ typedef struct plperl_proc_desc
 	CommandId	fn_cmin;
 	bool		lanpltrusted;
 	FmgrInfo	result_in_func;
-	Oid			result_in_elem;
+	Oid			result_typioparam;
 	int			nargs;
 	FmgrInfo	arg_out_func[FUNC_MAX_ARGS];
-	Oid			arg_out_elem[FUNC_MAX_ARGS];
+	Oid			arg_typioparam[FUNC_MAX_ARGS];
 	bool		arg_is_rowtype[FUNC_MAX_ARGS];
 	SV		   *reference;
 }	plperl_proc_desc;
@@ -428,7 +428,7 @@ plperl_call_perl_func(plperl_proc_desc * desc, FunctionCallInfo fcinfo)
 
 				tmp = DatumGetCString(FunctionCall3(&(desc->arg_out_func[i]),
 													fcinfo->arg[i],
-								 ObjectIdGetDatum(desc->arg_out_elem[i]),
+								 ObjectIdGetDatum(desc->arg_typioparam[i]),
 													Int32GetDatum(-1)));
 				XPUSHs(sv_2mortal(newSVpv(tmp, 0)));
 				pfree(tmp);
@@ -506,7 +506,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
 	{
 		retval = FunctionCall3(&prodesc->result_in_func,
 							   PointerGetDatum(SvPV(perlret, PL_na)),
-							   ObjectIdGetDatum(prodesc->result_in_elem),
+							   ObjectIdGetDatum(prodesc->result_typioparam),
 							   Int32GetDatum(-1));
 	}
 
@@ -671,7 +671,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
 			}
 
 			perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
-			prodesc->result_in_elem = typeStruct->typelem;
+			prodesc->result_typioparam = getTypeIOParam(typeTup);
 
 			ReleaseSysCache(typeTup);
 		}
@@ -715,7 +715,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger)
 					prodesc->arg_is_rowtype[i] = false;
 					perm_fmgr_info(typeStruct->typoutput,
 								   &(prodesc->arg_out_func[i]));
-					prodesc->arg_out_elem[i] = typeStruct->typelem;
+					prodesc->arg_typioparam[i] = getTypeIOParam(typeTup);
 				}
 
 				ReleaseSysCache(typeTup);
@@ -776,7 +776,7 @@ plperl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc)
 	char	   *outputstr;
 	HeapTuple	typeTup;
 	Oid			typoutput;
-	Oid			typelem;
+	Oid			typioparam;
 
 	output = sv_2mortal(newSVpv("{", 0));
 
@@ -817,7 +817,7 @@ plperl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc)
 				 tupdesc->attrs[i]->atttypid);
 
 		typoutput = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
-		typelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
+		typioparam = getTypeIOParam(typeTup);
 		ReleaseSysCache(typeTup);
 
 		/************************************************************
@@ -825,7 +825,7 @@ plperl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc)
 		 ************************************************************/
 		outputstr = DatumGetCString(OidFunctionCall3(typoutput,
 													 attr,
-											   ObjectIdGetDatum(typelem),
+											   ObjectIdGetDatum(typioparam),
 						   Int32GetDatum(tupdesc->attrs[i]->atttypmod)));
 		sv_catpvf(output, "'%s' => '%s',", attname, outputstr);
 		pfree(outputstr);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 1c0fe6f8cc..a91d9c53e4 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.76 2004/06/03 22:56:43 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.77 2004/06/06 00:41:28 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -383,7 +383,7 @@ do_compile(FunctionCallInfo fcinfo,
 			{
 				function->fn_retbyval = typeStruct->typbyval;
 				function->fn_rettyplen = typeStruct->typlen;
-				function->fn_rettypelem = typeStruct->typelem;
+				function->fn_rettypioparam = getTypeIOParam(typeTup);
 				perm_fmgr_info(typeStruct->typinput, &(function->fn_retinput));
 
 				/*
@@ -1704,7 +1704,7 @@ build_datatype(HeapTuple typeTup, int32 typmod)
 	typ->typlen = typeStruct->typlen;
 	typ->typbyval = typeStruct->typbyval;
 	typ->typrelid = typeStruct->typrelid;
-	typ->typelem = typeStruct->typelem;
+	typ->typioparam = getTypeIOParam(typeTup);
 	perm_fmgr_info(typeStruct->typinput, &(typ->typinput));
 	typ->atttypmod = typmod;
 
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index e479094099..a8b531874d 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3,7 +3,7 @@
  *			  procedural language
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.105 2004/06/05 19:48:09 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.106 2004/06/06 00:41:28 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -171,7 +171,7 @@ static char *convert_value_to_string(Datum value, Oid valtype);
 static Datum exec_cast_value(Datum value, Oid valtype,
 				Oid reqtype,
 				FmgrInfo *reqinput,
-				Oid reqtypelem,
+				Oid reqtypioparam,
 				int32 reqtypmod,
 				bool *isnull);
 static Datum exec_simple_cast_value(Datum value, Oid valtype,
@@ -393,7 +393,7 @@ plpgsql_exec_function(PLpgSQL_function * func, FunctionCallInfo fcinfo)
 			estate.retval = exec_cast_value(estate.retval, estate.rettype,
 											func->fn_rettype,
 											&(func->fn_retinput),
-											func->fn_rettypelem,
+											func->fn_rettypioparam,
 											-1,
 											&fcinfo->isnull);
 
@@ -1268,7 +1268,7 @@ exec_stmt_fori(PLpgSQL_execstate * estate, PLpgSQL_stmt_fori * stmt)
 	value = exec_eval_expr(estate, stmt->lower, &isnull, &valtype);
 	value = exec_cast_value(value, valtype, var->datatype->typoid,
 							&(var->datatype->typinput),
-							var->datatype->typelem,
+							var->datatype->typioparam,
 							var->datatype->atttypmod, &isnull);
 	if (isnull)
 		ereport(ERROR,
@@ -1284,7 +1284,7 @@ exec_stmt_fori(PLpgSQL_execstate * estate, PLpgSQL_stmt_fori * stmt)
 	value = exec_eval_expr(estate, stmt->upper, &isnull, &valtype);
 	value = exec_cast_value(value, valtype, var->datatype->typoid,
 							&(var->datatype->typinput),
-							var->datatype->typelem,
+							var->datatype->typioparam,
 							var->datatype->atttypmod, &isnull);
 	if (isnull)
 		ereport(ERROR,
@@ -2674,7 +2674,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
 
 			newvalue = exec_cast_value(value, valtype, var->datatype->typoid,
 									   &(var->datatype->typinput),
-									   var->datatype->typelem,
+									   var->datatype->typioparam,
 									   var->datatype->atttypmod,
 									   isNull);
 
@@ -2917,8 +2917,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
 			bool		havenullsubscript,
 						oldarrayisnull;
 			Oid			arraytypeid,
-						arrayelemtypeid,
-						arrayInputFn;
+						arrayelemtypeid;
 			int16		elemtyplen;
 			bool		elemtypbyval;
 			char		elemtypalign;
@@ -2954,7 +2953,7 @@ exec_assign_value(PLpgSQL_execstate * estate,
 			exec_eval_datum(estate, target, InvalidOid,
 							&arraytypeid, &oldarrayval, &oldarrayisnull);
 
-			getTypeInputInfo(arraytypeid, &arrayInputFn, &arrayelemtypeid);
+			arrayelemtypeid = get_element_type(arraytypeid);
 			if (!OidIsValid(arrayelemtypeid))
 				ereport(ERROR,
 						(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -3672,19 +3671,16 @@ make_tuple_from_row(PLpgSQL_execstate * estate,
 static char *
 convert_value_to_string(Datum value, Oid valtype)
 {
-	Oid			typOutput;
-	Oid			typElem;
+	Oid			typoutput;
+	Oid			typioparam;
 	bool		typIsVarlena;
-	FmgrInfo	finfo_output;
 
-	getTypeOutputInfo(valtype, &typOutput, &typElem, &typIsVarlena);
+	getTypeOutputInfo(valtype, &typoutput, &typioparam, &typIsVarlena);
 
-	fmgr_info(typOutput, &finfo_output);
-
-	return DatumGetCString(FunctionCall3(&finfo_output,
-										 value,
-										 ObjectIdGetDatum(typElem),
-										 Int32GetDatum(-1)));
+	return DatumGetCString(OidFunctionCall3(typoutput,
+											value,
+											ObjectIdGetDatum(typioparam),
+											Int32GetDatum(-1)));
 }
 
 /* ----------
@@ -3695,7 +3691,7 @@ static Datum
 exec_cast_value(Datum value, Oid valtype,
 				Oid reqtype,
 				FmgrInfo *reqinput,
-				Oid reqtypelem,
+				Oid reqtypioparam,
 				int32 reqtypmod,
 				bool *isnull)
 {
@@ -3712,7 +3708,7 @@ exec_cast_value(Datum value, Oid valtype,
 			extval = convert_value_to_string(value, valtype);
 			value = FunctionCall3(reqinput,
 								  CStringGetDatum(extval),
-								  ObjectIdGetDatum(reqtypelem),
+								  ObjectIdGetDatum(reqtypioparam),
 								  Int32GetDatum(reqtypmod));
 			pfree(extval);
 		}
@@ -3738,19 +3734,19 @@ exec_simple_cast_value(Datum value, Oid valtype,
 	{
 		if (valtype != reqtype || reqtypmod != -1)
 		{
-			Oid			typInput;
-			Oid			typElem;
+			Oid			typinput;
+			Oid			typioparam;
 			FmgrInfo	finfo_input;
 
-			getTypeInputInfo(reqtype, &typInput, &typElem);
+			getTypeInputInfo(reqtype, &typinput, &typioparam);
 
-			fmgr_info(typInput, &finfo_input);
+			fmgr_info(typinput, &finfo_input);
 
 			value = exec_cast_value(value,
 									valtype,
 									reqtype,
 									&finfo_input,
-									typElem,
+									typioparam,
 									reqtypmod,
 									isnull);
 		}
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 90ed37ada2..92ece7da29 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.46 2004/06/03 22:56:43 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.47 2004/06/06 00:41:28 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -160,7 +160,7 @@ typedef struct
 	int16		typlen;			/* stuff copied from its pg_type entry */
 	bool		typbyval;
 	Oid			typrelid;
-	Oid			typelem;
+	Oid			typioparam;
 	FmgrInfo	typinput;		/* lookup info for typinput function */
 	int32		atttypmod;		/* typmod (taken from someplace else) */
 }	PLpgSQL_type;
@@ -557,7 +557,7 @@ typedef struct PLpgSQL_function
 	int			fn_rettyplen;
 	bool		fn_retbyval;
 	FmgrInfo	fn_retinput;
-	Oid			fn_rettypelem;
+	Oid			fn_rettypioparam;
 	bool		fn_retistuple;
 	bool		fn_retset;
 
diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c
index d07af29c81..2b35954efb 100644
--- a/src/pl/plpython/plpython.c
+++ b/src/pl/plpython/plpython.c
@@ -29,7 +29,7 @@
  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *	$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.48 2004/06/05 19:48:09 tgl Exp $
+ *	$PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.49 2004/06/06 00:41:28 tgl Exp $
  *
  *********************************************************************
  */
@@ -51,6 +51,7 @@
 #include "nodes/makefuncs.h"
 #include "parser/parse_type.h"
 #include "tcop/tcopprot.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 #include "utils/typcache.h"
 
@@ -70,7 +71,7 @@ typedef struct PLyDatumToOb
 {
 	PLyDatumToObFunc func;
 	FmgrInfo	typfunc;
-	Oid			typelem;
+	Oid			typioparam;
 	bool		typbyval;
 }	PLyDatumToOb;
 
@@ -92,7 +93,7 @@ typedef union PLyTypeInput
 typedef struct PLyObToDatum
 {
 	FmgrInfo	typfunc;
-	Oid			typelem;
+	Oid			typioparam;
 	bool		typbyval;
 }	PLyObToDatum;
 
@@ -238,10 +239,10 @@ static void PLy_procedure_delete(PLyProcedure *);
 
 static void PLy_typeinfo_init(PLyTypeInfo *);
 static void PLy_typeinfo_dealloc(PLyTypeInfo *);
-static void PLy_output_datum_func(PLyTypeInfo *, Form_pg_type);
-static void PLy_output_datum_func2(PLyObToDatum *, Form_pg_type);
-static void PLy_input_datum_func(PLyTypeInfo *, Oid, Form_pg_type);
-static void PLy_input_datum_func2(PLyDatumToOb *, Oid, Form_pg_type);
+static void PLy_output_datum_func(PLyTypeInfo *, HeapTuple);
+static void PLy_output_datum_func2(PLyObToDatum *, HeapTuple);
+static void PLy_input_datum_func(PLyTypeInfo *, Oid, HeapTuple);
+static void PLy_input_datum_func2(PLyDatumToOb *, Oid, HeapTuple);
 static void PLy_output_tuple_funcs(PLyTypeInfo *, TupleDesc);
 static void PLy_input_tuple_funcs(PLyTypeInfo *, TupleDesc);
 
@@ -565,7 +566,7 @@ PLy_modify_tuple(PLyProcedure * proc, PyObject * pltd, TriggerData *tdata,
 
 			modvalues[i] = FunctionCall3(&proc->result.out.r.atts[atti].typfunc,
 										 CStringGetDatum(src),
-				 ObjectIdGetDatum(proc->result.out.r.atts[atti].typelem),
+				 ObjectIdGetDatum(proc->result.out.r.atts[atti].typioparam),
 						 Int32GetDatum(tupdesc->attrs[atti]->atttypmod));
 			modnulls[i] = ' ';
 
@@ -850,7 +851,7 @@ PLy_function_handler(FunctionCallInfo fcinfo, PLyProcedure * proc)
 		plrv_sc = PyString_AsString(plrv_so);
 		rv = FunctionCall3(&proc->result.out.d.typfunc,
 						   PointerGetDatum(plrv_sc),
-						   ObjectIdGetDatum(proc->result.out.d.typelem),
+						   ObjectIdGetDatum(proc->result.out.d.typioparam),
 						   Int32GetDatum(-1));
 	}
 
@@ -956,7 +957,7 @@ PLy_function_build_args(FunctionCallInfo fcinfo, PLyProcedure * proc)
 
 				dt = FunctionCall3(&(proc->args[i].in.d.typfunc),
 								   fcinfo->arg[i],
-							ObjectIdGetDatum(proc->args[i].in.d.typelem),
+							ObjectIdGetDatum(proc->args[i].in.d.typioparam),
 								   Int32GetDatum(-1));
 				ct = DatumGetCString(dt);
 				arg = (proc->args[i].in.d.func) (ct);
@@ -1119,7 +1120,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
 
 		rvTypeStruct = (Form_pg_type) GETSTRUCT(rvTypeTup);
 		if (rvTypeStruct->typtype != 'c')
-			PLy_output_datum_func(&proc->result, rvTypeStruct);
+			PLy_output_datum_func(&proc->result, rvTypeTup);
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1160,7 +1161,7 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid,
 		if (argTypeStruct->typtype != 'c')
 			PLy_input_datum_func(&(proc->args[i]),
 								 procStruct->proargtypes[i],
-								 argTypeStruct);
+								 argTypeTup);
 		else
 			proc->args[i].is_rowtype = 2; /* still need to set I/O funcs */
 
@@ -1327,7 +1328,6 @@ PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
 	for (i = 0; i < desc->natts; i++)
 	{
 		HeapTuple	typeTup;
-		Form_pg_type typeStruct;
 
 		if (desc->attrs[i]->attisdropped)
 			continue;
@@ -1338,11 +1338,10 @@ PLy_input_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
 		if (!HeapTupleIsValid(typeTup))
 			elog(ERROR, "cache lookup failed for type %u",
 				 desc->attrs[i]->atttypid);
-		typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
 
 		PLy_input_datum_func2(&(arg->in.r.atts[i]),
 							  desc->attrs[i]->atttypid,
-							  typeStruct);
+							  typeTup);
 
 		ReleaseSysCache(typeTup);
 	}
@@ -1365,7 +1364,6 @@ PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
 	for (i = 0; i < desc->natts; i++)
 	{
 		HeapTuple	typeTup;
-		Form_pg_type typeStruct;
 
 		if (desc->attrs[i]->attisdropped)
 			continue;
@@ -1376,52 +1374,55 @@ PLy_output_tuple_funcs(PLyTypeInfo * arg, TupleDesc desc)
 		if (!HeapTupleIsValid(typeTup))
 			elog(ERROR, "cache lookup failed for type %u",
 				 desc->attrs[i]->atttypid);
-		typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
 
-		PLy_output_datum_func2(&(arg->out.r.atts[i]), typeStruct);
+		PLy_output_datum_func2(&(arg->out.r.atts[i]), typeTup);
 
 		ReleaseSysCache(typeTup);
 	}
 }
 
 void
-PLy_output_datum_func(PLyTypeInfo * arg, Form_pg_type typeStruct)
+PLy_output_datum_func(PLyTypeInfo * arg, HeapTuple typeTup)
 {
 	enter();
 
 	if (arg->is_rowtype > 0)
 		elog(ERROR, "PLyTypeInfo struct is initialized for a Tuple");
 	arg->is_rowtype = 0;
-	PLy_output_datum_func2(&(arg->out.d), typeStruct);
+	PLy_output_datum_func2(&(arg->out.d), typeTup);
 }
 
 void
-PLy_output_datum_func2(PLyObToDatum * arg, Form_pg_type typeStruct)
+PLy_output_datum_func2(PLyObToDatum * arg, HeapTuple typeTup)
 {
+	Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
+
 	enter();
 
 	perm_fmgr_info(typeStruct->typinput, &arg->typfunc);
-	arg->typelem = typeStruct->typelem;
+	arg->typioparam = getTypeIOParam(typeTup);
 	arg->typbyval = typeStruct->typbyval;
 }
 
 void
-PLy_input_datum_func(PLyTypeInfo * arg, Oid typeOid, Form_pg_type typeStruct)
+PLy_input_datum_func(PLyTypeInfo * arg, Oid typeOid, HeapTuple typeTup)
 {
 	enter();
 
 	if (arg->is_rowtype > 0)
 		elog(ERROR, "PLyTypeInfo struct is initialized for Tuple");
 	arg->is_rowtype = 0;
-	PLy_input_datum_func2(&(arg->in.d), typeOid, typeStruct);
+	PLy_input_datum_func2(&(arg->in.d), typeOid, typeTup);
 }
 
 void
-PLy_input_datum_func2(PLyDatumToOb * arg, Oid typeOid, Form_pg_type typeStruct)
+PLy_input_datum_func2(PLyDatumToOb * arg, Oid typeOid, HeapTuple typeTup)
 {
+	Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
+
 	/* Get the type's conversion information */
 	perm_fmgr_info(typeStruct->typoutput, &arg->typfunc);
-	arg->typelem = typeStruct->typelem;
+	arg->typioparam = getTypeIOParam(typeTup);
 	arg->typbyval = typeStruct->typbyval;
 
 	/* Determine which kind of Python object we will convert to */
@@ -1569,7 +1570,7 @@ PLyDict_FromTuple(PLyTypeInfo * info, HeapTuple tuple, TupleDesc desc)
 		{
 			vdat = FunctionCall3(&info->in.r.atts[i].typfunc,
 								 vattr,
-							ObjectIdGetDatum(info->in.r.atts[i].typelem),
+							ObjectIdGetDatum(info->in.r.atts[i].typioparam),
 							   Int32GetDatum(desc->attrs[i]->atttypmod));
 			vsrc = DatumGetCString(vdat);
 
@@ -2027,7 +2028,7 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
 				plan->types[i] = HeapTupleGetOid(typeTup);
 				typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
 				if (typeStruct->typtype != 'c')
-					PLy_output_datum_func(&plan->args[i], typeStruct);
+					PLy_output_datum_func(&plan->args[i], typeTup);
 				else
 				{
 					PyErr_SetString(PLy_exc_spi_error,
@@ -2193,7 +2194,7 @@ PLy_spi_execute_plan(PyObject * ob, PyObject * list, int limit)
 			plan->values[i] =
 				FunctionCall3(&(plan->args[i].out.d.typfunc),
 							  CStringGetDatum(sv),
-							  ObjectIdGetDatum(plan->args[i].out.d.typelem),
+							  ObjectIdGetDatum(plan->args[i].out.d.typioparam),
 							  Int32GetDatum(-1));
 
 			Py_DECREF(so);
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 7d9336eb00..e51e56e6d7 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -31,7 +31,7 @@
  *	  ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.85 2004/05/30 23:40:41 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.86 2004/06/06 00:41:28 tgl Exp $
  *
  **********************************************************************/
 
@@ -51,7 +51,6 @@
 #include "access/heapam.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_proc.h"
-#include "catalog/pg_type.h"
 #include "commands/trigger.h"
 #include "executor/spi.h"
 #include "fmgr.h"
@@ -59,6 +58,7 @@
 #include "parser/parse_type.h"
 #include "tcop/tcopprot.h"
 #include "utils/builtins.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 #include "utils/typcache.h"
 
@@ -105,10 +105,10 @@ typedef struct pltcl_proc_desc
 	CommandId	fn_cmin;
 	bool		lanpltrusted;
 	FmgrInfo	result_in_func;
-	Oid			result_in_elem;
+	Oid			result_typioparam;
 	int			nargs;
 	FmgrInfo	arg_out_func[FUNC_MAX_ARGS];
-	Oid			arg_out_elem[FUNC_MAX_ARGS];
+	Oid			arg_typioparam[FUNC_MAX_ARGS];
 	bool		arg_is_rowtype[FUNC_MAX_ARGS];
 }	pltcl_proc_desc;
 
@@ -123,7 +123,7 @@ typedef struct pltcl_query_desc
 	int			nargs;
 	Oid		   *argtypes;
 	FmgrInfo   *arginfuncs;
-	Oid		   *argtypelems;
+	Oid		   *argtypioparams;
 }	pltcl_query_desc;
 
 
@@ -543,7 +543,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 
 				tmp = DatumGetCString(FunctionCall3(&prodesc->arg_out_func[i],
 													fcinfo->arg[i],
-							  ObjectIdGetDatum(prodesc->arg_out_elem[i]),
+							  ObjectIdGetDatum(prodesc->arg_typioparam[i]),
 													Int32GetDatum(-1)));
 				UTF_BEGIN;
 				Tcl_DStringAppendElement(&tcl_cmd, UTF_E2U(tmp));
@@ -622,7 +622,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS)
 		UTF_BEGIN;
 		retval = FunctionCall3(&prodesc->result_in_func,
 							   PointerGetDatum(UTF_U2E(interp->result)),
-							   ObjectIdGetDatum(prodesc->result_in_elem),
+							   ObjectIdGetDatum(prodesc->result_typioparam),
 							   Int32GetDatum(-1));
 		UTF_END;
 	}
@@ -908,7 +908,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 		int			attnum;
 		HeapTuple	typeTup;
 		Oid			typinput;
-		Oid			typelem;
+		Oid			typioparam;
 		FmgrInfo	finfo;
 
 		/************************************************************
@@ -943,7 +943,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 			elog(ERROR, "cache lookup failed for type %u",
 				 tupdesc->attrs[attnum - 1]->atttypid);
 		typinput = ((Form_pg_type) GETSTRUCT(typeTup))->typinput;
-		typelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
+		typioparam = getTypeIOParam(typeTup);
 		ReleaseSysCache(typeTup);
 
 		/************************************************************
@@ -955,7 +955,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS)
 		modvalues[attnum - 1] =
 			FunctionCall3(&finfo,
 						  CStringGetDatum(UTF_U2E(ret_value)),
-						  ObjectIdGetDatum(typelem),
+						  ObjectIdGetDatum(typioparam),
 				   Int32GetDatum(tupdesc->attrs[attnum - 1]->atttypmod));
 		UTF_END;
 	}
@@ -1150,7 +1150,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid)
 			}
 
 			perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func));
-			prodesc->result_in_elem = typeStruct->typelem;
+			prodesc->result_typioparam = getTypeIOParam(typeTup);
 
 			ReleaseSysCache(typeTup);
 		}
@@ -1198,7 +1198,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid)
 					prodesc->arg_is_rowtype[i] = false;
 					perm_fmgr_info(typeStruct->typoutput,
 								   &(prodesc->arg_out_func[i]));
-					prodesc->arg_out_elem[i] = typeStruct->typelem;
+					prodesc->arg_typioparam[i] = getTypeIOParam(typeTup);
 					snprintf(buf, sizeof(buf), "%d", i + 1);
 				}
 
@@ -1820,7 +1820,7 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
 	qdesc->nargs = nargs;
 	qdesc->argtypes = (Oid *) malloc(nargs * sizeof(Oid));
 	qdesc->arginfuncs = (FmgrInfo *) malloc(nargs * sizeof(FmgrInfo));
-	qdesc->argtypelems = (Oid *) malloc(nargs * sizeof(Oid));
+	qdesc->argtypioparams = (Oid *) malloc(nargs * sizeof(Oid));
 
 	/************************************************************
 	 * Prepare to start a controlled return through all
@@ -1833,7 +1833,7 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
 		pltcl_restart_in_progress = 1;
 		free(qdesc->argtypes);
 		free(qdesc->arginfuncs);
-		free(qdesc->argtypelems);
+		free(qdesc->argtypioparams);
 		free(qdesc);
 		ckfree((char *) args);
 		return TCL_ERROR;
@@ -1865,7 +1865,7 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
 		qdesc->argtypes[i] = HeapTupleGetOid(typeTup);
 		perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,
 					   &(qdesc->arginfuncs[i]));
-		qdesc->argtypelems[i] = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
+		qdesc->argtypioparams[i] = getTypeIOParam(typeTup);
 		ReleaseSysCache(typeTup);
 
 		list_free(typename->names);
@@ -2117,7 +2117,7 @@ pltcl_SPI_execp(ClientData cdata, Tcl_Interp *interp,
 				argvalues[j] =
 					FunctionCall3(&qdesc->arginfuncs[j],
 								  CStringGetDatum(UTF_U2E(callargs[j])),
-								  ObjectIdGetDatum(qdesc->argtypelems[j]),
+								  ObjectIdGetDatum(qdesc->argtypioparams[j]),
 								  Int32GetDatum(-1));
 				UTF_END;
 			}
@@ -2339,7 +2339,7 @@ pltcl_set_tuple_values(Tcl_Interp *interp, CONST84 char *arrayname,
 	CONST84 char *attname;
 	HeapTuple	typeTup;
 	Oid			typoutput;
-	Oid			typelem;
+	Oid			typioparam;
 
 	CONST84 char **arrptr;
 	CONST84 char **nameptr;
@@ -2390,7 +2390,7 @@ pltcl_set_tuple_values(Tcl_Interp *interp, CONST84 char *arrayname,
 				 tupdesc->attrs[i]->atttypid);
 
 		typoutput = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
-		typelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
+		typioparam = getTypeIOParam(typeTup);
 		ReleaseSysCache(typeTup);
 
 		/************************************************************
@@ -2405,7 +2405,7 @@ pltcl_set_tuple_values(Tcl_Interp *interp, CONST84 char *arrayname,
 		{
 			outputstr = DatumGetCString(OidFunctionCall3(typoutput,
 														 attr,
-											   ObjectIdGetDatum(typelem),
+											   ObjectIdGetDatum(typioparam),
 						   Int32GetDatum(tupdesc->attrs[i]->atttypmod)));
 			UTF_BEGIN;
 			Tcl_SetVar2(interp, *arrptr, *nameptr, UTF_E2U(outputstr), 0);
@@ -2434,7 +2434,7 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
 	char	   *attname;
 	HeapTuple	typeTup;
 	Oid			typoutput;
-	Oid			typelem;
+	Oid			typioparam;
 
 	for (i = 0; i < tupdesc->natts; i++)
 	{
@@ -2464,7 +2464,7 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
 				 tupdesc->attrs[i]->atttypid);
 
 		typoutput = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput;
-		typelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem;
+		typioparam = getTypeIOParam(typeTup);
 		ReleaseSysCache(typeTup);
 
 		/************************************************************
@@ -2479,7 +2479,7 @@ pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
 		{
 			outputstr = DatumGetCString(OidFunctionCall3(typoutput,
 														 attr,
-											   ObjectIdGetDatum(typelem),
+											   ObjectIdGetDatum(typioparam),
 						   Int32GetDatum(tupdesc->attrs[i]->atttypmod)));
 			Tcl_DStringAppendElement(retval, attname);
 			UTF_BEGIN;