Commit 78b6181b by Scott

Simplify handling of IN/VALUES queries

parent b0cd6dfb
...@@ -172,7 +172,7 @@ class DbConnection ...@@ -172,7 +172,7 @@ class DbConnection
* @param array $params * @param array $params
* @return DbResult * @return DbResult
*/ */
public function query($query, $params = array()) public function query($query, $params = [])
{ {
if (!$this->isConnected()) { if (!$this->isConnected()) {
$this->connect(); $this->connect();
...@@ -182,9 +182,7 @@ class DbConnection ...@@ -182,9 +182,7 @@ class DbConnection
// handle old-style placeholders // handle old-style placeholders
$query = str_replace(['#', '$'], '?', $query); $query = str_replace(['#', '$'], '?', $query);
// handle IN queries // handle IN queries
$query = $this->applyArraySub($query, $params); list($query, $params) = $this->expandQueryParameters($query, $params);
$params = $this->flattenArray($params);
if (substr_count($query, '?') != count($params)) { if (substr_count($query, '?') != count($params)) {
throw new SelectSpecException('The number of parameters and placeholders do not match'); throw new SelectSpecException('The number of parameters and placeholders do not match');
...@@ -549,75 +547,64 @@ class DbConnection ...@@ -549,75 +547,64 @@ class DbConnection
} }
/** /**
* Substitute single '?' in a SQL query with multiple '?' for array parameters. * Substitute single '?' in a SQL query with multiple '?' for array parameters, and flatten parameter list accordingly.
* @param string $query * @param string $query
* @param array $params * @param array $params
* @return string * @return array Query and flattened parameter list
* @throws SelectSpecException * @throws SelectSpecException
*/ */
public function applyArraySub($query, $params) public function expandQueryParameters($query, array $params = [])
{ {
$result = ''; $numParams = count($params);
$hasArray = false; $explodedQuery = explode('?', $query);
$paramInfo = array();
foreach ($params as $param) {
if (is_array($param)) {
// If the first subparam is an array, the rest of the parameter groups should have the same
// amount of elements. E.G.: the output should be '(?, ?), (?, ?)' rather than '(?), (?, ?)'
$subArrayCount = isset($param[0]) && is_array($param[0]) ? count($param[0]) : 0;
$paramInfo[] = array(
'count' => count($param),
'sub_array_count' => $subArrayCount,
);
if ($subArrayCount > 0) { if ($numParams !== count($explodedQuery) - 1) {
foreach ($param as $subParam) { throw new SelectSpecException('The number of parameters and placeholders do not match');
$subParamCount = count($subParam);
if ($subParamCount != $subArrayCount) {
throw new SelectSpecException('All parameter groups must have the same amount of parameters');
}
} }
if (empty($params)) {
return [$query, $params];
} }
$hasArray = true; $outQuery = '';
} else { $outParams = [];
$paramInfo[] = array( // use array_values to ensure consistent indexing
'count' => 1, foreach (array_values($params) as $i => $param) {
'sub_array_count' => 0, $outQuery .= $explodedQuery[$i];
); if (is_array($param)) {
} $subArray = array_values($param);
}
if (!$hasArray) { if (is_array($subArray[0])) {
return $query; // INSERT..VALUES query for inserting multiple rows
$subArrayCount = count($subArray[0]);
foreach ($subArray as $subArrayParam) {
// If the first subparam is an array, the rest of the parameter groups should have the same
// amount of elements, i.e. the output should be '(?, ?), (?, ?)' rather than '(?), (?, ?)'
if (!is_array($subArrayParam) || count($subArrayParam) !== $subArrayCount) {
throw new SelectSpecException('All parameter groups must have the same amount of parameters');
} }
$explodedQuery = explode('?', $query); $outParams = array_merge($outParams, $subArrayParam);
foreach ($explodedQuery as $index => $explodedQueryPart) {
$result .= $explodedQueryPart;
// Ignore the last part of the $explodedQueryPart
if (!isset($paramInfo[$index])) {
continue;
} }
// If the parameter is not an array with sub arrays $outQuery .= $this->repeatStringWithSeparators(
if ($paramInfo[$index]['sub_array_count'] == 0) { '(' . $this->repeatStringWithSeparators('?', $subArrayCount) . ')',
// Turn this SQL 'IN (?)' into 'IN (?, ?, ?)' for arrays with no sub arrays count($subArray)
$result .= $this->repeatStringWithSeparators('?', $paramInfo[$index]['count']);
} else {
// Turn this SQL 'IN ?' into 'IN (?, ?), (?, ?)' for arrays with sub arrays
$result .=
$this->repeatStringWithSeparators(
'(' . $this->repeatStringWithSeparators('?', $paramInfo[$index]['sub_array_count']) . ')',
$paramInfo[$index]['count']
); );
} else {
// WHERE..IN query
$outQuery .= $this->repeatStringWithSeparators('?', count($subArray));
$outParams = array_merge($outParams, $subArray);
}
} else {
// standard query
$outQuery .= '?';
$outParams[] = $param;
} }
} }
return $result; $outQuery .= $explodedQuery[$numParams];
return [$outQuery, $outParams];
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment