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 SQLSTATEコード化体系

図9-1の説明が続きます
「図9-1 SQLSTATEコード化体系」の説明

表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を使用したエラー・レポートの主要コンポーネント

エラー・レポートはSQLCA内の変数によって異なります。この項では、エラー・レポートの主要コンポーネントについて説明します。また、この次の項ではSQLCAを詳しく説明します。

9.5.1 ステータス・コード

すべての実行SQL文は、SQLCA変数sqlcodeにステータス・コードを戻します。戻されたステータス・コードはWHENEVERディレクティブによって暗黙的に、あるいは独自のコードによって明示的にチェックできます。

0(ゼロ)のステータス・コードは、Oracleがエラーまたは例外を検出せずに文を実行したことを意味します。正のステータス・コードは、Oracleが例外を検出した上で文を実行したことを意味します。負のステータス・コードは、エラーが発生したためにOracleがSQL文を実行しなかったことを意味します。

9.5.2 警告フラグ

警告フラグはSQLCA変数のsqlwarn[0]からsqlwarn[7]に戻されます。これは暗黙的にも明示的にもチェックできます。警告フラグは、Oracleでエラーとみなされない実行時の条件をチェックするのに便利です。標識変数がなければ、Oracleではエラー・メッセージが発行されます。

9.5.3 処理済行数

最後に実行したSQL文で処理された行数は、SQLCA変数sqlca.sqlerrd[2]に戻されます。これは明示的にチェックできます。

厳密にはこの変数はエラー・レポート用ではなく、誤りを防止するためのものです。たとえば、表から約10行を削除するとします。削除処理後にsqlca.sqlerrd[2]をチェックすると、75行が削除されていました。このような場合は、念のため削除処理をロールバックしてWHERE句の検索条件を確認することが可能です。

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.5.5 エラー・メッセージ・テキスト

Oracleエラーのエラー・コードおよびメッセージはSQLCA変数SQLERRMCに格納されます。テキストの最初の最大70文字が格納されます。70文字を超えるメッセージすべてを取得するには、sqlglm()関数を使用します。

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エラー・コード

  • 警告フラグ

  • イベント情報

  • 処理済行数

  • 診断情報

sqlca.hヘッダー・ファイルは次のとおりです。

