Skip to content

Thin client in/out object does not persist with executemany #599

Description

@Aetylus
  1. What versions are you using?
19.28.0.0.0
platform.platform: Windows-10-10.0.22631-SP0
sys.maxsize > 2**32: True
platform.python_version: 3.11.15
oracledb.__version__: 4.0.2
  1. Is it an error or a hang or a crash?

It's neither a hang or a crash, but a behavior issue.

  1. What error(s) or behavior you are seeing?

Given the following package body/spec:

create or replace package array_test is
   type t_log_message is record (
      status varchar2(30),
      id varchar2(9),
      message varchar2(32767)
   );
   type t_log_messages is table of t_log_message index by binary_integer;

   procedure p_add_log_message(
      i_status varchar2,
      i_id varchar2,
      i_message varchar2,
      io_log_messages in out nocopy t_log_messages
   );
end;
/

create or replace package body array_test is
   procedure p_add_log_message(
      i_status varchar2,
      i_id varchar2,
      i_message varchar2,
      io_log_messages in out nocopy t_log_messages
   ) is
      l_index binary_integer := io_log_messages.last();
   begin
      if l_index is null then
         l_index := 0;
      else
         l_index := l_index + 1;
      end if;
      io_log_messages(l_index).status := i_status;
      io_log_messages(l_index).id := i_id;
      io_log_messages(l_index).message := i_message;
   end;
end;
/

The output of the following Python code is not as expected:

from getpass import getpass

import oracledb as db

size = 4
connection = db.connect(user='tom', password=getpass(), dsn='ORCL')
cursor = connection.cursor()

LogMessages = connection.gettype('ARRAY_TEST.T_LOG_MESSAGES')
log_messages = LogMessages.newobject()

data = []
for i in range(0, size):
    data.append(['INFO', str(i + 1), 'Hello world', log_messages])

cursor = connection.cursor()

cursor.executemany('''\
begin
    array_test.p_add_log_message(
        i_status => :1,
        i_id => :2,
        i_message => :3,
        io_log_messages => :4
    );
    array_test.p_add_log_message(
        i_status => :1,
        i_id => :2,
        i_message => :3 || ' 2',
        io_log_messages => :4
    );
end;
''', data)

for key, value in log_messages.asdict().items():
    print({
        key: {
            'status': value.STATUS,
            'id': value.ID,
            'message': value.MESSAGE,
        }}
    )

It seems the T_LOG_MESSAGES object created is passed in and out the first time the PL/SQL block is called, but does not seem to persist updates in any subsequent calls. This results in only the first and last calls affecting the T_LOG_MESSAGES object, as seen in the actual output:

{0: {'status': 'INFO', 'id': '1', 'message': 'Hello world'}}
{1: {'status': 'INFO', 'id': '1', 'message': 'Hello world 2'}}
{2: {'status': 'INFO', 'id': '4', 'message': 'Hello world'}}
{3: {'status': 'INFO', 'id': '4', 'message': 'Hello world 2'}}

I would expect the output to be:

{0: {'status': 'INFO', 'id': '1', 'message': 'Hello world'}}
{1: {'status': 'INFO', 'id': '1', 'message': 'Hello world 2'}}
{2: {'status': 'INFO', 'id': '2', 'message': 'Hello world'}}
{3: {'status': 'INFO', 'id': '2', 'message': 'Hello world 2'}}
{4: {'status': 'INFO', 'id': '3', 'message': 'Hello world'}}
{5: {'status': 'INFO', 'id': '3', 'message': 'Hello world 2'}}
{6: {'status': 'INFO', 'id': '4', 'message': 'Hello world'}}
{7: {'status': 'INFO', 'id': '4', 'message': 'Hello world 2'}}
  1. Does your application call init_oracle_client()?

No. It behaves as expected in thick mode, if oracledb.init_oracle_client() is called before a connection is made.

  1. Include a runnable Python script that shows the problem.

See question 3.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions