From f8de9c75f17e04b7891380d37316a8e42a913a6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Karbula?= Date: Wed, 14 Oct 2020 13:56:28 +0200 Subject: [PATCH] MySqlDriver driver uses subqueries (#265) --- src/Database/Drivers/MySqlDriver.php | 14 ++++++++++---- tests/Database/Table/SqlBuilder.addWhere().phpt | 11 +---------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/Database/Drivers/MySqlDriver.php b/src/Database/Drivers/MySqlDriver.php index a130a9d19..fdadb427c 100644 --- a/src/Database/Drivers/MySqlDriver.php +++ b/src/Database/Drivers/MySqlDriver.php @@ -27,6 +27,9 @@ class MySqlDriver implements Nette\Database\ISupplementalDriver /** @var Nette\Database\Connection */ private $connection; + /** @var string */ + private $version; + /** * Driver options: @@ -36,8 +39,8 @@ class MySqlDriver implements Nette\Database\ISupplementalDriver public function initialize(Nette\Database\Connection $connection, array $options): void { $this->connection = $connection; - $charset = $options['charset'] - ?? (version_compare($connection->getPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION), '5.5.3', '>=') ? 'utf8mb4' : 'utf8'); + $this->version = $connection->getPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION); + $charset = $options['charset'] ?? (version_compare($this->version, '5.5.3', '>=') ? 'utf8mb4' : 'utf8'); if ($charset) { $connection->query('SET NAMES ?', $charset); } @@ -203,7 +206,10 @@ public function isSupported(string $item): bool // MULTI_COLUMN_AS_OR_COND due to mysql bugs: // - http://bugs.mysql.com/bug.php?id=31188 // - http://bugs.mysql.com/bug.php?id=35819 - // and more. - return $item === self::SUPPORT_SELECT_UNGROUPED_COLUMNS || $item === self::SUPPORT_MULTI_COLUMN_AS_OR_COND; + // SUPPORT_SUBSELECT is slow before 5.7 + // - http://mysqlserverteam.com/derived-tables-in-mysql-5-7/ + return $item === self::SUPPORT_SELECT_UNGROUPED_COLUMNS + || $item === self::SUPPORT_MULTI_COLUMN_AS_OR_COND + || ($item === self::SUPPORT_SUBSELECT && version_compare($this->version, '5.7', '>=')); } } diff --git a/tests/Database/Table/SqlBuilder.addWhere().phpt b/tests/Database/Table/SqlBuilder.addWhere().phpt index ac97fad76..113fc3add 100644 --- a/tests/Database/Table/SqlBuilder.addWhere().phpt +++ b/tests/Database/Table/SqlBuilder.addWhere().phpt @@ -38,10 +38,7 @@ test('?name', function () use ($context) { test('test Selection as a parameter', function () use ($context) { $sqlBuilder = new SqlBuilder('book', $context); $sqlBuilder->addWhere('id', $context->table('book')); - Assert::equal(reformat([ - 'mysql' => 'SELECT * FROM `book` WHERE (`id` IN (?))', - 'SELECT * FROM [book] WHERE ([id] IN (SELECT [id] FROM [book]))', - ]), $sqlBuilder->buildSelectQuery()); + Assert::equal(reformat(['SELECT * FROM [book] WHERE ([id] IN (SELECT [id] FROM [book]))']), $sqlBuilder->buildSelectQuery()); }); @@ -50,7 +47,6 @@ test('test more Selection as a parameter', function () use ($context) { $sqlBuilder->addWhere('id', $context->table('book')); $sqlBuilder->addWhere('id', $context->table('book_tag')->select('book_id')); Assert::equal(reformat([ - 'mysql' => 'SELECT * FROM `book` WHERE (`id` IN (?)) AND (`id` IN (?))', 'SELECT * FROM [book] WHERE ([id] IN (SELECT [id] FROM [book])) AND ([id] IN (SELECT [book_id] FROM [book_tag]))', ]), $sqlBuilder->buildSelectQuery()); }); @@ -60,7 +56,6 @@ test('test more Selection as one of more argument', function () use ($context) { $sqlBuilder = new SqlBuilder('book', $context); $sqlBuilder->addWhere('id ? AND id ?', $context->table('book')->where('id', 2), $context->table('book_tag')->select('book_id')); Assert::equal(reformat([ - 'mysql' => 'SELECT * FROM `book` WHERE (`id` IN (?) AND `id` IN (?))', 'SELECT * FROM [book] WHERE ([id] IN (SELECT [id] FROM [book] WHERE ([id] = ?)) AND [id] IN (SELECT [book_id] FROM [book_tag]))', ]), $sqlBuilder->buildSelectQuery()); }); @@ -82,7 +77,6 @@ test('test Selection with parameters as a parameter', function () use ($context) $sqlBuilder->addWhere('id', $context->table('book')->having('COUNT(:book_tag.tag_id) >', 1)); $schemaSupported = $context->getConnection()->getSupplementalDriver()->isSupported(ISupplementalDriver::SUPPORT_SCHEMA); Assert::equal(reformat([ - 'mysql' => 'SELECT * FROM `book` WHERE (`id` IN (?))', 'SELECT * FROM [book] WHERE ([id] IN (SELECT [id] FROM [book] LEFT JOIN ' . ($schemaSupported ? '[public].[book_tag] ' : '') . '[book_tag] ON [book].[id] = [book_tag].[book_id] HAVING COUNT([book_tag].[tag_id]) > ?))', ]), $sqlBuilder->buildSelectQuery()); Assert::count(1, $sqlBuilder->getParameters()); @@ -93,7 +87,6 @@ test('test Selection with column as a parameter', function () use ($context) { $sqlBuilder = new SqlBuilder('book', $context); $sqlBuilder->addWhere('id', $context->table('book')->select('id')); Assert::equal(reformat([ - 'mysql' => 'SELECT * FROM `book` WHERE (`id` IN (?))', 'SELECT * FROM [book] WHERE ([id] IN (SELECT [id] FROM [book]))', ]), $sqlBuilder->buildSelectQuery()); }); @@ -103,7 +96,6 @@ test('test multiple placeholder parameter', function () use ($context) { $sqlBuilder = new SqlBuilder('book', $context); $sqlBuilder->addWhere('id ? OR id ?', null, $context->table('book')); Assert::equal(reformat([ - 'mysql' => 'SELECT * FROM `book` WHERE (`id` IS NULL OR `id` IN (?))', 'SELECT * FROM [book] WHERE ([id] IS NULL OR [id] IN (SELECT [id] FROM [book]))', ]), $sqlBuilder->buildSelectQuery()); }); @@ -176,7 +168,6 @@ test('tests NOT', function () use ($context) { $sqlBuilder->addWhere('id NOT', null); $sqlBuilder->addWhere('id NOT', $context->table('book')->select('id')); Assert::equal(reformat([ - 'mysql' => 'SELECT * FROM `book` WHERE (`id` NOT IN (?)) AND (`id` IS NOT NULL) AND (`id` NOT IN (?))', 'SELECT * FROM [book] WHERE ([id] NOT IN (?)) AND ([id] IS NOT NULL) AND ([id] NOT IN (SELECT [id] FROM [book]))', ]), $sqlBuilder->buildSelectQuery()); });