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


ストアード・プロシージャーからの結果セットの戻り

DB2 CLI、ODBC、JDBC、または SQLJ クライアント・アプリケーションに 1 つまたは複数の結果セットを戻すように、ストアード・プロシージャーをコーディングすることができます。このサポートには以下のものが含まれます。

結果セットの処理についての追加情報は、以下を参照してください。

例: ストアード・プロシージャーからの結果セットを戻す

このストアード・プロシージャーの例では、以下のサポートされている言語で結果セットをクライアント・アプリケーションに戻す方法を示しています。

C
spserver.sqc

Java
Spserver.java

このストアード・プロシージャーの例は、 IN パラメーターを 1 つ受け入れ、 OUT パラメーター 1 つと結果セット 1 つを戻します。ストアード・プロシージャーでは IN パラメーターが使用されて、 STAFF 表で SALARY が IN パラメーターよりも大きい行の NAME、 JOB、SALARY 列の値を含む結果セットが作成されます。

(1)
CREATE PROCEDURE ステートメントの DYNAMIC RESULT SETS 文節を使用して、ストアード・プロシージャーを登録します。たとえば、C の組み込み SQL で作成されたストアード・プロシージャーを登録するには、以下のようなステートメントを発行します。

   CREATE PROCEDURE RESULT_SET_CLIENT
      (IN salValue DOUBLE, OUT sqlCode INTEGER)
      DYNAMIC RESULT SETS 1
      LANGUAGE C
      PARAMETER STYLE GENERAL
      NO DBINFO
      FENCED
      READS SQL DATA
      PROGRAM TYPE SUB
      EXTERNAL NAME 'spserver!one_result_set_to_client'

(2)
C ストアード・プロシージャーの組み込み SQL では、 DECLARE CURSOR および OPEN CURSOR ステートメントを使用してオープン・カーソルを作成します。 CLI ストアード・プロシージャーでは、 SQLPrepare および SQLBindParameter API を使用して結果セットを作成します。 JDBC で作成された Java のストアード・プロシージャーでは、 prepareStatement および executeQuery メソッドを使用して結果セットを作成します。

(3)
カーソルまたは結果セットをクローズせずにデータベースへの接続をクローズします。このステップは、 C のストアード・プロシージャーの組み込み SQL には、適用されません。

(4)
Java ストアード・プロシージャー: PARAMETER STYLE JAVA ストアード・プロシージャーが戻す結果セットごとに、それに対応する ResultSet[] 引き数をストアード・プロシージャー方式のシグニチャーに含める必要があります。

C の例: SPSERVER.SQC (one_result_set_to_client)

  SQL_API_RC SQL_API_FN one_result_set_to_client
    (double *insalary, sqlint32 *out_sqlerror)
  {
    EXEC SQL INCLUDE SQLCA;
    EXEC SQL WHENEVER SQLERROR GOTO return_error;
    l_insalary = *insalary;
    *out_sqlerror = 0;
    EXEC SQL DECLARE c3 CURSOR FOR      (2)
      SELECT name, job, CAST(salary AS INTEGER)
      FROM staff
      WHERE salary > :l_insalary
      ORDER BY salary;
    EXEC SQL OPEN c3;                   (2)
    /* Leave cursor open to return result set */
    return (0);   (3)
    /* Copy SQLCODE to OUT parameter if SQL error occurs */
  return_error:
    {
      *out_sqlerror = SQLCODE;
      EXEC SQL WHENEVER SQLERROR CONTINUE;
      return (0);
    }
  } /* end one_result_set_to_client function */

Java の例: Spserver.java (resultSetToClient)

   public static void resultSetToClient
        (double inSalaryThreshold, // double input
         int[] errorCode,            // SQLCODE output
         ResultSet[] rs)             // ResultSet output (4)
         throws SQLException
   {
      errorCode[0] = 0; // SQLCODE = 0 unless SQLException occurs
      try {
         // Get caller's connection to the database
         Connection con =
           DriverManager.getConnection("jdbc:default:connection");
         // get salary result set using a parameter marker
         String query = "SELECT name, job, CAST(salary AS DOUBLE) " +
                 "FROM staff " +
                 "WHERE salary > ? " +
                 "ORDER BY salary";
         // prepare the SQL statement
         PreparedStatement stmt = con.prepareStatement(query);
         // set the value of the parameter marker (?)
         stmt.setDouble(1, inSalaryThreshold);
         // get the result set that will be returned to the client
         rs[0] = stmt.executeQuery(); (2)
         // to return a result set to the client, do not close ResultSet
         con.close(); (3)
      }
      catch (SQLException sqle)
      { 
         errorCode[0] = sqle.getErrorCode();
      }
   }

