この章では、Oracle Call Interface(OCI)を使用してプログラムを作成する際に必要となる基本概念の概要を説明します。
この章は、次の項目で構成されています。
この章では、OCIアプリケーションの開発における基本的な概念とプロシージャについて説明します。この章を読み終えると、基本的なOCIアプリケーションの作成に必要なツールについてほとんど習得したことになります。
この章は、次の項に大きくわかれています。
ヘッダー・ファイル: OCIクライアント・アプリケーション開発のためのヘッダー・ファイルとMakefileの場所を示します。
OCIプログラム構造 − OCIアプリケーションの基本構造と作成の主なステップを説明します。
OCIデータ構造 − ハンドルと記述子について説明します。
OCIプログラミング・ステップ − OCIアプリケーションのコーディングに必要な各ステップを詳しく説明します。
OCIでのエラー処理 − OCIアプリケーションでのエラー処理について説明します。
その他のコーディング・ガイドライン − OCIアプリケーションのコーディングに役立つ情報を説明します。
OCIプログラムでのPL/SQL使用方法 − OCIアプリケーションでPL/SQLを使用する場合の重要ポイントについて説明します。
新規ユーザーは、この章の情報に特に注意してください。この章は、以降の章を理解する基本となります。以降の章は、この章の内容を補足しています。
現行リリースでは、LinuxおよびUNIXプラットフォームでOCIおよびOCCIクライアント・アプリケーションを開発するために必要なOCI/OCCIヘッダー・ファイルは$ORACLE_HOME/rdbms/public
ディレクトリにあります。
すべてのデモ・プログラムとヘッダー・ファイルは、引き続き$ORACLE_HOME/rdbms/demo
ディレクトリにあります。すべてのデモ・プログラムに関して、これらのファイルはExamplesメディアからのみインストールできます。これらのプログラムの名前とその目的の詳細は、付録B「OCIデモ・プログラム」を参照してください。
開発に必要なOCI/OCCIヘッダー・ファイルは、$ORACLE_HOME/rdbms/public
にあり、Oracle Databaseサーバー環境でもOracle Databaseクライアント管理およびカスタム環境でも使用できます。
demo
ディレクトリに複数のMakefileが用意されています。各Makefileのコメントには、OCI実行可能ファイルを作成する際の指示が含まれています。コンパイル・エラーとリンク・エラーを回避するために、できるかぎりこれらのデモ用Makefileを使用することをお薦めします。
demo_rdbms.mk
ファイルは$ORACLE_HOME/rdbms/demo
ディレクトリ内にあるサンプルMakefileです。コメントには、デモ用OCIプログラムのビルド方法が含まれています。demo_rdbms.mk
ファイルには、すでに$ORACLE_HOME/rdbms/public
ディレクトリが含まれています。独自にカスタマイズしたMakefileが、INCLUDEパスの$ORACLE_HOME/rdbms/public
ディレクトリにあることを確認してください。
同じディレクトリに、32ビット・クライアント実行可能ファイル作成用のMakefileであるdemo_rdbms32.mk
があります。このMakefileでは、demo_rdbms.mk
を使用して、外部プロシージャ・コール用にデータベース・サーバーにロードされる共有ライブラリを作成します。
また、demo
には64ビット・クライアント実行可能ファイル作成用のdemo_rdbms64.mk
もあります。このMakefileでも、demo_rdbms.mk
を使用して、データベース・サーバーにロードされる外部プロシージャ・コール用共有ライブラリを作成します。
ociucb.mk
は、demo
にあるコールバック共有ライブラリ作成用Makefileです。このMakefileにも、使用方法に関するコメントが含まれています。
OCIアプリケーションの全般的な目標は、マルチ・ユーザーのために稼働することです。N層構造では、マルチ・ユーザーがクライアント・アプリケーションにHTTP要求を送信します。クライアント・アプリケーションでは、データ交換やデータ処理など、いくつかのデータ操作を実行する必要があります。
OCIでは、次のプログラム基本構造を使用しています。
OCIプログラミング環境およびスレッドの初期化
必要なハンドルの割当て、およびサーバー接続とユーザー・セッションの確立
サーバー上でのSQL文の実行、データベース・サーバーとの間でのデータ交換、必要なアプリケーション・データ処理の実行
プリコンパイルされたSQL文の実行、または新規に実行する文の準備
ユーザー・セッションおよびサーバー接続の終了
フリー・ハンドル
図2-1「基本的なOCIプログラムの流れ」は、OCIアプリケーションのステップの流れを示しています。各ステップの詳細は、「OCIプログラミング・ステップ」の項を参照してください。
図およびステップ・リストは、OCIプログラミングのステップを簡潔に表したものです。さらに、プログラムの機能性に応じて様々なバリエーションが考えられます。複数セッションおよび複数トランザクションの管理やオブジェクトの使用など、より高度な機能が組み込まれるOCIアプリケーションには、追加のステップが必要です。
すべてのOCIファンクション・コールは、ある環境のコンテキスト内で実行されます。1つのOCIプロセス内に複数の環境が存在することが可能です。環境でプロセスレベルの初期化が必要になった場合には、自動的に実行されます。
注意: OCIアプリケーションには、アクティブな接続および文を2つ以上含めることができます。 |
ハンドルと記述子は、OCIアプリケーションで定義された不透明なデータ構造体です。ハンドルと記述子は、特定の割当てコールによって直接割り当てるか、あるいはOCI関数を使用して暗黙的に割り当てることができます。
7.xアップグレードの注意: リリース7.x OCIのアプリケーション作成の経験を持つプログラマは、大部分のOCIコールに使用されているこれらの新しいデータ構造に慣れる必要があります。 |
ハンドルおよび記述子を使用して、データ、接続またはアプリケーション動作に関係する情報を格納します。ハンドルについては、次の項で詳しく定義します。
ほとんどの場合、OCIコールのパラメータ・リストには、ハンドルが1つ以上含まれています。ハンドルとは、OCIライブラリによって割り当てられる記憶領域を指す不透明なポインタです。ハンドルを使用すると、コンテキストや接続に関する情報(環境コンテキスト・ハンドルやサービス・コンテキスト・ハンドルなど)を格納できます。またOCI関数やデータに関する情報(エラー・ハンドルや記述ハンドルなど)を格納する場合もあります。つまり、ハンドルを使用するとアプリケーションではなくライブラリでこのデータを維持できるため、プログラミングが簡単になります。
ほとんどのOCIアプリケーションでは、ハンドルに格納されている情報へのアクセスが必要となります。この情報にアクセスして設定するには、属性の入手および設定のためのOCIコールであるOCIAttrGet()
およびOCIAttrSet()
を使用します。
表2-1は、OCI用に定義されているハンドルを示しています。それぞれのハンドル・タイプについて、OCIコールでハンドル・タイプを識別するために使用される、Cデータ型およびハンドル・タイプ定数をリストしています。
表2-1 OCIハンドル・タイプ
説明 | Cデータ型 | ハンドル・タイプ定数 |
---|---|---|
OCI環境ハンドル |
|
|
OCIエラー・ハンドル |
|
|
OCIサービス・コンテキスト・ハンドル |
|
|
OCI文ハンドル |
|
|
OCIバインド・ハンドル |
|
|
OCI定義ハンドル |
|
|
OCI記述ハンドル |
|
|
OCIサーバー・ハンドル |
|
|
OCIユーザー・セッション・ハンドル |
|
|
OCI認証情報ハンドル |
|
|
OCI接続プール・ハンドル |
|
|
OCIセッション・プール・ハンドル |
|
|
OCIトランザクション・ハンドル |
|
|
OCI複合オブジェクト検索(COR)ハンドル |
|
|
OCIスレッド・ハンドル |
|
該当なし |
OCIサブスクリプション・ハンドル |
|
|
OCIダイレクト・パス・コンテキスト・ハンドル |
|
|
OCIダイレクト・パス関数コンテキスト・ハンドル |
|
|
OCIダイレクト・パス列配列ハンドル |
|
|
OCIダイレクト・パス・ストリーム・ハンドル |
|
|
OCIプロセス・ハンドル |
|
|
OCI管理ハンドル |
|
|
OCI HAイベント・ハンドル |
|
該当なし |
アプリケーションでは、すべてのハンドル(バインド・ハンドル、定義ハンドルおよびスレッド・ハンドルは除く)が、特定の環境ハンドルに対して割り当てられます。環境ハンドルをパラメータの1つとして、ハンドル割当てコールに渡します。こうして、割り当てられたハンドルは、その特定の環境に固有のものとなります。
バインド・ハンドルおよび定義ハンドルは、文ハンドルを親として割り当てられ、そのハンドルによって表される文についての情報を含みます。
注意: バインド・ハンドルおよび定義ハンドルは、OCIライブラリによって暗黙的に割り当てられるため、ユーザーによる割当ては不要です。 |
環境ハンドルはOCIEnvCreate()
またはOCIEnvNlsCreate()
のコールによって割り当てられ、初期化されます。このコールのいずれかは、すべてのOCIアプリケーションで必要です。
ユーザー割当てハンドルは、すべてOCIハンドル割当てコールOCIHandleAlloc()
によって初期化されます。
ハンドルには、セッション・ハンドル、ダイレクト・パス・コンテキスト・ハンドル、スレッド・ハンドル、CORハンドル、サブスクリプション・ハンドル、記述ハンドル、文ハンドル、サービス・コンテキスト・ハンドル、エラー・ハンドル、サーバー・ハンドル、接続プール・ハンドル、イベント・ハンドルおよび管理ハンドルなど様々なタイプがあります。
スレッド・ハンドルは、OCIThreadHndInit()
コールによって割り当てられます。
アプリケーションは、ハンドルが不要になった時点で全ハンドルを解放する必要があります。すべてのハンドルはOCIHandleFree()
関数によって解放されます。
ハンドルにより、グローバル変数を使用する必要性が少なくなります。また、エラー・レポートが簡単になります。エラー・ハンドルは、エラーと診断情報を戻すために使用します。
環境ハンドルは、すべてのOCI関数をコールするコンテキストを定義します。各環境ハンドルにはメモリー・キャッシュがあり、これによってメモリー・アクセスが高速になります。環境ハンドルに基づくメモリーの割当ては、このキャッシュで行われます。キャッシュへのアクセスは、複数のスレッドが同じ環境ハンドルに基づいてメモリーの割当てを試行する場合にシリアライズされます。複数のスレッドで単一の環境ハンドルを共有する場合、スレッドはキャッシュへのアクセスをブロックすることがあります。
環境ハンドルは、parentパラメータとしてOCIHandleAlloc()
コールに渡され、その他のすべてのハンドル・タイプを割り当てます。バインド・ハンドルと定義ハンドルは、暗黙的に割り当てられます。
エラー・ハンドルは、ほとんどのOCIコールにパラメータとして渡されます。エラー・ハンドルは、OCI操作中に発生したエラーについての情報をメンテナンスします。コールでエラーが発生した場合、エラー・ハンドルをOCIErrorGet()
に渡して、発生したエラーに関する追加情報を取得することができます。
ほとんどのOCIコールではパラメータの1つとしてエラー・ハンドルが必要であるため、エラー・ハンドルの割当ては、OCIアプリケーションの最初のステップです。
サービス・コンテキスト・ハンドルは、サーバーに対するOCIコールの操作コンテキストを決定する属性を定義します。サービス・コンテキストには、サーバー接続、ユーザー・セッションおよびトランザクションを示す3つのハンドルが属性として含まれています。これらの属性を、図2-2「サービス・コンテキストのコンポーネント」に示します。
サーバー・ハンドルは、データベースとの接続を識別します。これは、接続指向のトランスポート・メカニズムによって物理接続に変換されます。
ユーザー・セッション・ハンドルは、ユーザーのロールと権限(ユーザーのセキュリティ・ドメインとも呼ばれる)およびコールを実行するための操作コンテキストを定義します。
トランザクション・ハンドルは、SQL操作を実行するトランザクションを定義します。トランザクション・コンテキストには、フェッチ状態やパッケージのインスタンス化などの、ユーザー・セッション状態の情報が含まれています。
この方法によるサービス・コンテキストの分析は、拡張性を提供し、プログラマは、洗練された複数層のアプリケーションとトランザクション処理(TP)モニターを作成して、複数のアプリケーション・サーバーと異なるトランザクション・コンテキスト上の複数のユーザーの要求を実行できます。
サービス・コンテキスト・ハンドルを使用する際は、その前にOCIHandleAlloc()
またはOCILogon()
によって、割当てと初期化を行う必要があります。サービス・コンテキスト・ハンドルは、OCIHandleAlloc()
によって明示的に割り当てられます。また、サーバー・ハンドル、セッション・ハンドルおよびトランザクション・ハンドルでは、OCIAttrSet()
を使用して初期化できます。サービス・コンテキスト・ハンドルがOCILogon()
によって暗黙的に割り当てられている場合には、すでに初期化されています。
データベース接続ごとに常時シングル・ユーザー・セッションのみをメンテナンスするアプリケーションでは、OCILogon()
をコールして、初期化されたサービス・コンテキスト・ハンドルを取得できます。
より複雑なセッション管理を必要とするアプリケーションでは、サービス・コンテキストを明示的に割り当てる必要があります。また、サーバー・ハンドルおよびユーザー・セッション・ハンドルは、サービス・コンテキストに明示的に設定する必要があります。OCIServerAttach()
コールとOCISessionBegin()
コールは、サーバー・ハンドルとユーザー・セッション・ハンドルを初期化します。
グローバル・トランザクションの場合、あるいはセッションに対してアクティブなトランザクションが複数存在する場合、アプリケーションではトランザクションを明示的に定義するのみです。また、アプリケーションでは、データベースの内容を変更した際にOCIによって自動的に作成された暗黙的トランザクションを正しく処理できます。
文ハンドルは、SQL文またはPL/SQL文と、それぞれに関連付けられた属性を識別するコンテキストです。これについて図2-3「文ハンドル」で示しています。
入力バインド変数および出力バインド変数に関する情報は、バインド・ハンドルに格納されます。OCIライブラリでは、OCIBindByName()
またはOCIBindByPos()
関数でバインドされた各プレースホルダのバインド・ハンドルが割り当てられます。ユーザーはバインド・ハンドルを割り当てることはできません。バインド・ハンドルは、バインド・コールによって暗黙的に割り当てられます。
問合せ(select文)でフェッチされて戻されたデータは、定義ハンドルの指定に従って変換および格納されます。またOCIライブラリによって、OCIDefineByPos()
で定義された各出力変数の定義ハンドルが割り当てられます。ユーザーは定義ハンドルを割り当てることはできません。定義ハンドルは、定義コールによって暗黙的に割り当てられます。
バインド・ハンドルおよび定義ハンドルはOCIライブラリによって暗黙的に割り当てられ、バインド操作または定義操作が繰り返されると、透過的に再利用されます。バインド・ハンドルまたは定義ハンドルの実際の値は、バインドおよび定義に関する章で説明する拡張バインド操作または定義操作のためにアプリケーションで必要とされます。ハンドルが解放されるのは、文ハンドルが解放されたとき、または文ハンドルに新しい文が準備されたときです。バインド・ハンドルまたは定義ハンドルを明示的に割り当てると、メモリー・リークが発生する可能性があります。バインド・ハンドルまたは定義ハンドルを明示的に解放すると、プログラムが異常終了する可能性があります。
記述ハンドルは、OCI記述コールであるOCIDescribeAny()
によって使用されます。このコールは、ファンクションやプロシージャなどデータベース内のスキーマ・オブジェクトに関する情報を取得します。このコールでは、記述されているオブジェクトに関する情報とともに、パラメータの1つとして記述ハンドルが使用されます。コールが完了すると、記述ハンドルには、そのオブジェクトに関する情報が含まれています。OCIアプリケーションでは、パラメータ記述子の属性を通して記述情報を取得します。
複合オブジェクト検索(COR)ハンドルは、Oracleデータベース・サーバー内のオブジェクトを操作する一部のOCIアプリケーションによって使用されます。このハンドルには、他のオブジェクトによって参照されるオブジェクトの検索について指示するCOR記述子が含まれています。
サブスクリプション・ハンドルは、登録およびサブスクライブを行うOCIクライアント・アプリケーションによって使用され、データベース・イベントまたはAQネームスペース内のイベントの通知を受け取るために使用されます。サブスクリプション・ハンドルは、クライアントからの登録に関するすべての情報をカプセル化します。
ダイレクト・パス・ハンドルは、Oracleデータベース・サーバー内でダイレクト・パス・ロード・エンジンを利用するOCIアプリケーションに必要です。ダイレクト・パス・ロード・インタフェースを使用して、アプリケーションからOracleサーバーのダイレクト・ブロック・フォーマッタにアクセスできます。図2-4「ダイレクト・パス・ハンドル」では、各種ダイレクト・パス・ハンドルを示しています。
すべてのOCIハンドルには、そのハンドルに格納されたデータを表す属性があります。ハンドル属性は、属性取得コールOCIAttrGet()
を使用して読み取ることができます。また、属性設定コールOCIAttrSet()
を使用して変更することもできます。
たとえば、次の文ではOCI_ATTR_USERNAME
属性に書き込むことで、セッション・ハンドルにユーザー名を設定しています。
text username[] = "hr"; err = OCIAttrSet ((void *) mysessp, OCI_HTYPE_SESSION, (void *)username, (ub4) strlen((char *)username), OCI_ATTR_USERNAME, (OCIError *) myerrhp);
コールの前に特定のハンドル属性を設定することが必要なOCI関数もあります。たとえば、ユーザーのログイン・セッションを確立するためにOCISessionBegin()
をコールする場合は、コールの実行前にユーザー名とパスワードをユーザー・セッション・ハンドルに設定する必要があります。
完了後、ハンドル属性に有用なデータを戻すOCI関数もあります。たとえば、OCIStmtExecute()
をコールしてSQL問合せを実行した場合は、選択リスト項目に関する記述情報が文ハンドルに戻されます。
ub4 parmcnt; /* get the number of columns in the select list */ err = OCIAttrGet ((void *)stmhp, (ub4)OCI_HTYPE_STMT, (void *) &parmcnt, (ub4 *) 0, (ub4)OCI_ATTR_PARAM_COUNT, errhp);
OCIの記述子およびロケータは、データ固有の情報をメンテナンスする不透明なデータ構造体です。これらの記述子とロケータ、Cデータ型および、OCI型の記述子をOCIDescriptorAlloc()
のコール内で割り当てるために使用するOCI型定数を、表2-2に示します。OCIDescriptorFree()
関数は、記述子とロケータを解放します。OCIArrayDescriptorAlloc()関数およびOCIArrayDescriptorFree()関数も参照してください。
表2-2 記述子タイプ
説明 | Cデータ型 | OCI型定数 |
---|---|---|
スナップショット記述子 |
|
|
結果セット記述子 |
|
|
LOBデータ型ロケータ |
|
|
|
|
|
読取り専用パラメータ記述子 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ユーザー・コールバック記述子 |
|
|
登録要求でのデータベース・サーバーの識別名 |
|
|
複合オブジェクト記述子 |
|
|
アドバンスト・キューイング・エンキュー・オプション |
|
|
アドバンスト・キューイング・デキュー・オプション |
|
|
アドバンスト・キューイング・メッセージ・プロパティ |
|
|
アドバンスト・キューイング・エージェント |
|
|
アドバンスト・キューイング通知 |
|
|
アドバンスト・キューイング・リスニング・オプション |
|
|
アドバンスト・キューイング・メッセージ・プロパティ |
|
|
変更通知 |
なし |
|
表の変更 |
なし |
|
行の変更 |
なし |
|
注意: OCILobLocator に対するC型は1つのみですが、このロケータは内部LOBおよび外部LOBに対しては異なるOCI型定数で割り当てられます。後述のLOBロケータの項で、この違いについて説明します。 |
各記述子型の主な用途は次のとおりです。各記述子型については、後述の項で説明します。
OCISnapshot
− 文の実行時に使用
OCILobLocator
: LOBコール(OCI_DTYPE_LOB
)またはBFILE
コール(OCI_DTYPE_FILE
)で使用
OCIParam
− 記述コールで使用
OCIRowid
−ROWID
値のバインドまたは定義で使用
OCIDateTime
およびOCIInterval
− 日時および時間隔データ型で使用
OCIComplexObjectComp
− 複合オブジェクト検索で使用
OCIAQEnqOptions
、OCIAQDeqOptions
、OCIAQMsgProperties
、OCIAQAgent
− アドバンスト・キューイングで使用
OCIAQNotify
− パブリッシュ・サブスクライブ通知で使用
OCIServerDNs
−LDAPベースのパブリッシュ・サブスクライブ通知で使用
スナップショット記述子は、OCIStmtExecute()
のコールを実行するためのオプション・パラメータです。この記述子は、特定のデータベース・スナップショットに対する問合せが実行されることを示します。データベース・スナップショットは、ある特定の時点におけるデータベースの状態を表します。
スナップショット記述子は、OCIDescriptorAlloc()
のコールで、OCI_DTYPE_SNAP
をtype
パラメータとして渡すことによって割り当てられます。
ラージ・オブジェクト(LOB)は、バイナリ(BLOB)または文字(CLOB)データを保持できるOracleデータ型です。データベース内では、LOBロケータと呼ばれる不透明なデータ構造が、データベース行のLOB列、あるいはオブジェクトのLOB属性の位置に格納されます。このロケータは、別の位置に格納されている実際のLOB値を指すポインタとして機能します。
注意: アプリケーションによって、LOBロケータを使用する場合と使用しない場合があります。LOBのデータ・インタフェースを使用できますが、このインタフェースはLOBロケータを必要としません。このインタフェースでは、 CLOB 列の文字データ、またはBLOB 列のRAW データをバインドまたは定義できます。 |
OCI LOBロケータは、LOB(BLOBまたはCLOB)またはFILE(BFILE
)に対するOCI操作の実行に使用されます。OCILobXXX
関数では、LOB値のかわりにLOBロケータがパラメータとして使用されます。OCI LOB関数では、パラメータとして実際のLOBデータは使用されません。この関数では、パラメータとしてLOBロケータを使用し、LOBロケータによって参照されるLOBデータを操作します。
LOBロケータは、OCIDescriptorAlloc()
のコールで、BLOB
またはCLOB
のtype
パラメータとしてのOCI_DTYPE_LOB
、およびBFILE
のOCI_DTYPE_FILE
を渡すことによって割り当てられます。
注意: これらの2つのLOBロケータ型は交換できません。 BLOB かCLOB をバインドまたは定義するとき、アプリケーションでは、OCI_DTYPE_LOB を使用してロケータが適切に割り当てられるようにする必要があります。同様に、BFILE をバインドまたは定義するとき、アプリケーションでは、OCI_DTYPE_FILE を使用してロケータが割り当てられるようにする必要があります。 |
OCIアプリケーションでは、選択リストの要素としてLOB列または属性を含むSQL文を発行することによって、サーバーからLOBロケータを取り出せます。その場合、アプリケーションは最初にLOBロケータを割り当て、次にそれを使用して出力変数を定義します。同様に、LOBロケータは、SQL文でLOBとプレースホルダとの間の関連付けを行うバインド操作の一部として使用できます。
OCIアプリケーションは、パラメータ記述子を使用して、選択リスト列またはスキーマ・オブジェクトについての情報を取得します。この情報は、記述操作を通して取得されます。
このパラメータ記述子は、OCIDescriptorAlloc()
を使用して割り当てられることのない唯一の記述子タイプです。パラメータ記述子は、OCIParamGet()
コールを使用してパラメータの位置を指定することによって、記述ハンドル、文ハンドル、または複合オブジェクト検索ハンドルの属性としてのみ取得できます。
ROWID
記述子(OCIRowid
)は、Oracle ROWIDを取り出して使用する必要があるアプリケーションで使用されます。リリース8.x以上のOCIを使用してROWID
を操作するために、アプリケーションではSQL選択リスト内のROWIDの位置に対応するROWID
記述子を定義し、その記述子内のROWID
を検索できます。この同じ記述子を、後でINSERT
文またはWHERE
句の入力変数にバインドできます。
また、文の実行後に文ハンドルでOCIAttrGet()
を使用し、ROWID
を記述子にリダイレクトできます。
これらの記述子は、日付、日時または時間隔データ型(OCIDate
、OCIDateTime
およびOCIInterval
)を使用するアプリケーションで使用されます。これらの記述子は、バインドおよび定義で使用され、メモリーを割り当てたり解放する関数のOCIDescAlloc()
およびOCIDescFree()
にパラメータとして渡されます。
OCIDescriptorAlloc()
コールには、そのパラメータ・リストにxtramem_sz
パラメータが含まれています。このパラメータは、記述子またはロケータとともに割り当てるユーザー・メモリー量を指定するために使用します。
通常、アプリケーションは、このパラメータを使用して、記述子またはロケータと同じ存続期間を持つアプリケーション定義の構造体を割り当てます。この構造体は、アプリケーション・ブックキーピングまたはコンテキスト情報の格納に使用できます。
xtramem_sz
パラメータを使用すると、アプリケーションでは、各記述子またはロケータを割り当てたり、割当て解除するたびに、メモリーを明示的に割り当てたり、割当て解除する必要がありません。メモリーは記述子またはロケータとともに割り当てられるため、記述子またはロケータを解放すると(OCIDescriptorFree()
により)、ユーザーのデータ構造も解放されます。
OCIHandleAlloc()
コールには、ハンドルと同じ存続期間を持つユーザー・メモリーを割り当てるための同様のパラメータがあります。
OCIEnvCreate()
コールおよびOCIEnvInit()
コールには、環境ハンドルと同じ存続期間を持つユーザー・メモリーを割り当てるための同様のパラメータがあります。
この後の各項では、OCIアプリケーションを開発する各ステップについて詳しく説明します。いくつかのステップは、オプションです。たとえば、文が問合せでない場合には、選択リスト項目を記述または定義する必要はありません。
関連項目:
|
次の各項では、OCIのアプリケーションで必要なステップについて説明します。
また、OCI関数のいずれか、またはすべてのステップ間で、アプリケーション固有の処理も発生します。
この項では、OCI環境を初期化してサーバーとの接続を確立し、ユーザーがデータベースに対してアクションを実行できるように許可する方法を説明します。
次の3つの項では、OCI環境を初期化するための3つの主要なステップについて説明します。
各OCIファンクション・コールは、OCIEnvCreate()
コールで作成された環境のコンテキスト内で実行されます。このコールは、他のOCIコールの実行よりも先に行う必要があります。唯一の例外は、OCI共有モードのプロセスレベルの属性を設定する場合です。
OCIEnvCreate()
のmode
パラメータは、OCIライブラリ関数をコールするアプリケーションが次のことを行うかどうか指定します。
スレッド化環境での実行(mode
= OCI_THREADED
)
サブスクリプションの使用(mode
= OCI_EVENTS
)
これらのモードは、環境ごとに設定できます。
アプリケーションがオブジェクトのバインドおよび定義を行う場合、またはOCIのオブジェクト・ナビゲーション・コールを使用する場合は、オブジェクト・モードでの初期化が必要です。また、アプリケーションでこれらの機能をすべて使用しないようにしたり(mode
= OCI_DEFAULT
)、縦線で区切って組み合せて使用することもできます。たとえば、mode
= (OCI_THREADED
| OCI_OBJECT
)を指定すると、アプリケーションはスレッド化環境で動作し、オブジェクトを使用します。
OCI環境ごとにユーザー定義のメモリー管理関数を指定できます。
関連項目:
|
Oracleは、ハンドルと記述子を割り当てたり割当て解除するためのOCI関数を提供します。ハンドルは、OCIHandleAlloc()
を使用して割り当てた後、OCIコールに渡す必要があります(OCIBindByPos()
のように、OCIコールがユーザーにかわってハンドルを割り当てる場合は除きます)。
OCIHandleAlloc()
を使用して、表2-1「OCIハンドル・タイプ」にリストされた種類のハンドルを割当てできます。アプリケーションの機能に応じて、これらのハンドルのいくつかまたはすべてを割り当ててください。
アプリケーションでは、OCIEnvNlsCreate()
をコールしてOCI環境ハンドルを初期化する必要があります。既存のアプリケーションで、OCIEnvCreate()
が使用されていた可能性があります。
アプリケーションで、このステップに従ってサーバー接続を確立し、ユーザー・セッションを開始する場合、いくつかのオプションがあります。
注意: OCIInitialize() およびOCIEnvInit() コールのかわりに、OCIEnvCreate() またはOCIEnvNlsCreate() を使用する必要があります。OCIInitialize() およびOCIEnvInit() コールは、下位互換性を保つためにサポートされています。 |
このオプションは、単純化されたログイン方法です。データベース接続ごとに常時シングル・ユーザー・セッションのみをメンテナンスする場合に使用できます。
アプリケーションからOCILogon2()
をコールすると、OCIライブラリは、渡されたサービス・コンテキスト・ハンドルを初期化し、次に、要求を行ったユーザーが指定したサーバーへの接続を作成します。
次の例は、シングル・ユーザー・セッション(ユーザー名hr
、パスワードhr
およびデータベースoracledb
)を開始するためのOCILogon2()
のコールを示しています。
OCILogon2(envhp, errhp, &svchp, (text *)"hr", (ub4)strlen("hr"), (text *)"hr", (ub4)strlen("hr"), (text *)"oracledb", (ub4)strlen("oracledb"), OCI_DEFAULT);
このコールのパラメータには、接続を確立するために使用するサービス・コンテキスト・ハンドル(初期化済)、ユーザー名、ユーザーのパスワードおよびデータベース名を含めることができます。このコールでは、最後のパラメータmode
をOCI_DEFAULT
に設定することで、旧OCILogon()
コールと同じ結果が得られます。新しいアプリケーションでは、OCILogon2()
を使用します。この関数によって、サーバー・ハンドルおよびユーザー・セッション・ハンドルが暗黙的に割り当てられます。
アプリケーションがこのログイン方法を使用する場合、サービス・コンテキスト、サーバーおよびユーザー・セッション・ハンドルはすべて読取り専用となります。つまり、OCIAttrSet()
コールによってサービス・コンテキスト・ハンドルの該当する属性を変更することにより、アプリケーションがセッションまたはトランザクションを切り替えることはできません。
アプリケーションでOCILogon2()
を使用してセッションおよび認可を初期化した場合は、OCILogoff()
を使用してそれらを終了する必要があります。
通常、プロキシ認証は、ファイアウォールなどの中間層のある環境で採用されるプロセスです。そのような環境では、エンド・ユーザーが中間層で認証され、この中間層がそのユーザーのかわりに—ユーザーのプロキシとして、データベースで認証されます。中間層はプロキシ・ユーザーとしてデータベースにログインします。プロキシ・ユーザーは識別情報を切り替えることができ、データベースにログインした後、エンド・ユーザーの識別情報に切り替えることができます。プロキシ・ユーザーは、特定のエンド・ユーザーに対する適切な権限を使用して、エンド・ユーザーのかわりに操作を実行できます。
データベース・ユーザーのプロキシは、OCIと次のBNF構文を持つALTER
USER
文でサポートされます。
ALTER USER <targetuser> GRANT CONNECT THROUGH <proxy> [AUTHENTICATION REQUIRED];
ALTER
USER
文は、アプリケーションで一度のみ使用されます。以降は、何回でも接続できます。OCIでは、接続文字列または関数OCIAttrSet()
(パラメータOCI_ATTR_PROXY_CLIENT
付き)を使用できます。
プロキシの切替えが行われると、現在接続しているユーザーがプロキシのターゲット・ユーザーになります。元のユーザーの識別情報は、権限の計算対象としては使用されません。元のユーザーはローカル・ユーザーまたは外部ユーザーになります。
次の例は、OCIAttrSet()
(セッション・ハンドルの属性OCI_ATTR_USERNAME
を渡す)とともに、OCILogon2()
(mode
= OCI_DEFAULT
を設定)、OCILogon()
、OCISessionBegin()
などの関数内で使用できる接続文字列を示しています。
ローカル・ユーザーを別のローカル・ユーザーの代理にする場合
DilbertとJoeの2人は、それぞれがローカル・データベース・ユーザーです。DilbertをJoeの代理にするには、次のSQL文を使用します。
ALTER USER joe GRANT CONNECT THROUGH dilbert;
ユーザー名dilbert
をjoe
の代理にするには、接続文字列を次のようにします(dilbert
のパスワードはtiger123
)。
dilbert[joe]/tiger123@db1
[ と ] は、実際に接続文字列に入力します。
ローカル・ユーザーを別のローカル・ユーザーの代理とし、かつ各ユーザー名を引用符で囲む必要がある場合
"Dilbert"と"Joe"の2人は、それぞれがローカル・データベース・ユーザーです。これらの名前は大/小文字を区別し、引用符で囲む必要があります。"Dilbert"を"Joe"の代理にするには、次のSQL文を使用します。
ALTER USER "Joe" GRANT CONNECT THROUGH "Dilbert";
"Dilbert"を"Joe"の代理にするには、接続文字列を次のようにします(文字 " も含めます)。
"Dilbert"["Joe"]/tiger123@db1
ローカル・ユーザーdilbert[mybert ]
がデータベースに接続する場合
データベース"dilbert[mybert]"にユーザーが存在し、このユーザーのデータベース接続方法は次のとおりです([ と ] は実際に接続文字列に入力します)。
"dilbert[mybert]"/tiger123 rem the user was already created this way: rem CREATE USER "dilbert[mybert]" IDENTIFIED BY tiger123;
ローカル・ユーザーを別のローカル・ユーザーの代理にし、かつユーザー名に [ ] を含める場合
dilbert[mybert]およびjoe[myjoe]の2人は、文字 [ と ] を含んだデータベース・ユーザーです。dilbert[mybert]を[myjoe]の代理にするには、接続文を次のようにします。
"dilbert[mybert]"["joe[myjoe]"]/tiger123
ターゲット・ユーザー名を設定するには、ALTER
USER
文の後、OCIプログラムを使用して、その中のOCIAttrSet()
によって属性OCI_ATTR_PROXY_CLIENT
およびプロキシdilbert
を設定します。たとえば、次のようにします。
ALTER USER joe GRANT CONNECT THROUGH dilbert;
プログラム内で次の各文を使用して複数回接続を行います。
OCIAttrSet(session, OCI_HTYPE_SESSION, (void *)"dilbert", (ub4)strlen("dilbert"), OCI_ATTR_USERNAME, error_handle); OCIAttrSet(session, OCI_HTYPE_SESSION, (void *)"tiger123", (ub4)strlen("tiger123"), OCI_ATTR_PASSWORD, error_handle); OCIAttrSet(session, OCI_HTYPE_SESSION, (void *)"joe", (ub4)strlen("joe"), OCI_ATTR_PROXY_CLIENT, error_handle);
関連項目: |
このオプションでは、明示的なアタッチ・コールおよびセッション開始コールを使用して、データベース接続で複数のユーザー・セッションおよび接続を作成します。サーバーにアタッチし、セッションを開始するための具体的なコールは、次のとおりです。
OCIServerAttach()
− OCI操作用のデータ・サーバーにアクセスするためのアクセス・パスを作成します。
OCISessionBegin()
− 特定のサーバーに対するユーザーのセッションを確立します。ユーザーがサーバーに対する操作を実行するには、このコールが必須です。
異なるサービス・コンテキスト・ハンドルおよびセッション・コンテキスト・ハンドルを使用するOCISessionBegin()
への後続コールは、前のユーザーをログオフするため、エラーを引き起こします。移行不可能な2つの同時セッションを実行するには、2番目のOCISessionBegin()
コールに、同じサービス・コンテキスト・ハンドルおよび新しいセッション・コンテキスト・ハンドルを使用する必要があります。
これらのコールにより、データベースに対してSQL文およびPL/SQL文を実行できる操作環境が設定されます。
関連項目:
|
OCI環境の作成および初期化の使用例を次に示します。
サーバー・コンテキストを作成し、それをサービス・ハンドルに設定します。
次に、ユーザー・セッション・ハンドルを作成し、データベース・ユーザー名とパスワードを使用してそれを初期化します。
簡潔にするため、エラー・チェックは含まれていません。
#include <oci.h> ... main() { ... OCIEnv *myenvhp; /* the environment handle */ OCIServer *mysrvhp; /* the server handle */ OCIError *myerrhp; /* the error handle */ OCISession *myusrhp; /* user session handle */ OCISvcCtx *mysvchp; /* the service handle */ ... /* initialize the mode to be the threaded and object environment */ (void) OCIEnvCreate(&myenvhp, OCI_THREADED|OCI_OBJECT, (void *)0, 0, 0, 0, (size_t) 0, (void **)0); /* allocate a server handle */ (void) OCIHandleAlloc ((void *)myenvhp, (void **)&mysrvhp, OCI_HTYPE_SERVER, 0, (void **) 0); /* allocate an error handle */ (void) OCIHandleAlloc ((void *)myenvhp, (void **)&myerrhp, OCI_HTYPE_ERROR, 0, (void **) 0); /* create a server context */ (void) OCIServerAttach (mysrvhp, myerrhp, (text *)"inst1_alias", strlen ("inst1_alias"), OCI_DEFAULT); /* allocate a service handle */ (void) OCIHandleAlloc ((void *)myenvhp, (void **)&mysvchp, OCI_HTYPE_SVCCTX, 0, (void **) 0); /* set the server attribute in the service context handle*/ (void) OCIAttrSet ((void *)mysvchp, OCI_HTYPE_SVCCTX, (void *)mysrvhp, (ub4) 0, OCI_ATTR_SERVER, myerrhp); /* allocate a user session handle */ (void) OCIHandleAlloc ((void *)myenvhp, (void **)&myusrhp, OCI_HTYPE_SESSION, 0, (void **) 0); /* set user name attribute in user session handle */ (void) OCIAttrSet ((void *)myusrhp, OCI_HTYPE_SESSION, (void *)"hr", (ub4)strlen("hr"), OCI_ATTR_USERNAME, myerrhp); /* set password attribute in user session handle */ (void) OCIAttrSet ((void *)myusrhp, OCI_HTYPE_SESSION, (void *)"hr", (ub4)strlen("hr"), OCI_ATTR_PASSWORD, myerrhp); (void) OCISessionBegin ((void *) mysvchp, myerrhp, myusrhp, OCI_CRED_RDBMS, OCI_DEFAULT); /* set the user session attribute in the service context handle*/ (void) OCIAttrSet ((void *)mysvchp, OCI_HTYPE_SVCCTX, (void *)myusrhp, (ub4) 0, OCI_ATTR_SESSION, myerrhp); ... }
demo
ディレクトリ内のデモ・プログラムcdemo81.c
は、このプロセスとエラー・チェックを例示しています。
アプリケーションは、OCITransCommit()
をコールすることにより、データベースへの変更をコミットします。このコールは、サービス・コンテキストをパラメータの1つとして使用します。トランザクションは、変更がコミットされるサービス・コンテキストに対応付けられています。このトランザクションは、アプリケーションで明示的に作成されたか、または、アプリケーションがデータベースを変更したときに暗黙的に作成された可能性があります。
注意: OCIExecute() コールのOCI_COMMIT_ON_SUCCESS モードを使用すると、トランザクションをコミットするかどうかを、各文の実行後にアプリケーションで選択できるため、ラウンドトリップを削減できます。 |
トランザクションをロールバックするには、OCITransRollback()
コールを使用します。
通常のログオフ以外のなんらかの方法でアプリケーションとOracleの接続が切断された場合(ネットワークとの接続が切れるなど)、OCITransCommit()
をコールしていないと、アクティブ・トランザクションはすべて自動的にロールバックされます。
OCIアプリケーションは、終了する前に、次の3つのステップの実行が必要です。
各セッションに対してOCISessionEnd()
をコールし、ユーザー・セッションを終了します。
各データ・ソースに対してOCIServerDetach()
をコールし、データ・ソースへのアクセスを終了します。
各ハンドルに対してOCIHandleFree()
をコールし、明示的に全ハンドルの割当てを解除します。
環境ハンドルを削除し、環境ハンドルに関連付けられたその他のハンドルの割当てをすべて解除します。
注意: 親ハンドルが解放されると、それに対応付けられた子ハンドルもすべて自動的に解放されます。 |
OCIServerDetach()
およびOCISessionEnd()
のコールは、必須ではありませんが、お薦めします。アプリケーションがOCITransCommit()
(トランザクション・コミット)をコールしないで終了すると、保留状態のトランザクションはすべて自動的にロールバックされます。
注意: アプリケーションで OCILogon() の単純化されたログイン方法を使用する場合は、OCILogoff() をコールするとセッションが終了し、サーバーとの接続が切断され、サービス・コンテキスト・ハンドルとそれに関連付けられたハンドルが解放されます。ただし、アプリケーションにより割り当てた他のハンドルは、そのアプリケーションから解放してください。 |
OCIファンクション・コールには、表2-3「OCIリターン・コード」にリストされた一連のリターン・コードが用意されています。これらのコードにより、コールの成功または失敗(OCI_SUCCESS
、OCI_ERROR
など)や、アプリケーションが必要とするその他の情報(OCI_NEED_DATA
、OCI_STILL_EXECUTING
など)が示されます。大部分のOCIコールは、これらのコードの1つを戻します。
サーバーへの接続がOCI_ERROR
で終了しないように、アプリケーションでは、サーバー・ハンドル内の属性OCI_ATTR_SERVER_STATUS
の値をチェックできます。属性の値がOCI_SERVER_NOT_CONNECTED
の場合、サーバーへの接続およびユーザー・セッションを再確立する必要があります。
表2-3 OCIリターン・コード
OCIリターン・コード | 説明 |
---|---|
関数は正常に終了しました。 |
|
関数は正常に終了しました。 |
|
関数が終了しました。これ以上データはありません。 |
|
関数が失敗しました。 |
|
無効なハンドルがパラメータとして渡されたか、ユーザー・コールバックで無効なハンドルまたは無効なコンテキストが渡されました。追加診断情報はありません。 |
|
アプリケーションで、ランタイム・データを提供する必要があります。 |
|
サービス・コンテキストが非ブロック化モードで確立されたため、現行の操作は即時完了できませんでした。この操作を完了するには、これを再度コールする必要があります。 |
|
このコードはコールバック関数からのみ戻されます。これは、コールバック関数が、OCIライブラリの標準処理再開を示唆していることを示します。 |
エラーが発生したことがリターン・コードに示されている場合、アプリケーションではOCIErrorGet()
をコールして、Oracle固有のエラー・コードおよびメッセージを取り出せます。OCIErrorGet()
へのパラメータの1つは、エラーが発生したコールに渡されたエラー・ハンドルです。
注意: レコードがなくなる( OCI_NO_DATA が戻される)まで、繰り返しOCIErrorGet() をコールすると、複数の診断レコードを取り出すことができます。OCIErrorGet() は、最大1個の診断レコードを戻します。 |
表2-4に、フェッチされたデータが正常、NULL、または切捨ての場合の、OCIリターン・コード、エラー番号、標識変数および列リターン・コードを示します。
表2-4 リターン・コードとエラー・コード
データの状態 | リターン・コード | インジケータ − 戻さない場合 | インジケータ − 戻す場合 |
---|---|---|---|
NULL、切捨て以外 |
戻さない場合 |
error = 0 |
error = 0 indicator = 0 |
NULL、切捨て以外 |
戻す場合 |
error = 0 return code = 0 |
error = 0 indicator = 0 return code = 0 |
NULLデータ |
戻さない場合 |
error = 1405 |
error = 0 indicator = -1 |
NULLデータ |
戻す場合 |
error = 1405 return code = 1405 |
error = 0 indicator = -1 return code = 1405 |
切捨てデータ |
戻さない場合 |
error = 1406 |
error = 1406 indicator = data_len |
切捨てデータ |
戻す場合 |
error = 24345 return code = 1405 |
error = 24345 indicator = data_len return code = 1406 |
切捨てデータの場合、data_len
は、長さがSB2MAXVAL
以下であった場合に切り捨てられたデータの実際の長さです。この値を超えていれば、インジケータが-2に設定されます。
一部の関数では、表2-3にリストされているOCIエラー・コード以外の値を戻します。これらの関数を使用する場合、OUTパラメータからではなく、ファンクション・コールから直接値が戻ります。それぞれの関数と戻り値の詳細は、該当する章を参照してください。
この項では、OCIアプリケーションをコーディングするときのその他の問題について説明します。
OCI関数には整数、ハンドル、文字列など、多様なデータ型のパラメータを使用することができます。パラメータの型によっては注意事項があり、以降の項で説明します。
データベース列にNULLを挿入する方法はいくつかあります。
1つは、INSERT
文またはUPDATE
文のテキストの中でリテラルNULL
を使用する方法です。たとえば、次のようなSQL文があるとします。
INSERT INTO emp1 (ename, empno, deptno) VALUES (NULL, 8010, 20)
この文では、ENAME
列がNULL
になります。
OCIバインド・コールでは、標識変数を使用します。
NULL
を挿入するには、バッファ長パラメータと最大長パラメータの両方を、バインド・コールで0(ゼロ)に設定します。
注意: 対応する標識変数が定義コールで指定されていても、その標識変数を含まない変数にNULL選択リスト項目をフェッチすると、OracleはSQL92要件に従いエラーを戻します。 |
各バインドと定義OCIコールには、標識変数または標識変数の配列をDML文、PL/SQL文または問合せに関連付けるパラメータがあります。
C言語にはNULL値の概念がありません。したがって、標識変数と入力変数を関連付けることによって、関連付けられたプレースホルダがNULL
であるかどうかを指定します。データがOracleに渡されるとき、これらの標識変数の値によって、NULL
がデータベース・フィールドに割り当てられているかどうかが判断されます。
出力変数では、標識変数によって、Oracleから戻された値がNULL
または切り捨てられた値であるかどうかが判断されます。OCIStmtFetch()
コールでのNULL
フェッチ、またはOCIStmtExecute()
コールでの切捨ての場合は、OCIコールによりOCI_SUCCESS_WITH_INFO
が戻されます。出力標識変数が設定されます。
標識変数のデータ型はsb2
です。標識変数の配列の場合、各配列要素の型はsb2
です。
入力ホスト変数については、OCIアプリケーションは次の値を標識変数に割り当てることができます。
入力インジケータ値 | Oracleからのアクション |
---|---|
-1 | OracleはNULL を列に割り当て、入力変数の値は無視します。 |
>=0 | 入力変数の値を列に割り当てます。 |
出力については、Oracleは次の値を標識変数に割り当てます。
出力インジケータ値 | 意味 |
---|---|
-2 | 項目の長さが出力変数の長さよりも長いため、項目を切り捨てます。さらに、元の長さが、sb2 標識変数で戻せる最大長より長くなっています。 |
-1 | 選択された値がNULLで、出力変数の値は変更されません。 |
0 | 完全な値をホスト変数に割り当てます。 |
>0 | 項目の長さが出力変数の長さよりも長いため、項目を切り捨てます。標識変数に戻された正の値は、切捨て前の実際の長さです。 |
リリース8.0より後に導入されたデータ型の標識変数は、前述の説明どおりに機能します。例外はSQLT_NTY(名前付きデータ型)です。SQLT_NTY型のデータの場合、標識変数はインジケータ構造体へのポインタである必要があります。SQLT_REF型のデータでは、他の変数型と同様に、標準のスカラー・インジケータを使用します。
Object Type Translator(OTT)を使用してデータベース型をC構造体に変換すると、各オブジェクト型についてNULLインジケータ構造体が生成されます。この構造体には、アトミックNULLインジケータと各オブジェクト属性のインジケータが含まれます。
関連項目:
|
ほとんどのオペレーティング・システムでは、キーボードからオペレーティング・システムの割込み文字(通常は[Ctrl] + [C]キー)を入力することで、長時間実行されたり繰り返されているOCIコールを取り消すことができます。
注意: OCIコールの取消しをカーソルの取消しと混同しないように注意してください。カーソルの取消しは、 nrows パラメータを0(ゼロ)に設定し、OCIStmtFetch() をコールして行います。 |
長時間実行されたり繰り返されているコールをオペレーティング・システムへの割込みにより取り消した場合は、エラー・コードORA-01013「ユーザーによって現行の操作の取消しが要求されました。」が戻されます。
特定のサービス・コンテキスト・ポインタまたはサーバー・コンテキスト・ポインタを指定すると、OCIBreak()
関数は、サーバーに関連付けられている現在実行中のOCI関数をすべて即時(非同期)に停止します。これは通常、サーバーで長時間実行されている処理中のOCIコールを停止するために使用します。OCIReset()関数は、OCIアプリケーションがOCIBreak()
で機能を停止した後で、非ブロック化接続に対してプロトコル同期化を実行するために必要です。
注意: OCIBreak() は、Windows 2000やWindows XPなどのWindowsシステムで作動します。 |
長時間実行する可能性のあるコールは、非ブロック化コールを使用することによりステータスを監視することができます。新しいアプリケーションでは、マルチスレッドを使用します。
SELECT
...FOR
UPDATE
OF
...文に関連付けられたROWID
を、後のUPDATE
文またはDELETE
文に使用できます。ROWID
は、文ハンドルに対してOCIAttrGet()
をコールして取り出すことができ、これによりこのハンドルのOCI_ATTR_ROWID
属性を取り出せます。
たとえば、次のようなSQL文があるとします。
SELECT ename FROM emp1 WHERE empno = 7499 FOR UPDATE OF sal
この場合、フェッチが実行されると、ハンドルのROWID
属性には選択された行の行識別子が入ります。次のコードのようにOCIAttrGet()
をコールして、プログラムのバッファにROWID
を取り出すことができます。
OCIRowid *rowid; /* the rowid in opaque format */ /* allocate descriptor with OCIDescriptorAlloc() */ status = OCIDescriptorAlloc ((void *) envhp, (void **) &rowid, (ub4) OCI_DTYPE_ROWID, (size_t) 0, (void **) 0); status = OCIAttrGet ((void *) mystmtp, OCI_HTYPE_STMT, (void *) rowid, (ub4 *) 0, OCI_ATTR_ROWID, (OCIError *) myerrhp);
その後、保存されたROWID
をDELETE
文またはUPDATE
文で使用できます。たとえば、rowid
が行識別子の保存されているバッファである場合、後で次のようなSQL文を処理できます。
UPDATE emp1 SET sal = :1 WHERE rowid = :2
これは、新しいsalary(給与)をプレースホルダ:1
にバインドし、rowid
をプレースホルダ:2
にバインドして行います。rowid
を:2
にバインドする場合は、必ずデータ型コード104(ROWID
記述子)を使用してください。
プリフェッチを使用して、ROWIDの配列を後続のバッチ更新で使用するために選択できます。
一部のワードはOracleによって確保されています。つまり、それらのワードはOracleにとって特別な意味を持っており、再定義できません。このため、それらのワードを使用して、列、表、索引などのデータベース・オブジェクトに名前を付けることはできません。
表2-5「Oracle予約済ネームスペース」は、Oracleによって予約されているネームスペースのリストです。Oracleライブラリ内の関数名の最初の文字列は、このリストの文字列に制限されています。名前が競合する可能性があるため、これらの文字列で始まる関数名を付けないでください。
表2-5 Oracle予約済ネームスペース
ネームスペース | ライブラリ |
---|---|
|
XAアプリケーション専用の外部関数 |
|
OracleのプリコンパイラおよびSQL*Moduleアプリケーションで使用される外部SQLLIB関数 |
|
外部OCI関数、内部OCI関数 |
|
Oracle UPIレイヤーの関数名 |
|
Oracle Netネイティブ・サービス・プロダクト Oracle Net Rpcプロジェクト Oracle Netディレクトリ Oracle Netネットワーク・ライブラリ・レイヤー Oracle Net管理プロジェクト Oracle Netインターチェンジ Oracle Netトランスペアレント・ネットワーク・サービス Oracle Netドライバ Oracle Netセキュリティ・サービス SQL*Netバージョン1 Oracle Net 2タスク |
|
コア・ライブラリ関数 |
|
Oracleグローバリゼーション・サポート・レイヤーの関数名 |
|
システム依存ライブラリの関数名 |
|
カーネル・オブジェクト |
特定のネームスペースのすべての関数リストは、該当するOracleライブラリに対応したドキュメントを参照してください。
非ブロック化モードではラウンドトリップ回数とCPU使用率が増加するため、新しいアプリケーションではマルチスレッド・コールを使用します。
OCIでは、ブロック化モードまたは非ブロック化モードでサーバー接続を確立できます。接続がブロック化モードで行われた場合、結果が正常かエラーかにかかわらずコールが完了した場合にのみ、OCIコールはコントロールをOCIクライアント・アプリケーションに戻します。非ブロック化モードでは、コールが完了せずコールからOCI_STILL_EXECUTING
の値が戻されても、コントロールはただちにOCIプログラムに戻されます。
非ブロック化モードでは、アプリケーションで各OCI関数のリターン・コードをテストし、OCI_STILL_EXECUTING
が戻されるかどうかを確認する必要があります。この場合、OCIクライアントはこのOCIコールのサーバーでの再試行を待つ間、プログラム・ロジックの処理を継続できます。このモードは、Graphical User Interface(GUI)アプリケーション、リアルタイム・アプリケーションおよび分散環境の場合に特に有用です。
非ブロック化モードは非割込み駆動で、むしろポーリング・パラダイムに基づいています。これは、保留状態のコールがサーバーで終了したかどうかを、同一パラメータでそのコールを再び実行することにより、クライアント・アプリケーションがチェックする必要があることを意味します。
次の機能および関数は、非ブロック化モードではサポートされません。
ダイレクト・パス・ローダー
LOBバッファリング
オブジェクト
問合せキャッシュ
スクロール・カーソル
TAF
OCIAQEnqArray()
OCIAQDeqArray()
OCIDescribeAny()
OCILobArrayRead()
OCILobArrayWrite()
OCITransStart()
OCITransDetach()
注意: 非ブロック化OCIコールの再試行を待機している間、アプリケーションでは、待機している非ブロック化OCIに関連する他のOCIコールを実行しないでください。他のコールを実行すると、ORA-03124またはORA-24386のエラーが発生したり、場合によってはアプリケーションが停止することがあります。 このルールの唯一の例外は、 OCIBreak() コールとOCIReset() コールです。 |
アプリケーションのブロック化状態は、attrtype
パラメータをOCI_ATTR_NONBLOCKING_MODE
に設定して、サーバー・コンテキスト・ハンドルでOCIAttrSet()
をコールして状態を設定したり、OCIAttrGet()
をコールして状態を読み取ることにより、変更またはチェックすることができます。この属性を設定できるのは、OCISessionBegin()
またはOCILogon2()
がコールされた後でのみです。設定されていない場合は、エラーが戻されます。
注意: パラメータとしてサーバー・コンテキスト・ハンドルまたはサービス・コンテキスト・ハンドルを持つ関数のみが、 OCI_STILL_EXECUTING を戻します。 |
PL/SQLは、Oracleが開発したSQL言語の手続き型拡張機能です。PL/SQLは、単純な問合せやSQLデータ操作言語(DML)文よりも複雑なタスクをサポートします。PL/SQLを使用すると、複数の構文を単一のブロックにグループ化し、それを1単位として実行できます。次のような構文があります。
1つまたは複数のSQL文
変数宣言
代入文
IF...THEN...ELSE
文やループなどのプロシージャ型制御文
例外処理
OCIプログラムでPL/SQLブロックを使用して、次の操作ができます。
Oracleストアド・プロシージャおよびストアド・ファンクションのコール
複数のSQL文を指定したプロシージャ型制御文を結合し、1つの単位として実行
表、CURSOR FOR
ループ、例外処理など、特殊なPL/SQL機能へのアクセス
カーソル変数の使用
サーバー内のオブジェクトの操作
注意:
|
注意: PL/SQLコードを記述する場合は、パーサーにより、「--」で始まるものは改行まですべてコメントとみなされることに注意してください。「--」を使用してコメントを各行に示した場合、Cコンパイラでは各行に改行「¥n」が挿入されず、すべての行がPL/SQLブロックで単一行として連結されます。この特定のケースでは、ある行がコメントで終わっている場合、パーサーは次の行のPL/SQLコード抽出に失敗してしまいます。この問題を回避するには、各「--」コメントの後に「¥n」を入れ、そこでコメントが必ず終了するように注意してください。 |
次の項では、ロケール情報の導出、文字列の操作、キャラクタ・セット変換、OCIメッセージなど、グローバリゼーションに使用されるOCI関数について説明します。これらの関数には複数の目的および機能があるため、詳細は、このマニュアルの他の章を参照してください。
OCIEnvNlsCreate()
関数は、NLS_LANGおよびNLS_NCHARの設定とは関係なく、アプリケーションでキャラクタ・セット情報を設定できます。様々なクライアント側キャラクタ・セットIDおよび各国語キャラクタ・セットIDを使用して、同じシステム環境内で初期化した複数の環境ハンドルを1つのアプリケーションで使用できます。
OCIEnvNlsCreate(OCIEnv **envhp, ..., csid, ncsid);
csid
はキャラクタ・セットIDの値で、ncsid
は各国語キャラクタ・セットIDの値です。いずれの値も0(ゼロ)またはOCI_UTF16ID
に設定できます。両方とも0(ゼロ)の場合は、OCIEnvCreate()
を使用するのと同じになります。その他の引数は、OCIEnvCreate()
コールの引数と同じです。
OCIEnvNlsCreate()
は、OCI_UTF16ID
を検証するため、キャラクタ・セットをプログラムによって制御するための拡張機能です。
OCIEnvNlsCreate()
関数を使用してキャラクタ・セットIDを設定すると、NLS_LANGおよびNLS_NCHARの設定値が置換されます。OCIEnvNlsCreate()
関数では、NLSRTLでサポートされるすべてのキャラクタ・セット以外に、OCI_UTF16ID
をキャラクタ・セットIDとして設定できます(NLS_LANGまたはNLS_NCHARでは無効となります)。
AL16UTF16を除くすべてのOracleキャラクタ・セットIDは、OCIEnvNlsCreate()
関数を使用して指定され、メタデータのエンコーディング、SQL CHAR
データおよびSQL NCHAR
データを指定できます。
NLS_LANGおよびNLS_NCHARのキャラクタ・セットは、関数のOCINlsEnvironmentVariableGet()
を使用して取得できます。
OCINlsGetInfo()
は、OCI_UTF16IDがOCIEnvNlsCreate()
で使用されている場合に、OCI_UTF16ID
に関する情報を戻します。
OCIAttrGet()
は、OCIEnvNlsCreate()
に渡されたキャラクタ・セットIDおよび各国語キャラクタ・セットIDを戻します。これは、OCI_ATTR_ENV_CHARSET_ID
およびOCI_ATTR_ENV_NCHARSET_ID
を取得するために使用されます。これには、値OCI_UTF16ID
が含まれます。
OCIEnvNlsCreate()
を使用してcharset
およびncharset
パラメータにNULLが設定されている場合は、NLS_LANG
およびNLS_NCHAR
のキャラクタ・セットIDが戻されます。
この関数を使用してOCI_ATTR_CHARSET_FORM
がリセットされている場合、OCIAttrSet()は文字IDをデフォルトとして設定します。OCI_UTF16ID
は、OCIEnvNlsCreate()
でcharset
またはncharset
として渡される場合、有効なキャラクタ・セットIDの1つになります。
OCIBindByName()
およびOCIBindByPos()
は、OCIEnvNlsCreate()
コールのデフォルトのキャラクタ・セット(OCI_UTF16ID
を含む)を使用して、変数をバインドします。OCIEnvNlsCreate()
を使用する場合、実際の長さと戻される長さは常にバイト単位で表されます。
OCIDefineByPos()
は、OCIEnvNlsCreate()
のcharset
の値(OCI_UTF16ID
を含む)を持つ変数をデフォルトとして定義します。OCIEnvNlsCreate()
を使用する場合、実際の長さと戻される長さは常にバイト単位で表されます。バインド・ハンドルおよび定義ハンドルのこの動作は、OCIEnvCreate()
を使用する場合とは異なり、OCI_UTF16ID
はバインド・ハンドルおよび定義ハンドル用のキャラクタ・セットIDになります。
OCIは、サーバーとクライアント間のトランスレータとして機能し、制約チェックを行うための文字情報を渡します。
キャラクタ・セットには可変幅と固定幅の2種類があります。シングルバイト・キャラクタ・セットは、各バイトが1つの文字を表す固定幅キャラクタ・セットの特殊なケースです。
固定幅キャラクタ・セットの場合、バイト数は文字数の倍数であるため、制約チェックが簡単です。したがって、固定幅キャラクタ・セットでは、文字数を調べるために文字列全体をスキャンする必要がありません。これに対して、可変幅キャラクタ・セットでは、文字列全体をスキャンして文字数を調べる必要があります。
詳細は、「記述での文字長セマンティクスのサポート」および「OCIバインドおよび定義における文字変換」を参照してください。
グローバリゼーション・サポート関数は、環境ハンドルまたはユーザー・セッション・ハンドルを受け入れます。OCI環境ハンドルは、クライアントのNLS環境変数に関連付けられます。ALTER
SESSION
文がサーバーに発行された場合、この環境は変更されません。環境ハンドルに関連付けられたキャラクタ・セットは、クライアント・キャラクタ・セットです。OCIセッションハンドル(OCISessionBegin()
によって戻されます)は、サーバー・セッション環境に関連付けられます。ALTER
SESSION
文でセッション環境が変更された場合、NLS設定も変更されます。セッション・ハンドルに関連付けられたキャラクタ・セットは、データベース・キャラクタ・セットです。
セッションで最初のトランザクションが開始されるまで、OCIセッション・ハンドルには、関連付けられたNLS設定がないことに注意してください。SELECT
文では、トランザクションは開始されません。
関数の詳細および説明は、次を参照してください。
Oracleロケールは、言語、地域およびキャラクタ・セット定義で構成されます。ロケールは、曜日と月の名前、および日付、時刻、数値、通貨の書式などの表記規則を決定します。グローバル化されたアプリケーションは、ユーザーのロケール設定および文化の規則に対応しています。たとえば、ロケールをドイツに設定すると、月日の名前がドイツ語で表示されます。
OCINlsGetInfo()
関数を使用して、次の情報を取得できます。
曜日(翻訳済)
曜日の略称(翻訳済)
月名(翻訳済)
月名の略称(翻訳済)
はい/いいえ(翻訳済)
AM/PM(翻訳済)
AD/BC(翻訳済)
数値書式
借方/貸方
日付書式
通貨書式
デフォルトの言語
デフォルトの地域
デフォルト・キャラクタ・セット
デフォルトの言語ソート
デフォルト・カレンダ
次のサンプル・コードは、ロケール情報を取得して、エラーをチェックします。
sword MyPrintLinguisticName(envhp, errhp) OCIEnv *envhp; OCIError *errhp; { OraText infoBuf[OCI_NLS_MAXBUFSZ]; sword ret; ret = OCINlsGetInfo(envhp, /* environment handle */ errhp, /* error handle */ infoBuf, /* destination buffer */ (size_t) OCI_NLS_MAXBUFSZ, /* buffer size */ (ub2) OCI_NLS_LINGUISTIC_NAME); /* item */ if (ret != OCI_SUCCESS) { checkerr(errhp, ret, OCI_HTYPE_ERROR); ret = OCI_ERROR; } else { printf("NLS linguistic: %s\n", infoBuf); } return(ret); }
文字列操作では、マルチバイト文字列およびワイド・キャラクタ文字列がサポートされています。
マルチバイト文字列は、システム固有のOracleキャラクタ・セットでエンコードされています。マルチバイト文字列で動作する関数は、バイト単位で計算された文字列の長さを使用して、文字列全体を1つの単位として使用します。ワイド・キャラクタ文字列(wchar
)関数を使用すると、より柔軟に文字列を操作できます。ワイド・キャラクタ文字列は、文字ベースおよび文字列ベースの操作をサポートします。この場合、文字列の長さは、文字単位で計算されます。
ワイドキャラクタ・データ型OCIWchar
はOracle固有のものです。ANSI/ISO C標準で定義されているwchar_t
データ型と混同しないでください。Oracleワイド・キャラクタ・データ型は、すべてのオペレーティング・システムで常に4バイトですが、wchar_t
のサイズは、実装およびオペレーティング・システムによって異なります。Oracleワイド・キャラクタ・データ型は、マルチバイト文字を正規化するため、統一された固定幅になり、処理が簡単になります。これにより、Oracleワイド・キャラクタ・セットとシステム固有のキャラクタ・セット間でラウンドトリップ変換を行った場合でも、データは失われません。
文字列操作は、次のカテゴリに分類できます。
マルチバイト・キャラクタとワイド・キャラクタ間の文字列変換
文字の分類
大/小文字の変換
表示長の計算
比較、連結、検索などの一般的な文字列操作
単純な文字列操作の例を次に示します。
size_t MyConvertMultiByteToWideChar(envhp, dstBuf, dstSize, srcStr) OCIEnv *envhp; OCIWchar *dstBuf; size_t dstSize; OraText *srcStr; /* null terminated source string */ { sword ret; size_t dstLen = 0; size_t srcLen; /* get length of source string */ srcLen = OCIMultiByteStrlen(envhp, srcStr); ret = OCIMultiByteInSizeToWideChar(envhp, /* environment handle */ dstBuf, /* destination buffer */ dstSize, /* destination buffer size */ srcStr, /* source string */ srcLen, /* length of source string */ &dstLen); /* pointer to destination length */ if (ret != OCI_SUCCESS) { checkerr(envhp, ret, OCI_HTYPE_ENV); } return(dstLen); }
OCIの文字列分類機能について、詳しく説明します。
OCIで文字列を分類する方法の例を次に示します。
boolean MyIsNumberWideCharString(envhp, srcStr) OCIEnv *envhp; OCIWchar *srcStr; /* wide char source string */ { OCIWchar *pstr = srcStr; /* define and init pointer */ boolean status = TRUE; /* define and initialize status variable */ /* Check input */ if (pstr == (OCIWchar*) NULL) return(FALSE); if (*pstr == (OCIWchar) NULL) return(FALSE); /* check each character for digit */ do { if (OCIWideCharIsDigit(envhp, *pstr) != TRUE) { status = FALSE; break; /* non-decimal digit character */ } } while ( *++pstr != (OCIWchar) NULL); return(status); }
Oracleキャラクタ・セットとUnicode(16ビット、固定幅のUnicodeエンコーディング)間の変換がサポートされています。UnicodeからOracleキャラクタ・セットへの文字のマッピングが存在しない場合、置換文字が使用されます。したがって、変換して元のキャラクタ・セットに戻す場合、データが失われる可能性があります。
Unicodeキャラクタ・セットに関連するキャラクタ・セット変換関数では、データのバインド・バッファおよび定義バッファをub2
アドレスで揃える必要があります。揃っていない場合、エラーが発生します。
Unicodeへの単純な変換の例を次に示します。
/* Example of Converting Character Sets in OCI --------------------------------------------*/ size_t MyConvertMultiByteToUnicode(envhp, errhp, dstBuf, dstSize, srcStr) OCIEnv *envhp; OCIError *errhp; ub2 *dstBuf; size_t dstSize; OraText *srcStr; { size_t dstLen = 0; size_t srcLen = 0; OraText tb[OCI_NLS_MAXBUFSZ]; /* NLS info buffer */ ub2 cid; /* OCIEnv character set id */ /* get OCIEnv character set */ checkerr(errhp, OCINlsGetInfo(envhp, errhp, tb, sizeof(tb), OCI_NLS_CHARACTER_SET)); cid = OCINlsCharSetNameToId(envhp, tb); if (cid == OCI_UTF16ID) { ub2 *srcStrUb2 = (ub2*)srcStr; while (*srcStrUb2++) ++srcLen; srcLen *= sizeof(ub2); } else srcLen = OCIMultiByteStrlen(envhp, srcStr); checkerr(errhp, OCINlsCharSetConvert( envhp, /* environment handle */ errhp, /* error handle */ OCI_UTF16ID, /* Unicode character set id */ dstBuf, /* destination buffer */ dstSize, /* size of destination buffer */ cid, /* OCIEnv character set id */ srcStr, /* source string */ srcLen, /* length of source string */ &dstLen)); /* pointer to destination length */ return dstLen/sizeof(ub2); }
次の例では、メッセージ・ハンドルを作成し、impus.msg
からメッセージを取得するために初期化して、メッセージ番号128を取得し、メッセージ・ハンドルをクローズします。この例では、OCI環境ハンドル、OCIセッション・ハンドル、製品、機能およびキャッシュ・サイズが正しく初期化されていることを想定しています。
OCIMsg msghnd; /* message handle */ /* initialize a message handle for retrieving messages from impus.msg*/ err = OCIMessageOpen(hndl,errhp, &msghnd, prod,fac,OCI_DURATION_SESSION); if (err != OCI_SUCCESS) /* error handling */ ... /* retrieve the message with message number = 128 */ msgptr = OCIMessageGet(msghnd, 128, msgbuf, sizeof(msgbuf)); /* do something with the message, such as display it */ ... /* close the message handle when there are no more messages to retrieve */ OCIMessageClose(hndl, errhp, msghnd);
lmsgen
ユーティリティは、テキストベースのメッセージ・ファイル(.msg
)をバイナリ形式(.msb
)に変換します。これにより、ユーザーが提供したOracleメッセージおよびOCIメッセージを、希望する言語でOCI関数に戻すことができます。
lmsgen
text_file
product
facility
[language
]
次のように指定します。
text_file
は、メッセージ・テキスト・ファイルです。
product
は、製品の名前です。
facility
は、機能の名前です。
language
は、NLS_LANG
パラメータで指定された言語に対応する、オプションのメッセージ言語です。メッセージ・ファイルに言語のタグが正しく付いていない場合は、言語パラメータが必要です。
"/"
および"//
"で始まる行は、内部コメントとみなされるため、無視されます。
メッセージ・ファイルに特定の言語のタグを付けるには、次のような行を含めます。
# CHARACTER_SET_NAME= Japanese_Japan.JA16EUC
各メッセージには、3つのフィールドがあります。
message_number
,warning_level
,message_text
メッセージ番号は、メッセージ・ファイル内で一意であることが必要です。
警告レベルは、現在使用されていません。0に設定します。
メッセージ・テキストは、76バイトより長くできません。
Oracleメッセージ・テキスト・ファイルの例を次に示します。
/ Copyright (c) 2001 by the Oracle Corporation. All rights reserved. / This is a test us7ascii message file # CHARACTER_SET_NAME= american_america.us7ascii / 00000, 00000, "Export terminated unsuccessfully\n" 00003, 00000, "no storage definition found for segment(%lu, %lu)"
次の表は、lmsgen
パラメータのサンプル値を示します。
lmsgenパラメータ | 値 |
---|---|
product |
$HOME/myApplication |
facility |
imp |
language |
AMERICAN |
text_file |
impus.msg |
テキスト・メッセージ・ファイルの場所は、次のとおりです。
$HOME/myApp/mesg/impus.msg
テキスト・メッセージ・ファイル内の1行は、次のとおりです。
00128,2, "Duplicate entry %s found in %s"
lmsgen
ユーティリティは、テキスト・メッセージ・ファイル(impus.msg
)をバイナリ形式に変換します。これにより、impus.msb
というファイルが作成されます。
% lmsgen impus.msg $HOME/myApplication imp AMERICAN
出力結果は、次のようになります。
Generating message file impus.msg --> /home/scott/myApplication/mesg/impus.msb NLS Binary Message File Generation Utility: Version 9.2.0.0.0 -Production Copyright (c) Oracle Corporation 1979, 2001. All rights reserved. CORE 9.2.0.0.0 Production