ヘッダーをスキップ
Oracle® TimesTen In-Memory Database TTClassesガイド
11gリリース2 (11.2.2)
B66724-05
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

2 TTClassesについての理解とその使用方法

この章では、TTClassesの概要とベスト・プラクティスについて説明します。内容は次のとおりです。

TTClassesの概要

TimesTen C++ Interface Classesライブラリ(TTClasses)は、データベースへのアクセスに使用する最も一般的なODBC機能のラッパーを提供します。これは、ODBCよりも使用しやすく、パフォーマンスも低下させないAPIに対する需要に応えるために開発されました。

ODBCの詳細は、ODBC APIのリファレンス・マニュアルを参照してください。TimesTenでは、ODBC 2.5、拡張レベル1と、『Oracle TimesTen In-Memory Database C開発者ガイド』のTimesTen ODBC関数およびオプションに関する説明に示されている拡張レベル2の追加機能がサポートされています。

TTClassesは、TimesTenのODBCインタフェースにC++インタフェースを提供するだけでなく、TimesTenのトランザクション・ログAPI(XLA)へのインタフェースも提供します。XLAではデータベース内の1つ以上の表を監視できます。その表が他のアプリケーションによって変更されると、その変更がXLAを介して監視アプリケーションに通知されます。XLA機能が最も一般的に使用される局面に対して、TTClassesは便利なインタフェースを提供します。XLAの一般的な情報については、『Oracle TimesTen In-Memory Database C開発者ガイド』のXLAおよびTimesTenのイベント管理に関する説明を参照してください。

TTClassesは、TimesTen Data Managerを使用するアプリケーション・ソフトウェアを作成する際のベスト・プラクティスの推進も目的としています。このライブラリは、TimesTenを最適な方法で使用します。たとえば、自動コミットはデフォルトでは無効化されています。パラメータ化されたSQLが推奨されており、TTClassesでのその使用方法は、手動でコーディングされたODBCよりはるかに簡単になっています。

TTCmd、TTConnectionおよびTTConnectionPoolの使用

TTClassesは様々な方法で使用可能ですが、次の一般的な方法は成功実績があり、様々なアプリケーションで簡単に適用できます。

リアルタイム・アプリケーションでは、最適なパフォーマンスを得るために、準備済のSQL文を使用する必要があります。アプリケーションで使用されるすべてのSQL文について、文ごとに個別のTTCmdオブジェクトを使用して、アプリケーションの開始時に準備するのが理想的です。ODBCでは(したがってTTClassesでも)、文が特定の接続にバインドされるため、アプリケーションで使用される文の完全なセットが、データベースとのすべての接続に関連付けられるということがよく起こります。

これを実現する簡単な方法は、TTConnectionから導出されるアプリケーション固有のクラスを開発することです。たとえば、XYZという名前のアプリケーションには、XYZConnectionというクラスを作成できます。XYZConnectionクラスには、アプリケーションで使用する準備済のSQL文を表すプライベートTTCmdメンバーを含め、これでは、これらのプライベートTTCmdメンバーを介してアプリケーション固有のデータベース機能を実装する新しいパブリック・メソッドを提供します。

TTCmdオブジェクトは、使用前にSQL文(SELECTINSERTUPDATEまたはDELETE)と関連付ける必要があります。関連付けはPrepare()メソッドを使用して行います。これによってSQL文がコンパイルおよび最適化され、SQL文が効率的に実行されるようになります。Prepare()メソッドは文を準備するだけで、文を実行しない点に注意してください。

通常、TimesTenでは、性能の向上のために文はパラメータ化されます。次のようなSQL文を考えてみます。

SELECT col1 FROM table1 WHERE C = 10;
SELECT col1 FROM table1 WHERE C = 11;

これよりも、パラメータ化された1つの文を準備し、それを複数回実行した方がより効率的です。

SELECT col1 FROM table1 WHERE C = ?;

「?」の値は、TTCmd::setParam()メソッドを使用して実行時に指定します。

ODBCを直接使用する場合と違い、列またはパラメータを明示的にSQL文にバインドする必要はありません。TTCmdは、準備する際にすべての必要な列を自動的に定義しバインドします。パラメータは実行時にバインドされます。

準備は比較的負荷の高い操作であることに注意してください。アプリケーションは、(TTConnection::Connect()を使用して)TimesTenへの接続を確立する際に、その接続に関連付けられたすべてのTTCmdオブジェクトを準備する必要があります。アプリケーションのこのメイン実行ループの前に、すべてのSQL文を準備してください。

通常の操作の場合(TTEXCEPTフラグを使用してTTClassesおよびアプリケーションがコンパイルされる)、この操作中にエラーまたは警告が発生すると、TTStatusオブジェクトがスローされます。通常、TTClassesメソッドでエラーまたは警告が発生すると、この方法で例外がスローされます(アプリケーションはそれを適切に取得して処理する必要があります)。詳細は、「TTEXCEPT: C++例外のスロー」「TTStatus」を参照してください。TTClassesのクイック・スタート・デモ・アプリケーションでも、これの処理例を確認できます。(「TimesTen TTClassesデモについて」を参照してください。)


注意:

必要な特定のgetまたはsetメソッドがTTConnectionまたはTTCmdにない場合は、TTConnection::getHdbc()およびTTCmd::getHandle()メソッドを使用して、基礎となるODBC接続ハンドルおよび文ハンドルに直接アクセスできます。同様に、ODBC環境ハンドルにはTTGlobal::sqlhenv()メソッドでアクセスします。

例2-1 接続クラスの定義

TTConnectionから継承されるクラスの例を次に示します。

class XYZConnection : public TTConnection {
private:
  TTCmd updateData;
  TTCmd insertData;
  TTCmd queryData;

public:
  XYZConnection();
  ~XYZConnection();
  virtual void Connect (const char* connStr, const char* user, const char* pwd);
  void updateUser ();
  void addUser (char* nameP);
  void queryUser (const char* nameP, int* valueP);
};

この例では、XYZConnectionオブジェクトがTimesTenへの接続であり、アプリケーション固有の3つの操作(addUser()updateUser()およびqueryUser())の実行に使用できるようになっています。これらの操作はXYZアプリケーションに固有です。これらの3つのメソッドの実装では、アプリケーションのデータベース操作を実装するために、updateDatainsertDataおよびqueryData TTCmdオブジェクトを使用できます。

アプリケーションのSQL文を準備するために、XYZConnectionクラスは、TTConnection基本クラスから提供されるConnect()メソッドをオーバーロードします。XYZConnection::Connect()メソッドは、データベース接続を確立するために、基本クラスのConnect()メソッドをコールし、さらに、TTCmdオブジェクトごとにPrepare()メソッドもコールして、後で使用するSQL文を準備します。

例2-2 Connect()メソッドの定義

次に、XYZConnection::Connect()メソッドの実装例を示します。

void
XYZConnection::Connect(const char* connStr, const char* user, const char* pwd)
{
  try {
    TTConnection::Connect(connStr, user, pwd);
    updateData.Prepare(this, "update mydata v set foo = ? where bar = ?");
    insertData.Prepare(this, "insert into mydata values(?,0)");
    queryData.Prepare(this, "select i from mydata where name = ?");
  }
  catch (TTStatus st) {
    cerr << "Error in XYZConnection::Connect: " << st << endl;
  }
  return;
}

このConnect()メソッドにより、XYZConnectionオブジェクトとそのアプリケーション固有のメソッドが完全に動作可能になります。

この方法は、TTConnectionPoolクラスの設計でも非常に有効です。アプリケーションは、XYZConnection型のオブジェクトを多数作成し、それらをTTConnectionPoolオブジェクトに追加できます。TTConnectionPool::ConnectAll()がコールされると、アプリケーションはプール内のデータベースへのすべての接続を接続し、すべてのSQL文を準備します。切断するには、TTConnectionPool::DisconnectAll()を使用します。「TTConnectionPool」の使用方法の説明を参照してください(重要な情報があります)。

このアプリケーションの設計により、データベースへのアクセスがアプリケーションのビジネス・ロジックから簡単に分離できます。XYZConnectionクラスのみに、データベース固有のコードが含まれるようになります。

このアプリケーション設計の例は、TimesTenクイック・スタートに付属のいくつかのTTClassesのサンプル・プログラムで確認できます。「TimesTen TTClassesデモについて」を参照してください。

他の構成が可能なことに注意してください。アプリケーションで使用されるSQL文が、アプリケーション自体にハードコードされるのではなく、データベース内の表にリストされるよう、このスキームをさらに拡張したユーザーもいます。このようにすれば、アプリケーションの変更ではなくデータベースの変更によって、データベースの機能の変更を実装できます。

例2-3 Disconnect()メソッドの定義

次に、XYZConnection::Disconnect()メソッドの実装例を示します。

void
XYZConnection::Disconnect()
{
  updateData.Drop();
  insertData.Drop();
  queryData.Drop();
 
  TTConnection::Disconnect();
}

アクセス制御に関するTimesTen機能の考慮事項

TimesTenには、表、ビュー、マテリアライズド・ビュー、順序およびシノニムなどのデータベース・オブジェクトについて、オブジェクトレベルの解決法でデータベース・アクセスを制御する機能が含まれています。これらの機能の概要は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のアクセス制御の管理に関する説明を参照してください。『Oracle TimesTen In-Memory Database C開発者ガイド』のアクセス制御のためのTimesTen機能の検討に関する説明も参照してください。

このマニュアルで説明されている、または例で使用されている問合せ、SQL DML文またはSQL DDL文では、ユーザーは、その文を実行するための適切な権限を持っていることを前提としています。たとえば、表に対するSELECT文では、その表の所有権、その表に関して付与されているSELECT権限またはSELECT ANY TABLEシステム権限が必要です。

特定のSQL文に必要な権限については、『Oracle TimesTen In-Memory Database SQLリファレンス・ガイド』のSQL文に関する説明を参照してください。

権限は、SQLのGRANT文で付与され、SQLのREVOKE文で取り消されます。一部の権限は、各ユーザーがメンバーであるPUBLICロールを介して、すべてのユーザーに付与されます。このロールの詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス・ガイド』のPUBLICロールに関する項を参照してください。

これ以外にもアクセス制御は、データベースへの接続(「接続のアクセス制御」を参照)、接続属性の設定、XLAの使用(「アクセス制御がXLAに与える影響」を参照)、およびCユーティリティ関数の実行に影響します。


注意:

  • アクセス制御は無効にできません。

  • アクセス制御の権限は、データベースでSQLが準備されるときと実行されるときの両方で確認され、パフォーマンス・コストの大部分は準備時に発生します。


TimesTen接続の管理

この項では、データベースへの接続について、次の内容で説明します。

DSNの概要

『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』では、データベースのDSN(データソース名)の作成について説明しています。作成するDSNのタイプは、アプリケーションがデータベースに直接接続するか、クライアント接続するかによって異なります。

データベースに直接接続する場合は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のTimesTenデータベースの管理に関する説明を参照してください。UNIXまたはWindowsから直接接続するためのDSNの作成方法に関する説明があります。

データベースへのクライアント接続を作成する場合は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のTimesTen ClientおよびTimesTen Serverの使用方法に関する説明を参照してください。UNIXまたはWindowsからクライアント/サーバー接続を行うためのDSNの作成方法に関する説明があります。


注意:

TimesTen接続は、親プロセスから継承できません。子プロセスの作成前に(分岐)プロセスでデータベース接続が開かれた場合、子ではその接続を使用しないようにする必要があります。

接続および切断

「TTCmd、TTConnectionおよびTTConnectionPoolの使用」で説明しているXYZConnectionクラスを使用すると、次の例のようにTimesTenに対して切断および接続できます。

例2-4 TimesTenに対する接続および切断

  ...

  XYZConnection conn;
  char connStr[256];
  char user[30];
  char pwd[30];
 
  ...
 
  try {
    conn.Connect(connStr, user, pwd);
  }
  catch (TTWarning st) {
    cerr << "Warning connecting to TimesTen: " << st << endl;
  }
  catch (TTError st) {
    cerr << "Error connecting to TimesTen " << st << endl;
    exit(1);
  }

// ... Work with the database connection...

  try {
    conn.Disconnect();
  }
  catch (TTStatus st) {
    cerr << "Error disconnecting from TimesTen: " << st << endl;
    exit(1);
  }

接続のアクセス制御

この項では、TTClassesを使用しデータベースに接続する方法に関連する、アクセス制御機能について説明します。

一般的なアクセス制御の概要については、「アクセス制御のためのTimesTen機能の検討」を参照してください。

アクセス制御のための接続メソッド・シグネチャ

TTConnectionTTConnectionPoolおよびTTXlaPersistConnectionクラスには、次のメソッド・シグネチャが定義されています。

virtual void 
TTConnection::Connect(const char* connStr)
 
virtual void
TTConnection::Connect(const char* connStr, const char* username, 
                      const char* password)
 
virtual void
TTConnection::Connect(const char* connStr, 
                      DRIVER_COMPLETION_ENUM driverCompletion)

void 
TTConnectionPool::ConnectAll(const char* connStr)

void
TTConnectionPool::ConnectAll(const char* connStr, const char* username, 
                             const char* password)
 
virtual void
TTXlaPersistConnection::Connect(const char* connStr, const char* username, 
                                const char* password, const char* bookmarkStr, 
                                bool createBookmarkFlag)
 
virtual void
TTXlaPersistConnection::Connect(const char* connStr, 
                                DRIVER_COMPLETION_ENUM driverCompletion, 
                                const char * bookmarkStr, bool createBookmarkFlag)
 
virtual void
TTXlaPersistConnection::Connect(const char* connStr, const char* username, 
                                const char* password, const char* bookmarkStr)

virtual void
TTXlaPersistConnection::Connect(const char* connStr, 
                                DRIVER_COMPLETION_ENUM driverCompletion, 
                                const char * bookmarkStr)

注意:

  • 接続文字列(connStr値)では、DSN=testdb;uid=brian;pwd=welcomeのようにユーザー名とパスワードを指定できます。接続文字列、ユーザー名およびパスワードを引数として取るシグネチャについては、そのユーザー名とパスワード引数は接続文字列で指定されたユーザー名またはパスワードよりも優先されることに注意してください。

  • DRIVER_COMPLETION_ENUM値の詳細は、「TTConnection」を参照してください。


アクセス制御のためのCREATE SESSION権限

データベースに接続するための権限は、CREATE SESSION権限を使用して、インスタンス管理者以外のすべてのユーザーに明示的に付与する必要があります。これはシステム権限です。この権限は、直接またはPUBLICロールを使用して、管理者がユーザーに付与する必要があります。例および詳細は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のアクセス制御の管理に関する説明を参照してください。

XLA接続のためのXLA権限

CREATE SESSION権限の他に、ユーザーにはXLA接続を作成し、XLA機能を実行するためのXLA権限を付与する必要があります(「アクセス制御がXLAに与える影響」を参照)。

TimesTenデータの管理

この項では、データの操作に関して、次の内容で説明します。

パラメータのバインド

この項では、SQL文のパラメータのバインドについて説明します。TTCmdクラスには、パラメータをバインドするメソッドsetParam()BindParameter()(バッチ操作用)が用意されています。また、出力および入力/出力パラメータをサポートするため、またはデフォルトのバインド・タイプを上書きするためのregisterParam()も用意されています。パラメータが重複する場合は、TimesTenモードまたはOracleモードを判断するために、DuplicateBindMode TimesTen接続属性をサポートする機能も用意されています。


注意:

TimesTenのバインド・メカニズム(アーリー・バインディング)はOracle Databaseのバインド・メカニズム(レイト・バインディング)とは異なります。TimesTenは、問合せの準備の前にデータ型を必要とします。そのため、各バインド・パラメータのデータ型が指定されていないかSQL文から推測できないと、エラーが発生します。たとえば次のような文が、これに該当します。
SELECT 'x' FROM DUAL WHERE ? = ?;

この問題には、たとえば次のように対処できます。

SELECT 'x' from DUAL WHERE CAST(? as VARCHAR2(10)) = 
                           CAST(? as VARCHAR2(10)); 

内容は、次のとおりです。


注意:

TimesTen開発者ガイドで使用される「バインド・パラメータ」という用語(ODBC用語に準拠)は、TimesTenのPL/SQLのマニュアルで使用される「バインド変数」という用語(Oracle Database PL/SQL用語に準拠)と同じです。

入力パラメータのバインド

バッチ以外の操作では、TTCmd::setParam()メソッドを使用しSQL文の入力パラメータをバインドします(パラメータの位置とバインドする値を指定します)。バッチ操作では、TTCmd::BindParameter()メソッドを使用します。(バッチ操作の使用例については、例3-5「ExecuteBatch()メソッドの使用方法」を参照してください。)

バッチ以外の操作については、例2-5で、表に行を挿入するためにパラメータをバインドするクラスSampleConnectionのスニペットを示しています。(この例は、TimesTenクイック・スタート・デモのbasics.cppから引用されています。「TimesTen TTClassesデモについて」を参照してください。)この例ではConnect()メソッドの実装については省略されているため、Connect()の実装については例2-2を参照してください。

次のように定義される表basicsがあるとします。

create table basics (name char(10) not null primary key, i tt_integer);

例2-5 行を挿入するためのパラメータのバインド(バッチ以外の場合)

class SampleConnection : public TTConnection 
{
  using TTConnection::Connect;
 
  private:
    TTCmd        insertData;
    ...
 
  protected:
 
  public:
    SampleConnection();
    ~SampleConnection();
    virtual void Connect(const char* connStr, 
                         DRIVER_COMPLETION_ENUM driverCompletion);
    void insert(char* nameP);
    ...
 
  ...
  // Assume a Connect() method implemented with the following:
  // insertData.Prepare(this, "insert into basics values(:name, :value)");
  ...
}

//----------------------------------------------------------------------
 

void
SampleConnection::insert(char* nameP)
{
  static long i = 0;
  insertData.setParam(1, nameP);
  insertData.setParam(2, i++);
  insertData.Execute();
}
 
//----------------------------------------------------------------------

...

int
main(int argc, char** argv)
{
  ...
  char name[10];
  SampleConnection conn;
  ...

// Assume conn is an open connection.
  sprintf(name, "Robert");
  try {
    conn.insert(name); 
  }
  catch (TTStatus st) {
    cerr << "Error inserting row " << name << ":" << st << endl;
    conn.Rollback();
  }
}

パラメータの登録

TTCmdクラスには、SQLデータ型、精度、パラメータのスケール(該当する場合)およびパラメータが入力、出力または入力/出力であるかどうかを指定できるメソッドregisterParam()が用意されています。registerParam()コールは、出力または入力/出力パラメータに関して必要です(REF CURSOR(出力のみ)、あるいはPL/SQL RETURNING INTO句(出力のみ)、プロシージャまたは関数からのパラメータが考えられます)。

入力パラメータについては、TTClassesは、デフォルトでsetParam()またはBindParameter()コールに対して、表2-1のマッピングに従って、バインドされたCデータ型からSQLデータ型を導出します。通常、入力パラメータにregisterParam()コールは不要ですが、特定のSQLデータ型、精度またはスケールを使用する必要がある場合は、コールすることが可能です。

表2-1 TTClasses Cデータ型のSQLデータ型へのマッピング

Cデータ型 SQLデータ型

char*

SQL_CHAR、SQL_VARCHAR

void*

SQL_BINARY、SQL_VARBINARY

double

SQL_FLOAT、SQL_DOUBLE

DATE_STRUCT

SQL_DATE

float

SQL_REAL、SQL_DECIMAL

int

SQL_INTEGER

SQLBIGINT

SQL_BIGINT

SQLCHAR*

SQL_VARCHAR

SQLINTEGER

SQL_INTEGER

SQLSMALLINT

SQL_SMALLINT

SQLTINYINT

SQL_TINYINT

SQLWCHAR*

SQL_WCHAR、SQL_WVARCHAR

TIME_STRUCT

SQL_TIME

TIMESTAMP_STRUCT

SQL_TIMESTAMP

SQLHSTMT

SQL_REFCURSOR



重要:

ドライバ・マネージャを使用している場合、前述の表のすべてのCデータ型がサポートされている訳ではありません。「ODBCドライバ・マネージャ使用時の考慮事項(Windows)」を参照してください。

registerParam()コールは、関連するsetParam()またはBindParameter()コールの前後どちらかで使用可能であり、そのSQLデータ型、精度、スケール(該当する場合)に関しては優先されます。

メソッドのシグネチャは、次のように指定します。

inline void
TTCmd::registerParam(int pno,
                     int inputOutputType, 
                     int sqltype, 
                     int precision = 0, 
                     int scale = 0)
  • pnoは文内のパラメータの位置を示します。

  • inputOutputTypeは、TTCmd::PARAM_INTTCmd::PARAM_OUTまたはTTCmd::PARAM_INOUTです。

  • sqltypeはSQLデータ型のデータです(たとえば、SQL_INTEGER)。

  • precisionscale(いずれもオプション)は、ODBC SQLBindParameterコールの場合と同様に使用します。プリミティブ型(intなど)については、precisionscaleの設定は無視されます。


注意:

例については、次の「出力または入力/出力パラメータのバインド」の項を参照してください。その他のリファレンス情報は、「registerParam()」を参照してください。

出力または入力/出力パラメータのバインド

TTClassesでは、REF CURSOR(出力のみ)などの出力および入/出力パラメータ、OUTまたはIN OUTパラメータを持つPL/SQLプロシージャまたはファンクションからのパラメータ、またはRETURNING INTO句からのパラメータ(出力のみ)がサポートされています。

TTClassesにSQL文内のパラメータが出力または入力/出力であるかを通知するには、前述の項で説明したTTCmd::registerParam()メソッドを使用する必要があります。このメソッド・コールでは、intputOutputTypeの設定に適宜TTCmd::PARAM_OUTまたはTTCmd::PARAM_INOUTを使用します。

バッチ以外の操作では、SQL文の実行後に、適切なTTCmd::getParam()メソッドを使用し出力値を取得します(パラメータの位置および値の配置先の変数を指定します)。各データ型にはシグネチャがあります。

バッチ操作では、TTCmd::BindParameter()を、出力パラメータ、入力/出力パラメータまたは入力パラメータに使用します。これは文が実行される前にコールされます。文の実行後、出力値用のデータはBindParameter()コールで指定したバッファ内に配置されます。BindParameter()には、データ型ごとにシグネチャがあります。バッチ操作の入力/出力パラメータ用には、文の実行前にBindParameter()が1回のみコールされます。指定したバッファには、実行前には入力が含まれ、文の実行後には出力が含まれます。

次の例は、出力および入力/出力パラメータの使用方法を示す部分的なコードです。

例2-6 入力および入力/出力パラメータの使用(バッチ以外の場合)

この例では、入力および出力パラメータを使用します。setParam()コールで、入力パラメータ:aの値をバインドされます。getParam()コールで、出力パラメータ:bの値を取得されます。この出力パラメータも、必要に応じて登録されます。

...
// t1 has a single TT_INTEGER column
cmd.Prepare(&conn, "insert into t1 values (:a) returning c1 into :b");
cmd.setParam(1, 99);
cmd.registerParam(2, TTCmd::PARAM_OUT, SQL_INTEGER);
cmd.Execute();
SQLINTEGER outval;

if (cmd.getParam(2, &outval))
  cerr << "The output value is null." << endl;
else
  cerr << "The output value is " << outval << endl;
...

例2-7 入力および出力パラメータの使用(バッチの場合)

この例では、バッチ操作で入力パラメータおよび出力パラメータを使用します。最初のBindParameter()コールは、最初のパラメータ:aの入力データを提供します。2番目のBindParameter()コールは、2番目のパラメータ:bの出力データ用にバッファを提供します。

...
#define BATCH_SIZE  5
int input_int_array[BATCH_SIZE] = { 91, 92, 93, 94, 95 };
int output_int_array[BATCH_SIZE] = { -1, -1, -1, -1, -1 };
int numrows;
 
cmd.PrepareBatch(&conn, "insert into t1 values (:a) returning c1 into :b",
                 BATCH_SIZE);
cmd.BindParameter(1, BATCH_SIZE, input_int_array);
cmd.BindParameter(2, BATCH_SIZE, output_int_array);
cmd.registerParam(2, TTCmd::PARAM_OUT, SQL_INTEGER);
numrows = cmd.ExecuteBatch(BATCH_SIZE);
...

例2-8 入力/出力パラメータの使用

この例では、入力/出力パラメータを使用します。これは必要に応じて登録できます。setParam()コールはその入力値をバインドし、getParam()コールはその出力値を取得します。

...
cmd.Prepare(&conn, "begin :x := :x + 1; end;");
cmd.registerParam(1, TTCmd::PARAM_INOUT, SQL_INTEGER);
cmd.setParam(1, 99);
cmd.Execute();
SQLINTEGER outval;

if (cmd.getParam(1, &outval))
  cerr << "The output value is null." << endl;
else
  cerr << "The output value is " << outval << endl;
...

例2-9 出力および入力/出力パラメータの使用

この例では出力および入力/出力パラメータを使用します。次のPL/SQLプロシージャがあるとします。

create or replace procedure my_proc (
  a in number,
  b in number,
  c out number,
  d in out number ) as

begin
  c := a + b; 
  d := a + b - d; 
end my_proc;

このプロシージャの入力パラメータは、この例ではバインド・パラメータとしてではなく定数として取られるため、OUTパラメータおよびIN OUTパラメータのみがバインドされます。必要に応じて両方が登録されます。setParam()コールは、IN OUTパラメータ:var1の入力値を提供します。最初のgetParam()コールは、OUTパラメータ:sumの値を取得します。2番目のgetParam()コールは、IN OUTパラメータ:var1の出力値を取得します。

...
cmd.Prepare(&conn, "begin my_proc (10, 5, :sum, :var1); end;");
cmd.registerParam (1, TTCmd::PARAM_OUT, SQL_DECIMAL, 38);
cmd.registerParam (2, TTCmd::PARAM_INOUT, SQL_DECIMAL, 38);
cmd.setParam(2, "99");
cmd.Execute();
SQLINTEGER outval1, outval2;

if (cmd.getParam(1, &outval1))
  cerr << "The first output value is null." << endl;
else
  cerr << "The first output value is " << outval << endl;
if (cmd.getParam(2, &outval2))
  cerr << "The second output value is null." << endl;
else
  cerr << "The second output value is " << outval << endl;
...

重複パラメータのバインド

TimesTenでは、SQL文内の重複するパラメータのバインドに、2つの個別のモードがサポートされています。Oracleモードでは、TimesTen接続属性の設定がDuplicateBindMode=0(デフォルト)であり、同じパラメータ名が複数回出現しても、別のパラメータとみなされます。従来のTimesTenモードでは、DuplicateBindMode=1であり、同じパラメータ名が複数回出現すると同じパラメータとみなされます(以前のTimesTenリリースと同様)。


注意:

詳細は、『Oracle TimesTen In-Memory Databaseリファレンス』のDuplicateBindModeおよび『Oracle TimesTen In-Memory Database C開発者ガイド』のSQL文での重複するパラメータのバインドに関する説明を参照してください。

たとえば、次の問合せがあるとします。

SELECT * FROM employees
  WHERE employee_id < :a AND manager_id > :a AND salary < :b;

Oracleモードの場合、パラメータの位置番号が割り当てられると、名前の重複に関係なく、パラメータの出現ごとに番号が割り当てられます。アプリケーションは、少なくとも各パラメータ名の最初の出現時に値をバインドする必要があります。特定のパラメータ名がそれ以降に出現した場合は、アプリケーションはその出現に対して別の値をバインドすることも、そのパラメータの出現をバインドしないこともできます。後者の場合、最初の出現時と同じ値がそれ以降の出現時に使用されます。いずれの場合も、出現ごとに異なるパラメータ位置番号が付けられます。

TimesTenモードでは、重複パラメータを含むSQL文は、異なるパラメータ名のみが別のパラメータとみなされるように解析されます。バインドは、パラメータ名が最初に出現した位置に基づいて行われます。以降に出現する同じパラメータ名には、独自の位置番号は与えられず、同じパラメータ名の出現にはすべて同じ値が使用されます。

例2-10 パラメータの重複: Oracleモード

この例では、Oracleモードで、前述のSQL文でのaの2回目の出現に対して異なる値を使用します。

mycmd.setParam(1, ...); // first occurrence of :a
mycmd.setParam(2, ...); // second occurrence of :a
mycmd.setParam(3, ...); // occurrence of :b

aの両方の出現に対して同じ値を使用するには、次のように指定します。

mycmd.setParam(1, ...); // both occurrences of :a
mycmd.setParam(3, ...); // occurrence of :b

パラメータbは、位置3に存在するとみなされ、パラメータ数は3とみなされます。

例2-11 パラメータの重複: TimesTenモード

前述のSQL文は、TimesTenモードの場合、aの2回の出現は単一のパラメータとみなされ、個別にバインドすることはできません。

mycmd.setParam(1, ...); // both occurrences of :a
mycmd.setParam(2, ...); // occurrence of :b

TimesTenモードの場合、パラメータbは位置3ではなく位置2に存在するとみなされ、パラメータ数は2とみなされます。

REF CURSORの使用

REF CURSORはPL/SQLの概念で、SQLの結果セット上のカーソルに対するハンドルであり、PL/SQLとアプリケーションの間で渡すことができます。TimesTenでは、このカーソルをPL/SQL内で開くことができるため、REF CURSORをアプリケーションに渡して処理することができます。この使用方法は、OUT REF CURSORであり、これはPL/SQLに関するOUTパラメータです。すべての出力パラメータと同様に、これはTTCmd::registerParam()メソッドで登録する必要があります。(「パラメータの登録」および「出力または入力/出力パラメータのバインド」を参照してください。)

TimesTenの実装では、REF CURSORは別の文ハンドルにアタッチされています。アプリケーションは、1つの文ハンドルにREF CURSORパラメータを持つSQL文を準備し、次に、この文の実行前に、2つ目の文ハンドルをREF CURSORの値としてバインドします。この文の実行後、アプリケーションはこの結果の記述、バインドおよびフェッチを、結果セットの場合と同じAPIを使用して実行することができます。

TTCmdオブジェクトは単一のSQL文をカプセル化するため、TTClassesでは2つのTTCmdオブジェクトが使用してこのREF CURSORモデルをサポートします。

REF CURSORの詳細は、『Oracle TimesTen In-Memory Database PL/SQL開発者ガイド』のPL/SQL REF CURSORに関する説明を参照してください。


重要:

  • PL/SQLからアプリケーションへのOUT REF CURSORのみがサポートされるのに加えて、TimesTenでは、1つの文で1つのREFCURSORのみがサポートされます。

  • 「ODBCドライバ・マネージャ使用時の考慮事項(Windows)」に示すとおり、ODBCドライバ・マネージャを使用する場合、REF CURSORの機能はTTClassesではサポートされません。(この制限は、TimesTenクイック・スタートで提供しているデモのttdmドライバ・マネージャには該当しません。)


次に説明する、TTClassesでREF CURSORを使用する手順を、以降の例2-12で示します。

  1. REF CURSORを返すPL/SQL文に対して、TTCmdオブジェクトを宣言します(この例ではcmdPLSQL)。

  2. TTCmd*ポインタを宣言して、REF CURSOR用の2つ目のTTCmdオブジェクトをポイントします(この例ではcmdRefCursor)。

  3. 最初のTTCmdオブジェクト(cmdPLSQL)を使用してPL/SQL文を準備します。

  4. 最初のTTCmdオブジェクトのTTCmd::registerParam()メソッドを使用して、このREF CURSORを出力パラメータとして登録します。

  5. 最初のTTCmdオブジェクトを使用して、文を実行します。

  6. 最初のTTCmdオブジェクトのTTCmd::getParam()メソッドを使用して、REF CURSORを2つ目のTTCmdオブジェクト(&cmdRefCursorを使用)に取得します。REF CURSORには、getParam(int paramNo、TTCmd** rcCmd)のシグネチャがあります。

  7. REF CURSORのTTCmdオブジェクトから結果をフェッチして、必要に応じて処理します。

  8. 最初のTTCmdオブジェクトを削除します。

  9. REF CURSORのTTCmdオブジェクトへのポインタを削除します。

  10. delete文を発行して、REF CURSORのTTCmdオブジェクトを削除します。

例2-12 REF CURSORの使用

この例では、PL/SQL無名ブロックからREF CURSORを取得および処理します。説明については、前述の手順を参照してください。

...
TTCmd  cmdPLSQL;
TTCmd* cmdRefCur;
TTConnection conn;
...
 
// c1 is a TT_INTEGER column.
cmdPLSQL.Prepare(&conn, "begin open :rc for select c1 from t; end;")
cmdPLSQL.registerParam(1, TTCmd::PARAM_OUT, SQL_REFCURSOR);
cmdPLSQL.Execute();

if (cmdPLSQL.getParam(1, &cmdRefCur) == false)
{
  SQLINTEGER fetchval;
 
  while (!cmdRefCursor->FetchNext()) {
    cmdRefCur->getColumn(1, &fetchval);
  }
  cmdRefCursor->Drop();
  delete cmdRefCursor;
}

cmdPLSQL.Drop();

TTClassesでREF CURSORを使用する場合は、次のような使用上の注意があります。

  • PL/SQLとアプリケーションの間でREF CURSORを渡す場合、TimesTenでは、PL/SQLからアプリケーションへのOUT REF CURSORのみと、単一のREF CURSORのみを返す文がサポートされます。

  • 他のデータ型に対するTTCmd::getParam()コールとは異なり、REF CURSOR用のTTCmd**パラメータを使用したgetParam()コールは1回のみコールできます。それ以降のコールではNULLが返されます。REF CURSORを2度取得する必要がある場合は、文を再実行する必要があります。

  • 文を複数回実行する場合は、そのたびにREF CURSORパラメータを登録する必要があります。たとえば、ループ内で文の実行、REF CURSORパラメータの取得およびREF CURSORからのフェッチを行うには、次のようにパラメータの登録もループ内で行う必要があります。

    cmdPLSQL.Prepare(...);
    
    loop
       cmdPLSQL.registerParam(...);
       cmdPLSQL.Execute();
       cmdPLSQL.getParam(...);
       fetch loop
    end loop
    

    これを次の例2-13に示します。

  • どのTTCmdオブジェクト(REF CURSOR用のものを含む)も、ODBC文ハンドルが割り当てられます。REF CURSOR文ハンドルは、Drop()文の実行時に削除され、そのリソースはdelete文の後に解放されます。

例2-13 ループでのREF CURSORの使用

この例では、ループでREF CURSORを使用します。次の宣言とTTConnectionインスタンスconnを想定しています。

...
TTCmd query;
TTCmd* ref_cur;
...

ループは次のとおりです。

...
      cerr << "Selecting values using cursor" << endl;
      query.Prepare(&conn, "begin open :rc for select c1 from t1; end;");
      
      for (int round = 0; round < ROUNDS; round++) {
         cerr << "executing ref cursor round# " << (round+1) << endl;
         query.registerParam(1, TTCmd::PARAM_OUT, SQL_REFCURSOR);
         query.Execute();
         query.getParam(1, &ref_cur);
 
         while(true) {
            fetch_next = ref_cur -> FetchNext();
            if (fetch_next == 1)
                break;
 
            ref_cur -> getColumn(1, &val);
            cerr << "val = " << val << endl;
         }
         ref_cur->Drop();
         delete ref_cur;
      }
 
      conn.Commit();
      query.Drop();
...

ROWIDの使用

