Inserting data using mutation API wrapped in transaction causes the record to be inserted twice.
This did not happen in v1.
I believe this is happening because the precommit token is not handled correctly.
There is a code in Operation::transaction(...) that opens a transaction, but never sets a precommit token.
Below is the code block that's suppose to set the precommit token.
|
if ($precommitToken) { |
|
// Set the precommitToken from {@see Transaction::getPrecommitToken} |
|
$transaction->setPrecommitToken($precommitToken); |
|
} |
|
|
|
return $transaction; |
But this is never executed because there is a return statement above it.
Also, I think a precommit token needs to be set here as well.
|
$transaction = $this->operation->transaction($this->session, $operationTransactionOptions); |
|
// Set the transaction ID of the current transaction. |
|
$this->transactionId = $transaction->id(); |
Environment details
- OS: Alpine Linux
- PHP version: 8.4.23
- Package name and version: google/cloud-spanner v2.10.0
Code example
<?php
require __DIR__ . '/vendor/autoload.php';
use Google\Cloud\Spanner\SpannerClient;
use Google\Cloud\Spanner\Transaction;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
$projectId = getenv('DB_SPANNER_PROJECT_ID') ?: 'test-project';
$instanceId = getenv('DB_SPANNER_INSTANCE_ID') ?: 'test-instance';
$databaseId = getenv('DB_SPANNER_DATABASE_ID') ?: 'test-db';
$client = new SpannerClient([
'projectId' => $projectId,
'cacheItemPool' => new ArrayAdapter(),
]);
$instance = $client->instance($instanceId);
if (!$instance->exists()) {
$config = $client->instanceConfiguration('emulator-config');
$instance->create($config)->pollUntilComplete();
}
$database = $instance->database($databaseId);
$table = 'MutationTest';
if (!$database->exists()) {
$instance->createDatabase($databaseId, [
'statements' => [
"CREATE TABLE $table (id INT64 NOT NULL, name STRING(10)) PRIMARY KEY (id)",
],
])->pollUntilComplete();
}
$database->runTransaction(function (Transaction $tx) use ($table) {
$tx->insertBatch($table, [['id' => rand(), 'name' => 'test']]);
});
The above code will throw the following error.
Fatal error: Uncaught Google\Cloud\Core\Exception\ConflictException: {
"message": "Table MutationTest: Row {Int64(1653590878)} already exists.",
"code": 6,
"status": "ALREADY_EXISTS",
"details": [
{
"@type": "google.spanner.ConstraintError",
"typeUrl": "google.spanner.ConstraintError",
"value": ""
}
]
} in /project/vendor/google/cloud-core/src/RequestProcessorTrait.php:149
Inserting data using mutation API wrapped in transaction causes the record to be inserted twice.
This did not happen in v1.
I believe this is happening because the precommit token is not handled correctly.
There is a code in
Operation::transaction(...)that opens a transaction, but never sets a precommit token.Below is the code block that's suppose to set the precommit token.
google-cloud-php/Spanner/src/Operation.php
Lines 743 to 748 in 55feec8
But this is never executed because there is a return statement above it.
google-cloud-php/Spanner/src/Operation.php
Line 735 in 55feec8
Also, I think a precommit token needs to be set here as well.
google-cloud-php/Spanner/src/Transaction.php
Lines 456 to 458 in 9902096
Environment details
Code example
The above code will throw the following error.