Skip to content

Commit ed5a4c4

Browse files
Fixed bug when using bind variables with scrollable cursors.
1 parent 131e065 commit ed5a4c4

File tree

6 files changed

+49
-7
lines changed

6 files changed

+49
-7
lines changed

doc/src/release_notes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ oracledb `3.5.0 <https://github.com/oracle/python-oracledb/compare/v3.4.0...v3.5
1919
Thin Mode Changes
2020
+++++++++++++++++
2121

22+
#) Fixed bug when using bind variables with scrollable cursors.
23+
2224
Thick Mode Changes
2325
++++++++++++++++++
2426

src/oracledb/impl/thin/constants.pxi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ cdef enum:
240240
cdef enum:
241241
TNS_EXEC_FLAGS_DML_ROWCOUNTS = 0x4000
242242
TNS_EXEC_FLAGS_IMPLICIT_RESULTSET = 0x8000
243+
TNS_EXEC_FLAGS_NO_CANCEL_ON_EOF = 0x80
243244
TNS_EXEC_FLAGS_SCROLLABLE = 0x02
244245

245246
# fetch orientations

src/oracledb/impl/thin/cursor.pyx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ cdef class BaseThinCursorImpl(BaseCursorImpl):
7272
message.num_execs = 1
7373
if self.scrollable:
7474
message.fetch_orientation = TNS_FETCH_ORIENTATION_CURRENT
75-
message.fetch_pos = 1
75+
message.fetch_pos = self.rowcount + 1
7676
return message
7777

7878
cdef ExecuteMessage _create_scroll_message(self, object cursor,
@@ -116,7 +116,7 @@ cdef class BaseThinCursorImpl(BaseCursorImpl):
116116

117117
# build message
118118
message = self._create_message(ExecuteMessage, cursor)
119-
message.scroll_operation = self._more_rows_to_fetch
119+
message.scroll_operation = True
120120
message.fetch_orientation = orientation
121121
message.fetch_pos = <uint32_t> desired_row
122122
return message
@@ -259,8 +259,8 @@ cdef class ThinCursorImpl(BaseThinCursorImpl):
259259
cdef:
260260
Protocol protocol = <Protocol> self._conn_impl._protocol
261261
MessageWithData message
262-
if self._statement._sql is None:
263-
message = self._create_message(ExecuteMessage, cursor)
262+
if self._statement._sql is None or self.scrollable:
263+
message = self._create_execute_message(cursor)
264264
else:
265265
message = self._create_message(FetchMessage, cursor)
266266
protocol._process_single_message(message)
@@ -357,8 +357,8 @@ cdef class AsyncThinCursorImpl(BaseThinCursorImpl):
357357
Internal method used for fetching rows from the database.
358358
"""
359359
cdef MessageWithData message
360-
if self._statement._sql is None:
361-
message = self._create_message(ExecuteMessage, cursor)
360+
if self._statement._sql is None or self.scrollable:
361+
message = self._create_execute_message(cursor)
362362
else:
363363
message = self._create_message(FetchMessage, cursor)
364364
await self._conn_impl._protocol._process_single_message(message)

src/oracledb/impl/thin/messages/execute.pyx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ cdef class ExecuteMessage(MessageWithData):
8383
options |= TNS_EXEC_OPTION_EXECUTE
8484
if cursor_impl.scrollable and not self.parse_only:
8585
exec_flags |= TNS_EXEC_FLAGS_SCROLLABLE
86+
exec_flags |= TNS_EXEC_FLAGS_NO_CANCEL_ON_EOF
8687
if stmt._cursor_id == 0 or stmt._is_ddl:
8788
options |= TNS_EXEC_OPTION_PARSE
8889
if stmt._is_query:
@@ -100,7 +101,7 @@ cdef class ExecuteMessage(MessageWithData):
100101
options |= TNS_EXEC_OPTION_NOT_PLSQL
101102
elif stmt._is_plsql and num_params > 0:
102103
options |= TNS_EXEC_OPTION_PLSQL_BIND
103-
if num_params > 0:
104+
if num_params > 0 and not self.scroll_operation:
104105
options |= TNS_EXEC_OPTION_BIND
105106
if self.batcherrors:
106107
options |= TNS_EXEC_OPTION_BATCH_ERRORS

tests/test_4200_cursor_scrollable.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,22 @@ def test_4215(conn):
246246
cursor.scroll(mode="last")
247247
(fetched_value,) = cursor.fetchone()
248248
assert fetched_value == 5
249+
250+
251+
def test_4216(conn):
252+
"4216 - test scroll operation with bind values"
253+
cursor = conn.cursor(scrollable=True)
254+
base_value = 4215
255+
cursor.execute(
256+
"""
257+
select :base_value + 1 from dual
258+
union all
259+
select :base_value + 2 from dual
260+
union all
261+
select :base_value + 3 from dual
262+
""",
263+
dict(base_value=base_value),
264+
)
265+
cursor.scroll(mode="last")
266+
(fetched_value,) = cursor.fetchone()
267+
assert fetched_value == base_value + 3

tests/test_8600_cursor_scrollable_async.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,22 @@ async def test_8615(async_conn):
249249
await cursor.scroll(mode="last")
250250
(fetched_value,) = await cursor.fetchone()
251251
assert fetched_value == 5
252+
253+
254+
async def test_8616(async_conn):
255+
"8616 - test scroll operation with bind values"
256+
cursor = async_conn.cursor(scrollable=True)
257+
base_value = 4215
258+
await cursor.execute(
259+
"""
260+
select :base_value + 1 from dual
261+
union all
262+
select :base_value + 2 from dual
263+
union all
264+
select :base_value + 3 from dual
265+
""",
266+
dict(base_value=base_value),
267+
)
268+
await cursor.scroll(mode="last")
269+
(fetched_value,) = await cursor.fetchone()
270+
assert fetched_value == base_value + 3

0 commit comments

Comments
 (0)