Skip to content

Commit 92831d4

Browse files
Thick: fixed issue fetching NCLOB with oracledb.defaults.fetch_lobs =
False; tidied up LOB test cases.
1 parent 8ace6ad commit 92831d4

File tree

9 files changed

+155
-87
lines changed

9 files changed

+155
-87
lines changed

doc/src/release_notes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ oracledb 1.0.1 (TBD)
1212
--------------------
1313

1414
#) Thick: restored support for bequeath connections.
15+
#) Thick: fixed issue fetching NCLOB with
16+
`oracledb.defaults.fetch_lobs = False`.
1517
#) Thin: added support for multiple aliases in one entry in tnsnames.ora
1618
(`issue 3 <https://github.com/oracle/python-oracledb/issues/3>`__).
1719
#) Thin: return the same value for timestamp with time zone columns as thick

src/oracledb/impl/thick/utils.pyx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,8 @@ cdef object _convert_to_python(ThickConnImpl conn_impl, DbType dbtype,
275275
or oracle_type == DPI_ORACLE_TYPE_NCHAR \
276276
or oracle_type == DPI_ORACLE_TYPE_VARCHAR \
277277
or oracle_type == DPI_ORACLE_TYPE_NVARCHAR \
278-
or oracle_type == DPI_ORACLE_TYPE_LONG_VARCHAR:
278+
or oracle_type == DPI_ORACLE_TYPE_LONG_VARCHAR \
279+
or oracle_type == DPI_ORACLE_TYPE_LONG_NVARCHAR:
279280
as_bytes = &dbvalue.asBytes
280281
return as_bytes.ptr[:as_bytes.length].decode()
281282
elif oracle_type == DPI_ORACLE_TYPE_NUMBER:

tests/test_1600_dml_returning.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ def test_1618_dml_returning_with_lob_and_outconverter(self):
373373
lob_value = "A short CLOB - 1618"
374374
self.cursor.execute("""
375375
insert into TestCLOBs
376+
(IntCol, ClobCol)
376377
values (1, :in_val)
377378
returning CLOBCol into :out_val""",
378379
in_val=lob_value,
@@ -387,6 +388,7 @@ def test_1619_dml_returning_with_clob_converted_to_long(self):
387388
lob_value = "A short CLOB - 1619"
388389
self.cursor.execute("""
389390
insert into TestCLOBs
391+
(IntCol, ClobCol)
390392
values (1, :in_val)
391393
returning CLOBCol into :out_val""",
392394
in_val=lob_value,

tests/test_1900_lob_var.py

Lines changed: 83 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def __get_temp_lobs(self, sid):
4747
def __perform_test(self, lob_type, input_type):
4848
long_string = ""
4949
db_type = getattr(oracledb, "DB_TYPE_" + lob_type)
50-
self.cursor.execute("truncate table Test%ss" % lob_type)
50+
self.cursor.execute(f"truncate table Test{lob_type}s")
5151
for i in range(0, 11):
5252
if i > 0:
5353
char = chr(ord('A') + i - 1)
@@ -59,45 +59,76 @@ def __perform_test(self, lob_type, input_type):
5959
bind_value = long_string.encode()
6060
else:
6161
bind_value = long_string
62-
self.cursor.execute("""
63-
insert into Test%ss (
62+
self.cursor.execute(f"""
63+
insert into Test{lob_type}s (
6464
IntCol,
65-
%sCol
65+
{lob_type}Col
6666
) values (
6767
:integer_value,
6868
:long_string
69-
)""" % (lob_type, lob_type),
69+
)""",
7070
integer_value=i,
7171
long_string=bind_value)
7272
self.connection.commit()
73-
self.cursor.execute("""
74-
select *
75-
from Test%ss
76-
order by IntCol""" % lob_type)
73+
self.cursor.execute(f"""
74+
select
75+
IntCol,
76+
{lob_type}Col
77+
from Test{lob_type}s
78+
order by IntCol""")
7779
self.__validate_query(self.cursor, lob_type)
7880

81+
def __test_fetch_lobs_direct(self, lob_type):
82+
self.cursor.execute(f"truncate table Test{lob_type}s")
83+
data = []
84+
long_string = ""
85+
for i in range(1, 11):
86+
if i > 0:
87+
char = chr(ord('A') + i - 1)
88+
long_string += char * 25000
89+
if lob_type == "BLOB":
90+
data.append((i, long_string.encode()))
91+
else:
92+
data.append((i, long_string))
93+
self.cursor.executemany(f"""
94+
insert into Test{lob_type}s (
95+
IntCol,
96+
{lob_type}Col
97+
) values (
98+
:1,
99+
:2
100+
)""", data)
101+
with test_env.FetchLobsContextManager(False):
102+
self.cursor.execute(f"""
103+
select
104+
IntCol,
105+
{lob_type}Col
106+
from Test{lob_type}s
107+
order by IntCol""")
108+
self.assertEqual(data, self.cursor.fetchall())
109+
79110
def __test_lob_operations(self, lob_type):
80-
self.cursor.execute("truncate table Test%ss" % lob_type)
111+
self.cursor.execute(f"truncate table Test{lob_type}s")
81112
self.cursor.setinputsizes(long_string=getattr(oracledb, lob_type))
82113
long_string = "X" * 75000
83114
write_value = "TEST"
84115
if lob_type == "BLOB":
85116
long_string = long_string.encode("ascii")
86117
write_value = write_value.encode("ascii")
87-
self.cursor.execute("""
88-
insert into Test%ss (
118+
self.cursor.execute(f"""
119+
insert into Test{lob_type}s (
89120
IntCol,
90-
%sCol
121+
{lob_type}Col
91122
) values (
92123
:integer_value,
93124
:long_string
94-
)""" % (lob_type, lob_type),
125+
)""",
95126
integer_value=1,
96127
long_string=long_string)
97-
self.cursor.execute("""
98-
select %sCol
99-
from Test%ss
100-
where IntCol = 1""" % (lob_type, lob_type))
128+
self.cursor.execute(f"""
129+
select {lob_type}Col
130+
from Test{lob_type}s
131+
where IntCol = 1""")
101132
lob, = self.cursor.fetchone()
102133
self.assertEqual(lob.isopen(), False)
103134
lob.open()
@@ -132,7 +163,7 @@ def __test_pickle(self, lob_type):
132163
self.assertEqual(unpickled_value, value)
133164

134165
def __test_temporary_lob(self, lob_type):
135-
self.cursor.execute("truncate table Test%ss" % lob_type)
166+
self.cursor.execute(f"truncate table Test{lob_type}s")
136167
value = "A test string value"
137168
if lob_type == "BLOB":
138169
value = value.encode("ascii")
@@ -183,15 +214,21 @@ def __validate_query(self, rows, lob_type):
183214
def test_1900_bind_lob_value(self):
184215
"1900 - test binding a LOB value directly"
185216
self.cursor.execute("truncate table TestCLOBs")
186-
self.cursor.execute("insert into TestCLOBs values (1, 'Short value')")
217+
self.cursor.execute("""
218+
insert into TestCLOBs
219+
(IntCol, ClobCol)
220+
values (1, 'Short value')""")
187221
self.cursor.execute("select ClobCol from TestCLOBs")
188222
lob, = self.cursor.fetchone()
189-
self.cursor.execute("insert into TestCLOBs values (2, :value)",
190-
value=lob)
223+
self.cursor.execute("""
224+
insert into TestCLOBs
225+
(IntCol, ClobCol)
226+
values (2, :value)""",
227+
value=lob)
191228

192229
def test_1901_blob_cursor_description(self):
193230
"1901 - test cursor description is accurate for BLOBs"
194-
self.cursor.execute("select * from TestBLOBs")
231+
self.cursor.execute("select IntCol, BlobCol from TestBLOBs")
195232
expected_value = [
196233
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
197234
('BLOBCOL', oracledb.DB_TYPE_BLOB, None, None, None, None, 0)
@@ -212,7 +249,7 @@ def test_1904_blob_operations(self):
212249

213250
def test_1905_clob_cursor_description(self):
214251
"1905 - test cursor description is accurate for CLOBs"
215-
self.cursor.execute("select * from TestCLOBs")
252+
self.cursor.execute("select IntCol, ClobCol from TestCLOBs")
216253
expected_value = [
217254
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, False),
218255
('CLOBCOL', oracledb.DB_TYPE_CLOB, None, None, None, None, False)
@@ -252,7 +289,7 @@ def test_1912_multiple_fetch(self):
252289

253290
def test_1913_nclob_cursor_description(self):
254291
"1913 - test cursor description is accurate for NCLOBs"
255-
self.cursor.execute("select * from TestNCLOBs")
292+
self.cursor.execute("select IntCol, NClobCol from TestNCLOBs")
256293
expected_value = [
257294
('INTCOL', oracledb.DB_TYPE_NUMBER, 10, None, 9, 0, 0),
258295
('NCLOBCOL', oracledb.DB_TYPE_NCLOB, None, None, None, None, 0)
@@ -268,8 +305,10 @@ def test_1915_nclob_non_ascii_chars(self):
268305
value = "\u03b4\u4e2a"
269306
self.cursor.execute("truncate table TestNCLOBs")
270307
self.cursor.setinputsizes(val=oracledb.DB_TYPE_NVARCHAR)
271-
self.cursor.execute("insert into TestNCLOBs values (1, :val)",
272-
val=value)
308+
self.cursor.execute("""
309+
insert into TestNCLOBs (IntCol, NClobCol)
310+
values (1, :val)""",
311+
val=value)
273312
self.cursor.execute("select NCLOBCol from TestNCLOBs")
274313
nclob, = self.cursor.fetchone()
275314
self.cursor.setinputsizes(val=oracledb.DB_TYPE_NVARCHAR)
@@ -327,7 +366,11 @@ def test_1920_supplemental_characters(self):
327366
self.cursor.execute("truncate table TestCLOBs")
328367
lob = self.connection.createlob(oracledb.DB_TYPE_CLOB)
329368
lob.write(supplemental_chars)
330-
self.cursor.execute("insert into TestCLOBs values (1, :val)", [lob])
369+
self.cursor.execute("""
370+
insert into TestCLOBs
371+
(IntCol, ClobCol)
372+
values (1, :val)""",
373+
[lob])
331374
self.connection.commit()
332375
self.cursor.execute("select ClobCol from TestCLOBs")
333376
lob, = self.cursor.fetchone()
@@ -395,5 +438,17 @@ def test_1926_pickle_nclob(self):
395438
"1925 - test pickling of NCLOB"
396439
self.__test_pickle("NCLOB")
397440

441+
def test_1927_fetch_blob_as_bytes(self):
442+
"1927 - test fetching BLOB as bytes"
443+
self.__test_fetch_lobs_direct("BLOB")
444+
445+
def test_1928_fetch_clob_as_str(self):
446+
"1928 - test fetching CLOB as str"
447+
self.__test_fetch_lobs_direct("CLOB")
448+
449+
def test_1929_fetch_nclob_as_str(self):
450+
"1929 - test fetching NCLOB as str"
451+
self.__test_fetch_lobs_direct("NCLOB")
452+
398453
if __name__ == "__main__":
399454
test_env.run_test_cases()

tests/test_2200_number_var.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -466,14 +466,10 @@ def test_2236_out_bind_binary_int_with_large_value(self):
466466

467467
def test_2237_fetch_number_with_lobs_default_false(self):
468468
"2237 - fetch a number with oracledb.defaults.fetch_lobs = False"
469-
orig_fetch_lobs = oracledb.defaults.fetch_lobs
470-
oracledb.defaults.fetch_lobs = False
471-
try:
469+
with test_env.FetchLobsContextManager(False):
472470
self.cursor.execute("select 1 from dual")
473471
result, = self.cursor.fetchone()
474472
self.assertEqual(type(result), int)
475-
finally:
476-
oracledb.defaults.fetch_lobs = orig_fetch_lobs
477473

478474
if __name__ == "__main__":
479475
test_env.run_test_cases()

tests/test_2300_object_var.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -262,12 +262,18 @@ def test_2307_round_trip_object(self):
262262
self.cursor.execute("truncate table TestClobs")
263263
self.cursor.execute("truncate table TestNClobs")
264264
self.cursor.execute("truncate table TestBlobs")
265-
self.cursor.execute("insert into TestClobs values " \
266-
"(1, 'A short CLOB')")
267-
self.cursor.execute("insert into TestNClobs values " \
268-
"(1, 'A short NCLOB')")
269-
self.cursor.execute("insert into TestBlobs values " \
270-
"(1, utl_raw.cast_to_raw('A short BLOB'))")
265+
self.cursor.execute("""
266+
insert into TestClobs
267+
(IntCol, ClobCol)
268+
values (1, 'A short CLOB')""")
269+
self.cursor.execute("""
270+
insert into TestNClobs
271+
(IntCol, NClobCol)
272+
values (1, 'A short NCLOB')""")
273+
self.cursor.execute("""
274+
insert into TestBlobs
275+
(IntCol, BlobCol)
276+
values (1, utl_raw.cast_to_raw('A short BLOB'))""")
271277
self.connection.commit()
272278
self.cursor.execute("select CLOBCol from TestClobs")
273279
clob, = self.cursor.fetchone()

tests/test_3600_outputtypehandler.py

Lines changed: 26 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -47,43 +47,28 @@ def type_handler(cursor, name, default_type, size, precision, scale):
4747
self.assertEqual(type(fetched_value), type(expected_out_value))
4848
self.assertEqual(fetched_value, expected_out_value)
4949

50-
def __test_type_handler_blob(self, output_type):
50+
def __test_type_handler_lob(self, lob_type, output_type):
51+
db_type = getattr(oracledb, lob_type)
5152
def type_handler(cursor, name, default_type, size, precision, scale):
52-
if default_type == oracledb.DB_TYPE_BLOB:
53+
if default_type == db_type:
5354
return cursor.var(output_type, arraysize=cursor.arraysize)
5455
self.cursor.outputtypehandler = type_handler
55-
in_value = b"Some binary data"
56-
self.cursor.execute("truncate table TestBLOBs")
57-
self.cursor.execute("insert into TestBLOBs values(1, :val)",
58-
val=in_value)
56+
in_value = f"Some {lob_type} data"
57+
if lob_type == "BLOB":
58+
in_value = in_value.encode()
59+
self.cursor.execute(f"truncate table Test{lob_type}s")
60+
self.cursor.execute(f"""
61+
insert into Test{lob_type}s
62+
(IntCol, {lob_type}Col)
63+
values(1, :val)""",
64+
val=in_value)
5965
self.connection.commit()
60-
self.cursor.execute("select BlobCol, IntCol, BlobCol from TestBLOBs")
61-
self.assertEqual(self.cursor.fetchone(), (in_value, 1, in_value))
62-
63-
def __test_type_handler_clob(self, output_type):
64-
def type_handler(cursor, name, default_type, size, precision, scale):
65-
if default_type == oracledb.DB_TYPE_CLOB:
66-
return cursor.var(output_type, arraysize=cursor.arraysize)
67-
self.cursor.outputtypehandler = type_handler
68-
in_value = "Some clob data"
69-
self.cursor.execute("truncate table TestCLOBs")
70-
self.cursor.execute("insert into TestCLOBs values(1, :val)",
71-
val=in_value)
72-
self.connection.commit()
73-
self.cursor.execute("select ClobCol, IntCol, ClobCol from TestCLOBs")
74-
self.assertEqual(self.cursor.fetchone(), (in_value, 1, in_value))
75-
76-
def __test_type_handler_nclob(self, output_type):
77-
def type_handler(cursor, name, default_type, size, precision, scale):
78-
if default_type == oracledb.DB_TYPE_NCLOB:
79-
return cursor.var(output_type, arraysize=cursor.arraysize)
80-
self.cursor.outputtypehandler = type_handler
81-
in_value = "Some nclob data"
82-
self.cursor.execute("truncate table TestNCLOBs")
83-
self.cursor.execute("insert into TestNCLOBs values(1, :val)",
84-
val=in_value)
85-
self.connection.commit()
86-
self.cursor.execute("select NClobCol, IntCol, NClobCol from TestNCLOBs")
66+
self.cursor.execute(f"""
67+
select
68+
{lob_type}Col,
69+
IntCol,
70+
{lob_type}Col
71+
from Test{lob_type}s""")
8772
self.assertEqual(self.cursor.fetchone(), (in_value, 1, in_value))
8873

8974
def setUp(self):
@@ -424,23 +409,23 @@ def test_3655_BLOB_TO_LONG_RAW(self):
424409

425410
def test_3656_BLOB_TO_LONG_RAW(self):
426411
"3656 - output type handler conversion from permanent BLOBs to LONG_RAW"
427-
self.__test_type_handler_blob(oracledb.DB_TYPE_LONG_RAW)
412+
self.__test_type_handler_lob("BLOB", oracledb.DB_TYPE_LONG_RAW)
428413

429414
def test_3657_BLOB_TO_RAW(self):
430415
"3657 - output type handler conversion from permanent BLOBs to RAW"
431-
self.__test_type_handler_blob(oracledb.DB_TYPE_RAW)
416+
self.__test_type_handler_lob("BLOB", oracledb.DB_TYPE_RAW)
432417

433418
def test_3658_CLOB_TO_VARCHAR(self):
434419
"3658 - output type handler conversion from permanent CLOBs to VARCHAR"
435-
self.__test_type_handler_clob(oracledb.DB_TYPE_VARCHAR)
420+
self.__test_type_handler_lob("CLOB", oracledb.DB_TYPE_VARCHAR)
436421

437422
def test_3659_CLOB_TO_CHAR(self):
438423
"3659 - output type handler conversion from permanent CLOBs to CHAR"
439-
self.__test_type_handler_clob(oracledb.DB_TYPE_CHAR)
424+
self.__test_type_handler_lob("CLOB", oracledb.DB_TYPE_CHAR)
440425

441426
def test_3660_CLOB_TO_LONG(self):
442427
"3660 - output type handler conversion from permanent CLOBs to LONG"
443-
self.__test_type_handler_clob(oracledb.DB_TYPE_LONG)
428+
self.__test_type_handler_lob("CLOB", oracledb.DB_TYPE_LONG)
444429

445430
def test_3661_NCLOB_TO_CHAR(self):
446431
"3661 - output type handler conversion from NCLOB to CHAR"
@@ -462,15 +447,15 @@ def test_3663_NCLOB_TO_LONG(self):
462447

463448
def test_3664_NCLOB_TO_VARCHAR(self):
464449
"3664 - output type handler conversion from permanent NCLOBs to VARCHAR"
465-
self.__test_type_handler_nclob(oracledb.DB_TYPE_VARCHAR)
450+
self.__test_type_handler_lob("NCLOB", oracledb.DB_TYPE_VARCHAR)
466451

467452
def test_3665_NCLOB_TO_CHAR(self):
468453
"3665 - output type handler conversion from permanent NCLOBs to CHAR"
469-
self.__test_type_handler_nclob(oracledb.DB_TYPE_CHAR)
454+
self.__test_type_handler_lob("NCLOB", oracledb.DB_TYPE_CHAR)
470455

471456
def test_3666_NCLOB_TO_LONG(self):
472457
"3666 - output type handler conversion from permanent NCLOBs to LONG"
473-
self.__test_type_handler_nclob(oracledb.DB_TYPE_LONG)
458+
self.__test_type_handler_lob("NCLOB", oracledb.DB_TYPE_LONG)
474459

475460
def test_3667_NVARCHAR_to_VARCHAR(self):
476461
"3667 - output type handler conversion from NVARCHAR to VARCHAR"

0 commit comments

Comments
 (0)