Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 2 |
CRAP | |
65.22% |
30 / 46 |
Statement | |
0.00% |
0 / 1 |
|
0.00% |
0 / 2 |
45.26 | |
65.22% |
30 / 46 |
getStatement | |
0.00% |
0 / 1 |
12.37 | |
86.36% |
19 / 22 |
|||
execute | |
0.00% |
0 / 1 |
30.23 | |
45.83% |
11 / 24 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\Core\Database\Driver\sqlite\Statement. | |
*/ | |
namespace Drupal\Core\Database\Driver\sqlite; | |
use Drupal\Core\Database\StatementPrefetch; | |
use Drupal\Core\Database\StatementInterface; | |
/** | |
* SQLite implementation of \Drupal\Core\Database\Statement. | |
* | |
* The PDO SQLite driver only closes SELECT statements when the PDOStatement | |
* destructor is called and SQLite does not allow data change (INSERT, | |
* UPDATE etc) on a table which has open SELECT statements. This is a | |
* user-space mock of PDOStatement that buffers all the data and doesn't | |
* have those limitations. | |
*/ | |
class Statement extends StatementPrefetch implements StatementInterface { | |
/** | |
* {@inheritdoc} | |
* | |
* The PDO SQLite layer doesn't replace numeric placeholders in queries | |
* correctly, and this makes numeric expressions (such as COUNT(*) >= :count) | |
* fail. We replace numeric placeholders in the query ourselves to work | |
* around this bug. | |
* | |
* See http://bugs.php.net/bug.php?id=45259 for more details. | |
*/ | |
protected function getStatement($query, &$args = array()) { | |
if (count($args)) { | |
// Check if $args is a simple numeric array. | |
if (range(0, count($args) - 1) === array_keys($args)) { | |
// In that case, we have unnamed placeholders. | |
$count = 0; | |
$new_args = array(); | |
foreach ($args as $value) { | |
if (is_float($value) || is_int($value)) { | |
if (is_float($value)) { | |
// Force the conversion to float so as not to loose precision | |
// in the automatic cast. | |
$value = sprintf('%F', $value); | |
} | |
$query = substr_replace($query, $value, strpos($query, '?'), 1); | |
} | |
else { | |
$placeholder = ':db_statement_placeholder_' . $count++; | |
$query = substr_replace($query, $placeholder, strpos($query, '?'), 1); | |
$new_args[$placeholder] = $value; | |
} | |
} | |
$args = $new_args; | |
} | |
else { | |
// Else, this is using named placeholders. | |
foreach ($args as $placeholder => $value) { | |
if (is_float($value) || is_int($value)) { | |
if (is_float($value)) { | |
// Force the conversion to float so as not to loose precision | |
// in the automatic cast. | |
$value = sprintf('%F', $value); | |
} | |
// We will remove this placeholder from the query as PDO throws an | |
// exception if the number of placeholders in the query and the | |
// arguments does not match. | |
unset($args[$placeholder]); | |
// PDO allows placeholders to not be prefixed by a colon. See | |
// http://marc.info/?l=php-internals&m=111234321827149&w=2 for | |
// more. | |
if ($placeholder[0] != ':') { | |
$placeholder = ":$placeholder"; | |
} | |
// When replacing the placeholders, make sure we search for the | |
// exact placeholder. For example, if searching for | |
// ':db_placeholder_1', do not replace ':db_placeholder_11'. | |
$query = preg_replace('/' . preg_quote($placeholder) . '\b/', $value, $query); | |
} | |
} | |
} | |
} | |
return $this->pdoConnection->prepare($query); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function execute($args = array(), $options = array()) { | |
try { | |
$return = parent::execute($args, $options); | |
} | |
catch (\PDOException $e) { | |
if (!empty($e->errorInfo[1]) && $e->errorInfo[1] === 17) { | |
// The schema has changed. SQLite specifies that we must resend the query. | |
$return = parent::execute($args, $options); | |
} | |
else { | |
// Rethrow the exception. | |
throw $e; | |
} | |
} | |
// In some weird cases, SQLite will prefix some column names by the name | |
// of the table. We post-process the data, by renaming the column names | |
// using the same convention as MySQL and PostgreSQL. | |
$rename_columns = array(); | |
foreach ($this->columnNames as $k => $column) { | |
// In some SQLite versions, SELECT DISTINCT(field) will return "(field)" | |
// instead of "field". | |
if (preg_match("/^\((.*)\)$/", $column, $matches)) { | |
$rename_columns[$column] = $matches[1]; | |
$this->columnNames[$k] = $matches[1]; | |
$column = $matches[1]; | |
} | |
// Remove "table." prefixes. | |
if (preg_match("/^.*\.(.*)$/", $column, $matches)) { | |
$rename_columns[$column] = $matches[1]; | |
$this->columnNames[$k] = $matches[1]; | |
} | |
} | |
if ($rename_columns) { | |
// DatabaseStatementPrefetch already extracted the first row, | |
// put it back into the result set. | |
if (isset($this->currentRow)) { | |
$this->data[0] = &$this->currentRow; | |
} | |
// Then rename all the columns across the result set. | |
foreach ($this->data as $k => $row) { | |
foreach ($rename_columns as $old_column => $new_column) { | |
$this->data[$k][$new_column] = $this->data[$k][$old_column]; | |
unset($this->data[$k][$old_column]); | |
} | |
} | |
// Finally, extract the first row again. | |
$this->currentRow = $this->data[0]; | |
unset($this->data[0]); | |
} | |
return $return; | |
} | |
} |