Issue #3218978 by effulgentsia, daffie, mcdruid, Wim Leers: MySQL driver allows settings.php to remove ANSI_QUOTES from sql_mode, but doesn't work when it is
(cherry picked from commit cff1307c85
)
merge-requests/1102/head
parent
2bf4121694
commit
f0c7bb8380
|
@ -89,6 +89,35 @@ class Connection extends DatabaseConnection {
|
|||
*/
|
||||
protected $identifierQuotes = ['"', '"'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(\PDO $connection, array $connection_options) {
|
||||
// If the SQL mode doesn't include 'ANSI_QUOTES' (explicitly or via a
|
||||
// combination mode), then MySQL doesn't interpret a double quote as an
|
||||
// identifier quote, in which case use the non-ANSI-standard backtick.
|
||||
//
|
||||
// Because we still support MySQL 5.7, check for the deprecated combination
|
||||
// modes as well.
|
||||
//
|
||||
// @see https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_ansi_quotes
|
||||
$ansi_quotes_modes = ['ANSI_QUOTES', 'ANSI', 'DB2', 'MAXDB', 'MSSQL', 'ORACLE', 'POSTGRESQL'];
|
||||
$is_ansi_quotes_mode = FALSE;
|
||||
foreach ($ansi_quotes_modes as $mode) {
|
||||
// None of the modes in $ansi_quotes_modes are substrings of other modes
|
||||
// that are not in $ansi_quotes_modes, so a simple stripos() does not
|
||||
// return false positives.
|
||||
if (stripos($connection_options['init_commands']['sql_mode'], $mode) !== FALSE) {
|
||||
$is_ansi_quotes_mode = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($this->identifierQuotes === ['"', '"'] && !$is_ansi_quotes_mode) {
|
||||
$this->identifierQuotes = ['`', '`'];
|
||||
}
|
||||
parent::__construct($connection, $connection_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\KernelTests\Core\Database;
|
||||
|
||||
/**
|
||||
* Tests compatibility of the MySQL driver with various sql_mode options.
|
||||
*
|
||||
* @group Database
|
||||
*/
|
||||
class SqlModeTest extends DatabaseTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
if ($this->connection->databaseType() !== 'mysql') {
|
||||
$this->markTestSkipped("Skipping test since sql_mode is a MySQL-only feature.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests quoting identifiers in queries.
|
||||
*/
|
||||
public function testQuotingIdentifiers() {
|
||||
// Use SQL-reserved words for both the table and column names.
|
||||
$query = $this->connection->query('SELECT [update] FROM {select}');
|
||||
$this->assertEquals('Update value 1', $query->fetchObject()->update);
|
||||
$this->assertStringContainsString('SELECT `update` FROM `', $query->getQueryString());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDatabaseConnectionInfo() {
|
||||
$info = parent::getDatabaseConnectionInfo();
|
||||
|
||||
// This runs during setUp(), so is not yet skipped for non MySQL databases.
|
||||
// We defer skipping the test to later in setUp(), so that that can be
|
||||
// based on databaseType() rather than 'driver', but here all we have to go
|
||||
// on is 'driver'.
|
||||
if ($info['default']['driver'] === 'mysql') {
|
||||
$info['default']['init_commands']['sql_mode'] = "SET sql_mode = ''";
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue