class Statement in Drupal 9
Same name in this branch
- 9 core/lib/Drupal/Core/Database/Statement.php \Drupal\Core\Database\Statement
- 9 core/lib/Drupal/Core/Database/Driver/sqlite/Statement.php \Drupal\Core\Database\Driver\sqlite\Statement
Same name and namespace in other branches
- 8 core/lib/Drupal/Core/Database/Driver/sqlite/Statement.php \Drupal\Core\Database\Driver\sqlite\Statement
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.
Hierarchy
- class \Drupal\Core\Database\StatementPrefetch implements \Drupal\Core\Database\Iterator, StatementInterface
- class \Drupal\Core\Database\Driver\sqlite\Statement implements StatementInterface
Expanded class hierarchy of Statement
File
- core/
lib/ Drupal/ Core/ Database/ Driver/ sqlite/ Statement.php, line 17
Namespace
Drupal\Core\Database\Driver\sqliteView source
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 = []) {
if (is_array($args) && !empty($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 = [];
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 = [], $options = []) {
try {
$return = parent::execute($args, $options);
} catch (\PDOException $e) {
// The database schema might be changed by another process in between the
// time that the statement was prepared and the time the statement was run
// (e.g. usually happens when running tests). In this case, we need to
// re-run the query.
// @see http://www.sqlite.org/faq.html#q15
// @see http://www.sqlite.org/rescode.html#schema
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 = [];
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;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
Statement:: |
public | function |
Executes a prepared statement. Overrides StatementPrefetch:: |
|
Statement:: |
protected | function |
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. Overrides StatementPrefetch:: |
|
StatementPrefetch:: |
protected | property | The list of column names in this result set. | |
StatementPrefetch:: |
protected | property | The Drupal database connection object. | |
StatementPrefetch:: |
protected | property | The key of the current row. | |
StatementPrefetch:: |
protected | property | The current row, retrieved in \PDO::FETCH_ASSOC format. | |
StatementPrefetch:: |
protected | property | Main data store. | |
StatementPrefetch:: |
protected | property | Holds supplementary default fetch options. | |
StatementPrefetch:: |
protected | property | Holds the default fetch style. | |
StatementPrefetch:: |
protected | property | Driver-specific options. Can be used by child classes. | |
StatementPrefetch:: |
protected | property | Holds supplementary current fetch options (which will be used by the next fetch). | |
StatementPrefetch:: |
protected | property | Holds the current fetch style (which will be used by the next fetch). | |
StatementPrefetch:: |
protected | property | Reference to the PDO connection object for this statement. | |
StatementPrefetch:: |
protected | property | The query string. | |
StatementPrefetch:: |
protected | property | The number of rows in this result set. | |
StatementPrefetch:: |
protected | property | The number of rows affected by the last query. | |
StatementPrefetch:: |
protected | property | Is rowCount() execution allowed. | |
StatementPrefetch:: |
public | function | Return the current row formatted according to the current fetch style. | |
StatementPrefetch:: |
public | function |
Fetches the next row from a result set. Overrides StatementInterface:: |
|
StatementPrefetch:: |
public | function |
Returns an array containing all of the result set rows. Overrides StatementInterface:: |
|
StatementPrefetch:: |
public | function |
Returns the result set as an associative array keyed by the given field. Overrides StatementInterface:: |
|
StatementPrefetch:: |
public | function |
Returns the entire result set as a single associative array. Overrides StatementInterface:: |
|
StatementPrefetch:: |
public | function |
Fetches the next row and returns it as an associative array. Overrides StatementInterface:: |
|
StatementPrefetch:: |
public | function |
Returns an entire single column of a result set as an indexed array. Overrides StatementInterface:: |
|
StatementPrefetch:: |
public | function | ||
StatementPrefetch:: |
public | function |
Returns a single field from the next record of a result set. Overrides StatementInterface:: |
|
StatementPrefetch:: |
public | function |
Fetches the next row and returns it as an object. Overrides StatementInterface:: |
|
StatementPrefetch:: |
public | function | ||
StatementPrefetch:: |
public | function |
Gets the query string of this statement. Overrides StatementInterface:: |
|
StatementPrefetch:: |
public | function | ||
StatementPrefetch:: |
public | function | ||
StatementPrefetch:: |
public | function | ||
StatementPrefetch:: |
public | function |
Returns the number of rows affected by the last SQL statement. Overrides StatementInterface:: |
|
StatementPrefetch:: |
public | function |
Sets the default fetch mode for this statement. Overrides StatementInterface:: |
|
StatementPrefetch:: |
protected | function | Throw a PDO Exception based on the last PDO error. | |
StatementPrefetch:: |
public | function | ||
StatementPrefetch:: |
public | function | Constructs a StatementPrefetch object. | |
StatementPrefetch:: |
public | function | Implements the magic __get() method. | |
StatementPrefetch:: |
public | function | Implements the magic __set() method. |