use mro 'c3';
use DBIx::Class::Carp;
use Scalar::Util qw/blessed weaken/;
-use List::Util 'first';
-use Sub::Name();
-use Data::Dumper::Concise 'Dumper';
use Try::Tiny;
use Context::Preserve 'preserve_context';
-use DBIx::Class::_Util 'sigwarn_silencer';
+use DBIx::Class::_Util qw( sigwarn_silencer dbic_internal_try dump_value scope_guard set_subname );
use namespace::clean;
__PACKAGE__->sql_limit_dialect ('GenericSubQ');
my $replaced = __PACKAGE__->can($method);
- *{$method} = Sub::Name::subname $method => sub {
+ *{$method} = set_subname $method => sub {
my $self = shift;
$self->_writer_storage->$replaced(@_) if $self->_writer_storage;
$self->_bulk_storage->$replaced(@_) if $self->_bulk_storage;
sub _is_lob_column {
my ($self, $source, $column) = @_;
- return $self->_is_lob_type($source->column_info($column)->{data_type});
+ return $self->_is_lob_type(
+ $source->columns_info([$column])->{$column}{data_type}
+ );
}
sub _prep_for_execute {
# try to insert explicit 'DEFAULT's instead (except for identity, timestamp
# and computed columns)
if (not %$to_insert) {
+
+ my $ci;
+ # same order as add_columns
for my $col ($source->columns) {
next if $col eq $identity_col;
- my $info = $source->column_info($col);
-
- next if ref $info->{default_value} eq 'SCALAR'
- || (exists $info->{data_type} && (not defined $info->{data_type}));
-
- next if $info->{data_type} && $info->{data_type} =~ /^timestamp\z/i;
+ my $info = ( $ci ||= $source->columns_info )->{$col};
+
+ next if (
+ ref $info->{default_value} eq 'SCALAR'
+ or
+ (
+ exists $info->{data_type}
+ and
+ ! defined $info->{data_type}
+ )
+ or
+ (
+ ( $info->{data_type} || '' )
+ =~ /^timestamp\z/i
+ )
+ );
$to_insert->{$col} = \'DEFAULT';
}
my $blob_cols = $self->_remove_blob_cols($source, $to_insert);
- # do we need the horrific SELECT MAX(COL) hack?
- my $need_dumb_last_insert_id = (
- $self->_perform_autoinc_retrieval
- and
- ( ($self->_identity_method||'') ne '@@IDENTITY' )
- );
-
- my $next = $self->next::can;
-
- # we are already in a transaction, or there are no blobs
- # and we don't need the PK - just (try to) do it
+ # if a new txn is needed - it must happen on the _writer/new connection (for now)
+ my $guard;
if (
- ( !$blob_cols and !$need_dumb_last_insert_id )
- or
- $self->transaction_depth
+ ! $self->transaction_depth
+ and
+ (
+ $blob_cols
+ or
+ # do we need the horrific SELECT MAX(COL) hack?
+ (
+ $self->_perform_autoinc_retrieval
+ and
+ ( ($self->_identity_method||'') ne '@@IDENTITY' )
+ )
+ )
) {
- $self->_insert (
- $next, $source, $to_insert, $blob_cols, $identity_col
- );
- }
- # otherwise use the _writer_storage to do the insert+transaction on another
- # connection
- else {
- my $guard = $self->_writer_storage->txn_scope_guard;
-
- my $updated_cols = $self->_writer_storage->_insert (
- $next, $source, $to_insert, $blob_cols, $identity_col
- );
-
- $self->_identity($self->_writer_storage->_identity);
-
- $guard->commit;
-
- $updated_cols;
+ $self = $self->_writer_storage;
+ $guard = $self->txn_scope_guard;
}
-}
-
-sub _insert {
- my ($self, $next, $source, $to_insert, $blob_cols, $identity_col) = @_;
- my $updated_cols = $self->$next ($source, $to_insert);
+ my $updated_cols = $self->next::method ($source, $to_insert);
$self->_insert_blobs (
$source,
},
) if $blob_cols;
+ $guard->commit if $guard;
+
return $updated_cols;
}
if (keys %$fields) {
# Now set the identity update flags for the actual update
- local $self->{_autoinc_supplied_for_op} = (first
+ local $self->{_autoinc_supplied_for_op} = grep
{ $_->{is_auto_increment} }
values %{ $source->columns_info([ keys %$fields ]) }
- ) ? 1 : 0;
+ ;
my $next = $self->next::can;
my $args = \@_;
}
else {
# Set the identity update flags for the actual update
- local $self->{_autoinc_supplied_for_op} = (first
+ local $self->{_autoinc_supplied_for_op} = grep
{ $_->{is_auto_increment} }
values %{ $source->columns_info([ keys %$fields ]) }
- ) ? 1 : 0;
+ ;
return $self->next::method(@_);
}
my $columns_info = $source->columns_info;
- my $identity_col =
- first { $columns_info->{$_}{is_auto_increment} }
+ my ($identity_col) =
+ grep { $columns_info->{$_}{is_auto_increment} }
keys %$columns_info;
# FIXME - this is duplication from DBI.pm. When refactored towards
# the LobWriter this can be folded back where it belongs.
- local $self->{_autoinc_supplied_for_op} =
- (first { $_ eq $identity_col } @$cols)
- ? 1
- : 0
- ;
+ local $self->{_autoinc_supplied_for_op}
+ = grep { $_ eq $identity_col } @$cols;
my $use_bulk_api =
$self->_bulk_storage &&
my @source_columns = $source->columns;
# bcp identity index is 1-based
- my $identity_idx = first { $source_columns[$_] eq $identity_col } (0..$#source_columns);
+ my ($identity_idx) = grep { $source_columns[$_] eq $identity_col } (0..$#source_columns);
$identity_idx = defined $identity_idx ? $identity_idx + 1 : 0;
my @new_data;
# This ignores any data conversion errors detected by the client side libs, as
# they are usually harmless.
my $orig_cslib_cb = DBD::Sybase::set_cslib_cb(
- Sub::Name::subname _insert_bulk_cslib_errhandler => sub {
+ set_subname _insert_bulk_cslib_errhandler => sub {
my ($layer, $origin, $severity, $errno, $errmsg, $osmsg, $blkmsg) = @_;
return 1 if $errno == 36;
});
my $exception = '';
- try {
+ dbic_internal_try {
my $bulk = $self->_bulk_storage;
my $guard = $bulk->txn_scope_guard;
}
else {
$fields->{$col} = \"''";
- $blob_cols{$col} = $blob_val unless $blob_val eq '';
+ $blob_cols{$col} = $blob_val
+ if length $blob_val;
}
}
}
else {
$data->[$j][$i] = \"''";
$blob_cols[$j][$i] = $blob_val
- unless $blob_val eq '';
+ if length $blob_val;
}
}
}
sub _update_blobs {
my ($self, $source, $blob_cols, $where) = @_;
- my @primary_cols = try
+ my @primary_cols = dbic_internal_try
{ $source->_pri_cols_or_die }
catch {
$self->throw_exception("Cannot update TEXT/IMAGE column(s): $_")
my $table = $source->name;
- my @primary_cols = try
+ my @primary_cols = dbic_internal_try
{ $source->_pri_cols_or_die }
catch {
$self->throw_exception("Cannot update TEXT/IMAGE column(s): $_")
$self->throw_exception('Cannot update TEXT/IMAGE column(s) without primary key values')
if grep { ! defined $row_data->{$_} } @primary_cols;
+ # if we are 2-phase inserting a blob - there is nothing to retrieve anymore,
+ # regardless of the previous state of the flag
+ local $self->{_perform_autoinc_retrieval}
+ if $self->_perform_autoinc_retrieval;
+
my %where = map {( $_ => $row_data->{$_} )} @primary_cols;
for my $col (keys %$blob_cols) {
if (not $sth) {
$self->throw_exception(
"Could not find row in table '$table' for blob update:\n"
- . (Dumper \%where)
+ . dump_value \%where
);
}
- try {
+ # FIXME - it is not clear if this is needed at all. But it's been
+ # there since 2009 ( d867eedaa ), might as well let sleeping dogs
+ # lie... sigh.
+ weaken( my $wsth = $sth );
+ my $g = scope_guard { $wsth->finish if $wsth };
+
+ dbic_internal_try {
do {
$sth->func('CS_GET', 1, 'ct_data_info') or die $sth->errstr;
} while $sth->fetch;
else {
$self->throw_exception($_);
}
- }
- finally {
- $sth->finish if $sth;
};
}
}