Symfoware Server アプリケーション開発ガイド(埋込みSQL編) - FUJITSU - |
目次 索引 |
第4章 ルーチンを利用するアプリケーションの作成 | > 4.2 ファンクションルーチンを利用する場合 | > 4.2.4 ライブラリの作成 |
ここでは、ファンクションルーチンのライブラリとして利用者が登録するCプログラムの作成方法について、以下を説明します。
Cプログラムの関数インタフェース
ファンクションルーチンのライブラリで使用可能な標準関数
Cプログラムの関数の引数は、以下の順に2つの引数を固定で指定します。
1) 引数データのポインタリスト
2) 結果データのポインタリスト
例1
ファンクションルーチンのパラメタが3個の場合の関数宣言の例
/* 引数データのポインタリスト */ typedef struct in_ptr_list_tag { void *ptr[6]; /*ファンクションのパラメタの個数×2*/ } in_ptr_list_t; /* 結果データのポインタリスト */ typedef struct out_ptr_list_tag { void *ptr[2]; /*返却データと標識データの格納先*/ } out_ptr_list_t; void UserFunc001(in_ptr_list_t *in_p, /* 引数データのポインタリスト */ out_ptr_list_t *out_p) /* 結果データのポインタリスト */ { ・・・
例2
ファンクションルーチンのパラメタが10個の場合の関数宣言の例
/* 引数データのポインタリスト */ typedef struct in_ptr_list_tag { void *ptr[20]; /* ファンクションのパラメタの個数×2 */ } in_ptr_list_t; /* 結果データのポインタリスト */ typedef struct out_ptr_list_tag { void *ptr[2]; /* 返却データと標識データの格納先 */ } out_ptr_list_t; void UserFunc002(in_ptr_list_t *in_p, /* 引数データのポインタリスト */ out_ptr_list_t *out_p) /* 結果データのポインタリスト */ { ・・・
ファンクションルーチンの入力パラメタをCプログラムの関数が受け取るには、引数データのポインタリストを利用します。引数データのポインタリストは、CREATE FUNCTION文のパラメタ宣言順に、入力データの格納先アドレスおよび対応する標識データの格納先アドレスが並びます。
入力データがNULL値でない場合は、標識データに0が通知されます。入力データがNULL値の場合は、標識データに負の値が通知され、入力データの値は保証されません。
入力データは、ファンクションルーチンのパラメタ宣言で指定したデータ型と対応するC言語のデータ型で表現されます。また、標識データは2バイト整数型で表現されます。
パラメタのデータ型とC言語のデータ型の対応については、“ファンクションルーチンのパラメタのデータ型と対応するデータ形式”を参照してください。
ファンクションルーチンの結果としてCプログラムの関数から返却する結果データは、結果データのポインタリストを利用します。結果データのポインタリストには、結果データの格納先アドレスと結果の標識データの格納先アドレスが設定されています。
Cプログラムの関数は、処理終了までに結果データを指定先の領域に格納する必要があります。結果データは、CREATE FUNCTION文で指定した戻りデータ型に対応した形式で設定してください。標識データは、2バイト整数型で0を設定してください。結果をNULL値として返却する場合は、標識データに負の値を設定してください。標識データが負の値の場合は、結果データは返却されません。
パラメタのデータ型とC言語のデータ型の対応については、“ファンクションルーチンのパラメタのデータ型と対応するデータ形式”を参照してください。
ファンクションルーチンのパラメタとCプログラムの関数の引数のインタフェースについて、具体的な使用例を以下に示します。
例
ファンクションルーチン“USERFUNC001”の定義文
CREATE FUNCTION SCM1.USERFUNC001(IN CHAR(20), IN INTEGER, IN INTEGER ) RETURNS VARCHAR(60) LANGUAGE C NAME 'UserFunc001' LIBRARY '/usr/local/lib/libuserfunc001.so';
例
ファンクションルーチン“USERFUNC001”のCプログラム(プログラム名:userfunc001.c)の作成例
/* compile: cc -G -o libuserfunc001.so userfunc001.c */ /* DEBUG : cc -G -o libuserfunc001.so userfunc001.c -DDEBUG */ #include <stdio.h> #include <string.h> /* 引数データのポインタリスト */ typedef struct in_ptr_list_tag { void *ptr[6]; /* ファンクションのパラメタの個数×2 */ } in_ptr_list_t; /* 結果データのポインタリスト */ typedef struct out_ptr_list_tag { void *ptr[2]; /* 返却データと標識データの格納先 */ } out_ptr_list_t; extern void UserFunc001(in_ptr_list_t *in_p, out_ptr_list_t *out_p) { char *c1_data_p, *ret_data_p; int *c2_data_p, *c3_data_p; short *c1_ind_p, *c2_ind_p, *c3_ind_p, *ret_ind_p; char data1[21], ret[61]; int data2, data3; short ind1, ind2, ind3, ret_size; #ifdef DEBUG FILE *fp; #endif #ifdef DEBUG fp = fopen("/usr/local/work/func001.log", "w"); if (fp == NULL) return; fprintf(fp, "UserFunc001: start\n"); fflush(fp); #endif /* 入力情報 */ c1_data_p = (char *)in_p->ptr[0]; /* 引数1のデータ */ c1_ind_p = (short *)in_p->ptr[1]; /* 引数1の標識データ */ c2_data_p = (int *)in_p->ptr[2]; /* 引数2のデータ */ c2_ind_p = (short *)in_p->ptr[3]; /* 引数2の標識データ */ c3_data_p = (int *)in_p->ptr[4]; /* 引数3のデータ */ c3_ind_p = (short *)in_p->ptr[5]; /* 引数3の標識データ */ /* 出力情報 */ ret_data_p = (char *)out_p->ptr[0]; /* 結果のデータ格納先 */ ret_ind_p = (short *)out_p->ptr[1]; /* 結果の標識データ〃 */ /* 入力データを自動変数に取り出す */ memcpy(data1, c1_data_p, 20); /* 文字列として扱うため終端にNULL文字設定 */ data1[20] = '\0'; data2 = *c2_data_p; data3 = *c3_data_p; ind1 = *c1_ind_p; ind2 = *c2_ind_p; ind3 = *c3_ind_p; #ifdef DEBUG fprintf(fp, "UserFunc001: para1=%s, para2=%ld, para3=%ld\n", data1, data2, data3); fflush(fp); #endif /* 結果データの作成 */ sprintf(ret, "NAME=%20s, CODE=%ld, AGE=%ld", data1, data2, data3); ret_size = strlen(ret); #ifdef DEBUG fprintf(fp, "UserFunc001: ret=%s\n", ret); fflush(fp); #endif /* 指定された結果データの格納先に結果データを書き込む */ memcpy(ret_data_p, &ret_size, sizeof(short)); memcpy((ret_data_p + sizeof(short)), ret, ret_size); *ret_ind_p = 0; #ifdef DEBUG fprintf(fp, "UserFunc001: end\n"); fflush(fp); fclose(fp); #endif return; }
上記の例では、#ifdef DEBUG〜#endif間にデバッグ用の処理を追加しています。後述のテストドライバと組み合わせることでSymfoware/RDBを介さない単体テストを行うことができます。ファンクションルーチンではfprintf関数やいくつかの関数の使用を制限していますが、単体テストであれば、上記のように使用することができます。コンパイル時にデファイン値DEBUGを指定してください。Symfoware/RDBを介して実行するときは、DEBUGを外して再コンパイルしてください。
例
ファンクションルーチン“USERFUNC001”の定義文
CREATE FUNCTION SCM1.USERFUNC001(IN CHAR(20), IN INTEGER, IN INTEGER ) RETURNS VARCHAR(60) LANGUAGE C NAME 'UserFunc001' LIBRARY 'D:\FORSYMFO\FUNCLIB\USERFUNC001.DLL';
例
ファンクションルーチン“USERFUNC001”のCプログラムの作成例
#include <stdio.h> #include <string.h> /* 引数データのポインタリスト */ typedef struct in_ptr_list_tag { void *ptr[6]; /* ファンクションのパラメタの個数×2 */ } in_ptr_list_t; /* 結果データのポインタリスト */ typedef struct out_ptr_list_tag { void *ptr[2]; /* 返却データと標識データの格納先 */ } out_ptr_list_t; extern __declspec(dllexport) void UserFunc001(in_ptr_list_t *in_p, out_ptr_list_t *out_p) { char *c1_data_p, *ret_data_p; int *c2_data_p, *c3_data_p; short *c1_ind_p, *c2_ind_p, *c3_ind_p, *ret_ind_p; char data1[21], ret[61]; int data2, data3; short ind1, ind2, ind3, ret_size; #ifdef DEBUG FILE *fp; #endif #ifdef DEBUG fp = fopen("D:\\FORSYMFO\\WORK\\FUNC001.LOG", "w"); if (fp == NULL) return; fprintf(fp, "UserFunc001: start\n"); fflush(fp); #endif /* 入力情報 */ c1_data_p = (char *)in_p->ptr[0]; /* 引数1のデータ */ c1_ind_p = (short *)in_p->ptr[1]; /* 引数1の標識データ */ c2_data_p = (int *)in_p->ptr[2]; /* 引数2のデータ */ c2_ind_p = (short *)in_p->ptr[3]; /* 引数2の標識データ */ c3_data_p = (int *)in_p->ptr[4]; /* 引数3のデータ */ c3_ind_p = (short *)in_p->ptr[5]; /* 引数3の標識データ */ /* 出力情報 */ ret_data_p = (char *)out_p->ptr[0]; /* 結果のデータ格納先 */ ret_ind_p = (short *)out_p->ptr[1]; /* 結果の標識データ〃 */ /* 入力データを自動変数に取り出す */ memcpy(data1, c1_data_p, 20); /* 文字列として扱うため終端にNULL文字設定 */ data1[20] = '\0'; data2 = *c2_data_p; data3 = *c3_data_p; ind1 = *c1_ind_p; ind2 = *c2_ind_p; ind3 = *c3_ind_p; #ifdef DEBUG fprintf(fp, "UserFunc001: para1=%s, para2=%ld, para3=%ld\n", data1, data2, data3); fflush(fp); #endif /* 結果データの作成 */ sprintf(ret, "NAME=%20s, CODE=%ld, AGE=%ld", data1, data2, data3); ret_size = strlen(ret); #ifdef DEBUG fprintf(fp, "UserFunc001: ret=%s\n", ret); fflush(fp); #endif /* 指定された結果データの格納先に結果データを書き込む */ memcpy(ret_data_p, &ret_size, sizeof(short)); memcpy((ret_data_p + sizeof(short)), ret, ret_size); *ret_ind_p = 0; #ifdef DEBUG fprintf(fp, "UserFunc001: end\n"); fflush(fp); fclose(fp); #endif return; }
上記の例では、#ifdef DEBUG〜#endif間にデバッグ用の処理を追加しています。後述のテストドライバと組み合わせることでSymfoware/RDBを介さない単体テストを行うことができます。ファンクションルーチンではfprintf関数やいくつかの関数の使用を制限していますが、単体テストであれば、上記のように使用することができます。コンパイル時にデファイン値DEBUGを指定してください。Symfoware/RDBを介して実行するときは、DEBUGを外して再コンパイルしてください。
ファンクションルーチンのライブラリで使用可能なC言語の標準関数について、以下に示します。使用不可の関数を使用した際の動作は保証されません。
また、プログラム中にSQL文を記述することはできません。
関数の種別 |
インクルードファイル |
関数名 |
使用の可否 |
---|---|---|---|
文字列関数 |
string.h |
strcat,strncat,strcmp,strncmp,strcpy,strncpy,strlen |
○ |
stdlib.h |
atof,atoi,atol |
○ |
|
算術関数 |
stdlib.h |
abs,rand,srand |
○ |
math.h |
acos,asin,atan,cos,exp,log,sin,tan,sqrt |
○ |
|
メモリ制御 |
stdlib.h |
malloc,free,realloc |
○ |
時間関数 |
time.h |
asctime,ctime,gmtime,localtime,time |
○ |
標準入出力 |
stdio.h |
sprintf |
○ |
fgets,gets,fputs,puts,fgetc,getc,fputc,putc, |
× |
||
低水準入出力 |
fcntl.h |
open,creat |
× |
unistd.h |
close,lseek,read,write |
× |
|
ファイル操作 |
unistd.h |
chdir,rmdir |
× |
stdio.h |
rename |
× |
|
プロセス制御 |
stdlib.h |
abort |
× |
unistd.h |
fork,execl,execv,execle,execve,execvp |
× |
|
signal.h |
signal |
× |
|
wait.h |
wait |
× |
|
その他の関数 |
*.h |
getenv,putenv, ... |
× |
○:使用可能
×:使用不可
目次 索引 |