Skip to content

Commit f5b704b

Browse files
committed
Incorporated comments
1 parent 8b63b9c commit f5b704b

File tree

7 files changed

+67
-55
lines changed

7 files changed

+67
-55
lines changed

google/cloud/spanner_dbapi/client_side_statement_executor.py

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,32 +46,25 @@ def execute(connection: "Connection", parsed_statement: ParsedStatement):
4646
:type parsed_statement: ParsedStatement
4747
:param parsed_statement: parsed_statement based on the sql query
4848
"""
49-
if parsed_statement.client_side_statement_type == ClientSideStatementType.COMMIT:
49+
if connection.is_closed:
50+
raise ProgrammingError(CONNECTION_CLOSED_ERROR)
51+
statement_type = parsed_statement.client_side_statement_type
52+
if statement_type == ClientSideStatementType.COMMIT:
5053
connection.commit()
5154
return None
52-
if parsed_statement.client_side_statement_type == ClientSideStatementType.BEGIN:
55+
if statement_type == ClientSideStatementType.BEGIN:
5356
connection.begin()
5457
return None
55-
if parsed_statement.client_side_statement_type == ClientSideStatementType.ROLLBACK:
58+
if statement_type == ClientSideStatementType.ROLLBACK:
5659
connection.rollback()
5760
return None
58-
if (
59-
parsed_statement.client_side_statement_type
60-
== ClientSideStatementType.SHOW_COMMIT_TIMESTAMP
61-
):
62-
if connection.is_closed:
63-
raise ProgrammingError(CONNECTION_CLOSED_ERROR)
61+
if statement_type == ClientSideStatementType.SHOW_COMMIT_TIMESTAMP:
6462
return _get_streamed_result_set(
6563
ClientSideStatementType.SHOW_COMMIT_TIMESTAMP.name,
6664
TypeCode.TIMESTAMP,
6765
connection._transaction.committed,
6866
)
69-
if (
70-
parsed_statement.client_side_statement_type
71-
== ClientSideStatementType.SHOW_READ_TIMESTAMP
72-
):
73-
if connection.is_closed:
74-
raise ProgrammingError(CONNECTION_CLOSED_ERROR)
67+
if statement_type == ClientSideStatementType.SHOW_READ_TIMESTAMP:
7568
return _get_streamed_result_set(
7669
ClientSideStatementType.SHOW_READ_TIMESTAMP.name,
7770
TypeCode.TIMESTAMP,
@@ -85,5 +78,6 @@ def _get_streamed_result_set(column_name, type_code, column_value):
8578
)
8679

8780
result_set = PartialResultSet(metadata=ResultSetMetadata(row_type=struct_type_pb))
88-
result_set.values.extend([_make_value_pb(column_value)])
81+
if column_value is not None:
82+
result_set.values.extend([_make_value_pb(column_value)])
8983
return StreamedResultSet(iter([result_set]))

google/cloud/spanner_dbapi/client_side_statement_parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@
2424
RE_COMMIT = re.compile(r"^\s*(COMMIT)(TRANSACTION)?", re.IGNORECASE)
2525
RE_ROLLBACK = re.compile(r"^\s*(ROLLBACK)(TRANSACTION)?", re.IGNORECASE)
2626
RE_SHOW_COMMIT_TIMESTAMP = re.compile(
27-
r"^\s*(SHOW VARIABLE COMMIT_TIMESTAMP)", re.IGNORECASE
27+
r"^\s*(SHOW)\s*(VARIABLE)\s*(COMMIT_TIMESTAMP)", re.IGNORECASE
2828
)
2929
RE_SHOW_READ_TIMESTAMP = re.compile(
30-
r"^\s*(SHOW VARIABLE READ_TIMESTAMP)", re.IGNORECASE
30+
r"^\s*(SHOW)\s*(VARIABLE)\s*(READ_TIMESTAMP)", re.IGNORECASE
3131
)
3232

3333

google/cloud/spanner_dbapi/connection.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from google.cloud.spanner_v1 import RequestOptions
2424
from google.cloud.spanner_v1.session import _get_retry_delay
2525
from google.cloud.spanner_v1.snapshot import Snapshot
26+
from deprecated import deprecated
2627

2728
from google.cloud.spanner_dbapi.checksum import _compare_checksums
2829
from google.cloud.spanner_dbapi.checksum import ResultsChecksum
@@ -143,9 +144,10 @@ def database(self):
143144
return self._database
144145

145146
@property
147+
@deprecated(
148+
reason="This method is deprecated. Use spanner_transaction_started method"
149+
)
146150
def inside_transaction(self):
147-
"""Deprecated property which won't be supported in future versions.
148-
Please use spanner_transaction_started property instead."""
149151
return (
150152
self._transaction
151153
and not self._transaction.committed
@@ -310,7 +312,6 @@ def _rerun_previous_statements(self):
310312
status, res = transaction.batch_update(statements)
311313

312314
if status.code == ABORTED:
313-
self._spanner_transaction_started = False
314315
raise Aborted(status.details)
315316

316317
retried_checksum = ResultsChecksum()
@@ -398,7 +399,7 @@ def begin(self):
398399
399400
:raises: :class:`InterfaceError`: if this connection is closed.
400401
:raises: :class:`OperationalError`: if there is an existing transaction
401-
that has begin or is running
402+
that has been started
402403
"""
403404
if self._transaction_begin_marked:
404405
raise OperationalError("A transaction has already started")

