From: Rafael Kitover Date: Sat, 25 Jul 2009 19:23:49 +0000 (+0000) Subject: make insert work as a nested transaction too X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=f6de71113251acc964444e57bf3d38a23dc09ffd;p=dbsrgits%2FDBIx-Class-Historic.git make insert work as a nested transaction too --- diff --git a/lib/DBIx/Class/Storage/DBI/Sybase.pm b/lib/DBIx/Class/Storage/DBI/Sybase.pm index 6460a3c..b320242 100644 --- a/lib/DBIx/Class/Storage/DBI/Sybase.pm +++ b/lib/DBIx/Class/Storage/DBI/Sybase.pm @@ -32,7 +32,7 @@ will be reblessed to L. You can also enable that driver explicitly, see the documentation for more details. With this driver there is unfortunately no way to get the C -without doing a C. But your queries will be cached. @@ -95,6 +95,14 @@ EOF } } +# Make sure we have CHAINED mode turned on, we don't know how DBD::Sybase was +# compiled. +sub _populate_dbh { + my $self = shift; + $self->next::method(@_); + $self->_dbh->{syb_chained_txn} = 1; +} + sub _using_freetds { my $self = shift; @@ -199,12 +207,9 @@ List::Util::first { $bind_info->{$_}{is_auto_increment} } (keys %$bind_info); } if ($identity_col) { -# Sybase has nested transactions, only the outermost is actually committed $sql = - "BEGIN TRANSACTION\n" . "$sql\n" . - $self->_fetch_identity_sql($ident, $identity_col) . "\n" . - "COMMIT"; + $self->_fetch_identity_sql($ident, $identity_col) . "\n"; } } @@ -233,14 +238,24 @@ sub _execute { sub last_insert_id { shift->_identity } -# override to handle TEXT/IMAGE +# override to handle TEXT/IMAGE and nested txn sub insert { my ($self, $source, $to_insert) = splice @_, 0, 3; my $dbh = $self->_dbh; my $blob_cols = $self->_remove_blob_cols($source, $to_insert); - my $updated_cols = $self->next::method($source, $to_insert, @_); +# Sybase has nested transactions fortunately, because we have to do the insert +# in a transaction to avoid race conditions with the SELECT MAX(COL) identity +# method used when placeholders are enabled. + my $updated_cols = do { + local $self->{auto_savepoint} = 1; + my $args = \@_; + my $method = $self->next::can; + $self->txn_do( + sub { $self->$method($source, $to_insert, @$args) } + ); + }; $self->_insert_blobs($source, $blob_cols, $to_insert) if %$blob_cols; diff --git a/lib/DBIx/Class/Storage/DBI/Sybase/Base.pm b/lib/DBIx/Class/Storage/DBI/Sybase/Base.pm index be57610..af2a98f 100644 --- a/lib/DBIx/Class/Storage/DBI/Sybase/Base.pm +++ b/lib/DBIx/Class/Storage/DBI/Sybase/Base.pm @@ -27,6 +27,19 @@ sub _ping { return $@ ? 0 : 1; } +sub _placeholders_supported { + my $self = shift; + my $dbh = $self->_dbh; + + return eval { +# There's also $dbh->{syb_dynamic_supported} but it can be inaccurate for this +# purpose. + local $dbh->{PrintError} = 0; +# this specifically tests a bind that is NOT a string + $dbh->selectrow_array('select 1 where 1 = ?', {}, 1); + }; +} + 1; =head1 AUTHORS diff --git a/t/746sybase.t b/t/746sybase.t index 7c9e56b..6d77b4e 100644 --- a/t/746sybase.t +++ b/t/746sybase.t @@ -76,6 +76,9 @@ SQL # so we start unconnected $schema->storage->disconnect; +# inserts happen in a txn, so we test txn nesting + $schema->txn_begin; + # test primary key handling my $new = $schema->resultset('Artist')->create({ name => 'foo' }); ok($new->artistid > 0, "Auto-PK worked"); @@ -88,6 +91,8 @@ SQL $seen_id{$new->artistid}++; } + $schema->txn_commit; + # test simple count is ($schema->resultset('Artist')->count, 7, 'count(*) of whole table ok');