File Coverage

blib/lib/DBIx/Class/Storage/DBI/SQLite.pm
Criterion Covered Total %
statement 63 102 61.7
branch 19 52 36.5
condition 10 35 28.5
subroutine 17 22 77.2
pod 3 4 75.0
total 112 215 52.0


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