Merge 'trunk' into 'prefetch_pager'
Peter Rabbitson [Fri, 15 Jan 2010 02:16:31 +0000 (02:16 +0000)]
r8162@Thesaurus (orig r8150):  abraxxa | 2009-12-18 15:59:58 +0100
Schema POD inprovement for dclone

r8163@Thesaurus (orig r8151):  abraxxa | 2009-12-18 16:07:27 +0100
link to DBIx::Class::Row

r8164@Thesaurus (orig r8152):  abraxxa | 2009-12-18 16:08:56 +0100
fixed typo in Changes

r8165@Thesaurus (orig r8153):  abraxxa | 2009-12-18 16:14:47 +0100
dclone pod take #2

r8169@Thesaurus (orig r8157):  ribasushi | 2009-12-19 18:47:42 +0100
detabify
r8170@Thesaurus (orig r8158):  ribasushi | 2009-12-19 19:41:42 +0100
Fix RT52812
r8171@Thesaurus (orig r8159):  caelum | 2009-12-23 07:16:29 +0100
minor POD fixes
r8175@Thesaurus (orig r8163):  ribasushi | 2009-12-24 09:59:52 +0100
Fix deployment_statements context sensitivity regression
r8176@Thesaurus (orig r8164):  ribasushi | 2009-12-24 10:13:37 +0100
Don't call the PK setter if no PK
r8204@Thesaurus (orig r8192):  caelum | 2009-12-30 22:58:47 +0100
bump CAG dep
r8231@Thesaurus (orig r8219):  matthewt | 2010-01-02 01:41:12 +0100
fix typo in variable name
r8238@Thesaurus (orig r8226):  rafl | 2010-01-02 18:46:40 +0100
Merge branch 'native_traits'

* native_traits:
  Port replicated storage from MXAH to native traits.
  Create branch native_traits
r8244@Thesaurus (orig r8232):  caelum | 2010-01-04 00:30:51 +0100
fix _rebless into sybase/mssql/nobindvars
r8247@Thesaurus (orig r8235):  caelum | 2010-01-05 13:54:56 +0100
 r22328@hlagh (orig r8201):  caelum | 2009-12-31 12:29:51 -0500
 new branch to fix table aliases in queries over the 30char limit
 r22329@hlagh (orig r8202):  caelum | 2009-12-31 12:55:50 -0500
 failing test
 r22330@hlagh (orig r8203):  caelum | 2009-12-31 13:00:35 -0500
 switch oracle tests to done_testing()
 r22331@hlagh (orig r8204):  caelum | 2009-12-31 15:02:50 -0500
 got something working
 r22332@hlagh (orig r8205):  caelum | 2009-12-31 15:08:30 -0500
 POD touchups
 r22343@hlagh (orig r8216):  caelum | 2010-01-01 07:42:03 -0500
 fix uninitialized warning and a bug in ResultSet
 r22419@hlagh (orig r8234):  caelum | 2010-01-05 07:53:18 -0500
 append half of a base64 MD5 to shortened table aliases for Oracle

