diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 2199e109d46ec142c0fa3c0626e9e252a9009975..9db486581ed543362f97c7ae0048e1adf30085df 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -10,7 +10,7 @@
  * Copyright (c) 2002-2008, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.80 2008/01/01 19:45:49 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.81 2008/03/25 19:26:53 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -764,7 +764,6 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
 		hash_seq_init(&hash_seq, prepared_queries);
 		while ((prep_stmt = hash_seq_search(&hash_seq)) != NULL)
 		{
-			HeapTuple	tuple;
 			Datum		values[5];
 			bool		nulls[5];
 
@@ -787,11 +786,9 @@ pg_prepared_statement(PG_FUNCTION_ARGS)
 										  prep_stmt->plansource->num_params);
 			values[4] = BoolGetDatum(prep_stmt->from_sql);
 
-			tuple = heap_form_tuple(tupdesc, values, nulls);
-
 			/* switch to appropriate context while storing the tuple */
 			MemoryContextSwitchTo(per_query_ctx);
-			tuplestore_puttuple(tupstore, tuple);
+			tuplestore_putvalues(tupstore, tupdesc, values, nulls);
 		}
 	}
 
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 6e7daa40e8fe7ed8b0bf8d2cdb11ac199fc34866..97d22dc2cd345e23f5317627b6d69331faff88fc 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.226 2008/01/01 19:45:49 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.227 2008/03/25 19:26:53 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1547,7 +1547,6 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
 	for (;;)
 	{
 		Datum		result;
-		HeapTuple	tuple;
 
 		CHECK_FOR_INTERRUPTS();
 
@@ -1649,15 +1648,15 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
 				 */
 				tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
 				tmptup.t_data = td;
-				tuple = &tmptup;
+
+				oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+				tuplestore_puttuple(tupstore, &tmptup);
 			}
 			else
 			{
-				tuple = heap_form_tuple(tupdesc, &result, &fcinfo.isnull);
+				oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
+				tuplestore_putvalues(tupstore, tupdesc, &result, &fcinfo.isnull);
 			}
-
-			oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
-			tuplestore_puttuple(tupstore, tuple);
 			MemoryContextSwitchTo(oldcontext);
 
 			/*
@@ -1702,15 +1701,13 @@ no_function_result:
 			int			natts = expectedDesc->natts;
 			Datum	   *nulldatums;
 			bool	   *nullflags;
-			HeapTuple	tuple;
 
 			MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
 			nulldatums = (Datum *) palloc0(natts * sizeof(Datum));
 			nullflags = (bool *) palloc(natts * sizeof(bool));
 			memset(nullflags, true, natts * sizeof(bool));
-			tuple = heap_form_tuple(expectedDesc, nulldatums, nullflags);
 			MemoryContextSwitchTo(econtext->ecxt_per_query_memory);
-			tuplestore_puttuple(tupstore, tuple);
+			tuplestore_putvalues(tupstore, expectedDesc, nulldatums, nullflags);
 		}
 	}
 
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index ca5604a61d5162666508912fb707a022ce144bf5..63bf48124a81f7265436fffe0c38d714490d4ed9 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.106 2008/01/01 19:45:55 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.107 2008/03/25 19:26:53 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -911,7 +911,6 @@ pg_cursor(PG_FUNCTION_ARGS)
 	while ((hentry = hash_seq_search(&hash_seq)) != NULL)
 	{
 		Portal		portal = hentry->portal;
-		HeapTuple	tuple;
 		Datum		values[6];
 		bool		nulls[6];
 
@@ -935,11 +934,9 @@ pg_cursor(PG_FUNCTION_ARGS)
 		values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL);
 		values[5] = TimestampTzGetDatum(portal->creation_time);
 
-		tuple = heap_form_tuple(tupdesc, values, nulls);
-
 		/* switch to appropriate context while storing the tuple */
 		MemoryContextSwitchTo(per_query_ctx);
-		tuplestore_puttuple(tupstore, tuple);
+		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
 	}
 
 	/* clean up and return the tuplestore */
diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c
index d6c192993e2de40b1db4821894ec972d07360176..da8de84d684b12c4e0dc09deb453c14622893fa2 100644
--- a/src/backend/utils/sort/tuplestore.c
+++ b/src/backend/utils/sort/tuplestore.c
@@ -38,7 +38,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.37 2008/03/10 20:06:27 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.38 2008/03/25 19:26:53 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -366,8 +366,6 @@ tuplestore_puttupleslot(Tuplestorestate *state,
 /*
  * "Standard" case to copy from a HeapTuple.  This is actually now somewhat
  * deprecated, but not worth getting rid of in view of the number of callers.
- * (Consider adding something that takes a tupdesc+values/nulls arrays so
- * that we can use heap_form_minimal_tuple() and avoid a copy step.)
  */
 void
 tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
@@ -380,6 +378,22 @@ tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
 	tuplestore_puttuple_common(state, (void *) tuple);
 }
 
