Throw away the error prone _strip_cond_qualifiers
Peter Rabbitson [Mon, 2 May 2011 11:36:18 +0000 (13:36 +0200)]
Review of 61f031bf made it clear that in order to make this work properly
pretty much the entire sqla logic will need to be replicated. So instead
the hacky approach was taken to abuse a botched version of SQLA which
is guaranteed to parse its own command tree correctly :)

lib/DBIx/Class/ResultSet.pm
lib/DBIx/Class/SQLMaker.pm
lib/DBIx/Class/Storage/DBIHacks.pm

index c4520f3..71fa590 100644 (file)
@@ -1654,12 +1654,8 @@ 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 = $needs_group_by_subq || (not defined $cond) || $self->_has_resolved_attr(qw/rows offset/);
+  my $needs_subq = $needs_group_by_subq || $self->_has_resolved_attr(qw/rows offset/);
 
   if ($needs_group_by_subq or $needs_subq) {
 
@@ -1704,10 +1700,23 @@ sub _rs_update_delete {
     return $self->result_source->storage->_subq_update_delete($subrs, $op, $values);
   }
   else {
+    # 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. What this code tries to do (badly) is to generate a condition
+    # with the qualifiers removed, by exploiting the quote mechanism of sqla
+    #
+    # this is atrocious and should be replaced by normal sqla introspection
+    # one sunny day
+    my ($sql, @bind) = do {
+      my $sqla = $rsrc->storage->sql_maker;
+      local $sqla->{_dequalify_idents} = 1;
+      $sqla->_recurse_where($self->{cond});
+    } if $self->{cond};
+
     return $rsrc->storage->$op(
       $rsrc,
       $op eq 'update' ? $values : (),
-      $cond,
+      $self->{cond} ? \[$sql, @bind] : (),
     );
   }
 }
index ba932a7..7686ff0 100644 (file)
@@ -93,6 +93,14 @@ BEGIN {
 # as the value to abuse with MSSQL ordered subqueries)
 sub __max_int () { 0x7FFFFFFF };
 
+# poor man's de-qualifier
+sub _quote {
+  $_[0]->next::method( ( $_[0]{_dequalify_idents} and ! ref $_[1] )
+    ? $_[1] =~ / ([^\.]+) $ /x
+    : $_[1]
+  );
+}
+
 sub new {
   my $self = shift->next::method(@_);
 
index 583045c..45131c7 100644 (file)
@@ -591,66 +591,6 @@ sub _inner_join_to_node {
   return \@new_from;
 }
 
-# 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. 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_from_array {
-  my ($self, $where) = @_;
-  my @cond;
-  for (my $i = 0; $i < @$where; $i++) {
-    my $entry = $where->[$i];
-    my $hash;
-    my $ref = ref $entry;
-    if ($ref eq 'HASH' or $ref eq 'ARRAY') {
-      $hash = $self->_strip_cond_qualifiers($entry);
-    }
-    elsif (! $ref) {
-      $entry =~ /([^.]+)$/;
-      $hash->{$1} = $where->[++$i];
-    }
-    push @cond, $hash;
-  }
-  return \@cond;
-}
-
-sub _strip_cond_qualifiers {
-  my ($self, $where) = @_;
-
-  my $cond = {};
-
-  # No-op. No condition, we're updating/deleting everything
-  return $cond unless $where;
-
-  if (ref $where eq 'ARRAY') {
-    $cond = $self->_strip_cond_qualifiers_from_array($where);
-  }
-  elsif (ref $where eq 'HASH') {
-    if ( (keys %$where) == 1 && ( (keys %{$where})[0] eq '-and' )) {
-      $cond->{-and} =
-        $self->_strip_cond_qualifiers_from_array($where->{-and});
-    }
-    else {
-      foreach my $key (keys %$where) {
-        if ($key eq '-or' && ref $where->{$key} eq 'ARRAY') {
-          $cond->{$key} = $self->_strip_cond_qualifiers($where->{$key});
-        }
-        else {
-          $key =~ /([^.]+)$/;
-          $cond->{$1} = $where->{$key};
-        }
-      }
-    }
-  }
-  else {
-    return undef;
-  }
-
-  return $cond;
-}
-
 sub _extract_order_criteria {
   my ($self, $order_by, $sql_maker) = @_;