Name: | DBMS_RCVMAN |
Status: | VALID |
Last modify: | 05/12/2002 |
Created: | 05/12/2002 |
Owner | Name | Type |
RMAN | DBMS_RCVCAT | PACKAGE BODY |
RMAN | DBMS_RCVMAN | PACKAGE BODY |
CREATE OR REPLACE PACKAGE "RMAN"."DBMS_RCVMAN" is
-- DE-HEAD <- tell SED where to cut
----------------------------------------
-- PUBLIC VARIABLES AND TYPES SECTION --
----------------------------------------
TRUE# CONSTANT number := 1;
FALSE# CONSTANT number := 0;
-- The values here must never be changed, because the 8.0 rman executables have
-- these values hard-coded in the krmkbt enum in krmk.h. The setFrom procedure
-- in particular is using hard-coded values.
-- The 8.1.5 rman executable calls a procedure, set_package_constants, that
-- re-assigns these constants to whatever the package needs them to be, then
-- queries the package for their new values. The 8.1.5 rman does not care
-- what the values are, however, the cursor used by reportGetDFDel used to use
-- these values to perform an order-by to return rows in preference order.
-- The preference order is used to decide which ones to delete.
-- As of 8.1.6, the order-by in reportGetDFDel is independant of these values.
-- The 8.1.6 rman does not use these values at all, except in setFrom.
-- However, for backwards compatibility with the 8.1.5 RMAN, these must remain
-- as public package constants.
COPY number := 1; -- any image copy of a file
FULL_DF_BACKUP number := 2; -- datafile in a full backup set
INCREMENTAL_DF_BACKUP number := 3; -- datafile in an incr backup set
BACKUP number := 4; -- any file in a backup set
OFFLINE_RANGE number := 5; -- an offline range
CUMULATIVE number := 6; -- cumulative incremental - for LIST only
PROXY number := 7; -- any proxy copy of a file
-- Recovery Action Kinds (Obsolete as of 8.1.6) --
implicitOfflRange CONSTANT NUMBER := 2**0;
cleanRange CONSTANT NUMBER := 2**1;
applyOfflRange CONSTANT NUMBER := 2**2;
dfCopy CONSTANT NUMBER := 2**3;
proxyFull CONSTANT NUMBER := 2**4;
buSet CONSTANT NUMBER := 2**5;
applyIncremental CONSTANT NUMBER := 2**6;
redo CONSTANT NUMBER := 2**7;
-- kind masks
maxKind CONSTANT NUMBER := redo; -- last real kind above
allKind CONSTANT NUMBER := (maxKind*2) - 1; -- all real backup types
fullKind CONSTANT NUMBER := dfCopy + proxyFull + buSet;
tagKind CONSTANT NUMBER := fullKind + applyIncremental;
-- pseudo kinds
deletedKind CONSTANT NUMBER := maxKind*2; -- action deleted
----------------------------------
-- Backupset Availability Masks --
----------------------------------
BSavailable CONSTANT BINARY_INTEGER := 2**0;
BSunavailable CONSTANT BINARY_INTEGER := 2**1;
BSdeleted CONSTANT BINARY_INTEGER := 2**2;
BSexpired CONSTANT BINARY_INTEGER := 2**3;
-- BSpartial_avail is a backupset validation mask and NOT a backuppiece
-- filter. For eg. to get 'A', 'U', 'X' pieces and to enable validation
-- to succeed for partially available backupset use
-- BSpartial_avail + BSavailable + BSunavailable + BSexpired.
BSpartial_avail CONSTANT BINARY_INTEGER := 2**4;
----------------------
-- BackupType Mask ---
----------------------
BSdatafile_full CONSTANT BINARY_INTEGER := 2**0;
BSdatafile_incr CONSTANT BINARY_INTEGER := 2**1;
BSarchivelog CONSTANT BINARY_INTEGER := 2**2;
---------------------------
-- ControlfileType Mask ---
---------------------------
BScfile_all CONSTANT BINARY_INTEGER := 2**0; -- shouldn't be altered
BScfile_auto CONSTANT BINARY_INTEGER := 2**1;
---------------------
-- Datafile Record --
---------------------
TYPE dfRec_t IS RECORD
(
dfNumber number,
dfCreationSCN number,
dfCreationTime date,
fileName varchar2(1024),
tsName varchar2(30),
tsNumber number,
status number,
blocks number,
blockSize number,
kbytes number,
unrecovSCN number,
stopSCN number,
readOnly number,
rfNumber number,
inBackup number, -- if greater than 0 then
-- included_in_database_backup is set
auxName varchar2(1024)
);
-------------------------
-- Archived Log Record --
-------------------------
TYPE alRec_t IS RECORD
(
key number,
recid number,
stamp number,
thread number,
sequence number,
fileName varchar2(1024),
lowSCN number,
lowTime date,
nextSCN number,
nextTime date,
rlgSCN number,
rlgTime date,
blocks number,
blockSize number,
status char(1),
compTime date,
duplicate number
);
-- All of the queries which return data about a backup/imagecopy/proxycopy
-- select into a rcvRec_t record type. We have standardized all of our
-- queries to have a common select-list and the results of the queries are
-- returned through a common public package function. The reason for this is
-- so that krmk.pc can populate its internal data structures consistantly,
-- regardless of what particular procedure it has called to query the catalog.
-- By having all queries select into the same record type, we can ensure
-- that all queries use the same select list. Any new fields that get added
-- to this record will require updating the select lists of all queries.
-- Failure to make the correct updates will result in PLSQL giving an error
-- when the package body is re-created, so the error will be easily detected
-- without the need to run any test suite.
-- The record is divided into three sections. These correpond to
-- three krmk.h data structures which will be populated with the data
-- from this record. Refer to krmk.h for a description of the purpose
-- of each of these three data strucutres.
-- Think of this as: the container acts on the object.
---------------------
-- Recovery Record --
---------------------
TYPE rcvRec_t IS RECORD
(
-- *** Recovery Container Section ***
type_con number(3), -- recovery container type
key_con number(15), -- primary key
recid_con number(10), -- recid
stamp_con number(10), -- stamp
setStamp_con number(10), -- set count if backup set (null)
setCount_con number(10), -- set stamp if backup set (null)
bsRecid_con number(10), -- backup set recid (null)
bsStamp_con number(10), -- backup set stamp (null)
bsKey_con number(15), -- backup set key (null)
bsLevel_con number(1), -- backup set level (null)
bsType_con char(1), -- backup set type
elapseSecs_con number(10), -- backup set elapse seconds (null)
pieceCount_con number(5), -- backup set piece count (null)
fileName_con varchar2(1024), -- filename if a copy (or) piece (null)
tag_con varchar2(32), -- tag (null)
-- filled in by addAction() for
-- backup sets
copyNumber_con number(3), -- backup set copy# (null) maxlimit 256
-- filled in by addAction() only
status_con char(1), -- status (null)
blocks_con number(10), -- size of file in blocks (null)
blockSize_con number(5), -- block size (null)
deviceType_con varchar2(255), -- device type required (null)
-- filled in by addAction() for
-- backup sets
compTime_con date, -- completion time
cfCreationTime_con date, -- controlfile creation time if
-- offline range (null)
pieceNumber_con number,
bpCompTime_con date,
-- *** Recovery Action Section ***
type_act number(2), -- recovery action type
fromSCN_act number(15),
toSCN_act number(15),
toTime_act date,
rlgSCN_act number(15),
rlgTime_act date,
dbincKey_act number(15),
level_act number(1),
-- *** Recovery Object Section ***
dfNumber_obj number(6),
dfCreationSCN_obj number(15),
cfSequence_obj number(15), -- controlfile autobackup sequence
cfDate_obj date, -- controlfile autobackup date
logSequence_obj number(10),
logThread_obj number(4),
logRlgSCN_obj number(15),
logRlgTime_obj date,
logLowSCN_obj number(15),
logLowTime_obj date,
logNextSCN_obj number(15),
logNextTime_obj date,
-- *** Retention Policy Section ***
keep_options number(4),
keep_until date,
-- *** Optimization Action Section ***
afzSCN_act number(15),
rfzTime_act date,
rfzSCN_act number(15)
);
------------------------------
-- Recovery Container Types --
------------------------------
-- NOTE: Order is important, it is used in an ORDER BY.
offlineRangeRec_con_t CONSTANT NUMBER := 2**0;
proxyCopy_con_t CONSTANT NUMBER := 2**1;
imageCopy_con_t CONSTANT NUMBER := 2**2;
backupSet_con_t CONSTANT NUMBER := 2**3;
deleted_con_t CONSTANT NUMBER := 2**8;
-- Masks
backupMask_con_t CONSTANT NUMBER := proxyCopy_con_t + imageCopy_con_t +
backupSet_con_t;
tagMask_con_t CONSTANT NUMBER := proxyCopy_con_t + imageCopy_con_t +
backupSet_con_t;
---------------------------
-- Recovery Action Types --
---------------------------
full_act_t CONSTANT NUMBER := 2**0;
incremental_act_t CONSTANT NUMBER := 2**1;
redo_act_t CONSTANT NUMBER := 2**2;
offlineRange_act_t CONSTANT NUMBER := 2**3;
cleanRange_act_t CONSTANT NUMBER := 2**4;
implicitRange_act_t CONSTANT NUMBER := 2**5;
spanningRange_act_t CONSTANT NUMBER := 2**6;
-----------------------------------------
-- Recovery Record Returning Functions --
-----------------------------------------
-- These defines are used as the funCode arg to getRcvRec to tell it which
-- function it should call. We do this so that krmk.pc can have a single
-- interface routine for getting a rcvRec_t.
getCfCopy CONSTANT NUMBER := 0;
getDfCopy CONSTANT NUMBER := 1;
getAnyProxy CONSTANT NUMBER := 2;
getCfBackup CONSTANT NUMBER := 3;
listCfCopy CONSTANT NUMBER := 4;
listDfCopy CONSTANT NUMBER := 5;
listCfBackup CONSTANT NUMBER := 6;
listDfBackup CONSTANT NUMBER := 7;
listAlBackup CONSTANT NUMBER := 8;
listDfProxy CONSTANT NUMBER := 9;
getRecovAction CONSTANT NUMBER := 10;
getAlBackup CONSTANT NUMBER := 11;
listAlCopy CONSTANT NUMBER := 12;
listBSet CONSTANT NUMBER := 13;
getSfBackup CONSTANT NUMBER := 14;
listSfBackup CONSTANT NUMBER := 15;
getAllBSet CONSTANT NUMBER := 16;
-----------------------
-- Backup Set Record --
-----------------------
TYPE bsRec_t IS RECORD
(
recid number,
stamp number,
key number,
setStamp number,
setCount number,
bsType char(1),
level number,
elapseSecs number,
compTime date,
status char(1),
pieceCount number,
keep_options number(4),
keep_until date
);
------------------------
-- Backup Piece Record --
-------------------------
TYPE bpRec_t IS RECORD
(
recid number,
stamp number,
key number,
bskey number,
setStamp number,
setCount number,
pieceNumber number,
copyNumber number,
status char(1),
compTime date,
handle varchar2(1024),
tag varchar2(32),
deviceType varchar2(255)
);
---------------------------------
-- Backupset Validation Record --
---------------------------------
TYPE validBackupSetRec_t IS RECORD
(
deviceType varchar2(255),
tag varchar2(32), -- may be null
copyNumber number, -- null if code 2 or 3
code number -- 1 => same copy#
-- 2 => mix of copy#s, but
-- same tag
-- 3 => mix of copy#s and tags
);
--------------------
-- backup history --
--------------------
TYPE bhistoryRec_t IS RECORD
(
key number,
device_type varchar2(255),
dfNumber number,
create_scn number,
reset_scn number,
reset_time date,
ckp_scn number,
stop_scn number,
logThread number,
logSequence number,
setStamp number,
setCount number,
compTime date,
nbackups number
);
-----------------------------------------------------
-- PUBLIC FUNCTION/PROCEDURE SPECIFICATION SECTION --
-----------------------------------------------------
----------------------------------------
-- Debugging functions and procedures --
----------------------------------------
FUNCTION dumpState(
lineno IN number)
RETURN varchar2;
PROCEDURE setDebugOn;
PROCEDURE setDebugOff;
----------------------------
-- Package Initialization --
----------------------------
-- This is a vestigal function that was released to customers in 8.1.3 Beta.
-- It is no longer called, and is no longer needed, but must still be here
-- because this version of the package may be called by an 8.1.3 rman
-- executable.
PROCEDURE initialize(rman_vsn IN number);
-- Used by 8.1.5 to re-assign the order of the backup_type constants to their
-- correct order. This procedure is not called by 8.1.4-, so the constants
-- will reamin set to the above values for those executables.
PROCEDURE set_package_constants;
-----------------------
-- Utility functions --
-----------------------
FUNCTION stamp2date(stamp IN number) RETURN date;
------------------------------
-- Set Database Incarnation --
------------------------------
-- setDatabase selects which target database subsequent dbms_rcvman
-- procedures operate on. Note that only the current incarnation can be
-- selected. If the target database or its current incarnation is not
-- registered then setDatabase will fail.
-- setDatabase sets the package state variables to point to the selected
-- database and its current incarnation.
-- The settings will be valid until the end of the session unless setDatabase
-- is called again
-- When dbms_rcvman package executes against the target database controlfile,
-- setDatabase just returns without doing anything.
-- Input parameters:
-- db_id
-- the value of kccfhdbi from the controlfile of the target database
-- db_name
-- the name of the database
-- reset_scn
-- the resetlogs SCN of this database
-- reset_time
-- the resetlogs time
-- Exceptions:
-- DATABASE_NOT_FOUND (ORA-20001)
-- No database with the given db_id was found in the recovery catalog
-- The database must be registered using registerDatabase first
-- DATABASE_INCARNATION_NOT_FOUND (ORA-20003)
-- No database incarnation matches the given arguments
-- The database incarnation must be registered using resetDatabase first
PROCEDURE setDatabase(
db_name IN varchar2
,reset_scn IN number
,reset_time IN date
,db_id IN number);
-- setDbincKey used in lieu of setDatabase for when SET DBID command is
-- issued.
PROCEDURE setDbincKey(
key IN number);
-- getParent Incarnation returns the parent incarnation. If resetlogs_change#
-- is NULL on input, then the current incarnation is returned. Returns TRUE
-- if a row was returned, otherwise returns FALSE.
FUNCTION getParentIncarnation(
resetlogs_change# IN OUT number
,resetlogs_time IN OUT date)
RETURN number;
-- getCheckpoint gets and returns the highest recovery catalog checkpoint SCN
-- for FULL checkpoints. This SCN indicates how current the datafilenames and
-- lognames in the recovery catalog are. This SCN can be compared with a
-- backup controlfile SCN to decide which name to use if they differ.
PROCEDURE getCheckpoint(
scn OUT number
,seq OUT number);
-- This version of getCheckpoint is only used internally by
-- dbms_rcvcat.cleanupCKP, to find out which rows can't be deleted from ckp.
PROCEDURE getCheckpoint(
scn OUT number
,seq OUT number
,ckp_key_1 OUT number
,ckp_key_2 OUT number);
-------------------
-- Query Filters --
-------------------
-- setCompletedRange sets completedBefore and/or completedAfter filters for
-- use by computeRecoveryActions.
-- setLikePattern sets fileName patter for computeRecoveryActions.
--
-- setUntilTime, setUntilScn, setUntilLog, resetUntil These procedures are
-- used to inform dbms_rcvman of an until_clause. The setUntil remains in
-- effect until another setUntil has been called, or until resetUntil has been
-- called. If none of these have been called, then all queries for name
-- translation, restore, and recovery should assume that a complete recovery
-- is being done. Otherwise, all restore and recovery queries should limit
-- their replies to backup sets and datafile copies that are appropriate for
-- use in an incomplete recovery until the specified until condition. Name
-- translations should be done relative to the specified epoch.
--
-- "appropriate" means that the fuzziness of the backup datafile or datafile
-- copy ends at an SCN less than the untilChange SCN (for untilChange), or the
-- low SCN of the specified log (for untilLog), or the fuzziness timestamp is
-- less than the specified time (for unttime). Note that datafiles have three
-- kinds of fuzziness, all of which must be less than the specified SCN or
-- time. If the fuzziness of a datafile is unknown, then it should be
-- ignored.
--
-- The setUntil procedures will signal an error when executed against
-- the target database controlfile. The resetUntil procedure can be
-- executed against the controlfile, it but doesn't have any effect.
-- Input parameters:
-- unttime
-- The incomplete recovery will stop when this timestamp is reached
-- in the redo log.
-- scn
-- The incomplete recovery will stop when this scn is reached in the redo
-- log.
-- sequence#, thread#
-- The incomplete recovery will stop when this log becomes the very next
-- log to be applied.
--
-- Exceptions:
-- NO_RECOVERY_CATALOG (ORA-20300)
-- this operation is not supported without the recovery catalog
-- SEQUENCE_IS_NULL (ORA-20205)
-- A null log sequence# was given
-- LOG_MISSING (ORA-20206)
-- No log with the give thread# and sequence# was found
PROCEDURE setCompletedRange(
after IN date
,before IN date);
PROCEDURE setLikePattern(
pattern IN varchar2);
-- Obsolete as of 8.1.6
PROCEDURE setAllFlag(
flag IN boolean);
PROCEDURE setAllIncarnations(
flag IN boolean);
PROCEDURE setUntilTime(
unttime IN date);
PROCEDURE setUntilScn(
scn IN number);
PROCEDURE setUntilLog(
sequence# IN number
,thread# IN number);
FUNCTION getUntilTime return date;
FUNCTION getUntilScn return number;
PROCEDURE resetUntil;
-- setFrom is used to limit the potential restore candidates to either
-- backup sets or datafile copies, or to allow either kind of file to
-- be used.
--
-- Input parameters:
-- restorefrom
-- One of BACKUP, COPY, or NULL.
PROCEDURE setFrom(
restorefrom IN number DEFAULT NULL);
-- setDeviceType specifies the type of an allocated device. It is called 1 or
-- more (up to 8) times , depending on the number of different device types
-- that are allocated. dbms_rcvman should return only files that can be
-- accessed through one of the device types specifed through this call.
--
-- Input parameters:
-- type
-- type of the device
-- Exceptions:
-- NULL_DEVICE_TYPE
-- A null device type was specied
-- TOO_MANY_DEVICE_TYPES
-- At most 8 device types can be specified
PROCEDURE setDeviceType(
type IN varchar2);
-- setDeviceTypeAny is an alternative to setDeviceType. It causes dbms_rcvman
-- to return a backup set on ANY device type.
PROCEDURE setStandby(
stby IN boolean);
PROCEDURE setDeviceTypeAny;
-- resetDeviceType resets the list of device types to null.
PROCEDURE resetDeviceType;
-- setTag is used to limit the restore candidates to backups and copies with
-- the given tag. If the tag is NULL then all backups and copies are searched
-- by the find functions.
--
-- Input parameters:
-- tag
-- tag of the datafile copies to be translated
-- The tag must be passed in uppercase ### ok?
PROCEDURE setTag(tag IN varchar2 DEFAULT NULL);
-- resetAll calls resetUntil, setFrom, resetDevice and setTag to reset
-- everything.
PROCEDURE resetAll;
---------------------------
-- Backup Set Validation --
---------------------------
-- Use the findValidBackupSetRec public variable to save a backupset record
-- for later use as an input argument to this procedure.
findValidBackupSetRcvRec rcvRec_t; -- place to save a rcvRec_t
PROCEDURE findValidBackupSet(
backupSetRec IN rcvRec_t
,deviceType IN varchar2 DEFAULT NULL
,tag IN varchar2 DEFAULT NULL
,available IN number DEFAULT TRUE# -- for compat.
,unavailable IN number DEFAULT FALSE# -- for compat.
,deleted IN number DEFAULT FALSE# -- for compat.
,expired IN number DEFAULT FALSE# -- for compat.
,availableMask IN binary_integer DEFAULT NULL); -- for compat.
findValidBackupSetBsRec bsRec_t; -- place to save a bsRec_t
-- Obsolete as of 8.1.7
PROCEDURE findValidBackupSet(
backupSetRec IN bsRec_t
,deviceType IN varchar2 DEFAULT NULL
,tag IN varchar2 DEFAULT NULL
,available IN number DEFAULT TRUE# -- for compat.
,unavailable IN number DEFAULT FALSE# -- for compat.
,deleted IN number DEFAULT FALSE# -- for compat.
,expired IN number DEFAULT FALSE# -- for compat.
,availableMask IN binary_integer DEFAULT NULL); -- for compat.
FUNCTION getValidBackupSet(
validBackupSetRec OUT validBackupSetRec_t
,checkDeviceIsAllocated IN number DEFAULT FALSE#)
RETURN number; -- TRUE# -> got a record
-- FALSE# -> no_data_found
---------------------
-- Get an rcvRec_t --
---------------------
-- This function is a cover function for all procedures/functions that
-- return a rcvRec_t. It routes the call to the correct procedure. It
-- is provided for the convienence of krmk.pc. The function return value
-- is whatever the underlying function returns. If we call a procedure,
-- then getRcvRec returns 0. Refer to the funCode list above in the
-- types/variables section.
FUNCTION getRcvRec(
funCode IN number
,rcvRec OUT rcvRec_t
,callAgain OUT number)
RETURN number;
--------------------------
-- Datafile Translation --
--------------------------
-- translateTableSpace translates a tablespace name into a list of datafile
-- numbers. translateDataBase translates the database into a list of datafile
-- numbers in the database excluding datafiles belonging to tablespaces
-- specified using skipTableSpace. The translation is performed relative to
-- epoch setting currently in use. getDataFile is used to obtain the datafile
-- numbers, one at a time until null is returned.
-- When doing the translation relative to current time the client should
-- ensure that recovery catalog is up-to-date. When doing translations
-- relative to an point-in-time in the past two potential anomalies may
-- show up.
--
-- 1) files belonging to a tablespace that was dropped before the point-in-time
-- may be returned since the drop_scn and drop_time are approximations.
-- As a result of this point-in-time recovery will restore and recover
-- a tablespace which will be dropped before the database is opened.
-- No real harm, just extra work for the recovery. And this won't happen
-- if rcvcat is resynced immediatly after dropping a tablespace.
-- 2) A tablespace which is created and dropped between two consecutive
-- recovery catalog resyncs will never be recorded in the rcvcat. It is
-- conceivable that such a tablespace existed at the intended point-in-time.
-- As a result the tablespace will not be recovered and must be dropped
-- after the database is opened. The worst case scenario is that a rollback
-- segment was also created in this tablespace. The recovered database
-- might fail to rollback some transactions. Again, this won't happen if
-- rcvcat is always resynced after creating a tablespace.
-- PS. These anomalies won't occur if the point-in-time is chosen to be
-- a rcvcat checkpoint.
-- Input parameters:
-- ts_name
-- name of the tablespace to be translated or skipped.
-- The name must be in uppercase
-- Exceptions:
-- TABLESPACE_DOES_NOT_EXIST (ORA-20202)
-- the tablespace to be translated does not exists (does not have any
-- datafiles). Check that the recovery catalog is current.
-- TRANSLATION_IN_PROGRESS (ORA-20203)
-- the previous translation conversation is still in progess.
-- To terminate get all datafiles with getDataFile.
-- TRANSLATION_NOT_IN_PROGRESS (ORA-20204)
-- getDataFile was called with no translation in progress
PROCEDURE translateDatabase(
sinceUntilSCN IN number DEFAULT NULL);
PROCEDURE skipTableSpace(
ts_name IN varchar2);
PROCEDURE translateTablespace(
ts_name IN varchar2);
-- translateDataFile translates the datafile name/number into
-- a datafile number and creation SCN and filename. getDataFile must
-- be called to obtain the translation info, just as for the other translate
-- functions.
-- Unlike the other translation functions, translateDatafile by name is always
-- performed relative to current time. If an until setting is in effect,
-- and if the filename is ambiguous, then an exception is raised. Ambiguous
-- means that the filename refers to different datafile at the until time than
-- it does at the current time. This happens only when a filename has been
-- reused. When fno and ckpscn are passed, the filename and other info as of
-- that scn is returned.
-- Input parameters:
-- fname
-- name of the datafile to be translated.
-- The name must be a normalized filename.
-- fno
-- The datafile number. If the datafile number was not in use at the
-- until time, then an exception is raised.
-- Exceptions:
-- DATAFILE_DOES_NOT_EXIST (ORA-20201)
-- the datafile to be translated does not exists
-- Check that the recovery catalog is current.
PROCEDURE translateDataFile(
fname IN varchar2);
PROCEDURE translateDatafile(
fno IN number);
PROCEDURE translateDatafile(
fno IN number
,ckpscn IN number);
-- translateAllDatafile returns a list of all datafiles that ever
-- existed in this database.
PROCEDURE translateAllDatafile;
PROCEDURE translateCorruptList;
PROCEDURE getDatafile(
dfRec OUT dfRec_t
,oldClient IN boolean DEFAULT FALSE);
-- Obsolete as of 8.1.6
PROCEDURE getDataFile(
file# OUT number
,crescn OUT number
,creation_time OUT date
,fname OUT varchar2
,ts_name OUT varchar2
,status OUT number
,blksize OUT number
,kbytes OUT number
,blocks OUT number
,unrecoverable_change# OUT number
,stop_change# OUT number
,read_only OUT number);
----------------------------
-- Online Log Translation --
----------------------------
-- translateOnlineLogs translates the database to a list of online redo logs.
-- The translation is always performed relative to current epoch.
PROCEDURE translateOnlineLogs;
PROCEDURE getOnlineLog(
fname OUT varchar2
,thread# OUT number
,group# OUT number);
-----------------------------
-- Archivedlog Translation --
-----------------------------
-- translateArchivedLogKey translates the archived log key to a archived
-- log recid and stamp in V$ARCHIVED_LOG.
-- translateArchivedLogRange* procedures translate a specified
-- archive log range to a list of archived logs.
-- getArchivedLog is used to get the recid and stamp for each archived log,
-- one at a time until null is returned.
-- The available, unavailable and deleted parameters are used to limit
-- the translation to archived logs with the desired status. For example,
-- only available archived logs can be backed up, but unavailable and deleted
-- archived logs can be restored from backups.
-- The duplicates parameter controls whether the translation returns all
-- archived logs or eliminates duplicate ones. Archived logs that have the
-- same thread#, sequence# and low_scn are considered duplicates. (duplicate
-- archived logs are usually created by copying archived logs).
-- Note that only archived logs recorded in the recovery catalog or
-- controlfile file are returned. If there is an archived log that belongs
-- to the range but is not known, there will be a "hole" in the range.
-- Input parameters:
-- al_key
-- key of the archived log record in the recovery catalog
-- thread#
-- return only logs that belong to this thread#
-- if NULL return logs for all threads
-- fromseq#
-- lowest log sequence number in the range
-- toseq#
-- highest log sequence number in the range
-- fromtime
-- exclude logs that were switched out before fromtime
-- totime
-- exclude logs that were switched in after totime
-- fromscn
-- exclude logs that were switched out before fromscn
-- toscn
-- exclude logs that were switched in after toscn
-- pattern
-- return only archived logs whose filename match the pattern
-- The pattern is matched against normalized filenames ### ok?
-- available
-- if TRUE (1) return available archived logs
-- unavailable
-- if TRUE (1) return unavailable archived logs
-- deleted
-- if TRUE (1) return deleted archived logs
-- online
-- if TRUE (1) return also inspected online logs (in addition to
-- archived logs)
-- duplicates
-- if TRUE (1) return all archived logs
-- if FALSE (0) eliminate duplicate archived logs
-- Output parameters:
-- recid
-- recid of the archived log record (in V$ARCHIVED_LOG)
-- stamp
-- stamp of the archived log record (in V$ARCHIVED_LOG)
-- thread#
-- sequence#
-- low_scn
-- fname
-- reset_scn
-- block_size
-- Exceptions:
-- NO_RECOVERY_CATALOG (ORA-20300)
-- this operation is not supported without the recovery catalog
-- ARCHIVED_LOG_DOES_NOT_EXIST
-- the key does not match any archived log
-- TRANSLATION_IN_PROGRESS (ORA-20203)
-- the previous translation conversation is still in progess.
-- To terminate get all datafiles with getArchivedLog.
-- TRANSLATION_NOT_IN_PROGRESS (ORA-20204)
-- getArchivedLog was called with no translation in progress
-- THREAD_IS_NULL (ORA-20210)
-- a null thread# was passed to translateArchivedLogSeqRange
-- HIGH_SEQUENCE_IS_NULL
-- a null toseq# was passed to translateArchivedLogSeqRange
-- UNTIL_TIME_IS_NULL (ORA-20212)
-- a null totime was passed to translateArchivedLogTimeRange
-- UNTIL_SCN_IS_NULL (ORA-20213)
-- a null toscn was passed to translateArchivedLogSCNRange
-- ARCHIVED_LOG_RANGE_IS_EMPTY
-- the specified range doesn't contain any archived log
------------------------------
-- Archived Log Translation --
------------------------------
PROCEDURE getArchivedLog(
alRec OUT alRec_t
,closeCursor IN boolean DEFAULT FALSE);
PROCEDURE translateArchivedLogKey(
al_key IN number
,available IN number DEFAULT 1 -- ignored (for compatability)
,unavailable IN number DEFAULT 1 -- ignored (for compatability)
,deleted IN number DEFAULT 1 -- ignored (for compatability)
,online IN number DEFAULT 1 -- ignored (for compatability)
,recid OUT number
,stamp OUT number
,thread# OUT number
,sequence# OUT number
,low_scn OUT number
,reset_scn OUT number
,block_size OUT number
,fname OUT varchar2
,needstby IN number DEFAULT NULL);
PROCEDURE translateArchivedLogName(
fname IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,online IN number -- ignored
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL -- for compatability
,needstby IN number DEFAULT NULL);
PROCEDURE translateArchivedLogSeqRange(
thread# IN number
,fromseq# IN number
,toseq# IN number
,pattern IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,online IN number -- ignored
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL -- for compatability
,needstby IN number DEFAULT NULL);
PROCEDURE translateArchivedLogTimeRange(
thread# IN number
,fromTime IN date
,toTime IN date
,pattern IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,online IN number -- ignored
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL -- for compatability
,needstby IN number DEFAULT NULL);
PROCEDURE translateArchivedLogSCNRange(
thread# IN number
,fromSCN IN number
,toSCN IN number
,pattern IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,online IN number
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL -- for compatability
,needstby IN number DEFAULT NULL);
PROCEDURE translateArchivedLogPattern(
pattern IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,online IN number -- ignored
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL -- for compatability
,needstby IN number DEFAULT NULL);
PROCEDURE translateArchivedLogCancel;
-- translateBackupPieceKey looks up a backup piece by primary key.
-- translateBackupPieceHandle looks up a backup piece by handle and deviceType.
-- translatebackupPieceTag looks up backup pieces by tag.
-- The available are unavailable parameters are used to limit the translation
-- to backup pieces with the desired status. For example, only available
-- backup pieces can be backed up, but unavailable pieces can be made
-- available. Deleted backup pieces are never returned.
-- Input parameters:
-- bp_key
-- key of the backup piece record in the recovery catalog
-- handle
-- backup piece handle
-- device type
-- device type on which the backup piece resides
-- Exceptions:
-- NO_RECOVERY_CATALOG (ORA-20300)
-- this operation is not supported without the recovery catalog
-- BACKUP_PIECE_DOES_NOT_EXIST
-- the key does not match any backup piece
-- BACKUP_PIECE_HANDLE_IS_AMBIGUOUS
-- the key does not match any backup piece
-- Obsolete as of 8.1.6
PROCEDURE getArchivedLog(
recid OUT number
,stamp OUT number
,thread# OUT number
,sequence# OUT number
,low_scn OUT number
,nxt_scn OUT number
,fname OUT varchar2
,reset_scn OUT number
,block_size OUT number
,blocks OUT number);
---------------------------------
-- Controlfilecopy Translation --
---------------------------------
-- translateControlFileCopyName translates a control file name into a list of
-- control file copies.
-- Input parameters:
-- fname
-- name of the controlfile copy to be translated.
-- The name must be a normalized filename
-- Exceptions:
-- CONTROLFILE_COPY_DOES_NOT_EXIST
-- The filename does not match any controlfile copy
PROCEDURE translateControlFileCopyName(
fname IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL); -- for compatability
PROCEDURE getControlFileCopy(
rcvRec IN OUT rcvRec_t);
-- Obsolete as of 8.1.6
PROCEDURE getControlFileCopy(
recid OUT number
,stamp OUT number
,reset_scn OUT number
,ckp_scn OUT number
,block_size OUT number);
------------------------------
-- Datafilecopy Translation --
------------------------------
PROCEDURE getDataFileCopy(
rcvRec OUT rcvRec_t
,closeCursor IN boolean DEFAULT FALSE);
-- translateDataFileCopyKey translates the datafile copy key into a
-- datafile copy recid and stamp in V$DATAFILE_COPY.
-- translateDataFileCopyNumber translates a file number and (optional) tag
-- to a datafile copy recid and stamp. Not used currently in 8.0.
-- translatedDataFileCopyName translates the datafile copy name into a
-- a list of datafile copies and getDataFileCopy returns the recid and stamp
-- of each datafile copy. The duplicates parameter controls whether
-- getDataFileCopy returns all matching datafile copies or just the most
-- recent copy (highest stamp in rcvcat or highest recid in controlfile).
-- translateDataFileCopyTag translates the tag into a list of datafile
-- copies and getDataFileCopy returns the recid and stamp of each datafile copy
-- one at a time until null is returned.
-- translateDataFileCopyFno translates a file number into a list of datafile
-- copies. getDataFileCopy returns the recid and stamp of each datafile
-- copy one at at time until null is returned. The duplicates parameter
-- controls whether getDataFileCopy returns all matching datafile copies or
-- just the most recent copy (highest stamp in rcvcat or highest recid in
-- controlfile).
-- The available are unavailable parameters are used to limit the translation
-- to datafile copies with the desired status. For example, only available
-- datafile copies can be backed up, but unavailable copies can be made
-- available. Deleted copies are never returned.
-- The duplicates parameter controls whether getDataFileCopy returns all
-- datafile copies or just the most recent (highest checkpoint scn) copy
-- of each datafile (file#).
-- Input parameters:
-- cdf_key
-- key of the datafile copy record in the recovery catalog
-- fname
-- name of the datafile copy to be translated.
-- The name must be a normalized filename
-- tag
-- tag of the datafile copies to be translated
-- The tag must be passed exactly as stored in the controlfile,
-- it is not uppercased by translate
-- available
-- if TRUE (1) return available datafile copies
-- unavailable
-- if TRUE (1) return unavailable datafile copies
-- duplicates
-- if TRUE (1) return all datafile copies
-- if FALSE (0) eliminate duplicate datafile copies
--
-- The remaining parameters are returned for deleteDataFileCopy
--
-- file#
-- fname
-- reset_scn
-- create_scn
-- ckp_scn
-- blocks_size
--
-- Exceptions:
-- NO_RECOVERY_CATALOG (ORA-20300)
-- translation by key is not supported without the recovery catalog
-- DATAFILE_COPY_DOES_NOT_EXIST
-- the specified key or filename does not match any datafile copy
-- DATAFILE_COPY_NAME_AMBIGUOUS
-- the specified filename matches more than one datafile copy
-- TAG_DOES_NOT_MATCH
-- the specified tag doesn't match any datafile copies
-- TRANSLATION_IN_PROGRESS (ORA-20203)
-- the previous translation conversation is still in progess.
-- To terminate get all datafiles with getDataFileCopy.
-- TRANSLATION_NOT_IN_PROGRESS (ORA-20204)
-- getDataFileCopy was called with no translation in progress
PROCEDURE translateDataFileCopyKey(
cdf_key IN number
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL); -- for compatability
-- Obsolete as of 8.1.6
PROCEDURE translateDataFileCopyKey(
cdf_key IN number
,available IN number
,unavailable IN number
,recid OUT number
,stamp OUT number
,file# OUT number
,fname OUT varchar2
,reset_scn OUT number
,create_scn OUT number
,ckp_scn OUT number
,block_size OUT number
,blocks OUT number);
PROCEDURE translateDataFileCopyName(
fname IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL); -- for compatability);
PROCEDURE translateDataFileCopyTag(
tag IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL); -- for compatability);
PROCEDURE translateDataFileCopyFno(
fno IN number
,available IN number DEFAULT NULL
,unavailable IN number DEFAULT NULL
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL);
-- Obsolete as of 8.1.6
PROCEDURE getDataFileCopy(
recid OUT number
,stamp OUT number
,file# OUT number
,fname OUT varchar2
,reset_scn OUT number
,create_scn OUT number
,ckp_scn OUT number
,block_size OUT number
,blocks OUT number);
----------------------------
-- Proxy Copy Translation --
----------------------------
PROCEDURE getProxyCopy(
rcvRec OUT rcvRec_t
,closeCursor IN boolean DEFAULT FALSE);
PROCEDURE translateProxyCopyKey(
pc_key IN number
,deviceType IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,expired IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL); -- for compatability
-- Obsolete as of 8.1.6
PROCEDURE translateProxyCopyKey(
pc_key IN number
,device_type IN varchar2
,available IN number
,unavailable IN number
,deleted IN number
,recid OUT number
,stamp OUT number
,handle OUT varchar2);
PROCEDURE translateProxyCopyHandle(
handle IN varchar2
,deviceType IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,expired IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL); -- for compatability
-- Obsolete as of 8.1.6
PROCEDURE translateProxyCopyHandle(
handle IN varchar2
,device_type IN varchar2
,available IN number
,unavailable IN number
,deleted IN number
,recid OUT number
,stamp OUT number);
PROCEDURE translateProxyCopyTag(
tag IN varchar2
,device_type IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL); -- for compatability
-- translateProxyCopyKey translates a proxy copy key to a
-- recid and stamp in V$PROXY_DATAFILE/V$PROXY_ARCHIVEDLOG
-- translateProxyCopyHandle translates handle and device type to a
-- proxy copy recid and stamp.
-- getProxyCopy returns one proxy copy after calling translateProxyCopyTag.
-- keep calling getProxyCopy until recid is null.
-- The available and unavailable parameters are used to limit the
-- translation to backup pieces with the desired status.
-- Input parameters:
-- pc_key
-- key of the proxy copy record in the recovery catalog
-- handle
-- proxy copy handle
-- device type
-- device type on which the proxy copy resides
-- Output parameters:
-- recid
-- recid/stamp of the proxy copy record (in V$PROXY_DATAFILE or
-- V$PROXY_ARCHIVEDLOG)
-- Exceptions:
-- NO_RECOVERY_CATALOG (ORA-20300)
-- this operation is not supported without the recovery catalog
-- PROXY_COPY_DOES_NOT_EXIST
-- the key does not match any proxy copy
-- PROXY_COPY_HANDLE_IS_AMBIGUOUS
-- the key matches more than one proxy copy
-- Obsolete as of 8.1.6
PROCEDURE getProxyCopy(
recid OUT number
,stamp OUT number
,handle OUT varchar2);
------------------------------
-- Backup Piece Translation --
------------------------------
PROCEDURE getBackupPiece(
bpRec OUT bpRec_t
,closeCursor IN boolean DEFAULT FALSE);
PROCEDURE translateBackupPieceKey(
key IN number
,available IN number DEFAULT TRUE#
,unavailable IN number DEFAULT TRUE#
,expired IN number DEFAULT TRUE#
,statusMask IN binary_integer DEFAULT NULL); -- for compatability
PROCEDURE translateBackupPieceKey( -- only used in 8.1.6
bp_key IN number
,available IN number
,unavailable IN number
,recid OUT number
,stamp OUT number
,handle OUT varchar2
,set_stamp OUT number
,set_count OUT number
,piece# OUT number);
PROCEDURE translateBackupPieceHandle(
handle IN varchar2
,deviceType IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,expired IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL); -- for compatability
PROCEDURE translateBackupPieceHandle( -- only used in 8.1.6
handle IN varchar2
,device_type IN varchar2
,available IN number
,unavailable IN number
,recid OUT number
,stamp OUT number
,set_stamp OUT number
,set_count OUT number
,piece# OUT number);
PROCEDURE translateBackupPieceTag(
tag IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL); -- for compatability
PROCEDURE translateBackupPieceBSKey(
key IN number
,tag IN varchar2 DEFAULT NULL
,deviceType IN varchar2 DEFAULT NULL
,pieceCount IN number
,duplicates IN number DEFAULT TRUE#
,copyNumber IN number DEFAULT NULL
,available IN number DEFAULT TRUE#
,unavailable IN number DEFAULT FALSE#
,deleted IN number DEFAULT FALSE#
,expired IN number DEFAULT FALSE#
,statusMask IN binary_integer DEFAULT NULL); -- for compatability
-- Obsolete as of 8.1.6
PROCEDURE translateBackupSetKey(
bs_key IN number
,device_type IN varchar2
,available IN number
,unavailable IN number
,deleted IN number
,duplicates IN number
,backup_type OUT varchar2
,recid OUT number
,stamp OUT number
,set_stamp OUT number
,set_count OUT number
,bslevel OUT number
,completion_time OUT date);
-- Obsolete as of 8.1
PROCEDURE translateBackupSetKey(
bs_key IN number
,device_type IN varchar2
,available IN number
,unavailable IN number
,deleted IN number
,duplicates IN number
,backup_type OUT varchar2
,recid OUT number
,stamp OUT number);
-- Obsolete as of 8.1.6
PROCEDURE translateBackupSetRecid(
recid IN number
,stamp IN number
,device_type IN varchar2
,bs_key OUT number
,bslevel OUT number
,completed OUT date);
-- Obsolete as of 8.1
PROCEDURE translateBackupSetRecid(
recid IN number
,stamp IN number
,device_type IN varchar2);
-- translateBackupPieceBSKey translates the specified backup set into a list of
-- backup pieces. If there are multiple available copies of a piece then
-- only the latest (with highest stamp) is returned. If there is no available
-- copy of a piece then raise an exception.
-- Input parameters:
-- key
-- key of the backup set record in the recovery catalog
-- recid
-- recid of the backup set record (in V$BACKUP_SET)
-- stamp
-- stamp of the backup set record (in V$BACKUP_SET)
-- Output parameters:
-- device_type
-- type of the device on which the piece resides
-- handle
-- handle to the backup piece
-- Exceptions:
-- BACKUP_SET_MISSING
-- no backup set with the specified recid and stamp found
-- NO_RECOVERY_CATALOG (ORA-20300)
-- translation by bs_key is not supported without the recovery catalog
-- Obsolete as of 8.1.6
PROCEDURE getBackupPiece(
recid OUT number
,stamp OUT number
,bpkey OUT number
,set_stamp OUT number
,set_count OUT number
,piece# OUT number
,copy# OUT number
,status OUT varchar2
,completion OUT date
,handle OUT varchar2);
-- Obsolete as of 8.1
PROCEDURE getBackupPiece(
recid OUT number
,stamp OUT number
,set_stamp OUT number
,set_count OUT number
,piece# OUT number
,handle OUT varchar2);
----------------------------
-- Backup Set Translation --
----------------------------
PROCEDURE translateBackupSetKey(
key IN number
,bsRec OUT bsRec_t);
PROCEDURE translateAllBackupSet(
backupType IN binary_integer
,tag IN varchar2
,statusMask IN binary_integer
,completedAfter IN date
,completedBefore IN date);
PROCEDURE getAllBackupSet(
rcvRec OUT rcvRec_t);
------------------------
-- Controlfile Backup --
------------------------
-- getControlfileBackup is not a public function, but needs to be here due
-- to bug 1269570.
FUNCTION getControlfileBackup(
rcvRec OUT rcvRec_t)
RETURN number;
-- findControlFileBackup finds the optimal copy or backup of the controlfile
-- based on the given criteria.
-- The optimal copy is the one with highest checkpoint SCN. Returns one of:
-- SUCCESS, AVAILABLE, UNAVAILABLE.
-- This is for 8.0.4 thru 8.1.5 compatibility
FUNCTION findControlFileBackup(
type OUT number
,recid OUT number
,stamp OUT number
,fname OUT varchar2
,device_type OUT varchar2
,ckp_scn OUT number)
RETURN number;
-- Obsolete as of 8.1.6 (8.1.5 uses this)
FUNCTION findControlFileBackup(
type OUT number
,recid OUT number
,stamp OUT number
,fname OUT varchar2
,device_type OUT varchar2
,ckp_scn OUT number
,rlg_scn OUT number
,blksize OUT number)
RETURN number;
-------------------------
-- Archived Log Backup --
-------------------------
PROCEDURE findArchivedLogBackup(
thread IN number
,sequence IN number
,lowSCN IN number);
-- findArchivedLogBackup finds a backup set containing the given archived log.
-- getArchivedLogBackup returns the record for the backup set. The return
-- value is one of: SUCCESS, AVAILABLE, UNAVAILABLE.
--
-- Input Parameter:
-- thread#
-- sequence#
-- low_scn
FUNCTION getArchivedLogBackup(
rcvRec OUT rcvRec_t)
RETURN binary_integer;
-- Obsolete as of 8.1.6
FUNCTION findArchivedLogBackup(
thread# IN number
,sequence# IN number
,low_scn IN number
,type OUT number
,recid OUT number
,stamp OUT number
,device_type OUT varchar2)
RETURN number;
-------------------
-- SPFILE Backup --
-------------------
FUNCTION getSpfileBackup(
rcvRec OUT rcvRec_t)
RETURN number;
---------------
-- List Copy --
---------------
PROCEDURE listTranslateControlfileCopy(
tag IN varchar2
,completedAfter IN date
,completedBefore IN date
,statusMask IN binary_integer DEFAULT
BSavailable+BSunavailable+BSexpired); -- default for 8.1
PROCEDURE listGetControlfileCopy(
rcvRec OUT rcvRec_t);
-- Obsolete as of 8.1.6
FUNCTION listGetControlfileCopy(
bcfkey OUT number
,ckpscn OUT number
,ckptime OUT date
,status OUT varchar2
,completion OUT date
,fname OUT varchar2)
RETURN number;
PROCEDURE listTranslateDataFileCopy(
file# IN number
,creation_change# IN number
,tag IN varchar2 DEFAULT NULL
,file_name_pattern IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,statusMask IN binary_integer DEFAULT BSavailable+BSunavailable);
-- default for 8.1
PROCEDURE listGetDataFileCopy(
rcvRec OUT rcvRec_t);
-- Obsolete as of 8.1.6
FUNCTION listGetDataFileCopy(
cdf_key OUT number
,status OUT varchar2
,fname OUT varchar2
,completion_time OUT date
,checkpoint_change# OUT number
,checkpoint_time OUT date)
RETURN number;
PROCEDURE listTranslateArchivedLogCopy(
thread# IN number
,sequence# IN number
,first_change# IN number
,file_name_pattern IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,statusMask IN binary_integer DEFAULT
BSavailable+BSunavailable+BSexpired -- 8.0/8.1 defaults
,needstby IN number DEFAULT NULL);
PROCEDURE listGetArchivedLogCopy(
rcvRec OUT rcvRec_t);
-- Obsolete as of 8.1.6
FUNCTION listGetArchivedLogCopy(
al_key OUT number
,status OUT varchar2
,fname OUT varchar2
,completion_time OUT date)
RETURN number;
-----------------
-- List Backup --
-----------------
PROCEDURE listTranslateControlfileBackup(
tag IN varchar2
,completedAfter IN date
,completedBefore IN date
,statusMask IN binary_integer DEFAULT
BSavailable+BSunavailable+BSexpired -- 8.0/8.1 defaults
,autobackup IN binary_integer DEFAULT BScfile_all);
PROCEDURE listGetControlfileBackup(
rcvRec OUT rcvRec_t);
-- Obsolete as of 8.1.6
FUNCTION listGetControlfileBackup(
bskey OUT number,
ckpscn OUT number,
ckptime OUT date)
RETURN number;
PROCEDURE listTranslateSpfileBackup(
completedAfter IN date
,completedBefore IN date);
PROCEDURE listGetSpfileBackup(
rcvRec OUT rcvRec_t);
PROCEDURE listTranslateDataFileBackup(
file# IN number
,creation_change# IN number
,tag IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,statusMask IN binary_integer DEFAULT
BSavailable+BSunavailable+BSexpired); -- 8.0/8.1 defaults
PROCEDURE listGetDataFileBackup(
rcvRec OUT rcvRec_t);
-- Obsolete as of 8.1.6
FUNCTION listGetDataFileBackup(
bs_key OUT number
,backup_type OUT varchar2
,incremental_level OUT number
,completion_time OUT date
,checkpoint_change# OUT number
,checkpoint_time OUT date)
RETURN number;
-- 8.1.5 LIST implementation
PROCEDURE translateBackupFile(
bs_recid IN number
,bs_stamp IN number
,fno IN number
,bskey OUT number
,inclevel OUT number
,backup_type OUT varchar2
,completed OUT date);
-- Used by 8.0 and 8.1.6, but not 8.1.5
PROCEDURE listTranslateArchivedLogBackup(
thread# IN number
,sequence# IN number
,first_change# IN number
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,statusMask IN binary_integer DEFAULT
BSavailable+BSunavailable+BSexpired); -- 8.0/8.1 defaults
PROCEDURE listGetArchivedLogBackup(
rcvRec OUT rcvRec_t);
-- Obsolete as of 8.1
FUNCTION listGetArchivedLogBackup(
bs_key OUT number
,completion_time OUT date)
RETURN number;
-- Obsolete as of 8.1.6, but used in 9.0
PROCEDURE listTranslateArchivedLogBackup(
thread# IN number DEFAULT NULL
,lowseq IN number DEFAULT NULL
,highseq IN number DEFAULT NULL
,lowscn IN number DEFAULT NULL
,highscn IN number DEFAULT NULL
,from_time IN date DEFAULT NULL
,until_time IN date DEFAULT NULL
,pattern IN varchar2 DEFAULT NULL);
-- Obsolete as of 8.1.6
FUNCTION listGetArchivedLogBackup(
bs_key OUT number
,thread# OUT number
,sequence# OUT number
,first_change# OUT number
,next_change# OUT number
,first_time OUT date
,next_time OUT date)
RETURN number;
--------------------
-- List Backupset --
--------------------
PROCEDURE listTranslateBackupsetFiles(
bs_key IN number);
PROCEDURE listGetBackupsetFiles(
rcvRec OUT rcvRec_t);
---------------------
-- List Proxy Copy --
---------------------
-- Note that this is used for both datafiles and the controlfile
PROCEDURE listTranslateProxyDataFile(
file# IN number
,creation_change# IN number
,tag IN varchar2 DEFAULT NULL
,handle_pattern IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,statusMask IN binary_integer DEFAULT
BSavailable+BSunavailable+BSexpired); -- default for 8.1
PROCEDURE listGetProxyDataFile(
rcvRec OUT rcvRec_t);
-- Obsolete as of 8.1.6
FUNCTION listGetProxyDataFile(
xdf_key OUT number
,recid OUT number
,stamp OUT number
,status OUT varchar2
,handle OUT varchar2
,completion_time OUT date
,checkpoint_change# OUT number
,checkpoint_time OUT date)
RETURN number;
-- This procedure serves absolutely no purpose. It is here only for
-- backwards compatbility with 8.1.5. The only call to this is from
-- krmkafs(), which gets called from krmkgra(). Since the calls are always
-- in sequence, we can simply save the last record returned from
-- getRecoveryAction and avoid doing an extra query.
-- The only value this functions returns that krmkgra() didn't already have
-- in 8.1.5 is the xdf_key. Completion time was being estimated from the
-- stamp.
PROCEDURE listTranslateProxyDFRecid(
recid IN number
,stamp IN number
,xdf_key OUT number
,file# OUT number
,status OUT varchar2
,handle OUT varchar2
,completion_time OUT date
,checkpoint_change# OUT number
,checkpoint_time OUT date);
-------------------------------
-- List Database Incarnation --
-------------------------------
PROCEDURE listTranslateDBIncarnation(
db_name IN varchar2 DEFAULT NULL);
FUNCTION listGetDBIncarnation(
db_key OUT number
,dbinc_key OUT number
,db_name OUT varchar2
,db_id OUT number
,current_inc OUT varchar2
,resetlogs_change# OUT number
,resetlogs_time OUT date)
RETURN number;
--------------------------------------
-- List Rollback Segment Tablespace --
--------------------------------------
PROCEDURE listRollbackSegTableSpace;
FUNCTION listGetTableSpace(
ts# OUT number
,ts_name OUT varchar2)
RETURN number;
------------------------
-- Incremental Backup --
------------------------
-- getIncrementalScn returns the starting scn for an incremental backup.
-- Input Parameters:
-- file#
-- datafile number
-- reset_scn
-- the resetlogs SCN of the datafile
-- reset_time
-- the resetlogs time of the datafile
-- incr_scn
-- level of the incremental backup
-- cumulative
-- TRUE# if the backup is cumulative
-- first
-- TRUE open the cursor, otherwise just fetch from already opened cursor
-- Exceptions
-- DATAFILE_DOES_NOT_EXIST
-- INVALID_LEVEL
-- NO_PARENT_BACKUP_FOUND
FUNCTION getIncrementalScn(
file# IN number
,create_scn IN number
,reset_scn IN number
,reset_time IN date
,incr_level IN number
,cumulative IN number)
RETURN number;
-- This one is an improved version of above. If you want to get
-- incremental scn for all datafiles by opening the cursor only once, then
-- using this will give enormous performance improvement.
--
-- NOTE!! NOTE!! NOTE!!
-- If you pass NULL to file# then it means all of the following
-- o all datafiles
-- o datafiles which has reset_scn and reset_time of current incarnation.
-- It is the callers responsibility to fetch the incremental scn of remaining
-- datafiles which doesn't have reset_scn and reset_time of current
-- incarnation.
PROCEDURE getIncrementalScn(
first IN boolean -- open the cursor if this is TRUE
,file# IN number
,create_scn IN number
,reset_scn IN number
,reset_time IN date
,incr_level IN number
,cumulative IN number
,rcvRec OUT rcvRec_t);
--------------------
-- Offline Ranges --
--------------------
PROCEDURE findOfflineRangeCopy(
offr_recid IN number
,offr_ckpscn IN number
,cf_cretime IN date
,dbinc_key IN number);
PROCEDURE getOfflineRangeCopy(
rcvRec OUT rcvRec_t);
-- Obsolete as of 8.1.6
FUNCTION getOfflineRangeCopy
RETURN varchar2;
-- findOfflineRangeCopy begins the search for a controlfile copy
-- containing a specified offline range. getOfflinRangeCopy is called
-- to retrieve the controlfile names one by one. NULL is returned at
-- end of fetch.
-- Input Parameters:
-- offr_recid
-- recid of offline range
-- offr_ckpscn
-- online checkpoint SCN (end) of offline range
-- dbinc_rlgscn
-- resetlogs SCN of the db incarnation that contains this range
-- Output Parameters:
-- offr_recid
-- recid of the offline range record
-- offr_stamp
-- stamp of the offline range record
-- type
-- type of the controlfile that contains the offline range.
-- COPY or BACKUP
-- recid
-- the recid of datafile copy record or
-- the recid of the backup set record
-- stamp
-- The timestamp associated with the recid in the controlfile.
-- fname
-- filename of the controlfile copy
-- NULL if a backup controlfile is returned
-- returns TRUE (1) if a copy or backup was found
-- returns FALSE (0) if no copy or backup was found
-- Exceptions:
-- OFFLINE_RANGE_NOT_FOUND (ORA-20250)
-- No offline range was found for the datafile starting at the offline SCN
---------------------------------------
-- Recovery Functions and Procedures --
---------------------------------------
PROCEDURE setComputeRecoveryActionMasks(
containerMask IN number
,actionMask IN number
,allRecords IN number
,availableMask IN binary_integer);
--Obsolete as of 8.1.7
PROCEDURE setComputeRecoveryActionMasks(
containerMask IN number
,actionMask IN number
,allRecords IN number);
-- Obsolete as of 8.1.6
PROCEDURE setRAflags(
kindMask IN number
,allRecords IN boolean);
FUNCTION computeRecoveryActions(
fno IN number, -- Datafile number.
crescn IN number, -- Datafile creation SCN.
df_rlgscn IN number -- Datafile resetlogs SCN. Null if this is a RESTORE
default null, -- command, else this is the value in the datafile
-- header for the datafile we are RECOVERing.
df_rlgtime IN date -- Datafile resetlogs time. Null if df_rlgscn is
default null, -- null, else value from datafile header.
df_ckpscn IN number -- Datafile checkpoint SCN. Null if df_rlgscn is
default null, -- null, else value from datafile header.
offlscn IN number -- kccfeofs (may be null).
default 0,
onlscn IN number -- kccfeonc (null if offlscn is null).
default 0,
onltime IN date -- kccfeonc_time
default null,
cleanscn IN number -- kccfecps if either SOR or WCC set, else null.
default 0,
clean2scn IN number -- CF ckpt SCN if WCC set, infinity if SOR bit set
default 0, -- else null.
clean2time IN date -- cf ckpt time if WCC, SYSDATE if SOR
default null,
allowfuzzy IN boolean -- TRUE if can be fuzzy at until SCN/time, FALSE if
default FALSE, -- not. default is FALSE.
partial_rcv IN boolean -- TRUE if can do partial recovery, FALSE if not
default FALSE,
cf_scn IN number -- controlfile checkpoint SCN (NULL if none mounted)
default NULL,
cf_cretime IN date -- controlfile creation time (NULL if none mounted)
default NULL,
cf_offrrid IN number -- recid of oldest offline range in controlfile
default NULL, -- (NULL if none mounted)
allCopies IN boolean -- if TRUE, then stack all valid copies of a bu set
default FALSE
) return binary_integer;
-- Returns:
-- SUCCESS -> the file can be restored/recovered.
-- else one of RESTORABLE, AVAILABLE, UNAVAILABLE, NO_ACTION.
-- computeRecoveryActions return values --
SUCCESS CONSTANT binary_integer := 0;
UNAVAILABLE CONSTANT binary_integer := 1;
AVAILABLE CONSTANT binary_integer := 2;
RESTORABLE CONSTANT binary_integer := 3;
NO_ACTION CONSTANT binary_integer := 4;
-- SUCCESS: A file has been found for RESTORE, or the file on disk
-- can be recovered.
-- UNAVAILABLE: If RESTORE, then no datafilecopy or level 0 backup was found.
-- If RECOVER, then some incremental backup is missing, or the
-- datafile on disk is too old to recover.
-- AVAILABLE: If RESTORE, then some level 0 or datafilecopy exists, but
-- the required device type is not allocated.
-- RESTORABLE: This is returned only when doing a RECOVER. It means that
-- the file on disk cannot be recovered, but there is some level
-- 0 or datafilecopy that could be restored and then recovered.
-- NO_ACTION: There are no incrementals or offline ranges to apply, but
-- the file should be recoverable with redo. No guarantee is
-- made that the logs needed are actually available.
FUNCTION getRecoveryAction(
action OUT rcvRec_t)
RETURN binary_integer;
-- Obsolete as of 8.1.6
FUNCTION getRecoveryAction(
kind OUT number
,set_stamp OUT number
,set_count OUT number
,recid OUT number
,stamp OUT number
,fname OUT varchar2
,blocksize OUT number
,blocks OUT number
,devtype OUT varchar2
,from_scn OUT number
,to_scn OUT number
,to_time OUT date
,rlgscn OUT number
,rlgtime OUT date
,cfcretime OUT date
,dbinc_key OUT number)
RETURN binary_integer;
PROCEDURE printRecoveryActions;
PROCEDURE trimRecoveryActions(
maxActions IN number
,containerMask IN number
,actionMask IN number);
-- trimRecoveryActions will trim the stack down to the specified number
-- actions if it contains more. This is used by report obsolete to implement
-- the redundancy count. The reason for it is that getRecoveryActions
-- returns actions in LIFO order. This means the oldest actions, which
-- were stacked most recently, are returned first. However, report obsolete
-- wants to keep only the most recent backups when constructing the
-- "must keep" list. We solve the problem by getting rid of any excess
-- actions first, and so the order in which getRecoveryActions returns them
-- won't matter. Note that only actions whose type_con and type_act are
-- selected by the masks will be deleted. Other actions are left on the
-- stack.
---------------------
-- Report Obsolete --
---------------------
PROCEDURE reportTranslateDFDel ;
-- pre 8.1.5 version
FUNCTION reportGetDFDel(
file# OUT number
,filetype OUT number
,checkpoint_change# OUT number
,checkpoint_time OUT date
,resetlogs_change# OUT number
,resetlogs_time OUT date
,incremental_change# OUT number
,fuzzy_change# OUT number
,recid OUT number
,stamp OUT number
,fname OUT varchar2
,restorable OUT number)
RETURN number;
-- 8.1.5+ version
FUNCTION reportGetDFDel(
file# OUT number
,filetype OUT number
,checkpoint_change# OUT number
,checkpoint_time OUT date
,resetlogs_change# OUT number
,resetlogs_time OUT date
,incremental_change# OUT number
,fuzzy_change# OUT number
,recid OUT number
,stamp OUT number
,fname OUT varchar2
,restorable OUT number
,key OUT number
,completion_time OUT date)
RETURN number;
------------
-- TSPITR --
------------
FUNCTION getCloneName(
fno IN number
,crescn IN number)
RETURN varchar2;
---------------
-- DUPLICATE --
---------------
FUNCTION wasFileOffline(
fno IN number
,untilscn IN number)
RETURN number;
-------------------------
-- RMAN Configuration ---
-------------------------
PROCEDURE getConfig(
conf# OUT number
,name IN OUT varchar2
,value IN OUT varchar2
,first IN boolean);
------------------------------
-- Get max(copy#) --
------------------------------
FUNCTION getmaxcopyno(
bsstamp IN number
,bscount IN number)
RETURN number;
--------------------------
-- Add Corruption Table --
--------------------------
PROCEDURE bmrAddCorruptTable(
dfnumber OUT number
,blknumber OUT number
,range OUT number
,first IN boolean);
------------------------
-- Get Backup History --
------------------------
PROCEDURE getDfBackupHistory(
backedUpDev IN varchar2
,first IN boolean
,file# IN number DEFAULT NULL
,crescn IN number DEFAULT NULL
,reset_scn IN number DEFAULT NULL
,reset_time IN date DEFAULT NULL
,bhistoryRec OUT bhistoryRec_t);
PROCEDURE getAlBackupHistory(
backedUpDev IN varchar2
,first IN boolean
,thread# IN number DEFAULT NULL
,sequence# IN number DEFAULT NULL
,bhistoryRec OUT bhistoryRec_t);
PROCEDURE getBsBackupHistory(
backedUpDev IN varchar2
,first IN boolean
,set_stamp IN number DEFAULT NULL
,set_count IN number DEFAULT NULL
,bhistoryRec OUT bhistoryRec_t);
-- Obsolute as of 9.0.1
PROCEDURE getBackupHistory(
dfRec IN dfRec_t
,backedUpDev IN varchar2
,nbackupsFlag IN number
,bscompletionFlag IN number
,nbackups OUT number
,bscompletion OUT date);
-- Obsolute as of 9.0.1
PROCEDURE getBackupHistory(
alRec IN alRec_t
,backedUpDev IN varchar2
,nbackupsFlag IN number
,bscompletionFlag IN number
,nbackups OUT number
,bscompletion OUT date);
-- Obsolute as of 9.0.1
PROCEDURE getBackupHistory(
bpRec IN bpRec_t
,backedUpDev IN varchar2
,nbackupsFlag IN number
,bscompletionFlag IN number
,nbackups OUT number
,bscompletion OUT date);
------------------
-- Version Info --
------------------
FUNCTION getPackageVersion
RETURN varchar2;
FUNCTION isStatusMatch(status IN VARCHAR2,
mask IN NUMBER) RETURN NUMBER;
FUNCTION isDeviceTypeAllocated(deviceType IN varchar2)
RETURN NUMBER;
FUNCTION isBackupTypeMatch(btype IN VARCHAR2,
mask IN binary_integer)
RETURN NUMBER;
pragma TIMESTAMP('2000-03-12:13:51:00');
END; -- dbms_rcvman or x$dbms_rcvman
-- CUT_HERE <- tell sed where to chop off the rest
CREATE OR REPLACE PACKAGE BODY "RMAN"."DBMS_RCVMAN" IS
-- prvtrmnu.sql
--
-- Copyright (c) Oracle Corporation 1995, 2001. All Rights Reserved.
--
-- NAME
-- prvtrmnu.sql - Recovery MANager package body
--
-- DESCRIPTION
-- This package contains procedures querying information that
-- Recovery Manager needs from the recovery catalog or the target
-- database control file
--
-- This is the version used by catrman.sql; there is a separate
-- body in the file prvtrmns.pls that is loaded into SYS; this one
-- is loaded into a user schema.
--
-- NOTES
-- Remember to make corresponding changes in prvtrmns.pls
--
-- MODIFIED (MM/DD/YY)
-- molagapp 02/14/02 - ignore debug exception
-- molagapp 02/01/02 - cast null
-- sdizdar 02/01/02 - bug-2209822: add auxName to cursors
-- molagapp 01/24/02 - rework backup history cursors
-- molagapp 01/23/02 - bug-2174697: add inCorebsRec_t framework
-- molagapp 01/19/02 - listBackupsetFiles - obey allIncarnations flg
-- molagapp 12/12/01 - bug 2146724
-- molagapp 11/29/01 - update package version 9.2.0
-- sdizdar 11/05/01 - fix findBackupsetFiles
-- molagapp 10/19/01 - add cfSequence, cfDate to recovery record
-- molagapp 10/17/01 - bug 1530744
-- molagapp 10/19/01 - bug 2067187
-- molagapp 10/06/01 - add translateAllBackupSet
-- sdizdar 09/07/01 - SPFILE backup:
-- - add getSpfileBackup(), listGetSpfileBackup(),
-- listTranslateSpfileBackup(), findSpfileBackup_c
-- molagapp 09/18/01 - bug-1999761
-- molagapp 07/23/01 - bug-1900314
-- fsanchez 05/23/01 - dbnewid
-- sdizdar 06/15/01 - bug-1782808:
-- - improve computerecoveryaction
-- - fix resetAll and setTransClause
-- molagapp 06/07/01 - bug-1712720: add setTransClause
-- molagapp 05/06/01 - add cursors to fix backup history performance
-- swerthei 04/16/01 - improve performance of getCheckpoint
-- sdizdar 04/21/01 - bug-961713: fix computeUntilSCN
-- swerthei 04/04/01 - use new corruption view
-- molagapp 05/08/01 - fix query performance
-- sdizdar 04/10/01 - bug-1717268: add flags to getBackupHistory
-- swerthei 04/03/01 - add new flavor of getCheckpoint
-- swerthei 03/12/01 - simplify lrtbs query
-- fsanchez 01/25/01 - bug-1586048
-- sdizdar 11/10/00 - bug-1496982: 8.2.0 -> 9.0.0
-- sdizdar 11/25/00 - fixed findConfig_c
-- sdizdar 11/09/00 - bug-1478539: add keep attributes to findBackupSet
-- dbeusee 10/27/00 - bug-1469307
-- sdizdar 11/04/00 - bug-1479780:
-- - findArchivedLogCopy doesn't return online logs
-- sdizdar 10/23/00 - bug-1477008:
-- - add controlfile to openRecoveryActionCursor
-- sagrawal 10/24/00 - Fixing defaults for body and spec
-- dbeusee 10/17/00 - bug-1462384
-- sdizdar 10/08/00 - bug-1398333:
-- - translate don't use rc_backup_set but bs
-- sdizdar 08/24/00 - trimRecoveryActions doesn't count "keep" backups
-- - keep atributes added to right views
-- dbeusee 09/25/00 - rman82_list_fixes_1
-- molagapp 08/23/00 - add autobackup arg to listTranslateCfileBackup
-- molagapp 08/28/00 - fix 8.2 upgrade
-- dbeusee 06/13/00 - rman82_maint_syntax_unification
-- dbeusee 07/20/00 - rman82_debug_enhancements
-- sdizdar 08/13/00 - Show all and misc improvement:
-- - change RECOVERABLE/UNERCOREVABLE to LOGS/NOLOGS
-- smuralid 08/08/00 - common sql fe changes
-- molagapp 07/19/00 - restore optimization.
-- sdizdar 06/29/00 - Configure auxfilename and exclude tablespace:
-- - add tsNumber and inBackup in
-- datafile translation
-- banand 06/23/00 - set duplicate in alRec_t
-- molagapp 06/08/00 - restartable backups
-- molagapp 06/01/00 - backup optimization
-- sdizdar 05/20/00 - RMAN Retention Policy (keep):
-- - add keep attributes in translation procedures
-- - modified setUntilTime
-- - modified findArcLogBackup/Copy
-- swerthei 06/29/00 - fix cursor variables
-- mjstewar 07/24/00 - OMF: set newname ... to new
-- banand 05/19/00 - use name and value in findConfig_c
-- dbeusee 05/03/00 - rman82_cf_status_unification
-- dbeusee 11/01/99 - status_mask
-- molagapp 05/18/00 - block media recovery
-- fsanchez 03/24/00 - instantiate_standby
-- sdizdar 04/15/00 - RMAN configuration: add getConfig
-- molagapp 04/27/00 - backup backupset: add getmaxcopyno
-- banand 04/12/00 - add tag options to recover cmd
-- dbeusee 04/03/00 - xcheck_autolocate
-- swerthei 03/30/00 - xcheck_autolocate: return backup piece device type
-- fsanchez 01/07/00 - bug-1040149
-- molagapp 02/16/00 - bug 1186598: fix compatibility with RMAN 8.1.5
-- executable
-- dbeusee 10/20/99 - bug-1043144: fix findProxyCopy
-- fsanchez 09/24/99 - fix findValidBackupSet_c cursor
-- mluong 08/30/99 - Fix typo
-- gpongrac 10/12/99 - remove validateBackupSetCursor_t
-- gpongrac 09/09/99 - comments
-- swerthei 08/05/99 - close cursors in resetAll
-- mluong 08/30/99 - fix typo
-- gpongrac 08/10/99 - fix translateArchivedLog
-- gpongrac 07/12/99 - bug 927353: translateArchivedLogSCNRange needs to
-- gpongrac 07/06/99 - change rcver to 8.1.6
-- gpongrac 06/16/99 - report obsolete support
-- gpongrac 01/12/99 - 8.2 restructure
-- gpongrac 04/08/99 - change REM to --
-- swerthei 12/28/98 - 787381 - consider proxies in getIncrementalSCN
-- swerthei 11/26/98 - more debugging improvements
-- swerthei 11/25/98 - enable debugging code from rman
-- gpongrac 11/25/98 - fix debugging in getRecveryAction0
-- dbeusee 11/13/98 - misc_815: Handle LIST RECOVERABLE UNTIL TIME...
-- dbeusee 11/11/98 - misc_815: fix LIST COPY LIKE...
-- dbeusee 11/07/98 - misc_815: fix LIST COPY/BS FROM TIME/UNTIL TIME..
-- dbeusee 10/30/98 - misc_815: added stamp2date for LIST COPY
-- dbeusee 10/19/98 - misc_815: fix LIST BACKUPSET FROM TIME...
-- gpongrac 10/19/98 - misc_815: fix LIST with TAG
-- dbeusee 10/17/98 - misc_815: fix LIST ALL device type filtering
-- gpongrac 10/05/98 - misc_815: fix recovery
-- gpongrac 09/10/98 - misc_815: fix computeRecoveryActions for list cmd
-- swerthei 10/24/98 - add proxy support to REPORT OBSOLETE
-- swerthei 10/20/98 - add listTranslateProxyDataFile, listGetProxyDataF
-- fsanchez 09/04/98 - bug719092
-- swerthei 06/22/98 - prepare for wrapping to recover.bsq
-- gpongrac 06/04/98 - fix comment
-- swerthei 06/01/98 - add CHANGE PROXY
-- swerthei 05/27/98 - proxy restore
-- dbeusee 05/15/98 - misc_81_fixes_1
-- fsanchez 05/12/98 - duplex_backup_set
-- dbeusee 04/21/98 - rpt_redundancy_enh
-- gpongrac 03/04/98 - fix getPackageVersion
-- dbeusee 04/06/98 - xcheck enh.
-- dbeusee 03/29/98 - Update comment about restore only (not true any m
-- fsanchez 03/25/98 - Duplexed backup sets
-- dbeusee 03/01/98 - list enh.
-- gpongrac 01/23/98 - upgrade catalog_version to 8.0.5
-- dbeusee 02/11/98 - Fix bug 613166.
-- fsanchez 01/04/98 - Allow setDatabase to receive dbid without dbname
-- gpongrac 12/23/97 - change findcontrolfilebackup
-- gpongrac 10/30/97 - bug 560638: fix validatebackupset
-- gpongrac 10/02/97 - allow <= in setuntiltime and dbq
-- gpongrac 09/03/97 - have dfcopy name xlate return filesize
-- tpystyne 09/11/97 - bug 480172, fix name translation
-- swerthei 08/29/97 - add getdatafile.read_only
-- swerthei 08/18/97 - add getdatafile.stop_change#
-- gpongrac 07/02/97 - change to version 8.0.4
-- gpongrac 07/01/97 - avoid offr records with stamp of 0
-- mzhou 08/07/97 - fix order by ts#
-- gpongrac 07/22/97 - chang lrtbs cursor to order by tsid so system ts
-- swerthei 04/23/97 - fix list backupset
-- gpongrac 04/22/97 - offline range can end at resetlogs scn
-- dalpern 04/16/97 - renamed as prvtrmnu, v. prvtrmns
-- gpongrac 04/11/97 - add cfscn to computeRecoveryActions
-- gpongrac 04/10/97 - add rlgtime to getRecoveryAction
-- gpongrac 04/10/97 - fix incarnation check at top of computeRecov...0
-- gpongrac 04/04/97 - add translateBackupPieceTag
-- gpongrac 04/04/97 - deal with controlfiles that have no offline range
-- gpongrac 04/01/97 - add offline range info to computeRecoveryActions
-- swerthei 03/27/97 - add getDataFile.ts_name
-- tpystyne 03/20/97 - update catalog version to 8.00.03
-- swerthei 03/21/97 - fix merge error
-- swerthei 03/12/97 - get file sizes in blocks, for metrics
-- gpongrac 03/17/97 - fix cursor to deal with inplicit offline ranges c
-- gpongrac 03/15/97 - add to_time for implicit offline ranges in comput
-- gpongrac 03/10/97 - remove df_ckpscn as arg to openRecoveryActionCurs
-- gpongrac 03/10/97 - add setDebugOn and setDebugOff
-- gpongrac 03/03/97 - verify df_rlgscn in computeRecoveryActions0
-- gpongrac 02/28/97 - check allocate device types in addAction
-- gpongrac 02/27/97 - only do partial recovery if have current controlf
-- gpongrac 02/26/97 - fix compile errors
-- gpongrac 02/26/97 - fix syntax errors
-- gpongrac 02/26/97 - add new recovery functions
-- gpongrac 02/20/97 - require offr.online_time be strictly less than un
-- gpongrac 02/20/97 - simplify handling of until time/scn in where clau
-- swerthei 01/21/97 - change parameters for translatebackupsetkey
-- swerthei 01/15/97 - add dumpState
-- gpongrac 01/14/97 - add getCloneName
-- tpystyne 12/17/96 - add listRollbackSegTableSpace
-- swerthei 01/08/97 - change parameters for backup piece translation
-- swerthei 01/06/97 - continue REPORT DELETABLE
-- gpongrac 01/06/97 - add nxtscn to getArchivedLog
-- swerthei 01/03/97 - add getParentIncarnation
-- ### comments from 1996 removed
---------------------------------------------
-- *** PACKAGE VARIABLES/TYPES SECTION *** --
---------------------------------------------
----------------------
-- Global Constants --
----------------------
MAXSCNVAL CONSTANT number := 9e125; -- guaranteed higher than any SCN
MAXSEQVAL CONSTANT number := 2**32-1;
MINDATEVAL CONSTANT date := to_date('01/01/1900','MM/DD/YYYY');
MAXDATEVAL CONSTANT date := to_date('12/31/9999','MM/DD/YYYY');
-- keep types (see definitions in krmi.h and rcv/if/kcc3.h)
KEEP_NO CONSTANT number := 0;
KEEP_LOGS CONSTANT number := 256;
KEEP_NOLOGS CONSTANT number := 512;
KEEP_CONSIST CONSTANT number := 1024;
DEB_UNDEF CONSTANT number := 0;
DEB_PRINT CONSTANT number := 0;
DEB_ENTER CONSTANT number := 1;
DEB_EXIT CONSTANT number := 2;
DEB_IN CONSTANT number := 3;
DEB_OPEN CONSTANT number := 4;
DEB_DEF_PNAME CONSTANT varchar2(50) := 'prvtrmnu';
----------------------
-- Global Variables --
----------------------
this_db_key number := NULL;
this_dbinc_key number := NULL;
this_reset_scn number := NULL;
this_reset_time date;
type pnames is table of varchar2(50) index by binary_integer;
pname_i number :=0;
last_pnames pnames;
debug boolean := FALSE;
--------------------
-- rcvRec_t Stack --
--------------------
TYPE rcvRecTab_t IS TABLE OF rcvRec_t; -- recovery record stack type
rcvRecStack rcvRecTab_t := rcvRecTab_t(); -- recovery record stack
-----------------------
-- getPackageVersion --
-----------------------
TYPE versionList_t IS TABLE OF varchar2(8) INDEX BY binary_integer;
versionList versionList_t;
versionMaxIndex binary_integer;
versionCounter binary_integer;
-----------------
-- setDatabase --
-----------------
catalogVersion CONSTANT VARCHAR2(8) := '09.02.00';
-- For getParentIncarnation
getParentIncarnationKey number;
---------------------
-- Filtering Flags --
---------------------
allIncarnations number; -- allow records from non-current
-- incarnation
ignoreCreationSCN number; -- a stupid flag that is here
-- only to provide behaviour that is
-- backwards compatible with a kludge
-- dbeusee put in to compensate for
-- one of his bugs.
untilSCN number;
untilTime date;
restoreSource number;
restoreTag bp.tag%TYPE;
onlyStandby number;
-------------------
-- setDeviceType --
-------------------
TYPE deviceList_t IS TABLE OF rc_backup_piece.device_type%TYPE
INDEX BY binary_integer;
deviceList deviceList_t;
deviceCount number;
diskDevice boolean;
anyDevice boolean;
-----------------------------------------
-- In Memory Validate BackupSet Record --
-----------------------------------------
-- We have faced performance problems when calling validateBackupSet.
-- This record is introduced to resolve the performance issues. The idea
-- is to keep all validBackupSet in memory and its deviceType. For example,
-- if a backupset is created on X devices, then Y records will pushed into
-- the stack for that backupset, where Y is the number of devices on which
-- this backupset satisfies the requested statusMask.
--
-- This is a stripped version of bsRec_t because we want to keep minimum
-- information in memory to determine a backupset is valid or not.
--
-- NOTE!! NOTE!! NOTE!!
-- It is extremely IMPORTANT to limit the size of record because keeping
-- huge amount of these records in memory will lead to ORA-6500
-- PLSQL: storage error when you have around 10MB records.
--
-- This is not used in catalog and exists here only for testing purpose.
-- We derefed this change in catalog because we were hitting ORA-6500 error
-- for around 1MB of records without seeing much performance benefit.
TYPE inCorebsRec_t IS RECORD
(
bsKey number,
setStamp number(10),
setCount number(10),
devindx pls_integer, -- index into the inCoredeviceList
pieceCount pls_integer
);
-----------------------
-- inCorebsRec Stack --
-----------------------
TYPE inCorebsRecTab_t IS TABLE OF inCorebsRec_t; -- incorebs record stack type
inCorebsRecStack inCorebsRecTab_t := inCorebsRecTab_t();
-- This is present to save memory because duplicating deviceType in
-- all inCorebsRec_t is just waste of memory since each deviceType is
-- is 255 bytes.
inCoredeviceList deviceList_t;
inCoredeviceCount binary_integer := 0; -- number of devices
-- for inCorebsRec_c cursor
TYPE inCorebsCursor_t IS RECORD
(
bsKey number,
setStamp number(10),
setCount number(10),
deviceType rc_backup_piece.device_type%TYPE,
pieceCount pls_integer
);
----------------------------
-- computeRecoveryActions --
----------------------------
TYPE rcvRecCursor_t IS REF CURSOR return rcvRec_t;
TYPE rcvRecStackState_t IS RECORD
(
lowAction number, -- action with lowest from_scn on
-- rcvRecStack that is not a fullKind.
-- Usually points to top of stack, but
-- if computeRA_allRecords is TRUE,
-- then may point down into stack.
savePoint number, -- most recently added full_act_t
top number -- top of stack at start of a recursive
-- test search of a possible parent
-- incarnation
);
rcvRecStackState rcvRecStackState_t;
computeRA_allRecords number; -- do not stop at first full backup and
-- return all incremental backups
computeRA_restorable boolean; -- cannot recover the datafile we've
-- requested to recover, but there
-- is a backup that we could restore
-- and recover.
computeRA_available boolean; -- there is a backup available on
-- some non-allocated device type
computeRA_availableMask binary_integer;
-- computeRecoveryAction/addAction/addRedo return code values
action_OK number := 0;
action_FAIL number := 1;
action_SKIP number := 2;
action_OLD_REDO number := 3;
action_WRONG_INCARNATION number := 4;
old_redo exception; -- redo from old incarnation
pragma exception_init(old_redo, -20501);
-----------------------
-- getRecoveryAction --
-----------------------
getRA_containerMask number;
getRA_actionMask number;
getRA_likePattern cdf.fname%TYPE;
getRA_completedAfter date;
getRA_completedBefore date;
------------------------
-- Translation Clause --
------------------------
tc_thread number;
tc_fromTime date;
tc_toTime date;
tc_fromSCN number;
tc_toSCN number;
tc_fromSeq number;
tc_toSeq number;
tc_pattern varchar2(512);
------------------------
-- Controlfile Backup --
------------------------
CURSOR findControlfileCopy(
currentIncarnation IN number DEFAULT TRUE#
,tag IN varchar2 DEFAULT NULL
,pattern IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,untilSCN IN number DEFAULT NULL
,statusMask IN binary_integer
,needstby IN number DEFAULT NULL)
RETURN rcvRec_t IS
-- Replaces: ccf_name, lccf
SELECT imageCopy_con_t type_con,
ccf_key key_con,
ccf_recid recid_con,
ccf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
fname fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
to_number(null) blocks_con, -- ccf doesn't have blocks
block_size blockSize_con,
'DISK' deviceType_con,
completion_time compTime_con,
create_time cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
ccf.ckp_scn toSCN_act,
ccf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
ccf.dbinc_key dbincKey_act,
to_number(null) level_act,
0 dfNumber_obj,
0 dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
ccf.keep_options keep_options,
ccf.keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM ccf, dbinc
WHERE dbinc.db_key = this_db_key -- belongs to this database
AND dbinc.dbinc_key = ccf.dbinc_key
AND (findControlfileCopy.currentIncarnation = FALSE# OR
this_dbinc_key = ccf.dbinc_key)
AND (findControlfileCopy.tag is NULL OR
findControlfileCopy.tag = tag)
AND (findControlfileCopy.pattern is NULL OR
fname LIKE findControlfileCopy.pattern)
AND (findControlfileCopy.completedAfter is NULL OR
completion_time >= findControlfileCopy.completedAfter)
AND (findControlfileCopy.completedBefore is NULL OR
completion_time <= findControlfileCopy.completedBefore)
AND (findControlfileCopy.untilSCN is NULL OR
ccf.ckp_scn <= findControlfileCopy.untilSCN)
AND isStatusMatch(status,statusMask) = TRUE#
AND (needstby is NULL OR
nvl(controlfile_type,'B') = decode(needstby, TRUE#, 'S', 'B'))
ORDER BY toSCN_act desc, -- for finding best backup
stamp_con desc; -- for LIST and to get most recent
CURSOR findControlfileProxyCopy(
currentIncarnation IN number DEFAULT TRUE#
,tag IN varchar2 DEFAULT NULL
,pattern IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,untilSCN IN number DEFAULT NULL
,statusMask IN binary_integer
,needstby IN number DEFAULT NULL)
RETURN rcvRec_t IS
-- Replaces: xcfq, lxdf
SELECT proxyCopy_con_t type_con,
xcf_key key_con,
xcf_recid recid_con,
xcf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
handle fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
to_number(null) blocks_con, -- xcf doesn't have blocks
block_size blockSize_con,
device_type deviceType_con,
completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
xcf.ckp_scn toSCN_act,
xcf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
xcf.dbinc_key dbincKey_act,
to_number(null) level_act,
0 dfNumber_obj,
0 dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
xcf.keep_options keep_options,
xcf.keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM xcf, dbinc
WHERE db_key = this_db_key -- belongs to this database
AND dbinc.dbinc_key = xcf.dbinc_key
AND (findControlfileProxyCopy.currentIncarnation = FALSE# OR
this_dbinc_key = xcf.dbinc_key)
AND (findControlfileProxyCopy.tag is NULL OR
findControlfileProxyCopy.tag = tag)
AND (findControlfileProxyCopy.pattern is NULL OR
handle LIKE findControlfileProxyCopy.pattern)
AND (findControlfileProxyCopy.completedAfter is NULL OR
completion_time >= findControlfileProxyCopy.completedAfter)
AND (findControlfileProxyCopy.completedBefore is NULL OR
completion_time <= findControlfileProxyCopy.completedBefore)
AND (findControlfileProxyCopy.untilSCN is NULL OR
xcf.ckp_scn <= findControlfileProxyCopy.untilSCN)
AND isStatusMatch(status,statusMask) = TRUE#
AND (needstby is NULL OR
nvl(controlfile_type,'B') = decode(needstby, TRUE#, 'S', 'B'))
ORDER BY toSCN_act desc, -- to find best backup
stamp_con desc; -- for LIST and to get most recent
CURSOR findControlfileBackup_c(
currentIncarnation IN number DEFAULT TRUE#
,pattern IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,untilSCN IN number DEFAULT NULL
,needstby IN number DEFAULT NULL
,typemask IN binary_integer DEFAULT BScfile_all )
RETURN rcvRec_t IS
-- Relaces: bcfq, lbcf. Note that for lbcf, filtering for tags
-- is now done elsewhere.
SELECT backupSet_con_t type_con,
bcf_key key_con,
bcf_recid recid_con,
bcf_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
bs.incr_level bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
bcf.blocks blocks_con,
bcf.block_size blockSize_con,
to_char(null) deviceType_con,
bs.completion_time compTime_con,
bcf.create_time cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
bcf.ckp_scn toSCN_act,
bcf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
bcf.dbinc_key dbincKey_act,
to_number(null) level_act,
0 dfNumber_obj,
0 dfCreationSCN_obj,
bcf.autobackup_sequence
cfSequence_obj,
bcf.autobackup_date cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
bs.keep_options keep_options,
bs.keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM bcf, bs, dbinc
WHERE dbinc.db_key = this_db_key -- belongs to this database
AND bs.db_key = this_db_key -- belongs to this database
AND bcf.dbinc_key = dbinc.dbinc_key -- join bcf and dbinc
AND bcf.bs_key = bs.bs_key -- join bcf and bs
AND (findControlfileBackup_c.currentIncarnation = FALSE# OR
this_dbinc_key = bcf.dbinc_key)
AND (findControlfileBackup_c.completedAfter is NULL OR
bs.completion_time >= findControlfileBackup_c.completedAfter)
AND (findControlfileBackup_c.completedBefore is NULL OR
bs.completion_time <= findControlfileBackup_c.completedBefore)
AND (findControlfileBackup_c.untilSCN is NULL OR
bcf.ckp_scn <= findControlfileBackup_c.untilSCN)
AND (needstby is NULL OR
nvl(controlfile_type,'B') = decode(needstby, TRUE#, 'S', 'B'))
AND ((typemask = 0 AND bcf.autobackup_date IS NULL) OR -- no autobackups
(bitand(typemask, BScfile_all) != 0) OR -- all backups
(bcf.autobackup_date IS NOT NULL AND -- only autobackups
bitand(typemask, BScfile_auto) != 0))
ORDER BY toSCN_act desc,
stamp_con desc;
--------------------
-- SPFILE Backups --
--------------------
CURSOR findSpfileBackup_c(
completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,untilTime IN date DEFAULT NULL)
RETURN rcvRec_t IS
SELECT backupSet_con_t type_con,
bsf_recid key_con,
bsf_recid recid_con,
bsf_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
bs.incr_level bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
0 blocks_con,
0 blockSize_con,
to_char(null) deviceType_con,
bs.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
0 toSCN_act,
modification_time toTime_act,
to_number(null) rlgSCN_act,
to_date(null) rlgTime_act,
to_number(null) dbincKey_act,
to_number(null) level_act,
to_number(null) dfNumber_obj,
to_number(null) dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
bs.keep_options keep_options,
bs.keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM bsf, bs, db
WHERE bsf.bs_key = bs.bs_key -- join bsf and bs
AND bs.db_key = this_db_key -- belongs to this database
AND bsf.db_key = db.db_key -- join bsf and db
AND (findSpfileBackup_c.completedAfter is NULL OR
bs.completion_time >= findSpfileBackup_c.completedAfter)
AND (findSpfileBackup_c.completedBefore is NULL OR
bs.completion_time <= findSpfileBackup_c.completedBefore)
AND (findSpfileBackup_c.untilTime is NULL OR
modification_time <= findSpfileBackup_c.untilTime)
ORDER BY toTime_act desc, -- for finding best backup
stamp_con desc; -- to get most recent
---------------------
-- Datafile Backup --
---------------------
getDatafileBackupLast rcvRec_t;
CURSOR findDatafileBackup_c(
sourcemask IN number
,fno IN number DEFAULT NULL
,crescn IN number DEFAULT NULL
-- makes sense when fno != NULL
,tag IN varchar2 DEFAULT NULL
,pattern IN varchar2 DEFAULT NULL
,reset_scn IN number DEFAULT NULL
,reset_time IN date DEFAULT NULL
,level IN number DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,untilSCN IN number DEFAULT NULL
,statusMask IN binary_integer DEFAULT BSavailable -- ignored for backupset because we didn't join bp
)
RETURN rcvRec_t IS
SELECT imageCopy_con_t type_con,
cdf.cdf_key key_con,
cdf.cdf_recid recid_con,
cdf.cdf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
cdf.fname fileName_con,
cdf.tag tag_con,
to_number(null) copyNumber_con,
cdf.status status_con,
cdf.blocks blocks_con,
cdf.block_size blockSize_con,
'DISK' deviceType_con,
cdf.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
cdf.ckp_scn toSCN_act,
cdf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
cdf.dbinc_key dbincKey_act,
cdf.incr_level level_act,
cdf.file# dfNumber_obj,
cdf.create_scn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
cdf.keep_options keep_options,
cdf.keep_until keep_until,
cdf.abs_fuzzy_scn afzSCN_act,
cdf.rcv_fuzzy_time rfzTime_act,
cdf.rcv_fuzzy_scn rfzSCN_act
FROM cdf, dbinc
WHERE (sourcemask is NULL OR bitand(sourcemask, imageCopy_con_t) != 0)
AND (dbinc.db_key = this_db_key) -- belongs to this database
AND (dbinc.dbinc_key = cdf.dbinc_key) -- join cdf and dbinc
AND (findDatafileBackup_c.reset_scn is NULL OR
(findDatafileBackup_c.reset_scn = dbinc.reset_scn AND
findDatafileBackup_c.reset_time = dbinc.reset_time))
AND ((findDatafileBackup_c.fno IS NULL AND file# != 0) OR -- no ctrl bkps
cdf.file# = findDatafileBackup_c.fno)
AND (findDatafileBackup_c.crescn is NULL OR
cdf.create_scn = findDatafileBackup_c.crescn)
AND isStatusMatch(status,statusMask) = TRUE#
AND (findDatafileBackup_c.tag is NULL OR
tag = findDatafileBackup_c.tag)
AND (findDatafileBackup_c.pattern is NULL OR
cdf.fname LIKE findDatafileBackup_c.pattern)
AND (findDatafileBackup_c.completedAfter is NULL OR
cdf.completion_time >= findDatafileBackup_c.completedAfter)
AND (findDatafileBackup_c.completedBefore is NULL OR
cdf.completion_time <= findDatafileBackup_c.completedBefore)
AND (findDatafileBackup_c.untilSCN is NULL OR
cdf.ckp_scn <= findDatafileBackup_c.untilSCN)
AND (findDatafileBackup_c.level is NULL OR
cdf.incr_level <= findDatafileBackup_c.level)
UNION ALL
SELECT proxyCopy_con_t type_con,
xdf.xdf_key key_con,
xdf.xdf_recid recid_con,
xdf.xdf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
xdf.handle fileName_con,
xdf.tag tag_con,
to_number(null) copyNumber_con,
xdf.status status_con,
xdf.blocks blocks_con,
xdf.block_size blockSize_con,
xdf.device_type deviceType_con,
xdf.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
xdf.ckp_scn toSCN_act,
xdf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
xdf.dbinc_key dbincKey_act,
xdf.incr_level level_act,
xdf.file# dfNumber_obj,
xdf.create_scn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
xdf.keep_options keep_options,
xdf.keep_until keep_until,
xdf.abs_fuzzy_scn afzSCN_act,
xdf.rcv_fuzzy_time rfzTime_act,
xdf.rcv_fuzzy_scn rfzSCN_act
FROM xdf, dbinc
WHERE (sourcemask is NULL OR bitand(sourcemask, proxyCopy_con_t) != 0)
AND (dbinc.db_key = this_db_key) -- belongs to this database
AND (dbinc.dbinc_key = xdf.dbinc_key) -- join xdf and dbinc
AND (findDatafileBackup_c.reset_scn is NULL OR
(findDatafileBackup_c.reset_scn = dbinc.reset_scn AND
findDatafileBackup_c.reset_time = dbinc.reset_time))
AND ((findDatafileBackup_c.fno IS NULL AND file# != 0) OR -- no ctrl bkps
xdf.file# = findDatafileBackup_c.fno)
AND (findDatafileBackup_c.crescn is NULL OR
xdf.create_scn = findDatafileBackup_c.crescn)
AND isStatusMatch(xdf.status,statusMask) = TRUE#
AND (findDatafileBackup_c.tag is NULL OR
xdf.tag = findDatafileBackup_c.tag)
AND (findDatafileBackup_c.pattern is NULL OR
xdf.handle LIKE findDatafileBackup_c.pattern)
AND (findDatafileBackup_c.completedAfter is NULL OR
xdf.completion_time >= findDatafileBackup_c.completedAfter)
AND (findDatafileBackup_c.completedBefore is NULL OR
xdf.completion_time <= findDatafileBackup_c.completedBefore)
AND (findDatafileBackup_c.untilSCN is NULL OR
xdf.ckp_scn <= findDatafileBackup_c.untilSCN)
AND (findDatafileBackup_c.level is NULL OR
xdf.incr_level <= findDatafileBackup_c.level)
UNION ALL
SELECT backupSet_con_t type_con,
bdf.bdf_key key_con,
bdf.bdf_recid recid_con,
bdf.bdf_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
bs.incr_level bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
bdf.blocks blocks_con,
bdf.block_size blockSize_con,
to_char(null) deviceType_con,
bs.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
decode(bdf.incr_scn, 0, full_act_t, incremental_act_t)
type_act,
bdf.incr_scn fromSCN_act,
bdf.ckp_scn toSCN_act,
bdf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
bdf.dbinc_key dbincKey_act,
bdf.incr_level level_act,
bdf.file# dfNumber_obj,
bdf.create_scn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
bs.keep_options keep_options,
bs.keep_until keep_until,
bdf.abs_fuzzy_scn afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM bdf, bs, dbinc
WHERE (sourcemask is NULL OR bitand(sourcemask, backupSet_con_t) != 0)
AND (dbinc.db_key = this_db_key) -- belongs to this database
AND (bs.db_key = this_db_key) -- belongs to this database
AND (bdf.dbinc_key = dbinc.dbinc_key) -- join bdf and dbinc
AND (bdf.bs_key = bs.bs_key) -- join bdf and bs
AND (findDatafileBackup_c.reset_scn is NULL OR
(findDatafileBackup_c.reset_scn = dbinc.reset_scn AND
findDatafileBackup_c.reset_time = dbinc.reset_time))
AND ((findDatafileBackup_c.fno IS NULL AND file# != 0) OR -- no ctrl bkps
file# = findDatafileBackup_c.fno)
AND (findDatafileBackup_c.crescn is NULL OR
bdf.create_scn = findDatafileBackup_c.crescn)
AND (findDatafileBackup_c.completedAfter is NULL OR
bs.completion_time >= findDatafileBackup_c.completedAfter)
AND (findDatafileBackup_c.completedBefore is NULL OR
bs.completion_time <= findDatafileBackup_c.completedBefore)
AND (findDatafileBackup_c.untilSCN is NULL OR
bdf.ckp_scn <= findDatafileBackup_c.untilSCN)
AND (findDatafileBackup_c.level is NULL OR
bdf.incr_level <= findDatafileBackup_c.level)
ORDER BY 33, -- dfNumber_obj
27 desc, -- toSCN_act
4 desc; -- stamp_con
CURSOR findDatafileCopyKey(
copyKey IN number
,statusMask IN binary_integer)
RETURN rcvRec_t IS
-- Replaces these cursors: cursor in translateDataFileCopyKey
SELECT imageCopy_con_t type_con,
cdf_key key_con,
cdf_recid recid_con,
cdf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
fname fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
blocks blocks_con,
block_size blockSize_con,
'DISK' deviceType_con,
completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
cdf.ckp_scn toSCN_act,
cdf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
cdf.dbinc_key dbincKey_act,
incr_level level_act,
file# dfNumber_obj,
create_scn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
cdf.keep_options keep_options,
cdf.keep_until keep_until,
cdf.abs_fuzzy_scn afzSCN_act,
cdf.rcv_fuzzy_time rfzTime_act,
cdf.rcv_fuzzy_scn rfzSCN_act
FROM cdf, dbinc
WHERE dbinc.db_key = this_db_key -- belongs to this database
AND dbinc.dbinc_key = cdf.dbinc_key -- join cdf and dbinc
AND (findDatafileCopyKey.copyKey = cdf_key)
AND isStatusMatch(status,statusMask) = TRUE#
ORDER BY dfNumber_obj, -- for duplicate filtering
toSCN_act desc, -- for tag translation
stamp_con desc; -- to get most recent
CURSOR findBackupsetFiles(
bskey IN number)
RETURN rcvRec_t IS
-- datafiles
SELECT backupSet_con_t type_con,
bdf_key key_con,
bdf_recid recid_con,
bdf_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
bs.incr_level bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
bdf.blocks blocks_con,
bdf.block_size blockSize_con,
to_char(null) deviceType_con,
bs.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
decode(bdf.incr_scn, 0, full_act_t, incremental_act_t)
type_act,
bdf.incr_scn fromSCN_act,
bdf.ckp_scn toSCN_act,
bdf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
bdf.dbinc_key dbincKey_act,
bdf.incr_level level_act,
file# dfNumber_obj,
create_scn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
bs.keep_options keep_options,
bs.keep_until keep_until,
bdf.abs_fuzzy_scn afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM bdf, bs, dbinc
WHERE (allIncarnations = TRUE# OR dbinc.dbinc_key = this_dbinc_key)
AND dbinc.db_key = this_db_key -- belongs to this database
AND dbinc.dbinc_key = bdf.dbinc_key -- join bdf and dbinc
AND bdf.bs_key = bs.bs_key -- join bdf and bs
AND bs.bs_key = bskey
UNION ALL
-- controlfile
SELECT backupSet_con_t type_con,
bcf_key key_con,
bcf_recid recid_con,
bcf_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
bs.incr_level bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
nvl(bcf.blocks,0) blocks_con,
bcf.block_size blockSize_con,
to_char(null) deviceType_con,
bs.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
to_number(null) fromSCN_act,
bcf.ckp_scn toSCN_act,
bcf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
bcf.dbinc_key dbincKey_act,
to_number(null) level_act,
0 dfNumber_obj,
0 dfCreationSCN_obj,
bcf.autobackup_sequence
cfSequence_obj,
bcf.autobackup_date cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
bs.keep_options keep_options,
bs.keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM bcf, bs, dbinc
WHERE (allIncarnations = TRUE# OR dbinc.dbinc_key = this_dbinc_key)
AND dbinc.db_key = this_db_key -- belongs to this database
AND dbinc.dbinc_key = bcf.dbinc_key -- join bcf and dbinc
AND bcf.bs_key = bs.bs_key -- join bcf and bs
AND bs.bs_key = bskey
UNION ALL
-- SPFILE
SELECT backupSet_con_t type_con,
bsf_recid key_con,
bsf_recid recid_con,
bsf_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
bs.incr_level bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
0 blocks_con,
0 blockSize_con,
to_char(null) deviceType_con,
bs.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
0 toSCN_act,
modification_time toTime_act,
to_number(null) rlgSCN_act,
to_date(null) rlgTime_act,
to_number(null) dbincKey_act,
to_number(null) level_act,
to_number(null) dfNumber_obj,
to_number(null) dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
bs.keep_options keep_options,
bs.keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM bsf, bs, db
WHERE bsf.bs_key = bs.bs_key -- join bsf and bs
AND bs.db_key = this_db_key -- belongs to this database
AND bsf.db_key = db.db_key -- join bsf and db
AND bs.bs_key = bskey
UNION ALL
-- archived logs
SELECT backupSet_con_t type_con,
brl.brl_key key_con,
brl.brl_recid recid_con,
brl.brl_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
to_number(null) bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
brl.blocks blocks_con,
brl.block_size blockSize_con,
to_char(null) deviceType_con,
bs.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
to_number(null) fromSCN_act,
to_number(null) toSCN_act,
to_date(null) toTime_act,
to_number(null) rlgSCN_act,
to_date(null) rlgTime_act,
dbinc.dbinc_key dbincKey_act,
to_number(null) level_act,
to_number(null) dfNumber_obj,
to_number(null) dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
brl.sequence# logSequence_obj,
brl.thread# logThread_obj,
dbinc.reset_scn logRlgSCN_obj,
dbinc.reset_time logRlgTime_obj,
brl.low_scn logLowSCN_obj,
brl.low_time logLowTime_obj,
brl.next_scn logNextSCN_obj,
brl.next_time logNextTime_obj,
to_number(null) keep_options,
to_date(null) keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM brl, bs, dbinc
WHERE (allIncarnations = TRUE# OR dbinc.dbinc_key = this_dbinc_key)
AND dbinc.db_key = this_db_key -- belongs to this database
AND dbinc.dbinc_key = brl.dbinc_key -- join brl and dbinc
AND brl.bs_key = bs.bs_key -- join brl and bs
AND bs.bs_key = bskey
ORDER BY 33, -- dfNumber_obj
38, -- logThread_obj
37; -- logSequence_obj
------------------
-- Proxy Copies --
------------------
CURSOR findProxyCopy(
tag IN varchar2 DEFAULT NULL
,handle IN varchar2 DEFAULT NULL
,deviceType IN varchar2 DEFAULT NULL
,statusMask IN binary_integer)
RETURN rcvRec_t IS
SELECT proxyCopy_con_t type_con,
xdf_key key_con,
xdf_recid recid_con,
xdf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
handle fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
blocks blocks_con,
block_size blockSize_con,
device_type deviceType_con,
completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
xdf.ckp_scn toSCN_act,
xdf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
xdf.dbinc_key dbincKey_act,
incr_level level_act,
file# dfNumber_obj,
create_scn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
xdf.keep_options keep_options,
xdf.keep_until keep_until,
xdf.abs_fuzzy_scn afzSCN_act,
xdf.rcv_fuzzy_time rfzTime_act,
xdf.rcv_fuzzy_scn rfzSCN_act
FROM xdf, dbinc
WHERE dbinc.db_key = this_db_key -- belongs to this database
AND dbinc.dbinc_key = xdf.dbinc_key -- join xdf and dbinc
AND (findProxyCopy.tag IS NULL OR
findProxyCopy.tag = tag)
AND (findProxyCopy.handle IS NULL OR
findProxyCopy.handle = handle)
AND (findProxyCopy.deviceType IS NULL OR
findProxyCopy.deviceType = device_type)
AND isStatusMatch(status,statusMask) = TRUE#
UNION ALL
SELECT proxyCopy_con_t type_con,
xcf_key key_con,
xcf_recid recid_con,
xcf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
handle fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
to_number(null) blocks_con, -- xcf doesn't have blocks
block_size blockSize_con,
device_type deviceType_con,
completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
xcf.ckp_scn toSCN_act,
xcf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
xcf.dbinc_key dbincKey_act,
to_number(null) level_act,
0 dfNumber_obj,
0 dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
xcf.keep_options keep_options,
xcf.keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM xcf, dbinc
WHERE db_key = this_db_key -- belongs to this database
AND dbinc.dbinc_key = xcf.dbinc_key -- join dbinc and xcf
AND (findProxyCopy.tag IS NULL OR
findProxyCopy.tag = tag)
AND (findProxyCopy.handle IS NULL OR
findProxyCopy.handle = handle)
AND (findProxyCopy.deviceType IS NULL OR
findProxyCopy.deviceType = device_type)
AND isStatusMatch(status,statusMask) = TRUE#;
CURSOR findProxyCopyKey(
key IN number DEFAULT NULL
,deviceType IN varchar2 DEFAULT NULL
,statusMask IN binary_integer)
RETURN rcvRec_t IS
SELECT proxyCopy_con_t type_con,
xdf_key key_con,
xdf_recid recid_con,
xdf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_date(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
handle fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
blocks blocks_con,
block_size blockSize_con,
device_type deviceType_con,
completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
xdf.ckp_scn toSCN_act,
xdf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
xdf.dbinc_key dbincKey_act,
incr_level level_act,
file# dfNumber_obj,
create_scn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
xdf.keep_options keep_options,
xdf.keep_until keep_until,
xdf.abs_fuzzy_scn afzSCN_act,
xdf.rcv_fuzzy_time rfzTime_act,
xdf.rcv_fuzzy_scn rfzSCN_act
FROM xdf, dbinc
WHERE dbinc.db_key = this_db_key -- belongs to this database
AND dbinc.dbinc_key = xdf.dbinc_key -- join xdf and dbinc
AND (findProxyCopyKey.key = xdf_key)
AND (findProxyCopyKey.deviceType IS NULL OR
findProxyCopyKey.deviceType = device_type)
AND isStatusMatch(status,statusMask) = TRUE#
UNION ALL
SELECT proxyCopy_con_t type_con,
xcf_key key_con,
xcf_recid recid_con,
xcf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_date(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
handle fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
to_number(null) blocks_con, -- xcf doesn't have blocks
block_size blockSize_con,
device_type deviceType_con,
completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
xcf.ckp_scn toSCN_act,
xcf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
xcf.dbinc_key dbincKey_act,
to_number(null) level_act,
0 dfNumber_obj,
0 dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
xcf.keep_options keep_options,
xcf.keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM xcf, dbinc
WHERE db_key = this_db_key -- belongs to this database
AND dbinc.dbinc_key = xcf.dbinc_key -- join dbinc and xcf
AND (findProxyCopyKey.key = xcf_key)
AND (findProxyCopyKey.deviceType IS NULL OR
findProxyCopyKey.deviceType = device_type)
AND isStatusMatch(status,statusMask) = TRUE#;
------------------------
-- Archivelog Backups --
------------------------
CURSOR findArchivedLogCopy(
currentIncarnation IN number
,thread IN number
,sequence IN number
,lowSCN IN number
,pattern IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,statusMask IN binary_integer
,needstby IN number DEFAULT NULL)
RETURN rcvRec_t IS
-- Replaces these cursors: lcal
SELECT imageCopy_con_t type_con,
al_key key_con,
recid recid_con,
stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_date(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
name fileName_con,
to_date(null) tag_con,
to_number(null) copyNumber_con,
status status_con,
blocks blocks_con,
block_size blockSize_con,
'DISK' deviceType_con,
completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
to_number(null) fromSCN_act,
to_number(null) toSCN_act,
to_date(null) toTime_act,
to_number(null) rlgSCN_act,
to_date(null) rlgTime_act,
dbinc_key dbincKey_act,
to_number(null) level_act,
to_number(null) dfNumber_obj,
to_number(null) dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
sequence# logSequence_obj,
thread# logThread_obj,
resetlogs_change# logRlgSCN_obj,
resetlogs_time logRlgTime_obj,
first_change# logLowSCN_obj,
first_time logLowTime_obj,
next_change# logNextSCN_obj,
next_time logNextTime_obj,
to_number(null) keep_options,
to_date(null) keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM rc_archived_log
WHERE db_key = this_db_key -- belongs to this database
AND(findArchivedLogCopy.currentIncarnation = FALSE# OR
this_dbinc_key = dbinc_key)
AND (thread IS NULL OR thread# = thread)
AND (sequence IS NULL OR sequence# = sequence)
AND (lowSCN IS NULL OR first_change# = lowSCN)
-- Pattern isn't really needed here. The LIKE clause should be
-- handled during name translation by krmkaltr. However, krmg.y
-- allows the LIKE clause as a listQualifier, so we need to support
-- it for that bizzarre case.
AND (pattern IS NULL OR name LIKE pattern)
AND (completedAfter IS NULL OR completion_time >= completedAfter)
AND (completedBefore IS NULL OR completion_time <= completedBefore)
AND isStatusMatch(status,statusMask) = TRUE#
AND (needstby is NULL OR
nvl(is_standby, 'NO') = decode(needstby, TRUE#, 'YES', 'NO'))
-- bug-1479780: translate should return only archived logs and not
-- online logs
AND (archived = 'YES')
AND (tc_thread IS NULL OR thread# = tc_thread)
AND (tc_fromSeq IS NULL OR sequence# >= tc_fromSeq)
AND (tc_toSeq IS NULL OR sequence# <= tc_toSeq)
AND (tc_fromSCN IS NULL OR next_change# > tc_fromSCN)
AND (tc_toSCN IS NULL OR first_change# < tc_toSCN)
AND (tc_pattern IS NULL or name like tc_pattern)
AND (tc_fromTime IS NULL or next_time > tc_fromTime)
AND (tc_toTime IS NULL or first_time <= tc_toTime)
ORDER BY thread#, sequence#, stamp_con desc;
CURSOR findArcLogBackup(
currentIncarnation IN number
,thread IN number
,sequence IN number
,lowSCN IN number
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL)
RETURN rcvRec_t IS
SELECT backupSet_con_t type_con,
brl.brl_key key_con,
brl.brl_recid recid_con,
brl.brl_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
to_number(null) bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
brl.blocks blocks_con,
brl.block_size blockSize_con,
to_char(null) deviceType_con,
bs.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
to_number(null) fromSCN_act,
to_number(null) toSCN_act,
to_date(null) toTime_act,
to_number(null) rlgSCN_act,
to_date(null) rlgTime_act,
dbinc.dbinc_key dbincKey_act,
to_number(null) level_act,
to_number(null) dfNumber_obj,
to_number(null) dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
brl.sequence# logSequence_obj,
brl.thread# logThread_obj,
dbinc.reset_scn logRlgSCN_obj,
dbinc.reset_time logRlgTime_obj,
brl.low_scn logLowSCN_obj,
brl.low_time logLowTime_obj,
brl.next_scn logNextSCN_obj,
brl.next_time logNextTime_obj,
to_number(null) keep_options,
to_date(null) keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM brl, bs, dbinc
WHERE dbinc.db_key = this_db_key -- belongs to this database
AND (currentIncarnation = FALSE# OR
this_dbinc_key = dbinc.dbinc_key)
AND (thread IS NULL OR brl.thread# = thread)
AND (sequence IS NULL OR brl.sequence# = sequence)
AND (lowSCN IS NULL OR brl.low_scn = lowSCN)
AND dbinc.dbinc_key = brl.dbinc_key -- join dbinc, brl
AND bs.bs_key = brl.bs_key -- join bs, brl
-- LIKE as a listOperand is not allowed for LIST BACKUP, so
-- pattern is ignored here.
AND (completedAfter IS NULL OR bs.completion_time >= completedAfter)
AND (completedBefore IS NULL OR bs.completion_time <= completedBefore)
AND (tc_thread IS NULL OR brl.thread# = tc_thread)
AND (tc_fromSeq IS NULL OR brl.sequence# >= tc_fromSeq)
AND (tc_toSeq IS NULL OR brl.sequence# <= tc_toSeq)
AND (tc_fromSCN IS NULL OR brl.next_scn > tc_fromSCN)
AND (tc_toSCN IS NULL OR brl.low_scn < tc_toSCN)
AND (tc_fromTime IS NULL or brl.next_time > tc_fromTime)
AND (tc_toTime IS NULL or brl.low_time <= tc_toTime)
ORDER BY brl.thread#, brl.sequence#, stamp_con desc;
CURSOR findAllBackupPiece(
backupType IN binary_integer
,tag IN varchar2
,statusMask IN binary_integer
,completedAfter IN date
,completedBefore IN date)
RETURN rcvRec_t IS
SELECT backupset_con_t type_con,
bp.bp_key key_con,
bp.bp_recid recid_con,
bp.bp_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
bs.incr_level bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
bp.handle fileName_con,
bp.tag tag_con,
bp.copy# copyNumber_con,
bp.status status_con,
to_number(null) blocks_con,
to_number(null) blockSize_con,
bp.device_type deviceType_con,
bs.completion_time compTime_con,
to_date(null) cfCreationTime_con,
bp.piece# pieceNumber_con,
bp.completion_time bpCompTime_con,
to_number(null) type_act,
to_number(null) fromSCN_act,
to_number(null) toSCN_act,
to_date(null) toTime_act,
to_number(null) rlgSCN_act,
to_date(null) rlgTime_act,
to_number(null) dbincKey_act,
to_number(null) level_act,
to_number(null) dfNumber_obj,
to_number(null) dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
bs.keep_options keep_options,
bs.keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM bp, bs
WHERE (bp.bs_key = bs.bs_key) -- join bp and bs
AND (bs.db_key = this_db_key) -- this database
AND (completedAfter IS NULL OR bs.completion_time >= completedAfter)
AND (completedBefore IS NULL OR bs.completion_time <= completedBefore)
AND (findAllBackupPiece.tag IS NULL or bp.tag = findAllBackupPiece.tag)
AND (isDeviceTypeAllocated(bp.device_type) = TRUE#)
AND (isStatusMatch(bp.status, statusMask) = TRUE#)
AND (findAllBackupPiece.backupType IS NULL OR
isBackupTypeMatch(bs.bck_type, backupType) = TRUE#)
-- the order here is important
ORDER BY bs.bs_key, bp.device_type, bp.tag, bp.copy#, bp.piece#;
---------------------------
-- Backup Set Validation --
---------------------------
getValidBackupSetLast validBackupSetRec_t;
getValidBackupSetCursor varchar2(30); -- to indicate what cursor was used
-- This cursor returns the device_type(s), tags, and copy#'s for which all
-- backup pieces of the specified backup set are available. A code field
-- is also provided which indicates whether the ORDER BY included all
-- 3 fields (1), or just device_type and tag (2), or just device_type (3).
-- NOTE: If you change the ORDER BY in the cursor, you probably need
-- to change getValidBackupSet. It depends on the order-by.
CURSOR findValidBackupSet_c(
bsKey IN number
,pieceCount IN number
,deviceType IN varchar2 DEFAULT NULL
,tag IN varchar2 DEFAULT NULL
,mask IN binary_integer)
RETURN dbms_rcvman.validBackupSetRec_t IS
-- N.B.
-- partial_avail means the backup set is unusable either because some
-- pieces are unavailable, expired or total backuppieces < existing
-- pieces. In other words the backupset is INCOMPLETE.
-- A partial_avail backupset can be made available by doing crosscheck,
-- catalog backuppiece(TBD), making pieces available.
-- Group by device_type, tag, and copy#. This way, we can see if there is
-- a set of pieces with the same copy# and tag.
SELECT device_type, tag, copy#, 1
FROM rc_backup_piece
WHERE bs_key = findValidBackupSet_c.bsKey
AND isStatusMatch(status,mask) = TRUE#
AND (findValidBackupSet_c.tag IS NULL OR
findValidBackupSet_c.tag = tag)
AND (findValidBackupSet_c.deviceType IS NULL OR
findValidBackupSet_c.deviceType = device_type)
GROUP BY device_type, tag, copy#
HAVING ((bitand(mask, dbms_rcvman.BSpartial_avail) = 0 AND
count(DISTINCT piece#) = findValidBackupSet_c.pieceCount) OR
(bitand(mask, dbms_rcvman.BSpartial_avail) <> 0 AND
count(DISTINCT piece#) <= findValidBackupSet_c.pieceCount))
UNION ALL
-- Allow a mix of copy numbers, but still the same tag. It is possible
-- that the backup set is available only if pieces with different copy#'s
-- are combined to form the complete set.
SELECT device_type, tag, to_number(null), 2
FROM rc_backup_piece
WHERE bs_key = findValidBackupSet_c.bsKey
AND ((bitand(mask, dbms_rcvman.BSavailable) <> 0 AND status = 'A') OR
(bitand(mask, dbms_rcvman.BSunavailable) <> 0 AND status = 'U') OR
(bitand(mask, dbms_rcvman.BSdeleted) <> 0 AND status = 'D') OR
(bitand(mask, dbms_rcvman.BSexpired) <> 0 AND status = 'X') OR
(bitand(mask, dbms_rcvman.BSpartial_avail) <> 0 AND
(status = 'A' OR status = 'U')))
AND (findValidBackupSet_c.tag IS NULL OR
findValidBackupSet_c.tag = tag)
AND (findValidBackupSet_c.deviceType IS NULL OR
findValidBackupSet_c.deviceType = device_type)
GROUP BY device_type, tag
HAVING ((bitand(mask, dbms_rcvman.BSpartial_avail) = 0 AND
count(DISTINCT piece#) = findValidBackupSet_c.pieceCount) OR
(bitand(mask, dbms_rcvman.BSpartial_avail) <> 0 AND
count(DISTINCT piece#) <= findValidBackupSet_c.pieceCount))
UNION ALL
-- Allow a mix of tags. It is possible that the backup set is available
-- only if we combine pieces with different tags. Since we are mixing
-- tags, we are definitly also going to be mixing copy#s because any set of
-- pieces composed of pieces with different tags must also have different
-- copy#s. Note that this is really moot until BACKUP BACKUP PIECE is
-- implemented. Until then all pieces of a backup set will have the same
-- tag, or no tag at all.
SELECT device_type, to_char(null), to_number(null), 3
FROM rc_backup_piece
WHERE bs_key = findValidBackupSet_c.bsKey
AND ((bitand(mask, dbms_rcvman.BSavailable) <> 0 AND status = 'A') OR
(bitand(mask, dbms_rcvman.BSunavailable) <> 0 AND status = 'U') OR
(bitand(mask, dbms_rcvman.BSdeleted) <> 0 AND status = 'D') OR
(bitand(mask, dbms_rcvman.BSexpired) <> 0 AND status = 'X') OR
(bitand(mask, dbms_rcvman.BSpartial_avail) <> 0 AND
(status = 'A' OR status = 'U')))
AND (findValidBackupSet_c.tag IS NULL OR
findValidBackupSet_c.tag = tag)
AND (findValidBackupSet_c.deviceType IS NULL OR
findValidBackupSet_c.deviceType = device_type)
GROUP BY device_type
HAVING ((bitand(mask, dbms_rcvman.BSpartial_avail) = 0 AND
count(DISTINCT piece#) = findValidBackupSet_c.pieceCount) OR
(bitand(mask, dbms_rcvman.BSpartial_avail) <> 0 AND
count(DISTINCT piece#) <= findValidBackupSet_c.pieceCount))
ORDER BY 1,2,3,4;
---------------------------------------------------------
-- findValidBackupSet_c optimized for 1 piece backupset --
----------------------------------------------------------
CURSOR findValidBackupSet1P_c(
bsKey IN number
,pieceCount IN number
,deviceType IN varchar2 DEFAULT NULL
,tag IN varchar2 DEFAULT NULL
,mask IN binary_integer)
RETURN validBackupSetRec_t IS
-- N.B.
-- We don't need to check partial_avail mask because there is just
-- one piece in this backupset. It just completely satisfies
-- statusMask provided.
-- We also don't need to group by
-- o device type because the 1 piece should completely exists on one device
-- o tag because the 1 piece should have the tag specified
-- o copy# because each piece has distinct copy number
--
SELECT device_type, tag, copy#, 1
FROM rc_backup_piece
WHERE bs_key = findValidBackupSet1P_c.bsKey
AND isStatusMatch(status,mask) = TRUE#
AND (findValidBackupSet1P_c.tag IS NULL OR
findValidBackupSet1P_c.tag = tag)
AND (findValidBackupSet1P_c.deviceType IS NULL OR
findValidBackupSet1P_c.deviceType = device_type) ;
-------------------
-- Backup Pieces --
-------------------
-- Replaces the following 8.1.x cursors:
-- bsq1, bsq2
-- NOTE: no indexs are used, so this cusor is likely to require a full
-- table scan of the bp table.
CURSOR findBackupPiece_c(
tag IN varchar2 DEFAULT NULL
,handle IN varchar2 DEFAULT NULL
,deviceType IN varchar2 DEFAULT NULL
,copyNumber IN number DEFAULT NULL
,statusMask IN binary_integer)
RETURN bpRec_t IS
SELECT bp_recid,
bp_stamp,
bp_key,
bp.bs_key,
set_stamp,
set_count,
piece#,
copy#,
bp.status,
bp.completion_time,
handle,
tag,
device_type
FROM bp, bs
WHERE bp.db_key = this_db_key -- belongs to this db
AND bs.db_key = this_db_key -- belongs to this db
AND bp.bs_key = bs.bs_key -- join bp and bs
AND (findBackupPiece_c.tag IS NULL OR
tag = findBackupPiece_c.tag)
AND (findBackupPiece_c.handle IS NULL OR
handle = findBackupPiece_c.handle)
AND (findBackupPiece_c.deviceType IS NULL OR
device_type = findBackupPiece_c.deviceType)
AND (findBackupPiece_c.copyNumber IS NULL OR
copy# = findBackupPiece_c.copyNumber)
AND isStatusMatch(bp.status,statusMask) = TRUE#
ORDER BY piece#, copy# desc, bp_stamp desc;
CURSOR findBackupPieceBpKey(
bpKey IN number
,tag IN varchar2 DEFAULT NULL
,handle IN varchar2 DEFAULT NULL
,deviceType IN varchar2 DEFAULT NULL
,copyNumber IN number DEFAULT NULL
,statusMask IN binary_integer)
RETURN bpRec_t IS
SELECT bp_recid,
bp_stamp,
bp_key,
bp.bs_key,
set_stamp,
set_count,
piece#,
copy#,
bp.status,
bp.completion_time,
handle,
tag,
device_type
FROM bp, bs
WHERE bp.db_key = this_db_key
AND bs.db_key = this_db_key
AND bp.bs_key = bs.bs_key
AND (bp_key = findBackupPieceBpKey.bpkey)
AND (findBackupPieceBpKey.tag IS NULL OR
tag = findBackupPieceBpKey.tag)
AND (findBackupPieceBpKey.handle IS NULL OR
handle = findBackupPieceBpKey.handle)
AND (findBackupPieceBpKey.deviceType IS NULL OR
device_type = findBackupPieceBpKey.deviceType)
AND (findBackupPieceBpKey.copyNumber IS NULL OR
copy# = findBackupPieceBpKey.copyNumber)
AND isStatusMatch(bp.status,statusMask) = TRUE#
ORDER BY piece#, copy# desc, bp_stamp desc;
CURSOR findBackupPieceBsKey(
bsKey IN number
,tag IN varchar2 DEFAULT NULL
,handle IN varchar2 DEFAULT NULL
,deviceType IN varchar2 DEFAULT NULL
,copyNumber IN number DEFAULT NULL
,statusMask IN binary_integer)
RETURN bpRec_t IS
SELECT bp_recid,
bp_stamp,
bp_key,
bp.bs_key,
set_stamp,
set_count,
piece#,
copy#,
bp.status,
bp.completion_time,
handle,
tag,
device_type
FROM bp, bs
WHERE bp.db_key = this_db_key
AND bs.db_key = this_db_key
AND bp.bs_key = bs.bs_key
AND (bs.bs_key = findBackupPieceBsKey.bsKey)
AND (findBackupPieceBsKey.tag IS NULL OR
tag = findBackupPieceBsKey.tag)
AND (findBackupPieceBsKey.handle IS NULL OR
handle = findBackupPieceBsKey.handle)
AND (findBackupPieceBsKey.deviceType IS NULL OR
device_type = findBackupPieceBsKey.deviceType)
AND (findBackupPieceBsKey.copyNumber IS NULL OR
copy# = findBackupPieceBsKey.copyNumber)
AND isStatusMatch(bp.status,statusMask) = TRUE#
ORDER BY piece#, copy# desc, bp_stamp desc;
----------------------
-- Name Translation --
----------------------
TYPE noRows_t IS RECORD
(
error number, -- error number
msg varchar2(100) -- error msg
);
-- The tablespace_list is used to hold the list of tablespace names to
-- skip when the SKIP TABLESPACE clause is specified.
TYPE tablespaceList_t is table of rc_tablespace.name%TYPE
index by binary_integer;
skipTablespaceList tablespaceList_t;
skipTablespaceCount number; -- number of tablespaces in list
--------------------------
-- Datafile Translation --
--------------------------
getDatafileCursor varchar2(30); -- pointer to current cursor
getDatafileNoRows noRows_t; -- Set by function that opens cursor
getDatafileLast dfRec_t; -- The last row returned
-- Translate the database within an SCN range. The datafiles are not part of
-- the database at their until the dictionary transaction commits.
-- Therefore the creation scn must be less than toSCN.
-- ### offline drop makes the above statement dangerous, so allow <=
-- Note that fromSCN and toSCN must not be null.
-- Note that inBackup field has value 1 if included_in_database_backup is 'YES'
CURSOR translateDatabase_c(
fromSCN number,
toSCN number)
RETURN dfRec_t IS
SELECT file#, creation_change#, creation_time,
name, tablespace_name, ts#,
null, blocks, block_size, bytes / 1024,
null, stop_change#, read_only, rfile#,
decode(included_in_database_backup, 'YES', 1, 0),
aux_name
FROM rc_datafile
WHERE db_key = this_db_key AND -- belongs to this database
dbinc_key = this_dbinc_key AND
creation_change# <= toSCN AND
(drop_change# is null OR drop_change# > fromSCN)
ORDER BY file#;
-- Translate a tablespace name (always relative to current time)
-- Note: inBackup field has value 1 if included_in_database_backup is 'YES'
CURSOR translateTablespace_c(
tsName varchar2)
RETURN dfRec_t IS
SELECT file#, creation_change#, creation_time,
name, tablespace_name, ts#,
null, blocks, block_size, bytes / 1024,
null, stop_change#, read_only, rfile#,
decode(included_in_database_backup, 'YES', 1, 0),
aux_name
FROM rc_datafile
WHERE db_key = this_db_key AND -- part of this db
tablespace_name = translateTablespace_c.tsName AND
dbinc_key = this_dbinc_key AND
((untilSCN is null AND drop_change# is null) OR
((creation_change# <= untilSCN) AND
(drop_change# is null or drop_change# > untilSCN)))
ORDER BY file#;
-- Translate a datafile name (always relative to current time
-- Note: inBackup field has value 1 if included_in_database_backup is 'YES'
CURSOR translateDatafileName(
fileName varchar2)
RETURN dfRec_t IS
SELECT file#, creation_change#, creation_time,
name, tablespace_name, ts#,
null, blocks, block_size, bytes / 1024,
null, stop_change#, read_only, rfile#,
decode(included_in_database_backup, 'YES', 1, 0),
aux_name
FROM rc_datafile
WHERE db_key = this_db_key AND -- belongs to this database
name = translateDatafilename.fileName AND -- filename matches
dbinc_key = this_dbinc_key AND
drop_change# is null AND -- filename currently part of db
(untilSCN is null OR creation_change# < untilSCN) AND
-- following "and" clause to detect ambiguous names
((untilSCN is null) OR -- no until clause
((untilTime is not null) AND not exists
(SELECT 1
FROM rc_datafile
WHERE dbinc_key = this_dbinc_key AND
name = translateDatafilename.fileName AND
nvl(creation_time, MINDATEVAL) < untilTime AND
drop_time > untilTime)) OR
((untilSCN is not null) AND not exists
(SELECT 1
FROM rc_datafile
WHERE dbinc_key = this_dbinc_key AND
name = translateDatafilename.fileName AND
creation_change# < untilSCN AND
drop_change# > untilSCN)));
-- Translate a datafile number
-- Note: inBackup field has value 1 if included_in_database_backup is 'YES'
CURSOR translateDatafileNumber(
fno number)
RETURN dfRec_t IS
SELECT file#, creation_change#, creation_time,
name, tablespace_name, ts#,
null, blocks, block_size, bytes / 1024,
null, stop_change#, read_only, rfile#,
decode(included_in_database_backup, 'YES', 1, 0),
aux_name
FROM rc_datafile
WHERE db_key = this_db_key AND -- belongs to this database
file# = translateDataFileNumber.fno AND -- filenumber matches
dbinc_key = this_dbinc_key AND
((untilSCN is null AND drop_change# is null) OR
((nvl(creation_time, MINDATEVAL) < untilTime OR
creation_change# < untilSCN) AND
(drop_time > untilTime OR
drop_change# > untilSCN OR
drop_change# is null)));
-- Translate a datafile number and checkpoint SCN
-- Note: inBackup field has value 1 if included_in_database_backup is 'YES'
CURSOR translateDatafileCheckpoint(
fno number
,ckpSCN number)
RETURN dfRec_t IS
SELECT file#, creation_change#, creation_time,
name, tablespace_name, ts#,
null, blocks, block_size, bytes / 1024,
null, stop_change#, read_only, rfile#,
decode(included_in_database_backup, 'YES', 1, 0),
aux_name
FROM rc_datafile
WHERE db_key = this_db_key -- belongs to this database
AND file# = translateDatafileCheckpoint.fno -- filenumber matches
AND dbinc_key = this_dbinc_key
AND translateDatafileCheckpoint.ckpSCN >= creation_change#
AND (drop_change# IS NULL OR
translateDatafileCheckpoint.ckpSCN < drop_change#);
-- Translate all datafiles that ever existed
-- Note that we return nulls for most fields here. This is because
-- the controlfile version of this cursor has to return nulls for them
-- because it doesn't have the information, and so we return nulls here
-- so that things are consistant.
-- We assume that if a datafile was added and backed up, then a resync
-- was done before the datafile was dropped. RMAN could not have created
-- the backup otherwise.
-- Note: inBackup field has value 1 if included_in_database_backup is 'YES'
CURSOR translateAllDatafile_c
RETURN dfRec_t IS
SELECT DISTINCT
file# dfNumber,
creation_change# dfCreationSCN,
creation_time dfCreationTime,
name fileName,
tablespace_name tsName,
ts# tsNumber,
to_char(null) status,
blocks blocks,
block_size blockSize,
bytes / 1024 kbytes,
to_number(null) unrecovSCN,
stop_change# stopSCN,
FALSE# readOnly,
rfile# rfNumber,
decode(included_in_database_backup, 'YES', 1, 0)
inBackup,
aux_name auxNAme
FROM rc_datafile
WHERE db_key = this_db_key
ORDER BY file#;
-- Translate all datafiles in rc_database_block_corruption
-- Note: inBackup field has value 1 if included_in_database_backup is 'YES'
CURSOR translateCorruptList_c
RETURN dfRec_t IS
SELECT DISTINCT
rcd.file#, rcd.creation_change#, rcd.creation_time,
rcd.name, rcd.tablespace_name, rcd.ts#,
null, rcd.blocks, rcd.block_size, rcd.bytes / 1024,
null, rcd.stop_change#, rcd.read_only, rcd.rfile#,
decode(rcd.included_in_database_backup, 'YES', 1, 0),
aux_name
FROM rc_datafile rcd,
(select distinct file# from rc_database_block_corruption) bc
WHERE rcd.db_key = this_db_key AND -- belongs to this database
rcd.file# = bc.file# AND -- filenumber matches
rcd.dbinc_key = this_dbinc_key AND
((untilSCN is null AND rcd.drop_change# is null) OR
((nvl(rcd.creation_time, MINDATEVAL) < untilTime OR
rcd.creation_change# < untilSCN) AND
(rcd.drop_time > untilTime OR
rcd.drop_change# > untilSCN OR
rcd.drop_change# is null)));
----------------------------
-- Online Log Translation --
----------------------------
CURSOR translateOnlineLogs_c IS
SELECT thread#, group#, name
FROM rc_redo_log
WHERE dbinc_key = this_dbinc_key
ORDER BY thread#, group#, name;
------------------------------
-- Archived Log Translation --
------------------------------
getArchivedLogNoRows noRows_t;
getArchivedLogDuplicates number; -- Duplicate filtering flag
getArchivedLogLast alRec_t; -- used for duplicate filtering
getArchivedLogCursor varchar2(40);
CURSOR translateArcLogKey(
alKey IN number
,needstby IN number DEFAULT NULL)
RETURN alRec_t IS
SELECT al_key,
recid,
stamp,
thread#,
sequence#,
name,
first_change#,
first_time,
next_change#,
next_time,
resetlogs_change#,
resetlogs_time,
blocks,
block_size,
status,
completion_time,
0
FROM rc_archived_log
WHERE db_key = this_db_key
AND (needstby is NULL OR
nvl(is_standby, 'NO') = decode(needstby, TRUE#, 'YES', 'NO'))
AND al_key = translateArcLogKey.alKey;
CURSOR translateArcLogName(
fname IN varchar2
,statusMask IN binary_integer
,online IN number -- IGNORED!
,needstby IN number DEFAULT NULL)
RETURN alRec_t IS
SELECT al_key,
recid,
stamp,
thread#,
sequence#,
name,
first_change#,
first_time,
next_change#,
next_time,
resetlogs_change#,
resetlogs_time,
blocks,
block_size,
status,
completion_time,
0
FROM rc_archived_log
WHERE db_key = this_db_key
AND name = translateArcLogName.fname
AND isStatusMatch(status,statusMask) = TRUE#
AND archived = 'YES'
AND (needstby is NULL OR
nvl(is_standby, 'NO') = decode(needstby, TRUE#, 'YES', 'NO'))
ORDER BY stamp desc;
CURSOR translateArcLogSeqRange(
thread# IN number
,fromseq# IN number
,toseq# IN number
,pattern IN varchar2
,statusMask IN binary_integer
,online IN number -- IGNORED!
,needstby IN number DEFAULT NULL)
RETURN alRec_t IS
SELECT al_key,
recid,
stamp,
thread#,
sequence#,
name,
first_change#,
first_time,
next_change#,
next_time,
resetlogs_change#,
resetlogs_time,
blocks,
block_size,
status,
completion_time,
0
FROM rc_archived_log
WHERE dbinc_key = this_dbinc_key
AND thread# = translateArcLogSeqRange.thread#
AND sequence# between nvl(fromseq#, 0)
and nvl(toseq#, MAXSEQVAL)
AND name is not null -- filter out cleared logs
AND (pattern is null OR name like pattern)
AND isstatusMatch(status,statusMask) = TRUE#
AND archived = 'YES'
AND (needstby is NULL OR
nvl(is_standby, 'NO') = decode(needstby, TRUE#, 'YES', 'NO'))
ORDER BY thread#, first_change#, sequence#, stamp desc;
CURSOR translateArcLogSeqRange2(
thread# IN number
,fromseq# IN number
,toseq# IN number
,needstby IN number DEFAULT NULL)
RETURN alRec_t IS
SELECT al_key,
recid,
stamp,
thread#,
sequence#,
name,
first_change#,
first_time,
next_change#,
next_time,
resetlogs_change#,
resetlogs_time,
blocks,
block_size,
status,
completion_time,
0
FROM rc_archived_log
WHERE dbinc_key = this_dbinc_key
AND thread# = translateArcLogSeqRange2.thread#
AND sequence# between nvl(fromseq#, 0)
and nvl(toseq#, MAXSEQVAL)
AND name is not null -- filter out cleared logs
AND archived = 'YES'
AND (needstby is NULL OR
nvl(is_standby, 'NO') = decode(needstby, TRUE#, 'YES', 'NO'))
UNION ALL
SELECT to_number(null),
to_number(null),
-1, -- to sort last (desc)
thread#,
sequence#,
to_char(null),
low_scn,
low_time,
next_scn,
next_time,
reset_scn,
reset_time,
blocks,
block_size,
'D',
to_date(null),
0
FROM brl, dbinc
WHERE brl.dbinc_key = dbinc.dbinc_key -- join condition
AND brl.dbinc_key = this_dbinc_key
AND thread# = translateArcLogSeqRange2.thread#
AND sequence# between nvl(fromseq#, 0)
and nvl(toseq#, MAXSEQVAL)
-- thread#, low_scn, al_stamp desc
ORDER BY 4, 7, 3 desc;
CURSOR translateArcLogTimeRange(
thread# IN number
,fromTime IN date
,toTime IN date
,pattern IN varchar2
,statusMask IN binary_integer
,online IN number -- IGNORED!
,needstby IN number DEFAULT NULL)
RETURN alRec_t IS
SELECT al_key,
al_recid,
al_stamp,
thread#,
sequence#,
fname,
low_scn,
low_time,
next_scn,
next_time,
reset_scn,
reset_time,
blocks,
block_size,
status,
completion_time,
0
FROM al, dbinc
WHERE al.dbinc_key = this_dbinc_key
AND dbinc.dbinc_key = this_dbinc_key
AND (translateArcLogTimeRange.thread# is NULL OR
thread# = translateArcLogTimeRange.thread#)
AND next_time > nvl(fromTime, MINDATEVAL)
AND low_time <= nvl(toTime, MAXDATEVAL)
AND fname is not null -- filter out cleared logs
AND (pattern is null OR fname like pattern)
AND isStatusMatch(status,statusMask) = TRUE#
AND archived = 'Y'
AND (needstby is NULL OR
nvl(is_standby, 'N') = decode(needstby, TRUE#, 'Y', 'N'))
ORDER BY thread#, low_scn, sequence#, al_stamp desc;
CURSOR translateArcLogTimeRange2(
thread# IN number
,fromTime IN date
,toTime IN date
,needstby IN number DEFAULT NULL)
RETURN alRec_t IS
SELECT al_key,
al_recid,
al_stamp,
thread#,
sequence#,
fname,
low_scn,
low_time,
next_scn,
next_time,
reset_scn,
reset_time,
blocks,
block_size,
status,
completion_time,
0
FROM al, dbinc
WHERE al.dbinc_key = this_dbinc_key
AND dbinc.dbinc_key = this_dbinc_key
AND (translateArcLogTimeRange2.thread# is NULL OR
thread# = translateArcLogTimeRange2.thread#)
AND next_time > nvl(fromTime, MINDATEVAL)
AND low_time <= nvl(toTime, MAXDATEVAL)
AND fname is not null -- filter out cleared logs
AND archived = 'Y'
AND (needstby is NULL OR
nvl(is_standby, 'N') = decode(needstby, TRUE#, 'Y', 'N'))
UNION ALL
SELECT to_number(null),
to_number(null),
-1, -- to sort last
thread#,
sequence#,
to_char(null),
low_scn,
low_time,
next_scn,
next_time,
reset_scn,
reset_time,
blocks,
block_size,
'D',
to_date(null),
0
FROM brl, dbinc
WHERE brl.dbinc_key = dbinc.dbinc_key -- join condition
AND brl.dbinc_key = this_dbinc_key
AND next_time > nvl(fromTime, MINDATEVAL)
AND low_time <= nvl(toTime, MAXDATEVAL)
AND (translateArcLogTimeRange2.thread# is NULL OR
thread# = translateArcLogTimeRange2.thread#)
-- thread#, low_scn, al_stamp desc
ORDER BY 4, 7, 3 desc;
-- This is the only cursor that respects the online parameter.
CURSOR translateArcLogSCNRange(
thread# IN number
,fromSCN IN number
,toSCN IN number
,pattern IN varchar2
,statusMask IN binary_integer
,online IN number
,needstby IN number DEFAULT NULL)
RETURN alRec_t IS
SELECT al_key,
al_recid,
al_stamp,
thread#,
sequence#,
fname,
low_scn,
low_time,
next_scn,
next_time,
reset_scn,
reset_time,
blocks,
block_size,
status,
completion_time,
0
FROM al, dbinc
WHERE al.dbinc_key = this_dbinc_key
AND dbinc.dbinc_key = this_dbinc_key
AND (translateArcLogSCNRange.thread# is NULL OR
thread# = translateArcLogSCNRange.thread#)
AND next_scn > nvl(fromSCN, 0)
AND low_scn < nvl(toSCN, MAXSCNVAL)
AND fname is not null -- filter out cleared logs
AND (pattern is null OR fname like pattern)
AND isStatusMatch(status,statusMask) = TRUE#
AND ("ONLINE" = 1 OR archived = 'Y')
AND (needstby is NULL OR
nvl(is_standby, 'N') = decode(needstby, TRUE#, 'Y', 'N'))
ORDER BY thread#, low_scn, al_stamp desc;
-- This cursor is used by krmkdmr(). krmkdmr() uses
-- this to get all archivelogs in the SCN range (x..infinity) where x
-- is the SCN where media recovery first requests a log. This is the only
-- cursor that respects the online parameter. Note that if we have
-- an inspected current online log in the list, then either that log has never
-- been archived, or if it has been archived, then the archived record has
-- a higher stamp, so the order by stamp desc means the archived copy
-- is returned first.
-- We union the al table with the brl table because
-- an archivedlog in the SCN range may have had its al record deleted or
-- uncataloged, but we still have a backup of that log. We could instead/also
-- union with rc_log_history, but if that gives us a log we wouldn't otherwise
-- see, then we will fail anyway since there is no copy or backup of that log.
-- As it is, we will give a meaningful error message if recovery asks for a log
-- we don't have, so there is no need to look at the log_history.
CURSOR translateArcLogSCNRange2(
thread# IN number
,fromSCN IN number
,toSCN IN number
,toTime IN date
,needstby IN number DEFAULT NULL)
RETURN alRec_t IS
SELECT al_key,
al_recid,
al_stamp,
thread#,
sequence#,
fname,
low_scn,
low_time,
next_scn,
next_time,
reset_scn,
reset_time,
blocks,
block_size,
status,
completion_time,
0
FROM al, dbinc
WHERE al.dbinc_key = this_dbinc_key
AND dbinc.dbinc_key = this_dbinc_key
AND (translateArcLogSCNRange2.thread# is NULL OR
thread# = translateArcLogSCNRange2.thread#)
AND next_scn > nvl(fromSCN, 0)
AND low_scn < nvl(toSCN, MAXSCNVAL)
AND (toTime IS NULL OR low_time < toTime)
AND (needstby is NULL OR
nvl(is_standby, 'N') = decode(needstby, TRUE#, 'Y', 'N'))
UNION ALL
SELECT to_number(null),
to_number(null),
-1, -- to sort last
thread#,
sequence#,
to_char(null),
low_scn,
low_time,
next_scn,
next_time,
reset_scn,
reset_time,
blocks,
block_size,
'D',
to_date(null),
0
FROM brl, dbinc
WHERE brl.dbinc_key = dbinc.dbinc_key -- join condition
AND brl.dbinc_key = this_dbinc_key
AND (translateArcLogSCNRange2.thread# is NULL OR
thread# = translateArcLogSCNRange2.thread#)
AND next_scn > nvl(fromSCN, 0)
AND low_scn < nvl(toSCN, MAXSCNVAL)
AND (toTime IS NULL OR low_time < toTime)
-- thread#, low_scn, al_stamp desc;
ORDER BY 4, 7, 3 desc;
CURSOR translateArcLogPattern(
pattern IN varchar2
,statusMask IN binary_integer
,online IN number -- IGNORED!
,needstby IN number DEFAULT NULL)
RETURN alRec_t IS
SELECT al_key,
recid,
stamp,
thread#,
sequence#,
name,
first_change#,
first_time,
next_change#,
next_time,
resetlogs_change#,
resetlogs_time,
blocks,
block_size,
status,
completion_time,
0
FROM rc_archived_log
WHERE dbinc_key = this_dbinc_key
AND (pattern is null or name like pattern)
AND isStatusMatch(status,statusMask) = TRUE#
AND archived = 'YES'
AND (needstby is NULL OR
nvl(is_standby, 'NO') = decode(needstby, TRUE#, 'YES', 'NO'))
ORDER BY thread#, first_change#, sequence#, stamp desc;
---------------------------------
-- Controlfilecopy Translation --
---------------------------------
getControlFileCopySingleRow boolean;
---------------------
-- getDatafileCopy --
---------------------
getDatafileCopyCursor varchar2(30);
getDatafileCopyNoRows noRows_t;
getDatafileCopyDuplicates number;
getDatafileCopyLast rcvRec_t;
getDatafileCopySingleRow boolean;
------------------
-- getProxyCopy --
------------------
getProxyCopyCursor varchar2(30);
getProxyCopyNoRows noRows_t;
getProxyCopyByHandle boolean;
--------------------
-- getBackupPiece --
--------------------
getBackupPieceCursor varchar2(30);
getBackupPieceNoRows noRows_t;
getBackupPieceDuplicates number; -- TRUE# -> duplicates OK
-- FALSE# -> eliminate duplicates
getBackupPieceLast bpRec_t;
-- getBackupPieceDeviceType must not be null if getBackupPieceDuplicates
-- is FALSE#.
getBackupPieceDeviceType bp.device_type%TYPE;
getBackupPieceExpectedPieces number;
getBackupPiecePieceCount number;
getBackupPieceByHandle boolean;
getBackupPieceAvailableMask binary_integer;
----------
-- List --
----------
listGetBackupTag bp.tag%TYPE;
listGetBackupAvailableMask binary_integer;
listGetProxyDatafileCursor varchar2(30);
-- This cursor is just a bad idea. It is here only for backward
-- compatibility with 8.1.
CURSOR lbal2(thread# number,
lowseq number,
highseq number,
lowscn number,
highscn number,
from_time date ,
until_time date)
RETURN rcvRec_t IS
SELECT backupSet_con_t type_con,
brl.brl_key key_con,
brl.brl_recid recid_con,
brl.brl_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
to_number(null) bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
brl.blocks blocks_con,
brl.block_size blockSize_con,
to_char(null) deviceType_con,
bs.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
to_number(null) fromSCN_act,
to_number(null) toSCN_act,
to_date(null) toTime_act,
to_number(null) rlgSCN_act,
to_date(null) rlgTime_act,
dbinc.dbinc_key dbincKey_act,
to_number(null) level_act,
to_number(null) dfNumber_obj,
to_number(null) dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
brl.sequence# logSequence_obj,
brl.thread# logThread_obj,
dbinc.reset_scn logRlgSCN_obj,
dbinc.reset_time logRlgTime_obj,
brl.low_scn logLowSCN_obj,
brl.low_time logLowTime_obj,
brl.next_scn logNextSCN_obj,
brl.next_time logNextTime_obj,
to_number(null) keep_options,
to_date(null) keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
from brl, bs, dbinc
where dbinc.db_key = this_db_key -- this database
and dbinc.dbinc_key = brl.dbinc_key -- join dbinc, brl
and bs.bs_key = brl.bs_key -- join bs, brl
and (lbal2.thread# is null or brl.thread# = lbal2.thread#)
and (brl.sequence# between nvl(lbal2.lowseq, 0)
and nvl(lbal2.highseq, MAXSEQVAL))
and (lowscn is null or brl.low_scn >= lowscn)
and (highscn is null or brl.next_scn< highscn)
and (from_time is null or bs.completion_time >= from_time)
and (until_time is null or bs.completion_time <= until_time)
--and (pattern is null or brl.name like pattern)
and bs.status != 'D'
order by bs.bs_key, brl.thread#, brl.sequence#;
CURSOR ldbi(
db_name varchar2)
IS
SELECT db_key, dbinc_key, name, dbid, current_incarnation,
resetlogs_change#, resetlogs_time
FROM rc_database_incarnation
WHERE (ldbi.db_name IS NULL OR
name = upper(ldbi.db_name))
ORDER BY dbid, resetlogs_change#;
CURSOR lrtbs
IS
SELECT DISTINCT ts.ts#, ts.ts_name
FROM ts, tsatt, ckp ckp1, ckp ckp2
-- Join ts to tsatt by dbinc_key, ts#, creation_scn
WHERE ts.dbinc_key = tsatt.dbinc_key
AND ts.ts# = tsatt.ts#
AND ts.create_scn = tsatt.create_scn
-- Join tsatt to the ckp row containing the first SCN where we know that
-- these tsatt values are valid. tsatt.start_ckp_key is never null.
AND ckp1.ckp_key = tsatt.start_ckp_key
-- Join tsatt to the ckp row containing an SCN beyond which we know that
-- these tsatt values are not valid. Do an outer join because
-- tsatt.end_ckp_key can be null.
AND ckp2.ckp_key(+) = tsatt.end_ckp_key
-- Select only rows belonging to the current incarnation.
AND ts.dbinc_key = this_dbinc_key
-- If there is an until SCN, select only tablespaces created earlier.
-- If there is no until SCN, let the row pass (it will be filtered by
-- the next condition if it has been dropped). create_scn is never null.
AND (ts.create_scn < untilSCN or untilSCN is NULL)
-- Select rows for tablespaces that have never been dropped, or which
-- were dropped more recently than the until SCN. If there is a
-- drop_scn and no until SCN (which means we don't want this row),
-- then both conditions are false (NULL always compares false, and
-- drop_scn is not null).
AND (ts.drop_scn > untilSCN or ts.drop_scn is NULL)
-- If there is an until SCN, select only those rows where we know that
-- the tsatt values were valid at or before that SCN. ckp1.ckp_scn is
-- never null. If there is no until SCN, let the row pass (it will be
-- filtered by the next condition if the tsatt values are no longer
-- valid).
AND (ckp1.ckp_scn <= untilSCN or untilSCN is NULL)
-- Select only those rows for which the tsatt values are still valid, or
-- were known to be valid AFTER the until SCN. If there is no until SCN
-- and the tsatt values are no longer valid (which means we don't want
-- this row), then both conditions will be false.
AND (ckp2.ckp_scn > untilSCN or ckp2.ckp_scn is NULL)
-- All that was just to get us here. Select only tablespaces which
-- contain one or more rollback segments.
AND tsatt.rbs_count > 0
ORDER BY 1;
-------------------------------------------------------
-- listTranslateProxyDFRecid and translateBackupFile --
-------------------------------------------------------
rcvRec_last rcvRec_t; -- last record returned from:
-- getRecoveryAction
-- findControlFileBackup
-------------------------
-- getOfflineRangeCopy --
-------------------------
CURSOR getOfflineRangeCopy_c(
offrRecid number
,offrCkpSCN number
,cfCreTime date
,dbincKey number)
RETURN rcvRec_t IS
SELECT imageCopy_con_t type_con,
ccf_key key_con,
ccf_recid recid_con,
ccf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
fname fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
to_number(null) blocks_con, -- ccf doesn't have blocks
block_size blockSize_con,
'DISK' deviceType_con,
completion_time compTime_con,
create_time cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
ccf.ckp_scn toSCN_act,
ccf.ckp_time toTime_act,
dbinc.reset_scn rlgSCN_act,
dbinc.reset_time rlgTime_act,
ccf.dbinc_key dbincKey_act,
to_number(null) level_act,
0 dfNumber_obj,
0 dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
ccf.keep_options keep_options,
ccf.keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM ccf, dbinc
WHERE dbinc.dbinc_key = getOfflineRangeCopy_c.dbincKey
AND dbinc.dbinc_key = ccf.dbinc_key
AND getOfflineRangeCopy_c.cfCretime = create_time
AND getOfflineRangeCopy_c.offrCkpSCN < ccf.ckp_scn
AND getOfflineRangeCopy_c.offrRecid >= min_offr_recid
AND status = 'A'
ORDER BY stamp_con desc;
-- list all backups/copies/offline-ranges for all datafiles,
-- for REPORT OBSOLETE
cursor rddf is
-- datafile copies
select 2 preference,
file#, COPY filetype, checkpoint_change#, checkpoint_time,
resetlogs_change#, resetlogs_time, 0 incremental_change#,
decode(decode(online_fuzzy,'NO',0,1)+decode(backup_fuzzy,'NO',0,1),
0,greatest(nvl(absolute_fuzzy_change#,0),
nvl(recovery_fuzzy_change#,0)),
maxscnval) fuzzy_change#,
recid, stamp, name, 0 set_stamp, 0 set_count, cdf_key key,
completion_time, 'DISK' device_type
from rc_datafile_copy
where db_key = this_db_key
and status != 'D'
union all
-- proxy datafile copies
select 3,
file#, PROXY, checkpoint_change#, checkpoint_time,
resetlogs_change#, resetlogs_time, 0,
decode(decode(online_fuzzy,'NO',0,1)+decode(backup_fuzzy,'NO',0,1),
0,greatest(nvl(absolute_fuzzy_change#,0),
nvl(recovery_fuzzy_change#,0)),
maxscnval),
recid, stamp, handle, 0, 0, xdf_key, completion_time, device_type
from rc_proxy_datafile
where db_key = this_db_key
and status != 'D'
union all
-- datafiles in backup sets
select decode(bs.bck_type, 'D', 4,
'I', 5),
file#,
decode(bs.bck_type, 'D', FULL_DF_BACKUP,
'I', INCREMENTAL_DF_BACKUP),
bdf.ckp_scn, bdf.ckp_time,
dbinc.reset_scn, dbinc.reset_time, bdf.incr_scn,
nvl(bdf.abs_fuzzy_scn,0),
bs.bs_recid, bs.bs_stamp, null, bs.set_stamp, bs.set_count, bs.bs_key,
bs.completion_time, null
from bdf, bs, dbinc
where dbinc.db_key = this_db_key -- this database
and dbinc.dbinc_key = bdf.dbinc_key -- join dbinc, bdf
and bdf.bs_key = bs.bs_key -- join bdf, bs
and bs.status != 'D'
union all
-- controlfile copies
select 2,
0, COPY, checkpoint_change#, checkpoint_time,
resetlogs_change#, resetlogs_time, 0, 0, recid, stamp, name, 0, 0,
ccf_key, completion_time, 'DISK'
from rc_controlfile_copy
where db_key = this_db_key
and status != 'D'
union all
-- proxy controlfile copies
select 3,
0, PROXY, checkpoint_change#, checkpoint_time,
resetlogs_change#, resetlogs_time, 0, 0, recid, stamp, handle, 0, 0,
xcf_key, completion_time, device_type
from rc_proxy_controlfile
where db_key = this_db_key
and status != 'D'
union all
-- controlfiles in backup sets
select 4,
0, FULL_DF_BACKUP,
bcf.ckp_scn, bcf.ckp_time, dbinc.reset_scn, dbinc.reset_time,
0, 0, bs.bs_recid, bs.bs_stamp, null,
bs.set_stamp, bs.set_count, bs.bs_key, bs.completion_time, null
from bcf, bs, dbinc
where dbinc.db_key = this_db_key -- this database
and dbinc.dbinc_key = bcf.dbinc_key -- join dbinc, bcf
and bcf.bs_key = bs.bs_key -- join bcf, bs
and bs.status != 'D'
union all
-- offline ranges
select 1,
file#, OFFLINE_RANGE, online_change#, online_time,
resetlogs_change#, resetlogs_time, offline_change#, 0,
recid, stamp, null, 0, 0, 0, online_time, null
from rc_offline_range ofr, rc_database_incarnation di
where ofr.db_key = this_db_key
and di.db_key = this_db_key
and ofr.dbinc_key = di.dbinc_key
-- The algorithm in krmkcofl (Construct Obsolete File List) depends on the
-- following ordering.
order by 2 asc, -- file#
4 desc, -- checkpoint_change#
1 asc, -- preference
15 desc; -- completion_time, to break ties if all else is equal
----------------
-- BMR cursor --
----------------
-- to add row in corruption table to BMR list-
CURSOR bmrAddCorruptTable_c
IS
SELECT DISTINCT
file#, block#, blocks
FROM rc_database_block_corruption bc
WHERE bc.db_key = this_db_key AND -- belongs to this database
bc.dbinc_key = this_dbinc_key;
------------------------
-- RMAN configuration --
------------------------
CURSOR findConfig_c(
name varchar2,
value varchar2)
IS
SELECT conf#, name, value
FROM rc_rman_configuration rm
WHERE db_key = this_db_key -- part of this database
AND ((findConfig_c.name is null OR
UPPER(findConfig_c.name) = UPPER(rm.name)) AND
(findConfig_c.value is null OR
UPPER(findConfig_c.value) = UPPER(rm.value)));
--------------------
-- Backup History --
--------------------
getLastBackupHistory bhistoryRec_t;
CURSOR dfBackupHistory_c(
file# IN number
,crescn IN number
,reset_scn IN number
,reset_time IN date)
RETURN bhistoryRec_t IS
SELECT
bs.bs_key key,
bp.device_type device_type,
bdf.file# dfNumber,
bdf.create_scn create_scn,
dbinc.reset_scn reset_scn,
dbinc.reset_time reset_time,
bdf.ckp_scn ckp_scn,
nvl(df.stop_scn, 0) stop_scn,
to_number(null) logThread,
to_number(null) logSequence,
to_number(null) setStamp,
to_number(null) setCount,
max(bs.completion_time) compTime,
0 nbackups
FROM bdf,
bs,
bp,
dbinc,
df
WHERE bdf.dbinc_key = dbinc.dbinc_key -- join dbinc, bdf
AND dbinc.db_key = this_db_key -- this database
AND bdf.create_scn = df.create_scn -- create scn match
AND bdf.file# = df.file# -- join bdf, df
AND (dfBackupHistory_c.file# IS NULL OR
df.file# = dfBackupHistory_c.file#)
AND (dfBackupHistory_c.crescn IS NULL OR
df.create_scn = dfBackupHistory_c.crescn)
AND (dfBackupHistory_c.reset_scn IS NULL OR
(dbinc.reset_scn = dfBackupHistory_c.reset_scn AND
dbinc.reset_time = dfBackupHistory_c.reset_time))
AND bdf.bs_key = bs.bs_key -- join bdf, bs
AND bdf.bs_key = bp.bs_key -- join bdf, bp
AND bs.status = 'A' -- available backupset
GROUP BY bs.bs_key, bp.device_type, bp.copy#, bdf.file#, bdf.create_scn,
dbinc.reset_scn, dbinc.reset_time, bdf.ckp_scn, df.stop_scn,
bs.pieces
HAVING ((count(DISTINCT bp.piece#) = bs.pieces) AND
(count(DISTINCT bp.device_type) = 1))
UNION ALL
SELECT
xdf.xdf_recid key,
xdf.device_type device_type,
xdf.file# dfNumber,
xdf.create_scn create_scn,
dbinc.reset_scn reset_scn,
dbinc.reset_time reset_time,
xdf.ckp_scn ckp_scn,
nvl(df.stop_scn, 0) stop_scn,
to_number(null) logThread,
to_number(null) logSequence,
to_number(null) setStamp,
to_number(null) setCount,
max(xdf.completion_time) compTime,
0 nbackups
FROM xdf,
df,
dbinc
WHERE xdf.dbinc_key = dbinc.dbinc_key -- join xdf, dbinc
AND dbinc.db_key = this_db_key -- this database
AND df.dbinc_key = this_dbinc_key -- this incarnation files
AND xdf.create_scn = df.create_scn -- create scn match
AND xdf.file# = df.file# -- join xdf, df
AND (dfBackupHistory_c.file# IS NULL OR
dfBackupHistory_c.file# = df.file#)
AND (dfBackupHistory_c.crescn IS NULL OR
df.create_scn = dfBackupHistory_c.crescn)
AND (dfBackupHistory_c.reset_scn IS NULL OR
(dbinc.reset_scn = dfBackupHistory_c.reset_scn AND
dbinc.reset_time = dfBackupHistory_c.reset_time))
AND xdf.status = 'A' -- available proxy al
GROUP BY xdf.xdf_recid, xdf.device_type, xdf.file#, xdf.create_scn,
dbinc.reset_scn, dbinc.reset_time, xdf.ckp_scn, df.stop_scn
-- order is important to find number of backups and max completion time
ORDER BY 3, -- file#
7, -- ckp_scn
8, -- stop_scn
2, -- device_type
13; -- completion time
CURSOR alBackupHistory_c(
thread# IN number,
sequence# IN number)
RETURN bhistoryRec_t IS
SELECT
bs.bs_key key,
bp.device_type device_type,
to_number(null) dfNumber,
to_number(null) create_scn,
dbinc.reset_scn reset_scn,
dbinc.reset_time reset_time,
to_number(null) ckp_scn,
to_number(null) stop_scn,
brl.thread# logThread,
brl.sequence# logSequence,
to_number(null) setStamp,
to_number(null) setCount,
max(bs.completion_time) compTime,
0 nbackups
FROM brl,
bs,
bp,
al,
dbinc
WHERE dbinc.dbinc_key = this_dbinc_key -- this incarnation
AND brl.dbinc_key = dbinc.dbinc_key -- join brl, dbinc
AND al.dbinc_key = this_dbinc_key -- this incarnation files
AND brl.thread# = al.thread# -- join brl and al
AND brl.sequence# = al.sequence#
AND (alBackupHistory_c.thread# IS NULL OR
alBackupHistory_c.thread# = al.thread#)
AND (alBackupHistory_c.sequence# IS NULL OR
alBackupHistory_c.sequence# = al.sequence#)
AND brl.bs_key = bs.bs_key -- join brl,bs
AND brl.bs_key = bp.bs_key -- join brl,bp
AND bs.status = 'A' -- available backupset
GROUP BY bs.bs_key, bp.device_type, bp.copy#, bs.pieces, brl.thread#,
brl.sequence#, dbinc.reset_scn, dbinc.reset_time
HAVING ((count(DISTINCT bp.piece#) = bs.pieces) AND
(count(DISTINCT bp.device_type) = 1))
-- order is important to find number of backups and max completion time
ORDER BY brl.thread#, brl.sequence#, bp.device_type;
CURSOR bsBackupHistory_c(
set_stamp IN number
,set_count IN number
)
RETURN bhistoryRec_t IS
SELECT
bs.bs_key key,
bp.device_type device_type,
to_number(null) dfNumber,
to_number(null) create_scn,
dbinc.reset_scn reset_scn,
dbinc.reset_time reset_time,
to_number(null) ckp_scn,
to_number(null) stop_scn,
to_number(null) logThread,
to_number(null) logSequence,
bs.set_stamp setStamp,
bs.set_count setCount,
max(bp.completion_time) compTime,
0 nbackups
FROM bp,
bs,
dbinc
WHERE bp.db_key = dbinc.db_key -- join bp, dbinc
AND dbinc.db_key = this_db_key -- this database
AND bp.bs_key = bs.bs_key -- join bs, bp
AND (bsBackupHistory_c.set_stamp IS NULL OR
(bsBackupHistory_c.set_stamp = bs.set_stamp AND
bsBackupHistory_c.set_count = bs.set_count))
AND bp.status = 'A'
GROUP BY bs.bs_key, bp.device_type, bs.set_stamp, bs.set_count,
bs.pieces, bp.copy#, dbinc.reset_scn, dbinc.reset_time
HAVING ((count(DISTINCT bp.piece#) = bs.pieces) AND
(count(DISTINCT bp.status) = 1))
-- order is important to find number of backups and max completion time
ORDER BY bs.bs_key, bp.device_type;
--
-- Two ways to validateBackupSet.
-- o validateBackupSet() old way.
-- o qukvalidateBackupSet() will use in-memory records and is faster. Before
-- this call you should populate the in-memory records once using
-- createinCorebsRecStack
--
validateBackupSet_method varchar2(30); -- tell the way to validate backupSet
--
-- We will use this cursor in 10iR1 to make validBackupSet() faster.
-- For now, only getIncrementalScn uses this.
--
CURSOR inCorebsRec_c(
backupType IN binary_integer
,tag IN varchar2
,statusMask IN number
,completedAfter IN date
,completedBefore IN date)
RETURN inCorebsCursor_t IS
SELECT bs.bs_key bsKey,
bs.set_stamp setStamp,
bs.set_count setCount,
bp.device_type deviceType,
bs.pieces pieceCount
FROM bp, bs
WHERE (bs.db_key = this_db_key) -- belongs to this database
AND (bs.bs_key = bp.bs_key) -- join bs and bp
AND (isStatusMatch(bp.status, inCorebsRec_c.statusMask) = TRUE#)
AND (inCorebsRec_c.backupType IS NULL OR
isBackupTypeMatch(bs.bck_type, backupType) = TRUE#)
AND (inCorebsRec_c.tag IS NULL OR
inCorebsRec_c.tag = bp.tag)
AND (completedAfter IS NULL OR bs.completion_time >= completedAfter)
AND (completedBefore IS NULL OR bs.completion_time <= completedBefore)
GROUP BY bs.bs_key, bs.set_stamp, bs.set_count, bp.device_type,
bs.pieces
HAVING ((bitand(statusMask, dbms_rcvman.BSpartial_avail) = 0 AND
count(DISTINCT bp.piece#) = bs.pieces) OR
(bitand(statusMask, dbms_rcvman.BSpartial_avail) <> 0 AND
count(DISTINCT bp.piece#) <= bs.pieces))
ORDER BY bs.bs_key;
------------------------------------------------
-- *** PRIVATE FUNCTION/PROCEDURE SECTION *** --
------------------------------------------------
---------------
-- Debugging --
---------------
------------------------------------- deb -------------------------------------
PROCEDURE deb(
type IN number
,line IN varchar2 DEFAULT NULL
)
IS
pname varchar2(50);
pref varchar(11) := 'DBGRCVMAN: ';
buffer_overflow exception;
pragma exception_init(buffer_overflow, -20000);
BEGIN
IF (not debug) THEN
RETURN;
END IF;
IF type = DEB_ENTER THEN
pname := line;
dbms_output.put_line(pref||rpad(' ',pname_i)||'ENTERING '||pname);
pname_i := pname_i + 1;
last_pnames(pname_i) := pname;
ELSIF type = DEB_IN THEN
dbms_output.put_line(pref||rpad(' ',pname_i+2)||last_pnames(pname_i)||
' '||line);
ELSIF type = DEB_EXIT THEN
IF (pname_i >= 1) THEN
pname := last_pnames(pname_i);
pname_i := pname_i - 1;
ELSE
pname := DEB_DEF_PNAME;
END IF;
IF line is not NULL THEN
dbms_output.put_line(pref||rpad(' ', pname_i)||'EXITING '||pname||
' '||line);
ELSE
dbms_output.put_line(pref||rpad(' ', pname_i)||'EXITING '||pname);
END IF;
ELSIF type = DEB_OPEN THEN
pname := last_pnames(pname_i);
dbms_output.put_line(pref||rpad(' ', pname_i)||'OPENING cursor '||
line||' in '||pname);
ELSE
dbms_output.put_line(pref||line);
END IF;
EXCEPTION
WHEN buffer_overflow THEN
-- More debug information printed in this session to exceed buffer limit.
-- dbms_output doesn't provide a way to flush current buffer.
-- Just continue by disable and enable it again. We have lost previous
-- debug information.
dbms_output.disable;
dbms_output.enable(1000000);
WHEN others THEN
dbms_output.put_line('caught exception during deb ' ||
substr(sqlerrm, 1, 512));
END;
FUNCTION bool2char(
flag IN boolean)
RETURN varchar2 IS
BEGIN
IF (flag) THEN
RETURN 'TRUE';
ELSE
RETURN 'FALSE';
END IF;
END bool2char;
--------------------------
-- Database Translation --
--------------------------
-- Private procedure to check if a tablespace should be skipped.
-------------------------------- skipTableSpace -------------------------------
FUNCTION skipTableSpace(
tsName IN varchar2)
RETURN boolean IS
BEGIN
deb(DEB_ENTER, 'skipTableSpace');
FOR i in 1..skipTablespaceCount LOOP
IF (tsName = skipTablespaceList(i)) THEN
deb(DEB_EXIT, 'with: TRUE');
RETURN TRUE;
END IF;
END LOOP;
deb(DEB_EXIT, 'with: FALSE');
RETURN FALSE;
END;
------------------------------
-- Package State Validation --
------------------------------
-------------------------------- validateState --------------------------------
PROCEDURE validateState(
anyCursor IN varchar2)
IS
BEGIN
IF (this_db_key IS NULL) THEN
raise_application_error(-20021, 'database not set');
END IF;
IF (this_dbinc_key IS NULL) THEN
raise_application_error(-20020, 'Database incarnation not set');
END IF;
IF (anyCursor IS NOT NULL) THEN
raise_application_error(-20203, 'Translation already started');
END IF;
END;
---------------------
-- Query Filtering --
---------------------
-- Private procedure to find the highest SCN that is associated with a
-- timestamp less than or equal to timeStamp. This will give us an
-- approximate untilSCN which we can use in the WHERE clause of the queries.
--
-- Scanning of v$datafile is done so that the name translation cursors
-- can rely on just the scnVar in their where clause.
--
-- Offline ranges are scanned so that ones whose online checkpoint time
-- is at or after the from time are skipped.
----------------------------- computeUntilSCN -------------------------------
PROCEDURE computeUntilSCN(
timeStamp IN date
,scn OUT number)
IS
mySCN number;
BEGIN
deb(DEB_ENTER, 'computeUntilSCN');
SELECT nvl(max(first_change#),0)
INTO mySCN
FROM rc_log_history
WHERE dbinc_key = this_dbinc_key
AND first_time <= timeStamp;
SELECT greatest(nvl(max(low_scn), 0), mySCN)
INTO mySCN
FROM al
WHERE dbinc_key = this_dbinc_key
AND low_time <= timeStamp;
SELECT greatest(nvl(max(checkpoint_change#),0), mySCN)
INTO mySCN
FROM rc_backup_datafile
WHERE dbinc_key = this_dbinc_key
AND checkpoint_time <= timeStamp;
SELECT greatest(nvl(max(absolute_fuzzy_change#),0), mySCN)
INTO mySCN
FROM rc_backup_datafile
WHERE dbinc_key = this_dbinc_key
AND completion_time <= timeStamp;
SELECT greatest(nvl(max(checkpoint_change#),0), mySCN)
INTO mySCN
FROM rc_backup_controlfile
WHERE dbinc_key = this_dbinc_key
AND checkpoint_time <= timeStamp;
SELECT greatest(nvl(max(checkpoint_change#),0), mySCN)
INTO mySCN
FROM rc_datafile_copy
WHERE dbinc_key = this_dbinc_key
AND checkpoint_time <= timeStamp;
SELECT greatest(nvl(max(absolute_fuzzy_change#),0), mySCN)
INTO mySCN
FROM rc_datafile_copy
WHERE dbinc_key = this_dbinc_key
AND completion_time <= timeStamp;
SELECT greatest(nvl(max(recovery_fuzzy_change#),0), mySCN)
INTO mySCN
FROM rc_datafile_copy
WHERE dbinc_key = this_dbinc_key
AND recovery_fuzzy_time <= timeStamp;
SELECT greatest(nvl(max(checkpoint_change#),0), mySCN)
INTO mySCN
FROM rc_controlfile_copy
WHERE dbinc_key = this_dbinc_key
AND checkpoint_time <= timeStamp;
SELECT greatest(nvl(max(checkpoint_change#),0), mySCN)
INTO mySCN
FROM rc_proxy_datafile
WHERE dbinc_key = this_dbinc_key
AND checkpoint_time <= timeStamp;
SELECT greatest(nvl(max(create_scn), 0), mySCN)
INTO mySCN
FROM df
WHERE dbinc_key = this_dbinc_key
AND create_time <= timeStamp;
SELECT greatest(nvl(max(stop_scn), 0), mySCN)
INTO mySCN
FROM df
WHERE dbinc_key = this_dbinc_key
AND stop_time <= timeStamp;
SELECT greatest(nvl(max(online_scn), 0), mySCN)
INTO mySCN
FROM offr
WHERE dbinc_key = this_dbinc_key
AND online_time <= timeStamp;
scn := mySCN;
deb(DEB_EXIT, 'with '||to_char(scn));
END computeUntilSCN;
---------------------------- isDeviceTypeAllocated ----------------------------
FUNCTION isDeviceTypeAllocated(
deviceType IN varchar2)
RETURN NUMBER IS
BEGIN
deb(DEB_ENTER, 'isDeviceTypeAllocated');
IF (anyDevice) THEN
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
END IF;
FOR i IN 1..deviceCount LOOP
IF deviceType = deviceList(i) THEN
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
END IF;
END LOOP;
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END isDeviceTypeAllocated;
----------------------------
-- Backup Set Translation --
----------------------------
-- Lookup a backup set by primary key or recid/stamp
-------------------------------- findBackupSet --------------------------------
PROCEDURE findBackupSet(
bsKey IN number DEFAULT NULL
,recid IN number DEFAULT NULL
,stamp IN number DEFAULT NULL
,bsRec OUT bsRec_t)
IS
BEGIN
deb(DEB_ENTER, 'findBackupSet');
deb(DEB_IN, 'bsKey:'||nvl(bsKey, -1));
IF (bsKey IS NOT NULL) THEN
SELECT recid,
stamp,
bs_key,
set_stamp,
set_count,
backup_type,
incremental_level,
elapsed_seconds,
completion_time,
status,
pieces,
decode (keep_options, 'LOGS' , KEEP_LOGS
, 'NOLOGS' , KEEP_NOLOGS
, 'CONSISTENT' , KEEP_CONSIST
, KEEP_NO),
keep_until
INTO bsRec
FROM rc_backup_set
WHERE db_key = this_db_key
AND findBackupSet.bsKey = bs_key;
ELSE
SELECT recid,
stamp,
bs_key,
set_stamp,
set_count,
backup_type,
incremental_level,
elapsed_seconds,
completion_time,
status,
pieces,
decode (keep_options, 'LOGS' , KEEP_LOGS
, 'NOLOGS' , KEEP_NOLOGS
, 'CONSISTENT' , KEEP_CONSIST
, KEEP_NO),
keep_until
INTO bsRec
FROM rc_backup_set
WHERE db_key = this_db_key
AND findBackupSet.recid = recid
AND findBackupSet.stamp = stamp;
END IF;
deb(DEB_EXIT);
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with error 20215');
raise_application_error(-20215, 'Backup set is missing');
END findBackupSet;
---------------------------
-- Backup Set Validation --
---------------------------
---------------------------- computeAvailableMask -----------------------------
FUNCTION computeAvailableMask(
available IN number
,unavailable IN number
,deleted IN number
,expired IN number
,partial_avail IN number DEFAULT 0)
RETURN binary_integer IS
rc binary_integer := 0;
BEGIN
deb(DEB_ENTER, 'computeAvailableMask');
IF (available > 0) THEN
rc := rc + dbms_rcvman.BSavailable;
END IF;
IF (unavailable > 0 ) THEN
rc := rc + dbms_rcvman.BSunavailable;
END IF;
IF (deleted > 0 ) THEN
rc := rc + dbms_rcvman.BSdeleted;
END IF;
IF (expired > 0 ) THEN
rc := rc + dbms_rcvman.BSexpired;
END IF;
IF (partial_avail > 0 ) THEN
rc := rc + dbms_rcvman.BSpartial_avail;
END IF;
deb(DEB_EXIT, 'with rc:'||to_char(rc));
RETURN rc;
END computeAvailableMask;
-- Validate a backup set has all pieces available according the the specified
-- arguments. Returns only 1 validBackupSetRec. There may be other sets of
-- pieces that match the criteria.
------------------------------ findValidBackupSet -----------------------------
PROCEDURE findValidBackupSet(
bsKey IN number
,pieceCount IN number
,deviceType IN varchar2 DEFAULT NULL
,tag IN varchar2 DEFAULT NULL
,availableMask IN binary_integer)
IS
BEGIN
deb(DEB_ENTER, 'findValidBackupSet');
IF (pieceCount = 1) THEN
IF (findValidBackupSet1P_c%ISOPEN) THEN
CLOSE findValidBackupSet1P_c;
END IF;
-- NOTE!! NOTE!! NOTE!!
-- We are aware the findValidBackupSet_c cursor doesn't scale
-- when there are more backup pieces. So, let's for now optimize
-- most case which is 1 piece in a backupset
deb(DEB_OPEN, 'findValidBackupSet1P_c');
OPEN findValidBackupSet1P_c(bsKey => bsKey,
pieceCount => pieceCount,
deviceType => deviceType,
tag => tag,
mask => availableMask);
getValidBackupSetCursor := 'findValidBackupSet1P_c';
ELSE -- more than one piece exists in this set
IF (findValidBackupSet_c%ISOPEN) THEN
CLOSE findValidBackupSet_c;
END IF;
deb(DEB_OPEN, 'findValidBackupSet_c');
OPEN findValidBackupSet_c(bsKey => bsKey,
pieceCount => pieceCount,
deviceType => deviceType,
tag => tag,
mask => availableMask);
getValidBackupSetCursor := 'findValidBackupSet_c';
END IF;
deb(DEB_IN, 'bsKey=' || to_char(bsKey) || ' pieceCount=' ||
to_char(pieceCount) ||' tag=' || nvl(tag, 'NULL'));
deb(DEB_IN, ' deviceType=' || nvl(deviceType, 'NULL') ||
' mask=' || to_char(availableMask));
getValidBackupSetLast.code := 99; -- init for getValidBackupSet
deb(DEB_EXIT);
END findValidBackupSet;
------------------------------ validateBackupSet0 -----------------------------
FUNCTION validateBackupSet0(
tag IN varchar2 DEFAULT NULL
,tagMatchRequired IN boolean DEFAULT TRUE
,checkDeviceIsAllocated IN boolean DEFAULT TRUE
,validRec OUT validBackupSetRec_t)
RETURN binary_integer IS
local validBackupSetRec_t;
rc binary_integer;
gotRecord number;
BEGIN
deb(DEB_ENTER, 'validateBackupSet0');
<<validationLoop>>
LOOP
<<nextRow>>
gotRecord := getValidBackupSet(validBackupSetRec => local,
checkDeviceIsAllocated => FALSE#);
EXIT WHEN gotRecord = FALSE#; -- cursor is closed already
IF (checkDeviceIsAllocated) THEN
IF (isDeviceTypeAllocated(local.deviceType) = FALSE#) THEN
deb(DEB_IN, 'device is not allocated');
-- The required deviceType is not allocated. Remember that
-- we found an available backup set though.
IF (rc IS NULL OR rc <> SUCCESS) THEN
deb(DEB_IN, 'set rc to available');
rc := dbms_rcvman.AVAILABLE;
END IF;
GOTO nextRow;
END IF;
END IF;
validRec := local; -- set OUT mode arg
IF (tag IS NOT NULL AND NOT tagMatchRequired) THEN
-- We are looking for backup sets with a particular tag, but
-- we want to know about a backup set even if its tag does not match.
-- In this case, the findValidBackupSet_c cursor did not do the
-- tag checking for us, so we need to do it here.
IF (tag = local.tag) THEN
-- We've found a match for the tag, so we are done. This
-- backupset meets all of the validation criteria. There may be
-- another set of pieces with a different copy# or a different
-- deviceType that also meet the criteria. If the caller wants to
-- find them, he will have to use the find/getValidBackupSet
-- procedures to get the entire list, or call this routine
-- again.
deb(DEB_IN, 'tag matches');
rc := SUCCESS;
deb(DEB_IN, 'exiting loop with rc: SUCCESS');
EXIT validationLoop;
ELSE
-- Even though the tag does not match, we want to remember
-- about this set of pieces. Keep looking for a match for our
-- tag though.
deb(DEB_IN, 'tag does not match, continuing search');
rc := SUCCESS;
END IF;
ELSE
-- Here, we know that the backupset is valid. There may be multiple
-- valid copies available, but we don't care. The fact that one copy
-- is available is good enough for us.
rc := SUCCESS;
deb(DEB_IN, 'exiting loop with rc: SUCCESS');
EXIT validationLoop;
END IF;
END LOOP;
IF (rc IS NULL) THEN
deb(DEB_IN, 'rc is null, setting to unavailable');
rc := dbms_rcvman.UNAVAILABLE;
END IF;
deb(DEB_EXIT, 'with rc:'||to_char(rc));
RETURN rc;
END validateBackupSet0;
------------------------------ validateBackupSet ------------------------------
FUNCTION validateBackupSet(
backupSetRec IN rcvRec_t
,tag IN varchar2 DEFAULT NULL
,tagMatchRequired IN boolean DEFAULT TRUE
,checkDeviceIsAllocated IN boolean DEFAULT TRUE
,availableMask IN binary_integer
,validRec OUT validBackupSetRec_t)
RETURN binary_integer IS
findTag bp.tag%TYPE;
BEGIN
deb(DEB_ENTER, 'validateBackupSet');
IF (tagMatchRequired) THEN
findTag := tag;
ELSE
-- Caller wants to know about backup sets even if they don't match
-- the tag he is looking for, so don't do any tag filtering in the
-- cursor.
findTag := NULL;
END IF;
deb(DEB_IN, 'calling findValidBackupSet with:');
deb(DEB_IN, ' tag=' || nvl(tag, 'NULL') ||
' findTag=' || nvl(findTag, 'NULL') ||
' tagMatchRequired=' || bool2char(tagMatchRequired) ||
' checkDevice=' || bool2char(checkDeviceIsAllocated) ||
' availableMask=' || to_char(availableMask));
-- Open cursor
findValidBackupSet(bsKey => backupSetRec.bsKey_con,
pieceCount => backupSetRec.pieceCount_con,
tag => findTag,
availableMask => availableMask);
deb(DEB_EXIT, 'with result from validateBackupSet0');
RETURN validateBackupSet0(
tag => tag,
tagMatchRequired => tagMatchRequired,
checkDeviceIsAllocated => checkDeviceIsAllocated,
validRec => validRec);
END validateBackupSet;
------------------------------
-- Backup Piece Translation --
------------------------------
------------------------------- findBackupPiece -------------------------------
PROCEDURE findBackupPiece(
bpKey IN number DEFAULT NULL
,bsKey IN number DEFAULT NULL
,tag IN varchar2 DEFAULT NULL
,handle IN varchar2 DEFAULT NULL
,deviceType IN varchar2 DEFAULT NULL
,copyNumber IN number DEFAULT NULL
,statusMask IN binary_integer DEFAULT BSavailable)
IS
BEGIN
deb(DEB_ENTER, 'findBackupPiece');
deb(DEB_IN, 'bpKey:'||nvl(bpKey, -1)||
' and bsKey:'||nvl(bsKey, -1));
validateState(getBackupPieceCursor);
IF (bpKey IS NOT NULL) THEN
deb(DEB_OPEN, 'findBackupPieceBpKey');
OPEN findBackupPieceBpKey(bpKey => bpKey,
tag => tag,
handle => handle,
deviceType => deviceType,
copyNumber => copyNumber,
statusMask => statusMask);
getBackupPieceCursor := 'findBackupPieceBpKey';
ELSIF (bsKey IS NOT NULL) THEN
deb(DEB_OPEN, 'findBackupPieceBsKey');
OPEN findBackupPieceBsKey(bsKey => bsKey,
tag => tag,
handle => handle,
deviceType => deviceType,
copyNumber => copyNumber,
statusMask => statusMask);
getBackupPieceCursor := 'findBackupPieceBsKey';
ELSE
deb(DEB_OPEN, 'findBackupPiece_c');
OPEN findBackupPiece_c( tag => tag,
handle => handle,
deviceType => deviceType,
copyNumber => copyNumber,
statusMask => statusMask);
getBackupPieceCursor := 'findBackupPiece_c';
END IF;
-- Initialize all of the getBackupPiece variables to their default
-- state.
getBackupPieceNoRows.error := NULL;
getBackupPieceDuplicates := TRUE#;
getBackupPieceLast.pieceNumber := NULL;
getBackupPieceDeviceType := deviceType;
getBackupPieceExpectedPieces := NULL;
getBackupPiecePieceCount := 0;
getBackupPieceByHandle := FALSE;
getBackupPieceAvailableMask := NULL;
deb(DEB_EXIT);
END findBackupPiece;
------------------------------------------
-- Compute Recovery Actions Subroutines --
------------------------------------------
--------------------------------- rcvRecPush ----------------------------------
PROCEDURE rcvRecPush(
rcvRec IN rcvRec_t)
IS
BEGIN
rcvRecStack.extend;
rcvRecStack(rcvRecStack.last) := rcvRec;
END rcvRecPush;
---------------------------------- rcvRecGet ----------------------------------
PROCEDURE rcvRecGet(
indx IN number
,rcvRec OUT rcvRec_t)
IS
BEGIN
rcvRec := rcvRecStack(indx);
END rcvRecGet;
---------------------------------- rcvRecTop ----------------------------------
PROCEDURE rcvRecTop(
rcvRec OUT rcvRec_t)
IS
BEGIN
IF (rcvRecStack.count = 0) THEN
rcvRec := NULL;
ELSE
rcvRecGet(rcvRecStack.count, rcvRec);
END IF;
END rcvRecTop;
---------------------------------- rcvRecPop ----------------------------------
PROCEDURE rcvRecPop(
rcvRec OUT rcvRec_t)
IS
BEGIN
rcvRecTop(rcvRec);
rcvRecStack.trim;
END rcvRecPop;
-------------------------------- rcvRecConvert --------------------------------
PROCEDURE rcvRecConvert(
rcvRec IN OUT rcvRec_t)
IS
BEGIN
-- Get rid of any nulls that would be unacceptable to the pre-8.1.6
-- RMAN. The pre-8.1.6 RMAN did not use null-indicators consistantly.
rcvRec.recid_con := nvl(rcvRec.recid_con, 0);
rcvRec.stamp_con := nvl(rcvRec.stamp_con, 0);
rcvRec.setStamp_con := nvl(rcvRec.setStamp_con, 0);
rcvRec.setCount_con := nvl(rcvRec.setCount_con, 0);
rcvRec.fileName_con := nvl(rcvRec.fileName_con, 'NULL');
rcvRec.blockSize_con := nvl(rcvRec.blockSize_con, 0);
rcvRec.blocks_con := nvl(rcvRec.blocks_con, 0);
rcvRec.deviceType_con := nvl(rcvRec.deviceType_con, 'NULL');
END rcvRecConvert;
--------------------------------- printRcvRec ---------------------------------
PROCEDURE printRcvRec(
action IN rcvRec_t)
IS
l varchar2(600);
cfcretime varchar2(100);
action_deleted boolean;
BEGIN
------------------------
-- Recovery Container --
------------------------
deb(DEB_PRINT, 'DUMPING RECOVERY CONTAINER');
-- Print the containter type
IF (action.type_con = backupSet_con_t) THEN
IF (action.type_act = full_act_t) THEN
deb(DEB_PRINT, ' Full Backup Set');
ELSE
deb(DEB_PRINT, ' Incremental Backup Set');
END IF;
ELSIF (action.type_con = proxyCopy_con_t) THEN
deb(DEB_PRINT, ' Proxy Backup');
ELSIF (action.type_con = imageCopy_con_t) THEN
deb(DEB_PRINT, ' Datafile Copy');
ELSIF (action.type_con = offlineRangeRec_con_t) THEN
IF (action.type_act = offlineRange_act_t) THEN
deb(DEB_PRINT, ' Offline Range Record');
ELSIF (action.type_act = cleanRange_act_t) THEN
deb(DEB_PRINT, ' Clean Range');
ELSIF (action.type_act = implicitRange_act_t) THEN
deb(DEB_PRINT, ' Implicit Offline Range');
ELSIF (action.type_act = spanningRange_act_t) THEN
deb(DEB_PRINT, ' Spanning Offline Range');
ELSE
deb(DEB_PRINT, ' Unknown Offline Range Action Type');
END IF;
ELSE
deb(DEB_PRINT, ' Uknown recovery container type');
END IF;
-- Print the type-specific containter data
IF (action.type_con = backupSet_con_t) THEN
deb(DEB_PRINT, ' bsKey=' || to_char(action.bsKey_con) ||
' bsRecid=' || to_char(action.bsRecid_con) ||
' bsStamp=' || to_char(action.bsStamp_con) ||
' setStamp=' || to_char(action.setStamp_con) ||
' setCount=' || to_char(action.setCount_con));
deb(DEB_PRINT, ' bsLevel=' || to_char(action.bsLevel_con) ||
' bsType=' || action.bsType_con ||
' pieceCount=' || to_char(action.pieceCount_con));
ELSIF (action.type_con = proxyCopy_con_t OR
action.type_con = imageCopy_con_t) THEN
deb(DEB_PRINT, ' fileName=' || action.fileName_con);
END IF;
-- Print the remaining container data
l := ' ';
-- key_con
IF (action.key_con is not null) THEN
l := l || ' key=' || to_char(action.key_con);
END IF;
-- recid_con, stamp_con
IF (action.recid_con is not null) THEN
l := l || ' recid=' || to_char(action.recid_con) ||
' stamp=' || to_char(action.stamp_con);
END IF;
-- status_con
IF (action.status_con is not null) THEN
l := l || ' status=' || action.status_con;
END IF;
IF (length(l) > 2) THEN
deb(DEB_PRINT, l);
END IF;
l := ' ';
-- tag
IF (action.tag_con is not null) THEN
l := l || ' tag=' || action.tag_con;
END IF;
-- compTime
IF (action.compTime_con is not null) THEN
l := l || ' compTime=' || to_char(action.compTime_con);
END IF;
IF (length(l) > 2) THEN
deb(DEB_PRINT, l);
END IF;
l := ' ';
IF (action.deviceType_con is not null) THEN
l := l || ' deviceType=' || action.deviceType_con;
END IF;
IF (action.blocks_con is not null) THEN
l := l || ' blocks=' || to_char(action.blocks_con) ||
' blockSize=' || to_char(action.blockSize_con);
END IF;
IF (action.cfCreationTime_con is not null) THEN
l := l || ' cfCreationTime=' || to_char(action.cfCreationTime_con);
END IF;
IF (action.pieceNumber_con is not null) THEN
l := l || ' pieceNumber=' || to_char(action.pieceNumber_con);
END IF;
IF (action.bpCompTime_con is not null) THEN
l := l || ' bpCompTime=' || to_char(action.bpCompTime_con);
END IF;
IF (length(l) > 2) THEN
deb(DEB_PRINT, l);
END IF;
l := ' ';
---------------------
-- Recovery Action --
---------------------
-- fromSCN
IF (action.fromSCN_act is not null) THEN
l := l || ' fromSCN=' || to_char(action.fromSCN_act);
END IF;
-- toSCN toTime
IF (action.toSCN_act is not null) THEN
l := l || ' toSCN=' || to_char(action.toSCN_act) ||
' toTime=' || to_char(action.toTime_act);
END IF;
-- level
IF (action.level_act is not null) THEN
l := l || ' level=' || to_char(action.level_act);
END IF;
IF (length(l) > 2) THEN
deb(DEB_PRINT, l);
END IF;
l := ' ';
IF (action.rlgSCN_act is not null) THEN
l := l || ' rlgSCN=' || to_char(action.rlgSCN_act) ||
' rlgTime=' || to_char(action.rlgTime_act) ||
' dbincKey=' || to_char(action.dbincKey_act);
END IF;
IF (length(l) > 2) THEN
deb(DEB_PRINT, l);
END IF;
l := ' ';
IF (action.afzSCN_act is not null) THEN
l := l || ' afzSCN=' || to_char(action.afzSCN_act);
END IF;
IF (length(l) > 2) THEN
deb(DEB_PRINT, l);
END IF;
l := ' ';
IF (action.rfzSCN_act is not null) THEN
l := l || ' rfzSCN=' || to_char(action.rfzSCN_act) ||
' rfzTime=' || to_char(action.rfzTime_act);
END IF;
IF (length(l) > 2) THEN
deb(l);
END IF;
l := ' ';
---------------------
-- Recovery Object --
---------------------
IF (action.dfNumber_obj IS NOT NULL) THEN
l := l || ' dfNumber=' || to_char(action.dfNumber_obj) ||
' creationSCN=' || to_char(action.dfCreationSCN_obj);
deb(DEB_PRINT, l);
l := ' ';
l := l || ' keep_options=' || nvl(to_char(action.keep_options), 'NULL') ||
' keep_until=' || nvl(to_char(action.keep_until), 'NULL');
deb(DEB_PRINT, l);
IF (action.cfSequence_obj IS NOT NULL) THEN
l := ' ';
l := l || ' cfSequence=' || to_char(action.cfSequence_obj) ||
' cfDate=' || to_char(action.cfDate_obj);
deb(DEB_PRINT, l);
END IF;
ELSIF (action.logSequence_obj IS NOT NULL) THEN
l := l || ' logSequence=' || to_char(action.logSequence_obj);
deb(DEB_PRINT, l);
l := ' ';
l := l || ' logThread=' || to_char(action.logThread_obj);
deb(DEB_PRINT, l);
l := ' ';
l := l || ' logLowSCN=' || to_char(action.logLowSCN_obj);
deb(DEB_PRINT, l);
l := ' ';
l := l || ' logLowTime=' || to_char(action.logLowTime_obj);
deb(DEB_PRINT, l);
l := ' ';
l := l || ' logNextSCN=' || nvl(to_char(action.logNextSCN_obj), 'NULL');
deb(DEB_PRINT, l);
l := ' ';
l := l || ' logNextTime=' || to_char(action.logNextTime_obj);
deb(DEB_PRINT, l);
l := ' ';
l := l || ' logRlgSCN=' || to_char(action.logRlgSCN_obj);
deb(DEB_PRINT, l);
l := ' ';
l := l || ' logRlgTime=' || to_char(action.logRlgTime_obj);
deb(DEB_PRINT, l);
ELSIF (action.toTime_act IS NOT NULL) THEN
deb(DEB_PRINT, ' SPFILE');
deb(DEB_PRINT, ' modification_time=' || to_char(action.toTime_act));
l := ' ';
l := l || ' keep_options=' || nvl(to_char(action.keep_options), 'NULL') ||
' keep_until=' || nvl(to_char(action.keep_until), 'NULL');
deb(DEB_PRINT, l);
ELSE
deb(DEB_PRINT, ' Unknown Recovery Object');
END IF;
EXCEPTION
WHEN OTHERS THEN
deb(DEB_PRINT, 'printRcvRec: caught an exception, aborting print');
RETURN;
END printRcvRec;
-- See if redo is needed to fill a gap between this action and the one
-- that follows it, which is already on the rcvRecStack and is pointed to
-- by rcvRecStackState.lowAction
---------------------------------- redoNeeded ---------------------------------
FUNCTION redoNeeded(
action IN rcvRec_t)
RETURN boolean IS
BEGIN
deb(DEB_ENTER, 'redoNeeded');
deb(DEB_PRINT, 'ENTERING redoNeeded');
IF (rcvRecStackState.lowAction > 0 AND -- Have a non-full_act_t on stack?
action.toSCN_act <
rcvRecStack(rcvRecStackState.lowAction).fromSCN_act) THEN
deb(DEB_EXIT, 'with: TRUE');
RETURN TRUE;
ELSE
deb(DEB_EXIT, 'with: FALSE');
RETURN FALSE;
END IF;
END redoNeeded;
---------------------------------- canAddRedo ---------------------------------
FUNCTION canAddRedo(
isAncestor IN boolean
,from_scn IN number
,from_rlgscn IN number
,to_action IN rcvRec_t
,partial_rcv IN boolean
,doingRecovery IN boolean)
RETURN number IS
BEGIN
deb(DEB_ENTER, 'canAddRedo');
IF (from_rlgscn = this_reset_scn) THEN
IF (partial_rcv) THEN
deb(DEB_EXIT, 'with: action_OK');
RETURN action_OK;
ELSE
-- A partial media recovery can only be done if we have a
-- current controlfile. A partial recovery does not
-- recover the controlfile. This could be implemented,
-- but it requires using an enqueue to ensure only
-- 1 process tries to recover the confile.
-- Since we aren't recovering the controlfile,
-- the file header won't be handled properly when
-- we hit controlfile redo. That is why we are
-- requiring a current controlfile. Since we don't have
-- one, we will have to do database recovery on this datafile.
-- It is possible that we have a current controlfile here,
-- but RMAN currently does not support partial media recovery.
deb(DEB_EXIT, 'with: action_FAIL');
RETURN action_FAIL;
END IF;
ELSE
deb(DEB_IN, 'from_rlgscn=' || nvl(to_char(from_rlgscn), 'NULL') ||
' this_reset_scn=' || to_char(this_reset_scn));
IF (isAncestor) THEN
deb(DEB_IN, 'isAncestor is TRUE;');
-- RMAN cannot yet apply redo from the non-current incarnation.
-- Someday this will be implemented. The idea is that RMAN will have
-- the DB mount a backup controlfile from the incarnation containing
-- the logs we need to apply, and then recovery should just work
-- normally since the logs, controlfile, and datafile(s) will all be
-- from the same incarnation. We will be able to apply redo from a
-- non-current incarnation only if isAncestor is TRUE. We don't want
-- to apply redo from an incarnation that we do not know with
-- certainty is one of our ancestors. Otherwise, we could be
-- applying redo to reach the start of an offline range spanning
-- resetlogs, which could certainly be the wrong thing to do. An
-- offline range should contain the reset SCN and timestamp of the
-- incarnation in which the offline range started, but unfortunately
-- it does not.
-- Now, we just document the above procedure. So, the report/delete
-- obsolete algorithm should not ignore previous incarnations.
-- NOTE: REPORT/DELETE OBSOLETE sets allIncarnations to TRUE
-- while LIST RECOVERABLE command does not.
IF (doingRecovery) THEN
deb(DEB_EXIT, 'with: action_OLD_REDO (doingRecovery)');
RETURN action_OLD_REDO;
ELSE
IF (allIncarnations = TRUE# AND NOT doingRecovery) THEN
deb(DEB_EXIT, 'with: action_OK (not doingRecovery)');
RETURN action_OK;
ELSE
deb(DEB_EXIT, 'with: action_OLD_REDO (allIncarnations is FALSE)');
RETURN action_OLD_REDO;
END IF;
END IF;
ELSE
deb(DEB_IN, 'isAncestor is FALSE;');
-- We should never attempt to apply redo from an incartion that
-- we don't know with certainty is one of our ancestors.
deb(DEB_EXIT, 'with: action_OLD_REDO');
RETURN action_OLD_REDO;
END IF;
END IF;
deb(DEB_EXIT, 'with undefined status');
END canAddRedo;
----------------------------------- addRedo -----------------------------------
FUNCTION addRedo(
isAncestor IN boolean
,from_scn IN number
,from_rlgscn IN number
,to_action IN rcvRec_t
,partial_rcv IN boolean
,doingRecovery IN boolean)
RETURN number IS
canAdd number;
redoRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'addRedo');
canAdd := canAddRedo(isAncestor, from_scn, from_rlgscn,
to_action, partial_rcv, doingRecovery);
IF (canAdd = action_FAIL) THEN
-- Trim to the last save point. If we are doing RESTORE or RECOVER,
-- then this will discard all actions we have stacked so far.
-- If we are doing LIST, this will discard all actions up to
-- the last full/level 0/copy/proxy-copy that we found. We never
-- need to trim actions that come after the save point since we
-- know they can be applied.
deb(DEB_IN, 'trimming to save_point');
-- Since we have a gap in the redo stream here, reset lowAction
-- to 0. No actions that may be coming after this one will cover
-- this gap since their to_scn's must be <= this action's.
-- It is possible that the lowAction is about to be trimmed, but
-- even if it remains on the stack, we have a broken chain and
-- need to start a new one.
rcvRecStackState.lowAction := 0;
rcvRecStack.trim(rcvRecStack.last -
greatest(rcvRecStackState.savePoint,
rcvRecStackState.top));
deb(DEB_EXIT, 'with: action_FAIL');
RETURN action_FAIL;
ELSIF (canAdd = action_OK) THEN
redoRec.type_act := redo_act_t;
redoRec.fromSCN_act := from_scn;
redoRec.toSCN_act := to_action.fromSCN_act;
redoRec.toTime_act := to_date(null);
redoRec.rlgSCN_act := from_rlgscn;
rcvRecPush(redoRec);
-- ### Some other fields should be filled in, but this code path never
-- taken currently, so doesn't matter yet.
deb(DEB_IN, 'from_scn=' || to_char(from_scn) ||
' to_scn=' || to_char(to_action.fromSCN_act));
deb(DEB_EXIT, 'with: action_OK');
RETURN action_OK;
ELSE -- ancestral incarnation
-- Application of redo from an ancestral incarnation is not supported.
-- However, we cannot trim these actions as we did in the case above
-- because they are required to reach the offline-range that spans
-- the resetlogs. So we simply return an error.
deb(DEB_EXIT, 'with: action_OLD_REDO');
RETURN action_OLD_REDO;
END IF;
deb(DEB_EXIT, 'with undefined status');
END addRedo;
---------------------------------- addAction ----------------------------------
FUNCTION addAction( -- add to the rcvRecStack
actionIN IN rcvRec_t -- if a backup set, we fill
-- in the tag and deviceType
,partial_rcv IN boolean
,isAncestor IN boolean
,cf_scn IN number DEFAULT NULL
,cf_cretime IN date DEFAULT NULL
,cf_offrrid IN number DEFAULT NULL
,allCopies IN boolean DEFAULT FALSE
,doingRecovery IN boolean DEFAULT TRUE)
RETURN number IS
action rcvRec_t;
validate_rc number;
cf_count number;
addRedo_rc number;
tagMatchRequired boolean;
validationRec validBackupSetRec_t;
lowAction rcvRec_t;
BEGIN
deb(DEB_ENTER, 'addAction');
deb(DEB_IN, ' action.type_con='|| to_char(action.type_con));
action := actionIN; -- copy to local variable
-- See if we have a gap that must be filled by redo. We must make this
-- check first because we want to return OLD_REDO if that condition
-- applies. We process actions in descending to_scn order, so it is OK to
-- add a redo action to the stack even if we cannot apply this action
-- because it fails validation or we don't have the right device type
-- allocated. The next action we see would require at least this much
-- redo. Note that this means we may have 2 adjacent redo actions on the
-- stack. getRecoveryAction will merge them.
IF (redoNeeded(action)) THEN
-- We need to do a partial media recovery from this to_scn to
-- get all the way to the lowActions's from_scn.
-- N.B:
-- A clean range always belongs to the current incarnation since it
-- comes from the controlfile and the controlfile defines the current
-- incarnation. Therefore, if this action is a clean range then we
-- must be searching the current incarnation. It is not possible for
-- the recoveryActionCursor to return a clean range when searching
-- recursively, even if we didn't know our parent incarnation. If
-- the clean range does not span the resetlogs SCN, then its from_scn
-- will be greater than the target_scn for any recursive search, and
-- the cursor will filter out the clean range. If the clean range
-- does span the resetlogs SCN, then the clean range's from_scn
-- becomes the target SCN for the recursive searches, and the cursor
-- will also filter it out. Therefore, we know that the lowAction
-- must be from the current incarnation. So we can simply add a redo
-- action to fill the gap between the clean range and the lowAction.
rcvRecGet(rcvRecStackState.lowAction, lowAction);
addRedo_rc := addRedo(isAncestor,
action.toSCN_act, action.rlgSCN_act,
lowAction,
partial_rcv,
doingRecovery);
IF (addRedo_rc = action_OLD_REDO) THEN
-- We cannot apply this action because there is an offline range
-- in the future of this action that we must apply, and it would
-- require redo to reach the offline range.
deb(DEB_EXIT, 'with addRedo_rc: '||to_char(addRedo_rc));
RETURN addRedo_rc;
ELSE
-- The other possible return codes from addRedo are
-- OK and FAIL. In either case, we are allowed to add this
-- action to the stack. The FAIL case is when partial_rcv
-- is false, so addRedo we just discards the actions previously
-- stacked up to the save point, if any.
NULL;
END IF;
ELSE -- redo not needed
-- If the lowAction is an offline range, then this action must
-- have a to_scn <= the offline range start SCN.
-- We don't actually need to check this though. The cursor looks at
-- only those actions with a to_scn <= the target_scn.
NULL;
END IF;
-- If this is a backup set, validate that it is available and we have the
-- right device type allocated to restore/list it, and also check that it
-- is available on a set of pieces with the right tag if a restoreTag has
-- been specified.
IF (action.type_con = backupSet_con_t) THEN
IF (computeRA_allRecords = TRUE# OR restoreTag IS NULL) THEN
tagMatchRequired := FALSE;
ELSE
tagMatchRequired := TRUE;
END IF;
-- Validate this backup set. This checks to see that a complete set of
-- pieces are available on the same device type. We also discover
-- if the pieces are all available with the same tag, and if so, from
-- the same copy#. These values are then stuffed into the rcvRec.
-- It is possible that a complete set of pieces is available on multiple
-- device types if the backupset has been copied. In this case, the
-- other device types are ignored. The ordering is simply the collating
-- sequence order for the deviceType (alphabetic). Since "DISK"
-- comes before "SBT_TAPE", this has the effect of prefering backupsets
-- on disk over those on tape, which is desired. It would be a better
-- implementation to have a preference column in the bp table, but
-- that is not really needed until we have something other than
-- SBT_TAPE and DISK.
--
-- If we are really performing a restore, then the underlying query
-- (findValidBackupSet) will be run twice, once from here and then again
-- later when RMAN obtains the backup pieces for this set. This is
-- unfortunate, but unavoidable. This is the reason why the copy#
-- tag and deviceType are stuffed into the rcvRec, so that the later
-- call to get the pieces can use those values in the query, which may
-- improve its performance. Also note that if this backupset is used
-- to restore multiple datafiles, then we validate it once for each
-- datafile. It may be a good idea to keep a list of backup set keys
-- that have been validated to improve performance when many datafiles
-- are being restored.
--
-- For RMAN commands such as LIST, the tag, deviceType, and copy#s will
-- be ignored. As of 8.1.6, those commands use the findValidBackupSet
-- procedure directly to obtain complete information about the
-- availablity of the backup set.
validate_rc :=
validateBackupSet(backupSetRec => action,
tag => restoreTag,
tagMatchRequired => tagMatchRequired,
checkDeviceIsAllocated => TRUE,
availableMask => computeRA_availableMask,
validRec => validationRec);
IF (validate_rc = dbms_rcvman.UNAVAILABLE) THEN
deb(DEB_EXIT, '(backup set is unavailable) with: action_FAIL');
RETURN action_FAIL;
ELSIF (validate_rc = dbms_rcvman.AVAILABLE) THEN
-- We cannot restore/list this backup set because we don't have the
-- right device type allocated. We want to remember this fact
-- so that we can give the user a meaningful error message.
computeRA_available := TRUE;
deb(DEB_EXIT, '(dont have required device type) with: action_FAIL');
RETURN action_FAIL;
ELSIF (validate_rc = SUCCESS) THEN
-- IF computeRA_allRecords is true and restoreTag is not
-- null, then we set tagMatchRequired to false, so it is possible
-- that this backupset did not validate with the right tag. Check
-- that the tag in the validationRec matches the restoreTag. If not,
-- then leave the tag_con field in the action record null. This will
-- cause this action to be skipped when getRecoveryAction is called.
IF (validationRec.tag = restoreTag OR
restoreTag IS NULL) THEN
action.tag_con := validationRec.tag;
END IF;
action.deviceType_con := validationRec.deviceType;
action.copyNumber_con := validationRec.copyNumber;
END IF;
ELSIF (action.type_con = proxyCopy_con_t) THEN
-- Check that we have the right deviceType allocated.
IF (isDeviceTypeAllocated(action.deviceType_con) = FALSE#) THEN
-- We cannot restore/list this backup set because we don't have the
-- right device type allocated. We want to remember this fact
-- so that we can give the user a meaningful error message.
computeRA_available := TRUE;
deb(DEB_EXIT, '(dont have required device type for proxy)'||
' with: action_FAIL');
RETURN action_FAIL;
END IF;
ELSIF (action.type_con = imageCopy_con_t) THEN
-- Check that we have a disk device allocated.
IF (not diskDevice) THEN
-- We don't have a disk device allocated, so we cannot
-- use a datafile copy.
computeRA_available := TRUE;
deb(DEB_EXIT, '(dont have required device type for proxy)'||
' with: action_FAIL');
RETURN action_FAIL;
END IF;
ELSIF (action.type_con = offlineRangeRec_con_t AND
action.type_act = offlineRange_act_t) THEN
-- First see if this offline range is in the current controlfile.
-- If so, we are cool. If not, then check that there exists at least
-- one controlfile copy that contains this offline range.
-- Note that if a controlfile contains no kccor records, then
-- the oldest recid will be zero. Both krmk.pc and krbc.c obey
-- this convention.
IF (cf_cretime = action.cfCreationTime_con AND
action.recid_con >= cf_offrrid AND
cf_offrrid > 0 and -- contains at least 1 record
cf_scn >= action.toSCN_act) THEN
NULL; -- range is in current cf, we're cool
ELSE
SELECT count(*)
INTO cf_count
FROM ccf
WHERE ccf.create_time = action.cfCreationTime_con AND
ccf.min_offr_recid <= action.recid_con AND
ccf.ckp_scn >= action.toSCN_act AND
ccf.min_offr_recid > 0; -- contains at least 1 record
IF (cf_count = 0) THEN
deb(DEB_EXIT, '(no controlfile copy with offline range)'||
' with: action_FAIL');
RETURN action_FAIL;
END IF;
END IF;
END IF;
<<addAnother>>
rcvRecPush(action); -- add record for this action
deb(DEB_IN, ' Added action:');
printRcvRec(action);
IF (allCopies AND action.type_con = backupSet_con_t) THEN
-- Keep calling validateBackupSet0 until it fails to return SUCCESS.
validate_rc :=
validateBackupSet0(tag => restoreTag,
tagMatchRequired => tagMatchRequired,
checkDeviceIsAllocated => TRUE,
validRec => validationRec);
IF (validate_rc <> SUCCESS) THEN
GOTO done;
END IF;
IF (validationRec.tag = restoreTag OR
restoreTag IS NULL) THEN
action.tag_con := validationRec.tag;
END IF;
action.deviceType_con := validationRec.deviceType;
action.copyNumber_con := validationRec.copyNumber;
GOTO addAnother;
END IF;
<<done>>
-- Update the lowAction pointer and the savePoint pointer if necessary.
IF (action.type_act = full_act_t) THEN
-- new full means new savePoint
deb(DEB_IN, ' action.type_act is range/full => setting savePoint='||
to_char(rcvRecStack.last));
rcvRecStackState.savePoint := rcvRecStack.last;
ELSIF (rcvRecStackState.lowAction = 0) THEN
-- no curent lowAction, then set
rcvRecStackState.lowAction := rcvRecStack.last;
ELSIF (action.fromSCN_act <
rcvRecStack(rcvRecStackState.lowAction).fromSCN_act) THEN
rcvRecStackState.lowAction := rcvRecStack.last; -- new lowAction
END IF;
deb(DEB_EXIT, 'with: action_OK');
RETURN action_OK;
END addAction;
----------------------------- fetchRecoveryAction -----------------------------
FUNCTION fetchRecoveryAction(
cv IN rcvRecCursor_t
,df_ckpscn IN number
,action IN OUT rcvRec_t)
RETURN boolean IS
top rcvRec_t;
BEGIN
deb(DEB_ENTER, 'fetchRecoveryAction');
<<retry>>
FETCH cv
INTO action;
IF (cv%NOTFOUND) THEN
action.type_con := NULL;
action.type_act := NULL;
deb(DEB_EXIT, 'with: FALSE');
RETURN FALSE;
END IF;
IF (action.compTime_con IS NULL AND -- was null in 8.0.2
action.type_con = backupSet_con_t) THEN
action.compTime_con := stamp2date(action.bsStamp_con);
END IF;
IF (computeRA_allRecords = TRUE#) THEN
deb(DEB_EXIT, 'with: TRUE');
RETURN TRUE;
END IF;
-- Discard this action if its fromSCN is not less than the most recently
-- stacked actions's fromSCN. Also check that the resetlogs SCNs are the
-- same. If they differ, then keep this action. This is necessary to
-- avoid discarding a spanning offline range here. The real offline range
-- and the spanning range(s) have the same fromSCN.
IF (rcvRecStack.count > 0) THEN
rcvRecTop(top);
IF (not (action.fromSCN_act < top.fromSCN_act) AND
action.rlgSCN_act = top.rlgSCN_act) THEN
deb(DEB_IN, 'discarding this action:');
printRcvRec(action);
GOTO retry;
END IF;
END IF;
deb(DEB_EXIT, 'with: TRUE');
RETURN TRUE;
END fetchRecoveryAction;
--------------------------- openRecoveryActionCursor --------------------------
PROCEDURE openRecoveryActionCursor(
rcvRecCursor IN OUT rcvRecCursor_t
,dbincKey IN number
,fno IN number
,creSCN IN number
,dfCkpSCN IN number
,dbincRlgSCN IN number
,dbincRlgTime IN date
,offlSCN IN number
,onlSCN IN number
,onlTime IN date
,cleanSCN IN number
,clean2SCN IN number
,clean2Time IN date
,targetSCN IN number)
IS
BEGIN
deb(DEB_ENTER, 'openRecoveryActionCursor');
deb(DEB_IN, 'target scn is ' || nvl(to_char(targetSCN), 'NULL'));
-- NOTES:
--
-- Procedure "setUntilTime" attempts to estimate the untilSCN by querying
-- all the scn/timestamp pairs in the recovery catalog whose timestamp is
-- strictly less than the until time. The result is an estimated untilSCN
-- that is very likely to be less than the actual incomplete recovery SCN
-- when the RECOVER UNTIL TIME is done. I.e. estimated untilSCN is
-- conservative. This calculation considers checkpoint SCN/timestamps for
-- backup datafiles and datafile copies, as well as their absolute fuzzy
-- SCNs/completion timestamps. We treat the completion timestamp as a
-- reasonable estimate of the absolute fuzzy time.
-- Note that the absolute fuzzy SCN can be equal to the until SCN because
-- it is higher than any SCN in the backup. We also allow the checkpoint
-- SCN and media recovery fuzzy SCN to be equal to the until SCN.
deb(DEB_OPEN, 'rcvRecCursor');
OPEN rcvRecCursor FOR -- open the cursor
-- Offline Ranges
SELECT offlineRangeRec_con_t type_con,
offr_key key_con,
offr_recid recid_con,
offr_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
to_number(null) blocks_con,
to_number(null) blockSize_con,
to_char(null) deviceType_con,
to_date(null) compTime_con,
cf_create_time cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
offlineRange_act_t type_act,
offline_scn fromSCN_act,
online_scn toSCN_act,
online_time toTime_act,
openRecoveryActionCursor.dbincRlgSCN rlgSCN_act,
openRecoveryActionCursor.dbincRlgTime rlgTime_act,
dbinc_key dbincKey_act,
to_number(null) level_act,
openRecoveryActionCursor.fno dfNumber_obj,
openRecoveryActionCursor.creSCN dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
to_number(null) keep_options,
to_date(null) keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM offr
WHERE dbinc_key = openRecoveryActionCursor.dbincKey
AND file# = openRecoveryActionCursor.fno
AND create_scn = openRecoveryActionCursor.creSCN
AND (openRecoveryActionCursor.dfCkpSCN is null OR
openRecoveryActionCursor.dfCkpSCN <= offline_scn)
AND (openRecoveryActionCursor.targetSCN is null OR
online_scn <= openRecoveryActionCursor.targetSCN)
AND (untilSCN is null OR online_scn < untilSCN)
-- If online_scn = untilSCN, don't
-- apply the offline range. The
-- dictionary txn that commits the
-- online occurred at a higher scn,
-- and recovery will probably stop
-- before getting to commit redo.
AND cf_create_time is not null -- offr recs added before 8.0.3 useless
AND offr_stamp <> 0 -- stamp = 0 -> from kccfe
UNION ALL
-- Datafile Copies
SELECT imageCopy_con_t type_con,
cdf_key key_con,
cdf_recid recid_con,
cdf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
fname fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
blocks blocks_con,
block_size blockSize_con,
'DISK' deviceType_con,
completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
ckp_scn toSCN_act,
ckp_time toTime_act,
openRecoveryActionCursor.dbincRlgSCN rlgSCN_act,
openRecoveryActionCursor.dbincRlgTime rlgTime_act,
dbinc_key dbincKey_act,
to_number(null) level_act,
openRecoveryActionCursor.fno dfNumber_obj,
openRecoveryActionCursor.creSCN dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
keep_options keep_options,
keep_until keep_until,
abs_fuzzy_scn afzSCN_act,
rcv_fuzzy_time rfzTime_act,
rcv_fuzzy_scn rfzSCN_act
FROM cdf
WHERE dbinc_key = openRecoveryActionCursor.dbincKey
AND file# = openRecoveryActionCursor.fno
AND create_scn = openRecoveryActionCursor.crescn
AND (openRecoveryActionCursor.dfCkpSCN is null OR
openRecoveryActionCursor.dfCkpSCN < ckp_scn)
AND (openRecoveryActionCursor.targetSCN is null OR
ckp_scn <= openRecoveryActionCursor.targetSCN)
AND (untilSCN is null OR
greatest(ckp_scn, abs_fuzzy_scn, rcv_fuzzy_scn) <= untilSCN)
AND status = 'A'
AND (restoreTag is NULL OR
tag = restoreTag OR
computeRA_allRecords = TRUE#)
AND (restoreSource is NULL OR restoreSource = COPY)
UNION ALL
-- Controlfile Copies
SELECT imageCopy_con_t type_con,
ccf_key key_con,
ccf_recid recid_con,
ccf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
fname fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
to_number(null) blocks_con,
block_size blockSize_con,
'DISK' deviceType_con,
completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
ckp_scn toSCN_act,
ckp_time toTime_act,
openRecoveryActionCursor.dbincRlgSCN rlgSCN_act,
openRecoveryActionCursor.dbincRlgTime rlgTime_act,
dbinc_key dbincKey_act,
to_number(null) level_act,
openRecoveryActionCursor.fno dfNumber_obj,
openRecoveryActionCursor.creSCN dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
keep_options keep_options,
keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM ccf
WHERE dbinc_key = openRecoveryActionCursor.dbincKey
AND 0 = openRecoveryActionCursor.fno
AND 0 = openRecoveryActionCursor.crescn
AND (openRecoveryActionCursor.dfCkpSCN is null OR
openRecoveryActionCursor.dfCkpSCN < ckp_scn)
AND (openRecoveryActionCursor.targetSCN is null OR
ckp_scn <= openRecoveryActionCursor.targetSCN)
AND (untilSCN is null OR
ckp_scn <= untilSCN)
AND status = 'A'
AND (restoreTag is NULL OR
tag = restoreTag OR
computeRA_allRecords = TRUE#)
AND (restoreSource is NULL OR restoreSource = COPY)
UNION ALL
-- Backup Sets
SELECT backupSet_con_t type_con,
bdf.bdf_key key_con,
bdf.bdf_recid recid_con,
bdf.bdf_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
bs.incr_level bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
bdf.blocks blocks_con,
bdf.block_size blockSize_con,
to_char(null) deviceType_con,
bdf.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
decode(bdf.incr_scn,
0, full_act_t,
incremental_act_t) type_act,
bdf.incr_scn fromSCN_act,
bdf.ckp_scn toSCN_act,
bdf.ckp_time toTime_act,
openRecoveryActionCursor.dbincRlgSCN rlgSCN_act,
openRecoveryActionCursor.dbincRlgTime rlgTime_act,
dbinc.dbinc_key dbincKey_act,
bdf.incr_level level_act,
openRecoveryActionCursor.fno dfNumber_obj,
openRecoveryActionCursor.crescn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
bs.keep_options keep_options,
bs.keep_until keep_until,
bdf.abs_fuzzy_scn afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM bdf, bs, dbinc
WHERE bdf.dbinc_key = openRecoveryActionCursor.dbincKey
AND bdf.file# = openRecoveryActionCursor.fno
AND bdf.create_scn = openRecoveryActionCursor.crescn
AND (openRecoveryActionCursor.dfCkpSCN IS NULL OR
openRecoveryActionCursor.dfCkpSCN < bdf.ckp_scn)
AND (openRecoveryActionCursor.targetSCN IS NULL OR
bdf.ckp_scn <= openRecoveryActionCursor.targetscn)
AND (untilSCN IS NULL OR
greatest(bdf.ckp_scn, bdf.abs_fuzzy_scn) <= untilSCN)
AND (restoreSource IS NULL OR restoreSource = BACKUP)
AND dbinc.dbinc_key = bdf.dbinc_key -- join dbinc, bdf
AND bs.bs_key = bdf.bs_key -- join bs, bdf
AND bs.status = 'A'
UNION ALL
-- Backup Sets with controlfiles
SELECT backupSet_con_t type_con,
bcf.bcf_key key_con,
bcf.bcf_recid recid_con,
bcf.bcf_stamp stamp_con,
bs.set_stamp setStamp_con,
bs.set_count setCount_con,
bs.bs_recid bsRecid_con,
bs.bs_stamp bsStamp_con,
bs.bs_key bsKey_con,
0 bsLevel_con,
bs.bck_type bsType_con,
((bs.completion_time - bs.start_time) * 86400)
elapseSecs_con,
bs.pieces pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
to_number(null) blocks_con,
bcf.block_size blockSize_con,
to_char(null) deviceType_con,
bs.completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
bcf.ckp_scn toSCN_act,
bcf.ckp_time toTime_act,
openRecoveryActionCursor.dbincRlgSCN rlgSCN_act,
openRecoveryActionCursor.dbincRlgTime rlgTime_act,
dbinc.dbinc_key dbincKey_act,
to_number(null) level_act,
openRecoveryActionCursor.fno dfNumber_obj,
openRecoveryActionCursor.crescn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
bs.keep_options keep_options,
bs.keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM bcf, bs, dbinc
WHERE bcf.dbinc_key = openRecoveryActionCursor.dbincKey
AND 0 = openRecoveryActionCursor.fno
AND 0 = openRecoveryActionCursor.crescn
AND (openRecoveryActionCursor.dfCkpSCN IS NULL OR
openRecoveryActionCursor.dfCkpSCN < bcf.ckp_scn)
AND (openRecoveryActionCursor.targetSCN IS NULL OR
bcf.ckp_scn <= openRecoveryActionCursor.targetscn)
AND (untilSCN IS NULL OR
bcf.ckp_scn <= untilSCN)
AND (restoreSource IS NULL OR restoreSource = BACKUP)
AND dbinc.dbinc_key = bcf.dbinc_key -- join dbinc, bcf
AND bs.bs_key = bcf.bs_key -- join bs, bcf
AND bs.status = 'A'
UNION ALL
-- Proxy Datafile Backups
SELECT proxyCopy_con_t type_con,
xdf_key key_con,
xdf_recid recid_con,
xdf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
handle fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
blocks blocks_con,
block_size blockSize_con,
device_type deviceType_con,
completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
ckp_scn toSCN_act,
ckp_time toTime_act,
openRecoveryActionCursor.dbincRlgSCN rlgSCN_act,
openRecoveryActionCursor.dbincRlgTime rlgTime_act,
dbinc_key dbincKey_act,
to_number(null) level_act,
openRecoveryActionCursor.fno dfNumber_obj,
openRecoveryActionCursor.crescn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
keep_options keep_options,
keep_until keep_until,
abs_fuzzy_scn afzSCN_act,
rcv_fuzzy_time rfzTime_act,
rcv_fuzzy_scn rfzSCN_act
FROM xdf
WHERE dbinc_key = openRecoveryActionCursor.dbincKey
AND file# = openRecoveryActionCursor.fno
AND create_scn = openRecoveryActionCursor.crescn
AND (openRecoveryActionCursor.dfCkpSCN IS NULL OR
openRecoveryActionCursor.dfCkpSCN < ckp_scn)
AND (openRecoveryActionCursor.targetSCN IS NULL OR
ckp_scn <= openRecoveryActionCursor.targetscn)
AND (untilSCN IS NULL OR
greatest(ckp_scn, abs_fuzzy_scn, rcv_fuzzy_scn) <= untilSCN)
AND status = 'A'
AND (restoreTag is NULL OR
tag = restoreTag OR
computeRA_allRecords = TRUE#)
AND (restoreSource is NULL OR restoreSource = BACKUP)
UNION ALL
-- Proxy Controlfile Backups
SELECT proxyCopy_con_t type_con,
xcf_key key_con,
xcf_recid recid_con,
xcf_stamp stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
handle fileName_con,
tag tag_con,
to_number(null) copyNumber_con,
status status_con,
to_number(null) blocks_con,
block_size blockSize_con,
device_type deviceType_con,
completion_time compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
full_act_t type_act,
0 fromSCN_act,
ckp_scn toSCN_act,
ckp_time toTime_act,
openRecoveryActionCursor.dbincRlgSCN rlgSCN_act,
openRecoveryActionCursor.dbincRlgTime rlgTime_act,
dbinc_key dbincKey_act,
to_number(null) level_act,
openRecoveryActionCursor.fno dfNumber_obj,
openRecoveryActionCursor.crescn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
keep_options keep_options,
keep_until keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM xcf
WHERE dbinc_key = openRecoveryActionCursor.dbincKey
AND 0 = openRecoveryActionCursor.fno
AND 0 = openRecoveryActionCursor.crescn
AND (openRecoveryActionCursor.dfCkpSCN IS NULL OR
openRecoveryActionCursor.dfCkpSCN < ckp_scn)
AND (openRecoveryActionCursor.targetSCN IS NULL OR
ckp_scn <= openRecoveryActionCursor.targetscn)
AND (untilSCN IS NULL OR
ckp_scn <= untilSCN)
AND status = 'A'
AND (restoreTag is NULL OR
tag = restoreTag OR
computeRA_allRecords = TRUE#)
AND (restoreSource is NULL OR restoreSource = BACKUP)
UNION ALL
-- Implicit offline Ranges
SELECT offlineRangeRec_con_t type_con,
to_number(null) key_con,
to_number(null) recid_con,
to_number(null) stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
to_number(null) blocks_con,
to_number(null) blockSize_con,
to_char(null) deviceType_con,
to_date(null) compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
implicitRange_act_t type_act,
openRecoveryActionCursor.offlSCN fromSCN_act,
openRecoveryActionCursor.onlSCN toSCN_act,
openRecoveryActionCursor.onlTime toTime_act,
openRecoveryActionCursor.dbincRlgSCN rlgSCN_act,
openRecoveryActionCursor.dbincRlgTime rlgTime_act,
openRecoveryActionCursor.dbincKey dbincKey_act,
to_number(null) level_act,
fno dfNumber_obj,
crescn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
to_number(null) keep_options,
to_date(null) keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM dual
WHERE offlscn <> 0
AND (openRecoveryActionCursor.dfCkpSCN is null OR
openRecoveryActionCursor.dfCkpSCN <=
openRecoveryActionCursor.offlSCN)
AND (openRecoveryActionCursor.onlSCN >= -- belongs to this incarnation
openRecoveryActionCursor.dbincRlgSCN)
AND (openRecoveryActionCursor.targetSCN is null OR
openRecoveryActionCursor.onlscn <= -- don't advance ckpt beyond
openRecoveryActionCursor.targetSCN) -- targetSCN
AND (untilSCN is null OR -- don't advance ckpt beyond until scn
openRecoveryActionCursor.onlSCN < untilSCN)
UNION ALL
SELECT offlineRangeRec_con_t type_con,
to_number(null) key_con,
to_number(null) recid_con,
to_number(null) stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
to_number(null) blocks_con,
to_number(null) blockSize_con,
to_char(null) deviceType_con,
to_date(null) compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
cleanRange_act_t type_act,
openRecoveryActionCursor.cleanSCN fromSCN_act,
openRecoveryActionCursor.clean2SCN toSCN_act,
openRecoveryActionCursor.clean2Time toTime_act,
openRecoveryActionCursor.dbincRlgSCN rlgSCN_act,
openRecoveryActionCursor.dbincRlgTime rlgTime_act,
openRecoveryActionCursor.dbincKey dbincKey_act,
to_number(null) level_act,
fno dfNumber_obj,
crescn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
to_number(null) keep_options,
to_date(null) keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM dual
WHERE openRecoveryActionCursor.cleanscn <> 0
AND (openRecoveryActionCursor.dfCkpSCN is null OR
openRecoveryActionCursor.dfCkpSCN <=
openRecoveryActionCursor.cleanscn)
AND -- belongs to this incarnation
(openRecoveryActionCursor.clean2scn >=
openRecoveryActionCursor.dbincRlgSCN)
AND -- ignore if starts beyond target
(openRecoveryActionCursor.targetscn is null OR
openRecoveryActionCursor.cleanscn <
openRecoveryActionCursor.targetSCN)
AND -- If clean2scn is infinite, then we processed this when scanning
-- the current incarnation,
(openRecoveryActionCursor.targetSCN is null OR
openRecoveryActionCursor.clean2SCN <=
openRecoveryActionCursor.targetSCN)
AND -- don't advance ckpt beyond until scn, unless we don't know
-- where this offline range ends.
(untilscn is null OR
openRecoveryActionCursor.clean2SCN <= untilSCN OR
openRecoveryActionCursor.clean2SCN = 281474976710655)
UNION ALL
SELECT offlineRangeRec_con_t type_con,
to_number(null) key_con,
to_number(null) recid_con,
to_number(null) stamp_con,
to_number(null) setStamp_con,
to_number(null) setCount_con,
to_number(null) bsRecid_con,
to_number(null) bsStamp_con,
to_number(null) bsKey_con,
to_number(null) bsLevel_con,
to_char(null) bsType_con,
to_number(null) elapseSecs_con,
to_number(null) pieceCount_con,
to_char(null) fileName_con,
to_char(null) tag_con,
to_number(null) copyNumber_con,
to_char(null) status_con,
to_number(null) blocks_con,
to_number(null) blockSize_con,
to_char(null) deviceType_con,
to_date(null) compTime_con,
to_date(null) cfCreationTime_con,
to_number(null) pieceNumber_con,
to_date(null) bpCompTime_con,
spanningRange_act_t type_act,
openRecoveryActionCursor.targetSCN fromSCN_act,
to_number(null) toSCN_act,
to_date(null) toTime_act,
openRecoveryActionCursor.dbincRlgSCN rlgSCN_act,
openRecoveryActionCursor.dbincRlgTime rlgTime_act,
openRecoveryActionCursor.dbincKey dbincKey_act,
to_number(null) level_act,
fno dfNumber_obj,
crescn dfCreationSCN_obj,
to_number(null) cfSequence_obj,
to_date(null) cfDate_obj,
to_number(null) logSequence_obj,
to_number(null) logThread_obj,
to_number(null) logRlgSCN_obj,
to_date(null) logRlgTime_obj,
to_number(null) logLowSCN_obj,
to_date(null) logLowTime_obj,
to_number(null) logNextSCN_obj,
to_date(null) logNextTime_obj,
to_number(null) keep_options,
to_date(null) keep_until,
to_number(null) afzSCN_act,
to_date(null) rfzTime_act,
to_number(null) rfzSCN_act
FROM dual
WHERE -- a offline range which spans multiple resetlogs triggers
-- this condition
openRecoveryActionCursor.targetSCN <
openRecoveryActionCursor.dbincRlgSCN
ORDER BY 27 desc, -- toSCN_act
26 asc, -- fromSCN_act
1 asc, -- type_con
4 desc; -- stamp_con
deb(DEB_EXIT);
END openRecoveryActionCursor;
---------------------------- computeRecoveryActions ---------------------------
FUNCTION computeRecoveryActions(
fno IN number -- Datafile number.
,crescn IN number -- Datafile creation SCN.
,df_rlgscn IN number -- Datafile resetlogs SCN.
-- Null if this is a RESTORE or LIST, else this
-- is the value in the datafile header for the
-- datafile we are RECOVERing.
,df_rlgtime IN date -- Datafile resetlogs time.
-- Null if df_rlgscn is null, else value from
-- datafile header.
,df_ckpscn IN number -- Datafile checkpoint SCN.
-- Null if df_rlgscn is null, else value from
-- datafile header.
,offlscn IN number -- kccfeofs (may be 0).
,onlscn IN number -- kccfeonc (0 if offlscn is 0).
,onltime IN date -- kccfeonc_time (ignored if kccfeofs is 0)
,cleanscn IN number -- kccfecps if either SOR or WCC set, else 0.
,clean2scn IN number -- CF ckpt SCN if WCC set.
-- Infinity if SOR bit set, else 0.
,clean2time IN date -- cf_checkpoint_time if WCC,
-- SYSDATE if SOR bit set.
,allowfuzzy IN boolean -- TRUE if can be fuzzy at until SCN/time,
-- FALSE if not.
,partial_rcv IN boolean
,target_scn IN number -- This is the SCN to which we want to recover
-- the datafile. Null unless we call
-- ourselves recursively to search a prior
-- incarnation. We search prior incarnations
-- only when there is an offline range
-- spanning the resetlogs SCN. So this SCN is
-- really the offline range start SCN.
,dbinc_key IN number -- The key of the database incarnation to
-- search in. This may be different from
-- df_rlgscn, and it may be different from the
-- package var "this_dbinc_key".
,cf_scn IN number
,cf_cretime IN date -- controlfile creation time.
-- NULL if none mounted.
,cf_offrrid IN number -- recid of oldest offline range in controlfile
-- NULL if none mounted.
,test_search IN boolean -- if TRUE, then we have called ourself
-- recursively and are not sure this is an
-- ancestral incarnation
,done IN OUT boolean -- set to TRUE if successful. (IN mode so
-- we can test it).
,allCopies IN boolean) -- if true, then stack all copies of
-- a backup set if it was duplexed or copied.
-- NOTES:
-- If all copies is FALSE, then we should at least count the number of copies
-- of a backup set in addAction and save this number in the rcvRec. This
-- would tell us how many copies of a backupset there are, which would be
-- useful for RMAN to know. For example, if the customer wanted redundancy=2
-- but there was only 1 copy of an incremental backup, then this incremental
-- could not be considered as a substitute for archivelogs.
RETURN boolean IS
---------------------
-- LOCAL VARIABLES --
---------------------
r_act_cv rcvRecCursor_t; -- cursor variable
action rcvRec_t; -- current row
lastAction rcvRec_t;
parentDbincKey number; -- my parent dbinc's key
dbinc_rlgscn number; -- resetlogs scn for dbinc_key
dbinc_rlgtime date; -- resetlogs time for dbinc_key
CURSOR dbinc_cursor(db_key number, rstscn number) IS
SELECT dbinc_key
FROM dbinc
WHERE dbinc.db_key = dbinc_cursor.db_key
AND dbinc.reset_scn < dbinc_cursor.rstscn;
dbinc_row dbinc_cursor%ROWTYPE;
savedrcvRecStackState rcvRecStackState_t;
addAction_rc number; -- return code
canAddRedo_rc number; -- return code
addRedo_rc number; -- return code
isAncestor boolean; -- TRUE if we find an action we could
-- apply with to_scn = target_scn
rc boolean; -- return code from recursive search
-- of possible parent incarnation
done_flag boolean; -- for use in recursive calls
doingRecovery boolean; -- doing RECOVER or not
BEGIN
deb(DEB_ENTER, 'computeRecoveryActions');
done := FALSE;
IF (df_rlgscn is not null) THEN -- doing RECOVER
doingRecovery := TRUE;
deb(DEB_IN, ' Doing recovery.');
ELSE
doingRecovery := FALSE;
deb(DEB_IN, ' Not doing recovery.');
END IF;
-- Compute this dbinc's resetlogs SCN and time --
SELECT reset_scn, reset_time
INTO dbinc_rlgscn, dbinc_rlgtime
FROM dbinc
WHERE dbinc.dbinc_key = computeRecoveryActions.dbinc_key;
IF (doingRecovery) THEN -- doing RECOVER
-- Check that this incarnation is reasonable for the
-- datafile we are trying to recover. We only want to look at
-- incarnations with a resetlogs SCN >= the datafile's resetlogs SCN.
IF (dbinc_rlgscn < df_rlgscn) THEN
deb(DEB_PRINT, 'dbinc_rlgscn < df_rlgscn (' || to_char(dbinc_rlgscn) ||
' < ' || to_char(df_rlgscn) || ')');
deb(DEB_EXIT, 'with: FALSE');
RETURN FALSE;
ELSIF (dbinc_rlgscn = df_rlgscn AND dbinc_rlgtime <> df_rlgtime) THEN
deb(DEB_PRINT, 'dbinc_rlgtime <> df_rlgtime');
deb(DEB_EXIT, 'with: FALSE');
RETURN FALSE;
END IF;
END IF;
IF (not test_search) THEN
-- This is not test search of a prior incarnation, therefore
-- we can set this flag right away.
deb(DEB_IN, ' This is ancestor.');
isAncestor := TRUE;
ELSE
isAncestor := FALSE;
END IF;
openRecoveryActionCursor(r_act_cv, dbinc_key,
fno, crescn, df_ckpscn,
dbinc_rlgscn, dbinc_rlgtime,
offlscn, onlscn, onltime,
cleanscn, clean2scn, clean2time, target_scn);
------------------------------------
-- Process the rows from r_act_cv --
------------------------------------
<<action_loop>>
LOOP
<<next_row>>
IF (fetchRecoveryAction(r_act_cv, df_ckpscn, action)) THEN
-----------------------------
-- Compute isAncestor flag --
-----------------------------
IF (bitand(action.type_con, backupMask_con_t) > 0 AND
action.toSCN_act = target_scn) THEN
deb(DEB_IN, ' This is ancestor.');
isAncestor := TRUE;
END IF;
IF (action.type_con = offlineRangeRec_con_t) THEN
-------------------
-- OFFLINE RANGE --
-------------------
deb(DEB_IN, ' found an offline range' ||
' from=' || to_char(action.fromSCN_act) ||
' to=' || to_char(action.toSCN_act));
IF (action.type_act = spanningRange_act_t) THEN
----------------------------------------------
-- OFFLINE RANGE spanning multiple resetlogs -
----------------------------------------------
deb(DEB_IN, ' offline range started before this resetlogs SCN');
-- We don't need to add this action to the stack. Just set
-- addAction_rc to action_OK so that we will take the
-- right path below and search our parent incarnation.
addAction_rc := action_OK;
ELSE
addAction_rc := addAction(actionIN => action,
partial_rcv => partial_rcv,
isAncestor => isAncestor,
cf_scn => cf_scn,
cf_cretime => cf_cretime,
cf_offrrid => cf_offrrid,
doingRecovery => doingRecovery);
END IF;
ELSIF (action.type_con = backupSet_con_t AND
action.type_act = incremental_act_t) THEN
----------------------------
-- INCREMENTAL BACKUP SET --
----------------------------
deb(DEB_IN, 'found an incremental backup set');
addAction_rc := addAction(actionIN => action,
partial_rcv => partial_rcv,
isAncestor => isAncestor,
allCopies => allCopies,
doingRecovery => doingRecovery);
ELSIF (action.type_act = full_act_t) THEN
------------------------------------------------------------
-- DATAFILE COPY or FULL or LEVEL 0 BACKUP SET/PROXY COPY --
------------------------------------------------------------
deb(DEB_IN, 'found a copy/full/level0/proxy copy');
IF (doingRecovery) THEN -- if doing a RECOVER
-- Datafilecopies and full backups are not interesting when
-- doing a RECOVER. So don't stack this action, but do set the
-- computeRA_restorable flag if we know this
-- incarnation is an ancestor of the previous one or this is
-- the current incarnation, and we can apply redo to this full
-- backup if it would need some.
IF (isAncestor) THEN
rcvRecTop(lastAction);
IF (not redoNeeded(action) OR
canAddRedo(isAncestor,
action.toSCN_act, action.rlgSCN_act,
lastAction, partial_rcv, doingRecovery) <>
action_OLD_REDO) THEN
computeRA_restorable := TRUE;
END IF;
END IF;
addAction_rc := action_SKIP;
ELSE -- not doing a RECOVER
addAction_rc := addAction(actionIN => action,
partial_rcv => partial_rcv,
isAncestor => isAncestor,
allCopies => allCopies,
doingRecovery => doingRecovery);
END IF;
ELSE
------------------------
-- UKNOWN ACTION KIND --
------------------------
deb(DEB_IN, 'unknown container type: ' ||
to_char(action.type_con) ||
' or action type: ' || to_char(action.type_act));
-- We should signal an internal error here, but we don't have
-- that ability from PLSQL. So just raise 20999.
deb(DEB_EXIT, 'with error 20999');
raise_application_error(-20999, 'unknown action kind');
END IF; -- "switch" on ACTION.KIND
---------------------------------------------
-- Handle the return code from addAction() --
---------------------------------------------
deb(DEB_IN, 'addAction returned code ' || to_char(addAction_rc));
IF (addAction_rc = action_OK) THEN -- the action was added
--------------------------------------
-- Check for terminating conditions --
--------------------------------------
IF (rcvRecStackState.savePoint > 0 AND
computeRA_allRecords = FALSE#) THEN
-- If we now have a fullKind action and we are not looking
-- for all records, then we are done. Note that this must
-- be a RESTORE because savePoint is never non-zero if we are
-- doing RECOVER because fullKind actions are discarded
-- by RECOVER.
deb(DEB_IN, 'savePoint > 0' ||
' and computeRA_allRecords = FALSE#');
done := TRUE;
EXIT action_loop;
END IF;
IF (df_ckpscn is not null) THEN -- if doing RECOVER
IF (action.type_con = offlineRangeRec_con_t) THEN
-- For offline ranges, the datafile must be checkpointed
-- precisely at the offline range start SCN.
IF (df_ckpscn = action.fromSCN_act) THEN
done := TRUE;
EXIT action_loop;
END IF;
ELSE
-- For any other action, it is sufficient if the datafile
-- is checkpointed >= the action's from_scn.
IF (df_ckpscn >= action.fromSCN_act) THEN
done := TRUE;
EXIT action_loop;
END IF;
END IF;
END IF;
----------------------------------------
-- Offline Range Spanning a Resetlogs --
----------------------------------------
-- If the action was an offline range and this offline range
-- started before the current resetlogs, then we must search the
-- previous incarnation.
IF (action.type_con = offlineRangeRec_con_t AND
action.fromSCN_act < dbinc_rlgscn) THEN
deb(DEB_IN, 'offline range spanning a resetlogs');
-- This action is the last action we will fetch from this
-- incarnation. There cannot be any other actions from this
-- incarnation with a lower toSCN. Incremental backups cannot
-- span resetlogs, and any full backup checkpointed at the end
-- of the offline range would have been returned from the
-- cursor already because full backups have a fromSCN of 0.
-- Get parent's dbinc key --
SELECT parent_dbinc_key
INTO parentDbincKey
FROM dbinc
WHERE dbinc.dbinc_key = computeRecoveryActions.dbinc_key;
IF (parentDbincKey is null) THEN -- we don't know our parent
-- Open a cursor to get all dbinc rows for this database
-- that could possibly be our parent incarnation. We will
-- search them all. If exactly one turns out to work,
-- then we assume it is our parent. If more than one works,
-- then we cannot decide and will fail. If none works, well
-- too bad.
deb(DEB_OPEN, 'dbinc_cursor');
OPEN dbinc_cursor(this_db_key, dbinc_rlgscn);
deb(DEB_PRINT, 'doing scan of all possible parent incarnations, top=' ||
to_char(rcvRecStack.last));
<<dbinc_loop>>
LOOP
FETCH dbinc_cursor
INTO dbinc_row;
EXIT WHEN dbinc_cursor%NOTFOUND;
deb(DEB_PRINT, 'starting test search of incarnation key=' ||
to_char(dbinc_row.dbinc_key));
savedrcvRecStackState := rcvRecStackState;
rcvRecStackState.top := rcvRecStack.last;
rc := computeRecoveryActions(fno, crescn,
df_rlgscn, df_rlgtime,
df_ckpscn,
offlscn,
onlscn, onltime,
cleanscn,
clean2scn, clean2time,
allowfuzzy, partial_rcv,
rcvRecStack(rcvRecStack.count).fromSCN_act,
dbinc_row.dbinc_key,
cf_scn, cf_cretime,
cf_offrrid,
TRUE, done_flag, allCopies);
-- Trim any actions that may have gotten stacked in
-- the test search. If rc was FALSE, then none should
-- have been stacked, but it doesn't hurt to do a
-- trim(0), so do it anyway.
deb(DEB_PRINT, 'last=' || to_char(rcvRecStack.last) ||
' trimming last ' ||
to_char(rcvRecStack.last - rcvRecStackState.top)
);
rcvRecStack.trim(rcvRecStack.last - rcvRecStackState.top);
rcvRecStackState := savedrcvRecStackState;
deb(DEB_PRINT, 'count is now ' || to_char(rcvRecStack.count));
IF (rc) THEN
-- We found an action with a checkpoint SCN that
-- matched the offline range start SCN. So we just
-- searched what was most likely our parent
-- incarnation. It is possible that the datafile went
-- offline clean at the same SCN in two different
-- incarnations. This is very unlikely, but if it
-- happens, then there is no way for us to decide
-- which incarnation was the correct one. So save the
-- dbinc_key, trim back any actions we may have added,
-- and continue the search. If we exhaust the
-- dbinc_cursor and find only 1 incarnation that
-- worked, we can assume it was the right one.
-- If we find more than one, then we have to give up.
IF (parentDbincKey is null) THEN
parentDbincKey := dbinc_row.dbinc_key;
ELSE
-- We've found a second incarnation that could be
-- our parent. Since we cannot distintuish between
-- them, we are done.
deb(DEB_PRINT, 'aborting search due to ambiguous ancestory');
CLOSE dbinc_cursor;
EXIT action_loop;
END IF;
END IF;
END LOOP; -- dbinc_loop
END IF; -- if we don't know our parent
-- If we know our parent from the catalog or just found our
-- parent in the search above, then search our parent.
IF (parentDbincKey is not null) THEN
deb(DEB_PRINT, 'starting search of parent incarnation key='||
to_char(parentDbincKey));
rc := computeRecoveryActions(fno, crescn,
df_rlgscn, df_rlgtime,
df_ckpscn,
offlscn,
onlscn, onltime,
cleanscn,
clean2scn, clean2time,
allowfuzzy, partial_rcv,
rcvRecStack(rcvRecStack.last).fromSCN_act,
parentDbincKey,
cf_scn, cf_cretime,
cf_offrrid,
FALSE, done_flag, allCopies);
IF (done_flag) THEN
done := TRUE;
END IF;
IF (action.type_act = spanningRange_act_t) THEN
-- We went recursive because of an offline range which
-- spanned multiple resetlogs. In this case, we
-- propagate the return code from the recursive search.
-- The incarnation we are currently searching is an
-- ancestor if the incarnation we just searched
-- recursively is an ancestor.
isAncestor := rc;
END IF;
END IF; -- we know or found our parent
EXIT action_loop;
END IF; -- offline range start SCN < dbinc_rlgscn
ELSIF (addAction_rc = action_FAIL) THEN -- FAIL
-- Cannot apply this action for some reason. That's OK,
-- there may be other actions that we can apply.
NULL;
ELSIF (addAction_rc = action_SKIP) THEN -- SKIP
-- We don't want to add this action to the stack.
NULL;
ELSIF (addAction_rc = action_OLD_REDO) THEN -- OLD_REDO
-- If OLD_REDO, then the to_scn of this action does not reach the
-- from_scn of the last stacked action, and we are searching an
-- ancestral incarnation where we cannot apply redo. We know we
-- will not see any actions with a higher to_scn, so this stops
-- our search. No other actions from this incarnation are usable
-- because we cannot reach the spanning offline range from them.
EXIT action_loop;
ELSE -- unknown return code
deb(DEB_EXIT, 'with error 20999');
raise_application_error(-20999, 'unknown add action return code');
END IF;
ELSE -- r_act_cv exhausted
deb(DEB_IN, 'end of cursor reached');
EXIT action_loop;
END IF; -- if fetchRecoveryAction
END LOOP;
CLOSE r_act_cv; -- done with cursor
IF (done) THEN
deb(DEB_EXIT);
RETURN isAncestor;
END IF;
-- There is nothing else in this incarnation that we can
-- restore or apply. If we are doing RECOVER (doingRecovery is TRUE),
-- then we can just apply redo to this datafile.
IF (doingRecovery) THEN -- if doing RECOVER
IF (rcvRecStack.count > 0) THEN -- if found some action
-- Add a redo action to go from the datafile's checkpoint up to
-- the from_scn of the last action we stacked. If partial_rcv is
-- FALSE, then addRedo() will trim the actions we stacked because we
-- cannot use them.
rcvRecTop(lastAction);
addRedo_rc := addRedo(isAncestor, df_ckpscn, df_rlgscn,
lastAction, partial_rcv, doingRecovery);
IF (addRedo_rc = action_OK OR addRedo_rc = action_FAIL) THEN
-- OK means we could do the partial recovery from the datafile
-- checkpoint up to the first action we found. FAIL means
-- we could not add the redo, but we don't really need to apply
-- any. In either case, the file can be successfully recovered.
done := TRUE;
END IF;
ELSE
deb(DEB_IN, 'no actions stacked');
-- We didn't stack any actions. So this datafile is recoverable only
-- if is from the current incarnation. Set the done flag accordingly.
IF (df_rlgscn = this_reset_scn AND
df_rlgtime = this_reset_time) THEN
done := TRUE;
END IF;
END IF;
ELSE -- not doing a RECOVER
-- We may decide to trim the stack here. Never trim beyond the top
-- of the stack. The top is normally 0, but it is non-zero when
-- we are making a test search to find our parent incarnation.
IF (rcvRecStackState.savePoint = 0) THEN
-- We did not find any fullKind actions that we could apply.
-- This means we cannot restore this file or there is nothing
-- interesting to list. Note that we may have some actions
-- stacked at this point, but they are not useful.
-- Here is where we could do a CREATE DATAFILE.
deb(DEB_IN, 'could try create datafile');
rcvRecStack.trim(rcvRecStack.count - rcvRecStackState.top);
-- purge all actions
ELSE
-- We found at least 1 fullKind action, so the file is
-- definitly restorable or there is something interesting to LIST.
-- No actions stacked after the savePoint are usable though because
-- there is no fullKind backup to which we could apply these
-- actions. So trim all actions up to the savePoint.
deb(DEB_IN, 'trim all actions after savePoint='||
to_char(greatest(rcvRecStackState.savePoint,
rcvRecStackState.top)));
rcvRecStack.trim(rcvRecStack.last -
greatest(rcvRecStackState.savePoint,
rcvRecStackState.top));
done := TRUE;
END IF;
END IF; -- if doing recover
IF (done) THEN
deb(DEB_IN, 'done is TRUE');
ELSE
deb(DEB_IN, 'done is FALSE');
END IF;
deb(DEB_EXIT);
RETURN isAncestor;
END computeRecoveryActions;
----------------------------- trimRecoveryActions -----------------------------
FUNCTION trimRecoveryActions(
maxActions IN number
,containerMask IN number
,actionMask IN number)
RETURN NUMBER IS
dummy rcvRec_t;
remaining number;
BEGIN
deb(DEB_ENTER, 'trimRecoveryActions[function]');
IF (rcvRecStack.count > 0) THEN
rcvRecPop(dummy);
remaining := trimRecoveryActions(maxActions, containerMask, actionMask);
-- If this record is one that would be selected by the masks in effect,
-- then we can keep it if the remaining records on the
-- the stack after trimming are less than the maxActions limit.
-- Note: if other kinds of filtering are going to occur in
-- getRecoveryAction, then that filtering should also be done here
-- so that we don't count a record that won't be seen by the client.
-- NOTE: In case that actionMask is full_act_t we will skip
-- "keep" backups.
IF ((bitand(dummy.type_con, containerMask) = 0) OR
(bitand(dummy.type_act, actionMask) = 0) OR
((bitand(actionMask, full_act_t) <> 0) AND
(dummy.keep_options <> KEEP_NO))) THEN
-- This record is not selected by the masks in effect or
-- or it is "keep" backup, so we keep it on the stack.
rcvRecPush(dummy);
deb(DEB_EXIT, 'with: '||to_char(remaining));
RETURN remaining;
ELSE
IF (remaining < maxActions) THEN
rcvRecPush(dummy); -- put back on stack
deb(DEB_EXIT, 'with: '||to_char(remaining+1));
RETURN remaining + 1;
ELSE
-- Cannot keep it.
deb(DEB_IN, 'deleting action:');
printRcvRec(dummy);
deb(DEB_EXIT, 'with: '||to_char(remaining));
RETURN remaining;
END IF;
END IF;
ELSE
deb(DEB_EXIT, 'with: 0');
RETURN 0;
END IF;
END trimRecoveryActions;
----------------------------- printinCorebsRec --------------------------------
PROCEDURE printinCorebsRec(
inCorebsRec IN inCorebsRec_t)
IS
BEGIN
deb(DEB_PRINT, 'bsKey= ' || nvl(to_char(inCorebsRec.bsKey), 'NULL') ||
' dev= ' || nvl(inCoredeviceList(inCorebsRec.devindx), 'NULL'));
-- Too much debug information will cause buffer overflow
-- deb(DEB_PRINT, 'setStamp= ' || to_char(inCorebsRec.setStamp));
-- deb(DEB_PRINT, 'setCount= ' || to_char(inCorebsRec.setCount));
-- deb(DEB_PRINT, 'pieceCount= ' || to_char(inCorebsRec.pieceCount));
END printinCorebsRec;
---------------------------- getinCoreDeviceType ------------------------------
-- Push the device type if it doesn't exists in the stack and
-- return the index. Otherwise just return the index.
--
FUNCTION getinCoreDeviceType(
deviceType IN varchar2)
RETURN NUMBER IS
BEGIN
FOR i IN 1..inCoredeviceCount LOOP
IF deviceType = inCoredeviceList(i) THEN
RETURN i;
END IF;
END LOOP;
inCoredeviceCount := inCoredeviceCount + 1;
inCoredeviceList(inCoredeviceCount) := deviceType;
RETURN inCoredeviceCount;
END getinCoreDeviceType;
-----------------------------resetIncoreData----------------------------------
PROCEDURE resetIncoreData
IS
BEGIN
IF (inCorebsRecStack.count > 0) THEN
inCorebsRecStack.delete;
inCorebsRecStack.trim(inCorebsRecStack.count); -- clear stack
END IF;
IF (inCoredeviceCount > 0) THEN
inCoredeviceList.delete;
END IF;
inCoredeviceCount := 0; -- clear device index
END resetIncoreData;
---------------------------- inCorebsRecPush ----------------------------------
PROCEDURE inCorebsRecPush(
inCorebsRec IN inCorebsRec_t)
IS
new number;
BEGIN
inCorebsRecStack.extend;
inCorebsRecStack(inCorebsRecStack.last) := inCorebsRec;
EXCEPTION
WHEN others THEN
deb(DEB_PRINT, 'caught exception during inCorebsRecPush count ' ||
inCorebsRecStack.count);
deb(DEB_EXIT, substr(sqlerrm, 1, 512));
raise;
END inCorebsRecPush;
----------------------------- inCorebsRecGet ----------------------------------
PROCEDURE inCorebsRecGet(
indx IN number
,inCorebsRec OUT inCorebsRec_t)
IS
BEGIN
inCorebsRec := inCorebsRecStack(indx);
END inCorebsRecGet;
----------------------------- inCorebsRecTop ----------------------------------
PROCEDURE inCorebsRecTop(
inCorebsRec OUT inCorebsRec_t)
IS
BEGIN
IF (inCorebsRecStack.count = 0) THEN
inCorebsRec := NULL;
ELSE
inCorebsRecGet(inCorebsRecStack.count, inCorebsRec);
END IF;
END inCorebsRecTop;
----------------------------- inCorebsRecPop ----------------------------------
PROCEDURE inCorebsRecPop(
inCorebsRec OUT inCorebsRec_t)
IS
BEGIN
inCorebsRecTop(inCorebsRec);
inCorebsRecStack.trim;
END inCorebsRecPop;
----------------------------qukvalidateBackupSet-------------------------------
-- quick validate backup set
FUNCTION qukvalidateBackupSet(
bsKey IN number)
RETURN BOOLEAN IS
bottom number;
mid number;
top number;
found boolean := FALSE; -- not found yet
BEGIN
deb(DEB_ENTER, 'qukvalidateBackupSet: ' || to_char(bsKey));
IF (inCorebsRecStack.count > 0) THEN
-- Since the stack is ordered by bskey, we will make use of that
-- to quickly search a given key
---------------------
--- Binary search ---
---------------------
bottom := 1;
top := inCorebsRecStack.count;
WHILE (NOT found) LOOP
mid := floor((top + bottom)/2); -- should never exceed top
IF (inCorebsRecStack(mid).bsKey = bsKey) THEN
found := TRUE;
ELSIF (inCorebsRecStack(mid).bsKey < bsKey) THEN
bottom := mid;
ELSE
top := mid;
END IF;
IF ((bottom + 1)>= top) THEN
-- since we floored we mayn't have compared the top and bottom
IF (inCorebsRecStack(top).bsKey = bsKey OR
inCorebsRecStack(bottom).bsKey = bsKey) THEN
found := TRUE;
END IF;
EXIT;
END IF;
END LOOP;
END IF;
IF found THEN
deb(DEB_EXIT, 'with: TRUE');
ELSE
deb(DEB_EXIT, 'with: FALSE');
END IF;
RETURN found;
EXCEPTION
WHEN others THEN
deb(DEB_PRINT, 'caught exception during qukvalidateBackupSet');
deb(DEB_PRINT, ' top = ' || to_char(top) ||
' mid = ' || to_char(mid) ||
' bottom= ' || to_char(bottom) ||
' stackcount= ' || to_char(inCorebsRecStack.count));
deb(DEB_EXIT, substr(sqlerrm, 1, 512));
raise;
END qukvalidateBackupSet;
--------------------------- createinCorebsRecStack ----------------------------
PROCEDURE createinCorebsRecStack(
backupType IN binary_integer
,tag IN varchar2 DEFAULT NULL
,statusMask IN number
,checkDeviceIsAllocated IN boolean DEFAULT TRUE
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL)
IS
local inCorebsCursor_t;
inCorebsRec inCorebsRec_t;
BEGIN
deb(DEB_ENTER, 'createinCorebsRecStack' || to_date(sysdate));
IF (inCorebsRec_c%ISOPEN) THEN
CLOSE inCorebsRec_c;
END IF;
resetIncoreData; -- clear all inCore data structures
OPEN inCorebsRec_c(backupType => backupType
,tag => tag
,statusMask => statusMask
,completedAfter => completedAfter
,completedBefore => completedBefore);
LOOP
<<nextRow>>
FETCH inCorebsRec_c INTO local;
EXIT WHEN inCorebsRec_c%NOTFOUND;
IF (checkDeviceIsAllocated AND
isDeviceTypeAllocated(local.deviceType) = FALSE#) THEN
GOTO nextRow;
END IF;
-- form a inCorebsRec
inCorebsRec.bsKey := local.bsKey;
inCorebsRec.setStamp := local.setStamp;
inCorebsRec.setCount := local.setCount;
inCorebsRec.devindx := getinCoreDeviceType(local.deviceType);
inCorebsRec.pieceCount := local.pieceCount;
inCorebsRecPush(inCorebsRec);
END LOOP;
CLOSE inCorebsRec_c;
deb(DEB_PRINT, 'inCorebsRecStack.count: ' ||
to_char(inCorebsRecStack.count));
-- print the entire incore stack
IF (debug AND inCorebsRecStack.count > 0) THEN
deb(DEB_PRINT, '*********START DUMPING INCORE BSREC STACK**********');
FOR this in 1..inCorebsRecStack.count LOOP
inCorebsRecGet(this, inCorebsRec);
printinCorebsRec(inCorebsRec);
END LOOP;
deb(DEB_PRINT, '***********END DUMPING INCORE BSREC STACK**********');
END IF;
EXCEPTION
WHEN others THEN
deb(DEB_PRINT, 'caught exception during createinCorebsRecStack');
deb(DEB_EXIT, substr(sqlerrm, 1, 512));
raise;
END createinCorebsRecStack;
-----------------------------------------------
-- *** PUBLIC FUNCTION/PROCEDURE SECTION *** --
-----------------------------------------------
---------------
-- Debugging --
---------------
---------------------------------- dumpState ----------------------------------
FUNCTION dumpState(
lineno IN number)
RETURN varchar2 IS
BEGIN
IF lineno = 1 THEN RETURN 'this_db_key='||this_db_key;
ELSIF lineno = 2 THEN RETURN 'this_dbinc_key='||this_dbinc_key;
ELSIF lineno = 3 THEN RETURN 'this_reset_scn='||this_reset_scn;
ELSIF lineno = 4 THEN RETURN 'this_reset_time='||this_reset_time;
ELSIF lineno = 5 THEN RETURN 'untilSCN='||untilSCN;
ELSIF lineno = 6 THEN RETURN 'untilTime='||untilTime;
ELSIF lineno = 7 THEN RETURN 'getRA_completedAfter='||getRA_completedAfter;
ELSIF lineno = 8 THEN RETURN
'getRA_completedBefore='||getRA_completedBefore;
ELSIF lineno = 9 THEN RETURN 'getRA_likePattern='||getRA_likePattern;
ELSIF lineno = 10 THEN RETURN 'getRA_containerMask='||getRA_containerMask;
ELSIF lineno = 11 THEN RETURN 'getRA_actionMask='||getRA_actionMask;
ELSIF lineno = 12 THEN RETURN 'computeRA_allRecords='||computeRA_allRecords;
ELSIF lineno = 13 THEN RETURN 'allIncarnations='||allIncarnations;
ELSE RETURN NULL;
END IF;
END dumpState;
---------------------------------- setDebugOn ---------------------------------
PROCEDURE setDebugOn
IS
BEGIN
debug := TRUE;
END setDebugOn;
--------------------------------- setDebugOff ---------------------------------
PROCEDURE setDebugOff
IS
BEGIN
debug := FALSE;
END setDebugOff;
----------------------------
-- Package Initialization --
----------------------------
-- This is a vestigal function that was released to customers in 8.1.3 Beta.
-- It is no longer called, and is no longer needed, but must still be here
-- because this version of the package may be called by an 8.1.3 rman
-- executable.
---------------------------------- initialize ---------------------------------
PROCEDURE initialize(
rman_vsn IN number)
IS
BEGIN
NULL;
END initialize;
---------------------------- set_package_constants ----------------------------
PROCEDURE set_package_constants
IS
BEGIN
-- This procedure exists only for backwards compatibility with RMAN 8.1.5.
-- This package no longer cares what the values are. The rddf cursor
-- now implements the order-by for preference using hard-coded values
-- that are not returned to the client.
NULL;
END set_package_constants;
-----------------------
-- Utility functions --
-----------------------
---------------------------------- stamp2date ---------------------------------
FUNCTION stamp2date(
stamp IN number)
RETURN date
IS
x number;
dt varchar2(19);
BEGIN
x := stamp;
dt := to_char(mod(x,60), 'FM09'); -- seconds
x := floor(x/60);
dt := to_char(mod(x,60), 'FM09') || ':' || dt; -- minutes
x := floor(x/60);
dt := to_char(mod(x,24), 'FM09') || ':' || dt; -- hours
x := floor(x/24);
dt := to_char(mod(x,31)+1, 'FM09') || ' ' || dt; -- days
x := floor(x/31);
dt := to_char(mod(x,12)+1, 'FM09') || '/' || dt; -- months
dt := to_char(floor(x/12)+1988) || '/' || dt;
RETURN to_date(dt, 'YYYY/MM/DD HH24:MI:SS');
END stamp2date;
------------------------------
-- Set Database Incarnation --
------------------------------
--------------------------------- setDatabase ---------------------------------
PROCEDURE setDatabase(
db_name IN varchar2
,reset_scn IN number
,reset_time IN date
,db_id IN number)
IS
local dbinc%rowtype; -- local variables
dbnm dbinc.db_name%TYPE;
current_inc varchar2(3);
rid char(18);
BEGIN
deb(DEB_ENTER, 'setDatabase');
this_db_key := NULL; -- clear in case exception raised
this_dbinc_key := NULL;
this_reset_scn := NULL;
this_reset_time := NULL;
-- verify that this package is compatible with the recovery catalog
BEGIN
SELECT null
INTO local.db_key
FROM rcver
WHERE version = catalogVersion;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with error 20299');
raise_application_error(-20299, 'Recovery catalog version mismatch');
END;
-- If the target database is mounted, then we have the db_id (kccfhdbi).
-- This can be used to find the row in the db table corresponding
-- to the target database, and it will indicate which incarnation
-- is currently considered the current one.
IF (db_id is not NULL) THEN
deb(DEB_IN, ' db_id=' || to_char(db_id));
BEGIN
SELECT db.db_key, curr_dbinc_key, dbinc.reset_scn, dbinc.reset_time
INTO local.db_key, local.dbinc_key,
local.reset_scn, local.reset_time
FROM db, dbinc
WHERE db_id = setDatabase.db_id -- should return 1 row
AND dbinc.dbinc_key = db.curr_dbinc_key;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with error 20001');
raise_application_error(-20001, 'Database not found');
END;
-- Validate SCN only only if the target database is indeed mounted
IF (db_name is NOT NULL) THEN
-- Now validate that the resetlogs SCN we were passed matches that
-- of the current incarnation of this database. If not, then
-- a reset database should be done, or the wrong controlfile is
-- mounted.
BEGIN
SELECT decode(dbinc.dbinc_key, db.curr_dbinc_key, 'YES', 'NO'),
dbinc.db_name, dbinc.rowid
INTO current_inc,
dbnm,
rid
FROM db, dbinc
WHERE db.db_key = dbinc.db_key
AND db.db_id = setDatabase.db_id
-- AND dbinc.db_name = setDatabase.db_name
AND dbinc.reset_scn = setDatabase.reset_scn
AND dbinc.reset_time = setDatabase.reset_time;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with error 20003');
raise_application_error(-20003,
'Database incarnation not found');
END;
IF (current_inc = 'NO') THEN
deb(DEB_EXIT, 'with error 20011');
raise_application_error(-20011,
'Database incarnation not current');
END IF;
IF (dbnm != setDatabase.db_name) THEN
deb(DEB_PRINT, 'DB_NAME changed from '||dbnm||' to '||
setDatabase.db_name);
UPDATE dbinc
SET dbinc.db_name = setDatabase.db_name
WHERE rowid = rid;
COMMIT;
END IF;
END IF;
ELSIF (db_name is NOT NULL) THEN
-- If db_id is unknown, try using db_name
deb(DEB_IN, 'db_id is null');
BEGIN
SELECT db.db_key, db.curr_dbinc_key, dbinc.reset_scn, dbinc.reset_time
INTO local.db_key, local.dbinc_key,
local.reset_scn, local.reset_time
FROM db, dbinc
WHERE db.curr_dbinc_key = dbinc.dbinc_key
AND dbinc.db_name = setDatabase.db_name;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with error 20001');
raise_application_error(-20001, 'Database not found');
WHEN too_many_rows THEN
deb(DEB_EXIT, 'with error 20005');
raise_application_error(-20005, 'Database name is ambiguous');
END;
ELSE
deb(DEB_EXIT, 'with error 20006');
raise_application_error(-20006, 'Database name is missing');
END IF;
this_db_key := local.db_key;
this_dbinc_key := local.dbinc_key;
this_reset_scn := local.reset_scn;
this_reset_time := local.reset_time;
deb(DEB_EXIT);
END setDatabase;
--------------------------------- setDbincKey ---------------------------------
PROCEDURE setDbincKey(
key IN number)
IS
BEGIN
deb(DEB_ENTER, 'setDbincKey');
IF (key is not null) THEN
this_dbinc_key := key;
ELSE
-- if this query gets more than 1 row, than you lose. try again.
SELECT curr_dbinc_key
INTO this_dbinc_key
FROM db;
END IF;
SELECT db_key, reset_scn
INTO this_db_key, this_reset_scn
FROM dbinc
WHERE dbinc_key = this_dbinc_key;
deb(DEB_EXIT);
END setDbincKey;
----------------------------- getParentIncarnation ----------------------------
FUNCTION getParentIncarnation(
resetlogs_change# IN OUT number
,resetlogs_time IN OUT date)
RETURN number IS
BEGIN
deb(DEB_ENTER, 'getParentIncarnation');
-- If input is null, this is the first call, and we return the current
-- incarnation's key.
IF (resetlogs_change# is null) THEN
getParentIncarnationKey := this_dbinc_key;
END IF;
SELECT resetlogs_change#, resetlogs_time, parent_dbinc_key
INTO resetlogs_change#, resetlogs_time, getParentIncarnationKey
FROM rc_database_incarnation where dbinc_key = getParentIncarnationKey;
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END getParentIncarnation;
-------------------------------- getCheckpoint --------------------------------
PROCEDURE getCheckpoint(
scn OUT number
,seq OUT number
,ckp_key_1 OUT number
,ckp_key_2 OUT number)
IS
full_row ckp%ROWTYPE;
either_row ckp%ROWTYPE;
BEGIN
deb(DEB_ENTER, 'getCheckpoint');
IF (this_dbinc_key is NULL) THEN
deb(DEB_EXIT, 'with error 20020');
raise_application_error(-20020, 'Database incarnation not set');
END IF;
-- Return the SCN and controlfile sequence from the ckp table row
-- with the greatest ckp_scn and same high_df_recid as the most recent FULL
-- checkpoint.
-- The first query finds the FULL ckp with the greatest ckp_scn.
-- If there are 2 FULL checkpoints with the same ckp_scn, we choose the
-- one with the highest cf_seq or the highest cf_create_time.
-- The second query finds the row of either ckp_type with the highest
-- ckp_scn for the high_df_recid and cf_create_time obtained in the
-- previous query. If there are 2 rows with the same ckp_scn for a
-- given recid and create_time, then we choose the one with the highest
-- cf_seq. If the cf_seq is the same, then the ckp_type columns *must*
-- differ because of the ckp_u1 constraint. In this unlikely case, we
-- choose the 'PARTIAL' one.
-- If the first query returns no rows, then it's not necessary to execute
-- the second query, but it does no harm, and there are probably no rows in
-- the ckp table for this dbinc_key anyway. If the first query does return
-- a row, then the second query will *always* return a row.
FOR r IN (SELECT /*+ first_rows */ * FROM ckp
WHERE dbinc_key = this_dbinc_key AND
ckp_type = 'FULL'
ORDER BY ckp_scn DESC, cf_create_time DESC, ckp_cf_seq DESC)
LOOP
full_row := r;
EXIT;
END LOOP;
FOR r IN (SELECT /*+ first_rows */ * FROM ckp
WHERE dbinc_key = this_dbinc_key AND
high_df_recid = full_row.high_df_recid AND
cf_create_time = full_row.cf_create_time
ORDER BY ckp_scn DESC, ckp_cf_seq DESC, ckp_type DESC)
LOOP
either_row := r;
EXIT;
END LOOP;
IF either_row.ckp_key IS NOT NULL THEN
scn := either_row.ckp_scn;
seq := either_row.ckp_cf_seq;
ckp_key_1 := full_row.ckp_key;
ckp_key_2 := either_row.ckp_key;
ELSE
scn := 0;
seq := 0;
ckp_key_1 := 0;
ckp_key_2 := 0;
END IF;
deb(DEB_EXIT);
END getCheckpoint;
PROCEDURE getCheckpoint(
scn OUT number
,seq OUT number)
IS
ckp_key_1 number;
ckp_key_2 number;
BEGIN
getCheckpoint(scn, seq, ckp_key_1, ckp_key_2);
END getCheckpoint;
-------------------
-- Query Filters --
-------------------
------------------------------ setCompletedRange ------------------------------
PROCEDURE setCompletedRange(
after IN date
,before IN date)
IS
BEGIN
getRA_completedAfter := after;
getRA_completedBefore := before;
END setCompletedRange;
-------------------------------- setLikePattern -------------------------------
PROCEDURE setLikePattern(
pattern IN varchar2)
IS
BEGIN
getRA_likePattern := pattern;
END setLikePattern;
------------------------------ setAllIncarnations -----------------------------
PROCEDURE setAllIncarnations(
flag IN boolean)
IS
BEGIN
IF (flag) THEN
allIncarnations := TRUE#;
ELSE
allIncarnations := FALSE#;
END IF;
END setAllIncarnations;
-- Obsolete as of 8.1.6
---------------------------------- setAllFlag ---------------------------------
PROCEDURE setAllFlag(
flag IN boolean)
IS
BEGIN
setAllIncarnations(flag);
IF (flag) THEN
ignoreCreationSCN := TRUE#;
ELSE
ignoreCreationSCN := FALSE#;
END IF;
END setAllFlag;
--------------------------------- setUntilTime --------------------------------
PROCEDURE setUntilTime(
unttime IN date)
IS
walk_dbinc_key number := NULL;
parent_dbinc_key number := NULL;
BEGIN
deb(DEB_ENTER, 'setUntilTime');
IF (this_dbinc_key is NULL) THEN
deb(DEB_EXIT, 'with error 20020');
raise_application_error(-20020, 'Database incarnation not set');
END IF;
walk_dbinc_key := this_dbinc_key;
<<parent_inc>>
untilSCN := NULL;
untilTime := unttime;
BEGIN
SELECT resetlogs_change#
INTO untilSCN
FROM rc_database
WHERE dbinc_key = walk_dbinc_key
AND resetlogs_time <= untilTime;
EXCEPTION
WHEN no_data_found THEN
BEGIN
IF (allIncarnations = TRUE#) THEN
SELECT parent_dbinc_key
INTO parent_dbinc_key
FROM dbinc
WHERE dbinc.dbinc_key = walk_dbinc_key;
walk_dbinc_key := parent_dbinc_key;
IF (walk_dbinc_key IS NULL) THEN
deb(DEB_IN, 'parent_dbinc_key=NULL -> exiting');
untilSCN := 0; -- begining of world
ELSE
deb(DEB_IN, 'parent_dbinc_key=' ||
to_char(parent_dbinc_key));
GOTO parent_inc; -- get scn of parent incarnation
END IF;
ELSE
deb(DEB_EXIT, 'with error 20007');
raise_application_error(-20207,
'until time is before resetlogs time');
END IF;
END;
END;
-- find the highest SCN that is associated with a timestamp less than or
-- equal to the untilTime. This will give us an approximation of the SCN
-- where point-in-time recovery will stop and we use it to limit the
-- candidates for restore to backups and copies that are not fuzzy at the
-- SCN.
computeUntilSCN(untilTime, untilSCN);
deb(DEB_EXIT, 'untilSCN='||to_char(untilSCN));
END setUntilTime;
--------------------------------- setUntilScn ---------------------------------
PROCEDURE setUntilScn(
scn IN number)
IS
BEGIN
deb(DEB_ENTER, 'setUntilSCN');
untilSCN := scn;
untilTime := NULL;
IF (this_dbinc_key is NULL) THEN
deb(DEB_EXIT, 'with error 20020');
raise_application_error(-20020, 'Database incarnation not set');
END IF;
BEGIN
SELECT untilSCN
INTO untilSCN
FROM rc_database
WHERE dbinc_key = this_dbinc_key
AND resetlogs_change# <= untilSCN;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with error 20008');
raise_application_error(-20208, 'until SCN is before resetlogs SCN');
END;
deb(DEB_EXIT);
END setUntilScn;
--------------------------------- setUntilLog ---------------------------------
PROCEDURE setUntilLog(
sequence# IN number
,thread# IN number)
IS
BEGIN
deb(DEB_ENTER, 'setUntilLog');
untilTime := NULL;
untilSCN := NULL;
IF (this_dbinc_key is NULL) THEN
deb(DEB_EXIT, 'with error 20020');
raise_application_error(-20020, 'Database incarnation not set');
END IF;
IF (sequence# is NULL) THEN
deb(DEB_EXIT, 'with error 20205');
raise_application_error(-20205, 'Incomplete UNTIL clause');
END IF;
BEGIN
-- set untilSCN to the low SCN of the specified log
SELECT first_change#
INTO untilSCN
FROM rc_log_history
WHERE dbinc_key = this_dbinc_key
AND thread# = nvl(setUntilLog.thread#, 1) -- default thread# is 1
AND sequence# = setUntilLog.sequence#;
EXCEPTION
WHEN no_data_found THEN
BEGIN
-- the specified log is not (yet?) in the recovery catalog.
-- try setting untilSCN to the next SCN of the previous log
SELECT next_change#
INTO untilSCN
FROM rc_log_history
WHERE dbinc_key = this_dbinc_key
-- default thread# is 1
AND thread# = nvl(setUntilLog.thread#, 1)
AND sequence# = setUntilLog.sequence# - 1;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with error 20206');
raise_application_error(-20206, 'Specified log does not exist');
END;
END;
deb(DEB_EXIT);
END setUntilLog;
--------------------------------- getUntilTime --------------------------------
FUNCTION getUntilTime
RETURN date IS
BEGIN
RETURN untilTime;
END getUntilTime;
--------------------------------- getUntilScn ---------------------------------
FUNCTION getUntilScn
RETURN number IS
BEGIN
RETURN untilScn;
END getUntilScn;
---------------------------------- resetUntil ---------------------------------
PROCEDURE resetUntil
IS
BEGIN
untilSCN := NULL;
untilTime := NULL;
END resetUntil;
----------------------------------- setFrom -----------------------------------
PROCEDURE setFrom(
restorefrom IN number DEFAULT NULL)
IS
BEGIN
IF (restorefrom in (BACKUP, COPY) OR restorefrom is NULL) THEN
restoreSource := restorefrom;
ELSE
raise_application_error(-20200, 'Invalid restore source');
END IF;
END setFrom;
-------------------------------- setDeviceType --------------------------------
PROCEDURE setDeviceType(
type IN varchar2)
IS
BEGIN
IF (deviceCount >= 8) THEN
raise_application_error(-20280, 'Too many device types');
END IF;
deviceCount := deviceCount + 1;
deviceList(deviceCount) := type;
IF (type = 'DISK') THEN
diskDevice := TRUE;
END IF;
END setDeviceType;
----------------------------------- setStandby ------------------------------
PROCEDURE setStandby(
stby IN boolean)
IS
BEGIN
if stby is NULL then
onlyStandby := NULL;
elsif stby then
onlyStandby := TRUE#;
else
onlyStandby := FALSE#;
end if;
END setStandby;
------------------------------- setDeviceTypeAny ------------------------------
PROCEDURE setDeviceTypeAny
IS
BEGIN
diskDevice := true;
anyDevice := true;
deviceCount := 0;
END setDeviceTypeAny;
------------------------------- resetDeviceType -------------------------------
PROCEDURE resetDeviceType
IS
BEGIN
FOR i in 1..8 LOOP
deviceList(i) := NULL;
END LOOP;
deviceCount := 0;
diskDevice := FALSE;
anyDevice := FALSE;
END resetDeviceType;
------------------------------------ setTag -----------------------------------
PROCEDURE setTag(
tag IN varchar2 DEFAULT NULL)
IS
BEGIN
restoreTag := tag;
END setTag;
------------------------------ setTransClause --------------------------------
--
-- For now, we use this only for archivelog translation.
--
PROCEDURE setTransClause(
thread IN NUMBER DEFAULT NULL
,fromTime IN DATE DEFAULT NULL
,toTime IN DATE DEFAULT NULL
,fromSCN IN NUMBER DEFAULT NULL
,toSCN IN NUMBER DEFAULT NULL
,fromSeq IN NUMBER DEFAULT NULL
,toSeq IN NUMBER DEFAULT NULL
,pattern IN VARCHAR2 DEFAULT NULL)
IS
BEGIN
deb(DEB_ENTER, 'setTransClause');
tc_thread := thread;
tc_fromTime := fromTime;
tc_toTime := toTime;
tc_fromSCN := fromSCN;
tc_toSCN := toSCN;
tc_fromSeq := fromSeq;
tc_toSeq := toSeq;
tc_pattern := pattern;
deb(DEB_IN, 'tc_thread= ' || tc_thread);
deb(DEB_IN, 'tc_fromSCN= ' || fromSCN);
deb(DEB_IN, 'tc_toSCN= ' || toSCN);
deb(DEB_IN, 'tc_fromTime= ' || fromTime);
deb(DEB_IN, 'tc_toTime= ' || toTime);
deb(DEB_IN, 'tc_fromSeq= ' || fromSeq);
deb(DEB_IN, 'tc_toSeq= ' || toSeq);
deb(DEB_IN, 'tc_pattern= ' || pattern);
deb(DEB_EXIT);
END setTransClause;
----------------------------------- resetAll ----------------------------------
PROCEDURE resetAll
IS
BEGIN
-- reset to defaults
setRAflags(kindMask => allKind,
allRecords => FALSE);
setAllFlag(FALSE);
setLikePattern(NULL);
setCompletedRange(after => NULL, before => NULL);
resetUntil;
setFrom(NULL);
resetDeviceType;
setTag(NULL); -- restoreTag := NULL
setStandby(NULL);
versionCounter := 1; -- for getPackageVersion
getArchivedLogCursor := NULL;
getBackupPieceCursor := NULL;
getDatafileCopyCursor := NULL;
getDatafileCursor := NULL;
getProxyCopyCursor := NULL;
setTransClause; -- reset TransClause
resetIncoreData; -- reset incore data structures
pname_i := 0; -- reset debuging
IF findControlfileCopy%ISOPEN THEN
CLOSE findControlfileCopy;
END IF;
IF findControlfileProxyCopy%ISOPEN THEN
CLOSE findControlfileProxyCopy;
END IF;
IF findControlfileBackup_c%ISOPEN THEN
CLOSE findControlfileBackup_c;
END IF;
IF findSpfileBackup_c%ISOPEN THEN
CLOSE findSpfileBackup_c;
END IF;
IF findDatafileCopyKey%ISOPEN THEN
CLOSE findDatafileCopyKey;
END IF;
IF findDatafileBackup_c%ISOPEN THEN
CLOSE findDatafileBackup_c;
END IF;
IF findProxyCopy%ISOPEN THEN
CLOSE findProxyCopy;
END IF;
IF findProxyCopyKey%ISOPEN THEN
CLOSE findProxyCopyKey;
END IF;
IF findArchivedLogCopy%ISOPEN THEN
CLOSE findArchivedLogCopy;
END IF;
IF findArcLogBackup%ISOPEN THEN
CLOSE findArcLogBackup;
END IF;
IF findValidBackupSet_c%ISOPEN THEN
CLOSE findValidBackupSet_c;
END IF;
IF findValidBackupSet1P_c%ISOPEN THEN
CLOSE findValidBackupSet1P_c;
END IF;
IF findBackupPiece_c%ISOPEN THEN
CLOSE findBackupPiece_c;
END IF;
IF findBackupPieceBpKey%ISOPEN THEN
CLOSE findBackupPieceBpKey;
END IF;
IF findBackupPieceBsKey%ISOPEN THEN
CLOSE findBackupPieceBsKey;
END IF;
IF translateDatabase_c%ISOPEN THEN
CLOSE translateDatabase_c;
END IF;
IF translateTablespace_c%ISOPEN THEN
CLOSE translateTablespace_c;
END IF;
IF translateDatafileName%ISOPEN THEN
CLOSE translateDatafileName;
END IF;
IF translateDatafileNumber%ISOPEN THEN
CLOSE translateDatafileNumber;
END IF;
IF translateDatafileCheckpoint%ISOPEN THEN
CLOSE translateDatafileCheckpoint;
END IF;
IF translateAllDatafile_c%ISOPEN THEN
CLOSE translateAllDatafile_c;
END IF;
IF translateCorruptList_c%ISOPEN THEN
CLOSE translateCorruptList_c;
END IF;
IF translateOnlineLogs_c%ISOPEN THEN
CLOSE translateOnlineLogs_c;
END IF;
IF translateArcLogKey%ISOPEN THEN
CLOSE translateArcLogKey;
END IF;
IF translateArcLogName%ISOPEN THEN
CLOSE translateArcLogName;
END IF;
IF translateArcLogSeqRange%ISOPEN THEN
CLOSE translateArcLogSeqRange;
END IF;
IF translateArcLogSeqRange2%ISOPEN THEN
CLOSE translateArcLogSeqRange2;
END IF;
IF translateArcLogTimeRange%ISOPEN THEN
CLOSE translateArcLogTimeRange;
END IF;
IF translateArcLogSCNRange%ISOPEN THEN
CLOSE translateArcLogSCNRange;
END IF;
IF translateArcLogSCNRange2%ISOPEN THEN
CLOSE translateArcLogSCNRange2;
END IF;
IF translateArcLogPattern%ISOPEN THEN
CLOSE translateArcLogPattern;
END IF;
IF lbal2%ISOPEN THEN
CLOSE lbal2;
END IF;
IF ldbi%ISOPEN THEN
CLOSE ldbi;
END IF;
IF lrtbs%ISOPEN THEN
CLOSE lrtbs;
END IF;
IF getOfflineRangeCopy_c%ISOPEN THEN
CLOSE getOfflineRangeCopy_c;
END IF;
IF rddf%ISOPEN THEN
CLOSE rddf;
END IF;
IF bmrAddCorruptTable_c%ISOPEN THEN
CLOSE bmrAddCorruptTable_c;
END IF;
IF findBackupsetFiles%ISOPEN THEN
CLOSE findBackupsetFiles;
END IF;
IF findAllBackupPiece%ISOPEN THEN
CLOSE findAllBackupPiece;
END IF;
IF dfBackupHistory_c%ISOPEN THEN
CLOSE dfBackupHistory_c;
END IF;
IF alBackupHistory_c%ISOPEN THEN
CLOSE alBackupHistory_c;
END IF;
IF bsBackupHistory_c%ISOPEN THEN
CLOSE bsBackupHistory_c;
END IF;
IF inCorebsRec_c%ISOPEN THEN
CLOSE inCorebsRec_c;
END IF;
validateBackupSet_method := NULL;
END resetAll;
---------------------------
-- Backup Set Validation --
---------------------------
------------------------------ findValidBackupSet -----------------------------
PROCEDURE findValidBackupSet(
backupSetRec IN rcvRec_t
,deviceType IN varchar2 DEFAULT NULL
,tag IN varchar2 DEFAULT NULL
,available IN number DEFAULT TRUE# -- for compat.
,unavailable IN number DEFAULT FALSE# -- for compat.
,deleted IN number DEFAULT FALSE# -- for compat.
,expired IN number DEFAULT FALSE# -- for compat.
,availableMask IN binary_integer DEFAULT NULL) -- for compat.
IS
BEGIN
deb(DEB_ENTER, 'findValidBackupSet');
findValidBackupSet(bsKey => backupSetRec.bsKey_con,
pieceCount => backupSetRec.pieceCount_con,
deviceType => deviceType,
tag => tag,
availableMask => NVL(availableMask,
computeAvailableMask(available, unavailable, deleted,
expired)));
deb(DEB_EXIT);
END findValidBackupSet;
-- This version of findValidBackupSet takes a bsRec_t instead of a rcvRec_t.
------------------------------ findValidBackupSet -----------------------------
PROCEDURE findValidBackupSet(
backupSetRec IN bsRec_t
,deviceType IN varchar2 DEFAULT NULL
,tag IN varchar2 DEFAULT NULL
,available IN number DEFAULT TRUE# -- for compat.
,unavailable IN number DEFAULT FALSE# -- for compat.
,deleted IN number DEFAULT FALSE# -- for compat.
,expired IN number DEFAULT FALSE# -- for compat.
,availableMask IN binary_integer DEFAULT NULL) -- for compat.
IS
BEGIN
deb(DEB_ENTER, 'findValidBackupSet bsRec_t');
findValidBackupSet(bsKey => backupSetRec.key,
pieceCount => backupSetRec.pieceCount,
deviceType => deviceType,
tag => tag,
availableMask => NVL(availableMask,
computeAvailableMask(available, unavailable, deleted,
expired)));
deb(DEB_EXIT);
END findValidBackupSet;
------------------------------ getValidBackupSet ------------------------------
FUNCTION getValidBackupSet(
validBackupSetRec OUT validBackupSetRec_t
,checkDeviceIsAllocated IN number DEFAULT FALSE#)
RETURN number IS
lastCode number;
checkRc number;
local validBackupSetRec_t;
BEGIN
deb(DEB_ENTER, 'getValidBackupSet');
-- If the cursor is not open, just return FALSE#.
IF (getValidBackupSetCursor = 'findValidBackupSet1P_c') THEN
IF (NOT findValidBackupSet1P_c%ISOPEN) THEN
RETURN FALSE#;
END IF;
ELSIF (getValidBackupSetCursor = 'findValidBackupSet_c') THEN
IF (NOT findValidBackupSet_c%ISOPEN) THEN
RETURN FALSE#;
END IF;
ELSE
raise_application_error(-20204, 'Translation not started');
END IF;
<<nextRow>>
IF (getValidBackupSetCursor = 'findValidBackupSet1P_c') THEN
FETCH findValidBackupSet1P_c
INTO local;
IF (findValidBackupSet1P_c%NOTFOUND) THEN
CLOSE findValidBackupSet1P_c;
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END IF;
ELSIF (getValidBackupSetCursor = 'findValidBackupSet_c') THEN
FETCH findValidBackupSet_c
INTO local;
IF (findValidBackupSet_c%NOTFOUND) THEN
CLOSE findValidBackupSet_c;
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END IF;
END IF;
lastCode := getValidBackupSetLast.code; -- save for test below
getValidBackupSetLast := local; -- save for next time here
IF (local.code <= lastCode) THEN
-- The findValidBackupSet cursor returns 4 colums: deviceType, tag,
-- copy#, and a code (1,2,3). If the code is 1, it means we found a
-- complete set of pieces with the same deviceType, tag, and copy#. We
-- always want to process records of type 1. If the code is 2, it means
-- we ignored copy#, and found a complete set of pieces with the same
-- deviceType and tag. We only want to process records of type 2 if
-- we did not see this deviceType/tag combination with code 1.
-- A code 3 record means we ignored copy# and tag, and found a complete
-- set of pieces with the same deviceType. We only want to process
-- records of code 3 if we did not see any records of type 1 or 2
-- for this device type.
-- The order by allows us to implement this very easily. We return a
-- record only if its code is <= the code for the last record we
-- fetched. This works because if there is a code 2 record, then it
-- will be followed by a code 3 record. If there is a code 1 record, it
-- will be followed by a code 2 and then code 3 record.
-- Since this record's code is <= the previous record's code, we
-- must be looking at a different deviceType, tag, and/or copy# than
-- before, or this is the first record. In either case, we want to
-- process the record.
IF (checkDeviceIsAllocated = TRUE#) THEN
IF (isDeviceTypeAllocated(local.deviceType) = FALSE#) THEN
deb(DEB_IN, 'device type not allocated: ' ||
local.deviceType);
GOTO nextRow;
END IF;
END IF;
validBackupSetRec := local; -- set OUT mode arg
deb(DEB_IN, 'returning valid rec deviceType=' ||
local.deviceType || ' tag=' || local.tag || ' copyNumber=' ||
to_char(local.copyNumber));
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
ELSE
deb(DEB_IN, ' local.code=' || to_char(local.code) ||
' lastCode=' || to_char(lastCode));
GOTO nextRow;
END IF;
deb(DEB_EXIT);
END getValidBackupSet;
---------------------
-- Get an rcvRec_t --
---------------------
---------------------------------- getRcvRec ----------------------------------
FUNCTION getRcvRec(
funCode IN number
,rcvRec OUT rcvRec_t
,callAgain OUT number)
RETURN number IS
rc number;
BEGIN
deb(DEB_ENTER, 'getRcvRec');
rc := 0; -- init for procedures
callAgain := TRUE#;
deb(DEB_IN, ' funCode=' || to_char(funCode));
IF (funCode = getCfCopy) THEN
getControlfileCopy(rcvRec);
ELSIF (funCode = getDfCopy) THEN
getDatafileCopy(rcvRec);
ELSIF (funCode = getAnyProxy) THEN
getProxyCopy(rcvRec);
ELSIF (funCode = getCfBackup) THEN
rc := getControlfileBackup(rcvRec);
callAgain := FALSE#;
ELSIF (funCode = getSfBackup) THEN
rc := getSpfileBackup(rcvRec);
callAgain := FALSE#;
ELSIF (funCode = listCfCopy) THEN
listGetControlfileCopy(rcvRec);
ELSIF (funCode = listDfCopy) THEN
listGetDatafileCopy(rcvRec);
ELSIF (funCode = listCfBackup) THEN
listGetControlfileBackup(rcvRec);
ELSIF (funCode = listSfBackup) THEN
listGetSpfileBackup(rcvRec);
ELSIF (funCode = listDfBackup) THEN
listGetDatafileBackup(rcvRec);
ELSIF (funCode = listAlBackup) THEN
listGetArchivedLogBackup(rcvRec);
ELSIF (funCode = listDfProxy) THEN
listGetProxyDatafile(rcvRec);
ELSIF (funCode = getRecovAction) THEN
callAgain := getRecoveryAction(rcvRec);
ELSIF (funCode = getAlBackup) THEN
rc := getArchivedLogBackup(rcvRec);
callAgain := FALSE#;
ELSIF (funCode = listAlCopy) THEN
listGetArchivedLogCopy(rcvRec);
ELSIF (funCode = listBSet) THEN
listGetBackupsetFiles(rcvRec);
ELSIF (funCode = getAllBSet) THEN
getAllBackupSet(rcvRec);
ELSE
deb(DEB_EXIT, 'with error 20999');
raise_application_error(-20999, 'getRcvRec: unknown funCode: ' ||
to_char(funCode));
END IF;
printRcvRec(rcvRec);
deb(DEB_EXIT, 'with rc:'||TO_CHAR(rc));
RETURN rc;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END getRcvRec;
--------------------------
-- Datafile Translation --
--------------------------
------------------------------ translateDatabase ------------------------------
PROCEDURE translateDatabase(
sinceUntilSCN IN number DEFAULT NULL)
IS
fromSCN number;
toSCN number;
BEGIN
deb(DEB_ENTER, 'translateDatabase');
validateState(getDatafileCursor);
IF (untilSCN is NULL) THEN
-- This range means: all datafiles that exist now
fromSCN := MAXSCNVAL;
toSCN := MAXSCNVAL;
ELSE -- an until clause is in effect
fromSCN := untilSCN;
IF (sinceUntilSCN = TRUE#) THEN
-- This flag means the caller wants datafiles that existed
-- since the until SCN. So the translation range is:
-- untilSCN...MAXSCNVAL
toSCN := MAXSCNVAL;
ELSE
-- This is the normal case when an until clause is in effect.
-- We want the datafiles that existed at the until SCN, but not
-- any that were created after that.
toSCN := fromSCN;
END IF;
END IF;
deb(DEB_OPEN, 'translateDatabase_c');
OPEN translateDatabase_c(fromSCN, toSCN);
getDatafileCursor := 'translateDatabase';
getDatafileNoRows.error := NULL; -- error not possible
skipTablespaceCount := 0;
getDatafileLast.dfNumber := NULL; -- no last row yet
deb(DEB_EXIT);
END translateDatabase;
-- Public procedure to add a tablespace to the skip list.
-------------------------------- skipTableSpace -------------------------------
PROCEDURE skipTableSpace(
ts_name IN varchar2)
IS
BEGIN
skipTablespaceCount := skipTablespaceCount + 1;
skipTablespaceList(skipTablespaceCount) := ts_name;
END skipTableSpace;
----------------------------- translateTablespace -----------------------------
PROCEDURE translateTablespace(
ts_name IN varchar2)
IS
BEGIN
deb(DEB_ENTER, 'translateTablespace');
validateState(getDatafileCursor);
deb(DEB_OPEN, 'translateTablespace_c');
OPEN translateTablespace_c(tsName => ts_name);
getDatafileCursor := 'translateTablespace';
getDatafileNoRows.error := -20202;
getDatafileNoRows.msg := 'Tablespace does not exist';
skipTablespaceCount := 0;
getDatafileLast.dfNumber := NULL; -- no last row yet
deb(DEB_EXIT);
END translateTablespace;
------------------------------ translateDataFile ------------------------------
PROCEDURE translateDataFile(
fname IN varchar2)
IS
BEGIN
deb(DEB_ENTER, 'translateDataFile_1');
validateState(getDatafileCursor);
deb(DEB_OPEN, 'translateDatafileName');
OPEN translateDatafileName(fileName => fname);
IF (untilSCN is NULL and untilTime is NULL) THEN
getDatafileNoRows.error := -20201;
getDatafileNoRows.msg := 'Datafile does not exist';
ELSE
getDatafileNoRows.error := -20222;
getDatafileNoRows.msg :=
'Datafile name does not exist or is ambiguous';
END IF;
getDatafileCursor := 'translateDatafileName';
skipTablespaceCount := 0;
getDatafileLast.dfNumber := NULL; -- no last row yet
deb(DEB_EXIT);
END translateDatafile;
------------------------------ translateDataFile ------------------------------
PROCEDURE translateDataFile(
fno IN number)
IS
BEGIN
deb(DEB_ENTER, 'translateDataFile_2');
validateState(getDatafileCursor);
deb(DEB_OPEN, 'translateDatafileNumber');
OPEN translateDatafileNumber(fno => fno);
getDatafileCursor := 'translateDatafileNumber';
getDatafileNoRows.error := -20201;
getDatafileNoRows.msg := 'Datafile does not exist';
skipTablespaceCount := 0;
getDatafileLast.dfNumber := NULL; -- no last row yet
deb(DEB_EXIT);
END translateDatafile;
------------------------------ translateDataFile ------------------------------
PROCEDURE translateDataFile(
fno IN number
,ckpscn IN number)
IS
BEGIN
deb(DEB_ENTER, 'translateDataFile_3');
validateState(getDatafileCursor);
deb(DEB_OPEN, 'translateDatafileCheckpoint');
OPEN translateDatafileCheckpoint(fno => fno,
ckpSCN => ckpscn);
getDatafileCursor := 'translateDatafileCheckpoint';
getDatafileNoRows.error := -20201;
getDatafileNoRows.msg := 'Datafile does not exist';
skipTablespaceCount := 0;
getDatafileLast.dfNumber := NULL; -- no last row yet
deb(DEB_EXIT);
END translateDatafile;
----------------------------- translateAllDataFile ----------------------------
PROCEDURE translateAllDatafile
IS
BEGIN
deb(DEB_ENTER, 'translateAllDataFile');
IF (translateAllDatafile_c%ISOPEN) THEN
CLOSE translateAllDatafile_c;
END IF;
deb(DEB_OPEN, 'translateAllDatafile_c');
OPEN translateAllDatafile_c;
getDatafileCursor := 'translateAllDatafile';
getDatafileNoRows.error := NULL; -- error not possible
skipTablespaceCount := 0;
getDatafileLast.dfNumber := NULL; -- no last row yet
deb(DEB_EXIT);
END;
PROCEDURE translateCorruptList
IS
BEGIN
validateState(getDatafileCursor);
OPEN translateCorruptList_c;
getDatafileCursor := 'translateCorruptList';
getDatafileNoRows.error := -20504;
getDatafileNoRows.msg := 'Corruption List does not exist';
skipTablespaceCount := 0;
getDatafileLast.dfNumber := NULL; -- no last row yet
END translateCorruptList;
-- Main getDatafile routine
--------------------------------- getDatafile ---------------------------------
PROCEDURE getDatafile(
dfRec OUT dfRec_t
,oldClient IN boolean DEFAULT FALSE)
IS
getDatafileRowcount number;
local dfRec_t;
BEGIN
deb(DEB_ENTER, 'getDataFile_1');
<<nextRow>>
IF (getDatafileCursor = 'translateDatabase') THEN
FETCH translateDatabase_c
INTO local;
IF (translateDatabase_c%NOTFOUND) THEN
-- Save rowcount before closing cursor
getDatafileRowcount := translateDatabase_c%ROWCOUNT;
CLOSE translateDatabase_c;
END IF;
ELSIF (getDatafileCursor = 'translateAllDatafile') THEN
FETCH translateAllDatafile_c
INTO local;
IF (translateAllDatafile_c%NOTFOUND) THEN
-- Save rowcount before closing cursor
getDatafileRowcount := translateAllDatafile_c%ROWCOUNT;
CLOSE translateAllDatafile_c;
END IF;
ELSIF (getDatafileCursor = 'translateTablespace') THEN
FETCH translateTablespace_c
INTO local;
IF (translateTablespace_c%NOTFOUND) THEN
-- Save rowcount before closing cursor
getDatafileRowcount := translateTablespace_c%ROWCOUNT;
CLOSE translateTablespace_c;
END IF;
ELSIF (getDatafileCursor = 'translateDatafileName') THEN
FETCH translateDatafileName
INTO local;
IF (translateDatafileName%NOTFOUND) THEN
-- Save rowcount before closing cursor
getDatafileRowcount := translateDatafileName%ROWCOUNT;
CLOSE translateDatafileName;
END IF;
IF (oldClient) THEN
-- We won't be called again, so close the cursor now.
IF (translateDatafileName%ISOPEN) THEN
CLOSE translateDatafileName;
END IF;
getDatafileCursor := NULL;
END IF;
ELSIF (getDatafileCursor = 'translateDatafileNumber') THEN
FETCH translateDatafileNumber
INTO local;
IF (translateDatafileNumber%NOTFOUND) THEN
-- Save rowcount before closing cursor
getDatafileRowcount := translateDatafileNumber%ROWCOUNT;
CLOSE translateDatafileNumber;
END IF;
IF (oldClient) THEN
-- We won't be called again, so close the cursor now.
IF (translateDatafileNumber%ISOPEN) THEN
CLOSE translateDatafileNumber;
END IF;
getDatafileCursor := NULL;
END IF;
ELSIF (getDatafileCursor = 'translateDatafileCheckpoint') THEN
FETCH translateDatafileCheckpoint
INTO local;
IF (translateDatafileCheckpoint%NOTFOUND) THEN
-- Save rowcount before closing cursor
getDatafileRowcount := translateDatafileCheckpoint%ROWCOUNT;
CLOSE translateDatafileCheckpoint;
END IF;
IF (oldClient) THEN
-- We won't be called again, so close the cursor now.
IF (translateDatafileCheckpoint%ISOPEN) THEN
CLOSE translateDatafileCheckpoint;
END IF;
getDatafileCursor := NULL;
END IF;
ELSIF (getDatafileCursor = 'translateCorruptList') THEN
FETCH translateCorruptList_c
INTO local;
IF (translateCorruptList_c%NOTFOUND) THEN
-- Save rowcount before closing cursor
getDatafileRowcount := translateCorruptList_c%ROWCOUNT;
CLOSE translateCorruptList_c;
END IF;
ELSE
deb(DEB_EXIT, 'with error 20204');
raise_application_error(-20204, 'Translation not started');
END IF;
IF (getDatafileRowcount IS NOT NULL) THEN -- if %NOTFOUND
getDatafileCursor := NULL; -- we closed it above
IF (getDatafileRowcount = 0 AND
getDatafileNoRows.error IS NOT NULL) THEN
-- Signal the appropriate error.
deb(DEB_EXIT, 'with norows error');
raise_application_error(getDatafileNoRows.error,
getDatafileNoRows.msg);
ELSE
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found; -- signal end-of-fetch
END IF;
END IF;
IF (skipTablespace(local.tsName)) THEN
GOTO nextRow;
END IF;
-- This isn't needed right now, but I am leaving it in because
-- it can't hurt.
IF (getDatafileLast.dfNumber = local.dfNumber AND
getDatafileLast.dfCreationSCN = local.dfCreationSCN) THEN
GOTO nextRow;
END IF;
getDatafileLast := local;
dfRec := local; -- set OUT mode arg
deb(DEB_EXIT);
END getDatafile;
-- Public procedure for 8.1.x and prior releases.
--------------------------------- getDatafile ---------------------------------
PROCEDURE getDatafile(
file# OUT number
,crescn OUT number
,creation_time OUT date
,fname OUT varchar2
,ts_name OUT varchar2
,status OUT number
,blksize OUT number
,kbytes OUT number
,blocks OUT number
,unrecoverable_change# OUT number
,stop_change# OUT number
,read_only OUT number)
IS
dfRec dfRec_t;
BEGIN
deb(DEB_ENTER, 'getDataFile_2');
getDatafile(dfRec, oldClient => TRUE);
file# := dfRec.dfNumber;
crescn := dfRec.dfCreationSCN;
creation_time := dfRec.dfCreationTime;
fname := dfRec.fileName;
ts_name := dfRec.tsName;
status := 0; -- this is kccfesta, which we don't have
blksize := dfRec.blockSize;
kbytes := dfRec.kbytes;
blocks := dfRec.blocks;
unrecoverable_change# := 0; -- this is kccfeurs which isn't kept in rcvcat
stop_change# := dfRec.stopSCN;
read_only := dfRec.readOnly;
deb(DEB_EXIT);
EXCEPTION
WHEN no_data_found THEN
-- This is end-of-fetch.
file# := NULL;
deb(DEB_EXIT, 'with no more records');
END getDatafile;
----------------------------
-- Online Log Translation --
----------------------------
----------------------------- translateOnlineLogs -----------------------------
PROCEDURE translateOnlineLogs
IS
BEGIN
deb(DEB_ENTER, 'translateOnlineLogs');
IF (translateOnlineLogs_c%ISOPEN) THEN
validateState('you bozo'); -- raise the error
END IF;
deb(DEB_OPEN, 'translateOnlineLogs_c');
OPEN translateOnlineLogs_c;
deb(DEB_EXIT);
END translateOnlineLogs;
--------------------------------- getOnlineLog --------------------------------
PROCEDURE getOnlineLog(
fname OUT varchar2
,thread# OUT number
,group# OUT number)
IS
BEGIN
deb(DEB_ENTER, 'getOnlineLog');
FETCH translateOnlineLogs_c
INTO thread#, group#, fname;
IF (translateOnlineLogs_c%NOTFOUND) THEN
CLOSE translateOnlineLogs_c;
deb(DEB_EXIT, 'with NULL (no archivelog found)'||fname);
fname := NULL; -- indicate end-of-fetch
RETURN;
END IF;
deb(DEB_EXIT, 'with archivelog:'||fname);
END getOnlineLog;
------------------------------
-- Archived Log Translation --
------------------------------
-------------------------------- getArchivedLog -------------------------------
PROCEDURE getArchivedLog(
alRec OUT alRec_t,
closeCursor IN boolean DEFAULT FALSE)
IS
getArchivedLogRowcount number;
local alRec_t;
BEGIN
deb(DEB_ENTER, 'getArchivedLog');
<<nextRow>>
IF (getArchivedLogCursor = 'translateArcLogKey') THEN
FETCH translateArcLogKey
INTO local;
IF (translateArcLogKey%NOTFOUND) THEN
getArchivedLogRowcount := translateArcLogKey%ROWCOUNT;
CLOSE translateArcLogKey;
END IF;
IF (closeCursor AND translateArcLogKey%ISOPEN) THEN
CLOSE translateArcLogKey;
END IF;
ELSIF (getArchivedLogCursor = 'translateArcLogName') THEN
FETCH translateArcLogName
INTO local;
IF (translateArcLogName%NOTFOUND) THEN
getArchivedLogRowcount := translateArcLogName%ROWCOUNT;
CLOSE translateArcLogName;
END IF;
IF (closeCursor AND translateArcLogName%ISOPEN) THEN
CLOSE translateArcLogName;
END IF;
ELSIF (getArchivedLogCursor = 'translateArcLogSeqRange') THEN
FETCH translateArcLogSeqRange
INTO local;
IF (translateArcLogSeqRange%NOTFOUND) THEN
getArchivedLogRowcount := translateArcLogSeqRange%ROWCOUNT;
CLOSE translateArcLogSeqRange;
END IF;
IF (closeCursor AND translateArcLogSeqRange%ISOPEN) THEN
CLOSE translateArcLogSeqRange;
END IF;
ELSIF (getArchivedLogCursor = 'translateArcLogSeqRange2') THEN
FETCH translateArcLogSeqRange2
INTO local;
IF (translateArcLogSeqRange2%NOTFOUND) THEN
getArchivedLogRowcount := translateArcLogSeqRange2%ROWCOUNT;
CLOSE translateArcLogSeqRange2;
END IF;
IF (closeCursor AND translateArcLogSeqRange2%ISOPEN) THEN
CLOSE translateArcLogSeqRange2;
END IF;
ELSIF (getArchivedLogCursor = 'translateArcLogTimeRange') THEN
FETCH translateArcLogTimeRange
INTO local;
IF (translateArcLogTimeRange%NOTFOUND) THEN
getArchivedLogRowcount := translateArcLogTimeRange%ROWCOUNT;
CLOSE translateArcLogTimeRange;
END IF;
IF (closeCursor AND translateArcLogTimeRange%ISOPEN) THEN
CLOSE translateArcLogTimeRange;
END IF;
ELSIF (getArchivedLogCursor = 'translateArcLogTimeRange2') THEN
FETCH translateArcLogTimeRange2
INTO local;
IF (translateArcLogTimeRange2%NOTFOUND) THEN
getArchivedLogRowcount := translateArcLogTimeRange2%ROWCOUNT;
CLOSE translateArcLogTimeRange2;
END IF;
IF (closeCursor AND translateArcLogTimeRange2%ISOPEN) THEN
CLOSE translateArcLogTimeRange2;
END IF;
ELSIF (getArchivedLogCursor = 'translateArcLogSCNRange') THEN
FETCH translateArcLogSCNRange
INTO local;
IF (translateArcLogSCNRange%NOTFOUND) THEN
getArchivedLogRowcount := translateArcLogSCNRange%ROWCOUNT;
CLOSE translateArcLogSCNRange;
END IF;
IF (closeCursor AND translateArcLogSCNRange%ISOPEN) THEN
CLOSE translateArcLogSCNRange;
END IF;
ELSIF (getArchivedLogCursor = 'translateArcLogSCNRange2') THEN
FETCH translateArcLogSCNRange2
INTO local;
IF (translateArcLogSCNRange2%NOTFOUND) THEN
getArchivedLogRowcount := translateArcLogSCNRange2%ROWCOUNT;
CLOSE translateArcLogSCNRange2;
END IF;
IF (closeCursor AND translateArcLogSCNRange2%ISOPEN) THEN
CLOSE translateArcLogSCNRange2;
END IF;
ELSIF (getArchivedLogCursor = 'translateArcLogPattern') THEN
FETCH translateArcLogPattern
INTO local;
IF (translateArcLogPattern%NOTFOUND) THEN
getArchivedLogRowcount := translateArcLogPattern%ROWCOUNT;
CLOSE translateArcLogPattern;
END IF;
IF (closeCursor AND translateArcLogPattern%ISOPEN) THEN
CLOSE translateArcLogPattern;
END IF;
ELSE
deb(DEB_EXIT, 'with error 20204');
raise_application_error(-20204, 'Translation not started');
END IF;
IF (closeCursor) THEN
getArchivedLogCursor := NULL;
END IF;
IF (getArchivedLogRowcount IS NOT NULL) THEN
getArchivedLogCursor := NULL; -- we closed it above
getArchivedLogLast := NULL; -- clear for next time
IF (getArchivedLogRowcount = 0 AND
getArchivedLogNoRows.error IS NOT NULL) THEN
-- Signal the appropriate error.
deb(DEB_EXIT, 'with norows error');
raise_application_error(getArchivedLogNoRows.error,
getArchivedLogNoRows.msg);
ELSE
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found; -- signal end-of-fetch
END IF;
END IF;
-- Eliminate duplicate archived logs unless getArchivedLogDuplicates is true
IF (local.thread = getArchivedLogLast.thread AND
local.sequence = getArchivedLogLast.sequence AND
local.lowSCN = getArchivedLogLast.lowSCN) THEN
local.duplicate := TRUE#;
END IF;
IF (getArchivedLogDuplicates = FALSE# AND -- if don't want duplicates
local.duplicate = TRUE#) THEN
GOTO nextRow;
END IF;
-- If stamp is -1, then this came from the brl table. Change stamp to
-- be null since -1 is not a legal stamp value.
IF (local.stamp = -1) THEN
local.stamp := NULL;
END IF;
IF getArchivedLogCursor IS NULL THEN
getArchivedLogLast := NULL; -- clear for next time
deb(DEB_PRINT, 'getArchivedLogLast := NULL');
ELSE
getArchivedLogLast := local;
deb(DEB_PRINT, 'getArchivedLogLast := local');
END IF;
alRec := local; -- set OUT mode arg
deb(DEB_EXIT);
END getArchivedLog;
--------------------------- translateArchivedLogKey ---------------------------
PROCEDURE translateArchivedLogKey(
alKey IN number
,needstby IN number DEFAULT NULL)
IS
BEGIN
deb(DEB_ENTER, 'translateArchivedLogKey');
validateState(getArchivedLogCursor);
deb(DEB_OPEN, 'translateArcLogKey');
OPEN translateArcLogKey(alKey => alKey, needstby => needstby);
getArchivedLogCursor := 'translateArcLogKey';
getArchivedLogDuplicates := NULL;
getArchivedLogNoRows.error := -20240;
getArchivedLogNoRows.msg := 'Archived log does not exist';
deb(DEB_EXIT);
END translateArchivedLogKey;
--------------------------- translateArchivedLogKey ---------------------------
PROCEDURE translateArchivedLogKey(
al_key IN number
,available IN number DEFAULT 1 -- ignored (for compatability)
,unavailable IN number DEFAULT 1 -- ignored (for compatability)
,deleted IN number DEFAULT 1 -- ignored (for compatability)
,online IN number DEFAULT 1 -- ignored (for compatability)
,recid OUT number
,stamp OUT number
,thread# OUT number
,sequence# OUT number
,low_scn OUT number
,reset_scn OUT number
,block_size OUT number
,fname OUT varchar2
,needstby IN number DEFAULT NULL)
IS
alRec alRec_t;
BEGIN
deb(DEB_ENTER, 'translateArchivedLogKey816');
translateArchivedLogKey(alKey => al_key, needstby => needstby);
getArchivedLog(alRec => alRec,
closeCursor => TRUE);
recid := alRec.recid;
stamp := alRec.stamp;
thread# := alRec.thread;
sequence# := alRec.sequence;
low_scn := alRec.lowSCN;
reset_scn := alRec.rlgSCN;
block_size := alRec.blockSize;
fname := alRec.fileName;
deb(DEB_EXIT);
END translateArchivedLogKey;
-- Translate archived log name. The archived logs are ordered by
-- stamp in order to return most recently created log first, because it
-- most likely to exist. Note that archived logs that belong to any
-- incarnation of the current database are returned.
--------------------------- translateArchivedLogName --------------------------
PROCEDURE translateArchivedLogName(
fname IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,online IN number -- ignored
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL -- for compatability
,needstby IN number DEFAULT NULL)
IS
BEGIN
deb(DEB_ENTER, 'translateArchivedLogName');
validateState(getArchivedLogCursor);
deb(DEB_OPEN, 'translateArcLogName');
OPEN translateArcLogName(fname => fname,
online => online,
statusMask => NVL(statusMask,
computeAvailableMask(available, unavailable,
deleted, 0)),
needstby => needstby);
getARchivedLogCursor := 'translateArcLogName';
getArchivedLogDuplicates := duplicates;
getArchivedLogNoRows.error := -20240;
getArchivedLogNoRows.msg := 'Archived log does not exist';
deb(DEB_EXIT);
END translateArchivedLogName;
-- Translate an archived log sequence range. The archived logs are ordered
-- by thread#, first_change#, sequence# to make detection of "missing"
-- archived logs in the range easy and to return the logs in the order that
-- recovery will apply them. Note that sequence number is reset if the
-- controlfile is recreated so first change must be before sequence# number
-- in the order by clause.
------------------------- translateArchivedLogSeqRange ------------------------
PROCEDURE translateArchivedLogSeqRange(
thread# IN number
,fromseq# IN number
,toseq# IN number
,pattern IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,online IN number -- ignored
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL -- for compatability
,needstby IN number DEFAULT NULL)
IS
mask number := NVL(statusMask,
computeAvailableMask(available, unavailable, deleted, 0));
BEGIN
deb(DEB_ENTER, 'translateArchivedLogSeqRange');
validateState(getArchivedLogCursor);
IF (thread# is NULL) THEN
deb(DEB_EXIT, 'with error 20210');
raise_application_error(-20210, 'Thread# is missing');
END IF;
IF (bitand(mask,BSdeleted) != 0 AND pattern IS NULL) THEN
-- Use the cursor that also looks at backup redo logs.
-- The online parameter is assumed to be FALSE#. Available and
-- unavailable are ignored. Since we are looking at backup redo logs,
-- pattern cannot be implemented here, so we use this cursor only if
-- pattern is null.
deb(DEB_OPEN, 'translateArcLogSeqRange2');
OPEN translateArcLogSeqRange2(thread# => thread#,
fromseq# => fromseq#,
toseq# => toseq#,
needstby => needstby);
getArchivedLogCursor := 'translateArcLogSeqRange2';
ELSE
deb(DEB_OPEN, 'translateArcLogSeqRange');
OPEN translateArcLogSeqRange(thread# => thread#,
fromseq# => fromseq#,
toseq# => toseq#,
pattern => pattern,
statusMask => mask,
online => online,
needstby => needstby);
getArchivedLogCursor := 'translateArcLogSeqRange';
END IF;
getArchivedLogDuplicates := duplicates;
getArchivedLogNoRows.error := -20242;
getArchivedLogNoRows.msg := 'No archived logs in the range specified';
setTransClause(thread => thread#,
fromSeq => fromseq#,
toSeq => toseq#,
pattern => pattern);
deb(DEB_EXIT);
END translateArchivedLogSeqRange;
-- Translate an archived log time range
------------------------ translateArchivedLogTimeRange ------------------------
PROCEDURE translateArchivedLogTimeRange(
thread# IN number
,fromTime IN date
,toTime IN date
,pattern IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,online IN number -- ignored
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL -- for compatability
,needstby IN number DEFAULT NULL)
IS
mask number := NVL(statusMask,
computeAvailableMask(available, unavailable, deleted, 0));
BEGIN
deb(DEB_ENTER, 'translateArchivedLogTimeRange');
validateState(getArchivedLogCursor);
IF (bitand(mask,BSdeleted) != 0 AND pattern IS NULL) THEN
-- Use the cursor that also looks at backup redo logs.
-- The online parameter is assumed to be FALSE#. Available and
-- unavailable are ignored. Since we are looking at backup redo logs,
-- pattern cannot be implemented here, so we use this cursor only if
-- pattern is null.
deb(DEB_OPEN, 'translateArcLogTimeRange2');
OPEN translateArcLogTimeRange2(thread# => thread#,
fromTime => fromTime,
toTime => toTime,
needstby => needstby);
getArchivedLogCursor := 'translateArcLogTimeRange2';
ELSE
deb(DEB_OPEN, 'translateArcLogTimeRange');
OPEN translateArcLogTimeRange(thread# => thread#,
fromTime => fromTime,
toTime => toTime,
pattern => pattern,
statusMask => mask,
online => online,
needstby => needstby);
getArchivedLogCursor := 'translateArcLogTimeRange';
END IF;
getArchivedLogDuplicates := duplicates;
getArchivedLogNoRows.error := -20242;
getArchivedLogNoRows.msg := 'No archived logs in the range specified';
setTransClause(thread => thread#,
fromTime => fromTime,
toTime => toTime,
pattern => pattern);
deb(DEB_EXIT);
END translateArchivedLogTimeRange;
-- Translate an archived log scn range
------------------------- translateArchivedLogSCNRange ------------------------
PROCEDURE translateArchivedLogSCNRange(
thread# IN number
,fromSCN IN number
,toSCN IN number
,pattern IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,online IN number
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL -- for compatability
,needstby IN number DEFAULT NULL)
IS
adjusted_toSCN number;
mask number := NVL(statusMask,
computeAvailableMask(available, unavailable, deleted, 0));
BEGIN
deb(DEB_ENTER, 'translateArchivedLogSCNRange');
validateState(getArchivedLogCursor);
IF (untilTime IS NULL) THEN
-- Adjust the toSCN to take the until SCN into account. The untilSCN
-- was either specified directly by the user, or it was computed from
-- the until logseq. In either case, it is the exact SCN at which
-- recovery will stop.
adjusted_toSCN := least(toSCN, nvl(untilSCN, toSCN));
ELSE
-- Leave the toSCN alone. We cannot adjust the toSCN using
-- the untilSCN here because the until SCN was estimated by
-- computeUntilSCN(), and this procedure deliberately estimates the
-- SCN low. We cannot tolerate a low estimated SCN here because
-- then we might filter out a log that will be needed by recovery.
-- So instead, we pass the untilTime to the cursor.
adjusted_toSCN := toSCN;
END IF;
-- 8.1.6 and later always make sure that the toSCN is greater than the
-- fromSCN, but 8.1.5 and earlier will call us with fromSCN==toSCN.
-- The query will fail if they are equal, so make the toSCN greater than
-- the fromSCN. It is also possible that adjusting by the untilSCN above
-- made the fromSCN==toSCN.
IF (adjusted_toSCN <= fromSCN) THEN
adjusted_toSCN := fromSCN+1;
END IF;
IF (bitand(mask,BSdeleted) != 0 AND pattern IS NULL) THEN
-- Use the cursor that also looks at backup redo logs.
-- The online parameter is assumed to be TRUE#. Available and
-- unavailable are ignored. Since we are looking at backup redo logs,
-- pattern cannot be implemented here, so we use this cursor only if
-- pattern is null.
deb(DEB_OPEN, 'translateArcLogSCNRange2');
OPEN translateArcLogSCNRange2(thread# => thread#,
fromSCN => fromSCN,
toSCN => adjusted_toSCN,
toTime => untilTime,
needstby => needstby);
getArchivedLogCursor := 'translateArcLogSCNRange2';
deb(DEB_IN, ' using cursor 2 fromSCN=' ||
to_char(fromSCN) || ' toSCN=' || to_char(adjusted_toSCN));
ELSE
deb(DEB_OPEN, 'translateArcLogSCNRange');
OPEN translateArcLogSCNRange(thread# => thread#,
fromSCN => fromSCN,
toSCN => adjusted_toSCN,
pattern => pattern,
statusMask => mask,
online => online,
needstby => needstby);
getArchivedLogCursor := 'translateArcLogSCNRange';
END IF;
getArchivedLogDuplicates := duplicates;
getArchivedLogNoRows.error := -20242;
getArchivedLogNoRows.msg := 'No archived logs in the range specified';
setTransClause(thread => thread#,
fromSCN => fromSCN,
toSCN => adjusted_toSCN,
pattern => pattern);
deb(DEB_EXIT);
END translateArchivedLogSCNRange;
-- Translate an archived log name pattern
------------------------- translateArchivedLogPattern -------------------------
PROCEDURE translateArchivedLogPattern(
pattern IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,online IN number
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL -- for compatability
,needstby IN number DEFAULT NULL)
IS
mask number := NVL(statusMask,
computeAvailableMask(available, unavailable, deleted, 0));
BEGIN
deb(DEB_ENTER, 'translateArchivedLogPattern');
IF (bitand(mask,BSdeleted) != 0 AND pattern IS NULL) THEN
-- Use the cursor that also looks at union of brl and al tables.
-- This must be 'archivelog all'. From 8.1.6+, this condition
-- is checked in krmk.pc (krmkaltr()). Here, to maintain compatibility
-- with lower version of RMAN (8.1.5-) exec, we move the check here.
-- This removes us from doing 'compatible' check
translateArchivedLogSCNRange(
thread# => NULL,
fromscn => 0,
toscn => 281474976710655+1,
pattern => NULL,
statusMask => mask,
online => online,
duplicates => duplicates);
ELSE
validateState(getArchivedLogCursor);
deb(DEB_OPEN, 'translateArcLogPattern');
OPEN translateArcLogPattern(pattern => pattern,
statusMask => mask,
online => online);
getArchivedLogCursor := 'translateArcLogPattern';
getArchivedLogDuplicates := duplicates;
getArchivedLogNoRows.error := -20242;
getArchivedLogNoRows.msg := 'No archived logs in the range specified';
setTransClause(pattern => pattern);
END IF;
deb(DEB_EXIT);
END translateArchivedLogPattern;
-------------------------- translateArchivedLogCancel -------------------------
PROCEDURE translateArchivedLogCancel
IS
BEGIN
deb(DEB_ENTER, 'translateArchivedLogCancel');
IF (getArchivedLogCursor = 'translateArcLogKey') THEN
CLOSE translateArcLogKey;
ELSIF (getArchivedLogCursor = 'translateArcLogName') THEN
CLOSE translateArcLogName;
ELSIF (getArchivedLogCursor = 'translateArcLogSeqRange') THEN
CLOSE translateArcLogSeqRange;
ELSIF (getArchivedLogCursor = 'translateArcLogTimeRange') THEN
CLOSE translateArcLogTimeRange;
ELSIF (getArchivedLogCursor = 'translateArcLogSCNRange') THEN
CLOSE translateArcLogSCNRange;
ELSIF (getArchivedLogCursor = 'translateArcLogPattern') THEN
CLOSE translateArcLogPattern;
END IF;
getArchivedLogCursor := NULL; -- we closed it above
deb(DEB_EXIT);
END translateArchivedLogCancel;
-- This public procedure for 8.1.5 and previous releases. Recid will be
-- null to indicate end-of-fetch. That was a bad interface design, but
-- we are stuck with it now.
-------------------------------- getArchivedLog -------------------------------
PROCEDURE getArchivedLog(
recid OUT number
,stamp OUT number
,thread# OUT number
,sequence# OUT number
,low_scn OUT number
,nxt_scn OUT number
,fname OUT varchar2
,reset_scn OUT number
,block_size OUT number
,blocks OUT number)
IS
alRec alRec_t;
BEGIN
deb(DEB_ENTER, 'getArchivedLog');
<<retry>>
getArchivedLog(alRec);
-- Bug 1186598: From 8.1.5- Rman EXEC does union of brl and al tables,
-- when deleted=TRUE.
-- Getting a null recid shouldn't affect us.
-- Return OUT mode args
recid := nvl(alRec.recid,0); -- no null indicator before 8.1.6
stamp := nvl(alRec.stamp, 0); -- no null indicator before 8.1.6
thread# := alRec.thread;
sequence# := alRec.sequence;
low_scn := alRec.lowSCN;
nxt_scn := alRec.nextSCN;
fname := nvl(alRec.fileName, 'null'); -- no null indicator
reset_scn := alRec.rlgSCN;
block_size := alRec.blockSize;
blocks := alRec.blocks;
deb(DEB_EXIT);
EXCEPTION
WHEN no_data_found THEN
recid := NULL; -- indicate end-of-fetch
stamp := NULL;
deb(DEB_EXIT, 'with no more records');
END getArchivedLog;
---------------------------------
-- Controlfilecopy Translation --
---------------------------------
-- Translate a controlfilecopy name.
------------------------- translateControlFileCopyName ------------------------
PROCEDURE translateControlFileCopyName(
fname IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL) -- for compatability
IS
BEGIN
deb(DEB_ENTER, 'translateControlFileCopyName');
-- Replaces ccf_name
deb(DEB_OPEN, 'findControlfileCopy');
OPEN findControlfileCopy(pattern => fname,
currentIncarnation => FALSE#,
statusMask => NVL(statusMask,
computeAvailableMask(available,unavailable,0,0)));
-- Initialize singleRow variable
IF (duplicates = FALSE#) THEN
getControlFileCopySingleRow := TRUE;
ELSE
getControlFileCopySingleRow := FALSE;
END IF;
deb(DEB_EXIT);
END translateControlFileCopyName;
------------------------------ getControlFileCopy -----------------------------
PROCEDURE getControlFileCopy(
rcvRec IN OUT rcvRec_t)
IS
getControlFileCopyRowcount number;
BEGIN
deb(DEB_ENTER, 'getControlFileCopy');
IF (NOT findControlfileCopy%ISOPEN) THEN
deb(DEB_EXIT, 'with error 20204');
raise_application_error(-20204, 'Translation not started');
END IF;
<<nextRow>>
FETCH findControlfileCopy
INTO rcvRec;
IF (findControlfileCopy%NOTFOUND) THEN
-- Save rowcount before closing cursor
getControlFileCopyRowcount := findControlfileCopy%ROWCOUNT;
CLOSE findControlfileCopy;
IF (getControlFileCopyRowcount = 0) THEN
deb(DEB_EXIT, 'with error 20220');
raise_application_error(-20220, 'Controlfile copy does not exist');
ELSE
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found; -- signal end-of-fetch
END IF;
END IF;
IF (getControlFileCopySingleRow = TRUE AND
findControlfileCopy%ROWCOUNT > 1) THEN
-- We only want a single row, and we've already returned 1 row, so
-- just treat this as end-of-fetch
CLOSE findControlfileCopy;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
deb(DEB_EXIT);
END getControlFileCopy;
-- Obsolete as of 8.1.6
------------------------------ getControlFileCopy -----------------------------
PROCEDURE getControlFileCopy(
recid OUT number
,stamp OUT number
,reset_scn OUT number
,ckp_scn OUT number
,block_size OUT number)
IS
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'getControlFileCopy');
getControlFileCopy(rcvRec);
recid := rcvRec.recid_con;
stamp := rcvRec.stamp_con;
reset_scn := rcvRec.rlgSCN_act;
ckp_scn := rcvRec.toSCN_act;
block_size := rcvRec.blockSize_con;
deb(DEB_EXIT);
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with no more records');
-- This just means end-of-fetch
recid := NULL; -- signal end-of-fetch to caller
END getControlFileCopy;
------------------------------
-- Datafilecopy Translation --
------------------------------
------------------------------- getDataFileCopy -------------------------------
PROCEDURE getDataFileCopy(
rcvRec OUT rcvRec_t
,closeCursor IN boolean DEFAULT FALSE)
IS
getDataFileCopyRowcount number;
local rcvRec_t;
BEGIN
deb(DEB_ENTER, 'getDataFileCopy');
<<nextRow>>
IF (getDatafileCopyCursor = 'findDatafileCopyKey') THEN
FETCH findDatafileCopyKey
INTO local;
IF (findDatafileCopyKey%NOTFOUND) THEN
getDataFileCopyRowcount := findDatafileCopyKey%ROWCOUNT;
CLOSE findDatafileCopyKey;
END IF;
IF (closeCursor AND findDatafileCopyKey%ISOPEN) THEN
CLOSE findDatafileCopyKey;
END IF;
ELSIF (getDatafileCopyCursor = 'findDatafileBackup_c') THEN
IF (getDataFileCopySingleRow = TRUE AND
findDatafileBackup_c%ROWCOUNT > 1) THEN
-- We only want a single row, and we've already returned 1 row, so
-- just treat this as end-of-fetch
CLOSE findDatafileBackup_c;
getDatafileCopyCursor := NULL;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
FETCH findDatafileBackup_c
INTO local;
IF (findDatafileBackup_c%NOTFOUND) THEN
getDataFileCopyRowcount := findDatafileBackup_c%ROWCOUNT;
CLOSE findDatafileBackup_c;
END IF;
IF (closeCursor AND findDatafileBackup_c%ISOPEN) THEN
CLOSE findDatafileBackup_c;
END IF;
ELSE
deb(DEB_EXIT, 'with error 20204');
raise_application_error(-20204, 'Translation not started');
END IF;
IF (closeCursor) THEN
getDatafileCopyCursor := NULL;
END IF;
IF (getDataFileCopyRowcount IS NOT NULL) THEN
getDatafileCopyCursor := NULL;
IF (getDataFileCopyRowcount = 0 AND
getDatafileCopyNoRows.error IS NOT NULL) THEN
deb(DEB_EXIT, 'with norows error');
raise_application_error(getDatafileCopyNoRows.error,
getDatafileCopyNoRows.msg);
ELSE
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found; -- signal end-of-fetch
END IF;
END IF;
IF (getDataFileCopyDuplicates = FALSE# AND
getDataFileCopyLast.dfNumber_obj = local.dfNumber_obj) THEN
GOTO nextRow;
END IF;
getDataFileCopyLast := local; -- save for duplicate filtering
rcvRec := local; -- set OUT mode arg
deb(DEB_EXIT);
END getDataFileCopy;
--------------------------- translateDataFileCopyKey --------------------------
PROCEDURE translateDataFileCopyKey(
cdf_key IN number
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL) -- for compatability
IS
BEGIN
deb(DEB_ENTER, 'translateDataFileCopyKey');
validateState(getDatafileCopyCursor);
-- Replaces cursor that used to be in translateDataFileCopyKey
deb(DEB_OPEN, 'findDataFileCopyKey');
OPEN findDataFileCopyKey(copyKey => cdf_key,
statusMask => NVL(statusMask,
computeAvailableMask(available, unavailable,
0, 0)));
getDatafileCopyCursor := 'findDatafileCopyKey';
getDataFileCopyNoRows.error := -20230;
getDataFileCopyNoRows.msg := 'Datafile copy does not exist';
getDataFileCopyDuplicates := NULL;
getDataFileCopySingleRow := NULL;
deb(DEB_EXIT);
END translateDatafileCopyKey;
-- Obsolete as of 8.1.6
--------------------------- translateDataFileCopyKey --------------------------
PROCEDURE translateDataFileCopyKey(
cdf_key IN number
,available IN number
,unavailable IN number
,recid OUT number
,stamp OUT number
,file# OUT number
,fname OUT varchar2
,reset_scn OUT number
,create_scn OUT number
,ckp_scn OUT number
,block_size OUT number
,blocks OUT number)
IS
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'translateDataFileCopyKey815');
translateDataFileCopyKey(cdf_key => cdf_key,
available => available,
unavailable => unavailable);
getDataFileCopy(rcvRec => rcvRec,
closeCursor => TRUE);
recid := rcvRec.recid_con;
stamp := rcvRec.stamp_con;
file# := rcvRec.dfNumber_obj;
fname := rcvRec.fileName_con;
reset_scn := rcvRec.rlgSCN_act;
create_scn := rcvRec.dfCreationSCN_obj;
ckp_scn := rcvRec.toSCN_act;
block_size := rcvRec.blockSize_con;
blocks := rcvRec.blocks_con;
deb(DEB_EXIT);
END translateDataFileCopyKey;
-- Translate a datafilecopy name. The datafile copies are ordered by
-- stamp in order to return most recently created copy first, because it
-- most likely to exist. Note that datafilecopies that belong to any
-- incarnation of the current database are returned.
-------------------------- translateDatafileCopyName --------------------------
PROCEDURE translateDatafileCopyName(
fname IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL) -- for compatability
IS
BEGIN
deb(DEB_ENTER, 'translateDatafileCopyName');
validateState(getDatafileCopyCursor);
-- Replaces cdf_name
deb(DEB_OPEN, 'findDatafileCopy');
OPEN findDatafileBackup_c(
sourcemask => imageCopy_con_t,
pattern => fname,
statusMask => nvl(statusMask,
computeAvailableMask(available,
unavailable,
0, 0))
);
getDatafileCopyCursor := 'findDatafileBackup_c';
getDatafileCopyNoRows.error := -20230;
getDatafileCopyNoRows.msg := 'Datafile copy does not exist';
getDatafileCopyDuplicates := duplicates;
getDatafileCopyLast.dfNumber_obj := NULL;
IF (duplicates = FALSE#) THEN
getDatafileCopySingleRow := TRUE;
ELSE
getDatafileCopySingleRow := FALSE;
END IF;
deb(DEB_EXIT);
END translateDatafileCopyName;
-- Translate a datafilecopy tag. The datafilecopies are ordered by file#
-- in order to make the duplicate elimination work and by descending
-- checkpoint scn to return most recent copy first.
-- ### only copies that belong to current database incarnation are returned,
-- We should change this in future to return datafile copies that belong
-- previous incarnations of the database. The difficulty is that the recovery
-- catalog may also contain datafile copies that belong to "orphaned"
-- incarnation of the database.
--------------------------- translateDataFileCopyTag --------------------------
PROCEDURE translateDataFileCopyTag(
tag IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL) -- for compatability
IS
BEGIN
deb(DEB_ENTER, 'translateDataFileCopyTag');
validateState(getDatafileCopyCursor);
-- Replaces cdf_tag. Note that we look only for ones in the current
-- incarnation because that is what cdf_tag did. If access to
-- datafilecopies in other incarnations is required, it must be done by
-- key or filename.
deb(DEB_OPEN, 'findDataFileBackup_c');
OPEN findDatafileBackup_c(
sourcemask => imageCopy_con_t,
tag => tag,
reset_scn => this_reset_scn,
reset_time => this_reset_time,
statusMask => nvl(statusMask,
computeAvailableMask(available,
unavailable,
0, 0))
);
getDatafileCopyCursor := 'findDatafileBackup_c';
getDataFileCopyNoRows.error := -20232;
getDataFileCopyNoRows.msg := 'Datafile copy tag does not match';
getDataFileCopyDuplicates := duplicates;
getDataFileCopyLast.dfNumber_obj := NULL;
getDataFileCopySingleRow := FALSE;
deb(DEB_EXIT);
END translateDataFileCopyTag;
-- Translate a datafilecopy file number. The datafile copies are ordered by
-- stamp in order to return most recently created copy first, because it
-- most likely to exist. Note that datafilecopies that belong to any
-- incarnation of the current database are returned.
-------------------------- translateDatafileCopyFno --------------------------
PROCEDURE translateDatafileCopyFno(
fno IN number
,available IN number DEFAULT NULL
,unavailable IN number DEFAULT NULL
,duplicates IN number
,statusMask IN binary_integer DEFAULT NULL)
IS
BEGIN
deb(DEB_ENTER, 'translateDatafileCopyFno');
validateState(getDatafileCopyCursor);
deb(DEB_OPEN, 'findDatafileBackup_c');
OPEN findDatafileBackup_c(
sourcemask => imageCopy_con_t,
fno => fno,
statusMask => NVL(statusMask,
computeAvailableMask(available,
unavailable,
0, 0))
);
getDatafileCopyCursor := 'findDatafileBackup_c';
getDatafileCopyNoRows.error := -20230;
getDatafileCopyNoRows.msg := 'Datafile copy does not exist';
getDatafileCopyDuplicates := duplicates;
getDatafileCopyLast.dfNumber_obj := NULL;
IF (duplicates = FALSE#) THEN
getDatafileCopySingleRow := TRUE;
ELSE
getDatafileCopySingleRow := FALSE;
END IF;
deb(DEB_EXIT);
END translateDatafileCopyFno;
-- Obsolete as of 8.1.6
------------------------------- getDataFileCopy -------------------------------
PROCEDURE getDataFileCopy(
recid OUT number
,stamp OUT number
,file# OUT number
,fname OUT varchar2
,reset_scn OUT number
,create_scn OUT number
,ckp_scn OUT number
,block_size OUT number
,blocks OUT number)
IS
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'getDataFileCopy');
getDataFileCopy(rcvRec);
recid := rcvRec.recid_con;
stamp := rcvRec.stamp_con;
file# := rcvRec.dfNumber_obj;
fname := rcvRec.fileName_con;
reset_scn := rcvRec.rlgSCN_act;
create_scn := rcvRec.dfCreationSCN_obj;
ckp_scn := rcvRec.toSCN_act;
block_size := rcvRec.blockSize_con;
blocks := rcvRec.blocks_con;
deb(DEB_EXIT);
EXCEPTION
WHEN no_data_found THEN
recid := NULL; -- signal end-of-fetch to client
deb(DEB_EXIT, 'with no more records');
END getDataFileCopy;
----------------------------
-- Proxy Copy Translation --
----------------------------
--------------------------------- getProxyCopy --------------------------------
PROCEDURE getProxyCopy(
rcvRec OUT rcvRec_t
,closeCursor IN boolean DEFAULT FALSE)
IS
getProxyCopyRowcount number;
dummy rcvRec_t;
BEGIN
deb(DEB_ENTER, 'getProxyCopy');
IF (getProxyCopyCursor = 'findProxyCopy') THEN
FETCH findProxyCopy
INTO rcvRec;
IF (findProxyCopy%NOTFOUND) THEN
getProxyCopyRowcount := findProxyCopy%ROWCOUNT;
CLOSE findProxyCopy;
ELSE
IF (getProxyCopyByHandle) THEN
-- Make sure there is only 1 row
FETCH findProxyCopy
INTO dummy;
IF (NOT findProxyCopy%NOTFOUND) THEN
CLOSE findProxyCopy;
deb(DEB_EXIT, 'with error 20311');
raise_application_error(-20311, 'Ambiguous proxy copy handle');
END IF;
END IF;
END IF;
IF (closeCursor AND findProxyCopy%ISOPEN) THEN
CLOSE findProxyCopy;
END IF;
ELSIF (getProxyCopyCursor = 'findProxyCopyKey') THEN
FETCH findProxyCopyKey
INTO rcvRec;
IF (findProxyCopyKey%NOTFOUND) THEN
getProxyCopyRowcount := findProxyCopyKey%ROWCOUNT;
CLOSE findProxyCopyKey;
END IF;
IF (closeCursor AND findProxyCopyKey%ISOPEN) THEN
CLOSE findProxyCopyKey;
END IF;
ELSE
deb(DEB_EXIT, 'with errors 20204');
raise_application_error(-20204, 'Translation not started');
END IF;
IF (closeCursor) THEN
getProxyCopyCursor := NULL;
END IF;
IF (getProxyCopyRowcount IS NOT NULL) THEN
getProxyCopyCursor := NULL;
IF (getProxyCopyRowcount = 0 AND
getProxyCopyNoRows.error IS NOT NULL) THEN
deb(DEB_EXIT, 'with norows error');
raise_application_error(getProxyCopyNoRows.error,
getProxyCopyNoRows.msg);
ELSE
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found; -- signal end-of-fetch
END IF;
END IF;
deb(DEB_EXIT);
END getProxyCopy;
---------------------------- translateProxyCopyKey ----------------------------
PROCEDURE translateProxyCopyKey(
pc_key IN number
,deviceType IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,expired IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL) -- for compatability
IS
BEGIN
deb(DEB_ENTER, 'translateProxyCopyKey');
validateState(getProxyCopyCursor);
deb(DEB_OPEN, 'findProxyCopyKey');
OPEN findProxyCopyKey(key => pc_key,
deviceType => deviceType,
statusMask => NVL(statusMask,
computeAvailableMask(available, unavailable, deleted,
expired)));
getProxyCopyCursor := 'findProxyCopyKey';
getProxyCopyNoRows.error := -20310;
getProxyCopyNoRows.msg := 'proxy copy is missing';
getProxyCopyByHandle := FALSE;
deb(DEB_EXIT);
END translateProxyCopyKey;
-- Obsolete as of 8.1.6
---------------------------- translateProxyCopyKey ----------------------------
PROCEDURE translateProxyCopyKey(
pc_key IN number
,device_type IN varchar2
,available IN number
,unavailable IN number
,deleted IN number
,recid OUT number
,stamp OUT number
,handle OUT varchar2)
IS
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'translateProxyCopyKey815');
translateProxyCopyKey(pc_key => pc_key,
deviceType => device_type,
available => available,
unavailable => unavailable,
deleted => deleted,
expired => unavailable);
getProxyCopy(rcvRec => rcvRec,
closeCursor => TRUE);
recid := rcvRec.recid_con;
stamp := rcvRec.stamp_con;
handle := rcvRec.fileName_con;
deb(DEB_EXIT);
END translateProxyCopyKey;
--------------------------- translateProxyCopyHandle --------------------------
PROCEDURE translateProxyCopyHandle(
handle IN varchar2
,deviceType IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,expired IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL) -- for compatability
IS
BEGIN
deb(DEB_ENTER, 'translateProxyCopyHandle');
validateState(getProxyCopyCursor);
deb(DEB_OPEN, 'findProxyCopy');
OPEN findProxyCopy(handle => handle,
deviceType => deviceType,
statusMask => NVL(statusMask,
computeAvailableMask(available, unavailable, deleted,
expired)));
getProxyCopyCursor := 'findProxyCopy';
getProxyCopyNoRows.error := -20310;
getProxyCopyNoRows.msg := 'proxy copy is missing';
getProxyCopyByHandle := TRUE;
deb(DEB_EXIT);
END translateProxyCopyHandle;
-- Obsolete as of 8.1.6
--------------------------- translateProxyCopyHandle --------------------------
PROCEDURE translateProxyCopyHandle(
handle IN varchar2
,device_type IN varchar2
,available IN number
,unavailable IN number
,deleted IN number
,recid OUT number
,stamp OUT number)
IS
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'translateProxyCopyHandle815');
translateProxyCopyHandle(handle => handle,
deviceType => device_type,
available => available,
unavailable => unavailable,
deleted => deleted,
expired => unavailable);
getProxyCopy(rcvRec => rcvRec,
closeCursor => TRUE);
recid := rcvRec.recid_con;
stamp := rcvRec.stamp_con;
deb(DEB_EXIT);
END translateProxyCopyHandle;
-- Translate a proxy copy tag into a list of proxy copies
---------------------------- translateProxyCopyTag ----------------------------
PROCEDURE translateProxyCopyTag(
tag IN varchar2
,device_type IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,deleted IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL) -- for compatability
IS
BEGIN
deb(DEB_ENTER, 'translateProxyCopyTag');
validateState(getProxyCopyCursor);
deb(DEB_OPEN, 'findProxyCopy');
OPEN findProxyCopy(tag => tag,
deviceType => device_type,
statusMask => NVL(statusMask,
computeAvailableMask(available, unavailable, deleted,
unavailable/*expired*/)));
getProxyCopyCursor := 'findProxyCopy';
getProxyCopyNoRows.error := -20310;
getProxyCopyNoRows.msg := 'no matching proxy copy found';
getProxyCopyByHandle := FALSE;
deb(DEB_EXIT);
END translateProxyCopyTag;
-- Obsolete as of 8.1.6
--------------------------------- getProxyCopy --------------------------------
PROCEDURE getProxyCopy(
recid OUT number
,stamp OUT number
,handle OUT varchar2)
IS
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'getProxyCopyHandle');
getProxyCopy(rcvRec);
recid := rcvRec.recid_con;
stamp := rcvRec.stamp_con;
handle := rcvRec.fileName_con;
deb(DEB_EXIT);
EXCEPTION
WHEN no_data_found THEN
recid := NULL; -- indicate end-of-fetch
deb(DEB_EXIT, 'with no more records');
END getProxyCopy;
------------------------------
-- Backup Piece Translation --
------------------------------
-------------------------------- getBackupPiece -------------------------------
PROCEDURE getBackupPiece(
bpRec OUT bpRec_t
,closeCursor IN boolean DEFAULT FALSE)
IS
dummy bpRec_t;
local bpRec_t;
eof boolean := FALSE;
BEGIN
deb(DEB_ENTER, 'getBackupPiece');
IF (getBackupPieceDuplicates = FALSE# AND
getBackupPieceDeviceType IS NULL) THEN
-- If duplicate filtering is requested, it means only 1 copy of each
-- piece is wanted. The deviceType must be specified in this case.
-- If not, then raise an exception.
deb(DEB_EXIT, 'with error 20000');
raise_application_error(-20000, 'deviceType must be specified');
END IF;
<<nextRow>>
IF (getBackupPieceCursor = 'findBackupPieceBpKey') THEN
FETCH findBackupPieceBpKey
INTO local;
IF (findBackupPieceBpKey%NOTFOUND) THEN
eof := TRUE;
CLOSE findBackupPieceBpKey;
END IF;
IF (closeCursor AND findBackupPieceBpKey%ISOPEN) THEN
CLOSE findBackupPieceBpKey;
END IF;
ELSIF (getBackupPieceCursor = 'findBackupPieceBsKey') THEN
FETCH findBackupPieceBsKey
INTO local;
IF (findBackupPieceBsKey%NOTFOUND) THEN
eof := TRUE;
CLOSE findBackupPieceBsKey;
END IF;
IF (closeCursor AND findBackupPieceBsKey%ISOPEN) THEN
CLOSE findBackupPieceBsKey;
END IF;
ELSIF (getBackupPieceCursor = 'findBackupPiece_c') THEN
FETCH findBackupPiece_c
INTO local;
IF (findBackupPiece_c%NOTFOUND) THEN
eof := TRUE;
CLOSE findBackupPiece_c;
ELSE
IF (getBackupPieceByHandle) THEN
-- Make sure we can only fetch 1 row.
FETCH findBackupPiece_c
INTO dummy;
IF (NOT findBackupPiece_c%NOTFOUND) THEN
CLOSE findBackupPiece_c;
deb(DEB_EXIT, 'with error 20261');
raise_application_error(-20261, 'Ambiguous backup piece handle');
END IF;
END IF;
END IF;
IF (closeCursor AND findBackupPiece_c%ISOPEN) THEN
CLOSE findBackupPiece_c;
END IF;
ELSE
deb(DEB_EXIT, 'with error 20204');
raise_application_error(-20204, 'Translation not started');
END IF;
IF (closeCursor OR eof) THEN
getBackupPieceCursor := NULL;
END IF;
IF (eof) THEN -- if end of fetch
-- If we've been requested to check that all pieces of the set
-- have been found, then perform the check.
IF (getBackupPieceDuplicates = FALSE#) THEN
-- We don't want duplicates, which means duplicate filtering is
-- in effect. We already asserted above that a deviceType has
-- been specified, so we know filtering is possible.
IF (getBackupPieceExpectedPieces IS NOT NULL AND
(getBackupPieceAvailableMask IS NULL OR
bitand(getBackupPieceAvailableMask,
dbms_rcvman.BSpartial_avail) = 0) AND
getBackupPieceExpectedPieces <> getBackupPiecePieceCount) THEN
deb(DEB_EXIT, 'with error 20216');
raise_application_error(-20216, 'Backup piece is missing');
END IF;
END IF;
IF (getBackupPiecePieceCount = 0 AND
getBackupPieceNoRows.error IS NOT NULL) THEN
deb(DEB_EXIT, 'with norows error');
raise_application_error(getBackupPieceNoRows.error,
getBackupPieceNoRows.msg);
ELSE
deb(DEB_EXIT, 'no more records');
RAISE no_data_found;
END IF;
END IF;
IF (getBackupPieceDuplicates = FALSE#) THEN
-- Client does not want duplicates, so lets filter out duplicate
-- pieces.
IF (local.pieceNumber = getBackupPieceLast.pieceNumber) THEN
-- This is a duplicate piece
GOTO nextRow;
END IF;
END IF;
getBackupPieceLast := local;
bpRec := local; -- set OUT mode arg
getBackupPiecePieceCount := getBackupPiecePieceCount + 1;
deb(DEB_EXIT);
END getBackupPiece;
--------------------------- translateBackupPieceKey ---------------------------
PROCEDURE translateBackupPieceKey(
key IN number
,available IN number DEFAULT TRUE#
,unavailable IN number DEFAULT TRUE#
,expired IN number DEFAULT TRUE#
,statusMask IN binary_integer DEFAULT NULL) -- for compatability
IS
BEGIN
-- Open cursor to lookup bp by primary key. Treat expired backup pieces
-- as if they were unavailable. We do this only because the interface
-- to translateBackupPieceKey was not enhanced to have an "expired"
-- argument when status 'X' was introduced.
-- Replaces the cursor that was in the 8.1.x translateBackupPieceKey.
deb(DEB_ENTER, 'translateBackupPieceKey');
findBackupPiece(bpKey => key,
statusMask => NVL(statusMask,
computeAvailableMask(available, unavailable, 0, unavailable)));
getBackupPieceNoRows.error := -20260;
getBackupPieceNoRows.msg := 'Backup piece is missing';
getBackupPieceAvailableMask := statusMask;
deb(DEB_EXIT);
END translateBackupPieceKey;
--------------------------- translateBackupPieceKey ---------------------------
PROCEDURE translateBackupPieceKey(
bp_key IN number
,available IN number
,unavailable IN number
,recid OUT number
,stamp OUT number
,handle OUT varchar2
,set_stamp OUT number
,set_count OUT number
,piece# OUT number)
IS
bpRec bpRec_t;
BEGIN
deb(DEB_ENTER, 'translateBackupPieceKey');
-- Open cursor to lookup bp by primary key. Treat expired backup pieces
-- as if they were unavailable. We do this only because the interface
-- to translateBackupPieceKey was not enhanced to have an "expired"
-- argument when status 'X' was introduced. It should have been enhanced
-- to have one, but since it was not, we have to assume the most
-- reasonable default value.
-- Replaces the cursor that was in the 8.1.x translateBackupPieceKey.
translateBackupPieceKey(key => bp_key,
statusMask =>
computeAvailableMask(available, unavailable, 0,
unavailable/*expired*/));
getBackupPiece(bpRec => bpRec,
closeCursor => TRUE);
recid := bpRec.recid;
stamp := bpRec.stamp;
handle := bpRec.handle;
set_stamp := bpRec.setStamp;
set_count := bpRec.setCount;
piece# := bpRec.pieceNumber;
deb(DEB_EXIT);
END translateBackupPieceKey;
-------------------------- translateBackupPieceHandle -------------------------
PROCEDURE translateBackupPieceHandle(
handle IN varchar2
,deviceType IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,expired IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL) -- for compatability
IS
BEGIN
deb(DEB_ENTER, 'translateBackupPieceHandle');
findBackupPiece(handle => handle,
deviceType => deviceType,
statusMask => NVL(statusMask,
computeAvailableMask(available, unavailable, 0, expired)));
getBackupPieceNoRows.error := -20260;
getBackupPieceNoRows.msg := 'Backup piece is missing';
getBackupPieceByHandle := TRUE;
getBackupPieceAvailableMask := statusMask;
deb(DEB_EXIT);
END translateBackupPieceHandle;
-------------------------- translateBackupPieceHandle -------------------------
PROCEDURE translateBackupPieceHandle( -- only used in 8.1.6
handle IN varchar2
,device_type IN varchar2
,available IN number
,unavailable IN number
,recid OUT number
,stamp OUT number
,set_stamp OUT number
,set_count OUT number
,piece# OUT number)
IS
bpRec bpRec_t;
BEGIN
deb(DEB_ENTER, 'translateBackupPieceHandle816');
translateBackupPieceHandle(handle => handle,
deviceType => device_type,
statusMask =>
computeAvailableMask(available, unavailable, 0,
unavailable/*expired*/));
getBackupPiece(bpRec => bpRec,
closeCursor => TRUE);
recid := bpRec.recid;
stamp := bpRec.stamp;
set_stamp := bpRec.setStamp;
set_count := bpRec.setCount;
piece# := bpRec.pieceNumber;
deb(DEB_EXIT);
END translateBackupPieceHandle;
-- Translate a backup piece tag into a list of backup pieces
--------------------------- translateBackupPieceTag ---------------------------
PROCEDURE translateBackupPieceTag(
tag IN varchar2
,available IN number DEFAULT NULL -- for compatability
,unavailable IN number DEFAULT NULL -- for compatability
,statusMask IN binary_integer DEFAULT NULL)
IS
BEGIN
deb(DEB_ENTER, 'translateBackupPieceTag');
findBackupPiece(tag => tag,
statusMask => NVL(statusMask,
computeAvailableMask(available, unavailable, 0,
/* expired = */unavailable)));
deb(DEB_EXIT);
END translateBackupPieceTag;
-------------------------- translateBackupPieceBSKey --------------------------
PROCEDURE translateBackupPieceBSKey(
key IN number
,tag IN varchar2 DEFAULT NULL
,deviceType IN varchar2 DEFAULT NULL
,pieceCount IN number
,duplicates IN number DEFAULT TRUE#
,copyNumber IN number DEFAULT NULL
,available IN number DEFAULT TRUE#
,unavailable IN number DEFAULT FALSE#
,deleted IN number DEFAULT FALSE#
,expired IN number DEFAULT FALSE#
,statusMask IN binary_integer DEFAULT NULL)
IS
BEGIN
deb(DEB_ENTER, 'translateBackupPieceBSKey');
findBackupPiece(bsKey => key,
tag => tag,
deviceType => deviceType,
copyNumber => copyNumber,
statusMask => NVL(statusMask,
computeAvailableMask(available, unavailable, deleted, expired)));
getBackupPieceDuplicates := duplicates;
getBackupPieceExpectedPieces := pieceCount;
getBackupPieceAvailableMask := statusMask;
deb(DEB_EXIT);
END translateBackupPieceBSKey;
-- Obsolete as of 8.1.6
---------------------------- translateBackupSetKey ----------------------------
PROCEDURE translateBackupSetKey(
bs_key IN number
,device_type IN varchar2
,available IN number
,unavailable IN number
,deleted IN number
,duplicates IN number
,backup_type OUT varchar2
,recid OUT number
,stamp OUT number
,set_stamp OUT number
,set_count OUT number
,bslevel OUT number
,completion_time OUT date)
IS
bsRec bsRec_t;
BEGIN
deb(DEB_ENTER, 'translateBackupSetKey815');
findBackupSet(bsKey => bs_key, -- Lookup backset by key
bsRec => bsRec);
backup_type := bsRec.bsType;
recid := bsRec.recid;
stamp := bsRec.stamp;
set_stamp := bsRec.setStamp;
set_count := bsRec.setCount;
bslevel := bsRec.level;
completion_time := bsRec.compTime;
-- Open cursor to lookup bp by backup set key. Treat expired pieces
-- as if they were unavailable. We do this only because the interface
-- to translateBackupSetKey was not enhanced to have an "expired"
-- argument when status 'X' was introduced. It should have been enhanced
-- to have one, but since it was not, we have to assume the most
-- reasonable default value.
-- Replaces bsq1
translateBackupPieceBSKey(key => bs_key,
deviceType => device_type,
pieceCount => bsRec.pieceCount,
available => available,
unavailable => unavailable,
deleted => deleted,
expired => unavailable);
getBackupPieceDuplicates := duplicates;
IF (device_type IS NULL) THEN
-- The pre-8.1.6 RMAN is broken. When doing a LIST (surprise surprise)
-- it calls this routine with device_type NULL, but the duplicates
-- flag is FALSE# (don't want duplicates). This makes no sense because
-- we can do duplicate filtering only when a device type is specified.
-- The old version of this package tolerated this client behaviour, but
-- this version is more strict and will raise an exception. So to avoid
-- getting an exception when the old RMAN is calling us, set the
-- duplicates flag to TRUE#. This package will then behave the same
-- as the old one.
getBackupPieceDuplicates := TRUE#; -- yes, we want duplicates
END IF;
IF (getBackupPieceDuplicates = FALSE#) THEN
-- If we don't want duplicate pieces, then we are probably planning
-- to access the backup set, so tell getBackupPiece to perform the
-- missing piece check.
getBackupPieceExpectedPieces := bsRec.pieceCount;
END IF;
deb(DEB_EXIT);
END translateBackupSetKey;
-- Obsolete as of 8.1
---------------------------- translateBackupSetKey ----------------------------
PROCEDURE translateBackupSetKey(
bs_key IN number
,device_type IN varchar2
,available IN number
,unavailable IN number
,deleted IN number
,duplicates IN number
,backup_type OUT varchar2
,recid OUT number
,stamp OUT number)
IS
set_stamp number;
set_count number;
bslevel number;
completion_time date;
BEGIN
deb(DEB_ENTER, 'translateBackupSetKey80');
translateBackupSetKey(bs_key, device_type, available, unavailable, deleted,
duplicates, backup_type, recid, stamp, set_stamp,
set_count, bslevel, completion_time);
deb(DEB_EXIT);
END translateBackupSetKey;
-- Obsolete as of 8.1.6
--------------------------- translateBackupSetRecid ---------------------------
PROCEDURE translateBackupSetRecid(
recid IN number
,stamp IN number
,device_type IN varchar2
,bs_key OUT number
,bslevel OUT number
,completed OUT date)
IS
bsRec bsRec_t;
pieceCount number;
validationRec validBackupSetRec_t;
gotRecord number;
duplicates_flag number;
BEGIN
deb(DEB_ENTER, 'translateBackupSetRecid815');
findBackupSet(recid => recid,
stamp => stamp,
bsRec => bsRec);
bs_key := bsRec.key;
bslevel := bsRec.level;
completed := bsRec.compTime;
-- See if all pieces are available from the same copy#. We already
-- know that the backupset is valid because we wouldn't be here
-- otherwise.
-- NOTE: device_type is null if doing REPORT OBSOLETE
findValidBackupSet(backupSetRec => bsRec,
tag => restoreTag,
deviceType => device_type,
available => TRUE#);
gotRecord := getValidBackupSet(validBackupSetRec => validationRec);
IF (getValidBackupSetCursor = 'findValidBackupSet_c') THEN
CLOSE findValidBackupSet_c;
ELSIF (getValidBackupSetCursor = 'findValidBackupSet1P_c') THEN
CLOSE findValidBackupSet1P_c;
END IF;
IF (gotRecord = FALSE#) THEN
-- Allow a mix of copy#s. It is probably the case that a backup piece
-- is missing and getBackupPiece will raise that error. I don't
-- know how we could have gotten here in that case, but getBackupPiece
-- will do the right thing.
validationRec.copyNumber := NULL;
END IF;
IF (device_type IS NULL) THEN
-- This is the REPORT OBSOLETE case
duplicates_flag := TRUE#;
ELSE
-- This is the normal case (restore/recover)
duplicates_flag := FALSE#;
END IF;
translateBackupPieceBSKey(key => bsRec.key,
tag => validationRec.tag,
deviceType => device_type,
pieceCount => bsRec.pieceCount,
duplicates => duplicates_flag,
copyNumber => validationRec.copyNumber,
available => TRUE#);
deb(DEB_EXIT);
END translateBackupSetRecid;
-- Obsolete as of 8.1
--------------------------- translateBackupSetRecid ---------------------------
PROCEDURE translateBackupSetRecid(
recid IN number
,stamp IN number
,device_type IN varchar2)
IS
bs_key number;
bslevel number;
completed date;
BEGIN
deb(DEB_ENTER, 'translateBackupSetRecid80');
translateBackupSetRecid(recid, stamp, device_type, bs_key, bslevel,
completed);
deb(DEB_EXIT);
END translateBackupSetRecid;
-- Obsolete as of 8.1.6
-------------------------------- getBackupPiece -------------------------------
PROCEDURE getBackupPiece(
recid OUT number
,stamp OUT number
,bpkey OUT number
,set_stamp OUT number
,set_count OUT number
,piece# OUT number
,copy# OUT number
,status OUT varchar2
,completion OUT date
,handle OUT varchar2)
IS
bpRec bpRec_t;
BEGIN
deb(DEB_ENTER, 'getBackupPiece815');
getBackupPiece(bpRec);
recid := bpRec.recid;
stamp := bpRec.stamp;
bpkey := bpRec.key;
set_stamp := bpRec.setStamp;
set_count := bpRec.setCount;
piece# := bpRec.pieceNumber;
copy# := bpRec.copyNumber;
status := bpRec.status;
completion := bpRec.compTime;
handle := bpRec.handle;
deb(DEB_EXIT);
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with no more records');
bpRec.recid := NULL; -- indicate end-of-fetch to client
END getBackupPiece;
-- Obsolete as of 8.1
-------------------------------- getBackupPiece -------------------------------
PROCEDURE getBackupPiece(
recid OUT number
,stamp OUT number
,set_stamp OUT number
,set_count OUT number
,piece# OUT number
,handle OUT varchar2)
IS
bpRec bpRec_t;
BEGIN
deb(DEB_ENTER, 'getBackupPiece80');
getBackupPiece(bpRec);
recid := bpRec.recid;
stamp := bpRec.stamp;
set_stamp := bpRec.setStamp;
set_count := bpRec.setCount;
piece# := bpRec.pieceNumber;
handle := bpRec.handle;
deb(DEB_EXIT);
EXCEPTION
WHEN no_data_found THEN
bpRec.recid := NULL; -- indicate end-of-fetch to client
deb(DEB_EXIT, 'with no more records');
END getBackupPiece;
----------------------------
-- Backup Set Translation --
----------------------------
---------------------------- translateBackupSetKey ----------------------------
PROCEDURE translateBackupSetKey(
key IN number
,bsRec OUT bsRec_t)
IS
BEGIN
deb(DEB_ENTER, 'translateBackupSetKey');
findBackupSet(bsKey => key,
bsRec => bsRec);
deb(DEB_EXIT);
END translateBackupSetKey;
------------------------
-- Controlfile Backup --
------------------------
----------------------------- getControlfileBackup ----------------------------
FUNCTION getControlfileBackup(
rcvRec OUT rcvRec_t)
RETURN number IS
found boolean := FALSE;
ccfrec rcvRec_t;
bcfrec rcvRec_t;
xcfrec rcvRec_t;
tag bp.tag%TYPE;
val_rc binary_integer;
rcvRecCursor rcvRecCursor_t;
validateRec validBackupSetRec_t;
BEGIN
deb(DEB_ENTER, 'getControlfileBackup');
validateState(null);
ccfrec.toSCN_act := 0;
bcfrec.toSCN_act := 0;
xcfrec.toSCN_act := 0;
IF (restoreSource = COPY OR restoreSource IS NULL) THEN
-- Replaces ccfq
deb(DEB_OPEN, 'findControlfileCopy');
OPEN findControlfileCopy(currentIncarnation => TRUE#,
tag => restoreTag,
untilSCN => untilSCN,
statusMask => BSavailable,
needstby => onlyStandby);
LOOP
FETCH findControlfileCopy
INTO ccfrec;
EXIT WHEN findControlfileCopy%NOTFOUND;
deb(DEB_PRINT, 'getControlfileBackup found a controlfilecopy:');
printRcvRec(ccfRec);
IF (NOT diskDevice) THEN
-- remember that we found one available copy
found := TRUE;
ccfrec.toSCN_act := 0; -- do not use this one
END IF;
EXIT; -- always return the first copy returned by the query
END LOOP;
CLOSE findControlfileCopy;
END IF;
IF (restoreSource = BACKUP OR restoreSource IS NULL) THEN
-- Replaces bcfq
deb(DEB_OPEN, 'findControlfileBackup');
OPEN findControlfileBackup_c(currentIncarnation => TRUE#,
untilSCN => untilSCN,
needstby => onlyStandby);
-- Find optimal backup set
LOOP
FETCH findControlfileBackup_c
INTO bcfrec;
EXIT WHEN findControlfileBackup_c%NOTFOUND;
deb(DEB_PRINT, 'getControlfileBackup found a controlfile backup:');
printRcvRec(bcfRec);
val_rc := validateBackupSet(
backupSetRec => bcfrec,
tag => restoreTag,
tagMatchRequired => TRUE,
checkDeviceIsAllocated => TRUE,
availableMask => BSavailable,
validRec => validateRec);
IF (val_rc = SUCCESS) THEN
bcfRec.tag_con := validateRec.tag;
bcfRec.deviceType_con := validateRec.deviceType;
bcfRec.copyNumber_con := validateRec.copyNumber;
-- Return the first one that we find
EXIT;
END IF;
bcfrec.toSCN_act := 0; -- do not use this one
IF (val_rc = dbms_rcvman.AVAILABLE) THEN
-- remember that we encountered at least one available backup
found := TRUE;
END IF;
END LOOP;
CLOSE findControlfileBackup_c;
-- Replaces xcfq
deb(DEB_OPEN, 'findControlfileProxyCopy');
OPEN findControlfileProxyCopy(currentIncarnation => TRUE#,
tag => restoreTag,
untilSCN => untilSCN,
statusMask => BSavailable,
needstby => onlyStandby);
-- Find optimal proxy copy
LOOP
FETCH findControlfileProxyCopy
INTO xcfrec;
EXIT WHEN findControlfileProxyCopy%NOTFOUND;
deb(DEB_PRINT, 'getControlfileBackup found a controlfile proxy copy:');
printRcvRec(xcfRec);
IF (isDeviceTypeAllocated(xcfrec.deviceType_con) = TRUE#) THEN
-- Return the first one that we find
EXIT;
END IF;
-- remember that we encountered at least one available backup
found := TRUE;
xcfrec.toSCN_act := 0; -- do not use this one
END LOOP;
CLOSE findControlfileProxyCopy;
END IF;
-- Return the backup or the copy depending on which one has the highest
-- checkpoint scn. In case the scns are equal and != 0 return the copy.
-- If both are 0 then return nothing (all NULLs).
IF (xcfrec.toSCN_act > greatest(ccfrec.toSCN_act, bcfrec.toSCN_act)) THEN
rcvRec := xcfrec;
ELSIF (bcfrec.toSCN_act > ccfrec.toSCN_act) THEN
rcvRec := bcfrec;
ELSIF (ccfrec.toSCN_act > 0) THEN
rcvRec := ccfrec;
ELSE
deb(DEB_PRINT, 'getControlfileBackup found no backup');
IF (found) THEN
deb(DEB_EXIT, 'with: AVAILABLE');
RETURN dbms_rcvman.AVAILABLE;
ELSE
deb(DEB_EXIT, 'with: UNAVAILABLE');
RETURN dbms_rcvman.UNAVAILABLE;
END IF;
END IF;
deb(DEB_EXIT, 'with: SUCCESS');
RETURN SUCCESS;
END getControlfileBackup;
-- This is for 8.0.4 compatibility
---------------------------- findControlFileBackup ----------------------------
FUNCTION findControlFileBackup(
type OUT number
,recid OUT number
,stamp OUT number
,fname OUT varchar2
,device_type OUT varchar2
,ckp_scn OUT number)
RETURN number IS
rcvRec rcvRec_t;
rc number;
BEGIN
deb(DEB_ENTER, 'findControlFileBackup804');
rc := getControlfileBackup(rcvRec);
IF (rc = SUCCESS) THEN
IF (rcvRec.type_con = imageCopy_con_t) THEN
type := COPY;
ELSIF (rcvRec.type_con = backupSet_con_t) THEN
type := BACKUP;
ELSIF (rcvRec.type_con = proxyCopy_con_t) THEN
type := PROXY;
ELSE
-- This is an unknown container type.
deb(DEB_EXIT, 'with: UNAVAILABLE');
RETURN dbms_rcvman.UNAVAILABLE;
END IF;
IF (type = BACKUP) THEN
recid := rcvRec.bsRecid_con;
stamp := rcvRec.bsStamp_con;
ELSE
recid := rcvRec.recid_con;
stamp := rcvRec.stamp_con;
END IF;
fname := rcvRec.fileName_con;
device_type := rcvRec.deviceType_con;
ckp_scn := rcvRec.toSCN_act;
deb(DEB_EXIT, 'with: SUCCESS');
RETURN SUCCESS;
ELSE
deb(DEB_EXIT, 'with: '||to_char(rc));
RETURN rc;
END IF;
deb(DEB_EXIT);
END findControlFileBackup;
-- Obsolete as of 8.1.6
---------------------------- findControlFileBackup ----------------------------
FUNCTION findControlFileBackup(
type OUT number
,recid OUT number
,stamp OUT number
,fname OUT varchar2
,device_type OUT varchar2
,ckp_scn OUT number
,rlg_scn OUT number
,blksize OUT number)
RETURN number IS
rcvRec rcvRec_t;
rc number;
BEGIN
deb(DEB_ENTER, 'findControlFileBackup815');
rc := getControlfileBackup(rcvRec);
IF (rc = SUCCESS) THEN
IF (rcvRec.type_con = imageCopy_con_t) THEN
type := COPY;
ELSIF (rcvRec.type_con = backupSet_con_t) THEN
type := BACKUP;
ELSIF (rcvRec.type_con = proxyCopy_con_t) THEN
type := PROXY;
rcvRec_last := rcvRec; -- save for translateProxyDFRecid
ELSE
-- This is an unknown container type.
deb(DEB_EXIT, 'with: UNAVAILABLE');
RETURN dbms_rcvman.UNAVAILABLE;
END IF;
IF (type = BACKUP) THEN
recid := rcvRec.bsRecid_con;
stamp := rcvRec.bsStamp_con;
ELSE
recid := rcvRec.recid_con;
stamp := rcvRec.stamp_con;
END IF;
fname := rcvRec.fileName_con;
device_type := rcvRec.deviceType_con;
ckp_scn := rcvRec.toSCN_act;
rlg_scn := rcvRec.rlgSCN_act;
blksize := rcvRec.blockSize_con;
deb(DEB_EXIT, 'with: SUCCESS');
RETURN SUCCESS;
ELSE
deb(DEB_EXIT, 'with: '||to_char(rc));
RETURN rc;
END IF;
END findControlFileBackup;
-------------------
-- SPFILE Backup --
-------------------
----------------------------- getSpFileBackup ----------------------------
FUNCTION getSpfileBackup(
rcvRec OUT rcvRec_t)
RETURN number IS
found boolean := FALSE;
bsfrec rcvRec_t;
tag bp.tag%TYPE;
val_rc binary_integer;
validateRec validBackupSetRec_t;
BEGIN
deb(DEB_ENTER, 'getSpfileBackup');
validateState(null);
-- Open the cursor
OPEN findSpfileBackup_c(untilTime => untilTime);
-- Find optimal backup set
LOOP
FETCH findSpfileBackup_c
INTO bsfrec;
EXIT WHEN findSpfileBackup_c%NOTFOUND;
deb(DEB_PRINT, 'getSpfileBackup found an SPFILE backup:');
printRcvRec(bsfRec);
val_rc := validateBackupSet(
backupSetRec => bsfrec,
tag => restoreTag,
tagMatchRequired => TRUE,
checkDeviceIsAllocated => TRUE,
availableMask => dbms_rcvman.BSavailable,
validRec => validateRec);
IF (val_rc = SUCCESS) THEN
bsfrec.tag_con := validateRec.tag;
bsfrec.deviceType_con := validateRec.deviceType;
bsfrec.copyNumber_con := validateRec.copyNumber;
-- Return the first one that we find
EXIT;
END IF;
bsfrec.toTime_act := to_date(null); -- do not use this one
IF (val_rc = dbms_rcvman.AVAILABLE) THEN
-- remember that we encountered at least one available backup
found := TRUE;
END IF;
END LOOP;
-- close the cursor
CLOSE findSpfileBackup_c;
IF (bsfrec.toTime_act IS NOT NULL) THEN
rcvRec := bsfrec;
ELSE
IF (found) THEN
deb(DEB_EXIT, 'with: AVAILABLE');
RETURN dbms_rcvman.AVAILABLE;
ELSE
deb(DEB_EXIT, 'with: UNAVAILABLE');
RETURN dbms_rcvman.UNAVAILABLE;
END IF;
END IF;
deb(DEB_EXIT, 'with: SUCCESS');
RETURN SUCCESS;
END getSpfileBackup;
-------------------------
-- Archived Log Backup --
-------------------------
---------------------------- findArchivedLogBackup ----------------------------
PROCEDURE findArchivedLogBackup(
thread IN number
,sequence IN number
,lowSCN IN number)
IS
BEGIN
deb(DEB_ENTER, 'findArchivedLogBackup');
validateState(null);
-- RMAN always looks for the log on disk before calling this, so we only
-- need to look for archivelog backup sets here.
-- Note that proxy copy for archivelogs is not supported.
deb(DEB_OPEN, 'findArcLogBackup');
OPEN findArcLogBackup(currentIncarnation => TRUE#,
thread => thread,
sequence => sequence,
lowSCN => lowSCN);
deb(DEB_EXIT);
END findArchivedLogBackup;
----------------------------- getArchivedLogBackup ----------------------------
FUNCTION getArchivedLogBackup(
rcvRec OUT rcvRec_t)
RETURN binary_integer IS
myRcvRec rcvRec_t;
validRec validBackupSetRec_t;
valRC number;
found boolean := FALSE;
BEGIN
deb(DEB_ENTER, 'getArchivedLogBackup');
LOOP
FETCH findArcLogBackup
INTO myRcvRec;
IF (findArcLogBackup%NOTFOUND) THEN
CLOSE findArcLogBackup;
IF (found) THEN
deb(DEB_EXIT, 'with: AVAILABLE');
RETURN dbms_rcvman.AVAILABLE;
ELSE
deb(DEB_EXIT, 'with: UNAVAILABLE');
RETURN dbms_rcvman.UNAVAILABLE;
END IF;
END IF;
valRC :=
validateBackupSet(backupSetRec => myRcvRec,
checkDeviceIsAllocated => TRUE,
tag => restoreTag,
availableMask => dbms_rcvman.BSavailable,
validRec => validRec);
IF (valRC = SUCCESS) THEN
CLOSE findArcLogBackup;
rcvRec := myRcvRec;
rcvRec.deviceType_con := validRec.deviceType;
rcvRec.tag_con := validRec.tag;
rcvRec.copyNumber_con := validRec.copyNumber;
deb(DEB_EXIT, 'with: SUCCESS');
RETURN SUCCESS;
ELSIF (valRC = dbms_rcvman.AVAILABLE) THEN
found := TRUE;
END IF;
END LOOP;
deb(DEB_EXIT);
END getArchivedLogBackup;
-- Obsolete as of 8.1.6
---------------------------- findArchivedLogBackup ----------------------------
FUNCTION findArchivedLogBackup(
thread# IN number
,sequence# IN number
,low_scn IN number
,type OUT number
,recid OUT number
,stamp OUT number
,device_type OUT varchar2)
RETURN number IS
rcvRec rcvRec_t;
RC binary_integer;
BEGIN
deb(DEB_ENTER, 'findArchivedLogBackup');
-- NOTE: The previous implementation of this checked the restore_from
-- variable. This is really not necessary as all RMAN versions always
-- called setFrom(backup) before calling this procedure.
findArchivedLogBackup(thread#, sequence#, low_scn);
RC := getArchivedLogbackup(rcvRec);
IF (RC = SUCCESS) THEN
type := BACKUP;
recid := rcvRec.bsRecid_con;
stamp := rcvRec.bsStamp_con;
device_type := rcvRec.deviceType_con;
END IF;
deb(DEB_EXIT, 'with: '||to_char(RC));
RETURN RC;
END findArchivedLogBackup;
---------------
-- List Copy --
---------------
------------------------- listTranslateControlfileCopy ------------------------
PROCEDURE listTranslateControlfileCopy(
tag IN varchar2
,completedAfter IN date
,completedBefore IN date
,statusMask IN binary_integer DEFAULT
BSavailable+BSunavailable+BSexpired) -- default for 8.1
IS
BEGIN
deb(DEB_ENTER, 'listTranslateControlfileCopy');
IF (findControlfileCopy%ISOPEN) THEN -- should not be open
CLOSE findControlfileCopy;
END IF;
-- Replaces the lccf cursor
deb(DEB_OPEN, 'findControlfileCopy');
OPEN findControlfileCopy(currentIncarnation => TRUE#,
tag => tag,
completedAfter => completedAfter,
completedBefore => completedBefore,
statusMask => statusMask);
deb(DEB_EXIT);
END listTranslateControlfileCopy;
---------------------------- listGetControlfileCopy ---------------------------
PROCEDURE listGetControlfileCopy(
rcvRec OUT rcvRec_t)
IS
BEGIN
deb(DEB_ENTER, 'listGetControlfileCopy');
FETCH findControlfileCopy
INTO rcvRec;
IF (findControlfileCopy%NOTFOUND) THEN
CLOSE findControlfileCopy;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
-- Do not need to check the allocated device types. Copies are available
-- only on type DISK, so we can assume we wouldn't even be here if
-- a DISK wasn't allocated.
deb(DEB_EXIT);
END listGetControlfileCopy;
-- Obsolete as of 8.1.6
---------------------------- listGetControlfileCopy ---------------------------
FUNCTION listGetControlfileCopy(
bcfkey OUT number,
ckpscn OUT number,
ckptime OUT date,
status OUT varchar2,
completion OUT date,
fname OUT varchar2) RETURN number
IS
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'listGetControlfileCopy');
listGetControlfileCopy(rcvRec);
bcfkey := rcvRec.key_con;
ckpscn := rcvRec.toSCN_act;
ckptime := rcvRec.toTime_act;
status := rcvRec.status_con;
completion := rcvRec.compTime_con;
fname := rcvRec.fileName_con;
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END listGetControlfileCopy;
-------------------------- listTranslateDataFileCopy --------------------------
PROCEDURE listTranslateDataFileCopy(
file# IN number
,creation_change# IN number
,tag IN varchar2 DEFAULT NULL
,file_name_pattern IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,statusMask IN binary_integer DEFAULT BSavailable+BSunavailable)
-- default for 8.1
IS
creationSCN number;
reset_scn number := NULL;
reset_time date := NULL;
BEGIN
deb(DEB_ENTER, 'listTranslateDataFileCopy');
IF (allIncarnations = TRUE#) THEN
reset_scn := NULL;
reset_time := NULL;
IF (ignoreCreationSCN = TRUE#) THEN
-- Since the flag is true, we want to list copies of all
-- incarnations of each datafile number. Set crescn to NULL so that
-- the query returns all datafilecopies of a particular file#.
-- This is used only by RMAN 8.1.5 and prior 8.1 releases.
creationSCN := NULL;
ELSE
creationSCN := creation_change#;
END IF;
ELSE
reset_scn := this_reset_scn;
reset_time := this_reset_time;
creationSCN := creation_change#;
END IF;
-- Replaces lcdf cursor
deb(DEB_OPEN, 'findDatafileBackup_c');
OPEN findDatafileBackup_c(sourcemask => imageCopy_con_t,
fno => file#,
crescn => creationSCN,
reset_scn => reset_scn,
reset_time => reset_time,
tag => tag,
pattern => file_name_pattern,
completedAfter => completedAfter,
completedBefore => completedBefore,
statusMask => statusMask);
deb(DEB_EXIT);
END listTranslateDataFileCopy;
----------------------------- listGetDataFileCopy -----------------------------
PROCEDURE listGetDataFileCopy(
rcvRec OUT rcvRec_t)
IS
BEGIN
deb(DEB_ENTER, 'listGetDataFileCopy');
FETCH findDatafileBackup_c
INTO rcvRec;
IF (findDatafileBackup_c%NOTFOUND) THEN
CLOSE findDatafileBackup_c;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
-- Do not need to check the allocated device types. Copies are available
-- only on type DISK, so we can assume we wouldn't even be here if
-- a DISK wasn't allocated.
deb(DEB_EXIT);
END listGetDatafileCopy;
-- Obsolete as of 8.1.6
----------------------------- listGetDataFileCopy -----------------------------
FUNCTION listGetDataFileCopy(
cdf_key OUT number
,status OUT varchar2
,fname OUT varchar2
,completion_time OUT date
,checkpoint_change# OUT number
,checkpoint_time OUT date)
RETURN number IS
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'listGetDataFileCopy815');
listGetDatafileCopy(rcvRec);
cdf_key := rcvRec.key_con;
status := rcvRec.status_con;
fname := rcvRec.fileName_con;
completion_time := rcvRec.compTime_con;
checkpoint_change# := rcvRec.toSCN_act;
checkpoint_time := rcvRec.toTime_act;
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END listGetDataFileCopy;
------------------------- listTranslateArchivedLogCopy ------------------------
PROCEDURE listTranslateArchivedLogCopy(
thread# IN number
,sequence# IN number
,first_change# IN number
,file_name_pattern IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,statusMask IN binary_integer DEFAULT
BSavailable+BSunavailable+BSexpired -- 8.0/8.1 defaults
,needstby IN number DEFAULT NULL)
IS
currentIncarnation number;
BEGIN
deb(DEB_ENTER, 'listTranslateArchivedLogCopy');
IF (allIncarnations = TRUE#) THEN
currentIncarnation := FALSE#; -- don't care about dbinc_key
ELSE
currentIncarnation := TRUE#;
END IF;
deb(DEB_OPEN, 'findArchivedLogCopy');
OPEN findArchivedLogCopy(currentIncarnation => currentIncarnation,
thread => thread#,
sequence => sequence#,
lowSCN => first_change#,
pattern => file_name_pattern,
completedAfter => completedAfter,
completedBefore => completedBefore,
statusMask => statusMask,
needstby => needstby);
deb(DEB_EXIT);
END listTranslateArchivedLogCopy;
---------------------------- listGetArchivedLogCopy ---------------------------
PROCEDURE listGetArchivedLogCopy(
rcvRec OUT rcvRec_t)
IS
BEGIN
deb(DEB_ENTER, 'listGetArchivedLogCopy');
-- Check if disk device is allocated. Copies are available
-- only on type DISK and no tag is associated with archivelog copies.
-- If any of these conditions are not satisfied - then no archivelogs
IF (restoreTag is not NULL OR
not diskDevice) THEN
CLOSE findArchivedLogCopy;
deb(DEB_EXIT, 'tag specified or no diskDevice allocated');
RAISE no_data_found;
END IF;
FETCH findArchivedLogCopy
INTO rcvRec;
IF (findArchivedLogCopy%NOTFOUND) THEN
CLOSE findArchivedLogCopy;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
deb(DEB_EXIT);
END listGetArchivedLogCopy;
-- Obsolete as of 8.1.6
---------------------------- listGetArchivedLogCopy ---------------------------
FUNCTION listGetArchivedLogCopy(
al_key OUT number
,status OUT varchar2
,fname OUT varchar2
,completion_time OUT date)
RETURN number IS
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'listGetArchivedLogCopy');
listGetArchivedLogCopy(rcvRec);
al_key := rcvRec.key_con;
status := rcvRec.status_con;
fname := rcvRec.fileName_con;
completion_time := rcvRec.compTime_con;
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END listGetArchivedLogCopy;
-----------------
-- List Backup --
-----------------
------------------------ listTranslateControlfileBackup -----------------------
PROCEDURE listTranslateControlfileBackup(
tag IN varchar2
,completedAfter IN date
,completedBefore IN date
,statusMask IN binary_integer DEFAULT
BSavailable+BSunavailable+BSexpired -- 8.0/8.1 defaults
,autobackup IN binary_integer DEFAULT BScfile_all)
IS
BEGIN
deb(DEB_ENTER, 'listTranslateControlfileBackup');
IF (findControlfileBackup_c%ISOPEN) THEN -- should not be open
CLOSE findControlfileBackup_c;
END IF;
-- Replaces the lbcf cursor. Note that the tag is handled by
-- validateBackupSet in the get() procedure.
deb(DEB_OPEN, 'findControlfileBackup_c');
OPEN findControlfileBackup_c(-- ### This is probably a bug.
-- currentIncarnation should probably be true,
-- as it is for listTranslateControlfileCopy
currentIncarnation => FALSE#,
completedAfter => completedAfter,
completedBefore => completedBefore,
typemask => autobackup);
-- The following parameters are saved in global variables for use by
-- the pre-8.1.6 listGetControlfileBackup procedure. Note that the 8.1.6
-- procedure does NOT use them. Instead, it is expected that the 8.1.6
-- RMAN will use the findValidBackupSet procedures to get a list of the
-- valid copies of a backup set.
listGetBackupTag := tag;
listGetBackupAvailableMask := statusMask;
deb(DEB_EXIT);
END listTranslateControlfileBackup;
--------------------------- listGetControlfileBackup --------------------------
PROCEDURE listGetControlfileBackup(
rcvRec OUT rcvRec_t)
IS
BEGIN
deb(DEB_ENTER, 'listGetControlfileBackup');
FETCH findControlfileBackup_c
INTO rcvRec;
-- Note: no backupset validation done here. RMAN should use the
-- findValidBackupSet procedures to do that.
IF (findControlfileBackup_c%NOTFOUND) THEN
CLOSE findControlfileBackup_c;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
deb(DEB_EXIT);
END listGetControlfileBackup;
-- Obsolete as of 8.1.6
--------------------------- listGetControlfileBackup --------------------------
FUNCTION listGetControlfileBackup(
bskey OUT number,
ckpscn OUT number,
ckptime OUT date)
RETURN number IS
rcvRec rcvRec_t;
validationRec validBackupSetRec_t;
validationRC binary_integer;
BEGIN
deb(DEB_ENTER, 'listGetControlfileBackup815');
<<nextRow>>
BEGIN
listGetControlfileBackup(rcvRec);
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END;
validationRC :=
validateBackupSet(backupSetRec => rcvRec,
tag => listGetBackupTag,
tagMatchRequired => TRUE,
checkDeviceIsAllocated => TRUE,
availableMask => listGetBackupAvailableMask,
validRec => validationRec);
IF (validationRC <> SUCCESS) THEN
GOTO nextRow;
END IF;
bskey := rcvRec.bsKey_con;
ckpscn := rcvRec.toSCN_act;
ckptime := rcvRec.toTime_act;
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END listGetControlfileBackup;
------------------------ listTranslateSpfileBackup ---------------------------
PROCEDURE listTranslateSpfileBackup(
completedAfter IN date
,completedBefore IN date)
IS
BEGIN
deb(DEB_ENTER, 'listTranslateSpfileBackup');
IF (findSpfileBackup_c%ISOPEN) THEN -- should not be open
CLOSE findSpfileBackup_c;
END IF;
deb(DEB_OPEN, 'findControlfileBackup_c');
OPEN findSpfileBackup_c(completedAfter => completedAfter,
completedBefore => completedBefore);
deb(DEB_EXIT);
END listTranslateSpfileBackup;
--------------------------- listGetSpfileBackup ------------------------------
PROCEDURE listGetSpfileBackup(
rcvRec OUT rcvRec_t)
IS
BEGIN
deb(DEB_ENTER, 'listGetSpfileBackup');
FETCH findSpfileBackup_c
INTO rcvRec;
-- Note: no backupset validation done here. RMAN should use the
-- findValidBackupSet procedures to do that.
IF (findSpfileBackup_c%NOTFOUND) THEN
CLOSE findSpfileBackup_c;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
deb(DEB_EXIT);
END listGetSpfileBackup;
------------------------- listTranslateDataFileBackup -------------------------
PROCEDURE listTranslateDataFileBackup(
file# IN number
,creation_change# IN number
,tag IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,statusMask IN binary_integer DEFAULT
BSavailable+BSunavailable+BSexpired) -- 8.0/8.1 defaults
IS
rlgSCN number;
rlgTime date;
crescn number;
BEGIN
deb(DEB_ENTER, 'listTranslateDataFileBackup');
IF (findDatafileBackup_c%ISOPEN) THEN
CLOSE findDatafileBackup_c;
END IF;
IF (allIncarnations = TRUE#) THEN
IF (ignoreCreationSCN = TRUE#) THEN
-- Since the flag is true, we want to list copies of all
-- incarnations of each datafile number. Set crescn to NULL so that
-- the query returns all datafilecopies of a particular file#.
-- This is used only by RMAN 8.1.5 and prior 8.1 releases.
-- Leave rlgSCN and Time be null.
crescn := NULL;
ELSE
crescn := creation_change#;
END IF;
ELSE
-- The 8.0 RMAN did not list backups that belonged to incarnations
-- other than the current incarnation.
rlgSCN := this_reset_scn;
rlgTime := this_reset_time;
crescn := creation_change#;
END IF;
-- Replaces lbdf
deb(DEB_OPEN, 'findDatafileBackup_c');
OPEN findDatafileBackup_c(sourceMask => backupSet_con_t,
fno => file#,
crescn => crescn,
reset_scn => rlgSCN,
reset_time => rlgTime,
completedAfter => completedAfter,
completedBefore => completedBefore);
-- The following parameters are saved in global variables for use by
-- the pre-8.1.6 listGetDatafileBackup procedure. Note that the 8.1.6
-- procedure does NOT use them. Instead, it is expected that the 8.1.6
-- RMAN will use the findValidBackupSet procedures to get a list of the
-- valid copies of a backup set.
listGetBackupTag := tag;
listGetBackupAvailableMask := statusMask;
deb(DEB_EXIT);
END listTranslateDataFileBackup;
---------------------------- listGetDataFileBackup ----------------------------
PROCEDURE listGetDataFileBackup(
rcvRec OUT rcvRec_t)
IS
BEGIN
deb(DEB_ENTER, 'listGetDataFileBackup');
FETCH findDatafileBackup_c
INTO rcvRec;
IF (findDatafileBackup_c%NOTFOUND) THEN
CLOSE findDatafileBackup_c;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
deb(DEB_EXIT);
END listGetDataFileBackup;
-- Obsolete as of 8.1.6
---------------------------- listGetDataFileBackup ----------------------------
FUNCTION listGetDataFileBackup(
bs_key OUT number
,backup_type OUT varchar2
,incremental_level OUT number
,completion_time OUT date
,checkpoint_change# OUT number
,checkpoint_time OUT date)
RETURN number IS
rcvRec rcvRec_t;
valRC binary_integer;
validationRec validBackupSetRec_t;
BEGIN
deb(DEB_ENTER, 'listGetDataFileBackup815');
<<nextRow>>
BEGIN
listGetDataFileBackup(rcvRec => rcvRec);
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END;
valRC :=
validateBackupSet(backupSetRec => rcvRec,
tag => listGetBackupTag,
tagMatchRequired => TRUE,
checkDeviceIsAllocated => TRUE,
availableMask => listGetBackupAvailableMask,
validRec => validationRec);
IF (valRC <> SUCCESS) THEN
GOTO nextRow;
END IF;
bs_key := rcvRec.bsKey_con;
IF (rcvRec.fromSCN_act = 0) THEN
backup_type := 'Full';
ELSE
backup_type := 'Incremental';
END IF;
incremental_level := rcvRec.level_act;
completion_time := rcvRec.compTime_con; -- somewhat bogus
checkpoint_change# := rcvRec.toSCN_act;
checkpoint_time := rcvRec.toTime_act;
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
END listGetDataFileBackup;
-- A stupid idea from the 8.1 LIST implementation
----------------------------- translateBackupFile -----------------------------
PROCEDURE translateBackupFile(
bs_recid IN number
,bs_stamp IN number
,fno IN number
,bskey OUT number
,inclevel OUT number
,backup_type OUT varchar2
,completed OUT date)
IS
BEGIN
deb(DEB_ENTER, 'translateBackupFile');
-- Rather than running another query to get values we already
-- fetched, we simply save the last rcvRec we fetched in a global
-- variable. We validate that the record matches
-- our input args, and then simply extract the values and return them.
-- The 8.1 implementation of LIST should have simply extended those other
-- functions to return the values that it required rather than executing
-- a 2nd query to fetch them, but that did not happen.
IF (rcvRec_last.type_con <> backupSet_con_t OR
rcvRec_last.bsRecid_con <> bs_recid OR
rcvRec_last.bsStamp_con <> bs_stamp) THEN
deb(DEB_EXIT, 'with error 20204');
raise_application_error(-20204, 'Translation not started');
END IF;
bskey := rcvRec_last.bsKey_con;
inclevel := rcvRec_last.level_act;
completed := rcvRec_last.compTime_con;
IF (rcvRec_last.logSequence_obj IS NOT NULL) THEN
backup_type := 'Archived Log';
ELSE
IF (rcvRec_last.fromSCN_act = 0) THEN
backup_type := 'Full';
ELSE
backup_type := 'Incremental';
END IF;
END IF;
deb(DEB_EXIT);
END translateBackupFile;
-- Used by 8.0 and 8.1.6, but not 8.1
------------------------ listTranslateArchivedLogBackup -----------------------
PROCEDURE listTranslateArchivedLogBackup(
thread# IN number
,sequence# IN number
,first_change# IN number
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,statusMask IN binary_integer DEFAULT
BSavailable+BSunavailable+BSexpired) -- 8.0/8.1 defaults
IS
currentInc number;
BEGIN
deb(DEB_ENTER, 'listTranslateArchivedLogBackup');
IF (allIncarnations = TRUE#) THEN
currentInc := FALSE#; -- don't care about dbinc_key
ELSE
currentInc := TRUE#;
END IF;
deb(DEB_OPEN, 'findArcLogBackup');
OPEN findArcLogBackup(currentIncarnation => currentInc,
thread => thread#,
sequence => sequence#,
lowSCN => first_change#,
completedAfter => completedAfter,
completedBefore => completedBefore);
listGetBackupAvailableMask := statusMask;
deb(DEB_EXIT);
END listTranslateArchivedLogBackup;
--------------------------- listGetArchivedLogBackup --------------------------
PROCEDURE listGetArchivedLogBackup(
rcvRec OUT rcvRec_t)
IS
BEGIN
deb(DEB_ENTER, 'listGetArchivedLogBackup');
FETCH findArcLogBackup
INTO rcvRec;
IF (findArcLogBackup%NOTFOUND) THEN
CLOSE findArcLogBackup;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
deb(DEB_EXIT);
END listGetArchivedLogBackup;
-- Obsolete as of 8.1
--------------------------- listGetArchivedLogBackup --------------------------
FUNCTION listGetArchivedLogBackup(
bs_key OUT number
,completion_time OUT date)
RETURN number IS
rcvRec rcvRec_t;
validRec validBackupSetRec_t;
valRC binary_integer;
BEGIN
deb(DEB_ENTER, 'listGetArchivedLogBackup');
<<get_next>>
listGetArchivedLogBackup(rcvRec);
valRC :=
validateBackupSet(backupSetRec => rcvRec,
checkDeviceIsAllocated => TRUE,
availableMask => listGetBackupAvailableMask,
validRec => validRec);
IF (valRC <> SUCCESS) THEN
GOTO get_next;
END IF;
bs_key := rcvRec.bsKey_con;
completion_time := rcvRec.compTime_con;
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END listGetArchivedLogBackup;
-- Obsolete as of 8.1.6.
-- This procedure is just a bad idea left here for backwards compatibility
-- with the broken LIST BACKUP OF ARCHIVELOG command of 8.1.
------------------------ listTranslateArchivedLogBackup -----------------------
PROCEDURE listTranslateArchivedLogBackup(
thread# IN number DEFAULT NULL
,lowseq IN number DEFAULT NULL
,highseq IN number DEFAULT NULL
,lowscn IN number DEFAULT NULL
,highscn IN number DEFAULT NULL
,from_time IN date DEFAULT NULL
,until_time IN date DEFAULT NULL
,pattern IN varchar2 DEFAULT NULL)
IS
BEGIN
deb(DEB_ENTER, 'listTranslateArchivedLogBackup815');
if lbal2%isopen then
close lbal2;
end if;
deb(DEB_OPEN, 'lbal2');
open lbal2(thread#, lowseq, highseq, lowscn, highscn, from_time, until_time);
deb(DEB_EXIT);
END listTranslateArchivedLogBackup;
-- Obsolete as of 8.1.6
--------------------------- listGetArchivedLogBackup --------------------------
FUNCTION listGetArchivedLogBackup(
bs_key OUT number
,thread# OUT number
,sequence# OUT number
,first_change# OUT number
,next_change# OUT number
,first_time OUT date
,next_time OUT date)
RETURN number IS
rcvRec rcvRec_t;
validRec validBackupSetRec_t;
BEGIN
deb(DEB_ENTER, 'listGetArchivedLogBackup815');
<<get_next>>
fetch lbal2 into rcvRec;
if lbal2%found then
deb(DEB_PRINT, 'listGetArchivedLogBackup: got a backupset:');
printRcvRec(rcvRec);
if validateBackupSet(backupSetRec => rcvRec,
checkDeviceIsAllocated => TRUE,
availableMask => dbms_rcvman.BSavailable +
dbms_rcvman.BSunavailable +
dbms_rcvman.BSexpired,
validRec => validRec) <> SUCCESS then
goto get_next;
end if;
bs_key := rcvRec.bsKey_con;
thread# := rcvRec.logThread_obj;
sequence# := rcvRec.logSequence_obj;
first_change# := rcvRec.logLowSCN_obj;
next_change# := rcvRec.logNextSCN_obj;
first_time := rcvRec.logLowTime_obj;
next_time := rcvRec.logNextTime_obj;
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
else
close lbal2;
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
end if;
END listGetArchivedLogBackup;
--------------------
-- List Backupset --
--------------------
PROCEDURE listTranslateBackupsetFiles(
bs_key IN number)
IS
BEGIN
IF findBackupsetFiles%ISOPEN THEN
CLOSE findBackupsetFiles;
END IF;
OPEN findBackupsetFiles(bs_key);
END;
PROCEDURE listGetBackupsetFiles(
rcvRec OUT rcvRec_t)
IS
BEGIN
FETCH findBackupsetFiles
INTO rcvRec;
IF (findBackupsetFiles%NOTFOUND) THEN
CLOSE findBackupsetFiles;
RAISE no_data_found;
END IF;
END;
------------------------
-- List All BackupSet --
------------------------
PROCEDURE translateAllBackupSet(
backupType IN binary_integer
,tag IN varchar2
,statusMask IN binary_integer
,completedAfter IN date
,completedBefore IN date)
IS
BEGIN
IF findAllBackupPiece%ISOPEN THEN
CLOSE findAllBackupPiece;
END IF;
OPEN findAllBackupPiece(backupType, tag, statusMask,
completedAfter, completedBefore);
END;
PROCEDURE getAllBackupSet(
rcvRec OUT rcvRec_t)
IS
BEGIN
FETCH findAllBackupPiece
INTO rcvRec;
IF (findAllBackupPiece%NOTFOUND) THEN
CLOSE findAllBackupPiece;
RAISE no_data_found;
END IF;
END;
---------------------
-- List Proxy Copy --
---------------------
-- Note that this is used for both datafiles and the controlfile
-------------------------- listTranslateProxyDataFile -------------------------
PROCEDURE listTranslateProxyDataFile(
file# IN number
,creation_change# IN number
,tag IN varchar2 DEFAULT NULL
,handle_pattern IN varchar2 DEFAULT NULL
,completedAfter IN date DEFAULT NULL
,completedBefore IN date DEFAULT NULL
,statusMask IN binary_integer DEFAULT BSavailable+BSunavailable+BSexpired)
-- default for 8.1
IS
currentInc number;
crescn number;
reset_scn number := NULL;
reset_time date := NULL;
BEGIN
deb(DEB_ENTER, 'listTranslateProxyDataFile');
validateState(null);
IF (allIncarnations = TRUE#) THEN
currentInc := FALSE#; -- don't care about dbinc_key
IF (ignoreCreationSCN = TRUE#) THEN
-- Since the flag is true, we want to list copies of all
-- incarnations of each datafile number. Set crescn to NULL so that
-- the query returns all datafilecopies of a particular file#.
-- This is used only by RMAN 8.1.5 and prior 8.1 releases.
crescn := NULL;
ELSE
crescn := creation_change#;
END IF;
ELSE
currentInc := TRUE#;
crescn := creation_change#;
END IF;
IF (currentInc = TRUE#) THEN
reset_scn := this_reset_scn;
reset_time := this_reset_time;
END IF;
IF (file# = 0) THEN
IF (findControlfileProxyCopy%ISOPEN) THEN
CLOSE findControlfileProxyCopy;
END IF;
-- This replaces lxdf
deb(DEB_OPEN, 'findControlfileProxyCopy');
OPEN findControlfileProxyCopy(currentIncarnation => currentInc,
tag => tag,
pattern => handle_pattern,
completedAfter => completedAfter,
completedBefore => completedBefore,
statusMask => statusMask);
listGetProxyDatafileCursor := 'findControlfileProxyCopy';
ELSE
IF (findDatafileBackup_c%ISOPEN) THEN
CLOSE findDatafileBackup_c;
END IF;
-- This replaces lxdf
OPEN findDatafileBackup_c(sourcemask => proxyCopy_con_t,
fno => file#,
crescn => crescn,
reset_scn => reset_scn,
reset_time => reset_time,
tag => tag,
pattern => handle_pattern,
completedAfter => completedAfter,
completedBefore => completedBefore,
statusMask => statusMask);
listGetProxyDatafileCursor := 'findDatafileBackup_c';
END IF;
deb(DEB_EXIT);
END listTranslateProxyDataFile;
----------------------------- listGetProxyDataFile ----------------------------
PROCEDURE listGetProxyDataFile(
rcvRec OUT rcvRec_t)
IS
local rcvRec_t;
BEGIN
deb(DEB_ENTER, 'listGetProxyDataFile');
<<nextRow>>
IF (listGetProxyDatafileCursor = 'findControlfileProxyCopy') THEN
FETCH findControlfileProxyCopy
INTO local;
IF (findControlfileProxyCopy%NOTFOUND) THEN
CLOSE findControlfileProxyCopy;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
ELSIF (listGetProxyDatafileCursor = 'findDatafileBackup_c') THEN
FETCH findDatafileBackup_c
INTO local;
IF (findDatafileBackup_c%NOTFOUND) THEN
CLOSE findDatafileBackup_c;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
ELSE
deb(DEB_EXIT, 'with error 20204');
raise_application_error(-20204, 'Translation not started');
END IF;
-- Proxy copies can be on different device types, so make sure we
-- have the right one allocated.
IF (isDeviceTypeAllocated(local.deviceType_con) = FALSE#) THEN
GOTO nextRow;
END IF;
rcvRec := local; -- set OUT mode arg
deb(DEB_EXIT);
END listGetProxyDataFile;
-- Obsolete as of 8.1.6
----------------------------- listGetProxyDataFile ----------------------------
FUNCTION listGetProxyDataFile(
xdf_key OUT number
,recid OUT number
,stamp OUT number
,status OUT varchar2
,handle OUT varchar2
,completion_time OUT date
,checkpoint_change# OUT number
,checkpoint_time OUT date)
RETURN number IS
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'listGetProxyDataFile815');
listGetProxyDataFile(rcvRec);
xdf_key := rcvRec.key_con;
recid := rcvRec.recid_con;
stamp := rcvRec.stamp_con;
status := rcvRec.status_con;
handle := rcvRec.fileName_con;
completion_time := rcvRec.compTime_con;
checkpoint_change# := rcvRec.toSCN_act;
checkpoint_time := rcvRec.toTime_act;
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END listGetProxyDataFile;
-- This procedure serves absolutely no purpose. It is here only for
-- backwards compatbility with 8.1.5. The only call to this is from
-- krmkafs(), which gets called from krmkgra(). Since the calls are always
-- in sequence, we can simply save the last record returned from
-- getRecoveryAction and avoid doing an extra query.
-- The only value this functions returns that krmkgra() didn't already have
-- in 8.1.5 is the xdf_key. Completion time was being estimated from the
-- stamp.
-------------------------- listTranslateProxyDFRecid --------------------------
PROCEDURE listTranslateProxyDFRecid(
recid IN number
,stamp IN number
,xdf_key OUT number
,file# OUT number
,status OUT varchar2
,handle OUT varchar2
,completion_time OUT date
,checkpoint_change# OUT number
,checkpoint_time OUT date)
IS
BEGIN
deb(DEB_ENTER, 'listTranslateProxyDFRecid');
-- See if the last rcvRec we returned matches the one requested here.
-- I think it will always be the case that we can use the value we
-- saved in rcvRec_last. But in case there is a path through Don's
-- spaghetti code that I could not find, I include the cursor from the
-- 8.1 package below and use it if the cached value is no good.
IF (recid <> rcvRec_last.recid_con OR
stamp <> rcvRec_last.stamp_con) THEN
select d.xdf_key, d.file#, d.status, d.handle, d.completion_time,
d.checkpoint_change#, d.checkpoint_time
into xdf_key, file#, status, handle, completion_time, checkpoint_change#,
checkpoint_time
from rc_proxy_datafile d
where db_key = this_db_key
and d.recid = listTranslateProxyDFRecid.recid
and d.stamp = listTranslateProxyDFRecid.stamp
union all
select c.xcf_key, 0, c.status, c.handle, c.completion_time,
c.checkpoint_change#, c.checkpoint_time
from rc_proxy_controlfile c
where db_key = this_db_key
and c.recid = listTranslateProxyDFRecid.recid
and c.stamp = listTranslateProxyDFRecid.stamp;
ELSE
deb(DEB_PRINT, 'listTranslateProxyDFRecid: using cached rcvRec_last');
xdf_key := rcvRec_last.key_con;
file# := rcvRec_last.dfNumber_obj;
status := rcvRec_last.status_con;
handle := rcvRec_last.fileName_con;
completion_time := rcvRec_last.compTime_con;
checkpoint_change# := rcvRec_last.toSCN_act;
checkpoint_time := rcvRec_last.toTime_act;
END IF;
deb(DEB_EXIT);
END listTranslateProxyDFRecid;
-------------------------------
-- List Database Incarnation --
-------------------------------
-------------------------- listTranslateDBIncarnation -------------------------
PROCEDURE listTranslateDBIncarnation(
db_name IN varchar2 DEFAULT NULL)
IS
BEGIN
deb(DEB_ENTER, 'listTranslateDBIncarnation');
IF (ldbi%isopen) THEN
CLOSE ldbi;
END IF;
deb(DEB_OPEN, 'ldbi');
OPEN ldbi(db_name);
deb(DEB_EXIT);
END listTranslateDBIncarnation;
----------------------------- listGetDBIncarnation ----------------------------
FUNCTION listGetDBIncarnation(
db_key OUT number
,dbinc_key OUT number
,db_name OUT varchar2
,db_id OUT number
,current_inc OUT varchar2
,resetlogs_change# OUT number
,resetlogs_time OUT date)
RETURN number
IS
BEGIN
deb(DEB_ENTER, 'listGetDBIncarnation');
FETCH ldbi
INTO db_key, dbinc_key, db_name, db_id, current_inc,
resetlogs_change#, resetlogs_time;
IF (ldbi%found) THEN
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
ELSE
CLOSE ldbi;
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END IF;
deb(DEB_EXIT);
END listGetDBIncarnation;
--------------------------------------
-- List Rollback Segment Tablespace --
--------------------------------------
-------------------------- listRollbackSegTableSpace --------------------------
PROCEDURE listRollbackSegTableSpace
IS
BEGIN
deb(DEB_ENTER, 'listRollbackSegTableSpace');
IF (lrtbs%ISOPEN) THEN
CLOSE lrtbs;
END IF;
deb(DEB_OPEN, 'lrtbs');
OPEN lrtbs;
deb(DEB_EXIT);
END listRollbackSegTableSpace;
------------------------------ listGetTableSpace ------------------------------
FUNCTION listGetTableSpace(
ts# OUT number
,ts_name OUT varchar2)
RETURN number
IS
BEGIN
deb(DEB_ENTER, 'listGetTableSpace');
FETCH lrtbs
INTO ts#, ts_name;
IF (lrtbs%FOUND) THEN
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
ELSE
CLOSE lrtbs;
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END IF;
deb(DEB_EXIT);
END listGetTableSpace;
------------------------
-- Incremental Backup --
------------------------
------------------------------ getIncrementalScn ------------------------------
PROCEDURE getIncrementalScn(
first IN boolean -- open the cursor if this is TRUE
,file# IN number
,create_scn IN number
,reset_scn IN number
,reset_time IN date
,incr_level IN number
,cumulative IN number
,rcvRec OUT rcvRec_t)
IS
ilevel number;
statusMask number := BSavailable;
local rcvRec_t;
validRec validBackupSetRec_t;
BEGIN
deb(DEB_ENTER, 'getIncrementalScn');
IF (incr_level not in (1,2,3,4) OR incr_level is NULL) THEN
raise_application_error(-20270, 'invalid incremental level');
END IF;
IF (cumulative not in (0,1) OR cumulative is NULL) THEN
raise_application_error(-20271, 'invalid cumulative option');
END IF;
-- Find the backup with highest checkpoint scn that
-- o belongs to the incarnation of datafile
-- o matches the given file#
-- o is an incremental backup/copy at level N or less if non-cumulative or
-- is an incremental backup/copy at level N-1 or less if cumulative
-- o belongs to an available backup set if backup
-- NOTE: Backups from ancestral incarnations are ignored, even if there is
-- a spanning offline range. Incremental backups cannot cross resetlogs
-- boundaries.
IF (cumulative = TRUE#) THEN
ilevel := incr_level - 1; -- Consider only higher level backups
ELSE
ilevel := incr_level;
END IF;
IF first THEN
IF (findDatafileBackup_c%ISOPEN) THEN
CLOSE findDatafileBackup_c;
END IF;
getDatafileBackupLast.type_con := NULL; -- clear the last backup record
--
-- UNCOMMENT the following when you want to test qukvalidateBackupSet
-- with inCoreBsRec data structures. We did this change in catalog too
-- because we could do complete testing. This is not needed in catalog
-- because we didn't see much performance benefit. More importantly, PLSQL
-- consumes more memory to push a record so that for around 1MB of records
-- we hit PLSQL-6500 error. This is not acceptable for catalog mode.
--
-- IF (file# IS NULL) THEN
-- -- No specific fileno was requested. So, this must be a large
-- -- query for more number of datafiles like database translation.
-- -- In nocatalog mode, the best performance is achieved by
-- -- having all backuppiece information in memory.
-- createinCorebsRecStack(
-- backupType => BSdatafile_full + BSdatafile_incr
-- ,tag => NULL
-- ,statusMask => statusMask
-- ,checkDeviceIsAllocated => FALSE
-- ,completedAfter => NULL
-- ,completedBefore => NULL);
-- validateBackupSet_method := 'qukvalidateBackupSet';
-- ELSE
-- validateBackupSet_method := 'validateBackupSet';
-- END IF;
-- Just use the usual method in catalog mode
validateBackupSet_method := 'validateBackupSet';
-- null reset_scn and reset_time means current incarnation
OPEN findDatafileBackup_c(sourcemask => to_number(NULL),
fno => file#,
crescn => create_scn,
reset_scn => nvl(reset_scn, this_reset_scn),
reset_time => nvl(reset_time, this_reset_time),
level => ilevel,
statusMask => statusMask);
END IF;
IF (NOT findDatafileBackup_c%ISOPEN) THEN
raise_application_error(-20272, 'cannot take incremental backup');
END IF;
LOOP
<<nextRow>>
FETCH findDatafileBackup_c
INTO local;
IF (findDatafileBackup_c%NOTFOUND) THEN
deb(DEB_PRINT, 'closing cursor');
CLOSE findDatafileBackup_c;
IF (file# is NOT NULL) THEN
-- there were no backups available for this file
deb(DEB_EXIT, 'with: cannot take incr backup');
raise_application_error(-20272, 'cannot take incremental backup');
ELSE
deb(DEB_EXIT, 'with: no data found');
raise no_data_found; -- no more datafile backups
END IF;
END IF;
IF (getDatafileBackupLast.type_con IS NOT NULL AND
getDatafileBackupLast.dfNumber_obj = local.dfNumber_obj) THEN
GOTO nextRow; -- this is a duplicate of what we saw earlier
END IF;
IF (local.type_con = backupSet_con_t) THEN
--
-- If this is same as the last backupset we validated, then
-- this must also succeed. Save that validation time.
--
IF (getDatafileBackupLast.type_con IS NULL OR
getDatafileBackupLast.type_con != backupSet_con_t OR
getDatafileBackupLast.setStamp_con != local.setStamp_con OR
getDatafileBackupLast.setCount_con != local.setCount_con) THEN
-- We have to check the validity of the backupset to
-- base an incremental backup upon it.
IF (validateBackupSet_method = 'qukvalidateBackupSet') THEN
-- This is a large query. Optimize this from in-memory tables
IF (NOT qukvalidateBackupSet(bsKey => local.bsKey_con)) THEN
GOTO nextRow; -- not a valid backupset
END IF;
ELSIF (validateBackupSet_method = 'validateBackupSet') THEN
IF (validateBackupSet(backupSetRec => local,
checkDeviceIsAllocated => FALSE,
availableMask => statusMask,
validRec => validRec)
= dbms_rcvman.UNAVAILABLE) THEN
GOTO nextRow; -- can't create an incr based on unavail backup
END IF;
ELSE
raise_application_error(-20204, 'Translation not started');
END IF;
END IF;
END IF;
getDatafileBackupLast := local; -- remember the last record
rcvRec := local;
deb(DEB_EXIT, 'with: valid record ');
EXIT; -- valid record. Create Incremental based on this SCN
END LOOP;
EXCEPTION
WHEN others THEN
deb(DEB_PRINT, 'caught an exception during getIncrementalScn');
deb(DEB_EXIT, substr(sqlerrm, 1, 512));
raise;
END getIncrementalScn;
------------------------------ getIncrementalScn ------------------------------
FUNCTION getIncrementalScn(
file# IN number
,create_scn IN number
,reset_scn IN number
,reset_time IN date
,incr_level IN number
,cumulative IN number)
RETURN number IS
rcvRec rcvRec_t;
BEGIN
getIncrementalScn(
first => TRUE
,file# => file#
,create_scn => create_scn
,reset_scn => reset_scn
,reset_time => reset_time
,incr_level => incr_level
,cumulative => cumulative
,rcvRec => rcvRec);
IF (findDatafileBackup_c%ISOPEN) THEN
CLOSE findDatafileBackup_c; -- close the one opened in getIncrementalScn
END IF;
RETURN rcvRec.toSCN_act;
END getIncrementalScn;
--------------------
-- Offline Ranges --
--------------------
-- Find a controlfile copy that contains the given offline range
-- The checkpoint scn of the controlfile must be greater than or equal to
-- the online scn because the offline range record is inserted into the
-- controlfile when the file is onlined. The controlfile creation time
-- must be equal to the cursor parameter.
-- Lastly, the min_offr_recid must be
-- less than or equal to the offline range recid to guarantee that record
-- has not been written over in the controlfile copy.
----------------------------- findOfflineRangeCopy ----------------------------
PROCEDURE findOfflineRangeCopy(
offr_recid IN number
,offr_ckpscn IN number
,cf_cretime IN date
,dbinc_key IN number)
IS
BEGIN
deb(DEB_ENTER, 'findOfflineRangeCopy');
validateState(null);
deb(DEB_OPEN, 'getOfflineRangeCopy_c');
OPEN getOfflineRangeCopy_c(offrRecid => offr_recid,
offrCkpSCN => offr_ckpscn,
cfCreTime => cf_cretime,
dbincKey => dbinc_key);
deb(DEB_EXIT);
END findOfflineRangeCopy;
----------------------------- getOfflineRangeCopy -----------------------------
PROCEDURE getOfflineRangeCopy(
rcvRec OUT rcvRec_t)
IS
BEGIN
deb(DEB_ENTER, 'getOfflineRangeCopy');
IF (NOT getOfflineRangeCopy_c%ISOPEN) THEN
deb(DEB_EXIT, 'with error 20204');
raise_application_error(-20204, 'Translation not started');
END IF;
FETCH getOfflineRangeCopy_c
INTO rcvRec;
IF (getOfflineRangeCopy_c%NOTFOUND) THEN
CLOSE getOfflineRangeCopy_c;
deb(DEB_EXIT, 'with no more records');
RAISE no_data_found;
END IF;
CLOSE getOfflineRangeCopy_c;
deb(DEB_EXIT);
END getOfflineRangeCopy;
-- Obsolete as of 8.1.6
----------------------------- getOfflineRangeCopy -----------------------------
FUNCTION getOfflineRangeCopy
RETURN varchar2 IS
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'getOfflineRangeCopy815');
getOfflineRangeCopy(rcvRec);
deb(DEB_EXIT, 'with: fileName');
RETURN rcvRec.fileName_con;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with: NULL');
RETURN NULL;
END getOfflineRangeCopy;
--------------------------------------
-- Recovery Functions and Procedures --
---------------------------------------
------------------------ setComputeRecoveryActionMasks ------------------------
PROCEDURE setComputeRecoveryActionMasks(
containerMask IN number
,actionMask IN number
,allRecords IN number
,availableMask IN binary_integer)
IS
BEGIN
deb(DEB_ENTER, 'setComputeRecoveryActionMasks');
getRA_containerMask := containerMask;
getRA_actionMask := actionMask;
computeRA_allRecords := allRecords;
computeRA_availableMask := availableMask;
deb(DEB_EXIT);
END setComputeRecoveryActionMasks;
-- Obsolete as of 8.1.7
------------------------ setComputeRecoveryActionMasks ------------------------
PROCEDURE setComputeRecoveryActionMasks(
containerMask IN number
,actionMask IN number
,allRecords IN number)
IS
BEGIN
deb(DEB_ENTER, 'setComputeRecoveryActionMasks816');
setComputeRecoveryActionMasks(
containerMask => containerMask,
actionMask => actionMask,
allRecords => allRecords,
availableMask => dbms_rcvman.BSavailable);
deb(DEB_EXIT);
END setComputeRecoveryActionMasks;
-- Obsolete as of 8.1.6
---------------------------------- setRAflags ---------------------------------
PROCEDURE setRAflags(
kindMask IN number
,allRecords IN boolean)
IS
containerMask number;
actionMask number;
allRecs number;
BEGIN
deb(DEB_ENTER, 'setRAflags');
-- Set container mask
containerMask := 0;
IF (bitand(kindMask, implicitOfflRange + cleanRange + applyOfflRange) > 0)
THEN
containerMask := containerMask + offlineRangeRec_con_t;
END IF;
IF (bitand(kindMask, dfCopy) > 0) THEN
containerMask := containerMask + imageCopy_con_t;
END IF;
IF (bitand(kindMask, buSet + applyIncremental) > 0) THEN
containerMask := containerMask + backupSet_con_t;
END IF;
IF (bitand(kindMask, proxyFull) > 0) THEN
containerMask := containerMask + proxyCopy_con_t;
END IF;
-- Set Action Mask
actionMask := 0;
IF (bitand(kindMask, dfCopy + ProxyFull + buSet) > 0) THEN
actionMask := actionMask + full_act_t;
END IF;
IF (bitand(kindMask, applyIncremental) > 0) THEN
actionMask := actionMask + incremental_act_t;
END IF;
IF (bitand(kindMask, redo) > 0) THEN
actionMask := actionMask + redo_act_t;
END IF;
IF (bitand(kindMask, implicitOfflRange) > 0) THEN
actionMask := actionMask + implicitRange_act_t;
END IF;
IF (bitand(kindMask, cleanRange) > 0) THEN
actionMask := actionMask + cleanRange_act_t;
END IF;
IF (bitand(kindMask, applyOfflRange) > 0) THEN
actionMask := actionMask + offlineRange_act_t;
END IF;
IF (allRecords) THEN
allRecs := TRUE#;
ELSE
allRecs := FALSE#;
END IF;
deb(DEB_PRINT, 'setRAflags kindMask=' || to_char(kindMask) ||
' containerMask=' || to_char(containerMask) ||
' actionMask=' || to_char(actionMask));
setComputeRecoveryActionMasks(containerMask, actionMask, allRecs);
deb(DEB_EXIT);
END setRAflags;
---------------------------- computeRecoveryActions ---------------------------
FUNCTION computeRecoveryActions(
fno IN number, -- Datafile number.
crescn IN number, -- Datafile creation SCN.
df_rlgscn IN number -- Datafile resetlogs SCN. Null unless we are doing
default null, -- a RECOVER, in which case is the value in the
-- datafile header.
df_rlgtime IN date -- Datafile resetlogs time. Null if df_rlgscn is
default null, -- null, else value from datafile header.
df_ckpscn IN number -- Datafile checkpoint SCN. Null if df_rlgscn is
default null, -- null, else value from datafile header.
offlscn IN number -- kccfeofs (0 -> no offline range)
default 0,
onlscn IN number -- kccfeonc (0 if offlscn is 0).
default 0,
onltime IN date -- kccfonc_time
default null,
cleanscn IN number -- kccfecps if either SOR or WCC set, else 0.
default 0,
clean2scn IN number -- CF ckpt SCN if WCC set, infinity if SOR bit set
default 0, -- else 0.
clean2time IN date -- controlfile ckpt time if WCC, SYSDATE if SOR, else
default null, -- this is ignored if cleanscn is 0
allowfuzzy IN boolean -- TRUE if can be fuzzy at until SCN/time, FALSE if
default FALSE, -- not. default is FALSE.
partial_rcv IN boolean -- TRUE if can do partial recovery, FALSE if not.
default FALSE, -- A partial recovery would be to recover a datafile
-- using redo up to some SCN, and then switching
-- back to incrementals. This would be done
-- because of a missing/unavailable incremental backup.
-- We need to know because a partial
-- media recovery can only be done if we have a
-- current controlfile. A partial recovery does not
-- recover the controlfile. This could be implemented,
-- but it requires using an enqueue to ensure only
-- 1 process tries to recover the confile.
-- Since we aren't recovering the controlfile,
-- the file header won't be handled properly when
-- we hit controlfile redo. That is why we are
-- requiring a current controlfile.
-- The default is false because RMAN currently does
-- not support partial recovery.
cf_scn IN number -- controlfile ckpt SCN (NULL if none mounted)
default NULL,
cf_cretime IN date -- controlfile creation time (NULL if none mounted)
default NULL,
cf_offrrid IN number -- recid of oldest offline range in controlfile
default NULL, -- (NULL if none mounted)
allCopies IN boolean
default FALSE)
RETURN binary_integer IS
rc boolean;
last number;
this number;
succ_flag boolean;
thisAct rcvRec_t;
BEGIN
deb(DEB_ENTER, 'computeRecoveryActions');
IF (this_dbinc_key is NULL) THEN
deb(DEB_EXIT, 'with error 20020');
raise_application_error(-20020, 'Database incarnation not set');
END IF;
IF (rcvRecStack.count > 0) THEN
rcvRecStack.trim(rcvRecStack.count);
END IF;
computeRA_restorable := FALSE;
computeRA_available := FALSE;
rcvRecStackState.lowAction := 0;
rcvRecStackState.savePoint := 0;
rcvRecStackState.top := 0;
IF (allCopies) THEN
deb(DEB_IN, 'allCopies is TRUE');
ELSE
deb(DEB_IN, 'allCopies is FALSE');
END IF;
deb(DEB_IN, 'this_dbinc_key is:'||to_char(this_dbinc_key));
rc := computeRecoveryActions(fno, crescn, df_rlgscn, df_rlgtime,
df_ckpscn,
offlscn, onlscn, onltime,
cleanscn, clean2scn, clean2time,
allowfuzzy, partial_rcv,
null, this_dbinc_key,
cf_scn, cf_cretime, cf_offrrid,
FALSE, succ_flag, allCopies);
IF (succ_flag) THEN
IF (rcvRecStack.count > 0) THEN
IF (computeRA_allRecords = FALSE#) THEN
-- We need to find any incremental backups that are redundant
-- and mark them to be skipped. It is possible that we
-- have stacked an incremental backup that we can skip because
-- it overlaps two other incremental backups.
-- We can delete action n if action n - 1 can be applied on
-- top of action n + 1. I.e., if the toSCN(n+1) >= fromSCN(n-1).
-- Note that the actions on the stack, from top..1, are in
-- descending toSCN order. This means n+1 comes before n-1.
-- Loop from top-1..2 These are the "middle" actions. Go in
-- reverse order since that is the order in which the stack was
-- built. "last" is the last action we know we are keeping.
-- We know we are keeping the action at the top of the stack, as it
-- is always a full backup. So "last" starts at the stack top.
-- "last" is n+1 in the formula above.
last := rcvRecStack.count;
FOR this IN REVERSE 2..rcvRecStack.count - 1 LOOP
IF ((rcvRecStack(last).toSCN_act >=
rcvRecStack(this-1).fromSCN_act) AND NOT
-- Keep it if allCopies and it is the same container.
(allCopies AND
rcvRecStack(this).key_con = rcvRecStack(this-1).key_con AND
rcvRecStack(this).type_con = rcvRecStack(this-1).type_con))
THEN
deb(DEB_PRINT, 'computeRecoveryActions: marking this action deleted:');
rcvRecGet(this, thisAct);
printRcvRec(thisAct);
rcvRecStack(this).type_con :=
rcvRecStack(this).type_con + deleted_con_t;
ELSE
-- We are going to keep this action, so it becomes the last.
last := this;
END IF;
END LOOP;
END IF; -- computeRA_allRecords = FALSE#
deb(DEB_EXIT, 'with: SUCCESS');
RETURN SUCCESS;
ELSE
deb(DEB_EXIT, 'with: NO_ACTION');
RETURN NO_ACTION; -- a recovery that can only use redo
END IF;
ELSIF (computeRA_available) THEN
deb(DEB_EXIT, 'with: AVAILABLE');
RETURN dbms_rcvman.AVAILABLE;
ELSIF (computeRA_restorable) THEN
deb(DEB_EXIT, 'with: RESTORABLE');
RETURN RESTORABLE;
ELSE
deb(DEB_EXIT, 'with: UNAVAILABLE');
RETURN dbms_rcvman.UNAVAILABLE;
END IF;
END computeRecoveryActions;
------------------------------ getRecoveryAction ------------------------------
FUNCTION getRecoveryAction(
action OUT rcvRec_t)
RETURN binary_integer IS
redoAction rcvRec_t;
skip boolean;
local rcvRec_t;
top rcvRec_t;
BEGIN
deb(DEB_ENTER, 'getRecoveryAction');
<<getNext>>
IF (rcvRecStack.count = 0) THEN
-- Signal to krmk we have reached the end.
-- We usually only get here if filtering, in which case we cannot
-- always predict when we have reached the last row.
--
-- pre-8.1.3 rman does not tell us to filter out any records (via
-- the RA flags), so we should not get here. If we do then it is
-- a protocol error, so we really should signal an error.
-- However, there is no way to signal an internal error from a
-- package. So just raise the no-data-found condition.
-- This will cause the pre-8.1.3 RMAN to signal an error because
-- it does not tolerate any errors from getRecoveryAction.
deb(DEB_EXIT, 'with no more records');
raise no_data_found;
END IF;
rcvRecPop(local);
-- See if we want this action kind or not
IF (bitand(local.type_con, getRA_containerMask) = 0) THEN
deb(DEB_PRINT, 'getRecoveryAction: skipping non-selected container type');
skip := TRUE; -- then skip this action
ELSIF (bitand(local.type_act, getRA_actionMask) = 0) THEN
deb(DEB_PRINT, 'getRecoveryAction: skipping non-selected action type');
skip := TRUE; -- then skip this action
ELSIF (bitand(local.type_con, deleted_con_t) > 0) THEN
deb(DEB_PRINT, 'getRecoveryAction: deleted action skipped:');
skip := TRUE; -- then skip this action
-- If we were doing a LIST, compare the TAG if specified
ELSIF (computeRA_allRecords = TRUE# AND
restoreTag is not null AND
bitand(local.type_con, tagMask_con_t) > 0 AND
(local.tag_con <> restoreTag OR local.tag_con is null)) THEN
deb(DEB_PRINT, 'getRecoveryAction: tag mismatch - skipped:');
skip := TRUE; -- then skip this action
-- Compare the COMPLETED AFTER time if specified. Note that
-- local.compTime may be null.
ELSIF (getRA_completedAfter IS NOT NULL AND
local.compTime_con < getRA_completedAfter) THEN
deb(DEB_PRINT, 'getRecoveryAction: compTime < completedAfter - skipped:');
skip := TRUE; -- then skip this action
-- Compare the COMPLETED BEFORE if specified
ELSIF (getRA_completedBefore IS NOT NULL AND
local.compTime_con > getRA_completedBefore) THEN
deb(DEB_PRINT, 'getRecoveryAction: compTime > completedBefore - skipped:');
skip := TRUE; -- then skip this action
-- Compare the LIKE pattern if specified
ELSIF (getRA_likePattern IS NOT NULL AND
local.fileName_con NOT LIKE getRA_likePattern) THEN
deb(DEB_PRINT, 'getRecoveryAction: LikePattern not matched - skipped:');
skip := TRUE; -- then skip this action
ELSE
skip := FALSE;
END IF;
IF (skip) THEN
printRcvRec(local);
GOTO getNext;
END IF;
<<merge_actions>>
IF (rcvRecStack.count > 0) THEN
--------------------------------------------------------
-- See if the next action can be merged with this one --
--------------------------------------------------------
rcvRecTop(top);
IF (local.type_act = redo_act_t AND
top.type_act = redo_act_t) THEN
-- Two contiguous redo actions can always be merged. We know they
-- must be from the same incarnation because an offline range
-- action always appears between 2 different incarnations.
redoAction := local;
rcvRecPop(local);
local.fromSCN_act := redoAction.fromSCN_act;
GOTO merge_actions;
END IF;
action := local;
rcvRec_last := local;
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#; -- more actions to return yet
ELSE
action := local;
rcvRec_last := local;
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#; -- this is the last action
END IF;
END getRecoveryAction;
-- Obsolete as of 8.1.6
------------------------------ getRecoveryAction ------------------------------
FUNCTION getRecoveryAction(
kind OUT number
,set_stamp OUT number
,set_count OUT number
,recid OUT number
,stamp OUT number
,fname OUT varchar2
,blocksize OUT number
,blocks OUT number
,devtype OUT varchar2
,from_scn OUT number
,to_scn OUT number
,to_time OUT date
,rlgscn OUT number
,rlgtime OUT date
,cfcretime OUT date
,dbinc_key OUT number)
RETURN binary_integer IS
rcvRec rcvRec_t;
rc binary_integer;
BEGIN
deb(DEB_ENTER, 'getRecoveryAction815');
rc := getRecoveryAction(rcvRec);
IF (rcvRec.type_con = offlineRangeRec_con_t) THEN
IF (rcvRec.type_act = offlineRange_act_t) THEN
kind := applyOfflRange;
ELSIF (rcvRec.type_act = cleanRange_act_t) THEN
kind := cleanRange;
ELSIF (rcvRec.type_act = implicitRange_act_t) THEN
kind := implicitOfflRange;
ELSE
deb(DEB_PRINT, 'cannot convert type_con=' || to_char(rcvRec.type_con) ||
' type_act=' || to_char(rcvRec.type_act) ||
' to recovery action kind');
deb(DEB_EXIT, 'with error 20000');
raise_application_error(-20000, 'internal error: getRecoveryAction');
END IF;
ELSIF (rcvRec.type_con = backupSet_con_t) THEN
IF (rcvRec.type_act = full_act_t) THEN
kind := buSet;
ELSE
kind := applyIncremental;
END IF;
ELSIF (rcvRec.type_con = proxyCopy_con_t) THEN
kind := proxyFull;
ELSIF (rcvRec.type_con = imageCopy_con_t) THEN
kind := dfCopy;
ELSIF (rcvRec.type_con IS NULL) THEN
IF (rcvRec.type_act = redo_act_t) THEN
kind := redo;
END IF;
END IF;
deb(DEB_PRINT, 'getRecoveryAction: kind=' || nvl(to_char(kind), 'null'));
rcvRecConvert(rcvRec); -- get rid of nulls
printRcvRec(rcvRec);
set_stamp := rcvRec.setStamp_con;
set_count := rcvRec.setCount_con;
IF (rcvRec.type_con = backupSet_con_t) THEN
recid := rcvRec.bsRecid_con;
stamp := rcvRec.bsStamp_con;
ELSE
recid := rcvRec.recid_con;
stamp := rcvRec.stamp_con;
END IF;
fname := rcvRec.fileName_con;
blocksize := rcvRec.blockSize_con;
blocks := rcvRec.blocks_con;
devtype := rcvRec.deviceType_con;
from_scn := rcvRec.fromSCN_act;
to_scn := rcvRec.toSCN_act;
to_time := rcvRec.toTime_act; -- null OK
rlgscn := rcvRec.rlgSCN_act;
rlgtime := rcvRec.rlgTime_act;
cfcretime := rcvRec.cfCreationTime_con; -- null OK
dbinc_key := rcvRec.dbincKey_act; -- null OK
deb(DEB_EXIT, 'with: '||to_char(rc));
RETURN rc;
END;
----------------------------- printRecoveryActions ----------------------------
PROCEDURE printRecoveryActions
IS
action rcvRec_t;
rc number;
BEGIN
deb(DEB_PRINT, '===== ' || to_char(rcvRecStack.count) || ' actions stacked =====');
IF (rcvRecStack.count = 0) THEN
return;
END IF;
LOOP
rc := getRecoveryAction(action);
printRcvRec(action);
EXIT WHEN rc = FALSE#;
END LOOP;
END printRecoveryActions;
----------------------------- trimRecoveryActions -----------------------------
PROCEDURE trimRecoveryActions(
maxActions IN number
,containerMask IN number
,actionMask IN number)
IS
n number;
BEGIN
deb(DEB_ENTER, 'trimRecoveryActions[procedure]');
n := trimRecoveryActions(maxActions, containerMask, actionMask);
deb(DEB_EXIT);
END trimRecoveryActions;
---------------------
-- Report Obsolete --
---------------------
----------------------------- reportTranslateDFDel ----------------------------
PROCEDURE reportTranslateDFDel
IS
BEGIN
deb(DEB_ENTER, 'reportTranslateDFDel');
IF (rddf%isopen) THEN
CLOSE rddf;
END IF;
deb(DEB_OPEN, 'rddf');
OPEN rddf;
deb(DEB_EXIT);
END reportTranslateDFDel;
-- pre-8.1.5 version. Discards unused out variables and PROXY rows.
-------------------------------- reportGetDFDel -------------------------------
FUNCTION reportGetDFDel(
file# OUT number
,filetype OUT number
,checkpoint_change# OUT number
,checkpoint_time OUT date
,resetlogs_change# OUT number
,resetlogs_time OUT date
,incremental_change# OUT number
,fuzzy_change# OUT number
,recid OUT number
,stamp OUT number
,fname OUT varchar2
,restorable OUT number)
RETURN number IS
rc number;
mytype number;
key number;
completion_time date;
BEGIN
deb(DEB_ENTER, 'reportGetDFDel80');
<<get_next>>
rc := reportGetDFDel( file#
,mytype
,checkpoint_change#
,checkpoint_time
,resetlogs_change#
,resetlogs_time
,incremental_change#
,fuzzy_change#
,recid
,stamp
,fname
,restorable
,key
,completion_time);
IF (rc = TRUE#) THEN
IF (mytype = PROXY) THEN
GOTO get_next;
END IF;
filetype := mytype;
END IF;
deb(DEB_EXIT, 'with: '||to_char(rc));
RETURN rc;
END reportGetDFDel;
-- 8.1.5+ version
-------------------------------- reportGetDFDel -------------------------------
FUNCTION reportGetDFDel(
file# OUT number
,filetype OUT number
,checkpoint_change# OUT number
,checkpoint_time OUT date
,resetlogs_change# OUT number
,resetlogs_time OUT date
,incremental_change# OUT number
,fuzzy_change# OUT number
,recid OUT number
,stamp OUT number
,fname OUT varchar2
,restorable OUT number
,key OUT number
,completion_time OUT date)
RETURN number IS
device_type rc_backup_piece.device_type%TYPE;
mytype number;
set_stamp number;
set_count number;
pref number;
bsRec bsRec_t;
validRec validBackupSetRec_t;
rcvRec rcvRec_t;
BEGIN
deb(DEB_ENTER, 'reportGetDFDel');
FETCH rddf
INTO pref, file#, mytype, checkpoint_change#, checkpoint_time,
resetlogs_change#, resetlogs_time, incremental_change#, fuzzy_change#,
recid, stamp, fname, set_stamp, set_count, key, completion_time,
device_type;
filetype := mytype;
IF (rddf%found) THEN
IF (mytype in (FULL_DF_BACKUP, INCREMENTAL_DF_BACKUP)) THEN
findBackupSet(recid => recid,
stamp => stamp,
bsRec => bsRec);
-- This is a bit dangerous. We are hacking together a rcvRec
-- from a bsRec.
rcvRec.bsKey_con := bsRec.key;
rcvRec.elapseSecs_con := bsRec.elapseSecs;
rcvRec.pieceCount_con := bsRec.pieceCount;
restorable := validateBackupSet(
backupSetRec => rcvRec,
checkDeviceIsAllocated => TRUE,
availableMask => dbms_rcvman.BSavailable,
validRec => validRec);
ELSIF (mytype = OFFLINE_RANGE) THEN
restorable := SUCCESS;
ELSE
IF (isDeviceTypeAllocated(device_type) = TRUE#) THEN
restorable := SUCCESS;
ELSE
restorable := dbms_rcvman.AVAILABLE;
END IF;
END IF;
deb(DEB_EXIT, 'with: '||TRUE#);
RETURN TRUE#;
ELSE
CLOSE rddf;
deb(DEB_EXIT, 'with: '||FALSE#);
RETURN FALSE#;
END IF;
END reportGetDFDel;
------------
-- TSPITR --
------------
--------------------------------- getCloneName --------------------------------
FUNCTION getCloneName(
fno IN number
,crescn IN number)
RETURN varchar2 IS
fname df.clone_fname%TYPE;
BEGIN
deb(DEB_ENTER, 'getCloneName');
IF (this_dbinc_key is NULL) THEN
deb(DEB_EXIT, 'with error 20020');
raise_application_error(-20020, 'Database incarnation not set');
END IF;
SELECT clone_fname
INTO fname
FROM df
WHERE dbinc_key = this_dbinc_key
AND file# = fno
AND create_scn = crescn;
deb(DEB_EXIT, 'with: '||fname);
RETURN fname;
EXCEPTION
WHEN no_data_found THEN
-- This should never happen. The fno and crescn values came from
-- the recovery catalog, so we should have this record.
deb(DEB_EXIT, 'with error 20218');
raise_application_error(-20218,
'Datafile not found in recovery catalog');
WHEN others THEN
deb(DEB_EXIT, 'Just raising error');
raise;
END getCloneName;
---------------
-- DUPLICATE --
---------------
--------------------------------- wasFileOffline ------------------------------
FUNCTION wasFileOffline(
fno IN number
,untilscn IN number)
RETURN number IS
x number;
BEGIN
deb(DEB_ENTER, 'wasFileOffline');
select 1
into x
from rc_offline_range ofr, rc_database_incarnation di
where ofr.db_key = this_db_key
and di.db_key = this_db_key
and ofr.dbinc_key = di.dbinc_key
and untilscn >= offline_change#
and untilscn < online_change#
and file# = fno;
deb(DEB_EXIT, 'with: TRUE#');
RETURN TRUE#;
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT, 'with: FALSE#');
RETURN FALSE#;
END wasFileOffline;
-------------------------
-- RMAN Configuration ---
-------------------------
-------------------------------- getConfig ------------------------------------
PROCEDURE getConfig(
conf# OUT number
,name IN OUT varchar2
,value IN OUT varchar2
,first IN boolean)
IS
eof boolean := FALSE;
BEGIN
IF (first) THEN
IF (findConfig_c%ISOPEN) THEN
CLOSE findConfig_c;
END IF;
OPEN findConfig_c(name, value);
END IF;
FETCH findConfig_c INTO conf#, name, value;
IF (findConfig_c%NOTFOUND) THEN
eof := TRUE;
CLOSE findConfig_c;
END IF;
IF (eof) THEN --- if end of fetch
RAISE no_data_found;
END IF;
END getConfig;
----------------------------------
-- Get max(copy#) backup piece --
----------------------------------
--------------------------------- getmaxcopyno---------------------------------
FUNCTION getmaxcopyno(
bsstamp IN number
,bscount IN number)
RETURN number IS
maxcopy number;
BEGIN
select max(copy#)
into maxcopy
from rc_backup_piece bp
where bp.set_stamp = bsstamp
and bp.set_count = bscount
and bp.db_key = this_db_key;
return maxcopy;
END getmaxcopyno;
--------------------------------------
-- Add corruption table to BMR list --
--------------------------------------
----------------------------- bmraddcorrupttable-------------------------------
PROCEDURE bmrAddCorruptTable(
dfnumber OUT number
,blknumber OUT number
,range OUT number
,first IN boolean)
IS
eof boolean := FALSE;
BEGIN
IF (first) THEN
IF (bmrAddCorruptTable_c%ISOPEN) THEN
CLOSE bmrAddCorruptTable_c;
END IF;
OPEN bmrAddCorruptTable_c;
END IF;
FETCH bmrAddCorruptTable_c INTO dfnumber, blknumber, range;
IF (bmrAddCorruptTable_c%NOTFOUND) THEN
eof := TRUE;
CLOSE bmrAddCorruptTable_c;
END IF;
IF (eof) THEN --- if end of fetch
RAISE no_data_found;
END IF;
END;
--------getBackupHistory------------
-- Get Backup History Information --
------------------------------------
PROCEDURE getDfBackupHistory(
backedUpDev IN varchar2
,first IN boolean
,file# IN number DEFAULT NULL
,crescn IN number DEFAULT NULL
,reset_scn IN number DEFAULT NULL
,reset_time IN date DEFAULT NULL
,bhistoryRec OUT bhistoryRec_t)
IS
eof boolean := FALSE;
local bhistoryRec_t;
icount number := 0;
BEGIN
deb(DEB_ENTER, 'getDfBackupHistory');
IF (first) THEN
getLastBackupHistory.key := NULL;
IF (dfBackupHistory_c%ISOPEN) THEN
CLOSE dfBackupHistory_c;
END IF;
deb(DEB_OPEN, 'dfBackupHistory_c');
OPEN dfBackupHistory_c(file# => file#,
crescn => crescn,
reset_scn => reset_scn,
reset_time => reset_time);
END IF;
IF (getLastBackupHistory.key IS NOT NULL AND
getLastBackupHistory.ckp_scn = getLastBackupHistory.stop_scn AND
(backedUpDev IS NULL OR
getLastBackupHistory.device_type = backedUpDev)) THEN
-- last file was offline/readonly now and backup on this device
icount := 1;
END IF;
IF (NOT dfBackupHistory_c%ISOPEN) THEN
eof := TRUE;
goto lastRow;
END IF;
<<nextRow>>
FETCH dfBackupHistory_c INTO local;
IF (dfBackupHistory_c%NOTFOUND) THEN
CLOSE dfBackupHistory_c;
eof := TRUE;
ELSIF (getLastBackupHistory.key IS NULL OR
(getLastBackupHistory.dfNumber = local.dfNumber AND
getLastBackupHistory.create_scn = local.create_scn AND
getLastBackupHistory.reset_scn = local.reset_scn AND
getLastBackupHistory.reset_time = local.reset_time)) THEN
IF (local.ckp_scn = local.stop_scn AND
(backedUpDev IS NULL OR local.device_type = backedUpDev)) THEN
-- this file is offline/readonly now and a bkup on this device
icount := icount + 1; -- bump the number of copies
END IF;
getLastBackupHistory := local; -- remember the last copy
goto nextRow;
END IF;
-- We are here either a different filenumber, create_scn, reset_scn
-- reset_time is seen or reached the eof
<<lastRow>>
IF (eof AND getLastBackupHistory.key IS NULL) THEN
deb(DEB_EXIT, 'with: no_data_found');
RAISE no_data_found;
END IF;
-- the last backup contains the maximum completion time because
-- we ordered by completion_time
bhistoryRec := getLastBackupHistory;
-- init the number of backups on this device
bhistoryRec.device_type := backedUpDev;
bhistoryRec.nbackups := icount;
IF (eof) THEN
getLastBackupHistory.key := NULL; -- for next time to raise no_data
ELSE
-- remember the last copy because we haven't returned this yet
getLastBackupHistory := local;
END IF;
deb(DEB_EXIT, 'with file# = ' || to_char(bhistoryRec.dfNumber) ||
' nbackups= ' || to_char(bhistoryRec.nbackups) ||
' compTime= ' || to_char(bhistoryRec.compTime));
END getDfBackupHistory;
PROCEDURE getAlBackupHistory(
backedUpDev IN varchar2
,first IN boolean
,thread# IN number DEFAULT NULL
,sequence# IN number DEFAULT NULL
,bhistoryRec OUT bhistoryRec_t)
IS
eof boolean := FALSE;
local bhistoryRec_t;
icount number := 0;
BEGIN
deb(DEB_ENTER, 'getAlBackupHistory');
IF (first) THEN
getLastBackupHistory.key := NULL;
IF (alBackupHistory_c%ISOPEN) THEN
CLOSE alBackupHistory_c;
END IF;
deb(DEB_OPEN, 'alBackupHistory_c');
OPEN alBackupHistory_c(thread# => thread#,
sequence# => sequence#);
END IF;
IF (getLastBackupHistory.key IS NOT NULL AND
(backedUpDev IS NULL OR
getLastBackupHistory.device_type = backedUpDev)) THEN
-- last fetch is a backup on this device
icount := 1;
END IF;
IF (NOT alBackupHistory_c%ISOPEN) THEN
eof := TRUE;
goto lastRow;
END IF;
<<nextRow>>
FETCH alBackupHistory_c INTO local;
IF (alBackupHistory_c%NOTFOUND) THEN
CLOSE alBackupHistory_c;
eof := TRUE;
ELSIF (getLastBackupHistory.key IS NULL OR
(getLastBackupHistory.logThread = local.logThread AND
getLastBackupHistory.logSequence = local.logSequence)) THEN
IF (backedUpDev IS NULL OR
local.device_type = backedUpDev) THEN
-- a backup exists on this device
icount := icount + 1; -- bump the number of copies
END IF;
getLastBackupHistory := local; -- remember the last copy
goto nextRow;
END IF;
-- We are here either because a different (thread#, sequence#) is seen or
-- reached the eof
<<lastRow>>
IF (eof AND getLastBackupHistory.key IS NULL) THEN
deb(DEB_EXIT, 'with: no_data_found');
RAISE no_data_found;
END IF;
-- the last backup contains the maximum completion time because
-- we ordered by completion_time
bhistoryRec := getLastBackupHistory;
-- init the backup cound and device type
bhistoryRec.device_type := backedUpDev;
bhistoryRec.nbackups := icount;
IF (eof) THEN
getLastBackupHistory.key := NULL; -- for next time to raise no_data
ELSE
-- remember the last copy because we haven't returned this yet
getLastBackupHistory := local;
END IF;
deb(DEB_EXIT, 'with (thread#, sequence#)=(' ||
to_char(bhistoryRec.logThread) || ',' ||
to_char(bhistoryRec.logSequence) || ')' ||
' nbackups= ' || bhistoryRec.nbackups||
' compTime= ' || to_char(bhistoryRec.compTime));
END getAlBackupHistory;
PROCEDURE getBsBackupHistory(
backedUpDev IN varchar2
,first IN boolean
,set_stamp IN number DEFAULT NULL
,set_count IN number DEFAULT NULL
,bhistoryRec OUT bhistoryRec_t)
IS
eof boolean := FALSE;
local bhistoryRec_t;
icount number := 0;
BEGIN
deb(DEB_ENTER, 'getBsBackupHistory');
IF (first) THEN
getLastBackupHistory.key := NULL;
IF (bsBackupHistory_c%ISOPEN) THEN
CLOSE bsBackupHistory_c;
END IF;
deb(DEB_OPEN, 'bsBackupHistory_c');
OPEN bsBackupHistory_c(set_stamp => set_stamp,
set_count => set_count);
END IF;
IF (getLastBackupHistory.key IS NOT NULL AND
(backedUpDev IS NULL OR
getLastBackupHistory.device_type = backedUpDev)) THEN
-- last backupset fetched is on this device
icount := 1;
END IF;
IF (NOT bsBackupHistory_c%ISOPEN) THEN
eof := TRUE;
goto lastRow;
END IF;
<<nextRow>>
FETCH bsBackupHistory_c INTO local;
IF (bsBackupHistory_c%NOTFOUND) THEN
CLOSE bsBackupHistory_c;
eof := TRUE;
ELSIF (getLastBackupHistory.key IS NULL OR
getLastBackupHistory.key = local.key) THEN
IF (backedUpDev IS NULL OR
local.device_type = backedUpDev) THEN
icount := icount + 1; -- bump the number of copies
END IF;
getLastBackupHistory := local; -- remember the last copy
goto nextRow;
END IF;
-- We are here either because a different key is seen or
-- reached the eof
<<lastRow>>
IF (eof AND getLastBackupHistory.key IS NULL) THEN
deb(DEB_EXIT, 'with: no_data_found');
RAISE no_data_found;
END IF;
-- the last backup contains the maximum completion time because
-- we ordered by completion_time
bhistoryRec := getLastBackupHistory;
-- init the device type and number of backups
bhistoryRec.device_type := backedUpDev;
bhistoryRec.nbackups := icount;
IF (eof) THEN
getLastBackupHistory.key := NULL; -- for next time to raise no_data
ELSE
-- remember the last copy because we haven't returned this yet
getLastBackupHistory := local;
END IF;
deb(DEB_EXIT, 'with set_stamp = ' || to_char(bhistoryRec.setStamp) ||
'set_count = ' || to_char(bhistoryRec.setCount) ||
' nbackups= ' || to_char(bhistoryRec.nbackups) ||
' compTime= ' || to_char(bhistoryRec.compTime));
END getBsBackupHistory;
-- Obsolete as of 9.0.1
-- DataFile History
PROCEDURE getBackupHistory(
dfRec IN dfRec_t
,backedUpDev IN varchar2
,nbackupsFlag IN number
,bscompletionFlag IN number
,nbackups OUT number
,bscompletion OUT date)
IS
bhistoryRec bhistoryRec_t;
BEGIN
deb(DEB_ENTER, 'getBackupHistory');
nbackups := 0;
bscompletion := NULL;
-- not interested in history
IF ((nbackupsFlag != 1 OR backedUpDev IS NULL) AND
bscompletionFlag != 1) THEN
deb(DEB_EXIT, 'with not interested');
RETURN;
END IF;
getDfBackupHistory(
backedUpDev => backedUpDev
,first => TRUE
,file# => dfRec.dfNumber
,crescn => dfRec.dfCreationSCN
,bhistoryRec => bhistoryRec
);
IF (dfBackupHistory_c%ISOPEN) THEN
CLOSE dfBackupHistory_c;
END IF;
getLastBackupHistory.key := NULL;
nbackups := bhistoryRec.nbackups;
bscompletion := bhistoryRec.compTime;
deb(DEB_EXIT);
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT);
nbackups := 0;
bscompletion := NULL;
END getBackupHistory;
-- Obsolete as of 9.0.1
-- Archivelog History
PROCEDURE getBackupHistory(
alRec IN alRec_t
,backedUpDev IN varchar2
,nbackupsFlag IN number
,bscompletionFlag IN number
,nbackups OUT number
,bscompletion OUT date)
IS
bhistoryRec bhistoryRec_t;
BEGIN
deb(DEB_ENTER, 'getBackupHistory');
nbackups := 0;
bscompletion := NULL;
-- not interested in history
IF ((nbackupsFlag != 1 OR backedUpDev IS NULL) AND
bscompletionFlag != 1) THEN
deb(DEB_EXIT, 'with not interested');
RETURN;
END IF;
getAlBackupHistory(
backedUpDev => backedUpDev
,first => TRUE
,thread# => alRec.thread
,sequence# => alRec.sequence
,bhistoryRec => bhistoryRec
);
IF (alBackupHistory_c%ISOPEN) THEN
CLOSE alBackupHistory_c;
END IF;
getLastBackupHistory.key := NULL;
nbackups := bhistoryRec.nbackups;
bscompletion := bhistoryRec.compTime;
deb(DEB_EXIT);
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT);
nbackups := 0;
bscompletion := NULL;
END;
-- Obsolete as of 9.0.1
-- BackupPiece History
PROCEDURE getBackupHistory(
bpRec IN bpRec_t
,backedUpDev IN varchar2
,nbackupsFlag IN number
,bscompletionFlag IN number
,nbackups OUT number
,bscompletion OUT date)
IS
bhistoryRec bhistoryRec_t;
BEGIN
deb(DEB_ENTER, 'getBackupHistory');
nbackups := 0;
bscompletion := NULL;
-- not interested in history
IF ((nbackupsFlag != 1 OR backedUpDev IS NULL) AND
bscompletionFlag != 1) THEN
deb(DEB_EXIT, 'with not interested');
RETURN;
END IF;
getbsBackupHistory(
backedUpDev => backedUpDev
,set_stamp => bpRec.setStamp
,set_count => bpRec.setCount
,first => TRUE
,bhistoryRec => bhistoryRec
);
IF (bsBackupHistory_c%ISOPEN) THEN
CLOSE bsBackupHistory_c;
END IF;
getLastBackupHistory.key := NULL;
nbackups := bhistoryRec.nbackups;
bscompletion := bhistoryRec.compTime;
deb(DEB_EXIT);
EXCEPTION
WHEN no_data_found THEN
deb(DEB_EXIT);
nbackups := 0;
bscompletion := NULL;
END;
------------------
-- Version Info --
------------------
-- Return all the protocol versions that we support, one at a time.
-- Return them in ascending version number order.
------------------------------ getPackageVersion ------------------------------
FUNCTION getPackageVersion
RETURN varchar2 IS
BEGIN
deb(DEB_ENTER, 'getPackageVersion');
IF (versionCounter > versionMaxIndex) THEN
versionCounter := 1;
deb(DEB_EXIT, 'with: NULL');
RETURN NULL;
END IF;
versionCounter := versionCounter + 1;
deb(DEB_EXIT, 'with: '||versionList(versionCounter - 1));
RETURN versionList(versionCounter - 1);
END getPackageVersion;
FUNCTION isStatusMatch(status IN VARCHAR2,
mask IN NUMBER) RETURN NUMBER IS
BEGIN
-- BSpartial_avail is a backupset validation mask and NOT a backuppiece
-- filter. For eg. BSpartial_avail + BSavailable + BSexpired means
-- select 'A' and 'X' pieces but validate the pieces in such a way
-- partial backupset succeeds. (see findValidBackupSet_c cursor)
IF (bitand(mask, BSavailable) != 0 AND status = 'A') OR
(bitand(mask, BSunavailable) != 0 AND status = 'U') OR
(bitand(mask, BSdeleted) != 0 AND status = 'D') OR
(bitand(mask, BSexpired) != 0 AND status = 'X') THEN
RETURN TRUE#;
ELSE
RETURN FALSE#;
END IF;
END isStatusMatch;
----------------------------- isBackupTypeMatch -------------------------------
FUNCTION isBackupTypeMatch(btype IN VARCHAR2,
mask IN binary_integer) RETURN NUMBER IS
BEGIN
IF (bitand(mask, BSdatafile_full) !=0 AND btype = 'D') OR
(bitand(mask, BSdatafile_incr) !=0 AND btype = 'I') OR
(bitand(mask, BSarchivelog) !=0 AND btype = 'L') THEN
RETURN TRUE#;
ELSE
RETURN FALSE#;
END IF;
END isBackupTypeMatch;
---------------------------
-- Package Instantiation --
---------------------------
BEGIN
-- initialize version list.
-- change version_max_index when adding new values.
versionList(1) := '08.00.04';
versionList(2) := '08.00.05';
versionList(3) := '08.01.03';
versionList(4) := '08.01.05';
versionList(5) := '08.01.06';
versionList(6) := '08.01.07';
versionList(7) := '09.00.00';
versionList(8) := '09.02.00';
-- initialize version list iterator variables
versionCounter := 1;
versionMaxIndex := 8; -- must match highest index used above
resetAll; -- init package variables to defaults
END dbms_rcvman;
See Also
List of packages