You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle PL/SQL中LZ_UNCOMPRESS解压压缩BLOB数据失败问题

Oracle PL/SQL:压缩BLOB存入JSON并避免解压错误的解决方案

问题根源

直接将压缩后的BLOB(二进制数据)转换为CLOB存储到JSON中会导致数据损坏。JSON是纯文本格式,无法直接存储原始二进制流,强制转换会因字符编码不兼容丢失字节,最终触发ORA-29294解压错误。

核心解决思路

将压缩后的BLOB通过Base64编码转换为可安全存储的文本字符串,存入JSON;读取时先解码回BLOB,再执行解压操作,确保二进制数据完整无损。

修正后的PL/SQL代码

DECLARE
  DATASET_JSON_WITH_COMPRESSED_BLOB JSON_OBJECT_T := JSON_OBJECT_T();
  DATASET_BLOB_DATA_CERNER_MONITORING BLOB;
  DATASET_BLOB_DATA_CERNER_MONITORING_BASE64_STR CLOB;
  DATASET_JSON_WITH_COMPRESSED_CLOB CLOB;
  CLIENT_ID VARCHAR2(50) := '12345'; -- 示例Client ID
  DATASET_BLOB_DATA BLOB;
  OBJECT_STORAGE_URI_CERNER_MONITORING VARCHAR2(500);
  OCI_CREDENTIAL VARCHAR2(400) := 'OCI$RESOURCE_PRINCIPAL';
  OCI_REGION VARCHAR2(50) := 'us-zzz-1';
  OBJECT_STORAGE_NAMESPACE VARCHAR2(50) := 'abcdefgh';
  BUCKET_NAME VARCHAR2(50) := 'analyticsContentTestBucket';
  l_content BLOB;
  l_content_clob CLOB;
  l_json_data JSON_OBJECT_T;
  uncompressed_blob BLOB;
  blob_length INT;

  -- 将RAW转为CLOB(处理Base64编码结果)
  FUNCTION raw_to_clob(p_raw RAW) RETURN CLOB IS
    l_clob CLOB;
    l_varchar VARCHAR2(32767);
  BEGIN
    l_varchar := UTL_RAW.CAST_TO_VARCHAR2(p_raw);
    DBMS_LOB.CREATETEMPORARY(l_clob, TRUE);
    DBMS_LOB.WRITEAPPEND(l_clob, LENGTH(l_varchar), l_varchar);
    RETURN l_clob;
  END;

  -- 将CLOB转为RAW(用于Base64解码)
  FUNCTION clob_to_raw(p_clob CLOB) RETURN RAW IS
    l_varchar VARCHAR2(32767);
    l_raw RAW(32767);
    l_offset NUMBER := 1;
    l_amount NUMBER := 32767;
  BEGIN
    DBMS_LOB.READ(p_clob, l_amount, l_offset, l_varchar);
    l_raw := UTL_RAW.CAST_TO_RAW(l_varchar);
    RETURN l_raw;
  END;

BEGIN
  -- 初始化测试BLOB数据
  DATASET_BLOB_DATA := UTIL.CLOB_TO_BLOB(TO_CLOB('There is BLOB data'));
  blob_length := DBMS_LOB.GETLENGTH(DATASET_BLOB_DATA);     
  DBMS_OUTPUT.PUT_LINE('原始BLOB长度: ' || blob_length);    

  -- 压缩BLOB数据
  DATASET_BLOB_DATA_CERNER_MONITORING := UTL_COMPRESS.LZ_COMPRESS(SRC => DATASET_BLOB_DATA);
  blob_length := DBMS_LOB.GETLENGTH(DATASET_BLOB_DATA_CERNER_MONITORING);
  DBMS_OUTPUT.PUT_LINE('压缩后BLOB长度: ' || blob_length);

  -- 将压缩BLOB转为Base64编码的CLOB,存入JSON
  DATASET_BLOB_DATA_CERNER_MONITORING_BASE64_STR := raw_to_clob(UTL_ENCODE.BASE64_ENCODE(DATASET_BLOB_DATA_CERNER_MONITORING));
  DATASET_JSON_WITH_COMPRESSED_BLOB.PUT('CLIENT_ID', CLIENT_ID);
  DATASET_JSON_WITH_COMPRESSED_BLOB.PUT('BLOB_DATA', DATASET_BLOB_DATA_CERNER_MONITORING_BASE64_STR);

  -- 输出并保存JSON
  DATASET_JSON_WITH_COMPRESSED_CLOB := DATASET_JSON_WITH_COMPRESSED_BLOB.TO_CLOB;
  DBMS_OUTPUT.PUT_LINE('生成的JSON内容: ' || DATASET_JSON_WITH_COMPRESSED_CLOB);

  -- 模拟从JSON读取并还原解压流程
  l_json_data := JSON_OBJECT_T.PARSE(DATASET_JSON_WITH_COMPRESSED_CLOB);
  l_content_clob := l_json_data.GET_STRING('BLOB_DATA');
  -- Base64解码回压缩BLOB
  l_content := UTL_ENCODE.BASE64_DECODE(clob_to_raw(l_content_clob));
  -- 解压数据
  uncompressed_blob := UTL_COMPRESS.LZ_UNCOMPRESS(SRC => l_content);
  blob_length := DBMS_LOB.GETLENGTH(uncompressed_blob);
  DBMS_OUTPUT.PUT_LINE('解压后BLOB长度: ' || blob_length);

  -- 生成OCI对象存储URI(可结合OCI SDK完成上传)
  OBJECT_STORAGE_URI_CERNER_MONITORING := 'https://objectstorage.' || OCI_REGION || '.oraclecloud.com/n/' || OBJECT_STORAGE_NAMESPACE || '/b/' || BUCKET_NAME || '/o/' || 'blobdata123.json';
END;
/

关键修正说明

  • Base64编码转换:使用UTL_ENCODE.BASE64_ENCODE将压缩后的BLOB转为RAW,再通过辅助函数转为CLOB存入JSON,确保二进制数据以文本形式安全存储。
  • 还原解码流程:读取JSON中的Base64字符串后,先转为RAW再通过UTL_ENCODE.BASE64_DECODE还原为压缩BLOB,最后执行解压操作。
  • 避免直接类型转换:移除原代码中TO_CLOB(压缩BLOB)这类直接转换,防止二进制数据因字符编码丢失损坏。

内容的提问来源于stack exchange,提问作者Debarshi Bhattacharyya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 09:54:55