Really fix INSERT RETURNING - simply make it a flag on the storage and keep the machi...
Peter Rabbitson [Wed, 24 Mar 2010 13:10:33 +0000 (13:10 +0000)]
lib/DBIx/Class/Row.pm
lib/DBIx/Class/Storage/DBI.pm
lib/DBIx/Class/Storage/DBI/InsertReturning.pm [deleted file]
lib/DBIx/Class/Storage/DBI/Pg.pm
t/72pg.t

index 7716985..ceb38d5 100644 (file)
@@ -363,7 +363,7 @@ sub insert {
   my $updated_cols = $source->storage->insert(
     $source,
     { $self->get_columns },
-    keys %auto_pri
+    (keys %auto_pri) && $source->storage->can_insert_returning
       ? { returning => [ sort { $auto_pri{$a} cmp $auto_pri{$b} } keys %auto_pri ] }
       : ()
     ,
index 74d39bc..00c8eb8 100644 (file)
@@ -33,7 +33,10 @@ __PACKAGE__->mk_group_accessors('simple' => @storage_options);
 # default cursor class, overridable in connect_info attributes
 __PACKAGE__->cursor_class('DBIx::Class::Storage::DBI::Cursor');
 
-__PACKAGE__->mk_group_accessors('inherited' => qw/sql_maker_class/);
+__PACKAGE__->mk_group_accessors('inherited' => qw/
+  sql_maker_class
+  can_insert_returning
+/);
 __PACKAGE__->sql_maker_class('DBIx::Class::SQLAHacks');
 
 
@@ -1387,13 +1390,32 @@ sub _prefetch_insert_auto_nextvals {
 
 sub insert {
   my $self = shift;
-  my ($source, $to_insert) = @_;
+  my ($source, $to_insert, $opts) = @_;
 
   my $updated_cols = $self->_prefetch_insert_auto_nextvals (@_);
 
   my $bind_attributes = $self->source_bind_attributes($source);
 
-  $self->_execute('insert' => [], $source, $bind_attributes, $to_insert);
+  my ($rv, $sth) = $self->_execute('insert' => [], $source, $bind_attributes, $to_insert, $opts);
+
+  if ($opts->{returning}) {
+    my @ret_cols = @{$opts->{returning}};
+
+    my @ret_vals = eval {
+      local $SIG{__WARN__} = sub {};
+      my @r = $sth->fetchrow_array;
+      $sth->finish;
+      @r;
+    };
+
+    my %ret;
+    @ret{@ret_cols} = @ret_vals if (@ret_vals);
+
+    $updated_cols = {
+      %$updated_cols,
+      %ret,
+    };
+  }
 
   return $updated_cols;
 }
diff --git a/lib/DBIx/Class/Storage/DBI/InsertReturning.pm b/lib/DBIx/Class/Storage/DBI/InsertReturning.pm
deleted file mode 100644 (file)
index f110cb5..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-package DBIx::Class::Storage::DBI::InsertReturning;
-
-use strict;
-use warnings;
-
-use base qw/DBIx::Class::Storage::DBI/;
-use mro 'c3';
-
-=head1 NAME
-
-DBIx::Class::Storage::DBI::InsertReturning - Storage component for RDBMSes
-supporting INSERT ... RETURNING
-
-=head1 DESCRIPTION
-
-Provides Auto-PK and
-L<is_auto_increment|DBIx::Class::ResultSource/is_auto_increment> support for
-databases supporting the C<INSERT ... RETURNING> syntax.
-
-=cut
-
-sub insert {
-  my $self = shift;
-  my ($source, $to_insert, $opts) = @_;
-
-  return $self->next::method (@_) unless ($opts && $opts->{returning});
-
-  my $updated_cols = $self->_prefetch_insert_auto_nextvals ($source, $to_insert);
-
-  my $bind_attributes = $self->source_bind_attributes($source);
-  my ($rv, $sth) = $self->_execute (insert => [], $source, $bind_attributes, $to_insert, $opts);
-
-  if (my @ret_cols = @{$opts->{returning}}) {
-
-    my @ret_vals = eval {
-      local $SIG{__WARN__} = sub {};
-      my @r = $sth->fetchrow_array;
-      $sth->finish;
-      @r;
-    };
-
-    my %ret;
-    @ret{@ret_cols} = @ret_vals if (@ret_vals);
-
-    $updated_cols = {
-      %$updated_cols,
-      %ret,
-    };
-  }
-
-  return $updated_cols;
-}
-
-=head1 AUTHOR
-
-See L<DBIx::Class/AUTHOR> and L<DBIx::Class/CONTRIBUTORS>
-
-=head1 LICENSE
-
-You may distribute this code under the same terms as Perl itself.
-
-=cut
-
-1;
index 46eee6f..1b5e6d8 100644 (file)
@@ -5,7 +5,6 @@ use warnings;
 
 use base qw/
     DBIx::Class::Storage::DBI::MultiColumnIn
-    DBIx::Class::Storage::DBI::InsertReturning
 /;
 use mro 'c3';
 
@@ -17,13 +16,19 @@ use Context::Preserve ();
 warn __PACKAGE__.": DBD::Pg 2.9.2 or greater is strongly recommended\n"
   if ($DBD::Pg::VERSION < 2.009002);  # pg uses (used?) version::qv()
 
+sub can_insert_returning {
+  # FIXME !!!
+  # pg before 8.2 doesn't support this, need to check version
+  return 1;
+}
+
 sub with_deferred_fk_checks {
   my ($self, $sub) = @_;
 
   my $txn_scope_guard = $self->txn_scope_guard;
 
   $self->_do_query('SET CONSTRAINTS ALL DEFERRED');
-  
+
   my $sg = Scope::Guard->new(sub {
     $self->_do_query('SET CONSTRAINTS ALL IMMEDIATE');
   });
@@ -32,18 +37,37 @@ sub with_deferred_fk_checks {
     after => sub { $txn_scope_guard->commit });
 }
 
+sub last_insert_id {
+  my ($self,$source,@cols) = @_;
+
+  my @values;
+
+  for my $col (@cols) {
+    my $seq = ( $source->column_info($col)->{sequence} ||= $self->dbh_do('_dbh_get_autoinc_seq', $source, $col) )
+      or $self->throw_exception( sprintf(
+        'could not determine sequence for column %s.%s, please consider adding a schema-qualified sequence to its column info',
+          $source->name,
+          $col,
+      ));
+
+    push @values, $self->_dbh->last_insert_id(undef, undef, undef, undef, {sequence => $seq});
+  }
+
+  return @values;
+}
+
 sub _sequence_fetch {
   my ($self, $function, $sequence) = @_;
 
   $self->throw_exception('No sequence to fetch') unless $sequence;
-  
+
   my ($val) = $self->_get_dbh->selectrow_array(
     sprintf "select $function('%s')",
       $sequence
   );
 
   return $val;
-} 
+}
 
 sub _dbh_get_autoinc_seq {
   my ($self, $dbh, $source, $col) = @_;
index 9251caa..ee6db29 100644 (file)
--- a/t/72pg.t
+++ b/t/72pg.t
@@ -265,11 +265,13 @@ my $st = $schema->resultset('SequenceTest')->create({ name => 'foo', pkid1 => 55
 is($st->pkid1, 55, "Auto-PK for sequence without default: First primary key set manually");
 
 
-######## test non-integer non-serial auto-pk
+######## test non-serial auto-pk
 
-$schema->source('TimestampPrimaryKey')->name('dbic_t_schema.timestamp_primary_key_test');
-my $row = $schema->resultset('TimestampPrimaryKey')->create({});
-ok $row->id;
+if ($schema->storage->can_insert_returning) {
+  $schema->source('TimestampPrimaryKey')->name('dbic_t_schema.timestamp_primary_key_test');
+  my $row = $schema->resultset('TimestampPrimaryKey')->create({});
+  ok $row->id;
+}
 
 ######## test with_deferred_fk_checks