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


入力 SQLDA プログラムの例

以下に、入力 SQLDA 構造の使用方法を示すサンプル・プログラムを挙げます。クライアント・アプリケーションは、Presidents という名前の表を作成し、その表にデータをロードするストアード・プロシージャーを呼び出します。

このプログラムにより、Presidents という名前の表が SAMPLE データベース内に作成されます。次いで、表中に WashingtonJefferson、および Lincoln という値を挿入します。

ストアード・プロシージャーを使用しないと、このサンプル・プログラムは図 23 に示すように、各 SQL ステートメントを処理するために 4 つの別個の要求でネットワークを経由してデータを伝送するように設計されます。

図 23. ストアード・プロシージャーを使用しない場合の入力 SQLDA の例


ストアード・プロシージャーを使用しない場合の入力 SQLDA の例

これとは異なり、サンプル・プログラムがストアード・プロシージャーの技法を活用して 1 つの要求ですべてのデータをネットワークを経由して伝送する場合には、サーバー・プロシージャーが SQL ステートメントをグループとして実行することが可能になります。この技法は図 24 に示されています。

図 24. ストアード・プロシージャーを使用する場合の入力 SQLDA の例


ストアード・プロシージャーを使用する場合の入力 SQLDA の例

入力 SQLDA クライアント・アプリケーション、および入力 SQLDA ストアード・プロシージャーの例を 入力 SQLDA クライアント・アプリケーション例の動作の仕組みに示します。

入力 SQLDA クライアント・アプリケーション例の動作の仕組み

  1. 入力 SQLDA 構造を初期化する。入力 SQLDA の以下のフィールドが初期化されます。
  2. サーバー・プロシージャーを呼び出す。アプリケーションはデータベース sample の位置から次のステートメントを使用してプロシージャー inpsrv を呼び出します。
    1. CALL ステートメント (ホスト変数指定)
    2. CALL ステートメント (SQLDA 指定)

CHECKERR マクロ / 関数は、プログラム外部にあるエラー検査ユーティリティーです。エラー検査ユーティリティーの所在は、ご使用のプログラミング言語により異なります。

C
DB2 API を呼び出す C プログラムの場合、 utilapi.c 内の sqlInfoPrint 関数は、 utilapi.h 内の API_SQL_CHECK として再定義されます。 C 組み込み SQL プログラムの場合は、 utilemb.sqc 内の sqlInfoPrint 関数は、 utilemb.h 内の EMB_SQL_CHECK として再定義されます。

COBOL
CHECKERRcheckerr.cbl という名前の外部プログラムです。

FORTRAN
CHECKERRutil.f ファイルにあるサブルーチンです。

REXX
CHECKERR は現行プログラムの終わりにあるプロシージャーです。

このエラー検査ユーティリティーのソース・コードについては、 プログラム例での GET ERROR MESSAGE の使用を参照してください。

