diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index b533470e1d523b1a87c45720ba9e54a7d7b25b07..4549ba00080d3b95105357fe90760f7a8e242c91 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.131 2004/10/13 01:25:10 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.132 2004/11/16 18:10:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -270,6 +270,14 @@ SPI_pop(void)
 	_SPI_curid--;
 }
 
+/* Restore state of SPI stack after aborting a subtransaction */
+void
+SPI_restore_connection(void)
+{
+	Assert(_SPI_connected >= 0);
+	_SPI_curid = _SPI_connected - 1;
+}
+
 /* Parse, plan, and execute a querystring */
 int
 SPI_execute(const char *src, bool read_only, int tcount)
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 3014dbce84083040c2989f35ef61191ee2ae1214..d5ba89fa3eaacc0cd03a3ad0876409f0aebf47ff 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -2,7 +2,7 @@
  *
  * spi.h
  *
- * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.49 2004/09/16 16:58:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.50 2004/11/16 18:10:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -81,6 +81,7 @@ extern int	SPI_connect(void);
 extern int	SPI_finish(void);
 extern void SPI_push(void);
 extern void SPI_pop(void);
+extern void SPI_restore_connection(void);
 extern int	SPI_execute(const char *src, bool read_only, int tcount);
 extern int	SPI_execute_plan(void *plan, Datum *Values, const char *Nulls,
 							 bool read_only, int tcount);
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 12ca6c0888ab8aa78629d0d22882e20f1d63f2a4..fddbfefac475b549b6b0ca922a83eccc975e527d 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3,7 +3,7 @@
  *			  procedural language
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.120 2004/09/16 16:58:44 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.121 2004/11/16 18:10:14 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -899,20 +899,11 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 		MemoryContext oldcontext = CurrentMemoryContext;
 		ResourceOwner oldowner = CurrentResourceOwner;
 		volatile bool caught = false;
-		int			xrc;
 
-		/*
-		 * Start a subtransaction, and re-connect to SPI within it
-		 */
-		SPI_push();
 		BeginInternalSubTransaction(NULL);
 		/* Want to run statements inside function's memory context */
 		MemoryContextSwitchTo(oldcontext);
 
-		if ((xrc = SPI_connect()) != SPI_OK_CONNECT)
-			elog(ERROR, "SPI_connect failed: %s",
-				 SPI_result_code_string(xrc));
-
 		PG_TRY();
 		{
 			rc = exec_stmts(estate, block->body);
@@ -928,12 +919,17 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 			edata = CopyErrorData();
 			FlushErrorState();
 
-			/* Abort the inner transaction (and inner SPI connection) */
+			/* Abort the inner transaction */
 			RollbackAndReleaseCurrentSubTransaction();
 			MemoryContextSwitchTo(oldcontext);
 			CurrentResourceOwner = oldowner;
 
-			SPI_pop();
+			/*
+			 * If AtEOSubXact_SPI() popped any SPI context of the subxact,
+			 * it will have left us in a disconnected state.  We need this
+			 * hack to return to connected state.
+			 */
+			SPI_restore_connection();
 
 			/* Look for a matching exception handler */
 			exceptions = block->exceptions;
@@ -960,15 +956,14 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
 		/* Commit the inner transaction, return to outer xact context */
 		if (!caught)
 		{
-			if ((xrc = SPI_finish()) != SPI_OK_FINISH)
-				elog(ERROR, "SPI_finish failed: %s",
-					 SPI_result_code_string(xrc));
-
 			ReleaseCurrentSubTransaction();
 			MemoryContextSwitchTo(oldcontext);
 			CurrentResourceOwner = oldowner;
-
-			SPI_pop();
+			/*
+			 * AtEOSubXact_SPI() should not have popped any SPI context,
+			 * but just in case it did, make sure we remain connected.
+			 */
+			SPI_restore_connection();
 		}
 	}
 	else
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index e1b57f9716b4719554e29309508642846ff1b1d7..8674fa9531d4423e31d3d39dd8f0c12da8706650 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -1931,6 +1931,36 @@ select * from foo;
  20
 (2 rows)
 
+-- Test for pass-by-ref values being stored in proper context
+create function test_variable_storage() returns text as $$
+declare x text;
+begin
+  x := '1234';
+  begin
+    x := x || '5678';
+    -- force error inside subtransaction SPI context
+    perform trap_zero_divide(-100);
+  exception
+    when others then
+      x := x || '9012';
+  end;
+  return x;
+end$$ language plpgsql;
+select test_variable_storage();
+NOTICE:  should see this
+CONTEXT:  SQL statement "SELECT  trap_zero_divide(-100)"
+PL/pgSQL function "test_variable_storage" line 7 at perform
+NOTICE:  should see this only if -100 <> 0
+CONTEXT:  SQL statement "SELECT  trap_zero_divide(-100)"
+PL/pgSQL function "test_variable_storage" line 7 at perform
+NOTICE:  should see this only if -100 fits in smallint
+CONTEXT:  SQL statement "SELECT  trap_zero_divide(-100)"
+PL/pgSQL function "test_variable_storage" line 7 at perform
+ test_variable_storage 
+-----------------------
+ 123456789012
+(1 row)
+
 --
 -- test foreign key error trapping
 --
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index 367a73986e1e20251c1db72a6dc9c041fb756243..f9f307b1ac041b2a6101175c41373c0f76368fa3 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -1696,6 +1696,24 @@ reset statement_timeout;
 
 select * from foo;
 
+-- Test for pass-by-ref values being stored in proper context
+create function test_variable_storage() returns text as $$
+declare x text;
+begin
+  x := '1234';
+  begin
+    x := x || '5678';
+    -- force error inside subtransaction SPI context
+    perform trap_zero_divide(-100);
+  exception
+    when others then
+      x := x || '9012';
+  end;
+  return x;
+end$$ language plpgsql;
+
+select test_variable_storage();
+
 --
 -- test foreign key error trapping
 --