From: Matt S Trout Date: Sun, 22 Apr 2012 18:04:29 +0000 (+0000) Subject: revert code changes for DQ rebastiality X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=b2b4cb3b6436d2b69ea2342d100f8b2be790298b;p=dbsrgits%2FDBIx-Class-Historic.git revert code changes for DQ rebastiality --- diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 2f76830..88409b0 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -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 diff --git a/lib/DBIx/Class/SQLMaker/LimitDialects.pm b/lib/DBIx/Class/SQLMaker/LimitDialects.pm index 7639988..d3ea35c 100644 --- a/lib/DBIx/Class/SQLMaker/LimitDialects.pm +++ b/lib/DBIx/Class/SQLMaker/LimitDialects.pm @@ -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 diff --git a/lib/DBIx/Class/Storage/DBIHacks.pm b/lib/DBIx/Class/Storage/DBIHacks.pm index a8eca16..3efd488 100644 --- a/lib/DBIx/Class/Storage/DBIHacks.pm +++ b/lib/DBIx/Class/Storage/DBIHacks.pm @@ -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 {