例: ストアード・プロシージャーからの結果セットを受け入れる

このクライアント・アプリケーションの例では、以下のサポートされている言語でストアード・プロシージャーからの結果セットを受け入れる方法が示されています。

C (CLI を使用)
spclient.c

Java
Spclient.java

このクライアント・アプリケーションの例は、 RESULT_SET_CLIENT ストアード・プロシージャーを呼び出し、 1 つの結果セットを受け入れます。それから、クライアント・アプリケーションは結果セットの内容を表示します。

(1)
CREATE PROCEDURE ステートメントで宣言したパラメーターに対応する引き数を指定したストアード・プロシージャーを呼び出します。

(2)
JDBC アプリケーションは、getNextResultSet メソッドを使用して、ストアード・プロシージャーの最初の結果セットを受け入れます。

(3)
結果セットから行を取り出します。 CLI クライアントの例では、 while ループを使用して結果セットのすべての行を取り出して表示しています。 JDBC クライアントの例は、結果セットのすべての行を取り出して表示する fetchAll というクラス方式を呼び出します。

CLI の例: SPCLIENT.C (one_result_set_to_client)
  #include <stdio.h>
  #include <string.h>
  #include <stdlib.h>
  #include <sqlcli1.h>
  #include <sqlca.h>
  #include "utilcli.h"          /* Header file for CLI sample code */
       SQLCHAR      stmt[50];
       SQLINTEGER   out_sqlcode;
       char         out_buffer[33];
       SQLINTEGER   indicator;
       struct sqlca sqlca;
       SQLRETURN    rc,rc1  ;
       char         procname[254];
       SQLHANDLE    henv;  /* environment handle */
       SQLHANDLE    hdbc;  /* connection handle */
       SQLHANDLE    hstmt1; /* statement handle */
       SQLHANDLE    hstmt2; /* statement handle */
       SQLRETURN    sqlrc = SQL_SUCCESS;
       double out_median;
       int oneresultset1(SQLHANDLE);
  int main(int argc, char *argv[])
   {
       SQLHANDLE    hstmt; /* statement handle */
       SQLHANDLE    hstmt_oneresult; /* statement handle */
       char         dbAlias[SQL_MAX_DSN_LENGTH + 1] ;
       char         user[MAX_UID_LENGTH + 1] ;
       char         pswd[MAX_PWD_LENGTH + 1] ;
       /* Declare  variables for passing data to INOUT_PARAM */
       double inout_median;
      /* checks the command line arguments */
       rc = CmdLineArgsCheck1( argc, argv, dbAlias, user, pswd );
       if ( rc != 0 )  return( 1 ) ;
      /* allocate an environment handle */
      printf("\n    Allocate an environment handle.\n");
      sqlrc = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
      if ( sqlrc != SQL_SUCCESS )
      {   printf( "\n--ERROR while allocating the environment handle.\n" ) ;
          printf( "  sqlrc             = %d\n", sqlrc);
          printf( "  line              = %d\n", __LINE__);
          printf( "  file              = %s\n", __FILE__);	
          return( 1 ) ;
      }
      /* allocate a database connection handle */
      printf("    Allocate a database connection handle.\n");
      sqlrc = SQLAllocHandle( SQL_HANDLE_DBC, henv, &hdbc ) ;
      HANDLE_CHECK( SQL_HANDLE_ENV, henv, sqlrc, &henv, &hdbc ) ;
      /* connect to the database */
      printf( "    Connecting to the database %s ...\n", dbAlias ) ;
      sqlrc = SQLConnect( hdbc,
                       (SQLCHAR *)dbAlias, SQL_NTS,
                       (SQLCHAR *)user, SQL_NTS,
                       (SQLCHAR *)pswd, SQL_NTS
                     ) ;
      HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, sqlrc, &henv, &hdbc ) ;
      printf( "    Connected to the database %s.\n", dbAlias ) ;
      /* set AUTOCOMMIT off */
      sqlrc = SQLSetConnectAttr( hdbc,
                                 SQL_ATTR_AUTOCOMMIT,
                                 SQL_AUTOCOMMIT_OFF, SQL_NTS) ;
      HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, sqlrc, &henv, &hdbc ) ;
      /* allocate one or more statement handles */
      printf("    Allocate a statement handle.\n");
      sqlrc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt ) ;
      HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, sqlrc, &henv, &hdbc ) ;
      sqlrc = SQLAllocHandle( SQL_HANDLE_STMT, hdbc, &hstmt_oneresult ) ;
      HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, sqlrc, &henv, &hdbc ) ;
     /********************************************************\
     * Call oneresultsettocaller stored procedure             *
     \********************************************************/
      rc = oneresultset1(hstmt_oneresult);
      rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt_oneresult ) ;
      HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
      /* ROLLBACK, free resources, and exit */
       rc = SQLEndTran( SQL_HANDLE_DBC, hdbc, SQL_COMMIT ) ;
       HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
       printf("\nStored procedure rolled back.\n\n");
      /* Disconnect from Remote Database */
       rc = SQLFreeHandle( SQL_HANDLE_STMT, hstmt ) ;
       HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
       printf( "\n>Disconnecting .....\n" ) ;
       rc = SQLDisconnect( hdbc ) ;
       HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
       rc = SQLFreeHandle( SQL_HANDLE_DBC, hdbc ) ;
       HANDLE_CHECK( SQL_HANDLE_DBC, hdbc, rc, &henv, &hdbc ) ;
       rc = SQLFreeHandle( SQL_HANDLE_ENV,  henv ) ;
       if ( rc != SQL_SUCCESS ) return( SQL_ERROR )  ;
       return( SQL_SUCCESS ) ;
  }
       int oneresultset1(hstmt)
       SQLHANDLE    hstmt; /* statement handle */
     {
     /********************************************************\
     * Call one_result_set_to_client stored procedure         *
     \********************************************************/
      double          insalary = 20000;
      SQLINTEGER      salary_int;
      SQLSMALLINT     num_cols;
      char            name[40];
      char            job[10];
      strcpy(procname, "RESULT_SET_CALLER");                                (1)
      printf("\nCALL stored procedure:  %s\n", procname);
      strcpy((char*)stmt,"CALL RESULT_SET_CALLER ( ?,? )");
      rc = SQLPrepare(hstmt, stmt, SQL_NTS);
      STMT_HANDLE_CHECK( hstmt, rc);
      /* Bind the parameter to application variables () */
      rc = SQLBindParameter(hstmt, 1,
                           SQL_PARAM_INPUT, SQL_C_DOUBLE,
                           SQL_DOUBLE,0,
                           0, &insalary,
                           0, NULL);
      rc = SQLBindParameter(hstmt, 2,
                           SQL_PARAM_OUTPUT, SQL_C_LONG,
                           SQL_INTEGER,0,
                           0, &out_sqlcode,
                           0, NULL);
      STMT_HANDLE_CHECK( hstmt, rc);
      rc = SQLExecute(hstmt);
      rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
      STMT_HANDLE_CHECK( hstmt, rc);
      rc = SQLNumResultCols( hstmt, &num_cols ) ;
      STMT_HANDLE_CHECK( hstmt, rc);
      printf("Result set returned %d columns\n", num_cols);
      /* bind columns to variables */
      rc = SQLBindCol( hstmt, 1, SQL_C_CHAR, name, 40, &indicator);
      STMT_HANDLE_CHECK( hstmt, rc);
      rc = SQLBindCol( hstmt, 2, SQL_C_CHAR, job, 10, &indicator);
      STMT_HANDLE_CHECK( hstmt, rc);
      rc = SQLBindCol( hstmt, 3, SQL_C_LONG, &salary_int, 0, &indicator);
      STMT_HANDLE_CHECK( hstmt, rc);
      /* fetch result set returned from stored procedure */
      rc = SQLFetch( hstmt );                                               (2)
      rc1 = SQLGetSQLCA(henv, hdbc, hstmt, &sqlca);
      STMT_HANDLE_CHECK( hstmt, rc);
      printf("\n--------Name---------,  --JOB--, ---Salary--  \n");
      while (rc  == SQL_SUCCESS && rc != SQL_NO_DATA_FOUND )                 (3)
      {
      printf("%20s,%10s,    %d\n",name,job,salary_int);
      rc = SQLFetch( hstmt );
      }
   
      STMT_HANDLE_CHECK( hstmt, rc);
     /* Check that the stored procedure executed successfully */
      if (rc == SQL_SUCCESS) {
       printf("Stored procedure returned successfully.\n");
       }
       else {
       printf("Stored procedure returned SQLCODE %d\n", out_sqlcode);
       }
      rc = SQLCloseCursor(hstmt);
      return(rc);
  }

Java の例: Spclient.java (resultSetToClient)
         // prepare the CALL statement for RESULT_SET_CLIENT
         procName = "RESULT_SET_CLIENT";
         sql = "CALL " + procName + "(?, ?)"; (1)
         callStmt = con.prepareCall(sql);
         // set input parameter to median value passed back by OUT_PARAM
         callStmt.setDouble (1, outMedian);
         // register the output parameter
         callStmt.registerOutParameter (2, Types.INTEGER);
         // call the stored procedure
         System.out.println ("\nCall stored procedure named " + procName);
         callStmt.execute();
         // retrieve output parameter
         outErrorCode = callStmt.getInt(2);
         if (outErrorCode == 0) {
            System.out.println(procName + " completed successfully");
            ResultSet rs = callStmt.getResultSet(); (2)
            while (rs.next()) {
               fetchAll(rs); (3)
            }
            // close ResultSet
            rs.close();
         }
         else  { // stored procedure failed
            System.out.println(procName + " failed with SQLCODE "
              + outErrorCode);
         }

問題の解決

ストアード・プロシージャー・アプリケーションが適正に実行されない場合には、以下のことを確認してください。

注:Java ストアード・プロシージャーのデバッグの詳細については、 Java でのストアード・プロシージャーのデバッグを参照してください。

