Index: includes/database/query.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/query.inc,v
retrieving revision 1.23
diff -u -p -r1.23 query.inc
--- includes/database/query.inc	24 May 2009 17:39:30 -0000	1.23
+++ includes/database/query.inc	3 Jun 2009 19:55:12 -0000
@@ -287,6 +287,12 @@ class InsertQuery extends Query {
    */
   protected $insertValues = array();
 
+  /**
+   * A SelectQuery object to fetch the rows that should be inserted.
+   * 
+   */
+  protected $from_query;
+
   public function __construct($connection, $table, array $options = array()) {
     if (!isset($options['return'])) {
       $options['return'] = Database::RETURN_INSERT_ID;
@@ -410,6 +416,11 @@ class InsertQuery extends Query {
     return $this;
   }
 
+  public function from(SelectQueryInterface $query) {
+    $this->from_query = $query;
+    return $this;
+  }
+
   /**
    * Executes the insert query.
    *
@@ -426,6 +437,11 @@ class InsertQuery extends Query {
 
     $last_insert_id = 0;
 
+    // Check if a SelectQuery is passed in and use that.
+    if (!empty($this->from_query)) {
+      return $this->connection->query((string) $this, array(), $this->queryOptions);
+    }
+
     // Confirm that the user did not try to specify an identical
     //  field and default field.
     if (array_intersect($this->insertFields, $this->defaultFields)) {
@@ -463,6 +479,10 @@ class InsertQuery extends Query {
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
 
+    if (!empty($this->from_query)) {
+      return "INSERT $delay INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->from_query;
+    }
+
     // For simplicity, we will use the $placeholders array to inject
     // default keywords even though they are not, strictly speaking,
     // placeholders for prepared statements.
Index: includes/database/mysql/query.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/mysql/query.inc,v
retrieving revision 1.11
diff -u -p -r1.11 query.inc
--- includes/database/mysql/query.inc	20 Apr 2009 20:02:30 -0000	1.11
+++ includes/database/mysql/query.inc	3 Jun 2009 19:55:12 -0000
@@ -22,12 +22,12 @@ class InsertQuery_mysql extends InsertQu
       throw new PDOException('You may not specify the same field to have a value and a schema-default value.');
     }
 
-    if (count($this->insertFields) + count($this->defaultFields) == 0) {
+    if (count($this->insertFields) + count($this->defaultFields) == 0 && empty($this->from_query)) {
       return NULL;
     }
 
     // Don't execute query without values.
-    if (!isset($this->insertValues[0]) && count($this->insertFields) > 0) {
+    if (!isset($this->insertValues[0]) && count($this->insertFields) > 0 && empty($this->from_query)) {
       return NULL;
     }
 
@@ -56,6 +56,10 @@ class InsertQuery_mysql extends InsertQu
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
 
+    if (!empty($this->from_query)) {
+      return "INSERT $delay INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->from_query;
+    }
+
     $query = "INSERT $delay INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
 
     $max_placeholder = 0;
Index: includes/database/pgsql/query.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/pgsql/query.inc,v
retrieving revision 1.12
diff -u -p -r1.12 query.inc
--- includes/database/pgsql/query.inc	24 May 2009 17:39:30 -0000	1.12
+++ includes/database/pgsql/query.inc	3 Jun 2009 19:55:13 -0000
@@ -22,12 +22,12 @@ class InsertQuery_pgsql extends InsertQu
       throw new PDOException('You may not specify the same field to have a value and a schema-default value.');
     }
 
-    if (count($this->insertFields) + count($this->defaultFields) == 0) {
+    if (count($this->insertFields) + count($this->defaultFields) == 0 && empty($this->from_query)) {
       return NULL;
     }
 
     // Don't execute query without values.
-    if (!isset($this->insertValues[0]) && count($this->insertFields) > 0) {
+    if (!isset($this->insertValues[0]) && count($this->insertFields) > 0 && empty($this->from_query)) {
       return NULL;
     }
 
@@ -82,6 +82,10 @@ class InsertQuery_pgsql extends InsertQu
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
 
+    if (!empty($this->from_query)) {
+      return "INSERT INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->from_query;
+    }
+
     $query = "INSERT INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
 
     $max_placeholder = 0;
Index: includes/database/sqlite/query.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/database/sqlite/query.inc,v
retrieving revision 1.5
diff -u -p -r1.5 query.inc
--- includes/database/sqlite/query.inc	3 May 2009 08:55:06 -0000	1.5
+++ includes/database/sqlite/query.inc	3 Jun 2009 19:55:13 -0000
@@ -21,11 +21,11 @@
 class InsertQuery_sqlite extends InsertQuery {
 
   public function execute() {
-    if (count($this->insertFields) + count($this->defaultFields) == 0) {
+    if (count($this->insertFields) + count($this->defaultFields) == 0 && empty($this->from_query)) {
       return NULL;
     }
     // Don't execute query without values.
-    if (!isset($this->insertValues[0]) && count($this->insertFields) > 0) {
+    if (!isset($this->insertValues[0]) && count($this->insertFields) > 0 && empty($this->from_query)) {
       return NULL;
     }
     if (count($this->insertFields)) {
@@ -39,6 +39,11 @@ class InsertQuery_sqlite extends InsertQ
   public function __toString() {
     // Produce as many generic placeholders as necessary.
     $placeholders = array_fill(0, count($this->insertFields), '?');
+
+    if (!empty($this->from_query)) {
+      return "INSERT INTO {" . $this->table . '} (' . implode(', ', $this->insertFields) . ') ' . $this->from_query;
+    }
+
     return 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') VALUES (' . implode(', ', $placeholders) . ')';
   }
 
Index: modules/simpletest/tests/database_test.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/database_test.test,v
retrieving revision 1.55
diff -u -p -r1.55 database_test.test
--- modules/simpletest/tests/database_test.test	1 Jun 2009 16:47:06 -0000	1.55
+++ modules/simpletest/tests/database_test.test	3 Jun 2009 19:55:16 -0000
@@ -513,6 +513,21 @@ class DatabaseInsertTestCase extends Dat
 
     $this->assertIdentical($id, '5', t('Auto-increment ID returned successfully.'));
   }
+
+  /**
+   * Test that the INSERT INTO ... SELECT ... syntax works.
+   */
+  function testInsertSelect() {
+    $query = db_select('test_people', 'tp')->fields('tp', array('name', 'age', 'job'));
+
+    db_insert('test')
+      ->fields(array('name', 'age', 'job'))
+      ->from($query)
+      ->execute();
+
+    $saved_age = db_query('SELECT age FROM {test} WHERE name = :name', array(':name' => 'Meredith'))->fetchField();
+    $this->assertIdentical($saved_age, '30', t('Can retrieve after inserting.'));
+  }
 }
 
 /**
