アプリケーション開発の手引き

診断処理と SQLCA 構造

SQL ステートメントを発行し、データベース・マネージャー API を呼び出すアプリケーションには、戻りコードと SQLCA 構造を検査しエラー条件を正確に調べることが求められます。

戻りコード

ほとんどのデータベース・マネージャーは処理が正常であれば、ゼロの戻りコードを戻します。一般に、ゼロ以外の戻りコードは、 2 次エラー処理機構の SQLCA 構造が破壊された可能性があることを示します。この場合、呼び出された API は実行されません。 SQLCA 構造が破壊される原因として、構造に対して無効なアドレスを渡したことが考えられます。

SQLCODE および SQLSTATE

エラー情報は、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 サーバーにアクセスするアプリケーションを開発する場合は、以下のようにしてください。
  • 可能な時点で、アプリケーションが SQLCODE ではなく SQLSTATE を検査するようにする。
  • アプリケーションが DB2 コネクトを使用する場合は、 DB2 コネクトに付属しているマッピング機能を用いて、異なるデータベース間の SQLCODE 変換をマップする。

SQLCA 構造におけるトークンの切り捨て

SQLCA 構造ではトークンが切り捨てられることがあるため、診断目的ではトークン情報を使用しないでください。表および列の名前は最高 128 バイトの長さで定義できますが、 SQLCA トークンは、17 バイトと切り捨て終止符 (>) を加えた長さで切り捨てられます。アプリケーションのロジックは、 sqlerrmc フィールドの実際の値によって決めるべきではありません。 SQLCA 構造およびトークンの切り捨ての説明については、SQL 解説書 を参照してください。

WHENEVER ステートメントを用いたエラー処理

WHENEVER ステートメントがあると、プリコンパイラーは、実行中にエラー、警告、または行が見つからないなどの状態が起こった場合にアプリケーションに指定のラベルまで進むように指示するソース・コードを生成します。 WHENEVER ステートメントは、別の WHENEVER ステートメントが状況を変更するまで、後続の実行可能 SQL ステートメントに影響を与えます。

WHENEVER ステートメントには以下の 3 つの基本形式があります。

     EXEC SQL WHENEVER SQLERROR   action
     EXEC SQL WHENEVER SQLWARNING action
     EXEC SQL WHENEVER NOT FOUND  action

上記のステートメントについて説明します。

SQLERROR
SQLCODE < 0 である状態を示します。

SQLWARNING
SQLWARN(0) = W または SQLCODE > 0 ですが、 100 ではない状態を示します。

NOT FOUND
SQLCODE = 100 である状態を識別します。

いずれの場合も、action は以下のどちらかになります。

CONTINUE
アプリケーションの次の命令を続行するよう指示します。

GO TO label
GO TO の後に指定されたラベルの直後のステートメントに進むように指示します。 (GO TO は、2 つの語とすることも、GOTO として 1 つの語とすることもできます。)

WHENEVER ステートメントを使用しない場合、実行中にエラー、警告、または例外状態が起こると、省略時のアクションとして処理が継続されることになります。

WHENEVER ステートメントは、影響を及ぼす SQL ステートメントの前に指定しなければなりません。そうしないと、プリコンパイラーは実行可能 SQL ステートメント用に余分のエラー処理コードを生成しなければならないことを認識しません。 3 つの基本形式はいつでも任意に組み合わせて活動状態にすることができます。これら 3 つの形式の宣言順序は重要ではありません。無限ループ状態を避けるには、SQL ステートメントをハンドラー内部で実行する前に、 WHENEVER 処理が取り消されていることを確認してください。 WHENEVER SQLERROR CONTINUE ステートメントを使用すれば、 SQL ステートメントをハンドラー内部で実行することができます。

WHENEVER ステートメントの詳細な説明については、 SQL 解説書 を参照してください。

例外、シグナル、割り込みハンドラーについての考慮事項

例外、シグナル、または割り込みハンドラーは、例外が起きたときに制御を獲得するルーチンです。ここで適用されるハンドラーのタイプは、操作環境によって異なります。以下のとおりです。

Windows 32 ビットのオペレーティング・システム
Ctrl-C または Ctrl-Break を押すことにより、割り込みが生成されます。

OS/2
Ctrl-C または Ctrl-Break を押すことにより、オペレーティング・システム例外が生成されます。

UNIX
通常、Ctrl-C を押すと SIGINT 割り込みシグナルが生成されます。キーボードは簡単に再定義できるため、 SIGINT はマシン上のさまざまなキー順序で生成される場合があることに注意してください。

上記のリストにないオペレーティング・システムについては、 アプリケーション構築の手引き を参照してください。

例外、シグナル、および割り込みハンドラーの中には 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 呼び出しを使用しないでください。出口ルーチンの中ではデータベースから切断することはできないことに注意してください。

プログラム例での GET ERROR MESSAGE の使用

C の例: UTILAPI.C および COBOL の例: CHECKERR.CBLで示しているコード・クリップは、渡される SQLCA に関する情報を GET ERROR MESSAGE API を使って得る方法について説明しています。

これらの例の作成に関する情報は、 README ファイルまたはこれらのサンプル・プログラムのヘッダー・セクションで見ることができます。

C の例: UTILAPI.C

#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") ;
    }		
    
}

Java の例: SQLException のキャッチ

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 値を参照してください。

COBOL の例: CHECKERR.CBL

       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.

REXX の例: CHECKERR プロシージャー

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


[ ページのトップ | 前ページ | 次ページ | 目次 | 索引 ]