表の各行には、ROWIDと呼ばれる一意の識別子があります。アプリケーションでは、ROWID疑似列から行のROWIDを取得します。ROWIDはバイナリまたは文字形式で表すことができます。

アプリケーションは、リテラルのROWID値を、SQL文のWHERE句などで、一重引用符で囲んだCHAR定数として指定できます。

ODBC SQLデータ型のSQL_ROWIDは、SQLデータ型のROWIDと対応します。

パラメータおよび結果セット列では、ROWIDは、Cデータ型のSQL_C_BINARYSQL_C_WCHARおよびSQL_C_CHARとの間で双方向に変換可能です。SQL_C_CHARは、ROWIDのデフォルトのCデータ型です。ROWIDのサイズは、SQL_C_BINARYとしては12バイト、SQL_C_CHARとしては18バイトおよびSQL_C_WCHARとしては36バイトです。

通常、TTClassesでは文字列としてのROWIDがサポートされていますが、TTClassesアプリケーションでは、ROWIDを文字列としてではなくROWID型としてPL/SQL無名ブロックに渡せるようになったことに注意してください。これを行うには、例2-14のように、TTCmd::registerParam()メソッドを使用してROWID入力パラメータをSQL_ROWID型として登録するする必要があります。

例2-14 ROWIDの使用

...
TTConnection conn;
TTCmd cmd;
...
cmd.Prepare(&conn, "begin delete from t1 where rowid = :x; end;");
cmd.registerParam(1, TTCmd::PARAM_IN, SQL_ROWID);
cmd.setParam(1, rowid_string);
cmd.Execute();
...

ROWIDおよびROWIDデータ型(使用方法および有効期間を含む)の詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス』のROWIDデータ型およびROWIDに関する説明を参照してください。


注意:

TimesTenでは、PL/SQL型のUROWIDはサポートされません。

LOBの作業

TimesTenではLOB(ラージ・オブジェクト)がサポートされています。これには、CLOB(Character LOB)、NCLOB(各国語LOB)およびBLOB(バイナリLOB)が含まれます。

LOBの概要およびCおよびC++でのLOBプログラミング・インタフェースの詳細は、『Oracle TimesTen In-Memory Database C開発者ガイド』のLOBの使用に関する説明を参照してください。LOBの簡易データ・インタフェースのみをTTClassesに適用可能です。

この項では、TTClassesでのLOBの使用について、次の内容で説明します。


重要:

TimesTenでは、アプリケーションで使用されるLOBは、トランザクションが終了すると無効になります。


注意:

TimesTenでは、データベースのキャラクタ・セットがTIMESTEN8の場合、CLOBはサポートされません。

次の情報も参照できます。

  • TimesTenでのLOBに関する詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス・ガイド』のLOBのデータ型に関する説明を参照してください。

  • LOBでのプログラミングに関する一般的な情報については、『Oracle Database SecureFilesおよびラージ・オブジェクト開発者ガイド』を参照してください(TimesTenの機能のみには限定されていません)。

TimesTen LOBとOracle Database LOBの違い

次の点に注意してください。

  • LOBのTimesTenでの実装とOracle Databaseでの実装の主要な違いは、TimesTenでは、アプリケーションで使用されるLOBは、トランザクションが終了すると無効になるということです。そのようなLOBは、コミットまたはロールバック後、明示または暗黙にかかわらず、無効になります。これは、Oracle Databaseの動作としてTimesTenのDDLCommitBehaviorが0(デフォルト)に設定されている場合のすべてのDDL文の後の場合も含みます。

  • TimesTenでは、BFILE、SecureFile、LOBに対する配列の読取りおよび書込みおよびLOBのコールバック関数はサポートされていません。

  • TimesTenでは、LOBの配列のバインドはサポートされていません。

  • TimesTenでは、LOBのバッチ処理はサポートされていません。

  • BLOBの場合、TimesTenでの16進リテラルの使用に違いがあります(詳細は、『Oracle TimesTen In-Memory Database SQLリファレンス』定数のHexadecimalLiteralに関する説明を参照してください)。

TTClassesでのLOBの簡易データ・インタフェースの使用

アプリケーションは、他のスカラー型同様、簡易データ・インタフェースでバインドおよび定義することによってLOBデータにアクセスできます。TTClassesの簡易データ・インタフェースでは、パラメータのバインドにgetParam()setParam()を使用し、結果行の定義にはgetColumn()またはgetColumnNullable()を使用します。アプリケーションは、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を使用します。


注意:

  • TTClassesでは、LOBのバッチ・モードはサポートされていません。

  • CLOBまたはNCLOBを、Cデータ型のSQL_C_BINARYとバインドすることは禁止されています。


例2-15に、TTClassesでのLOBの簡易データ・インタフェースの使用例を示します。

例2-15 TTClassesでのLOBの使用

この例は、作成および移入済のNCLOBBLOBおよびCLOB列がある表を前提としています。これらのLOB型に対して実行されるメソッドは、NCHARBINARYおよびCHARの場合とそれぞれ同じです。

#ifdef _WIN32
#include <ttcommon.h>
#endif
#include "TTInclude.h"
#define LOB_COL_SIZE 4194304

int main(int argc, char** argv) {

   TTConnection conn;
   TTCmd query;
   char conn_str[100] = "... your connection string ...";
   char tbl_name[20] = "... test table name ...";

   int num_rows = 0;
   char query_stmt[1000];
   int fetch_next;
   int value_is_null = 0;
   int column_type;
   SQLWCHAR * unicode_val;
   u_char * binary_val;
   char * alfanum_val;
   int b_len;
   int u_len;
 
   cerr << "Connecting to TimesTen <" << conn_str << ">" << endl;
 
   try {
      conn.Connect(conn_str);
      sprintf(query_stmt, "select * from %s", tbl_name);
      query.Prepare(&conn, query_stmt);
      query.Execute();
      const int num_result_cols = query.getNColumns();
 
      while (true) {
         // loop until no rows found
         // fetch a row; if no more rows, break out of loop
         // FetchNext returns 0 for success, 1 for SQL_NO_DATA_FOUND
         fetch_next = query.FetchNext();
         if (fetch_next == 1)
            break;
 
         for (int col = 1; col <= num_result_cols; col++) {
            value_is_null = 0;
            column_type = query.getColumnType(col);
 
            switch (column_type) {
 
               case SQL_WLONGVARCHAR:
 
                  value_is_null = query.getColumnNullable(col,
                          (SQLWCHAR**) & unicode_val, &u_len);
                  if (value_is_null) {
                     cerr << "NCLOB value is NULL";
                  } else {
                     cerr << "NCLOB value length = " << u_len << endl;
                     // do something with NCLOB value
                  }
                  break;
 
               case SQL_LONGVARBINARY:
 
                  value_is_null = query.getColumnNullable(col,
                          (void**) & binary_val, &b_len);
                  if (value_is_null) {
                     cerr << "BLOB value is NULL";
                  } else {
                     cerr << "BLOB value length = " << b_len << endl;
                     // do something with BLOB value
                  }
                  break;
 
               case SQL_LONGVARCHAR:
 
                  alfanum_val = (char*) malloc(LOB_COL_SIZE + 1);
                  value_is_null = query.getColumnNullable(col, alfanum_val);
                  if (value_is_null) {
                     cerr << "CLOB value is NULL";
                  } else {
                    cerr << "CLOB value length = " << strlen(alfanum_val) << endl;
                     // do something with BLOB value
                  }
                  free(alfanum_val);
                  break;
 
               default:
                  break;
            }
         }
 
         num_rows++;
         cerr << "row " << num_rows << " fetched" << endl;
      }
      cerr << num_rows << " rows returned" << endl;
   } catch (TTError err) {
      cerr << "\nError" << err << endl;
   }
   query.Drop();
   conn.Disconnect();
   return 0;
}

