Skip to Main Content
  • Questions
  • To read blob image from remote database over the dblink.

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Vijayakumar.

Asked: September 08, 2002 - 11:34 pm UTC

Last updated: April 27, 2011 - 4:58 pm UTC

Version: 8.1.6

Viewed 10K+ times! This question is

You Asked

Hi Tom,
We have 8i db one on the production server and another on the webserver (public access for online service). I have the same table created in both the database.
I have a procedure to load the all the images form the file system about (1400) into this table (blob field) in production server through oracle forms user interface. (working fine)
Once it is loaded and verified, then I have another procedure to transfer this data to the webserver table (identical table) over the db link (working fine).
The dblink is only oneway (prod -> webserver only).

Now the user wants a form interface to validate the data tranfer (query only). Wants to scroll through and see all the images on the form one by one.

Since I am not allowed to create public synonym (not allowed due to maintaince issue in our current setup) for the remote table, what is the best way to achieve my objective.
I was trying to do with reference cursor and build a form based on reference cursor, but it is not allowed according to oracle document if it is blob/clob field.
The suggested workaround is to use DBMS_LOB package.

How can I achieve this using DBMS_LOB package?. Any solution?

Thanks
Vijayakumar Belaguli



and Tom said...

The easiest way I know to do this is:


create global temporary table T ( b blob ) on commit delete rows;


Now, your program would execute:

insert into t select blob_column from table@remote_site where ....;


and then it would work on the blob in table T locally. Much easier then trying to piecewise fetch it using dbms_lob@remote_site!

When you commit, the blob will disappear.

