Skip to content

Commit

Permalink
feat(db_api): make rowcount property NotImplemented (#603)
Browse files Browse the repository at this point in the history
Co-authored-by: larkee <31196561+larkee@users.noreply.github.com>
  • Loading branch information
Ilya Gurov and larkee committed Oct 14, 2021
1 parent a6adbcb commit b5a567f
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 27 deletions.
23 changes: 8 additions & 15 deletions google/cloud/spanner_dbapi/cursor.py
Expand Up @@ -44,8 +44,6 @@

from google.rpc.code_pb2 import ABORTED, OK

_UNSET_COUNT = -1

ColumnDetails = namedtuple("column_details", ["null_ok", "spanner_type"])
Statement = namedtuple("Statement", "sql, params, param_types, checksum, is_insert")

Expand All @@ -60,7 +58,6 @@ class Cursor(object):
def __init__(self, connection):
self._itr = None
self._result_set = None
self._row_count = _UNSET_COUNT
self.lastrowid = None
self.connection = connection
self._is_closed = False
Expand Down Expand Up @@ -119,12 +116,15 @@ def description(self):

@property
def rowcount(self):
"""The number of rows produced by the last `.execute()`.
"""The number of rows produced by the last `execute()` call.
:rtype: int
:returns: The number of rows produced by the last .execute*().
:raises: :class:`NotImplemented`.
"""
return self._row_count
raise NotImplementedError(
"The `rowcount` property is non-operational. Request "
"resulting rows are streamed by the `fetch*()` methods "
"and can't be counted before they are all streamed."
)

def _raise_if_closed(self):
"""Raise an exception if this cursor is closed.
Expand Down Expand Up @@ -153,11 +153,7 @@ def _do_execute_update(self, transaction, sql, params):
result = transaction.execute_update(
sql, params=params, param_types=get_param_types(params)
)
self._itr = None
if type(result) == int:
self._row_count = result

return result
self._itr = iter([result])

def _do_batch_update(self, transaction, statements, many_result_set):
status, res = transaction.batch_update(statements)
Expand Down Expand Up @@ -421,9 +417,6 @@ def _handle_DQL_with_snapshot(self, snapshot, sql, params):
# Read the first element so that the StreamedResultSet can
# return the metadata after a DQL statement. See issue #155.
self._itr = PeekIterator(self._result_set)
# Unfortunately, Spanner doesn't seem to send back
# information about the number of rows available.
self._row_count = _UNSET_COUNT

def _handle_DQL(self, sql, params):
if self.connection.read_only and not self.connection.autocommit:
Expand Down
20 changes: 8 additions & 12 deletions tests/unit/spanner_dbapi/test_cursor.py
Expand Up @@ -62,11 +62,10 @@ def test_property_description(self):
self.assertIsInstance(cursor.description[0], ColumnInfo)

def test_property_rowcount(self):
from google.cloud.spanner_dbapi.cursor import _UNSET_COUNT

connection = self._make_connection(self.INSTANCE, self.DATABASE)
cursor = self._make_one(connection)
self.assertEqual(cursor.rowcount, _UNSET_COUNT)
with self.assertRaises(NotImplementedError):
cursor.rowcount

def test_callproc(self):
from google.cloud.spanner_dbapi.exceptions import InterfaceError
Expand Down Expand Up @@ -94,26 +93,25 @@ def test_close(self, mock_client):
cursor.execute("SELECT * FROM database")

def test_do_execute_update(self):
from google.cloud.spanner_dbapi.cursor import _UNSET_COUNT
from google.cloud.spanner_dbapi.checksum import ResultsChecksum

connection = self._make_connection(self.INSTANCE, self.DATABASE)
cursor = self._make_one(connection)
cursor._checksum = ResultsChecksum()
transaction = mock.MagicMock()

def run_helper(ret_value):
transaction.execute_update.return_value = ret_value
res = cursor._do_execute_update(
cursor._do_execute_update(
transaction=transaction, sql="SELECT * WHERE true", params={},
)
return res
return cursor.fetchall()

expected = "good"
self.assertEqual(run_helper(expected), expected)
self.assertEqual(cursor._row_count, _UNSET_COUNT)
self.assertEqual(run_helper(expected), [expected])

expected = 1234
self.assertEqual(run_helper(expected), expected)
self.assertEqual(cursor._row_count, expected)
self.assertEqual(run_helper(expected), [expected])

def test_execute_programming_error(self):
from google.cloud.spanner_dbapi.exceptions import ProgrammingError
Expand Down Expand Up @@ -706,7 +704,6 @@ def test_setoutputsize(self):

def test_handle_dql(self):
from google.cloud.spanner_dbapi import utils
from google.cloud.spanner_dbapi.cursor import _UNSET_COUNT

connection = self._make_connection(self.INSTANCE, mock.MagicMock())
connection.database.snapshot.return_value.__enter__.return_value = (
Expand All @@ -718,7 +715,6 @@ def test_handle_dql(self):
cursor._handle_DQL("sql", params=None)
self.assertEqual(cursor._result_set, ["0"])
self.assertIsInstance(cursor._itr, utils.PeekIterator)
self.assertEqual(cursor._row_count, _UNSET_COUNT)

def test_context(self):
connection = self._make_connection(self.INSTANCE, self.DATABASE)
Expand Down

0 comments on commit b5a567f

Please sign in to comment.