この章では、TimesTenプログラミング機能について取り上げ、TimesTenデータベースに接続して使用するためにODBCを使用する方法について説明します。内容は次のとおりです。
TimesTenでは、ODBC 2.5、拡張レベル1がサポートされており、拡張レベル2用の追加機能もありますが、これらの機能については、第10章「TimesTen ODBC関数およびオプション」を参照してください。
|
注意:
|
データベースにDSNを作成する方法の詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』を参照してください。作成するDSNのタイプは、アプリケーションがデータベースに直接接続するか、クライアント接続するかによって異なります。
データベースに直接接続する場合は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のTimesTenデータベースの管理に関する説明を参照してください。UNIXまたはWindowsから直接接続するためのDSNの作成方法に関する説明があります。
データベースへのクライアント接続を作成する場合は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のTimesTen ClientおよびTimesTen Serverの使用方法に関する説明を参照してください。UNIXまたはWindowsからクライアント/サーバー接続を行うためのDSNの作成方法に関する説明があります。
|
注意:
|
この項の以降の内容は次のとおりです。
データベースへの接続およびそれに関連する機能の実行には、次のODBC関数を使用できます。
SQLConnect: ドライバをロードしてデータベースに接続します。接続ハンドルは、ステータス、トランザクションの状態、結果およびエラー情報などの接続情報が格納される場所を指します。
SQLDriverConnect: SQLConnectでサポートされている情報(データソース(データベース)、ユーザー名およびパスワード)よりも詳細な情報が必要な場合に、SQLConnectのかわりに使用します。
SQLAllocConnect: 指定した環境内の接続ハンドルにメモリーを割り当てます。
SQLDisconnect: データベースから切断します。既存の接続ハンドルを唯一の引数として使用します。
これらの関数の詳細は、ODBC APIのリファレンス・マニュアルを参照してください。
この項では、データベースに対する接続および切断の例を示します。
例2-1 接続および切断(抜粋)
このコード部分では、SQLConnectおよびSQLDisconnectを起動して、FixedDsというデータベースに対する接続および切断を行います。アプリケーションで初めてSQLConnectを起動すると、データベースFixedDsが作成されます。その後のSQLConnectの起動では、既存のデータベースに接続されます。
#include <sql.h>
SQLRETURN retcode;
SQLHDBC hdbc;
...
retcode = SQLConnect(hdbc,
(SQLCHAR*)"FixedDs", SQL_NTS,
(SQLCHAR*)"johndoe", SQL_NTS,
(SQLCHAR*)"opensesame", SQL_NTS);
...
retcode = SQLDisconnect(hdbc);
...
例2-2 接続および切断(完全なプログラム)
この例には、データベースを作成し、データベースに対して接続および切断を行う完全なプログラムが含まれています。この例では、SQLConnectではなくSQLDriverConnectを使用して接続を設定し、SQLAllocConnectを使用してメモリーを割り当てます。また、エラー・メッセージの取得方法についても示します。(「エラー処理」も参照してください。)
#ifdef WIN32
#include <windows.h>
#else
#include <sqlunix.h>
#endif
#include <sql.h>
#include <sqlext.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static void chkReturnCode(SQLRETURN rc, SQLHENV henv,
SQLHDBC hdbc, SQLHSTMT hstmt,
char* msg, char* filename,
int lineno, BOOL err_is_fatal);
#define DEFAULT_CONNSTR "DSN=sampledb_1122;PermSize=32"
int
main(int ac, char** av)
{
SQLRETURN rc = SQL_SUCCESS;
/* General return code for the API */
SQLHENV henv = SQL_NULL_HENV;
/* Environment handle */
SQLHDBC hdbc = SQL_NULL_HDBC;
/* Connection handle */
SQLHSTMT hstmt = SQL_NULL_HSTMT;
/* Statement handle */
SQLCHAR connOut[255];
/* Buffer for completed connection string */
SQLSMALLINT connOutLen;
/* Number of bytes returned in ConnOut */
SQLCHAR *connStr = (SQLCHAR*)DEFAULT_CONNSTR;
/* Connection string */
rc = SQLAllocEnv(&henv);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Unable to allocate an "
"environment handle\n");
exit(1);
}
rc = SQLAllocConnect(henv, &hdbc);
chkReturnCode(rc, henv, SQL_NULL_HDBC,
SQL_NULL_HSTMT,
"Unable to allocate a "
"connection handle\n",
__FILE__, __LINE__, 1);
rc = SQLDriverConnect(hdbc, NULL,
connStr, SQL_NTS,
connOut, sizeof(connOut),
&connOutLen,
SQL_DRIVER_NOPROMPT);
chkReturnCode(rc, henv, hdbc, SQL_NULL_HSTMT,
"Error in connecting to the"
" database\n",
__FILE__, __LINE__, 1);
rc = SQLAllocStmt(hdbc, &hstmt);
chkReturnCode(rc, henv, hdbc, SQL_NULL_HSTMT,
"Unable to allocate a "
"statement handle\n",
__FILE__, __LINE__, 1);
/* Your application code here */
if (hstmt != SQL_NULL_HSTMT) {
rc = SQLFreeStmt(hstmt, SQL_DROP);
chkReturnCode(rc, henv, hdbc, hstmt,
"Unable to free the "
"statement handle\n",
__FILE__, __LINE__, 0);
}
rc = SQLDisconnect(hdbc);
chkReturnCode(rc, henv, hdbc,
SQL_NULL_HSTMT,
"Unable to close the "
"connection\n",
__FILE__, __LINE__, 0);
rc = SQLFreeConnect(hdbc);
chkReturnCode(rc, henv, hdbc,
SQL_NULL_HSTMT,
"Unable to free the "
"connection handle\n",
__FILE__, __LINE__, 0);
rc = SQLFreeEnv(henv);
chkReturnCode(rc, henv, SQL_NULL_HDBC,
SQL_NULL_HSTMT,
"Unable to free the "
"environment handle\n",
__FILE__, __LINE__, 0);
return 0;
}
static void
chkReturnCode(SQLRETURN rc, SQLHENV henv,
SQLHDBC hdbc, SQLHSTMT hstmt,
char* msg, char* filename,
int lineno, BOOL err_is_fatal)
{
#define MSG_LNG 512
SQLCHAR sqlState[MSG_LNG];
/* SQL state string */
SQLINTEGER nativeErr;
/* Native error code */
SQLCHAR errMsg[MSG_LNG];
/* Error msg text buffer pointer */
SQLSMALLINT errMsgLen;
/* Error msg text Available bytes */
SQLRETURN ret = SQL_SUCCESS;
if (rc != SQL_SUCCESS &&
rc != SQL_NO_DATA_FOUND ) {
if (rc != SQL_SUCCESS_WITH_INFO) {
/*
* It's not just a warning
*/
fprintf(stderr, "*** ERROR in %s, line %d:"
" %s\n",
filename, lineno, msg);
}
/*
* Now see why the error/warning occurred
*/
while (ret == SQL_SUCCESS ||
ret == SQL_SUCCESS_WITH_INFO) {
ret = SQLError(henv, hdbc, hstmt,
sqlState, &nativeErr,
errMsg, MSG_LNG,
&errMsgLen);
switch (ret) {
case SQL_SUCCESS:
fprintf(stderr, "*** %s\n"
"*** ODBC Error/Warning = %s, "
"TimesTen Error/Warning "
" = %d\n",
errMsg, sqlState,
nativeErr);
break;
case SQL_SUCCESS_WITH_INFO:
fprintf(stderr, "*** Call to SQLError"
" failed with return code of "
"SQL_SUCCESS_WITH_INFO.\n "
"*** Need to increase size of"
" message buffer.\n");
break;
case SQL_INVALID_HANDLE:
fprintf(stderr, "*** Call to SQLError"
" failed with return code of "
"SQL_INVALID_HANDLE.\n");
break;
case SQL_ERROR:
fprintf(stderr, "*** Call to SQLError"
" failed with return code of "
"SQL_ERROR.\n");
break;
case SQL_NO_DATA_FOUND:
break;
} /* switch */
} /* while */
if (rc != SQL_SUCCESS_WITH_INFO && err_is_fatal) {
fprintf(stderr, "Exiting.\n");
exit(-1);
}
}
}
データベースへの接続時に接続文字列を指定して、プログラムで接続属性を設定または上書きできます。
接続属性の全般的な詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』を参照してください。一般接続属性には、特に権限は必要ありません。データベースが初めてロードされたときに最初の接続属性が設定され、すべての接続に持続的に使用されます。最初の接続属性の設定を変更してデータベースをロードできるのは、インスタンス管理者のみです。特定の接続属性に関する固有の情報を含む詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』の接続属性に関する説明を参照してください。
このコード部分では、mydsnというデータベースに接続して、SQLDriverConnectコールで、アプリケーションがパススルー設定の3を使用することを示します。PassThroughは一般接続属性であることに注意してください。
SQLHDBC hdbc;
SQLCHAR ConnStrOut[512];
SQLSMALLINT cbConnStrOut;
SQLRETURN rc;
rc = SQLDriverConnect(hdbc, NULL,
"DSN=mydsn;PassThrough=3", SQL_NTS,
ConnStrOut, sizeof (ConnStrOut),
&cbConnStrOut, SQL_DRIVER_NOPROMPT);
|
注意: データベースへの接続ごとに、いくつかのファイルがオープンします。多数のスレッドを使用し、スレッドごとに別々の接続を使用するアプリケーションでは、各スレッドに対して複数のファイルがオープンします。このようなアプリケーションでは、オペレーティング・システムで同時にオープンできるファイル記述子の許可された最大数(構成されている最大値)を超える可能性があります。この場合は、多数のオープン・ファイルを許可するようシステムを設定します。『Oracle TimesTen In-Memory Databaseリファレンス』のオープン・ファイルの数の制限に関する項を参照してください。 |
defaultという名前が付けられているデフォルトDSNは、odbc.iniファイルまたはsys.odbc.iniファイルで定義できます。デフォルトDSNの定義の詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のデフォルトDSNの設定に関する説明を参照してください。
SQLConnectまたはSQLDriverConnectがコールされた場合、次のような状況で関連するデータ・ソースが接続されます。
SQLConnectでは、デフォルトDSNが定義済の場合、ServerNameが検出できないデータソースを指定する場合、nullポインタを指定する場合、または明示的にdefaultの値に設定される場合に使用されます。参考に、SQLConnectコール・シーケンスを示します。
SQLRETURN SQLConnect(
SQLHDBC ConnectionHandle,
SQLCHAR * ServerName,
SQLSMALLINT NameLength1,
SQLCHAR * UserName,
SQLSMALLINT NameLength2,
SQLCHAR * Authentication,
SQLSMALLINT NameLength3);
サーバー名としてdefaultを使用します。ユーザー名と認証値はそのまま使用します。
SQLDriverConnectでは、デフォルトDSNが定義済の場合、接続文字列にDSNキーワードが含まれない場合、またはデータソースが検出されない場合に使用されます。参考に、SQLDriverConnectコール・シーケンスを示します。
SQLRETURN SQLDriverConnect(
SQLHDBC ConnectionHandle,
SQLHWND WindowHandle,
SQLCHAR * InConnectionString,
SQLSMALLINT StringLength1,
SQLCHAR * OutConnectionString,
SQLSMALLINT BufferLength,
SQLSMALLINT * StringLength2Ptr,
SQLUSMALLINT DriverCompletion);
DSNキーワードとしてdefaultを使用します。ユーザー名とパスワードはそのまま使用します。
直接モードまたはドライバ・マネージャを備えたクライアント/サーバー・モードの場合、次のことに注意してください。
ドライバ・マネージャを使用していない場合、TimesTenがこの機能を管理します。デフォルトDSNは、TimesTenデータベースである必要があります。
ドライバ・マネージャを使用している場合、ドライバ・マネージャがこの機能を管理します。デフォルトDSNは、TimesTenデータベースである必要はありません。
任意のユーザー(インスタンス管理者以外)がデータベースに接続するには、CREATE SESSION権限を付与する必要があります。これはシステム権限であるため、インスタンス管理者、またはADMIN権限を持っただれかによって直接またはPUBLICロールを通してユーザーに付与する必要があります。例および詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のアクセス制御の管理に関する項を参照してください。
XLA接続を作成してXLA機能を実行するには、ユーザーにCREATE SESSIONだけでなく、XLA権限が付与されている必要があります(「アクセス制御がXLAに与える影響」を参照)。
この項では、TimesTenデータベースのデータの処理について説明します。内容は次のとおりです。
TimesTenの機能を使用するには、次の表に示すTimesTenファイルをアプリケーションにインクルードする必要があります。
| インクルード・ファイル | 説明 |
|---|---|
timesten.h |
TimesTenのODBC機能 |
tt_errCode.h |
TimesTenのエラー・コード
このファイルは、TimesTenエラー・コードを定義済の定数マップします。 |
|
注意: 標準ODBCのsql.hファイルは、timesten.hの一部としてインクルードされます。標準のODBC機能のみを使用している場合:
インクルードされるファイルにアクセスするには、適切なインクルード・パスを設定します。関連情報については、「アプリケーションのコンパイルおよびリンク」を参照してください。 |
SQLを使用してデータを管理する方法については、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のTimesTenデータベースのデータの処理に関する説明を参照してください。この項では、Cアプリケーション内でSQL文を実行するために使用される一般的な書式について説明します。内容は次のとおりです。
SQL文を実行するODBC関数は次の2つです。
SQLExecute: SQLPrepareで準備されている文を実行します。実行結果を使用してアプリケーションが実行された後、その結果を破棄して、別のパラメータ値でSQLExecuteを再実行することができます。
通常、バインド・パラメータを使用するDML文または複数回実行される文に使用します。
SQLExecDirect: 文を準備して実行します。
通常、DDL文、または数回のみ実行される、バインド・パラメータを使用しないDML文に使用します。
これらの関数の詳細は、ODBC APIのリファレンス・マニュアルを参照してください。
SQLExecDirect関数は、例2-4に示すように使用できます。
SQLExecute関数とSQLPrepare関数の使用方法は、次の項「問合せの準備および実行とカーソルの使用」に示します。
例2-4 SQLExecDirectを使用したSQL文の実行
次のコード例では、CustIDおよびCustNameという2つの列を持つ、NameIDという表を作成します。この表では、名前(文字)が識別子(整数)にマップされます。
#include <sql.h>
SQLRETURN rc;
SQLHSTMT hstmt;
...
rc = SQLExecDirect(hstmt, (SQLCHAR*)
"CREATE TABLE NameID (CustID INTEGER, CustName VARCHAR(50))",
SQL_NTS);
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
... /* handle error */
この項では、問合せの準備および実行とカーソル使用の基本的な手順を示します。アプリケーションでは、カーソルを使用して問合せの結果がスクロールされ、一度に1つの結果行が確認されます。
|
重要: TimesTenでは、コミットやロールバックなど、トランザクションを終了する操作は、接続と関連付けられているすべてのカーソルをクローズします。 |
ODBC設定では、カーソルは常に結果セットに関連付けられています。この関連付けはODBCドライバによって行われます。アプリケーションでは、「SQLSetStmtOptionおよびSQLGetStmtOptionのオプションのサポート」で説明されているSQLSetStmtOptionオプションを使用して、一度にフェッチする行数などのカーソル特性を制御できます。問合せを実行する場合の手順は、通常は次のとおりです。
SQLPrepareを使用して、SELECT文を実行するための準備をします。
SQLBindParameter(文にパラメータが含まれている場合)を使用して、各パラメータをアプリケーション・アドレスにバインドします。「SQLBindParameter関数」を参照してください。(次の例2-5ではパラメータをバインドしていません。)
SQLBindColをコールして結果の列に記憶域およびデータ型を割り当て、列の結果をアプリケーション内のローカル変数記憶域にバインドします。
SQLExecuteをコールして、SELECT文を実行します。「SQLExecDirect関数およびSQLExecute関数」を参照してください。
SQLFetchをコールして結果をフェッチします。文ハンドルを指定します。
SQLFreeStmtをコールして文ハンドルを解放します。文ハンドルおよびSQL_CLOSE、SQL_DROP、SQL_UNBINDまたはSQL_RESET_PARAMSのいずれかを指定します。
これらのODBC関数の詳細は、ODBC APIのリファレンス・マニュアルを参照してください。例は、この章およびTimesTenクイック・スタート全体で表示されます(「SAMPLE PROGRAMS」の下の「ODBC (C)」リンク)。
|
注意:
|
例2-5 問合せの実行およびカーソルの使用
この例では、ODBCコールを使用して問合せを準備および実行する方法を示します。わかりやすくするために、エラーのチェックは省略してあります。前述のODBC関数以外に、この例では、SQLNumResultColsを使用して結果セット内の列数を返し、SQLDescribeColを使用して結果セットの1つの列の記述(列名、型、精度、スケールおよびNULL値可能)を返し、SQLBindColを使用して記憶域およびデータ型を結果セット内の列に割り当てます。これらすべての関数の詳細は、ODBC APIのリファレンス・マニュアルを参照してください。
#include <sql.h>
SQLHSTMT hstmt;
SQLRETURN rc;
int i;
SQLSMALLINT numCols;
SQLCHAR colname[32];
SQLSMALLINT colnamelen, coltype, scale, nullable;
SQLULEN collen [MAXCOLS];
SQLLEN outlen [MAXCOLS];
SQLCHAR* data [MAXCOLS];
/* other declarations and program set-up here */
/* Prepare the SELECT statement */
rc = SQLPrepare(hstmt,
(SQLCHAR*) "SELECT * FROM EMP WHERE AGE>20",
SQL_NTS);
/* ... */
/* Determine number of columns in result rows */
rc = SQLNumResultCols(hstmt, &numCols);
/* ... */
/* Describe and bind the columns */
for (i = 0; i < numCols; i++) {
rc = SQLDescribeCol(hstmt,
(SQLSMALLINT) (i + 1),
colname,(SQLSMALLINT)sizeof(colname), &colnamelen, &coltype, &collen[i],
&scale, &nullable);
/* ... */
data[i] = (SQLCHAR*) malloc (collen[i] +1); //Allocate space for column data.
rc = SQLBindCol(hstmt, (SQLSMALLINT) (i + 1),
SQL_C_CHAR, data[i],
COL_LEN_MAX, &outlen[i]);
/* ... */
}
/* Execute the SELECT statement */
rc = SQLExecute(hstmt);
/* ... */
/* Fetch the rows */
if (numCols > 0) {
while ((rc = SQLFetch(hstmt)) == SQL_SUCCESS ||
rc == SQL_SUCCESS_WITH_INFO) {
/* ... "Process" the result row */
} /* end of for-loop */
if (rc != SQL_NO_DATA_FOUND)
fprintf(stderr,
"Unable to fetch the next row\n");
/* Close the cursor associated with the SELECT statement */
rc = SQLFreeStmt(hstmt, SQL_CLOSE);
}
標準のODBCでは、結果セットの列記述のような文に関する情報をアプリケーションで使用可能にしたり、これらの情報にSQLDescribeColなどのコールでアクセスできるように、SQLPrepareコールはSQL文をコンパイルします。この機能を実現するには、SQLPrepareコールをサーバーに送信して処理する必要があります。
このことは、たとえば、Oracle Call Interface(OCI)で期待される動作とは対照的で、OCIでは、準備コールは単にパラメータの名前と位置を抽出するための、クライアントで実行される軽量処理であることが期待されています。
クライアントとサーバー間の不要なラウンドトリップを回避し、OCIが期待する動作との一貫性を実現するために、TimesTenクライアント・ライブラリに実装されたSQLPrepareでは、遅延準備と呼ばれる処理が実行され、リクエストは要求されるまでサーバーに送信されません。ラウンドトリップが必要になる場合の例を、次に示します。
SQLExecuteコールがある場合。まだサーバーに送信されていない遅延準備コールがある場合、クライアント上のSQLExecuteコールはSQLExecDirectコールに変換されることに注意してください。
SQLエンジンからのみ取得可能な、問合せに関する情報のリクエストがある場合(SQLDescribeColコールがある場合など)。標準のODBCのこのようなコールの多くは、以前にSQLPrepareコールで返された情報にアクセスできますが、遅延準備機能を使用している場合は、SQLPrepareコールがサーバーに送信され、情報は必要な場合にのみアプリケーションに返されます。
|
注意: 遅延準備機能はTimesTenの直接ドライバでは実装されていません(必須ではありません)。 |
遅延準備の実装には、アプリケーションまたはユーザー・レベルの変更は必要ありません。ただし、次の関数のいずれかをコールすると、以前に準備された文で必要とされた情報がまだ取得されていなかった場合には、サーバーに対するラウンドトリップが発生する可能性があります。
SQLColAttributes
SQLDescribeCol
SQLDescribeParam
SQLNumResultCols
SQLNumParams
SQLGetStmtOption(SQLエンジンでコンパイルされている文に依存するオプションの場合)
また、これらの関数のいずれかをコールすると、以前のSQLPrepareコールのエラーが、これらのコールの1つが実行されるまで遅延される場合があることに注意してください。また、これらのコールで、コール自体に固有のエラーの他に、SQLPrepareに固有のエラーも返される場合があります。
TimesTenによるODBCの拡張によって、アプリケーションはODBCドライバのバッファに複数のデータ行をプリフェッチできます。これにより、クライアント/サーバー・アプリケーションのパフォーマンスを向上させることができます。
TT_PREFETCH_COUNT文オプションによって、1回のSQLFetchコールでプリフェッチする行数が決定されます。このオプションは、TimesTenに直接接続するアプリケーションには何もメリットがないことに注意してください。
コールのTT_PREFETCH_COUNTは、SQLSetStmtOptionまたはSQLSetConnectOptionに設定できます(接続に関連付けられる文すべてのデフォルト値をオプションで設定します)。値には0(ゼロ)から128までの任意の整数を設定できます。次に、その例を示します。
rc = SQLSetConnectOption(hdbc, TT_PREFETCH_COUNT, 100);
この設定を使用すると、接続時の最初のSQLFetchコールで100行がプリフェッチされます。後続のSQLFetchコールは、ODBCバッファが使い果たされるまで、データベースのかわりにODBCバッファからフェッチします。ODBCバッファが使い果たされると、次のSQLFetchコールでは別の100行がバッファにフェッチされます。
プリフェッチを無効にするには、TT_PREFETCH_COUNTを1に設定します。
プリフェッチ数を0(ゼロ)に設定すると、TimesTenはデータベースに設定した分離レベルに応じてデフォルトのプリフェッチ数を使用し、プリフェッチ数をTT_PREFETCH_COUNT値に設定します。コミット読取り分離レベルでは、デフォルトのプリフェッチの値は5です。シリアライズ可能分離レベルでは、デフォルトは128です。デフォルトのプリフェッチの値はほとんどのアプリケーションに最適な設定です。一般的に、値を高く設定すると、リソースの使用量がわずかに増加しますが、大きい結果セットに対するパフォーマンスは向上する可能性があります。
この項では、SQL文の入力または出力パラメータをバインドする方法について説明します。内容は次のとおりです。
|
注意: TimesTen開発者ガイドで使用される「バインド・パラメータ」という用語(ODBC用語に準拠)は、TimesTenのPL/SQLのマニュアルで使用される「バインド変数」という用語(Oracle Database PL/SQL用語に準拠)と同じです。 |
ODBCのSQLBindParameter関数を使用して、SQL文のパラメータをバインドします。これには、入力、出力または入力/出力パラメータを含むことができます。
ODBCを介して入力パラメータをバインドするには、fParamType引数にSQL_PARAM_INPUTを設定してSQLBindParameter関数を使用します。SQLBindParameter関数の詳細は、ODBC APIのリファレンス・マニュアルを参照してください。表2-1に、この引数の簡単な概要を示します。
ODBCを介して出力または入力/出力パラメータをバインドするには、fParamType引数にSQL_PARAM_OUTPUTまたはSQL_PARAM_INPUT_OUTPUTをそれぞれ設定してSQLBindParameter関数を使用します。入力パラメータと同様に、fSqlType引数、cbColDef引数およびibScale引数を(必要に応じて)使用して、データ型を指定します。
表2-1 SQLBindParameterの引数
| 引数 | 型 | 説明 |
|---|---|---|
|
|
|
文ハンドル |
|
|
|
左から右へ順に、1から始まるパラメータ番号 |
|
|
|
入力または出力を示す、 |
|
|
|
パラメータのCデータ型 |
|
|
|
パラメータのSQLデータ型 |
|
|
|
|
|
|
|
|
|
|
|
パラメータのデータに使用するバッファへのポインタ |
|
|
|
|
|
|
|
パラメータの長さに使用するバッファへのポインタ |
|
注意: TimesTenのデータ型の精度およびスケールの詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス』のデータ型に関する説明を参照してください。 |
バインド・パラメータのデータ型の割当ては、次のように決定されます。
TimesTenで実行される文のパラメータのデータ型の割当ては、TimesTenが決定します。具体的には、次のようになります。
TimesTen内で実行されるSQL文の場合、TimesTenの問合せオプティマイザがSQLパラメータのデータ型を決定します。
Oracle Databaseで実行されるか、Oracle Databaseの機能に基づいた文に対するパラメータのデータ型の割当ては、次のようにアプリケーションが決定します。
Oracle Database内で実行されるSQL文(TimesTen Application-Tier Database Cache (TimesTen Cache)からのパススルー文)の場合は、アプリケーションは、ODBC SQLBindParameter関数にコールする際に、その関数のfSqlType、cbColDefおよびibScale引数に基づいて(該当する場合)、データ型を指定する必要があります。
TimesTen内で実行されるPL/SQLブロックまたはプロシージャで、PL/SQL実行エンジンにOracle Databaseと同じ基本的な機能がある場合は、アプリケーションは、SQLBindParameterに対するコールでデータ型を指定する必要があります(Oracle Database内で実行されるSQL文の場合と同様)。
そのため、PL/SQLのホスト・バインド(PL/SQLブロック内でコロンより前にある変数やパラメータ)については、fSqlTypeおよび該当するその他の引数に従って、PL/SQLブロック内ではなく、SQLBindParameterへのコールでホスト・バインドのデータ型が事実上宣言されることに注意してください。
ODBCドライバは、C値とSQLまたはPL/SQLのデータ型間で必要な型の変換を行います。サポートされていないCとSQLやCとPL/SQLの組合せでは、エラーが発生します。それらは、C型からSQL型またはPL/SQL型(入力パラメータ)、SQL型またはPL/SQL型からC型(出力パラメータ)または両方(入力/出力パラメータ)の変換の場合です。
|
注意: TimesTenのバインド・メカニズム(アーリー・バインディング)はOracle Databaseのバインド・メカニズム(レイト・バインディング)とは異なります。TimesTenは、問合せの準備の前にデータ型を必要とします。そのため、各バインド・パラメータのデータ型が指定されていないかSQL文から推測できないと、エラーが発生します。たとえば次のような文が、これに該当します。SELECT 'x' FROM DUAL WHERE ? = ?; この問題には、たとえば次のように対処できます。
SELECT 'x' from DUAL WHERE CAST(? as VARCHAR2(10)) =
CAST(? as VARCHAR2(10));
|
表2-2に、ODBCデータ型とSQL型またはPL/SQLデータ型とのマッピングを示します。
表2-2 ODBC SQLとTimesTen SQLまたはPL/SQLとのデータ型のマッピング
| ODBCデータ型(fSqlType) | SQLまたはPL/SQLのデータ型 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
注意:
|
TimesTenのPL/SQLに対する入力パラメータでは、ODBCのSQLBindParameter関数のfSqlType引数、cbColDef引数およびibScale引数を(必要に応じて)使用して、データ型を指定します。これは、「パラメータのデータ型の割当ての決定および変換」の記載されている、SQL入力パラメータのサポート方法とは異なります。
また、SQLBindParameterのrgbValue引数、cbValueMax引数およびpcbValue引数も、入力パラメータでは次のように使用します。
rgbValue: 文を実行する前に、アプリケーションは、アプリケーションに渡されるパラメータ値を格納するバッファを指します。
cbValueMax: 文字データおよびバイナリ・データの場合、rgbValueが指す入力値の最大長(バイト)を示します。他のすべてのデータ型の場合、cbValueMaxは無視され、rgbValueが指す値の長さはSQLBindParameterのfCType引数に指定したCデータ型の長さで決定されます。
pcbValue: 文を実行する前に、次のいずれかを含むバッファを指します。
rgbValueが指す値の実際の長さ
注意: 入力パラメータの場合、文字データまたはバイナリ・データにのみ有効です。
空文字で終了する文字列の場合は、SQL_NTS
NULL値の場合は、SQL_NULL_DATA
TimesTenのPL/SQLからの出力パラメータでは、前述の入力パラメータに記載したとおり、ODBCのSQLBindParameter関数のfSqlType引数、cbColDef引数およびibScale引数を(必要に応じて)使用して、データ型を指定します。
また、SQLBindParameterのrgbValue引数、cbValueMax引数およびpcbValue引数も、出力パラメータでは次のように使用します。
rgbValue: 文の実行中に、文から返された値を格納するバッファを指します。
cbValueMax: 文字データおよびバイナリ・データの場合、rgbValueが指す出力値の最大長(バイト)を示します。他のすべてのデータ型の場合、cbValueMaxは無視され、rgbValueが指す値の長さはSQLBindParameterのfCType引数に指定したCデータ型の長さで決定されます。
ODBCでは、データが切り捨てられる場合でも、すべての文字データが空文字で終了することに注意してください。そのため、出力パラメータに文字データが含まれる場合、cbValueMaxはデータの最長値+空文字を保持できる十分な大きさである必要があります(CHARおよびVARCHARパラメータでは1バイト大きい値、またはNCHARおよびNVARCHARパラメータでは2バイト大きい値)。
pcbValue: 文を実行した後に、次のいずれかを含むバッファを指します。
rgbValueが指す値の実際の長さ(文字データおよびバイナリ・データのみでなく、すべてのCデータ型が対象)
注意: rgbValueが指すバッファに値が収まるかどうかに関係なく、完全なパラメータ値の長さです。
NULL値の場合は、SQL_NULL_DATA
例2-6 出力パラメータのバインド
この例では、PL/SQLの無名ブロックを準備、バインドおよび実行する方法を示します。無名ブロックでは、値abcdeをバインド・パラメータaに、値123をバインド・パラメータbに割り当てます。
SQLPrepareは無名ブロックを準備します。SQLBindParameterは、最初のパラメータ(a)をデータ型SQL_VARCHARの出力パラメータとしてバインドし、2番目のパラメータ(b)をデータ型SQL_INTEGERの出力パラメータとしてバインドします。SQLExecuteは無名ブロックを実行します。
{
SQLHSTMT hstmt;
char aval[11];
SQLLEN aval_len;
SQLINTEGER bval;
SQLLEN bval_len;
SQLAllocStmt(hdbc, &hstmt);
SQLPrepare(hstmt,
(SQLCHAR*)"begin :a := 'abcde'; :b := 123; end;",
SQL_NTS);
SQLBindParameter(hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_VARCHAR,
10, 0, (SQLPOINTER)aval, sizeof(aval), &aval_len);
SQLBindParameter(hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER,
0, 0, (SQLPOINTER)&bval, sizeof(bval), &bval_len);
SQLExecute(hstmt);
printf("aval = [%s] (length = %d), bval = %d\n", aval, (int)aval_len, bval);
}
TimesTenのPL/SQLに対する入力/出力パラメータでは、前述の入力パラメータに記載したとおり、ODBCのSQLBindParameter関数のfSqlType引数、cbColDef引数およびibScale引数を(必要に応じて)使用して、データ型を指定します。
また、SQLBindParameterのrgbValue引数、cbValueMax引数およびpcbValue引数も、入力/出力パラメータでは次のように使用します。
rgbValue: 最初に、「入力パラメータのバインド」で説明したとおり、文を実行する前に使用します。次に、前の項「出力パラメータのバインド」で説明したとおり、文の実行中に使用します。入力/出力パラメータの場合、文の実行で出力された値は、アプリケーションによって上書きされないかぎり、直後に続く文の実行に対する入力値になります。また、実行時データの使用中にバインドされる入力/出力値の場合、rgbValueの値は、ODBCのSQLParamData関数で返されるトークンおよび出力値が格納されるバッファへのポインタの両方として機能します。
cbValueMax: 文字データおよびバイナリ・データの場合、最初に、「入力パラメータのバインド」で説明したとおりに使用します。次に、前の項「出力パラメータのバインド」で説明したとおりに使用します。他のすべてのデータ型の場合、cbValueMaxは無視され、rgbValueが指す値の長さはSQLBindParameterのfCType引数に指定したCデータ型の長さで決定されます。
ODBCでは、データが切り捨てられる場合でも、すべての文字データが空文字で終了することに注意してください。そのため、出力/出力パラメータに文字データが含まれる場合、cbValueMaxはデータの最長値+空文字を保持できる十分な大きさである必要があります(CHARおよびVARCHARパラメータでは1バイト大きい値、またはNCHARおよびNVARCHARパラメータでは2バイト大きい値)。
pcbValue: 最初に、「入力パラメータのバインド」で説明したとおり、文を実行する前に使用します。次に、前の項「出力パラメータのバインド」で説明したとおり、文の実行後に使用します。
|
重要: 文字データおよびバイナリ・データの場合、cbValueMaxに使用する値を慎重に検討してください。実際のバッファ・サイズよりも小さい値を使用すると、誤った切捨て警告が発生します。実際のバッファ・サイズよりも大きい値を使用すると、ODBCドライバによってrgbValueバッファが上書きされ、メモリーが破損することがあります。 |
TimesTenでは、SQL文で重複したパラメータをバインドするための2つの異なるモードがサポートされます。(PL/SQL文については、「PL/SQLでの重複したパラメータのバインド」を参照してください。)
Oracleモード: 同じパラメータ名の複数の出現は異なるパラメータとみなされます。
従来のTimesTenモード: 以前のリリースと同様に、同じパラメータ名の複数の出現は同じパラメータとみなされます。
DuplicateBindMode TimesTen一般接続属性を使用すると、目的のモードを選択できます。DuplicateBindMode=0(デフォルト)はOracleモードで、DuplicateBindMode=1はTimesTenモードです。この属性は一般接続属性であるため、同じデータベースに対する複数の接続でそれぞれ異なる値を使用できます。この属性の詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』のDuplicateBindModeに関する項を参照してください。
この項の後半では、次の問合せを検討しながら各モードの詳細を説明します。
SELECT * FROM employees WHERE employee_id < :a AND manager_id > :a AND salary < :b;
|
注意:
|
Oracleモード(DuplicateBindMode=0)では、1つのSQL文に含まれる同じパラメータ名の複数の出現は異なるパラメータとみなされます。パラメータの位置番号が割り当てられるとき、名前の重複に関係なく、パラメータの出現ごとに番号が与えられます。アプリケーションは、少なくとも各パラメータ名の最初の出現時に値をバインドする必要があります。特定のパラメータ名の2回目以降の出現に関して、アプリケーションでは次の選択肢があります。
出現ごとに異なる値をバインドします。
出現したパラメータをバインドしないでおきます。この場合には、最初の出現時と同じ値が使用されます。
いずれの場合も、出現ごとに異なるパラメータ位置番号が付けられます。
前述のSQL文のaの2回目の出現に対して異なる値を使用するには、次のように指定します。
SQLBindParameter(..., 1, ...); /* first occurrence of :a */ SQLBindParameter(..., 2, ...); /* second occurrence of :a */ SQLBindParameter(..., 3, ...); /* occurrence of :b */
aの両方の出現に対して同じ値を使用するには、次のように指定します。
SQLBindParameter(..., 1, ...); /* both occurrences of :a */ SQLBindParameter(..., 3, ...); /* occurrence of :b */
いずれの場合も、パラメータbは位置3に存在するとみなされます。
Oracleモードでは、SQLNumParams ODBC関数はこの例のパラメータの数として3を返します。
TimesTenモード(DuplicateBindMode=1)では、重複したパラメータを含むSQL文は、異なるパラメータ名のみが別のパラメータとしてみなされるように解析されます。
バインドは、パラメータ名が最初に出現した位置に基づいて行われます。その後、このパラメータ名が出現しても、それ専用の位置番号は与えられません。同じパラメータ名が出現するたびに、すべて同じ値が使用されます。
前述のSQL文の場合、2つのaの出現は1つのパラメータとみなされるため、別々にバインドできません。
SQLBindParameter(..., 1, ...); /* both occurrences of :a */ SQLBindParameter(..., 2, ...); /* occurrence of :b */
TimesTenモードでは、パラメータbは位置3ではなく、位置2に存在するとみなされることに注意してください。
TimesTenモードでは、SQLNumParams ODBC関数はこの例のパラメータの数として2を返します。
前述の説明は、独自のセマンティクスを持つPL/SQLには当てはまりません。PL/SQLでは、それぞれの一意のパラメータ名に値をバインドします。たとえば、次のブロックを実行するアプリケーションは、:aに対応する1つのパラメータのみをバインドします。
DECLARE x NUMBER; y NUMBER; BEGIN x:=:a; y:=:a; END;
次のブロックを実行するアプリケーションでも、1つのパラメータのみをバインドします。
BEGIN INSERT INTO tab1 VALUES(:a, :a); END
さらに、次のCALL文でも同様です。
...CALL proc(:a, :a)...
次のブロックを実行するアプリケーションでは、:aを1番目のパラメータ、:bを2番目のパラメータとして、2つのパラメータをバインドします。各INSERT文の2番目のパラメータは、最初のINSERT文の最初のパラメータと同じ値を使用します。
BEGIN INSERT INTO tab1 VALUES(:a, :a); INSERT INTO tab1 VALUES(:b, :a); END
BINARY_DOUBLEおよびBINARY_FLOATデータ型は、IEEEの浮動小数点の値Inf、-InfおよびNaNを格納および取得します。アプリケーションでprintf、scanfまたはstrtodのような文字データへの変換を必要とするC言語機能を使用した場合、浮動小数点の値はINF、-INFおよびNANとして返されます。これらのキャラクタ文字列を浮動少数点の値に戻すことはできません。
Windowsのドライバ・マネージャを使用するアプリケーションでは、SQL_WCHARまたはSQL_WVARCHARのfSqlType値を渡す際に、SQLBindParameterからSQL状態S1004(SQLデータ型が範囲外)エラーが発生する場合があります。この問題は、かわりにfSqlTypeに次のいずれかの値を渡すことで回避できます。
SQL_WCHARではなくSQL_WCHAR_DM_SQLBINDPARAMETER_BYPASS
SQL_WVARCHARではなくSQL_WVARCHAR_DM_SQLBINDPARAMETER_BYPASS
これらの値は、意味的にはSQL_WCHARおよびSQL_WVARCHARと同じですが、Windowsのドライバ・マネージャからのエラーを回避します。これらは、ドライバ・マネージャとリンクするアプリケーションまたはTimesTen ODBCの直接ドライバやODBCクライアント・ドライバと直接リンクするアプリケーションで使用できます。
ODBC関数の詳細は、「SQLBindParameter関数」を参照してください。
REF CURSORはPL/SQLの1つの概念で、SQL結果セット上のカーソルに対するハンドルであり、PL/SQLとアプリケーションの間で受渡しすることができます。TimesTenでは、PL/SQL内でカーソルをオープンでき、そのREF CURSORをアプリケーションに渡すことができます。結果は、アプリケーション内でODBCコールを使用して処理できます。これがOUT REF CURSOR(PL/SQLに対するOUTパラメータ)です。REF CURSORは文ハンドルにアタッチされ、アプリケーションは任意の結果セットと同じAPIを使用して結果セットを記述およびフェッチできます。
REF CURSORを使用するには、次の手順を実行します。REF CURSOR OUTパラメータを使用してカーソルを返すPL/SQL文を想定しています。REF CURSORでは、「問合せの準備および実行とカーソルの使用」のカーソルの例と同じ準備、バインド、実行およびフェッチの基本的な手順を使用します。
SQLPrepareを使用して、最初の文ハンドルと関連付けるPL/SQL文を準備します。
SQLBindParameterを使用して、文の各パラメータをバインドします。REF CURSOR出力パラメータをバインドする場合、割り当てられた2番目の文ハンドルをrgbValue(データ・バッファへのポインタ)として使用します。
pcbValue引数、ibScale引数、cbValueMax引数およびpcbValue引数は、REF CURSORに対しては無視されます。
SQLBindParameterのこれらの引数および他の引数の詳細は、「SQLBindParameter関数」および「出力パラメータのバインド」を参照してください。
SQLBindColをコールして、結果列をローカル変数の記憶域にバインドします。
SQLExecuteをコールして、文を実行します。
SQLFetchをコールして結果をフェッチします。PL/SQLからアプリケーションにREF CURSORが渡された後、アプリケーションは結果セットの場合と同様に、その結果を記述およびフェッチできます。
SQLFreeStmtを使用して文ハンドルを解放します。
これらの手順を、次の例で実際に行ってみます。これらの関数の詳細は、ODBC APIのリファレンス・マニュアルを参照してください。REF CURSORの詳細は、『Oracle TimesTen In-Memory Database PL/SQL開発者ガイド』のPL/SQL REF CURSORに関する説明を参照してください。
|
重要: PL/SQLとアプリケーションの間のREF CURSORの受渡しについて、TimesTenでは、PL/SQLからアプリケーションへのOUT REF CURSORのみと、単一のREF CURSORのみを返す文がサポートされます。 |
例2-7 問合せの実行およびREF CURSORの使用
この例では、REF CURSORをループで使用して、問合せの準備、パラメータのバインド、問合せの実行、ローカル変数記憶域への結果のバインド、および結果のフェッチを行う基本的な手順を示します。わかりやすくするためにエラー処理は省略しています。以前に概要を示したODBC関数以外に、この例ではSQLAllocStmtを使用して文ハンドルにメモリーを割り当てます。
refcursor_example(SQLHDBC hdbc)
{
SQLCHAR* stmt_text;
SQLHSTMT plsql_hstmt;
SQLHSTMT refcursor_hstmt;
SQLINTEGER deptid;
SQLINTEGER depts[3] = {10,30,40};
SQLINTEGER empid;
SQLCHAR lastname[30];
SQLINTEGER i;
/* allocate 2 statement handles: one for the plsql statement and
* one for the ref cursor */
SQLAllocStmt(hdbc, &plsql_hstmt);
SQLAllocStmt(hdbc, &refcursor_hstmt);
/* prepare the plsql statement */
stmt_text = (SQLCHAR*)
"begin "
"open :refc for "
"select employee_id, last_name "
"from employees "
"where department_id = :dept; "
"end;";
SQLPrepare(plsql_hstmt, stmt_text, SQL_NTS);
/* bind parameter 1 (:refc) to refcursor_hstmt */
SQLBindParameter(plsql_hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_REFCURSOR,
SQL_REFCURSOR, 0, 0, refcursor_hstmt, 0, 0);
/* bind parameter 2 (:deptid) to local variable deptid */
SQLBindParameter(plsql_hstmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_INTEGER, 0, 0, &deptid, 0, 0);
/* loop through values for :deptid */
for (i=0; i<3; i++)
{
deptid = depts[i];
/* execute the plsql statement */
SQLExecute(plsql_hstmt);
/*
* The result set is now attached to refcursor_hstmt.
* Bind the result columns and fetch the result set.
*/
/* bind result column 1 to local variable empid */
SQLBindCol(refcursor_hstmt, 1, SQL_C_SLONG,
(SQLPOINTER)&empid, 0, 0);
/* bind result column 2 to local variable lastname */
SQLBindCol(refcursor_hstmt, 2, SQL_C_CHAR,
(SQLPOINTER)lastname, sizeof(lastname), 0);
/* fetch the result set */
while(SQLFetch(refcursor_hstmt) != SQL_NO_DATA_FOUND){
printf("%d, %s\n", empid, lastname);
}
/* close the ref cursor statement handle */
SQLFreeStmt(refcursor_hstmt, SQL_CLOSE);
}
/* drop both handles */
SQLFreeStmt(plsql_hstmt, SQL_DROP);
SQLFreeStmt(refcursor_hstmt, SQL_DROP);
}
DML RETURNINGと呼ばれるRETURNING INTO句をINSERT、UPDATEまたはDELETE文で使用すると、処理の影響を受けた行の特定の項目を返すことができます。これにより、処理の影響を受けた対象を確認する場合などに、後続のSELECT文および別個のラウンドトリップが不要になります。
ODBCの場合、DML RETURNINGは単一行処理から項目を返すことに限定されます。この句では、項目を出力パラメータのリストに返します。「パラメータのバインドおよび文の実行」の記述に従って、出力パラメータをバインドします。
TimesTenでのRETURNING INTO句のSQL構文および制限については、『Oracle TimesTen In-Memory Database SQLリファレンス』のINSERT、UPDATEおよびDELETEに関する説明を参照してください。
DML RETURNINGの詳細は、『Oracle Database PL/SQL言語リファレンス』のRETURNING INTO句に関する項を参照してください。
例2-8 DML RETURNING
この例は、例2-10を元に、主要な部分を太字で強調表示したものです。
void
update_example(SQLHDBC hdbc)
{
SQLCHAR* stmt_text;
SQLHSTMT hstmt;
SQLINTEGER raise_pct;
char hiredate_str[30];
char last_name[30];
SQLLEN hiredate_len;
SQLLEN numrows;
/* allocate a statement handle */
SQLAllocStmt(hdbc, &hstmt);
/* prepare an update statement to give a raise to one employee hired
before a given date and return that employee's last name */
stmt_text = (SQLCHAR*)
"update employees "
"set salary = salary * ((100 + :raise_pct) / 100.0) "
"where hire_date < :hiredate and rownum = 1 returning last_name into "
":last_name";
SQLPrepare(hstmt, stmt_text, SQL_NTS);
/* bind parameter 1 (:raise_pct) to variable raise_pct */
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_DECIMAL, 0, 0, (SQLPOINTER)&raise_pct, 0, 0);
/* bind parameter 2 (:hiredate) to variable hiredate_str */
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_TIMESTAMP, 0, 0, (SQLPOINTER)hiredate_str,
sizeof(hiredate_str), &hiredate_len);
/* bind parameter 3 (:last_name) to variable last_name */
SQLBindParameter(hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_CHAR,
SQL_VARCHAR, 30, 0, (SQLPOINTER)last_name,
sizeof(last_name), NULL);
/* set parameter values to give a 10% raise to an employee hired before
* January 1, 1996. */
raise_pct = 10;
strcpy(hiredate_str, "1996-01-01");
hiredate_len = SQL_NTS;
/* execute the update statement */
SQLExecute(hstmt);
/* tell us who the lucky person is */
printf("Gave raise to %s.\n", last_name );
/* drop the statement handle */
SQLFreeStmt(hstmt, SQL_DROP);
/* commit the changes */
SQLTransact(henv, hdbc, SQL_COMMIT);
}
この例では、昇給の対象者としてKingが返されます。
データベース表の各行には、ROWIDと呼ばれる一意の識別子があります。アプリケーションでは、ROWID擬似列から行のROWIDを取得できます。ROWIDはバイナリまたは文字形式で表すことができます。
アプリケーションでは、SQL文のWHERE句などで、一重引用符で囲んだCHAR定数としてリテラルのROWID値を指定できます。
表2-2に示すとおり、ODBC SQLデータ型のSQL_ROWIDはSQLデータ型のROWIDに対応します。
パラメータおよび結果セット列では、ROWIDは、Cデータ型のSQL_C_BINARY、SQL_C_WCHARおよびSQL_C_CHARとの間で双方向に変換可能です。SQL_C_CHARは、ROWIDのデフォルトのCデータ型です。ROWIDのサイズは、SQL_C_BINARYとしては12バイト、SQL_C_CHARとしては18バイトおよびSQL_C_WCHARとしては36バイトです。
ROWIDおよびROWIDデータ型の使用方法および存続期間などの詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス』のROWIDデータ型およびROWIDに関する説明を参照してください。
|
注意: TimesTenでは、PL/SQL型UROWIDはサポートされていません。 |
TimesTenではLOB(ラージ・オブジェクト)がサポートされています。これには、CLOB(Character LOB)、NCLOB(National Character LOB)およびBLOB(Binary LOB)が含まれます。
この項では、次の各項目で、LOBの概要とODBCでの使用について説明します。
|
注意: データベース・キャラクタ・セットがTIMESTEN8の場合、TimesTenではCLOBをサポートしません。 |
次の情報も参照できます。
APIに固有の情報は、「TimesTen OCIでのLOB」および「TimesTen Pro*C/C++でのLOB」を参照してください。
TimesTenでのLOBの詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス』のLOBのデータ型に関する説明を参照してください。
LOBによるプログラミングの一般的な情報(TimesTen機能に固有ではない)は、Oracle Database SecureFileおよびラージ・オブジェクト開発者ガイドを参照してください。
LOBは、ラージ・バイナリ・オブジェクト(BLOB)またはキャラクタ・オブジェクト(CLOBまたはNCLOB)です。TimesTenでは、BLOBのサイズは最大16MBで、CLOBまたはNCLOBは最大4MBです。他に注記がなければ、TimesTenでのLOBには、Oracle Databaseと基本的に同じ機能があります。(次の項「TimesTen LOBとOracle Database LOBの相違点」を参照。)
LOBは、永続または一時のいずれかです。永続LOBは、データベースのLOB列に存在します。一時LOBは、アプリケーション内にのみ存在します。一時LOBがTimesTenによって暗黙的に作成される場合があります。たとえば、SELECT文で追加の文字列が連結されたLOBを指定した場合に、連結されたデータを含むためにTimesTenによって一時LOBが作成されます。TimesTen ODBCでは、すべての一時LOBは暗黙的に管理されます。
一時LOBは、TimesTenの一時データ領域に格納されます。
次のことに注意してください。
TimesTen LOB実装とOracle Database実装の主な違いは、TimesTenでは、アプリケーションで使用されたLOBはトランザクションの終了後は有効ではないことです。アプリケーションで使用されたLOBはすべて(明示的、暗黙的のどちらの場合も)、コミットまたはロールバックの後に無効化されます。これには、TimesTen DDLCommitBehaviorが0(ゼロ)(デフォルト)に設定されている場合(Oracle Databaseの動作に対応)、すべてのDDL文の実行後が含まれます。
TimesTenでは、BFILE、SecureFile、LOBに対する配列読取りおよび書込みまたはLOBに対するコールバック関数をサポートしていません。
TimesTenでは、LOBに対する配列のバインドをサポートしていません。
TimesTenでは、LOBに対するバッチ処理をサポートしていません。
BLOBに関して、TimesTenでの16進リテラルの使用方法に違いがあります。『Oracle TimesTen In-Memory Database SQLリファレンス』の定数でHexadecimalLiteralに関する説明を参照してください。
CまたはC++プログラムでのTimesTen LOBへのアクセスには、次の3つのプログラミング方法があります。
簡易データ・インタフェース(ODBC、OCI、Pro*C/C++、TTClasses): その他のスカラー型と同様に、バインドおよび定義を使用してLOBデータを1チャンクで転送します。
ピース単位のデータ・インタフェース(ODBC): バインドおよび定義の拡張書式を使用して複数ピース単位でLOBデータを転送します。これは、ストリーミングまたはdata-at-execの使用(プログラムの実行時)と呼ばれることがあります。TimesTenでは、LOBデータをピース単位で探索するポーリング・ループを使用した、ピース単位のデータ・インタフェースをサポートしています。(ピース単位による別の方法であるコールバック関数の使用は、Oracle Databaseではサポートされていますが、TimesTenではサポートされていません。)
LOBロケータ・インタフェース(OCI、Pro*C/C++): SQLでLOBロケータを選択し、ファイル・システムへのアクセスで使用するAPIと概念的に似ているAPIを介して、LOBデータにアクセスします。LOBロケータ・インタフェースを使用すると、LOBデータを分割してまたは単一チャンクで使用できます。(「TimesTen OCIでのLOB」および「TimesTen Pro*C/C++でのLOB」を参照。)
LOBロケータ・インタフェースは、使用できる場合は最適なユーティリティを提供します。
簡易データ・インタフェースを使用すると、他のスカラー型と同様に、アプリケーションからバインドおよび定義によってLOBデータにアクセスできます。ODBCでの簡易データ・インタフェースでは、パラメータのバインドにSQLBindParameterを使用し、結果列の定義にSQLBindColを使用します。アプリケーションは、SQLデータ型を使用してバインドまたは定義することが可能で、このSQLデータ型は次に示すように対応する変数型と互換性があります。
BLOBデータでは、SQL型SQL_LONGVARBINARYおよびC型SQL_C_BINARYを使用します。
CLOBデータでは、SQL型SQL_LONGVARCHARおよびC型SQL_C_CHARを使用します。
NCLOBデータでは、SQL型SQL_WLONGVARCHARおよびC型SQL_C_WCHARを使用します。
LOBデータに対するSQLBindParameterコールおよびSQLBindColコールは、この章で前述した他のデータ型に対するコールとよく似ています。
|
注意: CLOBまたはNCLOBでC型のSQL_C_BINARYを使用したバインドは禁止されています。 |
ピース単位のインタフェースを使用すると、アプリケーションから、LOBデータの各部分に個別にアクセスできます。簡易データ・インタフェースで実行されるのと同様のアクションで、アプリケーションによってパラメータがバインドされ、結果が定義されますが、プログラム実行時(at exec)にデータが提供されたものか取得されたものであるかが示されます。TimesTenでは、すべてのLOBデータが読み取られるか書き込まれるまで継続されるポーリング・ループを介してピース単位のデータ・インタフェースを実装できます。
ODBCでのピース単位のデータ・インタフェースでは、SQLParamDataとSQLPutDataをポーリング・ループで使用してパラメータをバインドし(次の例2-9を参照)、SQLGetDataをポーリング・ループで使用して結果を取得します。BLOB、CLOBおよびNCLOBでサポートされるSQLおよびCのデータ型の詳細は、前述の項「ODBCでのLOBの簡易データ・インタフェースの使用」を参照してください。
|
注意: 様々なAPIに対する同様のピース単位のデータ・アクセスは、TimesTenの以前のリリースからサポートされています(varデータ型の場合)。 |
例2-9 SQLPutDataの使用、ODBCのピース単位のデータ・インタフェース
このプログラムの抜粋では、SQLPutDataとSQLParamDataをポーリング・ループで使用して、LOBデータをピース単位でデータベースに挿入します。コードが実行されるとき、CLOB列には"123ABC"の値が含まれています。
...
/* create a table */
create_stmt = "create table clobtable ( c clob )";
rc = SQLExecDirect(hstmt, (SQLCHAR *)create_stmt, SQL_NTS);
if(rc != SQL_SUCCESS){/* ...error handling... */}
/* initialize an insert statement */
insert_stmt = "insert into clobtable values(?)";
rc = SQLPrepare(hstmt, (SQLCHAR *)insert_stmt, SQL_NTS);
if(rc != SQL_SUCCESS){/* ...error handling... */}
/* bind the parameter and specify that we will be using
* SQLParamData/SQLPutData */
rc = SQLBindParameter
hstmt, /* statement handle */
1, /* colnum number */
SQL_PARAM_INPUT, /* param type */
SQL_C_CHAR, /* C type */
SQL_LONGVARCHAR, /* SQL type (ignored) */
2, /* precision (ignored) */
0, /* scale (ignored) */
0, /* putdata token */
0, /* ignored */
&pcbvalue); /* indicates use of SQLPutData */
if(rc != SQL_SUCCESS){/* ...error handling... */}
pcbvalue = SQL_DATA_AT_EXEC;
/* execute the statement -- this should return SQL_NEED_DATA */
rc = SQLExecute(hstmt);
if(rc != SQL_NEED_DATA){/* ...error handling... */}
/* while we still have parameters that need data... */
while((rc = SQLParamData(hstmt, &unused)) == SQL_NEED_DATA){
memcpy(char_buf, "123", 3);
rc = SQLPutData(hstmt, char_buf, 3);
if(rc != SQL_SUCCESS){/* ...error handling... */}
memcpy(char_buf, "ABC", 3);
rc = SQLPutData(hstmt, char_buf, 3);
if(rc != SQL_SUCCESS){/* ...error handling... */}
}
...
パススルーLOB(TimesTenを介してアクセスされるOracle DatabaseのLOB)は、TimesTen LOBとして公開され、TimesTenによってTimesTen LOBとほぼ同じようにサポートされますが、次の点に注意してください。
TimesTen LOBのサイズ制限は、パススルーによるOracle DatabaseのLOBの格納には適用されません。
TimesTenのローカルLOBと同様に、アプリケーションで使用されるパススルーLOBは、トランザクションの終了後は有効ではありません。
実行したDML変更(更新、挿入または削除)が自動的にコミットされるよう、自動コミットはデフォルトで有効になっています(ODBCの指定に従って)。ただし、この機能を無効にして、変更を明示的にコミット(またはロールバック)することをお薦めします。これを設定するには、次のようにSQLSetConnectOptionコールでSQL_AUTOCOMMITオプションを使用します。
rc = SQLSetConnectOption(hdbc, SQL_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF);
自動コミットが無効になっている場合は、次のコミットの例のように、SQLTransact ODBC関数を使用してトランザクションをコミットまたはロールバックできます。
rc = SQLTransact(henv, hdbc, SQL_COMMIT);
これらの関数の詳細は、ODBC APIのリファレンス・マニュアルを参照してください。
|
注意:
|
トランザクションの追加情報は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のトランザクションの概要に関する説明を参照してください。
例2-10 データベースの更新および変更のコミット
この例では、選択した従業員の昇給を行う文を準備して実行した後、手動で変更をコミットします。自動コミットが事前に無効にされていることを前提としています。
update_example(SQLHDBC hdbc)
{
SQLCHAR* stmt_text;
SQLHSTMT hstmt;
SQLINTEGER raise_pct;
char hiredate_str[30];
SQLLEN hiredate_len;
SQLLEN numrows;
/* allocate a statement handle */
SQLAllocStmt(hdbc, &hstmt);
/* prepare an update statement to give raises to employees hired before a
* given date */
stmt_text = (SQLCHAR*)
"update employees "
"set salary = salary * ((100 + :raise_pct) / 100.0) "
"where hire_date < :hiredate";
SQLPrepare(hstmt, stmt_text, SQL_NTS);
/* bind parameter 1 (:raise_pct) to variable raise_pct */
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG,
SQL_DECIMAL, 0, 0, (SQLPOINTER)&raise_pct, 0, 0);
/* bind parameter 2 (:hiredate) to variable hiredate_str */
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_TIMESTAMP, 0, 0, (SQLPOINTER)hiredate_str,
sizeof(hiredate_str), &hiredate_len);
/* set parameter values to give a 10% raise to employees hired before
* January 1, 1996. */
raise_pct = 10;
strcpy(hiredate_str, "1996-01-01");
hiredate_len = SQL_NTS;
/* execute the update statement */
SQLExecute(hstmt);
/* print the number of employees who got raises */
SQLRowCount(hstmt, &numrows);
printf("Gave raises to %d employees.\n", numrows);
/* drop the statement handle */
SQLFreeStmt(hstmt, SQL_DROP);
/* commit the changes */
SQLTransact(henv, hdbc, SQL_COMMIT);
}
前述の項では、TimesTenデータを管理するための主な機能について説明しました。この項では、次にリストするその他の機能について説明します。
TimesTenでは、スタンドアロンまたはパッケージの一部であるPL/SQLプロシージャ(procname)またはPL/SQLファンクション(funcname)をコールするため、またはTimesTenの組込みプロシージャ(procname)をコールするための、すべてのプログラミング・インタフェースの次の各構文書式がサポートされています。
CALL procname[(argumentlist)] CALL funcname[(argumentlist)] INTO :returnparam CALL funcname[(argumentlist)] INTO ?
TimesTen ODBCでは、次の各構文書式もサポートされています。
{ CALL procname[(argumentlist)] }
{ ? = [CALL] funcname[(argumentlist)] }
{ :returnparam = [CALL] funcname[(argumentlist)] }
次のODBCの例では、TimesTen ttCkpt組込みプロシージャをコールします。
rc = SQLExecDirect (hstmt, (SQLCHAR*) "call ttCkpt",SQL_NTS);
これらの例では、PL/SQLプロシージャmyprocを2つのパラメータでコールします。
rc = SQLExecDirect(hstmt, (SQLCHAR*) "{ call myproc(:param1, :param2) }",SQL_NTS);
rc = SQLExecDirect(hstmt, (SQLCHAR*) "{ call myproc(?, ?) }",SQL_NTS);
PL/SQLファンクションmyfuncをコールするいくつかの方法を次に示します。
rc = SQLExecDirect (hstmt, (SQLCHAR*) "CALL myfunc() INTO :retparam",SQL_NTS);
rc = SQLExecDirect (hstmt, (SQLCHAR*) "CALL myfunc() INTO ?",SQL_NTS);
rc = SQLExecDirect (hstmt, (SQLCHAR*) "{ :retparam = myfunc() }",SQL_NTS);
rc = SQLExecDirect (hstmt, (SQLCHAR*) "{ ? = myfunc() }",SQL_NTS);
CALL構文の詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス』のCALLに関する説明を参照してください。
|
注意:
|
TimesTenには、実行するSQL文またはプロシージャ・コールの時間を制限する方法が2つあり、SQLExecute、SQLExecDirectまたはSQLFetchコールに適用されます。
前者の場合、タイムアウト期間に達すると、文の実行が停止し、エラーがスローされます。後者の場合、しきい値に達すると、SNMPトラップがスローされますが実行は継続されます。
タイムアウトまでのSQL文の実行時間を制御するには、SQLSetStmtOptionまたはSQLSetConnectOptionコールを使用してSQL_QUERY_TIMEOUTオプションを設定することで、タイムアウト値を秒単位で指定できます。値0はタイムアウトが発生しないことを示します。このような名前であるにもかかわらず、このタイムアウト値は問合せのみではなく、実行可能なすべてのSQL文に適用されます。
TimesTenでは、SqlQueryTimeout一般接続属性を使用することで、タイムアウト値を接続、つまり接続の任意の文に対して指定できます。(『Oracle TimesTen In-Memory Databaseリファレンス』のSqlQueryTimeoutに関する説明も参照してください。)SQL_QUERY_TIMEOUTオプションを指定したSQLSetConnectOptionのコールは、前の問合せタイムアウトの設定を上書きします。SQL_QUERY_TIMEOUTオプションを指定したSQLSetStmtOptionのコールは、特定の文の接続設定を上書きします。
問合せのタイムアウト制限は、SQL文がアクティブに実行されている場合にのみ有効です。コミット中またはロールバック中にはタイムアウトは発生しません。多数の行に対して更新、削除または挿入を行うトランザクションでは、コミットまたはロールバックが完了するまでに時間がかかる場合があります。その間、タイムアウト値は無視されます。
|
注意: ロック・タイムアウト値およびSQL問合せタイムアウト値の両方が指定されている場合は、まず、2つの値の小さい方の値によってタイムアウトが発生します。ロック・タイムアウトについては、『Oracle TimesTen In-Memory Databaseリファレンス』のttLockWait(組込みプロシージャ)またはLockWait(一般接続属性)に関する説明、またはOracle TimesTen In-Memory Databaseトラブルシューティング・ガイドのデッドロックとタイムアウトの確認に関する説明を参照してください。 |
SQL文の実行が指定期間(秒単位)を超えた場合に、サポート・ログに警告を書き込んでSNMPトラップをスローするように、TimesTenを構成できます。実行は継続され、しきい値による影響は受けません。
このSNMPトラップの名前はttQueryThresholdWarnTrapです。SNMPトラップの構成方法については、『Oracle TimesTen In-Memory Databaseエラー・メッセージおよびSNMPトラップ』参照してください。このような名前であるにもかかわらず、このしきい値は実行可能なすべてのSQL文に適用されます。
デフォルトでは、アプリケーションはしきい値をQueryThreshold一般接続属性設定から取得します(『Oracle TimesTen In-Memory Databaseリファレンス』のQueryThresholdに関する説明を参照)。SQLSetConnectOptionコールでTT_QUERY_THRESHOLDオプションを設定すると、現在の接続の接続属性の設定が上書きされます。
SQLSetConnectOptionでしきい値を設定するには、次のように入力します。
RETCODE SQLSetConnectOption(hdbc, TT_QUERY_THRESHOLD, seconds);
SQLSetStmtOptionコールでTT_QUERY_THRESHOLDオプションを設定すると、その文に対する接続属性の設定およびSQLSetConnectOptionによる設定が上書きされます。この設定は、ODBC文ハンドルを使用して実行されるSQL文に適用されます。
SQLSetStmtOptionでしきい値を設定するには、次のように入力します。
RETCODE SQLSetStmtOption(hstmt, TT_QUERY_THRESHOLD, seconds);
SQLGetConnectOptionまたはSQLGetStmtOption ODBC関数を使用して、TT_QUERY_THRESHOLDの現在の値を取得できます。
RETCODE SQLGetConnectOption(hdbc, TT_QUERY_THRESHOLD, paramvalue); RETCODE SQLGetStmtOption(hstmt, TT_QUERY_THRESHOLD, paramvalue);
この項では、TimesTen Cacheの使用に関する機能について説明します。
TimesTen Cacheの詳細は、『Oracle TimesTen Application-Tier Database Cacheユーザーズ・ガイド』を参照してください。
一般接続属性の詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』のパススルーに関する説明を参照してください。パススルー設定の詳細は、『Oracle TimesTen Application-Tier Database Cacheユーザーズ・ガイド』のパススルー・レベルの設定に関する説明を参照してください。
TimesTenでは、パススルー・レベルを一時的に設定するためのPassThroughフラグを含む、様々なフラグを設定するためのttOptSetFlag組込みプロシージャが提供されています。次の例のとおり、ttOptSetFlagを使用して、CアプリケーションでPassThroughを設定できます(この例では、パススルー・レベルは1に設定されます)。この設定によって、トランザクションが終了するまで、準備されたすべての文に適用されます。
rc = SQLExecDirect (hstmt, "call ttOptSetFlag ('PassThrough', 1)",SQL_NTS);
この組込みプロシージャの詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』のttOptSetFlagに関する説明を参照してください。
SQL文がTimesTenデータベースで実行されるか、またはOracle Databaseにパススルーされて実行されるかを確認するには、TT_STMT_PASSTHROUGH_TYPE文オプションを指定したODBC関数SQLGetStmtOptionをコールします。これは次の例のようになります。
rc = SQLGetStmtOption(hStmt, TT_STMT_PASSTHROUGH_TYPE, &passThroughType);
SQL文の準備の後に、このコールを実行できます。これは、PassThrough設定1、2、4または5の場合(文が実際にパススルーされるかどうかの確認がコンパイル時まで行われない)に有効です。TT_STMT_PASSTHROUGH_NONEが返された場合、文はTimesTenで実行されます。TT_STMT_PASSTHROUGH_ORACLEが返された場合、文はOracle Databaseにパススルーされて実行されます。
|
注意: TT_STMT_PASSTHROUGH_TYPEは、SQLGetStmtOptionでのみサポートされていて、SQLSetStmtOptionではサポートされていません。 |
TimesTen Cacheでは、FLUSH CACHE GROUP、LOAD CACHE GROUP、REFRESH CACHE GROUPまたはUNLOAD CACHE GROUP文の実行の後、ODBC関数SQLRowCountを使用するとフラッシュ、ロード、リフレッシュまたはアンロードされたキャッシュ・インスタンスの数が返されます。
詳細は、『Oracle TimesTen Application-Tier Database Cacheユーザーズ・ガイド』の処理の影響を受けるキャッシュ・インスタンスの数の確認に関する項を参照してください。
SQLRowCountの全般的な情報については、ODBC APIのリファレンス・マニュアルを参照してください。
TimesTenによるODBCの拡張によって、アプリケーションで言語ソート、文字列の長さセマンティクス、およびキャラクタ・セット変換中のエラー・レポートに関するオプションを設定できます。これらのオプションは、SQLSetConnectOptionへのコールで使用できます。オプションは、timesten.hファイル(「TimesTen includeファイル」を参照)で定義します。
言語ソート、長さセマンティクスおよびキャラクタ・セットの詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のグローバリゼーション・サポートに関する項を参照してください。
この項では、次のTimesTen ODBCグローバリゼーション・サポートについて説明します。
このオプションには、言語比較で使用する照合順番を指定します。サポートされている言語ソートについては、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』の単一言語ソートに関する説明および多言語ソートに関する説明を参照してください。
このオプションには、文字列値を指定します。デフォルトはBINARYです。
また、同じ機能を持つNLS_SORT一般接続属性の説明も参照してください(『Oracle TimesTen In-Memory Databaseリファレンス』のNLS_SORTに関する説明を参照)。実行時オプションのTT_NLS_SORTは、NLS_SORT接続属性より優先されることに注意してください。
このオプションには、バイト・セマンティクスを使用するか、キャラクタ・セマンティクスを使用するかを指定します。指定できる値は次のとおりです。
TT_NLS_LENGTH_SEMANTICS_BYTE (デフォルト)
TT_NLS_LENGTH_SEMANTICS_CHAR
また、同じ機能を持つNLS_LENGTH_SEMANTICS一般接続属性の説明も参照してください(『Oracle TimesTen In-Memory Databaseリファレンス』のNLS_LENGTH_SEMANTICSに関する説明を参照)。実行時オプションのTT_NLS_LENGTH_SEMANTICSは、NLS_LENGTH_SEMANTICS接続属性より優先されることに注意してください。
このオプションでは、SQL処理中に、NCHARまたはNVARCHAR2データとCHARまたはVARCHAR2データの間の暗黙的または明示的なキャラクタ・タイプの変換中にデータが消失した場合に、エラーがレポートされるかどうかを指定します。このオプションは、バインドの結果としてのODBCによる変換には適用されません。
指定できる値は次のとおりです。
TRUE: 変換中のエラーがレポートされます。
FALSE: 変換中のエラーはレポートされません(デフォルト)。
また、同じ機能を持つNLS_NCHAR_CONV_EXCP一般接続属性の説明も参照してください(『Oracle TimesTen In-Memory Databaseリファレンス』のNLS_NCHAR_CONV_EXCPに関する説明を参照)。実行時オプションのTT_NLS_NCHAR_CONV_EXCPは、NLS_NCHAR_CONV_EXCP接続属性より優先されることに注意してください。
レプリケーションを使用するアプリケーションの場合、parallel replicationを使用することでパフォーマンスを向上させることができます。これは、トランザクションの変更をレプリケーション・スキーム内のノードにレプリケートおよび適用するために並行して動作する複数のスレッドを使用します。TimesTenでは、次のタイプのパラレル・レプリケーションをサポートしています。
自動パラレル・レプリケーション(ReplicationApplyOrdering=0): トランザクションの依存性と、コミット順に適用されたすべての変更を自動的に適用する、複数のスレッドにおけるパラレル・レプリケーション。これはデフォルトです。
コミット依存性を無効にした自動パラレル・レプリケーション(ReplicationApplyOrdering=2): トランザクションの依存性を自動的に強制するが、サブスクライバ・データベース上でマスター・データベース上と同じ順序でコミットされるトランザクションは強制しない、複数スレッドでのパラレル・レプリケーション。このモードでは、オプションでレプリケーション・トラックを指定できます。
ユーザー定義のパラレル・レプリケーション(ReplicationApplyOrdering=1): クラシック・レプリケーション・スキームを使用し、トランザクションの依存性の予測性が高く、レシーバでのコミット順序が元のデータベース上のコミット順序と同じである必要がないアプリケーションの場合。トランザクションの追跡数を指定し、各追跡に特定のトランザクションを適用できます。すべての追跡の読取り、送信および適用はパラレルに行われます。
詳細および使用シナリオについては、『Oracle TimesTen In-Memory Database開発者および管理者ガイド』のパラレル・レプリケーションの構成に関する説明を参照してください。
|
注意: ユーザー定義のパラレル・レプリケーションは通常、お薦めできません。レプリケーション・ノード間のデータの相違を回避するために注意する必要があるためです。 |
パラレル・レプリケーションを使用し、レプリケーション・トラックを指定するODBCアプリケーションでは、TT_REPLICATION_TRACK接続オプションを使用した接続時のトランザクションのトラック番号を指定できます(「SQLSetConnectOptionおよびSQLGetConnectOption用のオプションのサポート」を参照)。(または、一般接続属性ReplicationTrackまたはALTER SESSIONのパラメータREPLICATION_TRACKを使用します。)
ODBC 2.0以下のリリースで使用されていたデータ型は、ISO 92標準に準拠するために名前が変更されています。TimesTenに付属のサンプル・プログラムは、SQL 3.0データ型を使用して記述されています。次の表に、2.0データ型およびそれに対応する3.0データ型を示します。
TimesTenでは、ODBC 2.5、拡張レベル1がサポートされており、拡張レベル2用の追加機能もありますが、これらの機能については、第10章「TimesTen ODBC関数およびオプション」を参照してください。
| ODBC 2.0データ型 | ODBC 3.0データ型 |
|---|---|
HDBC |
SQLHDBC |
HENV |
SQLHENV |
HSTMT |
SQLHSTMT |
HWND |
SQLHWND |
LDOUBLE |
SQLDOUBLE |
RETCODE |
SQLRETURN |
SCHAR |
SQLSCHAR |
SDOUBLE |
SQLFLOATS |
SDWORD |
SQLINTEGER |
SFLOAT |
SQLREAL |
SWORD |
SQLSMALLINT |
UCHAR |
SQLCHAR |
UDWORD |
SQLUINTEGER |
UWORD |
SQLUSMALLINT |
いずれのバージョンのデータ型もTimesTenで制限なしに使用される場合があります。
また、ODBC 2.0のドキュメントに記載されているFAR修飾子は必要ないことにも注意してください。
TimesTenには、表、ビュー、マテリアライズド・ビュー、順序、シノニムなどのデータベース・オブジェクトについて、オブジェクト・レベルの解決法でデータベース・アクセスを制御する機能が含まれています。これらの機能の概要は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のアクセス制御の管理に関する項を参照してください。
この項では、SQL処理、データベース接続、XLAおよびCユーティリティ関数に関連するアクセス制御について説明します。
このマニュアルで説明されている、または例で使用されている問合せ、SQL DMLまたはDDL文では、ユーザーは、その文の実行のために適切な権限を持っていることを前提としています。たとえば、表に対するSELECT文では、その表の所有権、その表に関して付与されているSELECT権限またはSELECT ANY TABLEシステム権限が必要です。同様に、DML文にはその表の所有権、その表に関して付与されている適切なDML権限(UPDATEなど)または適切なANY TABLE権限(UPDATE ANY TABLEなど)が必要です。
DDL文の場合、CREATE TABLEにはユーザー・スキーマのCREATE TABLE権限またはその他のスキーマのCREATE ANY TABLE権限が必要です。ALTER TABLEには、所有権またはALTER ANY TABLEシステム権限が必要です。DROP TABLEには、所有権またはDROP ANY TABLEシステム権限が必要です。オブジェクト・レベルのALTER権限またはDROP権限はありません。
特定のSQL文に必要な権限については、『Oracle TimesTen In-Memory Database SQLリファレンス・ガイド』のSQL文に関する項を参照してください。
権限は、SQLのGRANT文で付与され、REVOKE文で取り消されます。一部の権限は、各ユーザーがメンバーであるPUBLICロールを介して、すべてのユーザーに付与されます。このロールの詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス・ガイド』のPUBLICロールに関する項を参照してください。
また、アクセス制御は、このマニュアルで説明している次の内容に関係します。
データベースへの接続: 「接続のアクセス制御」を参照してください。
接続属性の設定: 「プログラムでの接続属性の設定」を参照してください。
XLAの構成および管理とXLA関数の使用: 「アクセス制御がXLAに与える影響」を参照してください。第9章「XLAリファレンス」も参照してください。各XLA関数のドキュメントは、必要な権限を示しています。
Cユーティリティ関数の実行: 第8章「TimesTenユーティリティAPI」を参照してください。各ユーティリティのドキュメントは、権限が必要かどうかを示しています。
|
注意:
|
この項の内容は次のとおりです。
アプリケーションでは、コールのたびにエラーおよび警告をチェックする必要があります。これによって、開発およびデバッグ時に時間および労力が大幅に節約されます。TimesTenに付属のデモ・プログラムには、エラー・チェックの例が含まれています。
エラーは、install_dir/include/tt_errCode.hファイルで定義されているTimesTenエラー・コード(エラー番号)またはエラー文字列のいずれかを使用してチェックできます。エントリの書式は次のとおりです。
#define tt_ErrMemoryLock 712
各メッセージについては、『Oracle TimesTen In-Memory Databaseエラー・メッセージおよびSNMPトラップ』のエラーおよび警告のリストに関する項を参照してください。
ODBC関数をコールした後、リターン・コードを確認します。リターン・コードがSQL_SUCCESSでない場合は、ODBC関数SQLErrorをコールするエラー処理ルーチンを使用して、関連するODBCハンドルのエラーを取得します。1回のODBCコールで、複数のエラーが返される場合もあります。アプリケーションは、すべてのエラーがエラー・スタックから読み取られるまでSQLError関数を繰り返しコールしてすべてのエラーを返すように記述されている必要があります。リターン・コードがSQL_NO_DATA_FOUNDになるまで、SQLErrorをコールし続けます。
SQLError関数およびその引数の詳細は、ODBC APIのリファレンス・マニュアルを参照してください。
一般的なODBCエラーを処理する関数の作成方法については、『Oracle TimesTen In-Memory Databaseエラー・メッセージおよびSNMPトラップ』のエラーおよび警告の取得に関する項を参照してください。
例2-11 ODBC関数コールでのエラーの確認
この例では、SQLAllocConnectをコールした後にエラー状況を確認できることを示しています。エラーが見つかった場合、エラー・メッセージが表示され、プログラムの実行は終了します。
rc = SQLAllocConnect(henv, &hdbc);
if (rc != SQL_SUCCESS) {
handleError(rc, henv, hdbc, hstmt, err_buf, &native_error);
fprintf(stderr,
"Unable to allocate a connection handle:\n%s\n",
err_buf);
exit(-1);
}
操作が完全には成功しない場合、TimesTenは、致命的なエラー、致命的ではないエラーまたは警告を返すことができます。
致命的なエラーとは、エラー・リカバリが終わるまでデータベースにアクセスできなくなるエラーのことです。致命的なエラーが発生すると、すべてのデータベースの接続を切断する必要があります。それ以後の処理は完了されません。致命的なエラーは、TimesTenのエラー・コード846および994で示されます。これらのエラーの処理は、標準的なエラーの処理とは異なります。特に、アプリケーションのエラー処理コードは、現行のトランザクションをロールバックし、データベースから切断する必要があります。
「致命的なエラーからのリカバリ」も参照してください。
致命的ではないエラーには、一意制約に違反しているINSERT文などの単純なエラーが含まれます。また、一部のアプリケーション障害およびプロセス障害も、致命的ではないエラーに含まれます。
TimesTenは、通常のエラー処理プロセスを通して致命的ではないエラーを返します。アプリケーションはエラーがないか確認し、適切に処理する必要があります。
致命的ではないエラーによってデータベースに影響が出た場合、エラーが返されることがあり、アプリケーションで適切に対処する必要があります。
アプリケーションでは、その処理を変更するか、または障害が発生した1つ以上のトランザクションをロールバックすることによって、致命的ではないエラーに対処できます。
致命的なエラーが発生した場合、TimesTenは、次の完全なクリーンアップおよびリカバリ・プロシージャを実行します。
データベースに対するすべての接続を無効化します。サーバーでのメモリー不足状態を回避するには、無効になったデータベースからアプリケーションを切断する必要があります。古いTimesTenインスタンスの共有メモリーは、エラー発生時にアクティブだったすべての接続が切断されるまで解放されません。古いTimesTenインスタンスに依然として接続されている非アクティブなアプリケーションは、手動で終了する必要があることがあります。
その後の最初の初期接続時に、チェックポイント・ファイルおよびトランザクション・ログ・ファイルからデータベースをリカバリします。
リカバリされたデータベースには、永続コミットされたすべてのトランザクションの状態が反映されます。また、非永続的にコミットされた一部のトランザクションも反映されます。
コミットされていないトランザクションまたはロールバックされたトランザクションは反映されません。
自動クライアント・フェイルオーバーは、TimesTenアクティブ・スタンバイ・ペア・レプリケーション構成での高可用性シナリオで使用されます。アクティブ・ノードに障害が発生した場合、新しいアクティブ(元のスタンバイ)・ノードへのフェイルオーバー(転送)が発生し、アプリケーションは新しいアクティブ・ノードに自動的に再接続されます。TimesTenは自動クライアント・フェイルオーバーが発生したときに、アプリケーションに警告を渡す機能を提供しているため、アプリケーションは適切な処理を行うことができます。
この項では、アプリケーション開発者に適用されるTimesTenでの自動クライアント・フェイルオーバーの実装を取り上げ、次のことについて説明します。
この機能の詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』の自動クライアント・フェイルオーバーの使用に関する説明を参照してください。
アプリケーションがまずアクティブ・ノードに接続すると、接続が登録され、この登録はスタンバイ・ノードにレプリケートされます。アクティブ・ノードで障害が発生すると、スタンバイ・ノードが新しいアクティブ・ノードになり、フェイルオーバーのことがクライアントに通知されます。この時点で、次の点に注意してください。
クライアントは新しいアクティブ・ノードに対して新しく接続しますが、以前と同じODBC接続ハンドルを使用します。ハンドル自体以外は、元の接続の状態は保持されません。アプリケーションは、新しいODBC文ハンドルをオープンする必要があります。
関数が登録された場合に、アプリケーションに関連付けられたフェイルオーバー・イベント関数を起動するフェイルオーバー・リスナー・スレッドが各クライアントにあります。(「フェイルオーバーのコールバック関数」を参照してください。)
元の接続からのすべてのクライアント文ハンドルは、無効とマークされます。これらの文ハンドルに対してAPIコールを実行すると、通常は次のように、tt_errCode.hで定義されている個別のフェイルオーバー・エラー・コードがSQL_ERRORとともに返されます。
SQLSTATE = S1000 "General Error", native error = tt_ErrFailoverInvalidation
SQLErrorおよびSQLFreeStmtコールについては例外で、通常どおり動作します。
また、次の点にも注意してください。
元のアクティブ・ノードに対するソケットは閉じられます。SQLDisconnectのコールは試行されません。
新しいアクティブな(元のスタンバイ) TimesTenノードに接続する場合、新しいサーバーDSNを指定するときを除き、元の接続リクエストから返された同じ接続文字列が使用されます。
新しい文ハンドルをオープンして必要なSQLPrepareコールを再実行するかどうかは、アプリケーション次第です。
フェイルオーバーがすでに発生し、クライアントがすでに新しいアクティブ・ノードに接続されている場合、次のフェイルオーバー・リクエストでは、元のアクティブ・ノードへの再接続が試みられます。再接続に失敗した場合、タイムアウトになるまで2つのサーバーへの接続の試行が交互に行われ、この間は接続はブロックされます。タイムアウト値は、TimesTenクライアント接続属性TTC_Timeout (デフォルトは60秒)に従いますが、TTC_Timeoutの設定にかかわらず、最小値は60秒です。(この属性の詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』のTTC_Timeoutに関する説明を参照してください。)
フェイルオーバー接続は、事前に作成されるのではなく、必要に応じてのみ作成されます。
フェイルオーバーの間、TimesTenは登録されているユーザー定義関数に対してコールバックを行います。この関数は、フェイルオーバーが発生している状況で実行する必要があるカスタム処理を行います。(「フェイルオーバーのコールバック関数」を参照してください。)
次に示すパブリック接続オプションは、新しい接続に伝播されます。該当する場合は、対応する一般接続属性をカッコ内に示しています。TT_REGISTER_FAILOVER_CALLBACKオプションは、コールバック関数を登録するために使用します。
SQL_ACCESS_MODE SQL_AUTOCOMMIT SQL_TXN_ISOLATION (Isolation) SQL_OPT_TRACE SQL_QUIET_MODE TT_PREFETCH_CLOSE TT_CLIENT_TIMEOUT (TTC_TIMEOUT) TT_REGISTER_FAILOVER_CALLBACK
次に示すオプションは、接続属性またはSQLSetConnectOptionコールで設定されている場合には新しい接続に伝播されますが、TimesTen組込みプロシージャまたはALTER SESSIONで設定されている場合には新しい接続に伝播されません。
TT_NLS_SORT (NLS_SORT) TT_NLS_LENGTH_SEMANTICS (NLS_LENGTH_SEMANTICS) TT_NLS_NCHAR_CONV_EXCP (NLS_NCHAR_CONV_EXCP) TT_DYNAMIC_LOAD_ENABLE (DynamicLoadEnable) TT_DYNAMIC_LOAD_ERROR_MODE (DynamicLoadErrorMode)
次に示すオプションは、接続ハンドルで設定されている場合には新しい接続に伝播されます。
SQL_QUERY_TIMEOUT TT_PREFETCH_COUNT
詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』の自動クライアント・フェイルオーバーの構成に関する説明を参照してください。
|
注意: TTC_Server2、TTC_Server_DSN2またはTCP_Port2のいずれかを設定することは、暗黙的に次のことを意味します。
|
フェイルオーバーが発生すると、TimesTenは目的の処理を行うためにユーザー定義関数に対してコールバックを行います。この関数は、新しいアクティブな(元のスタンバイ)ノードへの接続試行が開始されたときにコールされ、接続の試行が完了した後に再度コールされます。たとえば、文ハンドルを正常にリストアするために、この関数を使用できます。
関数APIの定義は次のとおりです。
typedef SQLRETURN (*ttFailoverCallbackFcn_t) (SQLHDBC, /* hdbc */ SQLPOINTER, /* foCtx */ SQLUINTEGER, /* foType */ SQLUINTEGER); /* foEvent */
各要素の意味は次のとおりです。
hdbcは、障害が発生した接続のODBC接続ハンドルです。
foCtxは、アプリケーション定義のデータ構造体に対するポインタで、必要に応じて使用します。
foTypeは、フェイルオーバーのタイプです。これに対して、TimesTenでサポートされている値はTT_FO_SESSIONのみであり、セッションが再確立されます。この場合、文の再準備は行われません。
foEventは、サポートされている次の値を使用して、発生したイベントを示します。
TT_FO_BEGIN: フェイルオーバーの開始。
TT_FO_ABORT: フェイルオーバーの失敗。TTC_Timeoutで指定した時間(アクティブ・スタンバイ・フェイルオーバーの最小値である60秒)の間、再試行が実行されましたが成功しませんでした。
TT_FO_END: フェイルオーバーの正常終了。
TT_FO_ERROR: フェイルオーバー接続に失敗しましたが、再試行されます。
TT_FO_REAUTHはTimesTenクライアント・フェイルオーバーではサポートされないことに注意してください。
コールバック関数を登録するには、SQLSetConnectOptionコールを使用してTimesTen TT_REGISTER_FAILOVER_CALLBACKオプションを設定し、指定するオプション値はCデータ型の構造体ttFailoverCallback_tへのポインタで、この構造体はtimesten.hファイルに次のように定義されており、コールバック関数を参照します。
typedef struct{
SQLHDBC appHdbc;
ttFailoverCallbackFcn_t callbackFcn;
SQLPOINTER foCtx;
} ttFailoverCallback_t;
各要素の意味は次のとおりです。
appHdbcはODBC接続ハンドルであり、SQLSetConnectOptionコール・シーケンスのhdbcと同じ値である必要があります。(これは、ドライバ・マネージャを使用している場合のドライバ・マネージャの実装詳細のために、データ構造体で必要になります。)
callbackFcnは、コールバック関数を指定します。(NULLに設定すると、指定した接続のコールバックが取り消されます。フェイルオーバーは変わらずに発生しますが、アプリケーションが通知を受けることはありません。)
foCtxは、前述の関数で説明したように、アプリケーション定義のデータ構造体に対するポインタです。
コールバックを必要とする接続ごとに、TT_REGISTER_FAILOVER_CALLBACKを設定します。ttFailoverCallback_t構造体の値は、SQLSetConnectOptionコールが実行されるときにコピーされます。アプリケーションで構造体を保持する必要はありません。TT_REGISTER_FAILOVER_CALLBACKが接続に対して複数回設定されている場合、最後の設定が優先されます。
|
注意:
|
例2-12 フェイルオーバーのコールバック関数および登録
この例では次の機能を示しています。
グローバルに定義されるユーザー構造体タイプFOINFO、およびタイプFOINFOの構造体変数foStatus
フェイルオーバーが発生すると常にfoStatus構造体を更新するコールバック関数FailoverCallback()
登録関数RegisterCallback()。次の処理を行います。
タイプttFailoverCallback_tの構造体failoverCallbackを宣言します。
foStatus値を初期化します。
接続ハンドル、foStatusへのポインタおよびコールバック関数(FailoverCallback)で構成されるfailoverCallbackデータ値を設定します。
SQLSetConnectOptionコールを使用してコールバック関数を登録し、TT_REGISTER_FAILOVER_CALLBACKをfailoverCallbackへのポインタとして設定します。
/* user defined structure */
struct FOINFO
{
int callCount;
SQLUINTEGER lastFoEvent;
};
/* global variable passed into the callback function */
struct FOINFO foStatus;
/* the callback function */
SQLRETURN FailoverCallback (SQLHDBC hdbc,
SQLPOINTER pCtx,
SQLUINTEGER FOType,
SQLUINTEGER FOEvent)
{
struct FOINFO* pFoInfo = (struct FOINFO*) pCtx;
/* update the user defined data */
if (pFoInfo != NULL)
{
pFoInfo->callCount ++;
pFoInfo->lastFoEvent = FOEvent;
printf ("Failover Call #%d\n", pFoInfo->callCount);
}
/* the ODBC connection handle */
printf ("Failover HDBC : %p\n", hdbc);
/* pointer to user data */
printf ("Failover Data : %p\n", pCtx);
/* the type */
switch (FOType)
{
case TT_FO_SESSION:
printf ("Failover Type : TT_FO_SESSION\n");
break;
default:
printf ("Failover Type : (unknown)\n");
}
/* the event */
switch (FOEvent)
{
case TT_FO_BEGIN:
printf ("Failover Event: TT_FO_BEGIN\n");
break;
case TT_FO_END:
printf ("Failover Event: TT_FO_END\n");
break;
case TT_FO_ABORT:
printf ("Failover Event: TT_FO_ABORT\n");
break;
case TT_FO_REAUTH:
printf ("Failover Event: TT_FO_REAUTH\n");
break;
case TT_FO_ERROR:
printf ("Failover Event: TT_FO_ERROR\n");
break;
default:
printf ("Failover Event: (unknown)\n");
}
return SQL_SUCCESS;
}
/* function to register the callback with the failover connection */
SQLRETURN RegisterCallback (SQLHDBC hdbc)
{
SQLRETURN rc;
ttFailoverCallback_t failoverCallback;
/* initialize the global user defined structure */
foStatus.callCount = 0;
foStatus.lastFoEvent = -1;
/* register the connection handle, callback and the user defined structure */
failoverCallback.appHdbc = hdbc;
failoverCallback.foCtx = &foStatus;
failoverCallback.callbackFcn = FailoverCallback;
rc = SQLSetConnectOption (hdbc, TT_REGISTER_FAILOVER_CALLBACK,
(SQLULEN)&failoverCallback);
return rc;
}
フェイルオーバーが発生すると、コールバック関数は次のような出力を生成します。
Failover Call #1 Failover HDBC : 0x8198f50 Failover Data : 0x818f8ac Failover Type : TT_FO_SESSION Failover Event: TT_FO_BEGIN