使用dbms_metadata.get_ddl时报ORA-06502和ORA-06512错误
现象:
SQL> select dbms_metadata.get_ddl(‘TRIGGER’, ‘AFTER_CONTAINER_INSERT_TRG’, ‘JYJX’) from dual;
ERROR:
ORA-06502: PL/SQL: numeric or value error
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "SYS.DBMS_METADATA_UTIL", line 294
说明:
1)数据库版本为9.2.0.8,comptiple参数时9.2.0.0.0
2) 使用该方式获取对象的定义时,数据库中某些对象能成功,某些对象不能成功。
3)使用PLSQL的report窗口执行报同样错误
4)使用PLSQL的dbms_metadata.get_ddl报同样错误
5)使用PLSQL的查看功能可以看到该触发器的定义
6)将相同数据导入到10205数据库中后,使用同样方式获取DDL时正常。
使用6502event跟踪:
alter system set event="6502 trace name errorstack level 12" scope=spfile;
shutdown immediate;
startup
select dbms_metadata.get_ddl(‘TRIGGER’, ‘AFTER_CONTAINER_INSERT_TRG’, ‘JYJX’) from dual;
追踪文件:
*** SESSION ID
9.3) 2014-04-14 11:21:11.616
17 *** 2014-04-14 11:21:11.616
18 ksedmp: internal or fatal error
19 ORA-06502: PL/SQL: numeric or value error: character string buffer too small
20 Current SQL statement for this session:
21 SELECT VALUE(KU$) TRIGGER_T FROM SYS.KU$_TRIGGER_VIEW KU$ WHERE KU$.SCHEMA_OBJ.NAME=’AFTER_CONTAINER_INSERT_TRG’ AND KU$.SCHEMA_OBJ.OWNER_NAME=’JYJX’
22 —– PL/SQL Call Stack —–
23 object line object
24 handle number name
25 0×5bbbdaa8 294 package body SYS.DBMS_METADATA_UTIL
26 0×5bb5b42c 83 package body SYS.DBMS_XMLGEN
27 0×5bb5b42c 83 package body SYS.DBMS_XMLGEN
28 0×5bbca654 362 package body SYS.DBMS_METADATA
29 0×5bbca654 418 package body SYS.DBMS_METADATA
30 0×5bbca654 457 package body SYS.DBMS_METADATA
31 0×5bbca654 640 package body SYS.DBMS_METADATA
32 0×5bbca654 1260 package body SYS.DBMS_METADATA
33 0×5bbda7c8 1 anonymous block
可以看到报错的SQL为:
SELECT VALUE(KU$) TRIGGER_T FROM SYS.KU$_TRIGGER_VIEW KU$ WHERE KU$.SCHEMA_OBJ.NAME=’AFTER_CONTAINER_INSERT_TRG’ AND KU$.SCHEMA_OBJ.OWNER_NAME=’JYJX’
单独执行该SQL:
SQL> SELECT VALUE(KU$) TRIGGER_T FROM SYS.KU$_TRIGGER_VIEW KU$ WHERE KU$.SCHEMA_OBJ.NAME=’AFTER_CONTAINER_INSERT_TRG’ AND KU$.SCHEMA_OBJ.OWNER_NAME=’JYJX’;
SELECT VALUE(KU$) TRIGGER_T FROM SYS.KU$_TRIGGER_VIEW KU$ WHERE KU$.SCHEMA_OBJ.NAME=’AFTER_CONTAINER_INSERT_TRG’ AND KU$.SCHEMA_OBJ.OWNER_NAME=’JYJX’
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "SYS.DBMS_METADATA_UTIL", line 294
查看SYS.KU$_TRIGGER_VIEW的定义:
CREATE OR REPLACE VIEW SYS.KU$_TRIGGER_VIEW OF ku$_trigger_t WITH OBJECT OID (obj_num) AS
select ‘1′,’0′,
t.obj#, value(o),
(select value(bo) from ku$_schemaobj_view bo
where t.baseobject = bo.obj_num),
t.type#, t.update$, t.insert$, t.delete$, t.definition, t.whenclause,
sys.dbms_metadata_util.long2varchar(t.actionsize,
‘SYS.TRIGGER$’,
‘ACTION#’,
t.rowid),
case when t.actionsize > 4000
then
sys.dbms_metadata_util.long2vcmax(t.actionsize,
‘SYS.TRIGGER$’,
‘ACTION#’,
t.rowid)
else NULL
end,
t.actionsize,
t.enabled, t.property, t.sys_evts
from sys.ku$_schemaobj_view o, sys.trigger$ t
where t.obj# = o.obj_num AND
(SYS_CONTEXT(‘USERENV’,'CURRENT_USERID’) IN (o.owner_num, 0) OR
EXISTS ( SELECT * FROM session_roles
WHERE role=’SELECT_CATALOG_ROLE’ ));
注意到该视图调用了函数sys.dbms_metadata_util.long2vcmax。
查看DBMS_METADATA_UTIL中的LONG2VCMAX函数:
– LONG2VCMAX: Convert a LONG column value to a VARCHAR2 and each line
– max length is 2000
– PARAMETERS:
– length – length of the LONG
– tab – table name
– col – column name
– row – rowid of the row
– RETURNS: LONG value converted to VARCHAR2
– otherwise NULL
FUNCTION long2vcmax(
length IN NUMBER,
tab IN VARCHAR2,
col IN VARCHAR2,
row IN UROWID)
RETURN sys.ku$_vcnt;
还有另外一个函数LONG2VCNT:
– LONG2VCNT: Convert a LONG column value to an array of VARCHAR2
– PARAMETERS:
– length – length of the LONG
– tab – table name
– col – column name
– row – rowid of the row
– RETURNS: LONG value converted to array of VARCHAR2 if length > 4000
– otherwise NULL
FUNCTION long2vcnt(
length IN NUMBER,
tab IN VARCHAR2,
col IN VARCHAR2,
row IN UROWID)
RETURN sys.ku$_vcnt;
可以看到这两个函数的输入参数及返回值是一样的,而第二个函数,即long2vcnt是支持length大于4000的。
因此,可选择以下解决方案:
修改视图SYS.KU$_TRIGGER_VIEW的定义,替换函数long2vcmax为long2vcnt。
通过这种方法可以解决ORA-06502错误,但是该方式修改了SYS用户的内容,因此不保证不会引起其他问题。
解决方案二
在测试过程中发现将相同的数据导入到10205数据库中后,不存在问题,进一步又发现使用PLSQL的查看功能获取到
存储过程的定义后,将该定义复制到一个会话中并重新执行一遍后也可解决6502错误。
所以,解决方案就是讲存在问题的触发器定义通过PLSQL查看等方式获取出来并重新执行。