cx_Oracle и пользовательские типы - PullRequest
2 голосов
/ 09 июня 2009

Кто-нибудь знает более простой способ работы с пользовательскими типами в Oracle с помощью cx_Oracle?

Например, если у меня есть эти два типа:

CREATE type my_type as object(
component   varchar2(30)
,key    varchar2(100)
,value   varchar2(4000))
/
CREATE type my_type_tab as table of my_type
/

А затем процедура в пакете my_package выглядит следующим образом:

PROCEDURE my_procedure (param  in  my_type_tab);

Чтобы выполнить процедуру в PL / SQL, я могу сделать что-то вроде этого:

declare
  l_parms   my_type_tab;
  l_cnt     pls_integer;
begin
  l_parms := my_type_tab();
  l_parms.extend;
  l_cnt := l_parms.count;
  l_parms(l_cnt) := my_type('foo','bar','hello');
  l_parms.extend;
  l_cnt := l_parms.count;
  l_parms(l_cnt) := my_type('faz','baz','world');
  my_package.my_procedure(l_parms);
end;

Однако мне было интересно, как я могу сделать это в Python, как этот код:

import cx_Oracle
orcl = cx_Oracle.connect('foo:bar@mydb.com:5555/blah' + instance)
curs = orcl.cursor()
params = ???
curs.execute('begin my_package.my_procedure(:params)', params=params)

Если параметр был строкой, я могу сделать это, как указано выше, но, поскольку это пользовательский тип, я не знаю, как его вызвать, не прибегая к чистому коду PL / SQL.

Edit: Извините, я должен был сказать, что я искал способы сделать больше в коде Python вместо PL / SQL.

Ответы [ 3 ]

3 голосов
/ 10 июня 2009

Хотя cx_Oracle может выбирать пользовательские типы, насколько мне известно, он не поддерживает передачу пользовательских типов в качестве переменных связывания. Так, например, будет работать следующее:

cursor.execute("select my_type('foo', 'bar', 'hello') from dual")
val, = cursor.fetchone()
print val.COMPONENT, val.KEY, val.VALUE

Однако вы не можете создать объект Python, передать его в качестве входного аргумента, а затем cx_Oracle "перевести" объект Python в тип Oracle. Поэтому я бы сказал, что вам нужно будет создать входной аргумент в блоке PL / SQL.

Вы можете передать в списки Python, поэтому должно работать следующее:

components=["foo", "faz"]
values=["bar", "baz"]
keys=["hello", "world"]
cursor.execute("""
declare
  type udt_StringList is table of varchar2(4000) index by binary_integer;
  l_components udt_StringList := :p_components;
  l_keys udt_StringList := :p_keys;
  l_values udt_StringList := :p_values;
  l_parms my_type_tab;
begin
  l_parms.extend(l_components.count);
  for i in 1..l_components.count loop
    l_parms(i) := my_type(l_components(i), l_keys(i), l_values(i));
  end loop;

  my_package.my_procedure(l_parms);
end;""", p_components=components, p_values=values, p_keys=keys)
0 голосов
/ 09 июня 2009

Я не совсем уверен, что вы подразумеваете под жестко запрограммированным, но вы можете создать динамический массив следующим образом:

SQL> desc my_procedure
Parameter Type        Mode Default? 
--------- ----------- ---- -------- 
P_IN      MY_TYPE_TAB IN   

SQL> declare
  2     l_tab my_type_tab;
  3  begin
  4     select my_type(owner, table_name, column_name)
  5       bulk collect into l_tab
  6       from all_tab_columns
  7      where rownum <= 10;
  8     my_procedure (l_tab);
  9  end;
 10  /

PL/SQL procedure successfully completed

Это было протестировано с Oracle 11.1.0.6.

0 голосов
/ 09 июня 2009

Вы пытаетесь заполнить таблицу объектов более эффективно?

Если вы можете сделать SELECT, взгляните на предложение BULK COLLECT INTO

...