Skip to content

Commit adeacee

Browse files
authored
fix: increment seqno before execute calls to prevent InvalidArgument … (#19)
* fix: increment seqno before execute calls to prevent InvalidArgument errors after a previous error * make assignments atomic * add and update tests * revert snapshot.py change * formatting Co-authored-by: larkee <larkee@users.noreply.github.com>
1 parent 13a9027 commit adeacee

File tree

3 files changed

+52
-6
lines changed

3 files changed

+52
-6
lines changed

google/cloud/spanner_v1/transaction.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,11 @@ def execute_update(
201201
transaction = self._make_txn_selector()
202202
api = database.spanner_api
203203

204+
seqno, self._execute_sql_count = (
205+
self._execute_sql_count,
206+
self._execute_sql_count + 1,
207+
)
208+
204209
# Query-level options have higher precedence than client-level and
205210
# environment-level options
206211
default_query_options = database._instance._client._query_options
@@ -214,11 +219,9 @@ def execute_update(
214219
param_types=param_types,
215220
query_mode=query_mode,
216221
query_options=query_options,
217-
seqno=self._execute_sql_count,
222+
seqno=seqno,
218223
metadata=metadata,
219224
)
220-
221-
self._execute_sql_count += 1
222225
return response.stats.row_count_exact
223226

224227
def batch_update(self, statements):
@@ -259,15 +262,18 @@ def batch_update(self, statements):
259262
transaction = self._make_txn_selector()
260263
api = database.spanner_api
261264

265+
seqno, self._execute_sql_count = (
266+
self._execute_sql_count,
267+
self._execute_sql_count + 1,
268+
)
269+
262270
response = api.execute_batch_dml(
263271
session=self._session.name,
264272
transaction=transaction,
265273
statements=parsed,
266-
seqno=self._execute_sql_count,
274+
seqno=seqno,
267275
metadata=metadata,
268276
)
269-
270-
self._execute_sql_count += 1
271277
row_counts = [
272278
result_set.stats.row_count_exact for result_set in response.result_sets
273279
]

tests/unit/test_snapshot.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ def test_execute_sql_other_error(self):
311311
with self.assertRaises(RuntimeError):
312312
list(derived.execute_sql(SQL_QUERY))
313313

314+
self.assertEqual(derived._execute_sql_count, 1)
315+
314316
def test_execute_sql_w_params_wo_param_types(self):
315317
database = _Database()
316318
session = _Session(database)

tests/unit/test_transaction.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,19 @@ def test_execute_update_new_transaction(self):
413413
def test_execute_update_w_count(self):
414414
self._execute_update_helper(count=1)
415415

416+
def test_execute_update_error(self):
417+
database = _Database()
418+
database.spanner_api = self._make_spanner_api()
419+
database.spanner_api.execute_sql.side_effect = RuntimeError()
420+
session = _Session(database)
421+
transaction = self._make_one(session)
422+
transaction._transaction_id = self.TRANSACTION_ID
423+
424+
with self.assertRaises(RuntimeError):
425+
transaction.execute_update(DML_QUERY)
426+
427+
self.assertEqual(transaction._execute_sql_count, 1)
428+
416429
def test_execute_update_w_query_options(self):
417430
from google.cloud.spanner_v1.proto.spanner_pb2 import ExecuteSqlRequest
418431

@@ -513,6 +526,31 @@ def test_batch_update_wo_errors(self):
513526
def test_batch_update_w_errors(self):
514527
self._batch_update_helper(error_after=2, count=1)
515528

529+
def test_batch_update_error(self):
530+
database = _Database()
531+
api = database.spanner_api = self._make_spanner_api()
532+
api.execute_batch_dml.side_effect = RuntimeError()
533+
session = _Session(database)
534+
transaction = self._make_one(session)
535+
transaction._transaction_id = self.TRANSACTION_ID
536+
537+
insert_dml = "INSERT INTO table(pkey, desc) VALUES (%pkey, %desc)"
538+
insert_params = {"pkey": 12345, "desc": "DESCRIPTION"}
539+
insert_param_types = {"pkey": "INT64", "desc": "STRING"}
540+
update_dml = 'UPDATE table SET desc = desc + "-amended"'
541+
delete_dml = "DELETE FROM table WHERE desc IS NULL"
542+
543+
dml_statements = [
544+
(insert_dml, insert_params, insert_param_types),
545+
update_dml,
546+
delete_dml,
547+
]
548+
549+
with self.assertRaises(RuntimeError):
550+
transaction.batch_update(dml_statements)
551+
552+
self.assertEqual(transaction._execute_sql_count, 1)
553+
516554
def test_context_mgr_success(self):
517555
import datetime
518556
from google.cloud.spanner_v1.proto.spanner_pb2 import CommitResponse

0 commit comments

Comments
 (0)