google/cloud/spanner_dbapi/cursor.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,10 @@ def _handle_DQL_with_snapshot(self, snapshot, sql, params):
487487
# Unfortunately, Spanner doesn't seem to send back
488488
# information about the number of rows available.
489489
self._row_count = _UNSET_COUNT
490+
if self._result_set.metadata.transaction.read_timestamp is not None:
491+
snapshot._transaction_read_timestamp = (
492+
self._result_set.metadata.transaction.read_timestamp
493+
)
490494

491495
def _handle_DQL(self, sql, params):
492496
if self.connection.database is None:

google/cloud/spanner_v1/snapshot.py

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,9 @@
1515
"""Model a set of read-only queries to a database as a snapshot."""
1616

1717
import functools
18-
import itertools
1918
import threading
2019
from google.protobuf.struct_pb2 import Struct
21-
from google.cloud.spanner_v1 import (
22-
ExecuteSqlRequest,
23-
PartialResultSet,
24-
ResultSetMetadata,
25-
)
20+
from google.cloud.spanner_v1 import ExecuteSqlRequest
2621
from google.cloud.spanner_v1 import ReadRequest
2722
from google.cloud.spanner_v1 import TransactionOptions
2823
from google.cloud.spanner_v1 import TransactionSelector
@@ -452,17 +447,11 @@ def execute_sql(
452447
if self._transaction_id is None:
453448
# lock is added to handle the inline begin for first rpc
454449
with self._lock:
455-
return self._get_streamed_result_set(
456-
restart, request, trace_attributes, False
457-
)
450+
return self._get_streamed_result_set(restart, request, trace_attributes)
458451
else:
459-
return self._get_streamed_result_set(
460-
restart, request, trace_attributes, True
461-
)
452+
return self._get_streamed_result_set(restart, request, trace_attributes)
462453

463-
def _get_streamed_result_set(
464-
self, restart, request, trace_attributes, transaction_id_set
465-
):
454+
def _get_streamed_result_set(self, restart, request, trace_attributes):
466455
iterator = _restart_on_unavailable(
467456
restart,
468457
request,
@@ -474,16 +463,6 @@ def _get_streamed_result_set(
474463
self._read_request_count += 1
475464
self._execute_sql_count += 1
476465

477-
if self._read_only and not transaction_id_set:
478-
peek = next(iterator)
479-
response_pb = PartialResultSet.pb(peek)
480-
response_metadata = ResultSetMetadata.wrap(response_pb.metadata)
481-
if response_metadata.transaction.read_timestamp is not None:
482-
self._transaction_read_timestamp = (
483-
response_metadata.transaction.read_timestamp
484-
)
485-
iterator = itertools.chain([peek], iterator)
486-
487466
if self._multi_use:
488467
return StreamedResultSet(iterator, source=self)
489468
else:

tests/system/test_dbapi.py

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,25 @@ def test_begin_client_side(self, shared_instance, dbapi_database):
153153
conn3.close()
154154
assert got_rows == [updated_row]
155155

156-
def test_commit_timestamp_client_side(self):
156+
def test_commit_timestamp_client_side_transaction(self):
157157
"""Test executing SHOW_COMMIT_TIMESTAMP client side statement in a
158158
transaction."""
159159

160160
self._cursor.execute(
161161
"""
162162
INSERT INTO contacts (contact_id, first_name, last_name, email)
163+
VALUES (1, 'first-name', 'last-name', '[email protected]')
164+
"""
165+
)
166+
self._cursor.execute("SHOW VARIABLE COMMIT_TIMESTAMP")
167+
got_rows = self._cursor.fetchall()
168+
# As the connection is not committed we will get 0 rows
169+
assert len(got_rows) == 0
170+
assert len(self._cursor.description) == 1
171+
172+
self._cursor.execute(
173+
"""
174+
INSERT INTO contacts (contact_id, first_name, last_name, email)
163175
VALUES (2, 'first-name', 'last-name', '[email protected]')
164176
"""
165177
)
@@ -198,18 +210,33 @@ def test_read_timestamp_client_side(self):
198210
transaction."""
199211

200212
self._conn.read_only = True
201-
202213
self._cursor.execute("SELECT * FROM contacts")
214+
assert self._cursor.fetchall() == []
215+
216+
self._cursor.execute("SHOW VARIABLE READ_TIMESTAMP")
217+
read_timestamp_query_result_1 = self._cursor.fetchall()
218+
203219
self._cursor.execute("SELECT * FROM contacts")
204-
self._conn.commit()
220+
assert self._cursor.fetchall() == []
221+
205222
self._cursor.execute("SHOW VARIABLE READ_TIMESTAMP")
223+
read_timestamp_query_result_2 = self._cursor.fetchall()
206224

207-
got_rows = self._cursor.fetchall()
208-
assert len(got_rows) == 1
209-
assert len(got_rows[0]) == 1
225+
self._conn.commit()
226+
227+
self._cursor.execute("SHOW VARIABLE READ_TIMESTAMP")
228+
read_timestamp_query_result_3 = self._cursor.fetchall()
210229
assert len(self._cursor.description) == 1
211230
assert self._cursor.description[0].name == "SHOW_READ_TIMESTAMP"
212-
assert isinstance(got_rows[0][0], DatetimeWithNanoseconds)
231+
232+
assert (
233+
read_timestamp_query_result_1
234+
== read_timestamp_query_result_2
235+
== read_timestamp_query_result_3
236+
)
237+
assert len(read_timestamp_query_result_1) == 1
238+
assert len(read_timestamp_query_result_1[0]) == 1
239+
assert isinstance(read_timestamp_query_result_1[0][0], DatetimeWithNanoseconds)
213240

214241
def test_read_timestamp_client_side_autocommit(self):
215242
"""Test executing SHOW_READ_TIMESTAMP client side statement in a
@@ -225,6 +252,9 @@ def test_read_timestamp_client_side_autocommit(self):
225252
)
226253
self._conn.read_only = True
227254
self._cursor.execute("SELECT * FROM contacts")
255+
assert self._cursor.fetchall() == [
256+
(2, "first-name", "last-name", "[email protected]")
257+
]
228258
self._cursor.execute("SHOW VARIABLE READ_TIMESTAMP")
229259

230260
got_rows = self._cursor.fetchall()
@@ -725,8 +755,10 @@ def test_read_only(self):
725755
ReadOnly transactions.
726756
"""
727757

758+
self._conn.read_only = True
728759
self._cursor.execute("SELECT * FROM contacts")
729760
self._conn.commit()
761+
assert self._cursor.fetchall() == []
730762

731763
def test_read_only_dml(self):
732764
"""

tests/unit/spanner_dbapi/test_parse_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,13 @@ def test_classify_stmt(self):
5252
),
5353
("CREATE ROLE parent", StatementType.DDL),
5454
("commit", StatementType.CLIENT_SIDE),
55-
(" commit TRANSACTION ", StatementType.CLIENT_SIDE),
55+
(" commit TRANSACTION ", StatementType.CLIENT_SIDE),
5656
("begin", StatementType.CLIENT_SIDE),
5757
("start", StatementType.CLIENT_SIDE),
5858
("begin transaction", StatementType.CLIENT_SIDE),
5959
("start transaction", StatementType.CLIENT_SIDE),
60+
(" SHOW VARIABLE COMMIT_TIMESTAMP ", StatementType.CLIENT_SIDE),
61+
("SHOW VARIABLE READ_TIMESTAMP", StatementType.CLIENT_SIDE),
6062
("rollback", StatementType.CLIENT_SIDE),
6163
(" rollback TRANSACTION ", StatementType.CLIENT_SIDE),
6264
("GRANT SELECT ON TABLE Singers TO ROLE parent", StatementType.DDL),

0 commit comments

Comments
 (0)