UJP - 技術情報

Life is fun and easy!

不正IP報告数

Okan Sensor
 
メイン
ログイン
ブログ カテゴリ一覧

     

Pro*Cコーディング基礎


Pro*Cコーディング基礎


0.更新履歴

  • 1993.12.21 初版(MacWriteII版)
  • 1997.01.31 HTML化(タイトルを変えた)
  • 2000.09.13 レイアウトを奇麗に?しました.

1.DBを使用する為の定義

/* DBの返却値を設定しておくと便利*/
#define DB_SUCCESS              0
#define DB_NOTFOUND             1403
#define DB_BUSY                 (-54)

#define SETLEN(X)               X.len = strlen(X.arr)
#define SETNULL(X)              X.arr[X.len]=0

変数名

内容

SETLEN
 VARCHAR型の文字列長を調べその値を「x.len」に設定する

SETNULL
 DB上では文字列データ等に制御文字(\0)等を持たないので文字列を確定する為に「x.len」に格納してある数値番目の配列にヌル文字を設定する。

/* DBをアクセスする為に必要なエリアを定義する。*/
EXEC	SQL BEGIN DECLARE SECTION;

     /* DB access initialize using field */
     LOCAL   VARCHAR uid[20];             /* DB access user id.	*/
     LOCAL   VARCHAR pwd[20];             /* DB access user passwd*/

	/* DB update absolute value field */
	LOCAL	VARCHAR	DB_HOSTNAME[9];		/* Hostname		*/
	LOCAL	VARCHAR	DB_PGMID[9];		/* this program id	*/

     /* DB access field */
	LOCAL	VARCHAR	DB_BDBCD[9];		/**/
	LOCAL	VARCHAR	DB_BDBCYMD[7];		/**/
	LOCAL	VARCHAR	DB_BDBCHM[7];		/**/
	LOCAL	VARCHAR	DB_BDBIPGM[9];		/**/
	LOCAL	VARCHAR	DB_BDBITRN[9];		/**/

EXEC	SQL END DECLARE SECTION;

 BEGINENDの間にフィールドの定義を行う。 このエリアはグローバルである必要は無い。

 フィールド定義では、たとえばDBに3文字(char(3))で登録してある場合には、NULL文字分だけ+1して4文字定義する必要がある。

EXEC	SQL	INCLUDE	sqlca.h;

 DBとプログラム間の通信を行なうエリア。 アクセス情報(エラー等)を取得する事ができる。(Sql Communication Areaの略)

2.DBアクセス時のエラー処理

/* エラー処理 */
	switch(sqlca.sqlcode)
	{
	case DB_SUCCESS:
		EXEC	SQL	COMMIT	WORK;
		break;
	case DB_NOTFOUND:
		printf("Not Foundエn");
		break;
	dafault:
		printf("残念ながらDBに異常がありました。エn");
		printf("ROLL BACKしますので御了承ください。エn");
		printf("そしてシステム管理者に連絡してください。エn");
		printf("sqlcode=(%d)エn",sqlca.sqlcode);
		printf("sqlmsg =(%s)エn",sqlca.sqlerrm.sqlerrmc);
		EXEC	SQL	ROLLBACK	WORK	RELEASE;
		exit(FALSE);
	} /* end of switch () */

 正常に処理が終わった段階でCOMMITする。 これを行なう事で内容がデータベース内で反映される。

 sqlcaには、色々な情報を持っている場合があるがとりあえず次のような物を知っていれば良いでしょう。

SQLCA項目

内容

sqlca.sqlcode
 ORACLEのエラーコードが設定されている。 これを判定する事で実行したDBアクセスの処理結果が判定出来る。

sqlca.sqlerrm.sqlerrmc
 ORACLEのエラーコードに対するメッセージが文字列として設定されている。 これを読めば簡単なエラーであると解決できる(ハズ)

 DBのアクセスで通常以外のエラーが発生された場合、たとえば更新処理中に何か不具合があった場合に、何処まで更新されたか分からないので、その処理を実行する直前まで戻しておく必要があります。

 この様な場合に「ROLLBACK」を行ないます。

 ROLLBACKは、一番最近COMMITして時点までDBの情報を戻します。 最後にCOMMITが実行されているという事は、そこまでの情報は保証されているという事です。

3.DB検索処理

/* DBを検索して取り込む */
	strcpy(DB_ESORTKEY.arr,"KEY001");
	EXEC	SQL	SELECT
		ESBSYSID, ELISTID0,EPRTCENT
	INTO
		DB_ESBSYSID, DB_ELISTID0,DB_EPRTCENT
	FROM	TDSNNOD0
	WHERE	ESORTKEY = :DB_ESORTKEY;

	SETNULL(DB_ESBSYSID);
	SETNULL(DB_ELISTID0);
	SETNULL(DB_EPRTCENT);

 この例では、2つの項目を条件によりDBから検索するものである。

 SETNULL()を使用しているのは、DBより読み込まれた直後であると文字列の終了が確定されていない為である。 これは、次のような弊害を生む。

  • ABCというフィールドを持ってくる場合
  • 1回目の処理で「123456789」を持ってきた。
  • 2回目の処理で「9876」を持ってきた。

 SETNULL()で終点を確定していないと、2回目の処理で取得してABCというフィールドの中身は、前に読み込まれたエリアに上書きされて「987656789」となってしまう。

 キーがユニークとなっているものであると前提し、そのキーがあらかじめ設定されているという前提で検索することが出来る。(つまり該当する件数が一件しか無いといえる場合のみ)

 該当するDBレコードが複数ある場合には、それぞれINTOで取り込むエリアを配列で取っておく必要があるが、これを行なわないとメモリ領域を破壊してしまう。

 しかし、配列を取っていたとしても最大件数が固定である場合以外には、これは推奨出来ない。 たとえば「現在10件程だから100程配列をとっておけばいいや」などと考えている場合に、後から追加もおこりうるDBの場合、いつかプログムが異常終了する可能性がある。

