function Statement::getStatement

Same name and namespace in other branches
  1. 9 core/modules/sqlite/src/Driver/Database/sqlite/Statement.php \Drupal\sqlite\Driver\Database\sqlite\Statement::getStatement()
  2. 10 core/modules/sqlite/src/Driver/Database/sqlite/Statement.php \Drupal\sqlite\Driver\Database\sqlite\Statement::getStatement()
  3. 11.x core/modules/sqlite/src/Driver/Database/sqlite/Statement.php \Drupal\sqlite\Driver\Database\sqlite\Statement::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.

Overrides StatementPrefetch::getStatement

File

core/lib/Drupal/Core/Database/Driver/sqlite/Statement.php, line 29

Class

Statement
SQLite implementation of <a href="/api/drupal/core%21lib%21Drupal%21Core%21Database%21Statement.php/class/Statement/8.9.x" title="Default implementation of StatementInterface." class="local">\Drupal\Core\Database\Statement</a>.

Namespace

Drupal\Core\Database\Driver\sqlite

Code

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

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.