Propagate quote_names setting to SQLite SQLT producer
[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
b1dbf716 9use DBIx::Class::_Util 'modver_gt_or_eq';
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>
53bind value that is an object with overloaded stringification (nummification
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
68is emited only once per callsite per process and only when the condition in
69question is encountered. Thus it is very unlikey that your logsystem will be
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 #
216 local $@; # so that we do not clober the real error as set above
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 {
67b35a45 243 $_[1] =~ /^ (?: int(?:eger)? | (?:tiny|small|medium)int ) $/ix
ad7c50fc 244 ? DBI::SQL_INTEGER()
0e773352 245 : undef
246 ;
247}
248
632d1e0f 249# DBD::SQLite (at least up to version 1.31 has a bug where it will
250# non-fatally nummify a string value bound as an integer, resulting
251# in insertions of '0' into supposed-to-be-numeric fields
252# Since this can result in severe data inconsistency, remove the
253# bind attr if such a sitation is detected
254#
255# FIXME - when a DBD::SQLite version is released that eventually fixes
256# this sutiation (somehow) - no-op this override once a proper DBD
257# version is detected
258sub _dbi_attrs_for_bind {
259 my ($self, $ident, $bind) = @_;
75a1d824 260
632d1e0f 261 my $bindattrs = $self->next::method($ident, $bind);
262
75a1d824 263 # an attempt to detect former effects of RT#79576, bug itself present between
264 # 0.08191 and 0.08209 inclusive (fixed in 0.08210 and higher)
265 my $stringifiable = 0;
266
632d1e0f 267 for (0.. $#$bindattrs) {
75a1d824 268
269 $stringifiable++ if ( length ref $bind->[$_][1] and overload::Method($bind->[$_][1], '""') );
270
632d1e0f 271 if (
272 defined $bindattrs->[$_]
273 and
274 defined $bind->[$_][1]
275 and
276 $bindattrs->[$_] eq DBI::SQL_INTEGER()
277 and
445bc0cd 278 $bind->[$_][1] !~ /^ [\+\-]? [0-9]+ (?: \. 0* )? $/x
632d1e0f 279 ) {
280 carp_unique( sprintf (
445bc0cd 281 "Non-integer value supplied for column '%s' despite the integer datatype",
632d1e0f 282 $bind->[$_][0]{dbic_colname} || "# $_"
283 ) );
284 undef $bindattrs->[$_];
285 }
286 }
287
75a1d824 288 carp_unique(
289 'POSSIBLE *PAST* DATA CORRUPTION detected - see '
290 . 'DBIx::Class::Storage::DBI::SQLite/RT79576 or '
291 . 'http://v.gd/DBIC_SQLite_RT79576 for further details or set '
292 . '$ENV{DBIC_RT79576_NOWARN} to disable this warning. Trigger '
293 . 'condition encountered'
294 ) if (!$ENV{DBIC_RT79576_NOWARN} and $stringifiable > 1);
295
632d1e0f 296 return $bindattrs;
297}
298
732e4282 299=head2 connect_call_use_foreign_keys
300
301Used as:
302
303 on_connect_call => 'use_foreign_keys'
304
8384a713 305In L<connect_info|DBIx::Class::Storage::DBI/connect_info> to turn on foreign key
306(including cascading) support for recent versions of SQLite and L<DBD::SQLite>.
732e4282 307
308Executes:
309
8273e845 310 PRAGMA foreign_keys = ON
732e4282 311
312See L<http://www.sqlite.org/foreignkeys.html> for more information.
313
314=cut
315
316sub connect_call_use_foreign_keys {
317 my $self = shift;
318
319 $self->_do_query(
320 'PRAGMA foreign_keys = ON'
321 );
322}
323
843f8ecd 3241;
325
0c11ad0e 326=head1 AUTHOR AND CONTRIBUTORS
843f8ecd 327
0c11ad0e 328See L<AUTHOR|DBIx::Class/AUTHOR> and L<CONTRIBUTORS|DBIx::Class/CONTRIBUTORS> in DBIx::Class
843f8ecd 329
330=head1 LICENSE
331
332You may distribute this code under the same terms as Perl itself.
333
334=cut