Merge branch 'master' into dq2eb
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / ResultSet.pm
index 222e175..e24544c 100644 (file)
@@ -9,7 +9,8 @@ use Scalar::Util qw/blessed weaken reftype/;
 use DBIx::Class::_Util 'fail_on_internal_wantarray';
 use Try::Tiny;
 use Data::Compare (); # no imports!!! guard against insane architecture
-
+use Data::Query::Constants;
+use Data::Query::ExprHelpers;
 # not importing first() as it will clash with our own method
 use List::Util ();
 
@@ -1728,15 +1729,22 @@ sub _count_subq_rs {
         $sql_maker->{name_sep} = '';
       }
 
+      $sql_maker->clear_renderer;
+      $sql_maker->clear_converter;
+
       my ($lquote, $rquote, $sep) = map { quotemeta $_ } ($sql_maker->_quote_chars, $sql_maker->name_sep);
 
-      my $having_sql = $sql_maker->_parse_rs_attrs ({ having => $attrs->{having} });
+      my $having_sql = $sql_maker->_render_sqla(where => $attrs->{having});
+
+      $sql_maker->clear_renderer;
+      $sql_maker->clear_converter;
+
       my %seen_having;
 
       # search for both a proper quoted qualified string, for a naive unquoted scalarref
       # and if all fails for an utterly naive quoted scalar-with-function
       while ($having_sql =~ /
-        $rquote $sep $lquote (.+?) $rquote
+        (?: $rquote $sep)? $lquote (.+?) $rquote
           |
         [\s,] \w+ \. (\w+) [\s,]
           |
@@ -1926,12 +1934,18 @@ sub _rs_update_delete {
   if (! $needs_subq) {
     # 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. Tell SQLMaker to dequalify idents via a gross hack.
-    $cond = do {
-      my $sqla = $rsrc->storage->sql_maker;
-      local $sqla->{_dequalify_idents} = 1;
-      \[ $sqla->_recurse_where($self->{cond}) ];
-    };
+    # at all - so we convert the WHERE to a dq tree now, dequalify all
+    # identifiers found therein via a scan across the tree, and then use
+    # \{} style to pass the result onwards for use in the final query
+    if ($self->{cond}) {
+      $cond = do {
+        my $converter = $rsrc->storage->sql_maker->converter;
+        scan_dq_nodes({
+          DQ_IDENTIFIER ,=> sub { $_ = [ $_->[-1] ] for $_[0]->{elements} }
+        }, my $where_dq = $converter->_where_to_dq($self->{cond}));
+        \$where_dq;
+      };
+    }
   }
   else {
     # we got this far - means it is time to wrap a subquery
@@ -1953,14 +1967,19 @@ sub _rs_update_delete {
     my $subrs = (ref $self)->new($rsrc, $attrs);
 
     if (@$idcols == 1) {
-      $cond = { $idcols->[0] => { -in => $subrs->as_query } };
+      $cond = { $idcols->[0] => { -in => \$subrs->_as_select_dq } };
     }
     elsif ($storage->_use_multicolumn_in) {
       # no syntax for calling this properly yet
       # !!! EXPERIMENTAL API !!! WILL CHANGE !!!
-      $cond = $storage->sql_maker->_where_op_multicolumn_in (
-        $idcols, # how do I convey a list of idents...? can binds reside on lhs?
-        $subrs->as_query
+      my $left = $storage->sql_maker->_render_sqla(select_select => $idcols);
+      $left =~ s/^SELECT //i;
+      my $right = $storage->sql_maker
+                          ->converter
+                          ->_literal_to_dq(${$subrs->as_query});
+      $cond = \Operator(
+        { 'SQL.Naive' => 'in' },
+        [ Literal(SQL => "( $left )"), $right ],
       ),
     }
     else {
@@ -2667,6 +2686,19 @@ sub as_query {
   $aq;
 }
 
+sub _as_select_dq {
+  my $self = shift;
+  my $attrs = { %{ $self->_resolved_attrs } };
+  my $storage = $self->result_source->storage;
+  my (undef, $ident, @args) = $storage->_select_args(
+    $attrs->{from}, $attrs->{select}, $attrs->{where}, $attrs
+  );
+  $ident = $ident->from if blessed($ident);
+  $storage->sql_maker->converter->_select_to_dq(
+    $ident, @args
+  );
+}
+
 =head2 find_or_new
 
 =over 4