4.DB更新処理

/* 更新処理 */

/* 排他制御を行う*/
	EXEC	SQL
	SELECT
		ESBSYSID,ELISTIDO,EPRTCENT
	  INTO
		DB_ESBSYSID, DB_ELISTID0, DB_EPRTCENT
	FROM	TDSNNOD0
	WHERE	ESORTKEY = :DB_ESORTKEY
	FOR	UPDATE	OF	ALL; 

 更新を行なうレコードに対してロックをかけます。 この事を排他制御と言います。  この例の場合ALLと指定してあるので、このレコードに存在するフィールド全項目をロックするという事です。

 「限定されたフィールドのみ」ロックするには、ここにDBのフィールド名を設定します。

/* 更新を行う */
	EXEC	SQL	UPDATE	TDSNNOD0 SET
		BDBUYMD		=	TO_CHAR(SYSDATE,'YYMMDD'),
		BDBUHMS		=	TO_CHAR(SYSDATE,'HH24MISS'),
		ESBSYSID	=	:DB_ESBSYSID,
		ELISTID0	=	:DB_ELISTID0,
		EFIXDSN0	=	:DB_EFIXDSN0,
		ERENNO00	=	:DB_ERENNO00,
		EPRTCENT    =     :DB_EPRTCENT,
	WHERE	ESORTKEY	=	:DB_ESORTKEY;

6.排他処理とは

 DBは、一人だけが使用していると限られていない物です。 そこで自分が更新しようとしているデータを、他人が何処かで更新しようとたくらんでいる場合もあります。

 それを一時的に出来なくする処理を「排他制御」と言います。

 SQLでは、 ロックを行なった後にUPDATEを行ないCOMMITを発行すると排他制御は解除されます。

 厳密に言えば、ここのサンプルでは無かったのですが、「ロック出来たか」の処理コードの判定も必要でしょう。

7.追加(挿入)処理

/* 追加処理 */
EXEC	SQL	INSERT	INTO	TDSNNOD0
		(ESBSYSID, ELISTID0, EFIXDSN0, ERENNO00, 
		 EOVERRY1, EOVERRY2, ELISTNM0, EPRTJOB0, 
		 EPRTJOB1, EPRTSHEL, EPRTCENT, ESORTKEY,
		)
		VALUES
		(:DB_ESBSYSID, :DB_ELISTID0, :DB_EFIXDSN0, :DB_ERENNO00,
		 :DB_EOVERRY1, :DB_EOVERRY2, :DB_ELISTNM0, :DB_EPRTJOB0,
		 :DB_EPRTJOB1, :DB_EPRTSHEL, :DB_EPRTCENT, :DB_ESORTKEY,
		);

8.削除処理

/* 削除処理 */
EXEC	SQL	DELETE	FROM	TDSNNOD0
		WHERE	ESORTKEY	=	:DB_ESORTKEY;

9.カーソルを使った検索処理

/* カーソルの定義 */
EXEC	SQL	DECLARE	C1	CURSOR	FOR
SELECT	
	EPRTCENT, ESORTKEY
FROM	TDSNNOD0
ORDER	BY	ESORTKEY;

EXEC	SQL	OPEN	C1;

/* Headder */ 
fprintf(printer,"KEY   SHELL\n\n");

while(loop==TRUE)
{
	EXEC	SQL	FETCH	C1   	INTO
		DB_EPRTCENT, DB_ESORTKEY;

	switch(sqlca.sqlcode)
	{
	case	DB_SUCCESS:
		SETNULL(DB_EPRTCENT);
		SETNULL(DB_ESORTKEY);
		fprintf(printer,"%4s %6s \n", DB_ESORTKEY.arr,
							   DB_EPRTCENT.arr);
		break;
	case	DB_NOTFOUND:
		EXEC	SQL	CLOSE	C1;
		loop=FALSE;
		PRTclose(printer);
		break;
	default	:
		EXEC	SQL	CLOSE	C1;
		EXEC	SQL	ROLLBACK	WORK	RELEASE;
		loop=FALSE;
		PRTclose(printer);
		break;

	} /* end of switch() */
			
} /* end of while() */

 このプログラムでは、カーソルを使用し、一件づつ取り出したDBのフィールドを帳票イメージとしてファイルに書き出すプログラムです。

 カーソルを使用した処理を行なった後には、必ずCLOSEする様にしてください。

 カーソルを実行すると、該当するDBを一度にORACLEの制御するエリアに持ってくるのですが、CLOSEしないとこれが残ったままになり、「容量が足りないエラー」みたいなものが発生します。



広告スペース
Google