diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml
index 6cdd50230d9ee4318b539160560f4188116e199c..72e1a813cbb935c97b7f43c9be985e1641b6e4c0 100644
--- a/doc/src/sgml/spi.sgml
+++ b/doc/src/sgml/spi.sgml
@@ -1229,6 +1229,121 @@ TBD
 <!-- *********************************************** -->
 <!-- *********************************************** -->
 
+<REFENTRY ID="SPI-SPICOPYTUPLEDESC">
+<REFMETA>
+<REFENTRYTITLE>SPI_copytupledesc</REFENTRYTITLE>
+<REFMISCINFO>SPI - Tuple Descriptor Copy</REFMISCINFO>
+</REFMETA>
+<REFNAMEDIV>
+<REFNAME>SPI_copytupledesc
+</REFNAME>
+<REFPURPOSE>
+Makes copy of tuple descriptor in upper Executor context
+</REFPURPOSE>
+<INDEXTERM ID="IX-SPI-SPICOPYTUPLEDESC-1"><PRIMARY>SPI</PRIMARY><SECONDARY>copying tuple descriptors</SECONDARY></INDEXTERM>
+<INDEXTERM ID="IX-SPI-SPICOPYTUPLEDESC-2"><PRIMARY>SPI_copytupledesc</PRIMARY></INDEXTERM>
+</REFNAMEDIV>
+<REFSYNOPSISDIV>
+<REFSYNOPSISDIVINFO>
+<DATE>2001-08-02</DATE>
+</REFSYNOPSISDIVINFO>
+<SYNOPSIS>
+SPI_copytupledesc(<REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>)
+</SYNOPSIS>
+
+<REFSECT2 ID="R2-SPI-SPICOPYTUPLEDESC-1">
+<REFSECT2INFO>
+<DATE>2001-08-02</DATE>
+</REFSECT2INFO>
+<TITLE>Inputs
+</TITLE>
+<VARIABLELIST>
+<VARLISTENTRY>
+<TERM>
+TupleDesc <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
+</TERM>
+<LISTITEM>
+<PARA>
+Input tuple descriptor to be copied
+</PARA>
+</LISTITEM>
+</VARLISTENTRY>
+</VARIABLELIST>
+</REFSECT2>
+
+<REFSECT2 ID="R2-SPI-SPICOPYTUPLEDESC-2">
+<REFSECT2INFO>
+<DATE>2001-08-02</DATE>
+</REFSECT2INFO>
+<TITLE>Outputs
+</TITLE>
+<VARIABLELIST>
+<VARLISTENTRY>
+<TERM>
+TupleDesc
+</TERM>
+<LISTITEM>
+<PARA>
+Copied tuple descriptor
+<SimpleList>
+<Member>
+ <ReturnValue>non-NULL</ReturnValue>
+ if <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
+ is not NULL and the copy was successful
+</Member>
+<Member>
+   <ReturnValue>NULL</ReturnValue>
+ only if <REPLACEABLE CLASS="PARAMETER">tupdesc</REPLACEABLE>
+ is NULL
+</Member>
+</SimpleList>
+</para>
+</LISTITEM>
+</VARLISTENTRY>
+</VARIABLELIST>
+</REFSECT2>
+</REFSYNOPSISDIV>
+
+<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-1">
+<REFSECT1INFO>
+<DATE>2001-08-02</DATE>
+</REFSECT1INFO>
+<TITLE>Description
+</TITLE>
+<PARA>
+<FUNCTION>SPI_copytupledesc</FUNCTION> 
+   makes a copy of tupdesc in upper Executor context. See the section on Memory Management.
+</PARA>
+</REFSECT1>
+<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-2">
+<TITLE>Usage
+</TITLE>
+<Para>
+TBD
+</PARA>
+</REFSECT1>
+<!--
+<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-3">
+<TITLE>Algorithm
+</TITLE>
+<PARA>
+</PARA>
+</REFSECT1>
+-->
+<!--
+<REFSECT1 ID="R1-SPI-SPICOPYTUPLEDESC-4">
+<TITLE>Structures
+</TITLE>
+<PARA>None
+</PARA>
+</REFSECT1>
+-->
+</REFENTRY>
+
+<!-- *********************************************** -->
+<!-- *********************************************** -->
+<!-- *********************************************** -->
+
 <REFENTRY ID="SPI-SPIMODIFYTUPLE">
 <REFMETA>
 <REFENTRYTITLE>SPI_modifytuple</REFENTRYTITLE>
@@ -2647,10 +2762,13 @@ made in this context.
 
 <Para>
 
