我的环境是Oracle 11g。我有一个表T_IMG,其列是图像blob,图像标识符,图像的哈希计算为SHA256。我希望每次在T_IMG表中插入或更新行时计算图像哈希并将其插入到T_IMG表中。为此,我在T_IMG表上插入或更新时使用了before触发器,但是我无法访问触发器内的图像blob列。
CREATE TABLE TEST.T_IMG
(
IDN VARCHAR2(18 BYTE) NOT NULL,
IMG BLOB NOT NULL,
IMGHASH VARCHAR2(128 BYTE)
);
字符串和blob的SHA256哈希值由以下代码计算,该代码基于Sean Stuber在http://seanstuber.wordpress.com/2012/03/22/using-java-to-extend-dbms_crypto/的示例
CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED sha2 AS
import java.security.MessageDigest;
import oracle.sql.*;
public class sha2
{
public static oracle.sql.RAW get_digest_string( String p_string, int p_bits ) throws Exception
{
MessageDigest v_md = MessageDigest.getInstance( "SHA-" + p_bits );
byte[] v_digest;
v_digest = v_md.digest( p_string.getBytes( "UTF-8" ) );
return RAW.newRAW(v_digest);
}
public static oracle.sql.RAW get_digest_blob( oracle.sql.BLOB p_blob, int p_bits ) throws Exception
{
byte[] allBytesInBlob;
allBytesInBlob = p_blob.getBytes(1, (int) p_blob.length());
MessageDigest v_md = MessageDigest.getInstance( "SHA-" + p_bits );
byte[] v_digest = v_md.digest( allBytesInBlob );
return RAW.newRAW(v_digest);
}
}
/
CREATE OR REPLACE FUNCTION sha2_string(p_string in VARCHAR2, p_bits in number)
RETURN RAW AS LANGUAGE JAVA
NAME 'sha2.get_digest_string( java.lang.String, int ) return oracle.sql.RAW';
/
CREATE OR REPLACE FUNCTION sha2_blob(p_byte in BLOB, p_bits in number)
RETURN RAW AS LANGUAGE JAVA
NAME 'sha2.get_digest_blob( oracle.sql.BLOB, int ) return oracle.sql.RAW';
/
以上功能有效。测试他我得到:
SELECT sha2_string('0123456789',256) FROM DUAL;
SELECT sha2_blob(utl_raw.cast_to_raw('0123456789'),256) FROM DUAL;
SHA2_STRING( '0123456789',256)
-------------------------------------------------- ------------------------------ 84D89877F0D4041EFB6BF91A16F0248F2FD573E6AF05C19F96BEDB9F882F7882
选择了1行。SHA2_BLOB(UTL_RAW.CAST_TO_RAW( '0123456789'),256)
-------------------------------------------------- ------------------------------ 84D89877F0D4041EFB6BF91A16F0248F2FD573E6AF05C19F96BEDB9F882F7882
选择了1行。
我在T_IMG上插入或更新时使用before触发器来计算图像列的SH256散列。
CREATE OR REPLACE TRIGGER TEST.TR_IMG_UPSERT
BEFORE INSERT OR UPDATE
ON TEST.T_IMG
FOR EACH ROW
DECLARE
imghash varchar2(128);
vblob blob;
BEGIN
vblob := :new.IMG;
IF(vblob IS NOT NULL)THEN
/*-- this works
imghash := sha2_string('0123456789',256);
:new.imghash := imghash; */
/*-- this works too
vblob := utl_raw.cast_to_raw('0123456789');
imghash := sha2_blob(vblob,256);
:new.imghash := imghash; */
-- this DOES NOT work
imghash := sha2_blob(vblob,256);
:new.imghash := imghash;
END IF;
END;
/
触发器本身有效;它计算并在模拟数据(制造的字符串或blob)上插入哈希值,但在抛出以下错误时不在实际图像blob数据上:
ORA-29532:Java调用因未捕获的Java异常而终止:java.sql.SQLException:空顶操作无效
时出错
ORA-06512:在“TEST.SHA2_BLOB”,第1行 ORA-06512:在“TEST.TR_IMG_UPSERT”,第13行 ORA-04088:执行触发器'TEST.TR_IMG_UPSERT'
触发器似乎将:new.IMG数据读为空blob 。
为什么会发生这种情况?每次在T_IMG表中插入或更新行时,如何解决自动计算和将图像的哈希插入T_IMG表的问题?
注意:插入/更新数据行的客户端应用程序无法提供哈希值。
ADIM
答案 0 :(得分:2)
我在Oracle PL / SQL中执行了以下代码:
var idn varchar2(18 byte);
exec :idn := '0';
insert into t_img (idn, img) values (:idn, utl_raw.cast_to_raw('0123456789') );
commit;
select idn, dbms_lob.getlength(img) as length, imghash from t_img where idn=:idn;
update t_img set img=utl_raw.cast_to_raw('012345678901') where idn=:idn;
commit;
select idn, dbms_lob.getlength(img) as length, imghash from t_img where idn=:idn;
并且有效
SQL * Plus:2013年8月31日星期六11:20:04发布11.2.0.1.0版本
版权所有(c)1982,2010,Oracle。保留所有权利。
连接到:Oracle Database 11g 11.2.0.1.0版 - 64位 生产
PL / SQL程序已成功完成。
创建了1行。 提交完成。
IDN LENGTH IMGHASH
0 10 84D89877F0D4041EFB6BF91A16F0248F2FD573E6AF05C19F96BEDB9F882F7882
更新1行。 提交完成。
IDN LENGTH IMGHASH
0 12 5CE9AB10EA74270D12620DFACD74D262C6411E20761E459BB1B265DE883422AC
我发现我发布的错误只发生在Toad(11.6.0.43免费版)中提交手动编辑的IMG blob字段时,而不是在我通过PL / SQL执行表(插入,更新)时。 / p>
ADIM
答案 1 :(得分:0)
我不得不这样做:
create or replace TRIGGER DESPACHO_ACTA_ARCHIVO_IU
BEFORE INSERT OR UPDATE ON CAT_DESPACHO_ACTA_ARCHIVO FOR EACH ROW
DECLARE TEMPFLD BLOB;
blobid number;
BEGIN
SELECT BLOBTEMP_SEQ.NEXTVAL INTO blobid FROM SYS.DUAL;
INSERT INTO blobtemp VALUES (:new.bacta,blobid);
SELECT blobfield INTO :new.bacta FROM blobtemp where id =blobid ;
delete from blobtemp where id =blobid ;
:NEW.SHEX_SHA1 := sha2_blob(:new.bacta,1);
END;
创建临时表以强制blob持久化并获取正确的哈希值