1

私は現在、C で IBM DB2 v10 用の UDF を開発するプロジェクトに取り組んでいます。私の C コードはすべてrcdudf.c、次のような単一のファイルにバンドルされています。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sqlca.h>
#include <sqludf.h>

typedef unsigned int (*hash_function)(char*, unsigned int len);

unsigned int FNVHash (char* str, unsigned int len);

typedef struct hash_record 
{
    void* value;
    struct hash_record* next;
}hash_record;

typedef struct hash_bucket
{
    void* key;
    hash_record* head_record;
}hash_bucket;

typedef struct hash_table 
{
    int bucket_num;
    hash_bucket** hash_entry;
}hash_table;

int hash_init(hash_table** h_table, int bucket_num);

int hash_destroy(hash_table** h_table);

int hash_contains_key(hash_table** h_table, void* key, unsigned int key_len);

void hash_put_value(hash_table** h_table, void* key, unsigned int key_len, void* value, unsigned int value_len);

void hash_remove_value(hash_table** h_table, void* key, unsigned int key_len, void* value, unsigned int value_len);

void hash_print_contents(hash_table** h_table);

int hash_calculate_data_size(hash_table** h_table);

char* hash_concatenate_data_to_char_array(hash_table** h_table);


struct SCRATCHDATA 
{
    int num_buckets;
    hash_table *h_table;
};

#ifdef __cplusplus
extern "C"
#endif
void SQL_API_FN GatherDistinctValues( SQLUDF_VARCHAR *inputAttrKey, SQLUDF_VARCHAR *inputAttrValue, 
            SQLUDF_INTEGER *out, SQLUDF_SMALLINT *inputAttrKeyNullInd, SQLUDF_SMALLINT *inputAttrValueNullInd, 
        SQLUDF_SMALLINT *outInd, SQLUDF_TRAIL_ARGS_ALL)
{
    struct SCRATCHDATA *sp;
    sp = (struct SCRATCHDATA *) SQLUDF_SCRAT->data;
    switch (SQLUDF_CALLT)
    {
        case SQLUDF_FIRST_CALL:
            hash_init(&(sp->h_table), 7);
            break;
        case SQLUDF_NORMAL_CALL:
            if( *inputAttrKeyNullInd == 0 && *inputAttrValueNullInd  == 0 )
            {
                /**
                 * If the provided value is not NULL and it is not contained in the 
                 * Global hash Table, it is going to be added. Otherwise, 
                 * nothing is done (it already exists).
                 */
                if( hash_contains_key(&(sp->h_table), (void*) inputAttrKey, strlen(inputAttrKey)) == 0 )
                {
                    hash_put_value(&(sp->h_table), (void*) inputAttrKey, strlen(inputAttrKey), 
                            (void*) inputAttrValue, strlen(inputAttrValue));
                }
            }
            break;
        case SQLUDF_FINAL_CALL:
            break;
    }
    *out = 0;
    *outInd = 0;
    return;
}

ファイルの残りの部分には、定義されたメソッドの本体が存在します。この UDF を DB2 に「インストール」するために、提供されたスクリプトbldrtnを次のように実行します。

~$./bldrtn rcdudf

~/sqllib/function実行可能ファイルはディレクトリ内に保存されます。次に、DB2 で次のスクリプトを実行します。

CREATE OR REPLACE FUNCTION GatherDistinctVal( VARCHAR(255), VARCHAR(255) )
    RETURNS INTEGER 
    EXTERNAL NAME 'rcdudf!GatherDistinctValues' 
    NOT FENCED 
    CALLED ON NULL INPUT 
    NOT VARIANT 
    NO SQL 
    PARAMETER STYLE SQL 
    LANGUAGE C 
    NO EXTERNAL ACTION;

コマンドを発行する~$db2 -tvsf create-udf.sql。その後、次のように DB2 の Sample データベースで関数を呼び出そうとします。

~$ db2 "select gatherdistinctval('job',job) from employee"

1          
-----------
SQL0444N  Routine "*TINCTVAL" (specific name "SQL140520113052600") is 
implemented with code in library or path "...function/rcdudf", function 
"GatherDistinctValues" which cannot be accessed.  Reason code: "5".  
SQLSTATE=42724

