revert code changes for DQ rebastiality
Matt S Trout [Sun, 22 Apr 2012 18:04:29 +0000 (18:04 +0000)]
lib/DBIx/Class/ResultSet.pm
lib/DBIx/Class/SQLMaker/LimitDialects.pm
lib/DBIx/Class/Storage/DBIHacks.pm

index 2f76830..88409b0 100644 (file)
@@ -3487,7 +3487,6 @@ sub _resolved_attrs {
     # default order for collapsing unless the user asked for something
     $attrs->{order_by} = [ map { "$alias.$_" } $source->primary_columns ];
     $attrs->{_ordered_for_collapse} = 1;
-    $attrs->{_order_is_artificial} = 1;
   }
 
   # if both page and offset are specified, produce a combined offset
index 7639988..d3ea35c 100644 (file)
@@ -383,6 +383,18 @@ sub _prep_for_skimming_limit {
       # Whatever order bindvals there are, they will be realiased and
       # reselected, and need to show up at end of the initial inner select
       push @{$self->{select_bind}}, @{$self->{order_bind}};
+
+      # if this is a part of something bigger, we need to add back all
+      # the extra order_by's, as they may be relied upon by the outside
+      # of a prefetch or something
+      if ($rs_attrs->{_is_internal_subuery}) {
+        $sq_attrs->{selection_outer} .= sprintf ", $extra_order_sel->{$_} AS $_"
+          for sort
+            { $extra_order_sel->{$a} cmp $extra_order_sel->{$b} }
+              grep { $_ !~ /[^\w\-]/ }  # ignore functions
+              keys %$extra_order_sel
+        ;
+      }
     }
 
     # and this is order re-alias magic
index a8eca16..3efd488 100644 (file)
@@ -72,44 +72,20 @@ sub _adjust_select_args_for_complex_prefetch {
   $self->throw_exception ('Complex prefetches are not supported on resultsets with a custom from attribute')
     if (ref $from ne 'ARRAY' || ref $from->[0] ne 'HASH' || ref $from->[1] ne 'ARRAY');
 
+
   # generate inner/outer attribute lists, remove stuff that doesn't apply
   my $outer_attrs = { %$attrs };
   delete $outer_attrs->{$_} for qw/where bind rows offset group_by having/;
 
-  my $inner_attrs = { %$attrs };
+  my $inner_attrs = { %$attrs, _is_internal_subuery => 1 };
   delete $inner_attrs->{$_} for qw/for collapse _prefetch_selector_range select as/;
 
-  # if the user did not request it, there is no point using it inside
-  delete $inner_attrs->{order_by} if delete $inner_attrs->{_order_is_artificial};
-
   # generate the inner/outer select lists
   # for inside we consider only stuff *not* brought in by the prefetch
   # on the outside we substitute any function for its alias
   my $outer_select = [ @$select ];
   my $inner_select = [];
 
-  my ($root_source, $root_source_offset);
-
-  for my $i (0 .. $#$from) {
-    my $node = $from->[$i];
-    my $h = (ref $node eq 'HASH')                                ? $node
-          : (ref $node  eq 'ARRAY' and ref $node->[0] eq 'HASH') ? $node->[0]
-          : next
-    ;
-
-    if ( ($h->{-alias}||'') eq $attrs->{alias} and $root_source = $h->{-rsrc} ) {
-      $root_source_offset = $i;
-      last;
-    }
-  }
-
-  $self->throw_exception ('Complex prefetches are not supported on resultsets with a custom from attribute')
-    unless $root_source;
-
-  # use the heavy duty resolver to take care of aliased/nonaliased naming
-  my $colinfo = $self->_resolve_column_info($from);
-  my $selected_root_columns;
-
   my ($p_start, $p_end) = @{$outer_attrs->{_prefetch_selector_range}};
   for my $i (0 .. $p_start - 1, $p_end + 1 .. $#$outer_select) {
     my $sel = $outer_select->[$i];
@@ -118,44 +94,12 @@ sub _adjust_select_args_for_complex_prefetch {
       $sel->{-as} ||= $attrs->{as}[$i];
       $outer_select->[$i] = join ('.', $attrs->{alias}, ($sel->{-as} || "inner_column_$i") );
     }
-    elsif (! ref $sel and my $ci = $colinfo->{$sel}) {
-      $selected_root_columns->{$ci->{-colname}} = 1;
-    }
 
     push @$inner_select, $sel;
 
     push @{$inner_attrs->{as}}, $attrs->{as}[$i];
   }
 
-  # We will need to fetch all native columns in the inner subquery, which may be a part
-  # of an *outer* join condition. We can not just fetch everything because a potential
-  # has_many restricting join collapse *will not work* on heavy data types.
-  # Time for more horrible SQL parsing, aughhhh
-
-  # MASSIVE FIXME - in fact when we are fully transitioned to DQ and the support is
-  # is sane - we will need to trim the select list to *only* fetch stuff that is
-  # necessary to build joins. In the current implementation if I am selecting a blob
-  # and the group_by kicks in - we are fucked, and all the user can do is not select
-  # that column. This is silly!
-
-  my $retardo_sqla_cache = {};
-  for my $cond ( map { $_->[1] } @{$from}[$root_source_offset + 1 .. $#$from] ) {
-    for my $col (@{$self->_extract_condition_columns($cond, $retardo_sqla_cache)}) {
-      my $ci = $colinfo->{$col};
-      if (
-        $ci
-          and
-        $ci->{-source_alias} eq $attrs->{alias}
-          and
-        ! $selected_root_columns->{$ci->{-colname}}++
-      ) {
-        # adding it to both to keep limits not supporting dark selectors happy
-        push @$inner_select, $ci->{-fq_colname};
-        push @{$inner_attrs->{as}}, $ci->{-fq_colname};
-      }
-    }
-  }
-
   # construct the inner $from and lock it in a subquery
   # we need to prune first, because this will determine if we need a group_by below
   # the fake group_by is so that the pruner throws away all non-selecting, non-restricting
@@ -218,35 +162,28 @@ sub _adjust_select_args_for_complex_prefetch {
   # - it is part of the restrictions, in which case we need to collapse the outer
   #   result by tackling yet another group_by to the outside of the query
 
-  # work on a shallow copy
   $from = [ @$from ];
 
+  # so first generate the outer_from, up to the substitution point
   my @outer_from;
+  while (my $j = shift @$from) {
+    $j = [ $j ] unless ref $j eq 'ARRAY'; # promote the head-from to an AoH
 
-  # we may not be the head
-  if ($root_source_offset) {
-    # first generate the outer_from, up to the substitution point
-    @outer_from = splice @$from, 0, $root_source_offset;
-
-    my $root_node = shift @$from;
-
-    push @outer_from, [
-      {
-        -alias => $attrs->{alias},
-        -rsrc => $root_node->[0]{-rsrc},
-        $attrs->{alias} => $inner_subq,
-      },
-      @{$root_node}[1 .. $#$root_node],
-    ];
-  }
-  else {
-    my $root_node = shift @$from;
+    if ($j->[0]{-alias} eq $attrs->{alias}) { # time to swap
 
-    @outer_from = {
-      -alias => $attrs->{alias},
-      -rsrc => $root_node->{-rsrc},
-      $attrs->{alias} => $inner_subq,
-    };
+      push @outer_from, [
+        {
+          -alias => $attrs->{alias},
+          -rsrc => $j->[0]{-rsrc},
+          $attrs->{alias} => $inner_subq,
+        },
+        @{$j}[1 .. $#$j],
+      ];
+      last; # we'll take care of what's left in $from below
+    }
+    else {
+      push @outer_from, $j;
+    }
   }
 
   # scan the *remaining* from spec against different attributes, and see which joins are needed
@@ -277,6 +214,9 @@ sub _adjust_select_args_for_complex_prefetch {
     }
   }
 
+  # demote the outer_from head
+  $outer_from[0] = $outer_from[0][0];
+
   if ($need_outer_group_by and ! $outer_attrs->{group_by}) {
 
     my $unprocessed_order_chunks;
@@ -649,11 +589,11 @@ sub _inner_join_to_node {
 # yet another atrocity: attempt to extract all columns from a
 # where condition by hooking _quote
 sub _extract_condition_columns {
-  my ($self, $cond, $sql_maker_cache) = @_;
+  my ($self, $cond, $sql_maker) = @_;
 
   return [] unless $cond;
 
-  my $sm = $sql_maker_cache->{condparser} ||= $self->{_sql_ident_capturer} ||= do {
+  $sql_maker ||= $self->{_sql_ident_capturer} ||= do {
     # FIXME - replace with a Moo trait
     my $orig_sm_class = ref $self->sql_maker;
     my $smic_class = "${orig_sm_class}::_IdentCapture_";
@@ -696,9 +636,9 @@ sub _extract_condition_columns {
     $smic_class->new();
   };
 
-  $sm->_recurse_where($cond);
+  $sql_maker->_recurse_where($cond);
 
-  return [ sort keys %{$sm->_get_captured_idents} ];
+  return [ sort keys %{$sql_maker->_get_captured_idents} ];
 }
 
 sub _extract_order_criteria {