Skip to content

Commit 3d4f8f4

Browse files
sfc-gh-aalamKachesfc-gh-mkeller
authored
Test 1493 (#1515)
Co-authored-by: Kevin C <[email protected]> Co-authored-by: Mark Keller <[email protected]>
1 parent 72c4f15 commit 3d4f8f4

File tree

3 files changed

+41
-30
lines changed

3 files changed

+41
-30
lines changed

DESCRIPTION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Source code is also available at: https://github.com/snowflakedb/snowflake-conne
1313
- Fixed a bug in which we cannot call `SnowflakeCursor.nextset` before fetching the result of the first query if the cursor runs an async multistatement query.
1414
- Bumped vendored library urllib3 to 1.26.15
1515
- Bumped vendored library requests to 2.29.0
16-
16+
- Fixed a bug when `_prefetch_hook()` was not called before yielding results of `execute_async()`.
1717

1818
- v3.0.3(April 20, 2023)
1919
- Fixed a bug that prints error in logs for GET command on GCS.

src/snowflake/connector/cursor.py

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
TYPE_CHECKING,
2222
Any,
2323
Callable,
24-
Generator,
2524
Iterator,
2625
NamedTuple,
2726
NoReturn,
@@ -1242,37 +1241,30 @@ def executemany(
12421241

12431242
return self
12441243

1245-
def _result_iterator(
1246-
self,
1247-
) -> Generator[dict, None, None] | Generator[tuple, None, None]:
1248-
"""Yields the elements from _result and raises an exception when appropriate."""
1249-
try:
1250-
for _next in self._result:
1251-
if isinstance(_next, Exception):
1252-
Error.errorhandler_wrapper_from_ready_exception(
1253-
self._connection,
1254-
self,
1255-
_next,
1256-
)
1257-
self._rownumber += 1
1258-
yield _next
1259-
except TypeError as err:
1260-
if self._result_state == ResultState.DEFAULT:
1261-
raise err
1262-
else:
1263-
yield None
1264-
12651244
def fetchone(self) -> dict | tuple | None:
12661245
"""Fetches one row."""
12671246
if self._prefetch_hook is not None:
12681247
self._prefetch_hook()
12691248
if self._result is None and self._result_set is not None:
12701249
self._result = iter(self._result_set)
12711250
self._result_state = ResultState.VALID
1251+
12721252
try:
1273-
return next(self._result_iterator())
1274-
except StopIteration:
1275-
return None
1253+
_next = next(self._result, None)
1254+
if isinstance(_next, Exception):
1255+
Error.errorhandler_wrapper_from_ready_exception(
1256+
self._connection,
1257+
self,
1258+
_next,
1259+
)
1260+
if _next is not None:
1261+
self._rownumber += 1
1262+
return _next
1263+
except TypeError as err:
1264+
if self._result_state == ResultState.DEFAULT:
1265+
raise err
1266+
else:
1267+
return None
12761268

12771269
def fetchmany(self, size: int | None = None) -> list[tuple] | list[dict]:
12781270
"""Fetches the number of specified rows."""
@@ -1369,11 +1361,11 @@ def reset(self, closing: bool = False) -> None:
13691361

13701362
def __iter__(self) -> Iterator[dict] | Iterator[tuple]:
13711363
"""Iteration over the result set."""
1372-
# set _result if _result_set is not None
1373-
if self._result is None and self._result_set is not None:
1374-
self._result = iter(self._result_set)
1375-
self._result_state = ResultState.VALID
1376-
return self._result_iterator()
1364+
while True:
1365+
_next = self.fetchone()
1366+
if _next is None:
1367+
break
1368+
yield _next
13771369

13781370
def __cancel_query(self, query) -> None:
13791371
if self._sequence_counter >= 0 and not self.is_closed():

test/integ/test_async.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,25 @@ def test_simple_async(conn_cnx):
3535
assert cur.description
3636

3737

38+
def test_async_result_iteration(conn_cnx):
39+
"""Test yielding results of an async query.
40+
41+
Ensures that wait_until_ready is also called in __iter__() via _prefetch_hook().
42+
"""
43+
44+
def result_generator(query):
45+
with conn_cnx() as con:
46+
with con.cursor() as cur:
47+
cur.execute_async(query)
48+
cur.get_results_from_sfqid(cur.sfqid)
49+
yield from cur
50+
51+
gen = result_generator("select count(*) from table(generator(timeLimit => 5))")
52+
assert next(gen)
53+
with pytest.raises(StopIteration):
54+
next(gen)
55+
56+
3857
def test_async_exec(conn_cnx):
3958
"""Tests whether simple async query execution works.
4059

0 commit comments

Comments
 (0)