有時,我們會發現有些功能通過PL/SQL完成會很麻煩,而通過C/C++語言編程則會容易很多。因此,oracle提供了在PL/SQL程序裏直接調用外部函數(包括C函數或Java方法)的功能,從而擴展了PL/SQL的程序功能。調用外部函數的過程如下圖所示。
調用外部函數的過程
從上圖可以看出,調用外部函數的過程包括:
<!--[if !supportLists]-->1) <!--[endif]-->用戶進程執行PL/SQL程序。
<!--[if !supportLists]-->2) <!--[endif]-->在執行的PL/SQL程序過程中,調用了一個C/C++語言寫的函數:c_func。這裏需要藉助別名庫(Alias Library)。別名庫是數據庫裏的一個對象,用來描述一個外部函數所在的動態鏈接庫的路徑和名稱。通過別名庫,從而可以知道被調用的外部函數在哪個文件裏。
<!--[if !supportLists]-->3) <!--[endif]-->PL/SQL將對外部函數的調用請求發送給監聽器。
<!--[if !supportLists]-->4) <!--[endif]-->監聽器生成一個extproc進程,該進程專門用來處理對外部函數的調用。每個session都會生成一個屬於該session的extproc進程,並且在整個session生命週期裏,extproc進程會一直存在。
<!--[if !supportLists]-->5) <!--[endif]-->Extproc進程負責將別名庫所指定的動態鏈接庫文件加載到內存。
<!--[if !supportLists]-->6) <!--[endif]-->Extproc進程執行指定的外部函數,並將結果返回給服務器進程,進而返回給用戶進程。
需要對監聽器進行配置,從而啓動extproc進程,配置方式如前面的圖11-3所示。其中(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0))說明監聽extproc進程請求的地址;而SID_DESC部分則說明extproc進程的連接信息。
然後我們還要配置tnsnames.ora文件,注意,該文件也必須位於數據庫服務器端。我們需要添加如下圖的內容。
配置tnsnames.ora
配置完畢以後,可以嘗試tnsping連接字符串名稱,如果成功,則說明監聽沒有問題。
[oracle@book admin]$ tnsping EXTPROC_CONNECTION_DATA
接下來,我們創建一個C語言編寫的函數,如下所示。該函數完成的功能非常簡單,計算傳入參數的15%,並作爲稅額返回給調用者。
[oracle@book ~]$ vi calc_tax.c
calc_tax(n)
int n;
{
int tax;
tax=(n*15)/100;
return (tax);
}
將calc_tax.c文件編譯成動態鏈接庫,並將生成的庫文件拷貝到$ORACLE_HOME/bin目錄下:
[oracle@book ~]$ cc -shared -o calc_tax.so calc_tax.c
[oracle@book ~]$ cp calc_tax.so $ORACLE_HOME/bin
然後,我們創建一個別名庫,用來說明將要調用的C函數所在的庫文件,並將使用c_code別名庫的權限賦給HR用戶:
SQL> connect / as sysdba
SQL> create or replace library c_code as '$ORACLE_HOME/bin/calc_tax.so';
2 /
SQL> grant execute on c_code to hr;
要使用這個calc_tax函數,還必須在數據庫裏創建一個調用聲明。如下所示:
SQL> connect hr/hr
SQL> create or replace function call_c
2 (x binary_integer)
3 return binary_integer
4 as language C
5 library sys.c_code
6 name "calc_tax";
7 /
在調用聲明裏定義了calc_tax函數的傳入傳出參數、所在的別名庫名稱(library sys.c_code部分)、以及在動態鏈接庫中的函數名(name "calc_tax")等。
現在,我們就可以通過調用call_c,進而調用calc_tax函數了。如下所示:
SQL> set serveroutput on
SQL> var v_salary number;
SQL> var v_tax number;
SQL> exec :v_salary := 10000;
SQL> exec :v_tax := call_c(:v_salary);
SQL> print v_tax;
V_TAX
-----------------
1500
從返回結果可以看到,我們成功調用了C函數:calc_tax。注:以上內容摘自《Oracle數據庫核心技術與實務詳解-教你如何成爲10g OCP》一書。