Compute blob hash in trigger on blob's table

4k views Asked by At

My environment is Oracle 11g. I have a table T_IMG whose columns are an image blob, an image identifier, and the image's hash computed as SHA256. I want the image hash to be computed and inserted into the T_IMG table every time a row is inserted or updated in the T_IMG table. For this I use a before trigger on insert or update on the T_IMG table but I have difficulty accessing the image blob column inside the trigger.

CREATE TABLE TEST.T_IMG
(
    IDN       VARCHAR2(18 BYTE)      NOT NULL,
    IMG       BLOB                   NOT NULL,
    IMGHASH   VARCHAR2(128 BYTE)
);

The SHA256 hash for strings and blobs is computed by the following code that is based on Sean Stuber's example at 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';
/

The above functions work. Testing them I get:

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 row selected.

SHA2_BLOB(UTL_RAW.CAST_TO_RAW('0123456789'),256)
-------------------------------------------------------------------------------- 84D89877F0D4041EFB6BF91A16F0248F2FD573E6AF05C19F96BEDB9F882F7882
1 row selected.

I use a before trigger on insert or update on T_IMG to compute the SH256 hashing of the image column.

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;
/

The trigger by itself works; where it computes and inserts the hash value on mock-up data (manufactured string or blob) but not on the real image blob data when it throws the following error:

ORA-29532: Java call terminated by uncaught Java exception: java.sql.SQLException: Invalid empty lob operation
ORA-06512: at "TEST.SHA2_BLOB", line 1
ORA-06512: at "TEST.TR_IMG_UPSERT", line 13
ORA-04088: error during execution of trigger 'TEST.TR_IMG_UPSERT'

It seems that the trigger reads the :new.IMG data as an empty blob.

Why this happens and how can I solve my problem of automatically computing and inserting the image's hash into the T_IMG table every time a row is inserted or updated in the T_IMG table?

Note: The hash can not be provided by the client app inserting/updating the data rows.

AdiM

2

There are 2 answers

0
adim On BEST ANSWER

I executed the following code in 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;

and it works

SQL*Plus: Release 11.2.0.1.0 Production on Sat Aug 31 11:20:04 2013

Copyright (c) 1982, 2010, Oracle. All rights reserved.

Connected to: Oracle Database 11g Release 11.2.0.1.0 - 64bit Production

PL/SQL procedure successfully completed.

1 row created. Commit complete.

IDN LENGTH IMGHASH


0 10 84D89877F0D4041EFB6BF91A16F0248F2FD573E6AF05C19F96BEDB9F882F7882

1 row updated. Commit complete.

IDN LENGTH IMGHASH


0 12 5CE9AB10EA74270D12620DFACD74D262C6411E20761E459BB1B265DE883422AC

I've found out that the error I posted happens only upon committing a manually edited IMG blob field in Toad (11.6.0.43 free version) but not when I exercise the table (inserts, updates) via PL/SQL.

AdiM

0
user3063731 On

I had to do this trick:

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;

Create a temporarly table to force blob to persist and obtain the correct hash value