Unverified Commit fe62af54 by Scott Committed by GitHub

Merge pull request #737 from pupi1985/patch-128

 Add support to 'INSERT INTO ... VALUES $' queries
parents 1971c3e1 006e3a11
...@@ -21,7 +21,6 @@ namespace Q2A\Database; ...@@ -21,7 +21,6 @@ namespace Q2A\Database;
use PDO; use PDO;
use PDOException; use PDOException;
use PDOStatement; use PDOStatement;
use Q2A\Database\DbResult;
use Q2A\Database\Exceptions\SelectSpecException; use Q2A\Database\Exceptions\SelectSpecException;
class DbConnection class DbConnection
...@@ -184,8 +183,13 @@ class DbConnection ...@@ -184,8 +183,13 @@ class DbConnection
$query = str_replace(['#', '$'], '?', $query); $query = str_replace(['#', '$'], '?', $query);
// handle IN queries // handle IN queries
$query = $this->applyArraySub($query, $params); $query = $this->applyArraySub($query, $params);
$params = $this->flattenArray($params); $params = $this->flattenArray($params);
if (substr_count($query, '?') != count($params)) {
throw new SelectSpecException('The number of parameters and placeholders do not match');
}
try { try {
if (QA_DEBUG_PERFORMANCE) { if (QA_DEBUG_PERFORMANCE) {
global $qa_usage; global $qa_usage;
...@@ -550,34 +554,78 @@ class DbConnection ...@@ -550,34 +554,78 @@ class DbConnection
{ {
$result = ''; $result = '';
$hasArray = false; $hasArray = false;
$paramIndexCount = array(); $paramInfo = array();
foreach ($params as $param) { foreach ($params as $param) {
if (is_array($param)) { if (is_array($param)) {
$paramIndexCount[] = count($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 = is_array($param[0]) ? count($param[0]) : 0;
$paramInfo[] = array(
'count' => count($param),
'sub_array_count' => $subArrayCount,
);
if ($subArrayCount > 0) {
foreach ($param as $subParam) {
$subParamCount = count($subParam);
if ($subParamCount != $subArrayCount) {
throw new SelectSpecException('All parameter groups must have the same amount of parameters');
}
}
}
$hasArray = true; $hasArray = true;
} else { } else {
$paramIndexCount[] = 1; $paramInfo[] = array(
'count' => 1,
'sub_array_count' => 0,
);
} }
} }
if ($hasArray) { if (!$hasArray) {
$explodedQuery = explode('?', $query); return $query;
if (count($explodedQuery) != count($paramIndexCount) + 1) { }
throw new SelectSpecException('The number of parameters and placeholders do not match');
$explodedQuery = explode('?', $query);
foreach ($explodedQuery as $index => $explodedQueryPart) {
$result .= $explodedQueryPart;
// Ignore the last part of the $explodedQueryPart
if (!isset($paramInfo[$index])) {
continue;
} }
foreach ($explodedQuery as $index => $explodedQueryPart) {
$result .= $explodedQueryPart; // If the parameter is not an array with sub arrays
if (isset($paramIndexCount[$index])) { if ($paramInfo[$index]['sub_array_count'] == 0) {
$result .= $paramIndexCount[$index] == 1 // Turn this SQL 'IN (?)' into 'IN (?, ?, ?)' for arrays with no sub arrays
? '?' $result .= $this->repeatStringWithSeparators('?', $paramInfo[$index]['count']);
: str_repeat('?,', $paramIndexCount[$index] - 1) . '?'; } 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']
);
} }
return $result;
} }
return $query; return $result;
}
/**
* Repeat a string a given amount of times separating each of the instances with ', '.
* @param string $string
* @param int $amount
* @return string
*/
private function repeatStringWithSeparators($string, $amount)
{
return $amount == 1
? $string
: str_repeat($string . ', ', $amount - 1) . $string;
} }
/** /**
...@@ -609,7 +657,7 @@ class DbConnection ...@@ -609,7 +657,7 @@ class DbConnection
} }
/** /**
* Flatten a two-level array into a one-level array. * Flatten a two-level or three-level array into a one-level array.
* @param mixed $elements Input elements which can be one-level deep arrays * @param mixed $elements Input elements which can be one-level deep arrays
* @return array * @return array
*/ */
...@@ -618,7 +666,7 @@ class DbConnection ...@@ -618,7 +666,7 @@ class DbConnection
$result = array(); $result = array();
foreach ($elements as $element) { foreach ($elements as $element) {
if (is_array($element)) { if (is_array($element)) {
$result = array_merge($result, $element); $result = array_merge($result, $this->flattenArray($element));
} else { } else {
$result[] = $element; $result[] = $element;
} }
......
<?php
use Q2A\Database\DbConnection;
class DbConnectionTest extends PHPUnit_Framework_TestCase
{
/** @var DbConnection */
private $dbConnection;
protected function setUp()
{
$this->dbConnection = new DbConnection();
}
public function test__applyArraySub_success()
{
$result = $this->dbConnection->applyArraySub('SELECT * FROM table WHERE field = 1', array());
$this->assertSame('SELECT * FROM table WHERE field = 1', $result);
$result = $this->dbConnection->applyArraySub('SELECT * FROM table WHERE field = ?', array(1));
$this->assertSame('SELECT * FROM table WHERE field = ?', $result);
$result = $this->dbConnection->applyArraySub('SELECT * FROM table WHERE field IN (?)', array(array(1)));
$this->assertSame('SELECT * FROM table WHERE field IN (?)', $result);
$result = $this->dbConnection->applyArraySub('SELECT * FROM table WHERE field IN (?)', array(array(1, 2)));
$this->assertSame('SELECT * FROM table WHERE field IN (?, ?)', $result);
$result = $this->dbConnection->applyArraySub('INSERT INTO table(field) VALUES ?', array(array(array(1))));
$this->assertSame('INSERT INTO table(field) VALUES (?)', $result);
$result = $this->dbConnection->applyArraySub('INSERT INTO table(field) VALUES ?', array(array(array(1), array(2))));
$this->assertSame('INSERT INTO table(field) VALUES (?), (?)', $result);
$result = $this->dbConnection->applyArraySub('INSERT INTO table(field1, field2) VALUES ?', array(array(array(1, 2))));
$this->assertSame('INSERT INTO table(field1, field2) VALUES (?, ?)', $result);
$result = $this->dbConnection->applyArraySub('INSERT INTO table(field1, field2) VALUES ?', array(array(array(1, 2), array(3, 4))));
$this->assertSame('INSERT INTO table(field1, field2) VALUES (?, ?), (?, ?)', $result);
}
public function test__applyArraySub_parameter_groups_with_different_element_count_error()
{
$this->setExpectedException('Q2A\Database\Exceptions\SelectSpecException');
$this->dbConnection->applyArraySub('INSERT INTO table(field1, field2) VALUES ?', array(array(array(1, 2), array(3))));
}
}
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