Consolidate last_insert_id handling with a fallback-attempt on DBI::last_insert_id
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI.pm
index a4e3964..32c6ed1 100644 (file)
@@ -531,7 +531,7 @@ sub _normalize_connect_info {
     @args = @args[0,1,2];
   }
 
-  $info{arguments} = \@args; 
+  $info{arguments} = \@args;
 
   my @storage_opts = grep exists $attrs{$_},
     @storage_options, 'cursor_class';
@@ -1468,9 +1468,13 @@ sub insert_bulk {
     );
   }
 
+  # neither _execute_array, nor _execute_inserts_with_no_binds are
+  # atomic (even if _execute _array is a single call). Thus a safety
+  # scope guard
+  my $guard = $self->txn_scope_guard unless $self->{transaction_depth} != 0;
+
   $self->_query_start( $sql, ['__BULK__'] );
   my $sth = $self->sth($sql);
-
   my $rv = do {
     if ($empty_bind) {
       # bind_param_array doesn't work if there are no binds
@@ -1484,14 +1488,15 @@ sub insert_bulk {
 
   $self->_query_end( $sql, ['__BULK__'] );
 
+
+  $guard->commit if $guard;
+
   return (wantarray ? ($rv, $sth, @bind) : $rv);
 }
 
 sub _execute_array {
   my ($self, $source, $sth, $bind, $cols, $data, @extra) = @_;
 
-  my $guard = $self->txn_scope_guard unless $self->{transaction_depth} != 0;
-
   ## This must be an arrayref, else nothing works!
   my $tuple_status = [];
 
@@ -1540,9 +1545,6 @@ sub _execute_array {
       }),
     );
   }
-
-  $guard->commit if $guard;
-
   return $rv;
 }
 
@@ -1555,8 +1557,6 @@ sub _dbh_execute_array {
 sub _dbh_execute_inserts_with_no_binds {
   my ($self, $sth, $count) = @_;
 
-  my $guard = $self->txn_scope_guard unless $self->{transaction_depth} != 0;
-
   eval {
     my $dbh = $self->_get_dbh;
     local $dbh->{RaiseError} = 1;
@@ -1572,13 +1572,11 @@ sub _dbh_execute_inserts_with_no_binds {
 
   $self->throw_exception($exception) if $exception;
 
-  $guard->commit if $guard;
-
   return $count;
 }
 
 sub update {
-  my ($self, $source, @args) = @_; 
+  my ($self, $source, @args) = @_;
 
   my $bind_attrs = $self->source_bind_attributes($source);
 
@@ -1677,11 +1675,12 @@ sub _per_row_update_delete {
   my $row_cnt = '0E0';
 
   my $subrs_cur = $rs->cursor;
-  while (my @pks = $subrs_cur->next) {
+  my @all_pk = $subrs_cur->all;
+  for my $pks ( @all_pk) {
 
     my $cond;
     for my $i (0.. $#pcols) {
-      $cond->{$pcols[$i]} = $pks[$i];
+      $cond->{$pcols[$i]} = $pks->[$i];
     }
 
     $self->$op (
@@ -1745,7 +1744,7 @@ sub _select_args {
     select => $select,
     from => $ident,
     where => $where,
-    $rs_alias
+    $rs_alias && $alias2source->{$rs_alias}
       ? ( _source_handle => $alias2source->{$rs_alias}->handle )
       : ()
     ,
@@ -1834,7 +1833,7 @@ sub _select_args {
       &&
     (ref $ident eq 'ARRAY' && @$ident > 1)  # indicates a join
       &&
-    scalar $sql_maker->_order_by_chunks ($attrs->{order_by})
+    scalar $self->_parse_order_by ($attrs->{order_by})
   ) {
     # the RNO limit dialect above mangles the SQL such that the join gets lost
     # wrap a subquery here
@@ -1863,6 +1862,9 @@ sub _select_args {
     push @limit, $attrs->{rows}, $attrs->{offset};
   }
 
+  # try to simplify the joinmap further (prune unreferenced type-single joins)
+  $ident = $self->_prune_unused_joins ($ident, $select, $where, $attrs);
+
 ###
   # This would be the point to deflate anything found in $where
   # (and leave $attrs->{bind} intact). Problem is - inflators historically
@@ -2051,18 +2053,14 @@ Return the row id of the last insert.
 =cut
 
 sub _dbh_last_insert_id {
-    # All Storage's need to register their own _dbh_last_insert_id
-    # the old SQLite-based method was highly inappropriate
+    my ($self, $dbh, $source, $col) = @_;
 
-    my $self = shift;
-    my $class = ref $self;
-    $self->throw_exception (<<EOE);
+    my $id = eval { $dbh->last_insert_id (undef, undef, $source->name, $col) };
+
+    return $id if defined $id;
 
-No _dbh_last_insert_id() method found in $class.
-Since the method of obtaining the autoincrement id of the last insert
-operation varies greatly between different databases, this method must be
-individually implemented for every storage class.
-EOE
+    my $class = ref $self;
+    $self->throw_exception ("No storage specific _dbh_last_insert_id() method implemented in $class, and the generic DBI::last_insert_id() failed");
 }
 
 sub last_insert_id {
@@ -2584,7 +2582,10 @@ sub DESTROY {
   # some databases need this to stop spewing warnings
   if (my $dbh = $self->_dbh) {
     local $@;
-    eval { $dbh->disconnect };
+    eval {
+      %{ $dbh->{CachedKids} } = ();
+      $dbh->disconnect;
+    };
   }
 
   $self->_dbh(undef);