Many improvements of bigint handling across various DBD::SQLite versions
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / SQLite.pm
CommitLineData
843f8ecd 1package DBIx::Class::Storage::DBI::SQLite;
2
3use strict;
4use warnings;
2ad62d97 5
6use base qw/DBIx::Class::Storage::DBI/;
7use mro 'c3';
8
04ab4eb1 9use DBIx::Class::_Util qw(modver_gt_or_eq sigwarn_silencer);
632d1e0f 10use DBIx::Class::Carp;
8d1fb3e2 11use Try::Tiny;
632d1e0f 12use namespace::clean;
13
d5dedbd6 14__PACKAGE__->sql_maker_class('DBIx::Class::SQLMaker::SQLite');
6a247f33 15__PACKAGE__->sql_limit_dialect ('LimitOffset');
2b8cc2f2 16__PACKAGE__->sql_quote_char ('"');
6f7a118e 17__PACKAGE__->datetime_parser_type ('DateTime::Format::SQLite');
09cedb88 18
2fa97c7d 19=head1 NAME
20
21DBIx::Class::Storage::DBI::SQLite - Automatic primary key class for SQLite
22
23=head1 SYNOPSIS
24
25 # In your table classes
26 use base 'DBIx::Class::Core';
27 __PACKAGE__->set_primary_key('id');
28
29=head1 DESCRIPTION
30
31This class implements autoincrements for SQLite.
32
75a1d824 33=head2 Known Issues
34
35=over
36
37=item RT79576
38
39 NOTE - This section applies to you only if ALL of these are true:
40
41 * You are or were using DBD::SQLite with a version lesser than 1.38_01
42
43 * You are or were using DBIx::Class versions between 0.08191 and 0.08209
44 (inclusive) or between 0.08240-TRIAL and 0.08242-TRIAL (also inclusive)
45
46 * You use objects with overloaded stringification and are feeding them
47 to DBIC CRUD methods directly
48
49An unfortunate chain of events led to DBIx::Class silently hitting the problem
50described in L<RT#79576|https://rt.cpan.org/Public/Bug/Display.html?id=79576>.
51
52In order to trigger the bug condition one needs to supply B<more than one>
4a0eed52 53bind value that is an object with overloaded stringification (numification
75a1d824 54is not relevant, only stringification is). When this is the case the internal
55DBIx::Class call to C<< $sth->bind_param >> would be executed in a way that
56triggers the above-mentioned DBD::SQLite bug. As a result all the logs and
57tracers will contain the expected values, however SQLite will receive B<all>
58these bind positions being set to the value of the B<last> supplied
59stringifiable object.
60
61Even if you upgrade DBIx::Class (which works around the bug starting from
62version 0.08210) you may still have corrupted/incorrect data in your database.
63DBIx::Class will currently detect when this condition (more than one
64stringifiable object in one CRUD call) is encountered and will issue a warning
65pointing to this section. This warning will be removed 2 years from now,
66around April 2015, You can disable it after you've audited your data by
67setting the C<DBIC_RT79576_NOWARN> environment variable. Note - the warning
4a0eed52 68is emitted only once per callsite per process and only when the condition in
69question is encountered. Thus it is very unlikely that your logsystem will be
75a1d824 70flooded as a result of this.
71
72=back
73
2fa97c7d 74=head1 METHODS
75
76=cut
77
357eb92c 78sub backup {
79
80 require File::Spec;
81 require File::Copy;
82 require POSIX;
83
8795fefb 84 my ($self, $dir) = @_;
85 $dir ||= './';
c9d2e0a2 86
87 ## Where is the db file?
12c9beea 88 my $dsn = $self->_dbi_connect_info()->[0];
c9d2e0a2 89
90 my $dbname = $1 if($dsn =~ /dbname=([^;]+)/);
91 if(!$dbname)
92 {
93 $dbname = $1 if($dsn =~ /^dbi:SQLite:(.+)$/i);
94 }
357eb92c 95 $self->throw_exception("Cannot determine name of SQLite db file")
c9d2e0a2 96 if(!$dbname || !-f $dbname);
97
98# print "Found database: $dbname\n";
79923569 99# my $dbfile = file($dbname);
8795fefb 100 my ($vol, $dbdir, $file) = File::Spec->splitpath($dbname);
79923569 101# my $file = $dbfile->basename();
357eb92c 102 $file = POSIX::strftime("%Y-%m-%d-%H_%M_%S", localtime()) . $file;
c9d2e0a2 103 $file = "B$file" while(-f $file);
8795fefb 104
105 mkdir($dir) unless -f $dir;
106 my $backupfile = File::Spec->catfile($dir, $file);
107
357eb92c 108 my $res = File::Copy::copy($dbname, $backupfile);
c9d2e0a2 109 $self->throw_exception("Backup failed! ($!)") if(!$res);
110
8795fefb 111 return $backupfile;
c9d2e0a2 112}
113
86a51471 114sub _exec_svp_begin {
115 my ($self, $name) = @_;
116
117 $self->_dbh->do("SAVEPOINT $name");
118}
119
120sub _exec_svp_release {
121 my ($self, $name) = @_;
122
123 $self->_dbh->do("RELEASE SAVEPOINT $name");
124}
125
126sub _exec_svp_rollback {
127 my ($self, $name) = @_;
128
129 # For some reason this statement changes the value of $dbh->{AutoCommit}, so
130 # we localize it here to preserve the original value.
131 local $self->_dbh->{AutoCommit} = $self->_dbh->{AutoCommit};
132
133 $self->_dbh->do("ROLLBACK TRANSACTION TO SAVEPOINT $name");
134}
135
8d1fb3e2 136sub _ping {
137 my $self = shift;
2aeb3c7f 138
139 # Be extremely careful what we do here. SQLite is notoriously bad at
140 # synchronizing its internal transaction state with {AutoCommit}
141 # https://metacpan.org/source/ADAMK/DBD-SQLite-1.37/lib/DBD/SQLite.pm#L921
142 # There is a function http://www.sqlite.org/c3ref/get_autocommit.html
143 # but DBD::SQLite does not expose it (nor does it seem to properly use it)
144
145 # Therefore only execute a "ping" when we have no other choice *AND*
146 # scrutinize the thrown exceptions to make sure we are where we think we are
147 my $dbh = $self->_dbh or return undef;
148 return undef unless $dbh->FETCH('Active');
149 return undef unless $dbh->ping;
150
ab0b0a09 151 my $ping_fail;
152
153 # older DBD::SQLite does not properly synchronize commit state between
154 # the libsqlite and the $dbh
155 unless (defined $DBD::SQLite::__DBIC_TXN_SYNC_SANE__) {
b1dbf716 156 $DBD::SQLite::__DBIC_TXN_SYNC_SANE__ = modver_gt_or_eq('DBD::SQLite', '1.38_02');
ab0b0a09 157 }
2aeb3c7f 158
ab0b0a09 159 # fallback to travesty
160 unless ($DBD::SQLite::__DBIC_TXN_SYNC_SANE__) {
161 # since we do not have access to sqlite3_get_autocommit(), do a trick
162 # to attempt to *safely* determine what state are we *actually* in.
163 # FIXME
164 # also using T::T here leads to bizarre leaks - will figure it out later
165 my $really_not_in_txn = do {
166 local $@;
167
168 # older versions of DBD::SQLite do not properly detect multiline BEGIN/COMMIT
169 # statements to adjust their {AutoCommit} state. Hence use such a statement
170 # pair here as well, in order to escape from poking {AutoCommit} needlessly
171 # https://rt.cpan.org/Public/Bug/Display.html?id=80087
172 eval {
173 # will fail instantly if already in a txn
174 $dbh->do("-- multiline\nBEGIN");
175 $dbh->do("-- multiline\nCOMMIT");
176 1;
177 } or do {
178 ($@ =~ /transaction within a transaction/)
179 ? 0
180 : undef
181 ;
182 };
2aeb3c7f 183 };
2aeb3c7f 184
ab0b0a09 185 # if we were unable to determine this - we may very well be dead
186 if (not defined $really_not_in_txn) {
187 $ping_fail = 1;
188 }
189 # check the AC sync-state
190 elsif ($really_not_in_txn xor $dbh->{AutoCommit}) {
191 carp_unique (sprintf
192 'Internal transaction state of handle %s (apparently %s a transaction) does not seem to '
193 . 'match its AutoCommit attribute setting of %s - this is an indication of a '
194 . 'potentially serious bug in your transaction handling logic',
195 $dbh,
196 $really_not_in_txn ? 'NOT in' : 'in',
197 $dbh->{AutoCommit} ? 'TRUE' : 'FALSE',
198 );
199
200 # it is too dangerous to execute anything else in this state
201 # assume everything works (safer - worst case scenario next statement throws)
202 return 1;
203 }
2aeb3c7f 204 }
205
ab0b0a09 206 # do the actual test and return on no failure
207 ( $ping_fail ||= ! try { $dbh->do('SELECT * FROM sqlite_master LIMIT 1'); 1 } )
208 or return 1; # the actual RV of _ping()
209
210 # ping failed (or so it seems) - need to do some cleanup
211 # it is possible to have a proper "connection", and have "ping" return
212 # false anyway (e.g. corrupted file). In such cases DBD::SQLite still
213 # keeps the actual file handle open. We don't really want this to happen,
214 # so force-close the handle via DBI itself
215 #
4a0eed52 216 local $@; # so that we do not clobber the real error as set above
ab0b0a09 217 eval { $dbh->disconnect }; # if it fails - it fails
218 undef; # the actual RV of _ping()
8d1fb3e2 219}
220
2361982d 221sub deployment_statements {
96736321 222 my $self = shift;
2361982d 223 my ($schema, $type, $version, $dir, $sqltargs, @rest) = @_;
224
225 $sqltargs ||= {};
226
96736321 227 if (
228 ! exists $sqltargs->{producer_args}{sqlite_version}
229 and
230 my $dver = $self->_server_info->{normalized_dbms_version}
231 ) {
232 $sqltargs->{producer_args}{sqlite_version} = $dver;
6d766626 233 }
2361982d 234
f9b5239a 235 $sqltargs->{quote_identifiers}
236 = !!$self->sql_maker->_quote_chars
237 if ! exists $sqltargs->{quote_identifiers};
238
2361982d 239 $self->next::method($schema, $type, $version, $dir, $sqltargs, @rest);
240}
241
0e773352 242sub bind_attribute_by_data_type {
04ab4eb1 243
244 # According to http://www.sqlite.org/datatype3.html#storageclasses
245 # all numeric types are dynamically allocated up to 8 bytes per
246 # individual value
247 # Thus it should be safe and non-wasteful to bind everything as
248 # SQL_BIGINT and have SQLite deal with storage/comparisons however
249 # it deems correct
250 $_[1] =~ /^ (?: int(?:[1248]|eger)? | (?:tiny|small|medium|big)int ) $/ix
251 ? DBI::SQL_BIGINT()
0e773352 252 : undef
253 ;
254}
255
04ab4eb1 256# FIXME - what the flying fuck... work around RT#76395
257# DBD::SQLite warns on binding >32 bit values with 32 bit IVs
258sub _dbh_execute {
259 if (DBIx::Class::_ENV_::IV_SIZE < 8) {
260
261 if (! defined $DBD::SQLite::__DBIC_CHECK_dbd_mishandles_bound_BIGINT) {
262 $DBD::SQLite::__DBIC_CHECK_dbd_mishandles_bound_BIGINT = (
263 modver_gt_or_eq('DBD::SQLite', '1.37')
264 ) ? 1 : 0;
265 }
266
267 local $SIG{__WARN__} = sigwarn_silencer( qr/datatype mismatch/ )
268 if $DBD::SQLite::__DBIC_CHECK_dbd_mishandles_bound_BIGINT;
269 }
270
271 shift->next::method(@_);
272}
273
632d1e0f 274# DBD::SQLite (at least up to version 1.31 has a bug where it will
4a0eed52 275# non-fatally numify a string value bound as an integer, resulting
632d1e0f 276# in insertions of '0' into supposed-to-be-numeric fields
277# Since this can result in severe data inconsistency, remove the
4a0eed52 278# bind attr if such a situation is detected
632d1e0f 279#
280# FIXME - when a DBD::SQLite version is released that eventually fixes
4a0eed52 281# this situation (somehow) - no-op this override once a proper DBD
632d1e0f 282# version is detected
283sub _dbi_attrs_for_bind {
284 my ($self, $ident, $bind) = @_;
75a1d824 285
632d1e0f 286 my $bindattrs = $self->next::method($ident, $bind);
287
04ab4eb1 288 # somewhere between 1.33 and 1.37 things went horribly wrong
289 if (! defined $DBD::SQLite::__DBIC_CHECK_dbd_can_bind_bigint_values) {
290 $DBD::SQLite::__DBIC_CHECK_dbd_can_bind_bigint_values = (
291 modver_gt_or_eq('DBD::SQLite', '1.34')
292 and
293 ! modver_gt_or_eq('DBD::SQLite', '1.37')
294 ) ? 0 : 1;
295 }
296
75a1d824 297 # an attempt to detect former effects of RT#79576, bug itself present between
298 # 0.08191 and 0.08209 inclusive (fixed in 0.08210 and higher)
299 my $stringifiable = 0;
300
49f7b6c7 301 for my $i (0.. $#$bindattrs) {
75a1d824 302
49f7b6c7 303 $stringifiable++ if ( length ref $bind->[$i][1] and overload::Method($bind->[$i][1], '""') );
75a1d824 304
632d1e0f 305 if (
49f7b6c7 306 defined $bindattrs->[$i]
632d1e0f 307 and
49f7b6c7 308 defined $bind->[$i][1]
632d1e0f 309 and
d830d9f4 310 grep { $bindattrs->[$i] eq $_ } (
311 DBI::SQL_INTEGER(), DBI::SQL_TINYINT(), DBI::SQL_SMALLINT(), DBI::SQL_BIGINT()
312 )
632d1e0f 313 ) {
04ab4eb1 314 if ( $bind->[$i][1] !~ /^ [\+\-]? [0-9]+ (?: \. 0* )? $/x ) {
315 carp_unique( sprintf (
316 "Non-integer value supplied for column '%s' despite the integer datatype",
317 $bind->[$i][0]{dbic_colname} || "# $i"
318 ) );
319 undef $bindattrs->[$i];
320 }
321 elsif (
322 ! $DBD::SQLite::__DBIC_CHECK_dbd_can_bind_bigint_values
323 and
324 # unsigned 32 bit ints have a range of −2,147,483,648 to 2,147,483,647
325 # alternatively expressed as the hexadecimal numbers below
326 # the comparison math will come out right regardless of ivsize, since
327 # we are operating within 31 bits
328 # P.S. 31 because one bit is lost for the sign
329 ($bind->[$i][1] > 0x7fff_ffff or $bind->[$i][1] < -0x8000_0000)
330 ) {
331 carp_unique( sprintf (
332 "An integer value occupying more than 32 bits was supplied for column '%s' "
333 . 'which your version of DBD::SQLite (%s) can not bind properly so DBIC '
334 . 'will treat it as a string instead, consider upgrading to at least '
335 . 'DBD::SQLite version 1.37',
336 $bind->[$i][0]{dbic_colname} || "# $i",
337 DBD::SQLite->VERSION,
338 ) );
339 undef $bindattrs->[$i];
340 }
632d1e0f 341 }
342 }
343
75a1d824 344 carp_unique(
345 'POSSIBLE *PAST* DATA CORRUPTION detected - see '
346 . 'DBIx::Class::Storage::DBI::SQLite/RT79576 or '
347 . 'http://v.gd/DBIC_SQLite_RT79576 for further details or set '
348 . '$ENV{DBIC_RT79576_NOWARN} to disable this warning. Trigger '
349 . 'condition encountered'
350 ) if (!$ENV{DBIC_RT79576_NOWARN} and $stringifiable > 1);
351
632d1e0f 352 return $bindattrs;
353}
354
732e4282 355=head2 connect_call_use_foreign_keys
356
357Used as:
358
359 on_connect_call => 'use_foreign_keys'
360
8384a713 361In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to turn on foreign key
362(including cascading) support for recent versions of SQLite and L<DBD::SQLite>.
732e4282 363
364Executes:
365
8273e845 366 PRAGMA foreign_keys = ON
732e4282 367
368See L<http://www.sqlite.org/foreignkeys.html> for more information.
369
370=cut
371
372sub connect_call_use_foreign_keys {
373 my $self = shift;
374
375 $self->_do_query(
376 'PRAGMA foreign_keys = ON'
377 );
378}
379
843f8ecd 3801;
381
0c11ad0e 382=head1 AUTHOR AND CONTRIBUTORS
843f8ecd 383
0c11ad0e 384See L<AUTHOR|DBIx::Class/AUTHOR> and L<CONTRIBUTORS|DBIx::Class/CONTRIBUTORS> in DBIx::Class
843f8ecd 385
386=head1 LICENSE
387
388You may distribute this code under the same terms as Perl itself.
389
390=cut