r8249@Thesaurus (orig r8237):  caelum | 2010-01-05 15:27:40 +0100
minor change: use more of the hash if possible for oracle table alias shortening
r8251@Thesaurus (orig r8239):  caelum | 2010-01-06 02:20:17 +0100
bump perl_version to 5.8.1
r8252@Thesaurus (orig r8240):  caelum | 2010-01-06 02:21:41 +0100
remove alignment mark on base64 md5
r8260@Thesaurus (orig r8248):  ribasushi | 2010-01-07 11:21:55 +0100
5.8.1 is minimum required perl
r8261@Thesaurus (orig r8249):  ribasushi | 2010-01-07 11:22:42 +0100
Minor optimization
r8262@Thesaurus (orig r8250):  ribasushi | 2010-01-07 11:23:35 +0100
Wrong title
r8265@Thesaurus (orig r8253):  ribasushi | 2010-01-08 17:48:50 +0100
Resolve problem reported by http://lists.scsys.co.uk/pipermail/dbix-class/2009-December/008699.html
r8266@Thesaurus (orig r8254):  ribasushi | 2010-01-08 17:52:01 +0100
Put utf8columns in line with the store_column fix
r8267@Thesaurus (orig r8255):  ribasushi | 2010-01-08 19:03:26 +0100
Tests while hunting for something else
r8268@Thesaurus (orig r8256):  ribasushi | 2010-01-08 19:14:42 +0100
Make test look even more like http://lists.scsys.co.uk/pipermail/dbix-class/2009-November/008599.html
r8277@Thesaurus (orig r8265):  ribasushi | 2010-01-09 02:16:14 +0100
 r8263@Thesaurus (orig r8251):  ribasushi | 2010-01-08 15:43:38 +0100
 New branch to find a leak
 r8264@Thesaurus (orig r8252):  ribasushi | 2010-01-08 15:52:46 +0100
 Weird test failures
 r8272@Thesaurus (orig r8260):  ribasushi | 2010-01-09 01:24:56 +0100
 Proper invocation
 r8273@Thesaurus (orig r8261):  ribasushi | 2010-01-09 01:35:34 +0100
 Test for the real leak reason
 r8274@Thesaurus (orig r8262):  ribasushi | 2010-01-09 01:37:33 +0100
 Void ctx as it should be
 r8275@Thesaurus (orig r8263):  ribasushi | 2010-01-09 02:10:13 +0100
 A "fix" for sqlt-related schema leaks
 r8276@Thesaurus (orig r8264):  ribasushi | 2010-01-09 02:15:53 +0100
 Changes

r8287@Thesaurus (orig r8275):  caelum | 2010-01-10 11:29:06 +0100
 r22483@hlagh (orig r8272):  caelum | 2010-01-09 05:52:15 -0500
 new branch to add "normalize_connect_info" class method to Storage::DBI
 r22495@hlagh (orig r8274):  caelum | 2010-01-10 05:27:42 -0500
 split connect_info parser out into private _normalize_connect_info

r8289@Thesaurus (orig r8277):  caelum | 2010-01-10 12:04:52 +0100
fix connection details in ::DBI::Replicated docs
r8291@Thesaurus (orig r8279):  ribasushi | 2010-01-11 09:50:21 +0100
 r8077@Thesaurus (orig r8065):  ribasushi | 2009-12-12 14:24:30 +0100
 Branch for yet another mssql ordered prefetch problem
 r8079@Thesaurus (orig r8067):  ribasushi | 2009-12-12 14:37:48 +0100
 prefetch does not get disassembled properly
 r8112@Thesaurus (orig r8100):  ribasushi | 2009-12-13 00:07:00 +0100
 Extra test to highlight search_related inefficiency
 r8113@Thesaurus (orig r8101):  ribasushi | 2009-12-13 00:17:44 +0100
 Real test for search_related and prefetch
 r8114@Thesaurus (orig r8102):  ribasushi | 2009-12-13 00:19:57 +0100
 Fix corner case regression on search_related on a prefetching rs
 r8115@Thesaurus (orig r8103):  ribasushi | 2009-12-13 00:21:05 +0100
 Isolate prefetch heads using RNO with a subquery
 r8116@Thesaurus (orig r8104):  ribasushi | 2009-12-13 00:23:46 +0100
 Changes
 r8125@Thesaurus (orig r8113):  ribasushi | 2009-12-15 13:06:26 +0100
 Extend mssql limited prefetch tests
 r8126@Thesaurus (orig r8114):  ribasushi | 2009-12-15 13:08:56 +0100
 Add extra test to prove Alan wrong :)
 r8132@Thesaurus (orig r8120):  ribasushi | 2009-12-16 00:38:04 +0100
 Do not realias tables in the RNO subqueries
 r8133@Thesaurus (orig r8121):  ribasushi | 2009-12-16 00:50:52 +0100
 Deliberately disturb alphabetical order
 r8134@Thesaurus (orig r8122):  ribasushi | 2009-12-16 10:26:43 +0100
 Got a failing test
 r8135@Thesaurus (orig r8123):  ribasushi | 2009-12-16 10:49:10 +0100
 Cleanup
 r8136@Thesaurus (orig r8124):  ribasushi | 2009-12-16 10:51:58 +0100
 More moving around
 r8137@Thesaurus (orig r8125):  ribasushi | 2009-12-16 11:25:37 +0100
 The real mssql problem - it's... bad
 r8138@Thesaurus (orig r8126):  ribasushi | 2009-12-16 11:29:20 +0100
 Clearer debug
 r8139@Thesaurus (orig r8127):  ribasushi | 2009-12-16 11:47:48 +0100
 This is horrific but the tests pass... maybe someone will figure out something better
 r8140@Thesaurus (orig r8128):  ribasushi | 2009-12-16 16:45:47 +0100
 cleanup tests
 r8187@Thesaurus (orig r8175):  ribasushi | 2009-12-24 16:22:30 +0100
 Ordered subqueries do not work in mssql after all
 r8271@Thesaurus (orig r8259):  ribasushi | 2010-01-08 23:58:13 +0100
 Cleaner RNO sql
 r8279@Thesaurus (orig r8267):  ribasushi | 2010-01-09 10:13:16 +0100
 Subqueries no longer experimental
 r8280@Thesaurus (orig r8268):  ribasushi | 2010-01-09 11:26:46 +0100
 Close the book on mssql ordered subqueries
 r8281@Thesaurus (orig r8269):  ribasushi | 2010-01-09 11:36:36 +0100
 Changes and typos
 r8283@Thesaurus (orig r8271):  ribasushi | 2010-01-09 11:42:21 +0100
 Highlight the real problem
 r8285@Thesaurus (orig r8273):  ribasushi | 2010-01-10 10:07:10 +0100
 Rename subquery to subselect and rewrite POD (per castaway)
 r8290@Thesaurus (orig r8278):  ribasushi | 2010-01-10 17:01:24 +0100
 rename as per mst

r8295@Thesaurus (orig r8283):  caelum | 2010-01-11 23:42:30 +0100
make a public ::Schema::unregister_source
r8298@Thesaurus (orig r8286):  abraxxa | 2010-01-12 18:04:18 +0100
fixed a typo in Changes
more detailed explanation for the warning about has_one/might_have rels on nullable columns

r8307@Thesaurus (orig r8295):  abraxxa | 2010-01-13 17:28:05 +0100
added the sources parser arg to the example code

r8327@Thesaurus (orig r8315):  ribasushi | 2010-01-15 01:25:39 +0100
 r8167@Thesaurus (orig r8155):  ribasushi | 2009-12-19 12:50:13 +0100
 New branch for null-only-result fix
 r8168@Thesaurus (orig r8156):  ribasushi | 2009-12-19 12:51:21 +0100
 Failing test
 r8322@Thesaurus (orig r8310):  ribasushi | 2010-01-15 00:48:09 +0100
 Correct test order
 r8323@Thesaurus (orig r8311):  ribasushi | 2010-01-15 01:15:33 +0100
 Generalize the to-node inner-join-er to apply to all related_resultset calls, not just counts
 r8324@Thesaurus (orig r8312):  ribasushi | 2010-01-15 01:16:05 +0100
 Adjust sql-emitter tests
 r8326@Thesaurus (orig r8314):  ribasushi | 2010-01-15 01:25:10 +0100
 One more sql-test fix and changes

r8328@Thesaurus (orig r8316):  ribasushi | 2010-01-15 01:31:58 +0100
Strict mysql bugfix
r8329@Thesaurus (orig r8317):  ribasushi | 2010-01-15 01:38:53 +0100
Better description of mysql strict option
r8331@Thesaurus (orig r8319):  ribasushi | 2010-01-15 03:12:13 +0100
Update troubleshooting doc

lib/DBIx/Class/Storage/DBIHacks.pm

index a54477e..d8abdc2 100644 (file)
@@ -63,93 +63,30 @@ sub _adjust_select_args_for_complex_prefetch {
     push @$inner_select, $sel;
   }
 
