From 38d9d65c3cb70beea34a0edee0b439e395642b8e Mon Sep 17 00:00:00 2001 From: Jan Skrasek Date: Fri, 23 Apr 2021 22:25:06 +0200 Subject: [PATCH] switch to nextras/multi-query-parser [closes #59] --- composer.json | 4 + src/Bridges/NetteCaching/CachedPlatform.php | 7 ++ src/Platforms/IPlatform.php | 8 ++ src/Platforms/MySqlPlatform.php | 11 +++ src/Platforms/PostgreSqlPlatform.php | 11 +++ src/Platforms/SqlServerPlatform.php | 11 +++ src/Utils/FileImporter.php | 88 --------------------- tests/inc/IntegrationTestCase.php | 16 ++-- tests/inc/setup.php | 12 ++- 9 files changed, 70 insertions(+), 98 deletions(-) delete mode 100644 src/Utils/FileImporter.php diff --git a/composer.json b/composer.json index ba2d3924..0b06647e 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "nette/utils": "~3.0", "nette/finder": "~2.5", "nette/neon": "~3.0", + "nextras/multi-query-parser": "dev-main", "phpstan/extension-installer": "1.2.0", "phpstan/phpstan": "1.10.10", "phpstan/phpstan-deprecation-rules": "1.1.3", @@ -32,6 +33,9 @@ "symfony/http-kernel": "~4.4 || ~5.0", "tracy/tracy": "~2.7" }, + "suggest": { + "nextras/multi-query-parser": "Install this to support SQL file import." + }, "autoload": { "psr-4": { "Nextras\\Dbal\\": "src/" } }, diff --git a/src/Bridges/NetteCaching/CachedPlatform.php b/src/Bridges/NetteCaching/CachedPlatform.php index f689a35f..f39a9c5b 100644 --- a/src/Bridges/NetteCaching/CachedPlatform.php +++ b/src/Bridges/NetteCaching/CachedPlatform.php @@ -7,6 +7,7 @@ use DateTimeInterface; use Nette\Caching\Cache; use Nextras\Dbal\Platforms\IPlatform; +use Nextras\MultiQueryParser\IMultiQueryParser; class CachedPlatform implements IPlatform @@ -124,6 +125,12 @@ public function formatLimitOffset(?int $limit, ?int $offset): string } + public function createMultiQueryParser(): IMultiQueryParser + { + return $this->platform->createMultiQueryParser(); + } + + public function isSupported(int $feature): bool { return $this->platform->isSupported($feature); diff --git a/src/Platforms/IPlatform.php b/src/Platforms/IPlatform.php index 2261ff3a..2d5c7f24 100644 --- a/src/Platforms/IPlatform.php +++ b/src/Platforms/IPlatform.php @@ -8,6 +8,7 @@ use Nextras\Dbal\Platforms\Data\Column; use Nextras\Dbal\Platforms\Data\ForeignKey; use Nextras\Dbal\Platforms\Data\Table; +use Nextras\MultiQueryParser\IMultiQueryParser; interface IPlatform @@ -117,6 +118,13 @@ public function formatBlob(string $value): string; public function formatLimitOffset(?int $limit, ?int $offset): string; + /** + * Returns SQL file parser + * !!!This function requires nextras/multi-query-parser dependency!!! + */ + public function createMultiQueryParser(): IMultiQueryParser; + + /** * Checks whether any feature from IPlatform::SUPPORT_* is supported. * @internal diff --git a/src/Platforms/MySqlPlatform.php b/src/Platforms/MySqlPlatform.php index a9cead89..277adc63 100644 --- a/src/Platforms/MySqlPlatform.php +++ b/src/Platforms/MySqlPlatform.php @@ -15,6 +15,8 @@ use Nextras\Dbal\Utils\DateTimeHelper; use Nextras\Dbal\Utils\JsonHelper; use Nextras\Dbal\Utils\StrictObjectTrait; +use Nextras\MultiQueryParser\IMultiQueryParser; +use Nextras\MultiQueryParser\MySqlMultiQueryParser; use function addcslashes; use function explode; use function str_replace; @@ -220,6 +222,15 @@ public function formatLimitOffset(?int $limit, ?int $offset): string } + public function createMultiQueryParser(): IMultiQueryParser + { + if (!class_exists(MySqlMultiQueryParser::class)) { + throw new \RuntimeException("Missing nextras/multi-query-parser dependency. Install it first to use IPlatform::createMultiQueryParser()."); + } + return new MySqlMultiQueryParser(); + } + + public function isSupported(int $feature): bool { static $supported = [ diff --git a/src/Platforms/PostgreSqlPlatform.php b/src/Platforms/PostgreSqlPlatform.php index 94559ccc..7a16dbe0 100644 --- a/src/Platforms/PostgreSqlPlatform.php +++ b/src/Platforms/PostgreSqlPlatform.php @@ -14,6 +14,8 @@ use Nextras\Dbal\Utils\DateTimeHelper; use Nextras\Dbal\Utils\JsonHelper; use Nextras\Dbal\Utils\StrictObjectTrait; +use Nextras\MultiQueryParser\IMultiQueryParser; +use Nextras\MultiQueryParser\PostgreSqlMultiQueryParser; use function bin2hex; use function str_replace; use function strtr; @@ -255,6 +257,15 @@ public function formatLimitOffset(?int $limit, ?int $offset): string } + public function createMultiQueryParser(): IMultiQueryParser + { + if (!class_exists(PostgreSqlMultiQueryParser::class)) { + throw new \RuntimeException("Missing nextras/multi-query-parser dependency. Install it first to use IPlatform::createMultiQueryParser()."); + } + return new PostgreSqlMultiQueryParser(); + } + + public function isSupported(int $feature): bool { static $supported = [ diff --git a/src/Platforms/SqlServerPlatform.php b/src/Platforms/SqlServerPlatform.php index dc0bc6ba..7389c598 100644 --- a/src/Platforms/SqlServerPlatform.php +++ b/src/Platforms/SqlServerPlatform.php @@ -14,6 +14,8 @@ use Nextras\Dbal\Platforms\Data\Table; use Nextras\Dbal\Utils\JsonHelper; use Nextras\Dbal\Utils\StrictObjectTrait; +use Nextras\MultiQueryParser\IMultiQueryParser; +use Nextras\MultiQueryParser\SqlServerMultiQueryParser; class SqlServerPlatform implements IPlatform @@ -244,6 +246,15 @@ public function formatLimitOffset(?int $limit, ?int $offset): string } + public function createMultiQueryParser(): IMultiQueryParser + { + if (!class_exists(SqlServerMultiQueryParser::class)) { + throw new \RuntimeException("Missing nextras/multi-query-parser dependency. Install it first to use IPlatform::createMultiQueryParser()."); + } + return new SqlServerMultiQueryParser(); + } + + public function isSupported(int $feature): bool { static $supported = [ diff --git a/src/Utils/FileImporter.php b/src/Utils/FileImporter.php deleted file mode 100644 index d5cab75f..00000000 --- a/src/Utils/FileImporter.php +++ /dev/null @@ -1,88 +0,0 @@ -getPlatform()->getName(); - if ($platformName === MySqlPlatform::NAME) { - $parse = '[\'"]|/\*|-- |$'; - } elseif ($platformName === PostgreSqlPlatform::NAME) { - $parse = '[\'"]|/\*|-- |$|\$[^$]*\$'; - } elseif ($platformName === SqlServerPlatform::NAME) { - $parse = '[\'"[]|/\*|-- |$'; - } else { // general - $parse = '[\'"`#]|/\*|-- |$'; - } - - while ($query !== '') { - if ($offset === 0 && preg_match("~^{$space}*DELIMITER\\s+(\\S+)~i", $query, $match) === 1) { - $delimiter = $match[1]; - $query = substr($query, strlen($match[0])); - - } else { - preg_match('(' . preg_quote($delimiter) . "\\s*|$parse)", $query, $match, PREG_OFFSET_CAPTURE, $offset); // should always match - $found = $match[0][0]; - $offset = $match[0][1] + strlen($found); - - if (strlen($found) === 0 && rtrim($query) === '') { - break; - } - - if (strlen($found) === 0 || rtrim($found) === $delimiter) { // end of a query - $q = substr($query, 0, $match[0][1]); - - $queries++; - $connection->query('%raw', $q); - - $query = substr($query, $offset); - /** @var int $offset */ - $offset = 0; - - } else { // find matching quote or comment end - while (preg_match('(' . ($found === '/*' ? '\*/' : ($found === '[' ? ']' : (preg_match('~^-- |^#~', $found) === 1 ? "\n" : preg_quote($found) . "|\\\\."))) . '|$)s', $query, $match, PREG_OFFSET_CAPTURE, $offset) === 1) { //! respect sql_mode NO_BACKSLASH_ESCAPES - $s = $match[0][0]; - $offset = $match[0][1] + strlen($s); - if ($s[0] !== '\\') { - break; - } - } - } - } - } - - return $queries; - } -} diff --git a/tests/inc/IntegrationTestCase.php b/tests/inc/IntegrationTestCase.php index a08c9e0a..339c9ef8 100644 --- a/tests/inc/IntegrationTestCase.php +++ b/tests/inc/IntegrationTestCase.php @@ -2,9 +2,9 @@ namespace NextrasTests\Dbal; + use Nextras\Dbal\Connection; use Nextras\Dbal\Exception\InvalidArgumentException; -use Nextras\Dbal\Utils\FileImporter; use Tester\Environment; @@ -20,8 +20,12 @@ class IntegrationTestCase extends TestCase public function initData(Connection $connection) { $this->lockConnection($connection); - $platform = $connection->getPlatform()->getName(); - FileImporter::executeFile($connection, __DIR__ . "/../data/$platform-data.sql"); + $platform = $connection->getPlatform(); + $platformName = $platform->getName(); + $parser = $platform->createMultiQueryParser(); + foreach ($parser->parseFile(__DIR__ . "/../data/$platformName-data.sql") as $sql) { + $connection->query('%raw', $sql); + } } @@ -35,8 +39,8 @@ protected function lockConnection(Connection $connection) protected function createConnection($params = []) { $options = array_merge([ - 'user' => NULL, - 'password' => NULL, + 'user' => null, + 'password' => null, 'searchPath' => ['public'], ], Environment::loadData(), $params); return new Connection($options); @@ -46,7 +50,7 @@ protected function createConnection($params = []) public function __get($name) { if ($name === 'connection') { - if ($this->defaultConnection === NULL) { + if ($this->defaultConnection === null) { $this->defaultConnection = $this->createConnection(); } return $this->defaultConnection; diff --git a/tests/inc/setup.php b/tests/inc/setup.php index 944257ea..d6d75e7e 100644 --- a/tests/inc/setup.php +++ b/tests/inc/setup.php @@ -1,7 +1,7 @@ getPlatform()->getName(); - $resetFunction = require __DIR__ . "/../data/{$platform}-reset.php"; + $platform = $connection->getPlatform(); + $platformName = $platform->getName(); + $resetFunction = require __DIR__ . "/../data/{$platformName}-reset.php"; $resetFunction($connection, $configDatabase); - FileImporter::executeFile($connection, __DIR__ . "/../data/{$platform}-init.sql"); + $parser = $platform->createMultiQueryParser(); + foreach ($parser->parseFile(__DIR__ . "/../data/{$platformName}-init.sql") as $sql) { + $connection->query('%raw', $sql); + } } echo "[setup] All done.\n\n";