#783814: enforce that only simple SELECT queries are passed to db_query() and DatabaseConnection::query() to prevent module authors from writing non-portable queries unknowingly.

From: Damien Tournoud <damien@tournoud.net>


---
 database/database.inc        |   33 +++++++++++++++++++++++++++------
 database/mysql/database.inc  |    6 +++---
 database/mysql/schema.inc    |   28 ++++++++++++++--------------
 database/pgsql/database.inc  |    6 +++---
 database/pgsql/schema.inc    |   26 +++++++++++++-------------
 database/query.inc           |   25 +++++++++++++++++++++++++
 database/schema.inc          |    4 ++--
 database/sqlite/database.inc |    8 ++------
 database/sqlite/schema.inc   |   14 +++++++-------
 9 files changed, 96 insertions(+), 54 deletions(-)

diff --git includes/database/database.inc includes/database/database.inc
index 5c771b1..56c60af 100644
--- includes/database/database.inc
+++ includes/database/database.inc
@@ -316,6 +316,10 @@ abstract class DatabaseConnection extends PDO {
    *   further up the call chain can take an appropriate action. To suppress
    *   that behavior and simply return NULL on failure, set this option to
    *   FALSE.
+   * - unsafe: By default, only simple SELECT queries will be accepted by the
+   *   db_query() call. You can set this flag to TRUE to pass other types of
+   *   of query directly to the database engine. The behavior of the database
+   *   layer in that case is undefined.
    *
    * @return
    *   An array of default query options.
@@ -326,6 +330,7 @@ abstract class DatabaseConnection extends PDO {
       'fetch' => PDO::FETCH_OBJ,
       'return' => Database::RETURN_STATEMENT,
       'throw_exception' => TRUE,
+      'unsafe' => FALSE,
     );
   }
 
@@ -537,6 +542,15 @@ abstract class DatabaseConnection extends PDO {
         $stmt->execute(NULL, $options);
       }
       else {
+        // Whitelist queries. Only simple SELECT queries should be passed to this
+        // function (and the db_query() wrapper). The queries should start with
+        // SELECT and should not contain any quotes.
+        if (empty($options['unsafe'])) {
+          if (!preg_match('/\s*SELECT\s+[^\']+/', $query)) {
+            throw new DatabaseInvalidQueryException('Unsafe query passed to db_query(): ' . $query);
+          }
+        }
+
         $this->expandArguments($query, $args);
         $stmt = $this->prepareQuery($query);
         $stmt->execute($args, $options);
@@ -908,7 +922,7 @@ abstract class DatabaseConnection extends PDO {
         if (empty($this->transactionLayers)) {
           break;
         }
-        $this->query('ROLLBACK TO SAVEPOINT ' . $savepoint);
+        $this->query('ROLLBACK TO SAVEPOINT ' . $savepoint, array(), array('unsafe' => TRUE));
         return;
       }
     }
@@ -965,7 +979,7 @@ abstract class DatabaseConnection extends PDO {
     // If we're already in a transaction then we want to create a savepoint
     // rather than try to create another transaction.
     if ($this->inTransaction()) {
-      $this->query('SAVEPOINT ' . $name);
+      $this->query('SAVEPOINT ' . $name, array(), array('unsafe' => TRUE));
     }
     else {
       parent::beginTransaction();
@@ -1004,7 +1018,7 @@ abstract class DatabaseConnection extends PDO {
         }
       }
       else {
-        $this->query('RELEASE SAVEPOINT ' . $name);
+        $this->query('RELEASE SAVEPOINT ' . $name, array(), array('unsafe' => TRUE));
         break;
       }
     }
@@ -1580,6 +1594,11 @@ abstract class Database {
 }
 
 /**
+ * Exception thrown when an unsafe query is passed to DatabaseConnection::query().
+ */
+class DatabaseInvalidQueryException extends Exception { }
+
+/**
  * Exception for when popTransaction() is called with no active transaction.
  */
 class DatabaseTransactionNoActiveException extends Exception { }