-  # normalize a copy of $from, so it will be easier to work with further
-  # down (i.e. promote the initial hashref to an AoH)
-  $from = [ @$from ];
-  $from->[0] = [ $from->[0] ];
-  my %original_join_info = map { $_->[0]{-alias} => $_->[0] } (@$from);
-
-
-  # decide which parts of the join will remain in either part of
-  # the outer/inner query
-
-  # First we compose a list of which aliases are used in restrictions
-  # (i.e. conditions/order/grouping/etc). Since we do not have
-  # introspectable SQLA, we fall back to ugly scanning of raw SQL for
-  # WHERE, and for pieces of ORDER BY in order to determine which aliases
-  # need to appear in the resulting sql.
-  # It may not be very efficient, but it's a reasonable stop-gap
-  # Also unqualified column names will not be considered, but more often
-  # than not this is actually ok
-  #
-  # In the same loop we enumerate part of the selection aliases, as
-  # it requires the same sqla hack for the time being
-  my ($restrict_aliases, $select_aliases, $prefetch_aliases);
-  {
-    # produce stuff unquoted, so it can be scanned
-    my $sql_maker = $self->sql_maker;
-    local $sql_maker->{quote_char};
-    my $sep = $self->_sql_maker_opts->{name_sep} || '.';
-    $sep = "\Q$sep\E";
-
-    my $non_prefetch_select_sql = $sql_maker->_recurse_fields ($inner_select);
-    my $prefetch_select_sql = $sql_maker->_recurse_fields ($outer_attrs->{_prefetch_select});
-    my $where_sql = $sql_maker->where ($where);
-    my $group_by_sql = $sql_maker->_order_by({
-      map { $_ => $inner_attrs->{$_} } qw/group_by having/
-    });
-    my @non_prefetch_order_by_chunks = (map
-      { ref $_ ? $_->[0] : $_ }
-      $sql_maker->_order_by_chunks ($inner_attrs->{order_by})
-    );
-
 
-    for my $alias (keys %original_join_info) {
-      my $seen_re = qr/\b $alias $sep/x;
-
-      for my $piece ($where_sql, $group_by_sql, @non_prefetch_order_by_chunks ) {
-        if ($piece =~ $seen_re) {
-          $restrict_aliases->{$alias} = 1;
-        }
-      }
+  # scan the from spec against different attributes, and see which joins are needed
+  # in what role
+  my $inner_aliastypes =
+    $self->_resolve_aliases_from_select_args( $from, $where, $inner_select, $inner_attrs );
+  my $outer_aliastypes =
+    $self->_resolve_aliases_from_select_args( $from, $where, $outer_select, $outer_attrs );
 
-      if ($non_prefetch_select_sql =~ $seen_re) {
-          $select_aliases->{$alias} = 1;
-      }
 
-      if ($prefetch_select_sql =~ $seen_re) {
-          $prefetch_aliases->{$alias} = 1;
-      }
 
-    }
-  }
+  # normalize a copy of $from, so it will be easier to work with further
+  # down (i.e. promote the initial hashref to an AoH)
+  $from = [ @$from ];
+  $from->[0] = [ $from->[0] ];
 
-  # Add any non-left joins to the restriction list (such joins are indeed restrictions)
-  for my $j (values %original_join_info) {
-    my $alias = $j->{-alias} or next;
-    $restrict_aliases->{$alias} = 1 if (
-      (not $j->{-join_type})
-        or
-      ($j->{-join_type} !~ /^left (?: \s+ outer)? $/xi)
-    );
-  }
-
-  # mark all join parents as mentioned
-  # (e.g.  join => { cds => 'tracks' } - tracks will need to bring cds too )
-  for my $collection ($restrict_aliases, $select_aliases) {
-    for my $alias (keys %$collection) {
-      $collection->{$_} = 1
-        for (@{ $original_join_info{$alias}{-join_path} || [] });
-    }
-  }
 
   # construct the inner $from for the subquery
-  my %inner_joins = (map { %{$_ || {}} } ($restrict_aliases, $select_aliases) );
+  my %inner_joins = (map { %$_ } (values %$inner_aliastypes) );
   my @inner_from;
   for my $j (@$from) {
     push @inner_from, $j if $inner_joins{$j->[0]{-alias}};
   }
 
