スケーラブルデータベースサーバ HiRDB Version 8 UAP開発ガイド
ストアドプロシジャは,SQLで記述した一連のデータベース処理手続きを,手続きとしてデータベースに登録しておく機能です。
データベースを操作する場合,FETCH文で検索し,データの有無によってUPDATE文,又はINSERT文の発行を繰り返すと,クライアントとサーバ間のオーバヘッドが増大します。このようなデータベースアクセス処理を手続き(プロシジャ)として定義しておくと,CALL文で手続きを呼び出すだけで,一連の処理を実行できるため,クライアントサーバ間のデータの受渡しなどオーバヘッドの抑制が図れます。また,手続き中のSQL文はコンパイルされた形式(SQLオブジェクト)でサーバ側に登録されているため,処理を共用化できる以外に,SQL解析のオーバヘッドも削減できます。
SQLストアドプロシジャの効果を次の図に示します。
図4-9 SQLストアドプロシジャの効果
SQLストアドプロシジャは,CREATE PROCEDURE又はCREATE TYPE実行時に手続きがデータベースに登録され,DROP PROCEDURE実行時に削除されます。
登録した手続きは,CALL文で呼び出して実行します。
SQLオブジェクトが無効になっている手続きがある場合は,ALTER PROCEDURE又はALTER ROUTINEで手続きを再作成することもできます。
また,既にSQLストアドプロシジャがある場合には,pddefrevコマンドを実行すれば,既にあるSQLストアドプロシジャの定義系SQLを作成できます。処理が似ているSQLストアドプロシジャを新たに作成するときに使用すると便利です。pddefrevコマンドについては,マニュアル「HiRDB Version 8 コマンドリファレンス」を参照してください。
SQLストアドプロシジャの定義と実行を次の図に示します。
図4-10 SQLストアドプロシジャの定義と実行
SQLストアドプロシジャの例として,複数のSQL文と,それらを制御する文(ルーチン制御SQL)を組み合わせて一つの手続き(プロシジャ)として定義する例とそれを呼び出して実行する例を次の図に示します。
図4-11 SQLストアドプロシジャの例
SQLストアドプロシジャのデバッグをする場合,参照するSQL変数,SQLパラメタなどを,ルーチン制御SQLのWRITE LINE文を使用してクライアント側のファイルに出力して行います。WRITE LINE文については,マニュアル「HiRDB Version 8 SQLリファレンス」を参照してください。
SQLストアドプロシジャ中にWRITE LINE文を記述する例を次に示します。
CREATE PROCEDURE proc_1 (IN fromdate date, IN todate date) BEGIN : : WRITE LINE 'fromdate='||char(fromdate); ..........................1 WRITE LINE 'todate='||char(todate); ..............................2 : : |
WRITE LINE文を記述したSQLストアドプロシジャから,WRITE LINE文の値式の値をクライアント側のファイルに出力する場合,クライアント環境定義PDWRTLNFILSZを設定し,UAPからSQLストアドプロシジャを呼び出します。例を次に示します。
setenv PDWRTLNFILSZ 4096 |
PDWRTLNFILSZ=4096 |
strcpy(e_fromdate, "2003-06-01"); strcpy(e_todate, "2003-06-30"); EXEC SQL CALL proc_1(IN :e_fromdate, IN :e_todate); |
fromdate=2003-06-01 todate=2003-06-30 |
注 出力ファイルは,クライアント環境定義PDWRTLNPATHで設定します。
デバッグ終了後,WRITE LINE文を記述したSQLストアドプロシジャから,WRITE LINE文の値式の値をファイルに出力する必要がなくなった場合,クライアント環境定義PDWRTLNFILSZを省略してUAPを実行してください。PDWRTLNFILSZの指定を省略すると,SQLストアドプロシジャ中のWRITE LINE文は実行されません。
次のSQL文をストアドプロシジャ中で実行すると,トランザクションを決着できます。ただし,Cストアドプロシジャ中では,SQL文を実行できません。
次のSQLを実行した場合,自動的にCOMMITが行われます。
次の条件に該当する場合,自動的にROLLBACKが行われます。
ストアドプロシジャ中でトランザクションを決着した後にエラーが発生した場合,そのプロシジャの実行は途中で終了します。エラーになったストアドプロシジャを再実行する場合,プロシジャの処理は先頭から実行されるため,エラー発生前のトランザクション解決までに行った操作が,二重に実行されてよいかどうかを考慮する必要があります。例を次に示します。
SQLストアドプロシジャ定義時に,CREATE PROCEDUREのDYNAMIC RESULT SETS句に1以上の値を指定した場合,結果集合返却機能を使用できます。なお,SQLストアドファンクションについては,結果集合返却機能は使用できません。
SQLストアドプロシジャ内での,SELECT文の実行によって得られるカーソルを,SQLストアドプロシジャの呼び出し元で参照する機能を,結果集合返却機能といいます。
結果集合返却機能の概要を次の図に示します。
図4-12 結果集合返却機能の概要(SQLストアドプロシジャの場合)
結果集合返却機能を使用できる呼び出し元の言語を次に示します。
SQLストアドプロシジャ内で,表emps_1,及び表emps_2に対して,id<10の条件を満たす列id,name,及びageを取得します。呼び出し元で2個の結果集合を受け取り,これらを操作します。
CREATE PROCEDURE proc2(IN param1 INTEGER) ............... 1 DYNAMIC RESULT SETS 2 ................................. 2 BEGIN DECLARE CUR1 CURSOR WITH RETURN ..................... 3 FOR SELECT id,name,age FROM emps_1 WHERE id < param1 ORDER BY id; DECLARE CUR2 CURSOR WITH RETURN ..................... 4 FOR SELECT id,name,age FROM emps_2 WHERE id < param1 ORDER BY id; OPEN CUR1; .......................................... 5 OPRN CUR2; .......................................... 6 END; .................................................. 7 |
#include <stdio.h> #include <string.h> main() { EXEC SQL BEGIN DECLARE SECTION; struct { short len; char str[31]; } cur1; int emp_id; char emp_name[13]; int emp_age; EXEC SQL END DECLARE SECTION; --------(HiRDBへのCONNECT処理(省略))-------- cur1.len = sprintf(cur1.str, "cursor1"); .................... 1 EXEC SQL CALL PROC(10); ..................................... 2 If (SQLCODE == 120) { ....................................... 3 EXEC SQL ALLOCATE GLOBAL :cur1 FOR PROCEDURE PROC2; ........................... 4 printf("*** emps_1 ***\n"); ............................... 5 while (1) { ............................................... 5 EXEC SQL FETCH GLOBAL :cur1 ............................. 5 INTO :emp_id,:emp_name,:emp_age; ............. 5 if (SQLCODE<0 || SQLCODE==100) break; ................... 5 printf("ID=%d NAME=%s AGE=%d\n", ...................... 5 emp_id, emp_name, emp_age); ....................... 5 } ......................................................... 5 CLOSE GLOBAL :cur1; ....................................... 6 if (SQLCODE==121) { ....................................... 7 printf("*** emps_2 ***\n"); ............................. 8 while (1) { ............................................. 8 EXEC SQL FETCH GLOBAL :cur1 ............................... 8 INTO :emp_id,:emp_name,:emp_age; ........... 8 if (SQLCODE<0 || SQLCODE==100) break; ................. 8 printf("ID=%d NAME=%s AGE=%d\n", .................... 8 emp_id, emp_name, emp_age); ..................... 8 } ....................................................... 8 CLOSE GLOBAL :cur1; ..................................... 9 } } } |
All Rights Reserved. Copyright (C) 2006, 2016, Hitachi, Ltd.