From: Arthur Axel 'fREW' Schmidt Date: Fri, 31 May 2013 14:25:13 +0000 (-0500) Subject: Support INSERT RETURNING for SQL Server X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=f1b1d954fa373d7aabd24de2712cfa141f030540;p=dbsrgits%2FDBIx-Class.git Support INSERT RETURNING for SQL Server --- diff --git a/lib/DBIx/Class/SQLMaker/MSSQL.pm b/lib/DBIx/Class/SQLMaker/MSSQL.pm index 39e2c4f..943bf4d 100644 --- a/lib/DBIx/Class/SQLMaker/MSSQL.pm +++ b/lib/DBIx/Class/SQLMaker/MSSQL.pm @@ -13,4 +13,74 @@ sub _rno_default_order { return \ '(SELECT(1))'; } -1; +# more or less copy pasted directly from ::SQLMaker +sub insert { + my $self = shift; + my $table = $self->_table(shift); + my $data = shift || return; + my $options = shift; + + if (! $data or (ref $data eq 'HASH' and !keys %{$data} ) ) { + my @bind; + my $sql = sprintf( + 'INSERT INTO %s DEFAULT VALUES', $_[0]->_quote($table) + ); + + if ( ($options||{})->{returning} ) { + my $s; + ($s, @bind) = $self->_insert_returning ($options); + $sql .= $s; + } + + return ($sql, @bind); + } + + my $method = $self->_METHOD_FOR_refkind("_insert", $data); + my ($sql, @bind) = $self->$method($data); + + $sql = join " ", $self->_sqlcase('insert into'), $table, $sql; + + if ($options->{returning}) { + my ($s, @b) = $self->_insert_returning ($options); + $sql =~ s/\bVALUES\b/$s VALUES/; + @bind = (@b, @bind); + } + + return wantarray ? ($sql, @bind) : $sql; +} + + +# insert returning docs at +# http://msdn.microsoft.com/en-us/library/ms177564.aspx + +sub _insert_returning { + my ($self, $options) = @_; + + my $f = $options->{returning}; + + my @f_list = do { + if (! ref $f) { + ($f) + } + elsif (ref $f eq 'ARRAY') { + @$f + } + elsif (ref $f eq 'SCALAR') { + ( + ($$f) + ) + } + else { + $self->throw_exception("Unsupported INSERT RETURNING option $f"); + } + }; + + return ( + join ' ', + $self->_sqlcase(' output'), + join ', ', + map $self->_quote("INSERTED.$_"), @f_list, + ); +} + +1 diff --git a/lib/DBIx/Class/Storage/DBI/MSSQL.pm b/lib/DBIx/Class/Storage/DBI/MSSQL.pm index 5cc2644..11b4af6 100644 --- a/lib/DBIx/Class/Storage/DBI/MSSQL.pm +++ b/lib/DBIx/Class/Storage/DBI/MSSQL.pm @@ -71,7 +71,11 @@ sub _prep_for_execute { # point we don't have many guarantees we will get what we expected. # http://msdn.microsoft.com/en-us/library/ms190315.aspx # http://davidhayden.com/blog/dave/archive/2006/01/17/2736.aspx - if ($self->_perform_autoinc_retrieval and not $self->_no_scope_identity_query) { + if ( + not $self->_use_insert_returning and + $self->_perform_autoinc_retrieval and + not $self->_no_scope_identity_query + ) { $sql .= "\nSELECT SCOPE_IDENTITY()"; } @@ -91,7 +95,9 @@ sub _execute { my $identity; # we didn't even try on ftds - unless ($self->_no_scope_identity_query) { + if (not $self->_use_insert_returning and + not $self->_no_scope_identity_query + ) { ($identity) = try { $sth->fetchrow_array }; $sth->finish; } @@ -194,6 +200,9 @@ sub _ping { }; } +# check for 2005 or greater here. +sub _use_insert_returning { $_[0]->_sql_server_2005_or_higher } + package # hide from PAUSE DBIx::Class::Storage::DBI::MSSQL::DateTime::Format; diff --git a/t/746mssql.t b/t/746mssql.t index 5e062f6..db86ffc 100644 --- a/t/746mssql.t +++ b/t/746mssql.t @@ -16,6 +16,12 @@ my ($dsn, $user, $pass) = @ENV{map { "DBICTEST_MSSQL_ODBC_${_}" } qw/DSN USER PA plan skip_all => 'Set $ENV{DBICTEST_MSSQL_ODBC_DSN}, _USER and _PASS to run this test' unless ($dsn && $user); +my $schema; +for my $use_insert_returning (0, 1) { + no warnings qw/redefine once/; + require DBIx::Class::Storage::DBI::MSSQL; + local *DBIx::Class::Storage::DBI::MSSQL::_use_insert_returning = + sub { $use_insert_returning }; { my $srv_ver = DBICTest::Schema->connect($dsn, $user, $pass)->storage->_server_info->{dbms_version}; @@ -23,7 +29,7 @@ plan skip_all => 'Set $ENV{DBICTEST_MSSQL_ODBC_DSN}, _USER and _PASS to run this } DBICTest::Schema->load_classes('ArtistGUID'); -my $schema = DBICTest::Schema->connect($dsn, $user, $pass); +$schema = DBICTest::Schema->connect($dsn, $user, $pass); { no warnings 'redefine'; @@ -500,6 +506,7 @@ SQL } } } +} done_testing;