CHAPTER 2: |
パーシステントストアードモジュール |
Empressの重要な1つの機能として、データベースに ユーザーが定義した関数やオペレータ、ストアードプロシージャおよびトリガーを スキーマのオブジェクトとして格納することをユーザーに提供します。 これらのオブジェクトは、 SQL 文およびアプリケーションプログラムから実行されることができます。
ストアードプロシージャは、どのようなクライアントからでも実行することができる 手続き上のデータベースオブジェクトです。
トリガーは、イベントが発生した場合や条件を満たす場合に自動的に実行される ストアードプロシージャの特別なタイプです。 一般的にトリガーは、追加、更新、削除のようなデータベースのイベントと 関連付けられます。
PSMが Empress RDBMSにとって非常に有益な改良である理由は以下になります。
多くのアプリケーションプログラムの場合、結果を得るために ある回数、データベースアクセスの実行を行います。 このプログラムが、クライアント・サーバー環境上で繰り返し実行を要求した場合、 ネットワークのオーバーヘッドによって時間を浪費することになります。 このプログラムをサーバー側で実行することで、より効果的になります。 これを行う1つの方法として、プロシージャのプログラムを記述し、 スキーマ定義の一部としてデータベース内に格納します。 この方法は、パフォーマンスが向上するだけでなく、 アプリケーションプログラムがより構造化されます。
Empressは、 標準のディストリビューションに含まれる 多くの関数およびオペレータを提供しています。 (詳しくはEmpress SQL: リファレンスマニュアルの 関数を参照してください。) しかし、データを操作するための追加の機能が必要な場合、 ユーザーの特別な要求を満足させるために ユーザー定義関数機能によってEmpressの機能を 拡張することができます。 パーシステントストアードモジュールは、 EmpressRDBMS へ簡単にユーザー定義関数を組み込むための インターフェイスを提供します。
このセクションでは、 ダイナミックローダブルライブラリおよびスタテックライブラリとして、 パーシステントストアードモジュールにユーザー定義関数(UDF)を 組み込む方法を記述します。
ここでは、ダイナミックローダブルライブラリとして、 パーシステントストアードモジュールにユーザー定義関数(UDF)を 組み込む方法を記述します。
例えば/usr/joeディレクトリに Cプログラムファイルfact.cが置かれていると仮定します。 このファイルには、1つのパラメータを受け取り、その階乗の計算を実行し、 結果を返すfactorial関数が含まれます。
long factorial(long num) { int i; long res=1; for (i=1; i<=num; i++) res *= i; return (res); }
fact.cのコンパイルとfact.dllのシェアードオブジェクトの作成は 以下になります。
emppsmcc -o fact.dll fact.c
ソースファイルに Empress データベースをアクセスするための Empress のルーチンが含まれている場合(例えばmrルーチンのような) 同じコマンドを使用することができます。
以下のステップは、 PSM としてデータベースへ 外部関数factを格納する方法です。 一度、これが完了すれば、 factは、そのデータベースのEmpressの関数となり、 DROP MODULEコマンドが発行されるまでキーワードは有効です。
オペレーティングシステムのプロンプトから Empress 対話型 SQLセッションを呼び出します。
empsql db_name
対話型 SQLセッション内で、以下のSQL コマンドを発行します。
CREATE MODULE module_fact FUNCTION fact (GENERIC INTEGER) RETURNS GENERIC INTEGER EXTERNAL NAME factorial; END MODULE; UPDATE MODULE module_fact FROM "/usr/joe/fact.dll"
これでSQL 文からfact関数を使用することができます。 例えば、
SELECT attr1, attr2, fact(attr2) FROM table_name; SELECT fact(attr1) - fact<attr2) PRINT "Differences" FROM table_name;
ユーザー定義関数は、またWHERE句の条件式中でも使用することができます。
SELECT * FROM table_name WHERE attr1 * 1000 > fact(attr3);
attr1およびattr2、attr3は table_nameテーブルの数値アトリビュートです。
Empressは、いくつかの場所でユーザー定義関数を使用することができます。
1. Empress SQL内の以下の箇所で使用することができます。
これらの用法は、Empressのビルトイン関数と同じです。
2. Empress 4GL内の以下の箇所で使用できます。
用法は、Empressのビルトイン関数および4GLプロシージャ と同じです。
3. Empress Report Writer内の以下の箇所で使用できます。
これらの用法は、Empressのビルトイン関数と同じです。
4. Empress Hypermedia(Internet Application Toolkit) 内の以下の箇所で使用できます。
これらの用法は、Empressのビルトイン関数と同じです。
ユーザー定義関数はまたmrの expression ルーチンによる式の構築を通して C プログラムからも使用することができます。 (詳しくは Empress ホスト言語: C カーネルレベルインターフェイス mr ルーチンを参照してください。)
動的なシェアードライブラリのロードが有効ではないプラットフォームの 場合(例えばQNX)、ユーザーはユーザー定義関数の呼び出しおよび定義 するために静的にPSMをリンクすることができます。
動的なシェアードライブラリのロードが有効なプラットフォームの場合、 静的なパーシステントストアードモジュールのリンクは動作しません。 現在のところ、2,3のプラットフォームのみが 静的なパーシステントストアードモジュールのリンクを使用することが必要です。ここでは、静的なリンク環境上で パーシステントストアードモジュールに ユーザー定義関数(UDF)を 組み込む手順を示します。
サンプルの関数として、階乗計算を実行する関数を /usr/joeというディレクトリに fact.cファイルに記述します。 この関数は、1つのinteger の引数を取り、long integer の値を返します。
long factorial(long num) { int i; long res=1; for (i=1; i<=num; i++) res *= i; return (res); }
fact.cをコンパイルし、fact.aライブラリを作成は、 以下のように行います。
emppsmcc -o fact.a fact.c
以下の手順は、 PSM としてデータベースへ 外部関数factを格納する方法です。 一度、登録すれば、 factは、そのデータベースのEmpressの関数となり、 DROP MODULEコマンドが発行されるまでキーワードは有効です。
対話型 SQLセッション内で、以下のSQL コマンドを発行します。
CREATE MODULE module_fact FUNCTION fact (GENERIC INTEGER) RETURNS GENERIC INTEGER EXTERNAL NAME factorial; END MODULE; UPDATE MODULE module_fact FROM "/usr/joe/fact.a"
動的なローディングの PSM と異なっている点は、 この関数は、実行形式のファイル中に明示的にリンクされるまで 有効ではありません。
Empressシステム管理者から、以下の操作をすることで すべてのユーザーに対して、この関数を有効にすることができます。
最初にライブラリを再構築します。
cd $EMPRESSPATH/rdbms/custom/src/usrfns ./mklib db_name
次に実行形式のファイルを作成します。 例えば、empsqlコマンドに対してfactを有効にする ためには、以下のように行います。
cd $EMPRESSPATH/rdbms/conf_bin ./mkexec empsql
$EMPRESSPATH/rdbms/custom/src/usrfns/mklibコマンドは、 システムライブラリを修正するために使用することに注意してください。 (このコマンドの発行はEmpressシステム管理者であることが必要です。) このコマンドは以下の構文になります。
mklib [db_name ... ]
システムライブラリに追加するモジュールが含まれる データベース名のリストを引数にとります。
これでempsql内で関数factを使用することができます。
オペレーティングシステムから以下のようにEmpress 対話型 SQLセッションを起動します。
empsql db_name
対話型 SQLセッション内で、以下の SQL コマンドが実行できます。
SELECT attr1, attr2, fact(attr2) FROM table_name; SELECT fact(attr1) - fact<attr2) PRINT "Differences" FROM table_name;
また、WHERE句内では以下のように使用します。
SELECT * FROM table_name WHERE attr1 * 1000 > fact(attr3);
attr1およびattr2、attr3は table_nameテーブルのアトリビュートです。
以下はパーシステントストアードモジュール SQL の一覧です。
表 2-1 SQL/PSM コマンド
コマンド | 説明 |
CREATE MODULE | このコマンドは、データ辞書へモジュール定義を格納するために使用されます。 これは、ユーザー定義の関数、オペレーション、プロシージャ、または集計関数の ためのエントリポイントを作成します。 また、モジュール定義をロード可能なシェアードライブラリモジュールとリンクするために UPDATE MODULEコマンドは必要です。 |
UPDATE MODULE | このコマンドは、 モジュール定義をロード可能なシェアードライブラリモジュールとリンクするために 使用されます。 |
DROP MODULE | このコマンドは、データベースのデータ辞書からモジュール定義を削除します。 モジュールとして定義されていた、関数、およびプロシージャ、オペレータは Empressから認識されなくなります。 |
DISPLAY MODULE | このコマンドは、データベースのデータ辞書からモジュール定義を取得し、表示します。 |
CREATE TRIGGER | このコマンドは、データ辞書にトリガー定義を登録するために使用されます。 定義行うとトリガーは自動的に有効になります。 ALTER TABLE コマンドは、トリガーを一時的に無効化するために使用することが できます。(必要なときに有効にすることができます。) |
DROP TRIGGER | このコマンドは、データ辞書からトリガーの定義を削除するために使用されます。 |
ALTER TABLE | このコマンドは、トリガーの動作を有効にするかあるいは無効にするかを指定するために 使用します。また、トリガーの優先順位を変更にも使用されます。 |
CREATE COMMENT | このコマンドは、モジュールおよびトリガーのコメントを付けるために使用されます。 |
DROP COMMENT | このコマンドは、モジュールおよびトリガーのコメントを削除するために使用します。 |
これらのコマンドの詳細は A4: SQL リファレンスマニュアルを参照してください。
CREATE MODULEコマンドでユーザー定義関数を宣言する場合、 その関数のパラメータのリストと戻り値のタイプを指定します。 例えば、
DECLARE FUNCTION funct1 (integer, IN float) RETURNS INTEGER EXTERNAL NAME func2 PARAMETER STYLE GENERAL;
パラメータリストは、PARAMETER STYLE GENERALおよび PARAMETER STYLE SQLの2つのスタイルのうち1つを指定することができます。 これらは以下に定義されます。
ユーザー定義関数に渡すこのパラメータのスタイルは、 有効なパラメータタイプのリストが、 明示的に述べられたことと同じ意味になります。 ヌル値は、IN または INOUT モードの パラメータタイプで制限されます。
ユーザー定義関数に渡すこのパラメータのスタイルは、 有効なパラメータタイプのリストが、以下のように定義されたことを 意味します。
最初のnのパラメータは、nの明示的な定義になります。 パラメータモードは、定義したものです。
ルーチンが、関数、オペレータ、および集計関数である場合のみ、 次のパラメータは、返される結果と対応する出力パラメータになります。 パラメータモードはOUTです。
次のnパラメータが(n+1、ルーチンが関数、オペレータか集計関数である場合) 最初のn (またはn+1)のパラメータを伴う 1 : 1 で対応する ヌル指示子パラメータです。 パラメータモードは、最初のnパラメータに定義された値になります。
次のパラメータはINOUTパラメータです。 ルーチンの成功、または失敗を示します。 そのデータタイプは、長さ5文字の文字タイプです。
次はINパラメータです。 これは、実行するための外部ルーチン名を渡すために使用されます。
次のパラメータは、パラメータモードINで、 実行するための特別な外部ルーチン名を渡すために使用されます。
最後のパラメータは、パラメータモードINOUTで、 診断エリアに配置するためのメッセージテキストです。
PARAMETER STYLE GENERAL パラメータスタイルは、 名前によって指示されるため、より一般的で使用することが簡単ですが、 ヌル値を扱えないため、融通性はよくありません。 PARAMETER STYLE SQLは、ユーザーに多くの制御を提供します。
Empressは、パラメータタイプと戻り値のための 以下の3つのグループのデータタイプを認めます。
汎用データタイプは、パラメータによってバインドされないデータを表します。
MS データタイプは、パラメータによってバインドされるデータを表します。 例えば、CHARデータタイプは、lengthとtypeのパラメータを 受け取ります MS データタイプは、特別な汎用データタイプと関連付けらています。 例えば、MS データタイプDATE, TIME および MICROTIMESTAMPは、 以下の C の構造体定義された汎用データgen_dateに基づいています。
typedef struct { long gen_year; /* actual year. e.g. 1999, 2000, etc */ long gen_month; /* 1 to 12. 1 = January, ... */ long gen_day; /* 1 to 31 */ long gen_hour; /* 0 10 23 */ long gen_minute; /* 0 to 59 */ long gen_second; /* 0 to 59 */ long gen_microsec; /* 0 to 999999 */ } gen_date;
この関連付けは、それが基づいている汎用データタイプとして、 同じ処理ルーチンを使用するためにMS データタイプを含む処理を することを認めます。
gen_binaryは、以下の C 構造体で定義されています。
struct gen_binary_segment { long data_len; /* length of binary data in segment */ msbyte* data; /* binary data */ long reserved[6]; }; typedef struct gen_binary_segment gen_binary_segment; struct gen_binary { long total_data_len; /* total length of binary data */ int flags; /* bit arrray of flags */ int num_segments; /* number of segments, typically 1 */ gen_binary_segment segment [1 /* actually: num_segments */]; }; typedef struct gen_binary gen_binary; #define GEN_BINARY_SEGMENTS_ALLOCATED (1 << 0)
この構造体は、$EMPRESSPATH/include/usrfns/generic.hファイルに 定義されています。
注意
total_data_len は、 それぞれのgen_binary_segmentのdata_lenの合計にする 必要があります。
GEN_BINARY_SEGMENTS_ALLOCATEDにフラグ設定されている場合、 セグメントデータは、個別のバッファにアロケートされていることを 意味します。設定されていない場合は、セグメントデータは、解放されない スタテックなバッファを意味します。
C プログラムデータタイプ構成($EMPRESSPATH/include/usrfns.hファイルに 定義されています。)とEmpress ユーザー定義関数 への対応は、以下になります。
表 2-2 汎用データタイプとUDF C プログラムデータタイプの対応
汎用データタイプ | UDF C Program Data Type (戻り値/パラメータモード IN) |
UDF C Program Data Type (パラメータモード OUT/INOUT) |
GENERIC CHAR | char * | char ** |
GENERIC INTEGER | long | long * |
GENERIC DECIMAL | gen_dec | gen_dec * |
GENERIC FLOAT | double | double * |
GENERIC DATE | gen_date | gen_date * |
GENERIC BOOLEAN | int | int * |
GENERIC EXTERNAL | char * | char ** |
GENERIC INTERVAL | gen_date | gen_date * |
GENERIC BINARY | gen_binary * | gen_binary ** |
Table 2-3 MS データタイプとUDF C プログラムデータタイプの対応
MS データタイプ | UDF C プログラムデータタイプ |
CHAR CHARACTER |
char * |
SHORTINTEGER SMALLINT |
short * |
INTEGER INT |
long * |
LONGINTEGER | long * |
DATE | gen_date * |
DOLLAR | gen_dec * |
REAL | float * |
LONGFLOAT DOUBLE PRECISION |
double * |
FLOAT | If decimal places <= 6: float * If decimal places > 6: double * |
TEXT | char ** |
BULK | gen_binary ** |
DECIMAL DEC |
gen_dec * |
TIME | gen_date * |
NLSCHAR NLSCHARACTER |
char * |
NLSTEXT | char ** |
WON | gen_dec * |
MICROTIMESTAMP | gen_date * |
表 2-4 C データタイプ と UDF C プログラムデータタイプ
C データタイプ | UDF C プログラムデータタイプ (戻り値/パラメータモードIN) |
UDF C プログラムデータタイプ (パラメータモード OUT/INOUT) |
"C char" | char | char * |
"C schar" | signed char | signed char * |
"C uchar" | unsigned char | unsigned char * |
"C short" | short | short * |
"C ushort" | unsigned short | unsigned short * |
"C int" | int | int * |
"C uint" | unsigned int | unsigned int * |
"C long" | long | long * |
"C ulong" | unsigned long | unsigned long * |
"C float" | float | float * |
"C double" | double | double * |
"C string" | char * | char ** |
"C string_static" | char * | char ** |
注意: いくつかのコンパイラでは、 パラメータモードINの"C float"は、 機能しないことがあります。 この場合、パラメータモードINの"C float"の使用を 避けるようにしてください。
このセクションでは、PSMの構文とユーザーエラーメッセージのリストと
簡単な説明を示します。
2.6.1 構文エラーメッセージ
CREATE MODULEコマンドを発行した際にモジュール名が指定されていません。
DROP MODULEコマンドを発行した際にモジュール名が指定されていません。
CREATE MODULE コマンドのLANGUAGEオプションを発行した際に言語が指定されていません。
CREATE MODULEコマンドのLANGUAGEオプションを発行した際に 括弧の後に言語パラメータが指定されていません。
UPDATE MODULEコマンドのFOR system_nameオプションを発行した際に システム名が指定されていません。
UPDATE MODULEコマンドを発行した際に DLL ファイル名が指定されていません。
CREATE MODULEコマンドでのSQL起動ルーチンの宣言で、 正しいルーチン名が指定されていません。
CREATE MODULEコマンドのOPERATORの宣言で、 オペレータのためのオペレータクラスが指定されていません。 (例えばPREFIX, POSTFIX など)
CREATE MODULEコマンドのSQL起動ルーチンの宣言で、 パラメータリストが正しく指定されていません。
CREATE MODULEコマンドの FUNCTION、OPERATORおよび AGGREGATE FUNCTIONの宣言で、RETURNSキーワードの後の 返り値のデータタイプが指定されていません。
CREATE MODULEコマンドの FUNCTION、OPERATORおよび AGGREGATE FUNCTIONの宣言で、返り値のデータタイプが指定されていません。
CREATE MODULEコマンドのSQL起動ルーチンの宣言で、 external指定が見つかりません。(すなわちキーワードEXTERNAL)
CREATE MODULEコマンドのSQL起動ルーチンの宣言で、 EXTERNALキーワードの後の指定が正しくありません。
CREATE MODULEコマンドのSQL起動ルーチンの宣言で、 パラメータスタイル指定が正しくありません。 (PARAMETER STYLE SQL または PARAMETER STYLE GENERALのいずれか)
CREATE MODULEコマンドのALLOCATE WORKSPACEオプションで ワークスペースのサイズなしで指定されています。
CREATE MODULEコマンドのSQL起動ルーチンの宣言で、 正しくない外部名を伴ったBEGIN EXPRESSIONが指定されています。
CREATE MODULEコマンドのAGGREGATE FUNCTIONの宣言で、 BEGIN GROUPの指定がされていません。
CREATE MODULEコマンドのAGGREGATE FUNCTIONの宣言で、 BODY の指定がされていません。
CREATE MODULEコマンドのAGGREGATE FUNCTIONの宣言で、 END GROUPの指定がされていません。
トリガーの指定がなしに CREATE TRIGGERコマンドの発行されました。
トリガー名の指定がなしに トリガーのプロパティを変更するためのALTER TABLEコマンドの発行されました。
トリガーイベントのBEFOREまたはAFTERの指定なしに CREATE TRIGGERコマンドが発行されました。
トリガーイベントの指定なしに CREATE TRIGGERコマンドが発行されました。 (DELETE, INSERT または UPDATE)
トリガープロシージャ名の指定なしに CREATE TRIGGERコマンドが発行されました。 (EXECUTE trigger_procedure_name).
EXECUTE指定なしに CREATE TRIGGERコマンドが発行されました。
プライオリティ指定なしにALTER TABLEコマンドの PRIORITYオプションが指定されています。
トリガーのプライオリティを変更するための ALTER TABLEコマンドの発行されましたが、 PRIORITYキーワードが見つかりません。
CREATE MODULEコマンドの発行で、 EXTERNAL指定が間違っています。
CREATE MODULEコマンドの発行で、 END MODULEのキーワードMODULEが 見つかりません。
CREATE MODULEコマンドのAGGREGATE FUNCTIONの宣言で、 AGGREGATEの後のキーワードFUNCTIONが見つかりません。
CREATE MODULEのALLOCATE WORKSPACEオプションの指定で、 ALLOCATEの後のキーワードWORKSPACEが見つかりません。
CREATE TRIGGERのFOR EACH ROWオプションの指定で、 FORの後のキーワードEACHが見つかりません。
CREATE TRIGGERのFOR EACH ROWオプションの指定で、 EACHの後のキーワードROWが見つかりません。
ENABLE または DISABLE ALL TRIGGERS のALTER TABLEコマンドの発行で、 ALLの後のキーワードTRIGGERSが見つかりません。
CREATE MODULEモジュールコマンドの FUNCTION, OPERATORおよびAGGREGATE FUNCTION にパラメータモードOUTを伴い宣言されましたが、 このモードはPROCEDUREのみ有効です。
CREATE MODULEモジュールコマンドの FUNCTION, OPERATORおよびAGGREGATE FUNCTION にパラメータモードINOUTを伴い宣言されましたが、 このモードはPROCEDUREのみ有効です。
CREATE MODULEコマンドの数値パラメータを伴った infix オペレータ(OPERATOR INFIX precedence)の宣言で、 優先順位が範囲以外(1..6)です。
boolean パラメータを伴った infix オペレータ(OPERATOR INFIX precedence)の宣言で、 優先順位が範囲以外(1..2)です。
SQL起動ルーチンまたは言語指定なしで CREATE MODULEコマンドの発行されました。
prefix および postfix オペレータは、1つのパラメータだけが許されます。
infix(挿入辞)、comparison(比較)、equality (等価) のオペレータは、 2つのパラメータのみ許されます。
同じモジュール内の他のルーチンとして、 同じ外部名を伴った SQL 起動ルーチンが宣言されました。
存在しないファイルの使用を試みました。
不適切なパラメータが指定されました。
不正なモジュール名が指定されました。
不適切なルーチン名が指定されました。
不適切なパラメータが指定されました。
不適切なパラメータ番号が指定されました。
SQL起動ルーチンに無効な外部名が指定されました。
不正なトリガー名が指定されました。
存在しているモジュールと重複した名前のモジュールを作成しようとしました。
存在しないモジュールを使用しようとしました。
同じルーチン内の他のパラメータとして、 同じ名前を持つパラメータを指定しました。
存在しないパラメータを使用しようとしました。
このパラメータデータタイプは boolean でなければなりません。
パラメータデータは、数値データでなければなりません。
返り値のデータタイプは、booleanでなければなりません。
返り値のデータタイプは、数値データでなければなりません。
boolean データタイプを返す集計関数が宣言されました。
異なるルーチンクラスで同じ名前の重複したルーチンが宣言されました。
オペレータのパラメータが非常に多く指定されました。
既に存在しているトリガーと同じ名前のトリガーを作成しようとしました。
存在しないトリガーを使用しようとしました。
存在しているルーチンと同じ名前のルーチンの宣言をしようとしました。
存在しないルーチンを使用しようとしました。
mrefunc()関数を呼び出したとき、 無効なルーチンあるいは不適切なパラメータが見つかりました。