From 45d04099df76c00d93479b2617fb9975807fdb43 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 8 May 2003 22:19:58 +0000
Subject: [PATCH] Reinstate pg_type's typsend and typreceive columns.  They
 don't do much yet, but they're there.  Also some editorial work on CREATE
 TYPE reference page.

---
 doc/src/sgml/catalogs.sgml                |  37 ++-
 doc/src/sgml/ref/create_type.sgml         | 238 +++++++++++-------
 src/backend/catalog/heap.c                |   4 +-
 src/backend/catalog/pg_type.c             |  30 ++-
 src/backend/commands/typecmds.c           | 280 ++++++++++++++--------
 src/backend/utils/adt/arrayfuncs.c        |  30 ++-
 src/backend/utils/adt/pseudotypes.c       |  24 +-
 src/bin/pg_dump/pg_dump.c                 |  76 +++++-
 src/include/catalog/catversion.h          |   4 +-
 src/include/catalog/pg_attribute.h        |  38 +--
 src/include/catalog/pg_class.h            |   4 +-
 src/include/catalog/pg_proc.h             |  16 +-
 src/include/catalog/pg_type.h             | 266 ++++++++++----------
 src/include/utils/array.h                 |   4 +-
 src/include/utils/builtins.h              |   4 +-
 src/test/regress/expected/oidjoins.out    |  16 ++
 src/test/regress/expected/type_sanity.out |  47 ++++
 src/test/regress/sql/oidjoins.sql         |   8 +
 src/test/regress/sql/type_sanity.sql      |  34 +++
 19 files changed, 794 insertions(+), 366 deletions(-)

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index e70cee4506f..0cc355330dd 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,6 +1,6 @@
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
- $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.69 2003/04/15 13:23:35 petere Exp $
+ $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.70 2003/05/08 22:19:55 tgl Exp $
  -->
 
 <chapter id="catalogs">
@@ -3315,9 +3315,9 @@
   <para>
    The catalog <structname>pg_type</structname> stores information about data types.  Base types
    (scalar types) are created with <command>CREATE TYPE</command>.
-   A complex type is automatically created for each table in the database, to
+   A composite type is automatically created for each table in the database, to
    represent the row structure of the table.  It is also possible to create
-   complex types with <command>CREATE TYPE AS</command> and
+   composite types with <command>CREATE TYPE AS</command> and
    derived types with <command>CREATE DOMAIN</command>.
   </para>
 
@@ -3378,12 +3378,9 @@
       <entry>
        <structfield>typbyval</structfield> determines whether internal
        routines pass a value of this type by value or by reference.
-       Only <type>char</type>, <type>short</type>, and
-       <type>int</type> equivalent items can be passed by value, so if
-       the type is not 1, 2, or 4 bytes long,
-       <productname>PostgreSQL</> does not have
-       the option of passing by value and so
-       <structfield>typbyval</structfield> had better be false.
+       <structfield>typbyval</structfield> had better be false if
+       <structfield>typlen</structfield> is not 1, 2, or 4 (or 8 on machines
+       where Datum is 8 bytes).
        Variable-length types are always passed by reference. Note that
        <structfield>typbyval</structfield> can be false even if the
        length would allow pass-by-value; this is currently true for
@@ -3397,7 +3394,7 @@
       <entry></entry>
       <entry>
        <structfield>typtype</structfield> is <literal>b</literal> for
-       a base type, <literal>c</literal> for a complex type (i.e.,
+       a base type, <literal>c</literal> for a composite type (i.e.,
        a table's row type), <literal>d</literal> for a derived type (i.e.,
        a domain), or <literal>p</literal> for a pseudo-type.  See also
        <structfield>typrelid</structfield>
@@ -3431,7 +3428,7 @@
       <entry><type>oid</type></entry>
       <entry><literal>pg_class.oid</literal></entry>
       <entry>
-       If this is a complex type (see
+       If this is a composite type (see
        <structfield>typtype</structfield>), then this column points to
        the <structname>pg_class</structname> entry that defines the
        corresponding table.  (For a free-standing composite type, the
@@ -3468,14 +3465,28 @@
       <entry><structfield>typinput</structfield></entry>
       <entry><type>regproc</type></entry>
       <entry><literal>pg_proc.oid</literal></entry>
-      <entry>Input conversion function</entry>
+      <entry>Input conversion function (text format)</entry>
      </row>
 
      <row>
       <entry><structfield>typoutput</structfield></entry>
       <entry><type>regproc</type></entry>
       <entry><literal>pg_proc.oid</literal></entry>
-      <entry>Output conversion function</entry>
+      <entry>Output conversion function (text format)</entry>
+     </row>
+
+     <row>
+      <entry><structfield>typreceive</structfield></entry>
+      <entry><type>regproc</type></entry>
+      <entry><literal>pg_proc.oid</literal></entry>
+      <entry>Input conversion function (binary format), or 0 if none</entry>
+     </row>
+
+     <row>
+      <entry><structfield>typsend</structfield></entry>
+      <entry><type>regproc</type></entry>
+      <entry><literal>pg_proc.oid</literal></entry>
+      <entry>Output conversion function (binary format), or 0 if none</entry>
      </row>
 
      <row>
diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml
index 70a4a6cb808..5fe4d2be4fc 100644
--- a/doc/src/sgml/ref/create_type.sgml
+++ b/doc/src/sgml/ref/create_type.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v 1.41 2003/04/22 10:08:08 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_type.sgml,v 1.42 2003/05/08 22:19:56 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -16,18 +16,22 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
+CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
+    ( <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [, ... ] )
+
 CREATE TYPE <replaceable class="parameter">typename</replaceable> (
-    INPUT = <replaceable class="parameter">input_function</replaceable>, OUTPUT = <replaceable class="parameter">output_function</replaceable>
-      , INTERNALLENGTH = { <replaceable class="parameter">internallength</replaceable> | VARIABLE }
-    [ , DEFAULT = <replaceable class="parameter">default</replaceable> ]
-    [ , ELEMENT = <replaceable class="parameter">element</replaceable> ] [ , DELIMITER = <replaceable class="parameter">delimiter</replaceable> ]
+    INPUT = <replaceable class="parameter">input_function</replaceable>,
+    OUTPUT = <replaceable class="parameter">output_function</replaceable>
+    [ , RECEIVE = <replaceable class="parameter">receive_function</replaceable> ]
+    [ , SEND = <replaceable class="parameter">send_function</replaceable> ]
+    [ , INTERNALLENGTH = { <replaceable class="parameter">internallength</replaceable> | VARIABLE } ]
     [ , PASSEDBYVALUE ]
     [ , ALIGNMENT = <replaceable class="parameter">alignment</replaceable> ]
     [ , STORAGE = <replaceable class="parameter">storage</replaceable> ]
+    [ , DEFAULT = <replaceable class="parameter">default</replaceable> ]
+    [ , ELEMENT = <replaceable class="parameter">element</replaceable> ]
+    [ , DELIMITER = <replaceable class="parameter">delimiter</replaceable> ]
 )
-
-CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
-    ( <replaceable class="PARAMETER">attribute_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [, ... ] )
 </synopsis>
  </refsynopsisdiv>
 
@@ -49,18 +53,42 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
    table in the same schema.)
   </para>
 
+  <refsect2>
+   <title>Composite Types</title>
+
+  <para>
+   The first form of <command>CREATE TYPE</command>
+   creates a composite type.
+   The composite type is specified by a list of attribute names and data types.
+   This is essentially the same as the row type
+   of a table, but using <command>CREATE TYPE</command> avoids the need to
+   create an actual table when all that is wanted is to define a type.
+   A stand-alone composite type is useful as the return type of a function.
+  </para>
+  </refsect2>
+
   <refsect2>
    <title>Base Types</title>
 
   <para>
-   The first form of <command>CREATE TYPE</command> creates a new base type
-   (scalar type).  It  requires  the
-   registration of two functions (using <command>CREATE
-   FUNCTION</command>) before defining the
-   type. The internal representation of the new base type is determined by
-   <replaceable class="parameter">input_function</replaceable>, which
-   converts the type's external  representation to an internal
-   representation  usable by the
+   The second form of <command>CREATE TYPE</command> creates a new base type
+   (scalar type).  The parameters may appear in any order, not only that
+   illustrated above, and most are optional.  You must register
+   two or more functions (using <command>CREATE FUNCTION</command>) before
+   defining the type.  The support functions 
+   <replaceable class="parameter">input_function</replaceable> and
+   <replaceable class="parameter">output_function</replaceable>
+   are required, while the functions
+   <replaceable class="parameter">receive_function</replaceable> and
+   <replaceable class="parameter">send_function</replaceable>
+   are optional.  Generally these functions have to be coded in C
+   or another low-level language.
+  </para>
+
+  <para>
+   The <replaceable class="parameter">input_function</replaceable>
+   converts the type's external textual representation to the internal
+   representation  used by the
    operators and functions defined for the type.
    <replaceable class="parameter">output_function</replaceable>
    performs the reverse transformation.  The input function may be
@@ -70,7 +98,7 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
    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,
    and the third is the <literal>typmod</> of the destination column, if known.
-   It should return a value of the data type itself.
+   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>.
@@ -78,22 +106,50 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
    The output function should return type <type>cstring</type>.
   </para>
 
+  <para>
+   The optional <replaceable class="parameter">receive_function</replaceable>
+   converts the type's external binary representation to the internal
+   representation.  If this function is not supplied, the type cannot
+   participate in binary input.  The binary representation should be
+   chosen to be cheap to convert to internal form, while being reasonably
+   portable.  (For example, the standard integer datatypes use network
+   byte order as the external binary representation, while the internal
+   representation is in the machine's native byte order.)  The receive
+   function should perform adequate checking to ensure that the value is
+   valid.
+   The receive function should be declared as taking one argument of type
+   <type>internal</type> and returning a value of the data type itself.
+   (The argument actually supplied is a pointer to a StringInfo buffer
+   holding the received byte string.)  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 should be declared as taking one argument of the
+   new data type and returning type <type>bytea</type>.
+  </para>
+
   <para>
    You should at this point be wondering how the input and output functions
    can be declared to have results or arguments of the new type, when they have
    to be created before the new type can be created.  The answer is that the
-   input function must be created first, then the output function, then the
-   data type.
+   input function must be created first, then the output function (and
+   the binary I/O functions if wanted), and finally the data type.
    <productname>PostgreSQL</productname> will first see the name of the new
    data type as the return type of the input function.  It will create a
    <quote>shell</> type, which is simply a placeholder entry in
    the system catalog, and link the input function definition to the shell
-   type.  Similarly the output function will be linked to the (now already
+   type.  Similarly the other functions will be linked to the (now already
    existing) shell type.  Finally, <command>CREATE TYPE</> replaces the
    shell entry with a complete type definition, and the new type can be used.
   </para>
 
   <para>
+   While the details of the new type's internal representation are only
+   known to the I/O functions and other functions you create to work with
+   the type, there are several properties of the internal representation
+   that must be declared to <productname>PostgreSQL</productname>.
+   Foremost of these is
+   <replaceable class="parameter">internallength</replaceable>.
    Base data types can be fixed-length, in which case
    <replaceable class="parameter">internallength</replaceable> is a
    positive integer, or variable  length, indicated by setting
@@ -104,34 +160,9 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
    length of this value of the type.
   </para>
 
-  <para>
-   To indicate that a type is an array, specify the type of the array
-   elements using the <literal>ELEMENT</> key word.  For example, to
-   define an array of 4-byte integers (<type>int4</type>), specify
-   <literal>ELEMENT = int4</literal> More details about array types
-   appear below.
-  </para>
-
-  <para>
-   To indicate the delimiter to be used between values in the external
-   representation of arrays of this type, <replaceable
-   class="parameter">delimiter</replaceable> can be
-   set to a specific character.  The default delimiter is the comma
-   (<literal>,</literal>).  Note that the delimiter is associated
-   with the array element type, not the array type itself.
-  </para>
-
-  <para>
-   A default value may be specified, in case a user wants columns of the
-   data type to default to something other than the null value.
-   Specify the default with the <literal>DEFAULT</literal> key word.
-   (Such a default may be overridden by an explicit <literal>DEFAULT</literal>
-   clause attached to a particular column.)
-  </para>
-
   <para>
    The optional flag <literal>PASSEDBYVALUE</literal> indicates that
-   values of this data type are passed by value rather than by
+   values of this data type are passed by value, rather than by
    reference.  You may not pass by value types whose internal
    representation is larger than the size of the <type>Datum</> type
    (4 bytes on most machines, 8 bytes on a few).
@@ -163,20 +194,32 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
    table preferentially over <literal>extended</literal> and
    <literal>external</literal> items.)
   </para>
-  </refsect2>
 
-  <refsect2>
-   <title>Composite Types</title>
+  <para>
+   A default value may be specified, in case a user wants columns of the
+   data type to default to something other than the null value.
+   Specify the default with the <literal>DEFAULT</literal> key word.
+   (Such a default may be overridden by an explicit <literal>DEFAULT</literal>
+   clause attached to a particular column.)
+  </para>
 
   <para>
-   The second form of <command>CREATE TYPE</command>
-   creates a composite type.
-   The composite type is specified by a list of attribute names and data types.
-   This is essentially the same as the row type
-   of a table, but using <command>CREATE TYPE</command> avoids the need to
-   create an actual table when all that is wanted is to define a type.
-   A stand-alone composite type is useful as the return type of a function.
+   To indicate that a type is an array, specify the type of the array
+   elements using the <literal>ELEMENT</> key word.  For example, to
+   define an array of 4-byte integers (<type>int4</type>), specify
+   <literal>ELEMENT = int4</literal>. More details about array types
+   appear below.
+  </para>
+
+  <para>
+   To indicate the delimiter to be used between values in the external
+   representation of arrays of this type, <replaceable
+   class="parameter">delimiter</replaceable> can be
+   set to a specific character.  The default delimiter is the comma
+   (<literal>,</literal>).  Note that the delimiter is associated
+   with the array element type, not the array type itself.
   </para>
+
   </refsect2>
 
   <refsect2>
@@ -218,7 +261,7 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
  </refsect1>
   
  <refsect1>
-  <title>Parameter</title>
+  <title>Parameters</title>
 
   <variablelist>
    <varlistentry>
@@ -231,11 +274,20 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">internallength</replaceable></term>
+    <term><replaceable class="parameter">attribute_name</replaceable></term>
     <listitem>
      <para>
-      A numeric constant that specifies the internal length of the new
-      type.
+      The name of an attribute (column) for the composite type.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="parameter">data_type</replaceable></term>
+    <listitem>
+     <para>
+      The name of an existing data type to become a column of the
+      composite type.
      </para>
     </listitem>
    </varlistentry>
@@ -245,7 +297,7 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
     <listitem>
      <para>
       The name of a function that converts data from the type's
-      external form to the its internal form.
+      external textual form to its internal form.
      </para>
     </listitem>
    </varlistentry>
@@ -255,37 +307,38 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
     <listitem>
      <para>
       The name of a function that converts data from the type's
-      internal form to a form suitable for display.
+      internal form to its external textual form.
      </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">element</replaceable></term>
+    <term><replaceable class="parameter">receive_function</replaceable></term>
     <listitem>
      <para>
-      The type being created is an array; this specifies the type of
-      the array elements.
+      The name of a function that converts data from the type's
+      external binary form to its internal form.
      </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">delimiter</replaceable></term>
+    <term><replaceable class="parameter">send_function</replaceable></term>
     <listitem>
      <para>
-      The delimiter character to be used between values in arrays made
-      of this type.
+      The name of a function that converts data from the type's
+      internal form to its external binary form.
      </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">default</replaceable></term>
+    <term><replaceable class="parameter">internallength</replaceable></term>
     <listitem>
      <para>
-      The default value for the data type.  If this is omitted, the
-      default is null.
+      A numeric constant that specifies the length in bytes of the new
+      type's internal representation.  The default assumption is that
+      it is variable-length.
      </para>
     </listitem>
    </varlistentry>
@@ -306,7 +359,7 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
     <term><replaceable class="parameter">storage</replaceable></term>
     <listitem>
      <para>
-      The storage strateg for the data type.  If specified, must be
+      The storage strategy for the data type.  If specified, must be
       <literal>plain</literal>, <literal>external</literal>,
       <literal>extended</literal>, or <literal>main</literal>; the
       default is <literal>plain</literal>.
@@ -315,19 +368,31 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">attribute_name</replaceable></term>
+    <term><replaceable class="parameter">default</replaceable></term>
     <listitem>
      <para>
-      The name of an attribute of the composite type.
+      The default value for the data type.  If this is omitted, the
+      default is null.
      </para>
     </listitem>
    </varlistentry>
 
    <varlistentry>
-    <term><replaceable class="parameter">data_type</replaceable></term>
+    <term><replaceable class="parameter">element</replaceable></term>
     <listitem>
      <para>
-      The name of an existing data type.
+      The type being created is an array; this specifies the type of
+      the array elements.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><replaceable class="parameter">delimiter</replaceable></term>
+    <listitem>
+     <para>
+      The delimiter character to be used between values in arrays made
+      of this type.
      </para>
     </listitem>
    </varlistentry>
@@ -378,7 +443,17 @@ CREATE TYPE <replaceable class="parameter">typename</replaceable> AS
   <title>Examples</title>
 
   <para>
-   This example creates the data type <type>box</type> and then uses the
+   This example creates a composite type and uses it in
+   a function definition:
+<programlisting>
+CREATE TYPE compfoo AS (f1 int, f2 text);
+CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS
+  'SELECT fooid, fooname FROM foo' LANGUAGE SQL;
+</programlisting>
+  </para>
+
+  <para>
+   This example creates the base data type <type>box</type> and then uses the
    type in a table definition:
 <programlisting>
 CREATE TYPE box (
@@ -424,15 +499,6 @@ CREATE TABLE big_objs (
 </programlisting>
   </para>
 
-  <para>
-   This example creates a composite type and uses it in
-   a function definition:
-<programlisting>
-CREATE TYPE compfoo AS (f1 int, f2 text);
-CREATE FUNCTION getfoo() RETURNS SETOF compfoo AS 'SELECT fooid, fooname FROM foo' LANGUAGE SQL;
-</programlisting>
-  </para>
-
   <para>
    More examples, including suitable input and output functions, are
    in <xref linkend="extend">.
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 5a6ec98e1b8..ea70765d432 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.242 2003/04/29 22:13:08 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.243 2003/05/08 22:19:56 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -675,6 +675,8 @@ AddNewRelationType(const char *typeName,
 			   ',',				/* default array delimiter */
 			   F_RECORD_IN,		/* input procedure */
 			   F_RECORD_OUT,	/* output procedure */
+			   F_RECORD_RECV,	/* receive procedure */
+			   F_RECORD_SEND,	/* send procedure */
 			   InvalidOid,		/* array element type - irrelevant */
 			   InvalidOid,		/* domain base type - irrelevant */
 			   NULL,			/* default type value - none */
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 66b6788eeef..90ad20f2d54 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.86 2003/01/08 21:40:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.87 2003/05/08 22:19:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -84,6 +84,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
 	values[i++] = ObjectIdGetDatum(InvalidOid); /* typelem */
 	values[i++] = ObjectIdGetDatum(InvalidOid); /* typinput */
 	values[i++] = ObjectIdGetDatum(InvalidOid); /* typoutput */
+	values[i++] = ObjectIdGetDatum(InvalidOid); /* typreceive */
+	values[i++] = ObjectIdGetDatum(InvalidOid); /* typsend */
 	values[i++] = CharGetDatum('i');	/* typalign */
 	values[i++] = CharGetDatum('p');	/* typstorage */
 	values[i++] = BoolGetDatum(false);	/* typnotnull */
@@ -117,6 +119,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
 								 InvalidOid,
 								 InvalidOid,
 								 InvalidOid,
+								 InvalidOid,
+								 InvalidOid,
 								 NULL,
 								 false);
 
@@ -151,6 +155,8 @@ TypeCreate(const char *typeName,
 		   char typDelim,
 		   Oid inputProcedure,
 		   Oid outputProcedure,
+		   Oid receiveProcedure,
+		   Oid sendProcedure,
 		   Oid elementType,
 		   Oid baseType,
 		   const char *defaultTypeValue,		/* human readable rep */
@@ -222,6 +228,8 @@ TypeCreate(const char *typeName,
 	values[i++] = ObjectIdGetDatum(elementType);		/* typelem */
 	values[i++] = ObjectIdGetDatum(inputProcedure);		/* typinput */
 	values[i++] = ObjectIdGetDatum(outputProcedure);	/* typoutput */
+	values[i++] = ObjectIdGetDatum(receiveProcedure);	/* typreceive */
+	values[i++] = ObjectIdGetDatum(sendProcedure);		/* typsend */
 	values[i++] = CharGetDatum(alignment);		/* typalign */
 	values[i++] = CharGetDatum(storage);		/* typstorage */
 	values[i++] = BoolGetDatum(typeNotNull);	/* typnotnull */
@@ -314,6 +322,8 @@ TypeCreate(const char *typeName,
 								 relationKind,
 								 inputProcedure,
 								 outputProcedure,
+								 receiveProcedure,
+								 sendProcedure,
 								 elementType,
 								 baseType,
 								 (defaultTypeBin ?
@@ -345,6 +355,8 @@ GenerateTypeDependencies(Oid typeNamespace,
 						 char relationKind,		/* ditto */
 						 Oid inputProcedure,
 						 Oid outputProcedure,
+						 Oid receiveProcedure,
+						 Oid sendProcedure,
 						 Oid elementType,
 						 Oid baseType,
 						 Node *defaultExpr,
@@ -388,6 +400,22 @@ GenerateTypeDependencies(Oid typeNamespace,
 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 	}
 
+	if (OidIsValid(receiveProcedure))
+	{
+		referenced.classId = RelOid_pg_proc;
+		referenced.objectId = receiveProcedure;
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	}
+
+	if (OidIsValid(sendProcedure))
+	{
+		referenced.classId = RelOid_pg_proc;
+		referenced.objectId = sendProcedure;
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+	}
+
 	/*
 	 * If the type is a rowtype for a relation, mark it as internally
 	 * dependent on the relation, *unless* it is a stand-alone
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 0523878f2a7..f7bf3d3ee87 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.34 2003/04/29 22:13:08 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.35 2003/05/08 22:19:56 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -20,7 +20,7 @@
  * NOTES
  *	  These things must be defined and committed in the following order:
  *		"create function":
- *				input/output functions
+ *				input/output, recv/send functions
  *		"create type":
  *				type
  *		"create operator":
@@ -73,7 +73,10 @@ typedef struct
 } RelToCheck;
 
 
-static Oid	findTypeIOFunction(List *procname, Oid typeOid, bool isOutput);
+static Oid	findTypeInputFunction(List *procname, Oid typeOid);
+static Oid	findTypeOutputFunction(List *procname, Oid typeOid);
+static Oid	findTypeReceiveFunction(List *procname, Oid typeOid);
+static Oid	findTypeSendFunction(List *procname, Oid typeOid);
 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
 static void domainOwnerCheck(HeapTuple tup, TypeName *typename);
 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
@@ -92,17 +95,21 @@ DefineType(List *names, List *parameters)
 	char	   *typeName;
 	Oid			typeNamespace;
 	AclResult	aclresult;
-	int16		internalLength = -1;	/* int2 */
+	int16		internalLength = -1;	/* default: variable-length */
 	Oid			elemType = InvalidOid;
 	List	   *inputName = NIL;
 	List	   *outputName = NIL;
+	List	   *receiveName = NIL;
+	List	   *sendName = NIL;
 	char	   *defaultValue = NULL;
 	bool		byValue = false;
 	char		delimiter = DEFAULT_TYPDELIM;
 	char		alignment = 'i';	/* default alignment */
-	char		storage = 'p';	/* default TOAST storage method */
+	char		storage = 'p';		/* default TOAST storage method */
 	Oid			inputOid;
 	Oid			outputOid;
+	Oid			receiveOid = InvalidOid;
+	Oid			sendOid = InvalidOid;
 	char	   *shadow_type;
 	List	   *pl;
 	Oid			typoid;
@@ -137,10 +144,10 @@ DefineType(List *names, List *parameters)
 			inputName = defGetQualifiedName(defel);
 		else if (strcasecmp(defel->defname, "output") == 0)
 			outputName = defGetQualifiedName(defel);
-		else if (strcasecmp(defel->defname, "send") == 0)
-			;					/* ignored -- remove after 7.3 */
 		else if (strcasecmp(defel->defname, "receive") == 0)
-			;					/* ignored -- remove after 7.3 */
+			receiveName = defGetQualifiedName(defel);
+		else if (strcasecmp(defel->defname, "send") == 0)
+			sendName = defGetQualifiedName(defel);
 		else if (strcasecmp(defel->defname, "delimiter") == 0)
 		{
 			char	   *p = defGetString(defel);
@@ -236,8 +243,12 @@ DefineType(List *names, List *parameters)
 	/*
 	 * Convert I/O proc names to OIDs
 	 */
-	inputOid = findTypeIOFunction(inputName, typoid, false);
-	outputOid = findTypeIOFunction(outputName, typoid, true);
+	inputOid = findTypeInputFunction(inputName, typoid);
+	outputOid = findTypeOutputFunction(outputName, typoid);
+	if (receiveName)
+		receiveOid = findTypeReceiveFunction(receiveName, typoid);
+	if (sendName)
+		sendOid = findTypeSendFunction(sendName, typoid);
 
 	/*
 	 * Verify that I/O procs return the expected thing.  If we see OPAQUE,
@@ -269,6 +280,20 @@ DefineType(List *names, List *parameters)
 			elog(ERROR, "Type output function %s must return cstring",
 				 NameListToString(outputName));
 	}
+	if (receiveOid)
+	{
+		resulttype = get_func_rettype(receiveOid);
+		if (resulttype != typoid)
+			elog(ERROR, "Type receive function %s must return %s",
+				 NameListToString(receiveName), typeName);
+	}
+	if (sendOid)
+	{
+		resulttype = get_func_rettype(sendOid);
+		if (resulttype != BYTEAOID)
+			elog(ERROR, "Type send function %s must return bytea",
+				 NameListToString(sendName));
+	}
 
 	/*
 	 * now have TypeCreate do all the real work.
@@ -284,6 +309,8 @@ DefineType(List *names, List *parameters)
 				   delimiter,	/* array element delimiter */
 				   inputOid,	/* input procedure */
 				   outputOid,	/* output procedure */
+				   receiveOid,	/* receive procedure */
+				   sendOid,		/* send procedure */
 				   elemType,	/* element type ID */
 				   InvalidOid,	/* base type ID (only for domains) */
 				   defaultValue,	/* default type value */
@@ -314,6 +341,8 @@ DefineType(List *names, List *parameters)
 			   DEFAULT_TYPDELIM,	/* array element delimiter */
 			   F_ARRAY_IN,		/* input procedure */
 			   F_ARRAY_OUT,		/* output procedure */
+			   F_ARRAY_RECV,	/* receive procedure */
+			   F_ARRAY_SEND,	/* send procedure */
 			   typoid,			/* element type ID */
 			   InvalidOid,		/* base type ID */
 			   NULL,			/* never a default type value */
@@ -418,6 +447,8 @@ DefineDomain(CreateDomainStmt *stmt)
 	int16		internalLength;
 	Oid			inputProcedure;
 	Oid			outputProcedure;
+	Oid			receiveProcedure;
+	Oid			sendProcedure;
 	bool		byValue;
 	char		delimiter;
 	char		alignment;
@@ -495,6 +526,8 @@ DefineDomain(CreateDomainStmt *stmt)
 	/* I/O Functions */
 	inputProcedure = baseType->typinput;
 	outputProcedure = baseType->typoutput;
+	receiveProcedure = baseType->typreceive;
+	sendProcedure = baseType->typsend;
 
 	/* Inherited default value */
 	datum = SysCacheGetAttr(TYPEOID, typeTup,
@@ -628,6 +661,8 @@ DefineDomain(CreateDomainStmt *stmt)
 				   delimiter,	/* array element delimiter */
 				   inputProcedure,		/* input procedure */
 				   outputProcedure,		/* output procedure */
+				   receiveProcedure,	/* receive procedure */
+				   sendProcedure,		/* send procedure */
 				   basetypelem, /* element type ID */
 				   basetypeoid, /* base type ID */
 				   defaultValue,	/* default type value (text) */
@@ -731,135 +766,184 @@ RemoveDomain(List *names, DropBehavior behavior)
 
 
 /*
- * Find a suitable I/O function for a type.
+ * Find suitable I/O functions for a type.
  *
  * typeOid is the type's OID (which will already exist, if only as a shell
  * type).
  */
+
 static Oid
-findTypeIOFunction(List *procname, Oid typeOid, bool isOutput)
+findTypeInputFunction(List *procname, Oid typeOid)
 {
 	Oid			argList[FUNC_MAX_ARGS];
 	Oid			procOid;
 
-	if (isOutput)
+	/*
+	 * Input functions can take a single argument of type CSTRING, or
+	 * three arguments (string, element OID, typmod).
+	 *
+	 * For backwards compatibility we allow OPAQUE in place of CSTRING;
+	 * if we see this, we issue a NOTICE and fix up the pg_proc entry.
+	 */
+	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
+
+	argList[0] = CSTRINGOID;
+
+	procOid = LookupFuncName(procname, 1, argList);
+	if (OidIsValid(procOid))
+		return procOid;
+
+	argList[1] = OIDOID;
+	argList[2] = INT4OID;
+
+	procOid = LookupFuncName(procname, 3, argList);
+	if (OidIsValid(procOid))
+		return procOid;
+
+	/* No luck, try it with OPAQUE */
+	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
+
+	argList[0] = OPAQUEOID;
+
+	procOid = LookupFuncName(procname, 1, argList);
+
+	if (!OidIsValid(procOid))
+	{
+		argList[1] = OIDOID;
+		argList[2] = INT4OID;
+
+		procOid = LookupFuncName(procname, 3, argList);
+	}
+
+	if (OidIsValid(procOid))
 	{
+		/* Found, but must complain and fix the pg_proc entry */
+		elog(NOTICE, "TypeCreate: changing argument type of function %s "
+			 "from OPAQUE to CSTRING",
+			 NameListToString(procname));
+		SetFunctionArgType(procOid, 0, CSTRINGOID);
 		/*
-		 * Output functions can take a single argument of the type, or two
-		 * arguments (data value, element OID).
-		 *
-		 * For backwards compatibility we allow OPAQUE in place of the actual
-		 * type name; if we see this, we issue a NOTICE and fix up the
-		 * pg_proc entry.
+		 * Need CommandCounterIncrement since DefineType will likely
+		 * try to alter the pg_proc tuple again.
 		 */
-		MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
+		CommandCounterIncrement();
 
-		argList[0] = typeOid;
+		return procOid;
+	}
 
-		procOid = LookupFuncName(procname, 1, argList);
-		if (OidIsValid(procOid))
-			return procOid;
+	/* Use CSTRING (preferred) in the error message */
+	argList[0] = CSTRINGOID;
 
-		argList[1] = OIDOID;
+	func_error("TypeCreate", procname, 1, argList, NULL);
 
-		procOid = LookupFuncName(procname, 2, argList);
-		if (OidIsValid(procOid))
-			return procOid;
+	return InvalidOid;			/* keep compiler quiet */
+}
 
-		/* No luck, try it with OPAQUE */
-		MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
+static Oid
+findTypeOutputFunction(List *procname, Oid typeOid)
+{
+	Oid			argList[FUNC_MAX_ARGS];
+	Oid			procOid;
 
-		argList[0] = OPAQUEOID;
+	/*
+	 * Output functions can take a single argument of the type, or two
+	 * arguments (data value, element OID).
+	 *
+	 * For backwards compatibility we allow OPAQUE in place of the actual
+	 * type name; if we see this, we issue a NOTICE and fix up the
+	 * pg_proc entry.
+	 */
+	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
 
-		procOid = LookupFuncName(procname, 1, argList);
+	argList[0] = typeOid;
 
-		if (!OidIsValid(procOid))
-		{
-			argList[1] = OIDOID;
+	procOid = LookupFuncName(procname, 1, argList);
+	if (OidIsValid(procOid))
+		return procOid;
 
-			procOid = LookupFuncName(procname, 2, argList);
-		}
+	argList[1] = OIDOID;
 
-		if (OidIsValid(procOid))
-		{
-			/* Found, but must complain and fix the pg_proc entry */
-			elog(NOTICE, "TypeCreate: changing argument type of function %s from OPAQUE to %s",
-				 NameListToString(procname), format_type_be(typeOid));
-			SetFunctionArgType(procOid, 0, typeOid);
-			/*
-			 * Need CommandCounterIncrement since DefineType will likely
-			 * try to alter the pg_proc tuple again.
-			 */
-			CommandCounterIncrement();
+	procOid = LookupFuncName(procname, 2, argList);
+	if (OidIsValid(procOid))
+		return procOid;
 
-			return procOid;
-		}
+	/* No luck, try it with OPAQUE */
+	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
+
+	argList[0] = OPAQUEOID;
 
-		/* Use type name, not OPAQUE, in the failure message. */
-		argList[0] = typeOid;
+	procOid = LookupFuncName(procname, 1, argList);
 
-		func_error("TypeCreate", procname, 1, argList, NULL);
+	if (!OidIsValid(procOid))
+	{
+		argList[1] = OIDOID;
+
+		procOid = LookupFuncName(procname, 2, argList);
 	}
-	else
+
+	if (OidIsValid(procOid))
 	{
+		/* Found, but must complain and fix the pg_proc entry */
+		elog(NOTICE, "TypeCreate: changing argument type of function %s from OPAQUE to %s",
+			 NameListToString(procname), format_type_be(typeOid));
+		SetFunctionArgType(procOid, 0, typeOid);
 		/*
-		 * Input functions can take a single argument of type CSTRING, or
-		 * three arguments (string, element OID, typmod).
-		 *
-		 * For backwards compatibility we allow OPAQUE in place of CSTRING;
-		 * if we see this, we issue a NOTICE and fix up the pg_proc entry.
+		 * Need CommandCounterIncrement since DefineType will likely
+		 * try to alter the pg_proc tuple again.
 		 */
-		MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
+		CommandCounterIncrement();
 
-		argList[0] = CSTRINGOID;
+		return procOid;
+	}
 
-		procOid = LookupFuncName(procname, 1, argList);
-		if (OidIsValid(procOid))
-			return procOid;
+	/* Use type name, not OPAQUE, in the failure message. */
+	argList[0] = typeOid;
 
-		argList[1] = OIDOID;
-		argList[2] = INT4OID;
+	func_error("TypeCreate", procname, 1, argList, NULL);
 
-		procOid = LookupFuncName(procname, 3, argList);
-		if (OidIsValid(procOid))
-			return procOid;
+	return InvalidOid;			/* keep compiler quiet */
+}
 
-		/* No luck, try it with OPAQUE */
-		MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
+static Oid
+findTypeReceiveFunction(List *procname, Oid typeOid)
+{
+	Oid			argList[FUNC_MAX_ARGS];
+	Oid			procOid;
 
-		argList[0] = OPAQUEOID;
+	/*
+	 * Receive functions take a single argument of type INTERNAL.
+	 */
+	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
 
-		procOid = LookupFuncName(procname, 1, argList);
+	argList[0] = INTERNALOID;
 
-		if (!OidIsValid(procOid))
-		{
-			argList[1] = OIDOID;
-			argList[2] = INT4OID;
+	procOid = LookupFuncName(procname, 1, argList);
+	if (OidIsValid(procOid))
+		return procOid;
 
-			procOid = LookupFuncName(procname, 3, argList);
-		}
+	func_error("TypeCreate", procname, 1, argList, NULL);
 
-		if (OidIsValid(procOid))
-		{
-			/* Found, but must complain and fix the pg_proc entry */
-			elog(NOTICE, "TypeCreate: changing argument type of function %s "
-				 "from OPAQUE to CSTRING",
-				 NameListToString(procname));
-			SetFunctionArgType(procOid, 0, CSTRINGOID);
-			/*
-			 * Need CommandCounterIncrement since DefineType will likely
-			 * try to alter the pg_proc tuple again.
-			 */
-			CommandCounterIncrement();
+	return InvalidOid;			/* keep compiler quiet */
+}
 
-			return procOid;
-		}
+static Oid
+findTypeSendFunction(List *procname, Oid typeOid)
+{
+	Oid			argList[FUNC_MAX_ARGS];
+	Oid			procOid;
 
-		/* Use CSTRING (preferred) in the error message */
-		argList[0] = CSTRINGOID;
+	/*
+	 * Send functions take a single argument of the type.
+	 */
+	MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
 
-		func_error("TypeCreate", procname, 1, argList, NULL);
-	}
+	argList[0] = typeOid;
+
+	procOid = LookupFuncName(procname, 1, argList);
+	if (OidIsValid(procOid))
+		return procOid;
+
+	func_error("TypeCreate", procname, 1, argList, NULL);
 
 	return InvalidOid;			/* keep compiler quiet */
 }
@@ -1017,6 +1101,8 @@ AlterDomainDefault(List *names, Node *defaultRaw)
 							 0,	/* relation kind is n/a */
 							 typTup->typinput,
 							 typTup->typoutput,
+							 typTup->typreceive,
+							 typTup->typsend,
 							 typTup->typelem,
 							 typTup->typbasetype,
 							 defaultExpr,
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 9fee8516b86..f713fda7d57 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.87 2003/04/08 23:20:02 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.88 2003/05/08 22:19:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -752,6 +752,34 @@ array_out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(retval);
 }
 
+/*---------------------------------------------------------------------
+ * array_recv :
+ *		  converts an array from the external binary format to
+ *		  its internal format.
+ * return value :
+ *		  the internal representation of the input array
+ *--------------------------------------------------------------------
+ */
+Datum
+array_recv(PG_FUNCTION_ARGS)
+{
+	elog(ERROR, "array_recv: not implemented yet");
+	return 0;
+}
+
+/*-------------------------------------------------------------------------
+ * array_send :
+ *		   takes the internal representation of an array and returns a bytea
+ *		  containing the array in its external binary format.
+ *-------------------------------------------------------------------------
+ */
+Datum
+array_send(PG_FUNCTION_ARGS)
+{
+	elog(ERROR, "array_send: not implemented yet");
+	return 0;
+}
+
 /*-------------------------------------------------------------------------
  * array_length_coerce :
  *		  Apply the element type's length-coercion routine to each element
diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c
index 8d7b77202c2..59b31859189 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -16,7 +16,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/pseudotypes.c,v 1.5 2003/04/08 23:20:02 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/pseudotypes.c,v 1.6 2003/05/08 22:19:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,6 +48,28 @@ record_out(PG_FUNCTION_ARGS)
 	PG_RETURN_VOID();			/* keep compiler quiet */
 }
 
+/*
+ * record_recv		- binary input routine for pseudo-type RECORD.
+ */
+Datum
+record_recv(PG_FUNCTION_ARGS)
+{
+	elog(ERROR, "Cannot accept a constant of type %s", "RECORD");
+
+	PG_RETURN_VOID();			/* keep compiler quiet */
+}
+
+/*
+ * record_send		- binary output routine for pseudo-type RECORD.
+ */
+Datum
+record_send(PG_FUNCTION_ARGS)
+{
+	elog(ERROR, "Cannot display a value of type %s", "RECORD");
+
+	PG_RETURN_VOID();			/* keep compiler quiet */
+}
+
 
 /*
  * cstring_in		- input routine for pseudo-type CSTRING.
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 6de655b6cd1..322c41a9505 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12,7 +12,7 @@
  *	by PostgreSQL
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.328 2003/05/03 22:18:59 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.329 2003/05/08 22:19:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3016,8 +3016,12 @@ dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
 	char	   *typlen;
 	char	   *typinput;
 	char	   *typoutput;
+	char	   *typreceive;
+	char	   *typsend;
 	char	   *typinputoid;
 	char	   *typoutputoid;
+	char	   *typreceiveoid;
+	char	   *typsendoid;
 	char	   *typdelim;
 	char	   *typdefault;
 	char	   *typbyval;
@@ -3032,12 +3036,28 @@ dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
 	selectSourceSchema(tinfo->typnamespace->nspname);
 
 	/* Fetch type-specific details */
-	if (fout->remoteVersion >= 70300)
+	if (fout->remoteVersion >= 70400)
+	{
+		appendPQExpBuffer(query, "SELECT typlen, "
+						  "typinput, typoutput, typreceive, typsend, "
+						  "typinput::pg_catalog.oid as typinputoid, "
+						  "typoutput::pg_catalog.oid as typoutputoid, "
+						  "typreceive::pg_catalog.oid as typreceiveoid, "
+						  "typsend::pg_catalog.oid as typsendoid, "
+						  "typdelim, typdefault, typbyval, typalign, "
+						  "typstorage "
+						  "FROM pg_catalog.pg_type "
+						  "WHERE oid = '%s'::pg_catalog.oid",
+						  tinfo->oid);
+	}
+	else if (fout->remoteVersion >= 70300)
 	{
 		appendPQExpBuffer(query, "SELECT typlen, "
 						  "typinput, typoutput, "
+						  "'-' as typreceive, '-' as typsend, "
 						  "typinput::pg_catalog.oid as typinputoid, "
 						  "typoutput::pg_catalog.oid as typoutputoid, "
+						  "0 as typreceiveoid, 0 as typsendoid, "
 						  "typdelim, typdefault, typbyval, typalign, "
 						  "typstorage "
 						  "FROM pg_catalog.pg_type "
@@ -3046,10 +3066,16 @@ dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
 	}
 	else if (fout->remoteVersion >= 70100)
 	{
+		/*
+		 * Note: although pre-7.3 catalogs contain typreceive and typsend,
+		 * ignore them because they are not right.
+		 */
 		appendPQExpBuffer(query, "SELECT typlen, "
 						  "typinput, typoutput, "
+						  "'-' as typreceive, '-' as typsend, "
 						  "typinput::oid as typinputoid, "
 						  "typoutput::oid as typoutputoid, "
+						  "0 as typreceiveoid, 0 as typsendoid, "
 						  "typdelim, typdefault, typbyval, typalign, "
 						  "typstorage "
 						  "FROM pg_type "
@@ -3060,8 +3086,10 @@ dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
 	{
 		appendPQExpBuffer(query, "SELECT typlen, "
 						  "typinput, typoutput, "
+						  "'-' as typreceive, '-' as typsend, "
 						  "typinput::oid as typinputoid, "
 						  "typoutput::oid as typoutputoid, "
+						  "0 as typreceiveoid, 0 as typsendoid, "
 						  "typdelim, typdefault, typbyval, typalign, "
 						  "'p'::char as typstorage "
 						  "FROM pg_type "
@@ -3090,8 +3118,12 @@ dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
 	typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
 	typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
 	typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
+	typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
+	typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
 	typinputoid = PQgetvalue(res, 0, PQfnumber(res, "typinputoid"));
 	typoutputoid = PQgetvalue(res, 0, PQfnumber(res, "typoutputoid"));
+	typreceiveoid = PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid"));
+	typsendoid = PQgetvalue(res, 0, PQfnumber(res, "typsendoid"));
 	typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
 	if (PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
 		typdefault = NULL;
@@ -3115,6 +3147,20 @@ dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
 	if (funcInd >= 0 && g_finfo[funcInd].pronamespace->dump)
 		(*deps)[depIdx++] = strdup(typoutputoid);
 
+	if (strcmp(typreceiveoid, "0") != 0)
+	{
+		funcInd = findFuncByOid(g_finfo, numFuncs, typreceiveoid);
+		if (funcInd >= 0 && g_finfo[funcInd].pronamespace->dump)
+			(*deps)[depIdx++] = strdup(typreceiveoid);
+	}
+
+	if (strcmp(typsendoid, "0") != 0)
+	{
+		funcInd = findFuncByOid(g_finfo, numFuncs, typsendoid);
+		if (funcInd >= 0 && g_finfo[funcInd].pronamespace->dump)
+			(*deps)[depIdx++] = strdup(typsendoid);
+	}
+
 	/*
 	 * DROP must be fully qualified in case same name appears in
 	 * pg_catalog
@@ -3126,24 +3172,27 @@ dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
 
 	appendPQExpBuffer(q,
 					  "CREATE TYPE %s (\n"
-					  "    INTERNALLENGTH = %s,\n",
+					  "    INTERNALLENGTH = %s",
 					  fmtId(tinfo->typname),
 					  (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
 
 	if (fout->remoteVersion >= 70300)
 	{
 		/* regproc result is correctly quoted in 7.3 */
-		appendPQExpBuffer(q, "    INPUT = %s,\n    OUTPUT = %s",
-						  typinput, typoutput);
+		appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
+		appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
+		if (strcmp(typreceiveoid, "0") != 0)
+			appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
+		if (strcmp(typsendoid, "0") != 0)
+			appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
 	}
 	else
 	{
 		/* regproc delivers an unquoted name before 7.3 */
 		/* cannot combine these because fmtId uses static result area */
-		appendPQExpBuffer(q, "    INPUT = %s,\n",
-						  fmtId(typinput));
-		appendPQExpBuffer(q, "    OUTPUT = %s",
-						  fmtId(typoutput));
+		appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
+		appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
+		/* no chance that receive/send need be printed */
 	}
 
 	if (typdefault != NULL)
@@ -3159,13 +3208,18 @@ dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
 		/* reselect schema in case changed by function dump */
 		selectSourceSchema(tinfo->typnamespace->nspname);
 		elemType = getFormattedTypeName(tinfo->typelem, zeroAsOpaque);
-		appendPQExpBuffer(q, ",\n    ELEMENT = %s,\n    DELIMITER = ", elemType);
-		appendStringLiteral(q, typdelim, true);
+		appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
 		free(elemType);
 
 		(*deps)[depIdx++] = strdup(tinfo->typelem);
 	}
 
+	if (typdelim && strcmp(typdelim, ",") != 0)
+	{
+		appendPQExpBuffer(q, ",\n    DELIMITER = ");
+		appendStringLiteral(q, typdelim, true);
+	}
+
 	if (strcmp(typalign, "c") == 0)
 		appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
 	else if (strcmp(typalign, "s") == 0)
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 74e36730c54..97bac4df326 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.186 2003/05/06 00:20:33 tgl Exp $
+ * $Id: catversion.h,v 1.187 2003/05/08 22:19:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200305051
+#define CATALOG_VERSION_NO	200305081
 
 #endif
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index c2d07e822ad..d20938f54a0 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_attribute.h,v 1.101 2003/03/10 22:28:19 tgl Exp $
+ * $Id: pg_attribute.h,v 1.102 2003/05/08 22:19:56 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -238,14 +238,16 @@ typedef FormData_pg_attribute *Form_pg_attribute;
 { 1247, {"typelem"},	   26, 0,	4, 10, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \
 { 1247, {"typinput"},	   24, 0,	4, 11, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \
 { 1247, {"typoutput"},	   24, 0,	4, 12, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \
-{ 1247, {"typalign"},	   18, 0,	1, 13, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \
-{ 1247, {"typstorage"},    18, 0,	1, 14, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \
-{ 1247, {"typnotnull"},    16, 0,	1, 15, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \
-{ 1247, {"typbasetype"},   26, 0,	4, 16, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \
-{ 1247, {"typtypmod"},	   23, 0,	4, 17, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \
-{ 1247, {"typndims"},	   23, 0,	4, 18, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \
-{ 1247, {"typdefaultbin"}, 25, 0,  -1, 19, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 }, \
-{ 1247, {"typdefault"},    25, 0,  -1, 20, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 }
+{ 1247, {"typreceive"},	   24, 0,	4, 13, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \
+{ 1247, {"typsend"},	   24, 0,	4, 14, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \
+{ 1247, {"typalign"},	   18, 0,	1, 15, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \
+{ 1247, {"typstorage"},    18, 0,	1, 16, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \
+{ 1247, {"typnotnull"},    16, 0,	1, 17, 0, -1, -1, true, 'p', false, 'c', true, false, false, true, 0 }, \
+{ 1247, {"typbasetype"},   26, 0,	4, 18, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \
+{ 1247, {"typtypmod"},	   23, 0,	4, 19, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \
+{ 1247, {"typndims"},	   23, 0,	4, 20, 0, -1, -1, true, 'p', false, 'i', true, false, false, true, 0 }, \
+{ 1247, {"typdefaultbin"}, 25, 0,  -1, 21, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 }, \
+{ 1247, {"typdefault"},    25, 0,  -1, 22, 0, -1, -1, false, 'x', false, 'i', false, false, false, true, 0 }
 
 
 DATA(insert ( 1247 typname			19 -1 NAMEDATALEN	1 0 -1 -1 f p f i t f f t 0));
@@ -260,14 +262,16 @@ DATA(insert ( 1247 typrelid			26 0  4   9 0 -1 -1 t p f i t f f t 0));
 DATA(insert ( 1247 typelem			26 0  4  10 0 -1 -1 t p f i t f f t 0));
 DATA(insert ( 1247 typinput			24 0  4  11 0 -1 -1 t p f i t f f t 0));
 DATA(insert ( 1247 typoutput		24 0  4  12 0 -1 -1 t p f i t f f t 0));
-DATA(insert ( 1247 typalign			18 0  1  13 0 -1 -1 t p f c t f f t 0));
-DATA(insert ( 1247 typstorage		18 0  1  14 0 -1 -1 t p f c t f f t 0));
-DATA(insert ( 1247 typnotnull		16 0  1  15 0 -1 -1 t p f c t f f t 0));
-DATA(insert ( 1247 typbasetype		26 0  4  16 0 -1 -1 t p f i t f f t 0));
-DATA(insert ( 1247 typtypmod		23 0  4  17 0 -1 -1 t p f i t f f t 0));
-DATA(insert ( 1247 typndims			23 0  4  18 0 -1 -1 t p f i t f f t 0));
-DATA(insert ( 1247 typdefaultbin	25 0 -1  19 0 -1 -1 f x f i f f f t 0));
-DATA(insert ( 1247 typdefault		25 0 -1  20 0 -1 -1 f x f i f f f t 0));
+DATA(insert ( 1247 typreceive		24 0  4  13 0 -1 -1 t p f i t f f t 0));
+DATA(insert ( 1247 typsend			24 0  4  14 0 -1 -1 t p f i t f f t 0));
+DATA(insert ( 1247 typalign			18 0  1  15 0 -1 -1 t p f c t f f t 0));
+DATA(insert ( 1247 typstorage		18 0  1  16 0 -1 -1 t p f c t f f t 0));
+DATA(insert ( 1247 typnotnull		16 0  1  17 0 -1 -1 t p f c t f f t 0));
+DATA(insert ( 1247 typbasetype		26 0  4  18 0 -1 -1 t p f i t f f t 0));
+DATA(insert ( 1247 typtypmod		23 0  4  19 0 -1 -1 t p f i t f f t 0));
+DATA(insert ( 1247 typndims			23 0  4  20 0 -1 -1 t p f i t f f t 0));
+DATA(insert ( 1247 typdefaultbin	25 0 -1  21 0 -1 -1 f x f i f f f t 0));
+DATA(insert ( 1247 typdefault		25 0 -1  22 0 -1 -1 f x f i f f f t 0));
 DATA(insert ( 1247 ctid				27 0  6  -1 0 -1 -1 f p f i t f f t 0));
 DATA(insert ( 1247 oid				26 0  4  -2 0 -1 -1 t p f i t f f t 0));
 DATA(insert ( 1247 xmin				28 0  4  -3 0 -1 -1 t p f i t f f t 0));
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 715f24c8d10..db7f3709f9e 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_class.h,v 1.75 2003/03/10 22:28:19 tgl Exp $
+ * $Id: pg_class.h,v 1.76 2003/05/08 22:19:57 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -134,7 +134,7 @@ typedef FormData_pg_class *Form_pg_class;
  * ----------------
  */
 
-DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 f f r 20 0 0 0 0 0 t f f f _null_ ));
+DATA(insert OID = 1247 (  pg_type		PGNSP 71 PGUID 0 1247 0 0 0 0 f f r 22 0 0 0 0 0 t f f f _null_ ));
 DESCR("");
 DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 18 0 0 0 0 0 f f f f _null_ ));
 DESCR("");
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ee20811165b..d4904f77120 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.293 2003/04/17 04:50:20 tgl Exp $
+ * $Id: pg_proc.h,v 1.294 2003/05/08 22:19:57 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -993,9 +993,9 @@ DESCR("session user name");
 DATA(insert OID = 747 (  array_dims		   PGNSP PGUID 12 f f t f i 1 25 "2277" array_dims - _null_ ));
 DESCR("array dimensions");
 DATA(insert OID = 750 (  array_in		   PGNSP PGUID 12 f f t f s 3 2277 "2275 26 23"  array_in - _null_ ));
-DESCR("array");
+DESCR("I/O");
 DATA(insert OID = 751 (  array_out		   PGNSP PGUID 12 f f t f s 1 2275 "2277"  array_out - _null_ ));
-DESCR("array");
+DESCR("I/O");
 DATA(insert OID = 2091 (  array_lower	   PGNSP PGUID 12 f f t f i 2 23 "2277 23" array_lower - _null_ ));
 DESCR("array lower dimension");
 DATA(insert OID = 2092 (  array_upper	   PGNSP PGUID 12 f f t f i 2 23 "2277 23" array_upper - _null_ ));
@@ -3153,6 +3153,16 @@ DATA(insert OID =  2311 (  md5	   PGNSP PGUID 12 f f t f i 1 25 "25"  md5_text -
 DESCR("calculates md5 hash");
 
 
+DATA(insert OID = 2400 (  array_recv		   PGNSP PGUID 12 f f t f s 1 2277 "2281"  array_recv - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2401 (  array_send		   PGNSP PGUID 12 f f t f s 1 17 "2277"  array_send - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2402 (  record_recv		   PGNSP PGUID 12 f f t f i 1 2249 "2281"  record_recv - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2403 (  record_send		   PGNSP PGUID 12 f f t f i 1 17 "2249"  record_send - _null_ ));
+DESCR("I/O");
+
+
 /*
  * Symbolic values for provolatile column: these indicate whether the result
  * of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 4413e843991..b065c295d6b 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_type.h,v 1.140 2003/04/08 23:20:04 tgl Exp $
+ * $Id: pg_type.h,v 1.141 2003/05/08 22:19:57 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -99,8 +99,10 @@ CATALOG(pg_type) BOOTSTRAP
 	/*
 	 * I/O conversion procedures for the datatype.
 	 */
-	regproc		typinput;
+	regproc		typinput;		/* text format (required) */
 	regproc		typoutput;
+	regproc		typreceive;		/* binary format (optional) */
+	regproc		typsend;
 
 	/* ----------------
 	 * typalign is the alignment required when storing a value of this
@@ -198,7 +200,7 @@ typedef FormData_pg_type *Form_pg_type;
  *		compiler constants for pg_type
  * ----------------
  */
-#define Natts_pg_type					20
+#define Natts_pg_type					22
 #define Anum_pg_type_typname			1
 #define Anum_pg_type_typnamespace		2
 #define Anum_pg_type_typowner			3
@@ -211,14 +213,16 @@ typedef FormData_pg_type *Form_pg_type;
 #define Anum_pg_type_typelem			10
 #define Anum_pg_type_typinput			11
 #define Anum_pg_type_typoutput			12
-#define Anum_pg_type_typalign			13
-#define Anum_pg_type_typstorage			14
-#define Anum_pg_type_typnotnull			15
-#define Anum_pg_type_typbasetype		16
-#define Anum_pg_type_typtypmod			17
-#define Anum_pg_type_typndims			18
-#define Anum_pg_type_typdefaultbin		19
-#define Anum_pg_type_typdefault			20
+#define Anum_pg_type_typreceive			13
+#define Anum_pg_type_typsend			14
+#define Anum_pg_type_typalign			15
+#define Anum_pg_type_typstorage			16
+#define Anum_pg_type_typnotnull			17
+#define Anum_pg_type_typbasetype		18
+#define Anum_pg_type_typtypmod			19
+#define Anum_pg_type_typndims			20
+#define Anum_pg_type_typdefaultbin		21
+#define Anum_pg_type_typdefault			22
 
 
 /* ----------------
@@ -234,82 +238,82 @@ typedef FormData_pg_type *Form_pg_type;
 */
 
 /* OIDS 1 - 99 */
-DATA(insert OID = 16 (	bool	   PGNSP PGUID	1 t b t \054 0	 0 boolin boolout c p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 16 (	bool	   PGNSP PGUID	1 t b t \054 0	 0 boolin boolout - - c p f 0 -1 0 _null_ _null_ ));
 DESCR("boolean, 'true'/'false'");
 #define BOOLOID			16
 
-DATA(insert OID = 17 (	bytea	   PGNSP PGUID -1 f b t \054 0	0 byteain byteaout i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 17 (	bytea	   PGNSP PGUID -1 f b t \054 0	0 byteain byteaout - - i x f 0 -1 0 _null_ _null_ ));
 DESCR("variable-length string, binary values escaped");
 #define BYTEAOID		17
 
-DATA(insert OID = 18 (	char	   PGNSP PGUID	1 t b t \054 0	 0 charin charout c p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 18 (	char	   PGNSP PGUID	1 t b t \054 0	 0 charin charout - - c p f 0 -1 0 _null_ _null_ ));
 DESCR("single character");
 #define CHAROID			18
 
-DATA(insert OID = 19 (	name	   PGNSP PGUID NAMEDATALEN f b t \054 0 18 namein nameout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 19 (	name	   PGNSP PGUID NAMEDATALEN f b t \054 0 18 namein nameout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("31-character type for storing system identifiers");
 #define NAMEOID			19
 
-DATA(insert OID = 20 (	int8	   PGNSP PGUID	8 f b t \054 0	 0 int8in int8out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 20 (	int8	   PGNSP PGUID	8 f b t \054 0	 0 int8in int8out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("~18 digit integer, 8-byte storage");
 #define INT8OID			20
 
-DATA(insert OID = 21 (	int2	   PGNSP PGUID	2 t b t \054 0	 0 int2in int2out s p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 21 (	int2	   PGNSP PGUID	2 t b t \054 0	 0 int2in int2out - - s p f 0 -1 0 _null_ _null_ ));
 DESCR("-32 thousand to 32 thousand, 2-byte storage");
 #define INT2OID			21
 
-DATA(insert OID = 22 (	int2vector PGNSP PGUID INDEX_MAX_KEYS*2 f b t \054 0  21 int2vectorin int2vectorout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 22 (	int2vector PGNSP PGUID INDEX_MAX_KEYS*2 f b t \054 0  21 int2vectorin int2vectorout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("array of INDEX_MAX_KEYS int2 integers, used in system tables");
 #define INT2VECTOROID	22
 
-DATA(insert OID = 23 (	int4	   PGNSP PGUID	4 t b t \054 0	 0 int4in int4out i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 23 (	int4	   PGNSP PGUID	4 t b t \054 0	 0 int4in int4out - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("-2 billion to 2 billion integer, 4-byte storage");
 #define INT4OID			23
 
-DATA(insert OID = 24 (	regproc    PGNSP PGUID	4 t b t \054 0	 0 regprocin regprocout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 24 (	regproc    PGNSP PGUID	4 t b t \054 0	 0 regprocin regprocout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("registered procedure");
 #define REGPROCOID		24
 
-DATA(insert OID = 25 (	text	   PGNSP PGUID -1 f b t \054 0	0 textin textout i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 25 (	text	   PGNSP PGUID -1 f b t \054 0	0 textin textout - - i x f 0 -1 0 _null_ _null_ ));
 DESCR("variable-length string, no limit specified");
 #define TEXTOID			25
 
-DATA(insert OID = 26 (	oid		   PGNSP PGUID	4 t b t \054 0	 0 oidin oidout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 26 (	oid		   PGNSP PGUID	4 t b t \054 0	 0 oidin oidout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("object identifier(oid), maximum 4 billion");
 #define OIDOID			26
 
-DATA(insert OID = 27 (	tid		   PGNSP PGUID	6 f b t \054 0	 0 tidin tidout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 27 (	tid		   PGNSP PGUID	6 f b t \054 0	 0 tidin tidout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("(Block, offset), physical location of tuple");
 #define TIDOID		27
 
-DATA(insert OID = 28 (	xid		   PGNSP PGUID	4 t b t \054 0	 0 xidin xidout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 28 (	xid		   PGNSP PGUID	4 t b t \054 0	 0 xidin xidout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("transaction id");
 #define XIDOID 28
 
-DATA(insert OID = 29 (	cid		   PGNSP PGUID	4 t b t \054 0	 0 cidin cidout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 29 (	cid		   PGNSP PGUID	4 t b t \054 0	 0 cidin cidout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("command identifier type, sequence in transaction id");
 #define CIDOID 29
 
-DATA(insert OID = 30 (	oidvector  PGNSP PGUID INDEX_MAX_KEYS*4 f b t \054 0  26 oidvectorin oidvectorout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 30 (	oidvector  PGNSP PGUID INDEX_MAX_KEYS*4 f b t \054 0  26 oidvectorin oidvectorout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("array of INDEX_MAX_KEYS oids, used in system tables");
 #define OIDVECTOROID	30
 
-DATA(insert OID = 32 (	SET		   PGNSP PGUID -1 f b t \054 0	 0 unknownin unknownout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 32 (	SET		   PGNSP PGUID -1 f b t \054 0	 0 unknownin unknownout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("set of tuples");
 
-DATA(insert OID = 71 (	pg_type		 PGNSP PGUID 4 t c t \054 1247 0 record_in record_out i p f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 75 (	pg_attribute PGNSP PGUID 4 t c t \054 1249 0 record_in record_out i p f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 81 (	pg_proc		 PGNSP PGUID 4 t c t \054 1255 0 record_in record_out i p f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 83 (	pg_class	 PGNSP PGUID 4 t c t \054 1259 0 record_in record_out i p f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 86 (	pg_shadow	 PGNSP PGUID 4 t c t \054 1260 0 record_in record_out i p f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 87 (	pg_group	 PGNSP PGUID 4 t c t \054 1261 0 record_in record_out i p f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 88 (	pg_database  PGNSP PGUID 4 t c t \054 1262 0 record_in record_out i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 71 (	pg_type		 PGNSP PGUID 4 t c t \054 1247 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 75 (	pg_attribute PGNSP PGUID 4 t c t \054 1249 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 81 (	pg_proc		 PGNSP PGUID 4 t c t \054 1255 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 83 (	pg_class	 PGNSP PGUID 4 t c t \054 1259 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 86 (	pg_shadow	 PGNSP PGUID 4 t c t \054 1260 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 87 (	pg_group	 PGNSP PGUID 4 t c t \054 1261 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 88 (	pg_database  PGNSP PGUID 4 t c t \054 1262 0 record_in record_out record_recv record_send i p f 0 -1 0 _null_ _null_ ));
 
 /* OIDS 100 - 199 */
 
 /* OIDS 200 - 299 */
 
-DATA(insert OID = 210 (  smgr	   PGNSP PGUID 2 t b t \054 0 0 smgrin smgrout s p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 210 (  smgr	   PGNSP PGUID 2 t b t \054 0 0 smgrin smgrout - - s p f 0 -1 0 _null_ _null_ ));
 DESCR("storage manager");
 
 /* OIDS 300 - 399 */
@@ -319,192 +323,192 @@ DESCR("storage manager");
 /* OIDS 500 - 599 */
 
 /* OIDS 600 - 699 */
-DATA(insert OID = 600 (  point	   PGNSP PGUID 16 f b t \054 0 701 point_in point_out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 600 (  point	   PGNSP PGUID 16 f b t \054 0 701 point_in point_out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("geometric point '(x, y)'");
 #define POINTOID		600
-DATA(insert OID = 601 (  lseg	   PGNSP PGUID 32 f b t \054 0 600 lseg_in lseg_out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 601 (  lseg	   PGNSP PGUID 32 f b t \054 0 600 lseg_in lseg_out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("geometric line segment '(pt1,pt2)'");
 #define LSEGOID			601
-DATA(insert OID = 602 (  path	   PGNSP PGUID -1 f b t \054 0 0 path_in path_out d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 602 (  path	   PGNSP PGUID -1 f b t \054 0 0 path_in path_out - - d x f 0 -1 0 _null_ _null_ ));
 DESCR("geometric path '(pt1,...)'");
 #define PATHOID			602
-DATA(insert OID = 603 (  box	   PGNSP PGUID 32 f b t \073 0 600 box_in box_out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 603 (  box	   PGNSP PGUID 32 f b t \073 0 600 box_in box_out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("geometric box '(lower left,upper right)'");
 #define BOXOID			603
-DATA(insert OID = 604 (  polygon   PGNSP PGUID -1 f b t \054 0	 0 poly_in poly_out d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 604 (  polygon   PGNSP PGUID -1 f b t \054 0	 0 poly_in poly_out - - d x f 0 -1 0 _null_ _null_ ));
 DESCR("geometric polygon '(pt1,...)'");
 #define POLYGONOID		604
 
-DATA(insert OID = 628 (  line	   PGNSP PGUID 32 f b t \054 0 701 line_in line_out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 628 (  line	   PGNSP PGUID 32 f b t \054 0 701 line_in line_out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("geometric line (not implemented)'");
 #define LINEOID			628
-DATA(insert OID = 629 (  _line	   PGNSP PGUID	-1 f b t \054 0 628 array_in array_out d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 629 (  _line	   PGNSP PGUID	-1 f b t \054 0 628 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
 DESCR("");
 
 /* OIDS 700 - 799 */
 
-DATA(insert OID = 700 (  float4    PGNSP PGUID	4 f b t \054 0	 0 float4in float4out i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 700 (  float4    PGNSP PGUID	4 f b t \054 0	 0 float4in float4out - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("single-precision floating point number, 4-byte storage");
 #define FLOAT4OID 700
-DATA(insert OID = 701 (  float8    PGNSP PGUID	8 f b t \054 0	 0 float8in float8out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 701 (  float8    PGNSP PGUID	8 f b t \054 0	 0 float8in float8out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("double-precision floating point number, 8-byte storage");
 #define FLOAT8OID 701
-DATA(insert OID = 702 (  abstime   PGNSP PGUID	4 t b t \054 0	 0 nabstimein nabstimeout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 702 (  abstime   PGNSP PGUID	4 t b t \054 0	 0 nabstimein nabstimeout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("absolute, limited-range date and time (Unix system time)");
 #define ABSTIMEOID		702
-DATA(insert OID = 703 (  reltime   PGNSP PGUID	4 t b t \054 0	 0 reltimein reltimeout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 703 (  reltime   PGNSP PGUID	4 t b t \054 0	 0 reltimein reltimeout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("relative, limited-range time interval (Unix delta time)");
 #define RELTIMEOID		703
-DATA(insert OID = 704 (  tinterval PGNSP PGUID 12 f b t \054 0	 0 tintervalin tintervalout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 704 (  tinterval PGNSP PGUID 12 f b t \054 0	 0 tintervalin tintervalout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("(abstime,abstime), time interval");
 #define TINTERVALOID	704
-DATA(insert OID = 705 (  unknown   PGNSP PGUID -1 f b t \054 0	 0 unknownin unknownout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 705 (  unknown   PGNSP PGUID -1 f b t \054 0	 0 unknownin unknownout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("");
 #define UNKNOWNOID		705
 
-DATA(insert OID = 718 (  circle    PGNSP PGUID	24 f b t \054 0 0 circle_in circle_out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 718 (  circle    PGNSP PGUID	24 f b t \054 0 0 circle_in circle_out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("geometric circle '(center,radius)'");
 #define CIRCLEOID		718
-DATA(insert OID = 719 (  _circle   PGNSP PGUID	-1 f b t \054 0  718 array_in array_out d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 790 (  money	   PGNSP PGUID	 4 f b t \054 0 0 cash_in cash_out i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 719 (  _circle   PGNSP PGUID	-1 f b t \054 0  718 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 790 (  money	   PGNSP PGUID	 4 f b t \054 0 0 cash_in cash_out - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("$d,ddd.cc, money");
 #define CASHOID 790
-DATA(insert OID = 791 (  _money    PGNSP PGUID	-1 f b t \054 0  790 array_in array_out i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 791 (  _money    PGNSP PGUID	-1 f b t \054 0  790 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
 
 /* OIDS 800 - 899 */
-DATA(insert OID = 829 ( macaddr    PGNSP PGUID	6 f b t \054 0 0 macaddr_in macaddr_out i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 829 ( macaddr    PGNSP PGUID	6 f b t \054 0 0 macaddr_in macaddr_out - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("XX:XX:XX:XX:XX:XX, MAC address");
 #define MACADDROID 829
-DATA(insert OID = 869 ( inet	   PGNSP PGUID	-1 f b t \054 0 0 inet_in inet_out i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 869 ( inet	   PGNSP PGUID	-1 f b t \054 0 0 inet_in inet_out - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("IP address/netmask, host address, netmask optional");
 #define INETOID 869
-DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b t \054 0 0 cidr_in cidr_out i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 650 ( cidr	   PGNSP PGUID	-1 f b t \054 0 0 cidr_in cidr_out - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("network IP address/netmask, network address");
 #define CIDROID 650
 
 /* OIDS 900 - 999 */
 
 /* OIDS 1000 - 1099 */
-DATA(insert OID = 1000 (  _bool		 PGNSP PGUID -1 f b t \054 0	16 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1001 (  _bytea	 PGNSP PGUID -1 f b t \054 0	17 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1002 (  _char		 PGNSP PGUID -1 f b t \054 0	18 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1003 (  _name		 PGNSP PGUID -1 f b t \054 0	19 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1005 (  _int2		 PGNSP PGUID -1 f b t \054 0	21 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1006 (  _int2vector PGNSP PGUID -1 f b t \054 0	22 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1007 (  _int4		 PGNSP PGUID -1 f b t \054 0	23 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1008 (  _regproc	 PGNSP PGUID -1 f b t \054 0	24 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1009 (  _text		 PGNSP PGUID -1 f b t \054 0	25 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1028 (  _oid		 PGNSP PGUID -1 f b t \054 0	26 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1010 (  _tid		 PGNSP PGUID -1 f b t \054 0	27 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1011 (  _xid		 PGNSP PGUID -1 f b t \054 0	28 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1012 (  _cid		 PGNSP PGUID -1 f b t \054 0	29 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1013 (  _oidvector PGNSP PGUID -1 f b t \054 0	30 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1014 (  _bpchar	 PGNSP PGUID -1 f b t \054 0 1042 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1015 (  _varchar	 PGNSP PGUID -1 f b t \054 0 1043 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1016 (  _int8		 PGNSP PGUID -1 f b t \054 0	20 array_in array_out d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1017 (  _point	 PGNSP PGUID -1 f b t \054 0 600 array_in array_out d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1018 (  _lseg		 PGNSP PGUID -1 f b t \054 0 601 array_in array_out d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1019 (  _path		 PGNSP PGUID -1 f b t \054 0 602 array_in array_out d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1020 (  _box		 PGNSP PGUID -1 f b t \073 0 603 array_in array_out d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1021 (  _float4	 PGNSP PGUID -1 f b t \054 0 700 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1022 (  _float8	 PGNSP PGUID -1 f b t \054 0 701 array_in array_out d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1023 (  _abstime	 PGNSP PGUID -1 f b t \054 0 702 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1024 (  _reltime	 PGNSP PGUID -1 f b t \054 0 703 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1025 (  _tinterval PGNSP PGUID -1 f b t \054 0 704 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1027 (  _polygon	 PGNSP PGUID -1 f b t \054 0 604 array_in array_out d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1033 (  aclitem	 PGNSP PGUID 12 f b t \054 0 0 aclitemin aclitemout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1000 (  _bool		 PGNSP PGUID -1 f b t \054 0	16 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1001 (  _bytea	 PGNSP PGUID -1 f b t \054 0	17 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1002 (  _char		 PGNSP PGUID -1 f b t \054 0	18 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1003 (  _name		 PGNSP PGUID -1 f b t \054 0	19 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1005 (  _int2		 PGNSP PGUID -1 f b t \054 0	21 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1006 (  _int2vector PGNSP PGUID -1 f b t \054 0	22 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1007 (  _int4		 PGNSP PGUID -1 f b t \054 0	23 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1008 (  _regproc	 PGNSP PGUID -1 f b t \054 0	24 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1009 (  _text		 PGNSP PGUID -1 f b t \054 0	25 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1028 (  _oid		 PGNSP PGUID -1 f b t \054 0	26 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1010 (  _tid		 PGNSP PGUID -1 f b t \054 0	27 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1011 (  _xid		 PGNSP PGUID -1 f b t \054 0	28 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1012 (  _cid		 PGNSP PGUID -1 f b t \054 0	29 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1013 (  _oidvector PGNSP PGUID -1 f b t \054 0	30 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1014 (  _bpchar	 PGNSP PGUID -1 f b t \054 0 1042 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1015 (  _varchar	 PGNSP PGUID -1 f b t \054 0 1043 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1016 (  _int8		 PGNSP PGUID -1 f b t \054 0	20 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1017 (  _point	 PGNSP PGUID -1 f b t \054 0 600 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1018 (  _lseg		 PGNSP PGUID -1 f b t \054 0 601 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1019 (  _path		 PGNSP PGUID -1 f b t \054 0 602 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1020 (  _box		 PGNSP PGUID -1 f b t \073 0 603 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1021 (  _float4	 PGNSP PGUID -1 f b t \054 0 700 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1022 (  _float8	 PGNSP PGUID -1 f b t \054 0 701 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1023 (  _abstime	 PGNSP PGUID -1 f b t \054 0 702 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1024 (  _reltime	 PGNSP PGUID -1 f b t \054 0 703 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1025 (  _tinterval PGNSP PGUID -1 f b t \054 0 704 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1027 (  _polygon	 PGNSP PGUID -1 f b t \054 0 604 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1033 (  aclitem	 PGNSP PGUID 12 f b t \054 0 0 aclitemin aclitemout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("access control list");
 #define ACLITEMOID		1033
-DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b t \054 0 1033 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b t \054 0  829 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1041 (  _inet    PGNSP PGUID -1 f b t \054 0	869 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 651  (  _cidr    PGNSP PGUID -1 f b t \054 0	650 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1042 ( bpchar		 PGNSP PGUID -1 f b t \054 0	0 bpcharin bpcharout i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1034 (  _aclitem	 PGNSP PGUID -1 f b t \054 0 1033 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1040 (  _macaddr	 PGNSP PGUID -1 f b t \054 0  829 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1041 (  _inet    PGNSP PGUID -1 f b t \054 0	869 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 651  (  _cidr    PGNSP PGUID -1 f b t \054 0	650 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1042 ( bpchar		 PGNSP PGUID -1 f b t \054 0	0 bpcharin bpcharout - - i x f 0 -1 0 _null_ _null_ ));
 DESCR("char(length), blank-padded string, fixed storage length");
 #define BPCHAROID		1042
-DATA(insert OID = 1043 ( varchar	 PGNSP PGUID -1 f b t \054 0	0 varcharin varcharout i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1043 ( varchar	 PGNSP PGUID -1 f b t \054 0	0 varcharin varcharout - - i x f 0 -1 0 _null_ _null_ ));
 DESCR("varchar(length), non-blank-padded string, variable storage length");
 #define VARCHAROID		1043
 
-DATA(insert OID = 1082 ( date		 PGNSP PGUID	4 t b t \054 0	0 date_in date_out i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1082 ( date		 PGNSP PGUID	4 t b t \054 0	0 date_in date_out - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("ANSI SQL date");
 #define DATEOID			1082
-DATA(insert OID = 1083 ( time		 PGNSP PGUID	8 f b t \054 0	0 time_in time_out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1083 ( time		 PGNSP PGUID	8 f b t \054 0	0 time_in time_out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("hh:mm:ss, ANSI SQL time");
 #define TIMEOID			1083
 
 /* OIDS 1100 - 1199 */
-DATA(insert OID = 1114 ( timestamp	 PGNSP PGUID	8 f b t \054 0	0 timestamp_in timestamp_out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1114 ( timestamp	 PGNSP PGUID	8 f b t \054 0	0 timestamp_in timestamp_out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("date and time");
 #define TIMESTAMPOID	1114
-DATA(insert OID = 1115 ( _timestamp  PGNSP PGUID	-1 f b t \054 0 1114 array_in array_out d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1182 ( _date		 PGNSP PGUID	-1 f b t \054 0 1082 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1183 ( _time		 PGNSP PGUID	-1 f b t \054 0 1083 array_in array_out d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1184 ( timestamptz PGNSP PGUID	8 f b t \054 0	0 timestamptz_in timestamptz_out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1115 ( _timestamp  PGNSP PGUID	-1 f b t \054 0 1114 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1182 ( _date		 PGNSP PGUID	-1 f b t \054 0 1082 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1183 ( _time		 PGNSP PGUID	-1 f b t \054 0 1083 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1184 ( timestamptz PGNSP PGUID	8 f b t \054 0	0 timestamptz_in timestamptz_out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("date and time with time zone");
 #define TIMESTAMPTZOID	1184
-DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b t \054 0	1184 array_in array_out d x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1186 ( interval	 PGNSP PGUID 12 f b t \054 0	0 interval_in interval_out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b t \054 0	1184 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1186 ( interval	 PGNSP PGUID 12 f b t \054 0	0 interval_in interval_out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("@ <number> <units>, time interval");
 #define INTERVALOID		1186
-DATA(insert OID = 1187 ( _interval	 PGNSP PGUID	-1 f b t \054 0 1186 array_in array_out d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1187 ( _interval	 PGNSP PGUID	-1 f b t \054 0 1186 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
 
 /* OIDS 1200 - 1299 */
-DATA(insert OID = 1231 (  _numeric	 PGNSP PGUID -1 f b t \054 0	1700 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1266 ( timetz		 PGNSP PGUID 12 f b t \054 0	0 timetz_in timetz_out d p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1231 (  _numeric	 PGNSP PGUID -1 f b t \054 0	1700 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1266 ( timetz		 PGNSP PGUID 12 f b t \054 0	0 timetz_in timetz_out - - d p f 0 -1 0 _null_ _null_ ));
 DESCR("hh:mm:ss, ANSI SQL time");
 #define TIMETZOID		1266
-DATA(insert OID = 1270 ( _timetz	 PGNSP PGUID -1 f b t \054 0	1266 array_in array_out d x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1270 ( _timetz	 PGNSP PGUID -1 f b t \054 0	1266 array_in array_out array_recv array_send d x f 0 -1 0 _null_ _null_ ));
 
 /* OIDS 1500 - 1599 */
-DATA(insert OID = 1560 ( bit		 PGNSP PGUID -1 f b t \054 0	0 bit_in bit_out i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1560 ( bit		 PGNSP PGUID -1 f b t \054 0	0 bit_in bit_out - - i x f 0 -1 0 _null_ _null_ ));
 DESCR("fixed-length bit string");
 #define BITOID	 1560
-DATA(insert OID = 1561 ( _bit		 PGNSP PGUID -1 f b t \054 0	1560 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 1562 ( varbit		 PGNSP PGUID -1 f b t \054 0	0 varbit_in varbit_out i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1561 ( _bit		 PGNSP PGUID -1 f b t \054 0	1560 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1562 ( varbit		 PGNSP PGUID -1 f b t \054 0	0 varbit_in varbit_out - - i x f 0 -1 0 _null_ _null_ ));
 DESCR("variable-length bit string");
 #define VARBITOID	  1562
-DATA(insert OID = 1563 ( _varbit	 PGNSP PGUID -1 f b t \054 0	1562 array_in array_out i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1563 ( _varbit	 PGNSP PGUID -1 f b t \054 0	1562 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
 
 /* OIDS 1600 - 1699 */
 
 /* OIDS 1700 - 1799 */
-DATA(insert OID = 1700 ( numeric	   PGNSP PGUID -1 f b t \054 0	0 numeric_in numeric_out i m f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1700 ( numeric	   PGNSP PGUID -1 f b t \054 0	0 numeric_in numeric_out - - i m f 0 -1 0 _null_ _null_ ));
 DESCR("numeric(precision, decimal), arbitrary precision number");
 #define NUMERICOID		1700
 
-DATA(insert OID = 1790 ( refcursor	   PGNSP PGUID -1 f b t \054 0	0 textin textout i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 1790 ( refcursor	   PGNSP PGUID -1 f b t \054 0	0 textin textout - - i x f 0 -1 0 _null_ _null_ ));
 DESCR("reference cursor (portal name)");
 #define REFCURSOROID	1790
 
 /* OIDS 2200 - 2299 */
-DATA(insert OID = 2201 ( _refcursor    PGNSP PGUID -1 f b t \054 0 1790 array_in array_out i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2201 ( _refcursor    PGNSP PGUID -1 f b t \054 0 1790 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
 
-DATA(insert OID = 2202 ( regprocedure  PGNSP PGUID	4 t b t \054 0	 0 regprocedurein regprocedureout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2202 ( regprocedure  PGNSP PGUID	4 t b t \054 0	 0 regprocedurein regprocedureout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("registered procedure (with args)");
 #define REGPROCEDUREOID 2202
 
-DATA(insert OID = 2203 ( regoper	   PGNSP PGUID	4 t b t \054 0	 0 regoperin regoperout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2203 ( regoper	   PGNSP PGUID	4 t b t \054 0	 0 regoperin regoperout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("registered operator");
 #define REGOPEROID		2203
 
-DATA(insert OID = 2204 ( regoperator   PGNSP PGUID	4 t b t \054 0	 0 regoperatorin regoperatorout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2204 ( regoperator   PGNSP PGUID	4 t b t \054 0	 0 regoperatorin regoperatorout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("registered operator (with args)");
 #define REGOPERATOROID	2204
 
-DATA(insert OID = 2205 ( regclass	   PGNSP PGUID	4 t b t \054 0	 0 regclassin regclassout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2205 ( regclass	   PGNSP PGUID	4 t b t \054 0	 0 regclassin regclassout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("registered class");
 #define REGCLASSOID		2205
 
-DATA(insert OID = 2206 ( regtype	   PGNSP PGUID	4 t b t \054 0	 0 regtypein regtypeout i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2206 ( regtype	   PGNSP PGUID	4 t b t \054 0	 0 regtypein regtypeout - - i p f 0 -1 0 _null_ _null_ ));
 DESCR("registered type");
 #define REGTYPEOID		2206
 
-DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b t \054 0 2202 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 2208 ( _regoper	   PGNSP PGUID -1 f b t \054 0 2203 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 2209 ( _regoperator  PGNSP PGUID -1 f b t \054 0 2204 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 2210 ( _regclass	   PGNSP PGUID -1 f b t \054 0 2205 array_in array_out i x f 0 -1 0 _null_ _null_ ));
-DATA(insert OID = 2211 ( _regtype	   PGNSP PGUID -1 f b t \054 0 2206 array_in array_out i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b t \054 0 2202 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2208 ( _regoper	   PGNSP PGUID -1 f b t \054 0 2203 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2209 ( _regoperator  PGNSP PGUID -1 f b t \054 0 2204 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2210 ( _regclass	   PGNSP PGUID -1 f b t \054 0 2205 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2211 ( _regtype	   PGNSP PGUID -1 f b t \054 0 2206 array_in array_out array_recv array_send i x f 0 -1 0 _null_ _null_ ));
 
 /*
  * pseudo-types
@@ -515,25 +519,25 @@ DATA(insert OID = 2211 ( _regtype	   PGNSP PGUID -1 f b t \054 0 2206 array_in a
  * argument and result types (if supported by the function's implementation
  * language).
  */
-DATA(insert OID = 2249 ( record			PGNSP PGUID  4 t p t \054 0 0 record_in record_out	i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2249 ( record			PGNSP PGUID  4 t p t \054 0 0 record_in record_out record_recv record_send	i p f 0 -1 0 _null_ _null_ ));
 #define RECORDOID		2249
-DATA(insert OID = 2275 ( cstring		PGNSP PGUID -2 f p t \054 0 0 cstring_in cstring_out	c p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2275 ( cstring		PGNSP PGUID -2 f p t \054 0 0 cstring_in cstring_out - -	c p f 0 -1 0 _null_ _null_ ));
 #define CSTRINGOID		2275
-DATA(insert OID = 2276 ( any			PGNSP PGUID  4 t p t \054 0 0 any_in any_out	i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2276 ( any			PGNSP PGUID  4 t p t \054 0 0 any_in any_out - -	i p f 0 -1 0 _null_ _null_ ));
 #define ANYOID			2276
-DATA(insert OID = 2277 ( anyarray		PGNSP PGUID -1 f p t \054 0 0 anyarray_in anyarray_out	i x f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2277 ( anyarray		PGNSP PGUID -1 f p t \054 0 0 anyarray_in anyarray_out - -	i x f 0 -1 0 _null_ _null_ ));
 #define ANYARRAYOID		2277
-DATA(insert OID = 2278 ( void			PGNSP PGUID  4 t p t \054 0 0 void_in void_out	i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2278 ( void			PGNSP PGUID  4 t p t \054 0 0 void_in void_out - -	i p f 0 -1 0 _null_ _null_ ));
 #define VOIDOID			2278
-DATA(insert OID = 2279 ( trigger		PGNSP PGUID  4 t p t \054 0 0 trigger_in trigger_out	i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2279 ( trigger		PGNSP PGUID  4 t p t \054 0 0 trigger_in trigger_out - -	i p f 0 -1 0 _null_ _null_ ));
 #define TRIGGEROID		2279
-DATA(insert OID = 2280 ( language_handler	PGNSP PGUID  4 t p t \054 0 0 language_handler_in language_handler_out	i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2280 ( language_handler	PGNSP PGUID  4 t p t \054 0 0 language_handler_in language_handler_out - -	i p f 0 -1 0 _null_ _null_ ));
 #define LANGUAGE_HANDLEROID		2280
-DATA(insert OID = 2281 ( internal		PGNSP PGUID  4 t p t \054 0 0 internal_in internal_out	i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2281 ( internal		PGNSP PGUID  4 t p t \054 0 0 internal_in internal_out - -	i p f 0 -1 0 _null_ _null_ ));
 #define INTERNALOID		2281
-DATA(insert OID = 2282 ( opaque			PGNSP PGUID  4 t p t \054 0 0 opaque_in opaque_out	i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2282 ( opaque			PGNSP PGUID  4 t p t \054 0 0 opaque_in opaque_out - -	i p f 0 -1 0 _null_ _null_ ));
 #define OPAQUEOID		2282
-DATA(insert OID = 2283 ( anyelement		PGNSP PGUID  4 t p t \054 0 0 anyelement_in anyelement_out	i p f 0 -1 0 _null_ _null_ ));
+DATA(insert OID = 2283 ( anyelement		PGNSP PGUID  4 t p t \054 0 0 anyelement_in anyelement_out - -	i p f 0 -1 0 _null_ _null_ ));
 #define ANYELEMENTOID	2283
 
 /*
@@ -551,6 +555,8 @@ extern Oid	TypeCreate(const char *typeName,
 		   char typDelim,
 		   Oid inputProcedure,
 		   Oid outputProcedure,
+		   Oid receiveProcedure,
+		   Oid sendProcedure,
 		   Oid elementType,
 		   Oid baseType,
 		   const char *defaultTypeValue,
@@ -568,6 +574,8 @@ extern void GenerateTypeDependencies(Oid typeNamespace,
 									 char relationKind,
 									 Oid inputProcedure,
 									 Oid outputProcedure,
+									 Oid receiveProcedure,
+									 Oid sendProcedure,
 									 Oid elementType,
 									 Oid baseType,
 									 Node *defaultExpr,
diff --git a/src/include/utils/array.h b/src/include/utils/array.h
index 25f6abe6275..23a1d2b30e0 100644
--- a/src/include/utils/array.h
+++ b/src/include/utils/array.h
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: array.h,v 1.37 2003/04/08 23:20:04 tgl Exp $
+ * $Id: array.h,v 1.38 2003/05/08 22:19:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -82,6 +82,8 @@ typedef struct
  */
 extern Datum array_in(PG_FUNCTION_ARGS);
 extern Datum array_out(PG_FUNCTION_ARGS);
+extern Datum array_recv(PG_FUNCTION_ARGS);
+extern Datum array_send(PG_FUNCTION_ARGS);
 extern Datum array_length_coerce(PG_FUNCTION_ARGS);
 extern Datum array_eq(PG_FUNCTION_ARGS);
 extern Datum array_dims(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 224240d2f97..c5971679ce4 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: builtins.h,v 1.211 2003/04/08 23:20:04 tgl Exp $
+ * $Id: builtins.h,v 1.212 2003/05/08 22:19:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -346,6 +346,8 @@ extern Datum oidvectorgt(PG_FUNCTION_ARGS);
 /* pseudotypes.c */
 extern Datum record_in(PG_FUNCTION_ARGS);
 extern Datum record_out(PG_FUNCTION_ARGS);
+extern Datum record_recv(PG_FUNCTION_ARGS);
+extern Datum record_send(PG_FUNCTION_ARGS);
 extern Datum cstring_in(PG_FUNCTION_ARGS);
 extern Datum cstring_out(PG_FUNCTION_ARGS);
 extern Datum any_in(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
index d90dea6bc6c..0c31a5051ce 100644
--- a/src/test/regress/expected/oidjoins.out
+++ b/src/test/regress/expected/oidjoins.out
@@ -537,3 +537,19 @@ WHERE	typoutput != 0 AND
 ------+-----------
 (0 rows)
 
+SELECT	ctid, typreceive 
+FROM	pg_catalog.pg_type fk 
+WHERE	typreceive != 0 AND 
+	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typreceive);
+ ctid | typreceive 
+------+------------
+(0 rows)
+
+SELECT	ctid, typsend 
+FROM	pg_catalog.pg_type fk 
+WHERE	typsend != 0 AND 
+	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typsend);
+ ctid | typsend 
+------+---------
+(0 rows)
+
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index b8e8d4fcf00..c6fcb505c70 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -139,6 +139,53 @@ WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
 -----+---------+-----+---------
 (0 rows)
 
+-- Check for bogus typreceive routines
+SELECT p1.oid, p1.typname, p2.oid, p2.proname
+FROM pg_type AS p1, pg_proc AS p2
+WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND NOT
+    (p2.pronargs = 1 AND p2.proargtypes[0] = 'internal'::regtype);
+ oid | typname | oid | proname 
+-----+---------+-----+---------
+(0 rows)
+
+SELECT p1.oid, p1.typname, p2.oid, p2.proname
+FROM pg_type AS p1, pg_proc AS p2
+WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND NOT
+    (p1.typelem != 0 AND p1.typlen < 0) AND NOT
+    (p2.prorettype = p1.oid AND NOT p2.proretset);
+ oid | typname | oid | proname 
+-----+---------+-----+---------
+(0 rows)
+
+-- Varlena array types will point to array_recv
+SELECT p1.oid, p1.typname, p2.oid, p2.proname
+FROM pg_type AS p1, pg_proc AS p2
+WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND
+    (p1.typelem != 0 AND p1.typlen < 0) AND NOT
+    (p2.oid = 'array_recv'::regproc);
+ oid | typname | oid | proname 
+-----+---------+-----+---------
+(0 rows)
+
+-- Check for bogus typsend routines
+SELECT p1.oid, p1.typname, p2.oid, p2.proname
+FROM pg_type AS p1, pg_proc AS p2
+WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT
+    ((p2.pronargs = 1 AND p2.proargtypes[0] = p1.oid) OR
+     (p2.oid = 'array_send'::regproc AND
+      p1.typelem != 0 AND p1.typlen = -1));
+ oid | typname | oid | proname 
+-----+---------+-----+---------
+(0 rows)
+
+SELECT p1.oid, p1.typname, p2.oid, p2.proname
+FROM pg_type AS p1, pg_proc AS p2
+WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT
+    (p2.prorettype = 'bytea'::regtype AND NOT p2.proretset);
+ oid | typname | oid | proname 
+-----+---------+-----+---------
+(0 rows)
+
 -- **************** pg_class ****************
 -- Look for illegal values in pg_class fields
 SELECT p1.oid, p1.relname
diff --git a/src/test/regress/sql/oidjoins.sql b/src/test/regress/sql/oidjoins.sql
index 94f2ffba554..a9df8f666a1 100644
--- a/src/test/regress/sql/oidjoins.sql
+++ b/src/test/regress/sql/oidjoins.sql
@@ -269,3 +269,11 @@ SELECT	ctid, typoutput
 FROM	pg_catalog.pg_type fk 
 WHERE	typoutput != 0 AND 
 	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typoutput);
+SELECT	ctid, typreceive 
+FROM	pg_catalog.pg_type fk 
+WHERE	typreceive != 0 AND 
+	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typreceive);
+SELECT	ctid, typsend 
+FROM	pg_catalog.pg_type fk 
+WHERE	typsend != 0 AND 
+	NOT EXISTS(SELECT 1 FROM pg_catalog.pg_proc pk WHERE pk.oid = fk.typsend);
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index 1d3f998d23b..043a65934d2 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -109,6 +109,40 @@ FROM pg_type AS p1, pg_proc AS p2
 WHERE p1.typoutput = p2.oid AND p1.typtype in ('b', 'p') AND NOT
     (p2.prorettype = 'cstring'::regtype AND NOT p2.proretset);
 
+-- Check for bogus typreceive routines
+
+SELECT p1.oid, p1.typname, p2.oid, p2.proname
+FROM pg_type AS p1, pg_proc AS p2
+WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND NOT
+    (p2.pronargs = 1 AND p2.proargtypes[0] = 'internal'::regtype);
+
+SELECT p1.oid, p1.typname, p2.oid, p2.proname
+FROM pg_type AS p1, pg_proc AS p2
+WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND NOT
+    (p1.typelem != 0 AND p1.typlen < 0) AND NOT
+    (p2.prorettype = p1.oid AND NOT p2.proretset);
+
+-- Varlena array types will point to array_recv
+SELECT p1.oid, p1.typname, p2.oid, p2.proname
+FROM pg_type AS p1, pg_proc AS p2
+WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND
+    (p1.typelem != 0 AND p1.typlen < 0) AND NOT
+    (p2.oid = 'array_recv'::regproc);
+
+-- Check for bogus typsend routines
+
+SELECT p1.oid, p1.typname, p2.oid, p2.proname
+FROM pg_type AS p1, pg_proc AS p2
+WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT
+    ((p2.pronargs = 1 AND p2.proargtypes[0] = p1.oid) OR
+     (p2.oid = 'array_send'::regproc AND
+      p1.typelem != 0 AND p1.typlen = -1));
+
+SELECT p1.oid, p1.typname, p2.oid, p2.proname
+FROM pg_type AS p1, pg_proc AS p2
+WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT
+    (p2.prorettype = 'bytea'::regtype AND NOT p2.proretset);
+
 -- **************** pg_class ****************
 
 -- Look for illegal values in pg_class fields
-- 
GitLab