Issue #2358079 by pwolanin, Berdir: Require a specific placeholder format in db_query() in order to trigger argument expansion, and require explicit 'IN' parameter for conditions

8.0.x
Alex Pott 2015-02-03 09:42:28 +00:00
parent 58a891faa7
commit f46d6ad949
56 changed files with 147 additions and 115 deletions

View File

@ -246,7 +246,9 @@ use Drupal\Core\Site\Settings;
* @param $query * @param $query
* The prepared statement query to run. Although it will accept both named and * The prepared statement query to run. Although it will accept both named and
* unnamed placeholders, named placeholders are strongly preferred as they are * unnamed placeholders, named placeholders are strongly preferred as they are
* more self-documenting. * more self-documenting. If the argument corresponding to a placeholder is
* an array of values to be expanded, e.g. for an IN query, the placeholder
* should be named with a trailing bracket like :example[]
* @param $args * @param $args
* An array of values to substitute into the query. If the query uses named * An array of values to substitute into the query. If the query uses named
* placeholders, this is an associative array in any order. If the query uses * placeholders, this is an associative array in any order. If the query uses

View File

@ -86,7 +86,7 @@ class DatabaseBackend implements CacheBackendInterface {
// ::select() is a much smaller proportion of the request. // ::select() is a much smaller proportion of the request.
$result = array(); $result = array();
try { try {
$result = $this->connection->query('SELECT cid, data, created, expire, serialized, tags, checksum FROM {' . $this->connection->escapeTable($this->bin) . '} WHERE cid IN (:cids)', array(':cids' => array_keys($cid_mapping))); $result = $this->connection->query('SELECT cid, data, created, expire, serialized, tags, checksum FROM {' . $this->connection->escapeTable($this->bin) . '} WHERE cid IN ( :cids[] )', array(':cids[]' => array_keys($cid_mapping)));
} }
catch (\Exception $e) { catch (\Exception $e) {
// Nothing to do. // Nothing to do.

View File

@ -108,7 +108,7 @@ class DatabaseCacheTagsChecksum implements CacheTagsChecksumInterface, CacheTags
if ($query_tags) { if ($query_tags) {
$db_tags = array(); $db_tags = array();
try { try {
$db_tags = $this->connection->query('SELECT tag, invalidations FROM {cachetags} WHERE tag IN (:tags)', array(':tags' => $query_tags)) $db_tags = $this->connection->query('SELECT tag, invalidations FROM {cachetags} WHERE tag IN ( :tags[] )', array(':tags[]' => $query_tags))
->fetchAllKeyed(); ->fetchAllKeyed();
$this->tagCache += $db_tags; $this->tagCache += $db_tags;
} }

View File

@ -107,7 +107,7 @@ class DatabaseStorage implements StorageInterface {
public function readMultiple(array $names) { public function readMultiple(array $names) {
$list = array(); $list = array();
try { try {
$list = $this->connection->query('SELECT name, data FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name IN (:names)', array(':collection' => $this->collection, ':names' => $names), $this->options)->fetchAllKeyed(); $list = $this->connection->query('SELECT name, data FROM {' . $this->connection->escapeTable($this->table) . '} WHERE collection = :collection AND name IN ( :names[] )', array(':collection' => $this->collection, ':names[]' => $names), $this->options)->fetchAllKeyed();
foreach ($list as &$data) { foreach ($list as &$data) {
$data = $this->decode($data); $data = $this->decode($data);
} }

View File

@ -517,6 +517,7 @@ abstract class Connection implements \Serializable {
* *
* @throws \PDOException * @throws \PDOException
* @throws \Drupal\Core\Database\IntegrityConstraintViolationException * @throws \Drupal\Core\Database\IntegrityConstraintViolationException
* @throws \InvalidArgumentException
*/ */
public function query($query, array $args = array(), $options = array()) { public function query($query, array $args = array(), $options = array()) {
@ -581,38 +582,48 @@ abstract class Connection implements \Serializable {
* Drupal supports an alternate syntax for doing arrays of values. We * Drupal supports an alternate syntax for doing arrays of values. We
* therefore need to expand them out into a full, executable query string. * therefore need to expand them out into a full, executable query string.
* *
* @param $query * @param string $query
* The query string to modify. * The query string to modify.
* @param $args * @param array $args
* The arguments for the query. * The arguments for the query.
* *
* @return * @return bool
* TRUE if the query was modified, FALSE otherwise. * TRUE if the query was modified, FALSE otherwise.
*/ */
protected function expandArguments(&$query, &$args) { protected function expandArguments(&$query, &$args) {
$modified = FALSE; $modified = FALSE;
// If the placeholder value to insert is an array, assume that we need // If the placeholder indicated the value to use is an array, we need to
// to expand it out into a comma-delimited set of placeholders. // expand it out into a comma-delimited set of placeholders.
foreach (array_filter($args, 'is_array') as $key => $data) { foreach ($args as $key => $data) {
$is_bracket_placeholder = substr($key, -2) === '[]';
$is_array_data = is_array($data);
if ($is_bracket_placeholder && !$is_array_data) {
throw new \InvalidArgumentException('Placeholders with a trailing [] can only be expanded with an array of values.');
}
elseif (!$is_bracket_placeholder) {
if ($is_array_data) {
throw new \InvalidArgumentException('Placeholders must have a trailing [] if they are to be expanded with an array of values.');
}
// Scalar placeholder - does not need to be expanded.
continue;
}
// Handle expansion of arrays.
$key_name = str_replace('[]', '__', $key);
$new_keys = array(); $new_keys = array();
// We require placeholders to have trailing brackets if the developer
// intends them to be expanded to an array to make the intent explicit.
foreach (array_values($data) as $i => $value) { foreach (array_values($data) as $i => $value) {
// This assumes that there are no other placeholders that use the same // This assumes that there are no other placeholders that use the same
// name. For example, if the array placeholder is defined as :example // name. For example, if the array placeholder is defined as :example[]
// and there is already an :example_2 placeholder, this will generate // and there is already an :example_2 placeholder, this will generate
// a duplicate key. We do not account for that as the calling code // a duplicate key. We do not account for that as the calling code
// is already broken if that happens. // is already broken if that happens.
$new_keys[$key . '_' . $i] = $value; $new_keys[$key_name . $i] = $value;
} }
// Update the query with the new placeholders. // Update the query with the new placeholders.
// preg_replace is necessary to ensure the replacement does not affect $query = str_replace($key, implode(', ', array_keys($new_keys)), $query);
// placeholders that start with the same exact text. For example, if the
// query contains the placeholders :foo and :foobar, and :foo has an
// array of values, using str_replace would affect both placeholders,
// but using the following preg_replace would only affect :foo because
// it is followed by a non-word character.
$query = preg_replace('#' . $key . '\b#', implode(', ', array_keys($new_keys)), $query);
// Update the args array with the new placeholders. // Update the args array with the new placeholders.
unset($args[$key]); unset($args[$key]);

View File

@ -68,14 +68,9 @@ class Condition implements ConditionInterface, \Countable {
/** /**
* Implements Drupal\Core\Database\Query\ConditionInterface::condition(). * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
*/ */
public function condition($field, $value = NULL, $operator = NULL) { public function condition($field, $value = NULL, $operator = '=') {
if (!isset($operator)) { if (empty($operator)) {
if (is_array($value)) { $operator = '=';
$operator = 'IN';
}
else {
$operator = '=';
}
} }
if (empty($value) && is_array($value)) { if (empty($value) && is_array($value)) {
throw new InvalidQueryException(sprintf("Query condition '%s %s ()' cannot be empty.", $field, $operator)); throw new InvalidQueryException(sprintf("Query condition '%s %s ()' cannot be empty.", $field, $operator));
@ -211,7 +206,7 @@ class Condition implements ConditionInterface, \Countable {
// We assume that if there is a delimiter, then the value is an // We assume that if there is a delimiter, then the value is an
// array. If not, it is a scalar. For simplicity, we first convert // array. If not, it is a scalar. For simplicity, we first convert
// up to an array so that we can build the placeholders in the same way. // up to an array so that we can build the placeholders in the same way.
elseif (!$operator['delimiter']) { elseif (!$operator['delimiter'] && !is_array($condition['value'])) {
$condition['value'] = array($condition['value']); $condition['value'] = array($condition['value']);
} }
if ($operator['use_value']) { if ($operator['use_value']) {

View File

@ -46,8 +46,7 @@ interface ConditionInterface {
* the array is dependent on the $operator. * the array is dependent on the $operator.
* @param $operator * @param $operator
* The comparison operator, such as =, <, or >=. It also accepts more * The comparison operator, such as =, <, or >=. It also accepts more
* complex options such as IN, LIKE, LIKE BINARY, or BETWEEN. Defaults to IN * complex options such as IN, LIKE, LIKE BINARY, or BETWEEN. Defaults to =.
* if $value is an array, and = otherwise.
* *
* @return \Drupal\Core\Database\Query\ConditionInterface * @return \Drupal\Core\Database\Query\ConditionInterface
* The called object. * The called object.
@ -55,7 +54,7 @@ interface ConditionInterface {
* @see \Drupal\Core\Database\Query\ConditionInterface::isNull() * @see \Drupal\Core\Database\Query\ConditionInterface::isNull()
* @see \Drupal\Core\Database\Query\ConditionInterface::isNotNull() * @see \Drupal\Core\Database\Query\ConditionInterface::isNotNull()
*/ */
public function condition($field, $value = NULL, $operator = NULL); public function condition($field, $value = NULL, $operator = '=');
/** /**
* Adds an arbitrary WHERE clause to the query. * Adds an arbitrary WHERE clause to the query.

View File

@ -54,7 +54,7 @@ class Delete extends Query implements ConditionInterface {
/** /**
* Implements Drupal\Core\Database\Query\ConditionInterface::condition(). * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
*/ */
public function condition($field, $value = NULL, $operator = NULL) { public function condition($field, $value = NULL, $operator = '=') {
$this->condition->condition($field, $value, $operator); $this->condition->condition($field, $value, $operator);
return $this; return $this;
} }

View File

@ -342,7 +342,7 @@ class Merge extends Query implements ConditionInterface {
/** /**
* Implements Drupal\Core\Database\Query\ConditionInterface::condition(). * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
*/ */
public function condition($field, $value = NULL, $operator = NULL) { public function condition($field, $value = NULL, $operator = '=') {
$this->condition->condition($field, $value, $operator); $this->condition->condition($field, $value, $operator);
return $this; return $this;
} }

View File

@ -191,7 +191,7 @@ class Select extends Query implements SelectInterface {
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function condition($field, $value = NULL, $operator = NULL) { public function condition($field, $value = NULL, $operator = '=') {
$this->where->condition($field, $value, $operator); $this->where->condition($field, $value, $operator);
return $this; return $this;
} }

View File

@ -88,7 +88,7 @@ class SelectExtender implements SelectInterface {
/* Implementations of Drupal\Core\Database\Query\ConditionInterface for the WHERE clause. */ /* Implementations of Drupal\Core\Database\Query\ConditionInterface for the WHERE clause. */
public function condition($field, $value = NULL, $operator = NULL) { public function condition($field, $value = NULL, $operator = '=') {
$this->query->condition($field, $value, $operator); $this->query->condition($field, $value, $operator);
return $this; return $this;
} }

View File

@ -83,7 +83,7 @@ class Update extends Query implements ConditionInterface {
/** /**
* Implements Drupal\Core\Database\Query\ConditionInterface::condition(). * Implements Drupal\Core\Database\Query\ConditionInterface::condition().
*/ */
public function condition($field, $value = NULL, $operator = NULL) { public function condition($field, $value = NULL, $operator = '=') {
$this->condition->condition($field, $value, $operator); $this->condition->condition($field, $value, $operator);
return $this; return $this;
} }

View File

@ -454,7 +454,8 @@ abstract class EntityStorageBase extends EntityHandlerBase implements EntityStor
*/ */
protected function buildPropertyQuery(QueryInterface $entity_query, array $values) { protected function buildPropertyQuery(QueryInterface $entity_query, array $values) {
foreach ($values as $name => $value) { foreach ($values as $name => $value) {
$entity_query->condition($name, $value); // Cast scalars to array so we can consistently use an IN condition.
$entity_query->condition($name, (array) $value, 'IN');
} }
} }

View File

@ -667,7 +667,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
$table = $this->revisionDataTable ?: $this->dataTable; $table = $this->revisionDataTable ?: $this->dataTable;
$query = $this->database->select($table, 'data', array('fetch' => \PDO::FETCH_ASSOC)) $query = $this->database->select($table, 'data', array('fetch' => \PDO::FETCH_ASSOC))
->fields('data') ->fields('data')
->condition($this->idKey, array_keys($entities)) ->condition($this->idKey, array_keys($entities), 'IN')
->orderBy('data.' . $this->idKey); ->orderBy('data.' . $this->idKey);
if ($this->revisionDataTable) { if ($this->revisionDataTable) {
@ -676,7 +676,7 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
foreach ($entities as $values) { foreach ($entities as $values) {
$revision_ids[] = is_object($values) ? $values->getRevisionId() : $values[$this->revisionKey][LanguageInterface::LANGCODE_DEFAULT]; $revision_ids[] = is_object($values) ? $values->getRevisionId() : $values[$this->revisionKey][LanguageInterface::LANGCODE_DEFAULT];
} }
$query->condition($this->revisionKey, $revision_ids); $query->condition($this->revisionKey, $revision_ids, 'IN');
} }
$data = $query->execute(); $data = $query->execute();
@ -878,24 +878,24 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
$ids = array_keys($entities); $ids = array_keys($entities);
$this->database->delete($this->entityType->getBaseTable()) $this->database->delete($this->entityType->getBaseTable())
->condition($this->idKey, $ids) ->condition($this->idKey, $ids, 'IN')
->execute(); ->execute();
if ($this->revisionTable) { if ($this->revisionTable) {
$this->database->delete($this->revisionTable) $this->database->delete($this->revisionTable)
->condition($this->idKey, $ids) ->condition($this->idKey, $ids, 'IN')
->execute(); ->execute();
} }
if ($this->dataTable) { if ($this->dataTable) {
$this->database->delete($this->dataTable) $this->database->delete($this->dataTable)
->condition($this->idKey, $ids) ->condition($this->idKey, $ids, 'IN')
->execute(); ->execute();
} }
if ($this->revisionDataTable) { if ($this->revisionDataTable) {
$this->database->delete($this->revisionDataTable) $this->database->delete($this->revisionDataTable)
->condition($this->idKey, $ids) ->condition($this->idKey, $ids, 'IN')
->execute(); ->execute();
} }

View File

@ -75,7 +75,7 @@ class DatabaseStorage extends StorageBase {
public function getMultiple(array $keys) { public function getMultiple(array $keys) {
$values = array(); $values = array();
try { try {
$result = $this->connection->query('SELECT name, value FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name IN (:keys) AND collection = :collection', array(':keys' => $keys, ':collection' => $this->collection))->fetchAllAssoc('name'); $result = $this->connection->query('SELECT name, value FROM {' . $this->connection->escapeTable($this->table) . '} WHERE name IN ( :keys[] ) AND collection = :collection', array(':keys[]' => $keys, ':collection' => $this->collection))->fetchAllAssoc('name');
foreach ($keys as $key) { foreach ($keys as $key) {
if (isset($result[$key])) { if (isset($result[$key])) {
$values[$key] = $this->serializer->decode($result[$key]->value); $values[$key] = $this->serializer->decode($result[$key]->value);
@ -152,7 +152,7 @@ class DatabaseStorage extends StorageBase {
// Delete in chunks when a large array is passed. // Delete in chunks when a large array is passed.
while ($keys) { while ($keys) {
$this->connection->delete($this->table) $this->connection->delete($this->table)
->condition('name', array_splice($keys, 0, 1000)) ->condition('name', array_splice($keys, 0, 1000), 'IN')
->condition('collection', $this->collection) ->condition('collection', $this->collection)
->execute(); ->execute();
} }

View File

@ -51,10 +51,10 @@ class DatabaseStorageExpirable extends DatabaseStorage implements KeyValueStoreE
*/ */
public function getMultiple(array $keys) { public function getMultiple(array $keys) {
$values = $this->connection->query( $values = $this->connection->query(
'SELECT name, value FROM {' . $this->connection->escapeTable($this->table) . '} WHERE expire > :now AND name IN (:keys) AND collection = :collection', 'SELECT name, value FROM {' . $this->connection->escapeTable($this->table) . '} WHERE expire > :now AND name IN ( :keys[] ) AND collection = :collection',
array( array(
':now' => REQUEST_TIME, ':now' => REQUEST_TIME,
':keys' => $keys, ':keys[]' => $keys,
':collection' => $this->collection, ':collection' => $this->collection,
))->fetchAllKeyed(); ))->fetchAllKeyed();
return array_map(array($this->serializer, 'decode'), $values); return array_map(array($this->serializer, 'decode'), $values);

View File

@ -114,7 +114,7 @@ class DefaultMenuLinkTreeManipulators {
$nids = array_keys($node_links); $nids = array_keys($node_links);
$query = $this->queryFactory->get('node'); $query = $this->queryFactory->get('node');
$query->condition('nid', $nids); $query->condition('nid', $nids, 'IN');
// Allows admins to view all nodes, by both disabling node_access // Allows admins to view all nodes, by both disabling node_access
// query rewrite as well as not checking for the node status. The // query rewrite as well as not checking for the node status. The

View File

@ -118,7 +118,7 @@ class AliasStorage implements AliasStorageInterface {
*/ */
public function preloadPathAlias($preloaded, $langcode) { public function preloadPathAlias($preloaded, $langcode) {
$args = array( $args = array(
':system' => $preloaded, ':system[]' => $preloaded,
':langcode' => $langcode, ':langcode' => $langcode,
':langcode_undetermined' => LanguageInterface::LANGCODE_NOT_SPECIFIED, ':langcode_undetermined' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
); );
@ -132,13 +132,13 @@ class AliasStorage implements AliasStorageInterface {
if ($langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) { if ($langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) {
// Prevent PDO from complaining about a token the query doesn't use. // Prevent PDO from complaining about a token the query doesn't use.
unset($args[':langcode']); unset($args[':langcode']);
$result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND langcode = :langcode_undetermined ORDER BY pid ASC', $args); $result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN ( :system[] ) AND langcode = :langcode_undetermined ORDER BY pid ASC', $args);
} }
elseif ($langcode < LanguageInterface::LANGCODE_NOT_SPECIFIED) { elseif ($langcode < LanguageInterface::LANGCODE_NOT_SPECIFIED) {
$result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode ASC, pid ASC', $args); $result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN ( :system[] ) AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode ASC, pid ASC', $args);
} }
else { else {
$result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode DESC, pid ASC', $args); $result = $this->connection->query('SELECT source, alias FROM {url_alias} WHERE source IN ( :system[] ) AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode DESC, pid ASC', $args);
} }
return $result->fetchAllKeyed(); return $result->fetchAllKeyed();

View File

@ -178,7 +178,7 @@ class RouteProvider implements RouteProviderInterface, PagedRouteProviderInterfa
$routes_to_load = array_diff($names, array_keys($this->routes)); $routes_to_load = array_diff($names, array_keys($this->routes));
if ($routes_to_load) { if ($routes_to_load) {
$result = $this->connection->query('SELECT name, route FROM {' . $this->connection->escapeTable($this->tableName) . '} WHERE name IN (:names)', array(':names' => $routes_to_load)); $result = $this->connection->query('SELECT name, route FROM {' . $this->connection->escapeTable($this->tableName) . '} WHERE name IN ( :names[] )', array(':names[]' => $routes_to_load));
$routes = $result->fetchAllKeyed(); $routes = $result->fetchAllKeyed();
foreach ($routes as $name => $route) { foreach ($routes as $name => $route) {
@ -289,8 +289,8 @@ class RouteProvider implements RouteProviderInterface, PagedRouteProviderInterfa
return $collection; return $collection;
} }
$routes = $this->connection->query("SELECT name, route FROM {" . $this->connection->escapeTable($this->tableName) . "} WHERE pattern_outline IN (:patterns) ORDER BY fit DESC, name ASC", array( $routes = $this->connection->query("SELECT name, route FROM {" . $this->connection->escapeTable($this->tableName) . "} WHERE pattern_outline IN ( :patterns[] ) ORDER BY fit DESC, name ASC", array(
':patterns' => $ancestors, ':patterns[]' => $ancestors,
)) ))
->fetchAllKeyed(); ->fetchAllKeyed();

View File

@ -214,7 +214,7 @@ class BlockContentForm extends ContentEntityForm {
*/ */
public function validateForm(array &$form, FormStateInterface $form_state) { public function validateForm(array &$form, FormStateInterface $form_state) {
if ($this->entity->isNew()) { if ($this->entity->isNew()) {
$exists = $this->blockContentStorage->loadByProperties(array('info' => $form_state->getValue('info'))); $exists = $this->blockContentStorage->loadByProperties(array('info' => $form_state->getValue(['info', 0, 'value'])));
if (!empty($exists)) { if (!empty($exists)) {
$form_state->setErrorByName('info', $this->t('A block with description %name already exists.', array( $form_state->setErrorByName('info', $this->t('A block with description %name already exists.', array(
'%name' => $form_state->getValue(array('info', 0, 'value')), '%name' => $form_state->getValue(array('info', 0, 'value')),

View File

@ -886,7 +886,7 @@ class BookManager implements BookManagerInterface {
// @todo This should be actually filtering on the desired node status field // @todo This should be actually filtering on the desired node status field
// language and just fall back to the default language. // language and just fall back to the default language.
$nids = \Drupal::entityQuery('node') $nids = \Drupal::entityQuery('node')
->condition('nid', $nids) ->condition('nid', $nids, 'IN')
->condition('status', 1) ->condition('status', 1)
->execute(); ->execute();

View File

@ -50,7 +50,7 @@ class BookOutlineStorage implements BookOutlineStorageInterface {
public function loadMultiple($nids, $access = TRUE) { public function loadMultiple($nids, $access = TRUE) {
$query = $this->connection->select('book', 'b', array('fetch' => \PDO::FETCH_ASSOC)); $query = $this->connection->select('book', 'b', array('fetch' => \PDO::FETCH_ASSOC));
$query->fields('b'); $query->fields('b');
$query->condition('b.nid', $nids); $query->condition('b.nid', $nids, 'IN');
if ($access) { if ($access) {
$query->addTag('node_access'); $query->addTag('node_access');

View File

@ -72,7 +72,7 @@ class CommentStatistics implements CommentStatisticsInterface {
$options = $accurate ? array() : array('target' => 'replica'); $options = $accurate ? array() : array('target' => 'replica');
$stats = $this->database->select('comment_entity_statistics', 'ces', $options) $stats = $this->database->select('comment_entity_statistics', 'ces', $options)
->fields('ces') ->fields('ces')
->condition('ces.entity_id', array_keys($entities)) ->condition('ces.entity_id', array_keys($entities), 'IN')
->condition('ces.entity_type', $entity_type) ->condition('ces.entity_type', $entity_type)
->execute(); ->execute();

View File

@ -199,7 +199,7 @@ class CommentStorage extends SqlContentEntityStorage implements CommentStorageIn
public function getChildCids(array $comments) { public function getChildCids(array $comments) {
return $this->database->select('comment_field_data', 'c') return $this->database->select('comment_field_data', 'c')
->fields('c', array('cid')) ->fields('c', array('cid'))
->condition('pid', array_keys($comments)) ->condition('pid', array_keys($comments), 'IN')
->condition('default_langcode', 1) ->condition('default_langcode', 1)
->execute() ->execute()
->fetchCol(); ->fetchCol();

View File

@ -120,11 +120,11 @@ class NodeNewComments extends Numeric {
if ($nids) { if ($nids) {
$result = $this->database->query("SELECT n.nid, COUNT(c.cid) as num_comments FROM {node} n INNER JOIN {comment_field_data} c ON n.nid = c.entity_id AND c.entity_type = 'node' AND c.default_langcode = 1 $result = $this->database->query("SELECT n.nid, COUNT(c.cid) as num_comments FROM {node} n INNER JOIN {comment_field_data} c ON n.nid = c.entity_id AND c.entity_type = 'node' AND c.default_langcode = 1
LEFT JOIN {history} h ON h.nid = n.nid AND h.uid = :h_uid WHERE n.nid IN (:nids) LEFT JOIN {history} h ON h.nid = n.nid AND h.uid = :h_uid WHERE n.nid IN ( :nids[] )
AND c.changed > GREATEST(COALESCE(h.timestamp, :timestamp), :timestamp) AND c.status = :status GROUP BY n.nid", array( AND c.changed > GREATEST(COALESCE(h.timestamp, :timestamp), :timestamp) AND c.status = :status GROUP BY n.nid", array(
':status' => CommentInterface::PUBLISHED, ':status' => CommentInterface::PUBLISHED,
':h_uid' => $user->id(), ':h_uid' => $user->id(),
':nids' => $nids, ':nids[]' => $nids,
':timestamp' => HISTORY_READ_LIMIT, ':timestamp' => HISTORY_READ_LIMIT,
)); ));
foreach ($result as $node) { foreach ($result as $node) {

View File

@ -75,7 +75,7 @@ class Fid extends Numeric implements ContainerFactoryPluginInterface {
*/ */
public function titleQuery() { public function titleQuery() {
$fids = $this->entityQuery->get('file') $fids = $this->entityQuery->get('file')
->condition('fid', $this->value) ->condition('fid', $this->value, 'IN')
->execute(); ->execute();
$controller = $this->entityManager->getStorage('file'); $controller = $this->entityManager->getStorage('file');
$files = $controller->loadMultiple($fids); $files = $controller->loadMultiple($fids);

View File

@ -58,7 +58,7 @@ class ForumIndexStorage implements ForumIndexStorageInterface {
public function read(array $vids) { public function read(array $vids) {
return $this->database->select('forum', 'f') return $this->database->select('forum', 'f')
->fields('f', array('nid', 'tid')) ->fields('f', array('nid', 'tid'))
->condition('f.vid', $vids) ->condition('f.vid', $vids, 'IN')
->execute(); ->execute();
} }

View File

@ -205,7 +205,7 @@ class ForumManager implements ForumManagerInterface {
$query $query
->orderBy('f.sticky', 'DESC') ->orderBy('f.sticky', 'DESC')
->orderByHeader($header) ->orderByHeader($header)
->condition('n.nid', $nids) ->condition('n.nid', $nids, 'IN')
// @todo This should be actually filtering on the desired node language // @todo This should be actually filtering on the desired node language
// and just fall back to the default language. // and just fall back to the default language.
->condition('n.default_langcode', 1); ->condition('n.default_langcode', 1);

View File

@ -116,8 +116,9 @@ class EntityReferenceItemNormalizer extends FieldItemNormalizer implements UuidR
public function getUuid($data) { public function getUuid($data) {
if (isset($data['uuid'])) { if (isset($data['uuid'])) {
$uuid = $data['uuid']; $uuid = $data['uuid'];
if (is_array($uuid)) { // The value may be a nested array like $uuid[0]['value'].
$uuid = reset($uuid); if (is_array($uuid) && isset($uuid[0]['value'])) {
$uuid = $uuid[0]['value'];
} }
return $uuid; return $uuid;
} }

View File

@ -79,9 +79,9 @@ function history_read_multiple($nids) {
return $return; return $return;
} }
$result = db_query('SELECT nid, timestamp FROM {history} WHERE uid = :uid AND nid IN(:nids)', array( $result = db_query('SELECT nid, timestamp FROM {history} WHERE uid = :uid AND nid IN ( :nids[] )', array(
':uid' => \Drupal::currentUser()->id(), ':uid' => \Drupal::currentUser()->id(),
':nids' => array_keys($nodes_to_read), ':nids[]' => array_keys($nodes_to_read),
)); ));
foreach ($result as $row) { foreach ($result as $row) {
$nodes_to_read[$row->nid] = (int) $row->timestamp; $nodes_to_read[$row->nid] = (int) $row->timestamp;

View File

@ -406,7 +406,8 @@ class ImageItem extends FileItem {
); );
// Convert the stored UUID to a FID. // Convert the stored UUID to a FID.
$fids = []; $fids = [];
if ($file = $this->getEntityManager()->loadEntityByUuid('file', $settings['default_image']['uuid'])) { $uuid = $settings['default_image']['uuid'];
if ($uuid && ($file = $this->getEntityManager()->loadEntityByUuid('file', $uuid))) {
$fids[0] = $file->id(); $fids[0] = $file->id();
} }
$element['default_image']['uuid'] = array( $element['default_image']['uuid'] = array(

View File

@ -793,10 +793,10 @@ function locale_translation_update_file_history($file) {
function locale_translation_file_history_delete($projects = array(), $langcodes = array()) { function locale_translation_file_history_delete($projects = array(), $langcodes = array()) {
$query = db_delete('locale_file'); $query = db_delete('locale_file');
if (!empty($projects)) { if (!empty($projects)) {
$query->condition('project', $projects); $query->condition('project', $projects, 'IN');
} }
if (!empty($langcodes)) { if (!empty($langcodes)) {
$query->condition('langcode', $langcodes); $query->condition('langcode', $langcodes, 'IN');
} }
$query->execute(); $query->execute();
} }

View File

@ -333,7 +333,7 @@ function locale_cron_fill_queue() {
return $project['status'] == 1; return $project['status'] == 1;
}); });
$files = db_select('locale_file', 'f') $files = db_select('locale_file', 'f')
->condition('f.project', array_keys($projects)) ->condition('f.project', array_keys($projects), 'IN')
->condition('f.last_checked', $last, '<') ->condition('f.last_checked', $last, '<')
->fields('f', array('project', 'langcode')) ->fields('f', array('project', 'langcode'))
->execute()->fetchAll(); ->execute()->fetchAll();

View File

@ -93,7 +93,8 @@ class StringDatabaseStorage implements StringStorageInterface {
$query = $this->connection->select('locales_location', 'l', $this->options) $query = $this->connection->select('locales_location', 'l', $this->options)
->fields('l'); ->fields('l');
foreach ($conditions as $field => $value) { foreach ($conditions as $field => $value) {
$query->condition('l.' . $field, $value); // Cast scalars to array so we can consistently use an IN condition.
$query->condition('l.' . $field, (array) $value, 'IN');
} }
return $query->execute()->fetchAll(); return $query->execute()->fetchAll();
} }
@ -398,13 +399,14 @@ class StringDatabaseStorage implements StringStorageInterface {
} }
// If we have conditions for location's type or name, then we need the // If we have conditions for location's type or name, then we need the
// location table, for which we add a subquery. // location table, for which we add a subquery. We cast any scalar value to
// array so we can consistently use IN conditions.
if (isset($conditions['type']) || isset($conditions['name'])) { if (isset($conditions['type']) || isset($conditions['name'])) {
$subquery = $this->connection->select('locales_location', 'l', $this->options) $subquery = $this->connection->select('locales_location', 'l', $this->options)
->fields('l', array('sid')); ->fields('l', array('sid'));
foreach (array('type', 'name') as $field) { foreach (array('type', 'name') as $field) {
if (isset($conditions[$field])) { if (isset($conditions[$field])) {
$subquery->condition('l.' . $field, $conditions[$field]); $subquery->condition('l.' . $field, (array) $conditions[$field], 'IN');
unset($conditions[$field]); unset($conditions[$field]);
} }
} }
@ -422,12 +424,12 @@ class StringDatabaseStorage implements StringStorageInterface {
// Conditions for target fields when doing an outer join only make // Conditions for target fields when doing an outer join only make
// sense if we add also OR field IS NULL. // sense if we add also OR field IS NULL.
$query->condition(db_or() $query->condition(db_or()
->condition($field_alias, $value) ->condition($field_alias, (array) $value, 'IN')
->isNull($field_alias) ->isNull($field_alias)
); );
} }
else { else {
$query->condition($field_alias, $value); $query->condition($field_alias, (array) $value, 'IN');
} }
} }

View File

@ -22,7 +22,8 @@ class VariableMultiRow extends DrupalSqlBase {
public function query() { public function query() {
return $this->select('variable', 'v') return $this->select('variable', 'v')
->fields('v', array('name', 'value')) ->fields('v', array('name', 'value'))
->condition('name', $this->configuration['variables']); // Cast scalars to array so we can consistently use an IN condition.
->condition('name', (array) $this->configuration['variables'], 'IN');
} }
/** /**

View File

@ -45,7 +45,7 @@ class CommentVariable extends DrupalSqlBase {
} }
} }
$return = array(); $return = array();
$values = $this->getDatabase()->query('SELECT name, value FROM {variable} WHERE name IN (:name)', array(':name' => $variables))->fetchAllKeyed(); $values = $this->getDatabase()->query('SELECT name, value FROM {variable} WHERE name IN ( :name[] )', array(':name[]' => $variables))->fetchAllKeyed();
foreach ($node_types as $node_type) { foreach ($node_types as $node_type) {
foreach ($comment_prefixes as $prefix) { foreach ($comment_prefixes as $prefix) {
$name = $prefix . '_' . $node_type; $name = $prefix . '_' . $node_type;

View File

@ -33,7 +33,7 @@ class UploadInstance extends DrupalSqlBase {
$max_filesize = $max_filesize ? $max_filesize . 'MB' : ''; $max_filesize = $max_filesize ? $max_filesize . 'MB' : '';
$file_extensions = $this->variableGet('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'); $file_extensions = $this->variableGet('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp');
$return = array(); $return = array();
$values = $this->getDatabase()->query('SELECT name, value FROM {variable} WHERE name IN (:name)', array(':name' => $variables))->fetchAllKeyed(); $values = $this->getDatabase()->query('SELECT name, value FROM {variable} WHERE name IN ( :name[] )', array(':name[]' => $variables))->fetchAllKeyed();
foreach ($node_types as $node_type) { foreach ($node_types as $node_type) {
$name = $prefix . '_' . $node_type; $name = $prefix . '_' . $node_type;
if (isset($values[$name])) { if (isset($values[$name])) {

View File

@ -74,7 +74,7 @@ class Vid extends Numeric {
public function titleQuery() { public function titleQuery() {
$titles = array(); $titles = array();
$results = $this->database->query('SELECT nr.vid, nr.nid, npr.title FROM {node_revision} nr WHERE nr.vid IN (:vids)', array(':vids' => $this->value))->fetchAllAssoc('vid', PDO::FETCH_ASSOC); $results = $this->database->query('SELECT nr.vid, nr.nid, npr.title FROM {node_revision} nr WHERE nr.vid IN ( :vids[] )', array(':vids[]' => $this->value))->fetchAllAssoc('vid', PDO::FETCH_ASSOC);
$nids = array(); $nids = array();
foreach ($results as $result) { foreach ($results as $result) {
$nids[] = $result['nid']; $nids[] = $result['nid'];

View File

@ -21,7 +21,7 @@ class UidRevision extends Name {
public function query($group_by = FALSE) { public function query($group_by = FALSE) {
$this->ensureMyTable(); $this->ensureMyTable();
$placeholder = $this->placeholder(); $placeholder = $this->placeholder() . '[]';
$args = array_values($this->value); $args = array_values($this->value);

View File

@ -124,7 +124,7 @@ function _options_values_in_use($entity_type, $field_name, $values) {
if ($values) { if ($values) {
$factory = \Drupal::service('entity.query'); $factory = \Drupal::service('entity.query');
$result = $factory->get($entity_type) $result = $factory->get($entity_type)
->condition($field_name . '.value', $values) ->condition($field_name . '.value', $values, 'IN')
->count() ->count()
->accessCheck(FALSE) ->accessCheck(FALSE)
->range(0, 1) ->range(0, 1)

View File

@ -7,21 +7,36 @@
namespace Drupal\system\Tests\Database; namespace Drupal\system\Tests\Database;
use Drupal\Core\Database\DatabaseExceptionWrapper;
/** /**
* Tests Drupal's extended prepared statement syntax.. * Tests Drupal's extended prepared statement syntax..
* *
* @group Database * @group Database
*/ */
class QueryTest extends DatabaseTestBase { class QueryTest extends DatabaseTestBase {
/** /**
* Tests that we can pass an array of values directly in the query. * Tests that we can pass an array of values directly in the query.
*/ */
function testArraySubstitution() { function testArraySubstitution() {
$names = db_query('SELECT name FROM {test} WHERE age IN (:ages) ORDER BY age', array(':ages' => array(25, 26, 27)))->fetchAll(); $names = db_query('SELECT name FROM {test} WHERE age IN ( :ages[] ) ORDER BY age', array(':ages[]' => array(25, 26, 27)))->fetchAll();
$this->assertEqual(count($names), 3, 'Correct number of names returned'); $this->assertEqual(count($names), 3, 'Correct number of names returned');
$names = db_query('SELECT name FROM {test} WHERE age IN ( :ages[] ) ORDER BY age', array(':ages[]' => array(25)))->fetchAll();
$this->assertEqual(count($names), 1, 'Correct number of names returned');
}
/**
* Tests that we can not pass a scalar value when an array is expected.
*/
function testScalarSubstitution() {
try {
$names = db_query('SELECT name FROM {test} WHERE age IN ( :ages[] ) ORDER BY age', array(':ages[]' => 25))->fetchAll();
$this->fail('Array placeholder with scalar argument should result in an exception.');
}
catch (\InvalidArgumentException $e) {
$this->pass('Array placeholder with scalar argument should result in an exception.');
}
} }
/** /**
@ -37,7 +52,7 @@ class QueryTest extends DatabaseTestBase {
db_query("SELECT * FROM {test} WHERE name = :name", array(':name' => $condition))->fetchObject(); db_query("SELECT * FROM {test} WHERE name = :name", array(':name' => $condition))->fetchObject();
$this->fail('SQL injection attempt via array arguments should result in a database exception.'); $this->fail('SQL injection attempt via array arguments should result in a database exception.');
} }
catch (DatabaseExceptionWrapper $e) { catch (\InvalidArgumentException $e) {
$this->pass('SQL injection attempt via array arguments should result in a database exception.'); $this->pass('SQL injection attempt via array arguments should result in a database exception.');
} }

View File

@ -264,11 +264,11 @@ class EntityTranslationTest extends EntityLanguageTestBase {
// query. // query.
$query = \Drupal::entityQuery($entity_type); $query = \Drupal::entityQuery($entity_type);
$group = $query->andConditionGroup() $group = $query->andConditionGroup()
->condition('user_id', $properties[$default_langcode]['user_id'], '=', $default_langcode) ->condition('user_id', $properties[$default_langcode]['user_id'][0], '=', $default_langcode)
->condition('name', $properties[$default_langcode]['name'], '=', $default_langcode); ->condition('name', $properties[$default_langcode]['name'][0], '=', $default_langcode);
$result = $query $result = $query
->condition($group) ->condition($group)
->condition('name', $properties[$langcode]['name'], '=', $langcode) ->condition('name', $properties[$langcode]['name'][0], '=', $langcode)
->execute(); ->execute();
$this->assertEqual(count($result), 1, format_string('%entity_type: One entity loaded by name and uid using different language meta conditions.', array('%entity_type' => $entity_type))); $this->assertEqual(count($result), 1, format_string('%entity_type: One entity loaded by name and uid using different language meta conditions.', array('%entity_type' => $entity_type)));
@ -279,10 +279,10 @@ class EntityTranslationTest extends EntityLanguageTestBase {
$entity->save(); $entity->save();
$query = \Drupal::entityQuery($entity_type); $query = \Drupal::entityQuery($entity_type);
$default_langcode_group = $query->andConditionGroup() $default_langcode_group = $query->andConditionGroup()
->condition('user_id', $properties[$default_langcode]['user_id'], '=', $default_langcode) ->condition('user_id', $properties[$default_langcode]['user_id'][0], '=', $default_langcode)
->condition('name', $properties[$default_langcode]['name'], '=', $default_langcode); ->condition('name', $properties[$default_langcode]['name'][0], '=', $default_langcode);
$langcode_group = $query->andConditionGroup() $langcode_group = $query->andConditionGroup()
->condition('name', $properties[$langcode]['name'], '=', $langcode) ->condition('name', $properties[$langcode]['name'][0], '=', $langcode)
->condition("$this->field_name.value", $field_value, '=', $langcode); ->condition("$this->field_name.value", $field_value, '=', $langcode);
$result = $query $result = $query
->condition($langcode_key, $default_langcode) ->condition($langcode_key, $default_langcode)

View File

@ -363,7 +363,7 @@ class TaxonomyIndexTid extends ManyToOne {
} }
$query = \Drupal::entityQuery('taxonomy_term') $query = \Drupal::entityQuery('taxonomy_term')
->condition('name', $names) ->condition('name', $names, 'IN')
->condition('vid', $this->options['vid']) ->condition('vid', $this->options['vid'])
->addTag('term_access'); ->addTag('term_access');
$terms = Term::loadMultiple($query->execute()); $terms = Term::loadMultiple($query->execute());

View File

@ -136,7 +136,7 @@ class NodeTermData extends RelationshipPluginBase {
$query = db_select('taxonomy_term_data', 'td'); $query = db_select('taxonomy_term_data', 'td');
$query->addJoin($def['type'], 'taxonomy_index', 'tn', 'tn.tid = td.tid'); $query->addJoin($def['type'], 'taxonomy_index', 'tn', 'tn.tid = td.tid');
$query->condition('td.vid', array_filter($this->options['vids'])); $query->condition('td.vid', array_filter($this->options['vids']), 'IN');
$query->addTag('term_access'); $query->addTag('term_access');
$query->fields('td'); $query->fields('td');
$query->fields('tn', array('nid')); $query->fields('tn', array('nid'));

View File

@ -101,7 +101,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
*/ */
public function deleteTermHierarchy($tids) { public function deleteTermHierarchy($tids) {
$this->database->delete('taxonomy_term_hierarchy') $this->database->delete('taxonomy_term_hierarchy')
->condition('tid', $tids) ->condition('tid', $tids, 'IN')
->execute(); ->execute();
} }

View File

@ -27,7 +27,7 @@ class VocabularyStorage extends ConfigEntityStorage implements VocabularyStorage
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getToplevelTids($vids) { public function getToplevelTids($vids) {
return db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} th ON th.tid = t.tid WHERE t.vid IN (:vids) AND th.parent = 0', array(':vids' => $vids))->fetchCol(); return db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} th ON th.tid = t.tid WHERE t.vid IN ( :vids[] ) AND th.parent = 0', array(':vids[]' => $vids))->fetchCol();
} }
} }

View File

@ -26,7 +26,8 @@ class UserUid extends Name {
// table, we need to make sure {tracker_user} is JOINed and use its alias // table, we need to make sure {tracker_user} is JOINed and use its alias
// for the WHERE clause. // for the WHERE clause.
$tracker_user_alias = $this->query->ensureTable('tracker_user'); $tracker_user_alias = $this->query->ensureTable('tracker_user');
$this->query->addWhere(0, "$tracker_user_alias.uid", $this->value); // Cast scalars to array so we can consistently use an IN condition.
$this->query->addWhere(0, "$tracker_user_alias.uid", (array) $this->value, 'IN');
} }
} }

View File

@ -79,7 +79,7 @@ class Roles extends PrerenderList {
if ($uids) { if ($uids) {
$roles = user_roles(); $roles = user_roles();
$result = $this->database->query('SELECT u.entity_id as uid, u.roles_target_id as rid FROM {user__roles} u WHERE u.entity_id IN (:uids) AND u.roles_target_id IN (:rids)', array(':uids' => $uids, ':rids' => array_keys($roles))); $result = $this->database->query('SELECT u.entity_id as uid, u.roles_target_id as rid FROM {user__roles} u WHERE u.entity_id IN ( :uids[] ) AND u.roles_target_id IN ( :rids[] )', array(':uids[]' => $uids, ':rids[]' => array_keys($roles)));
foreach ($result as $role) { foreach ($result as $role) {
$this->items[$role->uid][$role->rid]['role'] = String::checkPlain($roles[$role->rid]->label()); $this->items[$role->uid][$role->rid]['role'] = String::checkPlain($roles[$role->rid]->label());
$this->items[$role->uid][$role->rid]['rid'] = $role->rid; $this->items[$role->uid][$role->rid]['rid'] = $role->rid;

View File

@ -31,7 +31,7 @@ class UserDeleteTest extends WebTestBase {
$query = db_select('user__roles', 'r'); $query = db_select('user__roles', 'r');
$roles_created = $query $roles_created = $query
->fields('r', array('entity_id')) ->fields('r', array('entity_id'))
->condition('entity_id', $uids) ->condition('entity_id', $uids, 'IN')
->countQuery() ->countQuery()
->execute() ->execute()
->fetchField(); ->fetchField();
@ -45,7 +45,7 @@ class UserDeleteTest extends WebTestBase {
$query = db_select('user__roles', 'r'); $query = db_select('user__roles', 'r');
$roles_after_deletion = $query $roles_after_deletion = $query
->fields('r', array('entity_id')) ->fields('r', array('entity_id'))
->condition('entity_id', $uids) ->condition('entity_id', $uids, 'IN')
->countQuery() ->countQuery()
->execute() ->execute()
->fetchField(); ->fetchField();

View File

@ -106,14 +106,15 @@ class UserData implements UserDataInterface {
*/ */
public function delete($module = NULL, $uid = NULL, $name = NULL) { public function delete($module = NULL, $uid = NULL, $name = NULL) {
$query = $this->connection->delete('users_data'); $query = $this->connection->delete('users_data');
// Cast scalars to array so we can consistently use an IN condition.
if (isset($module)) { if (isset($module)) {
$query->condition('module', $module); $query->condition('module', (array) $module, 'IN');
} }
if (isset($uid)) { if (isset($uid)) {
$query->condition('uid', $uid); $query->condition('uid', (array) $uid, 'IN');
} }
if (isset($name)) { if (isset($name)) {
$query->condition('name', $name); $query->condition('name', (array) $name, 'IN');
} }
$query->execute(); $query->execute();
} }

View File

@ -310,6 +310,7 @@ class ManyToOneHelper {
else { else {
$placeholder = $this->placeholder(); $placeholder = $this->placeholder();
if (count($this->handler->value) > 1) { if (count($this->handler->value) > 1) {
$placeholder .= '[]';
$this->handler->query->addWhereExpression(0, "$field $operator($placeholder)", array($placeholder => $value)); $this->handler->query->addWhereExpression(0, "$field $operator($placeholder)", array($placeholder => $value));
} }
else { else {

View File

@ -113,6 +113,7 @@ class Numeric extends ArgumentPluginBase {
if (count($this->value) > 1) { if (count($this->value) > 1) {
$operator = empty($this->options['not']) ? 'IN' : 'NOT IN'; $operator = empty($this->options['not']) ? 'IN' : 'NOT IN';
$placeholder .= '[]';
$this->query->addWhereExpression(0, "$this->tableAlias.$this->realField $operator($placeholder) $null_check", array($placeholder => $this->value)); $this->query->addWhereExpression(0, "$this->tableAlias.$this->realField $operator($placeholder) $null_check", array($placeholder => $this->value));
} }
else { else {

View File

@ -1357,7 +1357,7 @@ abstract class FilterPluginBase extends HandlerBase implements CacheablePluginIn
} }
if (isset($value)) { if (isset($value)) {
$this->value = $value; $this->value = $value;
if (empty($this->alwaysMultiple) && empty($this->options['expose']['multiple'])) { if (empty($this->alwaysMultiple) && empty($this->options['expose']['multiple']) && !is_array($value)) {
$this->value = array($value); $this->value = array($value);
} }
} }

View File

@ -54,7 +54,7 @@ class FilterEqualityTest extends ViewUnitTestBase {
'field' => 'name', 'field' => 'name',
'relationship' => 'none', 'relationship' => 'none',
'operator' => '=', 'operator' => '=',
'value' => array('value' => 'Ringo'), 'value' => 'Ringo',
), ),
)); ));
@ -98,7 +98,7 @@ class FilterEqualityTest extends ViewUnitTestBase {
'field' => 'name', 'field' => 'name',
'relationship' => 'none', 'relationship' => 'none',
'operator' => '!=', 'operator' => '!=',
'value' => array('value' => 'Ringo'), 'value' => 'Ringo',
), ),
)); ));
@ -172,12 +172,12 @@ class FilterEqualityTest extends ViewUnitTestBase {
1 => array( 1 => array(
'title' => 'Name is equal to Ringo', 'title' => 'Name is equal to Ringo',
'operator' => '=', 'operator' => '=',
'value' => array('value' => 'Ringo'), 'value' => 'Ringo',
), ),
2 => array( 2 => array(
'title' => 'Name is not equal to Ringo', 'title' => 'Name is not equal to Ringo',
'operator' => '!=', 'operator' => '!=',
'value' => array('value' => 'Ringo'), 'value' => 'Ringo',
), ),
), ),
), ),

View File

@ -144,7 +144,7 @@ class FilterStringTest extends ViewUnitTestBase {
'field' => 'name', 'field' => 'name',
'relationship' => 'none', 'relationship' => 'none',
'operator' => '!=', 'operator' => '!=',
'value' => array('value' => 'Ringo'), 'value' => 'Ringo',
), ),
)); ));
@ -756,7 +756,7 @@ class FilterStringTest extends ViewUnitTestBase {
2 => array( 2 => array(
'title' => 'Is not Ringo', 'title' => 'Is not Ringo',
'operator' => '!=', 'operator' => '!=',
'value' => array('value' => 'Ringo'), 'value' => 'Ringo',
), ),
3 => array( 3 => array(
'title' => 'Contains ing', 'title' => 'Contains ing',

View File

@ -1151,8 +1151,8 @@ function simpletest_script_load_messages_by_test_id($test_ids) {
foreach ($test_id_chunks as $test_id_chunk) { foreach ($test_id_chunks as $test_id_chunk) {
$result_chunk = Database::getConnection('default', 'test-runner') $result_chunk = Database::getConnection('default', 'test-runner')
->query("SELECT * FROM {simpletest} WHERE test_id IN (:test_ids) ORDER BY test_class, message_id", array( ->query("SELECT * FROM {simpletest} WHERE test_id IN ( :test_ids[] ) ORDER BY test_class, message_id", array(
':test_ids' => $test_id_chunk, ':test_ids[]' => $test_id_chunk,
))->fetchAll(); ))->fetchAll();
if ($result_chunk) { if ($result_chunk) {
$results = array_merge($results, $result_chunk); $results = array_merge($results, $result_chunk);