Small errors can happen and also resource control isn't always perfect in every company.
Björn Rost suggested to use DBMS_FLASHBACK.ENABLE_AT_TIME:
How about just calling DBMS_FLASHBACK.ENABLE_AT_TIME in your session? Why would you need an extra feature or button for that?— Bjoern Rost (@brost) September 28, 2018
A very clever suggestion!
Let's first look at the documentation:
DBMS_FLASHBACK
Using
DBMS_FLASHBACK
, you can flash back to a version of the database at a specified time or a specified system change number (SCN).and in more detail:
DBMS_FLASHBACK Overview
DBMS_FLASHBACK
provides an interface for the user to view the database at a particular time in the past, with the additional capacity provided by transaction back out features that allow for selective removal of the effects of individual transactions. This is different from a flashback database which moves the database back in time.When
DBMS_FLASHBACK is relevant only for the session in which it's called, so it doesn't change the database.DBMS_FLASHBACK
is enabled, the user session uses the Flashback version of the database, and applications can execute against the Flashback version of the database.But it's unclear what's meant by database in this context.
Here a small testcase which shows some unexpected results of DBMS_FLASHBACK:
(I slightly edite the text for better readability)
drop table x1; create table x1 (u number); insert into x1 (u) values (1); CREATE OR REPLACE FUNCTION "RETURN_SOMETHING" ( i NUMBER ) RETURN VARCHAR2 AS -- Version 1 BEGIN IF ( i = 1 ) THEN RETURN 'red'; ELSE RETURN 'blue'; END IF; END return_something; / select to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') now, u, return_something(u) rrr, dbms_flashback.get_system_change_number SCN from x1; NOW U RRR SCN ------------------- ---------- ----- ---------- 2018-10-01 19:37:56 1 red 24042787 exec sys.DBMS_SESSION.sleep(60);There should be nothing fancy up to this time.
The table and function are created and the select works fine.
I need the DBMS_SESSION.sleep to copy/paste the proper timestamp into the next block of code:
update x1 set u = 2 where u = 1; 1 row updated. CREATE OR REPLACE FUNCTION "RETURN_SOMETHING" ( i NUMBER ) RETURN VARCHAR2 AS -- Version 2 BEGIN IF ( i = 1 ) THEN RETURN 'oans'; ELSE RETURN 'zwoa'; END IF; END return_something; / select to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') now, u, return_something(u) rrr from x1; NOW U RRR ------------------- ---------- ----- 2018-10-01 19:39:32 2 zwoa
Still nothing spectacular here - just the preparation done.
Now onto the interesting part:
EXEC dbms_flashback.enable_at_time(to_timestamp('2018-10-01 19:38:00','YYYY-MM-DD HH24:MI:SS')); select to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') now, u, return_something(u) rrr from x1; NOW U RRR ------------------- ---------- ----- 2018-10-01 19:39:33 1 oans col text for A50 select text from dba_source where owner='BERX' and name='RETURN_SOMETHING' order by LINE asc; TEXT -------------------------------------------------- FUNCTION "RETURN_SOMETHING" ( i NUMBER ) RETURN VARCHAR2 AS -- Version 1 BEGIN IF ( i = 1 ) THEN RETURN 'red'; ELSE RETURN 'blue'; END IF; END return_something; 11 rows selected.
Here we can see how DBMS_FLASHBACK.ENABLE_AT_TIME is set to a time between the 1st insert & create function and the 2nd block.
With this setting, the content of table X1 is as expected. Also DBA_SOURCE shows the code of RETURN_SOMETHING.
But the function itself is not changed in memory and works as of it's state NOW, not at the given flashback time.
The flashback time version of RETURN_SOMETHING is even visible when you open it in SQLDeveloper (you have to believe me or test it).
Don't forget to clean up after the tests:
exec dbms_flashback.disable; select to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS') now, u, return_something(u) rrr from x1; NOW U RRR ------------------- ---------- ----- 2018-10-01 19:39:33 2 zwoa
For this testcase no COMMIT was used. ;-)
Keine Kommentare:
Kommentar veröffentlichen