INVISIBLE column with custom %ROWTYPE type: unexpected end of data · Issue #325 · oracle/python-oracledb (original) (raw)

Include a runnable Python script that shows the problem.

CREATE TABLE foo_tmp (
    "id" NUMBER,
    "code" VARCHAR2(255 BYTE),
    "thingy" VARCHAR2(1 BYTE) INVISIBLE
);

INSERT INTO foo_tmp (id, code, thingy) values (1, 'foo', 'f');

create or replace PACKAGE foo_test AS 

    TYPE foo_tmp_array IS TABLE OF foo_tmp%ROWTYPE
    INDEX BY BINARY_INTEGER;

    PROCEDURE prGetRecords (
        out_rec OUT foo_test.foo_tmp_array
    );

END foo_test;

create or replace PACKAGE BODY foo_test IS 

    PROCEDURE prGetRecords (
        out_rec OUT foo_test.foo_tmp_array
    ) 
    IS
        CURSOR c_foo_tmp IS
        SELECT *
        FROM foo_tmp;
    BEGIN
        OPEN  c_foo_tmp;
        FETCH c_foo_tmp BULK COLLECT INTO out_rec;
        CLOSE c_foo_tmp;
    END prGetRecords;

END foo_test;

import asyncio

from oracledb import create_pool_async, makedsn

async def list_data(pool): async with pool.acquire() as conn: data_coll_type = await conn.gettype("FOO_TEST.FOO_TMP_ARRAY") data_coll = data_coll_type.newobject()

    keyword_parameters = {
        "out_rec": data_coll,
    }

    proc_name = "foo_test.prGetRecords"

    await conn.callproc(
        name=proc_name,
        keyword_parameters=keyword_parameters,
    )

    rows = []

    for record in data_coll.aslist():
        row = {}

        for type_attr in data_coll.type.element_type.attributes:
            attr_name = type_attr.name
            attr_value = getattr(record, type_attr.name, None)
            row[f"{attr_name}"] = attr_value

        rows.append(row)

    return rows

async def main(): dsn = makedsn( host="mydbhost", port=1521, sid="myservicename", )

pool = create_pool_async(
    user="myuser,
    password="mypass",
    dsn=dsn,
)
rows = await list_data(pool)
print(rows)

asyncio.run(main())

[{'ID': 1.0, 'CODE': 'foo'}]
Traceback (most recent call last):
  File "/pathto/get_foo_records_test.py", line 54, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.11/asyncio/runners.py", line 188, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/runners.py", line 120, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/base_events.py", line 650, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/pathto/get_foo_records_test.py", line 50, in main
    rows = await list_data(pool)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/pathto/get_foo_records_test.py", line 30, in list_data
    attr_value = getattr(record, type_attr.name, None)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/pathto/lib/python3.11/site-packages/oracledb/dbobject.py", line 47, in __getattr__
    return self._impl.get_attr_value(attr_impl)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "src/oracledb/impl/thin/dbobject.pyx", line 452, in oracledb.thin_impl.ThinDbObjectImpl.get_attr_value
  File "src/oracledb/impl/thin/dbobject.pyx", line 162, in oracledb.thin_impl.ThinDbObjectImpl._ensure_unpacked
  File "src/oracledb/impl/thin/dbobject.pyx", line 278, in oracledb.thin_impl.ThinDbObjectImpl._unpack_data
  File "src/oracledb/impl/thin/dbobject.pyx", line 316, in oracledb.thin_impl.ThinDbObjectImpl._unpack_data_from_buf
  File "src/oracledb/impl/thin/dbobject.pyx", line 346, in oracledb.thin_impl.ThinDbObjectImpl._unpack_value
  File "src/oracledb/impl/base/buffer.pyx", line 720, in oracledb.base_impl.Buffer.read_str
  File "src/oracledb/impl/base/buffer.pyx", line 634, in oracledb.base_impl.Buffer.read_raw_bytes_and_length
  File "src/oracledb/impl/base/buffer.pyx", line 730, in oracledb.base_impl.Buffer.read_ub1
  File "src/oracledb/impl/base/buffer.pyx", line 152, in oracledb.base_impl.Buffer._get_raw
  File "/pathto/lib/python3.11/site-packages/oracledb/errors.py", line 181, in _raise_err
    raise error.exc_type(error) from cause
oracledb.exceptions.InternalError: DPY-5006: unexpected end of data: want 1 bytes but only 0 bytes are available