插入大于 2000 或 4000 字节的 BLOB 测试字符串

Insert BLOB test string bigger than 2000 or 4000 bytes

我在 oracle 中有一个带有 BLOB 列的 table,它可以存储 XML 以及 XMLs 压缩文件。这些是客户的要求,无法更改。 table 将被创建,我必须阅读和处理 BLOBs 中的一些信息。

我已经研究过,任何不清楚的解决方案都很清楚或对我有用。

我面临的问题是 INSERT XML 大于 2000 bytesutl_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. 看来Oracle
  3. BLOBs4000 bytes还有一个限制

对于这些情况我能做些什么?

首先,您需要了解什么是 LOB。它们 "large data",可能比 Oracle 中的任何其他数据类型都大。它们就像文件系统上的常规文件。为了写入文件系统上的文件,您必须

  1. 打开文件进行写入
  2. 如果您想从头开始填充文件,请截断文件
  3. 循环读取源数据块
  4. 在同一个循环中将数据块一个一个地附加到文件
  5. 关闭文件

LOB 的情况大致相同。在您的 table 中,一个 LOB (CLOB/BLOB/NCLOB) 列只是一个 pointer/reference 到您磁盘存储上保存实际数据的另一个地方。在标准的 Oracle 术语中,指针称为 "LOB locator"。你需要

  1. open/initialize LOB 定位器
  2. 截断 LOB 内容,如果您想从头开始填充它
  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 内容,如果您希望从头开始填充它...这是由 insert 中的 empty_blob() 调用完成的。
  4. 在循环中将您的数据块附加到 LOB 内容,一个接一个 = 这里只有 dbms_lob.writeappend() 的一次迭代,仅附加一个长度 aaa 的块 utl_raw.length(aaa)(最大 32767) 到 LOB v_b
  5. 关闭 LOB 定位器 = dbms_lob.close(LOB_LOC=>v_b);

函数utl_raw.cast_to_raw 将数据类型为 VARCHAR2 的值转换为原始值。显然,字符串的长度受限于 VARCHAR2 数据类型。如果您需要将大文本数据转换为 LOB,您可以使用 DBMS_LOB.CONVERTTOBLOB 过程。

例如,您可以创建将大字符串值(clob 作为输入)转换为 blob 的函数。像这样的 -

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;