includes/database/pgsql/database.inc | 24 ++++++++++++++++++++ includes/database/pgsql/query.inc | 20 ++++++++++++++++ includes/database/pgsql/schema.inc | 1 + modules/simpletest/tests/database_test.test | 32 +++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 0 deletions(-) diff --git includes/database/pgsql/database.inc includes/database/pgsql/database.inc index dbb3286..f3602d3 100644 --- includes/database/pgsql/database.inc +++ includes/database/pgsql/database.inc @@ -188,6 +188,30 @@ class DatabaseConnection_pgsql extends DatabaseConnection { return $id; } + + /** + * Overrides PDO::lastInsertId(). + * + * Catchs and handles the exception in case currval() fails. + */ + public function lastInsertId($name = null) { + try { + return parent::lastInsertId($name); + } catch(PDOException $e) { + if ($e->getCode() == 55000) { + // This fails if a value was inserted into the serial column and + // nextval() was never called. In that case, the last_insert_id is known + // by the caller and NULL is returned. + $last_insert_id = NULL; + } + else { + // If it is a different exception, re-throw it. + throw $e; + } + } + return $last_insert_id; + } + } /** diff --git includes/database/pgsql/query.inc includes/database/pgsql/query.inc index 8825229..f71e229 100644 --- includes/database/pgsql/query.inc +++ includes/database/pgsql/query.inc @@ -69,6 +69,26 @@ class InsertQuery_pgsql extends InsertQuery { } $last_insert_id = $this->connection->query($stmt, array(), $options); + // If a value was inserted into a serial column, update the sequence. + if (!empty($table_information->serial_fields)) { + // If the first serial field is in the insert fields, update the + // last_insert_id to that value. + $key = array_search($table_information->serial_fields[0], $this->insertFields); + if ($key !== FALSE) { + $last_insert_id = $insert_values[$key]; + } + + foreach ($table_information->serial_fields as $index => $serial_field) { + if (in_array($serial_field, $this->insertFields)) { + // Load the next sequence value and the max value of the table. + $new_value = $this->connection->query("SELECT NEXTVAL('" . $table_information->sequences[$index] . "') AS nextval, MAX(" . $serial_field . ") AS max FROM {" . $this->table . "}")->fetchObject(); + // Set the current sequence value to the bigger of those two values. + $curval = $new_value->nextval > $new_value->max ? $new_value->nextval : $new_value->max; + $this->connection->query("SELECT SETVAL('" . $table_information->sequences[$index] . "', :curval)", array(':curval' => $curval)); + } + } + } + // Re-initialize the values array so that we can re-use this query. $this->insertValues = array(); diff --git includes/database/pgsql/schema.inc includes/database/pgsql/schema.inc index cda525b..1b65f5d 100644 --- includes/database/pgsql/schema.inc +++ includes/database/pgsql/schema.inc @@ -66,6 +66,7 @@ class DatabaseSchema_pgsql extends DatabaseSchema { // return the last insert id. If there is more than 1 sequences the // first one (index 0 of the sequences array) will be used. $table_information->sequences[] = $matches[1]; + $table_information->serial_fields[] = $column->column_name; } } $this->tableInformation[$key] = $table_information; diff --git modules/simpletest/tests/database_test.test modules/simpletest/tests/database_test.test index 623bcb2..98c5d16 100644 --- modules/simpletest/tests/database_test.test +++ modules/simpletest/tests/database_test.test @@ -562,6 +562,38 @@ class DatabaseInsertTestCase extends DatabaseTestCase { ->execute(); $this->assertIdentical($id, '5', t('Auto-increment ID returned successfully.')); + + // Test a manual insert. + $id = db_insert('test') + ->fields(array( + 'id' => '10', + 'name' => 'Curly', + 'age' => '29', + )) + ->execute(); + + debug($id); + $this->assertIdentical($id, '10', t('ID returned properly for a manual ID insert.')); + + $id = db_insert('test') + ->fields(array( + 'id' => '7', + 'name' => 'Sascha', + 'age' => '24', + )) + ->execute(); + + debug($id); + $this->assertIdentical($id, '7', t('ID returned successfully for a manual ID insert smaller than the max value.')); + + $id = db_insert('test') + ->fields(array( + 'name' => 'Peter', + 'age' => '77', + )) + ->execute(); + + $this->assertTrue($id > 10, t('Auto-increment ID returned successfully after a manual ID was inserted.')); } /**