ヘッダーをスキップ
Pro*C/C++プログラマーズ・ガイド
11gリリース2(11.2)
B61343-01
  ドキュメント・ライブラリへ
ライブラリ
製品リストへ
製品
目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

9 ランタイム・エラーの処理

アプリケーション・プログラムでは、ランタイム・エラーを予想し、そのエラーをリカバリするように対処する必要があります。この章では、エラー・レポートとリカバリについて詳しく説明します。SQLコミュニケーション領域(SQLCA)、WHENEVERディレクティブおよびSQLSTATE状態変数を使用して、エラーおよび状態の変化を処理する方法を説明します。さらにOracle通信領域(ORACA)による問題点の診断方法も紹介します。この章の項目は、次のとおりです。

エラー処理の必要性

どのようなアプリケーション・プログラムでも、その大部分をエラー処理に当てる必要があります。エラー処理の主な目的は、エラーが発生してもプログラムの処理を続行できるようにすることです。エラーは設計ミス、コーディングの誤り、ハードウェア障害、誤ったユーザー入力をはじめ、様々な原因で発生します。

潜在的なエラーをすべて予測するのは無理ですが、プログラムにとって意味のある特定の種類のエラーについては、処理を考えることもできます。Pro*C/C++プリコンパイラにとっては、エラー処理とはSQL文の実行エラーの検出およびリカバリのことです。「値が切り捨てられました」などの警告や「データの終わり」などの状態変化も処理できるよう準備しておくこともできます。INSERT文、UPDATE文またはDELETE文では表内の処理対象行をすべて処理する前にエラーが発生することがあるため、SQL DML文を実行するたびにエラー状態および警告状態を調べることが特に重要です。

エラー処理の代替手段

アプリケーションの状態の変化およびエラーを検出するにはいくつかの手段があります。この章ではそれらの手段について説明しますが、特定の手段の推奨は行っていません。最終的にどの手段を使用するかは、作成中のアプリケーション・プログラムまたはツールがどのように設計されているかによって決まります。

状態変数

状態変数SQLSTATEまたはSQLCODEを別に宣言し、実行SQL文の後の値をそれぞれ調べて、適切なアクションを取ることができます。アクションとして、エラー報告関数をコールし、エラーがリカバリ不能なときはプログラムを終了することができます。または、データを調整するか変数を制御して、アクションを再試行することもできます。


関連項目


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文に関する情報、オプションの設定、システムの統計情報が含まれます。


関連項目


SQLSTATE状態変数

プリコンパイラのMODEコマンドライン・オプションは、ANSI/ISOへの準拠を制御します。MODE=ANSIのとき、SQLCAデータ構造体の宣言はオプションです。ただし、SQLCODEという状態変数は別に宣言する必要があります。SQL標準では、SQLSTATEという類似した状態変数が指定されています。SQLSTATEは、SQLCODEとともに使用しても別々に使用してもかまいません。

SQL文の実行後、Oracleサーバーは現在の適用範囲内のSQLSTATE変数にステータス・コードを戻します。ステータス・コードは、SQL文が正常に実行されたか例外(エラーまたは警告状態)が発生したかを示します。相互運用性(システム間で情報を簡単に交換する機能)を高めるために、共通のSQL例外がすべてSQL標準によってあらかじめ定義されています。

SQLCODEにはエラー・コードのみが格納されるのに対し、SQLSTATEにはエラー・コードおよび警告コードが格納されます。さらに、SQLSTATEの報告のメカニズムには、標準化されたコード化方式が採用されています。このため、SQLSTATEは状態変数として優先されます。 SQLCODE was a deprecated feature of SQL-92 that was retained only for compatibility with SQL-89. SQLCODE has been removed from all editions of the SQL standard subsequent to SQL-92.

SQLSTATEの宣言

MODE=ANSIのときは、SQLSTATEまたはSQLCODEを宣言する必要があります。SQLCAの宣言はオプションです。MODE=ORACLEのときは、SQLSTATEを宣言しても無視されます。

SQLCODEでは符号付き整数を格納し、宣言部の外で宣言できますが、SQLSTATEではヌル文字で終了する5文字の文字列を格納し、宣言部の中で宣言する必要があります。次のようにSQLSTATEを宣言します。

char  SQLSTATE[6];  /* Upper case is required. */ 

注意:

SQLSTATEは正確に6文字のサイズで宣言する必要があります。

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

SQLSTATEコード化体系
「図9-1 SQLSTATEコード化体系」の説明

表9-1にSQL92で事前定義済のクラスを示します。

表9-1 事前定義済のクラス・コード

クラス 条件

00

正常終了

01

警告

02

データなし

07

動的SQLエラー

08

接続例外

09

triggered action exception

0A

サポートされていない機能

0D

invalid target type specification

0E

invalid schema name list specification

0F

ロケータ例外

0L

invalid grantor

0M

invalid SQL-invoked procedure reference

0P

invalid role specification

0S

invalid transform group name specification

0T

target table disagrees with cursor specification

0U

attempt to assign to non-updatable column

0V

attempt to assign to ordering column

0W

prohibited statement encountered during trigger execution

0Z

診断例外

21

制約違反

22

データ例外

23

整合性制約違反

24

カーソル状態が無効

25

トランザクション状態が無効

26

SQL文名が無効

27

トリガー・データの変更違反

28

認証の指定が無効

2A

直接SQL構文エラーまたはアクセス規則違反

2B

依存権限記述子がまだ存在している

2C

キャラクタ・セット名が無効

2D

トランザクションの終了が無効

2E

接続名が無効

2F

SQLルーチン例外

2H

invalid collation name

30

invalid SQL statement identifier

33

SQL記述子名が無効

34

カーソル名が無効

35

条件番号が無効

36

cursor sensitivity exception

37

動的SQL構文エラーまたはアクセス規則違反

38

external routine exception

39

external routine invocation exception

3B

savepoint exception

3C

カーソル名があいまい

3D

カタログ名が無効

3F

スキーマ名が無効

40

トランザクションのロールバック

42

構文エラーまたはアクセス規則違反

44

WITH_CHECK_OPTION指定違反

HZ

リモート・データベース・アクセス



注意:

クラス・コードHZは国際標準ISO/IEC DIS 9579-2、リモート・データベース・アクセスで定義された条件用に予約されています。

表9-2に、SQLSTATEステータス・コードと条件のOracleエラーとの対応を示します。 Status codes in the range 60000 to 99999 are implementation-defined.

表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

リモート・データベース・アクセス

--


SQLSTATEの使用

次の規則は、オプションの設定をMODE=ANSIにしてプリコンパイルするときに、SQLSTATEをSQLCODEまたはSQLCAと併用する場合に適用されます。SQLSTATEは宣言部内で宣言する必要があります。宣言部内で宣言しなければ無視されます。

SQLSTATEを宣言する場合

  • SQLCODEの宣言はオプションです。宣言部の内部でSQLCODEを宣言すると、SQL処理を実行するたびにOracleサーバーはSQLSTATEおよびSQLCODEにステータス・コードを戻します。ただし、宣言部の外部でSQLCODEを宣言すると、OracleはSQLSTATEのみにステータス・コードを戻します。

  • SQLCAの宣言はオプションです。SQLCAを宣言すると、OracleはSQLSTATEおよびSQLCAにステータス・コードを戻します。この場合は、コンパイル・エラーを防ぐために、SQLCODEを宣言しないでください。

SQLSTATEを宣言しない場合

  • 宣言部の内部または外部で、SQLCODEを宣言する必要があります。SQL処理を実行するたびに、OracleサーバーはSQLCODEにステータス・コードを戻します。

  • SQLCAの宣言はオプションです。SQLCAを宣言すると、OracleはSQLCODEおよびSQLCAにステータス・コードを戻します。

独自のコードを作成してSQLSTATEを明示的にチェックするか、WHENEVER SQLERRORディレクティブを使用してSQLSTATEを暗黙的にチェックすることで、最新の実行SQL文の結果が得られます。実行SQL文およびPL/SQL文の後にのみSQLSTATEをチェックしてください。

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を割り当てます。ホスト・プログラムは内部SQLCAにはアクセスできません。SQLCAおよびSQLCODEの両方を宣言すると、OracleはSQL操作を実行するたびに同じステータス・コードを両方に戻します。

SQLCAを使用したエラー・レポートの主要コンポーネント

