我目前正在从事一个项目,该项目涉及用 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
此外,当我执行所有操作时,我以授权用户身份登录。
作为一个附加的实验,我ScalarUDF
从 DB2 的样本中创建了这个函数。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
谢谢你。