Skip to content

Commit 5dd313f

Browse files
Fixed bug when binding a temporary LOB IN/OUT to a PL/SQL procedure
(#468).
1 parent 49d9f3b commit 5dd313f

File tree

5 files changed

+60
-8
lines changed

5 files changed

+60
-8
lines changed

doc/src/release_notes.rst

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Thin Mode Changes
2727
(`issue 456 <https://github.com/oracle/python-oracledb/issues/456>`__).
2828
#) Fixed wildcard matching of domains in Subject Alternative Names
2929
(`issue 462 <https://github.com/oracle/python-oracledb/issues/462>`__).
30+
#) Fixed bug when binding a temporary LOB IN/OUT to a PL/SQL procedure
31+
(`issue 468 <https://github.com/oracle/python-oracledb/issues/468>`__).
3032

3133
Thick Mode Changes
3234
++++++++++++++++++

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -893,8 +893,11 @@ cdef class MessageWithData(Message):
893893
elif ora_type_num in (ORA_TYPE_NUM_CLOB,
894894
ORA_TYPE_NUM_BLOB,
895895
ORA_TYPE_NUM_BFILE):
896+
if not self.in_fetch:
897+
column_value = var_impl._values[pos]
896898
column_value = buf.read_lob_with_length(self.conn_impl,
897-
metadata.dbtype)
899+
metadata.dbtype,
900+
column_value)
898901
elif ora_type_num == ORA_TYPE_NUM_JSON:
899902
column_value = buf.read_oson()
900903
elif ora_type_num == ORA_TYPE_NUM_VECTOR:

src/oracledb/impl/thin/packet.pyx

+13-6
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ cdef class ReadBuffer(Buffer):
475475
return decoder.decode(data)
476476

477477
cdef object read_lob_with_length(self, BaseThinConnImpl conn_impl,
478-
DbType dbtype):
478+
DbType dbtype, object lob):
479479
"""
480480
Read a LOB locator from the buffer and return a LOB object containing
481481
it.
@@ -484,6 +484,7 @@ cdef class ReadBuffer(Buffer):
484484
uint32_t chunk_size, num_bytes
485485
BaseThinLobImpl lob_impl
486486
uint64_t size
487+
bytes locator
487488
type cls
488489
self.read_ub4(&num_bytes)
489490
if num_bytes > 0:
@@ -492,15 +493,21 @@ cdef class ReadBuffer(Buffer):
492493
else:
493494
self.read_ub8(&size)
494495
self.read_ub4(&chunk_size)
495-
lob_impl = conn_impl._create_lob_impl(dbtype, self.read_bytes())
496+
locator = self.read_bytes()
497+
if lob is None:
498+
lob_impl = conn_impl._create_lob_impl(dbtype, locator)
499+
cls = PY_TYPE_ASYNC_LOB \
500+
if conn_impl._protocol._transport._is_async \
501+
else PY_TYPE_LOB
502+
lob = cls._from_impl(lob_impl)
503+
else:
504+
lob_impl = lob._impl
505+
lob_impl._locator = locator
496506
lob_impl._size = size
497507
lob_impl._chunk_size = chunk_size
498508
lob_impl._has_metadata = \
499509
dbtype._ora_type_num != ORA_TYPE_NUM_BFILE
500-
cls = PY_TYPE_ASYNC_LOB \
501-
if conn_impl._protocol._transport._is_async \
502-
else PY_TYPE_LOB
503-
return cls._from_impl(lob_impl)
510+
return lob
504511

505512
cdef const char_type* read_raw_bytes(self, ssize_t num_bytes) except NULL:
506513
"""

tests/sql/create_schema.sql

+17
Original file line numberDiff line numberDiff line change
@@ -1479,6 +1479,12 @@ create or replace package &main_user..pkg_TestLOBs as
14791479
a_Size out number
14801480
);
14811481

1482+
procedure TestInOut (
1483+
a_CLOB in out clob,
1484+
a_SearchValue varchar2,
1485+
a_ReplaceValue varchar2
1486+
);
1487+
14821488
end;
14831489
/
14841490

@@ -1500,5 +1506,16 @@ create or replace package body &main_user..pkg_TestLOBs as
15001506
a_Size := dbms_lob.getlength(a_CLOB);
15011507
end;
15021508

1509+
procedure TestInOut (
1510+
a_CLOB in out clob,
1511+
a_SearchValue varchar2,
1512+
a_ReplaceValue varchar2
1513+
) is
1514+
begin
1515+
if a_SearchValue is not null then
1516+
a_CLOB := replace(a_CLOB, a_SearchValue, a_ReplaceValue);
1517+
end if;
1518+
end;
1519+
15031520
end;
15041521
/

tests/test_1900_lob_var.py

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -----------------------------------------------------------------------------
2-
# Copyright (c) 2020, 2024, Oracle and/or its affiliates.
2+
# Copyright (c) 2020, 2025, Oracle and/or its affiliates.
33
#
44
# This software is dual-licensed to you under the Universal Permissive License
55
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
@@ -614,6 +614,29 @@ def test_1938(self):
614614
var.setvalue(0, lob)
615615
self.assertIs(var.getvalue(), lob)
616616

617+
def test_1939(self):
618+
"1939 - temporary LOB in/out without modification"
619+
value = "test - 1939"
620+
var = self.cursor.var(oracledb.DB_TYPE_CLOB)
621+
var.setvalue(0, value)
622+
self.assertEqual(var.getvalue().read(), value)
623+
self.cursor.callproc("pkg_TestLOBs.TestInOut", [var, None, None])
624+
self.assertEqual(var.getvalue().read(), value)
625+
626+
def test_1940(self):
627+
"1940 - temporary LOB in/out with modification"
628+
search_value = "test"
629+
replace_value = "replaced"
630+
initial_value = f"{search_value} - 1939"
631+
final_value = f"{replace_value} - 1939"
632+
var = self.cursor.var(oracledb.DB_TYPE_CLOB)
633+
var.setvalue(0, initial_value)
634+
self.assertEqual(var.getvalue().read(), initial_value)
635+
self.cursor.callproc(
636+
"pkg_TestLOBs.TestInOut", [var, search_value, replace_value]
637+
)
638+
self.assertEqual(var.getvalue().read(), final_value)
639+
617640

618641
if __name__ == "__main__":
619642
test_env.run_test_cases()

0 commit comments

Comments
 (0)