diff --git a/postgresql-simple.cabal b/postgresql-simple.cabal
--- a/postgresql-simple.cabal
+++ b/postgresql-simple.cabal
@@ -1,5 +1,5 @@
 Name:                postgresql-simple
-Version:             0.3.2.0
+Version:             0.3.3.0
 Synopsis:            Mid-Level PostgreSQL client library
 Description:
     Mid-Level PostgreSQL client library, forked from mysql-simple.
@@ -75,7 +75,7 @@
 source-repository this
   type:     git
   location: http://github.com/lpsmith/postgresql-simple
-  tag:      v0.3.2.0
+  tag:      v0.3.3.0
 
 test-suite test
   type:           exitcode-stdio-1.0
diff --git a/src/Database/PostgreSQL/Simple.hs b/src/Database/PostgreSQL/Simple.hs
--- a/src/Database/PostgreSQL/Simple.hs
+++ b/src/Database/PostgreSQL/Simple.hs
@@ -111,9 +111,9 @@
 import           Blaze.ByteString.Builder
                    ( Builder, fromByteString, toByteString )
 import           Blaze.ByteString.Builder.Char8 (fromChar)
+import           Blaze.Text ( integral )
 import           Control.Applicative ((<$>), pure)
-import           Control.Exception
-                   ( Exception, throw, throwIO, finally )
+import           Control.Exception as E
 import           Control.Monad (foldM)
 import           Data.ByteString (ByteString)
 import           Data.Int (Int64)
@@ -463,7 +463,7 @@
        -> a
        -> (a -> row -> IO a)
        -> IO a
-doFold FoldOptions{..} conn _template q a f = do
+doFold FoldOptions{..} conn _template q a0 f = do
     stat <- withConnection conn PQ.transactionStatus
     case stat of
       PQ.TransIdle    -> withTransactionMode transactionMode conn go
@@ -481,11 +481,29 @@
       PQ.TransUnknown -> fail "foldWithOpts FIXME:  PQ.TransUnknown"
          -- Not sure what this means.
   where
-    go = do
-       -- FIXME:  what about name clashes with already-declared cursors?
-       _ <- execute_ conn ("DECLARE fold NO SCROLL CURSOR FOR " <> q)
-       loop a `finally` execute_ conn "CLOSE fold"
+    declare = do
+        name <- newTempName conn
+        _ <- execute_ conn $ mconcat 
+                 [ "DECLARE ", name, " NO SCROLL CURSOR FOR ", q ]
+        return name
+    fetch (Query name) = query_ conn $
+        Query (toByteString (fromByteString "FETCH FORWARD " 
+                             <> integral chunkSize
+                             <> fromByteString " FROM "
+                             <> fromByteString name
+                            ))
+    close name =
+        (execute_ conn ("CLOSE " <> name) >> return ()) `E.catch` \ex ->
+            -- Don't throw exception if CLOSE failed because the transaction is
+            -- aborted.  Otherwise, it will throw away the original error.
+            if isFailedTransactionError ex then return () else throwIO ex
 
+    go = bracket declare close $ \name ->
+         let loop a = do
+                 rs <- fetch name
+                 if null rs then return a else foldM f a rs >>= loop
+          in loop a0
+
 -- FIXME: choose the Automatic chunkSize more intelligently
 --   One possibility is to use the type of the results,  although this
 --   still isn't a perfect solution, given that common types (e.g. text)
@@ -495,9 +513,6 @@
     chunkSize = case fetchQuantity of
                  Automatic   -> 256
                  Fixed n     -> n
-    loop a = do
-      rs <- query conn "FETCH FORWARD ? FROM fold" (Only chunkSize)
-      if null rs then return a else foldM f a rs >>= loop
 
 -- | A version of 'fold' that does not transform a state value.
 forEach :: (ToRow q, FromRow r) =>
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DoAndIfThenElse #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 import Common
 import Database.PostgreSQL.Simple.FromField (FromField)
@@ -8,6 +9,7 @@
 import Control.Exception as E
 import Control.Monad
 import Data.ByteString (ByteString)
+import Data.IORef
 import Data.Typeable
 import qualified Data.ByteString as B
 import qualified Data.Map as Map
@@ -78,6 +80,48 @@
             [] $ \xs (Only x) -> return (x:xs)
     reverse xs @?= ([1..10000] :: [Int])
 
+    ref <- newIORef []
+    forEach conn "SELECT * FROM generate_series(1,?) a, generate_series(1,?) b"
+      (100 :: Int, 50 :: Int) $ \(a :: Int, b :: Int) -> do
+        xs <- readIORef ref
+        writeIORef ref $! (a,b):xs
+    xs <- readIORef ref
+    reverse xs @?= [(a,b) | a <- [1..100], b <- [1..50]]
+
+    -- Make sure fold propagates our exception.
+    ref <- newIORef []
+    True <- expectError (== TestException) $
+              forEach_ conn "SELECT generate_series(1,10)" $ \(Only a) ->
+                if a == 5 then do
+                  -- Cause a SQL error to trip up CLOSE.
+                  True <- expectError isSyntaxError $
+                          execute_ conn "asdf"
+                  True <- expectError ST.isFailedTransactionError $
+                          (query_ conn "SELECT 1" :: IO [(Only Int)])
+                  throwIO TestException
+                else do
+                  xs <- readIORef ref
+                  writeIORef ref $! (a :: Int) : xs
+    xs <- readIORef ref
+    reverse xs @?= [1..4]
+
+    withTransaction conn $ replicateM_ 2 $ do
+        xs <- fold_ conn "VALUES (1), (2), (3), (4), (5)"
+                [] $ \xs (Only x) -> return (x:xs)
+        reverse xs @?= ([1..5] :: [Int])
+
+    ref <- newIORef []
+    forEach_ conn "SELECT generate_series(1,101)" $ \(Only a) ->
+      forEach_ conn "SELECT generate_series(1,55)" $ \(Only b) -> do
+        xs <- readIORef ref
+        writeIORef ref $! (a :: Int, b :: Int) : xs
+    xs <- readIORef ref
+    reverse xs @?= [(a,b) | a <- [1..101], b <- [1..55]]
+
+    xs <- fold_ conn "SELECT 1 WHERE FALSE"
+            [] $ \xs (Only x) -> return (x:xs)
+    xs @?= ([] :: [Int])
+
     -- TODO: add more complete tests, e.g.:
     --
     --  * Fold in a transaction
@@ -183,17 +227,22 @@
 
     return ()
 
-  where
-    expectError p io =
-        (io >> return False) `E.catch` \ex ->
-        if p ex then return True else throwIO ex
-    isUniqueViolation SqlError{..} = sqlState == "23505"
-
 data TestException
   = TestException
   deriving (Eq, Show, Typeable)
 
 instance Exception TestException
+
+expectError :: Exception e => (e -> Bool) -> IO a -> IO Bool
+expectError p io =
+    (io >> return False) `E.catch` \ex ->
+    if p ex then return True else throwIO ex
+
+isUniqueViolation :: SqlError -> Bool
+isUniqueViolation SqlError{..} = sqlState == "23505"
+
+isSyntaxError :: SqlError -> Bool
+isSyntaxError SqlError{..} = sqlState == "42601"
 
 ------------------------------------------------------------------------
 
