From 5ecd4e3f3035d831a8c7581401651911234c2d92 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 9 May 2003 15:44:42 +0000
Subject: [PATCH] Binary send/receive routines for a few basic datatypes ---
 enough for testing purposes.

---
 src/backend/libpq/pqformat.c              | 186 ++++++++++++++-
 src/backend/utils/adt/int.c               |  92 ++++++-
 src/backend/utils/adt/int8.c              |  44 ++--
 src/backend/utils/adt/oid.c               |  69 +++++-
 src/backend/utils/adt/varlena.c           | 115 ++++++++-
 src/include/catalog/catversion.h          |   4 +-
 src/include/catalog/pg_proc.h             | 278 ++++++++++++----------
 src/include/catalog/pg_type.h             |  22 +-
 src/include/libpq/pqformat.h              |   9 +-
 src/include/utils/builtins.h              |  18 +-
 src/include/utils/int8.h                  |   4 +-
 src/test/regress/expected/type_sanity.out |  24 +-
 src/test/regress/sql/type_sanity.sql      |  10 +-
 13 files changed, 691 insertions(+), 184 deletions(-)

diff --git a/src/backend/libpq/pqformat.c b/src/backend/libpq/pqformat.c
index 6f574e383b7..65fb49f48a5 100644
--- a/src/backend/libpq/pqformat.c
+++ b/src/backend/libpq/pqformat.c
@@ -15,10 +15,16 @@
  * pq_getmessage, and then parsed and converted from that using the routines
  * in this module.
  *
+ * These same routines support reading and writing of external binary formats
+ * (typsend/typreceive routines).  The conversion routines for individual
+ * data types are exactly the same, only initialization and completion
+ * are different.
+ *
+ *
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.29 2003/05/08 18:16:36 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/libpq/pqformat.c,v 1.30 2003/05/09 15:44:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,14 +34,20 @@
  *		pq_beginmessage - initialize StringInfo buffer
  *		pq_sendbyte		- append a raw byte to a StringInfo buffer
  *		pq_sendint		- append a binary integer to a StringInfo buffer
+ *		pq_sendint64	- append a binary 8-byte int to a StringInfo buffer
  *		pq_sendbytes	- append raw data to a StringInfo buffer
- *		pq_sendcountedtext - append a text string (with character set conversion)
+ *		pq_sendcountedtext - append a counted text string (with character set conversion)
+ *		pq_sendtext		- append a text string (with conversion)
  *		pq_sendstring	- append a null-terminated text string (with conversion)
  *		pq_endmessage	- send the completed message to the frontend
  * Note: it is also possible to append data to the StringInfo buffer using
  * the regular StringInfo routines, but this is discouraged since required
  * character set conversion may not occur.
  *
+ * typsend support (construct a bytea value containing external binary data):
+ *		pq_begintypsend - initialize StringInfo buffer
+ *		pq_endtypsend	- return the completed string as a "bytea*"
+ *
  * Special-case message output:
  *		pq_puttextmessage - generate a character set-converted message in one step
  *		pq_putemptymessage - convenience routine for message with empty body
@@ -43,8 +55,10 @@
  * Message parsing after input:
  *		pq_getmsgbyte	- get a raw byte from a message buffer
  *		pq_getmsgint	- get a binary integer from a message buffer
+ *		pq_getmsgint64	- get a binary 8-byte int from a message buffer
  *		pq_getmsgbytes	- get raw data from a message buffer
  *		pq_copymsgbytes	- copy raw data from a message buffer
+ *		pq_getmsgtext	- get a counted text string (with conversion)
  *		pq_getmsgstring	- get a null-terminated text string (with conversion)
  *		pq_getmsgend	- verify message fully consumed
  */
@@ -101,7 +115,7 @@ pq_sendbytes(StringInfo buf, const char *data, int datalen)
 }
 
 /* --------------------------------
- *		pq_sendcountedtext - append a text string (with character set conversion)
+ *		pq_sendcountedtext - append a counted text string (with character set conversion)
  *
  * The data sent to the frontend by this routine is a 4-byte count field
  * followed by the string.  The count includes itself or not, as per the
@@ -132,6 +146,34 @@ pq_sendcountedtext(StringInfo buf, const char *str, int slen,
 	}
 }
 
+/* --------------------------------
+ *		pq_sendtext		- append a text string (with conversion)
+ *
+ * The passed text string need not be null-terminated, and the data sent
+ * to the frontend isn't either.  Note that this is not actually useful
+ * for direct frontend transmissions, since there'd be no way for the
+ * frontend to determine the string length.  But it is useful for binary
+ * format conversions.
+ * --------------------------------
+ */
+void
+pq_sendtext(StringInfo buf, const char *str, int slen)
+{
+	char	   *p;
+
+	p = (char *) pg_server_to_client((unsigned char *) str, slen);
+	if (p != str)				/* actual conversion has been done? */
+	{
+		slen = strlen(p);
+		appendBinaryStringInfo(buf, p, slen);
+		pfree(p);
+	}
+	else
+	{
+		appendBinaryStringInfo(buf, str, slen);
+	}
+}
+
 /* --------------------------------
  *		pq_sendstring	- append a null-terminated text string (with conversion)
  *
@@ -152,9 +194,11 @@ pq_sendstring(StringInfo buf, const char *str)
 		slen = strlen(p);
 		appendBinaryStringInfo(buf, p, slen + 1);
 		pfree(p);
-		return;
 	}
-	appendBinaryStringInfo(buf, str, slen + 1);
+	else
+	{
+		appendBinaryStringInfo(buf, str, slen + 1);
+	}
 }
 
 /* --------------------------------
@@ -188,6 +232,35 @@ pq_sendint(StringInfo buf, int i, int b)
 	}
 }
 
+/* --------------------------------
+ *		pq_sendint64	- append a binary 8-byte int to a StringInfo buffer
+ *
+ * It is tempting to merge this with pq_sendint, but we'd have to make the
+ * argument int64 for all data widths --- that could be a big performance
+ * hit on machines where int64 isn't efficient.
+ * --------------------------------
+ */
+void
+pq_sendint64(StringInfo buf, int64 i)
+{
+	uint32		n32;
+
+	/* High order half first, since we're doing MSB-first */
+#ifdef INT64_IS_BUSTED
+	/* don't try a right shift of 32 on a 32-bit word */
+	n32 = (i < 0) ? -1 : 0;
+#else
+	n32 = (uint32) (i >> 32);
+#endif
+	n32 = htonl(n32);
+	appendBinaryStringInfo(buf, (char *) &n32, 4);
+
+	/* Now the low order half */
+	n32 = (uint32) i;
+	n32 = htonl(n32);
+	appendBinaryStringInfo(buf, (char *) &n32, 4);
+}
+
 /* --------------------------------
  *		pq_endmessage	- send the completed message to the frontend
  *
@@ -205,6 +278,44 @@ pq_endmessage(StringInfo buf)
 	buf->data = NULL;
 }
 
+
+/* --------------------------------
+ *		pq_begintypsend		- initialize for constructing a bytea result
+ * --------------------------------
+ */
+void
+pq_begintypsend(StringInfo buf)
+{
+	initStringInfo(buf);
+	/* Reserve four bytes for the bytea length word */
+	appendStringInfoCharMacro(buf, '\0');
+	appendStringInfoCharMacro(buf, '\0');
+	appendStringInfoCharMacro(buf, '\0');
+	appendStringInfoCharMacro(buf, '\0');
+}
+
+/* --------------------------------
+ *		pq_endtypsend	- finish constructing a bytea result
+ *
+ * The data buffer is returned as the palloc'd bytea value.  (We expect
+ * that it will be suitably aligned for this because it has been palloc'd.)
+ * We assume the StringInfoData is just a local variable in the caller and
+ * need not be pfree'd.
+ * --------------------------------
+ */
+bytea *
+pq_endtypsend(StringInfo buf)
+{
+	bytea	   *result = (bytea *) buf->data;
+
+	/* Insert correct length into bytea length word */
+	Assert(buf->len >= VARHDRSZ);
+	VARATT_SIZEP(result) = buf->len;
+
+	return result;
+}
+
+
 /* --------------------------------
  *		pq_puttextmessage - generate a character set-converted message in one step
  *
@@ -289,6 +400,38 @@ pq_getmsgint(StringInfo msg, int b)
 	return result;
 }
 
+/* --------------------------------
+ *		pq_getmsgint64	- get a binary 8-byte int from a message buffer
+ *
+ * It is tempting to merge this with pq_getmsgint, but we'd have to make the
+ * result int64 for all data widths --- that could be a big performance
+ * hit on machines where int64 isn't efficient.
+ * --------------------------------
+ */
+int64
+pq_getmsgint64(StringInfo msg)
+{
+	int64		result;
+	uint32		h32;
+	uint32		l32;
+
+	pq_copymsgbytes(msg, (char *) &h32, 4);
+	pq_copymsgbytes(msg, (char *) &l32, 4);
+	h32 = ntohl(h32);
+	l32 = ntohl(l32);
+
+#ifdef INT64_IS_BUSTED
+	/* just lose the high half */
+	result = l32;
+#else
+	result = h32;
+	result <<= 32;
+	result |= l32;
+#endif
+
+	return result;
+}
+
 /* --------------------------------
  *		pq_getmsgbytes	- get raw data from a message buffer
  *
@@ -323,6 +466,39 @@ pq_copymsgbytes(StringInfo msg, char *buf, int datalen)
 	msg->cursor += datalen;
 }
 
+/* --------------------------------
+ *		pq_getmsgtext	- get a counted text string (with conversion)
+ *
+ *		Always returns a pointer to a freshly palloc'd result.
+ *		The result has a trailing null, *and* we return its strlen in *nbytes.
+ * --------------------------------
+ */
+char *
+pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
+{
+	char   *str;
+	char   *p;
+
+	if (rawbytes < 0 || rawbytes > (msg->len - msg->cursor))
+		elog(ERROR, "pq_getmsgtext: insufficient data left in message");
+	str = &msg->data[msg->cursor];
+	msg->cursor += rawbytes;
+
+	p = (char *) pg_client_to_server((unsigned char *) str, rawbytes);
+	if (p != str)				/* actual conversion has been done? */
+	{
+		*nbytes = strlen(p);
+	}
+	else
+	{
+		p = (char *) palloc(rawbytes + 1);
+		memcpy(p, str, rawbytes);
+		p[rawbytes] = '\0';
+		*nbytes = rawbytes;
+	}
+	return p;
+}
+
 /* --------------------------------
  *		pq_getmsgstring	- get a null-terminated text string (with conversion)
  *
diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c
index 73687d55ec9..141312d6674 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -8,14 +8,16 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/int.c,v 1.53 2003/03/11 21:01:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/int.c,v 1.54 2003/05/09 15:44:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * OLD COMMENTS
  *		I/O routines:
- *		 int2in, int2out, int2vectorin, int2vectorout, int4in, int4out
+ *		 int2in, int2out, int2recv, int2send
+ *		 int4in, int4out, int4recv, int4send
+ *		 int2vectorin, int2vectorout, int2vectorrecv, int2vectorsend
  *		Conversion routines:
  *		 itoi, int2_text, int4_text
  *		Boolean operators:
@@ -32,6 +34,7 @@
 #include <ctype.h>
 #include <limits.h>
 
+#include "libpq/pqformat.h"
 #include "utils/builtins.h"
 
 #ifndef SHRT_MAX
@@ -69,6 +72,31 @@ int2out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(result);
 }
 
+/*
+ *		int2recv			- converts external binary format to int2
+ */
+Datum
+int2recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+
+	PG_RETURN_INT16((int16) pq_getmsgint(buf, sizeof(int16)));
+}
+
+/*
+ *		int2send			- converts int2 to binary format
+ */
+Datum
+int2send(PG_FUNCTION_ARGS)
+{
+	int16		arg1 = PG_GETARG_INT16(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendint(&buf, arg1, sizeof(int16));
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
 /*
  *		int2vectorin			- converts "num num ..." to internal form
  *
@@ -131,6 +159,41 @@ int2vectorout(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(result);
 }
 
+/*
+ *		int2vectorrecv			- converts external binary format to int2vector
+ */
+Datum
+int2vectorrecv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	int16	   *result = (int16 *) palloc(sizeof(int16[INDEX_MAX_KEYS]));
+	int			slot;
+
+	for (slot = 0; slot < INDEX_MAX_KEYS; slot++)
+	{
+		result[slot] = (int16) pq_getmsgint(buf, sizeof(int16));
+	}
+	PG_RETURN_POINTER(result);
+}
+
+/*
+ *		int2vectorsend			- converts int2vector to binary format
+ */
+Datum
+int2vectorsend(PG_FUNCTION_ARGS)
+{
+	int16	   *int2Array = (int16 *) PG_GETARG_POINTER(0);
+	StringInfoData buf;
+	int			slot;
+
+	pq_begintypsend(&buf);
+	for (slot = 0; slot < INDEX_MAX_KEYS; slot++)
+	{
+		pq_sendint(&buf, int2Array[slot], sizeof(int16));
+	}
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
 /*
  * We don't have a complete set of int2vector support routines,
  * but we need int2vectoreq for catcache indexing.
@@ -173,6 +236,31 @@ int4out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(result);
 }
 
+/*
+ *		int4recv			- converts external binary format to int4
+ */
+Datum
+int4recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+
+	PG_RETURN_INT32((int32) pq_getmsgint(buf, sizeof(int32)));
+}
+
+/*
+ *		int4send			- converts int4 to binary format
+ */
+Datum
+int4send(PG_FUNCTION_ARGS)
+{
+	int32		arg1 = PG_GETARG_INT32(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendint(&buf, arg1, sizeof(int32));
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
 
 /*
  *		===================
diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c
index cf164561058..30ec836cd6d 100644
--- a/src/backend/utils/adt/int8.c
+++ b/src/backend/utils/adt/int8.c
@@ -7,36 +7,21 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.43 2003/03/11 21:01:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.44 2003/05/09 15:44:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <ctype.h>
-#include <time.h>
 #include <math.h>
-#include <float.h>
-#include <limits.h>
 
+#include "libpq/pqformat.h"
 #include "utils/int8.h"
 
 
 #define MAXINT8LEN		25
 
-#ifndef INT_MAX
-#define INT_MAX (0x7FFFFFFFL)
-#endif
-#ifndef INT_MIN
-#define INT_MIN (-INT_MAX-1)
-#endif
-#ifndef SHRT_MAX
-#define SHRT_MAX (0x7FFF)
-#endif
-#ifndef SHRT_MIN
-#define SHRT_MIN (-SHRT_MAX-1)
-#endif
-
 
 /***********************************************************************
  **
@@ -160,6 +145,31 @@ int8out(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(result);
 }
 
+/*
+ *		int8recv			- converts external binary format to int8
+ */
+Datum
+int8recv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+
+	PG_RETURN_INT64(pq_getmsgint64(buf));
+}
+
+/*
+ *		int8send			- converts int8 to binary format
+ */
+Datum
+int8send(PG_FUNCTION_ARGS)
+{
+	int64		arg1 = PG_GETARG_INT64(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendint64(&buf, arg1);
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
 
 /*----------------------------------------------------------
  *	Relational operators for int8s, including cross-data-type comparisons.
diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c
index 7404fc5b7b5..1a0a89605bb 100644
--- a/src/backend/utils/adt/oid.c
+++ b/src/backend/utils/adt/oid.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/oid.c,v 1.47 2002/06/20 20:29:38 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/oid.c,v 1.48 2003/05/09 15:44:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,8 +18,10 @@
 #include <errno.h>
 #include <limits.h>
 
+#include "libpq/pqformat.h"
 #include "utils/builtins.h"
 
+
 /*****************************************************************************
  *	 USER I/O ROUTINES														 *
  *****************************************************************************/
@@ -108,6 +110,31 @@ oidout(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(result);
 }
 
+/*
+ *		oidrecv			- converts external binary format to oid
+ */
+Datum
+oidrecv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+
+	PG_RETURN_OID((Oid) pq_getmsgint(buf, sizeof(Oid)));
+}
+
+/*
+ *		oidsend			- converts oid to binary format
+ */
+Datum
+oidsend(PG_FUNCTION_ARGS)
+{
+	Oid			arg1 = PG_GETARG_OID(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendint(&buf, arg1, sizeof(Oid));
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
 
 /*
  *		oidvectorin			- converts "num num ..." to internal form
@@ -119,11 +146,9 @@ Datum
 oidvectorin(PG_FUNCTION_ARGS)
 {
 	char	   *oidString = PG_GETARG_CSTRING(0);
-	Oid		   *result;
+	Oid		   *result = (Oid *) palloc(sizeof(Oid[INDEX_MAX_KEYS]));
 	int			slot;
 
-	result = (Oid *) palloc(sizeof(Oid[INDEX_MAX_KEYS]));
-
 	for (slot = 0; slot < INDEX_MAX_KEYS; slot++)
 	{
 		while (*oidString && isspace((unsigned char) *oidString))
@@ -173,6 +198,42 @@ oidvectorout(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(result);
 }
 
+/*
+ *		oidvectorrecv			- converts external binary format to oidvector
+ */
+Datum
+oidvectorrecv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	Oid		   *result = (Oid *) palloc(sizeof(Oid[INDEX_MAX_KEYS]));
+	int			slot;
+
+	for (slot = 0; slot < INDEX_MAX_KEYS; slot++)
+	{
+		result[slot] = (Oid) pq_getmsgint(buf, sizeof(Oid));
+	}
+	PG_RETURN_POINTER(result);
+}
+
+/*
+ *		oidvectorsend			- converts oidvector to binary format
+ */
+Datum
+oidvectorsend(PG_FUNCTION_ARGS)
+{
+	Oid		   *oidArray = (Oid *) PG_GETARG_POINTER(0);
+	StringInfoData buf;
+	int			slot;
+
+	pq_begintypsend(&buf);
+	for (slot = 0; slot < INDEX_MAX_KEYS; slot++)
+	{
+		pq_sendint(&buf, oidArray[slot], sizeof(Oid));
+	}
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+
 /*****************************************************************************
  *	 PUBLIC ROUTINES														 *
  *****************************************************************************/
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 7f928ec8acd..2a5f97ff028 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.96 2003/04/24 21:16:43 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.97 2003/05/09 15:44:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,16 +20,20 @@
 #include "miscadmin.h"
 #include "access/tuptoaster.h"
 #include "lib/stringinfo.h"
+#include "libpq/crypt.h"
+#include "libpq/pqformat.h"
 #include "utils/builtins.h"
 #include "utils/pg_locale.h"
 
-extern bool md5_hash(const void *buff, size_t len, char *hexsum);
 
 typedef struct varlena unknown;
 
 #define DatumGetUnknownP(X)			((unknown *) PG_DETOAST_DATUM(X))
+#define DatumGetUnknownPCopy(X)		((unknown *) PG_DETOAST_DATUM_COPY(X))
 #define PG_GETARG_UNKNOWN_P(n)		DatumGetUnknownP(PG_GETARG_DATUM(n))
+#define PG_GETARG_UNKNOWN_P_COPY(n)	DatumGetUnknownPCopy(PG_GETARG_DATUM(n))
 #define PG_RETURN_UNKNOWN_P(x)		PG_RETURN_POINTER(x)
+
 #define PG_TEXTARG_GET_STR(arg_) \
 	DatumGetCString(DirectFunctionCall1(textout, PG_GETARG_DATUM(arg_)))
 #define PG_TEXT_GET_STR(textp_) \
@@ -111,10 +115,10 @@ byteain(PG_FUNCTION_ARGS)
 
 	byte += VARHDRSZ;
 	result = (bytea *) palloc(byte);
-	result->vl_len = byte;		/* set varlena length */
+	VARATT_SIZEP(result) = byte;		/* set varlena length */
 
 	tp = inputText;
-	rp = result->vl_dat;
+	rp = VARDATA(result);
 	while (*tp != '\0')
 	{
 		if (tp[0] != '\\')
@@ -170,8 +174,8 @@ byteaout(PG_FUNCTION_ARGS)
 	int			len;
 
 	len = 1;					/* empty string has 1 char */
-	vp = vlena->vl_dat;
-	for (i = vlena->vl_len - VARHDRSZ; i != 0; i--, vp++)
+	vp = VARDATA(vlena);
+	for (i = VARSIZE(vlena) - VARHDRSZ; i != 0; i--, vp++)
 	{
 		if (*vp == '\\')
 			len += 2;
@@ -181,8 +185,8 @@ byteaout(PG_FUNCTION_ARGS)
 			len += 4;
 	}
 	rp = result = (char *) palloc(len);
-	vp = vlena->vl_dat;
-	for (i = vlena->vl_len - VARHDRSZ; i != 0; i--, vp++)
+	vp = VARDATA(vlena);
+	for (i = VARSIZE(vlena) - VARHDRSZ; i != 0; i--, vp++)
 	{
 		if (*vp == '\\')
 		{
@@ -207,6 +211,36 @@ byteaout(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(result);
 }
 
+/*
+ *		bytearecv			- converts external binary format to bytea
+ */
+Datum
+bytearecv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	bytea	   *result;
+	int			nbytes;
+
+	nbytes = buf->len - buf->cursor;
+	result = (bytea *) palloc(nbytes + VARHDRSZ);
+	VARATT_SIZEP(result) = nbytes + VARHDRSZ;
+	pq_copymsgbytes(buf, VARDATA(result), nbytes);
+	PG_RETURN_BYTEA_P(result);
+}
+
+/*
+ *		byteasend			- converts bytea to binary format
+ *
+ * This is a special case: just copy the input...
+ */
+Datum
+byteasend(PG_FUNCTION_ARGS)
+{
+	bytea	   *vlena = PG_GETARG_BYTEA_P_COPY(0);
+
+	PG_RETURN_BYTEA_P(vlena);
+}
+
 
 /*
  *		textin			- converts "..." to internal representation
@@ -259,6 +293,39 @@ textout(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(result);
 }
 
+/*
+ *		textrecv			- converts external binary format to text
+ */
+Datum
+textrecv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	text	   *result;
+	char	   *str;
+	int			nbytes;
+
+	str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
+	result = (text *) palloc(nbytes + VARHDRSZ);
+	VARATT_SIZEP(result) = nbytes + VARHDRSZ;
+	memcpy(VARDATA(result), str, nbytes);
+	pfree(str);
+	PG_RETURN_TEXT_P(result);
+}
+
+/*
+ *		textsend			- converts text to binary format
+ */
+Datum
+textsend(PG_FUNCTION_ARGS)
+{
+	text	   *t = PG_GETARG_TEXT_P(0);
+	StringInfoData buf;
+
+	pq_begintypsend(&buf);
+	pq_sendtext(&buf, VARDATA(t), VARSIZE(t) - VARHDRSZ);
+	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
 
 /*
  *		unknownin			- converts "..." to internal representation
@@ -280,7 +347,6 @@ unknownin(PG_FUNCTION_ARGS)
 	PG_RETURN_UNKNOWN_P(result);
 }
 
-
 /*
  *		unknownout			- converts internal representation to "..."
  */
@@ -299,6 +365,37 @@ unknownout(PG_FUNCTION_ARGS)
 	PG_RETURN_CSTRING(result);
 }
 
+/*
+ *		unknownrecv			- converts external binary format to unknown
+ */
+Datum
+unknownrecv(PG_FUNCTION_ARGS)
+{
+	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
+	unknown	   *result;
+	int			nbytes;
+
+	nbytes = buf->len - buf->cursor;
+	result = (unknown *) palloc(nbytes + VARHDRSZ);
+	VARATT_SIZEP(result) = nbytes + VARHDRSZ;
+	pq_copymsgbytes(buf, VARDATA(result), nbytes);
+	PG_RETURN_UNKNOWN_P(result);
+}
+
+/*
+ *		unknownsend			- converts unknown to binary format
+ *
+ * This is a special case: just copy the input, since it's
+ * effectively the same format as bytea
+ */
+Datum
+unknownsend(PG_FUNCTION_ARGS)
+{
+	unknown	   *vlena = PG_GETARG_UNKNOWN_P_COPY(0);
+
+	PG_RETURN_UNKNOWN_P(vlena);
+}
+
 
 /* ========== PUBLIC ROUTINES ========== */
 
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 97bac4df326..8046e5c4c68 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.187 2003/05/08 22:19:56 tgl Exp $
+ * $Id: catversion.h,v 1.188 2003/05/09 15:44:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200305081
+#define CATALOG_VERSION_NO	200305091
 
 #endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index d4904f77120..0d801214f58 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.294 2003/05/08 22:19:57 tgl Exp $
+ * $Id: pg_proc.h,v 1.295 2003/05/09 15:44:40 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -94,57 +94,57 @@ typedef FormData_pg_proc *Form_pg_proc;
 /* OIDS 1 - 99 */
 
 DATA(insert OID = 1242 (  boolin		   PGNSP PGUID 12 f f t f i 1 16 "2275"  boolin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1243 (  boolout		   PGNSP PGUID 12 f f t f i 1 2275 "16" boolout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1244 (  byteain		   PGNSP PGUID 12 f f t f i 1 17 "2275" byteain - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  31 (  byteaout		   PGNSP PGUID 12 f f t f i 1 2275 "17" byteaout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1245 (  charin		   PGNSP PGUID 12 f f t f i 1 18 "2275" charin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  33 (  charout		   PGNSP PGUID 12 f f t f i 1 2275 "18" charout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  34 (  namein			   PGNSP PGUID 12 f f t f i 1 19 "2275" namein - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  35 (  nameout		   PGNSP PGUID 12 f f t f i 1 2275 "19" nameout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  38 (  int2in			   PGNSP PGUID 12 f f t f i 1 21 "2275" int2in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  39 (  int2out		   PGNSP PGUID 12 f f t f i 1 2275 "21" int2out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  40 (  int2vectorin	   PGNSP PGUID 12 f f t f i 1 22 "2275" int2vectorin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  41 (  int2vectorout	   PGNSP PGUID 12 f f t f i 1 2275 "22" int2vectorout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  42 (  int4in			   PGNSP PGUID 12 f f t f i 1 23 "2275" int4in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  43 (  int4out		   PGNSP PGUID 12 f f t f i 1 2275 "23" int4out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  44 (  regprocin		   PGNSP PGUID 12 f f t f s 1 24 "2275" regprocin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  45 (  regprocout		   PGNSP PGUID 12 f f t f s 1 2275 "24" regprocout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  46 (  textin			   PGNSP PGUID 12 f f t f i 1 25 "2275" textin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  47 (  textout		   PGNSP PGUID 12 f f t f i 1 2275 "25" textout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  48 (  tidin			   PGNSP PGUID 12 f f t f i 1 27 "2275" tidin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  49 (  tidout			   PGNSP PGUID 12 f f t f i 1 2275 "27" tidout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  50 (  xidin			   PGNSP PGUID 12 f f t f i 1 28 "2275" xidin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  51 (  xidout			   PGNSP PGUID 12 f f t f i 1 2275 "28" xidout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  52 (  cidin			   PGNSP PGUID 12 f f t f i 1 29 "2275" cidin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  53 (  cidout			   PGNSP PGUID 12 f f t f i 1 2275 "29" cidout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  54 (  oidvectorin	   PGNSP PGUID 12 f f t f i 1 30 "2275" oidvectorin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  55 (  oidvectorout	   PGNSP PGUID 12 f f t f i 1 2275 "30" oidvectorout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  56 (  boollt			   PGNSP PGUID 12 f f t f i 2 16 "16 16"	boollt - _null_ ));
 DESCR("less-than");
 DATA(insert OID =  57 (  boolgt			   PGNSP PGUID 12 f f t f i 2 16 "16 16"	boolgt - _null_ ));
@@ -228,9 +228,9 @@ DATA(insert OID = 108 (  scalargtjoinsel   PGNSP PGUID 12 f f t f s 4 701 "2281
 DESCR("join selectivity of > and related operators on scalar datatypes");
 
 DATA(insert OID =  109 (  unknownin		   PGNSP PGUID 12 f f t f i 1 705 "2275"	unknownin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  110 (  unknownout	   PGNSP PGUID 12 f f t f i 1 2275	"705"	unknownout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 
 DATA(insert OID = 112 (  text			   PGNSP PGUID 12 f f t f i 1  25 "23"	int4_text - _null_ ));
 DESCR("convert int4 to text");
@@ -245,21 +245,21 @@ DATA(insert OID = 116 (  box_below		   PGNSP PGUID 12 f f t f i 2  16 "603 603"
 DESCR("is below");
 
 DATA(insert OID = 117 (  point_in		   PGNSP PGUID 12 f f t f i 1 600 "2275"  point_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 118 (  point_out		   PGNSP PGUID 12 f f t f i 1 2275 "600"  point_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 119 (  lseg_in		   PGNSP PGUID 12 f f t f i 1 601 "2275"  lseg_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 120 (  lseg_out		   PGNSP PGUID 12 f f t f i 1 2275 "601"  lseg_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 121 (  path_in		   PGNSP PGUID 12 f f t f i 1 602 "2275"  path_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 122 (  path_out		   PGNSP PGUID 12 f f t f i 1 2275 "602"  path_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 123 (  box_in			   PGNSP PGUID 12 f f t f i 1 603 "2275"  box_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 124 (  box_out		   PGNSP PGUID 12 f f t f i 1 2275 "603"  box_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 125 (  box_overlap	   PGNSP PGUID 12 f f t f i 2 16 "603 603"	box_overlap - _null_ ));
 DESCR("overlaps");
 DATA(insert OID = 126 (  box_ge			   PGNSP PGUID 12 f f t f i 2 16 "603 603"	box_ge - _null_ ));
@@ -412,9 +412,9 @@ DESCR("r-tree");
 /* OIDS 200 - 299 */
 
 DATA(insert OID = 200 (  float4in		   PGNSP PGUID 12 f f t f i 1 700 "2275"  float4in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 201 (  float4out		   PGNSP PGUID 12 f f t f i 1 2275 "700"  float4out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 202 (  float4mul		   PGNSP PGUID 12 f f t f i 2 700 "700 700"  float4mul - _null_ ));
 DESCR("multiply");
 DATA(insert OID = 203 (  float4div		   PGNSP PGUID 12 f f t f i 2 700 "700 700"  float4div - _null_ ));
@@ -440,9 +440,9 @@ DATA(insert OID = 213 (  int2um			   PGNSP PGUID 12 f f t f i 1 21 "21"  int2um
 DESCR("negate");
 
 DATA(insert OID = 214 (  float8in		   PGNSP PGUID 12 f f t f i 1 701 "2275"  float8in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 215 (  float8out		   PGNSP PGUID 12 f f t f i 1 2275 "701"  float8out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 216 (  float8mul		   PGNSP PGUID 12 f f t f i 2 701 "701 701"  float8mul - _null_ ));
 DESCR("multiply");
 DATA(insert OID = 217 (  float8div		   PGNSP PGUID 12 f f t f i 2 701 "701 701"  float8div - _null_ ));
@@ -501,21 +501,21 @@ DATA(insert OID = 239 (  line_distance	   PGNSP PGUID 12 f f t f i 2 701 "628 62
 DESCR("distance between");
 
 DATA(insert OID = 240 (  nabstimein		   PGNSP PGUID 12 f f t f s 1 702 "2275"  nabstimein - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 241 (  nabstimeout	   PGNSP PGUID 12 f f t f s 1 2275 "702"  nabstimeout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 242 (  reltimein		   PGNSP PGUID 12 f f t f s 1 703 "2275"  reltimein - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 243 (  reltimeout		   PGNSP PGUID 12 f f t f s 1 2275 "703"  reltimeout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 244 (  timepl			   PGNSP PGUID 12 f f t f i 2 702 "702 703"  timepl - _null_ ));
 DESCR("add");
 DATA(insert OID = 245 (  timemi			   PGNSP PGUID 12 f f t f i 2 702 "702 703"  timemi - _null_ ));
 DESCR("subtract");
 DATA(insert OID = 246 (  tintervalin	   PGNSP PGUID 12 f f t f s 1 704 "2275"  tintervalin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 247 (  tintervalout	   PGNSP PGUID 12 f f t f s 1 2275 "704"  tintervalout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 248 (  intinterval	   PGNSP PGUID 12 f f t f i 2 16 "702 704"	intinterval - _null_ ));
 DESCR("abstime in tinterval");
 DATA(insert OID = 249 (  tintervalrel	   PGNSP PGUID 12 f f t f i 1 703 "704"  tintervalrel - _null_ ));
@@ -732,9 +732,9 @@ DESCR("contained in?");
 DATA(insert OID = 346 (  poly_overlap	   PGNSP PGUID 12 f f t f i 2 16 "604 604"	poly_overlap - _null_ ));
 DESCR("overlaps");
 DATA(insert OID = 347 (  poly_in		   PGNSP PGUID 12 f f t f i 1 604 "2275"  poly_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 348 (  poly_out		   PGNSP PGUID 12 f f t f i 1 2275 "604"  poly_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 
 DATA(insert OID = 350 (  btint2cmp		   PGNSP PGUID 12 f f t f i 2 23 "21 21"	btint2cmp - _null_ ));
 DESCR("btree less-equal-greater");
@@ -846,9 +846,9 @@ DATA(insert OID = 459 (  text_smaller	   PGNSP PGUID 12 f f t f i 2 25 "25 25"	t
 DESCR("smaller of two");
 
 DATA(insert OID = 460 (  int8in			   PGNSP PGUID 12 f f t f i 1 20 "2275" int8in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 461 (  int8out		   PGNSP PGUID 12 f f t f i 1 2275 "20" int8out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 462 (  int8um			   PGNSP PGUID 12 f f t f i 1 20 "20"  int8um - _null_ ));
 DESCR("negate");
 DATA(insert OID = 463 (  int8pl			   PGNSP PGUID 12 f f t f i 2 20 "20 20"	int8pl - _null_ ));
@@ -1018,9 +1018,9 @@ DATA(insert OID = 384  (  array_coerce	   PGNSP PGUID 12 f f t f i 1 2277 "2277"
 DESCR("coerce array type to another array type");
 
 DATA(insert OID = 760 (  smgrin			   PGNSP PGUID 12 f f t f s 1 210 "2275"  smgrin - _null_ ));
-DESCR("storage manager(internal)");
+DESCR("I/O");
 DATA(insert OID = 761 (  smgrout		   PGNSP PGUID 12 f f t f s 1 2275 "210"  smgrout - _null_ ));
-DESCR("storage manager(internal)");
+DESCR("I/O");
 DATA(insert OID = 762 (  smgreq			   PGNSP PGUID 12 f f t f i 2 16 "210 210"	smgreq - _null_ ));
 DESCR("storage manager");
 DATA(insert OID = 763 (  smgrne			   PGNSP PGUID 12 f f t f i 2 16 "210 210"	smgrne - _null_ ));
@@ -1146,9 +1146,9 @@ DATA(insert OID =  867 (  cash_div_int2		   PGNSP PGUID 12 f f t f i 2 790 "790
 DESCR("divide");
 
 DATA(insert OID =  886 (  cash_in		   PGNSP PGUID 12 f f t f i 1 790 "2275"  cash_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  887 (  cash_out		   PGNSP PGUID 12 f f t f i 1 2275 "790"  cash_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID =  888 (  cash_eq		   PGNSP PGUID 12 f f t f i 2  16 "790 790"  cash_eq - _null_ ));
 DESCR("equal");
 DATA(insert OID =  889 (  cash_ne		   PGNSP PGUID 12 f f t f i 2  16 "790 790"  cash_ne - _null_ ));
@@ -1307,9 +1307,9 @@ DESCR("(internal)");
 DATA(insert OID = 1030 (  nonnullvalue	   PGNSP PGUID 12 f f f f i 1 16 "2276" nonnullvalue - _null_ ));
 DESCR("(internal)");
 DATA(insert OID = 1031 (  aclitemin		   PGNSP PGUID 12 f f t f s 1 1033 "2275"  aclitemin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1032 (  aclitemout	   PGNSP PGUID 12 f f t f s 1 2275 "1033"  aclitemout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1035 (  aclinsert		   PGNSP PGUID 12 f f t f s 2 1034 "1034 1033"	aclinsert - _null_ ));
 DESCR("add/update ACL item");
 DATA(insert OID = 1036 (  aclremove		   PGNSP PGUID 12 f f t f s 2 1034 "1034 1033"	aclremove - _null_ ));
@@ -1319,13 +1319,13 @@ DESCR("does ACL contain item?");
 DATA(insert OID = 1038 (  seteval		   PGNSP PGUID 12 f f t t v 1 23 "26"  seteval - _null_ ));
 DESCR("internal function supporting PostQuel-style sets");
 DATA(insert OID = 1044 (  bpcharin		   PGNSP PGUID 12 f f t f i 3 1042 "2275 26 23" bpcharin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1045 (  bpcharout		   PGNSP PGUID 12 f f t f i 1 2275 "1042"	bpcharout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1046 (  varcharin		   PGNSP PGUID 12 f f t f i 3 1043 "2275 26 23" varcharin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1047 (  varcharout	   PGNSP PGUID 12 f f t f i 1 2275 "1043"	varcharout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1048 (  bpchareq		   PGNSP PGUID 12 f f t f i 2 16 "1042 1042"	bpchareq - _null_ ));
 DESCR("equal");
 DATA(insert OID = 1049 (  bpcharlt		   PGNSP PGUID 12 f f t f i 2 16 "1042 1042"	bpcharlt - _null_ ));
@@ -1359,9 +1359,9 @@ DESCR("hash");
 DATA(insert OID = 1081 (  format_type	   PGNSP PGUID 12 f f f f s 2 25 "26 23" format_type - _null_ ));
 DESCR("format a type oid and atttypmod to canonical SQL");
 DATA(insert OID = 1084 (  date_in		   PGNSP PGUID 12 f f t f s 1 1082 "2275"	date_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1085 (  date_out		   PGNSP PGUID 12 f f t f s 1 2275 "1082"	date_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1086 (  date_eq		   PGNSP PGUID 12 f f t f i 2 16 "1082 1082"	date_eq - _null_ ));
 DESCR("equal");
 DATA(insert OID = 1087 (  date_lt		   PGNSP PGUID 12 f f t f i 2 16 "1082 1082"	date_lt - _null_ ));
@@ -1402,9 +1402,9 @@ DESCR("add");
 DATA(insert OID = 1142 (  date_mii		   PGNSP PGUID 12 f f t f i 2 1082 "1082 23"	date_mii - _null_ ));
 DESCR("subtract");
 DATA(insert OID = 1143 (  time_in		   PGNSP PGUID 12 f f t f s 3 1083 "2275 26 23"	time_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1144 (  time_out		   PGNSP PGUID 12 f f t f i 1 2275 "1083"	time_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1145 (  time_eq		   PGNSP PGUID 12 f f t f i 2 16 "1083 1083"	time_eq - _null_ ));
 DESCR("equal");
 
@@ -1418,9 +1418,9 @@ DATA(insert OID = 1149 (  circle_div_pt    PGNSP PGUID 12 f f t f i 2 718 "718 6
 DESCR("divide");
 
 DATA(insert OID = 1150 (  timestamptz_in   PGNSP PGUID 12 f f t f s 3 1184 "2275 26 23"	timestamptz_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1151 (  timestamptz_out  PGNSP PGUID 12 f f t f s 1 2275 "1184"	timestamptz_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1152 (  timestamptz_eq   PGNSP PGUID 12 f f t f i 2 16 "1184 1184"	timestamp_eq - _null_ ));
 DESCR("equal");
 DATA(insert OID = 1153 (  timestamptz_ne   PGNSP PGUID 12 f f t f i 2 16 "1184 1184"	timestamp_ne - _null_ ));
@@ -1437,9 +1437,9 @@ DATA(insert OID = 1159 (  timezone		   PGNSP PGUID 12 f f t f s 2 1114 "25 1184"
 DESCR("adjust timestamp to new time zone");
 
 DATA(insert OID = 1160 (  interval_in	   PGNSP PGUID 12 f f t f s 3 1186 "2275 26 23"	interval_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1161 (  interval_out	   PGNSP PGUID 12 f f t f i 1 2275 "1186"	interval_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1162 (  interval_eq	   PGNSP PGUID 12 f f t f i 2 16 "1186 1186"	interval_eq - _null_ ));
 DESCR("equal");
 DATA(insert OID = 1163 (  interval_ne	   PGNSP PGUID 12 f f t f i 2 16 "1186 1186"	interval_ne - _null_ ));
@@ -1628,9 +1628,9 @@ DATA(insert OID = 1311 ( overlaps			 PGNSP PGUID 14 f f f f i 4 16 "1083 1186 10
 DESCR("SQL92 interval comparison");
 
 DATA(insert OID = 1312 (  timestamp_in		 PGNSP PGUID 12 f f t f s 3 1114 "2275 26 23" timestamp_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1313 (  timestamp_out		 PGNSP PGUID 12 f f t f s 1 2275 "1114" timestamp_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1314 (  timestamptz_cmp	 PGNSP PGUID 12 f f t f i 2 23 "1184 1184"	timestamp_cmp - _null_ ));
 DESCR("less-equal-greater");
 DATA(insert OID = 1315 (  interval_cmp		 PGNSP PGUID 12 f f t f i 2 23 "1186 1186"	interval_cmp - _null_ ));
@@ -1678,9 +1678,9 @@ DESCR("print type names of oidvector field");
 
 
 DATA(insert OID = 1350 (  timetz_in		   PGNSP PGUID 12 f f t f s 3 1266 "2275 26 23"	timetz_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1351 (  timetz_out	   PGNSP PGUID 12 f f t f i 1 2275 "1266"	timetz_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1352 (  timetz_eq		   PGNSP PGUID 12 f f t f i 2 16 "1266 1266"	timetz_eq - _null_ ));
 DESCR("equal");
 DATA(insert OID = 1353 (  timetz_ne		   PGNSP PGUID 12 f f t f i 2 16 "1266 1266"	timetz_ne - _null_ ));
@@ -1885,9 +1885,9 @@ DATA(insert OID = 1449 (  polygon			PGNSP PGUID 12 f f t f i 1 604 "602"	path_po
 DESCR("convert path to polygon");
 
 DATA(insert OID = 1450 (  circle_in			PGNSP PGUID 12 f f t f i 1 718 "2275"  circle_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1451 (  circle_out		PGNSP PGUID 12 f f t f i 1 2275 "718"  circle_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1452 (  circle_same		PGNSP PGUID 12 f f t f i 2	16 "718 718"  circle_same - _null_ ));
 DESCR("same as?");
 DATA(insert OID = 1453 (  circle_contain	PGNSP PGUID 12 f f t f i 2	16 "718 718"  circle_contain - _null_ ));
@@ -1967,9 +1967,9 @@ DATA(insert OID = 1489 (  close_lseg		PGNSP PGUID 12 f f t f i 2 600 "601 601"	c
 DESCR("closest point to line segment on line segment");
 
 DATA(insert OID = 1490 (  line_in			PGNSP PGUID 12 f f t f i 1 628 "2275"  line_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1491 (  line_out			PGNSP PGUID 12 f f t f i 1 2275 "628"	line_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1492 (  line_eq			PGNSP PGUID 12 f f t f i 2	16 "628 628"	line_eq - _null_ ));
 DESCR("lines equal?");
 DATA(insert OID = 1493 (  line				PGNSP PGUID 12 f f t f i 2 628 "600 600"	line_construct_pp - _null_ ));
@@ -2017,9 +2017,9 @@ DATA(insert OID = 1556 (  npoints			PGNSP PGUID 12 f f t f i 1	23 "604"  poly_np
 DESCR("number of points in polygon");
 
 DATA(insert OID = 1564 (  bit_in			PGNSP PGUID 12 f f t f i 3 1560 "2275 26 23"	bit_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1565 (  bit_out			PGNSP PGUID 12 f f t f i 1 2275 "1560"	bit_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 
 DATA(insert OID = 1569 (  like				PGNSP PGUID 12 f f t f i 2 16 "25 25"  textlike - _null_ ));
 DESCR("matches LIKE expression");
@@ -2042,9 +2042,9 @@ DATA(insert OID = 1765 (  setval			PGNSP PGUID 12 f f t f v 3 20 "25 20 16"	setv
 DESCR("set sequence value and iscalled status");
 
 DATA(insert OID = 1579 (  varbit_in			PGNSP PGUID 12 f f t f i 3 1562 "2275 26 23"	varbit_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1580 (  varbit_out		PGNSP PGUID 12 f f t f i 1 2275 "1562"	varbit_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 
 DATA(insert OID = 1581 (  biteq				PGNSP PGUID 12 f f t f i 2 16 "1560 1560"  biteq - _null_ ));
 DESCR("equal");
@@ -2297,9 +2297,9 @@ DESCR("return portion of bitstring");
 
 /* for mac type support */
 DATA(insert OID = 436 (  macaddr_in			PGNSP PGUID 12 f f t f i 1 829 "2275"  macaddr_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 437 (  macaddr_out		PGNSP PGUID 12 f f t f i 1 2275 "829"  macaddr_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 
 DATA(insert OID = 752 (  text				PGNSP PGUID 12 f f t f i 1 25 "829"  macaddr_text - _null_ ));
 DESCR("MAC address to text");
@@ -2325,15 +2325,15 @@ DESCR("less-equal-greater");
 
 /* for inet type support */
 DATA(insert OID = 910 (  inet_in			PGNSP PGUID 12 f f t f i 1 869 "2275"  inet_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 911 (  inet_out			PGNSP PGUID 12 f f t f i 1 2275 "869"  inet_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 
 /* for cidr type support */
 DATA(insert OID = 1267 (  cidr_in			PGNSP PGUID 12 f f t f i 1 650 "2275"  cidr_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1427 (  cidr_out			PGNSP PGUID 12 f f t f i 1 2275 "650"  cidr_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 
 /* these are used for both inet and cidr */
 DATA(insert OID = 920 (  network_eq			PGNSP PGUID 12 f f t f i 2 16 "869 869"  network_eq - _null_ ));
@@ -2406,9 +2406,9 @@ DESCR("hash");
 
 /* OID's 1700 - 1799 NUMERIC data type */
 DATA(insert OID = 1701 ( numeric_in				PGNSP PGUID 12 f f t f i 3 1700 "2275 26 23"  numeric_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1702 ( numeric_out			PGNSP PGUID 12 f f t f i 1 2275 "1700"	numeric_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1703 ( numeric				PGNSP PGUID 12 f f t f i 2 1700 "1700 23"  numeric - _null_ ));
 DESCR("adjust numeric to typmod precision/scale");
 DATA(insert OID = 1704 ( numeric_abs			PGNSP PGUID 12 f f t f i 1 1700 "1700"	numeric_abs - _null_ ));
@@ -2544,9 +2544,9 @@ DATA(insert OID =  1283 ( quote_literal    PGNSP PGUID 12 f f t f i 1 25 "25" qu
 DESCR("quote a literal for usage in a querystring");
 
 DATA(insert OID = 1798 (  oidin			   PGNSP PGUID 12 f f t f i 1 26 "2275" oidin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 1799 (  oidout		   PGNSP PGUID 12 f f t f i 1 2275 "26" oidout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 
 
 DATA(insert OID = 1810 (  bit_length	   PGNSP PGUID 14 f f t f i 1 23 "17" "select octet_length($1) * 8" - _null_ ));
@@ -3026,25 +3026,25 @@ DATA(insert OID = 2159 (  stddev			PGNSP PGUID 12 t f f f i 1 1700 "1700"	aggreg
 
 
 DATA(insert OID = 2212 (  regprocedurein	PGNSP PGUID 12 f f t f s 1 2202 "2275"	regprocedurein - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2213 (  regprocedureout	PGNSP PGUID 12 f f t f s 1 2275 "2202"	regprocedureout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2214 (  regoperin			PGNSP PGUID 12 f f t f s 1 2203 "2275"	regoperin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2215 (  regoperout		PGNSP PGUID 12 f f t f s 1 2275 "2203"	regoperout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2216 (  regoperatorin		PGNSP PGUID 12 f f t f s 1 2204 "2275"	regoperatorin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2217 (  regoperatorout	PGNSP PGUID 12 f f t f s 1 2275 "2204"	regoperatorout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2218 (  regclassin		PGNSP PGUID 12 f f t f s 1 2205 "2275"	regclassin - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2219 (  regclassout		PGNSP PGUID 12 f f t f s 1 2275 "2205"	regclassout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2220 (  regtypein			PGNSP PGUID 12 f f t f s 1 2206 "2275"	regtypein - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2221 (  regtypeout		PGNSP PGUID 12 f f t f s 1 2275 "2206"	regtypeout - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 
 DATA(insert OID = 2246 ( fmgr_internal_validator PGNSP PGUID 12 f f t f s 1 2278 "26" fmgr_internal_validator - _null_ ));
 DESCR("(internal)");
@@ -3108,45 +3108,45 @@ DESCR("current user privilege on schema by schema oid");
 
 
 DATA(insert OID = 2290 (  record_in			PGNSP PGUID 12 f f t f i 1 2249 "2275"	record_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2291 (  record_out		PGNSP PGUID 12 f f t f i 1 2275 "2249"	record_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2292 (  cstring_in		PGNSP PGUID 12 f f t f i 1 2275 "2275"	cstring_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2293 (  cstring_out		PGNSP PGUID 12 f f t f i 1 2275 "2275"	cstring_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2294 (  any_in			PGNSP PGUID 12 f f t f i 1 2276 "2275"	any_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2295 (  any_out			PGNSP PGUID 12 f f t f i 1 2275 "2276"	any_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2296 (  anyarray_in		PGNSP PGUID 12 f f t f i 1 2277 "2275"	anyarray_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2297 (  anyarray_out		PGNSP PGUID 12 f f t f s 1 2275 "2277"	anyarray_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2298 (  void_in			PGNSP PGUID 12 f f t f i 1 2278 "2275"	void_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2299 (  void_out			PGNSP PGUID 12 f f t f i 1 2275 "2278"	void_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2300 (  trigger_in		PGNSP PGUID 12 f f t f i 1 2279 "2275"	trigger_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2301 (  trigger_out		PGNSP PGUID 12 f f t f i 1 2275 "2279"	trigger_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2302 (  language_handler_in	PGNSP PGUID 12 f f t f i 1 2280 "2275"	language_handler_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2303 (  language_handler_out	PGNSP PGUID 12 f f t f i 1 2275 "2280"	language_handler_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2304 (  internal_in		PGNSP PGUID 12 f f t f i 1 2281 "2275"	internal_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2305 (  internal_out		PGNSP PGUID 12 f f t f i 1 2275 "2281"	internal_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2306 (  opaque_in			PGNSP PGUID 12 f f t f i 1 2282 "2275"	opaque_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2307 (  opaque_out		PGNSP PGUID 12 f f t f i 1 2275 "2282"	opaque_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2312 (  anyelement_in		PGNSP PGUID 12 f f t f i 1 2283 "2275"	anyelement_in - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 DATA(insert OID = 2313 (  anyelement_out	PGNSP PGUID 12 f f t f i 1 2275 "2283"	anyelement_out - _null_ ));
-DESCR("(internal)");
+DESCR("I/O");
 
 /* cryptographic */
 DATA(insert OID =  2311 (  md5	   PGNSP PGUID 12 f f t f i 1 25 "25"  md5_text - _null_ ));
@@ -3161,6 +3161,42 @@ DATA(insert OID = 2402 (  record_recv		   PGNSP PGUID 12 f f t f i 1 2249 "2281"
 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");
+DATA(insert OID = 2404 (  int2recv			   PGNSP PGUID 12 f f t f i 1 21 "2281"  int2recv - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2405 (  int2send			   PGNSP PGUID 12 f f t f i 1 17 "21"  int2send - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2406 (  int4recv			   PGNSP PGUID 12 f f t f i 1 23 "2281"  int4recv - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2407 (  int4send			   PGNSP PGUID 12 f f t f i 1 17 "23"  int4send - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2408 (  int8recv			   PGNSP PGUID 12 f f t f i 1 20 "2281"  int8recv - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2409 (  int8send			   PGNSP PGUID 12 f f t f i 1 17 "20"  int8send - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2410 (  int2vectorrecv	   PGNSP PGUID 12 f f t f i 1 22 "2281"  int2vectorrecv - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2411 (  int2vectorsend	   PGNSP PGUID 12 f f t f i 1 17 "22"  int2vectorsend - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2412 (  bytearecv			   PGNSP PGUID 12 f f t f i 1 17 "2281"  bytearecv - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2413 (  byteasend			   PGNSP PGUID 12 f f t f i 1 17 "17"  byteasend - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2414 (  textrecv			   PGNSP PGUID 12 f f t f s 1 25 "2281"  textrecv - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2415 (  textsend			   PGNSP PGUID 12 f f t f s 1 17 "25"  textsend - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2416 (  unknownrecv		   PGNSP PGUID 12 f f t f i 1 705 "2281"  unknownrecv - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2417 (  unknownsend		   PGNSP PGUID 12 f f t f i 1 17 "705"  unknownsend - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2418 (  oidrecv			   PGNSP PGUID 12 f f t f i 1 26 "2281"  oidrecv - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2419 (  oidsend			   PGNSP PGUID 12 f f t f i 1 17 "26"  oidsend - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2420 (  oidvectorrecv		   PGNSP PGUID 12 f f t f i 1 30 "2281"  oidvectorrecv - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2421 (  oidvectorsend		   PGNSP PGUID 12 f f t f i 1 17 "30"  oidvectorsend - _null_ ));
+DESCR("I/O");
 
 
 /*
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index b065c295d6b..3091578b609 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.141 2003/05/08 22:19:57 tgl Exp $
+ * $Id: pg_type.h,v 1.142 2003/05/09 15:44:41 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -242,7 +242,7 @@ DATA(insert OID = 16 (	bool	   PGNSP PGUID	1 t b t \054 0	 0 boolin boolout - -
 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 bytearecv byteasend i x f 0 -1 0 _null_ _null_ ));
 DESCR("variable-length string, binary values escaped");
 #define BYTEAOID		17
 
@@ -254,19 +254,19 @@ DATA(insert OID = 19 (	name	   PGNSP PGUID NAMEDATALEN f b t \054 0 18 namein na
 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 int8recv int8send 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 int2recv int2send 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 int2vectorrecv int2vectorsend 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 int4recv int4send i p f 0 -1 0 _null_ _null_ ));
 DESCR("-2 billion to 2 billion integer, 4-byte storage");
 #define INT4OID			23
 
@@ -274,11 +274,11 @@ DATA(insert OID = 24 (	regproc    PGNSP PGUID	4 t b t \054 0	 0 regprocin regpro
 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 textrecv textsend 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 oidrecv oidsend i p f 0 -1 0 _null_ _null_ ));
 DESCR("object identifier(oid), maximum 4 billion");
 #define OIDOID			26
 
@@ -294,7 +294,7 @@ DATA(insert OID = 29 (	cid		   PGNSP PGUID	4 t b t \054 0	 0 cidin cidout - - i
 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 oidvectorrecv oidvectorsend i p f 0 -1 0 _null_ _null_ ));
 DESCR("array of INDEX_MAX_KEYS oids, used in system tables");
 #define OIDVECTOROID	30
 
@@ -362,7 +362,7 @@ DESCR("relative, limited-range time interval (Unix delta time)");
 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 unknownrecv unknownsend i p f 0 -1 0 _null_ _null_ ));
 DESCR("");
 #define UNKNOWNOID		705
 
@@ -477,7 +477,7 @@ DATA(insert OID = 1700 ( numeric	   PGNSP PGUID -1 f b t \054 0	0 numeric_in num
 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 textrecv textsend i x f 0 -1 0 _null_ _null_ ));
 DESCR("reference cursor (portal name)");
 #define REFCURSOROID	1790
 
diff --git a/src/include/libpq/pqformat.h b/src/include/libpq/pqformat.h
index 7167c6d63ad..bbeff288c4f 100644
--- a/src/include/libpq/pqformat.h
+++ b/src/include/libpq/pqformat.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pqformat.h,v 1.16 2003/05/08 18:16:37 tgl Exp $
+ * $Id: pqformat.h,v 1.17 2003/05/09 15:44:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,17 +20,24 @@ extern void pq_sendbyte(StringInfo buf, int byt);
 extern void pq_sendbytes(StringInfo buf, const char *data, int datalen);
 extern void pq_sendcountedtext(StringInfo buf, const char *str, int slen,
 							   bool countincludesself);
+extern void pq_sendtext(StringInfo buf, const char *str, int slen);
 extern void pq_sendstring(StringInfo buf, const char *str);
 extern void pq_sendint(StringInfo buf, int i, int b);
+extern void pq_sendint64(StringInfo buf, int64 i);
 extern void pq_endmessage(StringInfo buf);
 
+extern void pq_begintypsend(StringInfo buf);
+extern bytea *pq_endtypsend(StringInfo buf);
+
 extern void pq_puttextmessage(char msgtype, const char *str);
 extern void pq_putemptymessage(char msgtype);
 
 extern int	pq_getmsgbyte(StringInfo msg);
 extern unsigned int pq_getmsgint(StringInfo msg, int b);
+extern int64 pq_getmsgint64(StringInfo msg);
 extern const char *pq_getmsgbytes(StringInfo msg, int datalen);
 extern void pq_copymsgbytes(StringInfo msg, char *buf, int datalen);
+extern char *pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes);
 extern const char *pq_getmsgstring(StringInfo msg);
 extern void pq_getmsgend(StringInfo msg);
 
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index c5971679ce4..15dfd11a1f5 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.212 2003/05/08 22:19:57 tgl Exp $
+ * $Id: builtins.h,v 1.213 2003/05/09 15:44:42 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -90,11 +90,17 @@ extern Datum cideq(PG_FUNCTION_ARGS);
 /* int.c */
 extern Datum int2in(PG_FUNCTION_ARGS);
 extern Datum int2out(PG_FUNCTION_ARGS);
+extern Datum int2recv(PG_FUNCTION_ARGS);
+extern Datum int2send(PG_FUNCTION_ARGS);
 extern Datum int2vectorin(PG_FUNCTION_ARGS);
 extern Datum int2vectorout(PG_FUNCTION_ARGS);
+extern Datum int2vectorrecv(PG_FUNCTION_ARGS);
+extern Datum int2vectorsend(PG_FUNCTION_ARGS);
 extern Datum int2vectoreq(PG_FUNCTION_ARGS);
 extern Datum int4in(PG_FUNCTION_ARGS);
 extern Datum int4out(PG_FUNCTION_ARGS);
+extern Datum int4recv(PG_FUNCTION_ARGS);
+extern Datum int4send(PG_FUNCTION_ARGS);
 extern Datum i2toi4(PG_FUNCTION_ARGS);
 extern Datum i4toi2(PG_FUNCTION_ARGS);
 extern Datum int2_text(PG_FUNCTION_ARGS);
@@ -324,6 +330,8 @@ extern Datum oidnotin(PG_FUNCTION_ARGS);
 /* oid.c */
 extern Datum oidin(PG_FUNCTION_ARGS);
 extern Datum oidout(PG_FUNCTION_ARGS);
+extern Datum oidrecv(PG_FUNCTION_ARGS);
+extern Datum oidsend(PG_FUNCTION_ARGS);
 extern Datum oideq(PG_FUNCTION_ARGS);
 extern Datum oidne(PG_FUNCTION_ARGS);
 extern Datum oidlt(PG_FUNCTION_ARGS);
@@ -336,6 +344,8 @@ extern Datum oid_text(PG_FUNCTION_ARGS);
 extern Datum text_oid(PG_FUNCTION_ARGS);
 extern Datum oidvectorin(PG_FUNCTION_ARGS);
 extern Datum oidvectorout(PG_FUNCTION_ARGS);
+extern Datum oidvectorrecv(PG_FUNCTION_ARGS);
+extern Datum oidvectorsend(PG_FUNCTION_ARGS);
 extern Datum oidvectoreq(PG_FUNCTION_ARGS);
 extern Datum oidvectorne(PG_FUNCTION_ARGS);
 extern Datum oidvectorlt(PG_FUNCTION_ARGS);
@@ -462,6 +472,8 @@ extern Datum varcharoctetlen(PG_FUNCTION_ARGS);
 /* varlena.c */
 extern Datum textin(PG_FUNCTION_ARGS);
 extern Datum textout(PG_FUNCTION_ARGS);
+extern Datum textrecv(PG_FUNCTION_ARGS);
+extern Datum textsend(PG_FUNCTION_ARGS);
 extern Datum textcat(PG_FUNCTION_ARGS);
 extern Datum texteq(PG_FUNCTION_ARGS);
 extern Datum textne(PG_FUNCTION_ARGS);
@@ -490,9 +502,13 @@ extern Datum md5_text(PG_FUNCTION_ARGS);
 
 extern Datum unknownin(PG_FUNCTION_ARGS);
 extern Datum unknownout(PG_FUNCTION_ARGS);
+extern Datum unknownrecv(PG_FUNCTION_ARGS);
+extern Datum unknownsend(PG_FUNCTION_ARGS);
 
 extern Datum byteain(PG_FUNCTION_ARGS);
 extern Datum byteaout(PG_FUNCTION_ARGS);
+extern Datum bytearecv(PG_FUNCTION_ARGS);
+extern Datum byteasend(PG_FUNCTION_ARGS);
 extern Datum byteaoctetlen(PG_FUNCTION_ARGS);
 extern Datum byteaGetByte(PG_FUNCTION_ARGS);
 extern Datum byteaGetBit(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h
index 3cd2319e6eb..79ff4704401 100644
--- a/src/include/utils/int8.h
+++ b/src/include/utils/int8.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: int8.h,v 1.36 2002/10/25 22:08:44 tgl Exp $
+ * $Id: int8.h,v 1.37 2003/05/09 15:44:42 tgl Exp $
  *
  * NOTES
  * These data types are supported on all 64-bit architectures, and may
@@ -27,6 +27,8 @@ extern bool scanint8(const char *str, bool errorOK, int64 *result);
 
 extern Datum int8in(PG_FUNCTION_ARGS);
 extern Datum int8out(PG_FUNCTION_ARGS);
+extern Datum int8recv(PG_FUNCTION_ARGS);
+extern Datum int8send(PG_FUNCTION_ARGS);
 
 extern Datum int8eq(PG_FUNCTION_ARGS);
 extern Datum int8ne(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index c6fcb505c70..d466052fed3 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -148,14 +148,18 @@ WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND NOT
 -----+---------+-----+---------
 (0 rows)
 
+-- As of 7.4, this check finds refcursor, which is borrowing
+-- other types' I/O 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
     (p1.typelem != 0 AND p1.typlen < 0) AND NOT
-    (p2.prorettype = p1.oid AND NOT p2.proretset);
- oid | typname | oid | proname 
------+---------+-----+---------
-(0 rows)
+    (p2.prorettype = p1.oid AND NOT p2.proretset)
+ORDER BY 1;
+ oid  |  typname  | oid  | proname  
+------+-----------+------+----------
+ 1790 | refcursor | 2414 | textrecv
+(1 row)
 
 -- Varlena array types will point to array_recv
 SELECT p1.oid, p1.typname, p2.oid, p2.proname
@@ -168,15 +172,19 @@ WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND
 (0 rows)
 
 -- Check for bogus typsend routines
+-- As of 7.4, this check finds refcursor, which is borrowing
+-- other types' I/O 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)
+      p1.typelem != 0 AND p1.typlen = -1))
+ORDER BY 1;
+ oid  |  typname  | oid  | proname  
+------+-----------+------+----------
+ 1790 | refcursor | 2415 | textsend
+(1 row)
 
 SELECT p1.oid, p1.typname, p2.oid, p2.proname
 FROM pg_type AS p1, pg_proc AS p2
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index 043a65934d2..04a0557d836 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -116,11 +116,14 @@ 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);
 
+-- As of 7.4, this check finds refcursor, which is borrowing
+-- other types' I/O 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
     (p1.typelem != 0 AND p1.typlen < 0) AND NOT
-    (p2.prorettype = p1.oid AND NOT p2.proretset);
+    (p2.prorettype = p1.oid AND NOT p2.proretset)
+ORDER BY 1;
 
 -- Varlena array types will point to array_recv
 SELECT p1.oid, p1.typname, p2.oid, p2.proname
@@ -131,12 +134,15 @@ WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND
 
 -- Check for bogus typsend routines
 
+-- As of 7.4, this check finds refcursor, which is borrowing
+-- other types' I/O 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));
+      p1.typelem != 0 AND p1.typlen = -1))
+ORDER BY 1;
 
 SELECT p1.oid, p1.typname, p2.oid, p2.proname
 FROM pg_type AS p1, pg_proc AS p2
-- 
GitLab