エラー・レポートは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]をチェックしてください。これはエラーが発生したことを意味しています。

エラー・メッセージ・テキスト

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

SQLコミュニケーション領域(SQLCA)の使用

SQLCAはデータ構造体です。そのコンポーネントには、SQL文を実行するたびにOracleによって更新されるエラー、警告およびステータス情報が格納されます。つまり、SQLCAには常に最新のSQL処理の結果が反映されます。この結果を判断するために、SQLCA内の変数をチェックすることが可能です。

プログラムでは複数のSQLCAを使用できます。たとえば、1つのグローバルSQLCAと複数のローカルSQLCAを指定できます。ローカルなSQLCAへのアクセスは、プログラム内のスコープによって制限されます。Oracleは、スコープ内にあるSQLCAにのみ情報を戻します。


注意:

アプリケーションが、Oracle Netを使用してローカルとリモートのデータベースに同時にアクセスしている場合、すべてのデータベースが1つのSQLCAに書込みを行います。つまり、データベースごとに異なるSQLCAがあるわけではありません。

SQLCAの宣言

MODE=ORACLEのときは、SQLCAの宣言が必要です。SQLCAを宣言するには、次に示すようにINCLUDEまたは#include文を使用してSQLCAをプログラム内にコピーします。

EXEC SQL INCLUDE SQLCA; 

or

#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の内容

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

SQLCAの構造体

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

sqlcaid

この文字列コンポーネントはSQLCAに初期化されて、SQLコミュニケーション領域を示します。

sqlcabc

この整数コンポーネントにはSQLCA構造体の長さがバイト単位で格納されます。

sqlcode

この整数コンポーネントには最後に実行されたSQL文のステータス・コードが格納されます。SQL操作の結果を示すステータス・コードは次の数字のどれかになります。

ステータス・コード 説明
0 エラーまたは例外の検出なしで文が実行されたことを示します。
>0 文は実行されたが、例外が検出されたことを示します。この状態が発生するのは、WHERE句の検索条件を満たす行が見つからないとき、あるいはSELECT INTOやFETCHで行が戻されなかったときです。

MODE=ANSIのときは、どの行もINSERTできなければ+100がsqlcodeに戻されます。この状態が発生するのは、副問合せで処理に行が戻されなかったときです。

  • <0はデータベース、システム、ネットワークまたはアプリケーションのエラーが原因で、文が実行されなかったことを示します。このようなエラーは致命的です。こうしたエラーが発生すると、ほとんどの場合は現行のトランザクションがロールバックされます。

負のリターン・コードに対応するエラー・コードについては、『Oracle Databaseエラー・メッセージ』のリストを参照してください。

sqlerrm

この埋込み構造体には次の2つのコンポーネントがあります。

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

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

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

sqlerrp

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

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] このコンポーネントは将来使用するために予約されています。

sqlwarn

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

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

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

コンポーネント 説明
sqlwarn[0] このフラグは別の警告フラグが設定されていることを示します。
sqlwarn[1] このフラグは、切り捨てられた列値が出力ホスト変数に代入されたときに設定されます。これは文字データにのみ適用されます。つまり、Oracleは、警告で設定することも負のsqlcodeを戻すこともなく、特定の数値データを切り捨てます。

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

コンポーネント 説明
sqlwarn[2] AVG()やSUM()などのSQLグループ関数の結果にNULL列が使用されない場合、このフラグが設定されます。
sqlwarn[3] 問合せの選択リスト内の列の数がSELECT文またはFETCH文のINTO句内のホスト変数の数と一致しないときに、このフラグが設定されます。戻される項目の数は両者のうち少ない方の数となります。
sqlwarn[4] このフラグは現在使用されていません。
sqlwarn[5] このフラグが設定されるのは、EXEC SQL CREATE {PROCEDURE | FUNCTION | PACKAGE | PACKAGE BODY}文がPL/SQLコンパイル・エラーのために失敗したときです。
sqlwarn[6] このフラグは現在使用されていません。
sqlwarn[7] このフラグは現在使用されていません。

sqlext

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

PL/SQLの考慮事項

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

エラー・メッセージの全文の取得

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によって格納されたエラー・メッセージの切り捨てられていない場合の、実際の長さを示すスカラー変数です。


