As mentioned in a previous posting about ORA-22275, a temporary LOB can be turned into a persistent LOB by moving it into a table, however one thing is persistence and a different thing is LOB consistency.
Funny things happen when one gets fancy in the use of SAVEPOINT/ROLLBACK in conjunction with LOBs.
The following PL/SQL block represents a simple scenario of an ill-designed procedure that is rolling back under a certain condition thus invalidating the LOB pointer.
declareThe procedure can be modified as follows:
l_clob clob;
l_id number;
simulated_error exception;
begin
l_clob := dbms_xmlgen.getxml('select * from user_tables');
insert into files(document) values(l_clob) returning id into l_id;
dbms_lob.freetemporary(l_clob);
select document into l_clob
from files where id = l_id;
begin
raise simulated_error;
exception
when simulated_error then
rollback;
when others then raise;
end;
dbms_output.put_line(dbms_lob.getlength(l_clob));
end;
/
ORA-22922: nonexistent LOB value
ORA-06512: at "SYS.DBMS_LOB", line 560
ORA-06512: at line 19
declareThis time no ORA-22922 will be raised and apparently we managed to transform a temporary LOB locator into a persistent one without inserting any rows, because the insert statement was rolled back.
l_clob clob;
l_id number;
simulated_error exception;
begin
savepoint "test";
l_clob := dbms_xmlgen.getxml('select * from user_tables');
insert into files(document) values(l_clob) returning id into l_id;
dbms_lob.freetemporary(l_clob);
select document into l_clob
from files where id = l_id;
begin
raise simulated_error;
exception
when simulated_error then
rollback to "test";
when others then raise;
end;
dbms_output.put_line(dbms_lob.getlength(l_clob));
end;
/
Interestingly enough on my Oracle XE instance, if i further modify the program as follows, i'm eventually getting ORA-00600:
declareIf i insert a COMMIT statement before the final INSERT, we're back to the initial situation:
l_clob clob;
l_id number;
simulated_error exception;
begin
savepoint "test";
l_clob := dbms_xmlgen.getxml('select * from user_tables');
insert into files(document) values(l_clob) returning id into l_id;
dbms_lob.freetemporary(l_clob);
select document into l_clob
from files where id = l_id;
begin
raise simulated_error;
exception
when simulated_error then
rollback to "test";
when others then raise;
end;
dbms_output.put_line(dbms_lob.getlength(l_clob));
insert into files(document) values(l_clob);
commit;
end;
/
ORA-00600: internal error code, arguments: [7999], [300], [], [], [], [], [], []
ORA-06512: at line 21
declareIn conclusion ORA-22922 is a symptom of a program that is incorrectly handling LOB locators across transactions.
l_clob clob;
l_id number;
simulated_error exception;
begin
savepoint "test";
l_clob := dbms_xmlgen.getxml('select * from user_tables');
insert into files(document) values(l_clob) returning id into l_id;
dbms_lob.freetemporary(l_clob);
select document into l_clob
from files where id = l_id;
begin
raise simulated_error;
exception
when simulated_error then
rollback to "test";
when others then raise;
end;
dbms_output.put_line(dbms_lob.getlength(l_clob));
commit;
insert into files(document) values(l_clob);
commit;
end;
/
ORA-22922: nonexistent LOB value
ORA-06512: at line 22
For a complete review of weird effects achievable by tampering with LOB locators and partial LOB manipulation procedures, see the linked paragraph in the Oracle Application Developer's Guide for Large Objects - Advanced design considerations chapter.
See message translations for ORA-22922 and search additional resources.
2 comments:
I am getting this error sporadically. The same transaction works fine if I retry. Below is my table definition.
lob(DOC_DATA) store as securefile LS__DD1
(
tablespace DBLOB disable storage in row chunk 16k retention auto nocache logging
storage(maxextents unlimited pctincrease 0 freelists 12 freelist groups 2)
index LI__DD1 (tablespace DBLOB storage(maxextents unlimited pctincrease 0 freelists 6))
)
I have a simple insert statement in my Stored procedure.
The algorithm is as below.
sp name (arrDocData IN mytablename%TYPE,)
begin
insert into table_name (col1,col2,blobcol) values (inval,inval2,arrDocData)
commit write batch nowait ;
exception
errmsg:=errormsg;
rollback
end SPname;
My guess is that since you are committing the lob asynchronously, sometimes it works because it finishes quickly, sometimes doesn't.
It could be thatthe async feature is not "fit" for this specific case.
Just my 50 cents.
Post a Comment