diff --git a/core/includes/database/query.inc b/core/includes/database/query.inc
index 0effeda..f909cec 100644
--- a/core/includes/database/query.inc
+++ b/core/includes/database/query.inc
@@ -18,41 +18,59 @@ interface QueryConditionInterface {
   /**
    * Helper function: builds the most common conditional clauses.
    *
-   * This method can take a variable number of parameters. If called with two
-   * parameters, they are taken as $field and $value with $operator having a
-   * value of IN if $value is an array and = otherwise.
+   * This method can take a variable number of parameters.
+   *
+   * If called with 1 parameter, it should be a QueryConditionInterface that in
+   * itself forms a valid where clause. Use e.g. to build clauses with nested
+   * AND's and OR's.
+   *
+   * If called with 2 parameters, they are taken as $field and $value with
+   * $operator having a value of IN if $value is an array and = otherwise.
    *
    * Do not use this method to test for NULL values. Instead, use
    * QueryConditionInterface::isNull() or QueryConditionInterface::isNotNull().
    *
-   * @param $field
-   *   The name of the field to check. If you would like to add a more complex
-   *   condition involving operators or functions, use where().
-   * @param $value
-   *   The value to test the field against. In most cases, this is a scalar.
-   *   For more complex options, it is an array. The meaning of each element in
-   *   the array is dependent on the $operator.
-   * @param $operator
-   *   The comparison operator, such as =, <, or >=. It also accepts more
-   *   complex options such as IN, LIKE, or BETWEEN. Defaults to IN if $value is
-   *   an array, and = otherwise.
+   * To improve readability, the operators EXISTS and NOT EXISTS have their own
+   * utility method defined.
+   *
+   * @param string|QueryConditionInterface $field
+   *   The name of the field to check. This can also be QueryConditionInterface
+   *   in itself. Use where(), if you would like to add a more complex condition
+   *   involving operators or functions, or an already compiled condition.
+   * @param string|array|SelectQueryInterface|null $value
+   *   The value to test the field against. In most cases, and depending on the
+   *   operator, this will be a scalar or an array. As SQL accepts select
+   *   queries on any place where a scalar value or set is expected, $value may
+   *   also be a(n array of) SelectQueryInterface('s). If $operator is a unary
+   *   operator, e.g. EXISTS, $value should be null.
+   * @param string $operator
+   *   The operator to use. Supported for all supported databases are at least:
+   *   - The comparison operators =, <>, <, <=, >, >=.
+   *   - The operators BETWEEN, (NOT) IN, (NOT) EXISTS, (NOT) LIKE.
+   *   Other operators may or may not work.
+   *   Defaults to = if $value is a scalar and to IN if $value is an array.
    *
    * @return QueryConditionInterface
    *   The called object.
    *
    * @see QueryConditionInterface::isNull()
    * @see QueryConditionInterface::isNotNull()
+   * @see QueryConditionInterface::exists()
+   * @see QueryConditionInterface::notExist()
+   * @see QueryConditionInterface::where()
    */
   public function condition($field, $value = NULL, $operator = NULL);
 
   /**
    * Adds an arbitrary WHERE clause to the query.
    *
-   * @param $snippet
+   * @param string $snippet
    *   A portion of a WHERE clause as a prepared statement. It must use named
-   *   placeholders, not ? placeholders.
-   * @param $args
-   *   An associative array of arguments.
+   *   placeholders, not ? placeholders. The caller is responsible for providing
+   *   unique placeholders that do not interfere with the placeholers generated
+   *   by this QueryConditionInterface object.
+   * @param array $args
+   *   An associative array of arguments keyed by the named placeholders.
    *
    * @return QueryConditionInterface
    *   The called object.
@@ -62,8 +80,8 @@ interface QueryConditionInterface {
   /**
    * Sets a condition that the specified field be NULL.
    *
-   * @param $field
-   *   The name of the field to check.
+   * @param string|SelectQueryInterface $field
+   *   The name of the field or a subquery to check.
    *
    * @return QueryConditionInterface
    *   The called object.
@@ -73,8 +91,8 @@ interface QueryConditionInterface {
   /**
    * Sets a condition that the specified field be NOT NULL.
    *
-   * @param $field
-   *   The name of the field to check.
+   * @param string|SelectQueryInterface $field
+   *   The name of the field or a subquery to check.
    *
    * @return QueryConditionInterface
    *   The called object.
@@ -83,7 +101,7 @@ interface QueryConditionInterface {
 
   /**
    * Sets a condition that the specified subquery returns values.
-   * 
+   *
    * @param SelectQueryInterface $select
    *   The subquery that must contain results.
    *
@@ -91,10 +109,10 @@ interface QueryConditionInterface {
    *   The called object.
    */
   public function exists(SelectQueryInterface $select);
-  
+
   /**
    * Sets a condition that the specified subquery returns no values.
-   * 
+   *
    * @param SelectQueryInterface $select
    *   The subquery that must not contain results.
    *
@@ -102,9 +120,9 @@ interface QueryConditionInterface {
    *   The called object.
    */
   public function notExists(SelectQueryInterface $select);
-  
+
   /**
-   * Gets a complete list of all conditions in this conditional clause.
+   * Gets the, possibly nested, list of conditions in this conditional clause.
    *
    * This method returns by reference. That allows alter hooks to access the
    * data structure directly and manipulate it before it gets compiled.
@@ -119,12 +137,11 @@ interface QueryConditionInterface {
    * );
    * @endcode
    *
-   * In the special case that $operator is NULL, the $field is taken as a raw
-   * SQL snippet (possibly containing a function) and $value is an associative
-   * array of placeholders for the snippet.
-   *
    * There will also be a single array entry of #conjunction, which is the
    * conjunction that will be applied to the array, such as AND.
+   *
+   * @return array
+   *   The, possibly nested, list of all conditions (by reference).
    */
   public function &conditions();
 
@@ -283,14 +300,14 @@ abstract class Query implements QueryPlaceholderInterface {
 
   /**
    * The target of the connection object.
-   * 
+   *
    * @var string
    */
   protected $connectionTarget;
 
   /**
    * The key of the connection object.
-   * 
+   *
    * @var string
    */
   protected $connectionKey;
@@ -804,7 +821,7 @@ class DeleteQuery extends Query implements QueryConditionInterface {
     $this->condition->notExists($select);
     return $this;
   }
-  
+
   /**
    * Implements QueryConditionInterface::conditions().
    */
@@ -1053,7 +1070,7 @@ class UpdateQuery extends Query implements QueryConditionInterface {
     $this->condition->notExists($select);
     return $this;
   }
-  
+
   /**
    * Implements QueryConditionInterface::conditions().
    */
@@ -1545,7 +1562,7 @@ class MergeQuery extends Query implements QueryConditionInterface {
     $this->condition->notExists($select);
     return $this;
   }
-  
+
   /**
    * Implements QueryConditionInterface::conditions().
    */
@@ -1710,7 +1727,7 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
       if (is_array($value)) {
         $operator = 'IN';
       }
-      else {
+      else if (isset($value) || !($field instanceof QueryConditionInterface)) {
         $operator = '=';
       }
     }
@@ -1759,14 +1776,14 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
   public function exists(SelectQueryInterface $select) {
     return $this->condition('', $select, 'EXISTS');
   }
-  
+
   /**
    * Implements QueryConditionInterface::notExists().
    */
   public function notExists(SelectQueryInterface $select) {
     return $this->condition('', $select, 'NOT EXISTS');
   }
-  
+
   /**
    * Implements QueryConditionInterface::conditions().
    */
@@ -1801,67 +1818,97 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
       $conjunction = $conditions['#conjunction'];
       unset($conditions['#conjunction']);
       foreach ($conditions as $condition) {
-        if (empty($condition['operator'])) {
-          // This condition is a literal string, so let it through as is.
-          $condition_fragments[] = ' (' . $condition['field'] . ') ';
+        // Process field.
+        if ($condition['field'] instanceof QueryConditionInterface) {
+          // Left hand part is a structured condition or a subquery: compile,
+          // put brackets around it if it is a query, and collect any arguments.
+          $condition['field']->compile($connection, $queryPlaceholder);
+          $field_fragment = (string) $condition['field'];
+          if ($condition['field'] instanceof SelectQueryInterface) {
+            $field_fragment = '(' . $field_fragment . ')';
+          }
+          $arguments += $condition['field']->arguments();
+        }
+        else if (!isset($condition['operator'])) {
+          // Left hand part is a literal string added with the
+          // @see QueryConditionInterface::where() method. Put brackets around
+          // the snippet and collect the arguments from the value part.
+          $field_fragment = '(' . $condition['field'] . ')';
           $arguments += $condition['value'];
         }
         else {
-          // It's a structured condition, so parse it out accordingly.
-          // Note that $condition['field'] will only be an object for a dependent
-          // DatabaseCondition object, not for a dependent subquery.
-          if ($condition['field'] instanceof QueryConditionInterface) {
-            // Compile the sub-condition recursively and add it to the list.
-            $condition['field']->compile($connection, $queryPlaceholder);
-            $condition_fragments[] = '(' . (string) $condition['field'] . ')';
-            $arguments += $condition['field']->arguments();
+          // Left hand part is a normal field: add it as is.
+          $field_fragment = $condition['field'];
+        }
+
+        // Process operator. For simplicity, we convert all operators to a data
+        // structure to allow to specify a prefix, a delimeter and such.
+        if (!isset($condition['operator'])) {
+          // Empty operator: the field is assumed to be a valid condition on its
+          // own. Ignore the operator and value parts.
+          $operator = array('operator' => '', 'use_value' => FALSE);
+        }
+        else {
+          // Operator is a string. Find the associated data structure by first
+          // doing a database specific lookup, followed by a specification
+          // according to the SQL standard.
+          $operator = $connection->mapConditionOperator($condition['operator']);
+          if (!isset($operator)) {
+            $operator = $this->mapConditionOperator($condition['operator']);
           }
-          else {
-            // For simplicity, we treat all operators as the same data structure.
-            // In the typical degenerate case, this won't get changed.
-            $operator_defaults = array(
-              'prefix' => '',
-              'postfix' => '',
-              'delimiter' => '',
-              'operator' => $condition['operator'],
-              'use_value' => TRUE,
-            );
-            $operator = $connection->mapConditionOperator($condition['operator']);
-            if (!isset($operator)) {
-              $operator = $this->mapConditionOperator($condition['operator']);
-            }
-            $operator += $operator_defaults;
-
-            $placeholders = array();
-            if ($condition['value'] instanceof SelectQueryInterface) {
-              $condition['value']->compile($connection, $queryPlaceholder);
-              $placeholders[] = (string) $condition['value'];
-              $arguments += $condition['value']->arguments();
-              // Subqueries are the actual value of the operator, we don't
-              // need to add another below.
-              $operator['use_value'] = FALSE;
+          $operator += array('operator' => $condition['operator']);
+        }
+        $operator += array(
+          'prefix' => '',
+          'postfix' => '',
+          'delimiter' => '',
+          'use_value' => TRUE,
+        );
+        $operator_fragment = $operator['operator'];
+
+        // Process value.
+        $value_fragment = '';
+        if ($operator['use_value']) {
+          // For simplicity, we first convert to an array, so that we can handle
+          // the single and multi value cases the same.
+          if (!is_array($condition['value'])) {
+            if ($operator['operator'] == 'IN' && $condition['value'] instanceof QueryConditionInterface) {
+              // Special case: IN is followed by a select query instead of a set
+              // of values: unset prefix and postfix to prevent double brackets.
+              $operator['prefix'] = '';
+              $operator['postfix'] = '';
             }
-            // 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
-            // up to an array so that we can build the placeholders in the same way.
-            elseif (!$operator['delimiter']) {
-              $condition['value'] = array($condition['value']);
+            $condition['value'] = array($condition['value']);
+          }
+          // Process all separate values.
+          $value_fragment = array();
+          foreach ($condition['value'] as $value) {
+            if ($value instanceof QueryConditionInterface) {
+              // Right hand part is a subquery: compile, assure that brackets
+              // are put around it and collect any arguments.
+              $value->compile($connection, $queryPlaceholder);
+              $value_fragment[] = '(' . (string) $value . ')';
+              $arguments += $value->arguments();
             }
-            if ($operator['use_value']) {
-              foreach ($condition['value'] as $value) {
-                $placeholder = ':db_condition_placeholder_' . $queryPlaceholder->nextPlaceholder();
-                $arguments[$placeholder] = $value;
-                $placeholders[] = $placeholder;
-              }
+            else {
+              // Right hand part is a normal value: replace the value with a
+              // placeholder and add the value as an argument.
+              $placeholder = ':db_condition_placeholder_' . $queryPlaceholder->nextPlaceholder();
+              $value_fragment[] = $placeholder;
+              $arguments[$placeholder] = $value;
             }
-            $condition_fragments[] = ' (' . $connection->escapeField($condition['field']) . ' ' . $operator['operator'] . ' ' . $operator['prefix'] . implode($operator['delimiter'], $placeholders) . $operator['postfix'] . ') ';
           }
+          $value_fragment = $operator['prefix'] . implode($operator['delimiter'], $value_fragment) . $operator['postfix'];
         }
+        // Concatenate the left hand part, operator and right hand part.
+        $condition_fragments[] = trim(implode(' ', array($field_fragment, $operator_fragment, $value_fragment)));
       }
 
-      $this->changed = FALSE;
-      $this->stringVersion = implode($conjunction, $condition_fragments);
+      // Concatenate all conditions using the conjunction and brackets around
+      // the individual conditions to assure the proper evaluation order.
+      $this->stringVersion = count($condition_fragments) > 1 ? '(' . implode(") $conjunction (", $condition_fragments) . ')' : implode($condition_fragments);
       $this->arguments = $arguments;
+      $this->changed = FALSE;
     }
   }
 
@@ -1918,10 +1965,10 @@ class DatabaseCondition implements QueryConditionInterface, Countable {
     // $specials does not use drupal_static as its value never changes.
     static $specials = array(
       'BETWEEN' => array('delimiter' => ' AND '),
-      'IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
-      'NOT IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'),
-      'EXISTS' => array('prefix' => ' (', 'postfix' => ')'),
-      'NOT EXISTS' => array('prefix' => ' (', 'postfix' => ')'),
+      'IN' => array('delimiter' => ', ', 'prefix' => '(', 'postfix' => ')'),
+      'NOT IN' => array('delimiter' => ', ', 'prefix' => '(', 'postfix' => ')'),
+      'EXISTS' => array('prefix' => '(', 'postfix' => ')'),
+      'NOT EXISTS' => array('prefix' => '(', 'postfix' => ')'),
       'IS NULL' => array('use_value' => FALSE),
       'IS NOT NULL' => array('use_value' => FALSE),
       // Use backslash for escaping wildcard characters.
diff --git a/core/modules/simpletest/tests/database_test.test b/core/modules/simpletest/tests/database_test.test
index f54c5d5..468264f 100644
--- a/core/modules/simpletest/tests/database_test.test
+++ b/core/modules/simpletest/tests/database_test.test
@@ -1694,7 +1694,7 @@ class DatabaseSelectSubqueryTestCase extends DatabaseTestCase {
   }
 
   /**
-   * Test that we can use a subquery in a WHERE clause.
+   * Test that we can use a subquery with an IN operator in a WHERE clause.
    */
   function testConditionSubquerySelect() {
     // Create a subquery, which is just a normal query object.
@@ -1717,6 +1717,55 @@ class DatabaseSelectSubqueryTestCase extends DatabaseTestCase {
   }
 
   /**
+   * Test that we can use a subquery with a relational operator in a WHERE clause.
+   */
+  function testConditionSubquerySelect2() {
+    // Create a subquery, which is just a normal query object.
+    $subquery = db_select('test', 't2');
+    $subquery->addExpression('AVG(t2.age)');
+
+    // Create another query that adds a clause using the subquery.
+    $select = db_select('test', 't');
+    $select->addField('t', 'name');
+    $select->condition('t.age', $subquery, '<');
+
+    // The resulting query should be equivalent to:
+    // SELECT t.name
+    // FROM test t
+    // WHERE t.age < (SELECT AVG(t2.age) FROM test t2)
+    $people = $select->execute()->fetchCol();
+    $this->assertEqual(count($people), 2, t('Returned the correct number of rows.'));
+    $this->assertTrue(in_array('Paul', $people) && in_array('John', $people), t('Returned Paul and John.'));
+  }
+
+  /**
+   * Test that we can use 2 subqueries with a relational operator in a WHERE clause.
+   */
+  function testConditionSubquerySelect3() {
+    // Create subquery 1, which is just a normal query object.
+    $subquery1 = db_select('test_task', 'tt');
+    $subquery1->addExpression('AVG(tt.priority)');
+    $subquery1->where('tt.pid = t.id');
+
+    // Create subquery 2, which is just a normal query object.
+    $subquery2 = db_select('test_task', 'tt2');
+    $subquery2->addExpression('AVG(tt2.priority)');
+
+    // Create another query that adds a clause using the subqueries.
+    $select = db_select('test', 't');
+    $select->addField('t', 'name');
+    $select->condition($subquery1, $subquery2, '>');
+
+    // The resulting query should be equivalent to:
+    // SELECT t.name
+    // FROM test t
+    // WHERE (SELECT AVG(tt.priority) FROM test_task tt WHERE tt.pid = t.id) > (SELECT AVG(tt2.priority) FROM test_task tt2)
+    $people = $select->execute()->fetchCol();
+    $this->assertEqual(count($people), 1, t('Returned the correct number of rows.'));
+    $this->assertTrue(in_array('John', $people), t('Returned John.'));
+  }
+
+  /**
    * Test that we can use a subquery in a JOIN clause.
    */
   function testJoinSubquerySelect() {
