CLI の手引きおよび解説書

CLI の非同期実行

DB2 CLI は、非同期に関数のサブセットを実行可能です。DB2 CLI ドライバーは、関数を呼び出した後アプリケーションに制御を戻しますが、その関数が実行を完了する前にこのことが行われます。実行が完了するまでは、関数は呼び出されるたびに SQL_STILL_EXECUTING を戻します。完了の時点では、別の値 (たとえば、SQL_SUCCESS) を戻します。

非同期実行は、単一スレッドのオペレーティング・システムでのみ有益です。マルチスレッドのオペレーティング・システムで実行するアプリケーションは、その代わりに、分離スレッドで関数を実行すべきです。

非同期実行は、通常要求をサーバーに送信し、そして応答を待つ関数で可能となります。非同期に実行している関数は、待つのではなく、アプリケーションに制御を戻します。その後、アプリケーションは他のタスクを実行したり、オペレーティング・システムに制御を戻すこともできます。そして、SQL_STILL_EXECUTING 以外の戻りコードが返されるまで、割り込みを用いてその関数を繰り返しポーリングします。

典型的な非同期アプリケーション

非同期に関数を実行する各アプリケーションは、通常の CLI ステップに加えて以下のステップをその順序に従って完了する必要があります。

1. 環境のセットアップ

関数を非同期に確実に呼び出すには、アプリケーションは SQL_ASYNC_MODE のオプションを指定した SQLGetInfo() を呼び出します。

    /* See what type of Asynchronous support is available. */
    rc = SQLGetInfo( hdbc, /* Connection handle */
                     SQL_ASYNC_MODE, /* Query the support available */
                     &ubuffer, /* Store the result in this variable */
                     4,
                     &outlen);

SQLGetInfo() への呼び出しでは、以下の値のうちの 1 つが戻されます。

SQL_AM_STATEMENT - ステートメント・レベル
非同期実行をステートメント・レベルでオン / オフできるということを示します。

ステートメント・レベルの非同期実行は、ステートメント属性 SQL_ATTR_ASYNC_ENABLE を使用して設定されます。アプリケーションは、多くて 1 つの活動状態の関数を任意の 1 つの接続において非同期モードで実行させることができます。 SQLSetStmtAttr() を使用して、SQL_ASYNC_ENABLE_ON に設定してください。

    /* Set statement level asynchronous execution on */
    rc = SQLSetStmtAttr( hstmt, /* Statement handle */
                         SQL_ATTR_ASYNC_ENABLE,
                         (SQLPOINTER) SQL_ASYNC_ENABLE_ON,
                         0);

SQL_AM_CONNECTION - 接続レベル
DB2 ユニバーサル・データベースは SQL_AM_STATEMENT をサポートしますが、その他のデータ・ソースにより SQL_AM_CONNECTION が戻される可能性があります。接続におけるすべてのステートメントが、同じ方法で実行されることを示します。

接続レベルの非同期実行は、接続属性 SQL_ATTR_ASYNC_ENABLE を使用して設定されます。 SQLSetConnectAttr() を使用して、 SQL_ASYNC_ENABLE_ON に設定してください。

すでに割り当てられているすべてのステートメントは、この接続にこれから割り当てられるステートメント・ハンドルと同様に、非同期実行で使用可能です。

SQL_AM_NONE - 非同期実行がサポートされない
これは次の 2 つのいずれかの理由で戻されます。
  1. データ・ソースそのものが、非同期実行をサポートしない。
  2. DB2 CLI/ODBC の構成キーワード ASYNCENABLE が、非同期実行できないように明確に設定されている。詳細については、ASYNCENABLE を参照してください。

どちらの場合でも、関数は同期的に実行されます。アプリケーションが、 SQLSetStmtAttr() または SQLSetConnectAttr() を呼び出し、非同期実行をオンにする場合、 SQLSTATE として 01S02 (オプション値が変更された) が戻されます。

2. 非同期実行をサポートする関数の呼び出し

アプリケーションが非同期に実行される関数を呼び出すとき、次の 2 つの事柄のいずれかが生じます。

SQLSetStmtAttr() 関数の SQL_ATTR_ASYNC_ENABLE ステートメント属性を検査し、非同期に実行される関数のリストがあるかどうかを調べます。

以下の例では、両方の考えられる結果を考慮に入れた共通の while ループを例示しています。

while ( (rc = SQLExecDirect(hstmt, sqlstmt, SQL_NTS) ) == SQL_STILL_EXECUTING)
{
    /* Other processing can be performed here, between each call to
     * see if SQLExecDirect() has finished running asynchronously.
     * This section will never run if CLI runs the function
     * synchronously.
     */
}
/* The application continues at this point when SQLExecDirect() */
/* has finished running. */

3. 他の関数呼び出し間の非同期関数のポーリング

アプリケーションは、最初に関数を呼び出すために使用したのと同じ引き数を指定して繰り返し呼び出すことで、関数が終了したかどうかを判別します。戻りコード SQL_STILL_EXECUTING は、関数がまだ終了していないことを表し、その他の値はすでに終了したことを示します。 SQL_STILL_EXECUTING 以外の値は、関数が同期的に実行した場合に戻されるのと同じ戻りコードです。