注意:

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()を使用して、適切なエラー・メッセージを取得してください。

WHENEVERディレクティブの使用

デフォルトでは、プリコンパイルされたプログラムはOracleエラーおよび警告条件を無視し、可能であれば処理を続行します。自動条件チェックおよびエラー処理を実行するにはWHENEVERディレクティブが必要です。

WHENEVERディレクティブによって、OracleでエラーやSQLERROR、SQLWARNINGまたはNOT FOUND条件が検出されたときのアクションを指定できます。これらのアクションには、次の文の継続実行、ルーチンのコール、ラベル付き文への分岐、停止などがあります。

WHENEVERディレクティブの構文は次のとおりです。

EXEC SQL WHENEVER <condition> <action>; 

WHENEVERの条件

次の条件の有無を調べるためにOracleでSQLCAを自動チェックすることができます。

SQLWARNING

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

MODE=ANSIのときは、SQLCAの宣言はオプションです。ただし、WHENEVER SQLWARNINGを使用するには、SQLCAを宣言する必要があります。

SQLERROR

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

NOT FOUND

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

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

WHENEVERのアクション

前述の条件のいずれかが検出されたときは、プログラムで次のアクションを実行できます。

CONTINUE

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

DO

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

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

DO BREAK

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

DO CONTINUE

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

GOTO label_name

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

STOP

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

STOPが実際に行うのは、WHENEVER条件発生時のexit()コールの生成のみです。ここでは注意が必要です。STOPアクションは、Oracleからの切断前に何もメッセージを表示しません。

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の変数をチェックしてアクションの過程を決定する手順に注目してください。

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

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; 
    ... 

WHENEVERのガイドライン

この項では、一般的な問題点を回避するためのガイドラインを示します。

文の位置

通常、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内の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ディレクティブの分岐先のラベルは、この文と同じプリコンパイル・ファイル内にする必要があります。

エラー後の戻り

エラー処理後にプログラムに戻る必要がある場合は、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ディレクティブがないことを確認してください。

SQL文のテキスト取得

多くのプリコンパイラ・アプリケーションでは、処理中の文のテキスト、その長さ、指定されているSQLコマンド(INSERTやSELECTなど)を把握すると役に立ちます。これは、動的SQLを使用するアプリケーションでは特に重要です。

SQLStmtGetText()関数(旧称はsqlgls()関数)は、SQLLIBランタイム・ライブラリの一部であり、次の情報を戻します。

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)はゼロを戻します。発生する可能性のあるエラー条件は、次のとおりです。

制限

SQLStmtGetText()は、次のコマンドを含む文のテキストは戻しません。

  • CONNECT

  • COMMIT

  • ROLLBACK

  • FETCH

これらのコマンドのSQL機能コードはありません。

サンプル・プログラム

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

Oracle通信領域(ORACA)の使用

SQLCAが標準的なSQL通信を処理するのに対し、ORACAはOracle通信を処理します。ランタイム・エラーおよび状態の変化に関して、SQLCAにより提供されるものより詳しい情報が必要なときは、ORACAを使用します。ORACAには豊富な診断ツールが用意されています。ただし、ORACAの使用はランタイム・オーバーヘッドを増加させるため、あくまでもオプションです。

ORACAは問題の診断に役立つ上に、プログラムのOracleリソース、たとえばSQL文エグゼキュータやカーソル・キャッシュなどの利用を監視することを可能にします。

プログラムでは複数のORACAを使用できます。たとえば、1つのグローバルORACAと複数のローカルORACAを指定できます。ローカルなORACAへのアクセスは、プログラム内での適用範囲によって制限されます。Oracleでは適用範囲内のORACAにのみ情報が戻されます。

ORACAの宣言

ORACAを宣言するには、次に示すように、INCLUDE文または#includeプリプロセッサ・ディレクティブを使用してORACAを自分のプログラムにコピーします。

EXEC SQL INCLUDE ORACA; 

or

#include <oraca.h> 

ORACAがextern記憶域クラスであることが必要な場合は、プログラムに次のようにORACA_STORAGE_CLASSを定義します。

#define ORACA_STORAGE_CLASS extern

プログラムで宣言部を使用するときは、ORACAを宣言部の外側で定義する必要があります。

ORACAを使用可能にする

