エラー処理のためのコールバックの設定
SQLを発行した結果がエラー,警告,選択行なしのいずれかの結果であった場合に,どんな処理をするかをあらかじめ登録することができる.
これまでのサンプルでは,以下のような似たようなエラー処理が何度も記述されていた.
if (memcmp (sqlca.sqlstate, "00", 2) != 0)
{
fprintf (stderr, "%s\n", sqlca.sqlerrm.sqlerrmc);
exit (EXIT_FAILURE);
}
だが,このような記述はソースを著しく損ねる場合がある.大体面倒臭い.そこで,あらかじめSQL文を実行した結果がエラー,警告,選択行なしの場合に何を行うかを登録できれば便利である.
EXEC SQL WHENEVER 結果 処理;結果は以下の三つである.
- SQLERROR
- エラー.
- SQLWARNING
- 警告.
- NOT FOUND
- 選択行なし(SELECT文で行が選択されなかった).
- CONTINUE
- とくに何もせず続行.デフォルト.
- GOTO ラベル,GO TO ラベル
- Cのgoto文により指定したラベルにとぶ.
- SQLPRINT
- stderrにメッセージを出力.
- STOP
- exit(1)を実行.
- BREAK(※)
- Cのbreak文を実行.ループかswitch文内で使用.
- CALL 関数名 (引数), DO 関数名 (引数)
- 指定した引数で関数を呼び出す.引数がない場合は()内に何も記述しない.
※ ecpg 3.1.1ではなんかエラーになったが,GOTOで代替できるのでそんなに痛くはない.
エラー処理のコールバックを使用したサンプルを以下に示す.
このサンプルは,コールバックを設定し,不正なSQL文を発行したり,行が選択されないSELECT文を発行したりするものである.実行してみた.
$> ./callback -d tcp:postgresql://dbserver/firstdb -u matsu -p hogefuga [13399]: ECPGdebug: set to 1 [13399]: ECPGconnect: opening database firstdb on dbserver port <DEFAULT> for user matsu [13399]: ECPGexecute line 49: QUERY: INVALID SQL; on connection dbConnection [13399]: ECPGexecute line 49: Error: ERROR: parser: parse error at or near "invalid" [13399]: raising sqlstate YE000 in line 49, ''parser: parse error at or near "invalid"' in line 49.'. [13399]: ECPGtrans line 53 action = rollback connection = dbConnection AFTER POINT BEFORE while [13399]: ECPGexecute line 62: QUERY: INVALID SQL; on connection dbConnection [13399]: ECPGexecute line 62: Error: ERROR: parser: parse error at or near "invalid" [13399]: raising sqlstate YE000 in line 62, ''parser: parse error at or near "invalid"' in line 62.'. [13399]: ECPGtrans line 65 action = rollback connection = dbConnection AFTER while [13399]: ECPGexecute line 71: QUERY: INVALID SQL; on connection dbConnection [13399]: ECPGexecute line 71: Error: ERROR: parser: parse error at or near "invalid" [13399]: raising sqlstate YE000 in line 71, ''parser: parse error at or near "invalid"' in line 71.'. IN callback function [13399]: ECPGtrans line 72 action = rollback connection = dbConnection [13399]: ECPGexecute line 77: QUERY: create table hoge ( id integer , name char ( 8 )) on connection dbConnection [13399]: ECPGexecute line 77 Ok: CREATE [13399]: ECPGexecute line 79: QUERY: select * from hoge on connection dbConnection [13399]: ECPGexecute line 79: Correctly got 0 tuples with 2 fields [13399]: raising sqlcode 100 in line 79, 'No data found in line 79.'. sql error No data found in line 79. [13399]: ECPGtrans line 80 action = rollback connection = dbConnection [13399]: ECPGtrans line 86 action = rollback connection = dbConnection [13399]: ecpg_finish: Connection dbConnection closed.サンプルソースを確認しつつ,"AFTER POINT","BEFORE while","AFTER while","IN callback function","sql error No data found in line 79."という出力とその前の出力を確認するとコールバック処理されていることがわかる.
本頁で記述しているecpgの機能はコールバックと記述してきたが,それはプログラマがそのように(ある程度)錯覚してコーディングできるという意味であって,ecpgの実装では実際にはコールバックではない.ecpgの処理はだいたい以下のようである.
警告の場合のコールバック処理を,aの値に応じて切替えているつもりのコードである.これはecpgによって以下のように変換される.
このように,意図に反して警告の場合のコールバック処理は常に異常終了(STOP)である.上述のecpgの動作からして,プログラム実行時に条件に応じてコールバックを設定,変更するというのは,その恩恵の割に面倒臭い場合がある.どうしてもやりたいなら,以下のようになるだろうか.
これをecpgで変換すると以下のようになる.
このパターンではCREATE TABLEが一つだけだったが,コールバックの設定のために,例えば数十行を丸コピするとかなると,このコールバックの目的のからして本末転倒となる.
- ソースを「上から順に」なめる.Cの制御(関数呼び出しやif文など)は解析,解釈しない.とにかく「上から順に」なめる.
- 埋め込みSQLのパターンをCに変換.
- ecpgは処理状態を持っていて,その状態として埋め込みSQLで使用できる変数などが記憶,チェックされる.エラー処理時のコールバックもこの状態として記憶される.
- 特定の埋め込みSQLのパターンをCに変換する際,エラー処理時のコールバックの状態応じたCのパターンを追記.