TTClassesでのパススルーLOB

パススルーLOBは、TimesTenを介してアクセスするOracle Database内のLOBであり、TimesTen LOBとして公開され、TimesTenによってTimesTen LOBとほぼ同様にサポートされますが、次のことに注意する必要があります。

  • TimesTen LOBのサイズ制限は、パススルーによるOracle DatabaseのLOBの格納には適用されません。

  • TimesTenのローカルLOBと同様に、アプリケーションで使用されるパススルーLOBは、トランザクションが終了すると無効になります。

SQL文の実行に対するタイムアウトまたはしきい値の設定

TimesTenには、SQL文またはプロシージャ・コールの実行時間を制限する方法として、タイムアウト値の設定と、しきい値の設定の2つがあります。前者の場合、タイムアウト期間に達すると、文の実行が停止し、エラーがスローされます。値0はタイムアウトがないことを示します。後者の場合、しきい値に達すると、SNMPトラップがスローされますが実行は継続されます。

問合せのタイムアウト制限は、SQL文がアクティブに実行されている場合にのみ有効です。コミット中またはロールバック中にはタイムアウトは発生しません。

TTCmdオブジェクトに対し、これらを設定するには、TTCmdメソッドのsetQueryTimeout()およびsetQueryThreshold()を指定します。これらのメソッドは、TimesTenの接続属性SqlQueryTimeoutおよびQueryThresholdによってぞれぞれ指定される設定をオーバーライドする点に注意してください。

getQueryThreshold()メソッドでは、現在のしきい値の設定を読み取ることもできます。

これらの機能は、TTClassesでは、文レベルのみで使用でき、接続レベルでは使用できません。

関連情報については、『Oracle TimesTen In-Memory Database C開発者ガイド』のSQL文の実行のためのタイムアウトまたはしきい値の設定に関する説明を参照してください。


注意:

ロック・タイムアウト値およびSQL問合せのタイムアウト値の両方が指定されている場合は、まず、2つの値の小さい方の値によってタイムアウトが発生します。ロック・タイムアウトについては、『Oracle TimesTen In-Memory Databaseリファレンス』のttLockWait(組込みプロシージャ)またはLockWait(一般接続属性)に関する説明、またはOracle TimesTen In-Memory Databaseトラブルシューティング・ガイドのデッドロックとタイムアウトの確認に関する説明を参照してください。

TTClassesアプリケーションでの自動クライアント・フェイルオーバーの使用

TTClassesには、独自の自動クライアント・フェイルオーバー機能はありませんが、ODBCアプリケーションの場合と同様にTTClassesアプリケーションでTimesTen自動クライアント・フェイルオーバーを構成できます。これについては、『Oracle TimesTen In-Memory Database C開発者ガイド』の自分のアプリケーションでの自動クライアント・フェイルオーバーの使用に関する説明を参照してください。この機能の概要について、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』の自動クライアント・フェイルオーバーの使用に関する説明も参照してください。

TTClassesロギングの使用

TTClassesには、アプリケーションでデバッグ情報を取得するためのログ機能が用意されています。TTClassesのログは、プロセスと関連付けられます。特定のプロセスに対してロギングを有効にし、そのプロセスに対して1つの出力ログのストリームを作成できます。

TTClassesでは、様々なレベルのロギング情報をサポートしています。各ログ・レベルでの出力については、例2-17を参照してください。

ログ・レベルTTLOG_WARNは、TTClassesアプリケーションの開発時に非常に便利です。また、このログ・レベルではデータベースへの問合せ計画が生成されるため、本番アプリケーションにも適しています。

冗長度の高いログ・レベル(TTLOG_INFOおよびTTLOG_DEBUG)では大量のログ・データが生成されるため、アプリケーションのパフォーマンスに悪影響がある場合があります。これらのログ・レベルは本番環境では使用しないでください。

TTClassesロギングではstdoutまたはstderrのいずれかに出力することもできますが、TTClassesログ・ファイルに直接書き込むことをお薦めします。TTClassesのログ情報を、TTLOG_WARNのログ・レベルで/tmp/ttclasses.log出力ファイルに出力する方法を例2-16に示します。


注意:

デフォルトでは、TTClassesロギングは無効になっています。

例2-16 TTClassesログ情報の出力

ofstream output;
output.open("/tmp/ttclasses.log");
TTGlobal::setLogStream(output);
TTGlobal::setLogLevel(TTLog::TTLOG_WARN);

TTClassesを初めて使用するユーザーは、TTClassesロギングを試して、ログ・レベルTTLOG_ERRORでエラーがどのように出力されるか、ログ・レベルTTLOG_INFOおよびTTLOG_DEBUGで生成される情報の量を確認してください。

TTGlobalクラスを使用してロギングを行う方法の詳細は、「TTGlobal」を参照してください。

TTClassesのXLAの使用

トランザクション・ログAPI(XLA)とは、指定したデータベース表への変更についてTimesTenを監視し、これらの変更の通知をリアルタイムで受信するアプリケーションを実装できる関数のセットです。

XLAの主な目的は、トリガーに対する、高性能で非同期の代替手段を提供することです。

XLAは、データベース内の特定の表への変更の通知を返すとともに、これらのデータベース変更のトランザクション境界に関する情報も返します。この項では、トランザクション境界を使用しない例および使用する例を使用して、トランザクション境界のみでの更新(XLAアプリケーションでの一般的な要件)を確認する方法を示します。

この項のトピックは、次のとおりです。

XLAの詳細は、『Oracle TimesTen In-Memory Database C開発者ガイド』のXLAおよびTimesTenイベント管理に関する説明を参照してください。また、TTClassesのクイック・スタート・デモで、XLAのデモが提供されています。「TimesTen TTClassesデモについて」を参照してください。


重要:

  • 「ODBCドライバ・マネージャ使用時の考慮事項(Windows)」に示すとおり、XLA機能はODBCドライバ・マネージャに接続されたアプリケーションでは使用できません。

  • XLAブックマークがスタックした場合(これは先にブックマークを削除したり変更追跡を無効にしない状態で、XLAアプリケーションが予期せず停止したか、切断されると発生する可能性があります)、トランザクション・ログ・ファイルが過度に蓄積されていることがあります。この蓄積によって、ディスク領域が一杯になる場合があります。この状況の監視および解決に関する情報は、『Oracle TimesTen In-Memory Databaseオペレーション・ガイド』のトランザクション・ログ・ファイルの蓄積の監視に関する説明を参照してください。



注意:

  • LOB列がある表をサブスクライブすることは可能ですが、LOB値自体の情報は入手できません。

  • LOBを含む列は空(長さ0)またはnull(値が実際にNULLの場合)と通知されます。null列とnull以外の列の違いは、この方法で判別できます。

  • XLAリーダーは、インメモリー列圧縮を使用する表をサブスクライブできません。


トランザクション境界を使用しないXLA更新の確認

例2-17に、トランザクション境界を使用しないXLAの基本的な使用方法を示します。

HandleChange()メソッド内では、レコードがinsertか、updateか、deleteかに応じて、HandleInsert()HandleUpdate()HandleDelete()のいずれかの適切なメソッドがコールされます。

XLAレコードが特定のトランザクションにおける最後のレコードかどうかを示すフラグにユーザーがアクセスできるのは、HandleChange()内です。したがって、例2-17のループ内で、HandleChange()メソッドが、トランザクション境界に関する情報をループに渡して、この情報がconn.ackUpdates()をコールするタイミングに影響を与えることができるようにする方法はありません。

1つのトランザクションにつきレコードが数個しかない一般的な状況では、これは問題になりません。fetchUpdatesWait()コールで最大1000個のレコードを返すようXLAに要求しても、通常は数個のレコードが返されるだけです。XLAはできるだけ速くレコードを返し、データベース内で膨大な数のトランザクションが発生していても、通常はXLAレコードを一度に数個ずつ、短時間で取得することができ、XLAは最後に返されたレコードがトランザクション境界上にあることを確認します。たとえば、XLAに1000個のレコードを要求して、15個しか返されない場合は、15番目のレコードがほぼ確実にトランザクションの終了に当たります。

XLAによって、次のいずれかが保証されます。

  • 完了したトランザクション(おそらくXLAレコードの単一バッチにおける複数のトランザクション)でレコードのバッチが終了すること。

または

  • レコードのバッチに部分トランザクションが含まれ、同じバッチ内に完了したトランザクションがないこと、およびトランザクション境界に達するまで、その単一トランザクションの後続のXLAレコードのバッチが返されること。

例2-17 TTClassesのXLAプログラム

次の例に、TTClassesのXLAプログラムの一般的なメイン・ループを示します。(また、シグナル・ハンドラも存在すると仮定しています。)

TTXlaPersistConnection conn; // XLA connection
TTXlaTableList list(&conn); // tables being monitored
ttXlaUpdateDesc_t ** arry; // pointer to returned XLA records
int records_fetched;
// ...

while (!signal_received) {
  // fetch the updates
  conn.fetchUpdatesWait(&arry, MAX_RECS_TO_FETCH, &records_fetched, ...); 

  // Interpret the updates
  for(j=0;j < records_fetched;j++){
    ttXlaUpdateDesc_t *p;
    p = arry[j];
    list.HandleChange(p, NULL);
  } // end for each record fetched

  // periodically call ackUpdates()
  if (/* some condition is reached */) {
    conn.ackUpdates(); 
  }
}

トランザクション境界におけるXLA更新の確認

XLAアプリケーションでは、XLAレコードのバッチにおける最後のレコードにトランザクション境界があるかどうか検証し、このトランザクション境界のみでackUpdates()をコールする必要があります。このように、アプリケーション、システムまたはデータベースが失敗した場合、システムのリカバリ後はXLAブックマークがトランザクションの始めにあることなります。これは、操作に多数の行が関連する場合に特に重要です。データベースに対して挿入、更新、削除のバルク操作を実行する場合に、XLAアプリケーションが1000個のレコードを要求すると、1000個のレコードすべてが受信される場合もされない場合もあります。XLAを介して最後に返されるレコードには、おそらくトランザクション終了フラグが設定されていません。実際、トランザクションによって10,000個のレコードが変更された場合、トランザクション境界に達するまでに1000個のXLAレコードのブロックを最低でも10個フェッチする必要があります。

ただし、ackUpdates()は相対的に負荷の高い操作であるため、トランザクション境界ごとにackUpdates()をコールすることはお薦めしません。ユーザーは、リカバリ時間およびディスク容量の要件において、システムの全体的なスループットのバランスをとる必要があります。(XLAにそのログ・ファイルを参照するブックマークがある場合、チェックポイント操作ではTimesTenのトランザクション・ログ・ファイルを削除できない点に注意してください。関連情報は、『Oracle TimesTen In-Memory Databaseリファレンス』のttLogHoldsに関する説明を参照してください。)システムのスループット、リカバリ時間およびディスク領域の要件に応じ、アプリケーションによっては、1分ごとにackUpdates()を1回または複数回コールすることが適切である場合もあれば、1時間に1回または数回しかコールする必要がない場合もあります。

HandleChange()メソッドには、HandleChange()とメインXLAループとの間で情報の受渡しを可能にする第2のパラメータがあります。前述の例2-17例2-18の特にdo_acknowledgeの設定とHandleChange()コールの&do_acknowledgeパラメータを比較してください。

例2-18 トランザクション境界を使用するTTClassesのXLAプログラム

この例では、ackUpdates()は、このXLAレコードのバッチがトランザクション境界にあることがdo_acknowledgeフラグによって示された場合にのみコールされます。(この例では、シグナル・ハンドラも存在すると仮定しています。)

TTXlaPersistConnection conn; // XLA connection
TTXlaTableList list(&conn); // tables being monitored
ttXlaUpdateDesc_t ** arry; // ptr to returned XLA recs
int records_fetched;
int do_acknowledge;
int j;

// ...
while (!signal_received) {
  // fetch the updates
  conn.fetchUpdatesWait(&arry, MAX_RECS_TO_FETCH, &records_fetched, ...); 

  do_acknowledge = FALSE;

  // Interpret the updates
  for(j=0;j < records_fetched;j++){
    ttXlaUpdateDesc_t *p;
    p = arry[j];
    list.HandleChange(p, &do_acknowledge);
  } // end for each record fetched

  // periodically call ackUpdates()
  if (do_acknowledge == TRUE  /* and some other conditions ... */ ) {
    conn.ackUpdates();
  }
}

XLAのメイン・ループに対するこの変更だけではなく、HandleChange()メソッドをオーバーロードして、2つパラメータを持つ(ttXlaUpdateDesc_t*、void* pData)ようにする必要があります。「HandleChange()」を参照してください。pDataパラメータの使用方法は、クイック・スタートのxlasubscriber1のデモのとおりです。(「TimesTen TTClassesデモについて」を参照してください。)

アクセス制御がXLAに与える影響

データベース内の処理に与えるTimesTenアクセス制御の影響の概要については、「アクセス制御に関するTimesTen機能の考慮事項」を参照してください。アクセス制御はXLAに影響を与えます。

システム権限XLAは、XLAリーダーとしてTimesTenに接続する場合(CREATE SESSION権限も必要)、XLA関連のTimesTen C関数を実行する場合、およびXLA関連のTimesTen組込みプロシージャを実行する場合など、すべてのXLA機能で必要になります。

詳細は、『Oracle TimesTen In-Memory Database C開発者ガイド』のアクセス制御がXLAに与える影響に関する説明を参照してください。


注意:

XLA権限を持つユーザーは、データベースで実行されるすべてのDML文の通知を受信できます。その結果、XLA権限を持つユーザーは、この権限がない場合にアクセスが許可されていなかったデータベース・オブジェクトに関する情報を取得可能になります。実際、XLA権限は、実質的にSELECT ANY TABLESELECT ANY VIEWおよびSELECT ANY SEQUENCE権限と同じです。