#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#

#-----------------------------------------------------------------------------

=head1   runsqlcmd 



 This script is called to run the sql statements found in the files
   in either the default /opt/xcat/lib/perl/xCAT_schema  or the
   directory input with the -d flag.
   For more information see man runsqlcmd and the
   developers guide:
   http://xcat.svn.sourceforge.net/viewvc/xcat/xcat-core/trunk/xCAT-client/share/doc/xCAT2DevGuide.pdf

=cut

BEGIN
{
    $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
    $::XCATDIR  = $ENV{'XCATDIR'}  ? $ENV{'XCATDIR'}  : '/etc/xcat';
}

use lib "$::XCATROOT/lib/perl";
use xCAT::Utils;
use Getopt::Long;
use xCAT::MsgUtils;
use xCAT::Table;
use File::Path;
use strict;

#-----------------------------------------------------------------------------
# Main

$::progname = "runsqlcmd";
Getopt::Long::Configure("bundling");
$Getopt::Long::ignorecase = 0;
my ($directory, $help, $version,$verbose, $filelist);

# parse the options
if (
    !GetOptions(
                'd|dir=s'   => \$directory,
                'f|files=s' => \$filelist,
                'h|help'    => \$help,
                'v|version' => \$version,
                'V|verbose' => \$verbose,
    )
  )
{
    &usage;
    exit(1);
}
# see if they entered a command
my $args = join ' ', @ARGV;
my $command =  $args;

# display the usage if -h or --help is specified
if ($help)
{
    &usage;
    exit(0);
}
# display the version statement if -v or --version is specified
if ($version)
{
    my $version = xCAT::Utils->Version();
    xCAT::MsgUtils->message("I", $version);
    exit 0;
}
if (($filelist) && ($directory))
{
    xCAT::MsgUtils->message("E","Cannot enter both the -f and -d flags.");
    exit 1;
}
if (($command) && (($directory) || ($filelist)))
{
    xCAT::MsgUtils->message("E","Cannot enter both a command and the -d or -f flag.");
    exit 1;
}
my $tempfile;
if ($command) { # command on command line
     $tempfile="/tmp/runcmdfile.$$"; 
     my $cmd = "echo \"$command\"  > $tempfile";
     xCAT::Utils->runcmd($cmd,0);
     if ($::RUNCMD_RC != 0)
     {    # error
            xCAT::MsgUtils->message("E", "$cmd failed");
            exit 1;

     }
     # put on filelist
     $filelist=$tempfile;
} else {  # commands in a file

  if (!($filelist)) { # if no file list and no directory set default
     if (!($directory)) {
        $directory = "$::XCATROOT/lib/perl/xCAT_schema";  
     }
  }
}

my @filearray;
if ($filelist)
{    # use filelist
    $directory = "";                              #Get rid of the default
    @filearray = &process_file_list($filelist);
}
else
{

    if (!(-e $directory))
    {
        xCAT::MsgUtils->message("E",
                                "The $directory directory does not exist.");
        exit 1;
    }
}
my @sqlfilelist = xCAT::Table->get_filelist($directory, \@filearray, "sql");

if (@sqlfilelist) {  # if anything to do
  #determine database
  my $xcatcfg = xCAT::Table->get_xcatcfg();
  foreach my $file (@sqlfilelist)
  {
    if ($xcatcfg =~ /^DB2:/)
    {
        &rundb2cmd($file);
    }
    if ($xcatcfg =~ /^mysql:/)
    {
        &runmysqlcmd($file, $xcatcfg);
    }
    if ($xcatcfg =~ /^Pg:/)
    {
        &runpgsqlcmd($file, $xcatcfg);
    }
    if ($xcatcfg =~ /^SQLite:/)
    {
        # not supported but will leave routine in case we change our mind 
        if ($verbose) {
           xCAT::MsgUtils->message("SE", "The runsqlcmd does not support the SQLite database.");
        }
        #&runsqlitecmd($file,$xcatcfg);
        exit 1;
    }

  }
} else {
     if ($verbose) {
        xCAT::MsgUtils->message("SI", "The runsqlcmd has no files to process in $directory .");
     }
}
if ($tempfile) {
     my $cmd = "rm $tempfile";
     xCAT::Utils->runcmd($cmd,0);
     if ($::RUNCMD_RC != 0)
     {    # error
            xCAT::MsgUtils->message("E", "$cmd failed");
            exit 1;

     }
}   
exit 0;

#####################################
#  subroutines
#####################################

#-----------------------------------------------------------------------------

=head3    usage 
	
	Displays message for -h option

=cut

#-----------------------------------------------------------------------------

sub usage
{
    xCAT::MsgUtils->message(
        'I',
        "Usage:\nRuns the sql commands in files located in /opt/xcat/lib/perl/xCAT_schema by default, or the directory input with -d, or the list of files input with the -f flag, or the command input on the command line. Supports DB2,PostgreSQL,MySQL."
        );
    my $msg =
      "runsqlcmd  <-h|--help>\n           <-v|--version>\n           <-V|--verbose>\n           <-d|--dir>\n           <-f|--files>  \n           <sql command>";

    xCAT::MsgUtils->message('I', "$msg");
}

#-----------------------------------------------------------------------------

=head3   rundb2cmd  

	
  Run a commmand as the xcatdb instance id 
  Input: command 

=cut

#-----------------------------------------------------------------------------
sub rundb2cmd
{
    use File::Basename;
    my $file     = shift;
    my $rc       = 0;
    if (!(-e $file)) {  # file does not exist
        xCAT::MsgUtils->message("SE",
            "The file:$file does not exist. ");
        return;
    }
    my $filename = basename($file);                # strip filename
    my $tmpfile  = "/tmp/" . $filename . ".tmp";

    # must add connect to database to file
    my $cmd = "echo \"connect to xcatdb;\" >  $tmpfile";
    my @output = xCAT::Utils->runcmd($cmd, 0);
    if ($::RUNCMD_RC != 0)
    {
        xCAT::MsgUtils->message("SE", "$cmd failed");
        return;
    }

    # now add contents of sql file.
    $cmd = "cat $file >>  $tmpfile";
    @output = xCAT::Utils->runcmd($cmd, 0);
    if ($::RUNCMD_RC != 0)
    {
        xCAT::MsgUtils->message("SE", "$cmd failed");
        return;
    }

    $cmd = "\'";
    $cmd .= " db2 -tvf  ";
    $cmd .= "$tmpfile";
    $cmd .= ' 2>&1';
    $cmd .= "\'";
    xCAT::MsgUtils->message("SI", "Running su - xcatdb -c $cmd ");
    system("su - xcatdb -c $cmd");

    if ($? > 0)    # error
    {
        $rc = $? >> 8;
        xCAT::MsgUtils->message("SE",
                                "The command $cmd had errors. Return=$rc");
    }
    $cmd = "rm  $tmpfile";
    @output = xCAT::Utils->runcmd($cmd, 0);
    if ($::RUNCMD_RC != 0)
    {
        xCAT::MsgUtils->message("SE", "$cmd failed");
        return;
    }
    return;
}

#-----------------------------------------------------------------------------

=head3   runmysqlcmd  

	
  Run a sql commmand  
  Input: command 

=cut

#-----------------------------------------------------------------------------
sub runmysqlcmd
{
    my $file    = shift;
    my $xcatcfg = shift;
    my ($front,  $back)   = split('\;', $xcatcfg);
    my ($prefix, $dbname) = split('=',  $front);
    my ($host, $admin, $passwd) = split('\|', $back);
    my ($hostind, $hostname) = split('=', $host);
 
    my $rc  = 0;
    if (!(-e $file)) {  # file does not exist
        xCAT::MsgUtils->message("SE",
            "The file:$file does not exist. ");
        return;
    }
    # set correct path to the mysql cmd
    my $mysql;
    if (xCAT::Utils->isAIX()) {
      $mysql="/usr/local/mysql/bin/mysql";
    } else {
      $mysql="/usr/bin/mysql";
    }
    my $cmd =
      "$mysql --user=$admin --password=$passwd --host=$hostname $dbname \< $file   ";
    #xCAT::MsgUtils->message("SI", "Running mysql --user=$admin --host=$hostname $dbname $file ");
    system("$cmd");

    if ($? > 0)    # error
    {
        $rc = $? >> 8;
        # secure password
        $cmd = "$mysql --user=$admin --password=xxxxxx --host=$hostname $dbname \< $file   ";
        xCAT::MsgUtils->message("SE",
                                "The command $cmd had errors. Return=$rc");
    }
    return;
}

#-----------------------------------------------------------------------------

=head3   runpgsqlcmd  

	
  Run a sql commmand  
  Input: command 

=cut

#-----------------------------------------------------------------------------
sub runpgsqlcmd
{
    my $file    = shift;
    my $xcatcfg = shift;
    my ($front,  $back)   = split('\;', $xcatcfg);
    my ($prefix, $dbname) = split('=',  $front);
    my ($host, $admin, $passwd) = split('\|', $back);
    my ($hostind, $hostname) = split('=', $host);

    my $rc  = 0;
    if (!(-e $file)) {  # file does not exist
        xCAT::MsgUtils->message("SE",
            "The file:$file does not exist. ");
        return;
    }
    # set correct path to the psql cmd
    my $psql;
    if (xCAT::Utils->isAIX()) {
      $psql="/var/lib/pgsql/bin/psql";
    } else {
      $psql="/usr/bin/psql";
    }
    my $cmd =
      "PGPASSWORD=$passwd $psql -d $dbname -h $hostname -U $admin -f $file   ";
    #xCAT::MsgUtils->message("SI", "Running psql -d $dbname -h $hostname -U $admin -f $file ");
    system("$cmd");

    if ($? > 0)    # error
    {
        $rc = $? >> 8;
        xCAT::MsgUtils->message("SE",
                                "The command $cmd had errors. Return=$rc");
    }
    return;
}

#-----------------------------------------------------------------------------

=head3   runsqlitecmd  

	
  Run a sql commmand  
  Input: command 

=cut

#-----------------------------------------------------------------------------
sub runsqlitecmd
{
    my $file    = shift;
    my $xcatcfg = shift;

    return;
}

#-----------------------------------------------------------------------------

=head3   process_file_list  

	
  Expands all wildcards in file list and builds an array 
  Input: filelist 

=cut

#-----------------------------------------------------------------------------
sub process_file_list
{

    my $filelist = shift;
    my @filearray;
    push my @tmparray, split /,/, $filelist;

    # need to expand wildcards
    foreach my $file (@tmparray)
    {
        if ($file =~ tr/*/*/)
        {    # if wildcard add all the file
            my @files = glob("$file.sql");
            push(@filearray, @files);
        }
        else
        {    # else just the file
            push(@filearray, $file);
        }
    }
    return @filearray;
}