Merge 'trunk' into 'reduce_pings'
Rafael Kitover [Wed, 5 Aug 2009 09:19:57 +0000 (09:19 +0000)]
r6389@hlagh (orig r7140):  caelum | 2009-07-30 08:46:04 -0400
update sqlite test schema
r6394@hlagh (orig r7145):  robkinyon | 2009-07-30 10:13:21 -0400
Added prefetch caveats
r6395@hlagh (orig r7146):  robkinyon | 2009-07-30 10:20:02 -0400
Fixed caveats
r6398@hlagh (orig r7149):  caelum | 2009-07-30 11:56:01 -0400
make ::Oracle::Generic load without DBD::Oracle
r6399@hlagh (orig r7150):  caelum | 2009-07-30 12:04:47 -0400
make sure DBD::Oracle is loaded when using constants from it
r6404@hlagh (orig r7154):  castaway | 2009-07-30 16:17:33 -0400
Mangled Rob's example somewhat, still needs explaining whch circs exactly cause the borken results

r6405@hlagh (orig r7158):  mo | 2009-07-31 06:51:20 -0400
POD fix
r6406@hlagh (orig r7159):  mo | 2009-07-31 06:52:42 -0400
undo that attributes merge stuff
r9037@hlagh (orig r7166):  castaway | 2009-08-02 06:41:25 -0400
Mention ResultSet, ResultSource and Row in synopsis

r9038@hlagh (orig r7167):  castaway | 2009-08-02 08:10:53 -0400
Docs: Explainations of result sources and how to find them

r9042@hlagh (orig r7172):  ribasushi | 2009-08-03 05:01:44 -0400
Disable Pod::Inherit makefile calls, until we get to version 0.02
r9046@hlagh (orig r7176):  ribasushi | 2009-08-03 05:51:42 -0400
 r6983@Thesaurus (orig r6982):  ribasushi | 2009-07-04 11:46:57 +0200
 New branch to experiment with a sanifying mysql on_connect_call
 r6984@Thesaurus (orig r6983):  ribasushi | 2009-07-04 11:49:44 +0200
 Initial set_ansi_mode code - make sure to utilize _do_query instead of dbh->do, so the result is visible in the trace
 r6987@Thesaurus (orig r6986):  ribasushi | 2009-07-04 12:40:47 +0200
 Fix POD
 r7178@Thesaurus (orig r7175):  ribasushi | 2009-08-03 11:51:15 +0200
 Wrap up set_strict_mode for mysql

r9048@hlagh (orig r7178):  ribasushi | 2009-08-03 06:41:32 -0400
Sanify unqualified column bindtype handling
Silence a warning when using a custom {from}
r9068@hlagh (orig r7198):  caelum | 2009-08-04 16:18:27 -0400
update Changes
r9075@hlagh (orig r7205):  ribasushi | 2009-08-05 02:34:25 -0400
Bump dependencies:
Test::More for the new no_plan/done_testing goodies
File::Temp as per RT#48431
r9077@hlagh (orig r7207):  ribasushi | 2009-08-05 02:36:32 -0400
 r7156@Thesaurus (orig r7153):  robkinyon | 2009-07-30 20:06:04 +0200
 Create prefetch_redux branch
 r7164@Thesaurus (orig r7161):  robkinyon | 2009-07-31 22:41:01 +0200
 Added MooseX::Traits to Makefile.PL
 r7172@Thesaurus (orig r7169):  robkinyon | 2009-08-03 05:49:59 +0200
 Added two tests and marked one todo_skip
 r7187@Thesaurus (orig r7184):  ribasushi | 2009-08-03 17:24:41 +0200
 Use goto to preserve correct error-at-line reporting
 r7189@Thesaurus (orig r7186):  ribasushi | 2009-08-04 12:34:58 +0200
 Add an extra test specifically for distinct/prefetch
 Remove duplicate test in count/prefetch

 Switch to as_query instead of debug overloading
 r7190@Thesaurus (orig r7187):  ribasushi | 2009-08-04 12:35:57 +0200
 Fix how a distinct-induced group_by is calculated, taking in consideration the new prefetch mechanism
 r7197@Thesaurus (orig r7194):  ribasushi | 2009-08-04 17:31:33 +0200
 Traits not needed by anything currently in dbic
 r7198@Thesaurus (orig r7195):  ribasushi | 2009-08-04 17:41:14 +0200
 Move around tests a bit
 r7199@Thesaurus (orig r7196):  mo | 2009-08-04 21:10:57 +0200
 prefetch-grouped fails, again
 r7204@Thesaurus (orig r7201):  ribasushi | 2009-08-04 22:50:51 +0200
 Split the search_related prefetch tests into a standalone testfile
 r7205@Thesaurus (orig r7202):  ribasushi | 2009-08-04 23:05:03 +0200
 Move norbi's test to prefetch_redux - it's the same idea
 r7209@Thesaurus (orig r7206):  ribasushi | 2009-08-05 08:35:48 +0200
 Tadaaaa (even more prefetch insanity)

