Yuriy Kaminskiy wrote:
> In sqlite, ROLLBACK fails with SQLITE_BUSY when there are active/unfinished
> SELECT statements.
> As DBI's $dbh->rollback cannot handle errors in sane way, add workaround to
> reset all sth and retry when $dbh->rollback fails with SQLITE_BUSY.
> 
> PS For whatever reasons, "Error handling, part 2" cannot be sent to list
> (disappear into /dev/null without any diagnostics) :-|
> Will retry in few days if it won't appear in gmane or list archives.
> 

... after noticing
http://www.sqlite.org/src/ci/9913996e7b:
 Comment:   Enhance the sqlite3_data_count() routine so that it can be used to

            determine if SQLITE_DONE has been seen on the prepared statement.


Avoid unexpected interaction: proactively don't touch statements that should
have no effect on ROLLBACK failure.
To-be-squashed with patch 2/2.
On other hand, not sure, maybe this is unnecessary cruft; it works as is :-|
>From 43cb79dec18c62c069acbe873e61bac031e05e44 Mon Sep 17 00:00:00 2001
From: "Yuriy M. Kaminskiy" <yum...@gmail.com>
Date: Sat, 15 Oct 2011 01:34:59 +0400
Subject: [PATCH 3/3] Don't reset statements that have no pending data

Leave some extra statements in regression test.
Cosmetics/consistency: remove tabs.
To-be-squashed with previous patch.
---
 dbdimp.c                         |   15 ++++++++++-----
 t/49_rollback_with_active_stmt.t |   20 +++++++++++++++-----
 2 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/dbdimp.c b/dbdimp.c
index 7d90f29..bd3f415 100644
--- a/dbdimp.c
+++ b/dbdimp.c
@@ -377,11 +377,16 @@ sqlite_db_rollback(SV *dbh, imp_dbh_t *imp_dbh)
 
             /* COMPAT: sqlite3_next_stmt is only available for 3006000 or newer */
             while ((pStmt = sqlite3_next_stmt(imp_dbh->db, pStmt)) != NULL) {
-		/* FIXME:
-		 * This leaves $sth in somewhat confused state;
-		 * It would be better to iterate through active DBI sth's and
-		 * call sqlite_st_finish(), but I have no idea how.
-		 */
+                /* FIXME:
+                 * This leaves $sth in somewhat confused state;
+                 * It would be better to iterate through active DBI sth's and
+                 * call sqlite_st_finish(), but I have no idea how.
+                 */
+                if (sqlite3_data_count(pStmt) == 0) {
+                    sqlite_trace(dbh, imp_dbh, 6, form("no pending data in stmt %p", (void *)pStmt));
+                    continue;
+                }
+                sqlite_trace(dbh, imp_dbh, 5, form("sqlite3_reset stmt %p", (void *)pStmt));
                 sqlite3_reset(pStmt);
             }
             sqlite_trace(dbh, imp_dbh, 3, "ROLLBACK TRAN [retry]");
diff --git a/t/49_rollback_with_active_stmt.t b/t/49_rollback_with_active_stmt.t
index d010539..6a04368 100644
--- a/t/49_rollback_with_active_stmt.t
+++ b/t/49_rollback_with_active_stmt.t
@@ -12,7 +12,7 @@ use t::lib::Test qw/connect_ok dbfile/;
 use Test::More;
 use Test::NoWarnings;
 
-plan tests => 9 + 1;
+plan tests => 11 + 1;
 
 my $dbh = connect_ok(
     dbfile     => 'foo',
@@ -24,15 +24,25 @@ my $dbh = connect_ok(
 my $dbfile = dbfile('foo');
 
 $dbh->do("CREATE TABLE Blah ( id INTEGER )");
-$dbh->do("INSERT INTO Blah VALUES ( 1 )");
-$dbh->do("INSERT INTO Blah VALUES ( 2 )");
-$dbh->do("INSERT INTO Blah VALUES ( 3 )");
+my $ins;
+ok(($ins = $dbh->prepare("INSERT INTO Blah VALUES ( ? )")));
+
+$ins->execute(1);
+$ins->execute(2);
+$ins->execute(3);
 
 my $sth;
 
 ok(($sth = $dbh->prepare("SELECT id FROM Blah")), "prepare");
+
+my $sth2;
+ok(($sth2 = $dbh->prepare("SELECT id FROM Blah")), "prepare2");
+
 $dbh->do("BEGIN");
-$dbh->do("INSERT INTO Blah VALUES ( 4 )");
+$ins->execute(4);
+
+$sth2->execute;
+while($sth2->fetch) {}
 
 $sth->execute;
 ok(ref($sth->fetch), "fetch");
-- 
1.7.6.4

_______________________________________________
DBD-SQLite mailing list
DBD-SQLite@lists.scsys.co.uk
http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbd-sqlite

Reply via email to