Skip to Main Content
  • Questions
  • Insert CLOB in a table in remote database

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Duraiswamy.

Asked: April 11, 2002 - 10:45 am UTC

Last updated: June 26, 2009 - 9:51 am UTC

Version: 8.1.7

Viewed 10K+ times! This question is

You Asked

I have two databases connected by dblink and have a synonymn created for the remote table.

I try to run a stored procedure in database 1 and insert records into the table in the remote database.

My stored procedure fails to insert because one of the field is CLOB datatype.

I select the CLOB from one of the table in database 1 and
I am able to successfully bind the clob variable to the callablestatement in java using setObject(i, object)

If I remove the CLOB field from the insert statement then I am able to do it successfully.

Using setObject I am able to insert successfully into a table in the same database using the same java code.

How to insert CLOB from one database to other ? Any examples will help.

The project requirement is that it has to move record by record into the remote table and not all the records at one time. Each record has to be processed additionally after entered into the remote table. Moreover the additional operation should be (if possible) in single transaction.

and Tom said...

You have two choices

1) You'll have to READ the entire clob back into the java app then and then stream it over to the other database. That would stink.

2) you can use an update. DON'T fetch the clob back to java, just get the primary key (say column "x"). You will insert the row into the remote site, inserting NULL for the clob. To copy the clob from database A to database B without having to bring the clob back to the client -- you will:

update t@ora817dev
set y = ( select y from t where x = ? )
where x = ?;

Here y is the clob, X is the primary key, t@ora817dev is the remote table, t is the local table.


It is bad to have "requirements" that dictate how things must be processed. It is good to have a requirement that tells you the end result, dictating how that end result must be achieved is totally backwards.

You will find this "process a row at a time in a client and insert into a remote table" processing to be just about the slowest way to achieve your goals (not to mention hard to maintain). A tiny bit of plsql in your life could save you tons of heavy duty java code!


--------------------------------------------------------------------------------

Why would you fetch the data BACK to java to insert it into the remote tables?

Just

insert into remote_table select whatever_you_want from local_table;


That'll move the clob. You cannot put a LOB locator from db1 into db2 -- it's a pointer, that pointer is NOT valid in db2, only in db1.


Rating

  (23 ratings)

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

Comments

One have to use Pl/sql

G.Singh, April 11, 2002 - 1:12 pm UTC

As mentioned by Tom A little codeing of pl/sql will slove everything. Just make a Procedure to do such kind of thing. Pass it the apporprate value so that it can transfer From DB1 to DB2 Usinglinks . This way Java won't come in between.

Insert CLOB in a table in remote database

Duraiswamy Padmanaban, April 11, 2002 - 3:00 pm UTC

This is quite helpful hint to update the CLOB. We had to do record by record because the remote table has primary key generated by a sequence.

Though I would love to use the following sql, in this case I cannot use

insert into remote_table select * from localtable

as I have not heard that Oracle has any way to generate unique id on the fly.

If there is anyway that can be solved then it would be great.

Anyway, thanks Tom it was really a useful hint to do an update after insert of rest of field. I will try it out.

Tom Kyte
April 11, 2002 - 7:14 pm UTC

*triggers*

*calling PLSQL from SQL*

*insert into table select my_seq.nextval, ..... *


there are many ways...

kevin, June 22, 2006 - 9:34 am UTC


kevin, June 22, 2006 - 9:36 am UTC

Hi Tom,

I tried to run procedure in local database, and procedure in local database had an insert sql statement, to insert data to table "A" in remote database which has table structure: (id NUMBER, test_clob CLOB). After exec the procedure in local database, it give me an error like:

ORA-22992: cannot use LOB locators selected from remote tables

My procedure in local database is look like:

