Извлечение BLOB-файлов из таблицы Oracle с помощью массива UTL_FILE, некоторые сжатые, некоторые нет
У меня есть сценарий, который извлекает документы массово из таблицы Oracle BLOB. Это необходимо для огромного переписывания и преобразования базы данных из Oracle в SQL, где файлы будут храниться в таблице файлов SQL. Поскольку документы должны храниться в файловой системе, я должен вынуть их и записать в виде файлов. Это прекрасно работает для большинства моих документов. После того, как я сильно ударился головой о свой стол, я наконец понял, что это связано с тем, что во внешней системе есть какая-то логика, которая сжимает некоторые документы - хотя я действительно не могу выяснить критерии для этого. Во всяком случае, я искал и искал и не могу найти какую-либо логическую проверку, чтобы увидеть, сжаты ли они внутри таблицы BLOB-объектов Oracle, прежде чем я их извлеку. Если я пытаюсь распаковать их ВСЕ, когда извлекаю их, я получаю сообщение об ошибке на тех, которые не были сжаты. Так что теперь я думаю, что смогу запустить их все с распаковкой, а затем перехватить исключение и обработать остальные, экспортируя без распаковки. Я просто не могу получить правильный синтаксис в моем скрипте. Это новый вызов для меня, и у меня нет опыта написания сценариев такого рода, поэтому, пожалуйста, прости мое невежество. Вот ошибка, которую я получаю, когда пытаюсь распаковать их все, поэтому я пытаюсь это уловить:
ORA-29294: A data error occurred during compression or uncompression.
ORA-06512: at "SYS.UTL_SYS_COMPRESS", line 56
ORA-06512: at "SYS.UTL_SYS_COMPRESS", line 226
ORA-06512: at "SYS.UTL_COMPRESS", line 89
ORA-06512: at line 21
Вот сценарий:
DECLARE
CURSOR C1 IS Select FILE_ID || '---' || substr(DOCUMENTLOCATION,1,instr (DOCUMENTLOCATION,'.')-1)||'.doc' as FILE_NAME, FILE_BLOB, FILE_ID
From DOCUMENTS d inner join CASEJOURNAL c on d.FILE_ID = c.JOURNALENTRYID where (JOURNAL_ENTRY_TYPE = 117 or JOURNAL_ENTRY_TYPE = 3) AND c.DOCUMENTLOCATION Is Not Null AND d.MIME_TYPE = 'application/msword' AND FILE_ID between 1 and 10000;
v_blob_uncomp BLOB;
v_blob BLOB;
blob_length INTEGER;
out_file UTL_FILE.FILE_TYPE;
v_buffer RAW(32767);
chunk_size BINARY_INTEGER := 32767;
blob_position INTEGER := 1;
filename varchar2(255);
BEGIN
--Select BLOB file into variables
FOR I in C1
LOOP
filename := i.FILE_NAME;
v_blob_uncomp := UTL_COMPRESS.LZ_UNCOMPRESS(i.FILE_BLOB);
v_blob := i.FILE_BLOB;
-- Define the output directory
out_file := UTL_FILE.FOPEN('fileloc',filename,'wb',chunk_size);
--Get length of BLOB file and save to variable.
blob_length := DBMS_LOB.getlength(v_blob);
-- Write the data to the file
WHILE blob_position <= blob_length LOOP
IF blob_position + chunk_size - 1 > blob_length THEN
chunk_size := blob_length - blob_position + 1;
END IF;
DBMS_LOB.read(v_blob_uncomp, chunk_size, blob_position, v_buffer);
UTL_FILE.PUT_RAW(out_file, v_buffer, TRUE);
blob_position := blob_position + chunk_size;
END LOOP;
UTL_FILE.FCLOSE(out_file);
END LOOP;
END;
Я знаю, что скрипт работает, когда я не распаковываю какие-либо большие двоичные объекты, но те, которые были сжаты, не открываются. Это также работает, когда я выполняю распаковку определенных файлов, которые, как я знаю, были сжаты. Я просто пытаюсь заставить это работать в моем цикле для ВСЕХ файлов как-то. ТИА!
2 ответа
Если вы хотите перехватить определенный код ошибки Oracle в PL/SQL, у вас есть два варианта:
А) поймать все исключения; в обработчике проверьте, соответствует ли сообщение об ошибке тому, которое вы ищете; если так, обращайтесь с этим; если нет, повторно поднимите его. Это будет выглядеть примерно так:
BEGIN
v_blob := := UTL_COMPRESS.LZ_UNCOMPRESS(i.FILE_BLOB);
EXCEPTION
WHEN OTHERS THEN
IF sqlerrm LIKE 'ORA-29294%' THEN
v_blob := i.FILE_BLOB;
ELSE
RAISE;
END IF;
END;
B) объявить переменную исключения и сопоставить ее с конкретным кодом ошибки, который вас интересует, а затем перехватить только это исключение. Это будет выглядеть примерно так:
DECLARE
compression_error EXCEPTION;
pragma exception_init ( compression_error, -29294 );
BEGIN
v_blob := UTL_COMPRESS.LZ_UNCOMPRESS(i.FILE_BLOB);
EXCEPTION
WHEN compression_error THEN
v_blob := i.FILE_BLOB;
END;
В любом случае, я бы предложил обернуть это в функцию.
Я также отмечаю, что ваш код не сбрасывается blob_position
в 1, когда начинается обработка нового BLOB.
Вместо подхода "попробуй и проваливай" вы можете рассмотреть использование магических чисел: считайте несколько байтов с начала файла, если он запускается, скажем, с 504B (PK), тогда существует большая вероятность, что это будет zip-архив.,