Обработка очень большой строки в скрипте pl / sql - PullRequest
1 голос
/ 08 мая 2020

Я пытаюсь запустить приведенный ниже код, который считывает определение индекса для таблицы A, чтобы его можно было создать снова после того, как я удалю / создаю его в этом скрипте. Этот сценарий работает нормально, когда возвращаемое значение (ddl) невелико, но в других средах, где значение велико (140 КБ символов в одной строке), этот сценарий завершается с ошибкой, указанной ниже. Обратите внимание, что в этом случае я не могу использовать катушку из-за некоторых ограничений. Может ли кто-нибудь помочь в решении этой проблемы или предложить другой подход?

Заранее спасибо.

«Ошибка арифметики c, numeri c, строки, преобразования или ограничения Например, эта ошибка возникает, если делается попытка присвоить значение NULL переменной, объявленной как NOT NULL, или если предпринята попытка присвоить целое число больше 99 переменной, объявленной NUMBER (2). "

SET SERVEROUTPUT ON;
DECLARE 
my_cursor SYS_REFCURSOR;
TYPE clob_array IS VARRAY(15) OF CLOB;
index_array clob_array := clob_array();
v_clob CLOB;
--index_array SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST();
BEGIN
OPEN my_cursor FOR 'select replace(dbms_metadata.get_ddl (''INDEX'', index_name), ''"C",'', '''')
              from user_indexes
             where table_name = ''A''';

LOOP FETCH my_cursor INTO v_clob;
EXIT WHEN my_cursor%NOTFOUND;
index_array.extend;
index_array(index_array.count) := v_clob;
dbms_output.put_line(index_array(index_array.count));
END LOOP;
CLOSE my_cursor;
END;
/

Ответы [ 2 ]

1 голос
/ 08 мая 2020

Я смоделировал эту проблему, вы получаете эту ошибку из-за dbms_output.put_line, который отображает вывод. Попробуйте переключиться на UTL_FILE на стороне сервера ИЛИ Попробуйте использовать любые альтернативы

0 голосов
/ 20 июня 2020

Кстати, код можно упростить до:

declare
    type         clob_array is table of clob;
    index_array  clob_array := clob_array();
begin
    for r in (
        select replace(dbms_metadata.get_ddl('INDEX', index_name), '"C",') as index_ddl
        from   user_indexes
        where  table_name = 'A'
    )
    loop
        index_array.extend;
        index_array(index_array.count) := r.index_ddl;
        dbms_output.put_line(substr(index_array(index_array.count), 1, 32767));
    end loop;
end;

Я использовал substr(), чтобы ограничить значение, передаваемое в dbms_output.put_line, его документированным пределом . Вероятно, вы могли бы обойти это, разделив текст на более мелкие куски и, возможно, найдя позицию последнего пробела перед позицией 32767, чтобы избежать разделения слова.

Вот что я придумал:

declare
    type         clob_array is table of clob;
    index_array  clob_array := clob_array();

    procedure put_line
        ( p_text clob )
    is
        max_len constant simple_integer := 32767;
        line varchar2(max_len);
        remainder clob := p_text;
    begin
        while dbms_lob.getlength(remainder) > max_len loop
            line := dbms_lob.substr(remainder,max_len);
            line := substr(line, 1, instr(line, ' ', -1));
            remainder := substr(remainder, length(line) +1);
            dbms_output.put_line(line);
        end loop;
        
        if length(trim(remainder)) > 0 then
            dbms_output.put_line(remainder);
        end if;
    end put_line;
begin
     for r in (
        select replace(dbms_metadata.get_ddl('INDEX', index_name), '"C",') as index_ddl
        from   user_indexes
        where  table_name = 'A'
    )
    loop
        index_array.extend;
        index_array(index_array.count) := r.index_ddl;
        put_line(index_array(index_array.count));
    end loop;
end;
...