昨日はnuko_yokohamaさんのjsqueryを使ってみたでした。
普段わたしはウェブアプリをPHPで作っていて、そこからPostgreSQLへアクセスするのですが、バッチ処理やループ処理などはCやC++で書くことがあります。
少し前までは、C言語でバッチ処理を書いていて、ecpgを使った埋め込みSQLを使っていました。
AIXでDB2を使っていた経験があり、その延長で埋め込みSQLは便利だなと思っていたのです。
しかし、複雑なことをするに従って、また他のライブラリの都合などもあり、徐々にC++に移行してきました。
7日目の nuko_yokohama さんのスライドにもあったように、C++でecpgを使うのは、ちょっと微妙です。完全対応では無いので、何か問題が発生したときに切り分けで嵌まりそうです。
そこで、libpqxxという、C++ライブラリを使ってみました。
http://pqxx.org/development/libpqxx/
現在、最新バージョンとしては4.0.1が公開されています。
が、開発版のスナップショットも公開されています。
4.0.1はリリースが古く、それからちょこっと修正も入っているので、こちらの方がいいかなと思います。
http://pqxx.org/~jtv/tmp/pqxx/snapshot/
configure して make して make install 簡単ですね。
コードは、とてもシンプルです。
コネクションやトランザクション、結果などそれぞれがオブジェクトになるので、簡単にアクセスできます。
// パスワードは .pgpass にでも書いておきましょう
unique_ptr<pqxx::connection> db_conn(new pqxx::connection("host=pgsql.example.jp port=5432 dbname=testdb user=testuser application_name=testprog"));
try {
pqxx::read_transaction tran(*db_conn);
ostringstream query;
query << "SELECT val" << endl;
query << "FROM tbl" << endl;
query << "WHERE cond='cond'" << endl;
pqxx::result res(tran.exec( query.str() ));
if (res.begin() == res.end()) cerr << "nodata" << endl;
for (pqxx::result::const_iterator row = res.begin(); row != res.end(); row++) {
cout << row["val"] << endl;
}
tran.commit();
}
catch (const pqxx::sql_error& e) {
cerr << e.what() << " : SQL->" << e.query() << endl;
}
catch (const pqxx::usage_error& e) {
cerr << e.what() << endl;
}
更新でも同じ流れです。
pqxx::work tran(*db_conn);
std::ostringstream query;
query << "INSERT INTO tbl (" << endl;
query << "val, cond" << endl;
query << ") VALUES (" << endl;
query << " " << std::dec << val << endl;
query << ", " << tran.quote( cond ) << endl;
query << ")" << endl;
pqxx::result res(tran.exec( query.str() ));
tran.commit();
quoteだけではなく、ちゃんとプリペアドステートメントも使えます。
pqxx::connection_base &con_base(*db_conn);
con_base.prepare("sel", "SELECT name FROM tbl WHERE code=$1");
pqxx::read_transaction tran(*db_conn);
pqxx::result res( tran.prepared("sel")("hoge").exec() );
for (pqxx::result::const_iterator row = res.begin(); row != res.end(); row++) {
cout << row["name"] << endl;
}
tran.commit();
プリペアドステートメントはデータベースコネクションへ登録、実際のステートメントはトランザクションから
tran.prepared(ステートメント名)($1)($2)・・・.exec()という形式で呼び出します。
嵌まりどころがなくて、拍子抜けするぐらいです。
以前のバージョンでは、PostgreSQLのbigint型を扱うときにCのlong long int型を使おうとするには、includeファイルの定義を変更したりする必要があったのですが、今のバージョンでは不要です。
これでC++からも簡単PostgreSQL!!






