Pro*C の復習中 その1
Pro*cは以前ある現場にて3000キロステップ位書いたことがあるので
全くの未経験ではない。・・・が、
2010年の夏から秋にかけての短い期間だったため(言い訳)もうなんかほとんど忘れてしまった。なので、サンプロコードからどのへんがすっかり忘れているポイントなのかをはっきりさせたいと思う。こちらのサイトから引用しました。
■Pro*Cによる配列アクセスのサンプルプログラム
配列アクセスは、SQLの規格にはありませんが、大幅にデータベースの性能改善ができます。
以下のプログラムは、配列アクセスにより、データベースを全件検索するPro*Cのサンプルです。 パラメータを付けると、デバッグ用のトレースを表示します。
※サンプルソースここから
#include <stdin.h>
//Pro*Cによる配列アクセスのサンプルプログラム
EXEC SQL BEGIN DECLARE SECTION;・・・・①
varchar username[20];
varchar password[20];
char h_ddate[3000][7];
char h_kan[3000][9];
char h_ken[3000][6];
int h_kaisuu[3000];
char h_clas[3000][8];
int h_yoteibi[3000];
EXEC SQL END DECLARE SECTION;・・・・②
EXEC SQL INCLUDE sqlca;・・・・③
void main(int argc,char *argv[]){
int i;
/*例外宣言
EXEC SQL WHENNEVER SQLERROR GOTO errorpt;・・・・④
/*Oracle接続
strcpy(username.arr,"uuuuuu");
username.len=strlen(username.arr);
strcpy(password.arr,"pppppp");
password.len=strlen(password.arr);
EXEC SQL CONNECT :username IDENTIFIELD BY :password;・・・・⑤
/*カーソル宣言・・・・⑥
EXEC SQL DECLARE CUR1 CURSOR FOR
SELECT DDATE,KAN,KEN,KAISUU,CLASS,CODE,YOTEIBI FROM TESR_DB
WHERE YOTEIBI = 15;
/* カーソルのオープン・・・・⑦
EXEC SQL OPEN CUR1;
/* データの取り出し・・・・⑧
EXEC SQL FETCH CUR1 INTO
:h_ddate,:h_kan,:h_ken,:h_kaisuu,:h_class,:h_code,:h_yoteibi;
if(argc > 1){
for(i=0;i<2500;i++){
printf("%s,%s,%s,%d,%s,%s,%d\n",
h_ddate[i],h_kan[i],h_ken[i],h_kaisuu[i],
h_class[i],h_code[i],h_yoteibi[i]);
}
}
//カーソルのクローズ・・・・⑨
EXEC SQL CLOSE CUR1;
//コミット処理・・・・⑩
EXEC SQL COMMIT WORK RELEASE;
exit(0);
errorpt:
printf("\n\n%-79s \n",splca.sqlerrm.sqlerrmc);
EXEC SQL WHENNEVER SQLERROR CONTINUE;
}※サンプルソースここまで
というわけで短いコードながら、合計10個のPro*Cならではのポイントが出てきた。一つ一つ確認していこう。
①EXEC SQL BEGIN DECLARE SECTION;
EXEC SQL~で始まる文言はPro*Cのお約束で、C言語にてSQLの操作とかを行うときはこの宣言が必要になる。これは基本。
で、①は埋め込みSQLのホスト変数宣言を開始するときに必要な宣言であり、
②EXEC SQL END DECLARE SECTION;
は、埋め込みSQLのホスト変数宣言の終了するときに必要な宣言である。
ここで唐突にホスト宣言という言葉が出てきたが、ホスト変数とは埋め込みSQLで使う変数のことでSQLの操作に利用される変数のこと。
③EXEC SQL INCLUDE sqlca;
なんだっけこれ。もういきなり忘れてしまっているので調べ直す。
Pro*C/C++プリコンパラでは、「sqlca.h」や「oraca.h」「sqlda.h」などのヘッダファイルを提供していて、これらをインクルードする方法が2通りある。
#include <sqlca.h>
または、③の書き方。そもそもsqlca.hってなに?ってことなんだけど、
ランタイム・エラーの診断、およびプログラムによる様々なOracle Database 10gリソースの使用状況の監視に役立つoracle通信領域(ORACA)が含まれています。
ということで、SQLERRORの判定に使われるってことでいいんだろうか。他にもインクルードするファイルはいくつかあって、
・sql2oci.h
・sqlapr.h
・sqlcpr.h
・oraca.h
・sql2oci.h
こちらで解説されている。
④EXEC SQL WHENNEVER SQLERROR GOTO errorpt;
WHENEVERはSQLの例外宣言で、
SQLを実行した時に失敗(ユーザの誤りやXDBの異常によって,SQLが正常に実行されなかったとき)errorptへGOTOする処理。
でも実際にSQLを発行しているのはもうちょっと下なんだけど、これでいいのかな。
⑤EXEC SQL CONNECT :username IDENTIFIELD BY :password;
ユーザ名とパスワードを設定してDBに接続をしている処理。
⑥EXEC SQL DECLARE CUR1 CURSOR FOR
これの下でSELECT文を発行しているので、なんとなく処理はわかるのだけど、カーソルってなんだっけ?忘れてしまったので調べ直した。
SELECT文によってデータの抽出が行われて、条件に適合しているすべてのデータを「表」の形で表示する。けれどプログラムではホスト変数を介してデータを受け取らなくてはいけないので、「表」で出力されても処理ができない。
そこで、SELECT文で得られた表を保持しつつ、表中のデータを1行ずつ取り出すということをしている。SELECT文で得られた表は「カーソル」というポインタによって指定される。
表をファイルとして見立てた時に、カーソルはそのファイルポインタのようなものと考えると良い。なので、一旦カーソルの宣言をおこない
→exec sql declare カーソル名 cursor for select 文;
そしてカーソルをオープンする
→exec sql open カーソル名;
で、カーソル内の1行ずつデータを取り出すにはFETCH文を使う。
→exec sql fetch in カーソル名 into ホスト変数リスト ;
FETCHはすべての行を読み終わると、”not found”という例外を発生する仕組みになっているので、前もって例外発生時のアクションを指定する必要がある。
→exec sql whenever not found do break;
そして、カーソルをクローズする。
→ EXEC SQL CLOSE CUR1;
ここまでの流れは、⑥から⑨までの流れ。
でもこのサンプルにはnotfoundの例外処理がないな・・・。いいのか?
⑩ EXEC SQL COMMIT WORK RELEASE;
これは発行したSQLをコミットさせたいので実行しているのだと思うのだけど、SELECTでも必要なのだろうか。調べてみた。
COMMIT WORK RELEASEは、SQLをコミットさせるということではなくDBとの切断を行うための処理なのだそうだ。これを書かないとROLLBACKされるらしい。
ちなみに、Pro*Cの場合は EXEC SQL COMMIT WORK RELEASE;で、
ecpgの場合は、
EXEC SQL COMMIT;
EXEC SQL DISCONNECT;
と記述する。らしい。
OracleC/C++実践入門 (DBMagazine SELECTION)
- 作者: 笠原規男
- 出版社/メーカー: 翔泳社
- 発売日: 2004/07/17
- メディア: 単行本
- 購入: 1人 クリック: 56回
- この商品を含むブログ (5件) を見る