4 OCIプログラミングの基本
この章では、OCIを使用してプログラムを作成する際に必要となる概念および手順について説明します。
この章を読み終えると、基本的なOCIアプリケーションの作成に必要なツールについてほとんど習得したことになります。
この章の内容は次のとおりです。
新規ユーザーは、この章の情報に特に注意してください。この章は、以降の章を理解する基本となります。以降の章の内容は、この章の内容を補足しています。
関連項目:
-
多言語環境に適用されるOCI関数の詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』 を参照してください
-
カートリッジ・サービスに適用されるOCI関数の詳細は、『Oracle Databaseデータ・カートリッジ開発者ガイド』を参照してください
4.1 OCIプログラムのプログラミングの概要
OCIアプリケーションの全般的な目標は、マルチ・ユーザーのために稼働することです。
N層構造では、マルチ・ユーザーがクライアント・アプリケーションにHTTP要求を送信します。クライアント・アプリケーションでは、データ交換やデータ処理など、いくつかのデータ操作を実行する必要があります。
OCIでは、次の基本的なプログラム・フローを使用しています。
-
OCIプログラミング環境およびスレッドの初期化により環境を作成します。
-
必要なハンドルの割当て、およびサーバー接続とユーザー・セッションの確立。
-
サーバー上でのSQL文の実行、データベース・サーバーとの間でのデータ交換、必要なアプリケーション・データ処理の実行。
-
プリペアド文の実行、または新規に実行する文の準備
-
ユーザー・セッションを終了し、サーバー接続から切断します。
-
ハンドルおよびデータ構造を解放します。
図4-1は、OCIアプリケーションのステップの流れを示しています。「OCIプログラミング・ステップ」では、各ステップをより詳細に説明しています。
図およびステップ・リストは、OCIプログラミングのステップを簡潔に表したものです。さらに、プログラムの機能性に応じて様々なバリエーションが考えられます。複数セッションおよび複数トランザクションの管理やオブジェクトの使用など、より高度な機能が組み込まれるOCIアプリケーションには、追加のステップが必要です。
すべてのOCI関数コールは、ある環境のコンテキスト内で実行されます。1つのOCIプロセス内に複数の環境が存在することが可能です。環境でプロセスレベルの初期化が必要になった場合には、自動的に実行されます。
ノート:
OCIアプリケーションには、複数のアクティブな接続および文を含めることができます。
関連項目:
オブジェクトへのアクセスおよび操作の詳細は、「OCIオブジェクト・リレーショナル・プログラミング」から「OCIでのObject Type Translatorの使用」を参照してください
4.2 OCIデータ構造
ハンドルと記述子は、OCIアプリケーションで定義された不透明なデータ構造体です。
ハンドルと記述子は、特定の割当てコールによって直接割り当てるか、あるいはOCI関数を使用して暗黙的に割り当てることができます。
ノート:
リリース7.x OCIのアプリケーション作成の経験を持つプログラマは、大部分のOCIコールに使用されているこれらのデータ構造に慣れる必要があります。
ハンドルおよび記述子を使用して、データ、接続またはアプリケーション動作に関係する情報を格納します。ハンドルについては、次の項で詳しく定義します。
この項には、「ハンドル」のトピックが含まれています
関連トピック
4.2.1 ハンドル
ほとんどすべてのOCIコールには、パラメータ・リストに1つ以上のハンドルを含めることができます。
ハンドルは、OCIライブラリによって割り当てられる記憶域への不透明なポインタです。ハンドルを使用して、コンテキストまたは接続情報を格納するか(たとえば、環境ハンドルまたはサービス・コンテキスト・ハンドル)、またはOCI関数やデータに関する情報を格納します(たとえば、エラー・ハンドルまたは記述ハンドル)。ハンドルを使用すると、アプリケーションではなくライブラリにこのデータが保持されるため、プログラミングが簡単になります。
ほとんどのOCIアプリケーションでは、ハンドルに格納されている情報へのアクセスが必要となります。この情報にアクセスして設定するには、属性の入手および設定のためのOCIコールであるOCIAttrGet()
およびOCIAttrSet()
を使用します。
表4-1は、OCI用に定義されているハンドルを示しています。それぞれのハンドル・タイプについて、OCIコールでハンドル・タイプを識別するために使用される、Cデータ型およびハンドル・タイプ定数をリストしています。
表4-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イベント・ハンドル |
|
該当なし |
OCI SODAコレクション・ハンドル |
|
|
OCI SODAコレクション・カーソル・ハンドル |
|
|
OCI SODAドキュメント・カーソル・ハンドル |
|
|
OCI SODAドキュメント・ハンドル |
|
|
OCI SODA出力オプション・ハンドル |
|
|
OCI SODA操作オプション・ハンドル |
|
|
関連トピック
4.2.1.1 ハンドルの割当てと解放について
アプリケーションでは、すべてのハンドル(バインド・ハンドル、定義ハンドルおよびスレッド・ハンドルは除く)が、特定の環境ハンドルに対して割り当てられます。
環境ハンドルをパラメータの1つとして、ハンドル割当てコールに渡します。こうして、割り当てられたハンドルは、その特定の環境に固有のものとなります。
バインド・ハンドルおよび定義ハンドルは、文ハンドルを親として割り当てられ、そのハンドルによって表される文についての情報を含みます。
ノート:
バインド・ハンドルおよび定義ハンドルは、OCIライブラリによって暗黙的に割り当てられるため、ユーザーによる割当ては不要です。
環境ハンドルはOCIEnvCreate()
またはOCIEnvNlsCreate()
のコールによって割り当てられ、初期化され、このいずれかのコールがすべてのOCIアプリケーションで必要です。
ユーザー割当てハンドルは、すべてOCIハンドル割当てコールOCIHandleAlloc()
によって初期化されます。
ハンドルのタイプには、セッション・プール・ハンドル、ダイレクト・パス・コンテキスト・ハンドル、スレッド・ハンドル、CORハンドル、サブスクリプション・ハンドル、記述ハンドル、文ハンドル、サービス・コンテキスト・ハンドル、エラー・ハンドル、サーバー・ハンドル、接続プール・ハンドル、イベント・ハンドルおよび管理ハンドルがあります。
スレッド・ハンドルは、OCIThreadHndInit()
コールによって割り当てられます。
アプリケーションは、ハンドルが不要になった時点で全ハンドルを解放する必要があります。すべてのハンドルはOCIHandleFree()
関数によって解放されます。
ノート:
親ハンドルが解放されると、それに対応付けられた子ハンドルもすべて解放され、それ以降使用できなくなります。たとえば、文ハンドルが解放されると、それに関連付けられたバインド・ハンドルおよび定義ハンドルも解放されます。
ハンドルにより、グローバル変数を使用する必要性が少なくなります。また、エラー・レポートが簡単になります。エラー・ハンドルは、エラーと診断情報を戻すために使用します。
4.2.1.2 環境ハンドル
環境ハンドルは、すべてのOCI関数を起動させるコンテキストを定義します。各環境ハンドルにはメモリー・キャッシュがあり、これによってメモリー・アクセスが高速になります。環境ハンドルに基づくメモリーの割当ては、このキャッシュで行われます。キャッシュへのアクセスは、複数のスレッドが同じ環境ハンドルに基づいてメモリーの割当てを試行する場合にシリアライズされます。複数のスレッドで単一の環境ハンドルを共有する場合、スレッドはキャッシュへのアクセスをブロックすることがあります。
環境ハンドルは、parentパラメータとしてOCIHandleAlloc()コールに渡され、その他のすべてのハンドル・タイプを割り当てます。バインド・ハンドルと定義ハンドルは、暗黙的に割り当てられます。
4.2.1.3 エラー・ハンドル
エラー・ハンドルは、大部分のOCIコールにパラメータとして渡されます。
エラー・ハンドルは、OCI操作中に発生したエラーについての情報をメンテナンスします。コールでエラーが発生した場合、エラー・ハンドルをOCIErrorGet()
に渡して、発生したエラーに関する追加情報を取得することができます。
ほとんどのOCIコールではパラメータとしてエラー・ハンドルが必要であるため、エラー・ハンドルの割当ては、OCIアプリケーションの最初のステップの1つです。
関連トピック
4.2.1.4 サービス・コンテキスト・ハンドルとそれに対応付けられたハンドル
サービス・コンテキスト・ハンドル は、サーバーに対するOCIコールの操作コンテキストを決定する属性を定義します。
サービス・コンテキスト・ハンドルには、サーバー接続、ユーザー・セッションおよびトランザクションを表す属性として3つのハンドルが含まれています。これらの属性は、図4-2で説明されています。
-
サーバー・ハンドルは、データベースへの接続を識別します。これは、接続指向のトランスポート・メカニズムによって物理接続に変換されます。
-
ユーザー・セッション・ハンドルは、ユーザーのロールと権限(ユーザーのセキュリティ・ドメインとも呼ばれる)およびコールを実行するための操作コンテキストを定義します。
-
トランザクション・ハンドルは、SQL操作を実行するトランザクションを定義します。トランザクション・コンテキストには、フェッチ状態やパッケージのインスタンス化などの、ユーザー・セッション状態の情報が含まれています。
この方法によるサービス・コンテキスト・ハンドルの分析は、拡張性を提供し、プログラマは、洗練された複数層のアプリケーションとトランザクション処理(TP)モニターを作成して、複数のアプリケーション・サーバーと異なるトランザクション・コンテキスト上の複数のユーザーの要求を実行できます。
サービス・コンテキスト・ハンドルを使用する際は、その前にOCIHandleAlloc()
、OCILogon()
またはOCILogon2()
によって、割当てと初期化を行う必要があります。サービス・コンテキスト・ハンドルは、OCIHandleAlloc()
によって明示的に割り当てられます。また、サーバー・ハンドル、セッション・ハンドルおよびトランザクション・ハンドルでは、OCIAttrSet()
を使用して初期化できます。サービス・コンテキスト・ハンドルがOCILogon()
によって暗黙的に割り当てられている場合には、すでに初期化されています。
データベース接続ごとに常時シングル・ユーザー・セッションのみをメンテナンスするアプリケーションでは、OCILogon()
をコールして、初期化されたサービス・コンテキスト・ハンドルを取得できます。
より複雑なセッション管理を必要とするアプリケーションでは、サービス・コンテキスト・ハンドルを明示的に割り当てる必要があり、サーバー・ハンドルおよびユーザー・セッション・ハンドルは、サービス・コンテキスト・ハンドルに明示的に設定する必要があります。OCIServerAttach()
コールとOCISessionBegin()
コールは、サーバー・ハンドルとユーザー・セッション・ハンドルを初期化します。
グローバル・トランザクションの場合、あるいはセッションに対してアクティブなトランザクションが複数存在する場合、アプリケーションではトランザクションを明示的に定義するのみです。また、アプリケーションでは、データベースの内容を変更した際にOCIによって自動的に作成された暗黙的トランザクションを正しく処理できます。
関連項目:
-
サーバー接続およびユーザー・セッションの確立の詳細は、「OCI環境の初期化」および「パスワードおよびセッションの管理」を参照してください
4.2.1.5 文ハンドル、バインド・ハンドルおよび定義ハンドル
文ハンドルは、SQL文またはPL/SQL文と、それぞれに関連付けられた属性を識別するコンテキストです
図4-3に文ハンドルを示します。
入力および出力バインド変数に関する情報は、バインド・ハンドルに格納されています。OCIライブラリでは、OCIBindByName()
またはOCIBindByName2()
関数、あるいはOCIBindByPos()
またはOCIBindByPos2()
関数でバインドされた各プレースホルダのバインド・ハンドルが割り当てられます。ユーザーはバインド・ハンドルを割り当てることはできません。バインド・ハンドルは、バインド・コールによって暗黙的に割り当てられます。
問合せ(select文)によって戻されたフェッチ済データは、定義ハンドルの仕様に従って変換され、取得されます。またOCIライブラリによって、OCIDefineByPos()
またはOCIDefineByPos2()
で定義された各出力変数の定義ハンドルが割り当てられます。ユーザーは定義ハンドルを割り当てることはできません。定義ハンドルは、定義コールによって暗黙的に割り当てられます。
バインド・ハンドルおよび定義ハンドルはOCIライブラリによって暗黙的に割り当てられ、バインド操作または定義操作が繰り返されると、透過的に再利用されます。バインド・ハンドルまたは定義ハンドルの実際の値は、「OCIでのバインドおよび定義」で説明する拡張バインド操作または定義操作のためにアプリケーションで必要とされます。ハンドルが解放されるのは、文ハンドルが解放されたとき、または文ハンドルに新しい文が準備されたときです。バインド・ハンドルまたは定義ハンドルを明示的に割り当てると、メモリー・リークが発生する可能性があります。バインド・ハンドルまたは定義ハンドルを明示的に解放すると、プログラムが異常終了する可能性があります。
4.2.1.6 記述ハンドル
記述ハンドルは、OCI記述コールであるOCIDescribeAny()
によって使用されます。
OCIDescribeAny()
コールは、関数やプロシージャなど、データベース内のスキーマ・オブジェクトに関する情報を取得します。このコールでは、記述されているオブジェクトに関する情報とともに、パラメータの1つとして記述ハンドルが使用されます。コールが完了すると、記述ハンドルには、そのオブジェクトに関する情報が含まれています。OCIアプリケーションでは、パラメータ記述子の属性を通して記述情報を取得します。
関連項目:
-
OCIDescribeAny()
関数の使用方法の詳細は、「スキーマ・メタデータの記述」を参照してください
4.2.1.7 複合オブジェクト検索ハンドル
複合オブジェクト検索(COR)ハンドルは、Oracle Database内のオブジェクトを操作する一部のOCIアプリケーションによって使用されます。
複合オブジェクト検索ハンドルにはCOR記述子が含まれており、これは別のオブジェクトによって参照されるオブジェクトを取得する手順を提供します。
関連トピック
4.2.1.8 スレッド・ハンドル
スレッド・ハンドルはマルチスレッド・アプリケーションで使用されます。
マルチスレッド・アプリケーションで使用されているスレッド・ハンドルの詳細は、次の「OCIThreadパッケージ」を参照してください。
関連トピック
4.2.1.9 サブスクリプション・ハンドル
サブスクリプション・ハンドルは、登録およびサブスクライブを行うOCIクライアント・アプリケーションによって使用され、データベース・イベントまたはAQネームスペース内のイベントの通知を受け取るために使用されます。
サブスクリプション・ハンドルは、クライアントからの登録に関するすべての情報をカプセル化します。
関連トピック
4.2.1.10 ダイレクト・パス・ハンドル
ダイレクト・パス・ハンドルは、Oracle Database内でダイレクト・パス・ロード・エンジンを利用するOCIアプリケーションに必要です。
ダイレクト・パス・ロード・インタフェースを使用して、アプリケーションからOracle Databaseのダイレクト・ブロック・フォーマッタにアクセスできます。図4-4では、各種ダイレクト・パス・ハンドルを示しています。
4.2.1.11 接続プール・ハンドル
接続プール・ハンドルは、物理接続を仮想接続にプールするアプリケーションで使用されます。
接続プール・ハンドルは、特定のOCI関数をコールして物理接続を仮想接続にプールするアプリケーションで使用されます。
関連トピック
4.2.1.12 ハンドル属性
すべてのOCIハンドルには、そのハンドルに格納されているデータを表す属性があります。
ハンドル属性は、属性取得コールOCIAttrGet()
を使用して読み取ることができ、属性設定コールOCIAttrSet()
を使用して変更することもできます。
たとえば、例4-1の文では、OCI_ATTR_USERNAME
属性に書き込むことで、セッション・ハンドルにユーザー名を設定しています。
コールの前に特定のハンドル属性を設定することが必要なOCI関数もあります。たとえば、ユーザーのログイン・セッションを確立するためにOCISessionBegin()
をコールする場合は、コールの実行前にユーザー名とパスワードをユーザー・セッション・ハンドルに設定する必要があります。
完了後、ハンドル属性に有用なデータを戻すOCI関数もあります。たとえば、OCIStmtExecute()
をコールしてSQL問合せを実行した場合は、例4-2で示すように、選択リスト項目に関する記述情報が文ハンドルに戻されます。
関連項目:
-
多数の記述子の割当て方法を示す例は、「OCIArrayDescriptorAlloc()」の説明を参照してください
例4-1 セッション・ハンドルでユーザー名を設定するためのOCI_ATTR_USERNAME属性の使用
text username[] = "hr"; err = OCIAttrSet ((void *) mysessp, OCI_HTYPE_SESSION, (void *)username, (ub4) strlen((char *)username), OCI_ATTR_USERNAME, (OCIError *) myerrhp);
例4-2 選択リスト項目に関する記述情報の文ハンドルへの戻り
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);
4.2.1.13 OCI記述子
OCI記述子およびロケータ は、データ固有の情報を保持する不透明なデータ構造です。
表4-2では、OCI記述子とそのCデータ型、およびその型の記述子をOCIDescriptorAlloc()
のコール内で割り当てるOCI型定数を示しています。OCIDescriptorFree()
関数は、記述子とロケータを解放します。
表4-2 記述子タイプ
説明 | Cデータ型 | OCI型定数 |
---|---|---|
|
||
|
|
|
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
|
|
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
|
|
|
|
|
なし |
||
なし |
|
|
なし |
|
|
|
ノート:
OCILobLocator
に対するC型は1つのみですが、このロケータは内部LOBおよび外部LOBに対しては異なるOCI型定数で割り当てられます。「LOBおよびBFILEロケータ」ではこの違いについて説明します。
次のリストでは、各記述子型の主な目的について説明しています。その後の各項では、各記述子型をより詳細に説明しています。
-
OCISnapshot
- 文の実行時に使用 -
OCILobLocator
- LOBコール(OCI_DTYPE_LOB
)またはBFILE
コール(OCI_DTYPE_FILE
)で使用 -
OCIParam
- 記述コールで使用 -
OCIRowid
-ROWID
値のバインドまたは定義で使用 -
OCIDateTime
およびOCIInterval
- 日時および時間隔データ型で使用 -
OCIComplexObjectComp
- 複合オブジェクト検索で使用 -
OCIAQEnqOptions
、OCIAQDeqOptions
、OCIAQMsgProperties
、OCIAQAgent
- アドバンスト・キューイングで使用 -
OCIAQNotify
- パブリッシュ・サブスクライブ通知で使用 -
OCIServerDNs
- LDAPベースのパブリッシュ・サブスクライブ通知で使用
4.2.1.13.1 スナップショット記述子
スナップショット記述子は、実行コールOCIStmtExecute()
のオプション・パラメータです。
スナップショット記述子は、データベース・スナップショットに対する問合せが実行されることを示します。データベース・スナップショットは、ある特定の時点におけるデータベースの状態を表します。
スナップショット記述子は、OCIDescriptorAlloc()
のコールで、OCI_DTYPE_SNAP
をtype
パラメータとして渡すことによって割り当てられます。
4.2.1.13.2 LOB/BFILEロケータ
ラージ・オブジェクト(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
を渡すことによって割り当てられます。
ノート:
LOBロケータの2つのタイプは代替可能ではありません。BLOB
かCLOB
をバインドまたは定義するとき、アプリケーションでは、OCI_DTYPE_LOB
を使用してロケータが適切に割り当てられるようにする必要があります。同様に、BFILE
をバインドまたは定義するとき、アプリケーションでは、OCI_DTYPE_FILE
を使用してロケータが割り当てられるようにする必要があります。
OCIアプリケーションでは、選択リストの要素としてLOB列または属性を含むSQL文を発行することによって、Oracle DatabaseからLOBロケータを取り出せます。その場合、アプリケーションは最初にLOBロケータを割り当て、次にそれを使用して出力変数を定義します。同様に、LOBロケータは、SQL文でLOBとプレースホルダとの間の関連付けを行うバインド操作の一部として使用できます。
4.2.1.13.3 パラメータ記述子
OCIアプリケーションはパラメータ記述子を使用して、選択リスト列またはスキーマ・オブジェクトに関する情報を取得します。
この情報は、記述操作を通して取得されます。
このパラメータ記述子は、OCIDescriptorAlloc()
を使用して割り当てられることのない記述子タイプです。パラメータ記述子は、OCIParamGet()
コールを使用してパラメータの位置を指定することによって、記述ハンドル、文ハンドル、または複合オブジェクト検索ハンドルの属性としてのみ取得できます。
4.2.1.13.4 ROWID記述子
ROWID
記述子(OCIRowid
)は、Oracle ROWIDを取り出して使用する必要があるアプリケーションで使用されます。
ROWID
を操作するために、アプリケーションではSQL選択リスト内のROWIDの位置に対応するROWID
記述子を定義し、その記述子内のROWID
を検索できます。この同じ記述子を、後でINSERT
文またはWHERE
句の入力変数にバインドできます。
また、文の実行操作後に文ハンドルでOCIAttrGet()
を使用し、ROWID
を記述子にリダイレクトできます。
関連トピック
4.2.1.13.5 日付、日時および時間隔の記述子
日付、日時および時間隔の記述子は、日付、日時または時間隔データ型(OCIDate
、OCIDateTime
およびOCIInterval
)を使用するアプリケーションにより使用されます。
これらの記述子は、バインドおよび定義で使用され、メモリーの割当ておよび解放を行う関数OCIDescriptorAlloc()
およびOCIDescriptorFree()
にパラメータとして渡されます。
4.2.1.13.6 複合オブジェクト記述子
オブジェクトの処理時に、複合オブジェクト検索(COR)を使用すると、アプリケーションのパフォーマンスが向上する場合があります。
オブジェクトの処理時に、複合オブジェクト検索(COR)を使用すると、アプリケーションのパフォーマンスが向上する場合があります。
関連トピック
4.2.1.13.7 アドバンスト・キューイング記述子
データ固有の情報を保持するために使用するOracle Databaseアドバンスト・キューイング記述子がいくつか用意されています。
Oracle Databaseアドバンスト・キューイングは、Oracle Databaseと統合されたメッセージ・キューイングです。
4.2.1.13.8 ユーザー・メモリーの割当て
OCIDescriptorAlloc()
コールには、そのパラメータ・リストにxtramem_sz
パラメータが含まれています。
xtramem_sz
パラメータは、記述子またはロケータとともに割り当てるユーザー・メモリー量を指定するために使用します。
通常、アプリケーションは、このパラメータを使用して、記述子またはロケータと同じ存続期間を持つアプリケーション定義の構造体を割り当てます。この構造体は、アプリケーション・ブックキーピングまたはコンテキスト情報の格納に使用できます。
xtramem_sz
パラメータを使用すると、アプリケーションでは、各記述子またはロケータを割り当てたり、割当て解除するたびに、メモリーを明示的に割り当てたり、割当て解除する必要がありません。メモリーは記述子またはロケータとともに割り当てられるため、記述子またはロケータを解放すると(OCIDescriptorFree()
により)、ユーザーのデータ構造も解放されます。
OCIHandleAlloc()
コールには、ハンドルと同じ存続期間を持つユーザー・メモリーを割り当てるための同様のパラメータがあります。
OCIEnvCreate()
コール(および非推奨のOCIEnvInit()
コール)には、環境ハンドルと同じ存続期間を持つユーザー・メモリーを割り当てるための同様のパラメータがあります。
4.3 OCIプログラミング・ステップ
次の各項では、OCIアプリケーション開発の各ステップを詳細に説明します。
いくつかのステップは、オプションです。たとえば、文が問合せでない場合には、選択リスト項目を記述または定義する必要はありません。また、OCI関数のいずれか、またはすべてのステップ間で、アプリケーション固有の処理も発生します。
次の各項では、OCIのアプリケーションで必要なステップについて説明します。
関連項目:
-
SQL文の処理でのOCIコールの使用方法を示す例は、「OCIデモ・プログラム」の最初のサンプル・プログラムを参照してください。
-
実行時に動的にデータを提供する特殊な場合の詳細は、「OCIでのランタイム・データ割当てとピース単位操作」を参照してください
-
構造体配列を必要とする操作に対する特別な考慮事項については、「OCIでの構造体配列のバインドと定義について」を参照してください
-
OCIプログラム内でのSQL文の処理に必要なステップのアウトラインは、「OCIでのエラー処理」を参照してください
-
OCIを使用したマルチスレッド・アプリケーションのプログラミングの詳細は、「OCIマルチスレッド開発の概要」を参照してください
-
SQL文の種類の詳細は、「SQL文」を参照してください
4.3.1 OCI環境の初期化
この項では、OCI環境を初期化してサーバーとの接続を確立し、ユーザーがデータベースに対してアクションを実行できるように許可する方法を説明します。
次の3つの項では、OCI環境を初期化するための3つの主要なステップについて説明します。
4.3.1.1 OCI環境の作成について
各OCI関数コールは、OCIEnvCreate()
コールで作成された環境のコンテキスト内で実行されます。
OCIEnvCreate()
コールは、他のOCIコールの実行よりも先に行う必要があります。唯一の例外は、OCI共有モードのプロセスレベルの属性を設定する場合です。
OCIEnvCreate()
のmode
パラメータは、OCIライブラリ関数をコールするアプリケーションが次のことを行えるどうか指定します。
-
スレッド化環境での実行(
mode
=OCI_THREADED
)。 -
オブジェクト(
mode
=OCI_OBJECT
)の使用。AQサブスクリプション登録で使用します。 -
サブスクリプションの使用(
mode
=OCI_EVENTS
)。
これらのモードは、環境ごとに設定できます。
アプリケーションがオブジェクトのバインドおよび定義を行う場合、またはOCIのオブジェクト・ナビゲーション・コールを使用する場合は、オブジェクト・モードでの初期化が必要です。また、アプリケーションでこれらの機能をすべて使用しないようにしたり(mode
= OCI_DEFAULT
)、縦線で区切って組み合せて使用することもできます。たとえば、mode
= (OCI_THREADED
| OCI_OBJECT
)を指定すると、アプリケーションはスレッド化環境で動作し、オブジェクトを使用します。
OCI環境ごとにユーザー定義のメモリー管理関数を指定できます。
4.3.1.2 ハンドルおよび記述子の割当てについて
Oracle Databaseは、ハンドルと記述子の割当ておよび割当て解除をするためのOCI関数を提供します。
ハンドルは、OCIHandleAlloc()
を使用して割り当てた後、OCIコールに渡す必要があります(OCIBindByPos()
またはOCIBindByPos2()
のように、OCIコールがユーザーにかわってハンドルを割り当てる場合は除きます)。
OCIHandleAlloc()
を使用して、表4-1にリストされた種類のハンドルを割り当てることができます。アプリケーションの機能に応じて、これらのハンドルのいくつかまたはすべてを割り当ててください。
4.3.1.3 アプリケーションの初期化、接続およびセッション作成
アプリケーションでは、OCIEnvNlsCreate()
をコールしてOCI環境ハンドルを初期化する必要があります。既存のアプリケーションで、OCIEnvCreate()
が使用されていた可能性があります。
アプリケーションで、このステップに従ってOracle Database接続を確立し、ユーザー・セッションを開始する場合、いくつかのオプションがあります。
次のような方法があります。
ノート:
OCIInitialize()
およびOCIEnvInit()
コールのかわりに、OCIEnvCreate()
またはOCIEnvNlsCreate()
を使用する必要があります。OCIInitialize()
およびOCIEnvInit()
コールは、下位互換性を保つためにサポートされています。
4.3.1.3.1 シングル・ユーザー、単一接続
シングル・ユーザー、単一接続オプションは、単純化されたログイン方法で、アプリケーションで常にデータベース接続ごとにシングル・ユーザー・セッションのみを維持する場合に使用できます。
アプリケーションからOCILogon2()
またはOCILogon()
をコールすると、OCIライブラリは、渡されたサービス・コンテキスト・ハンドルを初期化し、要求を行ったユーザーが指定したOracle Databaseへの接続を作成します。
例4-3では、シングル・ユーザー・セッション(ユーザー名hr
、パスワードhr
およびデータベースoracledb
)を開始するためのOCILogon2()
のコールを示しています。
このコールのパラメータには、接続を確立するために使用するサービス・コンテキスト・ハンドル(初期化済)、ユーザー名、ユーザーのパスワードおよびデータベース名を含めることができます。このコールでは、最後のパラメータmode
をOCI_DEFAULT
に設定することで、旧OCILogon()
コールと同じ結果が得られます。新しいアプリケーションでは、OCILogon2()
を使用します。この関数によって、サーバー・ハンドルおよびユーザー・セッション・ハンドルが暗黙的に割り当てられます。
アプリケーションがこのログイン方法を使用する場合、サービス・コンテキスト、サーバーおよびユーザー・セッション・ハンドルはすべて読取り専用となります。つまり、OCIAttrSet()
コールを使用してサービス・コンテキスト・ハンドルの該当する属性を変更することにより、アプリケーションがセッションまたはトランザクションを切り替えることはできません。
アプリケーションでOCILogon2()
を使用してセッションおよび認可を初期化した場合は、OCILogoff()
を使用してそれらを終了する必要があります。
ノート:
この機能を簡単に説明するために、この例では、デプロイされたシステムで通常使用されるパスワード管理手法を実行していません。本番環境では、Oracle Databaseのパスワード管理ガイドラインに従い、サンプル・アカウントを無効にしてください。パスワード管理ガイドラインおよび他のセキュリティに関する推奨事項は、Oracle Databaseセキュリティ・ガイドを参照してください。
例4-3 シングル・ユーザー・セッションのためのOCILogon2コールの使用
OCILogon2(envhp, errhp, &svchp, (text *)"hr", (ub4)strlen("hr"), (text *)"hr", (ub4)strlen("hr"), (text *)"oracledb", (ub4)strlen("oracledb"), OCI_DEFAULT);
関連項目:
親プロセスによって作成された状態を子プロセスが再利用できるプロセス生成の機能を提供するオペレーティング・システムについては、「オペレーティング・システムの考慮事項」を参照してください。この項では、子プロセスが親によって作成されたものと同じデータベース接続を使用できない理由を説明します。
4.3.1.3.2 プロキシ経由のクライアント・アクセス
プロキシ認証は、ファイアウォールなどの中間層を伴う環境で一般的に使用されるプロセスで、エンド・ユーザーは中間層に対して認証を行い、中間層はエンド・ユーザーのプロキシとして、ユーザーのかわりにデータベースに対して認証を行います。
中間層は、データベースにプロキシ・ユーザーとしてログインします。プロキシ・ユーザーは識別情報を切り替えることができ、データベースにログインするとエンド・ユーザーの識別情報に切り替わります。プロキシ・ユーザーは、特定のエンド・ユーザーに適した認可を使用して、そのエンド・ユーザーにかわって操作を実行できます。
ノート:
Oracle 11gのリリース1では、受入れ可能なパスワードの基準が大幅に上げられ、セキュリティが向上しました。この項で示すパスワードの例は誤りです。パスワードには8文字以上使用する必要があります。詳細は、 『Oracle Databaseセキュリティ・ガイド』のパスワード保護のガイドラインを参照してください。
データベース・ユーザーのプロキシは、OCIと次のBNF構文を持つALTER
USER
文でサポートされます。
ALTER USER <targetuser> GRANT CONNECT THROUGH <proxy> [AUTHENTICATION REQUIRED];
ALTER
USER
文は、アプリケーションで一度のみ使用されます。以降は、何回でも接続できます。OCIでは、接続文字列または関数OCIAttrSet()
(パラメータOCI_ATTR_PROXY_CLIENT
付き)を使用できます。
Oracle Database 12c
リリース2 (12.2)以上では、各識別子の最大長が128バイトに増加しましたが、ユーザー名とプロキシの組合せは250バイトを超えることができません。
プロキシの切替えが行われると、現在接続しているユーザーがプロキシのターゲット・ユーザーになります。元のユーザーの識別情報は、権限の計算対象としては使用されません。元のユーザーはローカル・ユーザーまたは外部ユーザーになります。
例4-4から例4-11までは、OCILogon2()
(mode
= OCI_DEFAULT
を設定)、OCILogon()
、OCIAttrSet()
(セッション・ハンドルの属性OCI_ATTR_USERNAME
を渡す)を指定したOCISessionBegin()
などの関数で使用できる接続文字列を示しています。
例4-4では、DilbertとJoeが2人のローカル・データベース・ユーザーです。DilbertがJoeの代理ユーザーの役割を果たせるようにするには、例4-4に示すSQL文を使用します。
ユーザー名dilbert
をjoe
の代理にするには、例4-5に示す接続文字列を使用します。(ユーザー名dilbert
にはパスワードtiger123
があります)。
左と右のカッコ([ と ]) は、接続文字列に入力します。
例4-6では、"Dilbert"と"Joe"が2人のローカル・データベース・ユーザーです。名前には大文字と小文字の区別があり、二重引用符で囲む必要があります。"Dilbert"が"Joe"の代理ユーザーの役割を果たせるようにするには、例4-6に示すSQL文を使用します。
"Dilbert"を"Joe"の代理にするには、例4-7に示す接続文字列を使用します。必ず二重引用符(")を付けてください。
代理ユーザーが "dilbert[mybert]"として作成される場合、データベースに接続するには例4-8に示す接続文字列を使用します。(左と右のカッコ([ と ])は、接続文字列に入力します。)
例4-9では、dilbert[mybert]とjoe[myjoe]は、左右のカッコ([ と ])を含む2人のデータベース・ユーザーです。dilbert[mybert]がjoe[myjoe]の代理となるには、例4-9で示す接続文字列を使用します。
例4-10では、ALTER
USER
文を使用することによりターゲット・ユーザー名を設定できます。
ノート:
プロキシを介したクライアント・アクセスには互換性の問題があります。この機能は、Oracle Databaseリリース10.2で導入されたため、10.2より前のクライアントはこの機能を備えていません。新しいクライアントが10.2より前のOracle Databaseでこの機能を使用すると、接続は失敗し、データベースのリリース・レベルのチェック後にクライアントがエラーを戻します。
例4-4 ローカル・ユーザーに別のユーザーの代理の役割を付与
ALTER USER joe GRANT CONNECT THROUGH dilbert;
例4-5 代理ユーザー用に使用する接続文字列
dilbert[joe]/tiger123@db1
例4-6 ローカル・ユーザーに別のユーザーの代理の役割を付与する際の大文字と小文字の区別の維持
ALTER USER "Joe" GRANT CONNECT THROUGH "Dilbert";
例4-7 接続文字列での大文字と小文字の区別の維持
"Dilbert"["Joe"]/tiger123@db1
例4-8 接続文字列での"dilbert[mybert]"の使用
"dilbert[mybert]"/tiger123 rem the user was already created this way: rem CREATE USER "dilbert[mybert]" IDENTIFIED BY tiger123;
例4-9 接続文字列での"dilbert[mybert]"["joe[myjoe]"]の使用
"dilbert[mybert]"["joe[myjoe]"]/tiger123
例4-10 ターゲット・ユーザー名の設定
ALTER USER joe GRANT CONNECT THROUGH dilbert;
次に、例4-11で示すように、OCIプログラムで、OCIAttrSet()
コールを使用して属性OCI_ATTR_PROXY_CLIENT
とプロキシdilbert
を設定します。プログラム内で次の各文を使用して複数回接続を行います。
例4-11 OCIを使用したOCI_ATTR_PROXY_CLIENT属性および代理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);
4.3.1.3.3 プロキシを介さない複数のセッションまたは接続
プロキシを介さない複数のセッションまたは接続のオプションでは、明示的なアタッチ・コールおよびセッション開始コールを使用して、データベース接続で複数のユーザー・セッションおよび接続を維持します。
Oracle Databaseにアタッチし、セッションを開始するための具体的なコールは、次のとおりです。
-
OCIServerAttach()
- OCI操作用のOracle Databaseへのアクセス・パスを作成します。 -
OCISessionBegin()
- 特定のOracle Databaseに対するユーザーのセッションを確立します。ユーザーがOracle Databaseに対する操作を実行するには、このコールが必須です。
異なるサービス・コンテキスト・ハンドルおよびセッション・コンテキスト・ハンドルを使用するOCISessionBegin()
への後続コールは、前のユーザーをログオフするため、エラーを引き起こします。移行不可能な2つの同時セッションを実行するには、2番目のOCISessionBegin()
コールに、同じサービス・コンテキスト・ハンドルおよび新しいセッション・コンテキスト・ハンドルを使用する必要があります。
これらのコールにより、データベースに対してSQL文およびPL/SQL文を実行できる操作環境が設定されます。
関連項目:
-
複数のセッション、トランザクションおよび接続の維持の詳細は、「OCIでのセッション・プーリングと接続プーリング」を参照してください。
-
OCIEnvNlsCreate()
の使用方法の詳細は、「OCIからのクライアント文字セットの制御」を参照してください
例4-12は、OCI環境の作成および初期化を示しています。
-
サーバー・コンテキストを作成し、それをサービス・ハンドルに設定します。
-
次に、ユーザー・セッション・ハンドルを作成し、データベース・ユーザー名とパスワードを使用してそれを初期化します。
-
簡単にするために、エラー・チェックは含まれていません。
demo
ディレクトリ内のデモ・プログラムcdemo81.c
は、このプロセスとエラー・チェックを例示しています。
例4-12 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); ... }
4.3.2 OCIでのSQL文の処理について
OCIでのSQL文の処理に含まれる特定のステップについて説明します。
「OCIでのSQL文の使用」では、OCIでのSQL文の処理に含まれる特定のステップについて説明します。
4.3.3 操作のコミットまたはロールバック
アプリケーションは、OCITransCommit()
をコールすることにより、データベースへの変更をコミットします。
OCITransCommit()
コールは、サービス・コンテキストをパラメータの1つとして使用します。トランザクションは、変更がコミットされるサービス・コンテキストに対応付けられています。このトランザクションは、アプリケーションで明示的に作成されたか、または、アプリケーションがデータベースを変更したときに暗黙的に作成された可能性があります。
ノート:
OCIStmtExecute()
コールのOCI_COMMIT_ON_SUCCESS
モードを使用すると、各文の実行後にトランザクションを実行するかどうかをアプリケーションで選択できるため、ラウンドトリップを節約できます。
トランザクションをロールバックするには、OCITransRollback()
コールを使用します。
通常のログオフ以外のなんらかの方法でアプリケーションとOracle Databaseの接続が切断された場合(ネットワークとの接続が切れるなど)、OCITransCommit()
をコールしていないと、アクティブ・トランザクションはすべて自動的にロールバックされます。
4.3.4 アプリケーションの終了について
終了する前にアプリケーションで実行される処理について説明します。
OCIアプリケーションは、終了する前に、次の3つのステップの実行が必要です。
-
各セッションに対して
OCISessionEnd()
をコールし、ユーザー・セッションを終了します。 -
各データ・ソースに対して
OCIServerDetach()
をコールし、データ・ソースへのアクセスを終了します。 -
各ハンドルに対して
OCIHandleFree()
をコールし、明示的に全ハンドルの割当てを解除します。 -
環境ハンドルを削除し、環境ハンドルに関連付けられたその他のハンドルの割当てをすべて解除します。
ノート:
OCIの親ハンドルが解放されると、それに対応付けられた子ハンドルもすべて自動的に解放されます。
OCIServerDetach()
およびOCISessionEnd()
のコールは、必須ではありませんが、お薦めします。アプリケーションがOCITransCommit()
(トランザクション・コミット)をコールしないで終了すると、保留状態のトランザクションはすべて自動的にロールバックされます。
関連項目:
アプリケーションの終了時に解放されるハンドルを示す例は、「OCIデモ・プログラミング」の最初のサンプル・プログラムを参照してください
ノート:
アプリケーションでOCILogon2()
の単純化されたログイン方法を使用する場合は、OCILogoff()
をコールするとセッションが終了し、Oracle Databaseとの接続が切断され、サービス・コンテキスト・ハンドルとそれに関連付けられたハンドルが解放されます。ただし、アプリケーションにより割り当てた他のハンドルは、そのアプリケーションから解放してください。
4.3.5 OCIでのエラー処理
OCI関数コールには一連のリターン・コードが用意されています。
これらのOCI関数コールのリターン・コード(表4-3に記載)により、コールの成功または失敗(OCI_SUCCESS
、OCI_ERROR
など)や、アプリケーションが必要とするその他の情報(OCI_NEED_DATA
、OCI_STILL_EXECUTING
など)が示されます。大部分のOCIコールは、これらのコードの1つを戻します。
サーバーへの接続がOCI_ERROR
で終了しないように、アプリケーションでは、サーバー・ハンドル内の属性OCI_ATTR_SERVER_STATUS
の値をチェックできます。属性の値がOCI_SERVER_NOT_CONNECTED
の場合、サーバーへの接続およびユーザー・セッションを再確立する必要があります。
関連項目:
-
例外は、「その他の値を戻す関数」を参照してください
-
使用方法の詳細および例については、「OCIErrorGet()」を参照してください
表4-3 OCIリターン・コード
OCIリターン・コード | 値 | 説明 |
---|---|---|
0 |
関数は正常に終了しました。 |
|
1 |
関数は正常に終了しました。 |
|
100 |
関数が終了しました。これ以上データはありません。 |
|
-1 |
関数が失敗しました。 |
|
-2 |
無効なハンドルがパラメータとして渡されたか、ユーザー・コールバックで無効なハンドルまたは無効なコンテキストが渡されました。追加診断情報はありません。 |
|
99 |
アプリケーションで、ランタイム・データを提供する必要があります。 |
|
-3123 |
サービス・コンテキストが非ブロック化モードで確立されたため、現行の操作は即時完了できませんでした。この操作を完了するには、これを再度コールする必要があります。 |
|
-24200 |
このコードはコールバック関数からのみ戻されます。これは、コールバック関数が、OCIライブラリの標準処理再開を示唆していることを示します。 |
|
-24201 |
このコードはコールバック関数からのみ戻されます。これは、コールバック関数がユーザー行のコールバックにより実行されていることを示します。 |
エラーが発生したことがリターン・コードに示されている場合、アプリケーションではOCIErrorGet()
をコールして、Oracle Database固有のエラー・コードおよびメッセージを取り出せます。OCIErrorGet()
へのパラメータの1つは、エラーが発生したコールに渡されたエラー・ハンドルです。
ノート:
レコードがなくなる(OCI_NO_DATA
が戻される)まで、繰り返しOCIErrorGet()
をコールすると、複数の診断レコードを取り出すことができます。OCIErrorGet()
は、最大1個の診断レコードを戻します。
4.3.5.1 データのリターン・コードおよびエラー・コード
フェッチされたデータが正常、NULL、または切捨ての場合の、OCIリターン・コード、エラー番号、標識変数および列リターン・コードを示します。
表4-4 リターン・コードとエラー・コード
データの状態 | リターン・コード | インジケータ - 戻さない場合 | インジケータ - 戻す場合 |
---|---|---|---|
NULL、切捨て以外 |
戻さない場合 |
エラー = 0 |
エラー = 0 インジケータ = 0 |
NULL、切捨て以外 |
戻す場合 |
エラー = 0 リターン・コード = 0 |
エラー = 0 インジケータ = 0 リターン・コード = 0 |
NULLデータ |
戻さない場合 |
エラー = 1405 |
エラー = 0 インジケータ = -1 |
NULLデータ |
戻す場合 |
エラー = 1405 リターン・コード = 1405 |
エラー = 0 インジケータ = -1 リターン・コード = 1405 |
切捨てデータ |
戻さない場合 |
エラー = 1406 |
エラー = 1406 インジケータ = data_len |
切捨てデータ |
戻す場合 |
エラー = 24345 リターン・コード = 1405 |
エラー = 24345 インジケータ = data_len リターン・コード = 1406 |
切捨てデータの場合、data_len
は、長さがSB2MAXVAL
以下であった場合に切り捨てられたデータの実際の長さです。この値を超えていれば、インジケータが-2に設定されます。
4.3.5.2 その他の値を戻す関数
一部の関数では、OCIエラー・コード以外の値が戻されます。
これら以外のOCIエラー・コードは、表4-3に記載されています。これらの関数を使用する場合、OUT
パラメータからではなく、関数コールから直接値が戻ります。それぞれの関数と戻り値の詳細は、該当する章を参照してください。
4.4 その他のコーディング・ガイドライン
この項では、OCIアプリケーションをコーディングするときのその他の問題について説明します。
4.4.1 オペレーティング・システムの考慮事項
オペレーティング・システムでは、子プロセスで親プロセスによって作成された状態を再利用できるプロセス生成機能が提供されている場合があります。
子プロセスの生成後、この子プロセスでは、親によって作成されたものと同じデータベース接続を使用できません。親と同じデータベース接続を子プロセスのために使用しようとすると、Oracle Netでは、データベースへの1つの接続を使用できるのは1つのユーザー・プロセスのみであるため、好ましくない接続障害が発生して、間欠的なORA-03137
エラーが生じる可能性があります。
複数の同時接続が必要な場合、使用プラットフォームでスレッド・パッケージがサポートされていれば、スレッドの使用を検討します。シングル・スレッドまたはマルチ・スレッドのいずれのアプリケーションでも、同時接続はサポートされます。同時にオープンされる多数の接続によるパフォーマンス向上のため、それらのプーリングを検討してください。
4.4.2 パラメータの型
OCI関数には整数、ハンドル、文字列など、多様なデータ型のパラメータを使用することができます。
この項には次のトピックが含まれます:
関連項目:
パラメータのデータ型、およびパラメータを渡す際の規則の詳細は、「接続関数、認証関数および初期化関数」を参照してください
4.4.2.1 アドレス・パラメータ
アドレス・パラメータは、変数のアドレスをOracle Databaseに渡すために使用されます。
Cでは、通常スカラー・パラメータを値で渡すので、Cで開発する場合は注意してください。
4.4.2.2 整数パラメータ
2進整数およびshort型2進整数パラメータは、サイズがシステムによって異なる数値です。
システムでのこれらの整数のサイズは、ご使用のオペレーティング・システム用のOracle Databaseドキュメントを参照してください。
4.4.3 列へのNULLの挿入
データベース列にNULLを挿入する方法について説明します。
データベース列にNULLを挿入する方法はいくつかあります。
-
1つは、
INSERT
文またはUPDATE
文のテキストの中でリテラルNULL
を使用する方法です。たとえば、SQL文によりENAME
列はNULL
になります。INSERT INTO emp1 (ename, empno, deptno) VALUES (NULL, 8010, 20)
-
OCIバインド・コールでは、標識変数を使用します。
-
バッファ長パラメータと最大長パラメータの両方をバインド・コールで0 (ゼロ)に設定するには、
NULL
を挿入します。ノート:
対応する標識変数が定義コールで指定されていない変数に、NULL選択リスト項目をフェッチしようとすると、Oracle DatabaseはSQL標準要件に従いエラーを戻します。
関連トピック
4.4.4 標識変数
各バインドと定義OCIコールには、標識変数または標識変数の配列をDML文、PL/SQL文または問合せに関連付けるパラメータがあります。
C言語にはNULL値という概念がないため、標識変数を入力変数に関連付けることにより、関連するプレースホルダがNULL
であるかどうかを指定します。データがOracle Databaseに渡されると、この標識変数の値により、データベース・フィールドにNULL
が割り当てられるかどうかが決定されます。
出力変数では、標識変数によって、Oracleから戻された値がNULL
または切り捨てられた値であるかどうかが判断されます。OCIStmtFetch2()
コールでのNULL
フェッチ、またはOCIStmtExecute()
コールでの切捨ての場合は、OCIコールによりOCI_SUCCESS_WITH_INFO
が戻されます。出力標識変数が設定されます。
標識変数のデータ型はsb2
です。標識変数の配列の場合、各配列要素の型はsb2
です。
4.4.4.1 入力
標識変数に割当て可能な値について説明します。
入力ホスト変数については、OCIアプリケーションは次の値を標識変数に割り当てることができます。
入力インジケータ値 | Oracle Databaseからのアクション |
---|---|
-1 |
Oracle Databaseは |
>=0 |
入力変数の値を列に割り当てます。 |
4.4.4.2 出力
標識変数に割当て可能な値について説明します。
出力については、Oracle Databaseは次の値を標識変数に割り当てます。
出力インジケータ値 | 意味 |
---|---|
-2 |
項目の長さが出力変数の長さよりも長いため、項目を切り捨てます。さらに、元の長さが、 |
-1 |
選択された値がNULLで、出力変数の値は変更されません。 |
0 |
完全な値をホスト変数に割り当てます。 |
>0 |
項目の長さが出力変数の長さよりも長いため、項目を切り捨てます。標識変数に戻された正の値は、切捨て前の実際の長さです。 |
4.4.4.3 名前付きデータ型用およびREF用の標識変数
リリース8.0より後に導入されたデータ型の標識変数は、前述の説明どおりに機能します。
例外はSQLT_NTY (名前付きデータ型)です。SQLT_NTY型のデータの場合、標識変数はインジケータ構造体へのポインタである必要があります。SQLT_REF型のデータでは、他の変数型と同様に、標準のスカラー・インジケータを使用します。
Object Type Translator (OTT)を使用してデータベース型をC構造体に変換すると、各オブジェクト型についてNULLインジケータ構造体が生成されます。この構造体には、アトミックNULLインジケータと各オブジェクト属性のインジケータが含まれます。
関連項目:
-
NULLインジケータ構造体の詳細は、「OCIでのObject Type Translatorの使用」のOTT関連の記述、および「NULLインジケータ構造体」を参照してください
-
名前付きデータ型および
REF
のインジケータ・パラメータ設定の詳細は、「バインド関数、定義関数および記述関数」のOCIBindByName()
とOCIBindByPos()
の説明、「名前付きデータ型およびREFバインドの情報」および「名前付きデータ型、REF定義およびPL/SQL OUTバインドの情報」の項を参照してください
4.4.5 コールの取消しについて
長時間実行されたり繰り返されているOCIコールを取り消す方法について説明します。
ほとんどのオペレーティング・システムでは、キーボードからオペレーティング・システムの割込み文字(通常は[Ctrl] + [C]キー)を入力することで、長時間実行されたり繰り返されているOCIコールを取り消すことができます。
ノート:
これを、nrows
パラメータを0 (ゼロ)に設定し、OCIStmtFetch2()
をコールして行うカーソルの取消しと混同しないように注意してください。
長時間実行されたり繰り返されているコールをオペレーティング・システムへの割込みにより取り消した場合は、エラー・コードORA-01013
(「ユーザーによって現行の操作の取消しが要求されました」)が戻されます。
特定のサービス・コンテキスト・ポインタまたはサーバー・コンテキスト・ポインタを指定すると、OCIBreak()
関数は、サーバーに関連付けられている現在実行中のOCI関数をすべて即時(非同期)に停止します。これは通常、サーバーで長時間実行されている処理中のOCIコールを停止するために使用します。OCIReset()
関数は、OCIアプリケーションがOCIBreak()
で機能を停止した後で、非ブロック化接続に対してプロトコル同期化を実行するために必要です。
ノート:
OCIBreak()
はWindowsシステムで動作します。
長時間実行する可能性のあるコールは、非ブロック化コールを使用することによりステータスを監視できます。新しいアプリケーションでは、マルチスレッドを使用します。
4.4.6 位置指定の更新および削除
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
が行識別子が保存されているバッファである場合、新規給与をプレースホルダ:1
にバインドし、rowid
をプレースホルダ:2
にバインドすることで、次のようなSQL文を後から処理できます。
UPDATE emp1 SET sal = :1 WHERE rowid = :2
rowid
を:2
にバインドする場合は、必ずデータ型コード104 (ROWID
記述子、表5-2を参照)を使用してください。
プリフェッチを使用することで、後続のバッチ更新で使用するためにROWID
の配列を選択できます。
4.4.7 予約語
一部の語はOracleで予約されています。
つまり、一部の予約語はOracleにとって特別な意味を持っており、再定義できません。このため、それらのワードを使用して、列、表、索引などのデータベース・オブジェクトに名前を付けることはできません。
この項には次のトピックが含まれます: Oracle予約済ネームスペース
関連項目:
SQLおよびPL/SQLのOracleキーワードまたは予約語のリストを参照するには、『Oracle Database SQL言語リファレンス』および『Oracle Database PL/SQL言語リファレンス』を参照してください
4.4.7.1 Oracle予約済ネームスペース
Oracleで予約されているネームスペースについて説明します。特定のネームスペースのすべての関数リストは、該当するOracleライブラリに対応したドキュメントを参照してください。
表4-5は、Oracleによって予約されているネームスペースのリストです。Oracleライブラリ内の関数名の最初の文字列は、このリストの文字列に制限されています。名前が競合する可能性があるため、これらの文字列で始まる関数名を付けないでください。
表4-5 Oracle予約済ネームスペース
ネームスペース | ライブラリ |
---|---|
|
XAアプリケーション専用の外部関数 |
|
OracleのプリコンパイラおよびSQL*Moduleアプリケーションで使用される外部SQLLIB関数 |
|
外部OCI関数、内部OCI関数 |
|
Oracle UPIレイヤーの関数名 |
|
Oracle Netネイティブ・サービス・プロダクト Oracle Net RPCプロジェクト Oracle Net Directory Oracle Netネットワーク・ライブラリ・レイヤー Oracle Net管理プロジェクト Oracle Net Interchange Oracle Netトランスペアレント・ネットワーク・サービス Oracle Netドライバ Oracle Netセキュリティ・サービス Oracle Net V1 Oracle Net 2タスク |
|
コア・ライブラリ関数 |
|
Oracleグローバリゼーション・サポート・レイヤーの関数名 |
|
システム依存ライブラリの関数名 |
|
カーネル・オブジェクト |
4.4.8 OCIでのポーリング・モード操作
OCIには、完了をポーリングするコールがあります。
そのようなポーリング・コードのコールの例は、次のとおりです。
-
非ブロック化モードでのOCIコール
-
OCILobRead2()
およびOCILobWrite2()
などのピース単位のLOBデータで動作するOCIコール -
OCIStmtSetPieceInfo()
およびOCIStmtGetPieceInfo()
で使用されるOCIStmtExecute()
およびOCIStmtFetch2()
このような場合、OCIでは、アプリケーションで必ず同じOCIコールがその接続で繰り返され、その間にその接続でそれ以外のことが行われないようにする必要があります。そのような接続でその他のOCIコールを実行すると(OCIが制御をコール元に戻した場合)、予期しない動作が生じる可能性があります。
したがって、コール元は、そのようなポーリング・モードのOCIコールにより、同じコールがその接続で繰り返され、そのコールが完了するまで他のことが行われないようにする必要があります。
OCIBreak()
およびOCIReset()
は、このルールに対する例外です。これらのコールは、開始されたOCIコールをコール元が停止できるように使用されます。
4.4.9 OCIでの非ブロック化モード
OCIでは、ブロック化モードまたは非ブロック化モードでサーバー接続を確立できます。
ノート:
非ブロック化モードでは、コール元はコールが完了するまで、同じコールを繰り返す必要があるため、CPUの使用率が増加します。かわりに、マルチスレッド・モードを使用します。
接続がブロック化モードで行われた場合、結果が正常かエラーかにかかわらずコールが完了した場合にのみ、OCIコールはコントロールをOCIクライアント・アプリケーションに戻します。非ブロック化モードでは、コールが完了せずコールからOCI_STILL_EXECUTING
の値が戻されても、コントロールはただちにOCIプログラムに戻されます。
非ブロック化モードでは、アプリケーションで各OCI関数のリターン・コードをテストし、OCI_STILL_EXECUTING
が戻されるかどうかを確認する必要があります。この場合、OCIクライアントはこのOCIコールのサーバーでの再試行を待つ間、プログラム・ロジックの処理を継続できます。このモードは、グラフィカル・ユーザー・インタフェース(GUI)アプリケーション、リアルタイム・アプリケーションおよび分散環境の場合に特に有用です。
非ブロック化モードは非割込み駆動で、むしろポーリング・パラダイムに基づいています。これは、保留状態のコールがサーバーで終了したかどうかを、同一パラメータでそのコールを再び実行することにより、クライアント・アプリケーションでチェックする必要があることを意味します。
次の機能および関数は、非ブロック化モードではサポートされません。
-
ダイレクト・パス・ロード
-
LOBバッファリング
-
オブジェクト
-
問合せキャッシュ
-
スクロール・カーソル
-
透過的アプリケーション・フェイルオーバー(TAF)
-
OCIAQEnqArray
() -
OCIAQDeqArray()
-
OCIDescribeAny()
-
OCILobArrayRead()
-
OCILobArrayWrite()
-
OCITransStart()
-
OCITransDetach()
4.4.10 ブロック化モードの設定
アプリケーションのブロック化状態は、attrtype
パラメータをOCI_ATTR_NONBLOCKING_MODE
に設定して、サーバー・コンテキスト・ハンドルでOCIAttrSet()
をコールして状態を設定するか、OCIAttrGet()
をコールして状態を読み取ることにより、変更またはチェックすることができます。
OCI_ATTR_NONBLOCKING_MODE
属性を設定できるのは、OCISessionBegin()
またはOCILogon2()
がコールされた後でのみです。それ以外の場合はエラーが戻されます。
ノート:
パラメータとしてサーバー・コンテキスト・ハンドルまたはサービス・コンテキスト・ハンドルを持つ関数のみが、OCI_STILL_EXECUTING
を戻します。
関連項目:
4.5 OCIプログラムでのPL/SQLの使用について
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機能へのアクセス -
カーソル変数の使用
-
サーバー内のオブジェクトの操作
ノート:
-
OCIで直接処理できるのは無名ブロックのみであり、名前付きパッケージまたは名前付きプロシージャは処理できないのに対し、プログラマは常にパッケージ・コールまたはプロシージャ・コールを無名ブロック内に入れ、そのブロックを処理できます。
-
OCIでPL/SQLの開始/終了ブロックを実行する前に、インジケータを-1に設定するかまたは実際の長さを0に設定して、すべてのOUT変数を
NULL
に初期化する必要があることに注意してください。 -
OCIでは、PL/SQL
RECORD
データ型はサポートされていません。 -
OCIでPL/SQL VARCHAR2変数をバインドする場合、制御構造のオーバーヘッドにより、バインド変数の最大サイズは32767バイトです。
ノート:
PL/SQLコードの作成時には、パーサーにより一対のハイフン「--」と改行文字との間のすべてがコメントとして処理されることを覚えておいてください。「--」を使用してコメントを各行に示した場合、Cコンパイラでは各行に改行「¥n」が挿入されず、すべての行がPL/SQLブロックで単一行として連結されます。この特定のケースでは、ある行がコメントで終わっている場合、パーサーは次の行のPL/SQLコード抽出に失敗してしまいます。この問題を回避するには、各「--」コメントの後に「\n」を入れ、そこでコメントが必ず終了するようにしてください。
関連項目:
PL/SQLブロックのコーディングの詳細は、『Oracle Database PL/SQL言語リファレンス』 を参照してください
-
4.6 OCIグローバリゼーション・サポート
次の項では、ロケール情報の導出、文字列の操作、文字セット変換、OCIメッセージなど、グローバリゼーションに使用されるOCI関数について説明します。
これらの関数には複数の目的および機能があるため、詳細は、このマニュアルの他の章を参照してください。
4.6.1 OCIからのクライアント文字セットの制御
OCIEnvNlsCreate()
関数は、NLS_LANG
およびNLS_NCHAR
の設定とは関係なく、アプリケーションで文字セット情報を設定できます。
OCI_UTF16ID
はNLS_LANG
またはNLS_NCHAR
から設定できないため、OCIEnvNlsCreate()
を使用して設定する必要があります。様々なクライアント側文字セットIDおよび各国語文字セットIDを使用して、同じシステム環境内で初期化した複数の環境ハンドルを1つのアプリケーションで使用できます。たとえば、次のようにします。
OCIEnvNlsCreate(OCIEnv **envhpp, ..., csid, ncsid);
この例では、csid
はパラメータcharset
の文字セットIDの値であり、ncsid
はパラメータncharset
の各国語文字セットIDの値です。いずれの値も0 (ゼロ)またはOCI_UTF16ID
に設定できます。両方とも0 (ゼロ)の場合は、OCIEnvCreate()
を使用するのと同じになります。その他の引数は、OCIEnvCreate()
コールの引数と同じです。
AL16UTF16を除くすべてのOracle文字セットIDは、OCIEnvNlsCtrate()
関数を使用して指定され、メタデータのエンコーディング、SQL CHAR
データおよびSQL NCHAR
データを指定できます。
NLS_LANG
およびNLS_NCHAR
の文字セットは、別の関数のOCINlsEnvironmentVariableGet()
を使用して取得できます。
関連項目:
-
これらのコールの使用例を示す疑似コード・フラグメントは、「OCIでのクライアント文字セットの設定について」を参照してください
4.6.2 文字制御とOCIインタフェース
OCIインタフェースによる文字制御の実行方法について説明します。
OCINlsGetInfo()
関数は、その値がOCIEnvNlsCreate()
で使用されている場合に、OCI_UTF16ID
などの任意の文字セットに関する情報を戻します。
OCIAttrGet()
関数は、OCIEnvNlsCreate()
に渡された文字セットIDおよび各国語文字セットIDを戻します。これは、OCI_ATTR_ENV_CHARSET_ID
およびOCI_ATTR_ENV_NCHARSET_ID
を取得するために使用されます。これには、値OCI_UTF16ID
が含まれます。
OCIEnvNlsCreate()
を使用してcharset
およびncharset
パラメータに0 (ゼロ)が設定されている場合は、NLS_LANG
およびNLS_NCHAR
の文字セットIDが戻されます。
この関数を使用してOCI_ATTR_CHARSET_FORM
がリセットされる場合、OCIAttrSet()
関数は文字IDをデフォルトとして設定します。OCIEnvNlsCreate()
がcharset
またはncharset
として渡される場合、有効な文字セットIDにはOCI_UTF16ID
が含まれます。
OCIBindByName()
またはOCIBindByName2()
関数およびOCIBindByPos()
またはOCIBindByPos2()
関数は、OCIEnvNlsCreate()
コールのデフォルトの文字セット(OCI_UTF16ID
を含む)を使用して変数をバインドします。OCIEnvNlsCreate()
を使用する場合、実際の長さと戻される長さは常にバイト単位で表されます。
OCIDefineByPos()
またはOCIDefineByPos2()
関数は、OCIEnvNlsCreate()
のcharset
の値(OCI_UTF16ID
を含む)を持つ変数をデフォルトとして定義します。OCIEnvNlsCreate()
を使用する場合、実際の長さと戻される長さは常にバイト単位で表されます。バインド・ハンドルおよび定義ハンドルのこの動作は、OCIEnvCreate()
を使用する場合とは異なり、OCI_UTF16ID
はバインド・ハンドルおよび定義ハンドル用の文字セットIDになります。
4.6.3 OCIでの文字長セマンティクス
OCIは、サーバーとクライアント間のトランスレータとして機能し、制約チェックを行うための文字情報を渡します。
文字セットには、可変幅と固定幅の2種類があります。(シングルバイト文字セットは、各バイトが1文字を表す固定幅文字セットの特殊なケースです。)
固定幅文字セットの場合、バイト数は文字数の倍数であるため、制約チェックが簡単です。したがって、固定幅文字セットでは、文字数を調べるために文字列全体をスキャンする必要がありません。これに対して、可変幅文字セットでは、文字列全体をスキャンして文字数を調べる必要があります。
4.6.4 OCIでの文字セットのサポート
OCIによる文字セットのサポート方法について説明します。
OCIでの文字セットのサポートの詳細は、「記述操作での文字長セマンティクスのサポート」および「OCIバインドおよび定義における文字変換」を参照してください。
4.6.5 OCIの言語および地域の制御
NLSの言語および地域は、OCI環境ハンドルでOCI_ATTR_ENV_NLS_LANGUAGE
とOCI_ATTR_ENV_NLS_TERRITORY
属性を使用することにより、プログラム的に設定することもできます。
4.6.6 その他のOCIグローバリゼーション・サポート関数
グローバリゼーション・サポート関数は、環境ハンドルまたはユーザー・セッション・ハンドルを受け入れます。
OCI環境ハンドルは、クライアントのNLS環境変数に関連付けられます。ALTER
SESSION
文がサーバーに発行された場合、この環境は変更されません。環境ハンドルに関連付けられた文字セットは、クライアント文字セットです。OCIセッションハンドル(OCISessionBegin()
によって戻されます)は、サーバー・セッション環境に関連付けられます。ALTER
SESSION
文でセッション環境が変更された場合、NLS設定も変更されます。セッション・ハンドルに関連付けられた文字セットは、データベース文字セットです。
セッションで最初のトランザクションが開始されるまで、OCIセッション・ハンドルには、関連付けられたNLS設定がないことに注意してください。SELECT
文では、トランザクションは始まりません。
関連項目:
-
Unicodeを使用したOCIプログラミングの詳細は、『Oracle Databaseグローバリゼーション・サポート・ガイド』を参照してください
4.6.7 OCIでのロケール情報の取得について
Oracle Databaseロケールは、言語、地域および文字セット定義で構成されます。
ロケールは、曜日と月の名前、および日付、時刻、数値、通貨の書式などの表記規則を決定します。グローバル化されたアプリケーションは、ユーザーのロケール設定および文化の規則に対応しています。たとえば、ロケールをドイツに設定すると、月日の名前がドイツ語で表示されます。
OCINlsGetInfo()
関数を使用して、次の情報を取得できます。
-
曜日(翻訳済)
-
曜日の略称(翻訳済)
-
月名(翻訳済)
-
月名の略称(翻訳済)
-
はい/いいえ(翻訳済)
-
AM/PM (翻訳済)
-
AD/BC (翻訳済)
-
数値書式
-
借方/貸方
-
日付書式
-
通貨書式
-
デフォルトの言語
-
デフォルトの地域
-
デフォルトの文字セット
-
デフォルトの言語ソート
-
デフォルトのカレンダ
例4-13のコードでは、ロケール情報を取得し、エラーをチェックします。
例4-13 OCIでのロケール情報取得
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); }
4.6.8 OCIおよびBOM (バイト・オーダー・マーク)について
OCIでは、BOM (バイト・オーダー・マーク)がサポートも処理もされず、バイト・オーダーがアプリケーションが実行されているマシンにネイティブであるとみなされます。
使用するOCIアプリケーションでは、OCIが文字列のエンコードを検出できると想定されるBOMを含む文字列は渡されません。OCIアプリケーションでは、渡される文字列にBOMが存在する場合はそれを削除する必要があり、それがOCIの機能で想定されるエンコードであるようにする必要があります。
4.6.9 OCIでの文字列操作について
文字列操作では、マルチバイト文字列およびワイド・キャラクタ文字列がサポートされています。
マルチバイト文字列は、システム固有のOracle文字セットでエンコードされています。マルチバイト文字列で動作する関数は、バイト単位で計算された文字列の長さを使用して、文字列全体を1つの単位として使用します。ワイドキャラクタ(wchar
)文字列関数を使用すると、より柔軟に文字列を操作できます。これは、文字に基づいた操作および文字列に基づいた操作をサポートし、長さは文字列の長さを文字で計算した数値です。
ワイドキャラクタ・データ型OCIWchar
はOracle固有のもので、ANSI/ISO C標準で定義されているwchar_t
データ型と混同しないでください。Oracleのワイドキャラクタ・データ型はすべてのオペレーティング・システムで常に4バイトですが、wchar_t
のサイズは実装およびオペレーティング・システムによって異なります。Oracleワイド・キャラクタ・データ型は、マルチバイト文字を正規化するため、統一された固定幅になり、処理が簡単になります。これにより、Oracleのワイド文字セットとシステム固有の文字セット間でのラウンドトリップ変換の際、データが失われません。
文字列操作は、次のカテゴリに分類できます。
-
マルチバイト文字とワイド文字間の文字列変換
-
文字の分類
-
大/小文字の変換
-
表示長の計算
-
比較、連結、検索などの一般的な文字列操作
関連項目:
例4-14では、単純な文字列操作の例を示します。
OCI文字分類関数については、「OCI文字分類関数」で詳しく説明します。
例4-15では、OCIでの文字の分類方法を示します。
例4-14 OCIでの基本的な文字列操作
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); }
例4-15 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); }
4.6.10 OCIでの文字セットの変換について
Oracle文字セットとUnicode (16ビット、固定幅のUnicodeエンコーディング)間の変換がサポートされています。
UnicodeからOracle文字セットへの文字のマッピングが存在しない場合、置換文字が使用されます。したがって、変換して元の文字セットに戻す場合、データが失われる可能性があります。
Unicode文字セットに関連する文字セット変換関数では、データのバインド・バッファおよび定義バッファをub2
アドレスで揃える必要があり、揃っていない場合、エラーが発生します。
例4-16では、Unicodeへの単純な変換を示します。
関連項目:
例4-16 OCIでの文字セットの変換
/* 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); }
4.6.11 OCIメッセージ関数
ユーザー・メッセージAPIは、カートリッジ開発者が、独自のメッセージおよびOracle Databaseメッセージを取得するための単純なインタフェースを提供します。
例4-17では、メッセージ・ハンドルを作成し、impus.msg
からメッセージを取得するために初期化してメッセージ番号128を取得し、メッセージ・ハンドルをクローズします。この例では、OCI環境ハンドル、OCIセッション・ハンドル、製品、機能およびキャッシュ・サイズが正しく初期化されていることを想定しています。
例4-17 テキスト・メッセージ・ファイルからのメッセージ取得
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);
4.6.12 lmsgenユーティリティ
lmsgen
ユーティリティは、テキストベースのメッセージ・ファイル(.msg
)をバイナリ形式(.msb
)に変換し、これにより、ユーザーが提供したOracleメッセージおよびOCIメッセージを、希望する言語でOCI関数に戻すことができます。
ImsgenユーティリティのBNF構文は、次のとおりです。
lmsgen
text_file
product
facility
[language
]
前の構文では:
-
text_file
は、メッセージ・テキスト・ファイルです。 -
product
は、製品の名前です。 -
facility
は、機能の名前です。 -
language
は、NLS_LANG
パラメータで指定された言語に対応する、オプションのメッセージ言語です。メッセージ・ファイルに言語のタグが正しく付いていない場合は、言語パラメータが必要です。
4.6.12.1 テキスト・メッセージ・ファイルのガイドライン
テキスト・メッセージ・ファイルで従う必要があるガイドラインについて説明します。
テキスト・メッセージ・ファイルは、次のガイドラインに従う必要があります。
-
"
/"
および"//
"で始まる行は、内部コメントとみなされるため、無視されます。 -
メッセージ・ファイルに特定の言語のタグを付けるには、次のような行を含めます。
# CHARACTER_SET_NAME= Japanese_Japan.JA16EUC
-
各メッセージには、3つのフィールドがあります。
message_number
,warning_level
,message_text
-
メッセージ番号は、メッセージ・ファイル内で一意であることが必要です。
-
warning_levelは、現在使用されていません。0に設定します。
-
メッセージ・テキストは、76バイトより長くできません。
-
Oracle Databaseメッセージ・テキスト・ファイルの例を次に示します。
/ 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)"
4.6.12.2 テキスト・メッセージ・ファイルからのバイナリ・メッセージ・ファイル作成の例
テキスト・メッセージ・ファイルからバイナリ・メッセージ・ファイルを作成する方法について説明します。
次の表に、lmsgen
パラメータのサンプル値を示します。
lmsgenパラメータ | 値 |
---|---|
|
|
|
|
|
|
|
|
テキスト・メッセージ・ファイルの場所は、次のとおりです。
$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