|
有一个应用,在访问clob时抛出异常如下: FATAL ERROR IN TWO-TASK SERVER: error = 12152 *** 2008-07-17 18:28:43.912 ksedmp: internal or fatal error ORA-12571: TNS:packet writer failure RDBMS:9206,查metalink,证实为一个未公开的bug,为了挠过该bug,将clob类型的字段改成long类型,结果访问还是有问题,当长度超过一定的长度时,proc程序就只能读取前4000个字符,因为应用已经发布,修改代码已经来不急。查看了一下long字段的内容,发现文字内容很少的,大部分都是html的格式代码,只需要找出长度超过4000的记录,去掉该部分html代码应用就可以恢复正常;但怎么在long字段中找到超过4000字符记录呢?
用length、dbms_lob.getlength都不适合long类型,只好通过一段pl/sql代码,来计算超过4k的记录: declare v_str clob; v_cnt number; v_id number; begin for i in (select * from test order by id) loop v_str := i.txt; v_cnt := dbms_lob.getlength(v_str);
if v_cnt > 4000 then dbms_output.put_line('ID='||i.id||' LENGTH:'||dbms_lob.getlength(v_str)); end if; end loop; end; 查metalink,如何计算long字段的长度,找到官方推荐的方式,与偶计算结果的有一定的差异,但也可以达到自己的要求: CREATE OR REPLACE FUNCTION l_length(cTabName varchar2, cColName varchar2, cRowid varchar2) RETURN NUMBER IS cur_id integer; buff varchar2(32767); len integer; offset integer; v_length integer; stmt varchar2(500); ret integer; BEGIN stmt := ' SELECT ' || cColName || ' FROM ' || cTabName || ' WHERE rowid = ' || '''' || cRowid || ''''; cur_id := dbms_sql.open_cursor; dbms_sql.parse(cur_id, stmt, dbms_sql.NATIVE); dbms_sql.define_column_long(cur_id, 1); ret := dbms_sql.execute(cur_id); IF (dbms_sql.fetch_rows(cur_id) > 0) THEN offset := 0; len := 0; LOOP dbms_sql.column_value_long(cur_id, 1, 32767, offset, buff, v_length); len := len + v_length; EXIT WHEN v_length < 32767; offset := offset + v_length; END LOOP; END IF; dbms_sql.close_cursor(cur_id); return(len); END; ---- set serveroutput on size 100000;
DECLARE len number; cRowid varchar2(30); num number; cursor T_CURSOR is SELECT rowid FROM TABLE_NAME; BEGIN open T_CURSOR; LOOP FETCH T_CURSOR INTO cRowid; EXIT WHEN T_CURSOR%NOTFOUND; len := l_length('TABLE_NAME', 'LONG_COLUMN_NAME', cRowid); dbms_output.put_line(rowidtochar(cRowid) || '' || to_char(len, '999999')); END LOOP; END; /
|