[Dbix-class] Insert or Update (was ANNOUNCE: 0.08099_08)

Peter Corlett abuse at cabal.org.uk
Mon Apr 13 13:46:54 GMT 2009


On 13 Apr 2009, at 11:20, Peter Corlett wrote:
[...]
> So it looks like this still needs savepoints to do correctly. Of  
> course, one could always instead do a heroically complex bodge job  
> that looks really impressive but doesn't actually work.

And in the interests of STFUAWSC:

diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm
index 816b374..a8d501b 100644
--- a/lib/DBIx/Class/ResultSet.pm
+++ b/lib/DBIx/Class/ResultSet.pm
@@ -2103,13 +2103,43 @@ sub update_or_create {
    my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
    my $cond = ref $_[0] eq 'HASH' ? shift : {@_};

+  my $schema = $self->result_source->schema;
+
+  # Savepoints only work within a transaction, so we wrap ourselves  
into a
+  # transaction to make sure.
+  $schema->txn_begin;
+
+  # Start a savepoint. This fails if the underlying storage doesn't  
support
+  # savepoints, so we fall through to the previus implementation.
+  eval { $schema->svp_begin; };
+  unless($@) {
+    # now try an INSERT
+    my $row = eval { $self->create($cond); };
+    if($@) {
+      # If the INSERT failed, this suggests a failed constraint check  
due to
+      # duplicate keys. So we rollback the savepoint and do a
+      # SELECT-modify-UPDATE instead. We add the SELECT ... FOR UPDATE
+      # option to block any parallel queries on the same row.
+      $schema->svp_rollback;
+      $row = $self->find($cond, { %$attrs, for => 'update'} )
+	or die "Atomic update_or_create failed";
+      $row->update($cond);
+    }
+    $schema->svp_release;
+    $schema->txn_commit;
+    return $row;
+  }
+
    my $row = $self->find($cond, $attrs);
    if (defined $row) {
      $row->update($cond);
+    $schema->txn_commit;
      return $row;
    }

-  return $self->create($cond);
+  $row = $self->create($cond);
+  $schema->txn_commit;
+  return $row;
  }

  =head2 get_cache




More information about the DBIx-Class mailing list