OCamlでPostgreSQLにアクセスする
シンプルなPostgreSQLのOCamlライブラリがないかと探したところ、Mottl氏らによるpostgresql-ocamlというライブラリがありました。
というわけで、postgresql-ocamlの導入と簡単な使い方のご紹介です。
公式ページ
インストール
OPAM経由でインストールすると楽です。
opam update
opam upgrade
opam install postgresql-ocaml
インストールしたところ、ライブラリのディレクトリ(~/.opam/4.02.0/lib
)にpostgresql-ocaml
とpostgresql
ディレクトリが作成されていました。postgresql-ocaml
側が空で、本体はpostgresql
ディレクトリに格納されています。
ocamlfindに登録されているか確認します。
$ ocamlfind list bigarray (version: [distributed with Ocaml]) postgresql (version: 2.1.0) threads (version: [distributed with Ocaml]) unix (version: [distributed with Ocaml])
なお、postgresql-ocamlはbigarray, threads(とunix)を必要とします。
サンプルデータを仕込む
適当なSQLファイルを作成します。
example.sql:
-- テーブルを作成する CREATE TABLE customers ( id INTEGER PRIMARY KEY, name VARCHAR(20) NOT NULL, address VARCHAR(60) ); -- サンプルデータを投入する INSERT INTO customers (id, name, address) VALUES (100, '山田太郎', '東京都港区'), (200, '佐藤一郎', '東京都千代田区');
SQLファイルをロードします。
$ psql -U user1 example -f example.sql
ここではデータベース、テーブル、所有者を以下のようにしています。
- データベース名: example, 所有者: user1
- テーブル名: customers, 所有者: user1
PostgreSQLのセットアップやコマンドの使い方はこちらを参照: MacでPostgreSQL - 一歩前進
サンプルコード
前半は通常のクエリ発行で、後半はprepared statementを使用しています。
#use "topfind";; #thread;; #require "postgresql";; open Printf open Postgresql (* DB名、ユーザ名、パスワードを指定してconnectionクラスのインスタンスを作成する *) let conn = new connection ~dbname:"example" ~host:"localhost" ~user:"user1" ~password:"user1" () (* SQL文;$1, $2, ... でプレースホルダを指定できる *) let query = "SELECT id, name, address FROM customers WHERE id = $1" (* 取得した結果を表示する関数 *) let show res = for tuple = 0 to res#ntuples - 1 do for field = 0 to res#nfields - 1 do printf "%s, " (res#getvalue tuple field) done; print_newline () done (* 受け取った文字列sをパラメータとしてクエリを発行し、結果を出力する *) let run s = show @@ conn#exec ~expect:[Tuples_ok] ~params:[| s |] query;; (* @@ はHaskellの$と同じく、( ) を省略するためのもの * ~ はラベル付き引数 * ~expectは、結果がTuples_ok(データが返ってきた場合)以外であれば例外を出すという指定 * ~paramsでプレースホルダにバインドするパラメータを、配列で指定 *) run "100";; (* => 100, 山田太郎, 東京都港区, *) run "200";; (* => 200, 佐藤一郎, 東京都千代田区, *) run "300";; (* => (表示されない) *) (* test1 という識別名でprepared statementを作る *) assert ((conn#prepare "test1" query)#status = Command_ok);; let prepared_run s name = show @@ conn#exec_prepared ~expect:[Tuples_ok] ~params:[|s|] name ;; prepared_run "100" "test1";; (* => 100, 山田太郎, 東京都港区, *) prepared_run "200" "test1";; (* 200, 佐藤一郎, 東京都千代田区, *) prepared_run "300" "test1";; (* => (表示されない) *)