Commit f80c6184 authored by Dries's avatar Dries
Browse files

- Patch #349500 by Damien Tournoud et al: made db_query_temporary() generate...

- Patch #349500 by Damien Tournoud et al: made db_query_temporary() generate its own temporary table names.
parent 08f263fb
......@@ -295,6 +295,13 @@ abstract class DatabaseConnection extends PDO {
*/
protected $transactionalDDLSupport = FALSE;
/**
* An index used to generate unique temporary table names.
*
* @var integer
*/
protected $temporaryNameIndex = 0;
/**
* The schema object for this connection.
*
......@@ -909,6 +916,16 @@ public function popTransaction() {
*/
abstract public function queryRange($query, array $args, $from, $count, array $options = array());
/**
* Generate a temporary table name.
*
* @return
* A table name.
*/
protected function generateTemporaryTableName() {
return "db_temporary_" . $this->temporaryNameIndex++;
}
/**
* Runs a SELECT query and stores its results in a temporary table.
*
......@@ -925,17 +942,13 @@ abstract public function queryRange($query, array $args, $from, $count, array $o
* A string containing a normal SELECT SQL query.
* @param $args
* An array of values to substitute into the query at placeholder markers.
* @param $tablename
* The name of the temporary table to select into. This name will not be
* prefixed as there is no risk of collision.
* @param $options
* An associative array of options to control how the query is run. See
* the documentation for DatabaseConnection::defaultOptions() for details.
* @return
* A database query result resource, or FALSE if the query was not executed
* correctly.
* The name of the temporary table.
*/
abstract function queryTemporary($query, array $args, $tablename, array $options = array());
abstract function queryTemporary($query, array $args, array $options = array());
/**
* Returns the type of database driver.
......@@ -1788,20 +1801,19 @@ function db_query_range($query, $args, $from = 0, $count = 0, $options = array()
* placeholders, this is an associative array in any order. If the query uses
* unnamed placeholders (?), this is an indexed array and the order must match
* the order of placeholders in the query string.
* @param $tablename
* The name of the temporary table to select into. This name will not be
* prefixed as there is no risk of collision.
* @param $options
* An array of options to control how the query operates.
* @return
* The name of the temporary table.
*/
function db_query_temporary($query, $args, $tablename, $options = array()) {
function db_query_temporary($query, $args, $options = array()) {
if (!is_array($args)) {
$args = func_get_args();
array_shift($args);
}
list($query, $args, $options) = _db_query_process_args($query, $args, $options);
return Database::getActiveConnection($options['target'])->queryTemporary($query, $args, $tablename, $options);
return Database::getActiveConnection($options['target'])->queryTemporary($query, $args, $options);
}
/**
......
......@@ -50,8 +50,10 @@ public function queryRange($query, array $args, $from, $count, array $options =
return $this->query($query . ' LIMIT ' . $from . ', ' . $count, $args, $options);
}
public function queryTemporary($query, array $args, $tablename, array $options = array()) {
return $this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE ' . $tablename . ' Engine=MEMORY SELECT', $query), $args, $options);
public function queryTemporary($query, array $args, array $options = array()) {
$tablename = $this->generateTemporaryTableName();
$this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE {' . $tablename . '} Engine=MEMORY SELECT', $query), $args, $options);
return $tablename;
}
public function driver() {
......
......@@ -82,8 +82,10 @@ public function queryRange($query, array $args, $from, $count, array $options =
return $this->query($query . ' LIMIT ' . $count . ' OFFSET ' . $from, $args, $options);
}
public function queryTemporary($query, array $args, $tablename, array $options = array()) {
return $this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE ' . $tablename . ' AS SELECT', $query), $args, $options);
public function queryTemporary($query, array $args, array $options = array()) {
$tablename = $this->generateTemporaryTableName();
$this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE {' . $tablename . '} AS SELECT', $query), $args, $options);
return $tablename;
}
public function driver() {
......
......@@ -123,8 +123,10 @@ public function queryRange($query, array $args, $from, $count, array $options =
return $this->query($query . ' LIMIT ' . $from . ', ' . $count, $args, $options);
}
public function queryTemporary($query, array $args, $tablename, array $options = array()) {
return $this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE ' . $tablename . ' AS SELECT', $query), $args, $options);
public function queryTemporary($query, array $args, array $options = array()) {
$tablename = $this->generateTemporaryTableName();
$this->query(preg_replace('/^SELECT/i', 'CREATE TEMPORARY TABLE {' . $tablename . '} AS SELECT', $query), $args, $options);
return $tablename;
}
public function driver() {
......
......@@ -44,7 +44,7 @@ function database_test_query_database_test_alter_remove_range_alter(QueryAlterab
* Implementation of hook_menu().
*/
function database_test_menu() {
$items['database_test_db_query_temporary'] = array(
$items['database_test/db_query_temporary'] = array(
'access callback' => TRUE,
'page callback' => 'database_test_db_query_temporary',
);
......@@ -52,15 +52,17 @@ function database_test_menu() {
}
/**
* Run a db_query_temporary and print the number of rows in the resulting table.
* Run a db_query_temporary and output the table name and its number of rows.
*
* We need to test that the table created is temporary, so we run it here, in a
* separate menu callback request; After this request is done, the temporary
* table should automatically dropped.
*/
function database_test_db_query_temporary() {
db_query_temporary('SELECT status FROM {system}', array(), 'temporary');
print db_query('SELECT COUNT(*) FROM temporary')->fetchField();
$table_name = db_query_temporary('SELECT status FROM {system}', array());
drupal_json(array(
'table_name' => $table_name,
'row_count' => db_select($table_name)->countQuery()->execute()->fetchField(),
));
exit;
}
......@@ -1933,13 +1933,33 @@ class DatabaseTemporaryQueryTestCase extends DrupalWebTestCase {
parent::setUp('database_test');
}
/**
* Return the number of rows of a table.
*/
function countTableRows($table_name) {
return db_select($table_name)->countQuery()->execute()->fetchField();
}
/**
* Confirm that temporary tables work and are limited to one request.
*/
function testTemporaryQuery() {
$this->drupalGet('database_test_db_query_temporary');
$this->assertEqual(db_query('SELECT COUNT(*) FROM {system}')->fetchField(), $this->drupalGetContent(), t('The temporary table exists and contains the correct amount of rows.'));
$this->assertFalse(db_table_exists('temporary'), t('The temporary table is, indeed, temporary.'));
$this->drupalGet('database_test/db_query_temporary');
$data = json_decode($this->drupalGetContent());
if ($data) {
$this->assertEqual($this->countTableRows("system"), $data->row_count, t('The temporary table contains the correct amount of rows.'));
$this->assertFalse(db_table_exists($data->table_name), t('The temporary table is, indeed, temporary.'));
}
else {
$this->fail(t("The creation of the temporary table failed."));
}
// Now try to run two db_query_temporary() in the same request.
$table_name_system = db_query_temporary('SELECT status FROM {system}', array());
$table_name_users = db_query_temporary('SELECT uid FROM {users}', array());
$this->assertEqual($this->countTableRows($table_name_system), $this->countTableRows("system"), t('A temporary table was created successfully in this request.'));
$this->assertEqual($this->countTableRows($table_name_users), $this->countTableRows("users"), t('A second temporary table was created successfully in this request.'));
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment