# 
# dgcreate_o.pl
# 
# Copyright (c) 2004, 2009, Oracle and/or its affiliates.All rights reserved. 
#
#    NAME
#      dgcreate_10_2.pl
#
#    DESCRIPTION
#      Data Guard physical/logical post-DBClone standby creation
#      for 10.2 OMS
#
#    NOTES
#      This file is used by the 10.2 OMS for DG create standby jobs.
#      It is streamed to the Agent from the OMS side, and cannot be
#      used alone, as it calls some routines in db_clone_10_2.pl. Since
#      it does not include this file, it is bundled with db_clone_10_2.pl
#      during the streaming process. Therefore, it cannot be compiled
#      by itself from the command line.
#
#    MODIFIED   (MM/DD/YY)
#    ngade       02/17/09 - Code slap 10.2.0.5.0 -> 11.2 round 2
#    ngade       08/03/08 - Code Slap 10.2.0.5GC -> 11.2SA
#    sjconnol    10/20/08 - Support for no-broker creation
#    rimmidi     05/04/08 - Code slap from 11GC to 10.2.0.5
#    rimmidi     06/11/07 - Password File Modification
#    sjconnol    03/21/07 - Backport sjconnol_bug5699797a from main
#    sjconnol    02/13/07 - 
#    sjconnol    10/20/07 - Bug 6516731
#    ngade       11/03/06 - RMAN backup support
#    sjconnol    11/02/06 - Bug 5624530
#    ngade       09/19/06 - fix nls bug 5250491
#    sjconnol    07/11/06 - Bug 5352565
#    sjconnol    05/02/06 - Bug 5162803
#    sjconnol    09/28/05 - Bug 4636417, 4652338
#    sjconnol    09/14/05 - Bug 4607258
#    sxzhu       09/06/05 - ASM spfile support
#    sjconnol    08/29/05 - Bug 4562587
#    sjconnol    07/31/05 - Bug 4520686
#    sjconnol    07/05/05 - Bug 4474555
#    gallison    06/28/05 - Fix bug 4342419 
#    sjconnol    06/17/05 - Bug 4439779: revert to dgutil.pl
#    sjconnol    06/03/05 - Bug 4407481: include dgutil_core.pl
#    sjconnol    05/23/05 - Bug 4380906
#    sjconnol    03/15/05 - Bug 4225517
#    sjconnol    01/26/05 - Bug 4058815: support for ctrl file on raw
#    sjconnol    11/21/04 - Fix tempfile creation for OMF
#    sjconnol    11/12/04 - Stream rman.pl from OMS
#    sjconnol    09/29/04 - Cleanup old controlfile
#    sjconnol    09/08/04 - Incorporate all code from dgcreate.pl
#    sjconnol    08/10/04 - OMF support
#    sjconnol    08/02/04 - Creation
# 
require "flush.pl";
require "$ENV{EMDROOT}/sysman/admin/scripts/db/dg/dgutil.pl";

use strict;
#use warnings;
use Encode;

use vars qw/ $DGstbyLDA $DGprmyLDA 
             $DGInstance $DGOracleHome
             $DGdevMode $DGsiteID $DGresName $DGdisplayName 
             $DGdbObjID $DGautoDelete $DGuseBroker $DGcreateSnapshot
             $DGisLogical $DGdbVer $DGIfile $DGIfileForMV $DGIfiletmp1 
             $DGIfiletmp2 $DGis10gOrHigher $DGis102OrHigher $DGis11gOrHigher $DELIMITER $DGstbyUser $DGstbyPW $DGParam1
             $DGstbyTNS $brokerConnDesc $DGpitSCN @OFFLINE_FILES $NT $S $MV $TEMP
             $target_home $target_sid $db_10_or_higher @SQLCMDS 
             $rman_script $DGuseDuplicate $DGuseRMANBackup $DGConvertToLogical
             $db_username $rcvcat_username $rcvcat_connect_string $dbid
             $db_role $rman_command_id $is_repos_database $rin $rout
             $DGRecover
           /;

#$ENV{EMAGENT_PERL_TRACE_LEVEL} = 0;  #DEBUG level.

$SIG{__DIE__} = \&handleError;
$SIG{__WARN__} = \&handleCreateWarning;

## Handle DBI sql warnings
sub handleCreateWarning{
  debug("dgutil.handleCreateWarning()");
  if(defined($DBI::errstr)){
    ## Special handling for ORA-00283
    debug("SQL Warning: $DBI::errstr");
    if($DBI::errstr =~ /ORA-00283/){
      debug("dgutil.handleCreateWarning(): Re-running recovery");
      $DGRecover = 1;
    }
  }
  else{
    debug("$_[0]");
  }
}

sub DGcreateStandby_o{
  debug("dgcreate.DGcreateStandby_o: *** START ***");
  my($instance, $ohome, $lfile, $initfile, $islogical, $fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $logsizes, $tempNames, $tablespaces, $sizes, $autoextends, $dgopts, $newdbname, $controlfile, $toControlFiles, $maxinfo, $isOMF, $isASM, $spfileName, $conndesc, $use_rman_backup, $use_duplicate) = @_;

  ## environment setup
  DGcreateAdmin($instance, $ohome, $lfile, $initfile, $islogical, $conndesc, $dgopts, $use_duplicate, $use_rman_backup);
  DGsetStbyCreds();

  ## Remove old SPFILE
  DGrmInitFiles();

  ## For 9i and non-OMF 10g, run the old procedure after installing
  ##  2nd controlfile
  if(!$DGis10gOrHigher || (($isOMF ne "Y") && ($isASM ne "Y"))){
    ## Must substitute 2nd controlfile, created after db backup
    DGshutdownStby();
    ## Bug 4058815: Always restore ctrl file to ultimate location
    debug("dgcreate.DGcreateStandby_o: Changing init file control_files param to $toControlFiles");
    # Add ultimate ctrl file name to real init file
    #  (Bug 4652338: handle multiple controlfiles)
    commentInitFileEntry("control_files", $DGIfile);
    addControlFileToInitFile("$toControlFiles", $DGIfile);
    # Restore ctrl file to ultimate location
    DGstartupStbyNomount();
    if($DGuseDuplicate eq "N"){
      restoreBackupControlFile("${controlfile}tmp");
      unlink("${controlfile}tmp");
      unlink("${controlfile}");
    }
    DGshutdownStby();
    DGstartupStby();
    DGcreateStandby($instance, $ohome, $lfile, $initfile, $islogical, $fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends, $dgopts, $newdbname, $isOMF, $isASM);
  }
  ## For 10g OMF, run the new procedure
  else{
    ## For 10g, accomodate OMF by harvesting names from original ctrl file,
    ##  and then using these names for the rename.
    debug("dgcreate.DGcreateStandby_o: Getting names from original ctrl file");
    my($ids, $datafiles) = getRestoredDatafiles();
    $toDatafiles = $datafiles;

    ## Duplicate: no datafiles restored, so add dummy entries
    my $realCtlFile = "${controlfile}tmp";
    if($DGuseDuplicate eq "Y"){    
      debug("dgcreate.DGcreateStandby_o: Duplicate: no datafiles listed");
      ## Use the 1st datafile as the dummy entry; just need to list a file
      $toDatafiles = DGgetDatafile();
      $realCtlFile = DGgetCtlfile();
    }
    
    ## Must substitute 2nd controlfile, created after db backup. Needs
    ##  to be converted to OMF. Create dummy file to harvest OMF name, 
    ##  update init file, then copy the real ctrl file to OMF loc.
    ## Temporarily modify the db_name param in the init file; use of
    ##  primary db_name will cause ctrl file creation to fail if done
    ##  on same host
    DGshutdownStby();
    # Remove control_file entry from real init file
    #  (so create controlfile uses OMF)
    commentInitFileEntry("control_files", $DGIfile);
    
    # Create temp init file with original db_name
    copyFile("$DGIfile", "${DGIfile}tmp");
    
    # Modify orig init file with temporary db_name
    modifyInitFile("db_name", "temp", $DGIfile);
    # Bug 4607258; remove pwfile entry from temporary file
    commentInitFileEntry("remote_login_passwordfile", $DGIfile);
    
    # Create the dummy controlfile using init file with temp db_name
    createControlFile_10_2("temp", $toDatafiles, $logGroups, $toLogfiles, $logsizes, $maxinfo, $DGIfile, "N", "Y", "N");
    
    # Add OMF ctrl file name to real init file
    addControlFileNamesInInitFile("${DGIfile}tmp", "N");
    
    # Substitute real (containing new OMF ctl file name) init file for orig
    DGshutdownStby();
    copyFile("${DGIfile}tmp", "$DGIfile");
    removeFile("${DGIfile}tmp");
    
    # Restart db, restore real controlfile to OMF location
    DGstartupStbyNomount();
    
    restoreBackupControlFile("$realCtlFile");
    unlink("$realCtlFile");
    unlink("${controlfile}");
    
    # Restart db with correct OMF ctrl file
    DGshutdownStby();
    DGstartupStby();

    if($DGisLogical){
      DGcreateLogical10iOMF($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname, $isASM, $spfileName);
    }    
    else{
      DGcreatePhysicalOMF($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends, $isASM, $spfileName);
    }

    ## Add the resource and enable
    if($DGis102OrHigher){
      DGaddResource102($isOMF, $isASM, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname);
    }
    else{
      DGaddResource($isOMF, $isASM, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname);
    }
    DGdisconnect();
  }
  debug("dgcreate.DGcreateStandby_o: *** END ***");
}

sub DGcreatePhysicalOMF{
  debug("dgcreate.DGcreatePhysicalOMF: *** START ***");
  my($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends, $isASM, $spfileName) = @_;


  ##init.ora files for physical
  DGputIfile();

  ## bounce standby
  DGbounceStby();
  
  ## Rename files
  DGrenameFiles($fromDatafiles, $toDatafiles);

  ## Add new OMF logfiles
  addLogfilesOmf();
  #DGmigrateOnlineLogs();
  #DGmigrateStandbyLogs();

  ## Harvest the recovery SCN
  DGgetRecoverySCN();

  ## Recover the standby
  if(! $DGis102OrHigher){
    DGrecoverStby($tempNames);
  }
  
  ## Move the real init.ora file in place
  DGmvIfile();
  
  ## Create tempfiles (call dbclone routine)
  if(! $DGis102OrHigher){
    if($isASM eq "Y"){
      addTempfilesOmf($tempNames, $tablespaces, $sizes, $autoextends);    
    }
    else{
      addTempfilesOmf("",$tablespaces, $sizes, $autoextends);
    }
  }

  ## Create the SPFILE
  if($isASM eq "Y"){
    $DGstbyLDA->disconnect;
    copyFile("$DGIfile", "${DGIfile}.saved");
    &createSpfile($DGIfile, $spfileName);
  }
  else{
    DGcreateSpfile();
    unlink($DGIfile);
  }
  
  ## bounce standby
  DGbounceStby();

  ## Online offlined datafiles
  DGonlineDatafiles();

  ## Setup autodeletion policy 
  ## (Non-essential operation; do not process return val)
  DGsetAutoDelete();
  debug("dgcreate.DGcreatePhysicalOMF: *** END ***");
}

## 10i Logical creation
sub DGcreateLogical10iOMF{
  debug("dgcreate.DGcreateLogical10iOMF: *** START ***");
  my($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname, $isASM, $spfileName) = @_;

  ## Modify init.ora files for physical
  DGputIfile($newdbname);
  
  ## bounce standby, startup mount
  DGbounceStby();
  
  ## Rename files
  DGrenameFiles($fromDatafiles, $toDatafiles);

  ## Add new OMF logfiles
  addLogfilesOmf();
  #DGmigrateOnlineLogs();
  #DGmigrateStandbyLogs();

  ## Harvest the recovery SCN
  DGgetRecoverySCN();
  
  ## Recover the standby, open resetlogs
  DGrecoverStby();
  
  ## Create tempfiles (call dbclone routine)
  if($isASM eq "Y"){
    addTempfilesOmf($tempNames, $tablespaces, $sizes, $autoextends);    
  }
  else{
    addTempfilesOmf("",$tablespaces, $sizes, $autoextends);
  }

  ## bounce, startup mount
  DGbounceStby();

  ## DB ID/name change steps
  if(!$DGdevMode){
    ## Turn off broker before running nid
    my($sql) = "alter system set dg_broker_start=false scope=memory";
    printDebug("dgcreate.nid: $sql");
    my($dbcur) = $DGstbyLDA->prepare($sql);
    $dbcur->execute;

    ## Disconnect before running nid
    $DGstbyLDA->disconnect;

    ## Run NID to change DB ID/name; 10i NID shuts down database
    DGnid($newdbname);

    ## Database is now shutdown; create new password file
    DGorapwd();

    ## Move the real init.ora file in place
    DGmvIfile();

    ## Restart
    DGstartupStby();
  }
    
  ## Create the SPFILE
  if($isASM eq "Y"){
    $DGstbyLDA->disconnect;
    copyFile("$DGIfile", "${DGIfile}.saved");
    &createSpfile($DGIfile, $spfileName);
  }
  else{
    DGcreateSpfile();
    unlink($DGIfile);
  }

  ## Bounce
  DGbounceStby();

  ## Open resetlogs (only if NID was run)
  if(!$DGdevMode){
    DGopenStby();
  }
  debug("dgcreate.DGcreateLogical10iOMF: *** START ***");
}

sub DGsetPrmyCreds{
  my ($username, $password, $tns) = @_;
  my $mode = 2; # SYSDBA
  if(!$tns){
      EMD_PERL_DEBUG("dgcreate.DGsetPrmyCreds: not using connect desc");
      $DGprmyLDA = DBI->connect('dbi:Oracle:', "$username", "$password", 
				{ora_session_mode => $mode,
				 PrintError => 0,
				 RaiseError => 1});
  }
  else{
      EMD_PERL_DEBUG("dgcreate.DGsetPrmyCreds: using connect desc");
      $DGprmyLDA = DBI->connect('dbi:Oracle:', "$username@".$tns , "$password", 
				{ora_session_mode => $mode,
				 PrintError => 0,
				 RaiseError => 1});
  }
}

sub DGsetStbyCredsNoConn{
    ($DGstbyUser, $DGstbyPW, $DGstbyTNS) = @_;
}

sub DGsetStbyCreds{
  if(@_){
    EMD_PERL_DEBUG("dgcreate.DGsetStbyCreds: connect info passed");      
    ($DGstbyUser, $DGstbyPW, $DGstbyTNS) = @_;
  }
  my $mode = 2; # SYSDBA
  ## Bug 5699797: Always use full connect desc for Win
  if($DGstbyTNS && $NT){
      EMD_PERL_DEBUG("dgcreate.DGsetStbyCreds: using connect desc");
      $DGstbyLDA = DBI->connect('dbi:Oracle:', "$DGstbyUser@".$DGstbyTNS , "$DGstbyPW", 
				{ora_session_mode => $mode,
				 PrintError => 0,
				 RaiseError => 1});
  }
  else{
      EMD_PERL_DEBUG("dgcreate.DGsetStbyCreds: not using connect desc");
      $DGstbyLDA = DBI->connect('dbi:Oracle:', "$DGstbyUser", "$DGstbyPW", 
				{ora_session_mode => $mode,
				 PrintError => 0,
				 RaiseError => 1});
  }
}

sub DGdisconnect{
  debug("dgcreate.DGdisconnect");
  $DGprmyLDA->disconnect;
  $DGstbyLDA->disconnect;
}

sub DGcreateStandby{
  debug("dgcreate.DGcreateStandby");
  my($instance, $ohome, $lfile, $initfile, $islogical, $fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends, $dgopts, $newdbname, $isOMF, $isASM) = @_;

  if($DGisLogical){
    if($DGis10gOrHigher){
      DGcreateLogical10i($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname);
    }
    else{
      DGcreateLogical9i($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname);
    }
  }
  else{
    DGcreatePhysical($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends);
  }

  ## Add the resource and enable
  if($DGis102OrHigher){
    DGaddResource102($isOMF, $isASM, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname);
  }
  else{
    DGaddResource($isOMF, $isASM, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname);
  }

  DGdisconnect();
  unlink($DGIfile);
}
    
sub DGcreatePhysical{
  debug("dgcreate.DGcreatePhysical");
  my($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends) = @_;

  ##init.ora files for physical
  DGputIfile();
  
  ## bounce standby
  DGbounceStby();
  
  ## Rename files
  DGrenameFiles($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups);

  ## Harvest the recovery SCN
  DGgetRecoverySCN();

  ## Recover the standby
  if(! $DGis102OrHigher){
    DGrecoverStby($tempNames);
  }
  
  ## Move the real init.ora file in place
  DGmvIfile();
  
  ## Create the SPFILE
  DGcreateSpfile();
  
  ## Create tempfiles
  if(! $DGis102OrHigher){
    DGaddTempfiles($tempNames, $tablespaces, $sizes, $autoextends);
  }
  
  ## bounce standby
  DGbounceStby();

  ## Online offlined datafiles
  DGonlineDatafiles();

  ## Setup autodeletion policy 
  ## (Non-essential operation; do not process return val)
  DGsetAutoDelete();
}

## 9i Logical creation
sub DGcreateLogical9i{
  debug("dgcreate.DGcreateLogical9i");
  my($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname) = @_;

  ## Modify init.ora files for physical
  DGputIfile($newdbname);
  
  ## bounce standby, startup mount
  DGbounceStby();
  
  ## Rename files
  DGrenameFiles($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups);

  ## Harvest the recovery SCN
  DGgetRecoverySCN();
  
  ## Recover the standby, open resetlogs
  DGrecoverStby();
  
  ## Create tempfiles
  DGaddTempfiles($tempNames, $tablespaces, $sizes, $autoextends);

  ## Start logical apply (9i only)
  DGstartLogical();

  ## bounce, startup mount
  DGbounceStby();

  ## DB ID/name change steps
  if(!$DGdevMode){
    ## Run NID to change DB ID/name
    DGnid($newdbname);
    
    ## Move the real init.ora file in place
    DGmvIfile();
  }
    
  ## Create the SPFILE
  DGcreateSpfile();

  ## shutdown
  DGshutdownStby();

  if(!$DGdevMode){
    ## Create new orapwd file
    DGorapwd();
  }

  ## startup
  DGstartupStby();

  ## Open resetlogs (only if NID was run)
  if(!$DGdevMode){
    DGopenStby();
  }
}

## 10i Logical creation
sub DGcreateLogical10i{
  debug("dgcreate.DGcreateLogical9i");
  my($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname) = @_;

  ## Modify init.ora files for physical
  DGputIfile($newdbname);
  
  ## bounce standby, startup mount
  DGbounceStby();
  
  ## Rename files
  DGrenameFiles($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups);

  ## Harvest the recovery SCN
  DGgetRecoverySCN();
  
  ## Recover the standby, open resetlogs
  DGrecoverStby();
  
  ## Create tempfiles
  DGaddTempfiles($tempNames, $tablespaces, $sizes, $autoextends);

  ## bounce, startup mount
  DGbounceStby();

  ## DB ID/name change steps
  if(!$DGdevMode){
    ## Turn off broker before running nid
    my($sql) = "alter system set dg_broker_start=false scope=memory";
    printDebug("dgcreate.nid: $sql");
    my($dbcur) = $DGstbyLDA->prepare($sql);
    $dbcur->execute;

    ## Disconnect before running nid
    $DGstbyLDA->disconnect;

    ## Run NID to change DB ID/name; 10i NID shuts down database
    DGnid($newdbname);

    ## Database is now shutdown; create new password file
    DGorapwd();

    ## Move the real init.ora file in place
    DGmvIfile();

    ## Restart
    DGstartupStby();
  }
    
  ## Create the SPFILE
  DGcreateSpfile();

  ## Bounce
  DGbounceStby();

  ## Open resetlogs (only if NID was run)
  if(!$DGdevMode){
    DGopenStby();
  }

  ## Setup autodeletion policy 
  ## (Non-essential operation; do not process return val)
  DGsetAutoDelete();
}

sub DGgetStbyDest{
  my($stbydest);
  if($DGis10gOrHigher){
    my $recarea = get_init_param($DGstbyLDA, "db_recovery_file_dest");
    ## If the recovery area is in use, no need to return
    ##  a value; recovery will automatically use it
    if(defined($recarea) && ($recarea =~ /\S/)){
      debug("dgcreate.DGgetStbyDest: using recovery area: $recarea");
      return undef;
    }
    ## Otherwise, get the value of standby archive dest
    my $sql =  "select destination from v\$archive_dest where dest_name='STANDBY_ARCHIVE_DEST'";
    my $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
    my @row = $dbcur->fetchrow_array();
    $stbydest = $row[0];
  }
  else{
    $stbydest = get_init_param($DGstbyLDA, "standby_archive_dest");
  }
  debug("dgcreate.DGgetStbyDest: standby_archive_dest: $stbydest");
  return $stbydest;
}

sub DGrecoverStby102{
  my($tempfiles) = @_;
  my($sql, $dbcur, $dbcur2);
  debug("dgcreate.DGrecoverStby102: tempfiles = $tempfiles");
  ## For physical, only do recovery if there are tempfiles
  if(defined($tempfiles) && ($tempfiles eq "$DELIMITER")){
    debug("dgcreate.DGrecoverStby102: no recovery to be done, returning");
    return;
  }

  if($DGuseDuplicate eq "N"){    
    ## 10.2: tempfile entries are retained in stby controlfile;
    ##  run drop cmd for as many entries as are known
    $sql = "alter system set standby_file_management='MANUAL'";
    printDebug("dgcreate.DGrecoverStby102: $sql");
    $dbcur2 = $DGstbyLDA->prepare($sql);
    $dbcur2->execute;
    
    $sql = "SELECT FILE#, NAME from v\$tempfile";
    printDebug("dgcreate.DGrecoverStby102: $sql");
    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
    my @row;
    while(@row = $dbcur->fetchrow_array()){
      ## Bug 4520686: For OMF, TEMPFILE DROP will attempt to remove
      ##  the underlying OMF file, so always rename the file to a temporary
      ##  name before removing it.
      my($tempname) = "${TEMP}${S}temp$$";
      $sql = "ALTER DATABASE RENAME FILE '$row[1]' to '$tempname'";
      printDebug("dgcreate.DGrecoverStby102: $sql");
      $dbcur2 = $DGstbyLDA->prepare($sql);
      $dbcur2->execute;
      
      $sql = "ALTER DATABASE TEMPFILE $row[0] DROP";    
      printDebug("dgcreate.DGrecoverStby102: $sql");
      $dbcur2 = $DGstbyLDA->prepare($sql);
      $dbcur2->execute;
    }    

    $sql = "alter system set standby_file_management='AUTO'";
    printDebug("dgcreate.DGrecoverStby102: $sql");
    $dbcur2 = $DGstbyLDA->prepare($sql);
    $dbcur2->execute;
  }

  ## Harvest the recovery SCN
  DGgetRecoverySCN102();
  
  $sql = "ALTER DATABASE RECOVER MANAGED STANDBY DATABASE UNTIL CHANGE $DGpitSCN";

  ## Ignore potential ORA-283 error; just retry
  $DGstbyLDA->{RaiseError} = 0;
  $DGstbyLDA->{PrintError} = 1;
  
  ## $DGRecover will be reset by signal handler on ORA-283
  $DGRecover = 1;
  while($DGRecover){
    $DGRecover = 0;
    printDebug("dgcreate.DGrecoverStby102: $sql");
    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
  }

  ## Reactivate error handling
  $DGstbyLDA->{RaiseError} = 1;
  $DGstbyLDA->{PrintError} = 0;

  if(! ($DGConvertToLogical || $DGisLogical)){
    $sql = "ALTER DATABASE OPEN READ ONLY";
 
    printDebug("dgcreate.DGrecoverStby102: $sql");
    
    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
  }
}

sub DGrecoverStby{
  my($tempfiles) = @_;
  my($sql, $dbcur, $dbcur2);
  debug("dgcreate.DGrecoverStby: tempfiles = $tempfiles");

  ## For physical, only do recovery if there are tempfiles
  if(defined($tempfiles) && ($tempfiles eq "$DELIMITER")){
    debug("dgcreate.DGrecoverStby: no recovery to be done, returning");
    return;
  }

  my $fromclause = "";
  my $stbydest = DGgetStbyDest();
  ## If using recovery area (which will be true for OMF/ASM), no
  ## need to specify FROM clause
  if(defined($stbydest)){
    $fromclause = "FROM '$stbydest'";
  }
  $sql = "ALTER DATABASE RECOVER AUTOMATIC $fromclause STANDBY DATABASE UNTIL CHANGE $DGpitSCN";
  
  ## Backup controlfile used only for 9i logical
  if($DGisLogical && !$DGis10gOrHigher){
    $sql = "ALTER DATABASE RECOVER AUTOMATIC FROM '$stbydest' DATABASE UNTIL CHANGE $DGpitSCN USING BACKUP CONTROLFILE";
  }

  ## Only disable exception handling for physical
  if(!$DGisLogical){
    ## Want to ignore all ORA-00278, ORA-00279, ORA-00289, ORA-00280,
    ##  ORA-00310 , ORA-00334 errors during this type of recovery, as they
    ##  are normal
    ## Turn off all exception handling, turn on logging of errors;
    ##  if there's real error (not one of the ones above), we'll
    ##  catch it in the open
    $DGstbyLDA->{RaiseError} = 0;
    $DGstbyLDA->{PrintError} = 1;
  }

  printDebug("dgcreate.DGrecoverStby: $sql");

  $dbcur = $DGstbyLDA->prepare($sql);
  $dbcur->execute;

  if($DGisLogical){
    ## Bug 4636417: Always set logical to Max Perf (do for all db versions)
    $sql = "alter database set standby database to maximize performance";
    printDebug("dgcreate.DGrecoverStby: $sql");
    
    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;

    ## 10i logical: ACTIVATE (not open), bounce, open
    if($DGis10gOrHigher){
      $sql = "alter database activate standby database";
      printDebug("dgcreate.DGrecoverStby: $sql");

      $dbcur = $DGstbyLDA->prepare($sql);
      $dbcur->execute;

      DGbounceStby();

      $sql = "ALTER DATABASE OPEN";

      printDebug("dgcreate.DGrecoverStby: $sql");

      $dbcur = $DGstbyLDA->prepare($sql);
      $dbcur->execute;
    }
    ## 9i logical: Turn on guard prior to open
    else{
      $sql = "ALTER DATABASE GUARD ALL";
      printDebug("dgcreate.DGrecoverStby: $sql");

      $dbcur = $DGstbyLDA->prepare($sql);
      $dbcur->execute;

      $sql = "ALTER DATABASE OPEN RESETLOGS";

      printDebug("dgcreate.DGrecoverStby: $sql");

      $dbcur = $DGstbyLDA->prepare($sql);
      $dbcur->execute;
    }
  }
  ## Physical
  else{
    $sql = "ALTER DATABASE RECOVER CANCEL";

    printDebug("dgcreate.DGrecoverStby: $sql");

    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;

    ## Turn exception handling back on
    $DGstbyLDA->{RaiseError} = 1;
    $DGstbyLDA->{PrintError} = 0;
    
    $sql = "ALTER DATABASE OPEN READ ONLY";
 
    printDebug("dgcreate.DGrecoverStby: $sql");
    
    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
  }

  debug("dgcreate.DGrecoverStby: recovery complete to $DGpitSCN");
}

sub DGgetDatafile{
  my($sql, $dbcur);
  $sql = "SELECT NAME FROM V\$DATAFILE";
  $dbcur = $DGstbyLDA->prepare($sql);
  printDebug("dgcreate.DGgetDatafile: $sql");

  $dbcur->execute;

  my @row = $dbcur->fetchrow_array();
  my $file = $row[0];
  debug("dgcreate.DGgetDatafile: $file");
  return $file;
}

sub DGgetCtlfile{
  my($sql, $dbcur);
  $sql = "SELECT NAME FROM V\$CONTROLFILE";
  $dbcur = $DGstbyLDA->prepare($sql);
  printDebug("dgcreate.DGgetCtlfile: $sql");

  $dbcur->execute;

  my @row = $dbcur->fetchrow_array();
  my $file = $row[0];
  debug("dgcreate.DGgetCtlfile: $file");
  return $file;
}

sub DGgetRecoverySCN102{
  my($sql, $dbcur);

  $sql = "SELECT CHECKPOINT_CHANGE# FROM V\$DATABASE";
  $dbcur = $DGprmyLDA->prepare($sql);

  printDebug("dgcreate.DGgetRecoverySCN102: $sql");

  $dbcur->execute;

  my @row = $dbcur->fetchrow_array();
  $DGpitSCN = $row[0];
  debug("dgcreate.DGgetRecoverySCN: pitSCN: $DGpitSCN");
}

sub DGgetRecoverySCN{
  my($sql, $dbcur);

  ## 10i Logical: Recovery SCN is found on the standby, not the primary
  if($DGisLogical && $DGis10gOrHigher){
    $sql = "SELECT DI2LR_SCN FROM X\$KCCDI2";
    $dbcur = $DGstbyLDA->prepare($sql);
  }
  ## Otherwise, recovery SCN found on primary
  else{
    if($DGisLogical){
      $sql = "SELECT MAX(FIRST_CHANGE#) FROM V\$ARCHIVED_LOG WHERE DICTIONARY_BEGIN = 'YES'";
    }
    else{
      $sql = "SELECT MAX(NEXT_CHANGE#) FROM V\$ARCHIVED_LOG";
      #$sql = "SELECT CHECKPOINT_CHANGE# FROM V\$DATABASE";
    }
    $dbcur = $DGprmyLDA->prepare($sql);
  }

  printDebug("dgcreate.DGgetRecoverySCN: $sql");

  $dbcur->execute;

  my @row = $dbcur->fetchrow_array();
  $DGpitSCN = $row[0];
  debug("dgcreate.DGgetRecoverySCN: pitSCN: $DGpitSCN");
}
  
sub DGgetPrmyID{
  my $sql = "SELECT DBID from v\$database";

  printDebug("dgcreate.getPrmyID: $sql");

  my $dbcur = $DGprmyLDA->prepare($sql);
  $dbcur->execute;

  my @row = $dbcur->fetchrow_array();
  my($dbID) = $row[0];
  debug("dgcreate.getPrmyID: db ID: $dbID");
  return($dbID);
}

sub DGstartLogical(){
  debug("dgcreate.DGstartLogical: *** START ***");
  my($dbID) = DGgetPrmyID();

  my $sql = "Begin DBMS_LOGSTDBY.PRIMARY_DBID($dbID); End;";

  printDebug("dgcreate.DGstartLogical: $sql");

  my $dbcur = $DGstbyLDA->prepare($sql);
  $dbcur->execute;

  if($DGis10gOrHigher){
    $sql = "ALTER DATABASE START LOGICAL STANDBY APPLY";
  }
  else{
    $sql = "ALTER DATABASE START LOGICAL STANDBY APPLY INITIAL $DGpitSCN";
  }

  printDebug("dgcreate.DGstartLogical: $sql");

  $dbcur = $DGstbyLDA->prepare($sql);
  $dbcur->execute;

  $sql = "ALTER DATABASE STOP LOGICAL STANDBY APPLY";

  printDebug("dgcreate.DGstartLogical: $sql");

  $dbcur = $DGstbyLDA->prepare($sql);
  $dbcur->execute;
  
  debug("dgcreate.startupLogical: *** END ***");
}
  
sub DGonlineDatafiles{
  my($file, $dbcur);
  foreach $file (@OFFLINE_FILES){
    my($sql) = "ALTER DATABASE DATAFILE '$file' ONLINE";
    printDebug("dgcreate.DGonlineDatafiles: $sql");
    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
  }
}  

sub DGrenameFiles{
  my ($fromDatafiles, $toDatafiles, $fromLogfiles, $toLogfiles, $logGroups) = @_;

  my(@fromDatafiles) = split /$DELIMITER/, $fromDatafiles;
  my(@toDatafiles) = split /$DELIMITER/, $toDatafiles;

  my(@fromLogfiles, @toLogfiles, @logGroups);
  if($fromLogfiles){
    @fromLogfiles = split /$DELIMITER/, $fromLogfiles;
  }
  if($toLogfiles){
    @toLogfiles = split /$DELIMITER/, $toLogfiles;
  }
  if($logGroups){
    @logGroups = split /$DELIMITER/, $logGroups;
  }
  my($from, $dbcur);

  debug("dgcreate.DGrenameFiles: *** START ***");
  my($count) = 0;
  ## rename datafiles
  if($DGuseDuplicate eq 'Y') {
    debug("dgcreate.DGrenameFiles: Use Duplicate - Skipping rename datafiles");
    return;
  }

  foreach $from (@fromDatafiles){ 
    my($to) = $toDatafiles[$count];
    $count++;
    ## Skip rename if files are the same name
    ##  (Case insensitive match for NT)
    if(($from eq $to) || ($NT && (lc($from) eq lc($to)))){
      debug("dgcreate.DGrenameFiles: Skipping rename for same name: $from $to");      
      next;
    }
    
    my $sql = "ALTER DATABASE RENAME FILE '$from' to '$to'";
    printDebug("dgcreate.DGrenameFiles: $sql");
    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
    
    ## Bug 3736070: If the file is offline on the primary, take it offline
    ## on the standby so recovery doesn't try to recover it
    $sql = "SELECT STATUS FROM V\$DATAFILE WHERE NAME = '$from'";
    printDebug("dgcreate.DGrenameFiles: $sql");
    $dbcur = $DGprmyLDA->prepare($sql);
    $dbcur->execute;
    my @row = $dbcur->fetchrow_array();
    if($row[0] =~ /OFFLINE|RECOVER/i){
      printDebug("dgcreate.DGrenameFiles: datafile $from is offline on primary; taking $to offline on standby");
      push(@OFFLINE_FILES, $to);
      $sql = "ALTER DATABASE DATAFILE '$to' OFFLINE DROP";
      printDebug("dgcreate.DGrenameFiles: $sql");
      $dbcur = $DGstbyLDA->prepare($sql);
      $dbcur->execute;
    }
  }

  $count = 0;
  foreach $from (@fromLogfiles){ 
    my($to) = $toLogfiles[$count];
    $count++;
    ## Skip rename if files are the same name
    ##  (Case insensitive match for NT)
    if(($from eq $to) || ($NT && (lc($from) eq lc($to)))){
      debug("dgcreate.DGrenameFiles: Skipping rename for same name: $from $to");      
      next;
    }
    my $sql = "ALTER DATABASE RENAME FILE '$from' to '$to'";
    printDebug("dgcreate.DGrenameFiles: $sql");
    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
  }
  
  debug("dgcreate.DGrenameFiles: Data/log file rename complete");
  
  my($group, %donegroups);
  foreach $group (@logGroups){ 
    if(defined($donegroups{$group})){
      printDebug("dgcreate.DGrenameFiles: already processed group $group");      
      next;
    }
    $donegroups{$group} = 1;
    my $sql = "ALTER DATABASE CLEAR LOGFILE GROUP $group";
    printDebug("dgcreate.DGrenameFiles: $sql");
    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
  }
  
  debug("dgcreate.DGrenameFiles: Log groups created");
}

## Shutdown the standby
sub DGshutdownStby
{
  debug("dgcreate.DGshutdownStby: *** START ***");

  ## disconnect 
  $DGstbyLDA->disconnect;

  push(@SQLCMDS, "shutdown immediate");
  #executeSQLPlusSYSDBA($DGstbyUser, $DGstbyPW, $DGstbyTNS);
  executeSQLPlusSYSDBA($DGstbyUser, $DGstbyPW, '');
  
  debug("dgcreate.DGshutdownStby: *** END ***");
  undef @SQLCMDS;
}

## Shutdown the standby abort
sub DGshutdownStbyAbort
{
  debug("dgcreate.DGshutdownStbyAbort: *** START ***");

  ## disconnect 
  $DGstbyLDA->disconnect;

  push(@SQLCMDS, "shutdown abort");
  #executeSQLPlusSYSDBA($DGstbyUser, $DGstbyPW, $DGstbyTNS);
  executeSQLPlusSYSDBA($DGstbyUser, $DGstbyPW, '');
  
  debug("dgcreate.DGshutdownStbyAbort: *** END ***");
  undef @SQLCMDS;
}
  
## Open resetlogs (logical only)
sub DGopenStby
{
  debug("dgcreate.DGopenStby: *** START ***");
  
  push(@SQLCMDS, "ALTER DATABASE OPEN RESETLOGS"); 
  #executeSQLPlusSYSDBA($DGstbyUser, $DGstbyPW, $DGstbyTNS);
  executeSQLPlusSYSDBA($DGstbyUser, $DGstbyPW, '');
  
  debug("dgcreate.DGopenStby: *** END ***");
  undef @SQLCMDS;
}

## Startup the standby 
##  mount for logical
##  nomount for physical
sub DGstartupStby
{
  debug("dgcreate.DGstartupStby: *** START ***");
  
  if($DGis10gOrHigher || $DGisLogical){
    push(@SQLCMDS, "startup mount"); 
  }
  else{
    push(@SQLCMDS, "startup nomount"); 
    push(@SQLCMDS, "ALTER DATABASE MOUNT STANDBY DATABASE"); 
  }

  #executeSQLPlusSYSDBA($DGstbyUser, $DGstbyPW, $DGstbyTNS);
  executeSQLPlusSYSDBA($DGstbyUser, $DGstbyPW, '');

  ## Reconnect to standby
  DGsetStbyCreds();
  
  debug("dgcreate.DGstartupStby: *** END ***");
  undef @SQLCMDS;
}

## Startup the standby nomount
sub DGstartupStbyNomount{
  debug("dgcreate.DGstartupStbyNomount: *** START ***");
  
  push(@SQLCMDS, "startup nomount"); 

  executeSQLPlusSYSDBA($DGstbyUser, $DGstbyPW, '');

  ## Reconnect to standby
  DGsetStbyCreds();
  
  debug("dgcreate.DGstartupStbyNomount: *** END ***");
  undef @SQLCMDS;
}

sub DGbounceStby{
  DGshutdownStby();
  DGstartupStby();
}

sub DGcreateSpfile(){
  debug("dgcreate.DGcreateSpfile: *** START ***");
  
  my $sql = "CREATE SPFILE FROM PFILE='$DGIfile'";
  printDebug("dgcreate.DGcreateSpfile: $sql");
  my $dbcur = $DGstbyLDA->prepare($sql);
  $dbcur->execute;
  
  debug("dgcreate.DGcreateSpfile: *** END ***");
}

sub DGaddTempfiles{
  debug("dgcreate.DGaddTempfiles: *** START ***");

  my ($fileNames, $tablespaces, $sizes, $autoextends) = @_;
  if($fileNames eq "$DELIMITER"){
    debug("dgcreate.DGaddTempfiles: NO TEMPFILES TO ADD, returning");
    return;
  }

  my @tempTablespaces = split /$DELIMITER/, $tablespaces;
  my @tempFileNames = split /$DELIMITER/, $fileNames;
  my @tempSizes = split /$DELIMITER/, $sizes;
  my @tempAutoextends = split /$DELIMITER/, $autoextends;

  my $tempFileNames;
  my $index = 0;
  my($sql, $dbcur);

  foreach $tempFileNames (@tempFileNames)
  {
    $sql = "ALTER TABLESPACE $tempTablespaces[$index] ADD TEMPFILE '$tempFileNames' SIZE $tempSizes[$index] REUSE $tempAutoextends[$index]";
    printDebug("dgcreate.DGaddTempfiles: $sql");
    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
    $index++;
  }

  debug("dgcreate.DGaddTempfiles: *** END ***");
}

sub get_dbdisplayname
{
    my ($lda, $object_id) = @_;     
    my($indoc);
    my($outdoc);
    my($pos);    
    $indoc = "<DO_MONITOR><PROPERTY name=\"dbdisplayname\" object_id=\"$object_id\"/></DO_MONITOR>";
    $outdoc = get_dg_document($lda, $indoc);
    $pos = -1;
    my $retstr;
    ## First one is value_type=
    $retstr = get_dg_token($outdoc, "value", $pos);
    ## Second one is value=
    $retstr = get_dg_token($outdoc, "value", $pos);
    ## Need to remove %CREATING% (this does not get translated).		
    $pos = -1;
    if (($pos = index($retstr, "%CREATING%", $pos)) = 0)
    {
      $retstr = substr($retstr, 10, length($retstr));
    }

    debug("dgcreate.get_dbdisplayname: $retstr");
    return $retstr;
}

sub getNewIDs {
      my $indoc="<GETID site=\"$DGresName\" res=\"$DGresName\"/>";
      my $outdoc = get_dg_document($DGprmyLDA, $indoc);

      my $pos = -1;
      ## First one is object_id=
      $DGdbObjID = get_dg_token($outdoc, "object_id", $pos);

      $indoc="<GETID site=\"$DGresName\" />";
      $outdoc = get_dg_document($DGprmyLDA, $indoc);

      ## First one is object_id=
      $pos = -1;
      $DGsiteID = get_dg_token($outdoc, "object_id", $pos);
      debug("dgcreate.getNewIDs: DGdbObjID: $DGdbObjID, DGsiteID: $DGsiteID");
}

sub _DGremoveResource{
  my $indoc = "<DO_CONFIGURE_SITE><REMOVE><SITE_ID site_id=\"$DGsiteID\"/></REMOVE></DO_CONFIGURE_SITE>";
  
  debug("dgcreate._DGremoveRes: $indoc");
  DGprocessStatus(get_dg_document($DGprmyLDA, $indoc));
  debug("dgcreate._DGremoveRes: Database $DGresName removed");
}

sub _DGaddResource{
  my $state = $_[0];
  my $indoc = "<DO_CONFIGURE_DRC><ADD><DATABASE name=\"$DGresName\" connect=\"$brokerConnDesc\" role=\"$state\"/></ADD></DO_CONFIGURE_DRC>";
    
  debug("dgcreate._DGaddResource: $indoc");
  DGprocessStatus(get_dg_document($DGprmyLDA, $indoc));
  debug("dgcreate._DGaddResource: Database $DGresName re-added");
}

sub _DGfixName{
  my $name = $_[0];
  my $indoc = "<DO_CONFIGURE_SITE><EDIT><RESOURCE_ID res_id=\"$DGdbObjID\"/><EDIT_PROPERTY_LIST><VALUE name=\"DbDisplayName\" value=\"$name\"/></EDIT_PROPERTY_LIST></EDIT></DO_CONFIGURE_SITE>";

  debug("dgcreate._DGfixName: $indoc");
  DGprocessStatus(get_dg_document($DGprmyLDA, $indoc));
  debug("dgcreate._DGfixName: Display name set to $name for DB object");
}

sub _DGenable{
  my $indoc = "<DO_CONTROL><DO_COMMAND type=\"Enable\" object_id=\"$DGsiteID\"/></DO_CONTROL>";

  debug("dgcreate._DGenable: $indoc");
  DGprocessStatus(get_dg_document($DGprmyLDA, $indoc));
  debug("dgcreate._DGenable: Resource $DGresName enabled");
}

sub _DGdisable{
  my $indoc = "<DO_CONTROL><DO_COMMAND type=\"Disable\" object_id=\"$DGsiteID\"/></DO_CONTROL>";
  debug("dgcreate._DGdisable: $indoc");
  DGprocessStatus(get_dg_document($DGprmyLDA, $indoc));
  debug("dgcreate._DGdisable: $DGsiteID Disabled");
}