@@ -2195,9 +2214,11 @@ function db_autoload($class) {
 /**
  * Executes an arbitrary query string against the active database.
  *
- * Do not use this function for INSERT, UPDATE, or DELETE queries. Those should
- * be handled via the appropriate query builder factory. Use this function for
- * SELECT queries that do not require a query builder.
+ * This function cannot be used for INSERT, UPDATE, or DELETE queries, unless
+ * the 'unsafe' option is set. Those queries should be handled via the
+ * appropriate query builder factory. Use this function only for SELECT queries
+ * that do not require a query builder, and use the appropriate placeholders
+ * to pass string values.
  *
  * @param $query
  *   The prepared statement query to run. Although it will accept both named and
diff --git includes/database/mysql/database.inc includes/database/mysql/database.inc
index d868cec..549bc88 100644
--- includes/database/mysql/database.inc
+++ includes/database/mysql/database.inc
@@ -73,7 +73,7 @@ class DatabaseConnection_mysql extends DatabaseConnection {
 
   public function nextId($existing_id = 0) {
     static $shutdown_registered = FALSE;
-    $new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID));
+    $new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('unsafe' => TRUE, 'return' => Database::RETURN_INSERT_ID));
     // This should only happen after an import or similar event.
     if ($existing_id >= $new_id) {
       // If we INSERT a value manually into the sequences table, on the next
@@ -83,8 +83,8 @@ class DatabaseConnection_mysql extends DatabaseConnection {
       // other than duplicate keys. Instead, we use INSERT ... ON DUPLICATE KEY
       // UPDATE in such a way that the UPDATE does not do anything. This way,
       // duplicate keys do not generate errors but everything else does.
-      $this->query('INSERT INTO {sequences} (value) VALUES (:value) ON DUPLICATE KEY UPDATE value = value', array(':value' => $existing_id));
-      $new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('return' => Database::RETURN_INSERT_ID));
+      $this->query('INSERT INTO {sequences} (value) VALUES (:value) ON DUPLICATE KEY UPDATE value = value', array(':value' => $existing_id), array('unsafe' => TRUE));
+      $new_id = $this->query('INSERT INTO {sequences} () VALUES ()', array(), array('unsafe' => TRUE, 'return' => Database::RETURN_INSERT_ID));
     }
     if (!$shutdown_registered) {
       drupal_register_shutdown_function(array(get_class($this), 'nextIdDelete'));
diff --git includes/database/mysql/schema.inc includes/database/mysql/schema.inc
index 56fca57..ae23e51 100644
--- includes/database/mysql/schema.inc
+++ includes/database/mysql/schema.inc
@@ -289,7 +289,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
     }
 
     $info = $this->getPrefixInfo($new_name);
-    return $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO `' . $info['table'] . '`');
+    return $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO `' . $info['table'] . '`', array(), array('unsafe' => TRUE));
   }
 
   public function dropTable($table) {
@@ -297,7 +297,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('DROP TABLE {' . $table . '}');
+    $this->connection->query('DROP TABLE {' . $table . '}', array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -319,7 +319,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
     if (count($keys_new)) {
       $query .= ', ADD ' . implode(', ADD ', $this->createKeysSql($keys_new));
     }
-    $this->connection->query($query);
+    $this->connection->query($query, array(), array('unsafe' => TRUE));
     if (isset($spec['initial'])) {
       $this->connection->update($table)
         ->fields(array($field, $spec['initial']))
@@ -336,7 +336,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP `' . $field . '`');
+    $this->connection->query('ALTER TABLE {' . $table . '} DROP `' . $field . '`', array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -352,7 +352,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
       $default = is_string($default) ? "'$default'" : $default;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN `' . $field . '` SET DEFAULT ' . $default);
+    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN `' . $field . '` SET DEFAULT ' . $default, array(), array('unsafe' => TRUE));
   }
 
   public function fieldSetNoDefault($table, $field) {
@@ -360,13 +360,13 @@ class DatabaseSchema_mysql extends DatabaseSchema {
       throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN `' . $field . '` DROP DEFAULT');
+    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN `' . $field . '` DROP DEFAULT', array(), array('unsafe' => TRUE));
   }
 
   public function indexExists($table, $name) {
     // Returns one row for each column in the index. Result is string or FALSE.
     // Details at http://dev.mysql.com/doc/refman/5.0/en/show-index.html
-    $row = $this->connection->query('SHOW INDEX FROM {' . $table . "} WHERE key_name = '$name'")->fetchAssoc();
+    $row = $this->connection->query('SHOW INDEX FROM {' . $table . "} WHERE key_name = '$name'", array(), array('unsafe' => TRUE))->fetchAssoc();
     return isset($row['key_name']);
   }
 
@@ -378,7 +378,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
       throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . $this->createKeySql($fields) . ')');
+    $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . $this->createKeySql($fields) . ')', array(), array('unsafe' => TRUE));
   }
 
   public function dropPrimaryKey($table) {
@@ -386,7 +386,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP PRIMARY KEY');
+    $this->connection->query('ALTER TABLE {' . $table . '} DROP PRIMARY KEY', array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -398,7 +398,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
       throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ADD UNIQUE KEY `' . $name . '` (' . $this->createKeySql($fields) . ')');
+    $this->connection->query('ALTER TABLE {' . $table . '} ADD UNIQUE KEY `' . $name . '` (' . $this->createKeySql($fields) . ')', array(), array('unsafe' => TRUE));
   }
 
   public function dropUniqueKey($table, $name) {
@@ -406,7 +406,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP KEY `' . $name . '`');
+    $this->connection->query('ALTER TABLE {' . $table . '} DROP KEY `' . $name . '`', array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -418,7 +418,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
       throw new DatabaseSchemaObjectExistsException(t("Cannot add index %name to table %table: index already exists.", array('%table' => $table, '%name' => $name)));
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ADD INDEX `' . $name . '` (' . $this->createKeySql($fields) . ')');
+    $this->connection->query('ALTER TABLE {' . $table . '} ADD INDEX `' . $name . '` (' . $this->createKeySql($fields) . ')', array(), array('unsafe' => TRUE));
   }
 
   public function dropIndex($table, $name) {
@@ -426,7 +426,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP INDEX `' . $name . '`');
+    $this->connection->query('ALTER TABLE {' . $table . '} DROP INDEX `' . $name . '`', array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -442,7 +442,7 @@ class DatabaseSchema_mysql extends DatabaseSchema {
     if (count($keys_new)) {
       $sql .= ', ADD ' . implode(', ADD ', $this->createKeysSql($keys_new));
     }
-    $this->connection->query($sql);
+    $this->connection->query($sql, array(), array('unsafe' => TRUE));
   }
 
   public function prepareComment($comment, $length = NULL) {
diff --git includes/database/pgsql/database.inc includes/database/pgsql/database.inc
index 6c5cd97..de29d52 100644
--- includes/database/pgsql/database.inc
+++ includes/database/pgsql/database.inc
@@ -150,7 +150,7 @@ class DatabaseConnection_pgsql extends DatabaseConnection {
 
     // When PostgreSQL gets a value too small then it will lock the table,
     // retry the INSERT and if it's still too small then alter the sequence.
-    $id = $this->query("SELECT nextval('" . $sequence_name . "')")->fetchField();
+    $id = $this->query("SELECT nextval(:sequence)", array(':sequence' => $sequence_name))->fetchField();
     if ($id > $existing) {
       return $id;
     }
@@ -169,10 +169,10 @@ class DatabaseConnection_pgsql extends DatabaseConnection {
     }
 
     // Reset the sequence to a higher value than the existing id.
-    $this->query("ALTER SEQUENCE " . $sequence_name . " RESTART WITH " . ($existing + 1));
+    $this->query("ALTER SEQUENCE " . $sequence_name . " RESTART WITH " . ($existing + 1), array(), array('unsafe' => TRUE));
 
     // Retrive the next id. We know this will be as high as we want it.
-    $id = $this->query("SELECT nextval('" . $sequence_name . "')")->fetchField();
+    $id = $this->query("SELECT nextval(:sequence)", array(':sequence' => $sequence_name))->fetchField();
 
     $this->query("SELECT pg_advisory_unlock(" . POSTGRESQL_NEXTID_LOCK . ")");
 
diff --git includes/database/pgsql/schema.inc includes/database/pgsql/schema.inc
index 44dccdc..68eb2fd 100644
--- includes/database/pgsql/schema.inc
+++ includes/database/pgsql/schema.inc
@@ -292,14 +292,14 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
     foreach ($indexes as $index) {
       if (preg_match('/^' . preg_quote($old_full_name) . '_(.*)_idx$/', $index->indexname, $matches)) {
         $index_name = $matches[1];
-        $this->connection->query('ALTER INDEX ' . $index->indexname . ' RENAME TO {' . $new_name . '}_' . $index_name . '_idx');
+        $this->connection->query('ALTER INDEX ' . $index->indexname . ' RENAME TO {' . $new_name . '}_' . $index_name . '_idx', array(), array('unsafe' => TRUE));
       }
     }
 
     // Now rename the table.
     // Ensure the new table name does not include schema syntax.
     $prefixInfo = $this->getPrefixInfo($new_name);
-    $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $prefixInfo['table']);
+    $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $prefixInfo['table'], array(), array('unsafe' => TRUE));
   }
 
   public function dropTable($table) {
@@ -307,7 +307,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('DROP TABLE {' . $table . '}');
+    $this->connection->query('DROP TABLE {' . $table . '}' array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -340,7 +340,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
     }
     // Add column comment.
     if (!empty($spec['description'])) {
-      $this->connection->query('COMMENT ON COLUMN {' . $table . '}.' . $field . ' IS ' . $this->prepareComment($spec['description']));
+      $this->connection->query('COMMENT ON COLUMN {' . $table . '}.' . $field . ' IS ' . $this->prepareComment($spec['description']), array(), array('unsafe' => TRUE));
     }
   }
 
@@ -349,7 +349,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP COLUMN "' . $field . '"');
+    $this->connection->query('ALTER TABLE {' . $table . '} DROP COLUMN "' . $field . '"', array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -365,7 +365,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       $default = is_string($default) ? "'$default'" : $default;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" SET DEFAULT ' . $default);
+    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" SET DEFAULT ' . $default, array(), array('unsafe' => TRUE));
   }
 
   public function fieldSetNoDefault($table, $field) {
@@ -373,7 +373,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       throw new DatabaseSchemaObjectDoesNotExistException(t("Cannot remove default value of field %table.%field: field doesn't exist.", array('%table' => $table, '%field' => $field)));
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" DROP DEFAULT');
+    $this->connection->query('ALTER TABLE {' . $table . '} ALTER COLUMN "' . $field . '" DROP DEFAULT', array(), array('unsafe' => TRUE));
   }
 
   public function indexExists($table, $name) {
@@ -403,7 +403,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       throw new DatabaseSchemaObjectExistsException(t("Cannot add primary key to table %table: primary key already exists.", array('%table' => $table)));
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . implode(',', $fields) . ')');
+    $this->connection->query('ALTER TABLE {' . $table . '} ADD PRIMARY KEY (' . implode(',', $fields) . ')', array(), array('unsafe' => TRUE));
   }
 
   public function dropPrimaryKey($table) {
@@ -411,7 +411,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT ' . $this->prefixNonTable($table, 'pkey'));
+    $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT ' . $this->prefixNonTable($table, 'pkey'), array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -423,7 +423,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       throw new DatabaseSchemaObjectExistsException(t("Cannot add unique key %name to table %table: unique key already exists.", array('%table' => $table, '%name' => $name)));
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT "' . $this->prefixNonTable($table, $name, 'key') . '" UNIQUE (' . implode(',', $fields) . ')');
+    $this->connection->query('ALTER TABLE {' . $table . '} ADD CONSTRAINT "' . $this->prefixNonTable($table, $name, 'key') . '" UNIQUE (' . implode(',', $fields) . ')', array(), array('unsafe' => TRUE));
   }
 
   public function dropUniqueKey($table, $name) {
@@ -431,7 +431,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT "' . $this->prefixNonTable($table, $name, 'key') . '"');
+    $this->connection->query('ALTER TABLE {' . $table . '} DROP CONSTRAINT "' . $this->prefixNonTable($table, $name, 'key') . '"', array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -451,7 +451,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('DROP INDEX ' . $this->prefixNonTable($table, $name, 'idx'));
+    $this->connection->query('DROP INDEX ' . $this->prefixNonTable($table, $name, 'idx'), array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -485,7 +485,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema {
 
     // Rename the column if necessary.
     if ($field != $field_new) {
-      $this->connection->query('ALTER TABLE {' . $table . '} RENAME "' . $field . '" TO "' . $field_new . '_old"');
+      $this->connection->query('ALTER TABLE {' . $table . '} RENAME "' . $field . '" TO "' . $field_new . '_old"', array(), array('unsafe' => TRUE));
     }
 
     if (isset($new_keys)) {
diff --git includes/database/query.inc includes/database/query.inc
index ead5318..8c70aa7 100644
--- includes/database/query.inc
+++ includes/database/query.inc
@@ -323,6 +323,11 @@ class InsertQuery extends Query {
       $options['return'] = Database::RETURN_INSERT_ID;
     }
     $options += array('delay' => FALSE);
+
+    // This query builder will emit DML queries. Add the unsafe options to skip
+    // checks in DatabaseConnection::query().
+    $options['unsafe'] = TRUE;
+
     parent::__construct($connection, $options);
     $this->table = $table;
   }
@@ -586,6 +591,11 @@ class MergeQuery extends Query {
 
   public function __construct($connection, $table, array $options = array()) {
     $options['return'] = Database::RETURN_AFFECTED;
+
+    // This query builder will emit DML queries. Add the unsafe options to skip
+    // checks in DatabaseConnection::query().
+    $options['unsafe'] = TRUE;
+
     parent::__construct($connection, $options);
     $this->table = $table;
   }
@@ -850,6 +860,11 @@ class DeleteQuery extends Query implements QueryConditionInterface {
 
   public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
     $options['return'] = Database::RETURN_AFFECTED;
+
+    // This query builder will emit DML queries. Add the unsafe options to skip
+    // checks in DatabaseConnection::query().
+    $options['unsafe'] = TRUE;
+
     parent::__construct($connection, $options);
     $this->table = $table;
 
@@ -926,6 +941,11 @@ class TruncateQuery extends Query {
 
   public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
     $options['return'] = Database::RETURN_AFFECTED;
+
+    // This query builder will emit DML queries. Add the unsafe options to skip
+    // checks in DatabaseConnection::query().
+    $options['unsafe'] = TRUE;
+
     parent::__construct($connection, $options);
     $this->table = $table;
   }
@@ -992,6 +1012,11 @@ class UpdateQuery extends Query implements QueryConditionInterface {
 
   public function __construct(DatabaseConnection $connection, $table, array $options = array()) {
     $options['return'] = Database::RETURN_AFFECTED;
+
+    // This query builder will emit DML queries. Add the unsafe options to skip
+    // checks in DatabaseConnection::query().
+    $options['unsafe'] = TRUE;
+
     parent::__construct($connection, $options);
     $this->table = $table;
 
diff --git includes/database/schema.inc includes/database/schema.inc
index 012b74a..749582e 100644
--- includes/database/schema.inc
+++ includes/database/schema.inc
@@ -604,9 +604,9 @@ abstract class DatabaseSchema implements QueryPlaceholderInterface {
     if ($this->tableExists($name)) {
       throw new DatabaseSchemaObjectExistsException(t('Table %name already exists.', array('%name' => $name)));
     }
-  	$statements = $this->createTableSql($name, $table);
+    $statements = $this->createTableSql($name, $table);
     foreach ($statements as $statement) {
-    	$this->connection->query($statement);
+      $this->connection->query($statement, array(), array('unsafe' => TRUE));
     }
   }
 
diff --git includes/database/sqlite/database.inc includes/database/sqlite/database.inc
index 6062590..f133110 100644
--- includes/database/sqlite/database.inc
+++ includes/database/sqlite/database.inc
@@ -197,13 +197,9 @@ class DatabaseConnection_sqlite extends DatabaseConnection {
     // and integers and no known databases require special handling for those
     // simple cases. If another transaction wants to write the same row, it will
     // wait until this transaction commits.
-    $stmt = $this->query('UPDATE {sequences} SET value = GREATEST(value, :existing_id) + 1', array(
-      ':existing_id' => $existing_id,
-    ));
+    $stmt = $this->query('UPDATE {sequences} SET value = GREATEST(value, :existing_id) + 1', array(':existing_id' => $existing_id), array('unsafe' => TRUE));
     if (!$stmt->rowCount()) {
-      $this->query('INSERT INTO {sequences} (value) VALUES (:existing_id + 1)', array(
-        ':existing_id' => $existing_id,
-      ));
+      $this->query('INSERT INTO {sequences} (value) VALUES (:existing_id + 1)', array(':existing_id' => $existing_id), array('unsafe' => TRUE));
     }
     // The transaction gets committed when the transaction object gets destroyed
     // because it gets out of scope.
diff --git includes/database/sqlite/schema.inc includes/database/sqlite/schema.inc
index 515fc6a..1dcc0e3 100644
--- includes/database/sqlite/schema.inc
+++ includes/database/sqlite/schema.inc
@@ -244,7 +244,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
     // the table with curly braces incase the db_prefix contains a reference
     // to a database outside of our existsing database.
     $info = $this->getPrefixInfo($new_name);
-    $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $info['table']);
+    $this->connection->query('ALTER TABLE {' . $table . '} RENAME TO ' . $info['table'], array(), array('unsafe' => TRUE));
 
     // Drop the indexes, there is no RENAME INDEX command in SQLite.
     if (!empty($schema['unique keys'])) {
@@ -270,7 +270,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('DROP TABLE {' . $table . '}');
+    $this->connection->query('DROP TABLE {' . $table . '}', array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -311,8 +311,8 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
     $this->connection->insert($new_table)
       ->from($select)
       ->execute();
-    $old_count = $this->connection->query('SELECT COUNT(*) FROM {' . $table . '}')->fetchField();
-    $new_count = $this->connection->query('SELECT COUNT(*) FROM {' . $new_table . '}')->fetchField();
+    $old_count = $this->connection->query('SELECT COUNT(*) FROM {' . $table . '}', array(), array('unsafe' => TRUE))->fetchField();
+    $new_count = $this->connection->query('SELECT COUNT(*) FROM {' . $new_table . '}', array(), array('unsafe' => TRUE))->fetchField();
     if ($old_count == $new_count) {
       do {
         $temp_table = $table . '_' . $i++;
@@ -453,7 +453,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
   }
 
   public function indexExists($table, $name) {
-    return $this->connection->query('PRAGMA index_info({' . $table . '}_' . $name . ')')->fetchField() != '';
+    return $this->connection->query('PRAGMA index_info({' . $table . '}_' . $name . ')', array(), array('unsafe' => TRUE))->fetchField() != '';
   }
 
   public function dropIndex($table, $name) {
@@ -461,7 +461,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('DROP INDEX ' . $this->prefixNonTable($table, $name));
+    $this->connection->query('DROP INDEX ' . $this->prefixNonTable($table, $name), array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
@@ -485,7 +485,7 @@ class DatabaseSchema_sqlite extends DatabaseSchema {
       return FALSE;
     }
 
-    $this->connection->query('DROP INDEX ' . $this->prefixNonTable($table, $name));
+    $this->connection->query('DROP INDEX ' . $this->prefixNonTable($table, $name), array(), array('unsafe' => TRUE));
     return TRUE;
   }
 
