PL/SQL 擅長資料庫邏輯,但需存取作業系統資源(檔案、Excel、Outlook 等)時,透過外部程序呼叫 C/C++ 或 COM 物件更為合適。Oracle 8i 引入 External Procedures 機制,簡化了跨語言呼叫。
extproc 進程extproc 動態載入 DLL (Windows) / Shared Library (Unix)extprocextproc 將結果返還給 PL/SQLextproc 隨 Session 存續,Session 結束自動終止。
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = PLSExtProc)
(ORACLE_HOME = D:\oracle\ora92)
(PROGRAM = extproc)
)
)
LISTENER =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY = extproc1))
(ADDRESS = (PROTOCOL = TCP)(HOST = CHANET)(PORT = 1521))
)
EXTPROC_CONNECTION_DATA =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = IPC)(KEY = extproc1))
(CONNECT_DATA = (SID = PLSExtProc)(PRESENTATION = RO))
)
lsnrctl stop
lsnrctl start
tnsping EXTPROC_CONNECTION_DATA
Oracle 提供 ORDCOM 套件(C 外部程序)操作 COM 物件,三大核心動作:
| PL/SQL 型別 | COM VARIANT 型別 |
|---|---|
| VARCHAR2 | VT_BSTR |
| NUMBER | VT_R8 / VT_I4 |
| DATE | VT_DATE |
| BLOB | VT_ARRAY | VT_UI1 |
CreateObject(ProgID, ServerName):建立 COM 物件實例GetProperty(ObjectToken, PropertyName, ...):取得屬性SetProperty(ObjectToken, PropertyName, NewValue, ...):設定屬性Invoke(ObjectToken, MethodName, ...):呼叫方法DestroyObject(ObjectToken):釋放物件CREATE OR REPLACE PROCEDURE gen_excel_report(p_file VARCHAR2) AS
v_app BINARY_INTEGER; -- COM 物件 Token
v_wb BINARY_INTEGER;
v_ws BINARY_INTEGER;
v_range BINARY_INTEGER;
BEGIN
-- 1. 建立 Excel Application
v_app := ORDCOM.CreateObject('Excel.Application', 'localhost');
ORDCOM.SetProperty(v_app, 'Visible', 0); -- 背景執行
-- 2. 新增活頁簿與工作表
v_wb := ORDCOM.Invoke(v_app, 'Workbooks.Add');
v_ws := ORDCOM.GetProperty(v_wb, 'Worksheets', 1);
ORDCOM.SetProperty(v_ws, 'Name', 'SalesReport');
-- 3. 寫入標題列
v_range := ORDCOM.GetProperty(v_ws, 'Range', 'A1:C1');
ORDCOM.SetProperty(v_range, 'Value', ORDCOM.MakeSafeArray('Product,Qty,Amount'));
-- 4. 從資料庫讀取資料並寫入(略,使用 FOR 迴圈搭配 SetProperty)
-- 5. 儲存並關閉
ORDCOM.Invoke(v_wb, 'SaveAs', p_file);
ORDCOM.Invoke(v_wb, 'Close', FALSE);
ORDCOM.Invoke(v_app, 'Quit');
-- 6. 釋放資源
ORDCOM.DestroyObject(v_range);
ORDCOM.DestroyObject(v_ws);
ORDCOM.DestroyObject(v_wb);
ORDCOM.DestroyObject(v_app);
EXCEPTION
WHEN OTHERS THEN
-- 確保釋放 COM 物件
IF v_range IS NOT NULL THEN ORDCOM.DestroyObject(v_range); END IF;
IF v_ws IS NOT NULL THEN ORDCOM.DestroyObject(v_ws); END IF;
IF v_wb IS NOT NULL THEN ORDCOM.DestroyObject(v_wb); END IF;
IF v_app IS NOT NULL THEN ORDCOM.DestroyObject(v_app); END IF;
RAISE;
END;
/
extproc 進程以 Oracle 服務帳號執行,需具備存取 COM 元件權限