Rating

  (16 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

To read blob image from remote database over the dblink.", version 8.1.6

Belaguli vijayakumar, September 10, 2002 - 4:56 am UTC

Thanks for your reply and the solution.
Is there any other way of doing this without having to create any temporary table?
As mentioned earlier, the form interface is to be used only for querying remote table having images in blob field, so the question of issueing a commit does not arise at all.

Tom Kyte
September 10, 2002 - 7:32 am UTC

Yes, you can use dbms_lob but it would be heinously hard and the wrong way to do it.

You have 8i.
You have temporary tables.
It is the correct and proper and best answer.

I don't know what you mean by "the question of issuing a commit does not arise at all", of course it does.

length of remote images

A reader, March 09, 2005 - 3:12 pm UTC

Hi,

Consider the following scenario. I have a database db1 which has a table tab1 of structure

create table tab1
(
id number,
ssn varchar2(20),
img blob
);

I have another database db2 which is replicated from db1 every night. Database db2 has a table tab2 of structure

create table tab2
(
id number,
ssn varchar2(20),
img blob,
imgsize number
);

I have to insert data from db1.tab1 into db2.tab2 but I should insert null into img column in tab2 whereas I have to insert length(img) from tab1 into imgsize in tab2. But when I try to do

insert into tab2
select id, ssn, null, dbms_lob.getlength(img) from tab1@db1link;

I am getting an error ORA-22992: cannot use LOB locators selected from remote tables.
What is the easiest way to achieve this?

Thanks.




Tom Kyte
March 09, 2005 - 3:24 pm UTC

ops$tkyte@ORA9IR2> create table t1 ( x clob );
Table created.

ops$tkyte@ORA9IR2> insert into t1 values ( rpad('x',1324,'x') );

1 row created.


connect to another database:

ops$tkyte@ORA9IR2> create table t2 ( x number );
Table created.


ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> insert into t2
  2  select dbms_lob.getlength(x)
  3    from t1@ora9ir2.us.oracle.com@loopback;
select dbms_lob.getlength(x)
                          *
ERROR at line 2:
ORA-22992: cannot use LOB locators selected from remote tables


Connect back to other database:

ops$tkyte@ORA9IR2> create or replace view v
  2  as
  3  select dbms_lob.getlength(x) len_x from t1;
View created.


and connect locally again:

ops$tkyte@ORA9IR2> insert into t2
  2  select *
  3    from v@ora9ir2.us.oracle.com@loopback;

1 row created.



so, have a view at the remote that hides the lob from the dblink entirely. 

Image over remote link

A reader, March 18, 2005 - 10:50 am UTC

Hi Tom,

As per your suggestion, I created a view view1 on db1 as
select * from tab1;

I am trying to populate the table tab2 on db2 as

insert into tab2
select a.id, a.ssn, b.img, c.imgsize
from idtab a, tab1@db1link b, view1@db1link c
where a.id = b.id
and b.id = c.id
and a.id > 1000;

Note: The databases, tables, views in this question are those referred in the above question.

Even though this select statement returns only 20,000 rows, it takes forever and this query is never completing. Please help with this.

Thank You.


Tom Kyte
March 18, 2005 - 11:03 am UTC

no, it would be:

from idtab a, bigger_view@db1link

can you do that -- one remote reference.


have you looked at the plan to see what it is in fact doing?

A reader, March 18, 2005 - 11:06 am UTC

oh, so if I have the remote view of the same structure as the remote table then I can just select all the values from the view, Right... I will try this and let you know.

I haven't seen the plan yet.

Thanks a lot Tom.

Thanks!!

A reader, March 18, 2005 - 12:35 pm UTC

Hi Tom,

It works great.

Thanks a lot.

I got the ORA-22992 when I creating view via db_link on clob column

Prabhakar, April 15, 2005 - 7:45 am UTC

I went through the your suggetion which have mentioned here for creating view via db_link on clob column,

I tried  following scenario but I am not able to create view via db_link which we have clob column on base table(reomote table) 

Remote Database
------------

SQL> create table t1 ( x clob );

Table created.

SQL> Table created.
SQL> commit;

Commit complete.

SQL> desc t1
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 X                                                  CLOB



Replication Database.
---------------------

  1* create or replace view v as select dbms_lob.getlength(x) len_x from t1@test.world
SQL> /
create or replace view v as select dbms_lob.getlength(x) len_x from t1@test.world
                                                      *
ERROR at line 1:
ORA-22992: cannot use LOB locators selected from remote tables


Please let me know why I am getting same error ?
 

Tom Kyte
April 15, 2005 - 9:19 am UTC

go back up -- you create the view ON THE REMOTE DATABASE, not a view locally.

you need to use the dbms_lob package on the REMOTE database, not your local one.

What about copying over a remote BFILE

eric givler, September 08, 2005 - 11:18 am UTC

The insert into select with a blob works over a dblink, but if the remote table has a BFILE (this is something already in place and is written by a 3rd party), an attempt to do an insert into a blob won't work (inconsistent data types), and an attempt to bring in a bfile won't work (I'm assuming here the directory and file would have to be brought over as well as you get an ora-22285).

You had referred to "piece wise" extracting using dbms_lob at remote. What were you getting at here?



Tom Kyte
September 08, 2005 - 3:53 pm UTC

well, if I had to copy this stuff over - i would write the function to return the directory name/filename from the bfile on the remote site and select those functions and bfile them locally.

You have to move the file yourself.

I don't see how a piece wise extract would help you since you cannot write the bfile stuff out after you retrieve it really.

found more source on your site!!

eric givler, September 09, 2005 - 12:31 am UTC

The thread here:
</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:238014476571 <code>
provides an example of moving data from a long raw and simulating a to_lob.

I was able to "tweak" this to open up a connection via a java stored procedure to the remote table and then read from the remote inputstream and pull it into a local table as a blob. Getting the security permissions was a little quirky as it kept reporting all these different ports to give java permissions on for the remote server. I gave up on putting them in and gave permission on the remote ip as well as the remote host name.

Jdeveloper has a nice feature for deploying code (java stored procs) to the db and publishing a pl/sql wrapper.

Thanks again!

Tom Kyte
September 09, 2005 - 7:04 am UTC

Ah, I did not know you wanted them in the database, I thought you wanted a "bfile copy"

here's the code

eric givler, September 09, 2005 - 10:04 am UTC

Do you have any thoughts on this?


import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import oracle.jdbc.OracleResultSet;
import oracle.sql.BFILE;
import oracle.sql.BLOB;

public class movelr
{
/*
from: </code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:238014476571 <code>
be sure to add Libraries: Oracle JDBC
*/
public static void copyBfile(String p_unique_id)
throws Exception
{
int length;

Connection connRemote =
DriverManager.getConnection("jdbc:oracle:thin:@epenegora03:1526:EDEV",
"ivnet_user","iuseredev");

Connection connGivler =
DriverManager.getConnection("jdbc:default:connection:");

connRemote.setAutoCommit (false);
connGivler.setAutoCommit (false);
System.out.println( "connected..." );

// Create statements
PreparedStatement pstmt =
connRemote.prepareStatement
("select bfile_reference from ivnet_dba.iv_bfile_references " +
"where unique_id = ?");
pstmt.setString(1, p_unique_id );
System.out.println( "prepared statement for iv_bfile_references..." );

PreparedStatement stmtGetSEQ =
connGivler.prepareStatement
("select temp_pdf_id_seq.nextval from dual" );

PreparedStatement insertStmt =
connGivler.prepareStatement
("insert into temp_pdfs ( temp_pdf_id, unique_id, b ) " +
"values ( ?, ?, empty_blob() ) " );
System.out.println
( "prepared statement for BLOB insert..." );

PreparedStatement getStmt =
connGivler.prepareStatement
("select b from temp_pdfs where temp_pdf_id = ? for update");
System.out.println
( "prepared statement for BLOB select/lock..." );

// ResultSet rsetSource = pstmt.executeQuery();
OracleResultSet rsetSource = (OracleResultSet) pstmt.executeQuery();
System.out.println
( "executed statement for iv_bfile_references select..." );

System.out.println( "Move to first record..." );
rsetSource.next();

BFILE bfd = rsetSource.getBFILE(1);
bfd.openFile();

// ORA-22289: cannot perform FILEREAD operation on an unopened file or LOB
// When it was a ResultSet
// InputStream is = rsetSource.getBinaryStream(1);
InputStream is = bfd.getBinaryStream();

System.out.println( "Got BFILE stream...");

ResultSet rsetSEQ = stmtGetSEQ.executeQuery();
rsetSEQ.next();
long longTempPdfId = 0;
longTempPdfId = rsetSEQ.getLong(1);
System.out.println("longTempPdfId=" + longTempPdfId);

// Insert a new row and get select
// back the BLOB column
insertStmt.setLong(1, longTempPdfId);
insertStmt.setString(2, p_unique_id);
insertStmt.executeUpdate();

// get output blob and lock it.
getStmt.setLong(1, longTempPdfId);
OracleResultSet rsetOutput =
(OracleResultSet) getStmt.executeQuery();

rsetOutput.next();

// Warning(83,39): method getBinaryOutputStream() in class
// oracle.sql.BLOB has been deprecated
BLOB oBlob = rsetOutput.getBLOB(1);
OutputStream os = oBlob.getBinaryOutputStream();
System.out.println( "Got BLOB Outputstream..." );

System.out.println( "Moving data from IVNET to LOCAL...");
byte buffer[] = new byte[4096];
while ((length = is.read (buffer,0,4096)) != -1)
{
os.write( buffer, 0, length );
}

is.close();
os.close();
rsetOutput.close();


insertStmt.close();
getStmt.close();
bfd.closeFile(); // new
pstmt.close();
connGivler.commit();
connRemote.close();
connGivler.close();

} // copyBfile

} //

NOTE: the blob getBinaryOutputStream is deprecated.

Tom Kyte
September 09, 2005 - 11:11 am UTC

it is fine I guess (pretty old).

Does LOB data go through buffer cache?

A reader, October 14, 2005 - 3:26 pm UTC

Tom,
Are LOB reads buffered?
Thanks


Tom Kyte
October 14, 2005 - 5:58 pm UTC

they can be, if you declare the lob as cached.

by default - they are not.

Update LOB over dblink

Vin, February 16, 2006 - 9:22 pm UTC

Oracle 10.1.0.3.0 on Linux
tried doing a update of a lob column in a remote table using a view on remote database as per advice, but resulted in error.
please advice if there is any solution to this.

Remote Database:
SQL> create table t(x number,y clob);
Table created.
SQL> desc t
Name      Null?    Type
--------  ------   -------
X                  NUMBER
Y                  CLOB

SQL> create view t_lob_v 
as select x,dbms_lob.getlength(y) y from t;

View created.

Local Database:
SQL> desc t_lob_v@vdblink
 Name              Null?    Type
 ----------------- -------- ------------
 X                          NUMBER
 Y                          NUMBER

SQL> update t_lob_v@vdblink set y=y;
update t_lob_v@dlink set y=y
*
ERROR at line 1:
ORA-01733: virtual column not allowed here
ORA-02063: preceding line from DLINK
Thanks 

Tom Kyte
February 17, 2006 - 1:33 pm UTC

that would not work on a local database.

you are setting dbms_lob.getlegth - a function - that doesn't even make sense.

Update a remote lob

Vin, February 18, 2006 - 10:59 am UTC

which means, there is no method including using DBMS_LOB package to update a remote LOB.
The only possible ops as show in your example is using a mask to read a remote lob in insert as select.
I hope I understood it correctly.
Appreciate your time and effort.


Tom Kyte
February 18, 2006 - 4:45 pm UTC

sure there is, dbms_lob@remote.

you can call the remote dbms_lob package.

CLOB columns not accessible via database link

tariq, April 27, 2011 - 2:59 pm UTC

Dear Tom,

We are trying to access CLOB column through database link and we are getting (ORA-22992: cannot use LOB locators SELECTED FROM REMOTE TABLES)

we read your artical and perform the following steps but still issue persist.

1- Actual Query:
select a.subno,
a.transno,
a.excsystem,
a.spc_function,
a.equipid,
a.transstatus CRM_CMD_STATUS,
b.simcmd_status PRV_CMD_STATUS,
to_char(a.appdate, 'dd-MON-YYYY HH:MI:SS AM') Command_Time,
a.flex_fld1 Execution_Time,
to_char(b.command_Text)
from EIM_COMMAND_RECORD a , prv_sim_mml_transactions@TABS2MED611 b
where trunc(appdate) > trunc(sysdate - 2)
and a.transno = b.transaction_id
and (a.transstatus in ('10','20','40')
or b.simcmd_status in ('10','20','70','85'))
and a.exc != 'HLR1'
order by a.excsystem, a.transno;

--> We create view on the prv_sim_mml_transactions
Create view PRV.prv_sim_mml_transactions_view
AS
SELECT
COMMAND_ID ,
INTERFACE_ID ,
INTERNAL_CODE ,
NE_ID ,
PROTOCOL_ID ,
RESPONSE_ID ,
SIMCMD_QUEUE ,
SIMCMD_STATUS ,
ENTRY_DATETIME ,
LAST_CHANGE_DATETIME ,
TRANSACTION_ID ,
BUS_CMD_ID ,
BATCH_ID ,
CREATED_BY ,
MODIFIED_BY ,
DATE_CREATED ,
DATE_MODIFIED ,
IS_ROLLBACK ,
COMMAND_ORDER ,
COMMAND_ORDER_ARGUMENT ,
MMLCMDSET_ID ,
COMMAND_NR ,
INTERFACE_SEQ ,
RAW_RESPONSE ,
STRUCT_RESPONSE ,
CONSUMED_DATETIME ,
dbms_lob.getlength(COMMAND_TEXT) command_text
FROM PRV.prv_sim_mml_transactions
SYSTEM @ PRODMED>/

View created.

--> we tried to use this view but issue is here we create view based on getlength and this column getting the length of this column on the below query...please tell how can we create the above view which bring the result in the actual format/result.

-->new query based on view
select a.subno,
a.transno,
a.excsystem,
a.spc_function,
a.equipid,
a.transstatus CRM_CMD_STATUS,
b.simcmd_status PRV_CMD_STATUS,
to_char(a.appdate, 'dd-MON-YYYY HH:MI:SS AM') Command_Time,
a.flex_fld1 Execution_Time,
to_char(b.command_Text)
from EIM_COMMAND_RECORD a , prv_sim_mml_transactions_view@TABS2MED611 b
where trunc(appdate) > trunc(sysdate - 2)
and a.transno = b.transaction_id
and (a.transstatus in ('10','20','40')
or b.simcmd_status in ('10','20','70','85'))
and a.exc != 'HLR1'
order by a.excsystem, a.transno;

Tom Kyte
April 27, 2011 - 4:58 pm UTC

You are referencing the remote clob - command_text - with a local function, to_char.

You can use dbms_lob.substr( command_text, 4000, 1 ) in the remote view definition and reference that - it'll be a varchar2(4000), but only the first 4000 characters.

Else, you have to copy the lob over if you want the entire thing, put it in a global temporary table.

CLOB object continue

tariq, April 27, 2011 - 3:19 pm UTC

FYI.

SYSTEM @ PRODMED>desc prv.prv_sim_mml_transactions
Name Null? Type
----------------------------------------------------- -------- --------------------
COMMAND_ID NOT NULL NUMBER
INTERFACE_ID NOT NULL NUMBER
INTERNAL_CODE NUMBER
NE_ID NOT NULL NUMBER
PROTOCOL_ID NOT NULL NUMBER
RESPONSE_ID NUMBER
SIMCMD_QUEUE NOT NULL NUMBER(2)
SIMCMD_STATUS NOT NULL NUMBER(2)
ENTRY_DATETIME NOT NULL DATE
LAST_CHANGE_DATETIME NOT NULL DATE
TRANSACTION_ID NOT NULL VARCHAR2(50)
BUS_CMD_ID NOT NULL NUMBER
BATCH_ID VARCHAR2(10)
CREATED_BY VARCHAR2(30)
MODIFIED_BY VARCHAR2(30)
DATE_CREATED DATE
DATE_MODIFIED DATE
IS_ROLLBACK NUMBER(1)
COMMAND_ORDER VARCHAR2(20)
COMMAND_ORDER_ARGUMENT VARCHAR2(50)
MMLCMDSET_ID NUMBER(10)
COMMAND_NR NUMBER(2)
INTERFACE_SEQ VARCHAR2(20)
RAW_RESPONSE VARCHAR2(4000)
STRUCT_RESPONSE SYS.XMLTYPE
CONSUMED_DATETIME DATE
COMMAND_TEXT NOT NULL CLOB

CLOB object continue

tariq, April 27, 2011 - 3:19 pm UTC

FYI.

SYSTEM @ PRODMED>desc prv.prv_sim_mml_transactions
Name Null? Type
----------------------------------------------------- -------- --------------------
COMMAND_ID NOT NULL NUMBER
INTERFACE_ID NOT NULL NUMBER
INTERNAL_CODE NUMBER
NE_ID NOT NULL NUMBER
PROTOCOL_ID NOT NULL NUMBER
RESPONSE_ID NUMBER
SIMCMD_QUEUE NOT NULL NUMBER(2)
SIMCMD_STATUS NOT NULL NUMBER(2)
ENTRY_DATETIME NOT NULL DATE
LAST_CHANGE_DATETIME NOT NULL DATE
TRANSACTION_ID NOT NULL VARCHAR2(50)
BUS_CMD_ID NOT NULL NUMBER
BATCH_ID VARCHAR2(10)
CREATED_BY VARCHAR2(30)
MODIFIED_BY VARCHAR2(30)
DATE_CREATED DATE
DATE_MODIFIED DATE
IS_ROLLBACK NUMBER(1)
COMMAND_ORDER VARCHAR2(20)
COMMAND_ORDER_ARGUMENT VARCHAR2(50)
MMLCMDSET_ID NUMBER(10)
COMMAND_NR NUMBER(2)
INTERFACE_SEQ VARCHAR2(20)
RAW_RESPONSE VARCHAR2(4000)
STRUCT_RESPONSE SYS.XMLTYPE
CONSUMED_DATETIME DATE
COMMAND_TEXT NOT NULL CLOB

CLOB object continue

tariq, April 27, 2011 - 3:20 pm UTC

FYI.

SYSTEM @ PRODMED>desc prv.prv_sim_mml_transactions
Name Null? Type
----------------------------------------------------- -------- --------------------
COMMAND_ID NOT NULL NUMBER
INTERFACE_ID NOT NULL NUMBER
INTERNAL_CODE NUMBER
NE_ID NOT NULL NUMBER
PROTOCOL_ID NOT NULL NUMBER
RESPONSE_ID NUMBER
SIMCMD_QUEUE NOT NULL NUMBER(2)
SIMCMD_STATUS NOT NULL NUMBER(2)
ENTRY_DATETIME NOT NULL DATE
LAST_CHANGE_DATETIME NOT NULL DATE
TRANSACTION_ID NOT NULL VARCHAR2(50)
BUS_CMD_ID NOT NULL NUMBER
BATCH_ID VARCHAR2(10)
CREATED_BY VARCHAR2(30)
MODIFIED_BY VARCHAR2(30)
DATE_CREATED DATE
DATE_MODIFIED DATE
IS_ROLLBACK NUMBER(1)
COMMAND_ORDER VARCHAR2(20)
COMMAND_ORDER_ARGUMENT VARCHAR2(50)
MMLCMDSET_ID NUMBER(10)
COMMAND_NR NUMBER(2)
INTERFACE_SEQ VARCHAR2(20)
RAW_RESPONSE VARCHAR2(4000)
STRUCT_RESPONSE SYS.XMLTYPE
CONSUMED_DATETIME DATE
COMMAND_TEXT NOT NULL CLOB

More to Explore

CLOB/BLOB/etc

Complete documentation on Securefiles and Large Objects here