Commit 9079d784 authored by Dries's avatar Dries

- Patch #481288 by Berdir: add support for INSERT INTO ... SELECT FROM ... queries.

parent 41204a5a
...@@ -22,12 +22,12 @@ public function execute() { ...@@ -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.'); 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; return NULL;
} }
// Don't execute query without values. // 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; return NULL;
} }
...@@ -56,6 +56,10 @@ public function __toString() { ...@@ -56,6 +56,10 @@ public function __toString() {
// Default fields are always placed first for consistency. // Default fields are always placed first for consistency.
$insert_fields = array_merge($this->defaultFields, $this->insertFields); $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 '; $query = "INSERT $delay INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
$max_placeholder = 0; $max_placeholder = 0;
......
...@@ -22,12 +22,12 @@ public function execute() { ...@@ -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.'); 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; return NULL;
} }
// Don't execute query without values. // 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; return NULL;
} }
...@@ -82,6 +82,10 @@ public function __toString() { ...@@ -82,6 +82,10 @@ public function __toString() {
// Default fields are always placed first for consistency. // Default fields are always placed first for consistency.
$insert_fields = array_merge($this->defaultFields, $this->insertFields); $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 '; $query = "INSERT INTO {" . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
$max_placeholder = 0; $max_placeholder = 0;
......
...@@ -287,6 +287,12 @@ class InsertQuery extends Query { ...@@ -287,6 +287,12 @@ class InsertQuery extends Query {
*/ */
protected $insertValues = array(); protected $insertValues = array();
/**
* A SelectQuery object to fetch the rows that should be inserted.
*
*/
protected $fromQuery;
public function __construct($connection, $table, array $options = array()) { public function __construct($connection, $table, array $options = array()) {
if (!isset($options['return'])) { if (!isset($options['return'])) {
$options['return'] = Database::RETURN_INSERT_ID; $options['return'] = Database::RETURN_INSERT_ID;
...@@ -410,6 +416,11 @@ public function delay($delay = TRUE) { ...@@ -410,6 +416,11 @@ public function delay($delay = TRUE) {
return $this; return $this;
} }
public function from(SelectQueryInterface $query) {
$this->fromQuery = $query;
return $this;
}
/** /**
* Executes the insert query. * Executes the insert query.
* *
...@@ -426,6 +437,11 @@ public function execute() { ...@@ -426,6 +437,11 @@ public function execute() {
$last_insert_id = 0; $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 // Confirm that the user did not try to specify an identical
// field and default field. // field and default field.
if (array_intersect($this->insertFields, $this->defaultFields)) { if (array_intersect($this->insertFields, $this->defaultFields)) {
...@@ -463,6 +479,10 @@ public function __toString() { ...@@ -463,6 +479,10 @@ public function __toString() {
// Default fields are always placed first for consistency. // Default fields are always placed first for consistency.
$insert_fields = array_merge($this->defaultFields, $this->insertFields); $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 // For simplicity, we will use the $placeholders array to inject
// default keywords even though they are not, strictly speaking, // default keywords even though they are not, strictly speaking,
// placeholders for prepared statements. // placeholders for prepared statements.
......
...@@ -21,11 +21,11 @@ ...@@ -21,11 +21,11 @@
class InsertQuery_sqlite extends InsertQuery { class InsertQuery_sqlite extends InsertQuery {
public function execute() { public function execute() {
if (count($this->insertFields) + count($this->defaultFields) == 0) { if (count($this->insertFields) + count($this->defaultFields) == 0 && empty($this->fromQuery)) {
return NULL; return NULL;
} }
// Don't execute query without values. // 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; return NULL;
} }
if (count($this->insertFields)) { if (count($this->insertFields)) {
...@@ -39,6 +39,11 @@ public function execute() { ...@@ -39,6 +39,11 @@ public function execute() {
public function __toString() { public function __toString() {
// Produce as many generic placeholders as necessary. // Produce as many generic placeholders as necessary.
$placeholders = array_fill(0, count($this->insertFields), '?'); $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) . ')'; return 'INSERT INTO {' . $this->table . '} (' . implode(', ', $this->insertFields) . ') VALUES (' . implode(', ', $placeholders) . ')';
} }
......
...@@ -513,6 +513,21 @@ class DatabaseInsertTestCase extends DatabaseTestCase { ...@@ -513,6 +513,21 @@ class DatabaseInsertTestCase extends DatabaseTestCase {
$this->assertIdentical($id, '5', t('Auto-increment ID returned successfully.')); $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.'));
}
} }
/** /**
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment