I have a database "A" which accesses a table "B_TBL" in database "B" via database link to retrieve and insert data data. I also have a function in database "A" which get a BLOB from a table in database "B" over a database link. Since, I cannot create a View which retrieves a BLOb over a database link I have created a function. I am using a GLOBAL TEMPORARY table to get the BLOB in this function. The GLOBAL_NAMES is set to TRUE therefore I cannot have the same database link name in TEST and PRODUCTION and therefore requires me to change the View the Functions when I publish this from one database to another. I understand the need for the GLOBAL_NAMES to be set to true but is there a way that I could not have to change the View or modifying the functions when I publish on diferent databases?
-------------------------------------------------------------------------------
DATABASE A:
GLOBAL_NAMES = TRUE
CREATE PUBLIC DATABASE LINK B_DATABASE.XYZ.WORLD
CONNECT TO USERB
IDENTIFIED BY password
USING 'B_DATABASE.XYZ.WORLD';
CREATE VIEW B_TBL
AS
SELECT ID
FROM B_TBL@B_DATABASE.XYZ.WORLD;
CREATE GLOBAL TEMPORARY TABLE photo_temp
(
ID NUMBER,
photo BLOB
)
ON COMMIT DELETE ROWS
NOCACHE;
CREATE OR REPLACE function get_photo(id_p in number ) RETURN BLOB
is
photo_data blob := empty_blob();
begin
INSERT INTO photo_temp(ID,photo)
select ID,photo
from B_TBL@B_DATABASE.XYZ.WORLD
WHERE ID = id_p;
select photo_temp
into photo_data
from photo_temp
WHERE ID = id_p;
return photo_data;
exception
when NO_DATA_FOUND THEN
ROLLBACK;
RETURN NULL;
when others then
rollback;
RAISE_APPLICATION_ERROR('-20015','Exception in Function: get_photo(id_p in
number ). id: ='||id_p||', SQLERRM = '||SQLERRM||', SQLCODE = '||SQLCODE);
end get_photo;
/
-------------------------------------------------------------
DATABASE B:
TNS ENTRY: B_DATABASE.XYZ.WORLD
GLOBAL_NAMES = TRUE
CREATE TABLE B_TBL(
ID NUMBER,
PHOTO BLOB
);
you could use a synonym and create or replace it instead of a view or instead of a procedure referencing it.
but - at the end of the day, you obviously *have* to replace it, that is the entire goal of global names - to ensure "you are doing the right thing to the right database in the right environment".
You NEED them to point to different databases in test versus production.
I will say - your use of rollback is not necessary at all - and in fact I would say "is an extremely bad practice".
You have rollback in your no_data_found handler. If there is no data to be found, that means the insert could not have inserted anything - therefore, the rollback is not necessary (there is nothing to roll back) and - if you did do a rollback - you would EASILY break transactions that call you. If there was work to be rolled back, you should be using a savepoint ONLY - not rollback of the entire transaction:
begin
savepoint foo;
insert this
insert that
update the other thing
select into
exception
when no data found then rollback to FOO; return null;
that would be acceptable, but what you have *is not*, it is a bug.
Additionally, the rollback in the when others - not necessary. You are raising the exception - we'll roll back automagically when the error propagates to the client. consider:
ops$tkyte%ORA11GR2> create table t ( x int check (x>0) );
Table created.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> create or replace procedure p
2 as
3 begin
4 insert into t values ( 1 );
5 insert into t values ( 0 );
6 exception
7 when others then raise_application_error( -20015, 'Got error ' || dbms_utility.format_error_stack );
8 end;
9 /
Procedure created.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> exec p
BEGIN p; END;
*
ERROR at line 1:
ORA-20015: Got error ORA-02290: check constraint (OPS$TKYTE.SYS_C0012816) violated
ORA-06512: at "OPS$TKYTE.P", line 7
ORA-06512: at line 1
ops$tkyte%ORA11GR2> select * from t;
no rows selected
it is done for you automagically.
*remove your rollbacks, they are both wrong and should be consider a definite bug in the developed code*