From 5b706ba481cefa1a9bedc81fdd9c6d6ed8ccde7b Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Tue, 6 Feb 2007 22:49:24 +0000
Subject: [PATCH] Fix an error in the original coding of holdable cursors:
 PersistHoldablePortal thought that it didn't have to reposition the
 underlying tuplestore if the portal is atEnd.  But this is not so, because
 tuplestores have separate read and write cursors ... and the read cursor
 hasn't moved from the start. This mistake explains bug #2970 from William
 Zhang.

Note: the coding here is pretty inefficient, but given that no one has noticed
this bug until now, I'd say hardly anyone uses the case where the cursor has
been advanced before being persisted.  So maybe it's not worth worrying about.
---
 src/backend/commands/portalcmds.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index 7bb7f4a33ee..d1c119ca08f 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.59 2007/02/01 19:10:26 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.60 2007/02/06 22:49:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -392,15 +392,23 @@ PersistHoldablePortal(Portal portal)
 		ExecutorEnd(queryDesc);
 
 		/*
-		 * Reset the position in the result set: ideally, this could be
+		 * Set the position in the result set: ideally, this could be
 		 * implemented by just skipping straight to the tuple # that we need
 		 * to be at, but the tuplestore API doesn't support that. So we start
 		 * at the beginning of the tuplestore and iterate through it until we
-		 * reach where we need to be.  FIXME someday?
+		 * reach where we need to be.  FIXME someday?  (Fortunately, the
+		 * typical case is that we're supposed to be at or near the start
+		 * of the result set, so this isn't as bad as it sounds.)
 		 */
 		MemoryContextSwitchTo(portal->holdContext);
 
-		if (!portal->atEnd)
+		if (portal->atEnd)
+		{
+			/* we can handle this case even if posOverflow */
+			while (tuplestore_advance(portal->holdStore, true))
+				/* continue */ ;
+		}
+		else
 		{
 			long		store_pos;
 
-- 
GitLab