X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FRow.pm;h=310e10e65ea459a86ba0c881900a2c0088d5d8d7;hb=f50497ab497520c6f79154cdff283921c4d2cb9e;hp=7a2b90c3d3c43d9c01aa0bca9b4f7b35b638a1ef;hpb=68888c09820ea25810c03cdc7748ee374a7772b2;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Row.pm b/lib/DBIx/Class/Row.pm index 7a2b90c..310e10e 100644 --- a/lib/DBIx/Class/Row.pm +++ b/lib/DBIx/Class/Row.pm @@ -106,10 +106,10 @@ with NULL as the default, and save yourself a SELECT. sub __new_related_find_or_new_helper { my ($self, $relname, $data) = @_; + my $rsrc = $self->result_source; + # create a mock-object so all new/set_column component overrides will run: - my $rel_rs = $self->result_source - ->related_source($relname) - ->resultset; + my $rel_rs = $rsrc->related_source($relname)->resultset; my $new_rel_obj = $rel_rs->new_result($data); my $proc_data = { $new_rel_obj->get_columns }; @@ -117,7 +117,7 @@ sub __new_related_find_or_new_helper { MULTICREATE_DEBUG and warn "MC $self constructing $relname via new_result"; return $new_rel_obj; } - elsif ($self->result_source->_pk_depends_on($relname, $proc_data )) { + elsif ($rsrc->_pk_depends_on($relname, $proc_data )) { if (! keys %$proc_data) { # there is nothing to search for - blind create MULTICREATE_DEBUG and warn "MC $self constructing default-insert $relname"; @@ -132,7 +132,7 @@ sub __new_related_find_or_new_helper { return $new_rel_obj; } else { - my $us = $self->source_name; + my $us = $rsrc->source_name; $self->throw_exception ("'$us' neither depends nor is depended on by '$relname', something is wrong..."); } } @@ -314,7 +314,7 @@ sub insert { MULTICREATE_DEBUG and warn "MC $self pre-reconstructing $relname $rel_obj\n"; - my $them = { %{$rel_obj->{_relationship_data} || {} }, $rel_obj->get_inflated_columns }; + my $them = { %{$rel_obj->{_relationship_data} || {} }, $rel_obj->get_columns }; my $existing; # if there are no keys - nothing to search for @@ -342,34 +342,50 @@ sub insert { $rollback_guard ||= $source->storage->txn_scope_guard } + ## PK::Auto + my %auto_pri; + my $auto_idx = 0; + for ($self->primary_columns) { + if ( + not defined $self->get_column($_) + || + (ref($self->get_column($_)) eq 'SCALAR') + ) { + my $col_info = $source->column_info($_); + $auto_pri{$_} = $auto_idx++ unless $col_info->{auto_nextval}; # auto_nextval's are pre-fetched in the storage + } + } + MULTICREATE_DEBUG and do { no warnings 'uninitialized'; warn "MC $self inserting (".join(', ', $self->get_columns).")\n"; }; - my $updated_cols = $source->storage->insert($source, { $self->get_columns }); + my $updated_cols = $source->storage->insert( + $source, + { $self->get_columns }, + (keys %auto_pri) && $source->storage->_supports_insert_returning + ? { returning => [ sort { $auto_pri{$a} <=> $auto_pri{$b} } keys %auto_pri ] } + : () + , + ); + foreach my $col (keys %$updated_cols) { $self->store_column($col, $updated_cols->{$col}); + delete $auto_pri{$col}; } - ## PK::Auto - my @auto_pri = grep { - (not defined $self->get_column($_)) - || - (ref($self->get_column($_)) eq 'SCALAR') - } $self->primary_columns; - - if (@auto_pri) { - MULTICREATE_DEBUG and warn "MC $self fetching missing PKs ".join(', ', @auto_pri)."\n"; + if (keys %auto_pri) { + my @missing = sort { $auto_pri{$a} <=> $auto_pri{$b} } keys %auto_pri; + MULTICREATE_DEBUG and warn "MC $self fetching missing PKs ".join(', ', @missing )."\n"; my $storage = $self->result_source->storage; $self->throw_exception( "Missing primary key but Storage doesn't support last_insert_id" ) unless $storage->can('last_insert_id'); - my @ids = $storage->last_insert_id($self->result_source,@auto_pri); + my @ids = $storage->last_insert_id($self->result_source, @missing); $self->throw_exception( "Can't get last insert id" ) - unless (@ids == @auto_pri); - $self->store_column($auto_pri[$_] => $ids[$_]) for 0 .. $#ids; + unless (@ids == @missing); + $self->store_column($missing[$_] => $ids[$_]) for 0 .. $#missing; } - $self->{_dirty_columns} = {}; $self->{related_resultsets} = {}; @@ -468,7 +484,7 @@ the database row can not be constructed (see L for more details). -Also takes an optional hashref of C<< column_name => value> >> pairs +Also takes an optional hashref of C<< column_name => value >> pairs to update on the object first. Be aware that the hashref will be passed to C, which might edit it in place, so don't rely on it being the same after a call to C. If you @@ -502,16 +518,18 @@ this method. sub update { my ($self, $upd) = @_; - $self->throw_exception( "Not in database" ) unless $self->in_storage; my $ident_cond = $self->{_orig_ident} || $self->ident_condition; - $self->throw_exception('Unable to update a row with incomplete or no identity') - if ! keys %$ident_cond; - $self->set_inflated_columns($upd) if $upd; my %to_update = $self->get_dirty_columns; return $self unless keys %to_update; + + $self->throw_exception( "Not in database" ) unless $self->in_storage; + + $self->throw_exception('Unable to update a row with incomplete or no identity') + if ! keys %$ident_cond; + my $rows = $self->result_source->storage->update( $self->result_source, \%to_update, $ident_cond ); @@ -849,29 +867,15 @@ sub set_column { my $old_value = $self->get_column($column); $new_value = $self->store_column($column, $new_value); - my $dirty; - if (!$self->in_storage) { # no point tracking dirtyness on uninserted data - $dirty = 1; - } - elsif (defined $old_value xor defined $new_value) { - $dirty = 1; - } - elsif (not defined $old_value) { # both undef - $dirty = 0; - } - elsif ($old_value eq $new_value) { - $dirty = 0; - } - else { # do a numeric comparison if datatype allows it - if ($self->_is_column_numeric($column)) { - $dirty = $old_value != $new_value; - } - else { - $dirty = 1; - } - } + my $dirty = + $self->{_dirty_columns}{$column} + || + $self->in_storage # no point tracking dirtyness on uninserted data + ? ! $self->_eq_column_values ($column, $old_value, $new_value) + : 1 + ; - # sadly the update code just checks for keys, not for their value + # FIXME sadly the update code just checks for keys, not for their value $self->{_dirty_columns}{$column} = 1 if $dirty; # XXX clear out the relation cache for this column @@ -880,6 +884,26 @@ sub set_column { return $new_value; } +sub _eq_column_values { + my ($self, $col, $old, $new) = @_; + + if (defined $old xor defined $new) { + return 0; + } + elsif (not defined $old) { # both undef + return 1; + } + elsif ($old eq $new) { + return 1; + } + elsif ($self->_is_column_numeric($col)) { # do a numeric comparison if datatype allows it + return $old == $new; + } + else { + return 0; + } +} + =head2 set_columns $row->set_columns({ $col => $val, ... }); @@ -1359,7 +1383,6 @@ second argument to $resultset->search($cond, $attrs); sub discard_changes { my ($self, $attrs) = @_; - delete $self->{_dirty_columns}; return unless $self->in_storage; # Don't reload if we aren't real! # add a replication default to read from the master only