Как запросить определенное количество строк, чтобы избежать переполнения буфера при буферизации результата XML - PullRequest
0 голосов
/ 21 мая 2019

У меня есть скрипт, который запускает команду sqlplus для генерации XML-результата и его буферизации в файл.

Все идет хорошо, кроме случаев, когда я делаю это на большом столе. Возникает исключение переполнения буфера, когда я получаю сгусток, превышающий 1000000 байт ...

Затем я ищу способ выполнить несколько операторов SELECT в зависимости от этого размера сгустка. Например: если я получу 4 000 000 байтов, я бы выполнил 4 операции выбора, каждый из которых на 1/4 строк моей таблицы. Ты хоть представляешь, как я могу это сделать?

Вот пример моего кода:

sqlplus -s "DB" << EOF > /dev/null

set serveroutput on size unlimited;
set feedback off;
set pagesize 0;
set linesize 300;
set trimspool on;
set trimout on;
set termout off;
set wrap on;
set arraysize 200;

spool file.xml append;

DECLARE
   l_xmltype XMLTYPE;
   l_ctx dbms_xmlgen.ctxhandle;
   l_var VARCHAR(40);
   v_clob CLOB;
   v_clob_length INTEGER;
   amount INTEGER = 32767;
   buffer VARCHAR2(32767);
   pos INTEGER;

BEGIN

     l_ctx := dbms_xmlgen.newcontext('SELECT a.* FROM '||tableName||' a');

     dbms_xmlgen.setrowsettag(l_ctx, 'Table-'||tableName); 
     dbms_xmlgen.SetNullHandling(l_ctx, dbms_xmlgen.EMPTY_TAG);

     l_xmltype := dbms_xmlgen.getXmlType(l_ctx);
     dbms_xmlgen.closeContext(l_ctx);

     SELECT XMLSERIALIZE(DOCUMENT l_xmltype AS CLOB) into v_clob FROM dual;
     v_clob_length := length(v_clob);

     IF v_clob_length > 1000000 THEN 

        -- HERE (buffer overflow raised)
        return;

     END IF;

     WHILE pos < v_clob_length LOOP
        dbms_lob.read(v_clob, amount, pos, buffer);
        dbms_output.put_line(buffer);
        pos := pos + amount;
     END LOOP;

END;
/
spool off;

EOF

Если у вас есть лучшая идея, чтобы решить эту проблему, дайте мне знать! :)

Большое спасибо!

1 Ответ

0 голосов
/ 24 мая 2019

Ничего страшного, я нашел решение!

Для тех, у кого возникла бы эта проблема:

Я просто добавил условие, чтобы убедиться, что полученное значение clob превышает 1 000 000 байт.Если это так, я делю этот размер сгустка на 1000000 и получаю целое число, получаю количество строк в моей таблице и затем зацикливаюсь, выбирая только часть строк на каждой итерации.

Вот код:

IF v_clob_length > 1000000 THEN
   nbr_iteration := (v_clob_length/1000000)+1;
   execute immediate 'SELECT count(*) FROM '||myTable into nbr_rows;
   FOR i in 1..nbr_iteration LOOP
     current_calc := ((i/nbr_iteration)*nbr_rows)+1;
     l_ctx := dbms_xmlgen.newcontext('SELECT t.rowid, t.* FROM (SELECT t.*, row_number() over (order by rowid) rowNumber FROM '||myTable||' t) t WHERE rowNumber BETWEEN '||previous_calc||' AND '||current_calc||'');
     previous_calc := current_calc+1;
   END LOOP;
END IF;

Я знаю, что мой вопрос не совсем ясен, но все равно спасибо!:)

...