Skip to content

Fix "FROM" with the specified database #80

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 10 commits into
base: 1.5
Choose a base branch
from
6 changes: 5 additions & 1 deletion src/Mouf/Database/QueryWriter/CountNbResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ public function val()
{
$sql = 'SELECT count(*) as cnt FROM ('.$this->queryResult->toSql().') tmp';

return $this->connection->fetchColumn($sql);
return $this->connection->fetchOne(
$sql,
$this->queryResult->getParametersForBind(),
$this->queryResult->getParameterTypesForBind(),
);
}
}
54 changes: 48 additions & 6 deletions src/Mouf/Database/QueryWriter/QueryResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Mouf\Database\QueryWriter;

use Doctrine\DBAL\Types\Type;
use SQLParser\SqlRenderInterface;
use function method_exists;
use Mouf\Database\QueryWriter\Utils\DbHelper;
use Mouf\Utils\Value\ValueUtils;
Expand Down Expand Up @@ -48,25 +50,49 @@ class QueryResult implements ArrayValueInterface, PaginableInterface, SortableIn
private $offset;
/** @var int|null */
private $limit;
private int $conditionsMode;
private bool $extrapolateParameters;
/**
* @var Type[]|int[]|string[]
*/
private array $parameterTypes = [];

/**
* @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;
}

/**
* The list of parameters to apply to the SQL request.
*
* @param array<string, string>|array<string, ValueInterface>|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<string, string>|array<string, ValueInterface>|ArrayValueInterface
*/
public function getParameters(): array
{
return $this->parameters;
}

/**
Expand All @@ -76,8 +102,8 @@ 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));
$sql = $this->toSql().DbHelper::getFromLimitString($this->offset, $this->limit);
$pdoStatement = $this->connection->executeQuery($sql, $this->getParametersForBind(), $this->getParameterTypesForBind());

return new ResultSet($pdoStatement);
}
Expand All @@ -91,7 +117,23 @@ 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
);
}

public function getParametersForBind(): array
{
return $this->extrapolateParameters ? [] : $this->parameters;
}

public function getParameterTypesForBind(): array
{
return $this->extrapolateParameters ? [] : array_intersect_key($this->parameterTypes, $this->parameters);
}

/**
Expand Down
18 changes: 9 additions & 9 deletions src/Mouf/Database/QueryWriter/ResultSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -12,7 +12,7 @@
*/
class ResultSet implements \Iterator
{
/** @var Statement */
/** @var Result */
private $statement;
/** @var int */
private $key = 0;
Expand All @@ -23,12 +23,12 @@ class ResultSet implements \Iterator
/** @var int */
private $rewindCalls = 0;

public function __construct(Statement $statement)
public function __construct(Result $statement)
{
$this->statement = $statement;
}

public function rewind()
public function rewind(): void
{
++$this->rewindCalls;
if ($this->rewindCalls == 2) {
Expand All @@ -39,7 +39,7 @@ public function rewind()
/**
* @return array|false
*/
public function current()
public function current(): mixed
{
if (!$this->fetched) {
$this->fetch();
Expand All @@ -51,12 +51,12 @@ public function current()
/**
* @return int
*/
public function key()
public function key(): mixed
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure that we should introduce the mixed return type as this would require to target newer PHP version. What's your opinin on this ?

{
return $this->key;
}

public function next()
public function next(): void
{
++$this->key;
$this->fetched = false;
Expand All @@ -65,11 +65,11 @@ public function next()

private function fetch(): void
{
$this->result = $this->statement->fetch(FetchMode::ASSOCIATIVE);
$this->result = $this->statement->fetchAssociative();
$this->fetched = true;
}

public function valid()
public function valid(): bool
{
if (!$this->fetched) {
$this->fetch();
Expand Down
61 changes: 28 additions & 33 deletions src/SQLParser/Node/NodeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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']);
Expand Down Expand Up @@ -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'])) {
Expand Down Expand Up @@ -908,4 +877,30 @@ 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 'STRAIGHT_JOIN':
return 'STRAIGHT_JOIN';
case ',':
return ',';
default:
throw new \Exception("Unexpected join type: '".$originalJoinType."'");
}
}
}
4 changes: 2 additions & 2 deletions tests/Mouf/Database/MagicQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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])));
Expand Down