9 ランタイム・エラーの処理
アプリケーション・プログラムでは、ランタイム・エラーを予測して、そのエラーをリカバリするように対処する必要があります。この章では、エラー・レポートおよびリカバリを詳しく説明します。SQL通信領域(SQLCA)、WHENEVERディレクティブおよびSQLSTATE状態変数を使用して、エラーおよび状態の変化を処理する方法を説明します。さらにOracle通信領域(ORACA)による問題点の診断方法も紹介します。この章のトピックは、次のとおりです:
9.1 エラー処理の必要性
どのようなアプリケーション・プログラムでも、その大部分をエラー処理に当てる必要があります。エラー処理の主な目的は、エラーが発生してもプログラムの処理を続行できるようにすることです。エラーは設計ミス、コーディングの誤り、ハードウェア障害、誤ったユーザー入力をはじめ、様々な原因で発生します。
潜在的なエラーをすべて予測するのは無理ですが、プログラムにとって意味のある特定の種類のエラーについてアクションを考えることはできます。Pro*C/C++プリコンパイラにとっては、エラー処理とはSQL文の実行エラーの検出およびリカバリのことです。値が切り捨てられたことを示す警告やデータの終わりなどの状態の変更も処理できます。INSERT文、UPDATE文またはDELETE文では、表内の処理対象行すべてを処理する前に失敗することがあるため、SQLデータ操作文を実行するたびにエラー状態および警告状態がないか調べることが特に重要です。
9.2 エラー処理の代替手段
アプリケーションの状態の変化およびエラーを検出するにはいくつかの手段があります。この章ではそれらの手段について説明しますが、特定の手段の推奨は行っていません。最終的にどの手段を使用するかは、作成中のアプリケーション・プログラムまたはツールがどのように設計されているかによって決まります。
9.2.1 状態変数
状態変数SQLSTATEまたはSQLCODEを別に宣言し、実行SQL文の後の値をそれぞれ調べて、適切なアクションを取ることができます。アクションとして、エラー報告関数をコールし、エラーがリカバリ不能なときはプログラムを終了することができます。または、データを調整するか変数を制御して、アクションを再試行することもできます。
9.2.2 SQL通信領域
もう1つの手段は、プログラムにSQL通信領域構造体(sqlca)を組み込むことです。実行時にSQL文がOracleによって処理されると、この構造体のコンポーネントに値が格納されます。
注意:
このマニュアルでは、sqlca構造体は一般にSQL通信領域の頭字語(SQLCA)を使用して表記します。このマニュアルでC言語の構造体の特定のコンポーネントに言及するときには、構造体の名称(sqlca)を使用します。
SQLCAはヘッダー・ファイルsqlca.hに定義されています。次の文のどちらかを使用してSQLCAをプログラムにインクルードします。 
                     
- 
                           EXEC SQL INCLUDE SQLCA; 
- 
                           #include <sqlca.h> 
Oracleでは、すべての実行SQL文の後でSQLCAが更新されます。(SQLCAの値は宣言文の後では変更されません。)SQLCAに格納されているOracleリターン・コードをチェックすることで、プログラムはSQL文の結果を判断できます。この判断には次の2通りの方法があります。
- 
                           WHENEVERディレクティブによる暗黙的なチェック 
- 
                           SQLCAコンポーネントの明示的なチェック 
WHENEVERディレクティブを使用するか、SQLCAコンポーネントの明示的なチェックを使用するか、またはその両方を同時に使用することが可能です。
SQLCAで最も頻繁に使用されるコンポーネントは、状態変数(sqlca.sqlcode)およびエラー・コード(sqlca.sqlerrm.sqlerrmc)に関連するテキストです。他のコンポーネントには、警告フラグおよびSQL文の処理に関する各種の情報が格納されます。
注意:
SQLCODE(大文字)は常に個別の状態変数のことを指し、SQLCAのコンポーネントのことではありません。SQLCODEは、整数として宣言されます。SQLCAのコンポーネントsqlcodeのことを指す場合は、常に完全修飾名sqlca.sqlcodeが使用されます。
ランタイム・エラーについて、SQLCAに格納されている情報よりも詳細な情報が必要なときにORACAを使用します。ORACAは、Oracleの通信を処理するC言語の構造体です。この中にはカーソル統計情報、現行のSQL文に関する情報、オプションの設定、およびシステムの統計情報が含まれます。
9.3 SQLSTATE状態変数
プリコンパイラのMODEコマンドライン・オプションは、ANSI/ISOへの準拠を制御します。MODE=ANSIのとき、SQLCAデータ構造体の宣言はオプションです。ただし、SQLCODEという状態変数は別に宣言する必要があります。SQL標準では、SQLSTATEという類似した状態変数が指定されています。SQLSTATEは、SQLCODEとともに使用しても別々に使用してもかまいません。
SQL文の実行後、Oracleサーバーは現在の適用範囲内のSQLSTATE変数にステータス・コードを戻します。ステータス・コードは、SQL文が正常に実行されたか例外(エラーまたは警告状態)が発生したかを示します。相互運用性(システム間で情報を簡単に交換する機能)を高めるために、共通のSQL例外がすべてSQL標準によってあらかじめ定義されています。
SQLCODEにはエラー・コードのみが格納されるのに対し、SQLSTATEにはエラー・コードおよび警告コードが格納されます。さらに、SQLSTATEの報告のメカニズムには、標準化されたコード化方式が採用されています。このため、SQLSTATEは状態変数として優先されます。SQLCODEは、SQL-89との互換性を保つためにのみ維持されていた、SQL-92の非推奨の機能です。SQL-92より後のすべてのSQL標準バージョンで、SQLCODEは削除されています。
9.3.1 SQLSTATEの宣言について
MODE=ANSIのときは、SQLSTATEまたはSQLCODEを宣言する必要があります。SQLCAの宣言はオプションです。MODE=ORACLEのときは、SQLSTATEを宣言しても無視されます。
SQLCODEでは符号付き整数を格納し、宣言部の外で宣言できますが、SQLSTATEではヌル文字で終了する5文字の文字列を格納し、宣言部の中で宣言する必要があります。次のようにSQLSTATEを宣言します。
char SQLSTATE[6]; /* Upper case is required. */
注意:
SQLSTATEは正確に6文字のサイズで宣言する必要があります。
9.3.2 SQLSTATE値
SQLSTATEステータス・コードは、2文字のクラス・コードおよびその後に続く3文字のサブクラス・コードで構成されます。クラス・コード00(正常終了)以外のときには、クラス・コードは例外のカテゴリを示します。また、サブクラス・コード000(適用外)以外では、サブクラス・コードはそのカテゴリ内の特定の例外を示します。たとえば、SQLSTATEの値22012はクラス・コード22(データ例外)とサブクラス・コード012(ゼロ除算)を示します。
SQLSTATE値の5文字は、それぞれ数字(0から9)または大文字の英文字(AからZ)で構成されます。0から4の範囲の数字、またはAからHの範囲の文字で始まるクラス・コードは、事前定義済の状態(SQL標準で定義されている)用に確保されています。他のすべてのクラス・コードは実装定義の状態用に確保されています。事前定義クラスのうち、0から4の数字またはAからHの文字で始まるサブクラス・コードは、事前定義の副条件用に予約されています。他のすべてのサブクラス・コードは、実装時に定義される副条件用に予約されています。図9-1にコード化体系を示します。
表9-1にSQL92で事前定義済のクラスを示します。
表9-1 事前定義済のクラス・コード
| クラス | 条件 | 
|---|---|
| 00 | 正常終了 | 
| 01 | 警告 | 
| 02 | データなし | 
| 07 | 動的SQLエラー | 
| 08 | 接続例外 | 
| 09 | トリガー・アクション例外 | 
| 0A | サポートされていない機能 | 
| 0D | ターゲット・タイプの指定が無効 | 
| 0E | スキーマ名リストの指定が無効 | 
| 0F | ロケータ例外 | 
| 0L | 権限付与者が無効 | 
| 0M | SQLが呼び出したプロシージャ参照が無効 | 
| 0P | ロール指定が無効 | 
| 0S | 変換グループ名の指定が無効 | 
| 0T | ターゲット表がカーソル仕様と不一致 | 
| 0U | 更新可能でない列への割当て試行 | 
| 0V | 順序付け列への割当て試行 | 
| 0W | トリガー実行中の禁止された文の発生 | 
| 0Z | 診断例外 | 
| 21 | 制約違反 | 
| 22 | データ例外 | 
| 23 | 整合性制約違反 | 
| 24 | カーソル状態が無効 | 
| 25 | トランザクション状態が無効 | 
| 26 | SQL文名が無効 | 
| 27 | トリガー・データの変更違反 | 
| 28 | 認証の指定が無効 | 
| 2A | 直接SQL構文エラーまたはアクセス規則違反 | 
| 2B | 依存権限記述子がまだ存在しています。 | 
| 2C | キャラクタ・セット名が無効 | 
| 2D | トランザクションの終了が無効 | 
| 2E | 接続名が無効 | 
| 2F | SQLルーチン例外 | 
| 2H | 照合名が無効 | 
| 30 | SQL文識別子が無効 | 
| 33 | SQL記述子名が無効 | 
| 34 | カーソル名が無効 | 
| 35 | 条件番号が無効 | 
| 36 | カーソル更新検出例外 | 
| 37 | 動的SQL構文エラーまたはアクセス規則違反 | 
| 38 | 外部ルーチン例外 | 
| 39 | 外部ルーチン呼出しの例外 | 
| 3B | セーブポイント例外 | 
| 3C | カーソル名があいまい | 
| 3D | カタログ名が無効 | 
| 3F | スキーマ名が無効 | 
| 40 | トランザクションのロールバック | 
| 42 | 構文エラーまたはアクセス規則違反 | 
| 44 | WITH_CHECK_OPTION指定違反 | 
| HZ | リモート・データベース・アクセス | 
注意:
クラス・コードHZは、国際標準規格ISO/IEC DIS 9579-2で定義された条件であるリモート・データベース・アクセス用に確保されています。
表9-2に、SQLSTATEステータス・コードと条件のOracleエラーとの対応を示します。60000から99999の範囲のステータス・コードは実装時に定義されます。
表9-2 SQLSTATEステータス・コード
| コード | 条件 | Oracleエラー | 
|---|---|---|
| 00000 | 正常終了 | ORA-00000 | 
| 01000 | 警告 | -- | 
| 01001 | カーソル操作の競合 | -- | 
| 01002 | 切断エラー | -- | 
| 01003 | 集合関数でNULL値が削除されている | -- | 
| 01004 | 文字列データの右側切捨て | -- | 
| 01005 | 項目記述子領域が不十分 | -- | 
| 01006 | 権限が取り消されていない | -- | 
| 01007 | 権限が付与されていない | -- | 
| 01008 | 暗黙的なゼロビットの埋込み | -- | 
| 01009 | 情報スキーマの検索条件が長すぎます。 | -- | 
| 0100A | 情報スキーマの問合せ式が長すぎます。 | -- | 
| 02000 | データなし | ORA-01095 ORA-01403 | 
| 07000 | 動的SQLエラー | -- | 
| 07001 | USING句がパラメータ指定と一致しません。 | -- | 
| 07002 | USING句が相手指定と一致しません。 | -- | 
| 07003 | カーソル仕様を実行できません。 | -- | 
| 07004 | 動的パラメータにはUSING句が必要です。 | -- | 
| 07005 | プリコンパイルされたSQL文がカーソル仕様ではありません。 | -- | 
| 07006 | 制限付きのデータ型属性違反 | -- | 
| 07007 | 結果コンポーネントにはUSING句が必要、記述子の数が無効 | -- | 
| 07008 | 記述子の数が無効 | SQL-02126 | 
| 07009 | 記述子の索引が無効 | -- | 
| 08000 | 接続例外 | -- | 
| 08001 | SQLクライアントはSQL接続を確立できない | -- | 
| 08002 | 接続名を使用中 | -- | 
| 08003 | 接続が存在しません。 | SQL-02121 | 
| 08004 | SQLサーバーがSQL接続を拒否した | -- | 
| 08006 | 接続障害 | -- | 
| 08007 | トランザクションの結果が不明 | -- | 
| 0A000 | サポートされていない機能 | ORA-03000から03099 | 
| 0A001 | 複数サーバー・トランザクション | -- | 
| 21000 | 制約違反 | ORA-01427 SQL-02112 | 
| 22000 | データ例外 | -- | 
| 22001 | 文字列データの右側切捨て | ORA-01406 | 
| 22002 | NULL値 - インジケータ・パラメータなし | SQL-02124 | 
| 22003 | 数値が範囲外 | ORA-01426 | 
| 22005 | 割当てのエラー | -- | 
| 22007 | 日時書式が無効 | -- | 
| 22008 | 日時フィールドのオーバーフロー | ORA-01800から01899 | 
| 22009 | タイム・ゾーンによる時差が無効 | -- | 
| 22011 | 部分文字列のエラー | -- | 
| 22012 | 0による除算 | ORA-01476 | 
| 22015 | 間隔フィールドのオーバーフロー | -- | 
| 22018 | キャストの文字値が無効 | -- | 
| 22019 | エスケープ文字が無効 | ORA-00911 | 
| 22021 | レパートリに文字がありません。 | -- | 
| 22022 | インジケータのオーバーフロー | ORA-01411 | 
| 22023 | パラメータ値が無効 | ORA-01025 ORA-04000から04019 | 
| 22024 | C文字列が未終了 | ORA-01479 ORA-01480 | 
| 22025 | エスケープ・シーケンスが無効 | ORA-01424 ORA-01425 | 
| 22026 | 文字列データの長さが不一致 | ORA-01401 | 
| 22027 | 切捨てエラー | - | 
| 23000 | 整合性制約違反 | ORA-1400、ORA-02290から02299 | 
| 24000 | カーソル状態が無効 | ORA-001002 ORA-001003 SQL-02114 SQL-02117 | 
| 25000 | トランザクション状態が無効 | SQL-02118 | 
| 26000 | SQL文名が無効 | -- | 
| 27000 | トリガー・データの変更違反 | -- | 
| 28000 | 認証の指定が無効 | -- | 
| 2A000 | 直接SQL構文エラーまたはアクセス規則違反 | -- | 
| 2B000 | 依存権限記述子がまだ存在しています。 | -- | 
| 2C000 | キャラクタ・セット名が無効 | -- | 
| 2D000 | トランザクションの終了が無効 | -- | 
| 2E000 | 接続名が無効 | -- | 
| 33000 | SQL記述子名が無効 | -- | 
| 34000 | カーソル名が無効 | -- | 
| 35000 | 条件番号が無効 | -- | 
| 37000 | 動的SQL構文エラーまたはアクセス規則違反 | -- | 
| 3C000 | カーソル名があいまい | -- | 
| 3D000 | カタログ名が無効 | -- | 
| 3F000 | スキーマ名が無効 | -- | 
| 40000 | トランザクションのロールバック | ORA-02091 ORA-02092 | 
| 40001 | シリアライズの失敗 | -- | 
| 40002 | 整合性制約違反 | -- | 
| 40003 | 文の完了が不明 | -- | 
| 42000 | 構文エラーまたはアクセス規則違反 | ORA-00022 ORA-00251 ORA-00900から00999 ORA-01031 ORA-01490から01493 ORA-01700から01799 ORA-01900から02099 ORA-02140から02289 ORA-02420から02424 ORA-02450から02499 ORA-03276から03299 ORA-04040から04059 ORA-04070から04099 | 
| 44000 | WITH_CHECK_OPTION指定違反 | ORA-01402 | 
| 60000 | システム・エラー | ORA-00370から00429 ORA-00600から00899 ORA-06430から06449 ORA-07200から07999 ORA-09700から09999 | 
| 61000 | 共有サーバーおよび分離プロセスのエラー | ORA-00018から00035 ORA-00050から00068 ORA-02376から02399 ORA-04020から04039 | 
| 62000 | 共有サーバーおよび分離プロセスのエラー | ORA-00100から00120 ORA-00440から00569 | 
| 63000 | Oracle*XAおよび2タスク・インタフェースのエラー | ORA-00150から00159 ORA-02700から02899 ORA-03100から03199 ORA-06200から06249 SQL-02128 | 
| 64000 | 制御ファイル、データベース・ファイルおよびREDOファイルのエラー、アーカイブおよびメディア・リカバリのエラー | ORA-00200から00369 ORA-01100から01250 | 
| 65000 | PL/SQLのエラー | ORA-06500から06599 | 
| 66000 | Oracle Netドライバのエラー | ORA-06000から06149 ORA-06250から06429 ORA-06600から06999 ORA-12100から12299 ORA-12500から12599 | 
| 67000 | ライセンス許可エラー | ORA-00430から00439 | 
| 69000 | SQL*Connectのエラー | ORA-00570から00599 ORA-07000から07199 | 
| 72000 | SQL実行フェーズのエラー | ORA-00001 ORA-01000から01099 ORA-01401から01489 ORA-01495から01499 ORA-01500から01699 ORA-02400から02419 ORA-02425から02449 ORA-04060から04069 ORA-08000から08190 ORA-12000から12019 ORA-12300から12499 ORA-12700から21999 | 
| 82100 | メモリー不足のためメモリーが割り当てられません。 | SQL-02100 | 
| 82101 | カーソル・キャッシュが矛盾(UCE/CUCが不一致) | SQL-02101 | 
| 82102 | カーソル・キャッシュが矛盾(UCEのCUCエントリがない) | SQL-02102 | 
| 82103 | カーソル・キャッシュが矛盾(CUC参照の範囲外) | SQL-02103 | 
| 82104 | カーソル・キャッシュが矛盾(使用可能なCUCがない) | SQL-02104 | 
| 82105 | カーソル・キャッシュが矛盾(キャッシュにCUCエントリがない) | SQL-02105 | 
| 82106 | カーソル・キャッシュが矛盾(カーソル番号が無効) | SQL-02106 | 
| 82107 | ランタイム・ライブラリに対してプログラムが古すぎる; 再プリコンパイルが必要 | SQL-02107 | 
| 82108 | ランタイム・ライブラリに無効な記述子が渡されました。 | SQL-02108 | 
| 82109 | ホスト・キャッシュが矛盾(SIT参照が範囲外) | SQL-02109 | 
| 82110 | ホスト・キャッシュが矛盾(SQLの型が無効) | SQL-02110 | 
| 82111 | ヒープ一貫性のエラー | SQL-02111 | 
| 82113 | コード生成の内部整合性の障害 | SQL-02115 | 
| 82114 | リエントラント・コード・ジェネレータが無効なコンテキストを与えました。 | SQL-02116 | 
| 82117 | データベースへの接続でのOPENまたはPREPAREが無効です。 | SQL-02122 | 
| 82118 | アプリケーション・コンテキストが見つかりません。 | SQL-02123 | 
| 82119 | エラー・メッセージのテキストを取り出せない | SQL-02125 | 
| 82120 | プリコンパイラとSQLLIBのバージョンが不一致 | SQL-02127 | 
| 82121 | NCHARエラー; フェッチされたバイト数が奇数 | SQL-02129 | 
| 82122 | EXEC TOOLSインタフェースが使用できない | SQL-02130 | 
| 82123 | ランタイム・コンテキストは使用中です。 | SQL-02131 | 
| 82124 | ランタイム・コンテキストを割り当てできません。 | SQL-02132 | 
| 82125 | スレッドで使用するプロセスを初期化できません。 | SQL-02133 | 
| 82126 | ランタイム・コンテキストが無効 | SQL-02134 | 
| HZ000 | リモート・データベース・アクセス | -- | 
9.3.3 SQLSTATEの使用について
次の規則は、オプションの設定をMODE=ANSIにしてプリコンパイルするときに、SQLSTATEをSQLCODEまたはSQLCAと併用する場合に適用されます。SQLSTATEは宣言部内で宣言する必要があります。宣言部内で宣言しなければ無視されます。
9.3.3.1 SQLSTATEを宣言する場合
- 
                              SQLCODEの宣言はオプションです。宣言部の内部でSQLCODEを宣言すると、SQL処理を実行するたびにOracleサーバーはSQLSTATEおよびSQLCODEにステータス・コードを戻します。ただし、宣言部の外部でSQLCODEを宣言すると、OracleはSQLSTATEのみにステータス・コードを戻します。 
- 
                              SQLCAの宣言はオプションです。SQLCAを宣言すると、OracleはSQLSTATEおよびSQLCAにステータス・コードを戻します。この場合は、コンパイル・エラーを防ぐために、SQLCODEを宣言しないでください。 
9.3.3.2 SQLSTATEを宣言しない場合
- 
                              宣言部の内部または外部で、SQLCODEを宣言する必要があります。SQL処理を実行するたびに、OracleサーバーはSQLCODEにステータス・コードを戻します。 
- 
                              SQLCAの宣言はオプションです。SQLCAを宣言すると、OracleはSQLCODEおよびSQLCAにステータス・コードを戻します。 
独自のコードを作成してSQLSTATEを明示的にチェックするか、WHENEVER SQLERRORディレクティブを使用してSQLSTATEを暗黙的にチェックすることで、最新の実行SQL文の結果が得られます。実行SQL文およびPL/SQL文の後にのみSQLSTATEをチェックしてください。
9.4 SQLCODEの宣言について
MODE=ANSIで、SQLSTATE状態変数を宣言していない場合は、宣言部の内側または外側でSQLCODEというlong型の整数の変数を宣言する必要があります。次に例を示します。
/* declare host variables */ EXEC SQL BEGIN DECLARE SECTION; int emp_number, dept_number; char emp_name[20]; EXEC SQL END DECLARE SECTION; /* declare status variable--must be upper case */ long SQLCODE;
MODE=ORACLEの場合は、SQLCODEを宣言しても無視されます。
複数のSQLCODEを宣言することが可能です。ローカルなSQLCODEへのアクセスは、プログラム内の適用範囲によって制限されます。
SQLの動作が終わるたびに、Oracleから現在有効範囲にあるSQLCODEにステータス・コードが戻されます。したがって、プログラムでは、SQLCODEを明示的にチェックするか、WHENEVERディレクティブを暗黙的に指定することで、最新のSQL処理の結果を知ることができます。
特定のコンパイル・ユニットのSQLCAのかわりにSQLCODEを宣言すると、プリコンパイラでは、そのユニット用に内部SQLCAを1つ割り当てます。ホスト・プログラムでは、その内部SQLCAにアクセスできません。SQLCAおよびSQLCODEの両方を宣言すると、OracleはSQL操作を実行するたびに同じステータス・コードを両方に戻します。
9.5 SQLCAを使用したエラー・レポートの主要コンポーネント
9.5.4 解析エラー・オフセット
SQL文は実行前に必ず解析され、構文規則に従っているか、有効なデータベース・オブジェクトを参照しているかが検証されます。エラーが検出されると、SQLCA変数sqlca.sqlerrd[4]にオフセットが格納されます。これは明示的にチェックできます。このオフセットには、解析エラーの始まりを示すSQL文中の文字位置が示されています。通常のC言語の文字列と同様に、先頭の文字位置は0(ゼロ)です。たとえば、オフセットが9のとき、解析エラーは10番目の文字から始まっています。 
                     
解析エラー・オフセットは、準備と解析が別々に実行される状況で使用されます。その代表例は動的SQL文です。
解析エラーは、キーワードの欠落、キーワードの位置指定の誤り、キーワードのスペルミス、無効なオプションなどが原因で発生します。次に、動的SQL文の例を示します。
"UPDATE emp SET jib = :job_title WHERE empno = :emp_number"
これは解析エラーになります。
ORA-00904: invalid column name
原因は、列名JOBのスペルミスです。sqlca.sqlerrd[4] の値は15になりますが、これは誤った列名JIBが16番目の文字で始まっているためです。 
                     
SQL文に解析エラーがなければ、Oracleではsqlca.sqlerrd[4]が0(ゼロ)に設定されます。解析エラーが先頭の文字(文字位置は0(ゼロ))で始まっているときも、sqlca.sqlerrd[4]は0(ゼロ)に設定されます。このため、sqlca.sqlerrd[4]のチェックは、sqlca.sqlcodeが負の値(エラーが発生したことを示す)の場合にのみ行ってください。 
                     
9.6 SQL通信領域(SQLCA)の使用
SQLCAはデータ構造体です。そのコンポーネントには、SQL文を実行するたびにOracleによって更新されるエラー、警告およびステータス情報が格納されます。したがって、SQLCAには常に最新のSQLの動作結果が反映されます。この結果を判断するために、SQLCA内の変数をチェックすることが可能です。
プログラムでは複数のSQLCAを使用できます。たとえば、1つのグローバルSQLCAと複数のローカルSQLCAを設定できます。ローカルSQLCAへのアクセスは、プログラム内の有効範囲により制限されます。Oracleは、スコープ内にあるSQLCAにのみ情報を戻します。
注意:
アプリケーションでOracle Netを使用してローカル・データベースおよびリモート・データベースの組合せに同時にアクセスする場合、すべてのデータベースは1つのSQLCAに書き込みます。つまり、データベースごとに異なるSQLCAがあるわけではありません。
関連項目
9.6.1 SQLCAの宣言について
MODE=ORACLEのときは、SQLCAの宣言が必要です。SQLCAを宣言するには、次に示すようにINCLUDEまたは#include文を使用してSQLCAをプログラム内にコピーします。
EXEC SQL INCLUDE SQLCA;
または
#include <sqlca.h>
宣言部を使用するときは、SQLCAは宣言部の外側で宣言する必要があります。SQLCAを宣言しないとコンパイル時にエラーが発生します。
プログラムをプリコンパイルすると、INCLUDE SQLCA文はいくつかの変数宣言に置き換えられます。これらの変数宣言によって、Oracleとプログラムとの間の通信が可能になります。
MODE=ANSIのときは、SQLCAの宣言はオプションです。ただしこのとき、SQLCODEまたはSQLSTATE状態変数は宣言する必要があります。SQLCODE (必ず大文字)の型はintです。特定のコンパイル・ユニットでSQLCAのかわりにSQLCODEまたはSQLSTATEを宣言した場合、プリコンパイラではそのユニット用に内部SQLCAが割り当てられます。Pro*C/C++プログラムは、内部SQLCAにはアクセスできません。SQLCAおよびSQLCODEの両方を宣言すると、OracleはSQL操作を実行するたびに同じステータス・コードを両方に戻します。
注意:
SQLCAの宣言はMODE=ANSIのときにはオプションですが、WHENEVER SQLWARNINGディレクティブはSQLCAがなければ使用できません。したがって、WHENEVER SQLWARNINGディレクティブを使用する場合は、SQLCAを宣言する必要があります。
このマニュアルでは、SQLCODE状態変数を指す場合にSQLCODEを使用しています。また、SQLCA構造体のコンポーネントのことを明示する場合には、sqlca.sqlcodeを使用しています。
9.6.2 SQLCAの内容
SQLCAにはSQL文の実行結果に関する次の情報が格納されます。
- 
                              Oracleエラー・コード 
- 
                              警告フラグ 
- 
                              イベント情報 
- 
                              処理済行数 
- 
                              診断情報 
/*
NAME
  SQLCA : SQL Communications Area.
FUNCTION
  Contains no code. Oracle fills in the SQLCA with status info
  during the execution of a SQL stmt.
NOTES
  **************************************************************
  ***                                                        ***
  *** This file is SOSD.  Porters must change the data types ***
  *** appropriately on their platform.  See notes/pcport.doc ***
  *** for more information.                                  ***
  ***                                                        ***
  **************************************************************
  If the symbol SQLCA_STORAGE_CLASS is defined, then the SQLCA
  will be defined to have this storage class. For example:
 
    #define SQLCA_STORAGE_CLASS extern
 
  will define the SQLCA as an extern.
 
  If the symbol SQLCA_INIT is defined, then the SQLCA will be
  statically initialized. Although this is not necessary in order
  to use the SQLCA, it is a good programing practice not to have
  unitialized variables. However, some C compilers/operating systems
  don't allow automatic variables to be initialized in this manner.
  Therefore, if you are INCLUDE'ing the SQLCA in a place where it
  would be an automatic AND your C compiler/operating system doesn't
  allow this style of initialization, then SQLCA_INIT should be left
  undefined -- all others can define SQLCA_INIT if they wish.
  If the symbol SQLCA_NONE is defined, then the SQLCA
  variable will not be defined at all.  The symbol SQLCA_NONE
  should not be defined in source modules that have embedded SQL.
  However, source modules that have no embedded SQL, but need to
  manipulate a sqlca struct passed in as a parameter, can set the
  SQLCA_NONE symbol to avoid creation of an extraneous sqlca
  variable. 
*/
#ifndef SQLCA
#define SQLCA 1
struct   sqlca
         {
         /* ub1 */ char    sqlcaid[8];
         /* b4  */ long    sqlabc;
         /* b4  */ long    sqlcode;
         struct
           {
           /* ub2 */ unsigned short sqlerrml;
           /* ub1 */ char           sqlerrmc[70];
           } sqlerrm;
         /* ub1 */ char    sqlerrp[8];
         /* b4  */ long    sqlerrd[6];
         /* ub1 */ char    sqlwarn[8];
         /* ub1 */ char    sqlext[8];
         };
#ifndef SQLCA_NONE 
#ifdef   SQLCA_STORAGE_CLASS
SQLCA_STORAGE_CLASS struct sqlca sqlca
#else
         struct sqlca sqlca
#endif
#ifdef  SQLCA_INIT
         = {
         {'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '},
         sizeof(struct sqlca),
         0,
         { 0, {0}},
         {'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '},
         {0, 0, 0, 0, 0, 0},
         {0, 0, 0, 0, 0, 0, 0, 0},
         {0, 0, 0, 0, 0, 0, 0, 0}
         }
#endif
         ;
#endif
#endif9.6.3 SQLCAの構造
9.6.3.3 sqlcode
この整数コンポーネントには最後に実行されたSQL文のステータス・コードが格納されます。SQLの動作の結果を示すステータス・コードは、次のいずれかの数値です。
| ステータス・コード | 説明 | 
|---|---|
| 0 | エラーまたは例外の検出なしで文が実行されたことを示します。 | 
| >0 | 文は実行されたが、例外が検出されたことを示します。この状態が発生するのは、WHERE句の検索条件を満たす行がない場合、あるいはSELECT INTOまたはFETCHで1行も戻されなかった場合です。 | 
MODE=ANSIのときは、どの行もINSERTできないと+100がsqlcodeに戻されます。副問合せで処理に行が戻されなかったときにこの状態が発生します。
- 
                                 <0はデータベース、システム、ネットワークまたはアプリケーションのエラーが原因で、文が実行されなかったことを示します。このようなエラーは致命的です。このようなエラーが発生すると、ほとんどの場合はカレント・トランザクションがロールバックされます。 
