From 1d38a16fafa526add83b10ffeaa8a406002da763 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Thu, 15 Oct 2026 23:43:59 +1300 Subject: [PATCH] fix(postgres): read the sequence only for a document created without one createDocument() called lastInsertId(), which PostgreSQL answers with lastval(), after every insert. A document that brings its own $sequence inserts it into the identity column without calling nextval(), so on a session that has not called nextval() yet lastval() raises 55000 "lastval is not yet defined in this session" and the create fails. MariaDB, MySQL and SQLite answer 0 there instead of raising. It showed up as a SharedTables/Postgres CI failure in testDeleteDocument, which re-creates its fixture with the fixture's sequence on a fresh paratest process. The sequence is now read only when the document has none, as the value was already kept in that case. Co-Authored-By: Claude Opus 5.5 --- src/Database/Adapter/Postgres.php | 5 ++-- tests/e2e/Adapter/Scopes/DocumentTests.php | 32 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Database/Adapter/Postgres.php b/src/Database/Adapter/Postgres.php index 7f8d5757a..70fbdf49e 100644 --- a/src/Database/Adapter/Postgres.php +++ b/src/Database/Adapter/Postgres.php @@ -1102,8 +1102,9 @@ public function createDocument(Document $collection, Document $document): Docume $statement = $this->executeResult($result, Event::DocumentCreate); $this->execute($statement); - $lastInsertedId = $this->getDriver()->lastInsertId(); - $document[Document::SEQUENCE] ??= $lastInsertedId; + if (empty($document->getSequence())) { + $document[Document::SEQUENCE] = $this->getDriver()->lastInsertId(); + } $context = $this->writeContext(); $this->runWriteHooks(fn ($hook) => $hook->afterDocumentCreate($name, [$document], $context)); diff --git a/tests/e2e/Adapter/Scopes/DocumentTests.php b/tests/e2e/Adapter/Scopes/DocumentTests.php index 973550113..9a176685e 100644 --- a/tests/e2e/Adapter/Scopes/DocumentTests.php +++ b/tests/e2e/Adapter/Scopes/DocumentTests.php @@ -2948,6 +2948,38 @@ public function testUpdateDocument(): void $this->assertEquals($id, $new->getId()); } + public function testDocumentRecreatedWithItsSequenceInAFreshSessionKeepsIt(): void + { + $database = $this->getDatabase(); + $collection = 'own_sequence_'.\substr(\uniqid(), -6); + $database->createCollection(Collection::create( + id: $collection, + attributes: [Attribute::string(key: 'name', size: 20, required: true)], + permissions: [Permission::create(Role::any()), Permission::read(Role::any()), Permission::delete(Role::any())], + )); + + $document = $database->createDocument($collection, new Document([ + '$id' => 'own', + 'name' => 'first', + '$permissions' => [Permission::read(Role::any())], + ])); + $database->deleteDocument($collection, 'own'); + + $adapter = $database->getAdapter(); + if ($adapter instanceof Postgres) { + $driver = $adapter->getDriver(); + $this->assertInstanceOf(DatabasePDO::class, $driver); + $driver->exec('DISCARD SEQUENCES'); + } + + $recreated = $database->createDocument($collection, $document); + + $this->assertSame($document->getSequence(), $recreated->getSequence()); + $this->assertSame($document->getSequence(), $database->getDocument($collection, 'own')->getSequence()); + + $database->deleteCollection($collection); + } + public function testDeleteDocument(): void { $document = $this->initDocumentsFixture();