Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Corrected handling of list parameters with sparse types #2900

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion lib/Doctrine/DBAL/SQLParserUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ public static function expandListParameters($query, $params, $types)

if ($isPositional) {
ksort($params);
$types = self::fillMissingPositionalTypes($params, $types);
ksort($types);
} else {
$types = self::fillMissingNamedTypes($params, $types);
}

foreach ($types as $name => $type) {
Expand All @@ -109,7 +112,7 @@ public static function expandListParameters($query, $params, $types)
$arrayPositions[$name] = false;
}

if (( ! $arrayPositions && $isPositional)) {
if (empty($arrayPositions) && $isPositional) {
return [$query, $params, $types];
}

Expand Down Expand Up @@ -240,4 +243,51 @@ private static function extractParam($paramName, $paramsOrTypes, $isParam, $defa

throw SQLParserUtilsException::missingType($paramName);
}

/**
* @param array $params
* @param array $types
* @return array
*/
private static function fillMissingPositionalTypes($params, $types)
{
if (count($types) === 0 || count($params) === count($types)) {
return $types;
}

foreach ($params as $paramKey => $param) {
if (!isset($types[$paramKey])) {
$types[$paramKey] = null;
}
}

return $types;
}

/**
* @param array $params
* @param array $types
* @return array
*/
private static function fillMissingNamedTypes($params, $types)
{
if (count($types) === 0 || count($params) === count($types)) {
return $types;
}

$normalizer = function ($key) {
return $key[0] === ':' ? substr($key, 1) : $key;
};

$normalizedParamsKeys = array_map($normalizer, array_keys($params));
$normalizedTypesKeys = array_map($normalizer, array_keys($types));

foreach ($normalizedParamsKeys as $paramKey) {
if (!in_array($paramKey, $normalizedTypesKeys, true)) {
$types[$paramKey] = null;
}
}

return $types;
}
}
30 changes: 23 additions & 7 deletions tests/Doctrine/Tests/DBAL/SQLParserUtilsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public function dataExpandListParameters()
array(2 => \PDO::PARAM_STR, 1 => \PDO::PARAM_STR),
'SELECT * FROM Foo WHERE foo = ? AND bar = ? AND baz = ?',
array(1 => 'bar', 0 => 1, 2 => 'baz'),
array(1 => \PDO::PARAM_STR, 2 => \PDO::PARAM_STR)
array(0 => null, 1 => \PDO::PARAM_STR, 2 => \PDO::PARAM_STR)
),
// Positional: explicit keys for array params and array types
array(
Expand All @@ -169,6 +169,15 @@ public function dataExpandListParameters()
array(1, 2, 3, 'bar1', 'bar2', true),
array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_STR, \PDO::PARAM_STR, \PDO::PARAM_BOOL)
),
// Positional: non-explicit keys for array params and explicit keys for array types
array(
"SELECT * FROM Foo WHERE ? IN (?)",
array('foo', array('foo', 'bar')),
array(1 => Connection::PARAM_STR_ARRAY),
"SELECT * FROM Foo WHERE ? IN (?, ?)",
array('foo', 'foo', 'bar'),
array(null, \PDO::PARAM_STR, \PDO::PARAM_STR)
),
// Positional starts from 1: One non-list before and one after list-needle
array(
"SELECT * FROM Foo WHERE foo = ? AND bar IN (?) AND baz = ? AND foo IN (?)",
Expand All @@ -187,7 +196,6 @@ public function dataExpandListParameters()
array(1),
array(\PDO::PARAM_INT)
),

// Named parameters : Very simple with param int and string
array(
"SELECT * FROM Foo WHERE foo = :foo AND bar = :bar",
Expand Down Expand Up @@ -294,15 +302,15 @@ public function dataExpandListParameters()
array('foo' => Connection::PARAM_INT_ARRAY, 'baz' => 'string'),
'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ? OR baz = ?',
array(1, 2, 'bar', 'baz'),
array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_STR, 'string')
array(\PDO::PARAM_INT, \PDO::PARAM_INT, null, 'string')
),
array(
"SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar",
array('foo' => array(1, 2), 'bar' => 'bar'),
array('foo' => Connection::PARAM_INT_ARRAY),
'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?',
array(1, 2, 'bar'),
array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_STR)
array(\PDO::PARAM_INT, \PDO::PARAM_INT, null)
),
// Params/types with colons
array(
Expand All @@ -311,7 +319,7 @@ public function dataExpandListParameters()
array(':foo' => \PDO::PARAM_INT),
'SELECT * FROM Foo WHERE foo = ? OR bar = ?',
array('foo', 'bar'),
array(\PDO::PARAM_INT, \PDO::PARAM_STR)
array(\PDO::PARAM_INT, null)
),
array(
"SELECT * FROM Foo WHERE foo = :foo OR bar = :bar",
Expand All @@ -327,15 +335,23 @@ public function dataExpandListParameters()
array('foo' => Connection::PARAM_INT_ARRAY),
'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?',
array(1, 2, 'bar'),
array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_STR)
array(\PDO::PARAM_INT, \PDO::PARAM_INT, null)
),
array(
"SELECT * FROM Foo WHERE foo IN (:foo) OR bar = :bar",
array('foo' => array(1, 2), 'bar' => 'bar'),
array(':foo' => Connection::PARAM_INT_ARRAY),
'SELECT * FROM Foo WHERE foo IN (?, ?) OR bar = ?',
array(1, 2, 'bar'),
array(\PDO::PARAM_INT, \PDO::PARAM_INT, \PDO::PARAM_STR)
array(\PDO::PARAM_INT, \PDO::PARAM_INT, null)
),
array(
"SELECT * FROM Foo WHERE :foo IN (:bar)",
array('foo' => 1, 'bar' => array(1, 2)),
array('bar' => Connection::PARAM_INT_ARRAY),
"SELECT * FROM Foo WHERE ? IN (?, ?)",
array(1, 1, 2),
array(null, \PDO::PARAM_INT, \PDO::PARAM_INT)
),
// DBAL-522 - null valued parameters are not considered
array(
Expand Down