1 package DBIx::Class::Storage::DBI::SQLite;
6 use base qw/DBIx::Class::Storage::DBI/;
13 __PACKAGE__->sql_maker_class('DBIx::Class::SQLMaker::SQLite');
14 __PACKAGE__->sql_limit_dialect ('LimitOffset');
15 __PACKAGE__->sql_quote_char ('"');
16 __PACKAGE__->datetime_parser_type ('DateTime::Format::SQLite');
20 DBIx::Class::Storage::DBI::SQLite - Automatic primary key class for SQLite
24 # In your table classes
25 use base 'DBIx::Class::Core';
26 __PACKAGE__->set_primary_key('id');
30 This class implements autoincrements for SQLite.
38 NOTE - This section applies to you only if ALL of these are true:
40 * You are or were using DBD::SQLite with a version lesser than 1.38_01
42 * You are or were using DBIx::Class versions between 0.08191 and 0.08209
43 (inclusive) or between 0.08240-TRIAL and 0.08242-TRIAL (also inclusive)
45 * You use objects with overloaded stringification and are feeding them
46 to DBIC CRUD methods directly
48 An unfortunate chain of events led to DBIx::Class silently hitting the problem
49 described in L<RT#79576|https://rt.cpan.org/Public/Bug/Display.html?id=79576>.
51 In order to trigger the bug condition one needs to supply B<more than one>
52 bind value that is an object with overloaded stringification (nummification
53 is not relevant, only stringification is). When this is the case the internal
54 DBIx::Class call to C<< $sth->bind_param >> would be executed in a way that
55 triggers the above-mentioned DBD::SQLite bug. As a result all the logs and
56 tracers will contain the expected values, however SQLite will receive B<all>
57 these bind positions being set to the value of the B<last> supplied
60 Even if you upgrade DBIx::Class (which works around the bug starting from
61 version 0.08210) you may still have corrupted/incorrect data in your database.
62 DBIx::Class will currently detect when this condition (more than one
63 stringifiable object in one CRUD call) is encountered and will issue a warning
64 pointing to this section. This warning will be removed 2 years from now,
65 around April 2015, You can disable it after you've audited your data by
66 setting the C<DBIC_RT79576_NOWARN> environment variable. Note - the warning
67 is emited only once per callsite per process and only when the condition in
68 question is encountered. Thus it is very unlikey that your logsystem will be
69 flooded as a result of this.
83 my ($self, $dir) = @_;
86 ## Where is the db file?
87 my $dsn = $self->_dbi_connect_info()->[0];
89 my $dbname = $1 if($dsn =~ /dbname=([^;]+)/);
92 $dbname = $1 if($dsn =~ /^dbi:SQLite:(.+)$/i);
94 $self->throw_exception("Cannot determine name of SQLite db file")
95 if(!$dbname || !-f $dbname);
97 # print "Found database: $dbname\n";
98 # my $dbfile = file($dbname);
99 my ($vol, $dbdir, $file) = File::Spec->splitpath($dbname);
100 # my $file = $dbfile->basename();
101 $file = POSIX::strftime("%Y-%m-%d-%H_%M_%S", localtime()) . $file;
102 $file = "B$file" while(-f $file);
104 mkdir($dir) unless -f $dir;
105 my $backupfile = File::Spec->catfile($dir, $file);
107 my $res = File::Copy::copy($dbname, $backupfile);
108 $self->throw_exception("Backup failed! ($!)") if(!$res);
113 sub _exec_svp_begin {
114 my ($self, $name) = @_;
116 $self->_dbh->do("SAVEPOINT $name");
119 sub _exec_svp_release {
120 my ($self, $name) = @_;
122 $self->_dbh->do("RELEASE SAVEPOINT $name");
125 sub _exec_svp_rollback {
126 my ($self, $name) = @_;
128 # For some reason this statement changes the value of $dbh->{AutoCommit}, so
129 # we localize it here to preserve the original value.
130 local $self->_dbh->{AutoCommit} = $self->_dbh->{AutoCommit};
132 $self->_dbh->do("ROLLBACK TRANSACTION TO SAVEPOINT $name");
138 # Be extremely careful what we do here. SQLite is notoriously bad at
139 # synchronizing its internal transaction state with {AutoCommit}
140 # https://metacpan.org/source/ADAMK/DBD-SQLite-1.37/lib/DBD/SQLite.pm#L921
141 # There is a function http://www.sqlite.org/c3ref/get_autocommit.html
142 # but DBD::SQLite does not expose it (nor does it seem to properly use it)
144 # Therefore only execute a "ping" when we have no other choice *AND*
145 # scrutinize the thrown exceptions to make sure we are where we think we are
146 my $dbh = $self->_dbh or return undef;
147 return undef unless $dbh->FETCH('Active');
148 return undef unless $dbh->ping;
152 # older DBD::SQLite does not properly synchronize commit state between
153 # the libsqlite and the $dbh
154 unless (defined $DBD::SQLite::__DBIC_TXN_SYNC_SANE__) {
156 $DBD::SQLite::__DBIC_TXN_SYNC_SANE__ = eval { DBD::SQLite->VERSION(1.38_02); 1 }
162 # fallback to travesty
163 unless ($DBD::SQLite::__DBIC_TXN_SYNC_SANE__) {
164 # since we do not have access to sqlite3_get_autocommit(), do a trick
165 # to attempt to *safely* determine what state are we *actually* in.
167 # also using T::T here leads to bizarre leaks - will figure it out later
168 my $really_not_in_txn = do {
171 # older versions of DBD::SQLite do not properly detect multiline BEGIN/COMMIT
172 # statements to adjust their {AutoCommit} state. Hence use such a statement
173 # pair here as well, in order to escape from poking {AutoCommit} needlessly
174 # https://rt.cpan.org/Public/Bug/Display.html?id=80087
176 # will fail instantly if already in a txn
177 $dbh->do("-- multiline\nBEGIN");
178 $dbh->do("-- multiline\nCOMMIT");
181 ($@ =~ /transaction within a transaction/)
188 # if we were unable to determine this - we may very well be dead
189 if (not defined $really_not_in_txn) {
192 # check the AC sync-state
193 elsif ($really_not_in_txn xor $dbh->{AutoCommit}) {
195 'Internal transaction state of handle %s (apparently %s a transaction) does not seem to '
196 . 'match its AutoCommit attribute setting of %s - this is an indication of a '
197 . 'potentially serious bug in your transaction handling logic',
199 $really_not_in_txn ? 'NOT in' : 'in',
200 $dbh->{AutoCommit} ? 'TRUE' : 'FALSE',
203 # it is too dangerous to execute anything else in this state
204 # assume everything works (safer - worst case scenario next statement throws)
209 # do the actual test and return on no failure
210 ( $ping_fail ||= ! try { $dbh->do('SELECT * FROM sqlite_master LIMIT 1'); 1 } )
211 or return 1; # the actual RV of _ping()
213 # ping failed (or so it seems) - need to do some cleanup
214 # it is possible to have a proper "connection", and have "ping" return
215 # false anyway (e.g. corrupted file). In such cases DBD::SQLite still
216 # keeps the actual file handle open. We don't really want this to happen,
217 # so force-close the handle via DBI itself
219 local $@; # so that we do not clober the real error as set above
220 eval { $dbh->disconnect }; # if it fails - it fails
221 undef; # the actual RV of _ping()
224 sub deployment_statements {
226 my ($schema, $type, $version, $dir, $sqltargs, @rest) = @_;
231 ! exists $sqltargs->{producer_args}{sqlite_version}
233 my $dver = $self->_server_info->{normalized_dbms_version}
235 $sqltargs->{producer_args}{sqlite_version} = $dver;
238 $self->next::method($schema, $type, $version, $dir, $sqltargs, @rest);
241 sub bind_attribute_by_data_type {
242 $_[1] =~ /^ (?: int(?:eger)? | (?:tiny|small|medium)int ) $/ix
248 # DBD::SQLite (at least up to version 1.31 has a bug where it will
249 # non-fatally nummify a string value bound as an integer, resulting
250 # in insertions of '0' into supposed-to-be-numeric fields
251 # Since this can result in severe data inconsistency, remove the
252 # bind attr if such a sitation is detected
254 # FIXME - when a DBD::SQLite version is released that eventually fixes
255 # this sutiation (somehow) - no-op this override once a proper DBD
256 # version is detected
257 sub _dbi_attrs_for_bind {
258 my ($self, $ident, $bind) = @_;
260 my $bindattrs = $self->next::method($ident, $bind);
262 # an attempt to detect former effects of RT#79576, bug itself present between
263 # 0.08191 and 0.08209 inclusive (fixed in 0.08210 and higher)
264 my $stringifiable = 0;
266 for (0.. $#$bindattrs) {
268 $stringifiable++ if ( length ref $bind->[$_][1] and overload::Method($bind->[$_][1], '""') );
271 defined $bindattrs->[$_]
273 defined $bind->[$_][1]
275 $bindattrs->[$_] eq DBI::SQL_INTEGER()
277 $bind->[$_][1] !~ /^ [\+\-]? [0-9]+ (?: \. 0* )? $/x
279 carp_unique( sprintf (
280 "Non-integer value supplied for column '%s' despite the integer datatype",
281 $bind->[$_][0]{dbic_colname} || "# $_"
283 undef $bindattrs->[$_];
288 'POSSIBLE *PAST* DATA CORRUPTION detected - see '
289 . 'DBIx::Class::Storage::DBI::SQLite/RT79576 or '
290 . 'http://v.gd/DBIC_SQLite_RT79576 for further details or set '
291 . '$ENV{DBIC_RT79576_NOWARN} to disable this warning. Trigger '
292 . 'condition encountered'
293 ) if (!$ENV{DBIC_RT79576_NOWARN} and $stringifiable > 1);
298 =head2 connect_call_use_foreign_keys
302 on_connect_call => 'use_foreign_keys'
304 In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to turn on foreign key
305 (including cascading) support for recent versions of SQLite and L<DBD::SQLite>.
309 PRAGMA foreign_keys = ON
311 See L<http://www.sqlite.org/foreignkeys.html> for more information.
315 sub connect_call_use_foreign_keys {
319 'PRAGMA foreign_keys = ON'
325 =head1 AUTHOR AND CONTRIBUTORS
327 See L<AUTHOR|DBIx::Class/AUTHOR> and L<CONTRIBUTORS|DBIx::Class/CONTRIBUTORS> in DBIx::Class
331 You may distribute this code under the same terms as Perl itself.