r9079@hlagh (orig r7209):  ribasushi | 2009-08-05 02:38:41 -0400
 r7107@Thesaurus (orig r7104):  caelum | 2009-07-24 06:51:57 +0200
 new branch to move common mssql functionality into the base class, and other tweaks
 r7109@Thesaurus (orig r7106):  caelum | 2009-07-24 07:28:11 +0200
 moved code to ::DBI::MSSQL and added DT inflation test
 r7112@Thesaurus (orig r7109):  caelum | 2009-07-24 08:46:16 +0200
 merge in some more MSSQL code, including odbc dynamic cursor support
 r7113@Thesaurus (orig r7110):  caelum | 2009-07-24 08:49:54 +0200
 fix a warning in SQLAHacks
 r7114@Thesaurus (orig r7111):  caelum | 2009-07-24 09:22:33 +0200
 add placeholder support detection for mssql through dbd::sybase
 r7118@Thesaurus (orig r7115):  caelum | 2009-07-24 16:39:06 +0200
 minor doc clarification
 r7122@Thesaurus (orig r7119):  caelum | 2009-07-25 16:10:30 +0200
 move placeholder support detection into ::Sybase::Base
 r7123@Thesaurus (orig r7120):  caelum | 2009-07-25 16:12:01 +0200
 add a comment
 r7127@Thesaurus (orig r7124):  caelum | 2009-07-26 18:04:29 +0200
 SAVEPOINT methods for MSSQL
 r7140@Thesaurus (orig r7137):  caelum | 2009-07-30 10:12:45 +0200
 better tests for "smalldatetime" support in MSSQL
 r7142@Thesaurus (orig r7139):  caelum | 2009-07-30 13:29:19 +0200
 MSSQL GUID support
 r7147@Thesaurus (orig r7144):  caelum | 2009-07-30 15:38:33 +0200
 update sqlite test schema
 r7150@Thesaurus (orig r7147):  caelum | 2009-07-30 16:26:47 +0200
 make sure the new mssql insert method works on an un-reblessed storage
 r7151@Thesaurus (orig r7148):  caelum | 2009-07-30 16:55:35 +0200
 better rebless check for insert
 r7154@Thesaurus (orig r7151):  caelum | 2009-07-30 18:57:22 +0200
 add missing file
 r7155@Thesaurus (orig r7152):  caelum | 2009-07-30 19:00:40 +0200
 fix syntax error
 r7163@Thesaurus (orig r7160):  caelum | 2009-07-31 15:52:41 +0200
 fix a bug in _determine_driver
 r7166@Thesaurus (orig r7163):  caelum | 2009-08-01 18:10:23 +0200
 default collist for storage _resolve_column_info
 r7182@Thesaurus (orig r7179):  caelum | 2009-08-03 13:42:31 +0200
 check that dynamic cursors are functional if enabled
 r7184@Thesaurus (orig r7181):  ribasushi | 2009-08-03 14:23:37 +0200
 Adjust expected sql to match the new 'Track' table definition
 r7186@Thesaurus (orig r7183):  ribasushi | 2009-08-03 15:16:10 +0200
 Simplify code and add some comments
 r7200@Thesaurus (orig r7197):  caelum | 2009-08-04 21:31:16 +0200
 update oracle tests for new "track" table
 r7203@Thesaurus (orig r7200):  caelum | 2009-08-04 22:39:57 +0200
 update Changes

r9081@hlagh (orig r7211):  ribasushi | 2009-08-05 02:40:39 -0400
 r7213@Thesaurus (orig r7210):  ribasushi | 2009-08-05 08:40:20 +0200
 Really sanify _resolve_column_info

r9083@hlagh (orig r7213):  ribasushi | 2009-08-05 04:19:37 -0400
Reminder about discard_changes and friends
r9084@hlagh (orig r7214):  ribasushi | 2009-08-05 04:26:20 -0400
Reformat and fill-in changes
r9085@hlagh (orig r7215):  caelum | 2009-08-05 04:37:12 -0400
rename connect_call_use_mars to connect_call_use_MARS
r9086@hlagh (orig r7216):  ribasushi | 2009-08-05 04:38:14 -0400
Silence a TODO test
r9087@hlagh (orig r7217):  caelum | 2009-08-05 04:46:11 -0400
minor Changes update

1  2 
lib/DBIx/Class/Storage/DBI.pm
lib/DBIx/Class/Storage/DBI/Oracle/Generic.pm
lib/DBIx/Class/Storage/DBI/mysql.pm

@@@ -15,8 -15,8 +15,8 @@@ use Scalar::Util()
  use List::Util();
  
  __PACKAGE__->mk_group_accessors('simple' =>
-   qw/_connect_info _dbi_connect_info _dbh _sql_maker _sql_maker_opts
-      _conn_pid _conn_tid transaction_depth _dbh_autocommit savepoints/
+   qw/_connect_info _dbi_connect_info _dbh _sql_maker _sql_maker_opts _conn_pid
+      _conn_tid transaction_depth _dbh_autocommit _driver_determined savepoints/
  );
  
  # the values for these accessors are picked out (and deleted) from
@@@ -437,21 -437,12 +437,21 @@@ sub connect_info 
      }
    }
  
 -  %attrs = () if (ref $args[0] eq 'CODE');  # _connect() never looks past $args[0] in this case
 +  if (ref $args[0] eq 'CODE') {
 +    # _connect() never looks past $args[0] in this case
 +    %attrs = ()
 +  } else {
 +    %attrs = (%{ $self->_dbi_connect_attributes }, %attrs);
 +  }
  
    $self->_dbi_connect_info([@args, keys %attrs ? \%attrs : ()]);
    $self->_connect_info;
  }
  
 +sub _dbi_connect_attributes {
 +  return { AutoCommit => 1 };
 +}
 +
  =head2 on_connect_do
  
  This method is deprecated in favour of setting via L</connect_info>.