C の例: V5SPCLI.SQC

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlenv.h>
#include <sqlca.h>
#include <sqlda.h>
#include <sqlutil.h>
#include "util.h"
#define  CHECKERR(CE_STR)   if (check_error (CE_STR, &sqlca) != 0) return 1;
int main(int argc, char *argv[]) {
   EXEC SQL BEGIN DECLARE SECTION;
     char database[9];
     char userid[9];
     char passwd[19];
     char procname[255]  = "inpsrv";
     char table_name[11]    = "PRESIDENTS";
     char data_item0[21]    = "Washington";
     char data_item1[21]    = "Jefferson";
     char data_item2[21]    = "Lincoln";
     short tableind, dataind0, dataind1, dataind2;
   EXEC SQL END DECLARE SECTION;
   /* Declare Variables for CALL USING */
   struct sqlca    sqlca;
   struct sqlda   *inout_sqlda = NULL;
   char eBuffer[1024]; /* error message buffer */
   if (argc != 4) {
      printf ("\nUSAGE: inpcli remote_database userid passwd\n\n");
      return 1;
   }
   strcpy (database, argv[1]);
   strcpy (userid, argv[2]);
   strcpy (passwd, argv[3]);
   /* Connect to Remote Database */
   printf("CONNECT TO Remote Database.\n");
   EXEC SQL CONNECT TO :database USER :userid USING :passwd;
   CHECKERR ("CONNECT TO SAMPLE");
   /********************************************************\
   * Call the Remote Procedure via CALL with Host Variables *
   \********************************************************/
   printf("Use CALL with Host Variable to invoke the Server Procedure"
      " named inpsrv.\n");
   tableind = dataind0 = dataind1 = dataind2 = 0;
   EXEC SQL CALL :procname (:table_name:tableind, :data_item0:dataind0,
      :data_item1:dataind1, :data_item2:dataind2); (2a)
   /* COMMIT or ROLLBACK the transaction */
   if (SQLCODE == 0)
   { EXEC SQL COMMIT;
     printf("Server Procedure Complete.\n\n");
   }
   else
   { /* print the error message, roll back the transaction and return */
     sqlaintp (eBuffer, 1024, 80, &sqlca);
     printf("\n%s\n", eBuffer);
  
     EXEC SQL ROLLBACK;
     printf("Server Procedure Transaction Rolled Back.\n\n");
     return 1;
   }
   /* Allocate and Initialize Input SQLDA */   (1)
   inout_sqlda = (struct sqlda *)malloc( SQLDASIZE(4) );
   inout_sqlda->sqln = 4;
   inout_sqlda->sqld = 4;
   inout_sqlda->sqlvar[0].sqltype = SQL_TYP_NCSTR;
   inout_sqlda->sqlvar[0].sqldata = table_name;
   inout_sqlda->sqlvar[0].sqllen  = strlen( table_name ) + 1;
   inout_sqlda->sqlvar[0].sqlind  = &tableind;
   inout_sqlda->sqlvar[1].sqltype = SQL_TYP_NCSTR;
   inout_sqlda->sqlvar[1].sqldata = data_item0;
   inout_sqlda->sqlvar[1].sqllen  = strlen( data_item0 ) + 1;
   inout_sqlda->sqlvar[1].sqlind  = &dataind0;
   inout_sqlda->sqlvar[2].sqltype = SQL_TYP_NCSTR;
   inout_sqlda->sqlvar[2].sqldata = data_item1;
   inout_sqlda->sqlvar[2].sqllen  = strlen( data_item1 ) + 1;
   inout_sqlda->sqlvar[2].sqlind  = &dataind1;
   inout_sqlda->sqlvar[3].sqltype = SQL_TYP_NCSTR;
   inout_sqlda->sqlvar[3].sqldata = data_item2;
   inout_sqlda->sqlvar[3].sqllen  = strlen( data_item2 ) + 1;
   inout_sqlda->sqlvar[3].sqlind  = &dataind2;
   /***********************************************\
   * Call the Remote Procedure via CALL with SQLDA *
   \***********************************************/
   printf("Use CALL with SQLDA to invoke the Server Procedure named "
      "inpsrv.\n");
   tableind = dataind0 = dataind1 = dataind2 = 0;
   inout_sqlda->sqlvar[0].sqlind  = &tableind;
   inout_sqlda->sqlvar[1].sqlind  = &dataind0;
   inout_sqlda->sqlvar[2].sqlind  = &dataind1;
   inout_sqlda->sqlvar[3].sqlind  = &dataind2;
   EXEC SQL CALL :procname USING DESCRIPTOR :*inout_sqlda;  (2b)
   /* COMMIT or ROLLBACK the transaction */
   if (SQLCODE == 0)
   { EXEC SQL COMMIT;
     printf("Server Procedure Complete.\n\n");
   }
   else
   { /* print the error message, roll back the transaction and return */
     sqlaintp (eBuffer, 1024, 80, &sqlca);
     printf("\n%s\n", eBuffer);
  
     EXEC SQL ROLLBACK;
     printf("Server Procedure Transaction Rolled Back.\n\n");
     return 1;
   }
   /* Free allocated memory */
   free( inout_sqlda );
   /* Drop the PRESIDENTS table created by the stored procedure */
   EXEC SQL DROP TABLE PRESIDENTS;
   CHECKERR("DROP TABLE");
   
   /* Disconnect from Remote Database */
   EXEC SQL CONNECT RESET;
   CHECKERR ("CONNECT RESET");
   return 0;
}
/* end of program : inpcli.sqc */

入力 SQLDA ストアード・プロシージャー例の動作の仕組み

  1. サーバー・プロシージャーを宣言する。サーバー・プロシージャーは、SQLDA および SQLCA 構造へのポインターを受け取ります。
  2. 表を作成する。 SQLDA 構造の最初の SQLVAR に渡されたデータを使用して、 CREATE TABLE ステートメントが構成され、Presidents という名前の表の作成を実行します。
  3. 挿入ステートメントを準備する。パラメーター・マーカー ? を持つ INSERT ステートメントが準備されます。
  4. データを挿入する。直前に準備された INSERT ステートメントは、SQLDA 構造の 2〜4 番目の SQLVAR に渡されたデータを使用して実行します。パラメーター・マーカーは WashingtonJeffersonLincoln の値に置き換えられます。これらの値が Presidents 表に挿入されます。
  5. クライアント・アプリケーションに戻す。サーバー・プロシージャーはこの SQLCA をクライアント・アプリケーションの SQLCA に複写し、トランザクションが正常に終了した場合に COMMIT ステートメントを発行して、値 SQLZ_DISCONNECT_PROC を戻し、サーバー・プロシージャーからの呼び出しがこれ以上はないことを知らせます。

注:サーバー・プロシージャーは、AIX システム上では REXX で作成することはできません。

C の例: V5SPSRV.SQC

#include <memory.h>
#include <string.h>
#include <sqlenv.h>
#include <sqlutil.h>
#ifdef __cplusplus
extern "C"
#endif
SQL_API_RC SQL_API_FN inpsrv(void *reserved1,      (1)
           void *reserved2,
           struct sqlda   *inout_sqlda,
           struct sqlca   *ca)
{
   /* Declare a local SQLCA */
   EXEC SQL INCLUDE SQLCA;
   /* Declare Host Variables */
   EXEC SQL BEGIN DECLARE SECTION;
     char table_stmt[80]  = "CREATE TABLE ";
     char insert_stmt[80] = "INSERT INTO ";
     char insert_data[21];
   EXEC SQL END DECLARE SECTION;
   /* Declare Miscellanous Variables */
   int  cntr = 0;
   char *table_name;
   char *data_items[3];
   short  data_items_length[3];
   int  num_of_data = 0;
   /*-----------------------------------------------------------------*/
   /* Assign the data from the SQLDA to local variables so that we    */
   /* don't have to refer to the SQLDA structure further.  This will  */
   /* provide better portability to other platforms such as DB2 MVS   */
   /* where they receive the parameter list differently.              */
   /*-----------------------------------------------------------------*/
   table_name  = inout_sqlda->sqlvar[0].sqldata;
   num_of_data = inout_sqlda->sqld - 1;
   for (cntr = 0; cntr < num_of_data; cntr++)
   {
      data_items[cntr] = inout_sqlda->sqlvar[cntr+1].sqldata;
      data_items_length[cntr] = inout_sqlda->sqlvar[cntr+1].sqllen;
   }
   /*-----------------------------------------------------------------*/
   /* Create President Table                                          */
   /* - For simplicity, we'll ignore any errors from the              */
   /*   CREATE TABLE so that you can run this program even when the   */
   /*   table already exists due to a previous run.                   */
   /*-----------------------------------------------------------------*/
   EXEC SQL WHENEVER SQLERROR CONTINUE;
   strcat(table_stmt, table_name);
   strcat(table_stmt, " (name CHAR(20))");  (2)
   EXEC SQL EXECUTE IMMEDIATE :table_stmt;
   EXEC SQL WHENEVER SQLERROR GOTO ext;
   /*-----------------------------------------------------------------*/
   /* Generate and execute a PREPARE for an INSERT statement, and     */
   /* then insert the three presidents.                               */
   /*-----------------------------------------------------------------*/
   strcat(insert_stmt, table_name );
   strcat(insert_stmt, "  VALUES (?)");  (3)
   EXEC SQL PREPARE S1 FROM :insert_stmt;
   for (cntr = 0; cntr < num_of_data; cntr++)
   {
      strncpy(insert_data, data_items[cntr], data_items_length[cntr]);
      insert_data[data_items_length[cntr]] = '\0';
      EXEC SQL EXECUTE S1 USING :insert_data;  (4)
   }
   /*-----------------------------------------------------------------*/
   /* Return to caller                                                */
   /*   -  Copy the SQLCA                                             */
   /*   -  Update the output SQLDA.  Since there's no output to       */
   /*      return, we are setting the indicator values to -128 to     */
   /*      return only a null value.                                  */
   /*-----------------------------------------------------------------*/
ext:  (5)
   memcpy(ca, &sqlca, sizeof(struct sqlca));
   if (inout_sqlda != NULL)
   {
     for (cntr = 0; cntr < inout_sqlda->sqld; cntr++)
     {
       *(inout_sqlda->sqlvar[cntr].sqlind) = -128;
     }
   }
   return(SQLZ_DISCONNECT_PROC);
}


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