use base qw/DBIx::Class::Storage::DBI/;
use mro 'c3';
-use DBIx::Class::_Util qw(modver_gt_or_eq sigwarn_silencer);
+use SQL::Abstract 'is_plain_value';
+use DBIx::Class::_Util qw(modver_gt_or_eq sigwarn_silencer dbic_internal_try);
use DBIx::Class::Carp;
use Try::Tiny;
use namespace::clean;
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 will currently detect when this condition (more than one
-stringifiable object in one CRUD call) is encountered and will issue a warning
-pointing to this section. This warning will be removed 2 years from now,
-around April 2015, You can disable it after you've audited your data by
-setting the C<DBIC_RT79576_NOWARN> environment variable. Note - the warning
-is emitted only once per callsite per process and only when the condition in
-question is encountered. Thus it is very unlikely that your logsystem will be
-flooded as a result of this.
+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
sub _exec_svp_rollback {
my ($self, $name) = @_;
- # For some reason this statement changes the value of $dbh->{AutoCommit}, so
- # we localize it here to preserve the original value.
- local $self->_dbh->{AutoCommit} = $self->_dbh->{AutoCommit};
+ $self->_dbh->do("ROLLBACK TO SAVEPOINT $name");
- $self->_dbh->do("ROLLBACK TRANSACTION 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 {
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
- my $really_not_in_txn = do {
- local $@;
+
+ my $really_not_in_txn;
+
+ # not assigning RV directly to env above, because this causes a bizarre
+ # leak of the catch{} cref on older perls... wtf
+ dbic_internal_try {
# older versions of DBD::SQLite do not properly detect multiline BEGIN/COMMIT
# statements to adjust their {AutoCommit} state. Hence use such a statement
# pair here as well, in order to escape from poking {AutoCommit} needlessly
# https://rt.cpan.org/Public/Bug/Display.html?id=80087
- eval {
- # will fail instantly if already in a txn
- $dbh->do("-- multiline\nBEGIN");
- $dbh->do("-- multiline\nCOMMIT");
- 1;
- } or do {
- ($@ =~ /transaction within a transaction/)
- ? 0
- : undef
- ;
- };
+ #
+ # will fail instantly if already in a txn
+ $dbh->do("-- multiline\nBEGIN");
+ $dbh->do("-- multiline\nCOMMIT");
+
+ $really_not_in_txn = 1;
+ }
+ catch {
+ $really_not_in_txn = ( $_[0] =~ qr/transaction within a transaction/
+ ? 0
+ : undef
+ );
};
# if we were unable to determine this - we may very well be dead
}
# do the actual test and return on no failure
- ( $ping_fail ||= ! try { $dbh->do('SELECT * FROM sqlite_master LIMIT 1'); 1 } )
+ ( $ping_fail ||= ! dbic_internal_try { $dbh->do('SELECT * FROM sqlite_master LIMIT 1'); 1 } )
or return 1; # the actual RV of _ping()
# ping failed (or so it seems) - need to do some cleanup
# keeps the actual file handle open. We don't really want this to happen,
# so force-close the handle via DBI itself
#
- local $@; # so that we do not clobber the real error as set above
- eval { $dbh->disconnect }; # if it fails - it fails
+ dbic_internal_try { $dbh->disconnect }; # if it fails - it fails
undef; # the actual RV of _ping()
}
$sqltargs->{producer_args}{sqlite_version} = $dver;
}
- $sqltargs->{quote_identifiers}
- = !!$self->sql_maker->_quote_chars
- if ! exists $sqltargs->{quote_identifiers};
-
$self->next::method($schema, $type, $version, $dir, $sqltargs, @rest);
}
# DBD::SQLite warns on binding >32 bit values with 32 bit IVs
sub _dbh_execute {
if (
- DBIx::Class::_ENV_::IV_SIZE < 8
+ (
+ DBIx::Class::_ENV_::IV_SIZE < 8
+ or
+ DBIx::Class::_ENV_::OS_NAME eq 'MSWin32'
+ )
and
! defined $DBD::SQLite::__DBIC_CHECK_dbd_mishandles_bound_BIGINT
) {
|
\d+ \s type \s @{[ DBI::SQL_BIGINT() ]} \s as \s [-+]? \d+ (?: \. 0*)?
)
- /x ) if DBIx::Class::_ENV_::IV_SIZE < 8 and $DBD::SQLite::__DBIC_CHECK_dbd_mishandles_bound_BIGINT;
+ /x ) if (
+ (
+ DBIx::Class::_ENV_::IV_SIZE < 8
+ or
+ DBIx::Class::_ENV_::OS_NAME eq 'MSWin32'
+ )
+ and
+ $DBD::SQLite::__DBIC_CHECK_dbd_mishandles_bound_BIGINT
+ );
shift->next::method(@_);
}
my $bindattrs = $self->next::method($ident, $bind);
- # somewhere between 1.33 and 1.37 things went horribly wrong
if (! defined $DBD::SQLite::__DBIC_CHECK_dbd_can_bind_bigint_values) {
- $DBD::SQLite::__DBIC_CHECK_dbd_can_bind_bigint_values = (
- modver_gt_or_eq('DBD::SQLite', '1.34')
- and
- ! modver_gt_or_eq('DBD::SQLite', '1.37')
- ) ? 0 : 1;
+ $DBD::SQLite::__DBIC_CHECK_dbd_can_bind_bigint_values
+ = modver_gt_or_eq('DBD::SQLite', '1.37') ? 1 : 0;
}
- # an attempt to detect former effects of RT#79576, bug itself present between
- # 0.08191 and 0.08209 inclusive (fixed in 0.08210 and higher)
- my $stringifiable = 0;
-
for my $i (0.. $#$bindattrs) {
-
- $stringifiable++ if ( length ref $bind->[$i][1] and overload::Method($bind->[$i][1], '""') );
-
if (
defined $bindattrs->[$i]
and
}
elsif (
! $DBD::SQLite::__DBIC_CHECK_dbd_can_bind_bigint_values
- and
+ ) {
# unsigned 32 bit ints have a range of −2,147,483,648 to 2,147,483,647
# alternatively expressed as the hexadecimal numbers below
# the comparison math will come out right regardless of ivsize, since
# we are operating within 31 bits
# P.S. 31 because one bit is lost for the sign
- ($bind->[$i][1] > 0x7fff_ffff or $bind->[$i][1] < -0x8000_0000)
- ) {
- carp_unique( sprintf (
- "An integer value occupying more than 32 bits was supplied for column '%s' "
- . 'which your version of DBD::SQLite (%s) can not bind properly so DBIC '
- . 'will treat it as a string instead, consider upgrading to at least '
- . 'DBD::SQLite version 1.37',
- $bind->[$i][0]{dbic_colname} || "# $i",
- DBD::SQLite->VERSION,
- ) );
- undef $bindattrs->[$i];
+ if ($bind->[$i][1] > 0x7fff_ffff or $bind->[$i][1] < -0x8000_0000) {
+ carp_unique( sprintf (
+ "An integer value occupying more than 32 bits was supplied for column '%s' "
+ . 'which your version of DBD::SQLite (%s) can not bind properly so DBIC '
+ . 'will treat it as a string instead, consider upgrading to at least '
+ . 'DBD::SQLite version 1.37',
+ $bind->[$i][0]{dbic_colname} || "# $i",
+ DBD::SQLite->VERSION,
+ ) );
+ undef $bindattrs->[$i];
+ }
+ else {
+ $bindattrs->[$i] = DBI::SQL_INTEGER()
+ }
}
}
}
- carp_unique(
- 'POSSIBLE *PAST* DATA CORRUPTION detected - see '
- . 'DBIx::Class::Storage::DBI::SQLite/RT79576 or '
- . 'http://v.gd/DBIC_SQLite_RT79576 for further details or set '
- . '$ENV{DBIC_RT79576_NOWARN} to disable this warning. Trigger '
- . 'condition encountered'
- ) if (!$ENV{DBIC_RT79576_NOWARN} and $stringifiable > 1);
-
return $bindattrs;
}
);
}
-1;
+=head1 FURTHER QUESTIONS?
-=head1 AUTHOR AND CONTRIBUTORS
+Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
-See L<AUTHOR|DBIx::Class/AUTHOR> and L<CONTRIBUTORS|DBIx::Class/CONTRIBUTORS> in DBIx::Class
+=head1 COPYRIGHT AND LICENSE
-=head1 LICENSE
-
-You may distribute this code under the same terms as Perl itself.
+This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
+by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
+redistribute it and/or modify it under the same terms as the
+L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
=cut
+
+1;