class Statement

Same name in this branch

Specific SQLite implementation of DatabaseConnection.

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

Expanded class hierarchy of Statement

1 file declares its use of Statement
Connection.php in drupal/core/lib/Drupal/Core/Database/Driver/sqlite/Connection.php
Definition of Drupal\Core\Database\Driver\sqlite\Connection
1 string reference to 'Statement'
EasyRdf_Parser_RdfXml::reify in drupal/core/vendor/easyrdf/easyrdf/lib/EasyRdf/Parser/RdfXml.php
@ignore

File

drupal/core/lib/Drupal/Core/Database/Driver/sqlite/Statement.php, line 25
Definition of Drupal\Core\Database\Driver\sqlite\Statement

Namespace

Drupal\Core\Database\Driver\sqlite
View source
class Statement extends StatementPrefetch implements Iterator, StatementInterface {

  /**
   * SQLite specific implementation of getStatement().
   *
   * 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->dbh
      ->prepare($query);
  }
  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;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Statement::execute public function Executes a prepared statement. Overrides StatementPrefetch::execute
Statement::getStatement protected function SQLite specific implementation of getStatement(). Overrides StatementPrefetch::getStatement
StatementPrefetch::$columnNames protected property The list of column names in this result set.
StatementPrefetch::$connection protected property Reference to the Drupal database connection object for this statement.
StatementPrefetch::$currentKey protected property The key of the current row.
StatementPrefetch::$currentRow protected property The current row, retrieved in PDO::FETCH_ASSOC format.
StatementPrefetch::$data protected property Main data store.
StatementPrefetch::$dbh public property Reference to the database connection object for this statement.
StatementPrefetch::$defaultFetchOptions protected property Holds supplementary default fetch options.
StatementPrefetch::$defaultFetchStyle protected property Holds the default fetch style.
StatementPrefetch::$driverOptions protected property Driver-specific options. Can be used by child classes.
StatementPrefetch::$fetchOptions protected property Holds supplementary current fetch options (which will be used by the next fetch).
StatementPrefetch::$fetchStyle protected property Holds the current fetch style (which will be used by the next fetch).
StatementPrefetch::$queryString protected property The query string.
StatementPrefetch::$resultRowCount protected property The number of rows in this result set.
StatementPrefetch::$rowCount protected property The number of rows affected by the last query.
StatementPrefetch::current public function Return the current row formatted according to the current fetch style.
StatementPrefetch::fetch public function
StatementPrefetch::fetchAll public function
StatementPrefetch::fetchAllAssoc public function Returns the result set as an associative array keyed by the given field. Overrides StatementInterface::fetchAllAssoc
StatementPrefetch::fetchAllKeyed public function Returns the entire result set as a single associative array. Overrides StatementInterface::fetchAllKeyed
StatementPrefetch::fetchAssoc public function Fetches the next row and returns it as an associative array. Overrides StatementInterface::fetchAssoc
StatementPrefetch::fetchCol public function Returns an entire single column of a result set as an indexed array. Overrides StatementInterface::fetchCol
StatementPrefetch::fetchColumn public function
StatementPrefetch::fetchField public function Returns a single field from the next record of a result set. Overrides StatementInterface::fetchField
StatementPrefetch::fetchObject public function
StatementPrefetch::getQueryString public function Return the object's SQL query string. Overrides StatementInterface::getQueryString
StatementPrefetch::key public function
StatementPrefetch::next public function
StatementPrefetch::rewind public function
StatementPrefetch::rowCount public function Returns the number of rows affected by the last SQL statement. Overrides StatementInterface::rowCount
StatementPrefetch::setFetchMode public function
StatementPrefetch::throwPDOException protected function Throw a PDO Exception based on the last PDO error.
StatementPrefetch::valid public function
StatementPrefetch::__construct public function