/*
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

9.6.3 SQLCAの構造

この項では、SQLCAの構造体、そのコンポーネントおよびコンポーネントに格納できる値について説明します。

9.6.3.1 sqlcaid

この文字列コンポーネントはSQLCAに初期化されて、SQL通信領域を示します。

9.6.3.2 sqlcabc

この整数コンポーネントには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内に保存されているメッセージ・テキストの長さが格納されます。

sqlerrmc

この文字列コンポーネントには、sqlcode内に保存されているエラー・コードに対応したメッセージ・テキストが格納されます。文字列はヌル文字で終了しません。長さを調べるにはsqlerrmlコンポーネントを使用します。

このコンポーネントには最大70文字まで格納できます。71文字以上のメッセージ全体を取得するには、この後で説明するsqlglm関数を使用します。

sqlerrmcを参照する前にsqlcodeが負であることを確認する必要があります。sqlcodeが0(ゼロ)のときにsqlerrmcを参照すると、以前のSQL文に対応するメッセージが取得されることになります。

9.6.3.5 sqlerrp

この文字列コンポーネントは将来使用するために予約されています。

9.6.3.6 sqlerrd

この2進整数の配列には6つの要素があります。sqlerrd内のコンポーネントの説明を次に示します。

コンポーネント 説明

sqlerrd[0]

このコンポーネントは将来使用するために予約されています。

sqlerrd[1]

このコンポーネントは将来使用するために予約されています。

sqlerrd[2]

このコンポーネントには、その時点で最後に実行したSQL文によって処理された行数が格納されます。ただし、SQL文が失敗すると、1つの例外を除きsqlca.sqlerrd[2]の値は未定義となります。配列処理中にエラーが発生すると、そのエラーの発生した行で処理は停止します。そのため、sqlca.sqlerrd[2]は正常に処理された行数を示します。

処理済行数はOPEN文の後に0 (ゼロ)に設定され、FETCH文の後に増分されます。処理済行数は、EXECUTE文、INSERT文、UPDATE文、DELETE文およびSELECT INTO文について、正常に処理された行数を反映します。この数には、UPDATEやDELETE_CASCADEで処理された行は含まれません。たとえばWHERE句の条件を満たす20行が削除された後で、列制約条件に違反する5行が削除されたときの処理済行数は、25ではなく20となります。

コンポーネント 説明

sqlerrd[3]

このコンポーネントは将来使用するために予約されています。

sqlerrd[4]

このコンポーネントは、最後に実行されたSQL文中で解析エラーの始まりを示す文字位置を指定するオフセットを保持します。先頭の文字位置は0 (ゼロ)です。

sqlerrd[5]

このコンポーネントは将来使用するために予約されています。

9.6.3.7 sqlwarn

この1文字の配列には8つの要素があります。これらの要素は警告フラグとして使用されます。Oracleではそれに文字値W(警告)を割り当てることでフラグを設定します。

フラグは例外状態の発生を警告します。たとえば、切り捨てられた列値が出力ホスト変数に割り当てられると、警告フラグが設定されます。

sqlwarnのコンポーネントの説明を次に示します。

コンポーネント 説明

sqlwarn[0]

このフラグは別の警告フラグが設定されていることを示します。

sqlwarn[1]

このフラグは、切り捨てられた列値が出力ホスト変数に代入されたときに設定されます。これは文字データにのみ適用されます。つまり、Oracleは、警告で設定することも負のsqlcodeを戻すこともなく、特定の数値データを切り捨てます。

列値が切り捨てられたかどうか、またどれだけ切り捨てられたかを調べるには、出力ホスト変数に対応する標識変数をチェックします。標識変数によって戻された値が正の整数のときは、その値は列値の元の長さを示します。その値に応じてホスト変数の長さを増やすことができます。

コンポーネント 説明

sqlwarn[2]

AVG()やSUM()などのSQLグループ関数の結果にNULL列が使用されない場合、このフラグが設定されます。

sqlwarn[3]

問合せの選択リスト内の列の数がSELECT文またはFETCH文のINTO句内のホスト変数の数と一致しないときに、このフラグが設定されます。戻される項目の数は両者のうち少ない方の数となります。

sqlwarn[4]

このフラグは現在使用されていません。

sqlwarn[5]

PL/SQLのコンパイル・エラーが原因でEXEC SQL CREATE {PROCEDURE | FUNCTION | PACKAGE | PACKAGE BODY}文が失敗したときに、このフラグが設定されます。

sqlwarn[6]

このフラグは現在使用されていません。

sqlwarn[7]

このフラグは現在使用されていません。

9.6.3.8 sqlext

この文字列コンポーネントは将来使用するために予約されています。

9.6.4 PL/SQLの考慮事項

プリコンパイラ・アプリケーションで埋込みPL/SQLブロックを実行するときに、SQLCAのすべてのコンポーネントが設定されるわけではありません。たとえば、ブロックが複数の行をフェッチするときは、処理済行数(sqlerrd[2])には1しか設定されません。PL/SQLブロックの実行後は、SQLCAのsqlcodeおよびsqlerrmコンポーネントのみを使用してください。

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.1 WHENEVER条件

Oracleに自動的にSQLCAをチェックさせて、次の状態が存在しないかどうかを調べることができます。

9.8.1.1 SQLWARNING

sqlwarn[0]は、Oracleから警告(sqlwarn[1]からsqlwarn[7]までのいずれか1つも設定されます)が戻されたか、SQLCODEが+1403以外の正の値になっているために設定されます。たとえば、切り捨てられた列値が出力ホスト変数に割り当てられると、sqlwarn[0]が設定されます。

MODE=ANSIのときは、SQLCAの宣言はオプションです。ただし、WHENEVER SQLWARNINGを使用するには、必ずSQLCAを宣言してください。

9.8.1.2 SQLERROR

Oracleがエラーを戻したことにより、SQLCODEに負の値が設定されています。

9.8.1.3 NOT FOUND

OracleがWHERE句の検索条件を満たす行を検出できなかったか、SELECT INTOまたはFETCHが行を戻さなかったため、SQLCODEに+1403が設定されています(MODE=ANSIのときは+100)。

MODE=ANSIのときは、どの行もINSERTできないと+100がSQLCODEに戻されます。

9.8.2 WHENEVERアクション

Oracleで前述の状態のいずれかが検出されたときは、プログラムに次のいずれかのアクションを実行させることができます。

9.8.2.1 CONTINUE

可能であれば、プログラムは次の文からの実行を継続します。これはデフォルトの動作で、WHENEVERディレクティブを使用しない場合と同じです。このアクションを使用すると条件チェックを終了できます。

9.8.2.2 DO

制御をプログラム中のエラー処理関数に移します。ルーチンの最後に達すると、制御は失敗したSQL文の次の文に移ります。

関数の入力および終了について、通常の規則が適用されます。EXEC SQL WHENEVER ... DO ...ディレクティブで起動されるエラー・ハンドラにパラメータを渡し、関数によって値を戻すことができます。

9.8.2.3 DO BREAK

実際のbreak文はプログラム中に置かれます。このアクションはループ内で使用します。WHENEVER条件が成立すると、プログラムはそのループを抜けます。

9.8.2.4 DO CONTINUE

実際のcontinue文がプログラム中に置かれます。このアクションはループ内で使用します。WHENEVER条件が成立すると、プログラムはそのループの次の反復に移ります。

9.8.2.5 GOTO label_name

プログラムはラベル付き文に分岐します。ラベル名の長さに制限はありませんが、有効なのは最初の31文字のみです。異なる最大長を必要とするCコンパイラもあります。使用しているCコンパイラのユーザーズ・ガイドを参照してください。

9.8.2.6 STOP

プログラムは実行を停止し、COMMITされていない作業がロールバックされます。

STOPが実際に行うのは、WHENEVER条件発生時のexit()コールの生成のみです。ここでは注意が必要です。STOPアクションは、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.1 文の位置

通常、WHENEVERディレクティブはプログラムの最初の実行SQL文の前に指定します。この位置に指定した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内のlabelAfunc2内の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.8.6.5 エラー後の戻りについて

エラー処理後にプログラムに戻る必要がある場合は、DO routine_callアクションを使用します。または、次の例に示すように、sqlcodeの値をテストしてもかまいません。

... 
EXEC SQL UPDATE emp SET sal = sal * 1.10; 
if (sqlca.sqlcode < 0) 
{  /* handle error  */ 
 
EXEC SQL DROP INDEX emp_index;

アクティブなWHENEVER GOTOディレクティブまたはWHENEVER STOPディレクティブがないことを確認してください。

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.9.2 サンプル・プログラム

サンプル・プログラムsqlvcp.pcは、demoディレクトリにあります。このプログラムは、sqlgls()関数の使用方法を示します。

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.4 ランタイム・オプションの選択について

ORACAにはいくつかのオプション・フラグがあります。これらのフラグに0(ゼロ)以外の値を設定することで、次のことが可能になります。

  • SQL文のテキストの保存

  • DEBUG処理の有効化

  • カーソル・キャッシュの一貫性チェック(カーソル・キャッシュとは、カーソル管理に使用されるメモリーで継続的に更新される領域)

  • ヒープの一貫性チェック(ヒープは、動的変数のために予約されるメモリー領域)

  • カーソルの統計情報の収集

次の説明はオプションを選択するときの参考になります。

9.10.5 ORACAの構造体

この項では、ORACAの構造体とそのコンポーネントおよび格納できる値について説明します。

9.10.5.1 oracaid

この文字列コンポーネントは「ORACA」に初期化されて、Oracle通信領域を示します。

9.10.5.2 oracabc

この整数コンポーネントには、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.7 診断情報

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.10 oraslnr

この整数コンポーネントはカレントSQL文がある行またはその付近の行を識別します。

9.10.5.11 カーソル・キャッシュ統計情報

マスターDEBUGフラグ(oradbgf)およびカーソル・キャッシュ・フラグ(oracchf)が設定されているときは、次の変数を使用してカーソル・キャッシュ統計情報を収集できます。これらの変数は、プログラムがCOMMITコマンドまたはROLLBACKコマンドを発行するたびに自動的に設定されます。

内部的には、CONNECTされているデータベース別にこの変数のセットがあります。ORACA内の現在の設定値は、最後にCOMMITまたはROLLBACKが行われたデータベースに関係します。

9.10.5.12 orahoc

この整数コンポーネントは、プログラムの実行中にMAXOPENCURSORSに設定された最大値を記録します。

9.10.5.13 oramoc

この整数コンポーネントには、プログラムの要求によってオープンされたOracleカーソルの最大数が記録されます。MAXOPENCURSORSに設定されている値が小さすぎて、その結果プリコンパイラによってカーソル・キャッシュが拡張されると、この数はorahocより大きくなることがあります。

9.10.5.14 oracoc

この整数コンポーネントは、プログラムの要求によってオープンされているOracleカーソルのカレント数を記録します。

9.10.5.15 oranor

この整数コンポーネントには、プログラムの要求によって再度割り当てられたカーソル・キャッシュの数が記録されます。この数値は、カーソル・キャッシュのスラッシングの程度を示すもので、できるだけ小さく保つ必要があります。

9.10.5.16 oranpr

この整数コンポーネントは、プログラムの要求によって解析されたSQL文の数を記録します。

9.10.5.17 oranex

この整数コンポーネントは、プログラムの要求によって実行されたSQL文の数を記録します。この数値のoranprに対する割合は、できるかぎり高く保ってください。つまり、不要な再解析は回避する必要があります。

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); 
}