From 3b6a58cf797f71c7b3b4693565ef1b13741d32cf Mon Sep 17 00:00:00 2001 From: Rodion Kulakov Date: Sun, 8 Aug 2021 15:54:23 +0300 Subject: [PATCH 1/8] Fix "FROM" with the specified database --- src/SQLParser/Node/NodeFactory.php | 3 --- tests/Mouf/Database/MagicQueryTest.php | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/SQLParser/Node/NodeFactory.php b/src/SQLParser/Node/NodeFactory.php index 63d8965..396452a 100644 --- a/src/SQLParser/Node/NodeFactory.php +++ b/src/SQLParser/Node/NodeFactory.php @@ -150,9 +150,6 @@ public static function toObject(array $desc) $expr->setTable($desc['table']); } - - - $expr->setTable(str_replace('`', '', $desc['table'])); switch ($desc['join_type']) { case 'CROSS': $joinType = 'CROSS JOIN'; diff --git a/tests/Mouf/Database/MagicQueryTest.php b/tests/Mouf/Database/MagicQueryTest.php index 47e2d43..c5a3fc3 100644 --- a/tests/Mouf/Database/MagicQueryTest.php +++ b/tests/Mouf/Database/MagicQueryTest.php @@ -17,8 +17,8 @@ public function testStandardSelect() $sql = "SELECT GROUP_CONCAT(id SEPARATOR ', ') AS ids FROM users"; $this->assertEquals("SELECT GROUP_CONCAT(id SEPARATOR ', ') AS ids FROM users", self::simplifySql($magicQuery->build($sql))); - $sql = 'SELECT id FROM users WHERE name LIKE :name LIMIT :offset, :limit'; - $this->assertEquals("SELECT id FROM users WHERE name LIKE 'foo'", self::simplifySql($magicQuery->build($sql, ['name' => 'foo']))); + $sql = 'SELECT id FROM mysql.users WHERE name LIKE :name LIMIT :offset, :limit'; + $this->assertEquals("SELECT id FROM mysql.users WHERE name LIKE 'foo'", self::simplifySql($magicQuery->build($sql, ['name' => 'foo']))); $sql = 'SELECT id FROM users WHERE name LIKE :name LIMIT 2, :limit'; $this->assertEquals("SELECT id FROM users WHERE name LIKE 'foo' LIMIT 2, 10", self::simplifySql($magicQuery->build($sql, ['name' => 'foo', 'limit' => 10]))); From 132ed95226477472f37cf50ab30cabfb435d6ffd Mon Sep 17 00:00:00 2001 From: Rodion Kulakov Date: Sun, 8 Aug 2021 20:23:58 +0300 Subject: [PATCH 2/8] Add conditionsMode and extrapolateParameters to QueryResult --- src/Mouf/Database/QueryWriter/QueryResult.php | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/Mouf/Database/QueryWriter/QueryResult.php b/src/Mouf/Database/QueryWriter/QueryResult.php index d0287b3..fdcaa46 100644 --- a/src/Mouf/Database/QueryWriter/QueryResult.php +++ b/src/Mouf/Database/QueryWriter/QueryResult.php @@ -2,6 +2,7 @@ namespace Mouf\Database\QueryWriter; +use SQLParser\SqlRenderInterface; use function method_exists; use Mouf\Database\QueryWriter\Utils\DbHelper; use Mouf\Utils\Value\ValueUtils; @@ -48,15 +49,25 @@ class QueryResult implements ArrayValueInterface, PaginableInterface, SortableIn private $offset; /** @var int|null */ private $limit; + private int $conditionsMode; + private bool $extrapolateParameters; /** * @param Select $select * @param Connection $connection + * @param int $conditionsMode + * @param bool $extrapolateParameters */ - public function __construct(Select $select, Connection $connection) - { + public function __construct( + Select $select, + Connection $connection, + int $conditionsMode = SqlRenderInterface::CONDITION_APPLY, + bool $extrapolateParameters = true + ) { $this->select = $select; $this->connection = $connection; + $this->conditionsMode = $conditionsMode; + $this->extrapolateParameters = $extrapolateParameters; } /** @@ -76,8 +87,7 @@ public function setParameters($parameters): void */ public function val() { - $parameters = ValueUtils::val($this->parameters); - $pdoStatement = $this->connection->query($this->select->toSql($parameters, $this->connection->getDatabasePlatform()).DbHelper::getFromLimitString($this->offset, $this->limit)); + $pdoStatement = $this->connection->query($this->toSql().DbHelper::getFromLimitString($this->offset, $this->limit)); return new ResultSet($pdoStatement); } @@ -91,7 +101,13 @@ public function toSql() { $parameters = ValueUtils::val($this->parameters); - return $this->select->toSql($parameters, $this->connection->getDatabasePlatform()); + return $this->select->toSql( + $parameters, + $this->connection->getDatabasePlatform(), + 0, + $this->conditionsMode, + $this->extrapolateParameters + ); } /** From 38596ac3072f2db6bdf389cbe8a78f04fa66bba1 Mon Sep 17 00:00:00 2001 From: Rodion Kulakov Date: Thu, 12 Aug 2021 19:42:06 +0300 Subject: [PATCH 3/8] Add parameter types to QueryResult; pass parameters to queries if extrapolation is off --- .../Database/QueryWriter/CountNbResult.php | 7 ++++- src/Mouf/Database/QueryWriter/QueryResult.php | 30 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/Mouf/Database/QueryWriter/CountNbResult.php b/src/Mouf/Database/QueryWriter/CountNbResult.php index 0de2238..34bcaec 100644 --- a/src/Mouf/Database/QueryWriter/CountNbResult.php +++ b/src/Mouf/Database/QueryWriter/CountNbResult.php @@ -50,6 +50,11 @@ public function val() { $sql = 'SELECT count(*) as cnt FROM ('.$this->queryResult->toSql().') tmp'; - return $this->connection->fetchColumn($sql); + return $this->connection->fetchColumn( + $sql, + $this->queryResult->getParametersForBind(), + 0, + $this->queryResult->getParameterTypesForBind(), + ); } } diff --git a/src/Mouf/Database/QueryWriter/QueryResult.php b/src/Mouf/Database/QueryWriter/QueryResult.php index fdcaa46..592ddbe 100644 --- a/src/Mouf/Database/QueryWriter/QueryResult.php +++ b/src/Mouf/Database/QueryWriter/QueryResult.php @@ -2,6 +2,7 @@ namespace Mouf\Database\QueryWriter; +use Doctrine\DBAL\Types\Type; use SQLParser\SqlRenderInterface; use function method_exists; use Mouf\Database\QueryWriter\Utils\DbHelper; @@ -51,6 +52,10 @@ class QueryResult implements ArrayValueInterface, PaginableInterface, SortableIn private $limit; private int $conditionsMode; private bool $extrapolateParameters; + /** + * @var Type[]|int[]|string[] + */ + private array $parameterTypes = []; /** * @param Select $select @@ -74,10 +79,20 @@ public function __construct( * The list of parameters to apply to the SQL request. * * @param array|array|ArrayValueInterface $parameters + * @param Type[]|string[]|int[] $types Parameter types */ - public function setParameters($parameters): void + public function setParameters($parameters, array $types = []): void { $this->parameters = $parameters; + $this->parameterTypes = $types; + } + + /** + * @return array|array|ArrayValueInterface + */ + public function getParameters(): array + { + return $this->parameters; } /** @@ -87,7 +102,8 @@ public function setParameters($parameters): void */ public function val() { - $pdoStatement = $this->connection->query($this->toSql().DbHelper::getFromLimitString($this->offset, $this->limit)); + $sql = $this->toSql().DbHelper::getFromLimitString($this->offset, $this->limit); + $pdoStatement = $this->connection->executeQuery($sql, $this->getParametersForBind(), $this->getParameterTypesForBind()); return new ResultSet($pdoStatement); } @@ -110,6 +126,16 @@ public function toSql() ); } + public function getParametersForBind(): array + { + return $this->extrapolateParameters ? [] : $this->parameters; + } + + public function getParameterTypesForBind(): array + { + return $this->extrapolateParameters ? [] : array_intersect_key($this->parameterTypes, $this->parameters); + } + /** * Paginates the result set. * From 45ce309b30eba4d7bd774d422111663e14224c1d Mon Sep 17 00:00:00 2001 From: Rodion Kulakov Date: Tue, 1 Feb 2022 20:54:18 +0200 Subject: [PATCH 4/8] Fix join with a subquery fixes #74 --- src/SQLParser/Node/NodeFactory.php | 59 +++++++++++++----------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/src/SQLParser/Node/NodeFactory.php b/src/SQLParser/Node/NodeFactory.php index 54df8f9..124226b 100644 --- a/src/SQLParser/Node/NodeFactory.php +++ b/src/SQLParser/Node/NodeFactory.php @@ -150,38 +150,7 @@ public static function toObject(array $desc) $expr->setTable($desc['table']); } - - - $expr->setTable(str_replace('`', '', $desc['table'])); - switch ($desc['join_type']) { - case 'CROSS': - $joinType = 'CROSS JOIN'; - break; - case 'JOIN': - $joinType = 'JOIN'; - break; - case 'LEFT': - $joinType = 'LEFT JOIN'; - break; - case 'RIGHT': - $joinType = 'RIGHT JOIN'; - break; - case 'INNER': - $joinType = 'INNER JOIN'; - break; - case 'OUTER': - $joinType = 'OUTER JOIN'; - break; - case 'NATURAL': - $joinType = 'NATURAL JOIN'; - break; - case ',': - $joinType = ','; - break; - default: - throw new \Exception("Unexpected join type: '".$desc['join_type']."'"); - } - $expr->setJoinType($joinType); + $expr->setJoinType(self::mapJoinType($desc['join_type'])); if (isset($desc['alias']['name'])) { $expr->setAlias($desc['alias']['name']); @@ -222,7 +191,7 @@ public static function toObject(array $desc) $expr->setSubQuery(self::buildFromSubtree($desc['sub_tree'])); if (isset($desc['join_type'])) { - $expr->setJoinType($desc['join_type']); + $expr->setJoinType(self::mapJoinType($desc['join_type'])); } if (isset($desc['alias']['name'])) { @@ -908,4 +877,28 @@ public static function toSql($nodes, AbstractPlatform $platform, array $paramete return $sql; } + + private static function mapJoinType(string $originalJoinType): string + { + switch ($originalJoinType) { + case 'CROSS': + return 'CROSS JOIN'; + case 'JOIN': + return 'JOIN'; + case 'LEFT': + return 'LEFT JOIN'; + case 'RIGHT': + return 'RIGHT JOIN'; + case 'INNER': + return 'INNER JOIN'; + case 'OUTER': + return 'OUTER JOIN'; + case 'NATURAL': + return 'NATURAL JOIN'; + case ',': + return ','; + default: + throw new \Exception("Unexpected join type: '".$originalJoinType."'"); + } + } } From 0abbba9f74aed2c849beabc0527b1458142451f1 Mon Sep 17 00:00:00 2001 From: Rodion Kulakov Date: Tue, 18 Oct 2022 19:27:07 +0300 Subject: [PATCH 5/8] add return type for php 8.1 compat --- src/Mouf/Database/QueryWriter/ResultSet.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mouf/Database/QueryWriter/ResultSet.php b/src/Mouf/Database/QueryWriter/ResultSet.php index 5cffdec..0a0cb28 100644 --- a/src/Mouf/Database/QueryWriter/ResultSet.php +++ b/src/Mouf/Database/QueryWriter/ResultSet.php @@ -28,7 +28,7 @@ public function __construct(Statement $statement) $this->statement = $statement; } - public function rewind() + public function rewind(): void { ++$this->rewindCalls; if ($this->rewindCalls == 2) { @@ -39,7 +39,7 @@ public function rewind() /** * @return array|false */ - public function current() + public function current(): mixed { if (!$this->fetched) { $this->fetch(); @@ -51,12 +51,12 @@ public function current() /** * @return int */ - public function key() + public function key(): mixed { return $this->key; } - public function next() + public function next(): void { ++$this->key; $this->fetched = false; @@ -69,7 +69,7 @@ private function fetch(): void $this->fetched = true; } - public function valid() + public function valid(): bool { if (!$this->fetched) { $this->fetch(); From c8fc8dcccfc1125a8586440c93827897363d8ac8 Mon Sep 17 00:00:00 2001 From: Rodion Date: Mon, 24 Jul 2023 20:54:29 -0400 Subject: [PATCH 6/8] fix deprecation --- src/Mouf/Database/QueryWriter/CountNbResult.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mouf/Database/QueryWriter/CountNbResult.php b/src/Mouf/Database/QueryWriter/CountNbResult.php index 34bcaec..e31cde6 100644 --- a/src/Mouf/Database/QueryWriter/CountNbResult.php +++ b/src/Mouf/Database/QueryWriter/CountNbResult.php @@ -50,10 +50,9 @@ public function val() { $sql = 'SELECT count(*) as cnt FROM ('.$this->queryResult->toSql().') tmp'; - return $this->connection->fetchColumn( + return $this->connection->fetchOne( $sql, $this->queryResult->getParametersForBind(), - 0, $this->queryResult->getParameterTypesForBind(), ); } From 5c0871897b004f3217a2e25497879dfaf86e69d6 Mon Sep 17 00:00:00 2001 From: Rodion Date: Mon, 24 Jul 2023 20:56:43 -0400 Subject: [PATCH 7/8] doctrine v3 support --- src/Mouf/Database/QueryWriter/ResultSet.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mouf/Database/QueryWriter/ResultSet.php b/src/Mouf/Database/QueryWriter/ResultSet.php index 0a0cb28..d22f514 100644 --- a/src/Mouf/Database/QueryWriter/ResultSet.php +++ b/src/Mouf/Database/QueryWriter/ResultSet.php @@ -3,7 +3,7 @@ namespace Mouf\Database\QueryWriter; use Doctrine\DBAL\FetchMode; -use Doctrine\DBAL\Driver\Statement; +use Doctrine\DBAL\Result; /** * Wraps the results of a PDOStatement. @@ -12,7 +12,7 @@ */ class ResultSet implements \Iterator { - /** @var Statement */ + /** @var Result */ private $statement; /** @var int */ private $key = 0; @@ -23,7 +23,7 @@ class ResultSet implements \Iterator /** @var int */ private $rewindCalls = 0; - public function __construct(Statement $statement) + public function __construct(Result $statement) { $this->statement = $statement; } @@ -65,7 +65,7 @@ public function next(): void private function fetch(): void { - $this->result = $this->statement->fetch(FetchMode::ASSOCIATIVE); + $this->result = $this->statement->fetchAssociative(); $this->fetched = true; } From 2355589bbb2fad88c81e722cf6569ccd202a74b4 Mon Sep 17 00:00:00 2001 From: Rodion Kulakov Date: Thu, 28 Sep 2023 20:51:40 -0400 Subject: [PATCH 8/8] add STRAIGHT_JOIN support --- src/SQLParser/Node/NodeFactory.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/SQLParser/Node/NodeFactory.php b/src/SQLParser/Node/NodeFactory.php index 124226b..c7c4aff 100644 --- a/src/SQLParser/Node/NodeFactory.php +++ b/src/SQLParser/Node/NodeFactory.php @@ -895,6 +895,8 @@ private static function mapJoinType(string $originalJoinType): string return 'OUTER JOIN'; case 'NATURAL': return 'NATURAL JOIN'; + case 'STRAIGHT_JOIN': + return 'STRAIGHT_JOIN'; case ',': return ','; default: