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.')); + } } /**