我目前正在开发一个涉及在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
身份登录。
作为一个增加的实验,我从DB2的示例中创建了ScalarUDF
函数。 ScalarUDF的sql
创建脚本与create-udf.sql
完全相同,只更改了名称。在~/sqllib/function/
文件夹中创建的可执行文件为udfsrv
。
当我尝试执行scalarudf
时,它完美无缺。我仍然不明白为什么受防护的用户能够执行scalarudf
但他无法执行gatherdistinctvalues
。
我已发布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
谢谢。
答案 0 :(得分: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.
由于您似乎没有使用任何额外的库,我会检查目标文件位数与实例位数。
答案 1 :(得分:0)
问题是DB2的bldrtn
脚本无法处理从多个文件中使用代码的情况。此外,似乎添加用于在我的文件的开头定义哈希表和哈希函数的代码不起作用。
创建两个不同的文件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