+
   # if a multi-type join was needed in the subquery ("multi" is indicated by
   # presence in {collapse}) - add a group_by to simulate the collapse in the subq
   unless ($inner_attrs->{group_by}) {
@@ -213,10 +150,10 @@ sub _adjust_select_args_for_complex_prefetch {
   while (my $j = shift @$from) {
     my $alias = $j->[0]{-alias};
 
-    if ($select_aliases->{$alias} || $prefetch_aliases->{$alias}) {
+    if ($outer_aliastypes->{select}{$alias}) {
       push @outer_from, $j;
     }
-    elsif ($restrict_aliases->{$alias}) {
+    elsif ($outer_aliastypes->{restrict}{$alias}) {
       push @outer_from, $j;
 
       # FIXME - this should be obviated by SQLA2, as I'll be able to 
@@ -250,6 +187,83 @@ sub _adjust_select_args_for_complex_prefetch {
   return (\@outer_from, $outer_select, $where, $outer_attrs);
 }
 
+# Due to a lack of SQLA2 we fall back to crude scans of all the
+# select/where/order/group attributes, in order to determine what
+# aliases are neded to fulfill the query. This information is used
+# throughout the code to prune unnecessary JOINs from the queries
+# in an attempt to reduce the execution time.
+# Although the method is pretty horrific, the worst thing that can
+# happen is for it to fail due to an unqualified column, which in
+# turn will result in a vocal exception. Qualifying the column will
+# invariably solve the problem.
+sub _resolve_aliases_from_select_args {
+  my ( $self, $from, $where, $select, $attrs ) = @_;
+
+  $self->throw_exception ('Unable to analyze custom {from}')
+    if ref $from ne 'ARRAY';
+
+  # what we will return
+  my $aliases_by_type;
+
+  # see what aliases are there to work with
+  my $alias_list;
+  my @from = @$from; # if I don't copy weird shit happens
+  for my $j (@from) {
+    $j = $j->[0] if ref $j eq 'ARRAY';
+    $alias_list->{$j->{-alias}} = $j;
+  }
+
+  # set up a botched SQLA
+  my $sql_maker = $self->sql_maker;
+  my $sep = quotemeta ($self->_sql_maker_opts->{name_sep} || '.');
+  local $sql_maker->{quote_char}; # so that we can regex away
+
+
+  my $select_sql = $sql_maker->_recurse_fields ($select);
+  my $where_sql = $sql_maker->where ($where);
+  my $group_by_sql = $sql_maker->_order_by({
+    map { $_ => $attrs->{$_} } qw/group_by having/
+  });
+  my @order_by_chunks = (map
+    { ref $_ ? $_->[0] : $_ }
+    $sql_maker->_order_by_chunks ($attrs->{order_by})
+  );
+
+  # match every alias to the sql chunks above
+  for my $alias (keys %$alias_list) {
+    my $al_re = qr/\b $alias $sep/x;
+
+    for my $piece ($where_sql, $group_by_sql) {
+      $aliases_by_type->{restrict}{$alias} = 1 if ($piece =~ $al_re);
+    }
+
+    for my $piece ($select_sql, @order_by_chunks ) {
+      $aliases_by_type->{select}{$alias} = 1 if ($piece =~ $al_re);
+    }
+  }
+
+  # Add any non-left joins to the restriction list (such joins are indeed restrictions)
+  for my $j (values %$alias_list) {
+    my $alias = $j->{-alias} or next;
+    $aliases_by_type->{restrict}{$alias} = 1 if (
+      (not $j->{-join_type})
+        or
+      ($j->{-join_type} !~ /^left (?: \s+ outer)? $/xi)
+    );
+  }
+
+  # mark all join parents as mentioned
+  # (e.g.  join => { cds => 'tracks' } - tracks will need to bring cds too )
+  for my $type (keys %$aliases_by_type) {
+    for my $alias (keys %{$aliases_by_type->{$type}}) {
+      $aliases_by_type->{$type}{$_} = 1
+        for (@{ $alias_list->{$alias}{-join_path} || [] });
+    }
+  }
+
+  return $aliases_by_type;
+}
+
 sub _resolve_ident_sources {
   my ($self, $ident) = @_;