ruby-oci8でPL/SQLを呼んだとき、PL/SQL例外はどう処理される?

簡単なコードで検証してみた。

-- 例外を起こすだけのプロシージャ
CREATE OR REPLACE PROCEDURE EXCP_TEST_1 AS
  test EXCEPTION;
BEGIN
  RAISE test;
EXCEPTION
  WHEN test THEN
    RAISE;
END EXCP_TEST_1;

これをsqlplus上で実行すると以下のようになる。

Connected.
SQL> begin
  2  apxe.excp_test_1();
  3  end;
  4  /
begin
*
ERROR at line 1:
ORA-06510: PL/SQL: ユーザー定義の例外が発生しましたが、処理されませんでした ORA-06512:
"APXE.EXCP_TEST_1", 行7
ORA-06512: 行2

ふむふむ。ではrubyで実行すると?

pasta:learn_rspec mahm$ irb
>> require 'oci8'
=> true
>> OCI8.new('apxe','******','xe').exec('begin apxe.excp_test_1(); end;')
OCIError: ORA-06510: PL/SQL: ユーザー定義の例外が発生しましたが、処理されませんでした
ORA-06512: "APXE.EXCP_TEST_1", 行7
ORA-06512: 行1
	from stmt.c:539:in oci8lib.so
	from /Library/Ruby/Site/1.8/oci8.rb:759:in `exec'
	from /Library/Ruby/Site/1.8/oci8.rb:142:in `do_ocicall'
	from /Library/Ruby/Site/1.8/oci8.rb:759:in `exec'
	from /Library/Ruby/Site/1.8/oci8.rb:255:in `exec'
	from (irb):2

OCIErrorが発生するんですね。じゃあちゃんとした例外を返すようにしてみよう。

-- NO_DATA_FOUND例外を起こすプロシージャ
CREATE OR REPLACE PROCEDURE EXCP_TEST_2 AS
  test EXCEPTION;
BEGIN
  RAISE test;
EXCEPTION
  WHEN test THEN
    RAISE NO_DATA_FOUND;
END EXCP_TEST_2;
>> require 'oci8'
=> true
>> OCI8.new('apxe','******','xe').exec('begin apxe.excp_test_2(); end;')
OCINoData: No Data
	from stmt.c:539:in oci8lib.so
	from /Library/Ruby/Site/1.8/oci8.rb:759:in `exec'
	from /Library/Ruby/Site/1.8/oci8.rb:142:in `do_ocicall'
	from /Library/Ruby/Site/1.8/oci8.rb:759:in `exec'
	from /Library/Ruby/Site/1.8/oci8.rb:255:in `exec'
	from (irb):3
>> 

OCINoDataとな? ということはRuby側で例外処理したい場合はこんな風に書けば良いのかな。

pasta:learn_rspec mahm$ irb
>> require 'oci8'
=> true
>> begin
?> OCI8.new('apxe','apxe','xe').exec('begin apxe.excp_test_2(); end;')
>> rescue OCINoData
>> puts "OCINoData was catched!"
>> end
OCINoData was catched!
=> nil

実際にはエラー内容をもっと詳細にロギングしたり、プロジェクト内で定義したエラーコードを返したりしなければならないのでしょう。raise_application_errorを使っていくのも手か。

Oracle PL/SQL Best PracticeのChapter6ではQuest Error Managerを使用する例が載っていたりと、Error Handling周りの話はなかなか興味深い話で一杯です。ちゃんと考えなきゃね。

Oracle PL/SQL Best Practices: Write the Best PL/SQL Code of Your Life

Oracle PL/SQL Best Practices: Write the Best PL/SQL Code of Your Life