sub DGaddResource102{
  my($isOMF, $isASM, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname) = @_;

  my $apply_ready = "PHYSICAL-APPLY-READY";
  my $state = "PHYSICAL";
  ## Start out in physical state
  my $initstate = "PHYSICAL";
  if($DGConvertToLogical || $DGisLogical){
    $state = "LOGICAL";
  }

  my($indoc);

  ## For 10i, first remove the site (and database), then re-add it
  ##  so that the property harvest happens
  ## Save the original displayname (NLS bug: 4342419)
  $DGdisplayName = get_dbdisplayname($DGprmyLDA, $DGdbObjID);
  debug("dgcreate.DGaddResource102: saving original displayname=$DGdisplayName");
  
  ## Remove the resource
  _DGremoveResource();
  
  ## Add it back
  _DGaddResource($initstate);
  
  ## Always get new site id, database id from database after you add a resource.
  &getNewIDs;
  
  ## set LogShipping OFF.
  $indoc = "<DO_CONFIGURE_SITE><EDIT><RESOURCE_ID res_id=\"$DGdbObjID\"/><EDIT_PROPERTY_LIST><VALUE name=\"LogShipping\" value=\"OFF\"/></EDIT_PROPERTY_LIST></EDIT></DO_CONFIGURE_SITE>";
  
  debug("dgcreate.DGaddResource102: $indoc");
  DGprocessStatus(get_dg_document($DGprmyLDA, $indoc));
  debug("dgcreate.DGaddResource102: LogShipping = OFF");

  ## Turn off all exception handling on the primary, turn on logging of errors;
  ##  we don't want to error the whole job because of an enable problem
  $DGprmyLDA->{RaiseError} = 0;
  $DGprmyLDA->{PrintError} = 1;

  ## Give broker time to start on the standby
  waitForDG($DGstbyLDA);

  ## Enable
  _DGenable();

  ## Fix display name (add CREATING tag so it appears to be still creating in UI)
  _DGfixName('%CREATING%'.$DGdisplayName);
  
  ## set GoOnline to PHYSICAL-APPLY-READY
  $indoc = "<DO_CONTROL><DO_COMMAND type=\"GoOnline\" object_id=\"$DGdbObjID\" intended_state=\"$apply_ready\"/></DO_CONTROL>";
  
  debug("dgcreate.DGaddResource102: $indoc");
  DGprocessStatus(get_dg_document($DGprmyLDA, $indoc));
  debug("dgcreate.DGaddResource102: GoOnline = $apply_ready.");
  
  ## set LogShipping ON.
  $indoc = "<DO_CONFIGURE_SITE><EDIT><RESOURCE_ID res_id=\"$DGdbObjID\"/><EDIT_PROPERTY_LIST><VALUE name=\"LogShipping\" value=\"ON\"/></EDIT_PROPERTY_LIST></EDIT></DO_CONFIGURE_SITE>";
  debug("dgcreate.DGaddResource102: $indoc");
  DGprocessStatus(get_dg_document($DGprmyLDA, $indoc));
  debug("dgcreate.DGaddResource102: LogShipping = ON");
  
  ## Disable 
  _DGdisable();
  
  ## Do recovery
  DGrecoverStby102($tempNames);

  ## 10.2+ logical: convert from physical
  if($DGConvertToLogical){
    ## Build dictionary on primary
    my $sql = "begin DBMS_LOGSTDBY.BUILD; end;";
    printDebug("dgcreate.DGaddResource102: $sql");
    my $dbcur = $DGprmyLDA->prepare($sql);
    $dbcur->execute;
    
    ## Recovery to current primary point already done, so this recovery
    ##  will be garaunteed to go to the latest dict build done above
    $sql = "ALTER DATABASE RECOVER TO LOGICAL STANDBY $newdbname";
    printDebug("dgcreate.DGaddResource102: $sql");
    $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
    
    ## Bounce
    DGbounceStby();
    
    ## Open resetlogs 
    DGopenStby();
  }

  ## Add temp files (not necessary for duplicate)
  if($DGuseDuplicate eq "N"){
    if(($isOMF ne "Y") && ($isASM ne "Y")) {
      DGaddTempfiles($tempNames, $tablespaces, $sizes, $autoextends);
    }
    else{
      if($isASM eq "Y"){
        addTempfilesOmf($tempNames, $tablespaces, $sizes, $autoextends);
      }
      else{
        addTempfilesOmf("",$tablespaces, $sizes, $autoextends);
      }
    }
  }

  ## Bounce
  DGbounceStby();

  ## Open logical
  if($DGConvertToLogical){
    my $sql = "ALTER DATABASE OPEN";
    
    printDebug("dgcreate.DGrecoverStby: $sql");
    
    my $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
  }
  
  ## Remove the resource
  _DGremoveResource();
  
  ## Add it back
  _DGaddResource($state);
  
  ## Always get new site id, database id from database after you add a resource.
  &getNewIDs;
  
  ## Give broker time to start on the standby
  waitForDG($DGstbyLDA);
  
  ## Enable
  _DGenable();
  
  ## Fix up the display name
  _DGfixName($DGdisplayName);

  ## Convert to snapshot if specified
  if($DGcreateSnapshot){
      debug("dgcreate.DGaddResource102: Converting to snapshot");
      $indoc = "<DO_CONTROL><DO_COMMAND type=\"Convert\" object_id=\"$DGdbObjID\" args=\"physical_to_snapshot\"/></DO_CONTROL>";
      debug("dgcreate.DGaddResource102: $indoc");
      DGprocessStatus(get_dg_document($DGprmyLDA, $indoc));
      debug("dgcreate.DGaddResource102: Conversion to snapshot complete");
  }
  

  ## Disable broker of no-broker option selected
  if(!$DGuseBroker){
      debug("dgcreate.DGaddResource102: Disabling broker");
      $indoc = "<DO_CONFIGURE_DRC><REMOVE_DRC remove_dest=\"no\"/></DO_CONFIGURE_DRC>";
      debug("dgcreate.DGaddResource102: $indoc");
      DGprocessStatus(get_dg_document($DGprmyLDA, $indoc));
      debug("dgcreate.DGaddResource102: Broker disabled");
      my($sql) = "alter system set dg_broker_start=false";
      printDebug("dgcreate.DGrecoverStby102: $sql");
      my $dbcur = $DGprmyLDA->prepare($sql);
      $dbcur->execute;
      $dbcur = $DGstbyLDA->prepare($sql);
      $dbcur->execute;
  }      
}

sub DGaddResource{
  my($isOMF, $isASM, $tempNames, $tablespaces, $sizes, $autoextends, $newdbname) = @_;

  my $apply_ready = "PHYSICAL-APPLY-READY";
  my $state = "PHYSICAL";
  ## Start out in physical state
  my $initstate = "PHYSICAL";
  if($DGis10gOrHigher && ($DGConvertToLogical || $DGisLogical)){
    $state = "LOGICAL";
  }
  else{
    $state = "PHYSICAL-APPLY-ON";
    if($DGisLogical){
      $state = "LOGICAL-APPLY-ON";
    }
  }

  my($indoc);

  ## For 10i, first remove the site (and database), then re-add it
  ##  so that the property harvest happens
  if($DGis10gOrHigher){
  
    ## Save the original displayname (NLS bug: 4342419)
    $DGdisplayName = get_dbdisplayname($DGprmyLDA, $DGdbObjID);
    debug("dgcreate.DGaddResource: saving original displayname=$DGdisplayName");

    ## Remove the resource
    _DGremoveResource();
    
    ## Add it back
    _DGaddResource($initstate);

    ## Always get new site id, database id from database after you add a resource.
    &getNewIDs;
  }
  ## For 9i, add the resource
  else{
    $DGresName = encode("UTF-8", $DGresName);
    debug("converted to utf8: $DGresName");
    $indoc = "<DO_CONFIGURE_SITE><ADD><SITE_RESOURCE><SITE_ID site_id=\"$DGsiteID\"/><RESOURCE name=\"$DGresName\" parent_id=\"$DGsiteID\"><RESOURCE_TMPL_ID res_tmpl_id=\"256\"/><THREADED_PROPERTIES parent_state=\"PRIMARY\" default_state=\"READ-WRITE-XPTON\"/><THREADED_PROPERTIES parent_state=\"STANDBY\" default_state=\"$state\"/></RESOURCE></SITE_RESOURCE></ADD></DO_CONFIGURE_SITE>";
    debug("dgcreate.DGaddResource: $indoc");
    DGprocessStatus(get_dg_document($DGprmyLDA, $indoc));
    debug("dgcreate.DGaddResource: Resource $DGresName added");
  }

  ## Turn off all exception handling on the primary, turn on logging of errors;
  ##  we don't want to error the whole job because of an enable problem
  $DGprmyLDA->{RaiseError} = 0;
  $DGprmyLDA->{PrintError} = 1;

  ## Give broker time to start on the standby
  waitForDG($DGstbyLDA);

  ## Enable
  _DGenable();

  ## For 10i, fix up the display name
  if($DGis10gOrHigher){
    ## Fix display name
    _DGfixName($DGdisplayName);
  }
}
  