@@@ -630,7 -621,7 +630,7 @@@ database is not in C<AutoCommit> mode
  sub disconnect {
    my ($self) = @_;
  
 -  if( $self->connected ) {
 +  if( $self->_dbh ) {
      my @actions;
  
      push @actions, ( $self->on_disconnect_call || () );
@@@ -725,32 -716,14 +725,32 @@@ Returns the dbh - a data base handle o
  sub dbh {
    my ($self) = @_;
  
 -  $self->ensure_connected;
 +  if (not $self->_dbh) {
 +    $self->_populate_dbh;
 +  } else {
 +    $self->ensure_connected;
 +  }
 +  return $self->_dbh;
 +}
 +
 +sub _get_dbh {
 +  my $self = shift;
 +
 +  if (not $self->_dbh) {
 +    $self->_populate_dbh;
 +  }
    return $self->_dbh;
  }
  
  sub _sql_maker_args {
      my ($self) = @_;
  
 -    return ( bindtype=>'columns', array_datatypes => 1, limit_dialect => $self->dbh, %{$self->_sql_maker_opts} );
 +    return (
 +      bindtype=>'columns',
 +      array_datatypes => 1,
 +      limit_dialect => $self->_get_dbh,
 +      %{$self->_sql_maker_opts}
 +    );
  }
  
  sub sql_maker {
@@@ -767,7 -740,6 +767,7 @@@ sub _rebless {
  
  sub _populate_dbh {
    my ($self) = @_;
 +
    my @info = @{$self->_dbi_connect_info || []};
    $self->_dbh($self->_connect(@info));
  
    #  there is no transaction in progress by definition
    $self->{transaction_depth} = $self->_dbh_autocommit ? 0 : 1;
  
 +  $self->_run_connection_actions unless $self->{_in_determine_driver};
 +}
 +
 +sub _run_connection_actions {
 +  my $self = shift;
    my @actions;
  
    push @actions, ( $self->on_connect_call || () );
  sub _determine_driver {
    my ($self) = @_;
  
-   if (ref $self eq 'DBIx::Class::Storage::DBI') {
-     my $driver;
+   if (not $self->_driver_determined) {
+     if (ref($self) eq __PACKAGE__) {
+       my $driver;
 +    my $started_unconnected = 0;
 +    local $self->{_in_determine_driver} = 1;
  
-     if ($self->_dbh) { # we are connected
-       $driver = $self->_dbh->{Driver}{Name};
-     } else {
-       # try to use dsn to not require being connected, the driver may still
-       # force a connection in _rebless to determine version
-       ($driver) = $self->_dbi_connect_info->[0] =~ /dbi:([^:]+):/i;
+       if ($self->_dbh) { # we are connected
+         $driver = $self->_dbh->{Driver}{Name};
+       } else {
+         # try to use dsn to not require being connected, the driver may still
+         # force a connection in _rebless to determine version
+         ($driver) = $self->_dbi_connect_info->[0] =~ /dbi:([^:]+):/i;
+       }
+       my $storage_class = "DBIx::Class::Storage::DBI::${driver}";
+       if ($self->load_optional_class($storage_class)) {
+         mro::set_mro($storage_class, 'c3');
+         bless $self, $storage_class;
+         $self->_rebless();
+       }
 +      $started_unconnected = 1;
      }
  
-     my $storage_class = "DBIx::Class::Storage::DBI::${driver}";
-     if ($self->load_optional_class($storage_class)) {
-       mro::set_mro($storage_class, 'c3');
-       bless $self, $storage_class;
-       $self->_rebless();
-     }
+     $self->_driver_determined(1);
 +
 +    $self->_run_connection_actions
 +        if $started_unconnected && defined $self->_dbh;
    }
  }
  
@@@ -1018,13 -983,14 +1022,13 @@@ sub _svp_generate_name 
  
  sub txn_begin {
    my $self = shift;
 -  $self->ensure_connected();
    if($self->{transaction_depth} == 0) {
      $self->debugobj->txn_begin()
        if $self->debug;
      # this isn't ->_dbh-> because
      #  we should reconnect on begin_work
      #  for AutoCommit users
 -    $self->dbh->begin_work;
 +    $self->dbh_do(sub { $_[1]->begin_work });
    } elsif ($self->auto_savepoint) {
      $self->svp_begin;
    }
@@@ -1180,7 -1146,11 +1184,11 @@@ sub _execute 
  sub insert {
    my ($self, $source, $to_insert) = @_;
  
-   $self->_determine_driver;
+ # redispatch to insert method of storage we reblessed into, if necessary
+   if (not $self->_driver_determined) {
+     $self->_determine_driver;
+     goto $self->can('insert');
+   }
  
    my $ident = $source->from;
    my $bind_attributes = $self->source_bind_attributes($source);
        my $col_info = $source->column_info($col);
  
        if ( $col_info->{auto_nextval} ) {
 -        $updated_cols->{$col} = $to_insert->{$col} = $self->_sequence_fetch( 'nextval', $col_info->{sequence} || $self->_dbh_get_autoinc_seq($self->dbh, $source) );
 +        $updated_cols->{$col} = $to_insert->{$col} = $self->_sequence_fetch(
 +          'nextval',
 +          $col_info->{sequence} ||
 +            $self->_dbh_get_autoinc_seq($self->_get_dbh, $source)
 +        );
        }
      }
    }
@@@ -1217,8 -1183,6 +1225,8 @@@ sub insert_bulk 
    @colvalues{@$cols} = (0..$#$cols);
    my ($sql, @bind) = $self->sql_maker->insert($table, \%colvalues);
  
 +  $self->_determine_driver;
 +
    $self->_query_start( $sql, @bind );
    my $sth = $self->sth($sql);
  
  sub update {
    my $self = shift @_;
    my $source = shift @_;
 +  $self->_determine_driver;
    my $bind_attributes = $self->source_bind_attributes($source);
  
    return $self->_execute('update' => [], $source, $bind_attributes, @_);
  sub delete {
    my $self = shift @_;
    my $source = shift @_;
 -
 +  $self->_determine_driver;
    my $bind_attrs = $self->source_bind_attributes($source);
  
    return $self->_execute('delete' => [], $source, $bind_attrs, @_);
@@@ -1447,8 -1410,21 +1455,21 @@@ sub _select_args 
        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 $rs_alias;
+       # Unqialified column names are nice, but at the same time can be
+       # rather ambiguous. What we do here is basically go along with
+       # the loop, adding an unqualified column slot to $bind_attrs,
+       # alongside the fully qualified name. As soon as we encounter
+       # another column by that name (which would imply another table)
+       # we unset the unqualified slot and never add any info to it
+       # to avoid erroneous type binding. If this happens the users
+       # only choice will be to fully qualify his column name
+       if (exists $bind_attrs->{$col}) {
+         $bind_attrs->{$col} = {};
+       }
+       else {
+         $bind_attrs->{$col} = $bind_attrs->{$fqcn};
+       }
      }
    }
  
      ( $attrs->{rows} && keys %{$attrs->{collapse}} )
         ||
      ( $attrs->{group_by} && @{$attrs->{group_by}} &&
-       $attrs->{prefetch_select} && @{$attrs->{prefetch_select}} )
+       $attrs->{_prefetch_select} && @{$attrs->{_prefetch_select}} )
    ) {
      ($ident, $select, $where, $attrs)
        = $self->_adjust_select_args_for_complex_prefetch ($ident, $select, $where, $attrs);
@@@ -1521,14 -1497,15 +1542,15 @@@ sub _adjust_select_args_for_complex_pre
    # separate attributes
    my $sub_attrs = { %$attrs };
    delete $attrs->{$_} for qw/where bind rows offset group_by having/;
-   delete $sub_attrs->{$_} for qw/for collapse prefetch_select _collapse_order_by select as/;
+   delete $sub_attrs->{$_} for qw/for collapse _prefetch_select _collapse_order_by select as/;
  
-   my $alias = $attrs->{alias};
+   my $select_root_alias = $attrs->{alias};
    my $sql_maker = $self->sql_maker;
  
    # create subquery select list - consider only stuff *not* brought in by the prefetch
    my $sub_select = [];
-   for my $i (0 .. @{$attrs->{select}} - @{$attrs->{prefetch_select}} - 1) {
+   my $sub_group_by;
+   for my $i (0 .. @{$attrs->{select}} - @{$attrs->{_prefetch_select}} - 1) {
      my $sel = $attrs->{select}[$i];
  
      # alias any functions to the dbic-side 'as' label
      ];
    }
  
-   # mangle {from}
+   # mangle {from}, keep in mind that $from is "headless" from here on
    my $join_root = shift @$from;
-   my @outer_from = @$from;
  
    my %inner_joins;
    my %join_info = map { $_->[0]{-alias} => $_->[0] } (@$from);
  
-   # in complex search_related chains $alias may *not* be 'me'
-   # so always include it in the inner join, and also shift away
-   # from the outer stack, so that the two datasets actually do
-   # meet
-   if ($join_root->{-alias} ne $alias) {
-     $inner_joins{$alias} = 1;
-     while (@outer_from && $outer_from[0][0]{-alias} ne $alias) {
-       shift @outer_from;
-     }
-     if (! @outer_from) {
-       $self->throw_exception ("Unable to find '$alias' in the {from} stack, something is wrong");
-     }
-     shift @outer_from; # the new subquery will represent this alias, so get rid of it
-   }
+   # in complex search_related chains $select_root_alias may *not* be
+   # 'me' so always include it in the inner join
+   $inner_joins{$select_root_alias} = 1 if ($join_root->{-alias} ne $select_root_alias);
  
  
    # decide which parts of the join will remain on the inside
  
    # 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
-   for my $alias (keys %inner_joins) {
-     # the dot comes from some weirdness in collapse
-     # remove after the rewrite
-     if ($attrs->{collapse}{".$alias"}) {
-       $sub_attrs->{group_by} ||= $sub_select;
-       last;
+   unless ($sub_attrs->{group_by}) {
+     for my $alias (keys %inner_joins) {
+       # the dot comes from some weirdness in collapse
+       # remove after the rewrite
+       if ($attrs->{collapse}{".$alias"}) {
+         $sub_attrs->{group_by} ||= $sub_select;
+         last;
+       }
      }
    }
  
      $where,
      $sub_attrs
    );
-   # put it in the new {from}
-   unshift @outer_from, {
-     -alias => $alias,
+   my $subq_joinspec = {
+     -alias => $select_root_alias,
      -source_handle => $join_root->{-source_handle},
-     $alias => $subq,
+     $select_root_alias => $subq,
    };
  
+   # Generate a new from (really just replace the join slot with the subquery)
+   # Before we would start the outer chain from the subquery itself (i.e.
+   # SELECT ... FROM (SELECT ... ) alias JOIN ..., but this turned out to be
+   # a bad idea for search_related, as the root of the chain was effectively
+   # lost (i.e. $artist_rs->search_related ('cds'... ) would result in alias
+   # of 'cds', which would prevent from doing things like order_by artist.*)
+   # See t/prefetch/via_search_related.t for a better idea
+   my @outer_from;
+   if ($join_root->{-alias} eq $select_root_alias) { # just swap the root part and we're done
+     @outer_from = (
+       $subq_joinspec,
+       @$from,
+     )
+   }
+   else {  # this is trickier
+     @outer_from = ($join_root);
+     for my $j (@$from) {
+       if ($j->[0]{-alias} eq $select_root_alias) {
+         push @outer_from, [
+           $subq_joinspec,
+           @{$j}[1 .. $#$j],
+         ];
+       }
+       else {
+         push @outer_from, $j;
+       }
+     }
+   }
    # This is totally horrific - the $where ends up in both the inner and outer query
    # Unfortunately not much can be done until SQLA2 introspection arrives, and even
    # then if where conditions apply to the *right* side of the prefetch, you may have
@@@ -1715,7 -1708,7 +1753,7 @@@ sub _resolve_ident_sources 
  # also note: this adds -result_source => $rsrc to the column info
  #
  # usage:
- #   my $col_sources = $self->_resolve_column_info($ident, [map $_->[0], @{$bind}]);
+ #   my $col_sources = $self->_resolve_column_info($ident, @column_names);
  sub _resolve_column_info {
    my ($self, $ident, $colnames) = @_;
    my ($alias2src, $root_alias) = $self->_resolve_ident_sources($ident);
    my $sep = $self->_sql_maker_opts->{name_sep} || '.';
    $sep = "\Q$sep\E";
  
-   my (%return, %converted);
+   my (%return, %seen_cols);
+   # compile a global list of column names, to be able to properly
+   # disambiguate unqualified column names (if at all possible)
+   for my $alias (keys %$alias2src) {
+     my $rsrc = $alias2src->{$alias};
+     for my $colname ($rsrc->columns) {
+       push @{$seen_cols{$colname}}, $alias;
+     }
+   }
+   COLUMN:
    foreach my $col (@$colnames) {
      my ($alias, $colname) = $col =~ m/^ (?: ([^$sep]+) $sep)? (.+) $/x;
  
-     # deal with unqualified cols - we assume the main alias for all
-     # unqualified ones, ugly but can't think of anything better right now
-     $alias ||= $root_alias;
+     unless ($alias) {
+       # see if the column was seen exactly once (so we know which rsrc it came from)
+       if ($seen_cols{$colname} and @{$seen_cols{$colname}} == 1) {
+         $alias = $seen_cols{$colname}[0];
+       }
+       else {
+         next COLUMN;
+       }
+     }
  
      my $rsrc = $alias2src->{$alias};
-     $return{$col} = $rsrc && { %{$rsrc->column_info($colname)}, -result_source => $rsrc };
+     $return{$col} = $rsrc && {
+       %{$rsrc->column_info($colname)},
+       -result_source => $rsrc,
+       -source_alias => $alias,
+     };
    }
    return \%return;
  }
  
@@@ -1933,7 -1948,7 +1993,7 @@@ Returns the database driver name
  
  =cut
  
 -sub sqlt_type { shift->dbh->{Driver}->{Name} }
 +sub sqlt_type { shift->_get_dbh->{Driver}->{Name} }
  
  =head2 bind_attribute_by_data_type
  
@@@ -2180,7 -2195,7 +2240,7 @@@ See L<SQL::Translator/METHODS> for a li
  sub deployment_statements {
    my ($self, $schema, $type, $version, $dir, $sqltargs) = @_;
    # Need to be connected to get the correct sqlt_type
 -  $self->ensure_connected() unless $type;
 +  $self->_get_dbh() unless $type;
    $type ||= $self->sqlt_type;
    $version ||= $schema->schema_version || '1.x';
    $dir ||= './';
@@@ -2225,7 -2240,7 +2285,7 @@@ sub deploy 
      return if $line =~ /^\s+$/; # skip whitespace only
      $self->_query_start($line);
      eval {
 -      $self->dbh->do($line); # shouldn't be using ->dbh ?
 +      $self->_get_dbh->do($line);
      };
      if ($@) {
        carp qq{$@ (running "${line}")};
@@@ -2254,7 -2269,7 +2314,7 @@@ Returns the datetime parser clas
  sub datetime_parser {
    my $self = shift;
    return $self->{datetime_parser} ||= do {
 -    $self->ensure_connected;
 +    $self->_get_dbh;
      $self->build_datetime_parser(@_);
    };
  }
@@@ -26,9 -26,6 +26,6 @@@ This class implements autoincrements fo
  use base qw/DBIx::Class::Storage::DBI/;
  use mro 'c3';
  
- # For ORA_BLOB => 113, ORA_CLOB => 112
- use DBD::Oracle qw( :ora_types );
  sub _dbh_last_insert_id {
    my ($self, $dbh, $source, @columns) = @_;
    my @ids = ();
@@@ -79,7 -76,7 +76,7 @@@ sub _dbh_get_autoinc_seq 
  
  sub _sequence_fetch {
    my ( $self, $type, $seq ) = @_;
 -  my ($id) = $self->dbh->selectrow_array("SELECT ${seq}.${type} FROM DUAL");
 +  my ($id) = $self->_get_dbh->selectrow_array("SELECT ${seq}.${type} FROM DUAL");
    return $id;
  }
  
@@@ -212,7 -209,7 +209,7 @@@ sub connect_call_datetime_setup 
  sub _svp_begin {
      my ($self, $name) = @_;
  
 -    $self->dbh->do("SAVEPOINT $name");
 +    $self->_get_dbh->do("SAVEPOINT $name");
  }
  
  =head2 source_bind_attributes
@@@ -234,6 -231,7 +231,7 @@@ table with more than one LOB column
  
  sub source_bind_attributes 
  {
+       require DBD::Oracle;
        my $self = shift;
        my($source) = @_;
  
                my %column_bind_attrs = $self->bind_attribute_by_data_type($data_type);
  
                if ($data_type =~ /^[BC]LOB$/i) {
-                       $column_bind_attrs{'ora_type'}
-                               = uc($data_type) eq 'CLOB' ? ORA_CLOB : ORA_BLOB;
+                       $column_bind_attrs{'ora_type'} = uc($data_type) eq 'CLOB' ?
+                               DBD::Oracle::ORA_CLOB() :
+                               DBD::Oracle::ORA_BLOB();
                        $column_bind_attrs{'ora_field'} = $column;
                }
  
@@@ -264,7 -263,7 +263,7 @@@ sub _svp_release { 1 
  sub _svp_rollback {
      my ($self, $name) = @_;
  
 -    $self->dbh->do("ROLLBACK TO SAVEPOINT $name")
 +    $self->_get_dbh->do("ROLLBACK TO SAVEPOINT $name")
  }
  
  =head1 AUTHOR
@@@ -20,6 -20,14 +20,14 @@@ sub with_deferred_fk_checks 
    $self->_do_query('SET FOREIGN_KEY_CHECKS = 1');
  }
  
+ sub connect_call_set_strict_mode {
+   my $self = shift;
+   # the @@sql_mode puts back what was previously set on the session handle
+   $self->_do_query(q|SET SQL_MODE = CONCAT('ANSI,TRADITIONAL,ONLY_FULL_GROUP_BY,', @@sql_mode)|);
+   $self->_do_query(q|SET SQL_AUTO_IS_NULL = 0|);
+ }
  sub _dbh_last_insert_id {
    my ($self, $dbh, $source, $col) = @_;
    $dbh->{mysql_insertid};
@@@ -32,28 -40,28 +40,28 @@@ sub sqlt_type 
  sub _svp_begin {
      my ($self, $name) = @_;
  
 -    $self->dbh->do("SAVEPOINT $name");
 +    $self->_get_dbh->do("SAVEPOINT $name");
  }
  
  sub _svp_release {
      my ($self, $name) = @_;
  
 -    $self->dbh->do("RELEASE SAVEPOINT $name");
 +    $self->_get_dbh->do("RELEASE SAVEPOINT $name");
  }
  
  sub _svp_rollback {
      my ($self, $name) = @_;
  
 -    $self->dbh->do("ROLLBACK TO SAVEPOINT $name")
 +    $self->_get_dbh->do("ROLLBACK TO SAVEPOINT $name")
  }
  
  sub is_replicating {
 -    my $status = shift->dbh->selectrow_hashref('show slave status');
 +    my $status = shift->_get_dbh->selectrow_hashref('show slave status');
      return ($status->{Slave_IO_Running} eq 'Yes') && ($status->{Slave_SQL_Running} eq 'Yes');
  }
  
  sub lag_behind_master {
 -    return shift->dbh->selectrow_hashref('show slave status')->{Seconds_Behind_Master};
 +    return shift->_get_dbh->selectrow_hashref('show slave status')->{Seconds_Behind_Master};
  }
  
  # MySql can not do subquery update/deletes, only way is slow per-row operations.
@@@ -73,12 -81,16 +81,16 @@@ DBIx::Class::Storage::DBI::mysql - Stor
  Storage::DBI autodetects the underlying MySQL database, and re-blesses the
  C<$storage> object into this class.
  
-   my $schema = MyDb::Schema->connect( $dsn, $user, $pass );
+   my $schema = MyDb::Schema->connect( $dsn, $user, $pass, { set_strict_mode => 1 } );
  
  =head1 DESCRIPTION
  
  This class implements MySQL specific bits of L<DBIx::Class::Storage::DBI>.
  
+ It also provides a one-stop on-connect macro C<set_strict_mode> which sets
+ session variables such that MySQL behaves more predictably as far as the
+ SQL standard is concerned.
  =head1 AUTHORS
  
  See L<DBIx::Class/CONTRIBUTORS>