Skip to content

Commit 4264d7b

Browse files
Improved test suite; added check that the LOB type matches the expected
LOB type.
1 parent 250b072 commit 4264d7b

9 files changed

+936
-30
lines changed

doc/src/release_notes.rst

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Version 8.2 (TBD)
2222
#) The distributed transaction handle assosciated with the connection is now
2323
cleared on commit or rollback (`issue 530
2424
<https://github.com/oracle/python-cx_Oracle/issues/530>`__).
25+
#) Added check to ensure that when setting variables or object attributes, the
26+
type of the temporary LOB must match the expected type.
27+
#) Improved test suite.
2528

2629

2730
Version 8.1 (December 2020)

src/cxoTransform.c

+10
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,16 @@ int cxoTransform_fromPython(cxoTransformNum transformNum,
282282
case CXO_TRANSFORM_NCLOB:
283283
if (Py_TYPE(pyValue) == &cxoPyTypeLob) {
284284
lob = (cxoLob*) pyValue;
285+
if ((lob->dbType == cxoDbTypeBlob &&
286+
transformNum != CXO_TRANSFORM_BLOB) ||
287+
(lob->dbType == cxoDbTypeClob &&
288+
transformNum != CXO_TRANSFORM_CLOB) ||
289+
(lob->dbType == cxoDbTypeNclob &&
290+
transformNum != CXO_TRANSFORM_NCLOB)) {
291+
PyErr_SetString(PyExc_TypeError,
292+
"LOB must be of the correct type");
293+
return -1;
294+
}
285295
if (var) {
286296
if (dpiVar_setFromLob(var->handle, arrayPos,
287297
lob->handle) < 0)

test/test_1200_cursor.py

+48-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#------------------------------------------------------------------------------
2-
# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved.
33
#
44
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
55
#
@@ -14,6 +14,7 @@
1414
import test_env
1515
import cx_Oracle as oracledb
1616
import decimal
17+
import datetime
1718

1819
class TestCase(test_env.BaseTestCase):
1920

@@ -933,5 +934,51 @@ def test_1278_execute_with_incorrect_bind_values(self):
933934
self.assertRaises(oracledb.DatabaseError, self.cursor.execute,
934935
statement, value=var, value2=var, value3=var)
935936

937+
def test_1279_change_in_size_on_successive_bind(self):
938+
"1279 - change in size on subsequent binds does not use optimised path"
939+
self.cursor.execute("truncate table TestTempTable")
940+
data = [
941+
(1, "Test String #1"),
942+
(2, "ABC" * 100)
943+
]
944+
sql = "insert into TestTempTable (IntCol, StringCol) values (:1, :2)"
945+
for row in data:
946+
self.cursor.execute(sql, row)
947+
self.connection.commit()
948+
self.cursor.execute("select IntCol, StringCol from TestTempTable")
949+
self.assertEqual(self.cursor.fetchall(), data)
950+
951+
def test_1280_change_in_type_on_successive_bind(self):
952+
"1280 - change in type on subsequent binds cannot use optimised path"
953+
sql = "select :1 from dual"
954+
self.cursor.execute(sql, ('W',))
955+
row, = self.cursor.fetchone()
956+
self.assertEqual(row, 'W')
957+
self.cursor.execute(sql, ('S',))
958+
row, = self.cursor.fetchone()
959+
self.assertEqual(row, 'S')
960+
self.cursor.execute(sql, (7,))
961+
row, = self.cursor.fetchone()
962+
self.assertEqual(row, '7')
963+
964+
def test_1281_dml_can_use_optimised_path(self):
965+
"1281 - test that dml can use optimised path"
966+
data_to_insert = [
967+
(1, "Test String #1"),
968+
(2, "Test String #2"),
969+
(3, "Test String #3")
970+
]
971+
self.cursor.execute("truncate table TestTempTable")
972+
sql = "insert into TestTempTable (IntCol, StringCol) values (:1, :2)"
973+
for row in data_to_insert:
974+
with self.connection.cursor() as cursor:
975+
cursor.execute(sql, row)
976+
self.connection.commit()
977+
self.cursor.execute("""
978+
select IntCol, StringCol
979+
from TestTempTable
980+
order by IntCol""")
981+
self.assertEqual(self.cursor.fetchall(), data_to_insert)
982+
936983
if __name__ == "__main__":
937984
test_env.run_test_cases()

test/test_1300_cursor_var.py

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#------------------------------------------------------------------------------
2-
# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved.
33
#
44
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
55
#
@@ -94,5 +94,35 @@ def test_1304_fetch_cursor(self):
9494
self.assertEqual(number, i)
9595
self.assertEqual(cursor.fetchall(), [(i + 1,)])
9696

97+
def test_1305_ref_cursor_binds(self):
98+
"1305 - test that ref cursor binds cannot use optimised path"
99+
ref_cursor = self.connection.cursor()
100+
sql = """
101+
begin
102+
open :rcursor for
103+
select IntCol, StringCol
104+
from TestStrings where IntCol
105+
between :start_value and :end_value;
106+
end;"""
107+
self.cursor.execute(sql, rcursor=ref_cursor, start_value=2,
108+
end_value=4)
109+
expected_value = [
110+
(2, 'String 2'),
111+
(3, 'String 3'),
112+
(4, 'String 4')
113+
]
114+
rows = ref_cursor.fetchall()
115+
ref_cursor.close()
116+
self.assertEqual(rows, expected_value)
117+
ref_cursor = self.connection.cursor()
118+
self.cursor.execute(sql, rcursor=ref_cursor, start_value=5,
119+
end_value=6)
120+
expected_value = [
121+
(5, 'String 5'),
122+
(6, 'String 6')
123+
]
124+
rows = ref_cursor.fetchall()
125+
self.assertEqual(rows, expected_value)
126+
97127
if __name__ == "__main__":
98128
test_env.run_test_cases()

test/test_2300_object_var.py

+10-27
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,11 @@
1919

2020
class TestCase(test_env.BaseTestCase):
2121

22-
def __get_object_as_tuple(self, obj):
23-
if obj.type.iscollection:
24-
value = []
25-
for v in obj.aslist():
26-
if isinstance(v, oracledb.Object):
27-
v = self.__get_object_as_tuple(v)
28-
elif isinstance(value, oracledb.LOB):
29-
v = v.read()
30-
value.append(v)
31-
return value
32-
attribute_values = []
33-
for attribute in obj.type.attributes:
34-
value = getattr(obj, attribute.name)
35-
if isinstance(value, oracledb.Object):
36-
value = self.__get_object_as_tuple(value)
37-
elif isinstance(value, oracledb.LOB):
38-
value = value.read()
39-
attribute_values.append(value)
40-
return tuple(attribute_values)
41-
4222
def __test_data(self, expected_int_value, expected_obj_value,
4323
expected_array_value):
4424
int_value, object_value, array_value = self.cursor.fetchone()
4525
if object_value is not None:
46-
object_value = self.__get_object_as_tuple(object_value)
26+
object_value = self.get_db_object_as_plain_object(object_value)
4727
if array_value is not None:
4828
array_value = array_value.aslist()
4929
self.assertEqual(int_value, expected_int_value)
@@ -413,7 +393,7 @@ def test_2311_access_sub_object_parent_object_destroyed(self):
413393
obj.SUBOBJECTARRAY = array_type.newobject([sub_obj1, sub_obj2])
414394
sub_obj_array = obj.SUBOBJECTARRAY
415395
del obj
416-
self.assertEqual(self.__get_object_as_tuple(sub_obj_array),
396+
self.assertEqual(self.get_db_object_as_plain_object(sub_obj_array),
417397
[(2, "AB"), (3, "CDE")])
418398

419399
def test_2312_setting_attr_wrong_object_type(self):
@@ -452,15 +432,18 @@ def test_2315_trim_collection_list(self):
452432
subObj.SUBNUMBERVALUE = num_val
453433
subObj.SUBSTRINGVALUE = str_val
454434
array_obj.append(subObj)
455-
self.assertEqual(self.__get_object_as_tuple(array_obj), data)
435+
self.assertEqual(self.get_db_object_as_plain_object(array_obj), data)
456436
array_obj.trim(2)
457-
self.assertEqual(self.__get_object_as_tuple(array_obj), data[:2])
437+
self.assertEqual(self.get_db_object_as_plain_object(array_obj),
438+
data[:2])
458439
array_obj.trim(1)
459-
self.assertEqual(self.__get_object_as_tuple(array_obj), data[:1])
440+
self.assertEqual(self.get_db_object_as_plain_object(array_obj),
441+
data[:1])
460442
array_obj.trim(0)
461-
self.assertEqual(self.__get_object_as_tuple(array_obj), data[:1])
443+
self.assertEqual(self.get_db_object_as_plain_object(array_obj),
444+
data[:1])
462445
array_obj.trim(1)
463-
self.assertEqual(self.__get_object_as_tuple(array_obj), [])
446+
self.assertEqual(self.get_db_object_as_plain_object(array_obj), [])
464447

465448
if __name__ == "__main__":
466449
test_env.run_test_cases()

test/test_2500_string_var.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#------------------------------------------------------------------------------
2-
# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2016, 2021 Oracle and/or its affiliates. All rights reserved.
33
#
44
# Portions Copyright 2007-2015, Anthony Tuininga. All rights reserved.
55
#
@@ -428,5 +428,17 @@ def test_2531_long_xml_as_string(self):
428428
actual_value, = self.cursor.fetchone()
429429
self.assertEqual(actual_value.strip(), xml_string)
430430

431+
def test_2532_fetch_null_values(self):
432+
"2532 - fetching null and not null values can use optimised path"
433+
sql = """
434+
select * from TestStrings
435+
where IntCol between :start_value and :end_value"""
436+
self.cursor.execute(sql, start_value=2, end_value=5)
437+
self.assertEqual(self.cursor.fetchall(), self.raw_data[1:5])
438+
self.cursor.execute(sql, start_value=5, end_value=8)
439+
self.assertEqual(self.cursor.fetchall(), self.raw_data[4:8])
440+
self.cursor.execute(sql, start_value=8, end_value=10)
441+
self.assertEqual(self.cursor.fetchall(), self.raw_data[7:10])
442+
431443
if __name__ == "__main__":
432444
test_env.run_test_cases()

0 commit comments

Comments
 (0)