ORACAを使用可能にするには、コマンドラインに次のようにORACAオプションを指定する必要があります。

ORACA=YES 

またはインラインで次のように指定します。

EXEC ORACLE OPTION (ORACA=YES); 

その後にORACA内のフラグを設定することで、適切なランタイム・オプションを選択する必要があります。

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の構造体

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

oracaid

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

oracabc

この整数コンポーネントには、ORACAデータ構造体の長さがバイト単位で格納されています。

oracchf

マスターDEBUGフラグ(oradbgf)が設定されていると、このフラグによってカーソル・キャッシュの統計情報の収集と、各カーソル操作前のカーソル・キャッシュの一貫性チェックができます。

Oracleランタイム・ライブラリは一貫性チェックを行い、エラー・メッセージを発行することがあります。エラー・メッセージのリストについては、『Oracle Databaseエラー・メッセージ』を参照してください。それらのメッセージは、Oracleエラー・メッセージと同様にSQLCAに戻されます。

このフラグは次のいずれかを設定します。

  • キャッシュ一貫性チェックを使用禁止にする(デフォルト)。

  • キャッシュ一貫性チェックを使用可能にする。

oradbgf

このマスター・フラグを使用すると、DEBUGオプションをすべて選択できます。このフラグには次のいずれかを設定します。

すべてのDEBUG処理を使用禁止にする(デフォルト)。

すべてのDEBUG処理を使用可能にする。

orahchf

マスターDEBUGフラグ(oradbgf)が設定されていると、プリコンパイラによって動的にメモリーが割り当てまたは解放されるたびに、Oracleランタイム・ライブラリでヒープの一貫性がチェックされます。これはメモリー障害を起こすプログラムの不具合を検出するのに役立ちます。

このフラグはCONNECTコマンドを発行する前に設定する必要があります。また、このフラグは一度設定すると解除できなくなります。つまり、設定後にこのフラグの変更要求があっても無視されます。このフラグには次のいずれかを設定します。

  • ヒープ一貫性チェックを使用禁止にする(デフォルト)。

  • ヒープ一貫性チェックを使用可能にする。

orastxtf

このフラグを使用すると、カレントSQL文のテキストを保存するタイミングを指定できます。このフラグには次のいずれかを設定します。

  • SQL文のテキストを保存しない(デフォルト)。

  • SQLERRORのSQL文のテキストのみを保存する。

  • SQLERRORまたはSQLWARNINGのSQL文のテキストのみを保存する。

  • 常にSQL文のテキストを保存する。

SQL文のテキストは、orastxtという名前のORACA埋込み構造体に保存されます。

診断情報

ORACAは高度な診断情報を提供します。次の変数によってエラーの位置をすばやく特定できます。

orastxt

この埋込み構造体は、問題のあるSQL文を見つけるために使用します。これによって、Oracleで最後に解析されたSQL文のテキストを保存できます。この構造体には次の2つのコンポーネントが格納されています。

コンポーネント 説明
orastxtl この整数コンポーネントにはカレントSQL文の長さが格納されます。
orastxtc この文字列コンポーネントにはカレントSQL文のテキストが格納されます。先頭から70文字分のテキストが保存されます。文字列はヌル文字で終了しません。文字列を印刷するときは、orastxtl長さコンポーネントを使用します。

CONNECT、FETCH、COMMITなどの文は、プリコンパイラによって解析されますが、ORACAには保存されません。

orasfnm

この埋込み構造体は、カレントSQL文が含まれているファイルを識別します。このため、1つのアプリケーション用に複数のファイルをプリコンパイルするときにエラーを検出できます。この構造体には次の2つのコンポーネントが格納されています。

コンポーネント 説明
orasfnml この整数コンポーネントには、orasfnmcに保存されているファイル名の長さが格納されます。
orasfnmc この文字列コンポーネントにはファイル名が格納されます。先頭から70文字分が保存されます。

oraslnr

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

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

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

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

orahoc

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

oramoc

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

oracoc

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

oranor

この整数コンポーネントは、プログラムの要求によって再度割り当てられたカーソル・キャッシュの数を記録します。この数字はカーソル・キャッシュのスラッシングの程度を示します。可能なかぎり低く保ってください。

oranpr

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

oranex

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

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