Merge 'trunk' into 'sybase'
Rafael Kitover [Wed, 10 Jun 2009 11:12:08 +0000 (11:12 +0000)]
r5385@hlagh (orig r6528):  ribasushi | 2009-06-06 01:45:10 -0700
rename MC test dir
r5386@hlagh (orig r6529):  ribasushi | 2009-06-06 01:47:47 -0700
TODOified reentrancy counter - this shall be used to optimize MC some day
r5387@hlagh (orig r6530):  ribasushi | 2009-06-06 01:50:56 -0700
Port another forgotten MC fix
r5393@hlagh (orig r6537):  ribasushi | 2009-06-07 14:07:55 -0700
Fix for mysql subquery problem
r5394@hlagh (orig r6538):  ribasushi | 2009-06-07 14:36:43 -0700
Make empty/default inserts use standard SQL
r5395@hlagh (orig r6539):  ribasushi | 2009-06-07 15:59:21 -0700
Add mysql empty insert SQL override
Make SQLAHacks parts loadable at runtime via ensure_class_loaded
r5396@hlagh (orig r6540):  ribasushi | 2009-06-07 16:03:04 -0700
Make podcoverage happy
r5397@hlagh (orig r6541):  ribasushi | 2009-06-07 16:24:06 -0700
Fix find_or_new/create to stop returning random rows when default value insert is requested
r5398@hlagh (orig r6542):  ribasushi | 2009-06-08 02:36:56 -0700
Simply order_by/_virtual_order_by handling
r5406@hlagh (orig r6552):  ribasushi | 2009-06-08 14:56:41 -0700
duh
r5410@hlagh (orig r6556):  ash | 2009-06-09 03:20:34 -0700
Addjust bug to show problem with rows => 1 + child rel

r5411@hlagh (orig r6557):  ribasushi | 2009-06-09 04:12:46 -0700
Require a recent bugfixed Devel::Cycle
r5413@hlagh (orig r6559):  ash | 2009-06-09 06:07:30 -0700
Make IC::DT extra warning state the column name too

r5420@hlagh (orig r6574):  ribasushi | 2009-06-09 15:19:48 -0700
AuthorCheck fixes
r5424@hlagh (orig r6578):  ribasushi | 2009-06-09 15:52:17 -0700
 r6522@Thesaurus (orig r6521):  ribasushi | 2009-06-05 19:27:55 +0200
 New branch to try resultsource related stuff
 r6545@Thesaurus (orig r6544):  ribasushi | 2009-06-08 13:00:54 +0200
 First stab at adding resultsources to each join in select - works won-der-ful-ly
 r6546@Thesaurus (orig r6545):  ribasushi | 2009-06-08 13:14:08 +0200
 Commit failing test and thoughts on search arg deflation
 r6576@Thesaurus (orig r6575):  ribasushi | 2009-06-10 00:31:55 +0200
 Todoify DT in search deflation test until after 0.09
 r6577@Thesaurus (orig r6576):  ribasushi | 2009-06-10 00:48:07 +0200
 Factor out the $ident resolver

r5426@hlagh (orig r6580):  ribasushi | 2009-06-09 16:21:50 -0700
Move as_query out of the cursor
r5427@hlagh (orig r6581):  ribasushi | 2009-06-09 16:27:19 -0700
Think before commit
r5428@hlagh (orig r6582):  ribasushi | 2009-06-10 00:37:19 -0700
Clarify and disable rows/prefetch test - fix is easy, but architecturally unsound - need more time

1  2 
Makefile.PL
lib/DBIx/Class/Storage/DBI.pm

diff --combined Makefile.PL
@@@ -71,6 -71,7 +71,7 @@@ my %force_requires_if_author = 
  
    # t/52cycle.t
    'Test::Memory::Cycle'       => 0,
+   'Devel::Cycle'              => 1.10,
  
    # t/60core.t
    'DateTime::Format::MySQL'   => 0,
@@@ -92,7 -93,6 +93,7 @@@
    'Hash::Merge',                  => 0.11,
  
    # t/96_is_deteministic_value.t
 +  # t/746sybase.t
    'DateTime::Format::Strptime' => 0,
  );
  
@@@ -7,10 -7,9 +7,9 @@@ use strict
  use warnings;
  use Carp::Clan qw/^DBIx::Class/;
  use DBI;
- use DBIx::Class::SQLAHacks;
  use DBIx::Class::Storage::DBI::Cursor;
  use DBIx::Class::Storage::Statistics;
