diff --git a/includes/database/mysql/query.inc b/includes/database/mysql/query.inc
index b2dbae04c9a31ee243a14294deb177d5eb452387..84caf03868d584d2a16893c4478f9a64b25bd32a 100644
--- a/includes/database/mysql/query.inc
+++ b/includes/database/mysql/query.inc
@@ -22,12 +22,12 @@ public function execute() {
       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->fromQuery)) {
       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->fromQuery)) {
       return NULL;
     }
 
@@ -56,6 +56,10 @@ public function __toString() {
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
 
+    if (!empty($this->fromQuery)) {
+      return "INSERT $delay INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
+    }
+
     $query = "INSERT $delay INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
 
     $max_placeholder = 0;
diff --git a/includes/database/pgsql/query.inc b/includes/database/pgsql/query.inc
index d177212218b52d119e3beccfe49b4e80a8ddba35..489d57e657f460a5cb30755d57459a59215cf26c 100644
--- a/includes/database/pgsql/query.inc
+++ b/includes/database/pgsql/query.inc
@@ -22,12 +22,12 @@ public function execute() {
       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->fromQuery)) {
       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->fromQuery)) {
       return NULL;
     }
 
@@ -82,6 +82,10 @@ public function __toString() {
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
 
+    if (!empty($this->fromQuery)) {
+      return "INSERT INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
+    }
+
     $query = "INSERT INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
 
     $max_placeholder = 0;
diff --git a/includes/database/query.inc b/includes/database/query.inc
index 8d614a0dd12fc1c91e4abba1854d337165c122d6..ac14c4a2e5e77cc610d61130239ae812a6e7adf1 100644
--- a/includes/database/query.inc
+++ b/includes/database/query.inc
@@ -287,6 +287,12 @@ class InsertQuery extends Query {
    */
   protected $insertValues = array();
 
+  /**
+   * A SelectQuery object to fetch the rows that should be inserted.
+   * 
+   */
+  protected $fromQuery;
+
   public function __construct($connection, $table, array $options = array()) {
     if (!isset($options['return'])) {
       $options['return'] = Database::RETURN_INSERT_ID;
@@ -410,6 +416,11 @@ public function delay($delay = TRUE) {
     return $this;
   }
 
+  public function from(SelectQueryInterface $query) {
+    $this->fromQuery = $query;
+    return $this;
+  }
+
   /**
    * Executes the insert query.
    *
@@ -426,6 +437,11 @@ public function execute() {
 
     $last_insert_id = 0;
 
+    // Check if a SelectQuery is passed in and use that.
+    if (!empty($this->fromQuery)) {
+      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 @@ public function __toString() {
     // Default fields are always placed first for consistency.
     $insert_fields = array_merge($this->defaultFields, $this->insertFields);
 
+    if (!empty($this->fromQuery)) {
+      return "INSERT $delay INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') ' . $this->fromQuery;
+    }
+
     // For simplicity, we will use the $placeholders array to inject
     // default keywords even though they are not, strictly speaking,
     // placeholders for prepared statements.
diff --git a/includes/database/sqlite/query.inc b/includes/database/sqlite/query.inc
index 98fa8075449da852e3c85ab1e94b5534083f1bae..287fc9008d6f300359ffee26caf1ff1601ccc117 100644
--- a/includes/database/sqlite/query.inc
+++ b/includes/database/sqlite/query.inc
@@ -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->fromQuery)) {
       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->fromQuery)) {
       return NULL;
     }
     if (count($this->insertFields)) {
@@ -39,6 +39,11 @@ public function execute() {
   public function __toString() {
     // Produce as many generic placeholders as necessary.
     $placeholders = array_fill(0, count($this->insertFields), '?');
+
+    if (!empty($this->fromQuery)) {
+      return "INSERT INTO {" . $this->table . '} (' . implode(', ', $this->insertFields) . ') ' . $this->fromQuery;
+    }
+
     return 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') VALUES (' . implode(', ', $placeholders) . ')';
   }
 
diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test
index 7084ccf7e1722d5315fe109534a5cf1538afea55..6256ff22c674920d9352789c3d427122822ab136 100644
--- a/modules/simpletest/tests/database_test.test
+++ b/modules/simpletest/tests/database_test.test
@@ -513,6 +513,21 @@ class DatabaseInsertTestCase extends DatabaseTestCase {
 
     $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.'));
+  }
 }
 
 /**