python-oracledb icon indicating copy to clipboard operation
python-oracledb copied to clipboard

`LOB.read(0)` gives unhelpful error message in thin mode

Open doerwalter opened this issue 3 years ago • 3 comments

The following Python script:

import oracledb
db = oracledb.connect("user/pwd@db")
c = db.cursor()
c.execute("select to_clob('foo') from dual").fetchone()[0].read(0)

gives the following output:

Traceback (most recent call last):
  File "/Users/walter/oracledb_bug.py", line 4, in <module>
    c.execute("select to_clob('foo') from dual").fetchone()[0].read(0)
  File "/Users/walter/pyvenvs/default/lib/python3.10/site-packages/oracledb/lob.py", line 116, in read
    return self._impl.read(offset, amount)
  File "src/oracledb/impl/thin/lob.pyx", line 140, in oracledb.thin_impl.ThinLobImpl.read
  File "src/oracledb/impl/thin/protocol.pyx", line 294, in oracledb.thin_impl.Protocol._process_single_message
  File "src/oracledb/impl/thin/protocol.pyx", line 295, in oracledb.thin_impl.Protocol._process_single_message
  File "src/oracledb/impl/thin/protocol.pyx", line 288, in oracledb.thin_impl.Protocol._process_message
oracledb.exceptions.DatabaseError: ORA-03137: malformed TTC packet from client rejected: [kpolob:offset 0] [0] [0] [2] [] [] [] []

In thick mode I get:

Traceback (most recent call last):
  File "/Users/walter/oracledb_bug.py", line 5, in <module>
    c.execute("select to_clob('foo') from dual").fetchone()[0].read(0)
  File "/Users/walter/pyvenvs/default/lib/python3.10/site-packages/oracledb/lob.py", line 116, in read
    return self._impl.read(offset, amount)
  File "src/oracledb/impl/thick/lob.pyx", line 168, in oracledb.thick_impl.ThickLobImpl.read
  File "src/oracledb/impl/thick/utils.pyx", line 409, in oracledb.thick_impl._raise_from_odpi
  File "src/oracledb/impl/thick/utils.pyx", line 399, in oracledb.thick_impl._raise_from_info
oracledb.exceptions.DatabaseError: ORA-24801: Unzulässiger Parameterwert in OCI-LOB-Funktion

which at least gives a hint at what the problem is.

import sys, platform, oracledb

print(f"{platform.platform()=}")
print(f"{sys.maxsize > 2**32=}")
print(f"{platform.python_version()=}")
print(f"{oracledb.__version__=}")

prints

platform.platform()='macOS-12.4-x86_64-i386-64bit'
sys.maxsize > 2**32=True
platform.python_version()='3.10.4'
oracledb.__version__='1.0.0'

The database is an Oracle XE.

select value from nls_database_parameters where parameter='NLS_RDBMS_VERSION';

returns 21.0.0.0.0.

doerwalter avatar Jun 08 '22 16:06 doerwalter

If we adjust the code so that it returns an empty string instead of raising an exception, would you consider that preferable? I don't find the thick driver error to be all that helpful either! The other option is to create a more meaningful error -- but it seems unnecessary. Thoughts?

anthony-tuininga avatar Jun 08 '22 23:06 anthony-tuininga

The most helpful would probably be:

ValueError: offset must be > 0

BTW, passing a negative values currently results in:

OverflowError: can't convert negative value to uint64_t

so 0 is the only values with this behavour.

The most elegant API would be support for slices for LOB objects, since slices clip out of bound values automatically.

So instead of lob.read(1, 100) I could do lob[:100] and instead of lob.read(lob.getsize()-100) I could do lob[-100:] (I'm assuming that the default value for the amount parameter is "until the rest of the LOB".

doerwalter avatar Jun 09 '22 08:06 doerwalter

I've added error DPY-2030 to address this situation for both thin and thick. If you want to create a new enhancement request for supporting slices with LOBs, please go ahead; otherwise, I'll close this when 1.1 is released.

anthony-tuininga avatar Jul 20 '22 00:07 anthony-tuininga

This enhancement has been implemented in python-oracledb 1.1.0 which was just released.

anthony-tuininga avatar Sep 14 '22 16:09 anthony-tuininga