DB2 ODBC経由で接続してみる
またDB2ネタ(このところ、毎日触ってるもので...)。C/C++でプログラミングする場合、前回書いたようなSQL埋め込み型だとコードが冗長になるのでODBC経由での実装するにはどうしたらいいかと思って、あれこれサンプルを漁っていたら、昨日インストールしたruby用DB2ドライバ(ibm_db2.c)がまさにソレでした。ソースをチェックしてみたらconnect時にSQLSetEnvAttr()という関数でSQL_ATTR_ODBC_VERSION,SQL_OV_ODBC3を指定していました。このドライバのやり方を使えばEXEC SQL .... EXEC SQL END ...などと書かなくていいしmake時のバインド処理の手間も省けてGood!昨日作ったrubyのサンプルスクリプトとドライバ側でラップしているDB2APIの対比をしてみると大まかな流れがわかります。まとめてみると概ねこんなカンジ
| ruby | driver |
|---|---|
| DB2:connect | SQLAllocHandle(); SQLSetEnvAttr(); SQLAllocHandle(); SQLSetConnectAttr(); SQLConnect(); |
| DB2::prepare | SQLPrepare(); |
| DB2::bind_param | -(execute時にbind) |
| DB2::execute | SQLFreeStmt() SQLBindParameter(); SQLExecute(); |
| DB2::fetch_assoc | SQLFetch(); SQLGetData(); |
| DB2::close | SQLDisconnect(); SQLFreeHandle(); |
DB2::bind_paramは特になにもしていなくて、ステートメントの実行時(DB2::execute)にパラメータ数を調べ、SQLBindParameter()関数でバインドしています。実行時にパラメータをバインドするほうが何か有利なことがあるのでしょうか?(キャッシュとか?)あと、SQLステートメント実行前にSQLFreeStmt()でステートメントハンドルとカーソルハンドルをクローズする処理が入っていますが共有ライブラリとしての実装だからでしょうか?これらを踏まえてあらためて昨日のrubyスクリプトを再度C/C++で実装してみました。
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLCHAR statement[] =
"select a,b,c from tr_uriage where x > ?";
SQLCHAR a[10 + 1];
SQLCHAR b[ 3 + 1];
SQLINTEGER c;
SQLINTEGER min_suu = atoi(argv[1]);
SQLINTEGER olen = 0;
SQLAllocHandle(
SQL_HANDLE_ENV,SQL_NULL_HANDLE,&henv
);
SQLSetEnvAttr(
henv,SQL_ATTR_ODBC_VERSION,(void *)SQL_OV_ODBC3,0
);
SQLAllocHandle(
SQL_HANDLE_DBC,henv,&hdbc
);
SQLConnect(
hdbc,(SQLCHAR *)"sample",SQL_NTS,
(SQLCHAR*)"db2inst1",SQL_NTS,
(SQLCHAR*)"password",SQL_NTS
);
SQLPrepare(
hstmt,statement,SQL_NTS
);
SQLBindParameter(
hstmt,1,SQL_PARAM_INPUT,
SQL_INTEGER,SQL_INTEGER,0,0,&min_suu,0,NULL
);
SQLExecute(hstmt);
while((rc=SQLFetch(hstmt))==SQL_SUCCESS ||
rc==SQL_SUCCESS_WITH_INFO)
{
SQLGetData(hstmt,1,SQL_CHAR,a,sizeof(a),&olen);
SQLGetData(hstmt,2,SQL_CHAR,b,sizeof(b),&olen);
SQLGetData(hstmt,3,SQL_INTEGER,&c,sizeof(c),&olen);
cout << a << "," << b << "," << c << endl;
}
SQLDisconnect(hdbc);
SQLFreeStmt(hstmt,SQL_CLOSE);
SQLFreeStmt(hstmt,SQL_RESET_PARAMS);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc)Rubyスクリプトに比べるとやっぱりタイプ量は多いですが、埋め込みSQLよりはましかなぁ。やっぱ、普段はrubyかなと思いますが、一応押さえとしてはこういうやり方もあるということで間口は広がったかな。そういえばコードを読んでいる時気がついたんですが、rubyスクリプトでfetch_assocしたときのハッシュのキーが大文字になって嫌だなと思っていたのですがちゃんと指定がありましたよ...
conn = DB2::connect database,user,using,{'DB2_ATTR_CASE'=>DB2::CASE_LOWER}これでrow['a']でOK!






Comments