=== modified file 'includes/database/query.inc'
--- includes/database/query.inc	2009-02-22 16:53:41 +0000
+++ includes/database/query.inc	2009-03-07 20:50:53 +0000
@@ -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 implemen
     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 implemen
     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 Query
     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 Query
               'postfix' => '',
               'delimiter' => '',
               'operator' => $condition['operator'],
+              'use_value' => TRUE,
             );
             $operator = $connection->mapConditionOperator($condition['operator']);
             if (!isset($operator)) {
@@ -1079,10 +1128,12 @@ class DatabaseCondition implements Query
               $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 Query
       '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();

=== modified file 'includes/database/select.inc'
--- includes/database/select.inc	2009-02-22 16:53:41 +0000
+++ includes/database/select.inc	2009-03-07 20:55:38 +0000
@@ -579,6 +579,16 @@ class SelectQueryExtender implements Sel
     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 implemen
     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 implemen
     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() {

=== modified file 'modules/simpletest/tests/database_test.install'
--- modules/simpletest/tests/database_test.install	2008-12-23 07:48:24 +0000
+++ modules/simpletest/tests/database_test.install	2009-03-07 20:50:53 +0000
@@ -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;
 }
 

=== modified file 'modules/simpletest/tests/database_test.test'
--- modules/simpletest/tests/database_test.test	2009-02-26 07:30:26 +0000
+++ modules/simpletest/tests/database_test.test	2009-03-07 20:50:53 +0000
@@ -27,6 +27,18 @@ class DatabaseTestCase extends DrupalWeb
     $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 DrupalWeb
     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 Dat
     $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 Data
 
 /**
  * Test the SELECT builder.
- *
  */
 class DatabaseSelectTestCase extends DatabaseTestCase {
 
@@ -1169,6 +1203,38 @@ class DatabaseSelectTestCase extends Dat
     $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 without NULL age.'));
+    $this->assertEqual($names[0], 'Gonzo', t('Correct record returned for NULL age.'));
+    $this->assertEqual($names[1], 'Kermit', t('Correct record returned for NULL age.'));
+  }
 }
 
 /**