-   After <Function>SPI_connect</Function> is called current context is the procedure's one.  All
-allocations made via <Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility functions (except
-for <Function>SPI_copytuple</Function>, <Function>SPI_modifytuple</Function>,
- <Function>SPI_palloc</Function> and <Function>SPI_repalloc</Function>) are
+   After <Function>SPI_connect</Function> is called current context is the
+   procedure's one.  All allocations made via
+<Function>palloc</Function>/<Function>repalloc</Function> or by SPI utility
+functions (except for <Function>SPI_copytuple</Function>,
+<Function>SPI_copytupledesc</Function>,
+<Function>SPI_modifytuple</Function>,
+<Function>SPI_palloc</Function> and <Function>SPI_repalloc</Function>) are
 made in this context.
 </Para>
 
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 7b4030d580a58cb6379559eff70c015d97d99342..8c6420ae4ccfab712bf16a600a54f6ba7c5f5d53 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.56 2001/08/02 16:05:23 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.57 2001/08/02 18:08:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -333,6 +333,33 @@ SPI_copytuple(HeapTuple tuple)
 	return ctuple;
 }
 
+TupleDesc
+SPI_copytupledesc(TupleDesc tupdesc)
+{
+	MemoryContext oldcxt = NULL;
+	TupleDesc	ctupdesc;
+
+	if (tupdesc == NULL)
+	{
+		SPI_result = SPI_ERROR_ARGUMENT;
+		return NULL;
+	}
+
+	if (_SPI_curid + 1 == _SPI_connected)		/* connected */
+	{
+		if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
+			elog(FATAL, "SPI: stack corrupted");
+		oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
+	}
+
+	ctupdesc = CreateTupleDescCopy(tupdesc);
+
+	if (oldcxt)
+		MemoryContextSwitchTo(oldcxt);
+
+	return ctupdesc;
+}
+
 HeapTuple
 SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
 				Datum *Values, char *Nulls)
@@ -1232,7 +1259,7 @@ _SPI_end_call(bool procmem)
 }
 
 static bool
-_SPI_checktuples()
+_SPI_checktuples(void)
 {
 	uint32		processed = _SPI_current->processed;
 	SPITupleTable *tuptable = _SPI_current->tuptable;
@@ -1244,8 +1271,8 @@ _SPI_checktuples()
 			failed = true;
 	}
 	else
-/* some tuples were processed */
 	{
+		/* some tuples were processed */
 		if (tuptable == NULL)	/* spi_printtup was not called */
 			failed = true;
 		else if (processed != (tuptable->alloced - tuptable->free))
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 3a7c7807942ab4376183a35f8ad0b564986a562e..bef68bc7a6e52b39da61270fb4cf0c55d9f48e11 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -2,6 +2,7 @@
  *
  * spi.h
  *
+ * $Id: spi.h,v 1.28 2001/08/02 18:08:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,17 +49,17 @@ typedef struct
 	HeapTuple  *vals;			/* tuples */
 } SPITupleTable;
 
-#define SPI_ERROR_CONNECT		-1
-#define SPI_ERROR_COPY			-2
-#define SPI_ERROR_OPUNKNOWN		-3
-#define SPI_ERROR_UNCONNECTED	-4
-#define SPI_ERROR_CURSOR		-5
-#define SPI_ERROR_ARGUMENT		-6
-#define SPI_ERROR_PARAM			-7
-#define SPI_ERROR_TRANSACTION	-8
-#define SPI_ERROR_NOATTRIBUTE	-9
-#define SPI_ERROR_NOOUTFUNC		-10
-#define SPI_ERROR_TYPUNKNOWN	-11
+#define SPI_ERROR_CONNECT		(-1)
+#define SPI_ERROR_COPY			(-2)
+#define SPI_ERROR_OPUNKNOWN		(-3)
+#define SPI_ERROR_UNCONNECTED	(-4)
+#define SPI_ERROR_CURSOR		(-5)
+#define SPI_ERROR_ARGUMENT		(-6)
+#define SPI_ERROR_PARAM			(-7)
+#define SPI_ERROR_TRANSACTION	(-8)
+#define SPI_ERROR_NOATTRIBUTE	(-9)
+#define SPI_ERROR_NOOUTFUNC		(-10)
+#define SPI_ERROR_TYPUNKNOWN	(-11)
 
 #define SPI_OK_CONNECT			1
 #define SPI_OK_FINISH			2
@@ -87,6 +88,7 @@ extern void *SPI_saveplan(void *plan);
 extern int  SPI_freeplan(void *plan);
 
 extern HeapTuple SPI_copytuple(HeapTuple tuple);
+extern TupleDesc SPI_copytupledesc(TupleDesc tupdesc);
 extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts,
 				int *attnum, Datum *Values, char *Nulls);
 extern int	SPI_fnumber(TupleDesc tupdesc, char *fname);