2019-04-09 1416
use Getopt::Long qw(:config no_ignore_case);
use POSIX ":sys_wait_h";
use strict;
use vars qw/ %opt /;
our %transfer = ();
our $context = %opt;
our @tablespaces = ();
our @properties = ();
our %props;
our $tmp;
our $xttpath;
our $rmantfrdf;
our $rmandstdf;
our $xttprep;
our $rmanpath;
our $connectstring;
our $sqlSettings;
our $errfile;
our $getfile;
our $xtts_incr_backup = "xib";
our @rolltbsArray = ();
my %tbsHash;
my $fixCnvSql;
my $fixRollSql;
our @forkArray = ();
my $xttrollforwardp;
my $rollParallel = 0;
my $getParallel = 0;
my $metaTransfer = 0;
my $scpParms = 0;
our $xttprop;
our $cnvrSql = "xttcnvrtbkupdest.sql";
our $stageondest;
our $backupondest;
our $platformid;
our $connectstringcnvinst;
our $myversion = "2.0";
our %dirHash;
our $dirmaxVal = 100;
use constant PREPARE => 1;
use constant BCKPINCR => 2;
use constant NEWPLAN => 3;
use constant GETFILE => 5;
use constant BACKUP => 6;
use constant RESTORE => 7;
use constant RECOVER => 8;
use constant ROLLFORWARD => 9;
use constant RESINCRDMP => 10;
use constant LOCALFILE => 1;
use constant LINK => 2;
use constant VER11 => 1;
use constant VER12 => 2;
sub parseArg
{
GetOptions ($context,
'backup|b',
'bkpincr|B',
'convert|c',
'debug|d:i',
'bkpexport|E',
'generate|e',
'incremental|i',
'orahome|o=s',
'prepare|p',
'rollforward|r',
'determinescn|s',
'xttdir|D=s',
'propfile|F=s',
'getfile|G',
'propdir|I',
'clearerrorfile|L',
'orasid|O=s',
'restore|R',
'recover|X',
'resincrdmp|M',
'rolltbs|T=s',
'setupgetfile|S',
'ignoreerrors',
'version|v',
'help|h'
) or usage();
if ($context->{"help"})
{
usage();
}
if ($context->{"version"})
{
PrintMessage ("Version is $myversion");
exit (1);
}
if (defined ($context->{"debug"}) && ($context->{"debug"} == 0))
{
$context->{"debug"} = 1;
}
if ($ENV{'XTTDEBUG'})
{
$context->{"debug"} = $ENV{'XTTDEBUG'};
}
# User provided a directory, start from there to pick up files
if ($context->{"propdir"})
{
use File::Basename;
chdir (dirname($0));
}
if ($context->{"propfile"})
{
$xttprop = $context->{"propfile"};
}
else
{
$xttprop = "xtt.properties";
}
}
sub touchErrFile
{
my $message = $_[0];
open ERRFILE, ">>$errfile";
print ERRFILE "$messagen";
close ERRFILE;
}
sub Unlink
{
my $delFile = $_[0];
my $force = $_[1];
if ($force || ($context->{"debug"} < 2))
{
unlink ($delFile);
}
}
sub GetRMANTrace
{
my $fileAppend = $_[0];
my $trace = "";
my $traceFile;
if ($context->{"debug"})
{
$traceFile = "$tmp/rmantrc_".GetTimeStamp().
"_".$fileAppend.".trc";
$trace = "debug trace $traceFile";
}
return ($trace, $traceFile);
}
sub deleteErrFile
{
PrintMessage ("Deleting error file");
if (-e $errfile)
{
Unlink ($errfile, 1);
}
}
sub checkErrFile
{
if (-e $errfile)
{
{
die "
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Some failure occurred. Check $errfile for more details
If you have fixed the issue, please delete $errfile and run it
again OR run xttdriver.pl with -L option
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
";
}
}
}
sub debugprint
{
my $message = $_[0];
my $debuglevel = $_[1];
if ($context -> {"debug"} >= $debuglevel)
{
print $_[0] . "\n";
}
}
sub debug
{
debugprint ($_[0], 1);
}
sub debug3
{
debugprint ($_[0], 3);
}
sub debug4
{
debugprint ($_[0], 4);
}
sub Die
{
my $message = $_[0];
touchErrFile($message);
die "
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
$message
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
";
}
sub trim
{
my $string = $_[0];
$string =~ s/^s+//;
$string =~ s/\s+$//;
return $string;
}
sub checkError
{
my ($errorMessage, $output) = @_;
#No need to check for error when user does not want to
if (defined($context->{"ignoreerrors"}))
{
return;
}
chomp ($output);
$output = trim ($output);
if (($output =~ /ORA[-][0-9]/) || ($output =~ /SP2-.*/))
{
debug $output;
Die("$errorMessage");
}
debug $output;
}
sub PrintMessage
{
my $message = $_[0];
";
}
sub parseProperties
{
PrintMessage ("Parsing properties");
# Check if any failure occured and stop exection
checkErrFile();
@properties = qw(tablespaces stageondest storageondest dfcopydir
backupondest backupformat platformid oracle_home_cnvinst
oracle_sid_cnvinst asm_home asm_sid dstlink
srcdir dstdir srclink rollparallel getfileparallel
metatransfer desthost desttmpdir destuser);
open my $in, "$xttprop" or Die "$xttprop not found: $!";
while(<$in>)
{
next if /^#/;
$props{$1}=$2 while m/(\S+)=(.+)/g;
}
close $in;
if ($context -> {"debug"})
{
foreach my $pkey (keys %props)
{
print "Key: $pkey\n";
print "Values: $props{$pkey}\n";
}
}
@tablespaces = split(/,/, $props{'tablespaces'});
PrintMessage ("Done parsing properties");
}
sub check
{
my $arg = $_[0];
my $key = $_[1];
debug "ARGUMENT $key";
if (!defined ($arg))
{
Die ("Please define xtt.properties:$key");
}
}
sub checkNoPwdSSHEnabled
{
my $outFile = "";
if ($metaTransfer == 0)
{
return;
}
$outFile = "$tmp/transferFile".GetTimeStamp().".log";
unless (system ("ssh $scpParms \"echo host\" 2> $outFile") == 0)
{
my @failArray = ();
open FAIL, "$outFile";
@failArray = <FAIL>;
close FAIL;
Die ("Passwordless SSH not enabled to machine\n@failArray");
}
}
sub transferFiles
{
my @trnsfrFiles = @_;
my $output = 0;
my $files = "";
my $scpParmsL = "";
my $outFile = "$tmp/transferFile".GetTimeStamp().".log";
if ($metaTransfer == 0)
{
return;
}
foreach my $x (@trnsfrFiles)
{
chomp($x);
$files = $files."$x ";
}
$scpParmsL =
"-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ".
"NumberOfPasswordPrompts=0 ";
unless (system ("scp $scpParmsL $files ".$context -> {"remoteConnect"}.
":".$context->{'desttmp'}." 2> $outFile") == 0)
{
print "scp $scpParmsL $files ".$context -> {"remoteConnect"}.
":".$context->{'desttmp'}." 2> $outFile";
my @failArray = ();
open FAIL, "$outFile";
@failArray = <FAIL>;
close FAIL;
Die ("Unable to transfer files to destination machine\n@failArray");
}
Unlink ($outFile);
}
sub getParallelProp
{
my $propValue = $_[0];
# We need to find how how many cores are there in the machine and then use
# that number to see if what the user has provided is less than that
# For now we assume that max is 8
# use Sys::Info;
# use Sys::Info::Constants qw( :device_cpu );
# my $info = Sys::Info->new;
# my $cpu = $info->device( CPU => %options );
#
# printf "CPU: %sn", scalar($cpu->identify) || 'N/A';
# printf "CPU speed is %s MHzn", $cpu->speed || 'N/A';
# printf "There are %d CPUsn" , $cpu->count || 1;
# printf "CPU load: %sn" , $cpu->load || 0;
if ($propValue > 8)
{
$propValue = 8;
PrintMessage ("Maximum $propValue files will be fetched in parallel");
}
return $propValue;
}
sub checkProps
{
PrintMessage ("Checking properties");
# Check if any failure occured and stop exection
checkErrFile();
# The following are required irrespective of what option is used
check $props{'tablespaces'}, $properties[0];
check $props{'platformid'}, $properties[6];
check $props{'backupformat'}, $properties[5];
check $props{'stageondest'}, $properties[1];
if (!defined($props{'parallel'}) ||
$props{'parallel'} <= 0)
{
$props{'parallel'} = 8;
}
if (defined($props{'metatransfer'}))
{
if (!defined($props{'desthost'}))
{
Die ("Files transfered requested, but remote host not defined");
}
if (!defined($props{'desttmpdir'}))
{
Die ("Files transfered requested, but remote dir not defined");
}
if (defined($props{'destuser'}))
{
$context -> {"remoteConnect"} =
$props{'destuser'}."@".$props{'desthost'};
}
else
{
$context -> {"remoteConnect"} = $props{'desthost'};
}
$context -> {"desttmp"} = $props{'desttmpdir'};
$metaTransfer = 1;
$scpParms =
"-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ".
"NumberOfPasswordPrompts=0 ".$props{'desthost'};
}
if (!defined($props{'getfileparallel'}) ||
$props{'getfileparallel'} <= 0)
{
$getParallel = 1;
}
else
{
$getParallel = getParallelProp($props{'getfileparallel'});
}
# Depending on option the checks are done
if (defined($context->{"setupgetfile"}) ||
defined($context->{"getfile"}))
{
check $props{'srcdir'}, $properties[12];
check $props{'dstdir'}, $properties[13];
check $props{'srclink'}, $properties[14];
}
if (defined($context->{"prepare"}))
{
check $props{'dfcopydir'}, $properties[3];
}
if (defined($context->{"rollforward"}))
{
check $props{'backupondest'}, $properties[4];
}
if (defined($context->{"srcdir"}) &&
defined($context->{"dstdir"}))
{
my @srcDir = split(/,/, $props{'srcdir'});
my @dstDir = split(/,/, $props{'dstdir'});
my $dstCount = scalar (@dstDir);
my $srcCount = scalar (@srcDir);
if (($dstCount > 1) && ($srcCount != $dstCount))
{
Die ("checkProps: Number of source objects does not match ".
"destination objects");
}
if ($dstCount >= $dirmaxVal)
{
Die ("checkProps: Number of dir objects cannot exceed $dirmaxVal");
}
}
PrintMessage ("Done checking properties");
}
sub warnMesg
{
my $message = $_[0];
print "
$message
";
}
sub checkDbLink
{
my $sqlOutput ;
my $dblink = $_[0];
my $sqlQuery =
"select 'Count=' || count(*) from dual@"."$dblink;";
$sqlOutput = `sqlplus -L -s $connectstring <
$sqlSettings
$sqlQuery
quit;
EOF
`;
chomp ($sqlOutput);
$sqlOutput = trim ($sqlOutput);
if ($sqlOutput =~ m/^Count=(.*)/)
{
if ($1 <= 0)
{
Die ("Database link $props{'dstlink'} is not working");
}
}
else
{
Die ($sqlOutput);
}
}
sub checkDBState
{
my $sqlOutput ;
my $dblink = $_[0];
my $sqlQuery =
'select \'STATUS=\' || status FROM v\$instance;';
$sqlOutput = `sqlplus -L -s $connectstring <
$sqlSettings
$sqlQuery
quit;
EOF
`;
chomp ($sqlOutput);
$sqlOutput = trim ($sqlOutput);
if ($sqlOutput =~ m/^STATUS=(.*)/)
{
my $startStatus = trim ($1);
if ($startStatus ne "STARTED")
{
Die ("Open database in nomount mode and try rollforward again");
}
}
else
{
Die ($sqlOutput);
}
}
sub checkCompat
{
my $sqlOutput ;
my $sqlQuery =
'select to_number(replace(RPAD(value, 10, \'.0\'), \'.\')) from '.
'v\$parameter WHERE name = \'compatible\';';
$sqlOutput = `sqlplus -s -L $connectstring <
$sqlSettings
$sqlQuery
quit;
EOF
`;
chomp ($sqlOutput);
$sqlOutput = trim ($sqlOutput);
debug "$sqlOutputn";
if ($sqlOutput =~ m/.ORA-./)
{
Die ("Unable to check database compatibility");
}
if ($sqlOutput >= 121000)
{
return VER12;
}
else
{
return VER11;
}
}
sub getPlatName
{
my $sqlOutput ;
my $platid = $props{'platformid'};
my $sqlQuery =
'select platform_name from v\$transportable_platform '.
'where platform_id = '.$platid.';';
$sqlOutput = `sqlplus -s -L $connectstring <
$sqlSettings
$sqlQuery
quit;
EOF
`;
chomp ($sqlOutput);
$sqlOutput = trim ($sqlOutput);
if ($sqlOutput =~ m/.ORA-./)
{
Die ("Unable to fetch platform name");
}
return $sqlOutput;
}
sub fetchDirEntry
{
my $dirtoCheck = $_[0];
my $remoteLink = $_[1];
my @sqlOutput ;
my $sqlQuery ;
debug3 "fetchDirEntry: parms $remoteLink, $dirtoCheckn";
if ($remoteLink eq "")
{
debug "fetchDirEntry: remotelink not present\n";
$sqlQuery =
"SELECT 'DIRECTORY_NAME=' || DIRECTORY_NAME,
'DIRECTORY_PATH=' || DIRECTORY_PATH FROM ".
"ALL_DIRECTORIES WHERE DIRECTORY_NAME in ($dirtoCheck);";
}
else
{
$sqlQuery =
"SELECT 'DIRECTORY_NAME=' || DIRECTORY_NAME,
'DIRECTORY_PATH=' || DIRECTORY_PATH FROM ".
"ALL_DIRECTORIES\@".
"$remoteLink WHERE DIRECTORY_NAME in ($dirtoCheck);";
}
@sqlOutput = `sqlplus -L -s $connectstring <
$sqlSettings
$sqlQuery
quit;
EOF
`;
chomp (@sqlOutput);
return @sqlOutput;
}
sub fetchCheckDirObjectsDST
{
my $dirtoCheck = $_[0];
my $remoteLink = $_[1];
my $dirObjects = $_[2];
my $dirtoCheckLink;
my $dirObjPath;
my @sqlOutput ;
my $sqlQuery ;
my $found ;
my %dstHash = ();
debug "fetchCheckDirObjectsDST: Check dir path $remoteLinkn";
my @srcDir = split(/,/, $props{'srcdir'});
my @dstDir = split(/,/, $props{'dstdir'});
my $tempDir = '';
my $idx = 0;
my $dstCount = scalar (@dstDir);
my $srcCount = scalar (@srcDir);
if (($dstCount > 1) && ($srcCount != $dstCount))
{
Die ("fetchCheckDirObjectsDST: Number of source objects does not match ".
"destination objects");
}
foreach my $var (@dstDir)
{
$var = trim($var);
$tempDir = $tempDir."\'$var\',";
$dstHash{"$var"} = trim($dstDir[$idx]);
debug3 "fetchCheckDirObjectsDST: DestDir: ".$dstHash{"$var"}."\n";
if ($dstCount > 1)
{
$idx = $idx + 1;
}
}
if ($tempDir =~ m/(.*),/)
{
$tempDir = $1;
}
@sqlOutput = fetchDirEntry ($tempDir, $remoteLink);
foreach my $x (@sqlOutput)
{
$x = trim ($x);
if ($x =~ m/^DIRECTORY_NAME=(.*)DIRECTORY_PATH=(.*)/)
{
my $nameTemp = $1;
$dirObjPath = $2;
$nameTemp = trim($nameTemp);
if ($dirObjPath =~ m/(.*)\/$/) # Removes trailing spaces
{
$dirObjPath = $1;
}
$dirObjects->{$nameTemp} = $dirObjPath;
}
}
if ((keys%$dirObjects) == 0)
{
print "fetchCheckDirObjectsDST: Directory ".
"object \"$dirtoCheck\" does not exist\n";
Die (@sqlOutput);
}
return $dirObjPath;
}
sub fetchCheckDirObjectsSRC
{
my $dirtoCheck = $_[0];
my $remoteLink = $_[1];
my $dirObjects = $_[2];
my $dirObjPath;
my @sqlOutput ;
my $sqlQuery ;
my $found ;
my %srcHash = ();
debug "fetchCheckDirObjectsSRC: Check dir path $remoteLinkn";
my @srcDir = split(/,/, $props{'srcdir'});
my @dstDir = split(/,/, $props{'dstdir'});
my $tempDir = '';
my $idx = 0;
my $dstCount = scalar (@dstDir);
my $srcCount = scalar (@srcDir);
if (($dstCount > 1) && ($srcCount != $dstCount))
{
Die ("fetchCheckDirObjectsSRC: Number of source objects does not match ".
"destination objects");
}
foreach my $var (@srcDir)
{
$var = trim($var);
$tempDir = $tempDir."\'$var\',";
$srcHash{"$var"} = trim($dstDir[$idx]);
debug3 "fetchCheckDirObjectsSRC: SRCDIR: ".$srcHash{"$var"}."\n";
if ($dstCount > 1)
{
$idx = $idx + 1;
}
}
if ($tempDir =~ m/(.*),/)
{
$tempDir = $1;
}
@sqlOutput = fetchDirEntry ($tempDir, $remoteLink);
foreach my $x (@sqlOutput)
{
$x = trim ($x);
if ($x =~ m/^DIRECTORY_NAME=(.*)DIRECTORY_PATH=(.*)/)
{
my $nameTemp = $1;
$dirObjPath = $2;
$nameTemp = trim($nameTemp);
if ($dirObjPath =~ m/(.*)\/$/)
{
$dirObjPath = $1;
}
# Create a hash with SRC directory and the DST directory object names.
$dirObjects->{$dirObjPath}->{"SRC"} = $nameTemp;
$dirObjects->{$dirObjPath}->{"DST"} = $srcHash{"$nameTemp"};
}
}
if ((keys%$dirObjects) == 0)
{
print "fetchCheckDirObjectsSRC: Directory ".
"object \"$dirtoCheck\" does not exist\n";
Die (@sqlOutput);
}
return;
}
sub fixXTTNewDatafiles
{
my $dirObjects = $_[0];
my $replaceFile = 0;
my @destArray = ();
debug "fixXTTNewDatafiles: Entered";
open(RMANDSTDF, "$rmandstdf") ||
Die "Cant find $rmandstdf";
@destArray = ;
close RMANDSTDF;
foreach my $line (@destArray)
{
if ($line =~ /.*DESTDIR:.*/)
{
$replaceFile = 1;
last;
}
}
if ($replaceFile)
{
open(RMANDSTDF1, ">$rmandstdf"."temp") ||
Die "Cant find $rmandstdf";
foreach my $line (@destArray)
{
if ($line =~ m/(.*),DESTDIR:(.*)\,(.*)/)
{
debug3 "fixXTTNewDatafiles: $1\n";
my $dest = $dirObjects->{$2}->{"DST"};
print RMANDSTDF1 "$1,$dest".":$3\n";
}
else
{
print RMANDSTDF1 "$line";
}
}
close RMANDSTDF1;
Unlink ("$rmandstdf", 1);
system("\\cp $rmandstdf"."temp $rmandstdf");
}
}
sub verifySrcdirDatafiles
{
my $dfPath = "$tmp/xttprepare.cmd";
my @dfList = ();
my @unidfList = ();
my %seen;
my $name;
debug ("verifySrcdirDatafiles: Entered");
open DFLIST, $dfPath ;
@dfList = ;
close DFLIST;
foreach my $df (@dfList)
{
chomp ($df);
debug3 "verifySrcdirDatafiles: $df";
if ($df =~ /^#DNAME:(.*)/)
{
$name = $1;
if (! (grep { $_ eq $name } @unidfList))
{
push (@unidfList, $1);
}
}
}
foreach my $key (keys %dirHash)
{
debug4 "verifySrcdirDatafiles: Hash key".$key."\n";
debug4 "verifySrcdirDatafiles: Hash value".$dirHash{"$key"}."\n";
}
foreach my $df (@unidfList)
{
debug3 "verifySrcdirDatafiles: $df\n";
if (!defined($dirHash{$df}))
{
Die ("Datafile path $df and source directory object ".
"path ".$dirHash{$df}." doest not match");
}
}
}
sub generate_batch_tsoutput()
{
my $option = $_[0];
my $stageondest = $props{'stageondest'};
my $platform = "'$props{'platform'}'";
my $storageondest = $props{'storageondest'};
my $dfcopydir = $props{'dfcopydir'};
my $backupformat = $props{'backupformat'};
my $script_type = "PREPARE";
my $output;
my $tsbkupmap = "$tmp/tsbkupmap.txt";
my $incrbkups = "$tmp/incrbackups.txt";
my $number_of_tablespaces_per_batch =
int(($#tablespaces + 1)/$props{'parallel'});
# Check if any failure occured and stop exection
checkErrFile();
$number_of_tablespaces_per_batch = ($number_of_tablespaces_per_batch == 0)
? 1
: $number_of_tablespaces_per_batch;
my $total_sets = $number_of_tablespaces_per_batch * $props{'parallel'};
debug3 $connectstring;
debug3 "size of tablespace " . scalar(@tablespaces);
debug3 "No. of tablespaces per batch " . $number_of_tablespaces_per_batch;
my $countno = 0;
my $tablespace_str = "";
my $old_tablespace_str = "";
if ($option == BACKUP)
{
checkMove ($tsbkupmap);
checkMove ($incrbkups);
}
## Generate the rmanconvert.cmd and xttplan.txt from the output
## for Prepare
if (($option == PREPARE) || ($option == BACKUP) || ($option == GETFILE))
{
open(XTTPLAN, ">$xttpath") ||
die 'Cant find xttplan.txt, TMPDIR undefined';
if ($option == PREPARE)
{
open(RMANCONVERT, ">$rmanpath") ||
die 'Cant find rmanconvert.cmd, TMPDIR undefined';
}
# Generate new datafiles for 12c backup
elsif ($option == BACKUP)
{
$script_type = "BACKUP";
open(RMANDSTDF, ">$rmandstdf") ||
die 'Cant find $rmandstdf, TMPDIR undefined';
}
else
{
$script_type = "TRANSFER";
open(RMANDSTDF, ">$rmandstdf") ||
die 'Cant find $rmandstdf, TMPDIR undefined';
}
}
elsif ($option == BCKPINCR)
{
open XTTNEWPLAN, ">$tmp/xttplan.txt.new" or die $!;
$script_type = 'DETNEW';
}
elsif ($option == NEWPLAN)
{
$script_type = 'PREPNEXT';
}
## Based on parallelism, do so many tablespaces at a time.
my $ind = 0;
while ($ind < $total_sets ||
$ind < scalar(@tablespaces))
{
## Remove leading and trailing spaces.
$tablespaces[$ind] =~ s/^\s+//;
$tablespaces[$ind] =~ s/\s+$//;
## grab the rest
while ($ind < scalar(@tablespaces) &&
$ind >= $total_sets)
{
$tablespace_str .= "'" . $tablespaces[$ind] . "'";
if ($ind != $#tablespaces)
{
$tablespace_str .= ",";
}
$ind++;
}
if ($ind < $total_sets)
{
$tablespace_str .= "'" . $tablespaces[$ind] . "'";
if (($ind % $number_of_tablespaces_per_batch) !=
($number_of_tablespaces_per_batch-1))
{
$tablespace_str .= ",";
}
$countno++;
$ind++;
}
if ($countno == $number_of_tablespaces_per_batch ||
$ind == scalar(@tablespaces))
{
debug "TABLESPACE STRING :" . $tablespace_str;
$countno = 0;
## Subst. for tablespace names
open my $in, "xttprep.tmpl" or die $!;
if (($option == PREPARE) || ($option == BACKUP) ||
($option == GETFILE))
{
print "Prepare source for Tablespaces:
$tablespace_str $stageondest\n";
## Open the pareparesrc.sql file and substitute all the parameters
open my $prepout, ">xttpreparesrc.sql" or die $!;
while(<$in>)
{
s/%%stageondest%%/$stageondest/;
s/%%storageondest%%/$storageondest/;
s/%%dfcopydir%%/$dfcopydir/;
s/%%tmp%%/$tmp/;
s/%%parallel%%/$props{'parallel'}/;
s/%%type%%/$script_type/;
s/%%backupformat%%/$backupformat/;
if ($_ =~ /%%TABLESPACES%%/)
{
my @tbs = split(/,/, $tablespace_str);
foreach (@tbs)
{
print $prepout "$_,\n";
}
print $prepout "NULL\n";
}
else
{
print $prepout "$_";
}
}
close $in;
close $prepout;
## timestamp here -- start
print "xttpreparesrc.sql for $tablespace_str started at ".
(localtime) . "\n";
## Reset tablespace string
$old_tablespace_str = $tablespace_str;
$tablespace_str = "";
## Substitution ends here and xttpreparesrc.sql generated
my $output = `sqlplus -L -s $connectstring \@xttpreparesrc.sql`;
## timestamp here -- end
print "xttpreparesrc.sql for $tablespace_str ended at ".
(localtime) . "\n";
checkError ("Error in executing xttpreparesrc.sql", $output);
my @line = split /\n/, $output;
if (($option == BACKUP) || ($option == GETFILE))
{
foreach my $line (@line)
{
if ($line =~ /^#PLAN:/)
{
$line =~ s/^#PLAN://;
print XTTPLAN "$line\n";
if ($line =~ /(\S+)::::(\S+)/)
{
print RMANDSTDF "::$1\n";
}
}
elsif ($line =~ /^#TRANSFER:/)
{
$line =~ s/^#TRANSFER://;
if ($line =~ /.*source_file_name=(.*?),(.*?),(.*)/)
{
my $tsname = $1;
my $fullPath = trim($2);
my $fname = trim($3);
# Remove the trailing "/"
if ($fullPath =~ m/(.*)\/$/)
{
$fullPath = $1;
}
my $fullPath = $fullPath."/".$fname;
push(@{$transfer{$tsname}}, $fullPath);
}
}
elsif ($line =~ /^#NEWDESTDF:/)
{
$line =~ s/^#NEWDESTDF://;
print RMANDSTDF "$line\n";
}
}
# Verify that the files are in proper directory.
&verifySrcdirDatafiles();
}
if (($option == BACKUP) || ($option == PREPARE))
{
foreach my $line (@line)
{
if ($line =~ /^#PLAN:/)
{
$line =~ s/^#PLAN://;
print XTTPLAN "$line\n";
}
elsif ($line =~ /^#CONVERT:/)
{
$line =~ s/^#CONVERT://;
print RMANCONVERT "$line \n";
}
}
## Invoke the backup as copy routine once generated as the last
## step
my $rmancopycmd = "$tmp/xttprepare.cmd";
my ($rmanTrace, $traceFile) = GetRMANTrace("prepare");
$output = `rman target \/ $rmanTrace cmdfile $rmancopycmd`;
if ($output =~ /ERROR MESSAGE/)
{
Die("$output $!");
}
Unlink ($traceFile);
if ($option == BACKUP)
{
# We need to generate tsbkpupmap.txt for
&gentablespace_backupmap( $output ) ;
}
}
}
elsif ($option == BCKPINCR)
{
## Subst. for tablespace names
print "Prepare newscn for Tablespaces: $tablespace_str \n";
## Open the pareparesrc.sql file and substitute all the parameters
open my $prepout, ">xttdetnewfromscnsrc.sql" or die $!;
while(<$in>)
{
s/%%tmp%%/$tmp/;
s/%%type%%/$script_type/;
if ($_ =~ /%%TABLESPACES%%/)
{
my @tbs = split(/,/, $tablespace_str);
foreach (@tbs)
{
print $prepout "$_,\n";
}
print $prepout "NULL\n";
}
else
{
print $prepout "$_";
}
}
close $in;
close $prepout;
## Reset tablespace string
$tablespace_str = "";
## Substitution ends here and xttdetnewfromscnsrc.sql generated
$output = `sqlplus -L -s $connectstring \@xttdetnewfromscnsrc.sql`;
checkError ("Error in executing xttdetnewfromscnsrc.sql", $output);
my @line = split /\n/, $output;
foreach my $line (@line)
{
print XTTNEWPLAN $line . "\n";
}
}
elsif ($option == NEWPLAN)
{
## Subst. for tablespace names
print "Prepare newscn for Tablespaces: $tablespace_str \n";
## Open the pareparesrc.sql file and substitute all the parameters
open my $prepout, ">xttpreparenextiter.sql" or die $!;
while(<$in>)
{
s/%%tmp%%/$tmp/;
s/%%type%%/$script_type/;
if ($_ =~ /%%TABLESPACES%%/)
{
my @tbs = split(/,/, $tablespace_str);
foreach (@tbs)
{
print $prepout "$_,\n";
}
print $prepout "NULL\n";
}
else
{
print $prepout "$_";
}
}
close $in;
close $prepout;
## Reset tablespace string
$tablespace_str = "";
## Substitution ends here and xttpreparenextiter.sql generated
$output = `sqlplus -L -s $connectstring \@xttpreparenextiter.sql`;
checkError ("Error in executing xttpreparenextiter.sql", $output);
}
}
}
if (($option == PREPARE) || ($option == BACKUP) || ($option == GETFILE))
{
close (XTTPLAN);
if ($option == PREPARE)
{
close (RMANCONVERT);
}
elsif ($option == GETFILE)
{
close (RMANDSTDF);
# Replace the paths with the directory destination objects.
fixXTTNewDatafiles (\%dirHash);
# Ver: 1.4.1 We will generate the SQL file in the destination.
my $transferCount = 0;
open GETFILE1, ">$getfile";
foreach my $user (sort keys %transfer)
{
debug "$user: @{$transfer{$user}}\n";
foreach my $file (@{$transfer{$user}})
{
# Bug 17673476: If the destination file is for ASM, it does not
# work with automated filenames. So we convert the names here.
# The automated filenames will be of format "x.y.z". This will
# converted to "x_y_z"
my $srcFile;
my $destFile;
my $srcPath;
my $dstPath;
if ($file =~ m/(.*)\/(.*)/)
{
$srcFile = $2;
$srcPath = $dirHash{"$1"}->{"SRC"};
$dstPath = $dirHash{"$1"}->{"DST"};
}
if ($srcFile =~ m/(.*)\.([0-9]+)\.([0-9]+)/)
{
$destFile = "$1_$2_$3";
}
else
{
$destFile = $srcFile;
}
print GETFILE1
"$transferCount,$srcPath,$srcFile,$dstPath,$destFile\n";
}
$transferCount = $transferCount + 1;
}
close GETFILE1;
}
elsif ($option == BACKUP)
{
close (RMANDSTDF);
}
}
elsif ($option == BCKPINCR)
{
close (XTTNEWPLAN);
}
if ($metaTransfer)
{
my @trnsfrFiles = ();
if ($option == GETFILE)
{
push (@trnsfrFiles, "$tmp/xttnewdatafiles.txt");
push (@trnsfrFiles, "$tmp/getfile.sql");
transferFiles (@trnsfrFiles);
}
if ($option == BCKPINCR)
{
push (@trnsfrFiles, "$tmp/xttplan.txt");
transferFiles (@trnsfrFiles);
}
if ($option == PREPARE)
{
push (@trnsfrFiles, "$tmp/rmanconvert.cmd");
transferFiles (@trnsfrFiles);
@trnsfrFiles = ();
$context->{"desttmp"} = $props{'stageondest'};
push (@trnsfrFiles, $props{'dfcopydir'}."/*");
transferFiles (@trnsfrFiles);
$context -> {"desttmp"} = $props{'desttmpdir'};
}
if ($option == BACKUP)
{
@trnsfrFiles = ();
push (@trnsfrFiles, "$tmp/tsbkupmap.txt");
push (@trnsfrFiles, "$tmp/xttnewdatafiles.txt");
transferFiles (@trnsfrFiles);
open FILE, "$tmp/incrbackups.txt";
@trnsfrFiles = <FILE>;
close FILE;
$context->{"desttmp"} = $props{'stageondest'};
transferFiles (@trnsfrFiles);
$context -> {"desttmp"} = $props{'desttmpdir'};
}
}
}
sub assignGlobVars
{
if (! defined($context->{"xttdir"}))
{
if (defined($ENV{'TMPDIR'}))
{
$tmp = $ENV{'TMPDIR'};
}
else
{
Die ("TMPDIR not defined");
}
}
else
{
$tmp = $context->{"xttdir"};
}
$xttpath = "$tmp/xttplan.txt";
$rmantfrdf = "$tmp/rmantfrdf.sql";
$rmandstdf = "$tmp/xttnewdatafiles.txt";
$xttprep = "$tmp/xttprepare.cmd";
$rmanpath = "$tmp/rmanconvert.cmd";
$errfile = "$tmp/FAILED";
$getfile = "$tmp/getfile.sql";
$connectstring = "/ as sysdba";
$sqlSettings =
"SET TRIMSPOOL OFF LINES 32767 PAGES 0 FEEDBACK OFF ".
"VERIFY OFF DEFINE "&" TERMOUT OFF";
}
sub checkMove
{
my $srcPath = $_[0];
my $dstPath = $_[1];
if (!$dstPath)
{
my $timenow = time;
$dstPath = $srcPath.$timenow;
}
if (-e $srcPath)
{
system("\\mv $srcPath $dstPath");
}
}
sub fixXTTDestFile
{
my $replaceFile = 0;
my @destArray = ();
my %dirHash;
open(RMANDSTDF, "$rmandstdf") ||
Die "Cant find $rmandstdf";
@destArray = ;
close RMANDSTDF;
foreach my $line (@destArray)
{
if (($line !~ m/::.*/) && ($line =~ m/.*\:.*/))
{
$replaceFile = 1;
last;
}
}
if ($replaceFile)
{
&fetchCheckDirObjectsDST($props{'dstdir'}, "", \%dirHash);
open(RMANDSTDF1, ">$rmandstdf"."temp") ||
Die "Cant find $rmandstdf";
foreach my $line (@destArray)
{
if (($line !~ m/::.*/) && ($line =~ /.*,(.*):.*/))
{
my $tempDir = $1;
$line =~ s/$tempDir:/$dirHash{"$tempDir"}/;
}
if ($line =~ m/(.*)\/(.*)\.([0-9]+)\.(.*)/)
{
$line = "$1/$2_$3_$4\n";
}
print RMANDSTDF1 "$line";
}
close RMANDSTDF1;
}
if ($replaceFile)
{
Unlink ("$rmandstdf", 1);
system("\\cp $rmandstdf"."temp $rmandstdf");
}
}
sub getFilesSource
{
PrintMessage ("Getting datafiles from source");
my $output;
my $connectstringcnvinst;
my $pid;
my @getArray = ();
my $getFileTemp;
&checkDbLink($props{'srclink'});
fixXTTDestFile();
$connectstringcnvinst = "/ as sysdba";
open FILE, "$getfile" or Die ("Cannot open $getfile");;
@getArray = ;
close FILE;
foreach my $x (@getArray)
{
chomp ($x);
if ($x =~ m/(.*?),(.*?),(.*?),(.*?),(.*)/)
{
my $sqlQuery =
"BEGIN
DBMS_FILE_TRANSFER.GET_FILE(
source_directory_object => '".$2."',
source_file_name => '".$3."',
source_database => '".$props{'srclink'}."',
destination_directory_object => '".$4."',
destination_file_name => '".$5."');
END;
/
";
$getFileTemp = "getfile"."_$2"."_$3"."_$1".".sql";
$getFileTemp = lc ($getFileTemp);
open FILE, ">$getFileTemp";
print FILE "$sqlQuery\nquit\n";
close FILE;
ChecktoProceed($getParallel);
$pid = fork();
if ($pid == 0)
{
PrintMessage ("Executing getfile for $getFileTemp");
$output = `sqlplus -L -s \"$connectstringcnvinst\" \@$getFileTemp`;
checkError ("Error in executing $getFileTemp", $output);
Unlink ($getFileTemp);
exit (0);
}
else
{
UpdateForkArray ($pid, $getParallel);
}
}
}
while((my $pid = wait()) > 0)
{
#sleep (1);
}
PrintMessage ("Completed getting datafiles from source");
}
sub prepare
{
###
### Prepare starts here
###
PrintMessage ("Starting prepare phase");
# Check if any failure occured and stop exection
checkErrFile();
my $timenow = time;
## Perform cleanup of files by renaming the xttplan.txt, rmanconvert.cmd
## and xttprep.cmd (datafile copy)
checkMove($xttpath, $xttpath.$timenow);
checkMove($rmanpath, $rmanpath.$timenow);
checkMove($xttprep, $xttprep.$timenow);
## For each tablespace, lets generate the scripts
my $stageondest = $props{'stageondest'};
my $platform = "'$props{'platform'}'";
my $storageondest = $props{'storageondest'};
my $dfcopydir = $props{'dfcopydir'};
debug "Parallel:" . $props{'parallel'};
## Remove trailing '/'s
$dfcopydir = $1 if($dfcopydir=~/(.*)\/$/);
## Check if previous ".tf" files present.
##
my @present = glob("$dfcopydir/*.tf");
if (@present)
{
## Try deleting any existing copied datafiles
system("\\rm -f $dfcopydir/*.tf");
sleep 5;
}
if ($context->{"setupgetfile"})
{
&fetchCheckDirObjectsSRC($props{'srcdir'}, "", \%dirHash);
foreach my $keys (keys %dirHash)
{
debug4 "prepare: Key is $keys\n";
debug4 "prepare: Value is ".$dirHash{"$keys"}."\n";
}
&generate_batch_tsoutput(GETFILE);
}
elsif ($context->{"backup"})
{
&generate_batch_tsoutput(BACKUP);
}
else
{
&generate_batch_tsoutput(PREPARE);
}
PrintMessage ("Done with prepare phase");
}
sub checkExec
{
if (defined ($context->{"orahome"}))
{
$ENV{'ORACLE_HOME'} = $context->{"orahome"};
}
else
{
if (defined ($ENV{'ORACLE_HOME'}))
{
$context->{"orahome"} = $ENV{'ORACLE_HOME'};
}
else
{
Die ("Niether ORACLE_HOME defined or orahome passed to script") ;
}
}
if (defined ($context->{"orasid"}))
{
$ENV{'ORACLE_SID'} = $context->{"orasid"};
}
else
{
if (defined ($ENV{'ORACLE_SID'}))
{
$context->{"orasid"} = $ENV{'ORACLE_SID'};
}
else
{
Die ("Niether ORACLE_SID defined or orasid passed to script") ;
}
}
debug "ORACLE_SID : $context->{"orasid"}";
debug "ORACLE_HOME : $context->{"orahome"}";
$ENV{'PATH'} = "$context->{"orahome"}/bin".":".$ENV{'PATH'};
$context->{'sqlexec'} = "$context->{"orahome"}/bin/sqlplus";
$context->{'rmanexec'} = "$context->{"orahome"}/bin/rman";
if (! -x $context->{"rmanexec"})
{
Die ("RMAN executable not found in path");
}
if (! -x $context->{"sqlexec"})
{
Die ("SQLPLUS executable not found in path");
}
}
sub checkArg
{
if ($context->{"backup"} || $context->{"bkpincr"} ||
$context->{"bkpexport"} || $context->{"restore"} ||
$context->{"recover"} || $context->{"resincrdmp"})
{
my $ver = checkCompat();
if ($ver < VER12)
{
Die ("Unable to use given option with this version of DB. Min ver".
" required is 12.1.0.0");
}
}
}
sub Main
{
parseArg();
assignGlobVars();
checkArg();
# User wanted to clear file, do it so here
if ($context->{"clearerrorfile"})
{
Unlink ($errfile, 1);
}
parseProperties();
checkProps();
checkExec();
$context->{"platname"} = getPlatName();
#If we want specify tablespaces to be rolled forward, then store them in
#a hash
if ($context->{"rolltbs"})
{
@rolltbsArray = split (',', $context->{"rolltbs"});
foreach my $x (@rolltbsArray)
{
$tbsHash{"$x"}= 1;
}
}
if (($context->{"incremental"}) ||
($context->{"bkpincr"}) ||
($context->{"bkpexport"}))
{
backincr();
}
elsif ($context->{"rollforward"})
{
fixXTTDestFile();
rollforward();
}
elsif ($context->{"restore"})
{
fixXTTDestFile();
resrecBkp(RESTORE);
}
elsif (($context->{"recover"}) ||
($context->{"resincrdmp"}))
{
fixXTTDestFile();
resrecBkp(RECOVER);
if ($context->{"resincrdmp"})
{
createDumpFile();
plugin(LOCALFILE);
}
}
elsif ($context->{"determinescn"})
{
newplan();
}
elsif ($context->{"convert"})
{
#If the transfer is across the same endian then platformid will be
#set as 0.
if ($props{'platformid'} == 0)
{
genConvertDFNames();
}
else
{
convert();
}
}
elsif ($context->{"generate"})
{
plugin(LINK);
}
elsif (($context->{"prepare"}) || ($context->{"backup"}) ||
($context->{"setupgetfile"}))
{
checkNoPwdSSHEnabled ();
prepare();
}
elsif ($context->{"getfile"})
{
getFilesSource();
}
else
{
usage();
}
}
sub gentablespace_backupmap
{
my @line = split /n/, $_[0];
my $tsbkupmap = "$tmp/tsbkupmap.txt";
my $incrbkups = "$tmp/incrbackups.txt";
my $backupformat = $props{'backupformat'};
my $i = 0;
my @fnums = ();
my @fnumorder = ();
my $chan;
my %bpfn;
my %bpts;
my %chfn;
my $tsname;
my $fno;
my $order = 0;
my $dmpFile = 0;
open(TSBKMAP, ">>$tsbkupmap") ||
Die("Cant open tablespace backup map file $!");
open(INCRBKUPS, ">>$incrbkups") || Die("Cant open incr backups file $!");
while ($i <= $#line)
{
my $str = $line[$i];
if ($str =~ /^ts::(.*)$/)
{
$tsname = $1;
$order = 0;
}
elsif ($str =~ /channel (.*): specifying datafile/)
{
$chan = $1;
}
elsif ($str =~ /.*input Data Pump dump file.*/)
{ ## piece name is on the next line
$i++;
$str = $line[$i];
$chan = $1;
$dmpFile = 1;
}
## In HP, an issue was reported where in the RMAN output was
## shown as 'input datafile fno' instead of 'input datafile file number'.
## So parse for both here.
elsif (($str =~ /input datafile file number=(\d+) name/) ||
($str =~ /input datafile fno=(\d+) name/))
{
$fno = $1 + 0;
push(@fnums, $fno);
$i++;
next;
}
elsif (defined($chan) && $#fnums >= 0 )
{
my @new = @fnums;
$chfn{$chan} -> {"fnumarray"} = \@new;
@fnums = ();
}
elsif ($str =~ /channel (.*): finished piece/)
{
## piece name is on the next line
$i++;
$str = $line[$i];
$chan = $1;
if ($str =~ /piece handle=(.+)[\/](\S+) tag/)
{
if ($dmpFile)
{
my $piece = $2;
debug "backup piece:" . $piece . "\n" ;
debug "TSNAME:" . $tsname;
print TSBKMAP "DMPEXP::$piece\n";
print INCRBKUPS $backupformat."/$piece \n";
}
else
{
$bpfn{$2} -> {"fnumarray"} = $chfn{$chan} -> {"fnumarray"};
$order = $order + 1;
$bpfn{$2} -> {"fnumorder"} = $order;
debug "TSNAME:" . $tsname;
$bpts{$2} = $tsname;
}
}
}
elsif ($str =~ /including current control file in backup set/)
{
do
{
$i++;
$str = $line[$i];
}
while ($str !~ /Finished backup/);
}
$i++;
}
foreach my $pkey (keys %bpfn)
{
print INCRBKUPS $backupformat . "/$pkey\n";
my @fns = @{$bpfn{$pkey} -> {"fnumarray"}};
my $sizefns = @fns;
print TSBKMAP $bpts{$pkey} . "::";
my $orderx = $bpfn{$pkey} -> {"fnumorder"};
foreach my $v (@fns)
{
$sizefns--;
print TSBKMAP $v;
print TSBKMAP "," if ($sizefns > 0);
}
print TSBKMAP ":::". $orderx;
print TSBKMAP "=" . $pkey;
print TSBKMAP "\n";
}
close(TSBKMAP);
close(INCRBKUPS);
}
sub backincr()
{
PrintMessage ("Backup incremental");
checkErrFile();
## Move out any existing xttplan.txt.new
my $xttpathnew = "$tmp/xttplan.txt.new";
my @trnsfrFiles = ();
my $tsbkupmap = "$tmp/tsbkupmap.txt";
my $incrbkups = "$tmp/incrbackups.txt";
if ( -e $xttpathnew )
{
my $timenow = time;
system("\\mv $xttpathnew $xttpath" . $timenow);
}
## Generate the next round xttplan.txt
&generate_batch_tsoutput(BCKPINCR);
## At this point, we must have a new xttplan.txt.new
## populated with required from_scn's for next incremental backup.
debug "Start backup incremental" ;
# Clean up any rmanincr.cmd from TMPDIR area.
my $rmanincrpath = "$tmp/rmanincr.cmd";
my $timenow = time;
if ( -e $rmanincrpath )
{
system("\\mv $rmanincrpath $rmanincrpath" . $timenow);
}
debug "Crossed mv " ;
my $backupformat = $props{'backupformat'};
debug "Crossed mv $backupformat" ;
## Remove trailing '/'s
$backupformat = $1 if($backupformat=~/(.*)\/$/);
if ($context->{"bkpexport"})
{
open(XTTPLAN, $xttpath) || die 'Cant find xttplan.txt, TMPDIR undefined';
my $rman_str1 = "set nocfau;";
my $rman_str;
my @scnArray = ();
my @scnSortedArray = ();
my $scn;
my $rmCmd;
while (<XTTPLAN>)
{
if (/(\S+)::::(\S+)/)
{
push (@scnArray, $2);
}
}
close XTTPLAN;
if (!@scnArray)
{
ErrorMessage ("BACKUPINCR: Could not find lowest SCN");
}
@scnSortedArray = sort (@scnArray);
$scn = $scnSortedArray[0];
$rmCmd = "BACKUP FOR TRANSPORT INCREMENTAL from scn $scn TABLESPACE ".
" $props{'tablespaces'}".
" FORMAT '$backupformat/%U'".
" DATAPUMP FORMAT '$backupformat/%U';";
open(RMANINCR, ">$tmp/rmanincr.cmd") || Die("Cant open rmanincr.cmd $!");
print RMANINCR "$rmCmd";
close RMANINCR;
}
else
{
## Generate $tmp/rmanincr.cmd
debug "Generate $tmp/rmanincr.cmd";
open(RMANINCR, ">$tmp/rmanincr.cmd") || Die("Cant open rmanincr.cmd $!");
## Parse out xttplan.txt and build the rman command
open(XTTPLAN, $xttpath) || die 'Cant find xttplan.txt, TMPDIR undefined';
my $rman_str1 = "set nocfau;";
my $rman_str;
while (<XTTPLAN>)
{
if (/(\S+)::::(\S+)/)
{
my $tablespace = $1;
my $scn = $2;
my $rman_str;
print RMANINCR $rman_str1 . "\n";
$rman_str = "host 'echo ts::$tablespace';";
print RMANINCR $rman_str . "\n";
if ($context->{"bkpincr"})
{
$rman_str = "backup for transport allow INCONSISTENT ".
"incremental from scn $scn ";
}
else
{
$rman_str = "backup incremental from scn $scn ";
}
print RMANINCR $rman_str . "\n";
if ($context->{"incremental"})
{
$rman_str = " tag tts_incr_update tablespace '$tablespace' ".
" format";
print RMANINCR $rman_str . "\n";
}
else
{
$rman_str = " tablespace '$tablespace' format";
print RMANINCR $rman_str . "\n";
}
$rman_str = " '$backupformat/%U';";
print RMANINCR $rman_str . "\n";
}
}
close(XTTPLAN);
close(RMANINCR);
}
## Execute the rman command here
my ($rmanTrace, $traceFile) = GetRMANTrace("incrbackup");
my $output_str = "rman target \/ $rmanTrace cmdfile $rmanincrpath";
print $output_str . "n";
my $output = rman target \/ $rmanTrace cmdfile $rmanincrpath
;
print $output . "n";
checkMove ($tsbkupmap);
checkMove ($incrbkups);
&gentablespace_backupmap( $output ) ;
if ($metaTransfer)
{
@trnsfrFiles = ();
push (@trnsfrFiles, "$tmp/tsbkupmap.txt");
transferFiles (@trnsfrFiles);
open FILE, "$tmp/incrbackups.txt";
@trnsfrFiles = <FILE>;
close FILE;
$context->{"desttmp"} = $props{'stageondest'};
transferFiles (@trnsfrFiles);
$context -> {"desttmp"} = $props{'desttmpdir'};
}
Unlink ($traceFile);
PrintMessage ("Done backing up incrementals");
exit;
}
sub checkInArray
{
my $element = $_[0];
if (@rolltbsArray)
{
if ($tbsHash{"$element"})
{
return 1;
}
else
{
return 0;
}
}
else
{
return 1;
}
}
sub rmconvertedincr
{
# Check if any failure occured and stop exection
checkErrFile();
my $backupondest = $props{'backupondest'};
my $asmhome = $props{'asm_home'};
my $asmsid = $props{'asm_sid'};
my $rmcmd = "";
if (defined $props{'asm_home'})
{
## Lets first delete the incremental backup if any
## this will happen through asmcmd
my $oh_saved = $ENV{'ORACLE_HOME'};
my $ohsid_saved = $ENV{'ORACLE_SID'};
my $asmcmd = 0 ;
my $asmcmd_str;
$ENV{'ORACLE_HOME'} = $asmhome;
$ENV{'ORACLE_SID'} = $asmsid;
# Remove trailing spaces
$backupondest =~ s/\s+$//;
$asmsid =~ s/\s+$//;
$asmcmd_str = "asmcmd rm $backupondest/$xtts_incr_backup";
debug $asmcmd_str . " $asmhome .. $asmsid \n" ;
$asmcmd = `asmcmd rm $backupondest/$xtts_incr_backup`;
debug "ASMCMD: $asmcmd\n";
$ENV{'ORACLE_HOME'} = $oh_saved;
$ENV{'ORACLE_SID'} = $ohsid_saved;
if ($asmcmd == 0)
{
Unlink ("$backupondest/$xtts_incr_backup", 1);
}
}
else
{
Unlink ("$backupondest/$xtts_incr_backup", 1);
}
}
sub ChecktoProceed
{
my $parallel = $_[0];
# Check if any failure occured and stop exection
checkErrFile();
my $running = 0;
if ($#forkArray <= 0)
{
return;
}
do
{
$running = 0;
foreach my $index (0 .. $#forkArray)
{
my $x = $forkArray[$index];
if ($x <= 0)
{
next;
}
my $kid = waitpid($x, WNOHANG);
if ($kid >= 0)
{
$running = $running + 1;
}
else
{
$forkArray[$index] = 0;
}
}
} while ($running >= $parallel);
return;
}
sub UpdateForkArray
{
my ($pid, $parallel) = @_;
if ($#forkArray < $parallel)
{
push (@forkArray, $pid);
}
else
{
foreach my $index (0 .. $#forkArray)
{
my $x = $forkArray[$index];
if ($x == 0)
{
$forkArray[$index] = $pid;
last;
}
}
}
}
sub FixCnvScripts
{
my $toFixSql = $_[0];
my $inpSql = $_[1];
my $fixedStr = $_[2];
my $platformid = $props{'platformid'};
my $fixedStrL = "";
my $len = 0;
open XTTS_INCR_BACKUP, "<$inpSql";
open XTTS_INCR_BACKUP1, ">$toFixSql";
my @arrayXttincr = ;
# Bug 20192155: Use xib instead of "xtts_incr_backup" to prevent
# ORA error ORA-15126 with ASM
$fixedStrL = substr($fixedStr, 0, 42);
$xtts_incr_backup = "xib"."_".$fixedStrL;
$len = length ($xtts_incr_backup);
if ($len > 50)
{
ErrorMessage ("Length of backupiece exceeds 50 chars $xtts_incr_backup");
}
foreach my $x (@arrayXttincr)
{
chomp($x);
if ($x =~ m/(.*)xtts_incr_backup(.*)\,/)
{
print XTTS_INCR_BACKUP1 "$1$xtts_incr_backup$2,\n";
}
elsif ($x =~ m/(.*)xtts_incr_backup(.*)/)
{
print XTTS_INCR_BACKUP1 "$1$xtts_incr_backup$2\n";
}
elsif (!(($platformid == 0) && ($x =~ m/(.*)pltfrmfr(.*)/)))
{
print XTTS_INCR_BACKUP1 "$x\n";
}
else
{
print XTTS_INCR_BACKUP1 "$x\n";
}
}
close XTTS_INCR_BACKUP1;
close XTTS_INCR_BACKUP;
}
sub sortArrayOrder
{
return sort {
(($a =~ /::(.*):::.*/)[0] <=> ($b =~ /::(.*):::.*/)[0] ||
($a =~ /:::(.*?)=/)[0] <=> ($b =~ /:::(.*?)=/)[0]
)
} @_;
}
sub ConvertBackup
{
my $backup = $_[0];
my $dfno = $_[1];
my $fixCnvSql;
my $outputCnvrt;
$fixCnvSql = "$tmp/xxttconv_$backup"."_$dfno.sql";
FixCnvScripts ($fixCnvSql, $cnvrSql, $backup."_".$dfno);
Unlink ("$backupondest/$xtts_incr_backup", 1);
my $outputCnvrt =
`sqlplus -L -s \"$connectstringcnvinst\" \@$fixCnvSql $stageondest/$backup $backupondest $platformid`;
checkError ("$fixCnvSql execution failed", $outputCnvrt);
Unlink ($fixCnvSql);
}
sub RollPiece
{
my $sqlfile = $_[0];
my $outputCnvrt;
## now call generated rollforward
$outputCnvrt =
`sqlplus -L -s \"/ as sysdba\" \@$sqlfile`;
checkError ("$sqlfile execution failed", $outputCnvrt);
}
sub ConvertRoll
{
my ($fixedStr, $oldre, $rb, $rend, $bkupList, $rmList) = @_;
my $rollFile;
$rollFile = "$tmp/xxttroll_$fixedStr.sql";
open (XTTROLL, ">$rollFile") or Die $!;
print XTTROLL $rb;
foreach my $y (@{$rmList})
{
print XTTROLL $y;
}
foreach my $backup (@{$bkupList})
{
my $re = $oldre;
ConvertBackup ($backup, $fixedStr);
$re =~ s/##xtts_incr_backup/$xtts_incr_backup/;
print XTTROLL $re;
}
print XTTROLL $rend;
close XTTROLL;
RollPiece ($rollFile);
rmconvertedincr();
}
sub RestoreRecover
{
my ($fixedStr, $finalRes) = @_;
my $cmdfile = "$tmp/xttresrec_$fixedStr.cmd";
open RMANRE, ">$cmdfile";
print RMANRE "$finalResn";
close RMANRE;
my ($rmanTrace, $traceFile) = GetRMANTrace("resrec");
my $output = rman target \/ $rmanTrace cmdfile $cmdfile
;
debug ($output);
if ($output =~ /ERROR MESSAGE/)
{
Die("$output $!");
}
Unlink ($traceFile);
}
sub clearUpRollfwd
{
Unlink ($fixCnvSql);
Unlink ($xttrollforwardp);
Unlink ($fixRollSql);
rmconvertedincr();
}
sub rollforward()
{
PrintMessage ("Start rollforward");
# Check if any failure occured and stop exection
checkErrFile();
my $connectstringdest = "/ as sysdba";
my $ohcnv = $props{'cnvinst_home'};
my $ohcnvsid = $props{'cnvinst_sid'};
my $tsbkupmappath = "$tmp/tsbkupmap.txt";
my $tsn;
my $fixedSql;
my $pid = 0;
my $i = 0;
my $parent = 0;
my $count = 0;
my $newrm;
my $oldre;
my $rb = q(
set serveroutput on;
DECLARE
outhandle varchar2(512) ;
outtag varchar2(30) ;
done boolean ;
failover boolean ;
devtype VARCHAR2(512);
BEGIN
DBMS_OUTPUT.put_line('Entering RollForward');
-- Now the rolling forward.
devtype := sys.dbms_backup_restore.deviceAllocate;
sys.dbms_backup_restore.applySetDatafile(
check_logical => FALSE, cleanup => FALSE) ;
DBMS_OUTPUT.put_line('After applySetDataFile');
);
my $rm = q(
sys.dbms_backup_restore.applyDatafileTo(
dfnumber => ##fno,
toname => ##fname,
fuzziness_hint => 0, max_corrupt => 0, islevel0 => 0,
recid => 0, stamp => 0);
);
my $rmend = q(
DBMS_OUTPUT.put_line('Done: applyDataFileTo');
);
my $re = q(
DBMS_OUTPUT.put_line('Done: applyDataFileTo');
-- Restore Set Piece
sys.dbms_backup_restore.restoreSetPiece(
handle => '##backupondest/##xtts_incr_backup',
tag => null, fromdisk => true, recid => 0, stamp => 0) ;
DBMS_OUTPUT.put_line('Done: RestoreSetPiece');
-- Restore Backup Piece
sys.dbms_backup_restore.restoreBackupPiece(
done => done, params => null, outhandle => outhandle,
outtag => outtag, failover => failover);
DBMS_OUTPUT.put_line('Done: RestoreBackupPiece');
);
my $rend = q(
sys.dbms_backup_restore.restoreCancel(TRUE);
sys.dbms_backup_restore.deviceDeallocate;
END;
/
exit
);
$stageondest = $props{'stageondest'};
$backupondest = $props{'backupondest'};
$platformid = $props{'platformid'};
$re =~ s/##backupondest/$backupondest/;
$oldre = $re;
if (!defined($ohcnv))
{
$connectstringcnvinst = "/ as sysdba";
}
else
{
debug "convert instance: $ohcnv \n";
debug "convert instance: $ohcnvsid \n";
$connectstringcnvinst =
"/\@(DESCRIPTION=(ADDRESS=(PROTOCOL=BEQ)(PROGRAM=$ohcnv/bin/oracle)".
"(ARGV0=oracle$ohcnvsid)(ARGS='(DESCRIPTION=(LOCAL=YES)".
"(ADDRESS=(PROTOCOL=BEQ)))')".
"(ENVS='ORACLE_HOME=$ohcnv,ORACLE_SID=$ohcnvsid'))".
"(CONNECT_DATA=(SID=$ohcnvsid))) as sysdba";
}
my %tsbkupmap;
my @tsArray = ();
open my $in, $tsbkupmappath or Die ("$tsbkupmappath $!");
@tsArray = <$in>;
close $in;
foreach my $x (sortArrayOrder @tsArray)
{
$_ = $x;
next if /^#/;
if (m/(\S+):::.*?=(\S+)/g)
{
push (@{$tsbkupmap{$1}}, $2);
}
}
##
## Putting database on target in nomount
## as it could cause the following error.
## ORA-00600: internal error code, arguments: [2130], [33], [32], [4]
## The reason for this is :
##
## The code is trying to access KCCDEDBF (datafile) record# 33 when there
## is only record# 32. It looks when you try to apply the incremental
## backup on linux box, you are expecting the datafile# 33 to exists in the
## target database. However, that can't be always true.
##
## This is worked around by starting the target database iin nomount.
## The convert call/script should work in nomount state of database too.
##
if (defined($context->{"rolltbs"}))
{
checkDBState();
}
debug3 ("ROLLFORWARD: Starting DB in nomount mode");
my $outputstart = sqlplus -L -s \"/ as sysdba\" \@xttstartupnomount.sql
;
checkError ("Error in executing xttstartupnomount.sql", $outputstart);
## Generate xttrollforwarddest.sql that is the script
## that will rollforward all the converted datafiles.
my $tsbkcount = scalar keys %tsbkupmap;
if ($tsbkcount == 0)
{
Die ("No tablepsace entries found");
}
my @sortedkeys = sort keys %tsbkupmap;
foreach $tsn (@sortedkeys)
{
my ($ts, $rdfno, $order) = split(/::/, $tsn);
my $fixedStr;
if ($context->{"rolltbs"})
{
my $checkArray = checkInArray($ts);
if ($checkArray == 0)
{
next;
}
}
debug "rdfno " . $rdfno . "\n";
my @rdfnos = split /,/, $rdfno;
open (ROLLPLAN, "$tmp/xttnewdatafiles.txt") or Die $!;
my $scrape = 0;
# Check if any failure occured and stop exection
checkErrFile();
debug "BEFORE ROLLPLAN\n";
my @rmList = ();
while (<ROLLPLAN>)
{
if ($scrape == 1 && $_ !~ /::/)
{
chop;
my $oldrm = $rm;
my $dfstr = $_;
my ($dfno, $dfname) = split /,/, $dfstr;
my $ind;
## include the dfno only if present in the tsbkupmap.txt list
## of dfnos.
my $found = 0;
for ($ind = 0; $ind <= $#rdfnos ; $ind++)
{
if ($dfno == $rdfnos[$ind])
{
$found = 1;
last;
}
}
if ($found == 1)
{
debug "datafile number : $dfno \n";
debug "datafile name : $dfname\n";
$newrm = $rm;
$newrm =~ s/##fno/$dfno/;
$newrm =~ s/##fname/'$dfname'/;
push (@rmList, $newrm);
}
}
if (/^::$ts$/)
{
$scrape = 1;
}
elsif (/^::/)
{
$scrape = 0;
}
}
push (@rmList, $rmend);
close(ROLLPLAN);
debug "AFTER ROLLPLAN\n";
$rollParallel = $props{'rollparallel'};
$fixedStr = $rdfno;
$fixedStr =~ tr/,/_/;
# Bug 20192155: Use xib instead of "xtts_incr_backup" to prevent
# ORA error ORA-15126 with ASM
my $fixedStrL = substr($fixedStr, 0, 25);
if ($rollParallel)
{
ChecktoProceed($rollParallel);
$pid = fork();
if ($pid == 0)
{
ConvertRoll ($fixedStrL, $oldre, $rb ,$rend, \@{$tsbkupmap{$tsn}},
\@rmList);
exit (0);
}
else
{
UpdateForkArray ($pid, $rollParallel);
}
}
else
{
ConvertRoll ($fixedStrL, $oldre, $rb ,$rend, \@{$tsbkupmap{$tsn}},
\@rmList);
}
}
while((my $pid = wait()) > 0)
{
#sleep (1);
}
# Check if any failure occured and stop exection
checkErrFile();
my $outputstart = sqlplus -L -s \"/ as sysdba\" \@xttdbopen.sql
;
PrintMessage ("End of rollforward phase");
exit;
}
sub resrecBkp
{
my $option = $_[0];
PrintMessage ("Start restore/recover");
# Check if any failure occured and stop exection
checkErrFile();
my $tsbkupmappath = "$tmp/tsbkupmap.txt";
my $tsn;
my $fixedSql;
my $pid = 0;
my $i = 0;
my $parent = 0;
my $count = 0;
my $newrm;
my $oldre;
my $platName = $context->{"platname"};
$stageondest = $props{'stageondest'};
$platformid = $props{'platformid'};
my %tsbkupmap;
my @tsArray = ();
open my $in, $tsbkupmappath or Die ("$tsbkupmappath $!");
@tsArray = <$in>;
close $in;
foreach my $x (sortArrayOrder @tsArray)
{
$_ = $x;
next if /^#/;
if (m/(\S+):::.*?=(\S+)/g)
{
push (@{$tsbkupmap{$1}}, $2);
}
}
my $tsbkcount = scalar keys %tsbkupmap;
if ($tsbkcount == 0)
{
Die ("No tablepsace entries found");
}
my @sortedkeys = sort keys %tsbkupmap;
my $res = '';
my $finalRes = '';
foreach $tsn (@sortedkeys)
{
my ($ts, $rdfno, $order) = split(/::/, $tsn);
my $fixedStr;
debug "rdfno " . $rdfno . "\n";
my @rdfnos = split /,/, $rdfno;
open (ROLLPLAN, "$tmp/xttnewdatafiles.txt") or Die $!;
my $scrape = 0;
# Check if any failure occured and stop exection
checkErrFile();
debug "BEFORE ROLLPLAN\n";
my @rmList = ();
my $dfnofinal = 0;
$res = '';
while (<ROLLPLAN>)
{
if ($_ !~ /::/)
{
chop;
my $dfstr = $_;
my ($dfno, $dfname) = split /,/, $dfstr;
my $ind;
## include the dfno only if present in the tsbkupmap.txt list
## of dfnos.
my $found = 0;
for ($ind = 0; $ind <= $#rdfnos ; $ind++)
{
if ($dfno == $rdfnos[$ind])
{
$found = 1;
if (($option == RESTORE) || ($option == RECOVER))
{
if ($res ne '')
{
$res = $res.",";
}
if ($option == RECOVER)
{
$res = $res."'$dfname'";
}
else
{
$res = $res."$dfno format '$dfname'";
}
}
}
}
}
}
if ($option == RESTORE)
{
$finalRes =
"restore from platform '$platName' FOREIGN DATAFILE ".
$res.
" from backupset '$stageondest/@{$tsbkupmap{$tsn}}';\n";
}
elsif ($option == RECOVER)
{
$finalRes =
" recover from platform '$platName' FOREIGN DATAFILECOPY ".
$res.
" from backupset '$stageondest/@{$tsbkupmap{$tsn}}';\n";
}
close(ROLLPLAN);
debug "AFTER ROLLPLAN\n";
$rollParallel = $props{'rollparallel'};
$fixedStr = $rdfno;
$fixedStr =~ tr/,/_/;
if ($rollParallel)
{
ChecktoProceed($rollParallel);
$pid = fork();
if ($pid == 0)
{
RestoreRecover ($fixedStr, $finalRes);
exit (0);
}
else
{
UpdateForkArray ($pid, $rollParallel);
}
}
else
{
RestoreRecover ($fixedStr, $finalRes);
}
}
while((my $pid = wait()) > 0)
{
#sleep (1);
}
# Check if any failure occured and stop exection
checkErrFile();
PrintMessage ("End of restore/recover phase");
}
sub createDumpFile
{
my $option = $_[0];
my $finalRes = '';
my $bkPiece = '';
my $platName = $context->{"platname"};
PrintMessage ("Start creating dumpfile");
# Check if any failure occured and stop exection
checkErrFile();
my $tsbkupmappath = "$tmp/tsbkupmap.txt";
my %tsbkupmap;
my @tsArray = ();
open my $in, $tsbkupmappath or Die ("$tsbkupmappath $!");
@tsArray = <$in>;
close $in;
foreach my $x (sortArrayOrder @tsArray)
{
$_ = $x;
next if /^#/;
if (m/.*DMPEXP::(.*)/)
{
$bkPiece = $1;
last;
}
}
my $dmpFile = "impdp".GetTimeStamp().".dmp";
my $dumpDir;
$context->{"dmpfile"} = $dmpFile;
if (defined($props{'dumpdir'}))
{
$dumpDir = $props{'dumpdir'};
if (!-e $dumpDir)
{
$dumpDir = $tmp;
}
}
else
{
$dumpDir = $tmp;
}
$finalRes =
" restore from platform '$platName' ".
" dump file '$dmpFile' ".
" datapump destination '$dumpDir' ".
" from backupset '$stageondest/$bkPiece';\n";
debug "$finalResn";
open RMANRE, ">rman_createdmp.cmd";
print RMANRE "$finalResn";
close RMANRE;
my ($rmanTrace, $traceFile) = GetRMANTrace("convert");
my $output = rman target \/ $rmanTrace cmdfile rman_createdmp.cmd
;
debug ($output);
if ($output =~ /ERROR MESSAGE/)
{
Die("$output $!");
}
Unlink ($traceFile);
# Check if any failure occured and stop exection
checkErrFile();
PrintMessage ("End of creating dumpfile");
}
sub newplan()
{
# Check if any failure occured and stop exection
checkErrFile();
## Move the current xttplan.txt.new as xttplan.txt
## The xttplan.txt.new gets generated during backincr()
my $xttplanpath = "$tmp/xttplan.txt";
my $xttplanpathnew = "$tmp/xttplan.txt.new";
if ( -e $xttplanpath )
{
my $timenow = time;
system("\\mv $xttplanpath $xttplanpath" . $timenow);
system("\\mv $xttplanpathnew $xttplanpath");
}
## Checks that no tablespace went read only
## or datafiles offline
&generate_batch_tsoutput(NEWPLAN);
print "New $tmp/xttplan.txt with FROM SCN's generatedn";
exit;
}
sub convert()
{
PrintMessage ("Performing convert");
# Check if any failure occured and stop exection
checkErrFile();
my ($rmanTrace, $traceFile) = GetRMANTrace("convert");
my $output = rman target \/ $rmanTrace cmdfile $rmanpath
;
if ($output =~ /ERROR MESSAGE/)
{
Die("$output $!");
}
Unlink ($traceFile);
my @lines = split /n/, $output;
my $xttnewdata = "$tmp/xttnewdatafiles.txt";
if ( -e $xttnewdata )
{
my $timenow = time;
system("\\mv $xttnewdata $xttnewdata" . $timenow);
}
open(XTTNEW, ">$xttnewdata") || Die("Cant open xttnewdatafiles.txt");
foreach my $line (@lines)
{
my $tsname;
my $filno;
$_ = $line;
if (/converted datafile=(.+)\/(\w+)[_](\d+)\.xtf/)
{
print XTTNEW "$3,";
$line =~ s/.*converted datafile=//;
print XTTNEW "$line\n";
}
elsif(/^ts(\S+)/)
{
print XTTNEW $1 . "\n";
$tsname = $1;
}
}
close(XTTNEW);
PrintMessage ("Converted datafiles listed in: $xttnewdata");
exit;
}
sub genConvertDFNames
{
my @convertArray = ();
# Check if any failure occured and stop exection
checkErrFile();
open(RMANCONVERT, "$rmanpath") ||
die 'Cant find rmanconvert.cmd, TMPDIR undefined';
@convertArray = ;
close RMANCONVERT;
open(RMANDSTDF, ">$rmandstdf") ||
Die "Cant find $rmandstdf";
foreach my $x (@convertArray)
{
chomp($x);
$x = trim($x);
if ($x =~ /'(.*)\.tf'/)
{
$x = $1.".tf";
if ($x =~ /.*(.+)\/(\w+)[_](\d+)\.tf/)
{
print RMANDSTDF "::$2\n";
print RMANDSTDF "$3,$x\n";
}
}
}
close RMANDSTDF;
exit;
}
sub plugin()
{
my $option = $_[0];
PrintMessage ("Generating plugin");
# Check if any failure occured and stop exection
checkErrFile();
my $xttplugin = "$tmp/xttplugin.txt";
my $tts = "transport_tablespaces=";
my $tdf = "transport_datafiles=";
my $comma = 0;
my $xttnewdata = "$tmp/xttnewdatafiles.txt";
my $command_str;
my $dmpFile = $context->{"dmpfile"};
if ( -e $xttplugin )
{
my $timenow = time;
system("\\mv $xttplugin $xttplugin" . $timenow);
}
open(XTTPLUG, ">$xttplugin") || Die("Unable to open file $xttplugin");
if ($option == LINK)
{
$command_str =
"impdp directory=<DATA_PUMP_DIR> logfile=<tts_imp.log> \\" . "\n" .
"network_link=<ttslink> transport_full_check=no \\" . "\n" ;
}
else
{
$command_str =
"impdp directory=<DATA_PUMP_DIR> logfile=<tts_imp.log> \\" . "\n" .
"dumpfile=$dmpFile \\" . "\n" ;
}
print XTTPLUG $command_str;
if ($option == LINK)
{
print XTTPLUG $tts;
open(XTTPLAN, $xttpath) || Die("Cant find xttplan.txt\n $!");
while (<XTTPLAN>)
{
if ($comma == 1 && /::::/)
{
print XTTPLUG ",";
$comma = 0;
}
if (/(\S+)::::(\S+)/)
{
print XTTPLUG $1;
$comma = 1;
}
}
close(XTTPLAN);
print XTTPLUG " \\\n";
}
print XTTPLUG $tdf;
$comma = 0;
open(XTTNEWDATA, $xttnewdata) || Die("Cant find xttnewdatafiles.txt\n $!");
while ()
{
if ($comma == 1)
{
print XTTPLUG ",";
$comma = 0;
}
if (! /^::\S+/)
{
chop;
my ($dfno, $dfname) = split /,/, $_;
print XTTPLUG "'" . $dfname . "'";
$comma = 1;
}
}
print XTTPLUG "n";
close(XTTNEWDATA);
close(XTTPLUG);
PrintMessage ("Done generating plugin file $xttplugin");
exit;
}
sub usage
{
print STDERR << "EOF";
This program prepares, backsup and rollsforward tablespaces
for cross-platform transportable tablespaces.
usage: $0
{[--backup|-b] || [--bkpincr|-B] || [--bkpexport/E]
[--resincrdmp|M]
[--convert/-c] || [--generate|-e] || [--incremental|-i] ||
[[--prepare|-p] || [--getfile|-G]] ||
[--restore|R] || [--recover|X]
[--rollforward|-r [--rolltbs|-T <TBS1[,TBS2]>] ||
[--determinescn|-s] ||
[--orasid/O] || [--orahome|-o]]
[--help|-h]}
Additional options
------------------
[--debug|d] [--clearerrorfile|-C] [--xttdir|Dir <tmpdir>]
[-F/--propfile] [-I/--propdir]
-b : For 12c and above, generate transportable backups
-B : For 12c and above, generate level 1 transportable backups
-c : conversion of datafiles
-M : create the dump file from the generated backup
-e : generate impdp script: export over new link
-i : incremental backup
-p : prepare
-G : get datafiles from source database using get_file, should not
be used together with -p
-r : roll forward datafiles
-s : new from_scn values into xttplan.txt
-R : For 12c restore the datafiles from the backups
-X : For 12c recover the datafiles from the backups
-T : roll forward specific tablespace(s)
-h : this (help) message (Default)
-d : provides more debug information, also rman is called with debug
option so that tracing is better.
-L : delete the ERROR FILE and proceed with the execution
-D : Instead of defining environement variable, user can pass tmpdir
through xttdir
-O : Use this option to pass ORACLE_SID to override the environment
variable
-o : Use this option to pass ORACLE_HOME to override the environment
variable
-I : Use this option to mention the location from where the script
will pick the properties file etc
-F : Use this option to mention the location from where the script
will pick the properties file.
example: $0 -p
$0 -i
$0 -r
$0 -s
EOF
exit;
}
sub GetTimeStamp
{
my $timeStamp = $$."_".int(rand(1000));
return ($timeStamp);
}
Main();
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。