From: Peter Rabbitson Date: Thu, 12 Nov 2009 23:13:40 +0000 (+0000) Subject: The real fix for the non-introspectable condition bug, mst++ X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=40754d68307feec619c3e4df44fe0641a772f6f6;p=dbsrgits%2FDBIx-Class-Historic.git The real fix for the non-introspectable condition bug, mst++ --- diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index f8cb14f..1279ea5 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -1495,8 +1495,12 @@ sub _rs_update_delete { my $rsrc = $self->result_source; + # if a condition exists we need to strip all table qualifiers + # if this is not possible we'll force a subquery below + my $cond = $rsrc->schema->storage->_strip_cond_qualifiers ($self->{cond}); + my $needs_group_by_subq = $self->_has_resolved_attr (qw/collapse group_by -join/); - my $needs_subq = $self->_has_resolved_attr (qw/row offset/); + my $needs_subq = (not defined $cond) || $self->_has_resolved_attr(qw/row offset/); if ($needs_group_by_subq or $needs_subq) { @@ -1544,7 +1548,7 @@ sub _rs_update_delete { return $rsrc->storage->$op( $rsrc, $op eq 'update' ? $values : (), - $self->{cond}, + $cond, ); } } diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index 2df9d59..ebea220 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -1552,7 +1552,6 @@ sub update { my ($self, $source, $data, $where, @args) = @_; my $bind_attrs = $self->source_bind_attributes($source); - $where = $self->_strip_cond_qualifiers ($where); return $self->_execute('update' => [], $source, $bind_attrs, $data, $where, @args); } @@ -1562,35 +1561,69 @@ sub delete { my ($self, $source, $where, @args) = @_; my $bind_attrs = $self->source_bind_attributes($source); - $where = $self->_strip_cond_qualifiers ($where); return $self->_execute('delete' => [], $source, $bind_attrs, $where, @args); } # Most databases do not allow aliasing of tables in UPDATE/DELETE. Thus # a condition containing 'me' or other table prefixes will not work -# at all. Since we employ subqueries when multiple tables are involved -# (joins), it is relatively safe to strip all column qualifiers. Worst -# case scenario the error message will be a bit misleading, if the -# user supplies a foreign qualifier without a join (the message would -# be "can't find column X", when in fact the user shoud join T containing -# T.X) +# at all. What this code tries to do (badly) is introspect the condition +# and remove all column qualifiers. If it bails out early (returns undef) +# the calling code should try another approach (e.g. a subquery) sub _strip_cond_qualifiers { my ($self, $where) = @_; - my $sqlmaker = $self->sql_maker; - my ($sql, @bind) = $sqlmaker->_recurse_where($where); - return undef unless $sql; + my $cond = {}; - my ($qquot, $qsep) = map { quotemeta $_ } ( ($sqlmaker->quote_char||''), ($sqlmaker->name_sep||'.') ); - $sql =~ s/ (?: $qquot [\w\-]+ $qquot | [\w\-]+ ) $qsep //gx; + # No-op. No condition, we're updating/deleting everything + return $cond unless $where; - return \[$sql, @bind]; + if (ref $where eq 'ARRAY') { + $cond = [ + map { + my %hash; + foreach my $key (keys %{$_}) { + $key =~ /([^.]+)$/; + $hash{$1} = $_->{$key}; + } + \%hash; + } @$where + ]; + } + elsif (ref $where eq 'HASH') { + if ( (keys %$where) == 1 && ( (keys %{$where})[0] eq '-and' )) { + $cond->{-and} = []; + my @cond = @{$where->{-and}}; + for (my $i = 0; $i < @cond; $i++) { + my $entry = $cond[$i]; + my $hash; + if (ref $entry eq 'HASH') { + $hash = $self->_strip_cond_qualifiers($entry); + } + else { + $entry =~ /([^.]+)$/; + $hash->{$1} = $cond[++$i]; + } + push @{$cond->{-and}}, $hash; + } + } + else { + foreach my $key (keys %$where) { + $key =~ /([^.]+)$/; + $cond->{$1} = $where->{$key}; + } + } + } + else { + return undef; + } + + return $cond; } # We were sent here because the $rs contains a complex search # which will require a subquery to select the correct rows -# (i.e. joined or limited resultsets) +# (i.e. joined or limited resultsets, or non-introspectable conditions) # # Genarating a single PK column subquery is trivial and supported # by all RDBMS. However if we have a multicolumn PK, things get ugly.