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
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
*** CHANGES THAT MAY POSSIBLY BREAK YOUR OLD APPLICATIONS ***
- 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->handle_binary_nulls = FALSE;
imp_dbh->allow_multiple_statements = FALSE;
imp_dbh->use_immediate_transaction = FALSE;
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));
return TRUE;
}
if (strEQ(key, "sqlite_use_immediate_transaction")) {
imp_dbh->use_immediate_transaction = !(! SvTRUE(valuesv));
return TRUE;
}
if (strEQ(key, "sqlite_unicode")) {
#if PERL_UNICODE_DOES_NOT_WORK_WELL
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")) {
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 PERL_UNICODE_DOES_NOT_WORK_WELL
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)) {
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) {
return -2; /* -> undef in SQLite.xsi */
}

View file

@ -30,6 +30,7 @@ struct imp_dbh_st {
AV *aggregates;
SV *collation_needed_callback;
bool allow_multiple_statements;
bool use_immediate_transaction;
};
/* 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>
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
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
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
=head2 Statement Handle Attributes