# $Header: emdb/sysman/admin/scripts/db/convert/convert.pl /st_emdbsa_11.2/3 2009/02/06 23:27:15 hasriniv Exp $ # # convert.pl # # Copyright (c) 2004, 2009, Oracle and/or its affiliates.All rights reserved. # # NAME # convert.pl - # # DESCRIPTION # # # NOTES # # # MODIFIED (MM/DD/YY) # hasriniv 01/29/09 - Code sync # hasriniv 07/16/08 - Fix for bug 7171390 # nachen 06/19/08 - XbranchMerge nachen_bug-7144603 from st_emdbsa_11.1 # nachen 06/06/08 - fix internal references security issue # sxzhu 01/23/07 - Enable public for RAC # sxzhu 06/07/05 - Remove version check # sxzhu 04/15/05 - Specify recovery area size by MB # sxzhu 04/07/05 - Handle large plsql output # sxzhu 04/04/05 - Fix migrating online logs for RAC # sxzhu 03/02/05 - Workaround 10.1.0.4 ASM DB # sxzhu 02/18/05 - Handle no row return from query # sxzhu 02/11/05 - Handle generating revert script on NT # sxzhu 01/14/05 - More migrate logs # sxzhu 11/13/04 - Keep temp dir if asmTest set # sxzhu 10/28/04 - Add single quote around tablespace # sxzhu 10/14/04 - Support multiple channels and customizing tbs # sxzhu 09/27/04 - Migrate spfile between disk groups # sxzhu 09/17/04 - Do not copy online logs if on diskgroup # sxzhu 08/25/04 - Checkpoint after switching log # sxzhu 07/20/04 - Do not reset UserID # sxzhu 07/07/04 - Use singel rman command to backup datafiles # szhu 06/15/04 - Not create recovery script if not migrate db files # szhu 06/03/04 - Generate script to recover the original database # szhu 06/02/04 - Crosscheck before migrating archivelogs and others # szhu 05/13/04 - Migrate spfile # szhu 05/07/04 - Support hot migration # szhu 05/05/04 - Crosscheck copy and others # szhu 04/30/04 - Remove new logs before copy original ones # szhu 04/28/04 - Rebounce db after migrating online logs # szhu 04/13/04 - szhu_convert_0412 # szhu 03/30/04 - Creation # require "$ENV{EMDROOT}/sysman/admin/scripts/db/convert/convert_common.pl"; use strict; use warnings; use File::Temp qw/ tempfile tempdir /; use File::Spec; use vars qw/ $userID $OS $NT $S $TEMP $DELIMITER $DEFER_OUTPUT $OUTPUT_LOC $INDEX $CUSTOMIZE_LEVEL/; # Global variables #$userID = ""; $CUSTOMIZE_LEVEL = "tablespace"; #could also be datafile #$ENV{EMAGENT_PERL_TRACE_LEVEL} = 0; #DEBUG level. # Set environment variables # Call sub set_env_var() in emd_common.pl # set_env(oracleHome, oracleSid) sub set_env { EMD_PERL_DEBUG("convert.set_env(): *** START ***"); &set_env_var($_[0], $_[1]); EMD_PERL_DEBUG("convert.set_env(): *** END ***"); } # Set the source DB credential # setSrcDBCredential(userName, password) sub setSrcDBCredential { EMD_PERL_DEBUG("convert.setSrcDBCredential(): *** START ***"); my ($userName, $password, $tns) = @_; if(!$tns){ $userID = $userName."/".$password; } else{ $userID = $userName."/".$password."\@${tns}"; } EMD_PERL_DEBUG("convert.setSrcDBCredential(): User Name: $userName"); EMD_PERL_DEBUG("convert.setSrcDBCredential(): *** END ***"); } # Filter out DB credential from rman script, which is written to trace file # filterDBCredentialFromRmanScript(rmanScript) sub filterDBCredentialFromRmanScript { my ($rmanScript) = @_; my $position1 = index($rmanScript, "TARGET"); my $position2 = index($rmanScript, ";"); my $replacedLength = $position2 - $position1 - 7; substr($rmanScript, $position1 + 7, $replacedLength) = "username/password(Hiden intentionally)"; return $rmanScript; } # Parse the output string to detect ORA- errors # parseOutput(output) sub parseOutput { EMD_PERL_DEBUG("convert_common.parseOutput(): *** START ***"); my ($output) = @_; if ($output eq "") { EMD_PERL_ERROR("convert_common.parseOutput(): Output file is empty!"); } if($output !~ /RMAN-[0-9]/) { EMD_PERL_DEBUG("convert_common.parseOutput(): No Error found."); } else { EMD_PERL_ERROR("convert_common.parseOutput(): RMAN- ERROR! Exit! See output log."); exit(1); } EMD_PERL_DEBUG("convert_common.parseOutput(): *** END ***"); } # Run given rman script on DB # The caller is responsible to close the returned fileHandle # runRman(rmanScript, hideOutput) will hide standard output for any # defined parameter "hideOutput" # runRman(rmanScript) will print standard output sub runRman { EMD_PERL_DEBUG("convert.runRman(): *** START ***"); my ($rman_string) = $_[0]; my $rman_string_debug = &filterDBCredentialFromRmanScript($rman_string); EMD_PERL_DEBUG("convert.runRman(): RMAN Script:\n$rman_string_debug"); (my $fh, my $filename) = &create_temp_file(); if($NT) { $filename = "$TEMP\\"."convert.$$"; EMD_PERL_DEBUG("convert.runRman(): temp file: $filename"); open(RMAN_SCRIPT, "|$ENV{ORACLE_HOME}/bin/rman >$filename") || die "Cannot open pipe for RMAN_SCRIPT"; print RMAN_SCRIPT $rman_string; #close RMAN_SCRIPT || die "Bad RMAN_SCRIPT"; close RMAN_SCRIPT || print "Could not close pipe for RMAN_SCRIPT"; } else { open(RMAN_SCRIPT, "|$ENV{ORACLE_HOME}/bin/rman >$filename") || die "Cannot open pipe for RMAN_SCRIPT"; print RMAN_SCRIPT $rman_string; #close RMAN_SCRIPT || die "Bad RMAN_SCRIPT"; close RMAN_SCRIPT || print "Could not close pipe for RMAN_SCRIPT"; } #Open the temp file to print output to standard output and debug trace file open (OUT_PUT, "$filename") || die "Unable to open tempfile for OUT_PUT\n"; my @output_content = ; my $output_string = "@output_content"; close OUT_PUT; if(!defined($_[1])) { if(defined($DEFER_OUTPUT) && ($DEFER_OUTPUT eq 'Y')) { &deferOutput($output_string); } else { print STDOUT $output_string; } } EMD_PERL_DEBUG("convert.runRman(): OUT_PUT:\n$output_string"); &parseOutput($output_string); EMD_PERL_DEBUG("convert.runRman(): *** END ***"); return ($fh, $filename); } # Run srvctl utility with given command # runSrvctl(command) sub runSrvctl { EMD_PERL_DEBUG("convert.runSrvctl(): *** START ***"); my ($command) = @_; EMD_PERL_DEBUG("convert.runSrvctl(): Command:\n$command"); (my $fh, my $filename) = &create_temp_file(); if($NT) { $filename = "$TEMP\\"."convert.$$"; EMD_PERL_DEBUG("convert.runSrvctl(): temp file: $filename"); } # Do NOT check the return value of this command $command = "$ENV{ORACLE_HOME}${S}bin${S}srvctl ".${command}; my(@res) = `$command >$filename 2>&1`; my $mesg = getOutputFromFile($filename); if(defined($DEFER_OUTPUT) && ($DEFER_OUTPUT eq 'Y')) { &deferOutput($mesg); } else { print STDOUT $mesg; } if($?) { my($err) = "@res"; EMD_PERL_ERROR("convert.runSrvctl(): $command: $err"); exit(1); } close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.runSrvctl(): *** END ***"); } # Check if an spfile is used # return spfile name: if empty, no spfile is being used. # Call &set_env($oracleHome, $oracleSid) before calling this method. # spfileUsed() sub spfileUsed { EMD_PERL_DEBUG("convert.spfileUsed(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "set linesize 512;\n"; $sql_string .= "variable rowcount number;\n"; $sql_string .= "variable spfile_val varchar2(256);\n"; $sql_string .= "BEGIN\n"; $sql_string .= " select count(*) INTO :rowcount from v\$parameter where name = 'spfile';\n"; $sql_string .= " dbms_output.put_line('Row count: '||:rowcount);\n"; $sql_string .= " IF (:rowcount > 0) then\n"; $sql_string .= " select value INTO :spfile_val from v\$parameter where name = 'spfile';\n"; $sql_string .= " IF NOT (:spfile_val IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing spfile value: ');\n"; $sql_string .= " dbms_output.put_line('spfile# '||:spfile_val);\n"; $sql_string .= " end if;\n"; $sql_string .= " end if;\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); my $spfileName = ""; open (SPFILE, "$filename") || die "Unable to open tempfile for SPFILE\n"; while () { if ($_=~/\bspfile#/) { chomp($_); $spfileName = substr $_, 8; #spfile name starts from position 8 } } close SPFILE; close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.spfileUsed(): spfile name: $spfileName"); EMD_PERL_DEBUG("convert.spfileUsed(): *** END ***"); return $spfileName; } # Check if the target is a cluster database, get the db name # return israc (Y/N) and dbname # Call &set_env($oracleHome, $oracleSid) before calling this method. # getIsRacDbName() sub getIsRacDbName { EMD_PERL_DEBUG("convert.getIsRacDbName(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "set linesize 512;\n"; $sql_string .= "variable is_rac varchar2(20);\n"; $sql_string .= "variable db_unique_name varchar2(256);\n"; $sql_string .= "BEGIN\n"; $sql_string .= " select value INTO :is_rac from v\$parameter where name = 'cluster_database';\n"; $sql_string .= " dbms_output.put_line('Start printing RAC flag and unique db name: ');\n"; $sql_string .= " dbms_output.put_line('rac# '||:is_rac);\n"; $sql_string .= " select value INTO :db_unique_name from v\$parameter where name = 'db_unique_name';\n"; $sql_string .= " IF NOT (:db_unique_name IS NULL) then\n"; $sql_string .= " dbms_output.put_line('dbname# '||:db_unique_name);\n"; $sql_string .= " end if;\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); my $israc = ""; my $dbname = ""; open (DBNAME, "$filename") || die "Unable to open tempfile for DBNAME\n"; while () { if ($_=~/\brac#/) { chomp($_); $israc = substr $_, 5; #rac flag starts from position 5 if($israc eq "TRUE"){ $israc = "Y"; } else{ $israc = "N"; } } if ($_=~/\bdbname#/) { chomp($_); $dbname = substr $_, 8; #dbname starts from position 8 } } close DBNAME; close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.spfileUsed(): getIsRacDbName israc: $israc; dbname: $dbname"); EMD_PERL_DEBUG("convert.getIsRacDbName(): *** END ***"); return ($israc, $dbname); } # Check the DB block change tracking mode. If enabled, disable it. # Retrun tracking filename if enabled, otherwise, return empty. # Call &set_env(oracleHome, oracleSid) before calling this method. # checkAndDisableChangeTracking() sub checkAndDisableChangeTracking { EMD_PERL_DEBUG("convert.checkAndDisableChangeTracking(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "set linesize 513;\n"; $sql_string .= "variable status varchar2(20);\n"; $sql_string .= "variable filename varchar2(256);\n"; $sql_string .= "BEGIN\n"; $sql_string .= " select STATUS, FILENAME INTO :status, :filename from V\$BLOCK_CHANGE_TRACKING;\n"; $sql_string .= " IF NOT (:status IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing status value: ');\n"; $sql_string .= " dbms_output.put_line('status# '||:status);\n"; $sql_string .= " IF (:status = 'ENABLED') then\n"; $sql_string .= " execute immediate 'ALTER DATABASE DISABLE BLOCK CHANGE TRACKING';\n"; $sql_string .= " IF NOT (:filename IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing filename value: ');\n"; $sql_string .= " dbms_output.put_line('filename# '||:filename);\n"; $sql_string .= " end if;\n"; $sql_string .= " end if;\n"; $sql_string .= " end if;\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); my $status = ""; my $trackingFile = ""; open (CHANGE_TRACKING, "$filename") || die "Unable to open tempfile for CHANGE_TRACKING\n"; while () { if ($_=~/\bstatus#/) { chomp($_); $status = substr $_, 8; #status name starts from position 8 } if ($_=~/\bfilename#/) { chomp($_); $trackingFile = substr $_, 10; #trackingFile name starts from position 10 } } close CHANGE_TRACKING; close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.checkAndDisableChangeTracking(): Change tracking status: $status"); EMD_PERL_DEBUG("convert.checkAndDisableChangeTracking(): Change tracking filename: $trackingFile"); EMD_PERL_DEBUG("convert.checkAndDisableChangeTracking(): *** END ***"); return $trackingFile; } # Enable the DB block change tracking mode. # Call &set_env(oracleHome, oracleSid) before calling this method. # enableChangeTracking(tracking_file) sub enableChangeTracking { EMD_PERL_DEBUG("convert.enableChangeTracking(): *** START ***"); my ($tracking_file) = $_[0]; if(defined($tracking_file)) { EMD_PERL_DEBUG("convert.enableChangeTracking(): Change tracking file: $tracking_file"); } else { EMD_PERL_DEBUG("convert.enableChangeTracking(): Change tracking file: NOT DEFINED"); } my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "set linesize 513;\n"; $sql_string .= "variable status varchar2(20);\n"; $sql_string .= "variable filename varchar2(256);\n"; $sql_string .= "BEGIN\n"; $sql_string .= " dbms_output.enable(2000000);\n"; $sql_string .= " select STATUS INTO :status from V\$BLOCK_CHANGE_TRACKING;\n"; $sql_string .= " IF NOT (:status IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Block change tracking status: '||:status);\n"; $sql_string .= " IF (:status = 'DISABLED') then\n"; if(defined($tracking_file)) { $sql_string .= " execute immediate 'ALTER DATABASE ENABLE BLOCK CHANGE TRACKING USING FILE \'\'"."$tracking_file"."\'\' REUSE';\n"; } else { $sql_string .= " execute immediate 'ALTER DATABASE ENABLE BLOCK CHANGE TRACKING';\n"; } $sql_string .= " end if;\n"; $sql_string .= " end if;\n"; $sql_string .= " select STATUS, FILENAME INTO :status, :filename from V\$BLOCK_CHANGE_TRACKING;\n"; $sql_string .= " IF NOT (:status IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing status value: ');\n"; $sql_string .= " dbms_output.put_line('status# '||:status);\n"; $sql_string .= " end if;\n"; $sql_string .= " IF NOT (:filename IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing filename value: ');\n"; $sql_string .= " dbms_output.put_line('filename# '||:filename);\n"; $sql_string .= " end if;\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); my $status = ""; my $trackingFile = ""; open (CHANGE_TRACKING, "$filename") || die "Unable to open tempfile for CHANGE_TRACKING\n"; while () { if ($_=~/\bstatus#/) { chomp($_); $status = substr $_, 8; #status name starts from position 8 } if ($_=~/\bfilename#/) { chomp($_); $trackingFile = substr $_, 10; #trackingFile name starts from position 10 } } close CHANGE_TRACKING; close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.enableChangeTracking(): Change tracking status: $status"); EMD_PERL_DEBUG("convert.enableChangeTracking(): Change tracking filename: $trackingFile"); EMD_PERL_DEBUG("convert.enableChangeTracking(): *** END ***"); } # Get valid log file names (separated by delimiters) # Call &set_env($oracleHome, $oracleSid) before calling this method. # getLogFiles() sub getLogFiles { EMD_PERL_DEBUG("convert.getLogFiles(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "set linesize 513;\n"; $sql_string .= "variable status varchar2(7);\n"; $sql_string .= "variable filename varchar2(256);\n"; $sql_string .= "declare\n"; $sql_string .= " i binary_integer := 1;\n"; $sql_string .= "BEGIN\n"; $sql_string .= " dbms_output.enable(2000000);\n"; $sql_string .= " FOR cfrec IN (SELECT status, member FROM v\$logfile WHERE status is NULL or status='STALE')\n"; $sql_string .= " LOOP\n"; $sql_string .= " dbms_output.put_line('Checked file ' || i || ':');\n"; $sql_string .= " dbms_output.put_line('filename# '||cfrec.member);\n"; $sql_string .= " i := i + 1;\n"; $sql_string .= " END LOOP;\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); my $logFile = ""; my $logFiles = ""; open (LOG_FILE, "$filename") || die "Unable to open tempfile for LOG_FILE\n"; while () { if ($_=~/\bfilename#/) { chomp($_); $logFile = substr $_, 10; #logFile name starts from position 10 $logFiles .= ${logFile}.${DELIMITER}; EMD_PERL_DEBUG("convert.getLogFiles(): Filename: $logFile"); } } close LOG_FILE; close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.getLogFiles(): *** END ***"); return $logFiles; } # Get tempfile attributes (separated by delimiters) # Call &set_env($oracleHome, $oracleSid) before calling this method. # getTempFiles() sub getTempFiles { EMD_PERL_DEBUG("convert.getTempFiles(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "set linesize 513;\n"; $sql_string .= "variable filename varchar2(513);\n"; $sql_string .= "variable fileId number;\n"; $sql_string .= "variable size number;\n"; $sql_string .= "variable tablespace varchar2(30);\n"; $sql_string .= "variable autoextensible varchar2(3);\n"; $sql_string .= "variable nextsize number;\n"; $sql_string .= "variable maxsize number;\n"; $sql_string .= "declare\n"; $sql_string .= " i binary_integer := 1;\n"; $sql_string .= "BEGIN\n"; $sql_string .= " dbms_output.enable(2000000);\n"; $sql_string .= " FOR tfrec IN (SELECT v.name AS filename, v.file# as fileId, (d.bytes/1024) AS filesize, d.tablespace_name AS tbs, d.autoextensible AS autoexend, (d.increment_by * v.block_size/1024 ) AS nextsize, (d.maxblocks * v.block_size/1024) AS maxsize\n"; $sql_string .= " FROM v\$tempfile v, sys.dba_temp_files d \n"; $sql_string .= " WHERE v.file# = d.file_id and v.status='ONLINE' \n"; $sql_string .= " ORDER BY v.file#)\n"; $sql_string .= " LOOP\n"; $sql_string .= " dbms_output.put_line('Checked file ' || i || ':');\n"; $sql_string .= " dbms_output.put_line('filename# '||tfrec.filename);\n"; $sql_string .= " dbms_output.put_line('fileId# '||tfrec.fileId);\n"; $sql_string .= " dbms_output.put_line('size# '||tfrec.filesize);\n"; $sql_string .= " dbms_output.put_line('tablespace# '||tfrec.tbs);\n"; $sql_string .= " dbms_output.put_line('autoextend# '||tfrec.autoexend);\n"; $sql_string .= " dbms_output.put_line('nextsize# '||tfrec.nextsize);\n"; $sql_string .= " dbms_output.put_line('maxsize# '||tfrec.maxsize);\n"; $sql_string .= " i := i + 1;\n"; $sql_string .= " END LOOP;\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); my $tempFile = ""; my $tempFiles = ""; my $fileId = ""; my $fileIds = ""; my $size = ""; my $sizes = ""; my $tablespace = ""; my $tablespaces = ""; my $autoextend = ""; my $autoextends = ""; my $nextsize = ""; my $nextsizes = ""; my $maxsize = ""; my $maxsizes = ""; open (TEMP_FILE, "$filename") || die "Unable to open tempfile for TEMP_FILE\n"; while () { if ($_=~/\bfilename#/) { chomp($_); $tempFile = substr $_, 10; #file name starts from position 10 $tempFiles .= ${tempFile}.${DELIMITER}; } if ($_=~/\bfileId#/) { chomp($_); $fileId = substr $_, 8; #fileId starts from position 8 $fileIds .= ${fileId}.${DELIMITER}; } if ($_=~/\bsize#/) { chomp($_); $size = substr $_, 6; #size starts from position 6 $sizes .= ${size}."K".${DELIMITER}; } if ($_=~/\btablespace#/) { chomp($_); $tablespace = substr $_, 12; #tablespace starts from position 12 $tablespaces .= ${tablespace}.${DELIMITER}; } if ($_=~/\bautoextend#/) { chomp($_); $autoextend = substr $_, 12; #autoextend starts from position 12 $autoextends .= ${autoextend}.${DELIMITER}; } if ($_=~/\bnextsize#/) { chomp($_); $nextsize = substr $_, 10; #nextsize starts from position 10 $nextsizes .= ${nextsize}."K".${DELIMITER}; } if ($_=~/\bmaxsize#/) { chomp($_); $maxsize = substr $_, 9; #maxsize starts from position 9 $maxsizes .= ${maxsize}."K".${DELIMITER}; } } close TEMP_FILE; close $fh; if($NT) { &removeFile($filename); } my @tempAutoextends = split /$DELIMITER/, $autoextends; my @tempNextsizes = split /$DELIMITER/, $nextsizes; my @tempMaxsizes = split /$DELIMITER/, $maxsizes; my $tempAutoextend = ""; my $autoextendClause = ""; my $autoextendClauses = ""; my $index = 0; foreach $tempAutoextend (@tempAutoextends) { if($tempAutoextend eq "YES") { $autoextendClause = "AUTOEXTEND ON NEXT ".$tempNextsizes[$index]." MAXSIZE ".$tempMaxsizes[$index]; } else { $autoextendClause = " "; } $autoextendClauses .= ${autoextendClause}.${DELIMITER}; $index ++; } EMD_PERL_DEBUG("convert.getTempFiles(): Filenames: $tempFiles"); EMD_PERL_DEBUG("convert.getTempFiles(): FileIds: $fileIds"); EMD_PERL_DEBUG("convert.getTempFiles(): Sizes: $sizes"); EMD_PERL_DEBUG("convert.getTempFiles(): Tablespaces: $tablespaces"); EMD_PERL_DEBUG("convert.getTempFiles(): Autoextend Clauses: $autoextendClauses"); EMD_PERL_DEBUG("convert.getTempFiles(): *** END ***"); return ($tempFiles, $fileIds, $sizes, $tablespaces, $autoextendClauses); } # Associate front end tempDGs with the backend temp ids # if could not match ids for any reason, just use DB area # getToLocationsForTempfiles(ids, tempIDs, tempDGs, dbFilesLoc) sub getToLocationsForTempfiles { EMD_PERL_DEBUG("convert.getToLocationsForTempfiles(): *** START ***"); my ($ids, $tempIDs, $tempDGs, $dbFilesLoc) = @_; my @backIds = split /$DELIMITER/, $ids; my @frontIds = split /$DELIMITER/, $tempIDs; my @frontDgs = split /$DELIMITER/, $tempDGs; EMD_PERL_DEBUG("convert.getToLocationsForTempfiles(): dbFilesLoc: $dbFilesLoc"); EMD_PERL_DEBUG("convert.getToLocationsForTempfiles(): backIds: @backIds"); EMD_PERL_DEBUG("convert.getToLocationsForTempfiles(): frontIds: @frontIds"); EMD_PERL_DEBUG("convert.getToLocationsForTempfiles(): frontDgs: @frontDgs"); my $id1; my $id2; my $index = 0; my $toLocations = ""; foreach $id1 (@backIds) { $id2 = $frontIds[$index]; if($id1 eq $id2) { $toLocations .= $frontDgs[$index].${DELIMITER}; } else { $toLocations .= ${dbFilesLoc}.${DELIMITER}; } $index = $index + 1; } EMD_PERL_DEBUG("convert.getToLocationsForTempfiles(): toLocations: $toLocations"); EMD_PERL_DEBUG("convert.getToLocationsForTempfiles(): *** END ***"); return $toLocations; } # Drop tempfiles # Call &set_env($oracleHome, $oracleSid) before calling this method. # dropTempfiles(fileNames) sub dropTempfiles { EMD_PERL_DEBUG("convert.dropTempfiles(): *** START ***"); my ($fileNames) = @_; my @tempFileNames = split /$DELIMITER/, $fileNames; EMD_PERL_DEBUG("convert.dropTempfiles(): Files to be dropped: @tempFileNames"); #drop multiple tempfiles my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; my $tempFileName; foreach $tempFileName (@tempFileNames) { $sql_string .= "ALTER DATABASE TEMPFILE '$tempFileName' drop;\n"; } $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.dropTempfiles(): *** END ***"); } # Add tempfiles after opening the database # Call &set_env($oracleHome, $oracleSid) before calling this method. # addTempfilesConvert(toLocations, sizes, tablespaces, autoextends) sub addTempfilesConvert { EMD_PERL_DEBUG("convert.addTempfilesConvert(): *** START ***"); my ($toLocations, $sizes, $tablespaces, $autoextends) = @_; my @tempLocs = split /$DELIMITER/, $toLocations; my @tempSizes = split /$DELIMITER/, $sizes; my @tempTablespaces = split /$DELIMITER/, $tablespaces; my @tempAutoextends = split /$DELIMITER/, $autoextends; EMD_PERL_DEBUG("convert.addTempfilesConvert(): Temp files will be added to: @tempLocs"); #add multiple tempfiles my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; my $tempSize; my $index = 0; foreach $tempSize (@tempSizes) { $sql_string .= "ALTER TABLESPACE \"$tempTablespaces[$index]\" "; $sql_string .= "ADD TEMPFILE '$tempLocs[$index]' "; $sql_string .= "SIZE $tempSize REUSE $tempAutoextends[$index];\n"; $index ++; } $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.addTempfilesConvert(): *** END ***"); } # Backup a given file at the same location # Generate a unique name for the new file and return the new name # backupFile(srcfile) sub backupFile { EMD_PERL_DEBUG("convert.backupFile(): *** START ***"); my($srcfile) = @_; EMD_PERL_DEBUG("convert.backupFile(): Source File: $srcfile"); if(! -e $srcfile) { EMD_PERL_DEBUG("convert.backupFile(): File $srcfile does not exist!"); return ""; } my $destfile = ${srcfile}.".saved"; while(-e "$destfile") { EMD_PERL_DEBUG("convert.backupFile(): $destfile already exist"); $destfile .= "_1"; } EMD_PERL_DEBUG("convert.backupFile(): Destination File: $destfile"); !copyFile($srcfile, $destfile) || (EMD_PERL_DEBUG("convert.backupFile(): Error copying $srcfile to $destfile") && (die "convert.backupFile(): Error copying $srcfile to $destfile")); EMD_PERL_DEBUG("convert.backupFile(): *** END ***"); return $destfile; } # Retrun the space_used value. # Call &set_env(oracleHome, oracleSid) before calling this method. # getSpaceUsedInRecoveryArea() sub getSpaceUsedInRecoveryArea { EMD_PERL_DEBUG("convert.getSpaceUsedInRecoveryArea(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "variable rowcount number;\n"; $sql_string .= "variable used_space number;\n"; $sql_string .= "BEGIN\n"; $sql_string .= " select count(*) INTO :rowcount from v\$recovery_file_dest;\n"; $sql_string .= " IF (:rowcount > 0) then\n"; $sql_string .= " select NVL(space_used/1024/1024 + 10 - MOD(space_used/1024/1024,10), 0) as space_used_mb INTO :used_space from v\$recovery_file_dest;\n"; $sql_string .= " IF NOT (:used_space IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing used space value: ');\n"; $sql_string .= " dbms_output.put_line('space# '||:used_space);\n"; $sql_string .= " end if;\n"; $sql_string .= " end if;\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); my $space = 0; open (USED_SPACE, "$filename") || die "Unable to open tempfile for USED_SPACE\n"; while () { if ($_=~/\bspace#/) { chomp($_); $space = substr $_, 7; #space name starts from position 7 } } close USED_SPACE; close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.getSpaceUsedInRecoveryArea(): Used space in recovery area: $space"); EMD_PERL_DEBUG("convert.getSpaceUsedInRecoveryArea(): *** END ***"); return $space; } # Construct init parameters based on user selections # constructInitParameters(isMigrateDBFiles, isMigrateRecoveryFiles, isSetupRecoveryAreaOnly, # dbFilesLoc, recoveryFilesLoc, recoveryFilesSize, # multiplexLocsArray, recoverySpace) sub constructInitParameters { EMD_PERL_DEBUG("convert.constructInitParameters(): *** START ***"); my ($isMigrateDBFiles, $isMigrateRecoveryFiles, $isSetupRecoveryAreaOnly, $dbFilesLoc, $recoveryFilesLoc, $recoveryFilesSize, $multiplexLocsArray, $recoverySpace) = @_; EMD_PERL_DEBUG("convert.constructInitParameters(): isMigrateDBFiles: $isMigrateDBFiles"); EMD_PERL_DEBUG("convert.constructInitParameters(): isMigrateRecoveryFiles: $isMigrateRecoveryFiles"); EMD_PERL_DEBUG("convert.constructInitParameters(): isSetupRecoveryAreaOnly: $isSetupRecoveryAreaOnly"); EMD_PERL_DEBUG("convert.constructInitParameters(): dbFilesLoc: $dbFilesLoc"); EMD_PERL_DEBUG("convert.constructInitParameters(): recoveryFilesLoc: $recoveryFilesLoc"); EMD_PERL_DEBUG("convert.constructInitParameters(): recoveryFilesSize: $recoveryFilesSize"); EMD_PERL_DEBUG("convert.constructInitParameters(): multiplexLocsArray: $multiplexLocsArray"); EMD_PERL_DEBUG("convert.constructInitParameters(): recoverySpace: $recoverySpace"); my $SINGLEQUOTE = "'"; my $modifiedInitNames = ""; my $modifiedInitValues = ""; if($isMigrateDBFiles eq "Y") { $modifiedInitNames .= "DB_CREATE_FILE_DEST".${DELIMITER}; $modifiedInitValues .= ${SINGLEQUOTE}.$dbFilesLoc.${SINGLEQUOTE}.${DELIMITER}; } if($isMigrateRecoveryFiles eq "Y") { $modifiedInitNames .= "DB_RECOVERY_FILE_DEST_SIZE".${DELIMITER}; if($isSetupRecoveryAreaOnly eq "Y") { $modifiedInitValues .= ${recoveryFilesSize}."M".${DELIMITER}; } else { my $space = $recoverySpace + $recoveryFilesSize; #make sure the size is within limit if($space >= 2**44) { $space = 2**44 - 1; } $modifiedInitValues .= ${space}."M".${DELIMITER}; } $modifiedInitNames .= "DB_RECOVERY_FILE_DEST".${DELIMITER}; $modifiedInitValues .= ${SINGLEQUOTE}.${recoveryFilesLoc}.${SINGLEQUOTE}.${DELIMITER}; } my($multiplexInitNames, $multiplexInitValues) = getSimpleMultiplexParameters($multiplexLocsArray); $modifiedInitNames .= $multiplexInitNames; $modifiedInitValues .= $multiplexInitValues; #my($largePoolSizeName, $largePoolSizeValue) = getLargePoolSizeParameter(); #$modifiedInitNames .= $largePoolSizeName; #$modifiedInitValues .= $largePoolSizeValue; EMD_PERL_DEBUG("convert.constructInitParameters(): modifiedInitNames: $modifiedInitNames"); EMD_PERL_DEBUG("convert.constructInitParameters(): modifiedInitValues: $modifiedInitValues"); EMD_PERL_DEBUG("convert.constructInitParameters(): *** END ***"); return ($modifiedInitNames, $modifiedInitValues); } # Get multiplex parameters based on user selections and some complex algorithm # This method is not being used. # getMultiplexParameters(isMigrateRecoveryFiles, dbFilesLoc, # recoveryFilesLoc, multiplexLocsArray) sub getMultiplexParameters { EMD_PERL_DEBUG("convert.getMultiplexParameters(): *** START ***"); my ($isMigrateRecoveryFiles, $dbFilesLoc, $recoveryFilesLoc, $multiplexLocsArray) = @_; EMD_PERL_DEBUG("convert.getMultiplexParameters(): isMigrateRecoveryFiles: $isMigrateRecoveryFiles"); EMD_PERL_DEBUG("convert.getMultiplexParameters(): dbFilesLoc: $dbFilesLoc"); EMD_PERL_DEBUG("convert.getMultiplexParameters(): recoveryFilesLoc: $recoveryFilesLoc"); EMD_PERL_DEBUG("convert.getMultiplexParameters(): multiplexLocsArray: $multiplexLocsArray"); my $SINGLEQUOTE = "'"; my $modifiedInitNames = ""; my $modifiedInitValues = ""; my @multiplexLocs = split /$DELIMITER/, $multiplexLocsArray; #one multiplexing location is specified #the location is set the same as DB_CREATE_FILE_DEST if($#multiplexLocs == 0) { $modifiedInitNames .= "DB_CREATE_ONLINE_LOG_DEST_1".${DELIMITER}; $modifiedInitValues .= ${SINGLEQUOTE}.$dbFilesLoc.${SINGLEQUOTE}.${DELIMITER}; } #two multiplexing locations are specified #no need to set DB_CREATE_ONLINE_LOG_DEST_n if the #DB_CREATE_FILE_DEST and DB_RECOVERY_FILE_DEST are set #two multiplexing locations are specified #if only DB_CREATE_FILE_DEST is set #the first location is set the same as DB_CREATE_FILE_DEST #the second one is set as the second specified by user if($#multiplexLocs == 1) { $modifiedInitNames .= "DB_CREATE_ONLINE_LOG_DEST_1".${DELIMITER}; $modifiedInitValues .= ${SINGLEQUOTE}.$dbFilesLoc.${SINGLEQUOTE}.${DELIMITER}; if($isMigrateRecoveryFiles ne "Y") { $modifiedInitNames .= "DB_CREATE_ONLINE_LOG_DEST_2".${DELIMITER}; $modifiedInitValues .= ${SINGLEQUOTE}.$multiplexLocs[1].${SINGLEQUOTE}.${DELIMITER}; } } #three or more multiplexing locations are specified #the locations are set the same as DB_CREATE_FILE_DEST and DB_RECOVERY_FILE_DEST, #and other specified if($#multiplexLocs > 1) { my $index = ""; $modifiedInitNames .= "DB_CREATE_ONLINE_LOG_DEST_1".${DELIMITER}; $modifiedInitValues .= ${SINGLEQUOTE}.$dbFilesLoc.${SINGLEQUOTE}.${DELIMITER}; if($isMigrateRecoveryFiles eq "Y") { $modifiedInitNames .= "DB_CREATE_ONLINE_LOG_DEST_2".${DELIMITER}; $modifiedInitValues .= ${SINGLEQUOTE}.${recoveryFilesLoc}.${SINGLEQUOTE}.${DELIMITER}; foreach (2 .. ($#multiplexLocs)) { $index = $_ + 1; $modifiedInitNames .= "DB_CREATE_ONLINE_LOG_DEST_"."$index".${DELIMITER}; $modifiedInitValues .= ${SINGLEQUOTE}.$multiplexLocs[$_].${SINGLEQUOTE}.${DELIMITER}; } } else { foreach (1 .. ($#multiplexLocs)) { $index = $_ + 1; $modifiedInitNames .= "DB_CREATE_ONLINE_LOG_DEST_"."$index".${DELIMITER}; $modifiedInitValues .= ${SINGLEQUOTE}.$multiplexLocs[$_].${SINGLEQUOTE}.${DELIMITER}; } } } EMD_PERL_DEBUG("convert.getMultiplexParameters(): modifiedInitNames: $modifiedInitNames"); EMD_PERL_DEBUG("convert.getMultiplexParameters(): modifiedInitValues: $modifiedInitValues"); EMD_PERL_DEBUG("convert.getMultiplexParameters(): *** END ***"); return ($modifiedInitNames, $modifiedInitValues); } # Get multiplex parameters based on user selections and simple algorithm # Just set all user specifications as init parameters # getSimpleMultiplexParameters(multiplexLocsArray) sub getSimpleMultiplexParameters { EMD_PERL_DEBUG("convert.getSimpleMultiplexParameters(): *** START ***"); my ($multiplexLocsArray) = @_; EMD_PERL_DEBUG("convert.getSimpleMultiplexParameters(): multiplexLocsArray: $multiplexLocsArray"); my $SINGLEQUOTE = "'"; my $modifiedInitNames = ""; my $modifiedInitValues = ""; my @multiplexLocs = split /$DELIMITER/, $multiplexLocsArray; my $index = 0; foreach (0 .. ($#multiplexLocs)) { $index = $_ + 1; $modifiedInitNames .= "DB_CREATE_ONLINE_LOG_DEST_"."$index".${DELIMITER}; $modifiedInitValues .= ${SINGLEQUOTE}.$multiplexLocs[$_].${SINGLEQUOTE}.${DELIMITER}; } EMD_PERL_DEBUG("convert.getSimpleMultiplexParameters(): modifiedInitNames: $modifiedInitNames"); EMD_PERL_DEBUG("convert.getSimpleMultiplexParameters(): modifiedInitValues: $modifiedInitValues"); EMD_PERL_DEBUG("convert.getSimpleMultiplexParameters(): *** END ***"); return ($modifiedInitNames, $modifiedInitValues); } # Add 1MB if not an ASM DB # getLargePoolSizeParameter() sub getLargePoolSizeParameter { EMD_PERL_DEBUG("convert.getLargePoolSizeParameter(): *** START ***"); my $modifiedInitNames = ""; my $modifiedInitValues = ""; my $db_area = &getDBArea(); #For now, if db_area starts with '+', the DB is an ASM DB my $startStr = substr($db_area, 0, 1); if($startStr ne '+') { my $largePoolSize = &getLargePoolSize(); $largePoolSize = $largePoolSize + 1024000; $modifiedInitNames .= "LARGE_POOL_SIZE".${DELIMITER}; $modifiedInitValues .= ${largePoolSize}.${DELIMITER}; } EMD_PERL_DEBUG("convert.getLargePoolSizeParameter(): modifiedInitNames: $modifiedInitNames"); EMD_PERL_DEBUG("convert.getLargePoolSizeParameter(): modifiedInitValues: $modifiedInitValues"); EMD_PERL_DEBUG("convert.getLargePoolSizeParameter(): *** END ***"); return ($modifiedInitNames, $modifiedInitValues); } # Retrun the large_pool_size (bytes). # Call &set_env(oracleHome, oracleSid) before calling this method. # getLargePoolSize() sub getLargePoolSize { EMD_PERL_DEBUG("convert.getLargePoolSize(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "variable pool_size number;\n"; $sql_string .= "BEGIN\n"; $sql_string .= " select value INTO :pool_size from v\$parameter where name = 'large_pool_size';\n"; $sql_string .= " IF NOT (:pool_size IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing large pool size value: ');\n"; $sql_string .= " dbms_output.put_line('poolsize# '||:pool_size);\n"; $sql_string .= " end if;\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); my $size = ""; open (POOL_SIZE, "$filename") || die "Unable to open tempfile for POOL_SIZE\n"; while () { if ($_=~/\bpoolsize#/) { chomp($_); $size = substr $_, 10; #poolsize name starts from position 10 } } close POOL_SIZE; close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.getLargePoolSize(): Large pool size: $size"); EMD_PERL_DEBUG("convert.getLargePoolSize(): *** END ***"); return $size; } # Retrun db_create_file_dest value. # Call &set_env(oracleHome, oracleSid) before calling this method. # getDBArea() sub getDBArea { EMD_PERL_DEBUG("convert.getDBArea(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "variable db_area varchar2(512);\n"; $sql_string .= "BEGIN\n"; $sql_string .= " select value INTO :db_area from v\$parameter where name = 'db_create_file_dest';\n"; $sql_string .= " IF NOT (:db_area IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing db area value: ');\n"; $sql_string .= " dbms_output.put_line('dbarea# '||:db_area);\n"; $sql_string .= " end if;\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); my $db_area = ""; open (DB_AREA, "$filename") || die "Unable to open tempfile for DB_AREA\n"; while () { if ($_=~/\bdbarea#/) { chomp($_); $db_area = substr $_, 8; #dbarea name starts from position 8 } } close DB_AREA; close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.getDBArea(): DB Area: $db_area"); EMD_PERL_DEBUG("convert.getDBArea(): *** END ***"); return $db_area; } # Append name=value to init parameter file # appendInitFile(modifiedParamNames, modifiedParamValues, pfileFullName) sub appendInitFile { EMD_PERL_DEBUG("convert.appendInitFile(): *** START ***"); my ($modifiedParamNames, $modifiedParamValues, $pfileFullName) = @_; if(($modifiedParamNames eq "") || ($modifiedParamNames eq "$DELIMITER")) { EMD_PERL_DEBUG("convert.appendInitFile(): NO PARAMETER TO MODIFY, returning"); EMD_PERL_DEBUG("convert.appendInitFile(): *** END ***"); return; } EMD_PERL_DEBUG("convert.appendInitFile(): modifiedParamNames: $modifiedParamNames"); EMD_PERL_DEBUG("convert.appendInitFile(): modifiedParamValues: $modifiedParamValues"); my @modifiedParamNames = split /$DELIMITER/, $modifiedParamNames; my @modifiedParamValues = split /$DELIMITER/, $modifiedParamValues; open(INIT_ORA, ">>$pfileFullName") || die "Cannot open $pfileFullName"; #Add modified init parameters (name=value) in the materialized init.ora foreach (0 .. $#modifiedParamNames) { print INIT_ORA "$modifiedParamNames[$_]=$modifiedParamValues[$_]\n"; } close INIT_ORA || die "Cannot close $pfileFullName"; #For debug if($ENV{EMAGENT_PERL_TRACE_LEVEL} >= 0) { open (INIT_ORA_FILE, "$pfileFullName") || die "Unable to open tempfile for INIT_ORA_FILE\n"; my @file_content = ; my $file_string = "@file_content"; close INIT_ORA_FILE; EMD_PERL_DEBUG("convert.appendInitFile(): INIT_ORA_FILE:\n $file_string"); } EMD_PERL_DEBUG("convert.appendInitFile(): *** END ***"); } # Comment the control_files parameter in init parameter file # commentCtlFileParamInitFile(pfileFullName) sub commentCtlFileParamInitFile { EMD_PERL_DEBUG("convert.commentCtlFileParamInitFile(): *** START ***"); my ($pfileFullName) = @_; EMD_PERL_DEBUG("convert.commentCtlFileParamInitFile(): pfileFullName: $pfileFullName"); open(ORIG_INIT_ORA, "$pfileFullName") || die "Cannot open $pfileFullName"; my @output_content = ; my $contentString = "@output_content"; close ORIG_INIT_ORA; #comment name by prepending '#' my $name = "*.control_files"; my $upperContentString = uc $contentString; my $upperName = uc $name; my $index = index($upperContentString, $upperName); if($index < 0) { $name = "control_files"; } my $newName = "#"."$name"; my $quoteName = quotemeta($name); $contentString =~ s/$quoteName/$newName/gi; (my $fh, my $filename) = &create_temp_file(); open(INIT_ORA, ">$filename") || die "Cannot open $filename"; print INIT_ORA $contentString; close INIT_ORA || die "Cannot close $filename"; #overwrite the original file !copyFile($filename, $pfileFullName) || (EMD_PERL_DEBUG("convert.commentCtlFileParamInitFile(): Error copying $filename to $pfileFullName") && (die "convert.commentCtlFileParamInitFile(): Error copying $filename to $pfileFullName")); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.commentCtlFileParamInitFile(): *** END ***"); } # Modify init parameter file # If the name is found, comment it with '#', then append the new name=value # at the end of the file, if not found, just append name=value at the end of the file. # modifyInitFile(modifiedParamNames, modifiedParamValues, pfileFullName) sub modifyInitFile { EMD_PERL_DEBUG("convert.modifyInitFile(): *** START ***"); my ($modifiedParamNames, $modifiedParamValues, $pfileFullName) = @_; if(($modifiedParamNames eq "") || ($modifiedParamNames eq "$DELIMITER")) { EMD_PERL_DEBUG("convert.modifyInitFile(): NO PARAMETER TO MODIFY, returning"); EMD_PERL_DEBUG("convert.modifyInitFile(): *** END ***"); return; } EMD_PERL_DEBUG("convert.modifyInitFile(): modifiedParamNames: $modifiedParamNames"); EMD_PERL_DEBUG("convert.modifyInitFile(): modifiedParamValues: $modifiedParamValues"); my @modifiedParamNames = split /$DELIMITER/, $modifiedParamNames; my @modifiedParamValues = split /$DELIMITER/, $modifiedParamValues; open(ORIG_INIT_ORA, "$pfileFullName") || die "Cannot open $pfileFullName"; my @output_content = ; my $contentString = "@output_content"; close ORIG_INIT_ORA; #comment name by prepending '#' my $name = ""; my $newName = ""; my $index = -1; my $upperContentString = uc $contentString; my $upperName = ""; foreach (0 .. $#modifiedParamNames) { $name = "*.".$modifiedParamNames[$_]; $upperName = uc $name; $index = index($upperContentString, $upperName); if($index < 0) { $name = $modifiedParamNames[$_]; } $newName = "#"."$name"; my $quoteName = quotemeta($name); $contentString =~ s/$quoteName/$newName/gi; } (my $fh, my $filename) = &create_temp_file(); open(INIT_ORA, ">>$filename") || die "Cannot open $filename"; print INIT_ORA $contentString; #Append modified init parameters (name=value) in the materialized init.ora foreach (0 .. $#modifiedParamNames) { print INIT_ORA "$modifiedParamNames[$_]=$modifiedParamValues[$_]\n"; } close INIT_ORA || die "Cannot close $filename"; #For debug if($ENV{EMAGENT_PERL_TRACE_LEVEL} >= 0) { open (INIT_ORA_FILE, "$filename") || die "Unable to open tempfile for INIT_ORA_FILE\n"; my @file_content = ; my $file_string = "@file_content"; close INIT_ORA_FILE; EMD_PERL_DEBUG("convert.modifyInitFile(): INIT_ORA_FILE:\n $file_string"); } #overwrite the original file !copyFile($filename, $pfileFullName) || (EMD_PERL_DEBUG("convert.modifyInitFile(): Error copying $filename to $pfileFullName") && (die "convert.modifyInitFile(): Error copying $filename to $pfileFullName")); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.modifyInitFile(): *** END ***"); } # Modify spfile with given parameter names and values # Define the third argument if want to reset control file parameters # Call &set_env($oracleHome, $oracleSid) before calling this method. # modifySpfile(modifiedNames, modifiedValues, startNomount, resetCtl) sub modifySpfile { EMD_PERL_DEBUG("convert.modifySpfile(): *** START ***"); my ($modifiedNames, $modifiedValues, $startNomount, $resetCtl) = @_; #Replace the "%%%" with "'" in $modifiedParamValues #This is for control file name delimiters #$modifiedValues =~ s/%%%/'/g; EMD_PERL_DEBUG("convert.modifySpfile(): parameter names: $modifiedNames"); EMD_PERL_DEBUG("convert.modifySpfile(): parameter values: $modifiedValues"); EMD_PERL_DEBUG("convert.modifySpfile(): startNomount: $startNomount"); EMD_PERL_DEBUG("convert.modifySpfile(): resetCtl: $resetCtl"); my @modifiedNames = split /$DELIMITER/, $modifiedNames; my @modifiedValues = split /$DELIMITER/, $modifiedValues; my $sql_string = ""; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; if($startNomount eq "Y") { $sql_string .= "startup force nomount;\n"; } if($resetCtl eq "Y") { $sql_string .= "ALTER SYSTEM RESET control_files SCOPE=SPFILE sid='*'; \n"; } foreach (0 .. $#modifiedNames) { $sql_string .= "ALTER SYSTEM SET $modifiedNames[$_]=$modifiedValues[$_] SCOPE=BOTH"; if(((uc $modifiedNames[$_]) eq "DB_RECOVERY_FILE_DEST") || ((uc $modifiedNames[$_]) eq "DB_RECOVERY_FILE_DEST_SIZE") || (index((uc $modifiedNames[$_]), "DB_CREATE_ONLINE_LOG_DEST") >= 0)) { $sql_string .= " sid='*'; \n"; } else { $sql_string .= "; \n"; } } $sql_string .= "EXIT;\n"; my ($fh, $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.modifySpfile(): *** END ***"); } # Modify dynamic parameters with given parameter names and values # Call &set_env($oracleHome, $oracleSid) before calling this method. # modifyDynamicParameters(modifiedNames, modifiedValues) sub modifyDynamicParameters { EMD_PERL_DEBUG("convert.modifyDynamicParameters(): *** START ***"); my ($modifiedNames, $modifiedValues) = @_; EMD_PERL_DEBUG("convert.modifyDynamicParameters(): parameter names: $modifiedNames"); EMD_PERL_DEBUG("convert.modifyDynamicParameters(): parameter values: $modifiedValues"); my @modifiedNames = split /$DELIMITER/, $modifiedNames; my @modifiedValues = split /$DELIMITER/, $modifiedValues; my $sql_string = ""; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; foreach (0 .. $#modifiedNames) { $sql_string .= "ALTER SYSTEM SET $modifiedNames[$_]=$modifiedValues[$_] "; if(((uc $modifiedNames[$_]) eq "DB_RECOVERY_FILE_DEST") || ((uc $modifiedNames[$_]) eq "DB_RECOVERY_FILE_DEST_SIZE") || (index((uc $modifiedNames[$_]), "DB_CREATE_ONLINE_LOG_DEST") >= 0)) { $sql_string .= " sid='*'; \n"; } else { $sql_string .= "; \n"; } } $sql_string .= "EXIT;\n"; my ($fh, $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.modifyDynamicParameters(): *** END ***"); } # Restore one of the original control file to ASM. # Return the restored control file names if pfile is used, otherwise, return empty. # Call &set_env($oracleHome, $oracleSid) before calling this method. # restoreControlFile(pfile, origControlFiles) sub restoreControlFile { EMD_PERL_DEBUG("convert.restoreControlFile(): *** START ***"); my ($pfile, $origControlFiles) = @_; if($origControlFiles eq "") { EMD_PERL_ERROR("convert.restoreControlFile(): No original control file specified!"); return; } EMD_PERL_DEBUG("convert.restoreControlFile(): pfile: $pfile"); EMD_PERL_DEBUG("convert.restoreControlFile(): original control files: $origControlFiles"); #workaround for 10.1.0.4 ASM db shutdownDB("abort"); my @origControlFiles = split /$DELIMITER/, $origControlFiles; my $rman_string = ""; $rman_string .= "set echo off\n"; $rman_string .= "CONNECT TARGET $userID;\n"; $rman_string .= "set echo on\n"; if($pfile eq "") { $rman_string .= "startup force nomount;\n"; } else { $rman_string .= "startup force nomount pfile='$pfile';\n"; } $rman_string .= "restore controlfile from '$origControlFiles[0]'; \n"; $rman_string .= "EXIT;\n"; my ($fh, $filename) = &runRman($rman_string); close $fh; if($NT) { &removeFile($filename); } my $sql_string = ""; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "alter database mount;\n"; $sql_string .= "SELECT STATUS FROM V\$INSTANCE;\n"; $sql_string .= "EXIT;\n"; ($fh, $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } my $newControlFiles = ""; if($pfile ne "") { $newControlFiles = getControlFiles(); } EMD_PERL_DEBUG("convert.restoreControlFile(): *** END ***"); return $newControlFiles; } sub restoreControlFileDebug { EMD_PERL_DEBUG("convert.restoreControlFileDebug(): *** START ***"); my ($pfile, $origControlFiles) = @_; if($origControlFiles eq "") { EMD_PERL_ERROR("convert.restoreControlFileDebug(): No original control file specified!"); return; } EMD_PERL_DEBUG("convert.restoreControlFileDebug(): pfile: $pfile"); EMD_PERL_DEBUG("convert.restoreControlFileDebug(): original control files: $origControlFiles"); my @origControlFiles = split /$DELIMITER/, $origControlFiles; my $rman_string = ""; $rman_string .= "set echo off\n"; $rman_string .= "CONNECT TARGET $userID;\n"; $rman_string .= "set echo on\n"; if($pfile eq "") { $rman_string .= "startup force nomount;\n"; } else { $rman_string .= "startup force nomount pfile='$pfile';\n"; } $rman_string .= "EXIT;\n"; my ($fh, $filename) = &runRman($rman_string); close $fh; if($NT) { &removeFile($filename); } $rman_string = ""; $rman_string .= "set echo off\n"; $rman_string .= "CONNECT TARGET $userID;\n"; $rman_string .= "set echo on\n"; $rman_string .= "restore controlfile from '$origControlFiles[0]'; \n"; $rman_string .= "EXIT;\n"; ($fh, $filename) = &runRman($rman_string); close $fh; if($NT) { &removeFile($filename); } my $sql_string = ""; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "alter database mount;\n"; $sql_string .= "SELECT STATUS FROM V\$INSTANCE;\n"; $sql_string .= "EXIT;\n"; ($fh, $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } my $newControlFiles = ""; if($pfile ne "") { $newControlFiles = getControlFiles(); } EMD_PERL_DEBUG("convert.restoreControlFileDebug(): *** END ***"); return $newControlFiles; } # Allocate 4 rman channels if flag is on, otherwise do nothing # Call &set_env($oracleHome, $oracleSid) before calling this method. # allocateRMANChannels(allocateMultipleChannels) sub allocateRMANChannels { EMD_PERL_DEBUG("convert.allocateRMANChannels(): *** START ***"); my ($allocateMultipleChannels) = @_; EMD_PERL_DEBUG("convert.allocateRMANChannels(): allocateMultipleChannels: $allocateMultipleChannels"); my $rman_string = ""; if($allocateMultipleChannels eq "Y") { $rman_string .= "allocate channel dev1 type disk;\n"; $rman_string .= "allocate channel dev2 type disk;\n"; $rman_string .= "allocate channel dev3 type disk;\n"; $rman_string .= "allocate channel dev4 type disk;\n"; } EMD_PERL_DEBUG("convert.allocateRMANChannels(): *** END ***"); return $rman_string; } # Migrate all datafiles to ASM # To migrate all database files, pass "" for datafileNums # Call &set_env($oracleHome, $oracleSid) before calling this method. # migrateDatafiles(datafileNums, diskGroups, dbFilesLoc, parallelizeCopying) sub migrateDatafiles { EMD_PERL_DEBUG("convert.migrateDatafiles(): *** START ***"); my ($datafileNums, $diskGroups, $dbFilesLoc, $parallelizeCopying) = @_; EMD_PERL_DEBUG("convert.migrateDatafiles(): datafile numbers: $datafileNums"); EMD_PERL_DEBUG("convert.migrateDatafiles(): disk groups: $diskGroups"); EMD_PERL_DEBUG("convert.migrateDatafiles(): dbFilesLoc: $dbFilesLoc"); EMD_PERL_DEBUG("convert.migrateDatafiles(): parallelizeCopying: $parallelizeCopying"); my @datafileNums = split /$DELIMITER/, $datafileNums; my @diskGroups = split /$DELIMITER/, $diskGroups; my $rman_string = ""; $rman_string .= "set echo off\n"; $rman_string .= "CONNECT TARGET $userID;\n"; $rman_string .= "set echo on\n"; $rman_string .= "run {\n"; $rman_string .= &allocateRMANChannels($parallelizeCopying); if($#datafileNums == -1) #whole database migration { $rman_string .= "backup as copy database format '$dbFilesLoc'; \n"; } else #file by file { $rman_string .= "backup as copy \n"; #all datafiles except the last one foreach (0 .. $#datafileNums - 1) { $rman_string .= " ($CUSTOMIZE_LEVEL '$datafileNums[$_]' format '$diskGroups[$_]')\n"; } #the last datafile $rman_string .= " ($CUSTOMIZE_LEVEL '$datafileNums[$#datafileNums]' format '$diskGroups[$#datafileNums]');\n"; } $rman_string .= "} \n"; $rman_string .= "switch database to copy;\n"; $rman_string .= "change copy of database uncatalog; \n"; $rman_string .= "EXIT;\n"; my ($fh, $filename) = &runRman($rman_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.migrateDatafiles(): *** END ***"); } # Migrate all datafiles to ASM (hot level 0) # To migrate all database files, pass "" for datafileNums # Call &set_env($oracleHome, $oracleSid) before calling this method. # migrateDatafilesLevelZero(datafileNums, diskGroups, dbFilesLoc, parallelizeCopying) sub migrateDatafilesLevelZero { EMD_PERL_DEBUG("convert.migrateDatafilesLevelZero(): *** START ***"); my ($datafileNums, $diskGroups, $dbFilesLoc, $parallelizeCopying) = @_; EMD_PERL_DEBUG("convert.migrateDatafilesLevelZero(): datafile numbers: $datafileNums"); EMD_PERL_DEBUG("convert.migrateDatafilesLevelZero(): disk groups: $diskGroups"); EMD_PERL_DEBUG("convert.migrateDatafilesLevelZero(): dbFilesLoc: $dbFilesLoc"); EMD_PERL_DEBUG("convert.migrateDatafilesLevelZero(): parallelizeCopying: $parallelizeCopying"); my @datafileNums = split /$DELIMITER/, $datafileNums; my @diskGroups = split /$DELIMITER/, $diskGroups; my $rman_string = ""; $rman_string .= "set echo off\n"; $rman_string .= "CONNECT TARGET $userID;\n"; $rman_string .= "set echo on\n"; $rman_string .= "run {\n"; $rman_string .= &allocateRMANChannels($parallelizeCopying); if($#datafileNums == -1) #whole database migration { $rman_string .= "backup incremental level 0 as copy tag 'ASM_Migration' database format '$dbFilesLoc'; \n"; } else #file by file { $rman_string .= "backup incremental level 0 as copy tag 'ASM_Migration' \n"; #all datafiles except the last one foreach (0 .. $#datafileNums - 1) { $rman_string .= " ($CUSTOMIZE_LEVEL $datafileNums[$_] format '$diskGroups[$_]')\n"; } #the last one $rman_string .= " ($CUSTOMIZE_LEVEL $datafileNums[$#datafileNums] format '$diskGroups[$#datafileNums]');\n"; } $rman_string .= "} \n"; $rman_string .= "sql 'alter system archive log current';\n"; $rman_string .= "EXIT;\n"; my ($fh, $filename) = &runRman($rman_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.migrateDatafilesLevelZero(): *** END ***"); } # Migrate all datafiles to ASM (hot level 1) # To migrate all database files, pass "" for datafileNums # Call &set_env($oracleHome, $oracleSid) before calling this method. # migrateDatafilesLevelOne(parallelizeCopying) sub migrateDatafilesLevelOne { EMD_PERL_DEBUG("convert.migrateDatafilesLevelOne(): *** START ***"); my ($parallelizeCopying) = @_; EMD_PERL_DEBUG("convert.migrateDatafilesLevelOne(): parallelizeCopying: $parallelizeCopying"); my $rman_string = ""; $rman_string .= "set echo off\n"; $rman_string .= "CONNECT TARGET $userID;\n"; $rman_string .= "set echo on\n"; $rman_string .= "run { \n"; $rman_string .= &allocateRMANChannels($parallelizeCopying); $rman_string .= "backup incremental level 1 for recover of copy with tag 'ASM_Migration' database; \n"; $rman_string .= "recover copy of database with tag 'ASM_Migration'; \n"; $rman_string .= "} \n"; $rman_string .= "sql 'alter system archive log current';\n"; $rman_string .= "EXIT;\n"; my ($fh, $filename) = &runRman($rman_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.migrateDatafilesLevelOne(): *** END ***"); } # Migrate online logs to ASM # Call &set_env($oracleHome, $oracleSid) before calling this method. # migrateOnlineLogs() sub migrateOnlineLogs { EMD_PERL_DEBUG("convert.migrateOnlineLogs(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "declare\n"; $sql_string .= " cursor orlc is\n"; $sql_string .= " select distinct l.group#, l.thread#, l.bytes, lf.type\n"; $sql_string .= " from v\$log l, v\$logfile lf\n"; $sql_string .= " where l.group# = lf.group#\n"; $sql_string .= " order by l.thread#, l.group#;\n"; $sql_string .= " type numTab_t is table of number index by binary_integer;\n"; $sql_string .= " type charTab_t is table of varchar2(1024) index by binary_integer;\n"; $sql_string .= " grouplist numTab_t;\n"; $sql_string .= " threadlist numTab_t;\n"; $sql_string .= " byteslist numTab_t;\n"; $sql_string .= " typelist charTab_t;\n"; $sql_string .= " procedure migrateorlfile(gnumber IN number, tnumber IN number, bytes IN number, type IN varchar2) is\n"; $sql_string .= " retry number;\n"; $sql_string .= " stmt varchar2(1024);\n"; $sql_string .= " als varchar2(1024) := 'alter system switch logfile';\n"; $sql_string .= " chk varchar2(1024) := 'alter system checkpoint global';\n"; $sql_string .= " begin\n"; $sql_string .= " dbms_output.enable(2000000);\n"; $sql_string .= " select count(*) into retry from v\$log;\n"; $sql_string .= " if (type = 'STANDBY') then\n"; $sql_string .= " stmt := 'alter database add standby logfile thread ' || tnumber || ' size ' || bytes;\n"; $sql_string .= " else\n"; $sql_string .= " stmt := 'alter database add logfile thread ' || tnumber || ' size ' || bytes;\n"; $sql_string .= " end if;\n"; $sql_string .= " dbms_output.put_line('Execute stmt: ' || stmt);\n"; $sql_string .= " execute immediate stmt;\n"; $sql_string .= " stmt := 'alter database drop logfile group ' || gnumber;\n"; $sql_string .= " for i in 1..retry+1 loop\n"; $sql_string .= " begin\n"; $sql_string .= " dbms_output.put_line('Execute stmt: ' || stmt);\n"; $sql_string .= " execute immediate stmt;\n"; $sql_string .= " exit;\n"; $sql_string .= " exception when others then\n"; $sql_string .= " if i > retry then\n"; $sql_string .= " raise;\n"; $sql_string .= " end if;\n"; $sql_string .= " dbms_output.put_line('Execute stmt: ' || als);\n"; $sql_string .= " execute immediate als;\n"; $sql_string .= " dbms_output.put_line('Execute stmt: ' || chk);\n"; $sql_string .= " execute immediate chk;\n"; $sql_string .= " dbms_backup_restore.sleep(30);\n"; $sql_string .= " end;\n"; $sql_string .= " end loop;\n"; $sql_string .= " end;\n"; $sql_string .= "begin\n"; $sql_string .= " open orlc;\n"; $sql_string .= " fetch orlc bulk collect into grouplist, threadlist, byteslist, typelist;\n"; $sql_string .= " close orlc;\n"; $sql_string .= " for i in 1..grouplist.count loop\n"; $sql_string .= " migrateorlfile(grouplist(i), threadlist(i), byteslist(i), typelist(i));\n"; $sql_string .= " end loop;\n"; $sql_string .= " execute immediate 'alter system switch logfile';\n"; $sql_string .= "end;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n\n"; (my $fh, my $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.migrateOnlineLogs(): *** END ***"); } # Migrate online logs to ASM with hot migration approach # Call &set_env($oracleHome, $oracleSid) before calling this method. # migrateOnlineLogsHot() sub migrateOnlineLogsHot { EMD_PERL_DEBUG("convert.migrateOnlineLogsHot(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "declare\n"; $sql_string .= " cursor logfile_cur is\n"; $sql_string .= " select l.thread#, l.group#, l.bytes\n"; $sql_string .= " from v\$log l;\n"; $sql_string .= " type numTab_t is table of number index by binary_integer;\n"; $sql_string .= " grouplist numTab_t;\n"; $sql_string .= " threadlist numTab_t;\n"; $sql_string .= " byteslist numTab_t;\n"; $sql_string .= " procedure migrateorl ( thread# IN number, group# IN number, bytes IN number) is\n"; $sql_string .= " retry number := 5;\n"; $sql_string .= " stmt varchar2(1024);\n"; $sql_string .= " als varchar2(1024) := 'alter system archive log current';\n"; $sql_string .= " chk varchar2(1024) := 'alter system checkpoint global';\n"; $sql_string .= " begin\n"; $sql_string .= " dbms_output.enable(2000000);\n"; $sql_string .= " stmt := 'alter database add logfile thread '||thread#||' size '||bytes;\n"; $sql_string .= " dbms_output.put_line('Execute stmt: ' || stmt);\n"; $sql_string .= " execute immediate stmt;\n"; $sql_string .= " stmt := 'alter database drop logfile group '||group#;\n"; $sql_string .= " for I in 1 .. retry loop\n"; $sql_string .= " begin\n"; $sql_string .= " dbms_output.put_line('Execute stmt: ' || stmt);\n"; $sql_string .= " execute immediate stmt;\n"; $sql_string .= " exit;\n"; $sql_string .= " exception\n"; $sql_string .= " when others then\n"; $sql_string .= " if I > retry then\n"; $sql_string .= " raise;\n"; $sql_string .= " end if;\n"; $sql_string .= " dbms_output.put_line('Execute stmt: ' || als);\n"; $sql_string .= " execute immediate als;\n"; $sql_string .= " dbms_output.put_line('Execute stmt: ' || chk);\n"; $sql_string .= " execute immediate chk;\n"; $sql_string .= " end;\n"; $sql_string .= " end loop;\n"; $sql_string .= " end;\n"; $sql_string .= "begin\n"; $sql_string .= " open logfile_cur;\n"; $sql_string .= " fetch logfile_cur bulk collect into threadlist, grouplist, byteslist;\n"; $sql_string .= " close logfile_cur;\n"; $sql_string .= " for I in 1 .. threadlist.count loop\n"; $sql_string .= " migrateorl (threadlist(I), grouplist(I), byteslist(I) );\n"; $sql_string .= " end loop;\n"; $sql_string .= "end;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n\n"; (my $fh, my $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.migrateOnlineLogsHot(): *** END ***"); } # Migrate online logs to ASM for standby database with hot migration approach # Call &set_env($oracleHome, $oracleSid) before calling this method. # migrateOnlineLogsStandbyHot() sub migrateOnlineLogsStandbyHot { EMD_PERL_DEBUG("convert.migrateOnlineLogsStandbyHot(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "declare\n"; $sql_string .= " cursor logfile_cur is\n"; $sql_string .= " select l.thread#, l.group#, l.bytes\n"; $sql_string .= " from v\$standby_log l;\n"; $sql_string .= " type numTab_t is table of number index by binary_integer;\n"; $sql_string .= " grouplist numTab_t;\n"; $sql_string .= " threadlist numTab_t;\n"; $sql_string .= " byteslist numTab_t;\n"; $sql_string .= " procedure migratesrl ( thread# IN number, group# IN number, bytes IN number) is\n"; $sql_string .= " retry number := 5;\n"; $sql_string .= " stmt varchar2(1024);\n"; $sql_string .= " begin\n"; $sql_string .= " dbms_output.enable(2000000);\n"; $sql_string .= " if thread# = 0 then\n"; $sql_string .= " stmt := 'alter database add standby logfile size '||bytes;\n"; $sql_string .= " else\n"; $sql_string .= " stmt := 'alter database add standby logfile thread '||thread#||' size '||bytes;\n"; $sql_string .= " end if;\n"; $sql_string .= " dbms_output.put_line('Execute stmt: ' || stmt);\n"; $sql_string .= " execute immediate stmt;\n"; $sql_string .= " stmt := 'alter database drop standby logfile group '||group#;\n"; $sql_string .= " dbms_output.put_line('Execute stmt: ' || stmt);\n"; $sql_string .= " execute immediate stmt;\n"; $sql_string .= " dbms_backup_restore.sleep(30);\n"; $sql_string .= " end;\n"; $sql_string .= "begin\n"; $sql_string .= " open logfile_cur;\n"; $sql_string .= " fetch logfile_cur bulk collect into threadlist, grouplist, byteslist;\n"; $sql_string .= " close logfile_cur;\n"; $sql_string .= " for I in 1 .. threadlist.count loop\n"; $sql_string .= " migratesrl (threadlist(I), grouplist(I), byteslist(I) );\n"; $sql_string .= " end loop;\n"; $sql_string .= "end;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n\n"; (my $fh, my $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.migrateOnlineLogsStandbyHot(): *** END ***"); } # Retrun recovery file count. # Call &set_env(oracleHome, oracleSid) before calling this method. # getRecoveryFileCount() sub getRecoveryFileCount { EMD_PERL_DEBUG("convert.getRecoveryFileCount(): *** START ***"); my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "variable df_cnt number;\n"; $sql_string .= "variable cf_cnt number;\n"; $sql_string .= "variable bs_cnt number;\n"; $sql_string .= "variable al_cnt number;\n"; $sql_string .= "BEGIN\n"; $sql_string .= " dbms_output.enable(2000000);\n"; $sql_string .= " select count(*) INTO :df_cnt from v\$datafile_copy where status = 'A' and file# != 0;\n"; $sql_string .= " IF NOT (:df_cnt IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing datafile copy count: ');\n"; $sql_string .= " dbms_output.put_line('df# '||:df_cnt);\n"; $sql_string .= " end if;\n"; $sql_string .= " select count(*) INTO :cf_cnt from v\$datafile_copy where status = 'A' and file# = 0;\n"; $sql_string .= " IF NOT (:cf_cnt IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing controlfile copy count: ');\n"; $sql_string .= " dbms_output.put_line('cf# '||:cf_cnt);\n"; $sql_string .= " end if;\n"; $sql_string .= " select count(*) INTO :bs_cnt from v\$backup_piece p, v\$backup_set s where p.set_stamp = s.set_stamp and p.set_count = s.set_count and status = 'A';\n"; $sql_string .= " IF NOT (:bs_cnt IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing backup set count: ');\n"; $sql_string .= " dbms_output.put_line('bs# '||:bs_cnt);\n"; $sql_string .= " end if;\n"; $sql_string .= " select count(*) INTO :al_cnt from v\$archived_log where status = 'A';\n"; $sql_string .= " IF NOT (:al_cnt IS NULL) then\n"; $sql_string .= " dbms_output.put_line('Start printing archived log count: ');\n"; $sql_string .= " dbms_output.put_line('al# '||:al_cnt);\n"; $sql_string .= " end if;\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); my $df = -1; my $cf = -1; my $bs = -1; my $al = -1; open (FILE_COUNT, "$filename") || die "Unable to open tempfile for FILE_COUNT\n"; while () { if ($_=~/\bdf#/) { chomp($_); $df = substr $_, 4; #df name starts from position 4 } if ($_=~/\bcf#/) { chomp($_); $cf = substr $_, 4; #cf name starts from position 4 } if ($_=~/\bbs#/) { chomp($_); $bs = substr $_, 4; #bs name starts from position 4 } if ($_=~/\bal#/) { chomp($_); $al = substr $_, 4; #al name starts from position 4 } } close FILE_COUNT; close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.getRecoveryFileCount(): Number of datafile copies: $df"); EMD_PERL_DEBUG("convert.getRecoveryFileCount(): Number of controlfile copies: $cf"); EMD_PERL_DEBUG("convert.getRecoveryFileCount(): Number of backup sets: $bs"); EMD_PERL_DEBUG("convert.getRecoveryFileCount(): Number of archived logs: $al"); EMD_PERL_DEBUG("convert.getRecoveryFileCount(): *** END ***"); return ($df, $cf, $bs, $al); } # Migrate all recovery related files to ASM # Call &set_env($oracleHome, $oracleSid) before calling this method. # migrateRecoveryFiles(migrateArch, parallelizeCopying) sub migrateRecoveryFiles { EMD_PERL_DEBUG("convert.migrateRecoveryFiles(): *** START ***"); my ($migrateArch, $parallelizeCopying) = @_; EMD_PERL_DEBUG("convert.migrateRecoveryFiles(): Migrate archived logs: $migrateArch"); EMD_PERL_DEBUG("convert.migrateRecoveryFiles(): parallelizeCopying: $parallelizeCopying"); crossCheckRecoveryFiles($migrateArch); my($df, $cf, $bs, $al) = getRecoveryFileCount(); my $rman_string = ""; $rman_string .= "set echo off\n"; $rman_string .= "CONNECT TARGET $userID;\n"; $rman_string .= "set echo on\n"; $rman_string .= "run {\n"; $rman_string .= &allocateRMANChannels($parallelizeCopying); if($df > 0) { $rman_string .= "backup as copy datafilecopy all delete input;\n"; } if($cf > 0) { $rman_string .= "backup as copy controlfilecopy all delete input;\n"; } if($bs > 0) { $rman_string .= "backup as backupset backupset all delete input;\n"; } if(($migrateArch eq "Y") && ($al > 0)) { $rman_string .= "backup as copy archivelog all delete input;\n"; } $rman_string .= "} \n"; $rman_string .= "EXIT;\n"; my ($fh, $filename) = &runRman($rman_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.migrateRecoveryFiles(): *** END ***"); } # Crosscheck recovery files before migration, otherwise we may encounter rman errors # Call &set_env($oracleHome, $oracleSid) before calling this method. # crossCheckRecoveryFiles(migrateArch) sub crossCheckRecoveryFiles { EMD_PERL_DEBUG("convert.crossCheckRecoveryFiles(): *** START ***"); my ($migrateArch) = @_; EMD_PERL_DEBUG("convert.crossCheckRecoveryFiles(): Migrate archived logs: $migrateArch"); my $rman_string = ""; $rman_string .= "CONNECT TARGET $userID;\n"; $rman_string .= "crosscheck copy;\n"; $rman_string .= "crosscheck backup;\n"; $rman_string .= "crosscheck backupset;\n"; if($migrateArch eq "Y") { $rman_string .= "crosscheck archivelog all;\n"; } $rman_string .= "EXIT;\n"; my ($fh, $filename) = &runRman($rman_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.crossCheckRecoveryFiles(): *** END ***"); } # modify DB_RECOVERY_FILE_DEST_SIZE init param # Call &set_env($oracleHome, $oracleSid) before calling this method. # modifyRecoveryDestSizeInitParam(pfile, size, startNomount) sub modifyRecoveryDestSizeInitParam { EMD_PERL_DEBUG("convert.modifyRecoveryDestSizeInitParam(): *** START ***"); my ($pfile, $size, $startNomount) = @_; EMD_PERL_DEBUG("convert.modifyRecoveryDestSizeInitParam(): pfile: $pfile"); EMD_PERL_DEBUG("convert.modifyRecoveryDestSizeInitParam(): DB_RECOVERY_FILE_DEST_SIZE: $size MB"); EMD_PERL_DEBUG("convert.modifyRecoveryDestSizeInitParam(): startNomount: $startNomount"); my $modifiedParamNames = "DB_RECOVERY_FILE_DEST_SIZE"."$DELIMITER"; my $modifiedParamValues = "$size"."M"."$DELIMITER"; if($pfile eq "") { modifySpfile($modifiedParamNames, $modifiedParamValues, $startNomount, "N"); } else { modifyInitFile($modifiedParamNames, $modifiedParamValues, $pfile); } EMD_PERL_DEBUG("convert.modifyRecoveryDestSizeInitParam(): *** END ***"); } # Shutdown and nomount DB for migration # Call &set_env(oracleHome, oracleSid) before calling this method. # closeDBForMigration(pfile) sub closeDBForMigration { EMD_PERL_DEBUG("convert.closeDBForMigration(): *** START ***"); my ($pfile) = @_; #Check if the source DB is using spfile my $pfile_filename; #not defined my $spfile = &spfileUsed(); if($spfile eq "") #not using spfile { $pfile_filename = $pfile; EMD_PERL_DEBUG("convert.closeDBForMigration(): pfile: $pfile_filename"); } #shutdown the source DB &shutdownDB("immediate"); #startup the source DB &startupDB("nomount", $pfile_filename); EMD_PERL_DEBUG("convert.closeDBForMigration(): *** END ***"); } # Open the mounted source DB # Call &set_env(oracleHome, oracleSid) before calling this method. # alterDatabaseOpen() sub alterDatabaseOpen { EMD_PERL_DEBUG("convert.alterDatabaseOpen(): *** START ***"); my $sql_string = ""; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "alter database open;\n"; $sql_string .= "SELECT STATUS FROM V\$INSTANCE;\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.alterDatabaseOpen(): *** END ***"); } # Shutdown DB with specified option. # Option: normal, immediate, transactional, abort. # Call &set_env($oracleHome, $oracleSid) before calling this method. # shutdownDB(option) sub shutdownDB { EMD_PERL_DEBUG("convert.shutdownDB(): *** START ***"); my ($option) = ($_[0]); EMD_PERL_DEBUG("convert.shutdownDB(): option: $option"); my $sql_string = ""; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "shutdown $option\n"; $sql_string .= "EXIT;\n"; my ($fh, $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.shutdownDB(): *** END ***"); } # Start DB to specified mode. # Mode: nomount, mount, open (""), restrict, force. # Use the specified pfile if "pfileFullName" is defined. # Call &set_env($oracleHome, $oracleSid) before calling this method. # startupDB(mode, pfileFullName) sub startupDB { EMD_PERL_DEBUG("convert.startupDB(): *** START ***"); my ($mode, $pfile) = @_; if($mode eq "") { $mode = "open"; } EMD_PERL_DEBUG("convert.startupDB(): mode: $mode"); if($pfile ne "") { $pfile = "pfile='$_[1]'"; EMD_PERL_DEBUG("convert.startupDB(): pfile: $_[1]"); } my $sql_string = ""; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "startup force $mode $pfile;\n"; $sql_string .= "EXIT;\n"; my ($fh, $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.startupDB(): *** END ***"); } # Get DB version # Call &set_env($oracleHome, $oracleSid) before calling this method. # getDBVersion() sub getDBVersion { EMD_PERL_DEBUG("convert.getDBVersion(): *** START ***"); my $db_version = ""; my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n\n"; $sql_string .= "variable db_version varchar2(20);\n"; $sql_string .= "BEGIN\n"; $sql_string .= " select version INTO :db_version from v\$instance;\n"; $sql_string .= " dbms_output.put_line('Get DB version');\n"; $sql_string .= " dbms_output.put_line('DBversion#: '||:db_version);\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); open (DB_VERSION, "$filename") || die "Unable to open tempfile for DB_VERSION\n"; while () { if ($_=~/\bDBversion#/) { chomp($_); $db_version = substr $_, 12; #12 is the position that version starts EMD_PERL_DEBUG("convert.getDBVersion(): Database version: $db_version"); } } close DB_VERSION; close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.getDBVersion(): *** END ***"); return $db_version; } # Cleanup the migrated database. # Call &set_env($oracleHome, $oracleSid) before calling this method. # cleanupDBConvert() sub cleanupDBConvert { EMD_PERL_DEBUG("convert.cleanupDBConvert(): *** START ***"); my $rman_string = ""; $rman_string .= "set echo off\n"; $rman_string .= "CONNECT TARGET $userID;\n"; $rman_string .= "set echo on\n"; $rman_string .= "delete copy of database; \n"; $rman_string .= "YES\n"; $rman_string .= "EXIT;\n"; my ($fh, $filename) = &runRman($rman_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.cleanupDBConvert(): *** END ***"); } # Get output from file # getOutputFromFile(filename) sub getOutputFromFile { EMD_PERL_DEBUG("convert.getOutputFromFile(): *** START ***"); my ($filename) = @_; #Open the file to get output open (OUT_PUT, "$filename") || die "Unable to open file $filename for OUT_PUT\n"; my @output_content = ; my $mesg = "@output_content"; close OUT_PUT; EMD_PERL_DEBUG("convert.getOutputFromFile(): *** END ***"); return $mesg; } # This routine gets a unique dir name within a location based on given pattern. # Return the found dir name. # getUniqueDirName(dirPattern) sub getUniqueDirName { my ($dirPattern) = @_; EMD_PERL_DEBUG("convert.getUniqueDirName(): Get unique dir name based on $dirPattern"); my $dirNotExist = &dirNotExists($dirPattern); if($dirNotExist eq "OK") { EMD_PERL_DEBUG("convert.getUniqueDirName(): Directory $dirPattern is already unique"); return $dirPattern; } my $sibling = $dirPattern; while($dirNotExist eq "NOK") { EMD_PERL_DEBUG("convert.getUniqueDirName(): $sibling already exist"); $sibling .= "_1"; $dirNotExist = &dirNotExists($sibling); } return $sibling; } # Check if a specified directory NOT exists # Return OK if the directory NOT exists, otherwise, return NOK. # dirNotExists(dirName) sub dirNotExists { my ($dirName) = @_; if(! -e "$dirName") { EMD_PERL_DEBUG("convert.dirNotExists(): Directory $dirName does not exist"); return "OK"; } elsif(! -d "$dirName") { EMD_PERL_DEBUG("convert.dirNotExists(): $dirName is not a directory"); return "NOK"; } EMD_PERL_DEBUG("convert.dirNotExists(): Directory $dirName exists"); return "NOK"; } # Create temp location for recovery purpose # createTempLocationForRecovery(location) sub createTempLocationForRecovery { my ($location) = @_; EMD_PERL_DEBUG("convert.createTempLocationForRecovery(): Location: $location"); #No need since it is already unique when going through the wizard #$location = getUniqueDirName($location); #EMD_PERL_DEBUG("convert.createTempLocationForRecovery(): Unique Location: $location"); my $ret = &mkDir($location); if($ret eq "NOK") { EMD_PERL_ERROR("convert.createTempLocationForRecovery(): Could not create location: $location"); exit(1); } } # isAnyOnlinelogOnDiskgroup(logFiles) sub isAnyOnlinelogOnDiskgroup { my ($logFilesArray) = @_; EMD_PERL_DEBUG("convert.isAnyOnlinelogOnDiskgroup(): Log files: $logFilesArray"); my @logFiles = split /$DELIMITER/, $logFilesArray; my $anyOnDG = "N"; my $logFile = ""; my $startStr = ""; foreach $logFile (@logFiles) { $startStr = substr($logFile, 0, 1); if($startStr eq "+") { EMD_PERL_DEBUG("convert.isAnyOnlinelogOnDiskgroup(): $logFile starts with: $startStr"); $anyOnDG = "Y"; last; } } EMD_PERL_DEBUG("convert.isAnyOnlinelogOnDiskgroup(): Any logfile on disk group: $anyOnDG"); return $anyOnDG; } # Backup online logs # Return backup log file names # backupOnlineLogs(location, logFiles) sub backupOnlineLogs { my ($location, $logFilesArray) = @_; EMD_PERL_DEBUG("convert.backupOnlineLogs(): Location: $location"); EMD_PERL_DEBUG("convert.backupOnlineLogs(): Log files: $logFilesArray"); my @logFiles = split /$DELIMITER/, $logFilesArray; my $slash = "/"; if($NT) { $slash = "\\"; } my $index = 1; my $filename = ""; my $newName = ""; my $newNames = ""; my $logFile = ""; foreach $logFile (@logFiles) { $filename = &getBasename($logFile); $newName = $location.$slash.$filename.$index; !copyFile($logFile, $newName) || (EMD_PERL_DEBUG("Error copying $logFile to $location") && (die "Error copying $logFile to $location")); $index ++; $newNames .= $newName.$DELIMITER; } EMD_PERL_DEBUG("convert.backupOnlineLogs(): New Names: $newNames"); return $newNames; } # Backup original control files # Return backup control file names # backupOrigControlFiles(location, controlFiles) sub backupOrigControlFiles { my ($location, $controlFilesArray) = @_; EMD_PERL_DEBUG("convert.backupOrigControlFiles(): Location: $location"); EMD_PERL_DEBUG("convert.backupOrigControlFiles(): Control files: $controlFilesArray"); my @controlFiles = split /$DELIMITER/, $controlFilesArray; my $slash = "/"; if($NT) { $slash = "\\"; } my $index = 1; my $filename = ""; my $newName = ""; my $newNames = ""; my $controlFile = ""; foreach $controlFile (@controlFiles) { $filename = &getBasename($controlFile); $newName = $location.$slash.$filename.$index; !copyFile($controlFile, $newName) || (EMD_PERL_DEBUG("Error copying $controlFile to $location") && (die "Error copying $controlFile to $location")); $index ++; $newNames .= $newName.$DELIMITER; } EMD_PERL_DEBUG("convert.backupOrigControlFiles(): New Names: $newNames"); return $newNames; } # Restore online logs # restoreOnlineLogs(backupLogFiles, logFiles) sub restoreOnlineLogs { EMD_PERL_DEBUG("convert.restoreOnlineLogs(): *** START ***"); my ($backupLogFilesArray, $logFilesArray) = @_; EMD_PERL_DEBUG("convert.restoreOnlineLogs(): Backup log files: $backupLogFilesArray"); EMD_PERL_DEBUG("convert.restoreOnlineLogs(): Log files: $logFilesArray"); my @backupLogFiles = split /$DELIMITER/, $backupLogFilesArray; my @logFiles = split /$DELIMITER/, $logFilesArray; my $backupLogFile = ""; my $index = 0; foreach $backupLogFile (@backupLogFiles) { #&removeFile($logFiles[$index]); !copyFile($backupLogFile, $logFiles[$index]) || (EMD_PERL_DEBUG("Error copying $backupLogFile to $logFiles[$index]") && (die "Error copying $backupLogFile to $logFiles[$index]")); $index = $index + 1; } EMD_PERL_DEBUG("convert.restoreOnlineLogs(): *** END ***"); } # Restore control files # restoreOrigControlFiles(backupControlFiles, controlFiles) sub restoreOrigControlFiles { EMD_PERL_DEBUG("convert.restoreOrigControlFiles(): *** START ***"); my ($backupControlFilesArray, $controlFilesArray) = @_; EMD_PERL_DEBUG("convert.restoreOrigControlFiles(): Backup control files: $backupControlFilesArray"); EMD_PERL_DEBUG("convert.restoreOrigControlFiles(): Control files: $controlFilesArray"); my @backupControlFiles = split /$DELIMITER/, $backupControlFilesArray; my @controlFiles = split /$DELIMITER/, $controlFilesArray; my $backupControlFile = ""; my $index = 0; foreach $backupControlFile (@backupControlFiles) { &removeFile($controlFiles[$index]); !copyFile($backupControlFile, $controlFiles[$index]) || (EMD_PERL_DEBUG("Error copying $backupControlFile to $controlFiles[$index]") && (die "Error copying $backupControlFile to $controlFiles[$index]")); $index = $index + 1; } EMD_PERL_DEBUG("convert.restoreOrigControlFiles(): *** END ***"); } # Create or migrate spfile to ASM. # If pfile is used, create spfile from it to ASM; if spfile is used, create # a pfile from it on file system first, then create spfile from the pfile to ASM. # Create a pfile pointing to the migrated spfile under the same location as original # pfile or spfile (save the original pfile if there is any at that location). # Call &set_env($oracleHome, $oracleSid) before calling this method. # migrateSPFile(pfile, spfile, migratedSpfile, tempLoc) sub migrateSPFile { EMD_PERL_DEBUG("convert.migrateSPFile(): *** START ***"); #my ($pfile, $spfile, $migratedSpfile, $tempLoc) = @_; my ($pfile, $spfile, $migratedSpfile) = @_; (my $tempfh, my $tempFileName) = &create_temp_file(); close $tempfh; EMD_PERL_DEBUG("convert.migrateSPFile(): pfile: $pfile"); EMD_PERL_DEBUG("convert.migrateSPFile(): spfile: $spfile"); EMD_PERL_DEBUG("convert.migrateSPFile(): migratedSpfile: $migratedSpfile"); #EMD_PERL_DEBUG("convert.migrateSPFile(): tempLoc: $tempLoc"); my $slash = "/"; if($NT) { $slash = "\\"; } my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; if($pfile ne "") { $sql_string .= "create spfile='$migratedSpfile' from pfile='$pfile';\n"; } else { #my $temppfile = ${tempLoc}.${slash}."init.ora"; $sql_string .= "create pfile='$tempFileName' from spfile='$spfile';\n"; $sql_string .= "create spfile='$migratedSpfile' from pfile='$tempFileName';\n"; } $sql_string .= "exit;\n"; (my $fh, my $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } my $initFile = ""; if($pfile ne "") { $initFile = $pfile; } else { #my $initDir = &getDirname($spfile); my $initDir = &getDefaultDBLocation(); my $startStr = substr($initDir, 0, 1); if($startStr eq "+") { EMD_PERL_DEBUG("convert.migrateSPFile(): $initDir starts with: $startStr"); $initDir = &getDefaultDBLocation(); } $initFile = ${initDir}.${slash}."init".$ENV{ORACLE_SID}.".ora"; } backupFile($initFile); open(INIT_ORA, ">$initFile") || die "Cannot open $initFile"; print INIT_ORA "spfile='$migratedSpfile'"; close INIT_ORA || die "Cannot close $initFile"; # If original spfile is the default then rename it otherwise db will pick it up after a restart if($spfile ne "") { if(spfileAtDefaultLoc($spfile) eq "Y") { &backupFile($spfile); &removeFile($spfile); } } EMD_PERL_DEBUG("convert.migrateSPFile(): *** END ***"); return $initFile; } # Check if only setup recovery area without migrating database files # isOnlySetupRecoveryArea(isMigrateDBFiles, isMigrateRecoveryFiles, # isSetupRecoveryAreaOnly) sub isOnlySetupRecoveryArea { my ($isMigrateDBFiles, $isMigrateRecoveryFiles, $isSetupRecoveryAreaOnly) = @_; my $setupRecoveryAreaOnly = "FALSE"; if(($isMigrateDBFiles ne "Y") && ($isMigrateRecoveryFiles eq "Y") && ($isSetupRecoveryAreaOnly eq "Y")) { $setupRecoveryAreaOnly = "TRUE"; } return $setupRecoveryAreaOnly; } # Check if pfile exists if it is used # Return (spfileName, pfileFullName) # Non empty value means it is being used # checkPfile(pfileFullName) sub checkPfile { my ($pfileFullName) = @_; #Get spfile usage my $spfileName = spfileUsed(); if($spfileName eq "") { EMD_PERL_DEBUG("convert.checkPfile(): Using pfile: $pfileFullName"); if(! -e "$pfileFullName") { EMD_PERL_ERROR("convert.checkPfile(): File $pfileFullName does not exist"); exit(1); } } else { $pfileFullName = ""; EMD_PERL_DEBUG("convert.checkPfile(): Using spfile: $spfileName"); } return ($spfileName, $pfileFullName); } # Check if spfile is at default location ($OH/dbs) # Return Y/N # spfileAtDefaultLoc(spfile) sub spfileAtDefaultLoc { my ($spfile) = @_; my $atDefaultLoc = "Y"; my $OH = $ENV{ORACLE_HOME}; my $DBS = "dbs"; if($NT) { $DBS = "database"; } my $loc = &getDirname($spfile); my $spfile_OH = &getDirname($loc); my $dbs = &getBasename($loc); EMD_PERL_DEBUG("convert.spfileAtDefaultLoc(): spfile_OH: $spfile_OH"); EMD_PERL_DEBUG("convert.spfileAtDefaultLoc(): dbs: $dbs"); if($NT) { $spfile_OH = uc $spfile_OH; $OH = uc $OH; $dbs = uc $dbs; $DBS = uc $DBS; } if($spfile_OH ne $OH) { $atDefaultLoc = "N"; EMD_PERL_DEBUG("convert.spfileAtDefaultLoc(): $spfile is not under $OH"); } else { if($dbs ne $DBS) { $atDefaultLoc = "N"; EMD_PERL_DEBUG("convert.spfileAtDefaultLoc(): $spfile is not under $DBS"); } } return $atDefaultLoc; } # Get default database location ($OH/dbs) # Return location # getDefaultDBLocation() sub getDefaultDBLocation { my $OH = $ENV{ORACLE_HOME}; my $DBS = "dbs"; if($NT) { $DBS = "database"; } my $defaultLoc = File::Spec->catfile($OH, $DBS); EMD_PERL_DEBUG("convert.getDefaultDBLocation(): Default database location is $defaultLoc"); return $defaultLoc; } # Switch database to datafile copies at ASM # Call &set_env($oracleHome, $oracleSid) before calling this method. # switchDatafileCopies() sub switchDatafileCopies { EMD_PERL_DEBUG("convert.switchDatafileCopies(): *** START ***"); my $rman_string = ""; $rman_string .= "set echo off\n"; $rman_string .= "CONNECT TARGET $userID;\n"; $rman_string .= "set echo on\n"; $rman_string .= "switch database to copy; \n"; $rman_string .= "change copy of database uncatalog; \n"; $rman_string .= "EXIT;\n"; my ($fh, $filename) = &runRman($rman_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.switchDatafileCopies(): *** END ***"); } # Recover database # Call &set_env($oracleHome, $oracleSid) before calling this method. # recoverDatabase() sub recoverDatabase { EMD_PERL_DEBUG("convert.recoverDatabase(): *** START ***"); my $rman_string = ""; $rman_string .= "set echo off\n"; $rman_string .= "CONNECT TARGET $userID;\n"; $rman_string .= "set echo on\n"; $rman_string .= "recover database; \n"; $rman_string .= "EXIT;\n"; my ($fh, $filename) = &runRman($rman_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.recoverDatabase(): *** END ***"); } # Shutdown all db instances # Call &set_env(oracleHome, oracleSid) before calling this method (only OH needs to be set). # shutdownAllInstances(isRac, dbName) sub shutdownAllInstances { EMD_PERL_DEBUG("convert.shutdownAllInstances(): *** START ***"); my ($isRac, $dbName) = @_; EMD_PERL_DEBUG("convert.shutdownAllInstances(): isRac: $isRac"); EMD_PERL_DEBUG("convert.shutdownAllInstances(): dbName: $dbName"); if($isRac eq "Y") { my $cmd = "stop database -d $dbName"; my $statusCmd = "status database -d $dbName"; runSrvctl($cmd); runSrvctl($statusCmd); } else { EMD_PERL_DEBUG("convert.shutdownAllInstances(): $dbName is not a cluster database"); } EMD_PERL_DEBUG("convert.shutdownAllInstances(): *** END ***"); } # Startup all db instances # Call &set_env(oracleHome, oracleSid) before calling this method (only OH needs to be set). # startupAllInstances(isRac, dbName) sub startupAllInstances { EMD_PERL_DEBUG("convert.startupAllInstances(): *** START ***"); my ($isRac, $dbName) = @_; EMD_PERL_DEBUG("convert.startupAllInstances(): isRac: $isRac"); EMD_PERL_DEBUG("convert.startupAllInstances(): dbName: $dbName"); if($isRac eq "Y") { my $cmd = "start database -d $dbName"; my $statusCmd = "status database -d $dbName"; runSrvctl($cmd); runSrvctl($statusCmd); } else { EMD_PERL_DEBUG("convert.startupAllInstances(): $dbName is not a cluster database"); } EMD_PERL_DEBUG("convert.startupAllInstances(): *** END ***"); } # Associate all db instances with corresponding asm instances for RAC case # Call &set_env(oracleHome, oracleSid) before calling this method (only OH needs to be set). # associateDbAsmInstances(isRac, dbName, dbInstancesArray, asmInstancesArray) sub associateDbAsmInstances { EMD_PERL_DEBUG("convert.associateDbAsmInstances(): *** START ***"); my ($isRac, $dbName, $dbInstancesArray, $asmInstancesArray) = @_; my @dbInstances = split /$DELIMITER/, $dbInstancesArray; my @asmInstances = split /$DELIMITER/, $asmInstancesArray; EMD_PERL_DEBUG("convert.associateDbAsmInstances(): isRac: $isRac"); EMD_PERL_DEBUG("convert.associateDbAsmInstances(): dbName: $dbName"); EMD_PERL_DEBUG("convert.associateDbAsmInstances(): dbInstances: @dbInstances"); EMD_PERL_DEBUG("convert.associateDbAsmInstances(): asmInstances: @asmInstances"); if($isRac eq "Y") { my $cmd; my $dbInstance; my $index = 0; foreach $dbInstance (@dbInstances) { $cmd = "modify instance -d $dbName -i $dbInstance -s $asmInstances[$index]"; runSrvctl($cmd); $index = $index + 1; } } else { EMD_PERL_DEBUG("convert.associateDbAsmInstances(): $dbName is not a cluster database"); } EMD_PERL_DEBUG("convert.associateDbAsmInstances(): *** END ***"); } # Migrate the flashback files # Call &set_env(oracleHome, oracleSid) before calling this method. # migrateFlashbackFiles(pfileFullName, isRac, dbName) sub migrateFlashbackFiles { EMD_PERL_DEBUG("convert.migrateFlashbackFiles(): *** START ***"); my ($pfileFullName, $isRac, $dbName) = @_; EMD_PERL_DEBUG("convert.migrateFlashbackFiles(): pfileFullName: $pfileFullName"); shutdownDB("immediate"); shutdownAllInstances($isRac, $dbName); startupDB("mount", $pfileFullName); my $sql_string = ""; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "alter database flashback off;\n"; $sql_string .= "alter database flashback on;\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } alterDatabaseOpen(); startupAllInstances($isRac, $dbName); EMD_PERL_DEBUG("convert.migrateFlashbackFiles(): *** END ***"); } # Query the names of all database files # Call &set_env($oracleHome, $oracleSid) before calling this method. # checkDatabaseFiles() sub checkDatabaseFiles { EMD_PERL_DEBUG("convert.checkDatabaseFiles(): *** START ***"); my $sql_string = ""; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "select name \"datafile\" from v\$datafile;\n"; $sql_string .= "select name \"tempfile\" from v\$tempfile;\n"; $sql_string .= "select member \"logfile\" from v\$logfile;\n"; $sql_string .= "select name \"controlfile\" from v\$controlfile;\n"; $sql_string .= "select filename \"block_change_tracking\" from v\$block_change_tracking;\n"; $sql_string .= "select name \"flashback_database_logfile\" from v\$flashback_database_logfile;\n"; $sql_string .= "select value \"spfile\" from v\$parameter where name='spfile';\n"; $sql_string .= "exit;\n"; (my $fh, my $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.checkDatabaseFiles(): *** END ***"); } # Insert a script to an existing file # insertScriptToFile(directory, filename, script, insertFlag) sub insertScriptToFile { EMD_PERL_DEBUG("convert.insertScriptToFile(): *** START ***"); my ($directory, $filename, $script, $insertFlag) = @_; EMD_PERL_DEBUG("convert.insertScriptToFile(): directory: $directory"); EMD_PERL_DEBUG("convert.insertScriptToFile(): filename: $filename"); EMD_PERL_DEBUG("convert.insertScriptToFile(): script: $script"); EMD_PERL_DEBUG("convert.insertScriptToFile(): insertFlag: $insertFlag"); my $recoveryScript = File::Spec->catfile($directory, $filename); my $tempScript = File::Spec->catfile($directory, "temp.pl"); open(TEMP_SCRIPT, ">$tempScript") || die "Cannot open $tempScript"; my $oneLine = ""; open (RECOVERY_SCRIPT, "$recoveryScript") || die "Unable to open $recoveryScript\n"; while ($oneLine = ) { if($oneLine=~/$insertFlag/) { print TEMP_SCRIPT "$oneLine"; print TEMP_SCRIPT "$script"; } print TEMP_SCRIPT "$oneLine"; } close RECOVERY_SCRIPT; close TEMP_SCRIPT; !copyFile($tempScript, $recoveryScript) || (EMD_PERL_DEBUG("convert.insertScriptToFile(): Error copying $tempScript to $recoveryScript") && (die "convert.insertScriptToFile(): Error copying $tempScript to $recoveryScript")); &removeFile($tempScript); EMD_PERL_DEBUG("convert.insertScriptToFile(): *** END ***"); } # Generate script to restore online logs for the source database in case of failure # generateRestoreLogsScript(logBackupLoc, backupLogFiles, logFiles) sub generateRestoreLogsScript { EMD_PERL_DEBUG("convert.generateRestoreLogsScript(): *** START ***"); my ($logBackupLoc, $backupLogFilesArrayArg, $logFilesArrayArg) = @_; EMD_PERL_DEBUG("convert.generateRestoreLogsScript(): logBackupLoc: $logBackupLoc"); EMD_PERL_DEBUG("convert.generateRestoreLogsScript(): Backup log files: $backupLogFilesArrayArg"); EMD_PERL_DEBUG("convert.generateRestoreLogsScript(): Log files: $logFilesArrayArg"); if($NT) { $backupLogFilesArrayArg = &doubleBackSlashes($backupLogFilesArrayArg); $logFilesArrayArg = &doubleBackSlashes($logFilesArrayArg); } my $perlScript = ""; $perlScript .= "my \$backupLogFilesArray = \"$backupLogFilesArrayArg\";\n"; $perlScript .= "my \$logFilesArray = \"$logFilesArrayArg\";\n"; $perlScript .= "my \$delimiter = \":::\";\n"; $perlScript .= "my \@backupLogFiles = split /\$delimiter/, \$backupLogFilesArray;\n"; $perlScript .= "my \@logFiles = split /\$delimiter/, \$logFilesArray;\n"; $perlScript .= "my \$backupLogFile = \"\";\n"; $perlScript .= "my \$index = 0;\n"; $perlScript .= "foreach \$backupLogFile (\@backupLogFiles)\n"; $perlScript .= "{\n"; $perlScript .= " copy(\$backupLogFile, \$logFiles[\$index]) || (die \"Error copying \$backupLogFile to \$logFiles[\$index]\");\n"; $perlScript .= " \$index = \$index + 1;\n"; $perlScript .= "}\n"; $perlScript .= "\n"; EMD_PERL_DEBUG("convert.generateRestoreLogsScript(): restore logs script: $perlScript"); insertScriptToFile($logBackupLoc, "revert.pl", $perlScript, "# Restore the original online logs"); EMD_PERL_DEBUG("convert.generateRestoreLogsScript(): *** END ***"); } # Generate recovery script to recover the source database in case of failure # Call &set_env(oracleHome, oracleSid) before calling this method. # generateRecoveryScript(logBackupLoc, spfileName, pfileFullName, # backupInitOrSPFileName, isRac, dbName) sub generateRecoveryScript { EMD_PERL_DEBUG("convert.generateRecoveryScript(): *** START ***"); my ($logBackupLoc, $spfileName, $pfileFullName, $backupInitOrSPFileName, $isRac, $dbName) = @_; EMD_PERL_DEBUG("convert.generateRecoveryScript(): logBackupLoc: $logBackupLoc"); EMD_PERL_DEBUG("convert.generateRecoveryScript(): spfileName: $spfileName"); EMD_PERL_DEBUG("convert.generateRecoveryScript(): pfileFullName: $pfileFullName"); EMD_PERL_DEBUG("convert.generateRecoveryScript(): backupInitOrSPFileName: $backupInitOrSPFileName"); EMD_PERL_DEBUG("convert.generateRecoveryScript(): isRac: $isRac"); EMD_PERL_DEBUG("convert.generateRecoveryScript(): dbName: $dbName"); my $origInitFile = $spfileName; if ($spfileName eq "") { $origInitFile = $pfileFullName; } my $PATH_SP = ":"; my $SLASH = "/"; if($NT) { $PATH_SP =";"; $SLASH = "\\"; } my $ORACLE_HOME = ""; my $ORACLE_SID = ""; my $LD_LIBRARY_PATH = ""; my $SHLIB_PATH = ""; my $LIBPATH = ""; my $PATH = ""; my $sqlplus = ""; $ORACLE_HOME = $ENV{ORACLE_HOME}; $ORACLE_SID = $ENV{ORACLE_SID}; if(defined($ENV{LD_LIBRARY_PATH})){ $LD_LIBRARY_PATH = "$ENV{ORACLE_HOME}${SLASH}lib${PATH_SP}$ENV{LD_LIBRARY_PATH}"; } else{ $LD_LIBRARY_PATH = "$ENV{ORACLE_HOME}${SLASH}lib"; } if(defined($ENV{SHLIB_PATH})){ $SHLIB_PATH = "$ENV{ORACLE_HOME}${SLASH}lib${PATH_SP}$ENV{SHLIB_PATH}"; } else{ $SHLIB_PATH = "$ENV{ORACLE_HOME}${SLASH}lib"; } if(defined($ENV{LIBPATH})){ $LIBPATH = "$ENV{ORACLE_HOME}${SLASH}lib${PATH_SP}$ENV{LIBPATH}"; } else{ $LIBPATH = "$ENV{ORACLE_HOME}${SLASH}lib"; } if(defined($ENV{PATH})){ $PATH = "$ENV{ORACLE_HOME}${SLASH}bin${PATH_SP}$ENV{PATH}"; } else{ $PATH = "$ENV{ORACLE_HOME}${SLASH}bin"; } $sqlplus = "$ENV{ORACLE_HOME}${SLASH}bin${SLASH}sqlplus"; if($NT) { $sqlplus = &doubleBackSlashes($sqlplus); $backupInitOrSPFileName = &doubleBackSlashes($backupInitOrSPFileName); $origInitFile = &doubleBackSlashes($origInitFile); $LD_LIBRARY_PATH = &doubleBackSlashes($LD_LIBRARY_PATH); $SHLIB_PATH = &doubleBackSlashes($SHLIB_PATH); $LIBPATH = &doubleBackSlashes($LIBPATH); $PATH = &doubleBackSlashes($PATH); $ORACLE_HOME = &doubleBackSlashes($ORACLE_HOME); } my $sqlScript = ""; if($isRac ne "Y") { $sqlScript .= "open(SQL_SCRIPT, \"|$sqlplus /nolog\")\n"; $sqlScript .= " || die \"Cannot open pipe for SQL_SCRIPT\";\n"; $sqlScript .= "print SQL_SCRIPT \"connect / as sysdba\\n\";\n"; $sqlScript .= "print SQL_SCRIPT \"shutdown abort\\n\";\n"; if ($spfileName eq "") { $sqlScript .= "print SQL_SCRIPT \"startup pfile='$origInitFile'\\n\";\n"; } else { $sqlScript .= "print SQL_SCRIPT \"startup\\n\";\n"; } $sqlScript .= "close SQL_SCRIPT || die \"Bad SQL_SCRIPT\";\n"; } else { $sqlScript .= "print \"srvctl stop database -d $dbName ... \\n\";\n"; $sqlScript .= "my \@ret = `srvctl stop database -d $dbName`;\n"; $sqlScript .= "print \"\@ret\\n\";\n"; $sqlScript .= "print \"srvctl start database -d $dbName ... \\n\";\n"; $sqlScript .= "\@ret = `srvctl start database -d $dbName`;\n"; $sqlScript .= "print \"\@ret\\n\";\n"; $sqlScript .= "print \"srvctl status database -d $dbName ... \\n\";\n"; $sqlScript .= "\@ret = `srvctl status database -d $dbName`;\n"; $sqlScript .= "print \"\@ret\\n\";\n"; } my $restoreLogScript = ""; $restoreLogScript .= "# Restore the original online logs \n"; my $perlScript = ""; $perlScript .= "# Run this script to recover the original database. \n"; $perlScript .= "# It is assumed that the user running this script is a dba member. \n"; $perlScript .= "# If you could not connect the database with OS authentication, \n"; $perlScript .= "# please connect it as sys with sysdba role (by providing sys password), \n"; $perlScript .= "# then execute the following sql commands: \n"; $perlScript .= "# shutdown abort; startup \n"; $perlScript .= "\n"; $perlScript .= "use strict;\n"; $perlScript .= "use File::Copy;\n"; $perlScript .= "\n"; $perlScript .= "# Restore the original init.ora \n"; $perlScript .= "copy(\"$backupInitOrSPFileName\", \"$origInitFile\")\n"; $perlScript .= " or (die \"Can't copy '$backupInitOrSPFileName' to '$origInitFile': \$!\");\n"; $perlScript .= "\n"; $perlScript .= "$restoreLogScript"; $perlScript .= "# Set necessary environmental variables \n"; $perlScript .= "\$ENV{LD_LIBRARY_PATH} = \"$LD_LIBRARY_PATH\";\n"; $perlScript .= "\$ENV{SHLIB_PATH} = \"$SHLIB_PATH\";\n"; $perlScript .= "\$ENV{LIBPATH} = \"$LIBPATH\";\n"; $perlScript .= "\$ENV{PATH} = \"$PATH\";\n"; $perlScript .= "\$ENV{ORACLE_HOME} = \"$ORACLE_HOME\";\n"; $perlScript .= "\$ENV{ORACLE_SID} = \"$ORACLE_SID\";\n"; $perlScript .= "\n"; $perlScript .= "# Run sql script to start the original database \n"; $perlScript .= "$sqlScript\n"; $perlScript .= "\n"; EMD_PERL_DEBUG("convert.generateRecoveryScript(): recovery script: \n\n$perlScript"); my $recoveryScript = File::Spec->catfile($logBackupLoc, "revert.pl"); open(RECOVERY_SCRIPT, ">$recoveryScript") || die "Cannot open $recoveryScript"; print RECOVERY_SCRIPT "$perlScript"; close RECOVERY_SCRIPT || die "Cannot close $recoveryScript"; EMD_PERL_DEBUG("convert.generateRecoveryScript(): *** END ***"); } # Start deferring the standard output # set global variables: DEFER_OUTPUT, OUTPUT_LOC, INDEX # startDeferOutput(logBackupLoc) sub startDeferOutput { EMD_PERL_DEBUG("convert.startDeferOutput(): *** START ***"); my ($logBackupLoc) = @_; $DEFER_OUTPUT = 'Y'; $OUTPUT_LOC = File::Spec->catfile($logBackupLoc, "downtime_output"); $INDEX = 1; my $ret = &mkDir($OUTPUT_LOC); if($ret eq "NOK") { EMD_PERL_ERROR("convert.startDeferOutput(): Could not create location: $OUTPUT_LOC"); exit(1); } EMD_PERL_DEBUG("convert.startDeferOutput(): *** END ***"); } # End deferring the standard output and print output file contents to STDOUT # reset global variables: DEFER_OUTPUT, OUTPUT_LOC, INDEX # endDeferOutput() sub endDeferOutput { EMD_PERL_DEBUG("convert.endDeferOutput(): *** START ***"); my $index = 1; my $outputFile; foreach (1 .. ($INDEX - 1)) { $outputFile = File::Spec->catfile($OUTPUT_LOC, "output_file_".$index); #Open the file to get output open (OUT_PUT, "$outputFile") || die "Unable to open file $outputFile for OUT_PUT\n"; my @output_content = ; my $mesg = "@output_content"; close OUT_PUT; print STDOUT $mesg; $index ++; } #Remove the output location &removeDir($OUTPUT_LOC); $DEFER_OUTPUT = 'N'; $OUTPUT_LOC = ""; $INDEX = 1; EMD_PERL_DEBUG("convert.endDeferOutput(): *** END ***"); } # Enable/disable threads for other rac instances # Call &set_env($oracleHome, $oracleSid) before calling this method. # handleThreadsForOtherRacInstances(instance, action) sub handleThreadsForOtherRacInstances { EMD_PERL_DEBUG("convert.handleThreadsForOtherRacInstances(): *** START ***"); my ($instance, $action) = @_; my $sql_string = ""; $sql_string .= "set echo off\n"; $sql_string .= "CONNECT $userID AS SYSDBA;\n"; $sql_string .= "set echo on\n"; $sql_string .= "set serveroutput on;\n"; $sql_string .= "set linesize 513;\n"; $sql_string .= "BEGIN\n"; $sql_string .= " FOR tdrec IN (SELECT thread# FROM v\$thread WHERE instance <> '$instance')\n"; $sql_string .= " LOOP\n"; $sql_string .= " dbms_output.put_line('thread# ' || tdrec.thread#);\n"; $sql_string .= " execute immediate 'alter database $action thread ' || tdrec.thread#;\n"; $sql_string .= " END LOOP;\n"; $sql_string .= "END;\n"; $sql_string .= "/\n"; $sql_string .= "EXIT;\n"; (my $fh, my $filename) = &runSql($sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("convert.handleThreadsForOtherRacInstances(): *** END ***"); } # Migrate all recovery related files and backup datafiles as copies to ASM (hot) # # Modify init parameters # Migrate recovery related files # Bounce or enable block change tracking # Backup datafile as copies to ASM # # To migrate the whole database, pass "" for datafileNums # Call &set_env($oracleHome, $oracleSid) before calling this method. # preMigration(isMigrateDBFiles, isMigrateRecoveryFiles, isSetupRecoveryAreaOnly, # dbFilesLoc, recoveryFilesSize, recoveryFilesLoc, archLogLocation, # dbFileIDsArray, dbFileLocsArray, pfileFullName, multiplexLocsArray, # hotMigrationFlag, logBackupLoc, parallelizeCopying) sub preMigration { EMD_PERL_DEBUG("convert.preMigration(): *** START ***"); my ($isMigrateDBFiles, $isMigrateRecoveryFiles, $isSetupRecoveryAreaOnly, $dbFilesLoc, $recoveryFilesSize, $recoveryFilesLoc, $archLogLocation, $dbFileIDsArray, $dbFileLocsArray, $pfileFullName, $multiplexLocsArray, $hotMigrationFlag, $logBackupLoc, $parallelizeCopying) = @_; EMD_PERL_DEBUG("convert.preMigration(): isMigrateDBFiles: $isMigrateDBFiles"); EMD_PERL_DEBUG("convert.preMigration(): isMigrateRecoveryFiles: $isMigrateRecoveryFiles"); EMD_PERL_DEBUG("convert.preMigration(): isSetupRecoveryAreaOnly: $isSetupRecoveryAreaOnly"); EMD_PERL_DEBUG("convert.preMigration(): dbFilesLoc: $dbFilesLoc"); EMD_PERL_DEBUG("convert.preMigration(): recoveryFilesSize: $recoveryFilesSize"); EMD_PERL_DEBUG("convert.preMigration(): recoveryFilesLoc: $recoveryFilesLoc"); EMD_PERL_DEBUG("convert.preMigration(): archLogLocation: $archLogLocation"); EMD_PERL_DEBUG("convert.preMigration(): dbFileIDsArray: $dbFileIDsArray"); EMD_PERL_DEBUG("convert.preMigration(): dbFileLocsArray: $dbFileLocsArray"); EMD_PERL_DEBUG("convert.preMigration(): pfileFullName: $pfileFullName"); EMD_PERL_DEBUG("convert.preMigration(): multiplexLocsArray: $multiplexLocsArray"); EMD_PERL_DEBUG("convert.preMigration(): hotMigrationFlag: $hotMigrationFlag"); #EMD_PERL_DEBUG("convert.preMigration(): logBackupLoc: $logBackupLoc"); EMD_PERL_DEBUG("convert.preMigration(): parallelizeCopying: $parallelizeCopying"); ###Define variables used in this sub #for customizing datafile locations my @datafileNums = split /$DELIMITER/, $dbFileIDsArray; my @diskGroups = split /$DELIMITER/, $dbFileLocsArray; my $setupRecoveryAreaOnly = "FALSE"; my $spfileName; my $space = 0; my $modifiedInitNames; my $modifiedInitValues; my $backupInitOrSPFileName = ""; my $isRac; my $dbName; ###Get necessary info #check if setupRecoveryAreaOnly $setupRecoveryAreaOnly = isOnlySetupRecoveryArea($isMigrateDBFiles, $isMigrateRecoveryFiles, $isSetupRecoveryAreaOnly); #Get init file name, non empty value means it is being used ($spfileName, $pfileFullName) = checkPfile($pfileFullName); #Get space used in recovery area $space = getSpaceUsedInRecoveryArea(); ###Modify init parameters #Save the original init file or spfile #if($spfileName eq "") #{ # $backupInitOrSPFileName = backupFile($pfileFullName); #} #else #{ # $backupInitOrSPFileName = backupFile($spfileName); #} #Get isRac and dbName ($isRac, $dbName) = getIsRacDbName(); #Create temp location for recovery #This should be done after saving the original init file #so the generated recovery script contains the original init file location info. #The generated script should be saved in this location. #if($isMigrateDBFiles eq "Y") #{ # createTempLocationForRecovery($logBackupLoc); # generateRecoveryScript($logBackupLoc, $spfileName, $pfileFullName, # $backupInitOrSPFileName, $isRac, $dbName); #} #construct init parameters based on user selections ($modifiedInitNames, $modifiedInitValues) = constructInitParameters( $isMigrateDBFiles, $isMigrateRecoveryFiles, $isSetupRecoveryAreaOnly, $dbFilesLoc, $recoveryFilesLoc, $recoveryFilesSize, $multiplexLocsArray, $space); #Add or modify parameters in init file if($spfileName eq "") { modifyInitFile($modifiedInitNames, $modifiedInitValues, $pfileFullName); modifyDynamicParameters($modifiedInitNames, $modifiedInitValues); } else { modifySpfile($modifiedInitNames, $modifiedInitValues, "N", "N"); } if($setupRecoveryAreaOnly eq "TRUE") { return; } ###Migrate recovery related files if(($isMigrateRecoveryFiles eq "Y") && ($isSetupRecoveryAreaOnly ne "Y")) { migrateRecoveryFiles($archLogLocation, $parallelizeCopying); #Modify DB_RECOVERY_FILE_DEST_SIZE to reduce the used space by recovery files modifyRecoveryDestSizeInitParam($pfileFullName, $recoveryFilesSize, "N"); } ###Bounce or enable block change tracking if($isMigrateDBFiles eq "Y") { checkAndDisableChangeTracking(); if($hotMigrationFlag eq "Y") { enableChangeTracking(); } } ###Backup datafile as copies to ASM if(($hotMigrationFlag eq "Y") && ($isMigrateDBFiles eq "Y")) { migrateDatafilesLevelZero($dbFileIDsArray, $dbFileLocsArray, $dbFilesLoc, $parallelizeCopying); } EMD_PERL_DEBUG("convert.preMigration(): *** END ***"); } # Switch the database to use the datafile copies at ASM (cold) # # Backup database at level 1 (increamental) # Shutdown database # Restore control file # Switch database to copies at ASM # Recover database # Migrate spfile # Open database # Migrate temp files # Migrate online logs # Migrate flashback files (need to restart database) # Cleanup files on file system # # Call &set_env($oracleHome, $oracleSid) before calling this method. # switchDatabase(pfileFullName, dbFilesLoc, dbFileIDsArray, dbFileLocsArray, # isMigrateSPFile, migratedSpfile, isDeleteSourceDB, # logBackupLoc, flashbackFlag, hotMigrationFlag, # dbInstancesArray, asmInstancesArray, targetDBReposDB, # parallelizeCopying, tempIDs, tempDGs, asmTest) sub switchDatabase { EMD_PERL_DEBUG("convert.switchDatabase(): *** START ***"); my ($pfileFullName, $dbFilesLoc, $dbFileIDsArray, $dbFileLocsArray, $isMigrateSPFile, $migratedSpfile, $isDeleteSourceDB, $logBackupLoc, $flashbackFlag, $hotMigrationFlag, $dbInstancesArray, $asmInstancesArray, $targetDBReposDB, $parallelizeCopying, $tempIDs, $tempDGs, $asmTest) = @_; EMD_PERL_DEBUG("convert.switchDatabase(): pfileFullName: $pfileFullName"); EMD_PERL_DEBUG("convert.switchDatabase(): dbFilesLoc: $dbFilesLoc"); EMD_PERL_DEBUG("convert.switchDatabase(): dbFileIDsArray: $dbFileIDsArray"); EMD_PERL_DEBUG("convert.switchDatabase(): dbFileLocsArray: $dbFileLocsArray"); EMD_PERL_DEBUG("convert.switchDatabase(): isMigrateSPFile: $isMigrateSPFile"); EMD_PERL_DEBUG("convert.switchDatabase(): migratedSpfile: $migratedSpfile"); EMD_PERL_DEBUG("convert.switchDatabase(): isDeleteSourceDB: $isDeleteSourceDB"); #EMD_PERL_DEBUG("convert.switchDatabase(): logBackupLoc: $logBackupLoc"); EMD_PERL_DEBUG("convert.switchDatabase(): flashbackFlag: $flashbackFlag"); EMD_PERL_DEBUG("convert.switchDatabase(): hotMigrationFlag: $hotMigrationFlag"); EMD_PERL_DEBUG("convert.switchDatabase(): dbInstancesArray: $dbInstancesArray"); EMD_PERL_DEBUG("convert.switchDatabase(): asmInstancesArray: $asmInstancesArray"); EMD_PERL_DEBUG("convert.switchDatabase(): targetDBReposDB: $targetDBReposDB"); EMD_PERL_DEBUG("convert.switchDatabase(): parallelizeCopying: $parallelizeCopying"); EMD_PERL_DEBUG("convert.switchDatabase(): tempIDs: $tempIDs"); EMD_PERL_DEBUG("convert.switchDatabase(): tempDGs: $tempDGs"); EMD_PERL_DEBUG("convert.switchDatabase(): asmTest: $asmTest"); ###Define variables used in this sub my $spfileName; my $controlFileNamesArray; my $logFilesNamesArray; my $tempFiles; my $fileIds; my $sizes; my $tablespaces; my $autoextendClauses; my $backupLogs; my $isRac; my $dbName; my $anyOnlinelogOnDG; my $toLocationsForTempfiles; ###Get necessary info #Get init file name, non empty value means it is being used ($spfileName, $pfileFullName) = checkPfile($pfileFullName); #Get control file info $controlFileNamesArray = getControlFiles(); #Get the fullnames of valid log files $logFilesNamesArray = getLogFiles(); #Get tempfile names and attributes ($tempFiles, $fileIds, $sizes, $tablespaces, $autoextendClauses) = getTempFiles(); #Get isRac and dbName ($isRac, $dbName) = getIsRacDbName(); #check if any onlinelog resides on diskgroup $anyOnlinelogOnDG = isAnyOnlinelogOnDiskgroup($logFilesNamesArray); ###Backup database at level 1 if($hotMigrationFlag eq "Y") { migrateDatafilesLevelOne($parallelizeCopying); } if($targetDBReposDB eq 'Y') { #startDeferOutput($logBackupLoc); startDeferOutput(&getDefaultDBLocation); } ###Shutdown database shutdownDB("immediate"); #if rac, shutdown all instances shutdownAllInstances($isRac, $dbName); #if rac, disable crs service for the connected db instance if($isRac eq "Y") { runSrvctl("disable database -d $dbName"); } ###Backup online logs #if($anyOnlinelogOnDG eq "N") #{ # $backupLogs = backupOnlineLogs($logBackupLoc, $logFilesNamesArray); #} ###Restore control file #reset control file parameters if($spfileName eq "") { commentCtlFileParamInitFile($pfileFullName); } else { modifySpfile($DELIMITER, $DELIMITER, "Y", "Y"); } #Restore the control files to ASM and mount the instance my $restoredControlFiles = restoreControlFile($pfileFullName, $controlFileNamesArray); #if using pfile, add restored control files to init file and restart instance if($restoredControlFiles ne "") { addControlFileToInitFile($restoredControlFiles, $pfileFullName); shutdownDB("abort"); startupDB("mount", $pfileFullName); } ###Migrate spfile if($isMigrateSPFile eq "Y") { my $initFile = migrateSPFile($pfileFullName, $spfileName, $migratedSpfile); shutdownDB("abort"); startupDB("mount", $initFile); } ###Migrate datafiles if($hotMigrationFlag eq "Y") { ###Switch database to copies at ASM switchDatafileCopies(); ###Recover database recoverDatabase(); } else { migrateDatafiles($dbFileIDsArray, $dbFileLocsArray, $dbFilesLoc, $parallelizeCopying); } ###Drop temp files residing on file system dropTempfiles($tempFiles); #Generate restore log script before openning database #generateRestoreLogsScript($logBackupLoc, $backupLogs, $logFilesNamesArray); ###Open database alterDatabaseOpen(); if($targetDBReposDB eq 'Y') { endDeferOutput(); } ###Add temp files to ASM $toLocationsForTempfiles = getToLocationsForTempfiles($fileIds, $tempIDs, $tempDGs, $dbFilesLoc); addTempfilesConvert($toLocationsForTempfiles, $sizes, $tablespaces, $autoextendClauses); if($isRac eq "Y") { handleThreadsForOtherRacInstances($ENV{ORACLE_SID}, "disable"); } ###Migrate online log files if($hotMigrationFlag eq "Y") { migrateOnlineLogsHot(); migrateOnlineLogsStandbyHot(); } else { migrateOnlineLogs(); } if($isRac eq "Y") { handleThreadsForOtherRacInstances($ENV{ORACLE_SID}, "enable public"); } #if rac, enable crs service for the connected db instance if($isRac eq "Y") { runSrvctl("enable database -d $dbName"); } #if rac, startup all instances startupAllInstances($isRac, $dbName); if($isDeleteSourceDB ne "Y") { #Overwrite original online logs with the backup online logs if($anyOnlinelogOnDG eq "N") { #restoreOnlineLogs($backupLogs, $logFilesNamesArray); } } ###Migrate flashback files if($flashbackFlag eq "Y") { migrateFlashbackFiles($pfileFullName, $isRac, $dbName); } ###RAC: Associate database instances with asm instances associateDbAsmInstances($isRac, $dbName, $dbInstancesArray, $asmInstancesArray); ###Cleanup files on file system if($isDeleteSourceDB eq "Y") { #Cleanup database copy cleanupDBConvert(); #delete other database files on file system &removeFiles($controlFileNamesArray); &removeFiles($logFilesNamesArray); &removeFiles($tempFiles); } #Remove the temp backup location if($asmTest ne "Y") { &removeDir($logBackupLoc); } EMD_PERL_DEBUG("convert.switchDatabase(): *** END ***"); } # Verify the database has been moved to ASM (hot) # # Disable the block change tracking if it was off before the migration # Verify all files are residing on ASM # # Call &set_env($oracleHome, $oracleSid) before calling this method. # postMigration(changeTrackingFlag, hotMigrationFlag) sub postMigration { EMD_PERL_DEBUG("convert.postMigration(): *** START ***"); my ($changeTrackingFlag, $hotMigrationFlag) = @_; EMD_PERL_DEBUG("convert.postMigration(): changeTrackingFlag: $changeTrackingFlag"); EMD_PERL_DEBUG("convert.postMigration(): hotMigrationFlag: $hotMigrationFlag"); ###Disable/enable block change tracking # Hot: if it was disabled before the migration, then disable it here # Cold: if it was enabled before the migration, then enable it here if($hotMigrationFlag eq "Y") { if($changeTrackingFlag eq "N") { #For now, do not disable the change tracking since it will delete the tracking #file and the original database has migrated its tracking file to ASM. #If disable, the original database is not openable. #checkAndDisableChangeTracking(); } } else { if($changeTrackingFlag eq "Y") { enableChangeTracking(); } } ###Verify all files are residing on ASM checkDatabaseFiles(); EMD_PERL_DEBUG("convert.postMigration(): *** END ***"); } # Migrate the target DB to ASM # if hotMigrationFlag is set to "Y", do a hot migration, otherwise, do a cold migration # # HOT migration: # Migrate the target DB to ASM with short outage # Require the database be in ARCHIVELOG mode # # preMigration: migrate recovery files and backup the database as copies to ASM (hot) # switchDatabase: switch database to ASM copies (cold) # postMigration: disable or enable block change tracking files (hot) # # COLD migration: # Migrate the target DB to ASM with long outage # Do NOT require the target DB be in ARCHIVELOG mode # # preMigration: migrate recovery related files (hot) # switchDatabase: backup datafiles as ASM copies and switch database to copies (cold) # postMigration: disable or enable block change tracking files (hot) # # Call &set_env($oracleHome, $oracleSid) before calling this method. # Arguments values: # isMigrateDBFiles: Y/N, isMigrateRecoveryFiles: Y/N, archLogLocation: Y/N (migrate arch or not) # pfileFullName: a file full name/N, dbFilesLoc: one disk group, # dbFileIDsArray: file ID's separated by delimiters, # dbFileLocsArray: disk groups separated by delimiters, # isMigrateSPFile: Y/N, migratedSpfile: a unique file full name, # isDeleteSourceDB: Y/N, multiplexLocsArray: disk groups separated by delimiters, # recoveryFilesLoc: one disk group, recoveryFilesSize: size in MB, # isSetupRecoveryAreaOnly: Y/N, logBackupLoc: location to backup logs # flashbackFlag: Y/N, changeTrackingFlag: Y/N, hotMigrationFlag: Y/N # dbInstancesArray: db instance names for RAC, # asmInstancesArray: asm instance names for RAC, targetDBReposDB: Y/N # parallelizeCopying: allocate multiple rman channels: Y/N # tempIDs, tempDGs: the id's and disk groups for temp files # asmTest: a flag for regression: Y/N # migrateToASM(isMigrateDBFiles, isMigrateRecoveryFiles, archLogLocation, pfileFullName, # dbFilesLoc, dbFileIDsArray, dbFileLocsArray, isMigrateSPFile, migratedSpfile, # isDeleteSourceDB, multiplexLocsArray, recoveryFilesLoc, recoveryFilesSize, # isSetupRecoveryAreaOnly, logBackupLoc, flashbackFlag, changeTrackingFlag,hotMigrationFlag, # dbInstancesArray, asmInstancesArray, targetDBReposDB, parallelizeCopying, tempIDs, tempDGs, # asmTest) sub migrateToASM { EMD_PERL_DEBUG("convert.migrateToASM(): *** START ***"); my ($isMigrateDBFiles, $isMigrateRecoveryFiles, $archLogLocation, $pfileFullName, $dbFilesLoc, $dbFileIDsArray, $dbFileLocsArray, $isMigrateSPFile, $migratedSpfile, $isDeleteSourceDB, $multiplexLocsArray, $recoveryFilesLoc, $recoveryFilesSize, $isSetupRecoveryAreaOnly, $logBackupLoc, $flashbackFlag, $changeTrackingFlag, $hotMigrationFlag, $dbInstancesArray, $asmInstancesArray, $targetDBReposDB, $parallelizeCopying, $tempIDs, $tempDGs, $asmTest) = @_; EMD_PERL_DEBUG("convert.migrateToASM(): isMigrateDBFiles: $isMigrateDBFiles"); EMD_PERL_DEBUG("convert.migrateToASM(): isMigrateRecoveryFiles: $isMigrateRecoveryFiles"); EMD_PERL_DEBUG("convert.migrateToASM(): archLogLocation: $archLogLocation"); EMD_PERL_DEBUG("convert.migrateToASM(): pfileFullName: $pfileFullName"); EMD_PERL_DEBUG("convert.migrateToASM(): dbFilesLoc: $dbFilesLoc"); EMD_PERL_DEBUG("convert.migrateToASM(): dbFileIDsArray: $dbFileIDsArray"); EMD_PERL_DEBUG("convert.migrateToASM(): dbFileLocsArray: $dbFileLocsArray"); EMD_PERL_DEBUG("convert.migrateToASM(): isMigrateSPFile: $isMigrateSPFile"); EMD_PERL_DEBUG("convert.migrateToASM(): migratedSpfile: $migratedSpfile"); EMD_PERL_DEBUG("convert.migrateToASM(): isDeleteSourceDB: $isDeleteSourceDB"); EMD_PERL_DEBUG("convert.migrateToASM(): multiplexLocsArray: $multiplexLocsArray"); EMD_PERL_DEBUG("convert.migrateToASM(): recoveryFilesLoc: $recoveryFilesLoc"); EMD_PERL_DEBUG("convert.migrateToASM(): recoveryFilesSize: $recoveryFilesSize"); EMD_PERL_DEBUG("convert.migrateToASM(): isSetupRecoveryAreaOnly: $isSetupRecoveryAreaOnly"); #EMD_PERL_DEBUG("convert.migrateToASM(): logBackupLoc: $logBackupLoc"); EMD_PERL_DEBUG("convert.migrateToASM(): flashbackFlag: $flashbackFlag"); EMD_PERL_DEBUG("convert.migrateToASM(): changeTrackingFlag: $changeTrackingFlag"); EMD_PERL_DEBUG("convert.migrateToASM(): hotMigrationFlag: $hotMigrationFlag"); EMD_PERL_DEBUG("convert.migrateToASM(): dbInstancesArray: $dbInstancesArray"); EMD_PERL_DEBUG("convert.migrateToASM(): asmInstancesArray: $asmInstancesArray"); EMD_PERL_DEBUG("convert.migrateToASM(): targetDBReposDB: $targetDBReposDB"); EMD_PERL_DEBUG("convert.migrateToASM(): parallelizeCopying: $parallelizeCopying"); EMD_PERL_DEBUG("convert.migrateToASM(): tempIDs: $tempIDs"); EMD_PERL_DEBUG("convert.migrateToASM(): tempDGs: $tempDGs"); EMD_PERL_DEBUG("convert.migrateToASM(): asmTest: $asmTest"); preMigration($isMigrateDBFiles, $isMigrateRecoveryFiles, $isSetupRecoveryAreaOnly, $dbFilesLoc, $recoveryFilesSize, $recoveryFilesLoc, $archLogLocation, $dbFileIDsArray, $dbFileLocsArray, $pfileFullName, $multiplexLocsArray, $hotMigrationFlag, $logBackupLoc, $parallelizeCopying); if($isMigrateDBFiles eq "Y") { switchDatabase($pfileFullName, $dbFilesLoc, $dbFileIDsArray, $dbFileLocsArray, $isMigrateSPFile, $migratedSpfile, $isDeleteSourceDB, $logBackupLoc, $flashbackFlag, $hotMigrationFlag, $dbInstancesArray, $asmInstancesArray, $targetDBReposDB, $parallelizeCopying, $tempIDs, $tempDGs, $asmTest); } if($isMigrateDBFiles eq "Y") { postMigration($changeTrackingFlag, $hotMigrationFlag); } EMD_PERL_DEBUG("convert.migrateToASM(): *** END ***"); } 1; #Tests sub main_convert { #General tests $ENV{EMAGENT_PERL_TRACE_LEVEL} = 0; set_env("/private2/oracle/10.1.0.2", "v10102"); #set_env("/private2/oracle/10.1.0.2", "v10102", "/private2/oracle/10.1.0.2/network/admin/listener.ora"); #NT #set_env("C:/ade/szhu_sa0804/oracle", "ssa0804"); setSrcDBCredential("sys", "oracle"); #define variables for testing #Hot migration requires the DB ruuning in ARCHIVELOG mode my $hotMigrationFlag = "Y"; my $isMigrateDBFiles = "Y"; my $isMigrateRecoveryFiles = "Y"; my $archLogLocation = "N"; my $pfileFullName = "/private2/oracle/10.1.0.2/dbs/initv10102.ora"; my $dbFilesLoc = "+DATA1"; my $dbFileIDsArray = "1:::2:::3:::4:::"; my $dbFileLocsArray = "+DATA1:::+DATA2:::+DATA3:::+DATA3:::"; my $isMigrateSPFile = "N"; my $migratedSpfile = "+DATA1/v10102/spfilev10102.ora_121"; my $isDeleteSourceDB = "N"; my $multiplexLocsArray = ":::"; my $recoveryFilesLoc = "+DATA2"; my $recoveryFilesSize = "2048M"; my $isSetupRecoveryAreaOnly = "Y"; my $logBackupLoc = "/private2/oracle/10.1.0.2/dbs/v10102_121"; my $flashbackFlag = "N"; my $changeTrackingFlag = "N"; my $dbInstancesArray = ":::"; my $asmInstancesArray = ":::"; my $targetDBReposDB = ":::"; my $parallelizeCopying = "N"; my $tempIDs = ":::"; my $tempDGs = ":::"; my $asmTest = "N"; #test view db $hotMigrationFlag = "Y"; $isSetupRecoveryAreaOnly = "Y"; #set_env("/ade/szhu_sa0506/oracle", "ssa0506"); #setSrcDBCredential("sysman", "sysman"); #$pfileFullName = "/ade/szhu_sa0506/oracle/dbs/initssa0506.ora"; #$migratedSpfile = "+DATA1/ssa0506/spfilessa0506.ora_121"; #$logBackupLoc = "/ade/szhu_sa0506/oracle/dbs/ssa0506_121"; migrateToASM($isMigrateDBFiles, $isMigrateRecoveryFiles, $archLogLocation, $pfileFullName, $dbFilesLoc, $dbFileIDsArray, $dbFileLocsArray, $isMigrateSPFile, $migratedSpfile, $isDeleteSourceDB, $multiplexLocsArray, $recoveryFilesLoc, $recoveryFilesSize, $isSetupRecoveryAreaOnly, $logBackupLoc, $flashbackFlag, $changeTrackingFlag, $hotMigrationFlag, $dbInstancesArray, $asmInstancesArray, $targetDBReposDB, $parallelizeCopying, $tempIDs, $tempDGs, $asmTest); } #main_convert();