一次dbms_metadata.get_ddl时报ORA-06502和ORA-06512错误

使用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查看等方式获取出来并重新执行。


请使用浏览器的分享功能分享到微信等