Create or Replace procedure run_clob(p_id in number, p_file_name in varchar2)
AS
l_clob clob;
l_bfile bfile;
begin
insert into clob_table@dlog_link (id, test_clob ) values
(p_id, empty_clob() )
returning the_clob into l_clob;
l_bfile := BFILENAME ('TEMP_DIR', p_file_name);
DBMS_LOB.FILEOPEN(l_bfile);
DBMS_LOB.LOADFROMFILE(l_clob, l_bfile,
DBMS_LOB.getlength(l_bfile));
DBMS_LOB.FILECLOSE(l_bfile);
end;
/

Thank you

Tom Kyte
June 22, 2006 - 2:33 pm UTC

it is what it says - you have a lob locator that points to a REMOTE LOB.

You cannot do that to the lob locator over the dblink.

what you could do is load the clob locally, insert into over the dblink (table to table) - perhaps using a global temporary table.

kevin, June 22, 2006 - 2:41 pm UTC

Can you give me some sample code, how to do that please.

Thanks

Kevin, June 22, 2006 - 4:02 pm UTC

Tom,
First I've created procedure and run on local (database A).

Create or replace procedure test_clob (p_id in number)
AS
    l_clob    clob;
    l_bfile   bfile;
begin
    insert into clob_table (id, the_clob) values
    (p_id, empty_clob()) returning the the_clob into l_clob;
    
    l_bfile := BFILENAME ('TEMP_DIR', 'logfile.txt');
    DBMS_LOB.FILEOPEN(l_bfile);
    DBMS_LOB.LOADFROMFILE(l_clob, l_bfile,
            DBMS_LOB.getlength(l_bfile));
    DBMS_LOB.FILECLOSE(l_bfile);
end;
/

Procedure created

SQL> exec test_clob(1);

PL/SQL procedure successfully completed

SQL> select * from clob_table;
ID         THE_CLOB

1          testing clob column

After that, i've create a global temporary table in remote database (database B).

SQL> create global temporary table foo (id number, text clob);

Table created

SQL> insert into foo select * 
SQL> from clob_table@db_link;

0 row created.

When i ran "insert into foo select * from clob_table@db_link", one row support to insert into foo table instead of 0 row. Do you know why?

Thanks 

Tom Kyte
June 22, 2006 - 4:23 pm UTC

I meant to use the global temporary table the "other way around"

you

a) load into a global temporary table
b) insert into table@remote select * from gtt;


kevin, June 22, 2006 - 4:59 pm UTC

After i've followed your instruction like:

SQL> insert into foo@db_link from select * from gtt;

2 rows created.

And then i went to remote database 

SQL> select * from foo;

no rows selected.

but in local database, i did

SQL> select count(*) from foo@db_link;

2 rows created.

Can you tell me why no rows return when i do "select * from foo;" in remote database.

Thanks 

Tom Kyte
June 23, 2006 - 9:48 am UTC

did you commit?

Commit is the word

Michel Cadot, June 23, 2006 - 12:54 am UTC

You have to commit your insert before you can see the data in the remote database.



kevin, June 23, 2006 - 9:31 am UTC

I've follow your suggestion, but still can not see the data in remote database.

SQL> insert into foo@db_link select * from gtt;

1 row created.

SQL> commit;

Commit complete.

SQL> select count(*) from foo@db_link;

COUNT(*)
--------
       0

but when i ignore the commit statement and the count value is 1:

SQL> insert into foo@db_link select * from gtt;

1 row created.

SQL> select count(*) from foo@db_link;

COUNT(*)
-------
      1

But either way, still can not see the data in remote database. What is wrong with this?

Thanks Tom 

Tom Kyte
June 23, 2006 - 10:24 am UTC

if you do not use a gtt, what happens.



Kevin, June 23, 2006 - 10:37 am UTC

you meant, just pick another table instead of gtt.

That happen occur on window. But when i try to test on unix box with same procedure verything is fine. I don't know why.



Tom Kyte
June 23, 2006 - 1:14 pm UTC

sounds like you might be logging into the wrong databases during your testing then.



To Kevin

Michel Cadot, June 23, 2006 - 10:42 am UTC


What is your Oracle version (4 figures, please)?
And your Windows version (with SP number)?

Michel


kevin, June 23, 2006 - 3:31 pm UTC

My oracle is 9.2.0.1.0 and window is XP Home Edition SP 2

Tom,

Your answer is very excellent and very helpful on my project.
I have another question relate to previous post.

Create or replace procedure test_clob (p_id in number)
AS
    l_clob    clob;
    l_bfile   bfile;
begin
    insert into clob_table (id, the_clob) values
    (p_id, empty_clob()) returning the the_clob into l_clob;
    
    l_bfile := BFILENAME ('TEMP_DIR', 'logfile.txt');
    DBMS_LOB.FILEOPEN(l_bfile);
    DBMS_LOB.LOADFROMFILE(l_clob, l_bfile,
            DBMS_LOB.getlength(l_bfile));
    DBMS_LOB.FILECLOSE(l_bfile);
end;
/

I ran the procedure and data were inserted into the "clob_table" table and display by the following sql statement:

SQL> select id, dbms_lob.getlength(the_clob) from clob_table;

        ID DBMS_LOB.GETLENGTH(THE_CLOB)
---------- ----------------------------
         3                         2260
         4                         2260
         5                         8333
         6                        44497

After that, I've created a report in HTMLDB to display the information in the "clob_table" and i've an error like:

report error:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small

and I know the error popup because the length of the "id(6) column is greater than 32767 bytes. I've search around in this forum and otn website, but can not came up with any idea how to do it. Can you show me how to handle that situation please?

Thanks 
 

Tom Kyte
June 24, 2006 - 11:16 am UTC

try out the htmldb forum on otn.oracle.com - best place to get great answers for htmldb....

kevin, June 25, 2006 - 9:04 am UTC

Tom,

but how can i write a code to break a file and append the file, which located in server if the file greater than 32767.

thank you

Tom Kyte
June 25, 2006 - 11:39 am UTC

I don't know what you mean. No context here. what "file"?

kevin, June 26, 2006 - 1:56 pm UTC

Assume, i've create a table similar like:

CREATE table clob_table (id number, file_name varchar2(40),
                         output clob);

I'm also have two files name "logfile.txt and logfile2.txt" that are located in TEMP_DIR directory. "logfile.txt" has size = 10234 bytes, and "logfile2.txt" has size = 44479 bytes. 

I want to insert "logfile.txt and logfile2.txt" into clob_table by the following procedure below:

Create or replace procedure test_clob (p_id in number,
            p_file_name in varchar2, p_output in varchar2)
AS
    l_clob    clob;
    l_bfile   bfile;
begin
    insert into clob_table (id, file_name, output) values
    (p_id, p_file_name, empty_clob()) returning the output into l_clob;
    
    l_bfile := BFILENAME ('TEMP_DIR', 'p_output');
    DBMS_LOB.FILEOPEN(l_bfile);
    DBMS_LOB.LOADFROMFILE(l_clob, l_bfile,
            DBMS_LOB.getlength(l_bfile));
    DBMS_LOB.FILECLOSE(l_bfile);
end;
/

and first, i execute the procedure to insert a "logfile.txt" file into the clob_table by the following command:

SQL> exec test_clob (1,'log_file.txt', 'logfile.txt');

SQL> select id, file_name, dbms_lob.getlength(output)
     from clob_table;

ID    FILE_NAME     DBMS_LOB.GETLENGTH(OUTPUT)

1     log_file.txt  10234

SQL> select * from clob_table;

ID     FILE_NAME     OUTPUT

1      log_file.txt  AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

and then, i execute that procedure again to insert a "logfile2.txt" file into the "clob_table" table:

SQL> exec test_clob (2, 'log_file2.txt', 'logfile2.txt');


SQL> select id, file_name, dbms_lob.getlength(output)
     from clob_table;

ID       FILE_NAME       DBMS_LOB.GETLENGTH(OUTPUT)

1        log_file.txt    10234
2        log_file2.txt   44479

SQL> select * from clob_table;

ORA-06502: PL/SQL: numeric or value error: character string buffer to small;

Can you explain for me why select statement is ok when i try to retrieve the information for first time, but the second time, it poput the error message above.

How can i resolve that problems?

Thank your very much












 

Tom Kyte
June 26, 2006 - 2:43 pm UTC

that won't happen - do you have some fine grained access control or something else at play here?

That isn't a cut and paste, the error stack is too small.

Kevin, June 27, 2006 - 8:43 am UTC

Sorry, that was my fault, I meant that query cause in HTMLDB not in sqlplus. Can I ask you one more question?

How can i break a row into multiple piece if that row has a size greater than 32767 bytes.

Thank you so much.

Tom Kyte
June 27, 2006 - 9:32 am UTC

I don't understand what you mean by a "row has a size greater than 32k" or why you would need to break it up?

need more context.

Kevin, June 27, 2006 - 10:16 am UTC

Sorry, I'm not explain very clear.

Ok, Assume I have a file that located at TEMP_DIR directory, and TEMP_DIR directory contain the file name "log_file.txt" that has a size > 32767 bytes. I've created a procedure to insert "log_file.txt" that located at TEMP_DIR directory into "clob_table" table, like the following code below.

Create or replace procedure test_clob (p_id in number,
p_file_name in varchar2)
AS
l_clob clob;
l_bfile bfile;
begin

-- Need some code here to break the "log_file.txt"
-- before insert into clob_table. Because HTMLDB
-- just limited the size of each row up to 32767 bytes
-- otherwise will popup an error
-- report error:
-- ORA-06502: PL/SQL: numeric or value error:
-- character string buffer too small

insert into clob_table (id, the_clob) values
(p_id, empty_clob())
returning the the_clob into l_clob;

l_bfile := BFILENAME ('TEMP_DIR', 'p_file_name');
DBMS_LOB.FILEOPEN(l_bfile);
DBMS_LOB.LOADFROMFILE(l_clob, l_bfile,
DBMS_LOB.getlength(l_bfile));
DBMS_LOB.FILECLOSE(l_bfile);
end;
/

and I want to make a report to display the information in "clob_table" by using HTMLD. Since HTMLDB built using mod_plsql, the maximum size of a single report row is limited to 32767 bytes. That's why, i need to break the "log_file.txt" into multiple piece before insert into the "clob_table".

Thank you.


Tom Kyte
June 27, 2006 - 10:28 am UTC

you would not break up the lob, I have pages >32k on asktom here, I would not consider chunking stuff up.

You would create a report on the scalar data, showing the first bit of the text (perhaps as a link).

When you click on the link, you branch to a page that has a region of type PL/SQL. It would be passed the primary key (in order to locate the lob again).

You would select out the lob and do something like:

offset := 1;
lob_len := dbms_lob.getlength(l_lob);
loop
htp.prn( dbms_lob.substr( l_lob, 32000, offset ) );
offset := offset+32000;
exit when offset > lob_len;
end loop;


to print out the entire text.

Kevin, June 27, 2006 - 1:09 pm UTC

Thank you so much Tom. It's work wonderful.

Kevin, June 27, 2006 - 1:36 pm UTC

Tom,

Can I user HTML within pl/sql to make the text file look more organize? If yes, Please give me an example.

Thanks

Tom Kyte
June 27, 2006 - 2:45 pm UTC

I don't know what "more organize" means - you can use HTML, style sheets - anything you want to layout the text, much like I do on this page.

kevin, June 27, 2006 - 2:57 pm UTC

Can you give me little of sample code using HTML in PL/SQL?

Thank you

Tom Kyte
June 27, 2006 - 3:04 pm UTC

we already did, htp.prn!


just output any html you want


htp.prn( 'Hello world' );
htp.prn( htf.bold( 'Hello' ) || ' world' );

