JAVA儲存過程出現ORA-24345錯誤

yangtingkun發表於2008-08-18

寫了一個簡單的JAVA儲存過程,處理一個精度較大的數學問題,結果碰到了ORA-24345錯誤。

 

 

由於對JAVA不熟悉,JAVA儲存過程也很少使用,因此費了不少時間,總算寫了出來,但是在執行的時候發現了一個問題。

這個儲存過程是用來計算圓周率的取值的,相關演算法可以參考:http://yangtingkun.itpub.net/post/468/468870

關於儲存過程就不詳細描述了,下面直接看問題的產生:

SQL> create or replace and compile java source named "pi" as
  2  import java.math.BigDecimal;
  3  public class pi extends Object
  4  {
  5   public static String pi (int n)
  6   {
  7    BigDecimal result = new BigDecimal(1);
  8    for (int i=n;i>0;i--)
  9    {
 10     BigDecimal temp = new BigDecimal(i);
 11     result = new BigDecimal(2).add
 12      (result.multiply
 13       (temp.divide(new BigDecimal(1).add
 14        (temp.multiply
 15         (new BigDecimal(2))
 16        ),102,BigDecimal.ROUND_HALF_UP)
 17       )
 18      );
 19    }
 20    return result.toString();
 21   }
 22  }
 23  /

Java 已建立。

SQL> create or replace function f_pi (p_n in number) return varchar2 as
  2  language java name 'pi.pi(int) return String';
  3  /

函式已建立。

下面是呼叫結果:

SQL> select f_pi(10) from dual;

F_PI(10)
----------------------------------------------------------------------------------------------------
3.14084209564085725076437150740556313311731268387615136841143033093497489782319503681732783899966562

SQL> select f_pi(20) from dual;

F_PI(20)
----------------------------------------------------------------------------------------------------
3.14159211320774327955203808659259711079349608208228689356906807763678437061385664739133875908352702

SQL> select f_pi(50) from dual;
select f_pi(50) from dual
                     *
1 行出現錯誤:
ORA-24345:
出現截斷或空讀取錯誤


ERROR:
ORA-01002:
提取違反順序

 

未選定行

資料量比較小的時候沒有問題,一旦輸入引數值比較大,就會出現上面的這個錯誤。

測試還發現,如果將java儲存過程中的除法保留小數位數縮小一些,上面的查詢就可以得到結果,但是如果繼續增大資料量仍然會導致錯誤:

SQL> create or replace and compile java source named "pi" as
  2  import java.math.BigDecimal;
  3  public class pi extends Object
  4  {
  5   public static String pi (int n)
  6   {
  7    BigDecimal result = new BigDecimal(1);
  8    for (int i=n;i>0;i--)
  9    {
 10     BigDecimal temp = new BigDecimal(i);
 11     result = new BigDecimal(2).add
 12      (result.multiply
 13       (temp.divide(new BigDecimal(1).add
 14        (temp.multiply
 15         (new BigDecimal(2))
 16        ),10,BigDecimal.ROUND_HALF_UP)
 17       )
 18      );
 19    }
 20    return result.toString();
 21   }
 22  }
 23  /

Java 已建立。

SQL> select f_pi(100) from dual;
select f_pi(100) from dual
*
1 行出現錯誤:
ORA-29549:
YANGTK.pi已更改, Java 會話狀態被清除


SQL> select f_pi(100) from dual;

F_PI(100)
----------------------------------------------------------------------------------------------------
3.14159265347479757400080071875069256317928871566570517689083488598820471276504302524793754286818752

SQL> select f_pi(200) from dual;

F_PI(200)
----------------------------------------------------------------------------------------------------
3.14159265347479757400080071875090016088532653926425891578738668564238870675937454358049319246851093

SQL> select f_pi(500) from dual;
select f_pi(500) from dual
                      *
1 行出現錯誤:
ORA-24345:
出現截斷或空讀取錯誤


ERROR:
ORA-01002:
提取違反順序

 

未選定行

開始認為是JAVA緩衝區的問題,不過當前系統的SGAPGA的大小對於這個計算應該是綽綽有餘的:

SQL> SHOW SGA

Total System Global Area  603979776 bytes
Fixed Size                  1249332 bytes
Variable Size             239079372 bytes
Database Buffers          356515840 bytes
Redo Buffers                7135232 bytes
SQL> SHOW PARAMETER SGA_TARGET

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------
sga_target                           big integer 576M
SQL> SHOW PARAMETER PGA

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------
pga_aggregate_target                 big integer 191M

查詢了一下錯誤文件:

ORA-24345: A Truncation or null fetch error occurred
Cause: A truncation or a null fetch error"
Action: Please ensure that the buffer size is long enough to store the returned data.

這個描述就比較清晰了,由於VARCHAR2長度的限制導致了JAVA儲存過程返回的結果沒有辦法傳遞給PL/SQL

那麼只需要修改一下JAVA程式碼,返回適當長度的字串即可:

SQL> create or replace and compile java source named "pi" as
  2  import java.math.BigDecimal;
  3  public class pi extends Object
  4  {
  5   public static String pi (int n)
  6   {
  7    BigDecimal result = new BigDecimal(1);
  8    for (int i=n;i>0;i--)
  9    {
 10     BigDecimal temp = new BigDecimal(i);
 11     result = new BigDecimal(2).add
 12      (result.multiply
 13       (temp.divide(new BigDecimal(1).add
 14        (temp.multiply
 15         (new BigDecimal(2))
 16        ),102,BigDecimal.ROUND_HALF_UP)
 17       )
 18      );
 19    }
 20    return result.toString().substring(0,102);
 21   }
 22  }
 23  /

Java 已建立。

SQL> select f_pi(100) from dual;
select f_pi(100) from dual
*
1 行出現錯誤:
ORA-29549:
YANGTK.pi已更改, Java 會話狀態被清除


SQL> select f_pi(100) from dual;

F_PI(100)
----------------------------------------------------------------------------------------------------
3.14159265358979323846264338327929528649084412679106662169776161333278097211785395952441592543372994

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-429853/,如需轉載,請註明出處,否則將追究法律責任。

相關文章