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

以上所列问题都是我在实现是出现的,可能说的不够全,希望大家能给予补充!