2024年3月17日发(作者:)
关于oracle调用C外部函数
前端时间有一个关于在oracle中使用外部C函数的要求,在实现过程遇到了许多问题。
现在将这些问题总结一下,希望能给遇到同样问题的xdjm一点帮助!
实现过程如下
首先oracle环境配置:
需要在oracle主机服务器上修改如下文件
文件中添加
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY=EXTPROC))
)
(ENVS = EXTPROC_DLLS=ANY)
样例如下:
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = XY10000)(PORT = 1521))
)
[color=red] (ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY=EXTPROC))
)[/color]
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = PLSExtProc)
(ORACLE_HOME = D:oracleora92)
(ENVS = EXTPROC_DLLS=ANY)
[color=red] (PROGRAM = extproc)[/color]
)
(SID_DESC =
(GLOBAL_DBNAME = mydb)
(ORACLE_HOME = D:oracleora92)
(SID_NAME = mydb)
)
)
文件中添加
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY=EXTPROC))
)
EXTPROC_CONNECTION_DATA=
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY=EXTPROC))
)
(CONNECT_DATA =
(SID = PLSExtProc)
(PRESENTATION = RO)
)
)
样例如下:
MYDB =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = XY10000)(PORT = 1521))
)
[color=red] (ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY=EXTPROC))
)[/color]
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = mydb)
)
)
[color=red]EXTPROC_CONNECTION_DATA=
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY=EXTPROC))
)
(CONNECT_DATA =
(SID = PLSExtProc)
(PRESENTATION = RO)
)
)
[/color]
两个文件添加过程中,要保证KEY值是一样的!
修改完成后需要重启监听,在命令行输入Lsnrctl stop , Lsnrctl start .
如果在中没有添加 (ENVS = EXTPROC_DLLS=ANY) , 在使用C外部函
数时可能会出现如下错误:
ORA-28595: Extproc agent : Invalid DLL Path.
许多文档中提到如果中出现 default_domain
中的
EXTPROC_CONNECTION_DATA后添加.world ,即:
EXTPROC_CONNECTION_DATA[color=red].world[/color]=
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY=EXTPROC))
)
(CONNECT_DATA =
(SID = PLSExtProc)
world = ,需要在
(PRESENTATION = RO)
)
)
可是我在windows,AIX,Linux平台下都测试过,都存在
default_domain = world,而我在
中都没有添加.world,使用C外部函数都没有出错,不知道这个修改是
不是必须的。
将C程序生成动态库:
一个很简单的C程序例子 test.c ,我们要使用OUT这个函数
#include
OUT(int a)
{ int b=0;
b=a*30;
return b;
}
main()
{
printf("hello world!n");
}
需要将这个程序编译成动态库,windows下为.dll文件,AIX、LINUX下为.so文件。
windows平台下使用的VC 进行编译:
C:msdevVC98Bincl -I D:oracleora92ociinclude -I
C:msdevVC98include -I C:msdevVC98mfcinclude -D_DLL -D_MT /LD -Zi
test.c /link D: C:
C: C: /nod:libcmt
/DLL [color=red]/EXPORT:OUT[/color]
生成
注意后面要加上 /EXPORT:OUT(针对与windows) ,其中OUT就是需要使用的C函数
名。
如果不添加,在使用该函数时有可能出现如下错误:
ORA-06521: PL/SQL: 映射函数时出错
ORA-06522: Unable to load symbol from DLL
AIX平台下使用cc进行编译:
cc -G -q64 -o test.c
生成
-q64是针对oracle是否是64位 ,用sqlplus就登陆可以看到 ,如下:
SQL*Plus: Release 9.2.0.6.0 - Production on Sun Apr 13 14:06:58 2003
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.6.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.6.0 - Production
如果没有针对64位对C程序编译,可能会出现如下错误:
ORA-06520: PL/SQL: Error loading external library
ORA-06522: 0509-022 Cannot load module /cifsd01/bin/.
0509-103 The module has an invalid magic number.
LINUX平台下使用gcc进行编译:
gcc -fpic -o test.o -c test.c
gcc -shared -o test.o
生成;
添加c动态库到oracle:
oracle用户必须具有CREATE LIBRARY的权限
建立library:
windows
create or replace library TEST
as 'D:';
AIX
create or replace library TEST
as '/cifsd01/bin/';
许多文档说明如果是oracle9i,动态库必须放到 oracle 的lib目录下 ,
我在这几个平台下都试了一下,放在oracle主机上任何位置都可以正常运行。
创建oracle函数:
create or replace function outnum(num in binary_integer)
return binary_integer
as
language C
library TEST
name "OUT"
parameters(num int,return int);
"OUT"是C程序中的函数名,注意C是区分大小写的,一定要和C程序中的函数名一
样。
参数的数据类型与C函数的数据类型有相应的映射关系,如果配错,可能出现如下错
误:
ORA-28576: 丢失与外部代理程序的 RPC 连接
以上步骤完成后,就可以使用定义的C外部函数
SQL> select outnum(20) from dual;
OUTNUM(20)
----------
600
以上所列问题都是我在实现是出现的,可能说的不够全,希望大家能给予补充!
发布评论