1
0
Fork 0
mirror of https://github.com/DBD-SQLite/DBD-SQLite synced 2025-06-07 14:19:10 -04:00

DBD::SQLite: implemented sqlite_use_immediate_transaction to address #46289 and #42205

This commit is contained in:
Kenichi Ishigaki 2010-03-27 19:07:55 +00:00
parent 090bb74e25
commit 80b0265961
4 changed files with 57 additions and 1 deletions

View file

@ -1,5 +1,9 @@
Changes for Perl extension DBD-SQLite Changes for Perl extension DBD-SQLite
1.30_02 to be released
- Implemented sqlite_use_immediate_transaction database handle
attribute to avoid deadlocks easily (ISHIGAKI)
1.30_01 Wed 10 Mar 2010 1.30_01 Wed 10 Mar 2010
*** CHANGES THAT MAY POSSIBLY BREAK YOUR OLD APPLICATIONS *** *** CHANGES THAT MAY POSSIBLY BREAK YOUR OLD APPLICATIONS ***
- Resolved #54271: Inserting a string with utf-8 flag on - Resolved #54271: Inserting a string with utf-8 flag on

View file

@ -163,6 +163,7 @@ sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pa
imp_dbh->timeout = SQL_TIMEOUT; imp_dbh->timeout = SQL_TIMEOUT;
imp_dbh->handle_binary_nulls = FALSE; imp_dbh->handle_binary_nulls = FALSE;
imp_dbh->allow_multiple_statements = FALSE; imp_dbh->allow_multiple_statements = FALSE;
imp_dbh->use_immediate_transaction = FALSE;
sqlite3_busy_timeout(imp_dbh->db, SQL_TIMEOUT); sqlite3_busy_timeout(imp_dbh->db, SQL_TIMEOUT);
@ -345,6 +346,10 @@ sqlite_db_STORE_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv, SV *valuesv)
imp_dbh->allow_multiple_statements = !(! SvTRUE(valuesv)); imp_dbh->allow_multiple_statements = !(! SvTRUE(valuesv));
return TRUE; return TRUE;
} }
if (strEQ(key, "sqlite_use_immediate_transaction")) {
imp_dbh->use_immediate_transaction = !(! SvTRUE(valuesv));
return TRUE;
}
if (strEQ(key, "sqlite_unicode")) { if (strEQ(key, "sqlite_unicode")) {
#if PERL_UNICODE_DOES_NOT_WORK_WELL #if PERL_UNICODE_DOES_NOT_WORK_WELL
sqlite_trace(dbh, imp_dbh, 3, form("Unicode support is disabled for this version of perl.")); sqlite_trace(dbh, imp_dbh, 3, form("Unicode support is disabled for this version of perl."));
@ -379,6 +384,9 @@ sqlite_db_FETCH_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv)
if (strEQ(key, "sqlite_allow_multiple_statements")) { if (strEQ(key, "sqlite_allow_multiple_statements")) {
return sv_2mortal(newSViv(imp_dbh->allow_multiple_statements ? 1 : 0)); return sv_2mortal(newSViv(imp_dbh->allow_multiple_statements ? 1 : 0));
} }
if (strEQ(key, "sqlite_use_immediate_transaction")) {
return sv_2mortal(newSViv(imp_dbh->use_immediate_transaction ? 1 : 0));
}
if (strEQ(key, "sqlite_unicode")) { if (strEQ(key, "sqlite_unicode")) {
#if PERL_UNICODE_DOES_NOT_WORK_WELL #if PERL_UNICODE_DOES_NOT_WORK_WELL
sqlite_trace(dbh, imp_dbh, 3, "Unicode support is disabled for this version of perl."); sqlite_trace(dbh, imp_dbh, 3, "Unicode support is disabled for this version of perl.");
@ -578,7 +586,11 @@ sqlite_st_execute(SV *sth, imp_sth_t *imp_sth)
} }
else if (!DBIc_is(imp_dbh, DBIcf_AutoCommit)) { else if (!DBIc_is(imp_dbh, DBIcf_AutoCommit)) {
sqlite_trace(sth, imp_sth, 3, "BEGIN TRAN"); sqlite_trace(sth, imp_sth, 3, "BEGIN TRAN");
rc = sqlite_exec(sth, "BEGIN TRANSACTION"); if (imp_dbh->use_immediate_transaction) {
rc = sqlite_exec(sth, "BEGIN IMMEDIATE TRANSACTION");
} else {
rc = sqlite_exec(sth, "BEGIN TRANSACTION");
}
if (rc != SQLITE_OK) { if (rc != SQLITE_OK) {
return -2; /* -> undef in SQLite.xsi */ return -2; /* -> undef in SQLite.xsi */
} }

View file

@ -30,6 +30,7 @@ struct imp_dbh_st {
AV *aggregates; AV *aggregates;
SV *collation_needed_callback; SV *collation_needed_callback;
bool allow_multiple_statements; bool allow_multiple_statements;
bool use_immediate_transaction;
}; };
/* Statement Handle */ /* Statement Handle */

View file

@ -871,6 +871,39 @@ This C<AutoCommit> mode is independent from the autocommit mode
of the internal SQLite library, which always begins by a C<BEGIN> of the internal SQLite library, which always begins by a C<BEGIN>
statement, and ends by a C<COMMIT> or a <ROLLBACK>. statement, and ends by a C<COMMIT> or a <ROLLBACK>.
=head2 Transaction and Database Locking
Transaction by C<AutoCommit> or C<begin_work> is nice and handy, but
sometimes you may get an annoying "database is locked" error.
This typically happens when someone begins a transaction, and tries
to write to a database while other person is reading from the
database (in another transaction). You might be surprised but SQLite
doesn't lock a database when you just begin a normal (deferred)
transaction to maximize concurrency. It reserves a lock when you
issue a statement to write, but until you actually try to write
with a C<commit> statement, it allows other people to read from
the database. However, reading from the database also requires
C<shared lock>, and that prevents to give you the C<exclusive lock>
you reserved, thus you get the "database is locked" error, and
other people will get the same error if they try to write afterwards,
as you still have a C<pending> lock. C<busy_timeout> doesn't help
in this case.
To avoid this, set a transaction type explicitly. You can issue a
C<begin immediate transaction> (or C<begin exclusive transaction>)
for each transaction, or set C<sqlite_use_immediate_transaction>
database handle attribute to true (since 1.30_02) to always use
an immediate transaction (even when you simply use C<begin_work>
or turn off the C<AutoCommit>.).
my $dbh = DBI->connect("dbi:SQLite::memory:", "", "", {
sqlite_use_immediate_transaction => 1,
});
Note that this works only when all of the connections use the same
(non-deferred) transaction. See L<http://sqlite.org/lockingv3.html>
for locking details.
=head2 Processing Multiple Statements At A Time =head2 Processing Multiple Statements At A Time
L<DBI>'s statement handle is not supposed to process multiple L<DBI>'s statement handle is not supposed to process multiple
@ -972,6 +1005,12 @@ If you set this to true, C<do> method will process multiple
statements at one go. This may be handy, but with performance statements at one go. This may be handy, but with performance
penalty. See above for details. penalty. See above for details.
=item sqlite_use_immediate_transaction
If you set this to true, DBD::SQLite tries to issue a C<begin
immediate transaction> (instead of C<begin transaction>) when
necessary. See above for details.
=back =back
=head2 Statement Handle Attributes =head2 Statement Handle Attributes