エラー・コードに対応する負数のリターン・コードは、Oracle Databaseエラー・メッセージに記載されています
9.6.3.4 sqlerrm
この埋込み構造体には次の2つのコンポーネントがあります。
| コンポーネント | 説明 | 
|---|---|
| sqlerrml | |
| sqlerrmc | この文字列コンポーネントには、sqlcode内に保存されているエラー・コードに対応したメッセージ・テキストが格納されます。文字列はヌル文字で終了しません。長さを調べるにはsqlerrmlコンポーネントを使用します。 | 
9.6.3.6 sqlerrd
この2進整数の配列には6つの要素があります。sqlerrd内のコンポーネントの説明を次に示します。
処理済行数はOPEN文の後に0 (ゼロ)に設定され、FETCH文の後に増分されます。処理済行数は、EXECUTE文、INSERT文、UPDATE文、DELETE文およびSELECT INTO文について、正常に処理された行数を反映します。この数には、UPDATEやDELETE_CASCADEで処理された行は含まれません。たとえばWHERE句の条件を満たす20行が削除された後で、列制約条件に違反する5行が削除されたときの処理済行数は、25ではなく20となります。
9.6.3.7 sqlwarn
この1文字の配列には8つの要素があります。これらの要素は警告フラグとして使用されます。Oracleではそれに文字値W(警告)を割り当てることでフラグを設定します。
フラグは例外状態の発生を警告します。たとえば、切り捨てられた列値が出力ホスト変数に割り当てられると、警告フラグが設定されます。
sqlwarnのコンポーネントの説明を次に示します。
| コンポーネント | 説明 | 
|---|---|
| sqlwarn[0] | このフラグは別の警告フラグが設定されていることを示します。 | 
| sqlwarn[1] | このフラグは、切り捨てられた列値が出力ホスト変数に代入されたときに設定されます。これは文字データにのみ適用されます。つまり、Oracleは、警告で設定することも負のsqlcodeを戻すこともなく、特定の数値データを切り捨てます。 | 
列値が切り捨てられたかどうか、またどれだけ切り捨てられたかを調べるには、出力ホスト変数に対応する標識変数をチェックします。標識変数によって戻された値が正の整数のときは、その値は列値の元の長さを示します。その値に応じてホスト変数の長さを増やすことができます。
9.7 エラー・メッセージの全文の取得について
SQLCAには70文字までのエラー・メッセージを格納できます。71文字以上の(またはネストされた)エラー・メッセージ全体を取得するには、sqlglm()関数を使用する必要があります。次に構文を示します。 
                  
void sqlglm(unsigned char   *message_buffer, 
            size_t *buffer_size,
            size_t *message_length); 
各パラメータの意味は次のとおりです。
| 構文 | 説明 | 
|---|---|
| message_buffer | エラー・メッセージを格納するためのテキスト・バッファです(Oracleはバッファの最後まで空白文字で埋め込みます)。 | 
| buffer_size | バッファの最大サイズをバイト数で示したスカラー変数です。 | 
| message_length | Oracleによって格納されたエラー・メッセージの切り捨てられていない場合の、実際の長さを示すスカラー変数です。 | 
注意:
sqlglm()関数の最後の2つの引数の型は一般的なsize_tポインタとして示してあります。ただし、プラットフォームによっては型が異なることがあります。たとえば、多くのUNIXワークステーション・ポートでは、unsigned int *になります。
これらのパラメータのデータ型を判別するには、システムの標準インクルード・ディレクトリにあるsqlcpr.hファイルをチェックしてください。
Oracleエラー・メッセージの最大長は、エラー・コード、ネストされたメッセージ、表や列の名前など、メッセージの挿入部分を含めて512文字です。sqlglmによって戻されるエラー・メッセージの最大長は、buffer_sizeに指定した値によって決まります。 
                  
次の例では、sqlglmをコールして、200文字以内の長さのエラー・メッセージを取得します。 
                  
EXEC SQL WHENEVER SQLERROR DO sql_error(); 
... 
/* other statements */ 
... 
sql_error() 
{ 
    char msg[200]; 
    size_t buf_len, msg_len; 
 
    buf_len = sizeof (msg); 
    sqlglm(msg, &buf_len, &msg_len);   /* note use of pointers */
    if (msg_len > buf_len)
    msg_len = buf_len;
    printf("%.*s\n\n", msg_len, msg); 
    exit(1); 
} 
sqlglm()は、SQLエラーが発生したときにのみコールできます。sqlglmをコールする前に、SQLCODE (またはsqlca.sqlcode)の値が0(ゼロ)でないことを必ず確認してください。SQLCODEが0(ゼロ)のときにsqlglm()をコールすると、以前のSQL文に対応したメッセージが取得されることになります。
                  
注意:
複数のランタイム・コンテキストが使用される場合は、コンテキストを持つバージョンのsqlglmt()を使用して、適切なエラー・メッセージを取得してください。
関連項目
9.8 WHENEVERディレクティブの使用について
デフォルトでは、プリコンパイルされたプログラムはOracleエラーおよび警告の状態を無視し、可能であれば処理を続行します。自動条件チェックおよびエラー処理を実行するにはWHENEVERディレクティブが必要です。
WHENEVERディレクティブによって、OracleでエラーやSQLERROR、SQLWARNINGまたはNOT FOUND条件が検出されたときのアクションを指定できます。これらのアクションには、次の文の継続実行、ルーチンのコール、ラベル付きの文への分岐、停止などがあります。
WHENEVERディレクティブの構文は次のとおりです。
EXEC SQL WHENEVER <condition> <action>;
9.8.2 WHENEVERアクション
Oracleで前述の状態のいずれかが検出されたときは、プログラムに次のいずれかのアクションを実行させることができます。
9.8.3 WHENEVERの例
たとえば、プログラムで次のアクションが必要だとします。
- 
                           「データが見つかりません」という条件が発生したときには、close_cursorに進みます。 
- 
                           警告が発生したときは、次の文を続行します。 
- 
                           エラーが発生したときは、error_handlerに進みます。 
最初の実行SQL文の前に次のWHENEVERディレクティブを指定する必要があります。
EXEC SQL WHENEVER NOT FOUND GOTO close_cursor; EXEC SQL WHENEVER SQLWARNING CONTINUE; EXEC SQL WHENEVER SQLERROR GOTO error_handler;
次の例では、WHENEVER...DOディレクティブを使用して特定のエラーを処理します。
... 
EXEC SQL WHENEVER SQLERROR DO handle_insert_error("INSERT error"); 
EXEC SQL INSERT INTO emp (empno, ename, deptno) 
    VALUES (:emp_number, :emp_name, :dept_number); 
EXEC SQL WHENEVER SQLERROR DO handle_delete_error("DELETE error"); 
EXEC SQL DELETE FROM dept WHERE deptno = :dept_number; 
... 
handle_insert_error(char *stmt) 
{   switch(sqlca.sqlcode) 
    { 
    case -1: 
    /* duplicate key value */ 
        ... 
        break; 
    case -1401: 
    /* value too large */ 
        ... 
        break; 
    default: 
    /* do something here too */ 
        ... 
        break; 
    } 
} 
 
handle_delete_error(char *stmt) 
{ 
    printf("%s\n\n", stmt); 
    if (sqlca.sqlerrd[2] == 0) 
    { 
        /* no rows deleted */ 
        ... 
    } 
    else 
    {   ...
    } 
    ... 
} 
SQLCAの変数をチェックしてアクションの過程を決定する手順に注意してください。
9.8.4 DO BREAKとDO CONTINUEの利用
次の例では、コミッションを受け取っている従業員の分のみ、従業員の名前、給料、コミッションを表示する方法を示しています。
#include <sqlca.h>
#include <stdio.h>
main()
{
    char *uid = "scott/tiger";
    struct { char ename[12]; float sal; float comm; } emp;
    /* Trap any connection error that might occur. */
    EXEC SQL WHENEVER SQLERROR GOTO whoops;
    EXEC SQL CONNECT :uid;
    EXEC SQL DECLARE c CURSOR FOR
        SELECT ename, sal, comm FROM EMP ORDER BY ENAME ASC;
    EXEC SQL OPEN c;
    /* Set up 'BREAK' condition to exit the loop. */
    EXEC SQL WHENEVER NOT FOUND DO BREAK;
   /* The DO CONTINUE makes the loop start at the next iteration when an error occurs.*/
    EXEC SQL WHENEVER SQLERROR DO CONTINUE;
    while (1)
      {
          EXEC SQL FETCH c INTO :emp;
   /* An ORA-1405 would cause the 'continue' to occur. So only employees with */
   /* non-NULL commissions will be displayed. */
          printf("%s  %7.2f  %9.2f\n", emp.ename, emp.sal, emp.comm);
       }
/* This 'CONTINUE' shuts off the 'DO CONTINUE' allowing the program to 
   proceed if any further errors do occur, specifically, with the CLOSE */
    EXEC SQL WHENEVER SQLERROR CONTINUE;
    EXEC SQL CLOSE c;
    exit(EXIT_SUCCESS);
whoops:
    printf("%.*s\n", sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
    exit(EXIT_FAILURE);
}9.8.5 WHENEVER文の適用範囲
WHENEVER文は宣言部のため、そのスコープは論理的なものではなく位置的なものになります。つまり、WHENEVER文はプログラム・ロジックの流れではなく、ソース・ファイル内で物理的にWHENEVER文に続く実行SQL文をすべてテストします。したがって、WHENEVERディレクティブはテストする最初の実行SQL文の前に指定する必要があります。
あるWHENEVERディレクティブは、同じ条件をチェックする別のWHENEVERディレクティブに置き換えられるまでの間は有効です。
次の例では、最初のWHENEVER SQLERRORディレクティブは2番目のものに置き換えられます。したがって、このディレクティブの制御はCONNECT文のみに適用されます。2番目のWHENEVER SQLERRORディレクティブは、step1からstep3への制御の流れに関係なく、UPDATE文およびDROP文の両方に適用されます。
step1: EXEC SQL WHENEVER SQLERROR STOP; EXEC SQL CONNECT :username IDENTIFIED BY :password; ... goto step3; step2: EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL UPDATE emp SET sal = sal * 1.10; ... step3: EXEC SQL DROP INDEX emp_index; ...
9.8.6 WHENEVERのガイドライン
9.8.6.2 データの終わり条件の処理
カーソルを使用して行をフェッチするときは、プログラムでデータの終了条件を処理できるようにしておく必要があります。FETCHがデータを戻さないときは、プログラムは次のようにFETCHループを終了します。
EXEC SQL WHENEVER NOT FOUND DO break;
for (;;)
{
    EXEC SQL FETCH...
}
EXEC SQL CLOSE my_cursor; 
... 行が挿入されていない場合、INSERTはNOT FOUNDを戻します。この条件を取り上げない場合は、INSERTの前にEXEC SQL WHENEVER NOT FOUND CONTINUEを使用します。
EXEC SQL WHENEVER NOT FOUND DO break;
for(;;)
{
   EXEC SQL FETCH ...
   EXEC SQL WHENEVER NOT FOUND CONTINUE;
   EXEC SQL INSERT INTO ...
}
EXEC SQL CLOSE my_cursor;
...9.8.6.3 無限ループの回避について
WHENEVER SQLERROR GOTOディレクティブが、実行SQL文を含むエラー処理ルーチンに分岐しているときに、そのSQL文にエラーが発生すると、プログラムが無限ループに陥るおそれがあります。無限ループを回避するには、次に示すようにSQL文の前にWHENEVER SQLERROR CONTINUEを記述します。
EXEC SQL WHENEVER SQLERROR GOTO sql_error; ... sql_error: EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL ROLLBACK WORK RELEASE; ...
WHENEVER SQLERROR CONTINUE文を指定しなければ、ROLLBACKエラーが発生したときにこのルーチンが再び実行されるため、結果として無限ループに陥ります。
WHENEVER句は、注意して使用しないと問題が発生することがあります。たとえば、検索条件を満たす行がないためにDELETE文がNOT FOUNDを設定すると、次のコードは無限ループに陥ります。
/* improper use of WHENEVER */ 
... 
EXEC SQL WHENEVER NOT FOUND GOTO no_more; 
for (;;) 
{ 
    EXEC SQL FETCH emp_cursor INTO :emp_name, :salary; 
    ... 
} 
 
no_more: 
    EXEC SQL DELETE FROM emp WHERE empno = :emp_number; 
     ... 次の例では、GOTOのターゲットを再設定することで、NOT FOUND条件を適切に処理します。
/* proper use of WHENEVER */ 
... 
EXEC SQL WHENEVER NOT FOUND GOTO no_more; 
for (;;) 
{ 
    EXEC SQL FETCH emp_cursor INTO :emp_name, :salary; 
    ... 
} 
no_more: 
    EXEC SQL WHENEVER NOT FOUND GOTO no_match; 
    EXEC SQL DELETE FROM emp WHERE empno = :emp_number; 
    ... 
no_match: 
    ... 9.8.6.4 アドレス指定可能度の維持について
WHENEVER GOTOディレクティブによって制御されるすべてのSQL文が、必ずGOTOラベルに分岐するようにしてください。次のコードは、func1内のlabelAがfunc2内のINSERT文のスコープ内にないため、コンパイル時エラーが発生します。
func1() 
{ 
  
    EXEC SQL WHENEVER SQLERROR GOTO labelA; 
    EXEC SQL DELETE FROM emp WHERE deptno = :dept_number; 
    ... 
labelA: 
... 
} 
func2() 
{ 
  
    EXEC SQL INSERT INTO emp (job) VALUES (:job_title); 
    ... 
} 
WHENEVER GOTOディレクティブの分岐先のラベルは、この文と同じプリコンパイル・ファイル内にする必要があります。
9.9 SQL文のテキスト取得について
多くのプリコンパイラ・アプリケーションでは、処理中の文のテキスト、その長さ、指定されているSQLコマンド(INSERTやSELECTなど)を把握すると役に立ちます。これは、動的SQLを使用するアプリケーションについて特に当てはまります。
SQLStmtGetText()関数(旧称はsqlgls()関数)は、SQLLIBランタイム・ライブラリの一部であり、次の情報を戻します。
                  
- 
                        最後に解析されたSQL文のテキスト 
- 
                        文の有効な長さ 
- 
                        文で使用されているSQLコマンドの関数コード 
SQLStmtGetText()はスレッド・セーフです。静的SQL文を発行した後にSQLStmtGetText()関数をコールすることができます。動的SQL方法1のときは、SQL文が実行された後にSQLStmtGetText()をコールします。動的SQL方法2、3および4のときは、文がPREPAREするとすぐにSQLStmtGetText()をコールすることができます。 
                  
すべてのSQLLIB関数の新しい名前については、SQLLIBパブリック関数の新しい名前を参照してください。
SQLStmtGetText()のプロトタイプは、次のとおりです。 
                  
void SQLStmtGetText(dvoid *context, char *sqlstm, size_t *stmlen, size_t *sqlfc);
コンテキスト・パラメータはランタイム・コンテキストです。コンテキストの定義と使用方法は、コンテキスト変数を参照してください。
sqlstmパラメータは文字バッファです。このバッファには、SQL文の戻されたテキストが格納されます。プログラムでは、静的にバッファを宣言するか、動的にバッファのメモリーを割り当てる必要があります。
stmlenパラメータはsize_t変数です。SQLStmtGetText()をコールする前に、このパラメータにsqlstmバッファの実際のサイズをバイト単位で設定してください。SQLStmtGetText()が戻ると、sqlstmバッファにはSQL文テキストが入り、その後はバッファ長まで空白文字で埋められます。stmlenパラメータは、戻された文の実際のバイト数を戻します。埋め込まれた空白文字のバイト数は含まれません。stmlenの最大値はポート固有で、通常は最大整数サイズになります。
                  
sqlfcパラメータは、文のSQLコマンドのSQL機能コードを戻すsize_t変数です。表9-3は、各コマンドのSQL機能コードを示しています。
表9-3 SQL機能コード
| コード | SQL機能 | コード | SQL機能 | コード | SQL機能 | 
|---|---|---|---|---|---|
| 01 | CREATE TABLE | 26 | ALTER TABLE | 51 | DROP TABLESPACE | 
| 02 | SET ROLE | 27 | EXPLAIN | 52 | ALTER SESSION | 
| 03 | INSERT | 28 | GRANT | 53 | ALTER USER | 
| 04 | SELECT | 29 | REVOKE | 54 | COMMIT | 
| 05 | UPDATE | 30 | CREATE SYNONYM | 55 | ROLLBACK | 
| 06 | DROP ROLE | 31 | DROP SYNONYM | 56 | SAVEPOINT | 
| 07 | DROP VIEW | 32 | ALTER SYSTEM SWITCH LOG | 57 | CREATE CONTROL FILE | 
| 08 | DROP TABLE | 33 | SET TRANSACTION | 58 | ALTER TRACING | 
| 09 | DELETE | 34 | PL/SQL EXECUTE | 59 | CREATE TRIGGER | 
| 10 | CREATE VIEW | 35 | LOCK TABLE | 60 | ALTER TRIGGER | 
| 11 | DROP USER | 36 | (使用されていない) | 61 | DROP TRIGGER | 
| 12 | CREATE ROLE | 37 | RENAME | 62 | ANALYZE TABLE | 
| 13 | CREATE SEQUENCE | 38 | COMMENT | 63 | ANALYZE INDEX | 
| 14 | ALTER SEQUENCE | 39 | AUDIT | 64 | ANALYZE CLUSTER | 
| 15 | (使用されていない) | 40 | NOAUDIT | 65 | CREATE PROFILE | 
| 16 | DROP SEQUENCE | 41 | ALTER INDEX | 66 | DROP PROFILE | 
| 17 | CREATE SCHEMA | 42 | CREATE EXTERNAL DATABASE | 67 | ALTER PROFILE | 
| 18 | CREATE CLUSTER | 43 | DROP EXTERNAL DATABASE | 68 | DROP PROCEDURE | 
| 19 | CREATE USER | 44 | CREATE DATABASE | 69 | (使用されていない) | 
| 20 | CREATE INDEX | 45 | ALTER DATABASE | 70 | ALTER RESOURCE COST | 
| 21 | DROP INDEX | 46 | CREATE ROLLBACK SEGMENT | 71 | CREATE SNAPSHOT LOG | 
| 22 | DROP CLUSTER | 47 | ALTER ROLLBACK SEGMENT | 72 | ALTER SNAPSHOT LOG | 
| 23 | VALIDATE INDEX | 48 | DROP ROLLBACK SEGMENT | 73 | DROP SNAPSHOT LOG | 
| 24 | CREATE PROCEDURE | 49 | CREATE TABLESPACE | 74 | CREATE SNAPSHOT | 
| 25 | ALTER PROCEDURE | 50 | ALTER TABLESPACE | 75 | ALTER SNAPSHOT | 
| -- | -- | -- | -- | 76 | DROP SNAPSHOT | 
エラーが発生すると、長さパラメータ(stmlen)はゼロを戻します。発生する可能性のあるエラー条件は、次のとおりです。
- 
                        SQL文が解析されていません。 
- 
                        無効なパラメータ(たとえば、負の長さのパラメータ)を渡しました。 
- 
                        SQLLIBで内部例外が発生しました。 
9.9.1 制限(SQLStmtGetText()の使用)
SQLStmtGetText()は、次のコマンドを含む文のテキストは戻しません。 
                     
- 
                           CONNECT 
- 
                           COMMIT 
- 
                           ROLLBACK 
- 
                           FETCH 
これらのコマンドのSQL機能コードはありません。
9.10 Oracle通信領域(ORACA)の使用について
SQLCAが標準的なSQL通信を処理するのに対し、ORACAはOracle通信を処理します。ランタイム・エラーおよび状態の変化について、SQLCAで提供されるより詳しい情報が必要な場合は、ORACAを使用してください。これには、豊富な診断ツールが用意されています。ただし、ORACAの使用はランタイム・オーバーヘッドを増加させるため、あくまでもオプションです。
ORACAは問題の診断に役立つ上に、プログラムによるOracleリソース(SQL文エグゼキュータやカーソル・キャッシュなど)の利用を監視できます。
プログラムでは複数のORACAを使用できます。たとえば、1つのグローバルORACAと複数のローカルORACAを設定できます。ローカルORACAへのアクセスは、プログラム内のその有効範囲によって制限されます。Oracleでは適用範囲内のORACAにのみ情報が戻されます。
9.10.1 ORACAの宣言について
ORACAを宣言するには、次に示すように、INCLUDE文または#includeプリプロセッサ・ディレクティブを使用してORACAを自分のプログラムにコピーします。
EXEC SQL INCLUDE ORACA;
または
#include <oraca.h>
ORACAがextern記憶域クラスであることが必要な場合は、プログラムに次のようにORACA_STORAGE_CLASSを定義します。
#define ORACA_STORAGE_CLASS extern
プログラムで宣言部を使用するときは、ORACAを宣言部の外側で定義する必要があります。
9.10.2 ORACAの有効化について
ORACAを有効にするには、コマンドラインに次のようにORACAオプションを指定する必要があります。
ORACA=YES
またはインラインで次のように指定します。
EXEC ORACLE OPTION (ORACA=YES);
その後、ORACA内のフラグを設定することによって、適切なランタイム・オプションを選択する必要があります。
9.10.3 ORACAの内容
ORACAには、次のように、オプションの設定、システムの統計および高度な診断情報が保存されています。
- 
                              SQL文のテキスト(テキストの保存時に指定できます) 
- 
                              エラーが発生したファイルの名称(サブルーチンの使用時に便利です) 
- 
                              ファイル内のエラーの位置 
- 
                              カーソル・キャッシュのエラーおよび統計情報 
oraca.hの一部を次に示します。 
                        
/*
NAME
  ORACA : Oracle Communications Area.
  If the symbol ORACA_NONE is defined, then there will be no ORACA
  *variable*, although there will still be a struct defined.  This
  macro should not normally be defined in application code.
  If the symbol ORACA_INIT is defined, then the ORACA will be
  statically initialized. Although this is not necessary in order
  to use the ORACA, it is a good pgming practice not to have
  unitialized variables. However, some C compilers/operating systems
  don't allow automatic variables to be init'd in this manner. Therefore,
  if you are INCLUDE'ing the ORACA in a place where it would be
  an automatic AND your C compiler/operating system doesn't allow this style
  of initialization, then ORACA_INIT should be left undefined --
  all others can define ORACA_INIT if they wish.
*/
 
#ifndef  ORACA
#define  ORACA      1
 
struct    oraca
{
    char oracaid[8];   /* Reserved               */
    long oracabc;      /* Reserved               */
 
/*    Flags which are setable by User. */
 
   long  oracchf;      /* <> 0 if "check cur cache consistncy"*/
   long  oradbgf;      /* <> 0 if "do DEBUG mode checking"    */
   long  orahchf;      /* <> 0 if "do Heap consistency check" */
   long  orastxtf;     /* SQL stmt text flag            */
#define  ORASTFNON 0   /* = don't save text of SQL stmt       */
#define  ORASTFERR 1   /* = only save on SQLERROR         */
#define  ORASTFWRN 2   /* = only save on SQLWARNING/SQLERROR  */
#define  ORASTFANY 3      /* = always save             */
    struct
      {
  unsigned short orastxtl;
  char  orastxtc[70];
      } orastxt;         /* text of last SQL stmt          */
    struct
      {
  unsigned short orasfnml;
  char      orasfnmc[70];
      } orasfnm;        /* name of file containing SQL stmt    */
  long   oraslnr;        /* line nr-within-file of SQL stmt     */
  long   orahoc;         /* highest max open OraCurs requested  */
  long   oramoc;         /* max open OraCursors required         */
  long   oracoc;         /* current OraCursors open         */
  long   oranor;         /* nr of OraCursor re-assignments      */
  long   oranpr;         /* nr of parses               */
  long   oranex;         /* nr of executes            */
    };
#ifndef ORACA_NONE
#ifdef ORACA_STORAGE_CLASS
ORACA_STORAGE_CLASS struct oraca oraca
#else
struct oraca oraca
#endif
#ifdef ORACA_INIT
    =
    {
    {'O','R','A','C','A',' ',' ',' '},
    sizeof(struct oraca),
    0,0,0,0,
    {0,{0}},
    {0,{0}},
    0,
    0,0,0,0,0,0
    }
#endif
    ;
#endif
#endif
/* end oraca.h */
9.10.5 ORACAの構造体
この項では、ORACAの構造体とそのコンポーネントおよび格納できる値について説明します。
9.10.5.3 oracchf
マスターDEBUGフラグ(oradbgf)が設定されていると、このフラグによってカーソル・キャッシュの統計情報の収集と、各カーソル操作前のカーソル・キャッシュの一貫性チェックができます。
Oracleランタイム・ライブラリでは一貫性チェックが行われ、エラー・メッセージが発行されることがあります(エラー・メッセージについては、『Oracle Databaseエラー・メッセージ』を参照してください)。これらは、Oracleエラー・メッセージと同様にSQLCAに戻されます。
このフラグは次のいずれかを設定します。
- 
                                 キャッシュ一貫性チェックを使用禁止にします(デフォルト)。 
- 
                                 キャッシュ一貫性チェックを使用可能にします。 
9.10.5.4 oradbgf
このマスター・フラグを使用すると、DEBUGオプションをすべて選択できます。これには次の設定があります。
すべてのDEBUG処理を使用禁止にします(デフォルト)。
すべてのDEBUG処理を有効にします。
9.10.5.5 orahchf
マスターDEBUGフラグ(oradbgf)が設定されていると、プリコンパイラによって動的にメモリーが割り当てまたは解放されるたびに、Oracleランタイム・ライブラリでヒープの一貫性がチェックされます。これはメモリー障害を起こすプログラムの不具合を検出するのに役立ちます。
このフラグはCONNECTコマンドを発行する前に設定する必要があります。また、このフラグは一度設定すると解除できなくなります。つまり、設定後にこのフラグの変更要求があっても無視されます。これには次の設定があります。
- 
                                 ヒープ一貫性チェックを無効にします(デフォルト)。 
- 
                                 ヒープ一貫性チェックを有効にします。 
9.10.5.6 orastxtf
このフラグを使用すると、現行のSQL文のテキストを保存するタイミングを指定できます。これには次の設定があります。
- 
                                 SQL文のテキストを保存しません(デフォルト)。 
- 
                                 SQLERRORのSQL文のテキストのみ保存します。 
- 
                                 SQLERRORまたはSQLWARNINGのSQL文のテキストのみ保存します。 
- 
                                 常にSQL文のテキストを保存します。 
SQL文のテキストは、orastxtという名前のORACA埋込み構造体に保存されます。
9.10.5.8 orastxt
この埋込み構造体は、問題のあるSQL文を見つけるために使用します。Oracleで解析された最後のSQL文のテキストを保存できます。これには次の2つのコンポーネントが格納されています。
| コンポーネント | 説明 | 
|---|---|
| orastxtl | この整数コンポーネントにはカレントSQL文の長さが格納されます。 | 
| orastxtc | この文字列コンポーネントにはカレントSQL文のテキストが格納されます。先頭から最大70文字までのテキストが保存されます。文字列はヌル文字で終了しません。文字列を印刷するときは、oratxtl長さコンポーネントを使用します。 | 
プリコンパイラによって解析された文(CONNECT、FETCHおよびCOMMITなど)は、ORACAには保存されません。
9.10.5.9 orasfnm
この埋込み構造体は、カレントSQL文が含まれているファイルを識別します。このため、1つのアプリケーション用に複数のファイルをプリコンパイルするときにエラーを検出できます。これには次の2つのコンポーネントが格納されています。
| コンポーネント | 説明 | 
|---|---|
| orasfnml | この整数コンポーネントには、orasfnmcに保存されているファイル名の長さが格納されます。 | 
| orasfnmc | この文字列コンポーネントにはファイル名が格納されます。先頭から最大70文字が格納されます。 | 
9.10.5.13 oramoc
この整数コンポーネントには、プログラムの要求によってオープンされたOracleカーソルの最大数が記録されます。MAXOPENCURSORSに設定されている値が小さすぎて、その結果プリコンパイラによってカーソル・キャッシュが拡張されると、この数はorahocより大きくなることがあります。
9.10.5.15 oranor
この整数コンポーネントには、プログラムの要求によって再度割り当てられたカーソル・キャッシュの数が記録されます。この数値は、カーソル・キャッシュのスラッシングの程度を示すもので、できるだけ小さく保つ必要があります。
9.10.6 ORACAの例
次のプログラムは部門番号の入力を要求し、その部内の各従業員の名前および給与を2つの表のどちらかに挿入してから、ORACAからの診断情報を表示します。このプログラムはoraca.pcとしてdemoディレクトリにあり、オンラインで利用できます。
/* oraca.pc
 * This sample program demonstrates how to
 * use the ORACA to determine various performance
 * parameters at runtime.
 */
#include <stdio.h> 
#include <string.h>
#include <sqlca.h>
#include <oraca.h> 
EXEC SQL BEGIN DECLARE SECTION;
char *userid = "SCOTT/TIGER"; 
char  emp_name[21];
int   dept_number; 
float salary; 
char SQLSTATE[6];
EXEC SQL END DECLARE SECTION;
void sql_error(); 
main() 
{ 
    char temp_buf[32];
    EXEC SQL WHENEVER SQLERROR DO sql_error("Oracle error");
    EXEC SQL CONNECT :userid; 
    
    EXEC ORACLE OPTION (ORACA=YES);
    oraca.oradbgf  = 1;             /* enable debug operations */ 
    oraca.oracchf  = 1;      /* gather cursor cache statistics */ 
    oraca.orastxtf = 3;       /* always save the SQL statement */ 
    printf("Enter department number: "); 
    gets(temp_buf);
    dept_number = atoi(temp_buf);
    
    EXEC SQL DECLARE emp_cursor CURSOR FOR 
      SELECT ename, sal + NVL(comm,0) AS sal_comm
        FROM emp 
        WHERE deptno = :dept_number
        ORDER BY sal_comm DESC;
    EXEC SQL OPEN emp_cursor; 
    EXEC SQL WHENEVER NOT FOUND DO sql_error("End of data");
    
    for (;;) 
    { 
        EXEC SQL FETCH emp_cursor INTO :emp_name, :salary; 
        printf("%.10s\n", emp_name);
        if (salary < 2500) 
            EXEC SQL INSERT INTO pay1 VALUES (:emp_name, :salary); 
        else 
            EXEC SQL INSERT INTO pay2 VALUES (:emp_name, :salary);    
    } 
} 
void 
sql_error(errmsg)
char *errmsg;
{ 
    char buf[6];
    strcpy(buf, SQLSTATE);
    EXEC SQL WHENEVER SQLERROR CONTINUE; 
    EXEC SQL COMMIT WORK RELEASE; 
    
    if (strncmp(errmsg, "Oracle error", 12) == 0)
        printf("\n%s, sqlstate is %s\n\n", errmsg, buf);
    else
        printf("\n%s\n\n", errmsg);
    printf("Last SQL statement: %.*s\n", 
    oraca.orastxt.orastxtl, oraca.orastxt.orastxtc); 
    printf("\nAt or near line number %d\n", oraca.oraslnr); 
    printf
("\nCursor Cache Statistics\n------------------------\n"); 
    printf
("Maximum value of MAXOPENCURSORS:    %d\n", oraca.orahoc); 
    printf
("Maximum open cursors required:      %d\n", oraca.oramoc); 
    printf
("Current number of open cursors:     %d\n", oraca.oracoc); 
    printf
("Number of cache reassignments:      %d\n", oraca.oranor); 
    printf
("Number of SQL statement parses:     %d\n", oraca.oranpr); 
    printf
("Number of SQL statement executions: %d\n", oraca.oranex); 
    exit(1); 
} 
