# 
# $Header: emdb/sysman/admin/scripts/db/dataUtilities/tts.pl /st_emdbsa_11.2/3 2009/03/21 05:46:43 rasundar Exp $
#
# tts.pl
# 
# Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved. 
#
#    NAME
#      tts.pl - <one-line expansion of the name>
#
#    DESCRIPTION
#      <short description of component this file declares/defines>
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YY)
#    rasundar    03/18/09 - remove hardcoded password in test code
#    rasundar    03/04/09 - wrap tablespace name with double quotes during alter
#                           operation for fixing bug 8303346
#    vgoli       08/25/08 - fix bug#5634325: set dmpfile_format10g to TRUE if
#                           it is empty
#    ngade       07/26/05 - 
#    ngade       07/15/05 - support for generate asm->asm
#    ngade       06/17/05 - fix bug 4438359 for generate
#    ngade       06/09/05 - use dmpfile_format10g for xmltype tables.
#    ngade       05/16/05 - fix for tts in asm mode 
#    npamnani    04/14/05 - fix for bug 4115003; use tns connector and agent 
#                           oracle home/sid when using DBI on NT 
#    ngade       04/07/05 - fix for 9i imp
#    npamnani    02/03/05 - fix for bug 4159960,win platform 
#    ngade       01/31/05 - fix bug 4153859 - for RAC add quotes for convert tablespace.
#    ngade       11/11/04 - fix for asm instance
#    ngade       08/25/04 - fix for command block 
#    ngade       08/18/04 - fix COPY error
#    ngade       06/14/04 - 
#    ngade       05/28/04 - connect as sysdba for read_file_header 
#    npamnani    05/27/04 - 
#    ngade       05/26/04 - add read_file_header 
#    ngade       05/24/04 - add messages 
#    ngade       05/20/04 - changes for largeParameter support
#    ngade       05/19/04 - add create_dirs 
#    npamnani    05/18/04 - move disconnect_database
#    ngade       05/10/04 - modify tablespace query 
#    ngade       04/28/04 - ngade_tts_0428
#    ngade       04/07/04 - Creation
# 
require "$ENV{EMDROOT}/sysman/admin/scripts/db/dataUtilities/export.pl";
require "$ENV{EMDROOT}/sysman/admin/scripts/db/rman/rman.pl";
require "$ENV{EMDROOT}/sysman/admin/scripts/db/dataUtilities/import.pl";
require "$ENV{EMDROOT}/sysman/admin/scripts/db/dataUtilities/datapump_util.pl";

use DBI qw(:sql_types);
use DBD::Oracle qw(:ora_types);

use strict;

use constant TS_READ_ONLY         => 'READ ONLY';
use constant TS_OFFLINE           => 'OFFLINE';
use constant TS_ONLINE            => 'ONLINE';
use constant DELIMITER            => ':::';

## global variables.
## $ERROR_CODE is defined in rman.pl
use vars qw($oracle_home $oracle_sid $db_username $db_passwd $db_role $job_name $ts_df_list $db_10_or_higher $ERROR_CODE $dmpfile_format10g $tns_connect $AGENT_ORACLE_HOME $TARGET_ORACLE_HOME);

sub save_agent_oh
{
  $AGENT_ORACLE_HOME = $ENV{ORACLE_HOME};
}
sub set_agent_oh
{
  $oracle_home = $AGENT_ORACLE_HOME;
  print_debug("agent oracle_home: $oracle_home\n");

}
sub save_target_oh
{
  if(!$TARGET_ORACLE_HOME) #save only once
  {
     $TARGET_ORACLE_HOME = $oracle_home;
  }
}
sub set_target_oh
{
  $oracle_home = $TARGET_ORACLE_HOME;
  print_debug("target oracle_home: $oracle_home\n");
}

###################################################
## GENERATE TTS OPERATION.
## 1. do containment check.
## 2. make tablespace(s) read-only.
###################################################

sub create_dirs()
{
  my ($directory_name, $directory_path, $datafile_dirs) = @_;

  print_debug("create_dirs: $directory_name directory_path: $directory_path datafile_dirs: $datafile_dirs.\n");

  ## fix for bug 4193463; for tns connect use agent home/sid or DBI will fail
  save_agent_oh();
  save_target_oh();

  set_agent_oh();
  set_env_var($oracle_home, $oracle_sid, $db_10_or_higher);

  ## Create directories for datafiles
  my @df_dirs = split(/,/, $datafile_dirs);
  foreach my $df_dir(@df_dirs)
  {
    my $status = &mkDir($df_dir);
    if($status !~ /OK/i)
    {
      print STDOUT "Cannot create directory $df_dir\n";
      exit(1);
    }
  }

  ## Create Directory object in the database for 10g
  if(!defined($dmpfile_format10g) || $dmpfile_format10g =~ "")
  {
    $dmpfile_format10g = "TRUE";
  }

  if($db_10_or_higher =~ /TRUE/i && $dmpfile_format10g =~ /TRUE/i)
  {
    print_debug("Creating Directory Object: $directory_name Path: $directory_path db_username: $db_username, db_role: $db_role\n");

    create_directory_object($directory_name, $directory_path);
  }
}

sub prepare_job()
{  
  my($db_9i_or_higher, $incl_constraints, $full_check) = @_;  

  print_debug("Global Parameters\n: oracle_home:$oracle_home oracle_sid:$oracle_sid db_username:$db_username ts_df_list:$ts_df_list\n");

  set_env_var($oracle_home, $oracle_sid, $db_10_or_higher);

  my @ts_array = split(/,/, $ts_df_list);
  
  my $dbh = connect_database($db_username, $db_passwd, $db_role);    

  my $sql_containment_check_pre_9i = q{
    declare 
    function to_bool(i varchar2) return boolean is
      begin
         if  i is null              
            then return null;
         elsif i = 'FALSE' or i = '0' or i = 'false'
            then return false;
         else                          
            return true;
         end if;
      end;
      begin
            sys.dbms_tts.transport_set_check(:ts_df_list, to_bool(:incl_constraints));
          end;
  };
  my $sql_containment_check_9i_or_higher = q{
    declare 
    function to_bool(i varchar2) return boolean is
      begin
         if  i is null              
            then return null;
         elsif i = 'FALSE' or i = '0' or i = 'false'
            then return false;
         else                          
            return true;
        end if;
      end;
      begin
        sys.dbms_tts.transport_set_check(:ts_df_list, to_bool(:incl_constraints), to_bool(:full_check));
      end;
  };
  my $sql_containment_violations = q{
    select * from sys.transport_set_violations
  };
    
  ######
  ##  1. do transport check
  ######
    
  my $sql_containment_check;
  if($db_9i_or_higher =~ /TRUE/i)
  {
    $sql_containment_check = $sql_containment_check_9i_or_higher;
  }
  else
  {
    $sql_containment_check = $sql_containment_check_pre_9i;
  }
  my $dbcur = prepare_statement($dbh, $sql_containment_check, $job_name);
  
  if(!$incl_constraints)
  {
    $incl_constraints = "false";
  }
  if(!$full_check)
  {
    $full_check = "false";
  }
  print_debug("$job_name: Performing Transport Check ts_df_list: $ts_df_list $db_9i_or_higher $incl_constraints $full_check\n");
  
  $dbcur->bind_param(":ts_df_list", $ts_df_list);  
  
  ## There are some types, like boolean, that Oracle does not automatically convert to or from strings.  
  ## These need to be converted explicitly using sql or pl/sql functions.

  $dbcur->bind_param(":incl_constraints", $incl_constraints);  
  ## handle dbversion < 9i - full containment check not available.  
  if($db_9i_or_higher =~ /TRUE/i)
  {
  $dbcur->bind_param(":full_check", $full_check);  
  }


  execute_statement($dbh, $dbcur, $job_name);  
  $dbcur->finish();

  ######
  ##  2. get violations
  ######
  print_debug("$job_name: Getting Violations\n");
  my $dbcur = prepare_statement($dbh, $sql_containment_violations, $job_name);
  execute_statement($dbh, $dbcur, $job_name);  

  my $prepare_ts_status = "true";
  while(my(@data) = $dbcur->fetchrow) 
  {      
    ## Show violations to the user.
    print STDOUT "@data\n";
    $prepare_ts_status = "false";        
  }   
  $dbcur->finish();        
  
  ## Any violations exit.
  if($prepare_ts_status =~ /FALSE/i)
  {
    exit(1);
  }
  ######
  ##  3. make ts_read_only - First get online tablespaces which can be made read-only.
  ######
  my @online_ts_array = get_online_ts($dbh, $job_name);

  foreach my $ts_name(@online_ts_array)
  {        
      print_debug("Making Tablespace $ts_name read-only.\n");
    
      my $sql_ts_read_only = "alter tablespace \"".$ts_name."\" read only";  
      print_debug("sql_ts_read_only: $sql_ts_read_only\n");
      
      my $dbcur = prepare_statement($dbh, $sql_ts_read_only, $job_name);
      
      execute_statement($dbh, $dbcur, $job_name);  
      $dbcur->finish();    
  }
  disconnect_database($dbh);   

  ## print_debug("Online TS: @online_ts_array\n");
  save_ts(join(",",@online_ts_array));  
  print_debug("Done saving\n");

  ## For testing return the output.
  return(@online_ts_array);
}

## Do not modify this subroutine. Job System needs in this format
## so that parameters are passed from one step to another.
sub save_ts
{
  my ($ts_list) = @_;

  print_debug("Saving Read only Tablespaces: $ts_list\n");

  my $output1 = q{
    $$$--*$$
    <commandBlock>
      <executeProc name="save_tts_ts">
        <scalar>%job_id%</scalar>
        <scalar>%job_execution_id%</scalar>
};
  my $output2 = "<scalar>$ts_list</scalar>\n";
  my $output3 = q{
        <scalar>%job_owner%</scalar>
      </executeProc>
    </commandBlock>
    $$*--$$

  };

  ## Print output to STDOUT so that the job system, can pass in the 
  ## output to the next step. 
  ## This output will not show up in the jobs ui outputLog.
  print STDOUT $output1.$output2.$output3."\n";
}  

###################################################
## TTS UTIL.
## Get list of online tablespaces.
###################################################
sub get_online_ts
{
  my($dbh, $job_name) = @_;
  my @ts_array = split(/,/, $ts_df_list);

  print_debug("$job_name: Check Tabespace status: $ts_df_list\n");  

   my $sql_get_status = "select tablespace_name, status from dba_tablespaces where tablespace_name in('". join("','",@ts_array). "')";

  ## TODO: Test with the following query.
  ## my $sql_get_status = "select ts.name, df.status from sys.v\$datafile df, sys.v\$tablespace ts where ts.ts#=df.ts# and ts.name in('". join("','",@ts_array). "')";
  print_debug("sql_get_status: $sql_get_status\n");
  
  my $dbcur = prepare_statement($dbh, $sql_get_status, $job_name);

  my $status;
  my $name;
  my @online_ts_array;

  my $tablespace_name;
  ## $dbcur->bind_columns(undef, \($name, $status));  
  $dbcur->bind_columns(undef, \($tablespace_name, $status));  
  execute_statement($dbh, $dbcur, $job_name);  
  
  while($dbcur->fetch) 
  {
    print_debug("name: $tablespace_name status: $status\n");
    if($status =~ TS_OFFLINE)
    {      
      print STDOUT "Tablespace $tablespace_name is $status. Cannot proceed\n";      
      ## Showerror & exit, can't make it read-only.
      exit(1);      
    }
    elsif($status =~ TS_READ_ONLY)
    {
      ## tablespace already read-only
    }
    elsif($status =~ TS_ONLINE)
    {
      ## tablespace ONLINE.  
      push @online_ts_array, $tablespace_name;      
    }
    else
    {
      print STDOUT "Tablespace $tablespace_name unknowns status: $status\n";
      exit(1);
    }
  }
  $dbcur->finish(); 
  print_debug("$job_name: Online TS: @online_ts_array\n");    
  return @online_ts_array;
}

sub create_directory_object
{
  my($directory_name, $directory_path) = @_;

  my $dbh = connect_database($db_username, $db_passwd, $db_role);    
  my $sql_create_dir = "create or replace directory $directory_name as ". "'".$directory_path."'";  

  print_debug("sql_create_dir: $sql_create_dir\n");
      
  my $dbcur = prepare_statement($dbh, $sql_create_dir, $job_name);
      
  execute_statement($dbh, $dbcur, $job_name);  
  $dbcur->finish();    
  disconnect_database($dbh);   
}

###################################################
## GENERATE TTS OPERATION.
## Perform metadata-only export. 
###################################################
sub tts_export
{
  my($exp_script, $smp_ignore, $generate_log, $parse_errors, $log_file_name) = @_;
  print_debug("$job_name: ts_export: exp_script = $exp_script log_file_name: $log_file_name dmpfile_format10g: $dmpfile_format10g \n");
  my $role;

  save_agent_oh(); 
  save_target_oh();

  if(!defined($dmpfile_format10g) || $dmpfile_format10g =~ "")
  {
    $dmpfile_format10g = "TRUE";
  }
  if($dmpfile_format10g =~ /TRUE/i)
   {
      $role = $db_role;
   }
   else
   {
      ## for traditional exp/imp user must be connected as sysdba.
      $role = "SYSDBA";
   }
   print_debug("role : $role\n");

  if($generate_log =~ /FALSE/i && $db_10_or_higher =~ /TRUE/i && $dmpfile_format10g =~ /TRUE/i)
  {
    set_agent_oh();
    set_env_var($oracle_home, $oracle_sid, $db_10_or_higher);

    ## create temporary log file and pass it to the expdp script.
    (my $log_fh,$log_file_name) = create_temp_file("_expdat.log");
    my $dir_path = getDirname($log_file_name);
    my $dir_name = "EM_GEN_TTS_LOG_DIR";

    create_directory_object($dir_name, $dir_path);
    my $log_basename = getBasename($log_file_name);
    $exp_script = $exp_script. " logfile=$dir_name:$log_basename";
    set_target_oh();
  }

  &expdp($db_10_or_higher, $exp_script, $oracle_home, $oracle_sid, $db_username, $db_passwd, $role, $smp_ignore, $generate_log, $parse_errors, $log_file_name, $dmpfile_format10g);
  print_debug("tts_export $?\n");
  if($? != 0)
  {
    exit(1);
  }
}

###################################################
## GENERATE TTS OPERATION.
## Make tablespace read-write
###################################################
sub make_ts_rw
{
  my($ts_list) = @_;
  set_agent_oh();

  set_env_var($oracle_home, $oracle_sid, $db_10_or_higher);

  ## NOTE: If the job gets restarted after failure, the $ts_list
  ## may be a subset of the original list.

  if($ts_list)
  {
    print_debug("make_ts_rw: ts_list: $ts_list\n");

    my @ts_array = split(/,/, $ts_list);
    my $dbh = connect_database($db_username, $db_passwd, $db_role);  

    print_debug("Making Tablespaces read write: $ts_list\n");
  
    foreach my $ts_name(@ts_array)
    {      
      my $sql_ts_read_write = "alter tablespace \"".$ts_name."\" read write";  
      print_debug("make_ts_rw: sql_ts_read_write: $sql_ts_read_write\n");
    
      my $dbcur = prepare_statement($dbh, $sql_ts_read_write, $job_name);
    
      execute_statement($dbh, $dbcur, $job_name);  
      $dbcur->finish();    
    }
    disconnect_database($dbh);   
  }
}

###################################################
## INTEGRATE TTS OPERATION.
## Perform metadata-only import. 
###################################################
sub tts_import
{   
  save_agent_oh();
  save_target_oh();

  my($imp_script, $smp_ignore, $generate_log, $parse_errors, $log_file_name) = @_;
  print_debug("tts_import: imp_script = $imp_script log_file_name: $log_file_name oracle_home: $oracle_home oracle_sid: $oracle_sid , dmpfile_format: $dmpfile_format10g generate_log: $generate_log\n");  


  ## changes for asm 
  my $df_file = getDirname($log_file_name)."/".$job_name."_df.log";

  if($db_10_or_higher =~ /TRUE/i && &is_asm =~ /TRUE/i)
  {
    print_debug("tts_import: ASM Database...\n");
    open(DF_FILE, $df_file) || warn "Can't open $df_file to read:$!\n";
    my @df_list = <DF_FILE>;
    close DF_FILE;

    my $converted_df_list = "@df_list";
    print_debug("tts_import: converted_df_list: $converted_df_list\n");

    if($#df_list != -1)
    {
      if($dmpfile_format10g =~ /TRUE/i)
      {
         my($df_string1,$df_string2) = split(/transport_datafiles=/i, $imp_script); 
         my($df_names,$df_string3) = split(/job_name=/i, $df_string2); 
         $imp_script= $df_string1."transport_datafiles=".$converted_df_list." job_name=".$df_string3;
      }
      else
      {
         my($df_string1,$df_string2) = split(/datafiles=/i, $imp_script); 
         my($df_names,$df_string3) = split(/log=/i, $df_string2); 
         $imp_script= $df_string1."datafiles=".$converted_df_list." log=".$df_string3;
      }
      print_debug("tts_import:imp_script: $imp_script\n");
    }
  }
  
  set_target_oh();
  my $role;
  if(!defined($dmpfile_format10g) || $dmpfile_format10g =~ "")
  {
    $dmpfile_format10g = "TRUE";
  }
  if($dmpfile_format10g =~ /TRUE/i)
  {
     $role = $db_role;
  }
  else
  {
     ## for traditional exp/imp user must be connected as sysdba.
     $role = "SYSDBA";
  }
  if($generate_log =~ /FALSE/i && $db_10_or_higher =~ /TRUE/i && $dmpfile_format10g =~ /TRUE/i)
  {
    set_agent_oh();
    set_env_var($oracle_home, $oracle_sid, $db_10_or_higher);

    ## create temporary log file and pass it to the impdp script.
    (my $log_fh,$log_file_name) = create_temp_file("_import.log");
    my $dir_path = getDirname($log_file_name);
    my $dir_name = "EM_INT_TTS_LOG_DIR";

    create_directory_object($dir_name, $dir_path);
    my $log_basename = getBasename($log_file_name);
    $imp_script = $imp_script. " logfile=$dir_name:$log_basename";
    set_target_oh();
  }
  print_debug("role : $role\n");
  &impdp($db_10_or_higher, $imp_script, $oracle_home, $oracle_sid, $db_username, $db_passwd, $role, $smp_ignore, $generate_log, $parse_errors, $log_file_name, $dmpfile_format10g);
  print_debug("tts_import $?\n");
  if($? != 0)
  {
    exit(1);
  }

  if($db_10_or_higher =~ /TRUE/i && &is_asm =~ /TRUE/i)
  {
    if(-e $df_file)
    {
      removeFile($df_file);
    }
  }
}

sub is_asm
{
  set_agent_oh();

  my $is_asm = "FALSE";
  my $sql_is_asm = "select count(1) from v\$asm_client";
  set_env_var($oracle_home, $oracle_sid, $db_10_or_higher);
  my $dbh = connect_database($db_username, $db_passwd, $db_role);    
  my $dbcur = prepare_statement($dbh, $sql_is_asm, $job_name);

  execute_statement($dbh, $dbcur, $job_name);  

  if(my(@data) = $dbcur->fetchrow) 
  {
    print_debug("is_asm: data: @data\n");
    if($data[0] > 0)
    {
      $is_asm = "TRUE";
    }
  }
  $dbcur->finish();     
  disconnect_database($dbh);   
  return $is_asm;
}

###################################################
## TTS CONVERT OPERATION.
## Convert Tablespace/Datafiles.
###################################################
sub rman_convert
{
  save_agent_oh(); #connect using agent OH to check for asm
  save_target_oh();

  my($at_target, $from_platform, $to_platform, $from_to_file_list, $parallelism, $log_file_name) = @_;
  
  print_debug("$job_name: rman_convert: at_target: $at_target, from_platform: $from_platform, to_platform: $to_platform, from_to_file_list: $from_to_file_list, parallelism: $parallelism , log_file_name: $log_file_name\n");
  my @ts_df_array = split(/,/, $ts_df_list);

  my $rman_script = "convert";

  my $convert_status = "true";
  
  if($at_target =~ /TRUE/i)
  {
    $rman_script = $rman_script." datafile '". join("','", @ts_df_array)."'";
    print_debug("Performing RMAN Conversion at Source\n");
  }
  else
  {
    $rman_script = $rman_script." tablespace '". join("','", @ts_df_array)."'";
    print_debug("Performing RMAN Conversion at Target\n");
  }
  
  if($from_to_file_list)
  {
    my @from_to_file_array = split(DELIMITER, $from_to_file_list); 
    my @from_file_array = split(',', $from_to_file_array[0]);
    my @to_file_array = split(',', $from_to_file_array[1]);
  
    print_debug("from_file_array: @from_file_array: to_file_array:@to_file_array\n");
    my @from_to_array;

    print_debug("from_file_no: $#from_file_array: to_file_no:$#to_file_array \n");
    
    for(my $i=0; $i <= $#from_file_array; $i++)
    {
      push(@from_to_array, "'".$from_file_array[$i]."','".$to_file_array[$i]."'");   
    }
    $rman_script = $rman_script."\n db_file_name_convert ".join(",", @from_to_array)."\n";
  }  
  if($from_platform)
  {
    $rman_script = $rman_script." from platform '$from_platform'";
  }
  if($parallelism =~ /\d/)
  {
    $rman_script = $rman_script." parallelism $parallelism";
  }
  if($to_platform)
  {
    $rman_script = $rman_script." to platform '$to_platform'";
  }  
  $rman_script = $rman_script.";\n";

  my $rman_log;
  my $is_asm = &is_asm;
  if($is_asm =~ /TRUE/i && $db_10_or_higher =~ /TRUE/i)
  {
    # Create a temporary log File
    print_debug("ASM Database...\n");
    (my $rman_fh,$rman_log) = create_temp_file(".log");
    close $rman_fh;

    $rman_script = "spool log to $rman_log;\n$rman_script spool log off;\n";

    print_debug("rman_convert: spool log: $rman_log \n");
  }
  
  print_debug("$job_name: rman_convert: rman_script: $rman_script\n");  
  
  set_target_oh();
  set_env_var($oracle_home, $oracle_sid, $db_10_or_higher);
  print_debug("rman_convert: $rman_script $db_username $db_role $oracle_home $oracle_sid \n");
  my $exit_val = rman_tts($rman_script, $db_username, $db_passwd, $db_role, $oracle_home, $oracle_sid, $db_10_or_higher);
  
  ## Spoke to catherine.ying exit_val = 0 is success for now. 
  ## But changes would be there for success with warnings for 10gr2. 
  ## TODO: ISSUE: can we ignore success with warnings???.
  print_debug("rman_convert exit_val: $exit_val ERROR_CODE: $ERROR_CODE \n");
  if($is_asm =~ /TRUE/i && $db_10_or_higher =~ /TRUE/i)
  {
    parse_rman_log($rman_log, $log_file_name);
  }
  if($exit_val < 0 || $exit_val == $ERROR_CODE)
  {
    exit(1);
  }
}

sub parse_rman_log
{
  print_debug("Parsing RMAN logfile: $_[0]\n");

  my($rman_log, $log_file_name) = @_;
  if (-e $rman_log)
  {
    open(LOGFILE, $rman_log )|| die "Can't open :$rman_log\n";
    my @cont_arr = <LOGFILE>;
    close LOGFILE;

    print STDOUT @cont_arr;
    if(!defined($log_file_name))
    {
      return;
    }
    my $df_count = 0;
    my @converted_df = ();
    foreach my $cont (@cont_arr)
    {
      if($cont =~ /^converted datafile=/i)
      {
        print_debug("parse_log_file: converted datafile: $cont\n");
        (my $init, $converted_df[$df_count]) = split(/converted datafile=/,$cont);
        chomp($converted_df[$df_count]);
        $df_count++;
      }
    }
    ## write contents to a temporary file
    my $converted_df_list = join(",",@converted_df);
    my $df_file = getDirname($log_file_name)."/".$job_name."_df.log";

    print_debug("parse_log_file: df_file: $df_file contents: $converted_df_list\n");

    open(DF_FILE, ">$df_file") || warn "Can't open $df_file to write:$!\n";
    print DF_FILE $converted_df_list;
    close DF_FILE;
  }
  else
  {
    print_error("parse_rman_log: logfile does not exist: $_[0]");
    exit(1);
  }
}


###################################################
## TTS OS COPY OPERATION.
###################################################
sub do_copy
{
  my($from_to_file_list) = @_;
  my @from_to_file_array = split(DELIMITER, $from_to_file_list); 
  my @from_file_array = split(',', $from_to_file_array[0]);
  my @to_file_array = split(',', $from_to_file_array[1]);

  for(my $i=0; $i <= $#from_file_array; $i++)  
  {
    print_debug("$job_name: Copying file $from_file_array[$i] to $to_file_array[$i]\n");
    if($from_file_array[$i] eq $to_file_array[$i])
    {
      print STDOUT "Same file location. Not Copying - $from_file_array[$i]\n";
    }
    else
    {
      copyFile($from_file_array[$i], $to_file_array[$i]);
    }
  }
}

sub read_file_header
{
  my($datafile_list) = @_;
  my @datafiles = split(DELIMITER, $datafile_list);
  set_env_var($oracle_home, $oracle_sid, $db_10_or_higher);
  
  my $sql_read_file_header = q{
    declare
      db_name varchar2(100);
      f_no    binary_integer;
      n_blocks	 number;
      db_id   number;
      samend binary_integer := 1;
      unable_to_identify_file EXCEPTION;
      PRAGMA EXCEPTION_INIT(unable_to_identify_file, -19625);
      begin
        sys.dbms_backup_restore.readFileHeader(:fname, db_name,
          db_id, :tsname, f_no, n_blocks, :blksize, :plid, samend);
      exception when unable_to_identify_file then
        begin
          samend := 0;
          sys.dbms_backup_restore.readFileHeader(:fname, db_name,
            db_id, :tsname, f_no, n_blocks, :blksize, :plid, samend);
        end;
      end;
  };
  
  set_agent_oh();
  my $dbh = connect_database($db_username, $db_passwd, "sysdba");    
  foreach my $fname(@datafiles)
  {  
    my $tsname;
    my $blksize;
    my $plid;
    ## print_debug("read_file_header: reading file: $fname\n");
    
    my $dbcur = prepare_statement($dbh, $sql_read_file_header, $job_name);
  
    $dbcur->bind_param(":fname", $fname);   
  
    $dbcur->bind_param_inout(":tsname", \$tsname, 2);
    $dbcur->bind_param_inout(":blksize", \$blksize, 2);
    $dbcur->bind_param_inout(":plid", \$plid, SQL_INTEGER);
    
    execute_statement($dbh, $dbcur, $job_name);  
    $dbcur->finish();    
    print STDOUT $fname.DELIMITER.$tsname.DELIMITER.$blksize.DELIMITER.$plid.DELIMITER;    
  }
  disconnect_database($dbh);   
}

###################################################
## TEST GENERATE/INTEGRATE TTS operations. 
###################################################
## &generate_ts;
## &integrate_ts;
sub generate_ts
{
  $oracle_home = $ENV{ORACLE_HOME};
  $oracle_sid = $ENV{ORACLE_SID};
  $ts_df_list = "TS1,TS2,TS3";
  $job_name = "GENERATE_TTS1";  
  $db_username="sys";
  #### fill in the password here
  $db_passwd="";
  $db_role="sysdba";    
  $db_10_or_higher = "true";
  
  my $db_9i_or_higher = "true";
  my $copy_or_convert = "CONVERT";
  
  #### Step 1. Prepare Job
  my @online_ts_array = &prepare_job($db_9i_or_higher);

  #### Step 2. convert or copy TTS
  if($copy_or_convert =~ /'CONVERT'/i)
  {  
    my $to_platform = "Microsoft Windows IA (32-bit)";
    my $at_target = "FALSE";
    &rman_convert($at_target, "", $to_platform, "", "", "");    
  }
  elsif($copy_or_convert =~ /'COPY'/i)
  {
    my $to_dir_list = "/tmp/copy/DF1.dbf,/tmp/copy/DF3.dbf";        
    &do_copy($ts_df_list.DELIMITER. $to_dir_list);
  }

  #### Step 3. Export TTS
  my $exp_script = "dumpfile=expdat.dmp directory=TMP logfile=export.log transport_tablespaces=$ts_df_list job_name=$job_name";
  my $smp_ignore="FALSE";
  my $generate_log = "FALSE";
  my $parse_errors = "TRUE";
  my $log_file_name = "/tmp/exp.log";    

  &tts_export($exp_script, $smp_ignore, $generate_log, $parse_errors, $log_file_name);      
  
  ## pre-10g export. make sure to set 
  ## $db_10_or_higher = "false";
  ## my $exp_script = "file=/tmp/expdat.dmp log=/tmp/export.log transport_tablespace=y tablespaces=$ts_df_list";  
  ## &tts_export($exp_script, $smp_ignore, $generate_log, $parse_errors, $log_file_name);      

  ## Make Tablespace read-write.  
  &make_ts_rw(join(",", @online_ts_array));  
}

sub integrate_ts
{
  $oracle_home = $ENV{ORACLE_HOME};
  $oracle_sid = $ENV{ORACLE_SID};
  $ts_df_list = "/tmp/df1.dbf,/tmp/df2.dbf,/tmp/df3.dbf";
  $job_name = "INTEGRATE_TTS1";    
  $db_username="system";
  ### fill in the password here
  $db_passwd="";
  $db_role="SYSDBA";
  $db_10_or_higher = "true";

  my $ts_list="TS1,TS3";
  my $copy_or_convert = "OPY";

  $ts_df_list = "/tmp/df1.dbf".DELIMITER."/tmp/df2.dbf".DELIMITER."/tmp/df3.dbf";
  read_file_header($ts_df_list);
  
  #### Step 1. convert or copy TTS
  if($copy_or_convert =~ /CONVERT/i)  
  {
    my $from_file_list ="/tmp/copy/DF1.dbf,/tmp/copy/DF3.dbf";
    my $from_platform = "Solaris[tm] OE (32-bit)";  
    my $to_platform = "Microsoft Windows IA (32-bit)";
    my $to_file_list = "/tmp/copy/DF_1.DBF,/tmp//copy/DF_3.DBF";
    my $parallelism = "1";
    my $at_target = "TRUE";
    
    &rman_convert($at_target, $db_username, $from_platform, $to_platform, $from_file_list.DELIMITER.$to_file_list);
  }  
  elsif($copy_or_convert =~ /COPY/i)
  {
    my $from_dir_list = "/tmp/copy/DF1.dbf,/tmp/copy/DF3.dbf";        
    &do_copy($from_dir_list.DELIMITER.$ts_df_list);
  }

  #### Step 2. Import TTS
  my $imp_script = "dumpfile=expdat.dmp directory=TMP transport_datafiles=$ts_df_list logfile=import.log";
  
  ## pre-10g import. Make sure to set 
  ## $db_10_or_higher = "false";  
  ## my $imp_script = "file=/tmp/input/expdat.dmp transport_tablespace=y datafiles=$ts_df_list log=import.log";          
  my $smp_ignore="FALSE";
  my $generate_log = "TRUE";
  my $parse_errors = "TRUE";
  my $log_file_name = "/tmp/input/exp.log";    
  ## &tts_import($imp_script, $smp_ignore, $generate_log, $parse_errors, $log_file_name)

  ## Make Tablespace read-write.  
  &make_ts_rw($ts_list);    
}
1;
