UbuntuでPythonからcx_Oracleモジュールを使ってOracle Database 11gに接続する

Oracle Databaseを使うのは初めて。最新版は12cだけど、11gがまだ結構使われてるっぽい。
PythonからOracleに接続する場合はいくつか方法があるけど、今回はcx_Oracleを使うことにする。
試した環境は、Ubuntu 12.04、Python 2.7。
cx_Oracle
cx_Oracleは9i、10g、11gに対応していて、12cには対応していないみたい。

クライアントライブラリの入手とインストール

UbuntuのコミュニティのヘルプWikiにクライアントのインストール方法が書かれているので、これを参考にする。
Oracle Instant Client - Community Help Wiki
cx_Oracleは、Oracle Databaseのクライアントライブラリのインストールが必要となる。
pipやeasy_installでインストールする場合は、Cで書かれたモジュールをビルドするため、ヘッダファイルを含むパッケージのインストールも必要となる。
クライアントは以下のページから入手する。ダウンロードのためには会員登録(無料)が必須。
Oracle Instant Client Downloads
接続するOracle Databaseのバージョンでライブラリが異なるようなので注意する。
ダウンロードしたファイルは以下の3つ。

rpmなので、インストールにはalienを使う。alienコマンドがインストールされてない場合はaptでalienパッケージをインストールしておく。

$ sudo alien -i oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_64.rpm
$ sudo alien -i oracle-instantclient11.2-devel-11.2.0.4.0-1.x86_64.rpm
$ sudo alien -i oracle-instantclient11.2-sqlplus-11.2.0.4.0-1.x86_64.rpm

alienrpmdebパッケージに変換、インストールするツール。 -i オプションを指定すると、変換後にインストールとなる。
コマンドラインツールのsqlplusを使う場合はlibaio1パッケージを事前にインストールしておく。

ORACLE_HOMEとPATHの設定

インストール後、環境変数ORACLE_HOMEを設定する。profile.dにファイルを作るか、個人用の.bashrcなどに書いておく。

export ORACLE_HOME=/usr/lib/oracle/11.2/client64
export PATH=$PATH:$ORACLE_HOME/bin
includeディレクトリのシンボリックリンクを作成する

いくつかのパッケージはORACLE_HOME以下のincludeディレクトリを参照しようとするので、シンボリックリンクを作っておく。

$ sudo ln -s /usr/include/oracle/11.2/client64 $ORACLE_HOME/include
ldの設定

インストールしたライブラリのディレクトリをldの対象に追加する
/etc/ld.so.conf.d/oracle.conf

/usr/lib/oracle/11.2/client64/lib/

設定ファイルを作成したら、ldconfigを実行する。

$ sudo ldconfig

cx_Oracleのインストール

PythonのCモジュールをビルドできる状態で、cx_Oracleをpipなりeasy_installでインストールする。virtualenv環境へのインストールも特に問題ない。

(venv)$ pip install cx_Oracle

動作確認

対話インターフェースからcx_Oracleをimportして使ってみる。
接続先はAmazon RDSのOracleだったのだが、SIDを指定しないといけなかった。

>>> import cx_Oracle
>>> connection = cx_Oracle.connect("testuser", "testpassword", "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=oracledb.example.com) (PORT=1521))(CONNECT_DATA=(SID=ORCL)))")
>>> cursor = connection.cursor()
>>> cursor.execute("select * from test")
>>> for values in cursor:
...   print values
... 
(1, 'hoge', 123)

うまくいった。