sub DGprocessStatus{
  my($status) = @_;
  my @dbres_status_tokens = split(/[><]+/, $status);
  # Token 0 is "", token 1 is "RESULT ", token 2 is "MESSAGE "
  my($dbres_status) = $dbres_status_tokens[3];
  my @temp_tokens = split(/\s+/, $dbres_status);
  $dbres_status = $temp_tokens[0];
  EMD_PERL_DEBUG("dbres_status=$dbres_status.");

  if ($dbres_status eq "SUCCESS")
  {
    debug("dgcreate.DGprocessStatus: DG operation successful");
    return;
  }
  else
  {
    # Parse out the error from the big status.
    my $dbres_status_token;
    my $token_count = 0;
    my($dbres_status_text);
    foreach $dbres_status_token (@dbres_status_tokens)
    {
      # EMD_PERL_DEBUG("dbres_status_token=$dbres_status_token.");
      if ($dbres_status_token eq "ERROR_TEXT ")
      {
        $dbres_status_text = $dbres_status_tokens[$token_count + 1];
        last;
      }
      $token_count++;
    }
    if ($dbres_status eq "WARNING"){
      debug("dgcreate.DGprocessStatus: DG operation produced warning: $dbres_status_text");
    }
    elsif ($dbres_status eq "FAILURE"){
      die("$dbres_status_text");
    }
  }
}
  
##########################################################
## Setup for standby creation
##########################################################
sub DGcreateAdmin{
	debug("dgcreate.DGcreateAdmin: @_");
	## globals
	my($inst,	$ohome, $listenerfile, $initfile, $clonetype, $conndesc, $dgopts, $use_duplicate, $use_rman_backup) = @_;
  $DGInstance = $inst;
  $DGOracleHome = $ohome;
  ## Used for broker add site connect string (initial connect desc)
  $brokerConnDesc = $conndesc;
  
  ## ensure global clonePurpose is set in db_clone_10_2
  setClonePurpose($clonetype);
  
  ## Harvest DG options
  ##  1) dev mode
  ##  2) site ID
  ##  3) DB resource name
  my(@dgopts) = split(/$DELIMITER/, $dgopts);

  # SJC 9/18/03: Disable development mode
  #$DGdevMode = $dgopts[0];
  $DGdevMode = 0;

  $DGsiteID = $dgopts[1];
  $DGresName = $dgopts[2];
  ## displayName is 10i only
  $DGdisplayName = $dgopts[3];
  ## dbObjID is 10i only; distinct from siteID
  $DGdbObjID = $dgopts[4];
  ## autoDelete is 10i only; determines if rec area uses auto deletion
  $DGautoDelete = $dgopts[5];
  debug("dgcreate.DGcreateAdmin: Auto delete = $DGautoDelete");
  ## Create logical by converting phys (10.2 and up)
  $DGConvertToLogical = $dgopts[6];
  if($DGConvertToLogical){
    debug("dgcreate.DGcreateAdmin: Logical Standby 10.2+");
  }

  ## Disable broker after creation (10.2 and up)
  $DGuseBroker = $dgopts[7];

  ## Convert to snapshot after creation (11.1 and up)
  $DGcreateSnapshot = $dgopts[8];

  ## Use RMAN duplicate (11g feature)
  $DGuseDuplicate = $use_duplicate;

  ## Use RMAN existing backup (11g feature)
  $DGuseRMANBackup = $use_rman_backup;

  if($DGdevMode){
    debug("dgcreate.DGcreateAdmin: Development mode");
  }
  elsif(-e "/tmp/dgNoNewID"){
    debug("dgcreate.DGcreateAdmin: No NID mode");
    $DGdevMode = 1;
  }	

  $DGisLogical = 0;
  if($clonetype =~ /LOGICAL_STANDBY/){
    debug("dgcreate.DGcreateAdmin: Logical Standby");
    $DGisLogical = 1;
  }
  else{
    debug("dgcreate.DGcreateAdmin: Physical Standby");
  }

  debug("dgcreate.DGcreateAdmin: site ID: $DGsiteID");
  debug("dgcreate.DGcreateAdmin: resource name: $DGresName");

  ## Figure out DB Version (primary and standby will be same)
  my $dbver = get_dbversion($DGprmyLDA);
  if($dbver =~ /^1[1-9]/){
    debug("dgcreate.DGcreateAdmin: Database version: 11gR1 (or higher)");
    $DGis11gOrHigher = 1;
    $DGis102OrHigher = 1;
    $DGis10gOrHigher = 1;
    $DGdbVer = "11.1";
  }
  elsif($dbver =~ /^102/){
    debug("dgcreate.DGcreateAdmin: Database version: 10gR2");
    $DGis11gOrHigher = 0;
    $DGis10gOrHigher = 1;
    $DGis102OrHigher = 1;
    $DGdbVer = "10.2";
  }
  elsif($dbver =~ /^(101|100)/){
    debug("dgcreate.DGcreateAdmin: Database version: 10gR1");
    $DGis11gOrHigher = 0;
    $DGis102OrHigher = 0;
    $DGis10gOrHigher = 1;
    $DGdbVer = "10.1";
  }
  else{
    debug("dgcreate.DGcreateAdmin: Database version: 9iR2");
    $DGis11gOrHigher = 0;
    $DGis102OrHigher = 0;
    $DGis10gOrHigher = 0;
    $DGdbVer = "9.2";
  }

	## Environmentals
  ## These should already have been reset from the in-job Perl
  debug("ORACLE_HOME = $ENV{ORACLE_HOME}");
  debug("PATH = $ENV{PATH}");

	## Since the listener.ora file may not be the default one,
	##  set TNS_ADMIN to whatever directory the file is in
  if(defined($listenerfile) && $listenerfile){
    my($idx) = rindex($listenerfile,"$S");
    if($idx == -1){
      die("ERROR_TNS_ADMIN:$listenerfile");
      return;
    }
		
    my($tns) = substr($listenerfile,0,$idx);
    $ENV{TNS_ADMIN} = "$tns";
    debug("TNS_ADMIN = $ENV{TNS_ADMIN}");
  }

  if(defined($initfile) && $initfile){
    $DGIfile = $initfile;
    $DGIfileForMV = substr($DGIfile, rindex($DGIfile,"$S") + 1);
    ## Beware that the value of $DGIfiletmp will be inferred as 
    ##  "${Ifile}tmp" by the client, so any changes here must be performed
    ##  in the client code, too.
    $DGIfiletmp1 = "${DGIfile}tmp1";
    $DGIfiletmp2 = "${DGIfile}tmp2";
  }
}

##########################################################
## Move the "real" init.ora file to the correct name 
##########################################################
sub DGmvIfile{
	local($SIG{'CHLD'}) = 'DEFAULT';
  my($file) = $_[0];
  ## default: move temp file #1 to permanent slot
  if(!defined($file)){
    $file = $DGIfiletmp1;
  }
	debug("dgcreate.DGmvIfile: $_[0]");
	my($cmd) = "$MV $file $DGIfile";
	if($NT){
		# For NT, first delete the destination file.
		my($delcmd) = "del $DGIfile";
		debug("\t$delcmd");
		&DGrunCmd($delcmd);	
		$cmd = "$MV $file $DGIfileForMV";
	}
	debug("$cmd");
	if(&DGrunCmd($cmd)){
		return(1);
	}
}

