Issue #3185399 by alexpott, mondrake, daffie: Use RETURNING to determine last insert id in Drupal\Core\Database\Driver\pgsql\Insert
parent
3c2db2eda0
commit
340ff83bbe
|
@ -2,7 +2,6 @@
|
|||
|
||||
namespace Drupal\Core\Database\Driver\pgsql;
|
||||
|
||||
use Drupal\Core\Database\Database;
|
||||
use Drupal\Core\Database\DatabaseExceptionWrapper;
|
||||
use Drupal\Core\Database\IntegrityConstraintViolationException;
|
||||
use Drupal\Core\Database\Query\Insert as QueryInsert;
|
||||
|
@ -55,11 +54,6 @@ class Insert extends QueryInsert {
|
|||
if ($serial_key !== FALSE) {
|
||||
$serial_value = $insert_values[$serial_key];
|
||||
|
||||
// Force $last_insert_id to the specified value. This is only done
|
||||
// if $index is 0.
|
||||
if ($index == 0) {
|
||||
$last_insert_id = $serial_value;
|
||||
}
|
||||
// Sequences must be greater than or equal to 1.
|
||||
if ($serial_value === NULL || !$serial_value) {
|
||||
$serial_value = 1;
|
||||
|
@ -86,11 +80,6 @@ class Insert extends QueryInsert {
|
|||
}
|
||||
}
|
||||
|
||||
// PostgreSQL requires the table name to be specified explicitly when
|
||||
// requesting the last insert ID. If there are no sequences, then we can't
|
||||
// get a last insert id.
|
||||
$sequence_name = $table_information->sequences[0] ?? NULL;
|
||||
|
||||
// Create a savepoint so we can rollback a failed query. This is so we can
|
||||
// mimic MySQL and SQLite transactions which don't fail if a single query
|
||||
// fails. This is important for tables that are created on demand. For
|
||||
|
@ -98,17 +87,8 @@ class Insert extends QueryInsert {
|
|||
$this->connection->addSavepoint();
|
||||
try {
|
||||
$stmt->execute(NULL, $this->queryOptions);
|
||||
// Only use the returned last_insert_id if it is not already set.
|
||||
// PostgreSQL requires the table name to be specified explicitly when
|
||||
// requesting the last insert ID.
|
||||
if (!isset($last_insert_id)) {
|
||||
if ($this->queryOptions['return'] === Database::RETURN_INSERT_ID && $sequence_name !== NULL) {
|
||||
// cspell:ignore currval
|
||||
$last_insert_id = $this->connection->query("SELECT currval('$sequence_name')")->fetchField();
|
||||
}
|
||||
else {
|
||||
$last_insert_id = NULL;
|
||||
}
|
||||
if (isset($table_information->serial_fields[0])) {
|
||||
$last_insert_id = $stmt->fetchField();
|
||||
}
|
||||
$this->connection->releaseSavepoint();
|
||||
}
|
||||
|
@ -131,7 +111,7 @@ class Insert extends QueryInsert {
|
|||
// Re-initialize the values array so that we can re-use this query.
|
||||
$this->insertValues = [];
|
||||
|
||||
return $last_insert_id;
|
||||
return $last_insert_id ?? NULL;
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
|
@ -149,14 +129,29 @@ class Insert extends QueryInsert {
|
|||
// pass it back, as any remaining options are irrelevant.
|
||||
if (!empty($this->fromQuery)) {
|
||||
$insert_fields_string = $insert_fields ? ' (' . implode(', ', $insert_fields) . ') ' : ' ';
|
||||
return $comments . 'INSERT INTO {' . $this->table . '}' . $insert_fields_string . $this->fromQuery;
|
||||
$query = $comments . 'INSERT INTO {' . $this->table . '}' . $insert_fields_string . $this->fromQuery;
|
||||
}
|
||||
else {
|
||||
$query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
|
||||
|
||||
$query = $comments . 'INSERT INTO {' . $this->table . '} (' . implode(', ', $insert_fields) . ') VALUES ';
|
||||
|
||||
$values = $this->getInsertPlaceholderFragment($this->insertValues, $this->defaultFields);
|
||||
$query .= implode(', ', $values);
|
||||
|
||||
$values = $this->getInsertPlaceholderFragment($this->insertValues, $this->defaultFields);
|
||||
$query .= implode(', ', $values);
|
||||
}
|
||||
try {
|
||||
// Fetch the list of blobs and sequences used on that table.
|
||||
$table_information = $this->connection->schema()->queryTableInformation($this->table);
|
||||
if (isset($table_information->serial_fields[0])) {
|
||||
// Use RETURNING syntax to get the last insert ID in the same INSERT
|
||||
// query, see https://www.postgresql.org/docs/10/dml-returning.html.
|
||||
$query .= ' RETURNING ' . $table_information->serial_fields[0];
|
||||
}
|
||||
}
|
||||
catch (DatabaseExceptionWrapper $e) {
|
||||
// If we fail to get the table information it is probably because the
|
||||
// table does not exist yet so adding the returning statement is pointless
|
||||
// because the query will fail. This happens for tables created on demand,
|
||||
// for example, cache tables.
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue