Properly detect and test mysql v3 default JOIN behavior
Peter Rabbitson [Thu, 10 Apr 2014 22:43:35 +0000 (00:43 +0200)]
While investigating how to rewrite the rather useless 39712b481, it became
clear that not only can the test be performed offline, but that there is
already a pseudo-test due to sqlite's version of 3.x.y being mistaken for
MySQL 3

Properly fix the test to check behavior on both versions 3 and 4, and in the
process fix a potential bug of a stale sqlmaker when a reconnect cycle takes
place against a *different* physical rdbms (which btw makes me realize another
problem with trying to do mixed-environment replication... sigh)

lib/DBIx/Class/Storage/DBI.pm
lib/DBIx/Class/Storage/DBI/mysql.pm
t/71mysql.t
t/sqlmaker/mysql.t

index 5245bea..1a302ce 100644 (file)
@@ -1061,6 +1061,7 @@ sub _populate_dbh {
 
   $self->_dbh(undef); # in case ->connected failed we might get sent here
   $self->_dbh_details({}); # reset everything we know
+  $self->_sql_maker(undef); # this may also end up being different
 
   $self->_dbh($self->_connect);
 
index 83ee8b2..0605983 100644 (file)
@@ -106,15 +106,17 @@ sub _run_connection_actions {
 sub sql_maker {
   my $self = shift;
 
-  unless ($self->_sql_maker) {
-    my $maker = $self->next::method (@_);
+  # it is critical to get the version *before* calling next::method
+  # otherwise the potential connect will obliterate the sql_maker
+  # next::method will populate in the _sql_maker accessor
+  my $mysql_ver = $self->_server_info->{normalized_dbms_version};
 
-    # mysql 3 does not understand a bare JOIN
-    my $mysql_ver = $self->_dbh_get_info('SQL_DBMS_VER');
-    $maker->{_default_jointype} = 'INNER' if $mysql_ver =~ /^3/;
-  }
+  my $sm = $self->next::method(@_);
+
+  # mysql 3 does not understand a bare JOIN
+  $sm->{_default_jointype} = 'INNER' if $mysql_ver < 4;
 
-  return $self->_sql_maker;
+  $sm;
 }
 
 sub sqlt_type {
index 242989e..e1e68ee 100644 (file)
@@ -199,20 +199,6 @@ lives_ok { $cd->set_producers ([ $producer ]) } 'set_relationship doesnt die';
     my $cd = $rs->next;
     is ($cd->artist->name, $artist->name, 'Prefetched artist');
   }, 'join does not throw (mysql 3 test)';
-
-  # induce a jointype override, make sure it works even if we don't have mysql3
-  local $schema->storage->sql_maker->{_default_jointype} = 'inner';
-  is_same_sql_bind (
-    $rs->as_query,
-    '(
-      SELECT `me`.`cdid`, `me`.`artist`, `me`.`title`, `me`.`year`, `me`.`genreid`, `me`.`single_track`,
-             `artist`.`artistid`, `artist`.`name`, `artist`.`rank`, `artist`.`charfield`
-        FROM cd `me`
-        INNER JOIN `artist` `artist` ON `artist`.`artistid` = `me`.`artist`
-    )',
-    [],
-    'overridden default join type works',
-  );
 }
 
 ## Can we properly deal with the null search problem?
index 2755a3d..b5ce8a5 100644 (file)
@@ -12,6 +12,7 @@ use DBIC::DebugObj;
 my $schema = DBICTest::Schema->connect (DBICTest->_database, { quote_char => '`' });
 # cheat
 require DBIx::Class::Storage::DBI::mysql;
+*DBIx::Class::Storage::DBI::mysql::_get_server_version = sub { 5 };
 bless ( $schema->storage, 'DBIx::Class::Storage::DBI::mysql' );
 
 # check that double-subqueries are properly wrapped
@@ -102,7 +103,7 @@ bless ( $schema->storage, 'DBIx::Class::Storage::DBI::mysql' );
           FROM (
             SELECT `artist`.`artistid`
               FROM cd `me`
-              INNER JOIN `artist` `artist`
+              JOIN `artist` `artist`
                 ON `artist`.`artistid` = `me`.`artist`
             WHERE `artist`.`name` LIKE ?
           ) `_forced_double_subquery`
@@ -138,4 +139,32 @@ bless ( $schema->storage, 'DBIx::Class::Storage::DBI::mysql' );
   );
 }
 
+# Test support for inner joins on mysql v3
+for (
+  [ 3 => 'INNER JOIN' ],
+  [ 4 => 'JOIN' ],
+) {
+  my ($ver, $join_op) = @$_;
+
+  no warnings 'redefine';
+  local *DBIx::Class::Storage::DBI::mysql::_get_server_version = sub { $ver };
+
+  # we do not care at this point if data is available, just do a reconnect cycle
+  # to clear all caches
+  $schema->storage->disconnect;
+  $schema->storage->ensure_connected;
+
+  is_same_sql_bind (
+    $schema->resultset('CD')->search ({}, { prefetch => 'artist' })->as_query,
+    "(
+      SELECT `me`.`cdid`, `me`.`artist`, `me`.`title`, `me`.`year`, `me`.`genreid`, `me`.`single_track`,
+             `artist`.`artistid`, `artist`.`name`, `artist`.`rank`, `artist`.`charfield`
+        FROM cd `me`
+        $join_op `artist` `artist` ON `artist`.`artistid` = `me`.`artist`
+    )",
+    [],
+    "default join type works for version $ver",
+  );
+}
+
 done_testing;