この記事はJPOUG Advent Calendar 2017の3日目です。 さらに同日にもう1記事あげていますのでよろしければご覧ください。
次の仕事ではOracleとかかわらなくなりますが、思い入れがありますのでエントリ書いておきます。 PythonからOracle DatabaseにSQLを発行するまでの流れを簡単にまとめていきます。
PythonからOracle Databaseを利用するには
PythonからOracle DatabaseにSQLを発行したりするには、cx_Oracleを利用します。
cx_OracleはPythonのDB API2.0を実装するモジュールで、他のRDBMSに対するPython用モジュールとほぼ同じメソッドで利用できます。また、それらに加えてLOBやPL/SQLのカーソル等、Oracle独自の機能への対応も行われています。
今回は、cx_Oracleの導入から簡単なSELCTの実行までをまとめます。
検証環境について
本記事は以下の環境で作成しています。
接続先
- OS: Oracle Linux 6.9
- Oracle製品: Oracle Database 11.2.0.4
接続元
- OS: Mac OS X 10.12.6
- Software: Python 3.6
- Driver: cx_Oracle 6.0.3
cx_Oracleのインストール
cx_Oracle自体はpip install cx_oracle
で簡単に導入できます。
(ora) denzownoMacBook-Pro:tmp denzow$ conda install cx_oracle Fetching package metadata ........... Solving package specifications: . Package plan for installation in environment /Users/denzow/miniconda3/envs/ora: The following NEW packages will be INSTALLED: cx_oracle: 6.0.3-py36h6553998_0 Proceed ([y]/n)? y cx_oracle-6.0. 100% |############################| Time: 0:00:00 165.91 kB/s
しかし、そのまま利用しようとすると以下のようなエラーが発生します。
>>> import cx_Oracle >>> cx_Oracle.clientversion() Traceback (most recent call last): File "<stdin>", line 1, in <module> cx_Oracle.DatabaseError: DPI-1047: 64-bit Oracle Client library cannot be loaded: "dlopen(libclntsh.dylib, 1): image not found". See https://oracle.github.io/odpi/doc/installation.html#macos for help
エラー自体はlibclntsh.dylib
というライブラリが見つからなかったことを示しています。
これは、11.2までのODP.NETや12.1以降のの非管理対象のODP.NETと同じく、cx_OracleがOCI(正確にはODPI-C)のPythonバインディングであるためです。実際にOracleに接続する部分にはOCIを利用しているため、クライアント側には対応するライブラリが導入されている必要があります。
Orace ClientをOUIで入れても良いですが、instant Clientで十分ですのでそちらを利用する方が良いかと思います。各プラットフォームごとの手順は以下のドキュメントにまとめられています。
Macの場合はこちらよりinstantclient-basic-macos.x64-VERSIONのzipファイルを入手します。
今回は接続先にあわせてinstantclient-basic-macos.x64-11.2.0.4.0.zip
をダウンロードします。zipを展開すると以下のようなファイルが含まれています。
(ora) denzownoMacBook-Pro:~ denzow$ ls -l Downloads/instantclient_11_2/ total 380640 -rw-rw-rw-@ 1 denzow staff 484 4 11 2014 BASIC_README -rwxrwxrwx@ 1 denzow staff 14348 4 11 2014 adrci -rwxrwxrwx@ 1 denzow staff 40768 4 11 2014 genezi -r-xr-xr-x@ 1 denzow staff 66167420 2 7 2014 libclntsh.dylib.11.1 ★ -r-xr-xr-x@ 1 denzow staff 2817872 1 30 2014 libnnz11.dylib ★ -r-xr-xr-x@ 1 denzow staff 1897664 2 7 2014 libocci.dylib.11.1 -rwxrwxrwx@ 1 denzow staff 118707148 4 11 2014 libociei.dylib ★ -r-xr-xr-x@ 1 denzow staff 159004 1 7 2014 libocijdbc11.dylib -r--r--r--@ 1 denzow staff 2091135 1 29 2014 ojdbc5.jar -r--r--r--@ 1 denzow staff 2739616 1 29 2014 ojdbc6.jar -rwxrwxrwx@ 1 denzow staff 162380 4 11 2014 uidrvci -r--r--r--@ 1 denzow staff 66779 1 8 2014 xstreams.jar
このうち★をつけたライブラリを$HOME/lib
配下にコピーします。該当ディレクトリが存在しない場合は事前に作成しておきます。
mkdir $HOME/lib cp <any>/instantclient_11_2/{libclntsh.dylib.11.1,libnnz11.dylib,libociei.dylib} ~/lib/
Mac OSの場合、ライブラリの捜索パスのデフォルトは$HOME/lib;/usr/local/lib;/usr/lib
となっているため、$HOME/lib
にコピーすることで利用可能になるわけです。捜索パスについての詳細はこちらにまとまっています。
なお、他のプラットフォームの場合はそれぞれのOSに対応するinstantclientを用意します。その上で、Linux環境の場合はinstantclient_11_2
までのディレクトリをLD_LIBRARY_PATH
に追加することで利用可能になります。また、Windowsでは同ディレクトリをPATH環境変数に追加することで利用可能になります。
これで準備が整ったはずですので、接続に移っていきます。
cx_Oracleでの接続
まずは先程エラーになったcx_Oracle.clientversion()
を実行してみます。
>>> import cx_Oracle >>> cx_Oracle.clientversion() (11, 2, 0, 4, 0)
今度は正常に結果が帰ってきました。この値はcx_Oracleから呼び出されているOracleClientのライブラリのバージョンを示しています。
では、続いて接続してみます。なお、DB側のリスナーは以下の状態です。
[v1124@yamax admin]$ lsnrctl status LSNRCTL for Linux: Version 11.2.0.4.0 - Production on 01-12月-2017 02:05:20 Copyright (c) 1991, 2013, Oracle. All rights reserved. (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.56.55)(PORT=11204)))に接続中 リスナーのステータス ------------------------ 別名 LISTENER バージョン TNSLSNR for Linux: Version 11.2.0.4.0 - Production 開始日 01-12月-2017 01:25:16 稼働時間 0 日 0 時間 40 分 3 秒 トレース・レベル off セキュリティ ON: Local OS Authentication SNMP OFF パラメータ・ファイル /home/v1124/app/v1124/product/11.2.0/dbhome_1/network/admin/listener.ora ログ・ファイル /home/v1124/app/v1124/diag/tnslsnr/yamax/listener/alert/log.xml リスニング・エンドポイントのサマリー... (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.56.55)(PORT=11204))) (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC11204))) サービスのサマリー... サービス"v1124.world"には、1件のインスタンスがあります。 インスタンス"v1124"、状態READYには、このサービスに対する1件のハンドラがあります... サービス"v1124XDB.world"には、1件のインスタンスがあります。 インスタンス"v1124"、状態READYには、このサービスに対する1件のハンドラがあります... コマンドは正常に終了しました。
(HOST=192.168.56.55)(PORT=11204)
でv1124.wroldというサービス名で起動しています。こちらに接続していきます。なお、ユーザとパスワードはscott/tiger
を用意してあります。
>>> cx_Oracle.connect(user='scott', password='tiger', dsn='oralin:11204/v1124.world') Traceback (most recent call last): File "<stdin>", line 1, in <module> cx_Oracle.DatabaseError: ORA-21561: OID generation failed
見慣れぬエラーになりました。このエラーはクライアント側のホスト名を名前解決できない場合に発生するようです。
確かにMacOSで自ホスト名をhostsには書いていなかったので127.0.0.1になるように追記しておきます。以下のように自ホストへpingが通れば問題ありません。
(ora) denzownoMacBook-Pro:~ denzow$ ping `hostname` PING localhost (127.0.0.1): 56 data bytes 64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.066 ms 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.055 ms
では再度接続してみます。
>>> conn = cx_Oracle.connect(user='scott', password='tiger', dsn='oralin:11204/v1124.world') >>> conn <cx_Oracle.Connection to scott@oralin:11204/v1124.world>
無事に接続できたようです。念のためV$SESSIONからも確認しておきます。
SQL> select program, username from v$session where username='SCOTT'; PROGRAM USERNAME ------------------------------------------------ ------------------------------ python@denzownoMacBook-Pro.local (TNS V1-V3) SCOTT
セッションもはれているようですね。これで接続までが完了しました。
cx_OracleからSQLの実行
続いて、SQLを実行していきます。といっても、DBAPI 2.0に従ったインターフェースをもっているため、他のライブラリと基本的に同じ使い方になります。
>>> cur = conn.cursor() >>> for row in cur.execute('select * from v$version'): ... print(row[0]) ... Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production PL/SQL Release 11.2.0.4.0 - Production CORE 11.2.0.4.0 Production TNS for Linux: Version 11.2.0.4.0 - Production NLSRTL Version 11.2.0.4.0 - Production
connectionオブジェクトから作成したcursorオブジェクトを通じてSQLを発行し、その結果をfor文等で簡単に取得することができます。
なお、他のドライバによっては結果セットをPythonのディクショナリライクな形式で戻すオプションもありますが、cx_Oracle自体には提供されていないようです。
代替案として以下が参考になります。
cx_OracleとOracle Databaseのバージョン互換性
本ドキュメントにもあるようにcx_Oracle
が接続できるOracle Databaseのバージョンはcx_Oracle
のバージョンではなく、利用しているOracle Clientのライブラリのバージョンに依存します。
そのため通常のOracle Database/Oracle Client間のバージョン互換性と同じく、以下のドキュメントに従います。
Client / Server Interoperability Support Matrix for Different Oracle Versions (Doc ID 207303.1)
ただし、cx_Oracle
が現在動作保証されているOracle Clientは11.2,12.1,12.2だけですので11.2のClientが接続できる下限であるOracle Database 9.2がcx_Oracle
で接続できる最も古いバージョンになります。
まとめ
簡単ではありますが、Pythonからcx_Oracleを用いて接続する方法をご紹介しました。2018年もますます利用者が増えると思われるPythonからOracle Databaseを利用されようとする方に参考になれば幸いです。