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
相关产品推荐
相关产品推荐

