DBIx-Class
view release on metacpan or search on metacpan
lib/DBIx/Class/Storage/DBI/SQLite.pm view on Meta::CPAN
( shift->_server_info->{normalized_dbms_version} < '3.014' )
? 0
: 1
}
=head1 NAME
DBIx::Class::Storage::DBI::SQLite - Automatic primary key class for SQLite
=head1 SYNOPSIS
# In your table classes
use base 'DBIx::Class::Core';
__PACKAGE__->set_primary_key('id');
=head1 DESCRIPTION
This class implements autoincrements for SQLite.
=head2 Known Issues
=over
=item RT79576
NOTE - This section applies to you only if ALL of these are true:
* You are or were using DBD::SQLite with a version lesser than 1.38_01
* You are or were using DBIx::Class versions between 0.08191 and 0.08209
(inclusive) or between 0.08240-TRIAL and 0.08242-TRIAL (also inclusive)
* You use objects with overloaded stringification and are feeding them
to DBIC CRUD methods directly
An unfortunate chain of events led to DBIx::Class silently hitting the problem
described in L<RT#79576|https://rt.cpan.org/Public/Bug/Display.html?id=79576>.
In order to trigger the bug condition one needs to supply B<more than one>
bind value that is an object with overloaded stringification (numification
is not relevant, only stringification is). When this is the case the internal
DBIx::Class call to C<< $sth->bind_param >> would be executed in a way that
triggers the above-mentioned DBD::SQLite bug. As a result all the logs and
tracers will contain the expected values, however SQLite will receive B<all>
these bind positions being set to the value of the B<last> supplied
stringifiable object.
Even if you upgrade DBIx::Class (which works around the bug starting from
version 0.08210) you may still have corrupted/incorrect data in your database.
DBIx::Class warned about this condition for several years, hoping to give
anyone affected sufficient notice of the potential issues. The warning was
removed in 2015/v0.082820.
=back
=head1 METHODS
=cut
sub backup {
require File::Spec;
require File::Copy;
require POSIX;
my ($self, $dir) = @_;
$dir ||= './';
## Where is the db file?
my $dsn = $self->_dbi_connect_info()->[0];
my $dbname = $1 if($dsn =~ /dbname=([^;]+)/);
if(!$dbname)
{
$dbname = $1 if($dsn =~ /^dbi:SQLite:(.+)$/i);
}
$self->throw_exception("Cannot determine name of SQLite db file")
if(!$dbname || !-f $dbname);
# print "Found database: $dbname\n";
# my $dbfile = file($dbname);
my ($vol, $dbdir, $file) = File::Spec->splitpath($dbname);
# my $file = $dbfile->basename();
$file = POSIX::strftime("%Y-%m-%d-%H_%M_%S", localtime()) . $file;
$file = "B$file" while(-f $file);
mkdir($dir) unless -f $dir;
my $backupfile = File::Spec->catfile($dir, $file);
my $res = File::Copy::copy($dbname, $backupfile);
$self->throw_exception("Backup failed! ($!)") if(!$res);
return $backupfile;
}
sub _exec_svp_begin {
my ($self, $name) = @_;
$self->_dbh->do("SAVEPOINT $name");
}
sub _exec_svp_release {
my ($self, $name) = @_;
$self->_dbh->do("RELEASE SAVEPOINT $name");
}
sub _exec_svp_rollback {
my ($self, $name) = @_;
$self->_dbh->do("ROLLBACK TO SAVEPOINT $name");
# resync state for older DBD::SQLite (RT#67843)
# https://github.com/DBD-SQLite/DBD-SQLite/commit/9b3cdbf
if (
! modver_gt_or_eq('DBD::SQLite', '1.33')
and
$self->_dbh->FETCH('AutoCommit')
) {
$self->_dbh->STORE('AutoCommit', 0);
$self->_dbh->STORE('BegunWork', 1);
}
}
sub _ping {
my $self = shift;
# Be extremely careful what we do here. SQLite is notoriously bad at
# synchronizing its internal transaction state with {AutoCommit}
# https://metacpan.org/source/ADAMK/DBD-SQLite-1.37/lib/DBD/SQLite.pm#L921
# There is a function http://www.sqlite.org/c3ref/get_autocommit.html
# but DBD::SQLite does not expose it (nor does it seem to properly use it)
# Therefore only execute a "ping" when we have no other choice *AND*
# scrutinize the thrown exceptions to make sure we are where we think we are
my $dbh = $self->_dbh or return undef;
return undef unless $dbh->FETCH('Active');
return undef unless $dbh->ping;
my $ping_fail;
# older DBD::SQLite does not properly synchronize commit state between
# the libsqlite and the $dbh
unless (defined $DBD::SQLite::__DBIC_TXN_SYNC_SANE__) {
$DBD::SQLite::__DBIC_TXN_SYNC_SANE__ = modver_gt_or_eq('DBD::SQLite', '1.38_02');
}
# fallback to travesty
unless ($DBD::SQLite::__DBIC_TXN_SYNC_SANE__) {
# since we do not have access to sqlite3_get_autocommit(), do a trick
# to attempt to *safely* determine what state are we *actually* in.
# FIXME
# also using T::T here leads to bizarre leaks - will figure it out later
( run in 0.490 second using v1.01-cache-2.11-cpan-f56aa216473 )