アプリケーション・プログラムでは、ランタイム・エラーを予想し、そのエラーをリカバリするように対処する必要があります。この章では、エラー・レポートとリカバリについて詳しく説明します。SQLコミュニケーション領域(SQLCA)、WHENEVERディレクティブおよびSQLSTATE状態変数を使用して、エラーおよび状態の変化を処理する方法を説明します。さらにOracle通信領域(ORACA)による問題点の診断方法も紹介します。この章の項目は、次のとおりです。
どのようなアプリケーション・プログラムでも、その大部分をエラー処理に当てる必要があります。エラー処理の主な目的は、エラーが発生してもプログラムの処理を続行できるようにすることです。エラーは設計ミス、コーディングの誤り、ハードウェア障害、誤ったユーザー入力をはじめ、様々な原因で発生します。
潜在的なエラーをすべて予測するのは無理ですが、プログラムにとって意味のある特定の種類のエラーについては、処理を考えることもできます。Pro*C/C++プリコンパイラにとっては、エラー処理とはSQL文の実行エラーの検出およびリカバリのことです。「値が切り捨てられました」などの警告や「データの終わり」などの状態変化も処理できるよう準備しておくこともできます。INSERT文、UPDATE文またはDELETE文では表内の処理対象行をすべて処理する前にエラーが発生することがあるため、SQL DML文を実行するたびにエラー状態および警告状態を調べることが特に重要です。
アプリケーションの状態の変化およびエラーを検出するにはいくつかの手段があります。この章ではそれらの手段について説明しますが、特定の手段の推奨は行っていません。最終的にどの手段を使用するかは、作成中のアプリケーション・プログラムまたはツールがどのように設計されているかによって決まります。
状態変数SQLSTATEまたはSQLCODEを別に宣言し、実行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は、int型として宣言されます。SQLCAのコンポーネントsqlcodeのことを指す場合は、常に完全修飾名sqlca.sqlcodeが使用されます。 |
ランタイム・エラーについて、SQLCAに格納されている情報よりも詳細な情報が必要なときにORACAを使用できます。ORACAは、Oracleの通信を処理するC言語の構造体です。この中にはカーソルの統計情報、カレントSQL文に関する情報、オプションの設定、システムの統計情報が含まれます。
プリコンパイラのMODEコマンドライン・オプションは、ANSI/ISOへの準拠を制御します。MODE=ANSIのとき、SQLCAデータ構造体の宣言はオプションです。ただし、SQLCODEという状態変数は別に宣言する必要があります。SQL92では、SQLSTATEという類似した状態変数が指定されています。SQLSTATEは、SQLCODEとともに使用しても別々に使用してもかまいません。
SQL文の実行後、Oracleサーバーは現在の適用範囲内のSQLSTATE変数にステータス・コードを戻します。ステータス・コードは、SQL文が正常に実行されたか例外(エラーまたは警告状態)が発生したかを示します。相互運用性(システム間で情報を簡単に交換する機能)を高めるために、共通のSQL例外がすべてSQL92によってあらかじめ定義されています。
SQLCODEにはエラー・コードのみが格納されるのに対し、SQLSTATEにはエラー・コードおよび警告コードが格納されます。さらに、SQLSTATEの報告のメカニズムには、標準化されたコード化方式が採用されています。このため、SQLSTATEは状態変数として優先されます。SQL92ではSQLCODEはSQL89との互換性を保つためにのみ維持されている推奨しない機能で、標準の将来のバージョンからは削除される可能性があります。
MODE=ANSIのときは、SQLSTATEまたはSQLCODEを宣言する必要があります。SQLCAの宣言はオプションです。MODE=ORACLEのときは、SQLSTATEを宣言しても無視されます。
SQLCODEでは符号付き整数を格納し、宣言部の外で宣言できますが、SQLSTATEではヌル文字で終了する5文字の文字列を格納し、宣言部の中で宣言する必要があります。次のようにSQLSTATEを宣言します。
char SQLSTATE[6]; /* Upper case is required. */
注意: SQLSTATEは正確に6文字のサイズで宣言する必要があります。 |
SQLSTATEステータス・コードは、2文字のクラス・コードおよびその後に続く3文字のサブクラス・コードで構成されます。クラス・コード00(正常終了)以外のときには、クラス・コードは例外のカテゴリを示します。また、サブクラス・コード000(適用外)以外では、サブクラス・コードはそのカテゴリ内の特定の例外を示します。たとえば、SQLSTATEの値22012はクラス・コード22(データ例外)とサブクラス・コード012(ゼロ除算)を示します。
SQLSTATE値の5文字は、それぞれ数字(0〜9)または大文字の英文字(A〜Z)で構成されます。0〜4の範囲の数字、あるいはA〜Hの範囲の文字で始まるクラス・コードは、事前定義済の条件(SQL92で定義されている)用に確保されています。他のすべてのクラス・コードは実装時に定義される条件用に確保されています。事前定義済のクラスのうち、0〜4の範囲の数字およびA〜Hの範囲の文字で始まるサブクラス・コードは、事前定義済の副条件用に確保されています。他のサブクラス・コードはすべて実装時に定義される部分条件用に確保されています。図9-1にコード化体系を示します。
表9-1にSQL92で事前定義済のクラスを示します。
表9-1 事前定義済のクラス・コード
クラス | 条件 |
---|---|
00 |
正常終了 |
01 |
警告 |
02 |
データなし |
07 |
動的SQLエラー |
08 |
接続例外 |
0A |
サポートされていない機能 |
21 |
制約違反 |
22 |
データ例外 |
23 |
整合性制約違反 |
24 |
カーソル状態が無効 |
25 |
トランザクション状態が無効 |
26 |
SQL文名が無効 |
27 |
トリガー・データの変更違反 |
28 |
認証の指定が無効 |
2A |
直接SQL構文エラーまたはアクセス規則違反 |
2B |
依存権限記述子がまだ存在している |
2C |
キャラクタ・セット名が無効 |
2D |
トランザクションの終了が無効 |
2E |
接続名が無効 |
33 |
SQL記述子名が無効 |
34 |
カーソル名が無効 |
35 |
条件番号が無効 |
37 |
動的SQL構文エラーまたはアクセス規則違反 |
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 |
作成された文がカーソル仕様ではない |
-- |
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-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-01400〜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 |
リモート・データベース・アクセス |
-- |
次の規則は、オプションの設定をMODE=ANSIにしてプリコンパイルするときに、SQLSTATEをSQLCODEまたはSQLCAと併用する場合に適用されます。SQLSTATEは宣言部内で宣言する必要があります。宣言部内で宣言しなければ無視されます。
SQLCODEの宣言はオプションです。宣言部の内部でSQLCODEを宣言すると、SQL処理を実行するたびにOracleサーバーはSQLSTATEおよびSQLCODEにステータス・コードを戻します。ただし、宣言部の外部でSQLCODEを宣言すると、OracleはSQLSTATEのみにステータス・コードを戻します。
SQLCAの宣言はオプションです。SQLCAを宣言すると、OracleはSQLSTATEおよびSQLCAにステータス・コードを戻します。この場合は、コンパイル・エラーを防ぐために、SQLCODEを宣言しないでください。
宣言部の内部または外部で、SQLCODEを宣言する必要があります。SQL処理を実行するたびに、OracleサーバーはSQLCODEにステータス・コードを戻します。
SQLCAの宣言はオプションです。SQLCAを宣言すると、OracleはSQLCODEおよびSQLCAにステータス・コードを戻します。
独自のコードを作成してSQLSTATEを明示的にチェックするか、WHENEVER SQLERRORディレクティブを使用してSQLSTATEを暗黙的にチェックすることで、最新の実行SQL文の結果が得られます。実行SQL文およびPL/SQL文の後にのみSQLSTATEをチェックしてください。
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を割り当てます。ホスト・プログラムは内部SQLCAにはアクセスできません。SQLCAおよびSQLCODEの両方を宣言すると、OracleはSQL操作を実行するたびに同じステータス・コードを両方に戻します。
エラー・レポートはSQLCA内の変数によって異なります。この項では、エラー・レポートの主要コンポーネントについて説明します。また、この次の項ではSQLCAを詳しく説明します。
すべての実行SQL文は、SQLCA変数sqlcodeにステータス・コードを戻します。戻されたステータス・コードはWHENEVERディレクティブによって暗黙的に、あるいは独自のコードによって明示的にチェックできます。
0(ゼロ)のステータス・コードは、Oracleがエラーまたは例外を検出せずに文を実行したことを意味します。正のステータス・コードは、Oracleが例外を検出した上で文を実行したことを意味します。負のステータス・コードは、エラーが発生したためにOracleがSQL文を実行しなかったことを意味します。
警告フラグはSQLCA変数のsqlwarn[0]
からsqlwarn[7]
に戻されます。これは暗黙的にも明示的にもチェックできます。警告フラグは、Oracleでエラーとみなされない実行時の条件をチェックするのに便利です。標識変数がなければ、Oracleではエラー・メッセージが発行されます。
最後に実行したSQL文で処理された行数は、SQLCA変数sqlca.sqlerrd[2]
に戻されます。これは明示的にチェックできます。
厳密にはこの変数はエラー・レポート用ではなく、誤りを防止するためのものです。たとえば、表から約10行を削除するとします。削除処理後にsqlca.sqlerrd[2]
をチェックすると、75行が削除されていました。このような場合は、念のため削除処理をロールバックしてWHERE句の検索条件を確認することが可能です。
SQL文は実行前に必ず解析されます。つまり、構文規則に従っているか、さらに有効なデータベース・オブジェクトを参照しているかが検証されます。Oracleがエラーを検出すると、SQLCA変数sqlca.sqlerrd[4]
にオフセットが格納されます。これは明示的にチェックすることができます。このオフセットには、解析エラーの始まりを示すSQL文中の文字位置が指定されています。通常のC言語の文字列と同様に、先頭の文字位置は0です。たとえば、オフセットが9のとき、解析エラーは10番目の文字から始まっています。
解析エラー・オフセットは、準備と解析が別々に実行される状況で使用されます。その代表例は動的SQL文です。
解析エラーは、キーワードの欠落、キーワードの位置指定の誤り、キーワードのスペルミス、無効なオプションなどが原因で発生します。次に例を示します。
"UPDATE emp SET jib = :job_title WHERE empno = :emp_number"
この動的SQL文は解析エラーになります。
ORA-00904: invalid column name
原因は列名JOBのスペルミスです。誤った列名JIBが16番目の文字で始まっているため、sqlca.sqlerrd[4]
の値が15になっています。
SQL文に解析エラーがなければ、Oracleではsqlca.sqlerrd[4]
に0(ゼロ)が設定されます。解析エラーが先頭の文字(文字位置はゼロ)で始まっているときも、Oracleはsqlca.sqlerrd[4]
に0(ゼロ)設定します。したがって、sqlca.sqlcodeが負の場合のみ、sqlca.sqlerrd[4]
をチェックしてください。これはエラーが発生したことを意味しています。
SQLCAはデータ構造体です。そのコンポーネントには、SQL文を実行するたびにOracleによって更新されるエラー、警告およびステータス情報が格納されます。つまり、SQLCAには常に最新のSQL処理の結果が反映されます。この結果を判断するために、SQLCA内の変数をチェックすることが可能です。
プログラムでは複数のSQLCAを使用できます。たとえば、1つのグローバルSQLCAと複数のローカルSQLCAを指定できます。ローカルなSQLCAへのアクセスは、プログラム内のスコープによって制限されます。Oracleは、スコープ内にあるSQLCAにのみ情報を戻します。
注意: アプリケーションが、Oracle Netを使用してローカルとリモートのデータベースに同時にアクセスしている場合、すべてのデータベースが1つのSQLCAに書込みを行います。つまり、データベースごとに異なる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を使用しています。 |
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 #endif
この項では、SQLCAの構造体、そのコンポーネントおよびコンポーネントに格納できる値について説明します。
この整数コンポーネントには最後に実行されたSQL文のステータス・コードが格納されます。SQL操作の結果を示すステータス・コードは次の数字のどれかになります。
ステータス・コード | 説明 |
---|---|
0 | エラーまたは例外の検出なしで文が実行されたことを示します。 |
>0 | 文は実行されたが、例外が検出されたことを示します。この状態が発生するのは、WHERE句の検索条件を満たす行が見つからないとき、あるいはSELECT INTOやFETCHで行が戻されなかったときです。 |
MODE=ANSIのときは、どの行もINSERTできなければ+100がsqlcodeに戻されます。この状態が発生するのは、副問合せで処理に行が戻されなかったときです。
<0はデータベース、システム、ネットワークまたはアプリケーションのエラーが原因で、文が実行されなかったことを示します。このようなエラーは致命的です。こうしたエラーが発生すると、ほとんどの場合は現行のトランザクションがロールバックされます。
負のリターン・コードに対応するエラー・コードについては、『Oracle Databaseエラー・メッセージ』のリストを参照してください。
この埋込み構造体には次の2つのコンポーネントがあります。
コンポーネント | 説明 |
---|---|
sqlerrml | この整数コンポーネントには、sqlerrmc内に保存されているメッセージ・テキストの長さが格納されます。 |
sqlerrmc | この文字列コンポーネントには、sqlcode内に保存されているエラー・コードに対応したメッセージ・テキストが格納されます。文字列はヌル文字で終了しません。長さを調べるにはsqlerrmlコンポーネントを使用します。 |
このコンポーネントには最大70文字まで格納できます。71文字以上のメッセージ全体を取得するには、この後で説明するsqlglm
関数を使用します。
sqlerrmcを参照する前に、sqlcodeが負であることを確認する必要があります。sqlcodeが0(ゼロ)のときにsqlerrmcを参照すると、以前のSQL文に対応するメッセージが取得されることになります。
この2進整数の配列には6つの要素があります。sqlerrd内のコンポーネントの説明を次に示します。
処理済行数はOPEN文の後に0(ゼロ)に設定され、FETCH文の後に増分されます。処理済行数には、EXECUTE文、INSERT文、UPDATE文、DELETE文およびSELECT INTO文について、正常に処理された行数が反映されます。この数字にはUPDATEまたはDELETE CASCADEによって処理された行は含まれません。たとえば、WHERE句の条件を満たす20行が削除され、この削除により列制約条件に反する5行がさらに削除されたとき、処理済行数は、25ではなく、あくまでも20です。
この1文字の配列には8つの要素があります。これらの要素は警告フラグとして使用されます。Oracleは、それに文字値W(警告)を割り当てることでフラグを設定します。
フラグは例外条件の発生を警告します。たとえば、切り捨てられた列値をOracleが出力ホスト変数に代入するときに、警告フラグが設定されます。
sqlwarnのコンポーネントの説明を次に示します。
コンポーネント | 説明 |
---|---|
sqlwarn[0] | このフラグは別の警告フラグが設定されていることを示します。 |
sqlwarn[1] | このフラグは、切り捨てられた列値が出力ホスト変数に代入されたときに設定されます。これは文字データにのみ適用されます。つまり、Oracleは、警告で設定することも負のsqlcodeを戻すこともなく、特定の数値データを切り捨てます。 |
列値が切り捨てられたかどうか、またどのくらい切り捨てられたかを調べるには、出力ホスト変数に対応する標識変数をチェックします。標識変数によって戻された値が正の整数のときは、その値は列値の元の長さを示します。その値に応じてホスト変数の長さを増やすことができます。
この文字列コンポーネントは将来使用するために予約されています。
SQLCAには最高で70文字以内のエラー・メッセージを格納できます。71文字以上の(またはネストされた)エラー・メッセージ全体を取得するには、sqlglm()
関数を使用する必要があります。次に構文を示します。
void sqlglm(char *message_buffer, size_t *buffer_size, size_t *message_length);
パラメータは、次のとおりです。
構文 | 説明 |
---|---|
message_buffer | エラー・メッセージを格納するためのテキスト・バッファです(Oracleはバッファの最後まで空白文字で埋め込みます)。 |
buffer_size | バッファの最大サイズをバイト数で示したスカラー変数です。 |
message_length | Oracleによって格納されたエラー・メッセージの切り捨てられていない場合の、実際の長さを示すスカラー変数です。 |
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()を使用して、適切なエラー・メッセージを取得してください。 |
デフォルトでは、プリコンパイルされたプログラムはOracleエラーおよび警告条件を無視し、可能であれば処理を続行します。自動条件チェックおよびエラー処理を実行するにはWHENEVERディレクティブが必要です。
WHENEVERディレクティブによって、OracleでエラーやSQLERROR、SQLWARNINGまたはNOT FOUND条件が検出されたときのアクションを指定できます。これらのアクションには、次の文の継続実行、ルーチンのコール、ラベル付き文への分岐、停止などがあります。
WHENEVERディレクティブの構文は次のとおりです。
EXEC SQL WHENEVER <condition> <action>;
前述の条件のいずれかが検出されたときは、プログラムで次のアクションを実行できます。
可能であれば、プログラムは次の文からの実行を継続します。これはデフォルトの動作で、WHENEVERディレクティブを使用しない場合と同じです。このアクションを使用すると条件チェックを終了できます。
制御をプログラム中のエラー処理関数に移します。ルーチンの最後に達すると、制御は失敗したSQL文の次の文に移ります。
関数の入力および終了について、通常の規則が適用されます。EXEC SQL WHENEVER ... DO ...ディレクティブで起動されるエラー・ハンドラにパラメータを渡し、関数によって値を戻すことができます。
たとえば、プログラムで次のアクションが必要であるとします。
「データが見つかりません」という条件が発生したときには、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の変数をチェックしてアクションの過程を決定する手順に注目してください。
次の例では、コミッションを受け取っている従業員の分のみ、従業員の名前、給料、コミッションを表示する方法を示しています。
#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); }
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; ...
この項では、一般的な問題点を回避するためのガイドラインを示します。
通常、WHENEVERディレクティブはプログラムの最初の実行SQL文の前に指定します。この位置に指定したWHENEVERディレクティブはファイルの最後まで有効になるため、発生するすべてのエラーを確実にトラップできます。
カーソルを使用して行をフェッチするときは、プログラムでデータの終わり条件に対処できるようにする必要があります。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; ...
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: ...
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ディレクティブの分岐先のラベルは、この文と同じプリコンパイル・ファイル内にする必要があります。
多くのプリコンパイラ・アプリケーションでは、処理中の文のテキスト、その長さ、指定されている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パラメータは、戻されたSQL文の実際のバイト数を戻します。これは埋め込まれた空白文字のバイト数を含みません。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で内部の例外が生じました。
SQLCAが標準的なSQL通信を処理するのに対し、ORACAはOracle通信を処理します。ランタイム・エラーおよび状態の変化に関して、SQLCAにより提供されるものより詳しい情報が必要なときは、ORACAを使用します。ORACAには豊富な診断ツールが用意されています。ただし、ORACAの使用はランタイム・オーバーヘッドを増加させるため、あくまでもオプションです。
ORACAは問題の診断に役立つ上に、プログラムのOracleリソース、たとえばSQL文エグゼキュータやカーソル・キャッシュなどの利用を監視することを可能にします。
プログラムでは複数のORACAを使用できます。たとえば、1つのグローバルORACAと複数のローカルORACAを指定できます。ローカルなORACAへのアクセスは、プログラム内での適用範囲によって制限されます。Oracleでは適用範囲内のORACAにのみ情報が戻されます。
ORACAを宣言するには、次に示すように、INCLUDE文または#includeプリプロセッサ・ディレクティブを使用してORACAを自分のプログラムにコピーします。
EXEC SQL INCLUDE ORACA;
または
#include <oraca.h>
ORACAがextern記憶域クラスであることが必要な場合は、プログラムに次のようにORACA_STORAGE_CLASSを定義します。
#define ORACA_STORAGE_CLASS extern
プログラムで宣言部を使用するときは、ORACAを宣言部の外側で定義する必要があります。
ORACAを使用可能にするには、コマンドラインに次のようにORACAオプションを指定する必要があります。
ORACA=YES
またはインラインで次のように指定します。
EXEC ORACLE OPTION (ORACA=YES);
その後に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 */
ORACAにはいくつかのオプション・フラグがあります。これらのフラグにゼロ以外の値を設定することで、次のことが可能になります。
SQL文のテキストの保存
DEBUG処理の有効化
カーソル・キャッシュの一貫性チェック(カーソル・キャッシュとは、カーソル管理に使用されるメモリーで継続的に更新される領域を指します)
ヒープの一貫性チェック(ヒープとは動的変数のために予約されるメモリー領域を指します)
カーソルの統計情報の収集
次の説明はオプションを選択するときの参考になります。
この項では、ORACAの構造体とそのコンポーネントおよび格納できる値について説明します。
マスターDEBUGフラグ(oradbgf)が設定されていると、このフラグによってカーソル・キャッシュの統計情報の収集と、各カーソル操作前のカーソル・キャッシュの一貫性チェックができます。
Oracleランタイム・ライブラリは一貫性チェックを行い、エラー・メッセージを発行することがあります。エラー・メッセージのリストについては、『Oracle Databaseエラー・メッセージ』を参照してください。それらのメッセージは、Oracleエラー・メッセージと同様にSQLCAに戻されます。
このフラグは次のいずれかを設定します。
キャッシュ一貫性チェックを使用禁止にする(デフォルト)。
キャッシュ一貫性チェックを使用可能にする。
このマスター・フラグを使用すると、DEBUGオプションをすべて選択できます。このフラグには次のいずれかを設定します。
すべてのDEBUG処理を使用禁止にする(デフォルト)。
すべてのDEBUG処理を使用可能にする。
マスターDEBUGフラグ(oradbgf)が設定されていると、プリコンパイラによって動的にメモリーが割り当てまたは解放されるたびに、Oracleランタイム・ライブラリでヒープの一貫性がチェックされます。これはメモリー障害を起こすプログラムの不具合を検出するのに役立ちます。
このフラグはCONNECTコマンドを発行する前に設定する必要があります。また、このフラグは一度設定すると解除できなくなります。つまり、設定後にこのフラグの変更要求があっても無視されます。このフラグには次のいずれかを設定します。
ヒープ一貫性チェックを使用禁止にする(デフォルト)。
ヒープ一貫性チェックを使用可能にする。
このフラグを使用すると、カレントSQL文のテキストを保存するタイミングを指定できます。このフラグには次のいずれかを設定します。
SQL文のテキストを保存しない(デフォルト)。
SQLERRORのSQL文のテキストのみを保存する。
SQLERRORまたはSQLWARNINGのSQL文のテキストのみを保存する。
常にSQL文のテキストを保存する。
SQL文のテキストは、orastxtという名前のORACA埋込み構造体に保存されます。
この埋込み構造体は、問題のあるSQL文を見つけるために使用します。これによって、Oracleで最後に解析されたSQL文のテキストを保存できます。この構造体には次の2つのコンポーネントが格納されています。
コンポーネント | 説明 |
---|---|
orastxtl | この整数コンポーネントにはカレントSQL文の長さが格納されます。 |
orastxtc | この文字列コンポーネントにはカレントSQL文のテキストが格納されます。先頭から70文字分のテキストが保存されます。文字列はヌル文字で終了しません。文字列を印刷するときは、orastxtl長さコンポーネントを使用します。 |
CONNECT、FETCH、COMMITなどの文は、プリコンパイラによって解析されますが、ORACAには保存されません。
この埋込み構造体は、カレントSQL文が含まれているファイルを識別します。このため、1つのアプリケーション用に複数のファイルをプリコンパイルするときにエラーを検出できます。この構造体には次の2つのコンポーネントが格納されています。
コンポーネント | 説明 |
---|---|
orasfnml | この整数コンポーネントには、orasfnmcに保存されているファイル名の長さが格納されます。 |
orasfnmc | この文字列コンポーネントにはファイル名が格納されます。先頭から70文字分が保存されます。 |
マスターDEBUGフラグ(oradbgf)およびカーソル・キャッシュ・フラグ(oracchf)が設定されているときは、次の変数を使用してカーソル・キャッシュ統計情報を収集できます。これらの変数は、プログラムがCOMMITコマンドまたはROLLBACKコマンドを発行するたびに自動的に設定されます。
内部的には、CONNECTされているデータベース別にこの変数のセットがあります。ORACA内の現在の設定値は、最後にCOMMITまたはROLLBACKが行われたデータベースに関係します。
この整数コンポーネントは、プログラムの要求によってオープンされたOracleカーソルの最大数を記録します。MAXOPENCURSORSに設定されている数が小さすぎると、この数はorahocよりも大きくなることがあります。このとき、プリコンパイラによってカーソル・キャッシュが拡張されます。
この整数コンポーネントは、プログラムの要求によって再度割り当てられたカーソル・キャッシュの数を記録します。この数字はカーソル・キャッシュのスラッシングの程度を示します。可能なかぎり低く保ってください。
次のプログラムは部門番号の入力を要求し、その部内の各従業員の名前および給与を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); }