yangtingkun
===========================================================
JAVA存储过程出现ORA-24345错误
===========================================================

写了一个简单的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

yangtingkun 发表于:2008.08.18 23:52 ::分类: ( ORACLE ) ::阅读:(439次) :: 评论 (0)

发表评论
标题

在此添加评论
表情符号: smile laughing tongue angry crying sad wassat wink

称呼

邮箱地址(可选)

个人主页(可选)

 authimage


切换风格
新闻聚合
博客日历
文章归档...
最新发表...
最新评论...
最多阅读文章...
最多评论文章...
博客统计...
Blog信息
网站链接...