I'm writing a query for a reporting tool (Pentaho Report Designer) where I need to retrieve some jpgs that are stored in the Oracle 11 database. The trick is that the jogs (stored as BLOBs) include a 12 byte header (added by another application) that I need to remove. The reporting tool also requires the data to be returned as RAW data.
I am running into problems where it appears that the functions/procedures that I have found for manipulating BLOBs all have prohibitive size/length restrictions on them.
This query is as close to working as I can get it, using DBMS_LOB.SUBSTR(dbfile.filedata,2000,12):
select DBMS_LOB.SUBSTR(dbfile.filedata,2000,12) as filedata
from bms_0002005_251 safety
inner join bms_9999999_100 file02 on safety.bms_id = file02.bms_fk_0002005_839_ID
inner join bms_9999999_104 inc on safety.bms_fk_0002005_844_id = inc.bms_id
left join bms_dbfiles dbfile on file02.bms_9999999_40 = dbfile.uniqueid
For images <= 2000 bytes, this works perfectly, strips the 12 byte header and returns raw data like FFD8FFE000104A46494600010201006000600000FFEE000E41646F626500640000000001... etc
But for larger images (most of the images) 2000 is not enough, but as soon as I increase the substring length to 2001, the query fails:
ORA-06502: PL/SQL: numeric or value error: raw variable length too long ORA-06512: at line 1 06502. 00000 - "PL/SQL: numeric or value error%s"
This is the closest I have got, but long story short - is there any way in a single query I can strip the first 12 bytes from a large BLOB and return the data as RAW?
You can to convert Existing column data with blob data type to long raw data. v_length := dbms_lob. GETLENGTH(v_blob_update); -- Set the amount (bytes) to be converted equal to the length of the blob.
First we create a directory object pointing to the destination directory. CONN / AS SYSDBA CREATE OR REPLACE DIRECTORY BLOBS AS '/tmp/'; GRANT READ, WRITE ON DIRECTORY BLOBS TO my_user; Next we open the BLOB, read chunks into a buffer and write them to a file. Finally, you can check the file is produced correctly.
The DBMS_LOB package provides subprograms to operate on BLOBs, CLOBs, and NCLOBs. You can use DBMS_LOB to access and manipulate specific parts of LOBs or complete LOBs. You can also refer to "Large objects (LOBs)" in Oracle TimesTen In-Memory Database PL/SQL Developer's Guide.
Just create a user defined function to do this for you and use it in the select.
I whipped one simple example that does this by simply having the first offset at 13 instead of 1:
create or replace function strip12(p_blob in blob) return blob is
pragma autonomous_transaction;
l_length pls_integer;
l_loc pls_integer;
l_buffer pls_integer := 2000;
l_newblob blob;
begin
dbms_lob.createtemporary(lob_loc => l_newblob, cache => true);
l_length := dbms_lob.getlength(p_blob);
l_loc := 13;
while l_loc <= l_length loop
dbms_lob.append(dest_lob => l_newblob, src_lob => dbms_lob.substr(lob_loc => p_blob, amount => l_buffer, offset => l_loc));
l_loc := l_loc + l_buffer;
end loop;
return l_newblob;
end;
Then you simply use this in your select
select strip12(dbfile.filedata) as filedata
from bms_0002005_251 safety
inner join bms_9999999_100 file02
on safety.bms_id = file02.bms_fk_0002005_839_ID
inner join bms_9999999_104 inc
on safety.bms_fk_0002005_844_id = inc.bms_id
left join bms_dbfiles dbfile
on file02.bms_9999999_40 = dbfile.uniqueid
Regards
Generally speaking, it is not possible to modify a blob on-the-fly in a query, considering ORA-14553
.
Blob variable is a pointer to data, but not the data itself.
That's why functions like DBMS_LOB.SUBSTR
return not BLOB
or CLOB
, but RAW
or CHAR
- since data (variables) of the last types
are directly available in RAM.
Thus to query modified blob (with 12 bytes cut off from the head) we need to create and store the modified blob before querying. Depending on business requirements it can be done in place or by creating new blobs, preserving originals. In the case of the question I suppose we cannot modify original blobs in place.
Obviously, the second way (preserving originals) is more resource-intensive way.
Big picture of solution:
This causes more problems than it solves:
I guess there is a less painful solution - write a code in the outer party consuming the query results and modify blob data outside of the database.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With