SQL ステートメントを発行し、データベース・マネージャー API を呼び出すアプリケーションには、戻りコードと SQLCA 構造を検査しエラー条件を正確に調べることが求められます。
ほとんどのデータベース・マネージャーは処理が正常であれば、ゼロの戻りコードを戻します。一般に、ゼロ以外の戻りコードは、 2 次エラー処理機構の SQLCA 構造が破壊された可能性があることを示します。この場合、呼び出された API は実行されません。 SQLCA 構造が破壊される原因として、構造に対して無効なアドレスを渡したことが考えられます。
エラー情報は、SQLCA 構造の SQLCODE と SQLSTATE のフィールドに戻されます。SQLCA 構造は、すべての実行可能 SQL ステートメントとほとんどのデータベース・マネージャー API 呼び出しの実行後に更新されます。
実行可能 SQL ステートメントが入っているソース・ファイルには、 sqlca という名前を持つ SQLCA 構造が少なくとも 1 つあります。 SQLCA 構造は SQLCA インクルード・ファイルで定義されます。組み込み SQL ステートメントはないがデータベース・マネージャー API を呼び出すソース・ファイルには、 1 つまたは複数の SQLCA 構造を組み込むことができますが、各構造の名前は任意に付けられます。
ご使用のアプリケーションが FIPS 127-2 標準に準拠している場合、 SQLCA 構造の代わりに SQLSTATE および SQLCODE をホスト変数として宣言することができます。この方法に関しては、C または C++ アプリケーションの場合は C および C++ における SQLSTATE および SQLCODE 変数、 COBOL アプリケーションの場合は COBOL での SQLSTATE および SQLCODE 変数、または FORTRAN アプリケーションの場合は FORTRAN の SQLSTATE および SQLCODE 変数を参照してください。
SQLCODE 値が 0 である場合は、正常に実行されたことを示します (SQLWARN 警告状態を伴うこともあります)。正の値は、ステートメントは正常に実行されたが、ホスト変数の切り捨てなどの警告を伴うことを意味します。負の値は、エラー状態が起こったことを意味します。
追加のフィールド SQLSTATE には、他の IBM データベース製品および SQL92 準拠のデータベース・マネージャーと一貫性がある標準化エラー・コードが含まれています。実際には、SQLSTATE は多くのデータベース・マネージャーと共通であるため、可搬性を考慮する場合は SQLSTATE を使用します。
SQLWARN フィールドには、SQLCODE がゼロの場合でも警告標識の配列が含まれます。 SQLWARN 配列の第 1 要素である SQLWARN0 には、その他の要素がすべてブランクである場合はブランクが入ります。その他の要素の少なくとも 1 つに警告文字が含まれている場合は、 SQLWARN0 には W が入ります。
SQLCA 構造の詳細については 管理 API 解説書、 SQLCODE と SQLSTATE のエラー状態のリストについては、 メッセージ解説書 を参照してください。
注: | さまざまな IBM RDBMS サーバーにアクセスするアプリケーションを開発する場合は、以下のようにしてください。
|
SQLCA 構造ではトークンが切り捨てられることがあるため、診断目的ではトークン情報を使用しないでください。表および列の名前は最高 128 バイトの長さで定義できますが、 SQLCA トークンは、17 バイトと切り捨て終止符 (>) を加えた長さで切り捨てられます。アプリケーションのロジックは、 sqlerrmc フィールドの実際の値によって決めるべきではありません。 SQLCA 構造およびトークンの切り捨ての説明については、SQL 解説書 を参照してください。
WHENEVER ステートメントがあると、プリコンパイラーは、実行中にエラー、警告、または行が見つからないなどの状態が起こった場合にアプリケーションに指定のラベルまで進むように指示するソース・コードを生成します。 WHENEVER ステートメントは、別の WHENEVER ステートメントが状況を変更するまで、後続の実行可能 SQL ステートメントに影響を与えます。
WHENEVER ステートメントには以下の 3 つの基本形式があります。
EXEC SQL WHENEVER SQLERROR action EXEC SQL WHENEVER SQLWARNING action EXEC SQL WHENEVER NOT FOUND action
上記のステートメントについて説明します。
いずれの場合も、action は以下のどちらかになります。
WHENEVER ステートメントを使用しない場合、実行中にエラー、警告、または例外状態が起こると、省略時のアクションとして処理が継続されることになります。
WHENEVER ステートメントは、影響を及ぼす SQL ステートメントの前に指定しなければなりません。そうしないと、プリコンパイラーは実行可能 SQL ステートメント用に余分のエラー処理コードを生成しなければならないことを認識しません。 3 つの基本形式はいつでも任意に組み合わせて活動状態にすることができます。これら 3 つの形式の宣言順序は重要ではありません。無限ループ状態を避けるには、SQL ステートメントをハンドラー内部で実行する前に、 WHENEVER 処理が取り消されていることを確認してください。 WHENEVER SQLERROR CONTINUE ステートメントを使用すれば、 SQL ステートメントをハンドラー内部で実行することができます。
WHENEVER ステートメントの詳細な説明については、 SQL 解説書 を参照してください。
例外、シグナル、または割り込みハンドラーは、例外が起きたときに制御を獲得するルーチンです。ここで適用されるハンドラーのタイプは、操作環境によって異なります。以下のとおりです。
上記のリストにないオペレーティング・システムについては、 アプリケーション構築の手引き を参照してください。
例外、シグナル、および割り込みハンドラーの中には SQL ステートメントを置かないでください (COMMIT と ROLLBACK は例外)。これらのエラー状態が起きた場合には、データの矛盾を避けるために、 ROLLBACK するのが普通です。
例外 / シグナル / 割り込みハンドラーでの COMMIT および ROLLBACK のコーディングは、慎重に行ってください。これらのステートメントのいずれかをそれだけで呼び出す場合、 COMMIT または ROLLBACK は現行の SQL ステートメントが完了するまで実行されません (SQL ステートメントが実行中の場合)。これは、Ctrl-C ハンドラーから実行するには望ましい動作ではありません。
ROLLBACK を発行する前に、 INTERRUPT API (sqleintr/sqlgintr) を呼び出すことで解決できます。これは、現行の SQL 照会を中断させ (アプリケーションが SQL 照会を実行中の場合)、 ROLLBACK が即時に開始されるようにします。 ROLLBACK よりも COMMIT を実行するつもりならば、現行のコマンドを中断する必要はありません。
APPC を使用してリモート・データベース・サーバー (DB2 (AIX 版) または DB2 コネクトを使用したホスト・データベース・システム) にアクセスする場合に、アプリケーションは SIGUSR1 シグナルを受信することがあります。このシグナルは、回復不可能エラーが発生したり SNA 接続が停止したときに、 SNA サービス/6000 により生成されます。 SIGUSR1 を処理するには、シグナル・ハンドラーをアプリケーションに導入する必要があります。
さまざまなハンドラーの特定な詳細の考慮事項については、ご使用のプラットフォームの資料を参照してください。
出口リスト・ルーチンでは、SQL や DB2 API 呼び出しを使用しないでください。出口ルーチンの中ではデータベースから切断することはできないことに注意してください。
C の例: UTILAPI.C および COBOL の例: CHECKERR.CBLで示しているコード・クリップは、渡される SQLCA に関する情報を GET ERROR MESSAGE API を使って得る方法について説明しています。
これらの例の作成に関する情報は、 README ファイルまたはこれらのサンプル・プログラムのヘッダー・セクションで見ることができます。
#include <stdio.h> #include <stdlib.h> #include <sql.h> #include <sqlenv.h> #include <sqlda.h> #include <sqlca.h> #include <string.h> #include <ctype.h> #include "utilemb.h" EXEC SQL INCLUDE SQLCA; /*############################################################################# ** 1. SQL_CHECK section ** ** 1.1 - SqlInfoPrint - prints on the screen everything that ** goes unexpected. ** 1.2 - TransRollback - rolls back the transaction #############################################################################*/ /****************************************************************************** ** 1.1 - SqlInfoPrint - prints on the screen everything that ** goes unexpected. ******************************************************************************/ int SqlInfoPrint( char * appMsg, struct sqlca * pSqlca, int line, char * file ) { int rc = 0; char sqlInfo[1024]; char sqlInfoToken[1024]; char sqlstateMsg[1024]; char errorMsg[1024]; if (pSqlca->sqlcode != 0 && pSqlca->sqlcode != 100) { strcpy(sqlInfo, ""); if( pSqlca->sqlcode < 0) { sprintf( sqlInfoToken, "\n---- error report ----\n"); strcat( sqlInfo, sqlInfoToken); } else { sprintf( sqlInfoToken, "\n---- warning report ----\n"); strcat( sqlInfo, sqlInfoToken); } /* endif */ sprintf( sqlInfoToken, " app. message = %s\n", appMsg); strcat( sqlInfo, sqlInfoToken); sprintf( sqlInfoToken, " line = %d\n", line); strcat( sqlInfo, sqlInfoToken); sprintf( sqlInfoToken, " file = %s\n", file); strcat( sqlInfo, sqlInfoToken); sprintf( sqlInfoToken, " SQLCODE = %ld\n", pSqlca->sqlcode); strcat( sqlInfo, sqlInfoToken); /* get error message */ rc = sqlaintp( errorMsg, 1024, 80, pSqlca); /* return code is the length of the errorMsg string */ if( rc > 0) { sprintf( sqlInfoToken, "%s\n", errorMsg); strcat( sqlInfo, sqlInfoToken); } /* get SQLSTATE message */ rc = sqlogstt( sqlstateMsg, 1024, 80, pSqlca->sqlstate); if (rc == 0) { sprintf( sqlInfoToken, "%s\n", sqlstateMsg); strcat( sqlInfo, sqlInfoToken); } if( pSqlca->sqlcode < 0) { sprintf( sqlInfoToken, "--- end error report ---\n"); strcat( sqlInfo, sqlInfoToken); printf("%s", sqlInfo); return 1; } else { sprintf( sqlInfoToken, "--- end warning report ---\n"); strcat( sqlInfo, sqlInfoToken); printf("%s", sqlInfo); return 0; } /* endif */ } /* endif */ return 0; } /****************************************************************************** ** 1.2 - TransRollback - rolls back the transaction ******************************************************************************/ void TransRollback( ) { int rc = 0; /* rollback the transaction */ printf( "\nRolling back the transaction ...\n") ; EXEC SQL ROLLBACK; rc = SqlInfoPrint( "ROLLBACK", &sqlca, __LINE__, __FILE__); if( rc == 0) { printf( "The transaction was rolled back.\n") ; } }
JDBC および SQLJ アプリケーションは、 SQL 処理中にエラーが発生すると、SQLException をスローします。使用中のアプリケーションは SQLException を受け取り、以下のコードでそれを表示します。
try { Statement stmt = connection.createStatement(); int rowsDeleted = stmt.executeUpdate( "DELETE FROM employee WHERE empno = '000010'"); System.out.println( rowsDeleted + " rows were deleted"); } catch (SQLException sqle) { System.out.println(sqle); }
SQLExceptions 処理の詳細については、 Java の SQLSTATE および SQLCODE 値を参照してください。
Identification Division. Program-ID. "checkerr". Data Division. Working-Storage Section. copy "sql.cbl". * Local variables 77 error-rc pic s9(9) comp-5. 77 state-rc pic s9(9) comp-5. * Variables for the GET ERROR MESSAGE API * Use application specific bound instead of BUFFER-SZ * 77 buffer-size pic s9(4) comp-5 value BUFFER-SZ. * 77 error-buffer pic x(BUFFER-SZ). * 77 state-buffer pic x(BUFFER-SZ). 77 buffer-size pic s9(4) comp-5 value 1024. 77 line-width pic s9(4) comp-5 value 80. 77 error-buffer pic x(1024). 77 state-buffer pic x(1024). Linkage Section. copy "sqlca.cbl" replacing ==VALUE "SQLCA "== by == == ==VALUE 136== by == ==. 01 errloc pic x(80). Procedure Division using sqlca errloc. Checkerr Section. if SQLCODE equal 0 go to End-Checkerr. display "--- error report ---". display "ERROR occurred : ", errloc. display "SQLCODE : ", SQLCODE. ******************************** * GET ERROR MESSAGE API called * ******************************** call "sqlgintp" using by value buffer-size by value line-width by reference sqlca by reference error-buffer returning error-rc. ************************ * GET SQLSTATE MESSAGE * ************************ call "sqlggstt" using by value buffer-size by value line-width by reference sqlstate by reference state-buffer returning state-rc. if error-rc is greater than 0 display error-buffer. if state-rc is greater than 0 display state-buffer. if state-rc is less than 0 display "return code from GET SQLSTATE =" state-rc. if SQLCODE is less than 0 display "--- end error report ---" go to End-Prog. display "--- end error report ---" display "CONTINUING PROGRAM WITH WARNINGS!". End-Checkerr. exit program. End-Prog. stop run.
parse version rexxType . parse source platform . if platform == 'AIX/6000' & rexxType == 'REXXSAA' then do rcy = SysAddFuncPkg("db2rexx") end else do if RxFuncQuery('SQLDBS') <> 0 then rcy = RxFuncAdd( 'SQLDBS', 'db2ar', 'SQLDBS' ) if RxFuncQuery('SQLEXEC') <> 0 then rcy = RxFuncAdd( 'SQLEXEC', 'db2ar', 'SQLEXEC' ) end
.
.
.
call CHECKERR 'INSERT'
.
.
.
CHECKERR: arg errloc if ( SQLCA.SQLCODE = 0 ) then return 0 else do say '--- error report ---' say 'ERROR occurred :' errloc say 'SQLCODE :' SQLCA.SQLCODE /******************************\ * GET ERROR MESSAGE API called * \******************************/ call SQLDBS 'GET MESSAGE INTO :errmsg LINEWIDTH 80' say errmsg say '--- end error report ---' if (SQLCA.SQLCODE < 0 ) then exit else do say 'WARNING - CONTINUING PROGRAM WITH ERRORS' return 0 end end return 0 /* this variable (SYSTEM) must be user defined */ SYSTEM = AIX if SYSTEM = OS2 then do if RxFuncQuery('SQLDBS') <> 0 then rcy = RxFuncAdd( 'SQLDBS', 'DB2AR', 'SQLDBS' ) if RxFuncQuery('SQLEXEC') <> 0 then rcy = RxFuncAdd( 'SQLEXEC', 'DB2AR', 'SQLEXEC' ) end if SYSTEM = AIX then rcy = SysAddFuncPkg("db2rexx")
.
.
.
call CHECKERR 'INSERT'
.
.
.
CHECKERR: arg errloc if ( SQLCA.SQLCODE = 0 ) then return 0 else do say '--- error report ---' say 'ERROR occurred :' errloc say 'SQLCODE :' SQLCA.SQLCODE /******************************\ * GET ERROR MESSAGE API called * \******************************/ call SQLDBS 'GET MESSAGE INTO :errmsg LINEWIDTH 80' say errmsg say '--- end error report ---' if (SQLCA.SQLCODE < 0 ) then exit else do say 'WARNING - CONTINUING PROGRAM WITH ERRORS' return 0 end end return 0