2013-08-27 4 views
2

Oracle (11g) 기반 응용 프로그램에서는 파이프 라인 기능을 많이 사용하고 있습니다. 이제는 아래 함수 (컷 다운)에 표시된 것처럼 이러한 함수에서 발생한 오류보고가 어렵다는 것이 밝혀졌습니다. 프로 시저가 Java에서 호출되도록 존재하며 PL/SQL 실행 중에 어디에서나 오류가 발생합니다.Java에서 호출 된 파이프 라인 된 함수에서 PL/SQL 오류를 잡는 방법

ORACLE 부 :

set serveroutput on 

create table dummy (id NUMBER); 

create or replace package mytest 
as 
     type t_rec is record (id integer); 
     type t_tab is table of t_rec; 
     type t_ref_cur IS REF CURSOR RETURN t_rec; 

     function foo 
     return t_tab pipelined; 

     procedure bar(p_ref_cur out t_ref_cur); 
end mytest; 
/
show errors 

create or replace package body mytest 
as 
     function foo 
     return t_tab pipelined 
     is 
       v_cur SYS_REFCURSOR; 
       v_sql varchar2(2000); 
       v_rec t_rec; 
     begin 
       v_sql := 'select wrong_column from DUMMY'; 
       open v_cur for v_sql; 
       loop 
         fetch v_cur into v_rec; 
         exit when v_cur%notfound; 

         pipe row (v_rec); 
       end loop; 
     exception 
       when no_data_needed then 
         null; 
       when others then 
         dbms_output.put_line(SQLCODE||' '||sqlerrm); 
         raise no_data_found; 
     end foo; 

     procedure bar(p_ref_cur out t_ref_cur) 
     is 
     begin 
       open p_ref_cur for select * from table(foo); 
     end bar; 
end mytest; 
/
show errors 

-- call procedure bar() from pl/sql 
set serveroutput on 
declare v_ref_cur mytest.t_ref_cur; 
     v_rec mytest.t_rec; 
begin 
     mytest.bar(v_ref_cur); 
     loop 
       fetch v_ref_cur into v_rec; 
       exit when v_ref_cur%notfound; 
       dbms_output.put_line(v_rec.id); 
     end loop; 
end; 
/
show errors 

예외에서 상기 함수 결과를 실행 도시되고 :

ORA-00904: "WRONG_COLUMN": invalid column name

자바 부 :

package test1; 

import java.sql.CallableStatement; 
import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.ResultSet; 
import oracle.jdbc.OracleTypes; 

public class start { 

    public static void main(String[] args) 
    { 
     try 
     { 
      Connection con = DriverManager.getConnection("jdbc:oracle:thin:@...", "…", "…"); 
      CallableStatement stmt = con.prepareCall("BEGIN mytest.bar(?); END;"); 
      stmt.registerOutParameter(1, OracleTypes.CURSOR); 
      stmt.executeQuery(); 
      ResultSet rs = (ResultSet)stmt.getObject(1); 
      while (rs.next()) 
      { 
       System.out.println(rs.getInt(1)); 
      } 
      stmt.close(); 
      con.close(); 
     } catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 

예외없는 것 기음 찌르다. ResultSet이 비어 있습니다.

이것은 예상되는 동작입니까? 우리가 뭔가 잘못 했니? 해결 방법이 있습니까?

답변

3

문제는 당신이 bar 커서에 의해 예외로 취급되지 no_data_found을 제기하고있다 - 그것은 select (이 커서 효과적으로 open입니다,)에 대한 행이 돌아 오지 유효합니다. 익명 블록을 실행할 때 발생하는 예외는 아니고 dbms_output 호출 만 볼 수 있습니다. 블록이 성공적으로 완료되고 set serveroutput off이면 아무 것도 표시되지 않습니다. (편집 : this old AskTom thread talks about this behaviour too).

잡힌 후에 예외 유형을 변경하려고하는 이유가 명확하지 않습니다. 내가 할 수있는 유일한 이유는 당신이 가진 행동을 얻는 것이고, 어떤 에러가 처리해야만하는 예외가 아니라 빈 결과 셋을 제공하는 것입니다. 그것이 당신이하고 싶은 것을 원하지 않는다면, 그렇게하지 말고 명백한 것을 말하십시오. 그렇다면 자바 측에서 dbms_output 메시지를 찾아야합니다.

하지만 우선 단지 원의 예외 재발생하는 것을하고 싶지 왜 나는 볼 수 없습니다 :

  when others then 
        dbms_output.put_line(SQLCODE||' '||sqlerrm); 
        raise; 

... 또는 dbms_output 때문에 항상 볼 될 수 없습니다를 클라이언트, others 전혀 잡기. 자바 클라이언트가 그것을보기를 원할 때 예외를 잡아서 스쿼시하는 것은 약간 무의미하고 반 직관적 인 것처럼 보입니다.

자바 측의 예외가 다음 (e.getMessage()에서) 같은 것이다 :

ORA-00904: "WRONG_COLUMN": invalid identifier 
ORA-06512: at "SCHEMA.MYTEST", line 23 

은 아마도 당신은 PL/SQL의 스택 추적을 숨기고 단지 첫 번째 오류의 한 줄이 발생 보여주고 싶은, 오류를 추적 할 수 있도록 해당 정보를 유지하는 것이 더 유용 할 것 같습니다.