- use Scalar::Util qw/blessed weaken/;
+ use Scalar::Util();
  use List::Util();
  
  __PACKAGE__->mk_group_accessors('simple' =>
@@@ -603,6 -602,7 +602,7 @@@ sub sql_maker 
    my ($self) = @_;
    unless ($self->_sql_maker) {
      my $sql_maker_class = $self->sql_maker_class;
+     $self->ensure_class_loaded ($sql_maker_class);
      $self->_sql_maker($sql_maker_class->new( $self->_sql_maker_args ));
    }
    return $self->_sql_maker;
@@@ -717,7 -717,7 +717,7 @@@ sub _connect 
  
      if($dbh && !$self->unsafe) {
        my $weak_self = $self;
-       weaken($weak_self);
+       Scalar::Util::weaken($weak_self);
        $dbh->{HandleError} = sub {
            if ($weak_self) {
              $weak_self->throw_exception("DBI Exception: $_[0]");
@@@ -898,7 -898,7 +898,7 @@@ sub txn_rollback 
  sub _prep_for_execute {
    my ($self, $op, $extra_bind, $ident, $args) = @_;
  
-   if( blessed($ident) && $ident->isa("DBIx::Class::ResultSource") ) {
+   if( Scalar::Util::blessed($ident) && $ident->isa("DBIx::Class::ResultSource") ) {
      $ident = $ident->from();
    }
  
    return ($sql, \@bind);
  }
  
+ =head2 as_query
+ =over 4
+ =item Arguments: $rs_attrs
+ =item Return Value: \[ $sql, @bind ]
+ =back
+ Returns the SQL statement and bind vars that would result from the given
+ ResultSet attributes (does not actually run a query)
+ =cut
+ sub as_query {
+   my ($self, $rs_attr) = @_;
+   my $sql_maker = $self->sql_maker;
+   local $sql_maker->{for};
+   # my ($op, $bind, $ident, $bind_attrs, $select, $cond, $order, $rows, $offset) = $self->_select_args(...);
+   my @args = $self->_select_args($rs_attr->{from}, $rs_attr->{select}, $rs_attr->{where}, $rs_attr);
+   # my ($sql, $bind) = $self->_prep_for_execute($op, $bind, $ident, [ $select, $cond, $order, $rows, $offset ]);
+   my ($sql, $bind) = $self->_prep_for_execute(
+     @args[0 .. 2],
+     [ @args[4 .. $#args] ],
+   );
+   return \[ "($sql)", @{ $bind || [] }];
+ }
  sub _fix_bind_params {
      my ($self, @bind) = @_;
  
          } @bind;
  }
  
 +sub _flatten_bind_params {
 +    my ($self, @bind) = @_;
 +
 +    ### Turn @bind from something like this:
 +    ###   ( [ "artist", 1 ], [ "cdid", 1, 3 ] )
 +    ### to this:
 +    ###   ( 1, 1, 3 )
 +    return
 +        map {
 +            if ( defined( $_ && $_->[1] ) ) {
 +                @{$_}[ 1 .. $#$_ ];
 +            }
 +            else { undef; }
 +        } @bind;
 +}
 +
  sub _query_start {
      my ( $self, $sql, @bind ) = @_;
  
      if ( $self->debug ) {
          @bind = $self->_fix_bind_params(@bind);
-         
          $self->debugobj->query_start( $sql, @bind );
      }
  }
@@@ -1006,7 -1022,7 +1038,7 @@@ sub _execute 
  
  sub insert {
    my ($self, $source, $to_insert) = @_;
-   
    my $ident = $source->from; 
    my $bind_attributes = $self->source_bind_attributes($source);
  
@@@ -1108,7 -1124,7 +1140,7 @@@ sub delete 
    my $self = shift @_;
    my $source = shift @_;
    
-   my $bind_attrs = {}; ## If ever it's needed...
+   my $bind_attrs = $self->source_bind_attributes($source);
    
    return $self->_execute('delete' => [], $source, $bind_attrs, @_);
  }
  # Genarating a single PK column subquery is trivial and supported
  # by all RDBMS. However if we have a multicolumn PK, things get ugly.
  # Look at _multipk_update_delete()
- sub subq_update_delete {
+ sub _subq_update_delete {
    my $self = shift;
    my ($rs, $op, $values) = @_;
  
@@@ -1213,23 -1229,41 +1245,41 @@@ sub _select 
  
  sub _select_args {
    my ($self, $ident, $select, $condition, $attrs) = @_;
-   my $order = $attrs->{order_by};
  
    my $for = delete $attrs->{for};
    my $sql_maker = $self->sql_maker;
    $sql_maker->{for} = $for;
  
-   my @in_order_attrs = qw/group_by having _virtual_order_by/;
-   if (List::Util::first { exists $attrs->{$_} } (@in_order_attrs) ) {
-     $order = {
-       ($order
-         ? (order_by => $order)
-         : ()
-       ),
-       ( map { $_ => $attrs->{$_} } (@in_order_attrs) )
-     };
+   my $order = { map
+     { $attrs->{$_} ? ( $_ => $attrs->{$_} ) : ()  }
+     (qw/order_by group_by having _virtual_order_by/ )
+   };
+   my $bind_attrs = {};
+   my $alias2source = $self->_resolve_ident_sources ($ident);
+   for my $alias (keys %$alias2source) {
+     my $bindtypes = $self->source_bind_attributes ($alias2source->{$alias}) || {};
+     for my $col (keys %$bindtypes) {
+       my $fqcn = join ('.', $alias, $col);
+       $bind_attrs->{$fqcn} = $bindtypes->{$col} if $bindtypes->{$col};
+       # so that unqualified searches can be bound too
+       $bind_attrs->{$col} = $bind_attrs->{$fqcn} if $alias eq 'me';
+     }
    }
-   my $bind_attrs = {}; ## Future support
+   # This would be the point to deflate anything found in $condition
+   # (and leave $attrs->{bind} intact). Problem is - inflators historically
+   # expect a row object. And all we have is a resultsource (it is trivial
+   # to extract deflator coderefs via $alias2source above).
+   #
+   # I don't see a way forward other than changing the way deflators are
+   # invoked, and that's just bad...
    my @args = ('select', $attrs->{bind}, $ident, $bind_attrs, $select, $condition, $order);
    if ($attrs->{software_limit} ||
        $sql_maker->_default_limit_syntax eq "GenericSubQ") {
    return @args;
  }
  
+ sub _resolve_ident_sources {
+   my ($self, $ident) = @_;
+   my $alias2source = {};
+   # the reason this is so contrived is that $ident may be a {from}
+   # structure, specifying multiple tables to join
+   if ( Scalar::Util::blessed($ident) && $ident->isa("DBIx::Class::ResultSource") ) {
+     $alias2source->{$ident->alias} = $ident;
+   }
+   elsif (ref $ident eq 'ARRAY') {
+     for (@$ident) {
+       my $tabinfo;
+       if (ref $_ eq 'HASH') {
+         $tabinfo = $_;
+       }
+       if (ref $_ eq 'ARRAY' and ref $_->[0] eq 'HASH') {
+         $tabinfo = $_->[0];
+       }
+       $alias2source->{$tabinfo->{-alias}} = $tabinfo->{-result_source}
+         if ($tabinfo->{-result_source});
+     }
+   }
+   return $alias2source;
+ }
 -sub count {
 +sub _trim_attributes_for_count {
    my ($self, $source, $attrs) = @_;
 +  my %attrs = %$attrs;
 +
 +  # take off any column specs, any pagers, record_filter is cdbi, and no point of ordering a count
 +  delete @attrs{qw/select as rows offset page order_by record_filter/};
  
 -  my $tmp_attrs = { %$attrs };
 +  return \%attrs;
 +}
 +
 +sub count {
 +  my ($self, $source, $attrs) = @_;
  
 -  # take off any pagers, record_filter is cdbi, and no point of ordering a count
 -  delete $tmp_attrs->{$_} for (qw/select as rows offset page order_by record_filter/);
 +  my $tmp_attrs = $self->_trim_attributes_for_count($source, $attrs);
  
    # overwrite the selector
    $tmp_attrs->{select} = { count => '*' };
@@@ -1292,7 -1348,7 +1371,7 @@@ sub count_grouped 
    }
  
    $sub_attrs->{group_by} ||= [ map { "$attrs->{alias}.$_" } ($source->primary_columns) ];
-   $sub_attrs->{select} = $self->_grouped_count_select ($sub_attrs);
+   $sub_attrs->{select} = $self->_grouped_count_select ($source, $sub_attrs);
  
    $attrs->{from} = [{
      count_subq => $source->resultset_class->new ($source, $sub_attrs )->as_query
  # choke in various ways.
  #
  sub _grouped_count_select {
-   my ($self, $attrs) = @_;
-   return $attrs->{group_by};
+   my ($self, $source, $rs_args) = @_;
+   return $rs_args->{group_by};
  }
  
  sub source_bind_attributes {