Symfoware Server アプリケーション開発ガイド(埋込みSQL編) - FUJITSU -
目次 索引 前ページ次ページ

第4章 ルーチンを利用するアプリケーションの作成> 4.2 ファンクションルーチンを利用する場合> 4.2.4 ライブラリの作成

4.2.4.1 ライブラリとして登録するCプログラムの作成方法

ここでは、ファンクションルーチンのライブラリとして利用者が登録する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文を記述することはできません。

[表:使用可能なC言語の標準関]

関数の種別

インクルードファイル

関数名

使用の可否

文字列関数

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,
printf,fprintf,scanf,fscanf,sscanf,fflush,
fopen,fwrite,fread,fclose,fseek,feof,ferror

×

低水準入出力
関数

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, ...

×

○:使用可能

×:使用不可


目次 索引 前ページ次ページ

All Rights Reserved, Copyright(C) 富士通株式会社 2007-2008