DB2 CLI は、非同期に関数のサブセットを実行可能です。DB2 CLI ドライバーは、関数を呼び出した後アプリケーションに制御を戻しますが、その関数が実行を完了する前にこのことが行われます。実行が完了するまでは、関数は呼び出されるたびに SQL_STILL_EXECUTING を戻します。完了の時点では、別の値 (たとえば、SQL_SUCCESS) を戻します。
非同期実行は、単一スレッドのオペレーティング・システムでのみ有益です。マルチスレッドのオペレーティング・システムで実行するアプリケーションは、その代わりに、分離スレッドで関数を実行すべきです。
非同期実行は、通常要求をサーバーに送信し、そして応答を待つ関数で可能となります。非同期に実行している関数は、待つのではなく、アプリケーションに制御を戻します。その後、アプリケーションは他のタスクを実行したり、オペレーティング・システムに制御を戻すこともできます。そして、SQL_STILL_EXECUTING 以外の戻りコードが返されるまで、割り込みを用いてその関数を繰り返しポーリングします。
非同期に関数を実行する各アプリケーションは、通常の CLI ステップに加えて以下のステップをその順序に従って完了する必要があります。
関数を非同期に確実に呼び出すには、アプリケーションは 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_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_ATTR_ASYNC_ENABLE を使用して設定されます。 SQLSetConnectAttr() を使用して、 SQL_ASYNC_ENABLE_ON に設定してください。
すでに割り当てられているすべてのステートメントは、この接続にこれから割り当てられるステートメント・ハンドルと同様に、非同期実行で使用可能です。
どちらの場合でも、関数は同期的に実行されます。アプリケーションが、 SQLSetStmtAttr() または SQLSetConnectAttr() を呼び出し、非同期実行をオンにする場合、 SQLSTATE として 01S02 (オプション値が変更された) が戻されます。
アプリケーションが非同期に実行される関数を呼び出すとき、次の 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. */
アプリケーションは、最初に関数を呼び出すために使用したのと同じ引き数を指定して繰り返し呼び出すことで、関数が終了したかどうかを判別します。戻りコード SQL_STILL_EXECUTING は、関数がまだ終了していないことを表し、その他の値はすでに終了したことを示します。 SQL_STILL_EXECUTING 以外の値は、関数が同期的に実行した場合に戻されるのと同じ戻りコードです。
非同期実行の間に呼び出せる関数
以下の関数は、ある関数が非同期に実行されている間に呼び出し可能です。他のすべての関数は、SQLSTATE として HY010 (関数順序エラー) を戻します。
SQLGetDiagField() が非同期関数を実行しているステートメント・ハンドル上に呼び出されるとき、以下の値が戻されます。
SQLGetDiagRec() は、非同期関数を実行しているステートメント・ハンドル上に呼び出されるとき、常に SQL_NO_DATA を戻します。
アプリケーションは、 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 */