天天看點

在資料庫中自定義外部函數

在oracle中可以使用pl/sql來實作一些複雜的功能,同時可以通過自定義的外部函數來實作很多豐富的功能,我們可以基于c/c++來寫一些函數,然後把動态連結庫放入ORACLE_HOME中友善直接調用。

首先這種實作方法需要依賴于資料庫層面的服務extproc,監聽器會生成一個extproc程序,然後專門來處理外部函數的調用。

具體的配置可以在$ORACLE_HOME/network/admin下的listener.ora和tnsnames.ora中展現。

一般通過dbca建立的庫都會預設配置extproc的部分,可以看到它使用的是ipc協定而不是tcp協定。

樣例如下:

listener.ora

LIST=

  (DESCRIPTION=

    (ADDRESS_LIST=

      (ADDRESS=(PROTOCOL=tcp)(HOST=rac1)(PORT=1599))

      (ADDRESS=(PROTOCOL=ipc)(KEY=extproc))))

SID_LIST_LIST=

  (SID_LIST=

     (SID_DESC=

        (GLOBAL_DBNAME=TEST01)

        (ORACLE_HOME=/u03/ora11g/product/11.2.0/dbhome_1)

        (SID_NAME=TEST01)))

tnsnames.ora

EXTPROC01=

(DESCRIPTION=

 (ADDRESS=(PROTOCOL=ipc)(key=extproc))

 (CONNECT_DATA=(SERVICE_NAME=TEST01))

)

如果配置沒有問題,可以使用tnsping來驗證一下服務是否可用。

[ora11g@rac1 admin]$ tnsping extproc01

TNS Ping Utility for Linux: Version 11.2.0.3.0 - Production on 24-FEB-2015 06:03:53

Copyright (c) 1997, 2011, Oracle.  All rights reserved.

Used parameter files:

Used TNSNAMES adapter to resolve the alias

Attempting to contact (DESCRIPTION= (ADDRESS=(PROTOCOL=ipc)(key=extproc)) (CONNECT_DATA=(SERVICE_NAME=TEST01)))

OK (0 msec)

接下來我們來實作一個簡單的函數,大過年的我們就以紅包為例。我們傳入紅包的金額,直接放大100倍。比如傳入8塊,直接輸出800.

cat test.c

test(n)

int n;

{

     int lucky_money;

     lucky_money=100*n;

     return (lucky_money);

}

對編寫的c程式做編譯,生成動态連結庫檔案,然後直接拷貝到$ORACLE_HOME/bin下

[ora11g@rac1 extproc]$ cc -shared -o test.so test.c

[ora11g@rac1 extproc]$ ll

total 12

-rw-r--r-- 1 ora11g dba   83 Feb 24 05:42 test.c

-rwxr-xr-x 1 ora11g dba 5609 Feb 24 05:42 test.so

[ora11g@rac1 extproc]$ cp test.so $ORACLE_HOME/bin

這個時候我們就開始建立庫檔案,指向test.so,然後把權限賦予指定的使用者。

SQL> create  or replace library test_code as '$ORACLE_HOME/bin/test.so';

    /

Library created.

SQL> grant execute on test_code to n1;

Grant succeeded.

有了庫檔案,我們就開始定義函數,這個函數最終給會調用連結庫檔案

create or replace function func_test

(x binary_integer)

return binary_integer

as language C

library sys.test_code

name "test";

到此為止就大功告成了,我們的函數就建立成功了,來簡單驗證一下。

set serveroutput on

var lucky_money number;

var amount number;

exec :lucky_money :=8888;

exec :amount := func_test(8888);

print amount;

SQL>

    AMOUNT

----------

    888800

這種方式能夠屏蔽代碼層的抽象,直接開放豐富的功能,還是比較實用的。