外部プロシージャコール (extproc)

  1. 概要
  2. extproc の作り方
  3. oracle9i
  4. デバッグ
  5. FAQ

概要

oracle では PL/SQL から c で作成した外部ルーチンをコールするための機構として、 外部プロシージャコール (extproc) を用意しています。

extproc は $ORACLE_HOME/bin にあり、指定された共有ライブラリを動的にリンクし、 その中に含まれる指定された関数をコールします。

また extproc は tnslsnr から起動されます。 以下にプロセス概念図を示します。

oracle サーバ tnslsnr 外部プロシージャコール
PL/SQL ipc
LISTENER fork
extproc
+ 共有ライブラリ



外部プロシージャコールは、以下の手順で使用可能です。

  1. tnsnames.ora/listener.ora を設定する
  2. c で外部ルーチンを作成し、共用ライブラリを作成する
  3. PL/SQL から外部ルーチンをコールする sql を作成し、登録する
  4. 該当する listener を起動する
  5. PL/SQL のルーチンをコールする
  6. extproc が作成されていることを確認する

extproc の作り方

KROWN 13162 の例を作ります。(macB:ora817)

[ 課題 ] sample() を実行して、その返値が 1 の場合、テーブル sam に aaa をinsert します。 ただし、sample() は常に 1 を返します。

1. tnsnames.ora/listener.ora
tnsnames.ora

EXTPROC_CONNECTION_DATA =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = IPC)(KEY = extproc))
    )
    (CONNECT_DATA =
      (SID = PLSExtProc)
      (PRESENTATION = RO)
    )
  )

listener.ora

LISTENER2 =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS_LIST =
        (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC))
      )
    )
  )

SID_LIST_LISTENER2 =
  (SID_LIST =
    (SID_DESC =
      (SID_NAME = PLSExtProc)
      (ORACLE_HOME = /home1/METEOR/app/oracle/product/8.1.7)
      (PROGRAM = extproc)
    )
  )

2. ライブラリの作成

  cc -c sample.c -o sample.o
  ld -G -o sample.so sample.o
  cp sample.so /tmp

3. sql を作成し、登録する

SQL> @sample
SQL> @gcd

4. 該当する listener を起動する

> lsnrctl start LISTENER2

5. PL/SQL のルーチンをコールする

SQL> execute test
SQL> select * from sam;

 C
 ----------
 aaa

6. extproc プロセスの確認

> ps -ef | grep extproc | grep -v grep
ora817   19549     1  0 15:32 ?        00:00:00 extprocPLSExtProc (LOCAL=NO)

sample.c

 int sample(){
  return 1;
 }

sample.sql

 -- テストテーブルの作成
 create table sam(c char(10));

 -- ライブラリの作成(共有ライブラリの場所をプルパスで指定)
 create or replace library sample10 as
   '/tmp/sample.so';
 /

 -- sample を外部ファンクションとして登録
 create or replace function gcd
 return binary_integer as external
   library sample10
   name "sample"
   language c;
 /

gcd.sql

 -- gcd をコール
 create or replace procedure test is
    g binary_integer;
 begin
    g := gcd();  -- gcd をコール
    if g = 1 then
      insert into sam values('aaa');
    end if;
 end;
 /

oracle9i

oracle9i よりセキュリティが強化されたため、 listener.ora に以下の設定が必要になりました。

(ENVS="EXTPROC_DLLS=ANY")

また 32bit/64bit 版が作成できるものの場合は、特別な配慮が必要です。

(ENVS="XXXXX/lib:XXXXX:lib32")

デバッグ

外部プロシージャがコールされたかどうかは、以下で確認できます。 以下のコマンドで出力があれば、起動された extproc が動いていることを確認できます。 またエラーなどは $ORACLE_HOME/rdbms/log に書かれます。

truss -f -vall -o ext.truss -p IPC_TNSLSNR_PID

FAQ

質問

  1. 以下のエラーの対処法は?
    ORA-28575: 外部プロシージャ・エージェントへのRPC接続をオープンできません。
    ORA-06512: "TAKA.GCD", 行 0
    ORA-06512: "TAKA.TEST", 行 4
    
回答
  1. tnsnames.ora,listener.ora が正しく設定されているか調べましょう。 KROWN 84337,10921 参照