Skip to content

Commit

Permalink
Support INSERT RETURNING for SQL Server
Browse files Browse the repository at this point in the history
  • Loading branch information
Arthur Axel 'fREW' Schmidt committed Jun 7, 2013
1 parent eca657d commit f941438
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 4 deletions.
72 changes: 71 additions & 1 deletion lib/DBIx/Class/SQLMaker/MSSQL.pm
Expand Up @@ -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
13 changes: 11 additions & 2 deletions lib/DBIx/Class/Storage/DBI/MSSQL.pm
Expand Up @@ -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()";
}

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;

Expand Down
9 changes: 8 additions & 1 deletion t/746mssql.t
Expand Up @@ -20,14 +20,20 @@ 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};
ok ($srv_ver, 'Got a test server version on fresh schema: ' . ($srv_ver||'???') );
}

DBICTest::Schema->load_classes('ArtistGUID');
my $schema = DBICTest::Schema->connect($dsn, $user, $pass);
$schema = DBICTest::Schema->connect($dsn, $user, $pass);

{
no warnings 'redefine';
Expand Down Expand Up @@ -664,6 +670,7 @@ SQL
}
}
}
}

done_testing;

Expand Down

0 comments on commit f941438

Please sign in to comment.