-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implementation for Begin and Rollback clientside statements
- Loading branch information
Showing
8 changed files
with
200 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,7 +22,7 @@ | |
from google.cloud._helpers import UTC | ||
|
||
from google.cloud.spanner_dbapi.connection import Connection, connect | ||
from google.cloud.spanner_dbapi.exceptions import ProgrammingError | ||
from google.cloud.spanner_dbapi.exceptions import ProgrammingError, OperationalError | ||
from google.cloud.spanner_v1 import JsonObject | ||
from google.cloud.spanner_v1 import gapic_version as package_version | ||
from . import _helpers | ||
|
@@ -80,42 +80,43 @@ def init_connection(self, request, shared_instance, dbapi_database): | |
self._cursor.close() | ||
self._conn.close() | ||
|
||
@pytest.fixture | ||
def execute_common_statements(self): | ||
def _execute_common_statements(self, cursor): | ||
# execute several DML statements within one transaction | ||
self._cursor.execute( | ||
cursor.execute( | ||
""" | ||
INSERT INTO contacts (contact_id, first_name, last_name, email) | ||
VALUES (1, 'first-name', 'last-name', '[email protected]') | ||
""" | ||
) | ||
self._cursor.execute( | ||
cursor.execute( | ||
""" | ||
UPDATE contacts | ||
SET first_name = 'updated-first-name' | ||
WHERE first_name = 'first-name' | ||
""" | ||
) | ||
self._cursor.execute( | ||
cursor.execute( | ||
""" | ||
UPDATE contacts | ||
SET email = '[email protected]' | ||
WHERE email = '[email protected]' | ||
""" | ||
) | ||
|
||
@pytest.fixture | ||
def updated_row(self, execute_common_statements): | ||
return ( | ||
1, | ||
"updated-first-name", | ||
"last-name", | ||
"[email protected]", | ||
) | ||
|
||
def test_commit(self, updated_row): | ||
@pytest.mark.parametrize("client_side", [False, True]) | ||
def test_commit(self, client_side): | ||
"""Test committing a transaction with several statements.""" | ||
self._conn.commit() | ||
updated_row = self._execute_common_statements(self._cursor) | ||
if client_side: | ||
self._cursor.execute("""COMMIT""") | ||
else: | ||
self._conn.commit() | ||
|
||
# read the resulting data from the database | ||
self._cursor.execute("SELECT * FROM contacts") | ||
|
@@ -124,18 +125,80 @@ def test_commit(self, updated_row): | |
|
||
assert got_rows == [updated_row] | ||
|
||
def test_commit_client_side(self, updated_row): | ||
"""Test committing a transaction with several statements.""" | ||
self._cursor.execute("""COMMIT""") | ||
@pytest.mark.noautofixt | ||
def test_begin_client_side(self, shared_instance, dbapi_database): | ||
"""Test beginning a transaction using client side statement, | ||
where connection is in autocommit mode.""" | ||
|
||
conn1 = Connection(shared_instance, dbapi_database) | ||
conn1.autocommit = True | ||
cursor1 = conn1.cursor() | ||
cursor1.execute("begin transaction") | ||
updated_row = self._execute_common_statements(cursor1) | ||
|
||
# As the connection conn1 is not committed a new connection wont see its results | ||
conn2 = Connection(shared_instance, dbapi_database) | ||
cursor2 = conn2.cursor() | ||
cursor2.execute("SELECT * FROM contacts") | ||
conn2.commit() | ||
got_rows = cursor2.fetchall() | ||
assert got_rows != [updated_row] | ||
|
||
assert conn1._transaction_begin_marked is True | ||
conn1.commit() | ||
assert conn1._transaction_begin_marked is False | ||
|
||
# As the connection conn1 is committed a new connection should see its results | ||
conn3 = Connection(shared_instance, dbapi_database) | ||
cursor3 = conn3.cursor() | ||
cursor3.execute("SELECT * FROM contacts") | ||
conn3.commit() | ||
got_rows = cursor3.fetchall() | ||
assert got_rows == [updated_row] | ||
|
||
# read the resulting data from the database | ||
conn1.close() | ||
conn2.close() | ||
conn3.close() | ||
cursor1.close() | ||
cursor2.close() | ||
cursor3.close() | ||
|
||
def test_begin_success_post_commit(self): | ||
"""Test beginning a new transaction post commiting an existing transaction | ||
is possible on a connection, when connection is in autocommit mode.""" | ||
want_row = (2, "first-name", "last-name", "[email protected]") | ||
self._conn.autocommit = True | ||
self._cursor.execute("begin transaction") | ||
self._cursor.execute( | ||
""" | ||
INSERT INTO contacts (contact_id, first_name, last_name, email) | ||
VALUES (2, 'first-name', 'last-name', '[email protected]') | ||
""" | ||
) | ||
self._conn.commit() | ||
|
||
self._cursor.execute("begin transaction") | ||
self._cursor.execute("SELECT * FROM contacts") | ||
got_rows = self._cursor.fetchall() | ||
self._conn.commit() | ||
assert got_rows == [want_row] | ||
|
||
assert got_rows == [updated_row] | ||
def test_begin_error_before_commit(self): | ||
"""Test beginning a new transaction before commiting an existing transaction is not possible on a connection, when connection is in autocommit mode.""" | ||
self._conn.autocommit = True | ||
self._cursor.execute("begin transaction") | ||
self._cursor.execute( | ||
""" | ||
INSERT INTO contacts (contact_id, first_name, last_name, email) | ||
VALUES (2, 'first-name', 'last-name', '[email protected]') | ||
""" | ||
) | ||
|
||
with pytest.raises(OperationalError): | ||
self._cursor.execute("begin transaction") | ||
|
||
def test_rollback(self): | ||
@pytest.mark.parametrize("client_side", [False, True]) | ||
def test_rollback(self, client_side): | ||
"""Test rollbacking a transaction with several statements.""" | ||
want_row = (2, "first-name", "last-name", "[email protected]") | ||
|
||
|
@@ -162,7 +225,11 @@ def test_rollback(self): | |
WHERE email = '[email protected]' | ||
""" | ||
) | ||
self._conn.rollback() | ||
|
||
if client_side: | ||
self._cursor.execute("ROLLBACK") | ||
else: | ||
self._conn.rollback() | ||
|
||
# read the resulting data from the database | ||
self._cursor.execute("SELECT * FROM contacts") | ||
|
Oops, something went wrong.