Skip to content

Commit

Permalink
Merge 'sybase' into 'sybase_bulk_insert'
Browse files Browse the repository at this point in the history
  • Loading branch information
rkitover committed Sep 18, 2009
2 parents 177e39a + 758b594 commit f49102d
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 83 deletions.
10 changes: 7 additions & 3 deletions lib/DBIx/Class/Storage/DBI.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1339,8 +1339,12 @@ sub insert_bulk {
my %colvalues;
my $table = $source->from;
@colvalues{@$cols} = (0..$#$cols);
# XXX some bulk APIs require column list in database order
my ($sql, @bind) = $self->sql_maker->insert($table, \%colvalues);

my ($sql, $bind) = $self->_prep_for_execute (
'insert', undef, $source, [\%colvalues]
);
my @bind = @$bind
or croak 'Cannot insert_bulk without support for placeholders';

$self->_query_start( $sql, @bind );
my $sth = $self->sth($sql, 'insert', $sth_attr);
Expand Down Expand Up @@ -1372,6 +1376,7 @@ sub insert_bulk {
$placeholder_index++;
}
my $rv = eval { $sth->execute_array({ArrayTupleStatus => $tuple_status}) };
$sth->finish;
if (my $err = $@ || $sth->errstr) {
my $i = 0;
++$i while $i <= $#$tuple_status && !ref $tuple_status->[$i];
Expand All @@ -1394,7 +1399,6 @@ sub insert_bulk {
);
}

$sth->finish;
$self->_query_end( $sql, @bind );
return (wantarray ? ($rv, $sth, @bind) : $rv);
}
Expand Down
117 changes: 97 additions & 20 deletions lib/DBIx/Class/Storage/DBI/Sybase.pm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ __PACKAGE__->mk_group_accessors('simple' =>
);

my @also_proxy_to_extra_storages = qw/
connect_call_set_auto_cast auto_cast connect_call_blob_setup
connect_call_datetime_setup
disconnect _connect_info _sql_maker _sql_maker_opts disable_sth_caching
auto_savepoint unsafe cursor_class debug debugobj schema
/;
Expand Down Expand Up @@ -126,6 +129,7 @@ sub _init {

$writer_storage->_is_extra_storage(1);
$writer_storage->connect_info($self->connect_info);
$writer_storage->auto_cast($self->auto_cast);

$self->_writer_storage($writer_storage);

Expand Down Expand Up @@ -237,6 +241,12 @@ sub _is_lob_type {
$type && $type =~ /(?:text|image|lob|bytea|binary|memo)/i;
}

sub _is_lob_column {
my ($self, $source, $column) = @_;

return $self->_is_lob_type($source->column_info($column)->{data_type});
}

sub _prep_for_execute {
my $self = shift;
my ($op, $extra_bind, $ident, $args) = @_;
Expand Down Expand Up @@ -394,33 +404,66 @@ sub _insert {

sub update {
my $self = shift;
my ($source, $fields, $where) = @_;
my ($source, $fields, $where, @rest) = @_;

my $wantarray = wantarray;

my $blob_cols = $self->_remove_blob_cols($source, $fields);

my $table = $source->name;

my $identity_col = List::Util::first
{ $source->column_info($_)->{is_auto_increment} }
$source->columns;

my $is_identity_update = $identity_col && defined $fields->{$identity_col};

if (not $blob_cols) {
$self->_set_identity_insert($table, 'update') if $is_identity_update;
return $self->next::method(@_);
$self->_unset_identity_insert($table, 'update') if $is_identity_update;
}

# check that we're not updating a blob column that's also in $where
for my $blob (grep $self->_is_lob_column($source, $_), $source->columns) {
if (exists $where->{$blob} && exists $fields->{$blob}) {
croak
'Update of TEXT/IMAGE column that is also in search condition impossible';
}
}

# update+blob update(s) done atomically on separate connection
$self = $self->_writer_storage;

my $guard = $self->txn_scope_guard;

my @res;
if ($wantarray) {
@res = $self->next::method(@_);
}
elsif (defined $wantarray) {
$res[0] = $self->next::method(@_);
}
else {
$self->next::method(@_);
}
# First update the blob columns to be updated to '' (taken from $fields, where
# it is originally put by _remove_blob_cols .)
my %blobs_to_empty = map { ($_ => delete $fields->{$_}) } keys %$blob_cols;

$self->next::method($source, \%blobs_to_empty, $where, @rest);

# Now update the blobs before the other columns in case the update of other
# columns makes the search condition invalid.
$self->_update_blobs($source, $blob_cols, $where);

my @res;
if (%$fields) {
$self->_set_identity_insert($table, 'update') if $is_identity_update;

if ($wantarray) {
@res = $self->next::method(@_);
}
elsif (defined $wantarray) {
$res[0] = $self->next::method(@_);
}
else {
$self->next::method(@_);
}

$self->_unset_identity_insert($table, 'update') if $is_identity_update;
}

$guard->commit;

return $wantarray ? @res : $res[0];
Expand All @@ -429,16 +472,23 @@ sub update {
### the insert_bulk partially stolen from DBI/MSSQL.pm

sub _set_identity_insert {
my ($self, $table) = @_;
my ($self, $table, $op) = @_;

my $sql = sprintf (
'SET IDENTITY_INSERT %s ON',
'SET IDENTITY_%s %s ON',
(uc($op) || 'INSERT'),
$self->sql_maker->_quote ($table),
);

$self->_query_start($sql);

my $dbh = $self->_get_dbh;
eval { $dbh->do ($sql) };
if ($@) {
my $exception = $@;

$self->_query_end($sql);

if ($exception) {
$self->throw_exception (sprintf "Error executing '%s': %s",
$sql,
$dbh->errstr,
Expand All @@ -447,18 +497,25 @@ sub _set_identity_insert {
}

sub _unset_identity_insert {
my ($self, $table) = @_;
my ($self, $table, $op) = @_;

my $sql = sprintf (
'SET IDENTITY_INSERT %s OFF',
'SET IDENTITY_%s %s OFF',
(uc($op) || 'INSERT'),
$self->sql_maker->_quote ($table),
);

$self->_query_start($sql);

my $dbh = $self->_get_dbh;
$dbh->do ($sql);

$self->_query_end($sql);
}

## XXX add blob support
# for tests
sub _can_insert_bulk { 1 }

sub insert_bulk {
my $self = shift;
my ($source, $cols, $data) = @_;
Expand Down Expand Up @@ -647,15 +704,23 @@ EOF
DBD::Sybase::set_cslib_cb($orig_cslib_cb);
}

# Make sure blobs are not bound as placeholders, and return any non-empty ones
# as a hash.
sub _remove_blob_cols {
my ($self, $source, $fields) = @_;

my %blob_cols;

for my $col (keys %$fields) {
if ($self->_is_lob_type($source->column_info($col)->{data_type})) {
$blob_cols{$col} = delete $fields->{$col};
$fields->{$col} = \"''";
my $blob_val = delete $fields->{$col};
if (not defined $blob_val) {
$fields->{$col} = \'NULL';
}
else {
$fields->{$col} = \"''";
$blob_cols{$col} = $blob_val unless $blob_val eq '';
}
}
}

Expand Down Expand Up @@ -697,7 +762,7 @@ sub _insert_blobs {
my ($self, $source, $blob_cols, $row) = @_;
my $dbh = $self->_get_dbh;

my $table = $source->from;
my $table = $source->name;

my %row = %$row;
my (@primary_cols) = $source->primary_columns;
Expand All @@ -718,6 +783,18 @@ sub _insert_blobs {
$cursor->next;
my $sth = $cursor->sth;

if (not $sth) {
require Data::Dumper;
local $Data::Dumper::Terse = 1;
local $Data::Dumper::Indent = 1;
local $Data::Dumper::Useqq = 1;
local $Data::Dumper::Quotekeys = 0;
local $Data::Dumper::Sortkeys = 1;

croak "\nCould not find row in table '$table' for blob update:\n".
Data::Dumper::Dumper(\%where)."\n";
}

eval {
do {
$sth->func('CS_GET', 1, 'ct_data_info') or die $sth->errstr;
Expand Down
3 changes: 3 additions & 0 deletions lib/DBIx/Class/Storage/DBI/Sybase/NoBindVars.pm
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ sub _prep_interpolated_value {
return $value;
}

# for tests
sub _can_insert_bulk { 0 }

1;

=head1 NAME
Expand Down
Loading

0 comments on commit f49102d

Please sign in to comment.