Skip to content

Commit f24399e

Browse files
Added support for BFILE in thin mode.
1 parent c59a0cc commit f24399e

File tree

16 files changed

+232
-65
lines changed

16 files changed

+232
-65
lines changed

doc/src/api_manual/module.rst

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3016,10 +3016,6 @@ Also see the table :ref:`supporteddbtypes`.
30163016
Describes columns, attributes or array elements in a database that are of
30173017
type BFILE. It will compare equal to the DB API type :data:`BINARY`.
30183018

3019-
.. note::
3020-
3021-
DB_TYPE_BFILE database type is only supported in the python-oracledb
3022-
Thick mode. See :ref:`enablingthick`.
30233019

30243020
.. data:: DB_TYPE_BINARY_DOUBLE
30253021

doc/src/release_notes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Thin Mode Changes
1818
+++++++++++++++++
1919

2020
#) Added support for :ref:`two-phase commits <tpc>`.
21+
#) Added support for data of type :data:`~oracledb.DB_TYPE_BFILE`.
2122
#) When calling :meth:`ConnectionPool.acquire()` or
2223
:meth:`AsyncConnectionPool.acquire()`, the connection pool ``mode``
2324
:data:`oracledb.POOL_GETMODE_TIMEDWAIT` now always honors the
@@ -55,6 +56,10 @@ Common Changes
5556
#) Error ``DPY-2050: invalid flags for tpc_end()`` is now raised when invalid
5657
flags are passed to :meth:`Connection.tpc_end()`. Previously, ``TypeError``
5758
or ``DPI-1002: invalid OCI handle`` was raised instead.
59+
#) Error ``DPY-3025: operation is not supported on BFILE LOBs`` is now raised
60+
when operations are attempted on BFILE LOBs that are not permitted.
61+
Previously, ``ORA-22275: invalid LOB locator specified`` was raised
62+
instead.
5863
#) Error ``DPY-4005: timed out waiting for the connection pool to return a
5964
connection`` is now raised consistently when using get mode
6065
:data:`oracledb.POOL_GETMODE_TIMEDWAIT` and the timeout expires.

doc/src/user_guide/appendix_a.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ values.
454454
- :ref:`oracledb.LOB <lobobj>`, bytes, str
455455
* - BFILE
456456
- :data:`~oracledb.DB_TYPE_BFILE`
457-
- Not supported in python-oracledb Thin mode.
457+
- No relevant notes
458458
- Cannot be set
459459
* - JSON
460460
- :data:`~oracledb.DB_TYPE_JSON`

doc/src/user_guide/lob_data.rst

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ Using CLOB and BLOB Data
55
************************
66

77
Oracle Database uses :ref:`LOB objects <lobobj>` to store large data such as text, images,
8-
videos, and other multimedia formats. The maximum size of a LOB is limited to
8+
videos, and other multimedia formats. The maximum size of a LOB (large object) is limited to
99
the size of the tablespace storing it.
1010

11-
There are four types of LOB (large object):
11+
There are `four types of LOBs <https://www.oracle.com/pls/topic/lookup?ctx=
12+
dblatest&id=GUID-0A692C1B-1C95-4121-8F95-25BE465B87F6>`__:
1213

1314
* BLOB - Binary Large Object, used for storing binary data. python-oracledb uses
1415
the type :attr:`oracledb.DB_TYPE_BLOB`.
@@ -18,9 +19,12 @@ There are four types of LOB (large object):
1819
* NCLOB - National Character Large Object, used for string strings in the
1920
national character set format. python-oracledb uses the type
2021
:attr:`oracledb.DB_TYPE_NCLOB`.
21-
* BFILE - External Binary File, used for referencing a file stored on the
22-
host operating system outside of the database. python-oracledb uses the type
23-
:attr:`oracledb.DB_TYPE_BFILE`.
22+
* BFILE - External Binary File, used
23+
for referencing a file stored on the host operating system outside of
24+
the database. python-oracledb uses the type
25+
:attr:`oracledb.DB_TYPE_BFILE`. See `BFILEs <https://www.oracle.com/pls/
26+
topic/lookup?ctx=dblatest&id=GUID-D4642C92-F343-4700-9F1F-
27+
486F82249FB8>`__ for more information.
2428

2529
LOBs can be streamed to, and from, Oracle Database.
2630

src/oracledb/errors.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ def _raise_not_supported(feature: str) -> None:
284284
ERR_NAMED_TIMEZONE_NOT_SUPPORTED = 3022
285285
ERR_VECTOR_VERSION_NOT_SUPPORTED = 3023
286286
ERR_VECTOR_FORMAT_NOT_SUPPORTED = 3024
287+
ERR_OPERATION_NOT_SUPPORTED_ON_BFILE = 3025
287288

288289
# error numbers that result in DatabaseError
289290
ERR_TNS_ENTRY_NOT_FOUND = 4000
@@ -637,6 +638,9 @@ def _raise_not_supported(feature: str) -> None:
637638
ERR_NUMBER_WITH_EMPTY_EXPONENT: "invalid number: empty exponent",
638639
ERR_NUMBER_WITH_INVALID_EXPONENT: "invalid number: invalid exponent",
639640
ERR_OBJECT_IS_NOT_A_COLLECTION: "object {name} is not a collection",
641+
ERR_OPERATION_NOT_SUPPORTED_ON_BFILE: (
642+
"operation is not supported on BFILE LOBs"
643+
),
640644
ERR_ORACLE_NUMBER_NO_REPR: (
641645
"value cannot be represented as an Oracle number"
642646
),

src/oracledb/impl/base/connection.pyx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ cdef class BaseConnImpl:
9595
return value
9696
elif db_type_num in (DB_TYPE_NUM_CLOB,
9797
DB_TYPE_NUM_NCLOB,
98-
DB_TYPE_NUM_BLOB):
98+
DB_TYPE_NUM_BLOB,
99+
DB_TYPE_NUM_BFILE):
99100
if isinstance(value, (PY_TYPE_LOB, PY_TYPE_ASYNC_LOB)):
100101
lob_impl = value._impl
101102
if lob_impl.dbtype is not dbtype:
@@ -107,6 +108,7 @@ cdef class BaseConnImpl:
107108
expected_type_name=dbtype.name)
108109
return value
109110
elif self._allow_bind_str_to_lob \
111+
and db_type_num != DB_TYPE_NUM_BFILE \
110112
and isinstance(value, (bytes, str)):
111113
if db_type_num == DB_TYPE_NUM_BLOB:
112114
if isinstance(value, str):

src/oracledb/impl/base/types.pyx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ cdef class DbType:
110110

111111
# database types
112112
DB_TYPE_BFILE = DbType(DB_TYPE_NUM_BFILE, "DB_TYPE_BFILE", "BFILE",
113-
NATIVE_TYPE_NUM_LOB, 114)
113+
NATIVE_TYPE_NUM_LOB, 114, buffer_size_factor=4000)
114114
DB_TYPE_BINARY_DOUBLE = DbType(DB_TYPE_NUM_BINARY_DOUBLE,
115115
"DB_TYPE_BINARY_DOUBLE", "BINARY_DOUBLE",
116116
NATIVE_TYPE_NUM_DOUBLE, 101,

src/oracledb/impl/thick/utils.pyx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,8 @@ cdef int _convert_from_python(object value, DbType dbtype,
190190
dbvalue.asObject = obj_impl._handle
191191
elif oracle_type == DPI_ORACLE_TYPE_CLOB \
192192
or oracle_type == DPI_ORACLE_TYPE_BLOB \
193-
or oracle_type == DPI_ORACLE_TYPE_NCLOB:
193+
or oracle_type == DPI_ORACLE_TYPE_NCLOB \
194+
or oracle_type == DPI_ORACLE_TYPE_BFILE:
194195
if isinstance(value, PY_TYPE_LOB):
195196
lob_impl = value._impl
196197
if var_impl is not None:

src/oracledb/impl/thin/constants.pxi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,13 +528,18 @@ cdef enum:
528528
TNS_LOB_OP_CLOSE = 0x10000
529529
TNS_LOB_OP_IS_OPEN = 0x11000
530530
TNS_LOB_OP_ARRAY = 0x80000
531+
TNS_LOB_OP_FILE_EXISTS = 0x0800
532+
TNS_LOB_OP_FILE_OPEN = 0x0100
533+
TNS_LOB_OP_FILE_CLOSE = 0x0200
534+
TNS_LOB_OP_FILE_ISOPEN = 0x0400
531535

532536
# LOB locator constants
533537
cdef enum:
534538
TNS_LOB_LOC_OFFSET_FLAG_1 = 4
535539
TNS_LOB_LOC_OFFSET_FLAG_3 = 6
536540
TNS_LOB_LOC_OFFSET_FLAG_4 = 7
537541
TNS_LOB_QLOCATOR_VERSION = 4
542+
TNS_LOB_LOC_FIXED_OFFSET = 16
538543

539544
# LOB locator flags (byte 1)
540545
cdef enum:
@@ -554,6 +559,7 @@ cdef enum:
554559
# other LOB constants
555560
cdef enum:
556561
TNS_LOB_OPEN_READ_WRITE = 2
562+
TNS_LOB_OPEN_READ_ONLY = 11
557563
TNS_LOB_PREFETCH_FLAG = 0x2000000
558564

559565
# end-to-end metrics

src/oracledb/impl/thin/dbobject.pyx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,9 @@ cdef class ThinDbObjectImpl(BaseDbObjectImpl):
385385
TNS_DATA_TYPE_TIMESTAMP_LTZ,
386386
TNS_DATA_TYPE_TIMESTAMP_TZ):
387387
return buf.read_date()
388-
elif ora_type_num in (TNS_DATA_TYPE_CLOB, TNS_DATA_TYPE_BLOB):
388+
elif ora_type_num in (TNS_DATA_TYPE_CLOB,
389+
TNS_DATA_TYPE_BLOB,
390+
TNS_DATA_TYPE_BFILE):
389391
conn_impl = self.type._conn_impl
390392
locator = buf.read_bytes()
391393
if locator is None:

0 commit comments

Comments
 (0)