##########################################################
## Install a new init.ora file
##########################################################
sub DGputIfile{
	debug("dgcreate.DGputIfile");
	my($db_name) = @_;
	my($line);

	## Create main init.ora file for standby ($DGIfiletmp1). It will actually be 
	##  created under the temporary file name, initially.
	open(IFILETMP1,">$DGIfiletmp1") || die("ERROR_FILE_OPEN:$DGIfiletmp1");

	## Create temp init.ora ($DGIfiletmp2) file w/o db_file_name_convert, 
	##  log_file_name_convert, or standby_file_management. This is 
	##  so standby can start w/o these params set in order to do the
	##  file renaming. Also, strip log_archive_format parameter, so
	##  that if a manual recovery is done by the create process, a
	##  user specified format doesn't get in the way (log_archive_format
	##  will be preserved in the real spfile).
	open(IFILETMP2,">$DGIfiletmp2") || die("ERROR_FILE_OPEN:$DGIfiletmp2");

  ## Open the file copied over by DB Clone for reading, from which
  ##  the above two files will be created.
	open(IFILE,"$DGIfile") || die("ERROR_FILE_OPEN:$DGIfile");    

  while($line = <IFILE>){
    chomp($line);
    ## For Logical, substitute the new db_name, so it will match
    ##  the name set by the NID utility
    if((defined($db_name)) && $line =~ /^\s*(db_name)/i){
      debug("\tadding new db_name=$db_name for logical stby");
      print IFILETMP1 "db_name=$db_name\n";
      ## Keep old db_name in tempfile
      print IFILETMP2 "$line\n";
      next;
    }
    ## remove lock_name_space from main file; don't need it after db name change
    elsif((defined($db_name)) && $line =~ /^\s*lock_name_space/i){
      print IFILETMP2 "$line\n";
      next;
    }

    ## remove db/log_file_name_convert from temp file
		if($line =~ /^\s*(db_file_name_convert|log_file_name_convert|standby_file_management)/i){
      print IFILETMP1 "$line\n";
      next;
    }
    ## for 11g or higher audit_trail default is set to DB.
    ## In order to open the database in read only mode, we need to set this parameter to NONE/FALSE.
    if($line =~ /^\s*(audit_trail)/i){
      print IFILETMP1 "audit_trail=NONE\n";
      next;
    }

    print IFILETMP1 "$line\n";
    print IFILETMP2 "$line\n";
  }

  ## Bug 5162803: Set log_file_name_convert to empty string in the temp
  ##  init file that will be used during the file rename. This is necessary
  ##  to avoid ORA-19527 during CLEAR LOGFILE if the "keep primary names" 
  ##  option was used to create the standby.
  ## Bug 5624530: Empty strings cause ORA-09134 on Windows; use a dummy string
  print IFILETMP2 "log_file_name_convert=\'a\'\,\'a\'\n";  

	close(IFILE);
	close(IFILETMP1);
	close(IFILETMP2);

  ## Now that we're done producing the two init.ora files, move
  ##  the temp one into place.
  ## Return with no output if error; mvIfile will output an error messages
  if(&DGmvIfile("$DGIfiletmp2")){
    return;
  }

}

	
##########################################################
## Create a remote login passwordfile
##########################################################
sub DGorapwd{
	local($SIG{'CHLD'}) = 'DEFAULT';
	debug("dgcreate.DGorapwd");

  my($password);
	my($pwfile) = "${DGOracleHome}${S}dbs${S}orapw${DGInstance}";
	my($orapwexec) = "${DGOracleHome}${S}bin${S}orapwd";

	if($NT){
		$pwfile = "${DGOracleHome}${S}database${S}PWD${DGInstance}.ora";
		$orapwexec = "${DGOracleHome}${S}bin${S}orapwd.exe";
	}

	my($pwcmd);
  if($DGis102OrHigher){
    $password = $DGParam1;
    $pwcmd = "$orapwexec file=$pwfile password=$password entries=10 -ob";
  }
  else{
    $password = $DGstbyPW;
    $pwcmd = "$orapwexec file=$pwfile password=$password entries=10";
  }    

	## If the executable is there, and the file isn't, create it
	if((-e "$orapwexec") && !(-e "$pwfile")){
		if(&DGrunCmd($pwcmd)){
      exit(1);      
		}
		debug("Created file $pwfile");
	}
	## else, if file is there, remove it and recreate
	elsif(-e "$pwfile"){
		debug("Removing file $pwfile");
		if(unlink($pwfile)){
			if(&DGrunCmd($pwcmd)){
        exit(1);
			}
			debug("Created file $pwfile");
		}
		## If remove fails, that's an error 
		else{
			die("ERROR_RM_FILE:$pwfile");
		}
	}
	## 
	## else, there's a problem (probably no orapwd exec)
	else{
		die("ERROR_EXEC:orapwd");
	}
}

##########################################################
## Run the NID utility to change the database name. (Called
##  only to change dbname for a logical standby.)
##########################################################
sub DGnid{
	local($SIG{'CHLD'}) = 'DEFAULT';
	debug("dgcreate.DGnid: $_[0]");
	my($dbname) = @_;

	my($nidexec) = "${DGOracleHome}${S}bin${S}nid";

	if($NT){
		$nidexec = "${DGOracleHome}${S}bin${S}nid.exe";
	}

	## If a connect alias isn't specified, NID will connect
	##  to whatever ORACLE_SID is set to
	$ENV{ORACLE_SID} = "$DGInstance";

	my($cmd) = "echo Y | $nidexec TARGET=/ DBNAME=$dbname";
      
	debug("$cmd");		
	
	## If the executable is there, and the file isn't, create it
	if(-e "$nidexec"){
		if(&DGrunCmd($cmd)){
      exit(1);
		}
	}
	else{
		die("ERROR_EXEC:nid");
	}
}

##########################################################
## Remove the SPFILE file for an instance
## 
##  Since this is run at create time, the globals $DGInstance and
##  $DGOracleHome will be set when it's called.
##########################################################
sub DGrmInitFiles{
	debug("dgcreate.DGrmInitFiles");	
	
	my($file) = "${DGOracleHome}${S}dbs${S}spfile${DGInstance}.ora";	
	if($NT){
		$file = "${DGOracleHome}${S}database${S}spfile${DGInstance}.ora";
	}
	debug("\tlooking for $file");
	if(-e "$file"){
		debug("\tremoving file for for ${DGInstance}: $file");
		unlink($file)
			|| die("ERROR_RM_FILE:$file");
	}
}

##########################################################
## Setup the arch log file auto deletion policy using RMAN
## $DGautoDelete global set in createAdmin
##########################################################
sub DGsetAutoDelete{
	local($SIG{__WARN__}) = 'DEFAULT';
	debug("dgcreate.DGsetAutoDelete");	

  ## Logical auto delete feature (10.2 only); always set this
  ## (Actually not necessary since server will do by default, but leave it)
  if($DGisLogical && ($DGis102OrHigher)){
    my $sql = "Begin DBMS_LOGSTDBY.APPLY_SET('LOG_AUTO_DELETE','TRUE'); End;";
    printDebug("dgcreate.DGsetAutoDelete: $sql");
    my $dbcur = $DGstbyLDA->prepare($sql);
    $dbcur->execute;
  }

  ## Until setting-up rec area deletion policy makes sense for logical,
  ##  skip it. (Not done at all pre-10g.)
  if($DGisLogical || $DGConvertToLogical || !$DGis10gOrHigher || !$DGautoDelete){
    return;
  }

  ## Set these globals to avoid compile warnings in rman_o.pl
  $db_username = "";
  $rcvcat_username = "";
  $rcvcat_connect_string = "";
  $dbid = 0;
  $db_role = "";
  $rman_command_id = "";
  $is_repos_database = "";
  $rin = "";
  $rout = "";
  
  $target_home = $DGOracleHome;
  $target_sid = $DGInstance;
  $db_10_or_higher = "YES";

  $rman_script = "CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON STANDBY;";
  ## Don't want fatal error here to fail the job; trap any errors

  my($status) = eval{br_rman("NO", "");}; 
  if($@){
    debug("dgcreate.DGsetAutoDelete: RMAN script failed: $@");	
  }

  debug("dgcreate.DGsetAutoDelete: RMAN returned $status");	
}
 
sub DGrunCmd{
	local($SIG{'CHLD'}) = 'DEFAULT';
	my($cmd) = $_[0];
	my(@res) = `$cmd 2>&1`;
	debug("@res ");
	if($?){
		my($err) = $!;
		## If there is no system error, just put out the output
		if($err eq undef || ($err eq "")){
			$err = "@res";
			## To make multiline errors fit on one line (so it
			##  makes it back to the client) replace all \n with tabs.
			## The client will in turn replace the tabs with newlines
			##  before presenting the error to the user.
			$err =~ s/\n/\t/g;
		}
		chomp($err);
		## Send back only the OS components of error to client
		##  to minimize translation issues
    if($cmd !~ /password/i){
      printDebug("${cmd}: $err");
    }
		return(1);
	}
	return(0);
}


# Migrate online logs to ASM with hot migration approach
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# migrateOnlineLogsHot()
sub DGmigrateOnlineLogs
{
  EMD_PERL_DEBUG("dgcreate_o.DGMigrateOnlineLogs(): *** START ***");
  
  my $sql_string = "";
  $sql_string .= "set echo off\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 .= "    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) = &runSqlOnDestination($sql_string);  
  
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }
  
  EMD_PERL_DEBUG("dgcreate_o.DGMigrateOnlineLogs(): *** END ***");
}

# Migrate online logs to ASM for standby database with hot migration approach
# Call &set_env($oracleHome, $oracleSid) before calling this method.
# migrateOnlineLogsStandbyHot()
sub DGmigrateStandbyLogs
{
  EMD_PERL_DEBUG("dgcreate_o.DGmigrateStandbyLogs(): *** START ***");
  
  my $sql_string = "";
  $sql_string .= "set echo off\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 .= "    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) = &runSqlOnDestination($sql_string);  
  
  close $fh;
  if($NT)
  {
    &removeFile($filename);
  }
  
  EMD_PERL_DEBUG("dgcreate_o.DGmigrateStandbyLogs(): *** END ***");
}