| Symfoware(R) Server RDBユーザーズガイド 応用プログラム開発編 - FUJITSU - |
目次
索引
![]()
|
第3章 ルーチンを利用する応用プログラムの作成方法
3.2 ファンクションルーチンを利用する場合
3.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文のパラメタ宣言順に、入力データの格納先アドレスおよび対応する標識データの格納先アドレスが並びます。
入力データがナル値でない場合は、標識データに0が通知されます。入力データがナル値の場合は、標識データに負の値が通知され、入力データの値は保証されません。
入力データは、ファンクションルーチンのパラメタ宣言で指定したデータ型と対応するC言語のデータ型で表現されます。また、標識データは2バイト整数型で表現されます。
パラメタのデータ型とC言語のデータ型の対応については、“ファンクションルーチンのパラメタのデータ型と対応するデータ形式”を参照してください。

ファンクションルーチンの結果としてCプログラムの関数から返却する結果データは、結果データのポインタリストを利用します。結果データのポインタリストには、結果データの格納先アドレスと結果の標識データの格納先アドレスが設定されています。
Cプログラムの関数は、処理終了までに結果データを指定先の領域に格納する必要があります。結果データは、CREATE FUNCTION文で指定した戻りデータ型に対応した形式で設定してください。標識データは、2バイト整数型で0を設定してください。結果をナル値として返却する場合は、標識データに負の値を設定してください。標識データが負の値の場合は、結果データは返却されません。
パラメタのデータ型と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);
/* 文字列として扱うため終端にナル文字設定 */
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);
/* 文字列として扱うため終端にナル文字設定 */
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, ... |
× |
○:使用可能
×:使用不可
目次
索引
![]()
|