Commit 362aa81b authored by catch's avatar catch
Browse files

Issue #3312641 by nkoporec, Ratan Priya, Anchal_gupta, daffie, mglaman: Bring...

Issue #3312641 by nkoporec, Ratan Priya, Anchal_gupta, daffie, mglaman: Bring back temporary tables (Connection::queryTemporary())

(cherry picked from commit 22a9ced9)
parent 57451187
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Core\Database;

/**
 * Adds support for temporary tables.
 *
 * @ingroup database
 */
interface SupportsTemporaryTablesInterface {

  /**
   * Runs a SELECT query and stores its results in a temporary table.
   *
   * Use this as a substitute for ->query() when the results need to stored
   * in a temporary table. Temporary tables exist for the duration of the page
   * request. User-supplied arguments to the query should be passed in as
   * separate parameters so that they can be properly escaped to avoid SQL
   * injection attacks.
   *
   * Note that if you need to know how many results were returned, you should do
   * a SELECT COUNT(*) on the temporary table afterwards.
   *
   * @param string $query
   *   A string containing a normal SELECT SQL query.
   * @param array $args
   *   (optional) An array of values to substitute into the query at placeholder
   *   markers.
   * @param array $options
   *   (optional) An associative array of options to control how the query is
   *   run. See the documentation for DatabaseConnection::defaultOptions() for
   *   details.
   *
   * @return string
   *   The name of the temporary table.
   */
  public function queryTemporary($query, array $args = [], array $options = []);

}
+2 −0
Original line number Diff line number Diff line
@@ -1024,6 +1024,7 @@ renderered
renormalize
reparenting
reparsed
relpersistence
replyto
resave
resaved
@@ -1042,6 +1043,7 @@ revisionid
revisioning
revlog
revpub
relname
ribisi
ritchie
rolename
+11 −1
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
use Drupal\Core\Database\DatabaseNotFoundException;
use Drupal\Core\Database\DatabaseException;
use Drupal\Core\Database\Connection as DatabaseConnection;
use Drupal\Core\Database\SupportsTemporaryTablesInterface;
use Drupal\Core\Database\TransactionNoActiveException;

/**
@@ -19,7 +20,7 @@
/**
 * MySQL implementation of \Drupal\Core\Database\Connection.
 */
class Connection extends DatabaseConnection {
class Connection extends DatabaseConnection implements SupportsTemporaryTablesInterface {

  /**
   * Error code for "Unknown database" error.
@@ -222,6 +223,15 @@ public function queryRange($query, $from, $count, array $args = [], array $optio
    return $this->query($query . ' LIMIT ' . (int) $from . ', ' . (int) $count, $args, $options);
  }

  /**
   * {@inheritdoc}
   */
  public function queryTemporary($query, array $args = [], array $options = []) {
    $tablename = 'db_temporary_' . uniqid();
    $this->query('CREATE TEMPORARY TABLE {' . $tablename . '} Engine=MEMORY ' . $query, $args, $options);
    return $tablename;
  }

  public function driver() {
    return 'mysql';
  }
+39 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Tests\mysql\Kernel\mysql;

use Drupal\KernelTests\Core\Database\TemporaryQueryTestBase;

/**
 * Tests the temporary query functionality.
 *
 * @group Database
 */
class TemporaryQueryTest extends TemporaryQueryTestBase {

  /**
   * Confirms that temporary tables work.
   */
  public function testTemporaryQuery() {
    parent::testTemporaryQuery();

    $connection = $this->getConnection();

    $table_name_test = $connection->queryTemporary('SELECT [name] FROM {test}', []);

    // Assert that the table is indeed a temporary one.
    $temporary_table_info = $connection->query("SHOW CREATE TABLE {" . $table_name_test . "}")->fetchAssoc();
    $this->stringContains($temporary_table_info["Create Table"], "CREATE TEMPORARY TABLE");

    // Assert that both have the same field names.
    $normal_table_fields = $connection->query("SELECT * FROM {test}")->fetch();
    $temp_table_name = $connection->queryTemporary('SELECT * FROM {test}');
    $temp_table_fields = $connection->query("SELECT * FROM {" . $temp_table_name . "}")->fetch();

    $normal_table_fields = array_keys(get_object_vars($normal_table_fields));
    $temp_table_fields = array_keys(get_object_vars($temp_table_fields));

    $this->assertEmpty(array_diff($normal_table_fields, $temp_table_fields));
  }

}
+11 −1
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
use Drupal\Core\Database\DatabaseNotFoundException;
use Drupal\Core\Database\StatementInterface;
use Drupal\Core\Database\StatementWrapper;
use Drupal\Core\Database\SupportsTemporaryTablesInterface;

// cSpell:ignore ilike nextval

@@ -19,7 +20,7 @@
/**
 * PostgreSQL implementation of \Drupal\Core\Database\Connection.
 */
class Connection extends DatabaseConnection {
class Connection extends DatabaseConnection implements SupportsTemporaryTablesInterface {

  /**
   * The name by which to obtain a lock for retrieve the next insert id.
@@ -209,6 +210,15 @@ public function queryRange($query, $from, $count, array $args = [], array $optio
    return $this->query($query . ' LIMIT ' . (int) $count . ' OFFSET ' . (int) $from, $args, $options);
  }

  /**
   * {@inheritdoc}
   */
  public function queryTemporary($query, array $args = [], array $options = []) {
    $tablename = 'db_temporary_' . uniqid();
    $this->query('CREATE TEMPORARY TABLE {' . $tablename . '} AS ' . $query, $args, $options);
    return $tablename;
  }

  public function driver() {
    return 'pgsql';
  }
Loading