コンパイラーに付属するデバッガーを使用して、他のアプリケーションと同じようにローカルな FENCED ストアード・プロシージャーをデバッグできます。提供されるデバッガーの使用法については、コンパイラーの資料をご覧ください。

たとえば、Windows NT 上の Visual Studio(TM) に付属するデバッガーを使用するには、以下のステップを実行してください。

ステップ 1.

DB2_STPROC_ALLOW_LOCAL_FENCED レジストリー変数を true に設定する。

ステップ 2.

-Zi および -Od フラグを指定して、ストアード・プロシージャー DLL のソース・ファイルをコンパイルし、 -DEBUG オプションを使ってその DLL をリンクする。

ステップ 3.

作成された DLL をサーバーの instance_name \function ディレクトリーに複写する。

ステップ 4.

Visual Studio デバッガーを使って、サーバー上のクライアント・アプリケーションを呼び出す。クライアント・アプリケーション outcli.exe の場合は、次のコマンドを入力します。

   msdev spclient.exe

ステップ 5.

「Visual Studio デバッガー (Visual Studio debugger)」ウィンドウがオープンしたら、 「プロジェクト (Project)」-->「設定 (Settings)」を選択する。

ステップ 6.

デバッグ (Debug)」タブをクリックする。

ステップ 7.

カテゴリ (Category)」の矢印をクリックして、「追加の DLL (Additional DLLs)」を選択する。

ステップ 8.

新規 (New)」ボタンをクリックして、新規モジュールを作成する。

ステップ 9.

ブラウズ (Browse)」ボタンをクリックして、「ブラウズ (Browse)」ウィンドウをオープンする。

ステップ 10.

モジュール spserver.dll を選択して、「OK」をクリックし、「設定 (Settings)」ウィンドウをクローズする。

ステップ 11.

ストアード・プロシージャーのソース・ファイルをオープンして、ブレークポイントを設定する。

ステップ 12.

「実行 (Go)」ボタンをクリックする。ストアード・プロシージャーが呼び出されると、Visual Studio デバッガーは停止します。

ステップ 13.

この時点で、Visual Studio デバッガーを使って、ストアード・プロシージャーをデバッグすることができます。

Visual Studio デバッガーの使用に関する詳細については、 Visual Studio の製品資料を参照してください。


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