Вставить тестовую строку BLOB размером более 2000 или 4000 байт

у меня есть таблица в Oracle с BLOB столбец, который может хранить XMLs, а также XMLs на молнии. Это требования заказчика, и их нельзя изменить. Таблицы будут созданы, и я должен прочитать и работать с некоторой информацией внутри BLOBs.

Я исследовал, и любое из неясных решений было ясно или работало для меня.

проблема, с которой я сталкиваюсь, заключается в том, что INSERT XML простые данные больше, чем 2000 bytes С utl_raw.cast_to_raw используя DBeaver как менеджер баз данных. Я получил сообщение:

SQL Error [6502] [65000]: ORA-06502: PL/SQL: numeric or value error: raw variable length too long ORA-06512: at "SYS.UTL_RAW", line 224
java.sql.SQLException: ORA-06502: PL/SQL: numeric or value error: raw variable length too long
ORA-06512: at "SYS.UTL_RAW", line 224

проблемы

  1. я исследовал и UTL_RAW не может превышать 2000 bytes
  2. кажется, что есть еще одно ограничение 4000 bytes на BLOBs в Oracle

что я мог сделать для этих дел?

2 ответов


для начала вам нужно понять, что такое поле. Они являются "большими данными", возможно, больше, чем любые другие типы данных в Oracle. Они похожи на обычные файлы в файловой системе. Для того, чтобы записать в файл на filesytem, вам придется

  1. открыть файл для записи
  2. усечь файл, если вы хотите начать заполнять его с нуля
  3. прочитайте ваши исходные данные в кусках в цикле
  4. добавьте фрагменты данных в файл в такую же петлю, по одному
  5. закрыть файл

более или менее то же самое верно для LOBs. В вашей таблице столбец LOB (CLOB/BLOB/NCLOB) - это просто указатель/ссылка на другое место на вашем диске, содержащее фактические данные. В стандартных терминах Oracle указатель называется "LOB locator". Вам нужно

  1. открыть/инициализировать локатор LOB
  2. усечь содержимое LOB, если вы хотите начать заполнять его с скретч!--14-->
  3. добавьте куски данных в содержимое LOB в цикле, один за другим
  4. закройте локатор LOB

в PL/SQL это может выглядеть так:

-- create table blob_test(id number, b blob);

declare 
  v_b blob; 
  aaa raw(32767);
  longLine varchar2(32767);
begin 
  longLine :=  LPAD('aaaa', 32767,'x');
  aaa := UTL_RAW.CAST_TO_RAW(longLine);
  insert into blob_test values(1,empty_blob()) returning b into v_b;
  dbms_lob.open(v_b,dbms_lob.lob_readwrite);
  dbms_lob.writeappend(v_b,UTL_RAW.LENGTH (aaa) ,aaa);
  dbms_lob.close(LOB_LOC=>v_b);
  commit;
end;

объяснение:

  1. инициализировать локатор LOB = insert into blob_test values(1,empty_blob()) returning b into v_b;
  2. откройте локатор LOB для записи = dbms_lob.open(v_b,dbms_lob.lob_readwrite);
  3. усечь содержимое LOB, если вы хотите начать заполнять его с нуля ... Это делается empty_blob() звоните в insert.
  4. добавьте куски данных в содержимое LOB в цикле, один за другим = здесь только одна итерация dbms_lob.writeappend(), добавляя только один кусок aaa длиной utl_raw.length(aaa) (максимум 32767) в лоб v_b
  5. закройте локатор LOB = dbms_lob.close(LOB_LOC=>v_b);

функции utl_raw.cast_to_raw преобразует значение типа данных VARCHAR2 в необработанное значение. Очевидно, что длина строки ограничена типом данных VARCHAR2. Если вам нужно конвертировать большие текстовые данные в LOB вы можете использовать DBMS_LOB.CONVERTTOBLOB процедуры.

например, вы можете создать функцию для преобразования большого строкового значения (clob в качестве входного) в blob. что-то вроде этого ...--5-->

create or replace function ClobToBlob (p_clob in clob) return blob is
   l_dest_offset   integer := 1;
   l_source_offset integer := 1;
   p_csid          number  := 0;
   l_lang_context  integer := DBMS_LOB.DEFAULT_LANG_CTX;
   l_warning       integer := DBMS_LOB.WARN_INCONVERTIBLE_CHAR;
   l_tmpblob blob;

  begin
   dbms_lob.createtemporary(l_tmpblob, true);
   DBMS_LOB.CONVERTTOBLOB
  (
   l_tmpblob,
   p_clob,
   DBMS_LOB.LOBMAXSIZE,
   l_dest_offset,
   l_source_offset,
   p_csid,
   l_lang_context,
   l_warning
  );
  return l_tmpblob;
end;