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; | |
| } | |
| } |