diff options
author | Angie Byron <webchick@24967.no-reply.drupal.org> | 2009-03-14 17:45:55 +0000 |
---|---|---|
committer | Angie Byron <webchick@24967.no-reply.drupal.org> | 2009-03-14 17:45:55 +0000 |
commit | 193ba01e1fbdc525249f8c7ec0592831e1b7ffe2 (patch) | |
tree | 5b82dc0766cd3d558fc53f541816fab928d1c650 | |
parent | 38969b48ffd65d8bbf2b7c6722288c5341d7a4f6 (diff) | |
download | brdo-193ba01e1fbdc525249f8c7ec0592831e1b7ffe2.tar.gz brdo-193ba01e1fbdc525249f8c7ec0592831e1b7ffe2.tar.bz2 |
#343999 by Crell, chx, and Alexander Pas: Add facility for doing NULL / NOT NULL conditions to DBTNG.
-rw-r--r-- | includes/database/query.inc | 61 | ||||
-rw-r--r-- | includes/database/select.inc | 32 | ||||
-rw-r--r-- | modules/simpletest/tests/database_test.install | 31 | ||||
-rw-r--r-- | modules/simpletest/tests/database_test.test | 70 |
4 files changed, 188 insertions, 6 deletions
diff --git a/includes/database/query.inc b/includes/database/query.inc index dd6a4da9a..d22c0751a 100644 --- a/includes/database/query.inc +++ b/includes/database/query.inc @@ -48,6 +48,26 @@ interface QueryConditionInterface { public function where($snippet, $args = array()); /** + * Set a condition that the specified field be NULL. + * + * @param $field + * The name of the field to check. + * @return + * The called object. + */ + public function isNull($field); + + /** + * Set a condition that the specified field be NOT NULL. + * + * @param $field + * The name of the field to check. + * @return + * The called object. + */ + public function isNotNull($field); + + /** * Gets a complete list of all conditions in this conditional clause. * * This method returns by reference. That allows alter hooks to access the @@ -749,6 +769,16 @@ class DeleteQuery extends Query implements QueryConditionInterface { return $this; } + public function isNull($field) { + $this->condition->isNull($field); + return $this; + } + + public function isNotNull($field) { + $this->condition->isNotNull($field); + return $this; + } + public function &conditions() { return $this->condition->conditions(); } @@ -852,6 +882,16 @@ class UpdateQuery extends Query implements QueryConditionInterface { return $this; } + public function isNull($field) { + $this->condition->isNull($field); + return $this; + } + + public function isNotNull($field) { + $this->condition->isNotNull($field); + return $this; + } + public function &conditions() { return $this->condition->conditions(); } @@ -1012,6 +1052,14 @@ class DatabaseCondition implements QueryConditionInterface, Countable { return $this; } + public function isNull($field) { + return $this->condition($field, NULL, 'IS NULL'); + } + + public function isNotNull($field) { + return $this->condition($field, NULL, 'IS NOT NULL'); + } + public function &conditions() { return $this->conditions; } @@ -1061,6 +1109,7 @@ class DatabaseCondition implements QueryConditionInterface, Countable { 'postfix' => '', 'delimiter' => '', 'operator' => $condition['operator'], + 'use_value' => TRUE, ); $operator = $connection->mapConditionOperator($condition['operator']); if (!isset($operator)) { @@ -1079,10 +1128,12 @@ class DatabaseCondition implements QueryConditionInterface, Countable { $condition['value'] = array($condition['value']); } $placeholders = array(); - foreach ($condition['value'] as $value) { - $placeholder = ':db_condition_placeholder_' . $next_placeholder++; - $arguments[$placeholder] = $value; - $placeholders[] = $placeholder; + if ($operator['use_value']) { + foreach ($condition['value'] as $value) { + $placeholder = ':db_condition_placeholder_' . $next_placeholder++; + $arguments[$placeholder] = $value; + $placeholders[] = $placeholder; + } } $condition_fragments[] = ' (' . $condition['field'] . ' ' . $operator['operator'] . ' ' . $operator['prefix'] . implode($operator['delimiter'], $placeholders) . $operator['postfix'] . ') '; @@ -1122,6 +1173,8 @@ class DatabaseCondition implements QueryConditionInterface, Countable { 'IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'), 'NOT IN' => array('delimiter' => ', ', 'prefix' => ' (', 'postfix' => ')'), 'LIKE' => array('operator' => 'LIKE'), + 'IS NULL' => array('use_value' => FALSE), + 'IS NOT NULL' => array('use_value' => FALSE), ); $return = isset($specials[$operator]) ? $specials[$operator] : array(); diff --git a/includes/database/select.inc b/includes/database/select.inc index bef03f756..633965dcc 100644 --- a/includes/database/select.inc +++ b/includes/database/select.inc @@ -579,6 +579,16 @@ class SelectQueryExtender implements SelectQueryInterface { return $count; } + function isNull($field) { + $this->query->isNull($field); + return $this; + } + + function isNotNull($field) { + $this->query->isNotNull($field); + return $this; + } + public function __toString() { return (string)$this->query; } @@ -760,6 +770,17 @@ class SelectQuery extends Query implements SelectQueryInterface { return $this; } + public function isNull($field) { + $this->where->isNull($field); + return $this; + } + + public function isNotNull($field) { + $this->where->isNotNull($field); + return $this; + } + + public function compile(DatabaseConnection $connection) { return $this->where->compile($connection); } @@ -801,6 +822,17 @@ class SelectQuery extends Query implements SelectQueryInterface { return new $extender_name($this, $this->connection); } + public function havingIsNull($field) { + $this->having->isNull($field); + return $this; + } + + public function havingIsNotNull($field) { + $this->having->isNotNull($field); + return $this; + } + + /* Alter accessors to expose the query data to alter hooks. */ public function &getFields() { diff --git a/modules/simpletest/tests/database_test.install b/modules/simpletest/tests/database_test.install index bc1dce2b4..0a51d57fd 100644 --- a/modules/simpletest/tests/database_test.install +++ b/modules/simpletest/tests/database_test.install @@ -166,6 +166,37 @@ function database_test_schema() { 'primary key' => array('id'), ); + $schema['test_null'] = array( + 'description' => 'Basic test table for NULL value handling.', + 'fields' => array( + 'id' => array( + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'name' => array( + 'description' => "A person's name.", + 'type' => 'varchar', + 'length' => 255, + 'not null' => FALSE, + 'default' => '', + ), + 'age' => array( + 'description' => "The person's age.", + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => FALSE, + 'default' => 0), + ), + 'primary key' => array('id'), + 'unique keys' => array( + 'name' => array('name') + ), + 'indexes' => array( + 'ages' => array('age'), + ), + ); + return $schema; } diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test index 16b6c99fe..bc9a84b3b 100644 --- a/modules/simpletest/tests/database_test.test +++ b/modules/simpletest/tests/database_test.test @@ -27,6 +27,18 @@ class DatabaseTestCase extends DrupalWebTestCase { $schema['test_two_blobs'] = drupal_get_schema('test_two_blobs'); $schema['test_task'] = drupal_get_schema('test_task'); + $this->installTables($schema); + + $this->addSampleData(); + } + + /** + * Set up several tables needed by a certain test. + * + * @param $schema + * An array of table definitions to install. + */ + function installTables($schema) { // This ends up being a test for table drop and create, too, which is nice. $ret = array(); foreach ($schema as $name => $data) { @@ -39,8 +51,30 @@ class DatabaseTestCase extends DrupalWebTestCase { foreach ($schema as $name => $data) { $this->assertTrue(db_table_exists($name), t('Table @name created successfully.', array('@name' => $name))); } + } - $this->addSampleData(); + /** + * Set up tables for NULL handling. + */ + function ensureSampleDataNull() { + $schema['test_null'] = drupal_get_schema('test_null'); + $this->installTables($schema); + + db_insert('test_null') + ->fields(array('name', 'age')) + ->values(array( + 'name' => 'Kermit', + 'age' => 25, + )) + ->values(array( + 'name' => 'Fozzie', + 'age' => NULL, + )) + ->values(array( + 'name' => 'Gonzo', + 'age' => 27, + )) + ->execute(); } /** @@ -641,6 +675,7 @@ class DatabaseUpdateTestCase extends DatabaseTestCase { $num_matches = db_query("SELECT COUNT(*) FROM {test} WHERE job = :job", array(':job' => 'Musician'))->fetchField(); $this->assertIdentical($num_matches, '1', t('Updated fields successfully.')); } + } /** @@ -1033,7 +1068,6 @@ class DatabaseMergeTestCase extends DatabaseTestCase { /** * Test the SELECT builder. - * */ class DatabaseSelectTestCase extends DatabaseTestCase { @@ -1169,6 +1203,38 @@ class DatabaseSelectTestCase extends DatabaseTestCase { $this->assertEqual($record->age, 27, t('Age field has the correct value.')); $this->assertEqual($record->job, 'Singer', t('Job field has the correct value.')); } + + /** + * Test that we can find a record with a NULL value. + */ + function testNullCondition() { + $this->ensureSampleDataNull(); + + $names = db_select('test_null', 'tn') + ->fields('tn', array('name')) + ->isNull('age') + ->execute()->fetchCol(); + + $this->assertEqual(count($names), 1, t('Correct number of records found with NULL age.')); + $this->assertEqual($names[0], 'Fozzie', t('Correct record returned for NULL age.')); + } + + /** + * Test that we can find a record without a NULL value. + */ + function testNotNullCondition() { + $this->ensureSampleDataNull(); + + $names = db_select('test_null', 'tn') + ->fields('tn', array('name')) + ->isNotNull('tn.age') + ->orderBy('name') + ->execute()->fetchCol(); + + $this->assertEqual(count($names), 2, t('Correct number of records found withNOT NULL age.')); + $this->assertEqual($names[0], 'Gonzo', t('Correct record returned for NOT NULL age.')); + $this->assertEqual($names[1], 'Kermit', t('Correct record returned for NOT NULL age.')); + } } /** |