achieve the same, you just mark up the text, or if you like functions, there are functions that add the markup.

Kevin, June 27, 2006 - 3:22 pm UTC

Thank you so much Tom. My project can not complete without your help.

Thank you

Loading a File Into a Remote Database

Su Baba, February 21, 2007 - 7:47 pm UTC

Is there any way to load a file into a CLOB column in a remote database using PLSQL? The local machine only has Oracle Client (SQL*Plus) installed. I understand that dbms_lob.fileopen will only work when the file is on the database server. What's the workaround?
Tom Kyte
February 22, 2007 - 8:34 am UTC

perhaps the easiest way is:

a) create a scratch table locally
b) load lob using dbms_lob load from file locally
c) insert into remote select * from local to move it

Su Baba, February 22, 2007 - 11:40 am UTC

However, there is no local database. The local machine only has Oracle client installed. Given the case, is it possible to load the file using only PL/SQL?
Tom Kyte
February 22, 2007 - 11:56 am UTC

ahh, got it

you'll have to write a program or use sqlldr to load the file.

CLOB from procedure across db links work

Melissa, June 24, 2009 - 10:21 am UTC

OK so i've gathered from this that a CLOB can be copied using a procedure across a database link. I'm trying to bring the CLOB across the database link based on a trigger. I have it set up so that the trigger copies the CLOB from one database to another (via dblink). It seems to only work when the clob is under 4000 characters. Is this possible? My lead dba is saying its not possible to copy clobs over a db link in a trigger.

I was thinking of piecing it over 4000 characters at a time but that is very undesireable.

Heres my code:

SELECT count(*)
INTO intExists
FROM emaar_active.xxx@usar b
WHERE b.proj_no = :NEW.ts_proj_num;

IF intExists > 0 THEN
--UPDATE mash_admin.usr_re
-- SET ts_dd_1391 = empty_clob(),
-- ts_new_acquisition = empty_clob()
-- WHERE ts_id = :NEW.ts_id;

INSERT INTO stgng_area.usr_clob_temp_table
(dd_1391, ts_new_acquisition, ts_proj_num, ts_id)
SELECT b.justf_memo, b.proj_memo, b.proj_no, :NEW.ts_id
FROM emaar_active.xxx@usar b
WHERE b.proj_no = :NEW.ts_proj_num;

SELECT ts_new_acquisition
INTO :NEW.ts_new_acquisition
FROM stgng_area.usr_clob_temp_table
WHERE ts_proj_num = :NEW.ts_proj_num
AND ts_id = :NEW.ts_id;

DELETE FROM stgng_area.usr_clob_temp_table
WHERE ts_proj_num = :NEW.ts_proj_num
AND ts_id = :OLD.ts_id;

This is just a portion of my trigger. Also i'm pulling two clobs over and i've only seen this issue on one of the CLOBS i'm pulling over. The other seems to always come over fine. Is it possible that a column in my new instance could be corrupted?

Thanks in advance!!!!
Tom Kyte
June 26, 2009 - 9:51 am UTC

... My lead dba is saying its not possible
to copy clobs over a db link in a trigger.
....

correct, because most clobs are not done via a simple insert/update - they are modified piecewise - not via DML.


If you truly truly think (I emphasize 'think' - I think otherwise) that you need to replicate this data - use replication. If you do real time synchronous replication (as you are attempting) it becomes painfully obvious to everyone everywhere that you really meant to have A SINGLE DATABASE.


You cannot accomplish this via a trigger in real time, the data is not there.

Typically a lob is created via

insert into t (...., lob_column) values ( ...., empty_clob() ) returning lob_column into :host_variable;

stream data into :host_variable;


the trigger fires on insert, not on the streaming of data into the clob variable. the data just isn't there in the trigger at all in most cases.

More to Explore

CLOB/BLOB/etc

Complete documentation on Securefiles and Large Objects here