非同期実行の間に呼び出せる関数

以下の関数は、ある関数が非同期に実行されている間に呼び出し可能です。他のすべての関数は、SQLSTATE として HY010 (関数順序エラー) を戻します。

4. 実行中の診断情報

SQLGetDiagField() が非同期関数を実行しているステートメント・ハンドル上に呼び出されるとき、以下の値が戻されます。

SQLGetDiagRec() は、非同期関数を実行しているステートメント・ハンドル上に呼び出されるとき、常に SQL_NO_DATA を戻します。

5. 非同期関数呼び出しの取り消し

アプリケーションは、 SQLCancel() を呼び出して非同期に実行しているすべての関数の取り消し要求を発行することができます。しかし、場合によってはこの要求が実行されないこともあります (たとえば、関数がすでに終了している場合)。

SQLCancel() 呼び出しからの戻りコードは、取り消し要求が受信されたかどうかを示します。非同期関数の実行が停止したかどうかを示すのではありません。

関数が取り消されたかどうかを知らせる唯一の方法は、元の引き数を使用して、再度関数を呼び出すことです。

サンプルの非同期アプリケーション

以下の CLI サンプル async.c は、非同期に SQLExecDirect() を実行する簡単なアプリケーションを例示しています。これは、CLI のサンプル・プログラム fetch.c に基づいています。

/* ... */
    /* Make the result from SQLGetInfo() more meaningful by mapping */
    /* the returned value to the string. */
    static char ASYNCMODE[][19] =  {  "SQL_AM_NONE", 
                                      "SQL_AM_CONNECTION", 
                                      "SQL_AM_STATEMENT" };
/* ... */
     * See what type of Asynchronous support is available,
     * and whether or not the CLI/ODBC configuration keyword ASYNCENABLE
     * is set on or off.
     */
    rc = SQLGetInfo( hdbc, /* Connection handle */
                     SQL_ASYNC_MODE, /* Query the support available */
                     &ubuffer, /* Store the result in this variable */
                     4,
                     &outlen);
    CHECK_STMT(hstmt, rc);
    printf("SQL_ASYNC_MODE value from SQLGetInfo() is %s.\n\n",
            ASYNCMODE[ubuffer]);
    if (ubuffer == SQL_AM_NONE ) { /* Async not supported */
       printf("Asynchronous execution is not supported by this datasource\n");
       printf("or has been turned off by the CLI/ODBC configuration keyword\n");
       printf("ASYNCENABLE. The application will continue, but\n");
       printf("SQLExecDirect() will not be run asynchronously.\n\n");
       /* There is no need to set the SQLSetStmtAttr() option */
    } else {
       /* Set statement level asynchronous execution on */
       rc = SQLSetStmtAttr(
                hstmt,
                SQL_ATTR_ASYNC_ENABLE,
                (SQLPOINTER) SQL_ASYNC_ENABLE_ON,
                0);
       CHECK_STMT(hstmt, rc);
    }
    /* The while loop is new for the asynchronous sample, the */
    /* SQLExecDirect() call remains the same. */
    while ((rc = SQLExecDirect(hstmt, sqlstmt, SQL_NTS) ) == SQL_STILL_EXECUTING) {
       printf("   ...SQLExecDirect() still executing asynchronously...\n");
       /* Other processing can be performed here, between each call
        * to see if SQLExecDirect() has finished running asynchronously.
        * This section will never run if CLI runs the function
        * synchronously.
        */
   }
    CHECK_STMT(hstmt, rc);
    rc = SQLBindCol(hstmt, 1, SQL_C_CHAR, (SQLPOINTER) deptname.s, 15,
                    &deptname.ind);
    CHECK_STMT(hstmt, rc);
    rc = SQLBindCol(hstmt, 2, SQL_C_CHAR, (SQLPOINTER) location.s, 15,
                    &location.ind);
    CHECK_STMT(hstmt, rc);
    printf("Departments in Eastern division:\n");
    printf("DEPTNAME       Location\n");
    printf("-------------- -------------\n");
    while ((rc = SQLFetch(hstmt)) == SQL_SUCCESS) {
        printf("%-14.14s %-14.14s \n", deptname.s, location.s);
    }
    if (rc != SQL_NO_DATA_FOUND)
        check_error(henv, hdbc, hstmt, rc, __LINE__, __FILE__);
    rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
    CHECK_STMT(hstmt, rc);
    rc = SQLEndTran(SQL_HANDLE_ENV, henv, SQL_COMMIT);
    CHECK_DBC(hdbc, rc);
    printf("Disconnecting .....\n");
    rc = SQLDisconnect(hdbc);
    CHECK_DBC(hdbc, rc);
    rc = SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
    CHECK_DBC(hdbc, rc);
    rc = SQLFreeHandle(SQL_HANDLE_ENV, henv);
    if (rc != SQL_SUCCESS)
        return (terminate(henv, rc));
}                               /* end main */
 


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