diff --git a/includes/database/query.inc b/includes/database/query.inc index 7c590c2200dafa8292bc18be2e8c8fa5a17299f4..de421b30c1d1c2824cf6262a83fd684d23cb1c01 100644 --- a/includes/database/query.inc +++ b/includes/database/query.inc @@ -76,6 +76,28 @@ public function isNull($field); */ public function isNotNull($field); + /** + * Sets a condition that the specified subquery returns values. + * + * @param SelectQueryInterface $select + * The subquery that must contain results. + * + * @return 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. + * + * @return QueryConditionInterface + * The called object. + */ + public function notExists(SelectQueryInterface $select); + /** * Gets a complete list of all conditions in this conditional clause. * @@ -726,6 +748,22 @@ public function isNotNull($field) { return $this; } + /** + * Implements QueryConditionInterface::exists(). + */ + public function exists(SelectQueryInterface $select) { + $this->condition->exists($select); + return $this; + } + + /** + * Implements QueryConditionInterface::notExists(). + */ + public function notExists(SelectQueryInterface $select) { + $this->condition->notExists($select); + return $this; + } + /** * Implements QueryConditionInterface::conditions(). */ @@ -946,6 +984,22 @@ public function isNotNull($field) { return $this; } + /** + * Implements QueryConditionInterface::exists(). + */ + public function exists(SelectQueryInterface $select) { + $this->condition->exists($select); + return $this; + } + + /** + * Implements QueryConditionInterface::notExists(). + */ + public function notExists(SelectQueryInterface $select) { + $this->condition->notExists($select); + return $this; + } + /** * Implements QueryConditionInterface::conditions(). */ @@ -1416,6 +1470,22 @@ public function isNotNull($field) { return $this; } + /** + * Implements QueryConditionInterface::exists(). + */ + public function exists(SelectQueryInterface $select) { + $this->condition->exists($select); + return $this; + } + + /** + * Implements QueryConditionInterface::notExists(). + */ + public function notExists(SelectQueryInterface $select) { + $this->condition->notExists($select); + return $this; + } + /** * Implements QueryConditionInterface::conditions(). */ @@ -1614,6 +1684,20 @@ public function isNotNull($field) { return $this->condition($field, NULL, 'IS NOT NULL'); } + /** + * Implements QueryConditionInterface::exists(). + */ + 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(). */ @@ -1756,6 +1840,8 @@ protected function mapConditionOperator($operator) { 'BETWEEN' => array('delimiter' => ' AND '), '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/includes/database/select.inc b/includes/database/select.inc index 7f44063a2a02880cb2093618802de273e7486538..43f92671e3c40dc7e7dbfd1267bc4b8d0d738765 100644 --- a/includes/database/select.inc +++ b/includes/database/select.inc @@ -810,6 +810,16 @@ function isNotNull($field) { return $this; } + public function exists(SelectQueryInterface $select) { + $this->query->exists($select); + return $this; + } + + public function notExists(SelectQueryInterface $select) { + $this->query->notExists($select); + return $this; + } + public function __toString() { return (string) $this->query; } @@ -1022,6 +1032,16 @@ public function isNotNull($field) { return $this; } + public function exists(SelectQueryInterface $select) { + $this->where->exists($select); + return $this; + } + + public function notExists(SelectQueryInterface $select) { + $this->where->notExists($select); + return $this; + } + public function compile(DatabaseConnection $connection, QueryPlaceholderInterface $queryPlaceholder = NULL) { return $this->where->compile($connection, isset($queryPlaceholder) ? $queryPlaceholder : $this); } @@ -1069,7 +1089,17 @@ public function havingIsNotNull($field) { $this->having->isNotNull($field); return $this; } - + + public function havingExists(SelectQueryInterface $select) { + $this->having->exists($select); + return $this; + } + + public function havingNotExists(SelectQueryInterface $select) { + $this->having->notExists($select); + return $this; + } + public function forUpdate($set = TRUE) { if (isset($set)) { $this->forUpdate = $set; diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test index bfd67de9d5af37806f8f9cd086cc72e9d6a623b4..243dbba31e77ad6de9768a6a8c8b0f617cf909fc 100644 --- a/modules/simpletest/tests/database_test.test +++ b/modules/simpletest/tests/database_test.test @@ -1684,6 +1684,61 @@ class DatabaseSelectSubqueryTestCase extends DatabaseTestCase { $this->assertEqual(count($people), 2, t('Returned the correct number of rows.')); } + + /** + * Test EXISTS subquery conditionals on SELECT statements. + */ + function testExistsSubquerySelect() { + // Put George into {test_people}. + db_insert('test_people') + ->fields(array( + 'name' => 'George', + 'age' => 27, + 'job' => 'Singer', + )) + ->execute(); + // Base query to {test}. + $query = db_select('test', 't') + ->fields('t', array('name')); + // Subquery to {test_people}. + $subquery = db_select('test_people', 'tp') + ->fields('tp', array('name')) + ->condition('name', 'George'); + $query->exists($subquery); + $result = $query->execute(); + + // Ensure that we got the right record. + $record = $result->fetch(); + $this->assertEqual($record->name, 'George', t('Fetched name is correct using EXISTS query.')); + } + + /** + * Test NOT EXISTS subquery conditionals on SELECT statements. + */ + function testNotExistsSubquerySelect() { + // Put George into {test_people}. + db_insert('test_people') + ->fields(array( + 'name' => 'George', + 'age' => 27, + 'job' => 'Singer', + )) + ->execute(); + + // Base query to {test}. + $query = db_select('test', 't') + ->fields('t', array('name')); + // Subquery to {test_people}. + $subquery = db_select('test_people', 'tp') + ->fields('tp', array('name')) + ->condition('name', 'George'); + $query->notExists($subquery); + $result = $query->execute(); + + // Ensure that we got the right record. + $record = $result->fetch(); + $this->assertFalse($record, t('NOT EXISTS query returned no results.')); + } } /**