2017-05-05 28 views
0

これからguide私は単純なデータ型(例えばcx_Oracle.NUMBER)の連想配列をPL/SQLプロシージャに渡すことができます。cx_Oracle複合/複合配列をPLSQLプロシージャに渡す方法は?

CREATE OR REPLACE PACKAGE test 
IS 
    TYPE t_ids IS TABLE OF NUMBER INDEX BY PLS_INTEGER; 
    PROCEDURE foo(p_ids_i IN t_ids); 
END; 
/

それを呼び出すために:

ids = cursor.arrayvar(cx_Oracle.NUMBER, [1,2,3]) 
cursor.callproc('test.foo', [ids]) 

をしかし、私の代わりに、複雑な型を取る代わりに、次の手順fooを呼び出したいです。


# Raises NotSupportedError: Variable_TypeByPythonType(): unhandled data type 
foos = cursor.arrayvar((cx_Oracle.NUMBER, cx_Oracle.STRING), [(1, 'foo'), (2, 'bar')]) 

# Raises NotSupportedError: Variable_MakeArray(): type does not support arrays 
foos = cur.arrayvar(cx_Oracle.OBJECT, [(1, 'foo'), (2, 'bar')]) 
が失敗している:あなたは、パッケージの外型を作成することができように

# Raises DatabaseError: ORA-04043: object TEST.R_FOO does not exist 
record_type = conn.gettype('TEST.R_FOO') 

に見えます

CREATE OR REPLACE PACKAGE test 
IS 
    TYPE r_foo IS RECORD (id NUMBER, name VARCHAR2(10)); 
    TYPE t_complex IS TABLE OF r_foo INDEX BY PLS_INTEGER; 
    PROCEDURE foo(p_ids_i IN t_complex); 
END; 
/

は、私は次のようにいろいろなことを試してみましたそれを参照してください。

CREATE TYPE t_foo IS TABLE OF NUMBER; -- Not an Associative Array 

それを参照するには、次の

t = conn.gettype('T_FOO') 

しかし、あなたは、パッケージの外側に連想配列のレコードを作成することはできません。 RECORDをObjectに置き換えることはできますが、cx_Oracleが渡すことができる唯一のコレクションタイプであるAssociative Arrayを置き換えるものは何も考えられません。


全コード:

PL/SQL:

 

-- returns 12.1.0.2.0 
SELECT VERSION FROM v$instance; 

CREATE OR REPLACE PACKAGE test 
IS 
    TYPE r_foo IS RECORD (id NUMBER, name VARCHAR2(10)); 
    TYPE t_complex IS TABLE OF r_foo INDEX BY PLS_INTEGER; 
    PROCEDURE foo(p_ids_i IN t_complex); 
END; 
/

CREATE OR REPLACE PACKAGE BODY test 
IS 
    PROCEDURE foo(p_ids_i IN t_complex) 
    IS 
    BEGIN 
     FOR i IN p_ids_i.FIRST .. p_ids_i.LAST LOOP 
      DBMS_OUTPUT.PUT_LINE(p_ids_i(i).id || ' ' || p_ids_i(i).name); 
     END LOOP; 
    END; 
END; 
/

-- The following works as expected. 
DECLARE 
    l_complex test.t_complex; 
BEGIN 
    l_complex(1).id := 1; 
    l_complex(1).name := 'Matthew'; 

    l_complex(2).id := 2; 
    l_complex(2).name := 'Moisen'; 

    test.foo(l_complex); 
END; 

Pythonの:$ ORACLE_HOMEと私12cはクライアントに設定などでcx_Oracleを再インストールした後

 
import cx_Oracle 

print cx_Oracle.version # 5.3 
print cx_Oracle.clientversion() # (12, 1, 0, 2, 0) 

conn = cx_Oracle.connect('username/[email protected]') 
cur = conn.cursor() 

result = cur.execute("SELECT * FROM user_source WHERE name = 'TEST' and type = 'PACKAGE'") 

# This prints the package spec successfully 
for row in result: 
    print row 

# Raises DatabaseError: ORA-04043: object TEST.R_FOO does not exist 
conn.gettype('TEST.R_FOO') 

# Raises DatabaseError: ORA-04043: object TEST.T_COMPLEX does not exist 
conn.gettype('TEST.T_COMPLEX') 

# This raises the appropriate exception saying I called the procedure 
# incorrectly, demonstrating that I have access to it. 
cur.callproc('TEST.FOO', []) 

私はもう少し進んでいくことができましたが、まだappend操作でエラーが発生しました。

 
import cx_Oracle 

conn = cx_Oracle.connect('username/[email protected]') 

# This no longer raises an error 
recordTypeObj = conn.gettype('TEST.R_FOO') 
tableTypeObj = conn.gettype('TEST.T_COMPLEX') 
rec = recordTypeObj.newobject() 
tab = tableTypeObj.newobject() 

# This works fine 
rec.ID = 1 
rec.NAME = "foo" 

# This fails with 
# cx_Oracle.NotSupportedError: Object_ConvertFromPython(): unhandled data type 250 
tab.append(rec) 

答えて

1

これは、cx_Oracle 5.3以降でサポートされています。このようなことをサポートする "オブジェクト"構文を使用する必要があります。 [5.3のリリースノート]で

import cx_Oracle 

conn = cx_Oracle.Connection("cx_Oracle/[email protected]/orcl") 
recordTypeObj = conn.gettype("TEST.R_FOO") 
tableTypeObj = conn.gettype("TEST.T_COMPLEX") 

tab = tableTypeObj.newobject() 

rec = recordTypeObj.newobject() 
rec.ID = 1 
rec.NAME = "foo" 
tab.append(rec) 

rec = recordTypeObj.newobject() 
rec.ID = 2 
rec.NAME = "bar" 
tab.append(rec) 

cursor = conn.cursor() 
cursor.callproc("test.foo", [tab]) 
+0

(https://cx-oracle.readthedocs.io/en/latest/releasenotes.html)それが 'PL/SQLレコードの作成、変更および結合のためのサポートを追加すると言いますコレクション(Oracle 12.1で利用可能)」を参照してください。これがあなたが参照しているノートであるかどうか、これが11gで動作しないことを意味するかどうかは分かりますか? –

+0

はい。これは、Oracle 11gではサポートされていません。 –

+0

'conn.gettype( 'TEST.R_FOO')'が 'DatabaseError:ORA-04043:object test.r_foo does not exist'を投げています。 cx_Oracleはパッケージ内に型が見つからないようです。一方、それはパッケージ外の型を見つけることができます。更新された質問を見てもらえますか? –

関連する問題