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