前述の関数を定義するとFENCED、次のエラーが表示されます。

~$ db2 "select GatherDistinctVal('Job',job) from Employee"

1          
-----------
SQL1646N  A routine failed because the fenced user ID cannot access required 
files in the sqllib directory or other instance or database directories.

私は何を間違っていますか?rcdudfファイルが適切なディレクトリに存在することは確かです。また、create-udf.sqlスクリプトを実行すると、DB2 から成功メッセージが表示されます。

実行する~$ls -l ~/sqllib/function/と、次のようになります。

lrwxrwxrwx 1 root     db2iadm1    36 May 15 17:54 db2psmds -> /opt/ibm/db2/V10.1/function/db2psmds
drwxrwsr-t 2 db2inst1 db2iadm1  4096 May 15 17:54 db2rdf
lrwxrwxrwx 1 root     db2iadm1    35 May 15 17:54 db2rtsc -> /opt/ibm/db2/V10.1/function/db2rtsc
lrwxrwxrwx 1 root     db2iadm1    34 May 15 17:54 fpeevm -> /opt/ibm/db2/V10.1/function/fpeevm
-rw-r--r-- 1 db2inst1 db2iadm1  3256 May 20 17:58 GeneralHashFunctions.o
-rw-r--r-- 1 db2inst1 db2iadm1 11688 May 20 17:58 hash_table.o
-rwxr-xr-x 1 db2inst1 db2iadm1 17090 May 21 08:39 hopeless
drwxrwxr-x 3 db2inst1 db2iadm1  4096 May 14 16:07 jar
lrwxrwxrwx 1 root     db2iadm1    37 May 15 17:54 libdb2u.a -> /opt/ibm/db2/V10.1/function/libdb2u.a
-rwxr-xr-x 1 db2inst1 db2iadm1 17144 May 20 18:08 rcdudf
drwxrwsr-t 2 db2inst1 db2iadm1  4096 May  8 21:24 routine
lrwxrwxrwx 1 root     db2iadm1    33 May 15 17:54 tblpd -> /opt/ibm/db2/V10.1/function/tblpd
-rwxr-xr-x 1 db2inst1 db2iadm1 22280 May 20 16:27 testudf
-rwxr-xr-x 1 db2inst1 db2iadm1 34510 May 20 09:49 udfcli
-rwxr-xr-x 1 db2inst1 db2iadm1 13009 May 20 10:42 udfsrv
drwxrwsr-t 2 db2inst1 db2iadm1  4096 May 15 17:54 unfenced

ご覧のとおり、rcdudf 実行可能ファイルがそこにあり、読み取り/実行権限を持っています。db2inst1また、すべての操作を実行するときに、許可されたユーザーとしてログインしています。

追加の実験として、ScalarUDFDB2 のサンプルから関数を作成します。ScalarUDFの作成スクリプトは、名前が変わっただけでsqlまったく同じです。フォルダcreate-udf.sqlに作成される実行ファイルは. 実行しようとすると、完全に機能します。フェンシングされたユーザーが実行できるのに実行できない理由はまだわかりません。~/sqllib/function/udfsrvscalarudfscalarudfgatherdistinctvalues

db2 dbm get cfg今後の参考のために、次の結果を掲載しました。

~$ db2 get dbm cfg

      Database Manager Configuration

Node type = Enterprise Server Edition with local and remote clients

Database manager configuration release level            = 0x0f00

CPU speed (millisec/instruction)             (CPUSPEED) = 2.637255e-07
Communications bandwidth (MB/sec)      (COMM_BANDWIDTH) = 1.000000e+02

Max number of concurrently active databases     (NUMDB) = 32
Federated Database System Support           (FEDERATED) = NO
Transaction processor monitor name        (TP_MON_NAME) = 

Default charge-back account           (DFT_ACCOUNT_STR) = 

Java Development Kit installation path       (JDK_PATH) = /opt/ibm/java-x86_64-71/

