Database: Have buildStringCast() actually cast for MySQL, MSSQL
authorBrad Jorsch <bjorsch@wikimedia.org>
Wed, 20 Feb 2019 19:41:55 +0000 (14:41 -0500)
committerBrad Jorsch <bjorsch@wikimedia.org>
Wed, 20 Feb 2019 19:52:20 +0000 (14:52 -0500)
While these databases allow implicit casts (at least from int to
string), in MySQL at least the implicit cast can prevent appropriate
index usage (see T216183). So let's have buildStringCast() actually do
the cast.

This also changes the base implementation in Wikimedia\Rdmbs\Database to
explicitly cast. Any other subclasses should check whether this new
version works for them.

Bug: T216247
Change-Id: I98c67c857b35de3191d47ab28810d8eb21ddbbc8

RELEASE-NOTES-1.33
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/database/DatabaseMssql.php
includes/libs/rdbms/database/DatabaseMysqlBase.php

index 957384b..56d06a0 100644 (file)
@@ -309,6 +309,9 @@ because of Phabricator reports.
 === Other changes in 1.33 ===
 * (T201747) Html::openElement() warns if given an element name with a space
   in it.
+* The implementation of buildStringCast() in Wikimedia\Rdbms\Database has
+  changed to explicitly cast. Subclasses relying on the base-class
+  implementation should check whether they need to override it now.
 
 == Compatibility ==
 MediaWiki 1.33 requires PHP 7.0.13 or later. Although HHVM 3.18.5 or later is
index 974c7df..b3597df 100644 (file)
@@ -2278,7 +2278,9 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        }
 
        public function buildStringCast( $field ) {
-               return $field;
+               // In theory this should work for any standards-compliant
+               // SQL implementation, although it may not be the best way to do it.
+               return "CAST( $field AS CHARACTER )";
        }
 
        public function buildIntegerCast( $field ) {
index 93bb5d3..a6027e6 100644 (file)
@@ -1398,6 +1398,11 @@ class DatabaseMssql extends Database {
 
                return $old;
        }
+
+       public function buildStringCast( $field ) {
+               return "CAST( $field AS NVARCHAR )";
+       }
+
 }
 
 /**
index 186c89f..62110ef 100644 (file)
@@ -1548,6 +1548,10 @@ abstract class DatabaseMysqlBase extends Database {
                        !preg_match( '/^SELECT\s+(GET|RELEASE|IS_FREE)_LOCK\(/', $sql );
        }
 
+       public function buildStringCast( $field ) {
+               return "CAST( $field AS BINARY )";
+       }
+
        /**
         * @param string $field Field or column to cast
         * @return string