+/*
+ * Similar to tuplestore_puttuple(), but start from the values + nulls
+ * array. This avoids requiring that the caller construct a HeapTuple,
+ * saving a copy.
+ */
+void
+tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc,
+					 Datum *values, bool *isnull)
+{
+	MinimalTuple tuple;
+
+	tuple = heap_form_minimal_tuple(tdesc, values, isnull);
+
+	tuplestore_puttuple_common(state, (void *) tuple);
+}
+
 static void
 tuplestore_puttuple_common(Tuplestorestate *state, void *tuple)
 {
diff --git a/src/include/utils/tuplestore.h b/src/include/utils/tuplestore.h
index ee7d22b6114a3fc227ee3170dade67a6dd6b4d52..37f99fea3bd56288adebb64cd98ac22eb4430d74 100644
--- a/src/include/utils/tuplestore.h
+++ b/src/include/utils/tuplestore.h
@@ -22,7 +22,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/tuplestore.h,v 1.22 2008/01/01 19:45:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/tuplestore.h,v 1.23 2008/03/25 19:26:53 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -51,6 +51,8 @@ extern void tuplestore_set_eflags(Tuplestorestate *state, int eflags);
 extern void tuplestore_puttupleslot(Tuplestorestate *state,
 						TupleTableSlot *slot);
 extern void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple);
+extern void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc,
+								 Datum *values, bool *isnull);
 
 /* tuplestore_donestoring() used to be required, but is no longer used */
 #define tuplestore_donestoring(state)	((void) 0)
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 452c69cec733be72cbd0677d835ef18ba0397ad6..3ce8f60c2625bb03c62e4edee11ec4fc6eec633a 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plperl.c - perl as a procedural language for PostgreSQL
  *
- *	  $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.136 2008/01/23 00:55:47 adunstan Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.137 2008/03/25 19:26:53 neilc Exp $
  *
  **********************************************************************/
 
@@ -1869,7 +1869,6 @@ plperl_return_next(SV *sv)
 	FunctionCallInfo fcinfo;
 	ReturnSetInfo *rsi;
 	MemoryContext old_cxt;
-	HeapTuple	tuple;
 
 	if (!sv)
 		return;
@@ -1944,8 +1943,15 @@ plperl_return_next(SV *sv)
 
 	if (prodesc->fn_retistuple)
 	{
+		HeapTuple tuple;
+
 		tuple = plperl_build_tuple_result((HV *) SvRV(sv),
 										  current_call_data->attinmeta);
+
+		/* Make sure to store the tuple in a long-lived memory context */
+		MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
+		tuplestore_puttuple(current_call_data->tuple_store, tuple);
+		MemoryContextSwitchTo(old_cxt);
 	}
 	else
 	{
@@ -1967,14 +1973,14 @@ plperl_return_next(SV *sv)
 			isNull = true;
 		}
 
-		tuple = heap_form_tuple(current_call_data->ret_tdesc, &ret, &isNull);
+		/* Make sure to store the tuple in a long-lived memory context */
+		MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
+		tuplestore_putvalues(current_call_data->tuple_store,
+							 current_call_data->ret_tdesc,
+							 &ret, &isNull);
+		MemoryContextSwitchTo(old_cxt);
 	}
 
-	/* Make sure to store the tuple in a long-lived memory context */
-	MemoryContextSwitchTo(rsi->econtext->ecxt_per_query_memory);
-	tuplestore_puttuple(current_call_data->tuple_store, tuple);
-	MemoryContextSwitchTo(old_cxt);
-
 	MemoryContextReset(current_call_data->tmp_cxt);
 }
 
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 976246f67480c5279c1f2334c4cbde38b7a148c3..25702f2a8785aaa006c9c8b5242566cdcb816eb1 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.202 2008/01/01 19:46:00 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.203 2008/03/25 19:26:54 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2007,10 +2007,11 @@ static int
 exec_stmt_return_next(PLpgSQL_execstate *estate,
 					  PLpgSQL_stmt_return_next *stmt)
 {
-	TupleDesc	tupdesc;
-	int			natts;
-	HeapTuple	tuple;
-	bool		free_tuple = false;
+	TupleDesc		tupdesc;
+	int				natts;
+	MemoryContext	oldcxt;
+	HeapTuple		tuple = NULL;
+	bool			free_tuple = false;
 
 	if (!estate->retisset)
 		ereport(ERROR,
@@ -2048,9 +2049,10 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
 												tupdesc->attrs[0]->atttypmod,
 													isNull);
 
-					tuple = heap_form_tuple(tupdesc, &retval, &isNull);
-
-					free_tuple = true;
+					oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
+					tuplestore_putvalues(estate->tuple_store, tupdesc,
+										 &retval, &isNull);
+					MemoryContextSwitchTo(oldcxt);
 				}
 				break;
 
@@ -2087,7 +2089,6 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
 
 			default:
 				elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
-				tuple = NULL;	/* keep compiler quiet */
 				break;
 		}
 	}
@@ -2114,9 +2115,10 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
 										tupdesc->attrs[0]->atttypmod,
 										isNull);
 
-		tuple = heap_form_tuple(tupdesc, &retval, &isNull);
-
-		free_tuple = true;
+		oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
+		tuplestore_putvalues(estate->tuple_store, tupdesc,
+							 &retval, &isNull);
+		MemoryContextSwitchTo(oldcxt);
 
 		exec_eval_cleanup(estate);
 	}
@@ -2125,13 +2127,10 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
 		ereport(ERROR,
 				(errcode(ERRCODE_SYNTAX_ERROR),
 				 errmsg("RETURN NEXT must have a parameter")));
-		tuple = NULL;			/* keep compiler quiet */
 	}
 
 	if (HeapTupleIsValid(tuple))
 	{
-		MemoryContext oldcxt;
-
 		oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
 		tuplestore_puttuple(estate->tuple_store, tuple);
 		MemoryContextSwitchTo(oldcxt);