Database monitor heap size (4KB)          (MON_HEAP_SZ) = AUTOMATIC(90)
Java Virtual Machine heap size (4KB)     (JAVA_HEAP_SZ) = 2048
Audit buffer size (4KB)                  (AUDIT_BUF_SZ) = 0
Size of instance shared memory (4KB)  (INSTANCE_MEMORY) = AUTOMATIC(807642)
Instance memory for restart light (%) (RSTRT_LIGHT_MEM) = AUTOMATIC(10)
Agent stack size                       (AGENT_STACK_SZ) = 1024
Sort heap threshold (4KB)                  (SHEAPTHRES) = 0

Directory cache support                     (DIR_CACHE) = YES

Application support layer heap size (4KB)   (ASLHEAPSZ) = 15
Max requester I/O block size (bytes)         (RQRIOBLK) = 32767
Workload impact by throttled utilities(UTIL_IMPACT_LIM) = 10

Priority of agents                           (AGENTPRI) = SYSTEM
Agent pool size                        (NUM_POOLAGENTS) = AUTOMATIC(100)
Initial number of agents in pool       (NUM_INITAGENTS) = 0
Max number of coordinating agents     (MAX_COORDAGENTS) = AUTOMATIC(200)
Max number of client connections      (MAX_CONNECTIONS) = AUTOMATIC(MAX_COORDAGENTS)

Keep fenced process                        (KEEPFENCED) = YES
Number of pooled fenced processes         (FENCED_POOL) = AUTOMATIC(MAX_COORDAGENTS)
Initial number of fenced processes     (NUM_INITFENCED) = 0

Index re-creation time and redo index build  (INDEXREC) = RESTART

Transaction manager database name         (TM_DATABASE) = 1ST_CONN
Transaction resync interval (sec)     (RESYNC_INTERVAL) = 180

ありがとうございました。

4

2 に答える 2

1

これが答えではないことはわかっていますが、コメントするには大きすぎます。

SQL0444N RC 5 は、次のいずれかを意味します。

     There is insufficient memory to load the library containing the
     function or one or more symbols could not be resolved. This
     reason code indicates one of the following situations:
     1. One or more symbols might not have been resolved. The
        routine library might be dependent on a shared library that
        cannot be located (using the concatenation of directories
        specified in the LIBPATH environment variable in UNIX-based
        systems, the PATH environment variable in INTEL systems).
     2. The routine has a 64-bit library which is not supported
        within a 32-bit DB2 instance, or, the routine has a 32-bit
        library or DLL within a 64-bit DB2 instance that is
        incompatible with the routine definition.
     3. There was insufficient memory to load the library containing
        the function.

追加のライブラリを使用していないように見えるので、オブジェクト ファイルのビット数とインスタンスのビット数を確認します。

于 2014-05-21T12:22:58.343 に答える
0

問題はbldrtn、DB2 のスクリプトが、コードが複数のファイルから使用されるケースを処理しないことでした。また、ファイルの先頭にハッシュ テーブルとハッシュ関数を定義するためのコードを追加しても機能しなかったようです。

2 つの異なるファイルhash_table.hを作成hash_table.cし、そこに私の構造のコードを入力します。また、ファイルに の参照を追加しhash_table.hますrcdudf.c。その後bldrtn、各ソース ファイルのオブジェクト ファイルを最初に作成し、次にそれらをリンクするようにスクリプトを変更します。

詳細には、bldrtnファイルには次の変更されたコード行が含まれます。

$CC $EXTRA_C_FLAGS  -I$DB2PATH/include -c hash_table.c -D_REENTRANT
$CC $EXTRA_C_FLAGS  -I$DB2PATH/include -c GeneralHashFunctions.c -D_REENTRANT
$CC $EXTRA_C_FLAGS  -I$DB2PATH/include -c rcdudf.c -D_REENTRANT

$CC $LINK_FLAGS -o rcdudf rcdudf.o GeneralHashFunctions.o hash_table.o $EXTRA_LFLAG -L$DB2PATH/$LIB -ldb2 -lpthread

rm -f $DB2PATH/function/hopeless
cp hopeless $DB2PATH/function

このようにして、私のコードはバンドルされrcdudf、DB2 はそれを完全に実行できます。

注: 新しい UDF が登録されるたびに、DB2 を再始動する必要があるようです。

于 2014-05-21T17:48:50.753 に答える