Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663
This commit is contained in:
parent
eb34d130a8
commit
f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions
|
@ -239,6 +239,12 @@ abstract class Connection {
|
|||
* 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.
|
||||
* - allow_delimiter_in_query: By default, queries which have the ; delimiter
|
||||
* any place in them will cause an exception. This reduces the chance of SQL
|
||||
* injection attacks that terminate the original query and add one or more
|
||||
* additional queries (such as inserting new user accounts). In rare cases,
|
||||
* such as creating an SQL function, a ; is needed and can be allowed by
|
||||
* changing this option to TRUE.
|
||||
*
|
||||
* @return array
|
||||
* An array of default query options.
|
||||
|
@ -249,6 +255,7 @@ abstract class Connection {
|
|||
'fetch' => \PDO::FETCH_OBJ,
|
||||
'return' => Database::RETURN_STATEMENT,
|
||||
'throw_exception' => TRUE,
|
||||
'allow_delimiter_in_query' => FALSE,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -491,7 +498,7 @@ abstract class Connection {
|
|||
return '';
|
||||
|
||||
// Flatten the array of comments.
|
||||
$comment = implode('; ', $comments);
|
||||
$comment = implode('. ', $comments);
|
||||
|
||||
// Sanitize the comment string so as to avoid SQL injection attacks.
|
||||
return '/* ' . $this->filterComment($comment) . ' */ ';
|
||||
|
@ -516,7 +523,7 @@ abstract class Connection {
|
|||
*
|
||||
* Would result in the following SQL statement being generated:
|
||||
* @code
|
||||
* "/ * Exploit * / DROP TABLE node; -- * / UPDATE example SET field2=..."
|
||||
* "/ * Exploit * / DROP TABLE node. -- * / UPDATE example SET field2=..."
|
||||
* @endcode
|
||||
*
|
||||
* Unless the comment is sanitised first, the SQL server would drop the
|
||||
|
@ -529,7 +536,8 @@ abstract class Connection {
|
|||
* A sanitized version of the query comment string.
|
||||
*/
|
||||
protected function filterComment($comment = '') {
|
||||
return strtr($comment, ['*' => ' * ']);
|
||||
// Change semicolons to period to avoid triggering multi-statement check.
|
||||
return strtr($comment, ['*' => ' * ', ';' => '.']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -593,6 +601,16 @@ abstract class Connection {
|
|||
}
|
||||
else {
|
||||
$this->expandArguments($query, $args);
|
||||
// To protect against SQL injection, Drupal only supports executing one
|
||||
// statement at a time. Thus, the presence of a SQL delimiter (the
|
||||
// semicolon) is not allowed unless the option is set. Allowing
|
||||
// semicolons should only be needed for special cases like defining a
|
||||
// function or stored procedure in SQL. Trim any trailing delimiter to
|
||||
// minimize false positives.
|
||||
$query = rtrim($query, "; \t\n\r\0\x0B");
|
||||
if (strpos($query, ';') !== FALSE && empty($options['allow_delimiter_in_query'])) {
|
||||
throw new \InvalidArgumentException('; is not supported in SQL strings. Use only one statement at a time.');
|
||||
}
|
||||
$stmt = $this->prepareQuery($query);
|
||||
$stmt->execute($args, $options);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ class Tasks extends InstallTasks {
|
|||
catch (\Exception $e) {
|
||||
// Detect utf8mb4 incompability.
|
||||
if ($e->getCode() == Connection::UNSUPPORTED_CHARSET) {
|
||||
$this->fail(t('Your MySQL server and PHP MySQL driver must support utf8mb4 character encoding. Make sure to use a database system that supports this (such as MySQL/MariaDB/Percona 5.5.3 and up), and that the utf8mb4 character set is compiled in. See the <a href="@documentation" target="_blank">MySQL documentation</a> for more information.', array('@documentation' => 'https://dev.mysql.com/doc/refman/5.0/en/cannot-initialize-character-set.html')));
|
||||
$this->fail(t('Your MySQL server and PHP MySQL driver must support utf8mb4 character encoding. Make sure to use a database system that supports this (such as MySQL/MariaDB/Percona 5.5.3 and up), and that the utf8mb4 character set is compiled in. See the <a href=":documentation" target="_blank">MySQL documentation</a> for more information.', array(':documentation' => 'https://dev.mysql.com/doc/refman/5.0/en/cannot-initialize-character-set.html')));
|
||||
$info = Database::getConnectionInfo();
|
||||
$info_copy = $info;
|
||||
// Set a flag to fall back to utf8. Note: this flag should only be
|
||||
|
@ -164,13 +164,13 @@ class Tasks extends InstallTasks {
|
|||
// The mysqlnd driver supports utf8mb4 starting at version 5.0.9.
|
||||
$version = preg_replace('/^\D+([\d.]+).*/', '$1', $version);
|
||||
if (version_compare($version, self::MYSQLND_MINIMUM_VERSION, '<')) {
|
||||
$this->fail(t("The MySQLnd driver version %version is less than the minimum required version. Upgrade to MySQLnd version %mysqlnd_minimum_version or up, or alternatively switch mysql drivers to libmysqlclient version %libmysqlclient_minimum_version or up.", array('%version' => Database::getConnection()->version(), '%mysqlnd_minimum_version' => self::MYSQLND_MINIMUM_VERSION, '%libmysqlclient_minimum_version' => self::LIBMYSQLCLIENT_MINIMUM_VERSION)));
|
||||
$this->fail(t("The MySQLnd driver version %version is less than the minimum required version. Upgrade to MySQLnd version %mysqlnd_minimum_version or up, or alternatively switch mysql drivers to libmysqlclient version %libmysqlclient_minimum_version or up.", array('%version' => $version, '%mysqlnd_minimum_version' => self::MYSQLND_MINIMUM_VERSION, '%libmysqlclient_minimum_version' => self::LIBMYSQLCLIENT_MINIMUM_VERSION)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The libmysqlclient driver supports utf8mb4 starting at version 5.5.3.
|
||||
if (version_compare($version, self::LIBMYSQLCLIENT_MINIMUM_VERSION, '<')) {
|
||||
$this->fail(t("The libmysqlclient driver version %version is less than the minimum required version. Upgrade to libmysqlclient version %libmysqlclient_minimum_version or up, or alternatively switch mysql drivers to MySQLnd version %mysqlnd_minimum_version or up.", array('%version' => Database::getConnection()->version(), '%libmysqlclient_minimum_version' => self::LIBMYSQLCLIENT_MINIMUM_VERSION, '%mysqlnd_minimum_version' => self::MYSQLND_MINIMUM_VERSION)));
|
||||
$this->fail(t("The libmysqlclient driver version %version is less than the minimum required version. Upgrade to libmysqlclient version %libmysqlclient_minimum_version or up, or alternatively switch mysql drivers to MySQLnd version %mysqlnd_minimum_version or up.", array('%version' => $version, '%libmysqlclient_minimum_version' => self::LIBMYSQLCLIENT_MINIMUM_VERSION, '%mysqlnd_minimum_version' => self::MYSQLND_MINIMUM_VERSION)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -539,7 +539,8 @@ class Schema extends DatabaseSchema {
|
|||
// Add table prefixes before truncating.
|
||||
$comment = Unicode::truncate($this->connection->prefixTables($comment), $length, TRUE, TRUE);
|
||||
}
|
||||
|
||||
// Remove semicolons to avoid triggering multi-statement check.
|
||||
$comment = strtr($comment, array(';' => '.'));
|
||||
return $this->connection->quote($comment);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,10 @@ class Tasks extends InstallTasks {
|
|||
'function' => 'checkBinaryOutput',
|
||||
'arguments' => array(),
|
||||
);
|
||||
$this->tasks[] = array(
|
||||
'function' => 'checkStandardConformingStrings',
|
||||
'arguments' => array(),
|
||||
);
|
||||
$this->tasks[] = array(
|
||||
'function' => 'initializeDatabase',
|
||||
'arguments' => array(),
|
||||
|
@ -118,10 +122,9 @@ class Tasks extends InstallTasks {
|
|||
$this->pass(t('Database is encoded in UTF-8'));
|
||||
}
|
||||
else {
|
||||
$this->fail(t('The %driver database must use %encoding encoding to work with Drupal. Recreate the database with %encoding encoding. See !link for more details.', array(
|
||||
$this->fail(t('The %driver database must use %encoding encoding to work with Drupal. Recreate the database with %encoding encoding. See <a href="INSTALL.pgsql.txt">INSTALL.pgsql.txt</a> for more details.', array(
|
||||
'%encoding' => 'UTF8',
|
||||
'%driver' => $this->name(),
|
||||
'!link' => '<a href="INSTALL.pgsql.txt">INSTALL.pgsql.txt</a>'
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
@ -168,9 +171,9 @@ class Tasks extends InstallTasks {
|
|||
'%setting' => 'bytea_output',
|
||||
'%current_value' => 'hex',
|
||||
'%needed_value' => 'escape',
|
||||
'!query' => "<code>" . $query . "</code>",
|
||||
'@query' => $query,
|
||||
);
|
||||
$this->fail(t("The %setting setting is currently set to '%current_value', but needs to be '%needed_value'. Change this by running the following query: !query", $replacements));
|
||||
$this->fail(t("The %setting setting is currently set to '%current_value', but needs to be '%needed_value'. Change this by running the following query: <code>@query</code>", $replacements));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,6 +187,58 @@ class Tasks extends InstallTasks {
|
|||
return ($bytea_output == 'escape');
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures standard_conforming_strings setting is 'on'.
|
||||
*
|
||||
* When standard_conforming_strings setting is 'on' string literals ('...')
|
||||
* treat backslashes literally, as specified in the SQL standard. This allows
|
||||
* Drupal to convert between bytea, text and varchar columns.
|
||||
*/
|
||||
public function checkStandardConformingStrings() {
|
||||
$database_connection = Database::getConnection();
|
||||
if (!$this->checkStandardConformingStringsSuccess()) {
|
||||
// First try to alter the database. If it fails, raise an error telling
|
||||
// the user to do it themselves.
|
||||
$connection_options = $database_connection->getConnectionOptions();
|
||||
// It is safe to include the database name directly here, because this
|
||||
// code is only called when a connection to the database is already
|
||||
// established, thus the database name is guaranteed to be a correct
|
||||
// value.
|
||||
$query = "ALTER DATABASE \"" . $connection_options['database'] . "\" SET standard_conforming_strings = 'on';";
|
||||
try {
|
||||
$database_connection->query($query);
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
// Ignore possible errors when the user doesn't have the necessary
|
||||
// privileges to ALTER the database.
|
||||
}
|
||||
|
||||
// Close the database connection so that the configuration parameter
|
||||
// is applied to the current connection.
|
||||
Database::closeConnection();
|
||||
|
||||
// Recheck, if it fails, finally just rely on the end user to do the
|
||||
// right thing.
|
||||
if (!$this->checkStandardConformingStringsSuccess()) {
|
||||
$replacements = array(
|
||||
'%setting' => 'standard_conforming_strings',
|
||||
'%current_value' => 'off',
|
||||
'%needed_value' => 'on',
|
||||
'@query' => $query,
|
||||
);
|
||||
$this->fail(t("The %setting setting is currently set to '%current_value', but needs to be '%needed_value'. Change this by running the following query: <code>@query</code>", $replacements));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the standard_conforming_strings setting.
|
||||
*/
|
||||
protected function checkStandardConformingStringsSuccess() {
|
||||
$standard_conforming_strings = Database::getConnection()->query("SHOW standard_conforming_strings")->fetchField();
|
||||
return ($standard_conforming_strings == 'on');
|
||||
}
|
||||
|
||||
/**
|
||||
* Make PostgreSQL Drupal friendly.
|
||||
*/
|
||||
|
@ -195,18 +250,23 @@ class Tasks extends InstallTasks {
|
|||
// At the same time checking for the existence of the function fixes
|
||||
// concurrency issues, when both try to update at the same time.
|
||||
try {
|
||||
$connection = Database::getConnection();
|
||||
// Don't use {} around pg_proc table.
|
||||
if (!db_query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'rand'")->fetchField()) {
|
||||
db_query('CREATE OR REPLACE FUNCTION "rand"() RETURNS float AS
|
||||
if (!$connection->query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'rand'")->fetchField()) {
|
||||
$connection->query('CREATE OR REPLACE FUNCTION "rand"() RETURNS float AS
|
||||
\'SELECT random();\'
|
||||
LANGUAGE \'sql\''
|
||||
LANGUAGE \'sql\'',
|
||||
[],
|
||||
[ 'allow_delimiter_in_query' => TRUE ]
|
||||
);
|
||||
}
|
||||
|
||||
if (!db_query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'substring_index'")->fetchField()) {
|
||||
db_query('CREATE OR REPLACE FUNCTION "substring_index"(text, text, integer) RETURNS text AS
|
||||
if (!$connection->query("SELECT COUNT(*) FROM pg_proc WHERE proname = 'substring_index'")->fetchField()) {
|
||||
$connection->query('CREATE OR REPLACE FUNCTION "substring_index"(text, text, integer) RETURNS text AS
|
||||
\'SELECT array_to_string((string_to_array($1, $2)) [1:$3], $2);\'
|
||||
LANGUAGE \'sql\''
|
||||
LANGUAGE \'sql\'',
|
||||
[],
|
||||
[ 'allow_delimiter_in_query' => TRUE ]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -726,17 +726,23 @@ class Schema extends DatabaseSchema {
|
|||
// Usually, we do this via a simple typecast 'USING fieldname::type'. But
|
||||
// the typecast does not work for conversions to bytea.
|
||||
// @see http://www.postgresql.org/docs/current/static/datatype-binary.html
|
||||
$table_information = $this->queryTableInformation($table);
|
||||
$is_bytea = !empty($table_information->blob_fields[$field]);
|
||||
if ($spec['pgsql_type'] != 'bytea') {
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING "' . $field . '"::' . $field_def);
|
||||
if ($is_bytea) {
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING convert_from("' . $field . '"' . ", 'UTF8')");
|
||||
}
|
||||
else {
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING "' . $field . '"::' . $field_def);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Do not attempt to convert a field that is bytea already.
|
||||
$table_information = $this->queryTableInformation($table);
|
||||
if (!in_array($field, $table_information->blob_fields)) {
|
||||
if (!$is_bytea) {
|
||||
// Convert to a bytea type by using the SQL replace() function to
|
||||
// convert any single backslashes in the field content to double
|
||||
// backslashes ('\' to '\\').
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING decode(replace("' . $field . '"' . ", '\\', '\\\\'), 'escape');");
|
||||
$this->connection->query('ALTER TABLE {' . $table . '} ALTER "' . $field . '" TYPE ' . $field_def . ' USING decode(replace("' . $field . '"' . ", E'\\\\', E'\\\\\\\\'), 'escape');");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ class Schema extends DatabaseSchema {
|
|||
*/
|
||||
public function createTableSql($name, $table) {
|
||||
$sql = array();
|
||||
$sql[] = "CREATE TABLE {" . $name . "} (\n" . $this->createColumnsSql($name, $table) . "\n);\n";
|
||||
$sql[] = "CREATE TABLE {" . $name . "} (\n" . $this->createColumnsSql($name, $table) . "\n)\n";
|
||||
return array_merge($sql, $this->createIndexSql($name, $table));
|
||||
}
|
||||
|
||||
|
@ -60,12 +60,12 @@ class Schema extends DatabaseSchema {
|
|||
$info = $this->getPrefixInfo($tablename);
|
||||
if (!empty($schema['unique keys'])) {
|
||||
foreach ($schema['unique keys'] as $key => $fields) {
|
||||
$sql[] = 'CREATE UNIQUE INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $key . ' ON ' . $info['table'] . ' (' . $this->createKeySql($fields) . "); \n";
|
||||
$sql[] = 'CREATE UNIQUE INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $key . ' ON ' . $info['table'] . ' (' . $this->createKeySql($fields) . ")\n";
|
||||
}
|
||||
}
|
||||
if (!empty($schema['indexes'])) {
|
||||
foreach ($schema['indexes'] as $key => $fields) {
|
||||
$sql[] = 'CREATE INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $key . ' ON ' . $info['table'] . ' (' . $this->createKeySql($fields) . "); \n";
|
||||
$sql[] = 'CREATE INDEX ' . $info['schema'] . '.' . $info['table'] . '_' . $key . ' ON ' . $info['table'] . ' (' . $this->createKeySql($fields) . ")\n";
|
||||
}
|
||||
}
|
||||
return $sql;
|
||||
|
|
|
@ -188,6 +188,25 @@ class Condition implements ConditionInterface, \Countable {
|
|||
'operator' => $condition['operator'],
|
||||
'use_value' => TRUE,
|
||||
);
|
||||
// Remove potentially dangerous characters.
|
||||
// If something passed in an invalid character stop early, so we
|
||||
// don't rely on a broken SQL statement when we would just replace
|
||||
// those characters.
|
||||
if (stripos($condition['operator'], 'UNION') !== FALSE || strpbrk($condition['operator'], '[-\'"();') !== FALSE) {
|
||||
$this->changed = TRUE;
|
||||
$this->arguments = [];
|
||||
// Provide a string which will result into an empty query result.
|
||||
$this->stringVersion = '( AND 1 = 0 )';
|
||||
|
||||
// Conceptually throwing an exception caused by user input is bad
|
||||
// as you result into a WSOD, which depending on your webserver
|
||||
// configuration can result into the assumption that your site is
|
||||
// broken.
|
||||
// On top of that the database API relies on __toString() which
|
||||
// does not allow to throw exceptions.
|
||||
trigger_error('Invalid characters in query operator: ' . $condition['operator'], E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
$operator = $connection->mapConditionOperator($condition['operator']);
|
||||
if (!isset($operator)) {
|
||||
$operator = $this->mapConditionOperator($condition['operator']);
|
||||
|
|
|
@ -45,95 +45,140 @@ class SelectExtender implements SelectInterface {
|
|||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\PlaceholderInterface::uniqueIdentifier().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function uniqueIdentifier() {
|
||||
return $this->uniqueIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements Drupal\Core\Database\Query\PlaceholderInterface::nextPlaceholder().
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function nextPlaceholder() {
|
||||
return $this->placeholder++;
|
||||
}
|
||||
|
||||
/* Implementations of Drupal\Core\Database\Query\AlterableInterface. */
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addTag($tag) {
|
||||
$this->query->addTag($tag);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasTag($tag) {
|
||||
return $this->query->hasTag($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasAllTags() {
|
||||
return call_user_func_array(array($this->query, 'hasAllTags'), func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasAnyTag() {
|
||||
return call_user_func_array(array($this->query, 'hasAnyTag'), func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addMetaData($key, $object) {
|
||||
$this->query->addMetaData($key, $object);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMetaData($key) {
|
||||
return $this->query->getMetaData($key);
|
||||
}
|
||||
|
||||
/* Implementations of Drupal\Core\Database\Query\ConditionInterface for the WHERE clause. */
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function condition($field, $value = NULL, $operator = '=') {
|
||||
$this->query->condition($field, $value, $operator);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function &conditions() {
|
||||
return $this->query->conditions();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function arguments() {
|
||||
return $this->query->arguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function where($snippet, $args = array()) {
|
||||
$this->query->where($snippet, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function compile(Connection $connection, PlaceholderInterface $queryPlaceholder) {
|
||||
return $this->query->compile($connection, $queryPlaceholder);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function compiled() {
|
||||
return $this->query->compiled();
|
||||
}
|
||||
|
||||
/* Implementations of Drupal\Core\Database\Query\ConditionInterface for the HAVING clause. */
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function havingCondition($field, $value = NULL, $operator = '=') {
|
||||
$this->query->havingCondition($field, $value, $operator);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function &havingConditions() {
|
||||
return $this->query->havingConditions();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function havingArguments() {
|
||||
return $this->query->havingArguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function having($snippet, $args = array()) {
|
||||
$this->query->having($snippet, $args);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function havingCompile(Connection $connection) {
|
||||
return $this->query->havingCompile($connection);
|
||||
}
|
||||
|
@ -170,8 +215,9 @@ class SelectExtender implements SelectInterface {
|
|||
return $this;
|
||||
}
|
||||
|
||||
/* Implementations of Drupal\Core\Database\Query\ExtendableInterface. */
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function extend($extender_name) {
|
||||
$class = $this->connection->getDriverClass($extender_name);
|
||||
return new $class($this, $this->connection);
|
||||
|
@ -179,26 +225,44 @@ class SelectExtender implements SelectInterface {
|
|||
|
||||
/* Alter accessors to expose the query data to alter hooks. */
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function &getFields() {
|
||||
return $this->query->getFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function &getExpressions() {
|
||||
return $this->query->getExpressions();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function &getOrderBy() {
|
||||
return $this->query->getOrderBy();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function &getGroupBy() {
|
||||
return $this->query->getGroupBy();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function &getTables() {
|
||||
return $this->query->getTables();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function &getUnion() {
|
||||
return $this->query->getUnion();
|
||||
}
|
||||
|
@ -218,14 +282,23 @@ class SelectExtender implements SelectInterface {
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getArguments(PlaceholderInterface $queryPlaceholder = NULL) {
|
||||
return $this->query->getArguments($queryPlaceholder);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isPrepared() {
|
||||
return $this->query->isPrepared();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function preExecute(SelectInterface $query = NULL) {
|
||||
// If no query object is passed in, use $this.
|
||||
if (!isset($query)) {
|
||||
|
@ -235,6 +308,9 @@ class SelectExtender implements SelectInterface {
|
|||
return $this->query->preExecute($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute() {
|
||||
// By calling preExecute() here, we force it to preprocess the extender
|
||||
// object rather than just the base query object. That means
|
||||
|
@ -246,102 +322,168 @@ class SelectExtender implements SelectInterface {
|
|||
return $this->query->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function distinct($distinct = TRUE) {
|
||||
$this->query->distinct($distinct);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addField($table_alias, $field, $alias = NULL) {
|
||||
return $this->query->addField($table_alias, $field, $alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields($table_alias, array $fields = array()) {
|
||||
$this->query->fields($table_alias, $fields);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addExpression($expression, $alias = NULL, $arguments = array()) {
|
||||
return $this->query->addExpression($expression, $alias, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function join($table, $alias = NULL, $condition = NULL, $arguments = array()) {
|
||||
return $this->query->join($table, $alias, $condition, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function innerJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
|
||||
return $this->query->innerJoin($table, $alias, $condition, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function leftJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
|
||||
return $this->query->leftJoin($table, $alias, $condition, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function rightJoin($table, $alias = NULL, $condition = NULL, $arguments = array()) {
|
||||
return $this->query->rightJoin($table, $alias, $condition, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = array()) {
|
||||
return $this->query->addJoin($type, $table, $alias, $condition, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function orderBy($field, $direction = 'ASC') {
|
||||
$this->query->orderBy($field, $direction);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function orderRandom() {
|
||||
$this->query->orderRandom();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function range($start = NULL, $length = NULL) {
|
||||
$this->query->range($start, $length);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function union(SelectInterface $query, $type = '') {
|
||||
$this->query->union($query, $type);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function groupBy($field) {
|
||||
$this->query->groupBy($field);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function forUpdate($set = TRUE) {
|
||||
$this->query->forUpdate($set);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function countQuery() {
|
||||
return $this->query->countQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function isNull($field) {
|
||||
$this->query->isNull($field);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
function isNotNull($field) {
|
||||
$this->query->isNotNull($field);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function exists(SelectInterface $select) {
|
||||
$this->query->exists($select);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function notExists(SelectInterface $select) {
|
||||
$this->query->notExists($select);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString() {
|
||||
return (string) $this->query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __clone() {
|
||||
$this->uniqueIdentifier = uniqid('', TRUE);
|
||||
|
||||
|
|
|
@ -648,4 +648,12 @@ interface SelectInterface extends ConditionInterface, AlterableInterface, Extend
|
|||
*/
|
||||
public function forUpdate($set = TRUE);
|
||||
|
||||
/**
|
||||
* Returns a string representation of how the query will be executed in SQL.
|
||||
*
|
||||
* @return string
|
||||
* The Select Query object expressed as a string.
|
||||
*/
|
||||
public function __toString();
|
||||
|
||||
}
|
||||
|
|
|
@ -640,6 +640,8 @@ abstract class Schema implements PlaceholderInterface {
|
|||
* The prepared comment.
|
||||
*/
|
||||
public function prepareComment($comment, $length = NULL) {
|
||||
// Remove semicolons to avoid triggering multi-statement check.
|
||||
$comment = strtr($comment, [';' => '.']);
|
||||
return $this->connection->quote($comment);
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue