From 4529a9fc722d73c5ded0af53ccd38276aa51a1ce Mon Sep 17 00:00:00 2001 From: Takayasu Oyama Date: Mon, 3 Jun 2024 14:39:34 +0900 Subject: [PATCH] fix: Timestamp bound queries were not applied when in transaction (#213) fix/staleness-read-on-tx # Conflicts: # CHANGELOG.md # tests/ConnectionTest.php --- CHANGELOG.md | 6 +++++- src/Connection.php | 10 +++++++++- tests/ConnectionTest.php | 35 ++++++++++++++++++++++++++++++----- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e0be4c..7d8eab8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,13 @@ +# v7.4.2 (2024-06-03) + +Fixed +- Timestamp bound queries were not applied when in transaction (#213) + # v7.4.1 (2024-05-21) Fixed - authCache needs namespace for each connection (#210) - # v7.4.0 (2024-05-13) Added diff --git a/src/Connection.php b/src/Connection.php index ed885cf..2f8da17 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -578,9 +578,17 @@ protected function executeQuery(string $query, array $bindings, array $options): $options['requestOptions']['requestTag'] = $tag; } - if ($transaction = $this->getCurrentTransaction()) { + $forceReadOnlyTransaction = + ($options['exactStaleness'] ?? false) || + ($options['maxStaleness'] ?? false) || + ($options['minReadTimestamp'] ?? false) || + ($options['readTimestamp'] ?? false) || + ($options['strong'] ?? false); + + if (!$forceReadOnlyTransaction && $transaction = $this->getCurrentTransaction()) { return $transaction->execute($query, $options)->rows(); } + return $this->getSpannerDatabase()->execute($query, $options)->rows(); } diff --git a/tests/ConnectionTest.php b/tests/ConnectionTest.php index 95f46e5..f72e2b0 100644 --- a/tests/ConnectionTest.php +++ b/tests/ConnectionTest.php @@ -478,7 +478,7 @@ public function test_stale_reads(): void $this->assertNotEmpty($timestamp); $timestampBound = new StrongRead(); - $rows = $conn->selectWithOptions("SELECT * FROM ${tableName} WHERE userID = ?", [$uuid], $timestampBound->transactionOptions()); + $rows = $conn->selectWithOptions("SELECT * FROM {$tableName} WHERE userId = ?", [$uuid], $timestampBound->transactionOptions()); $this->assertCount(1, $rows); $this->assertSame($uuid, $rows[0]['userId']); $this->assertSame('first', $rows[0]['name']); @@ -486,26 +486,51 @@ public function test_stale_reads(): void $oldDatetime = Carbon::instance($timestamp->get())->subSecond(); $timestampBound = new ReadTimestamp($oldDatetime); - $rows = $conn->selectWithOptions("SELECT * FROM ${tableName} WHERE userID = ?", [$uuid], $timestampBound->transactionOptions()); + $rows = $conn->selectWithOptions("SELECT * FROM {$tableName} WHERE userId = ?", [$uuid], $timestampBound->transactionOptions()); $this->assertEmpty($rows); $timestampBound = new ExactStaleness(10); - $rows = $conn->selectWithOptions("SELECT * FROM ${tableName} WHERE userID = ?", [$uuid], $timestampBound->transactionOptions()); + $rows = $conn->selectWithOptions("SELECT * FROM {$tableName} WHERE userId = ?", [$uuid], $timestampBound->transactionOptions()); $this->assertEmpty($rows); $timestampBound = new MaxStaleness(10); - $rows = $conn->selectWithOptions("SELECT * FROM ${tableName} WHERE userID = ?", [$uuid], $timestampBound->transactionOptions()); + $rows = $conn->selectWithOptions("SELECT * FROM {$tableName} WHERE userId = ?", [$uuid], $timestampBound->transactionOptions()); $this->assertCount(1, $rows); $this->assertSame($uuid, $rows[0]['userId']); $this->assertSame('first', $rows[0]['name']); $timestampBound = new MinReadTimestamp($oldDatetime); - $rows = $conn->selectWithOptions("SELECT * FROM ${tableName} WHERE userID = ?", [$uuid], $timestampBound->transactionOptions()); + $rows = $conn->selectWithOptions("SELECT * FROM {$tableName} WHERE userId = ?", [$uuid], $timestampBound->transactionOptions()); $this->assertCount(1, $rows); $this->assertSame($uuid, $rows[0]['userId']); $this->assertSame('first', $rows[0]['name']); } + public function test_stale_reads_in_transaction(): void + { + $conn = $this->getDefaultConnection(); + $tableName = self::TABLE_NAME_USER; + $uuid = $this->generateUuid(); + + $conn->transaction(function(Connection $conn) use ($tableName, $uuid) { + $conn->insert("INSERT INTO {$tableName} (`userId`, `name`) VALUES ('{$uuid}', 'first')"); + + $oldDatetime = now()->subSecond(); + + $bounds = [ + new StrongRead(), + new ExactStaleness(10), + new MaxStaleness(10), + new ReadTimestamp($oldDatetime), + new MinReadTimestamp($oldDatetime), + ]; + foreach ($bounds as $timestampBound) { + $rows = $conn->selectWithOptions("SELECT * FROM {$tableName} WHERE userId = ?", [$uuid], $timestampBound->transactionOptions()); + $this->assertEmpty($rows); + } + }); + } + public function testEventListenOrder(): void { $receivedEventClasses = [];