#!/usr/bin/perl

use strict;
use warnings FATAL => 'all';

use SMT::Utils;

use IPC::Open3 ();
use Getopt::Long ();
use Cwd 'abs_path';

sub usage {
	die "Usage: $0 [-i | [ OPTIONS ] [sql-file-to-use.sql | - ]]\n    where possible OPTIONS are\n        --verbose\n        --select-mode or --select-mode-direct\n";
}

my ($verbose, $select_mode, $select_direct, $interactive);
if (not Getopt::Long::GetOptions(
	'verbose' => \$verbose,
	'select-mode' => \$select_mode,
	'select-mode-direct' => \$select_direct,
	'interactive' => \$interactive,
	)) {
	usage();
}

if ($interactive and ($select_direct or $select_mode)) {
	warn "Option --interactive cannot be used with --select-* options.\n";
	usage();
}
if ($select_mode and $select_direct) {
	warn "Options --select-mode and --select-mode-direct are exclusive.\n";
	usage();
}

if ($interactive) {
	if (@ARGV) {
		warn "In interactive mode, no input file is expected.\n";
		usage();
	}
} elsif (@ARGV != 1) {
	usage();
}

my $config_file = '/etc/smt.conf';

if (not -e $config_file) {
	die "The config file [$config_file] does not seem to exist.\n";
}

my $dbname = 'smt';
my $dbhost = 'localhost';
my $dbport = 5432;
my $cfg;
eval
{
    $cfg = SMT::Utils::getSMTConfig();
    my $config = $cfg->val('DB', 'config');
    foreach my $subval (split(/;/, $config))
    {
        if ($subval =~ /^DBI:mysql:database=(.+)/ && $1)
        {
            $dbname = $1;
        }
        if ($subval =~ /^host=(.+)/ && $1)
        {
            $dbhost = $1;
        }
        if ($subval =~ /^port=(.+)/ && $1)
        {
            $dbport = $1;
        }
    }
};
if($@ || !defined $cfg)
{
    print STDERR sprintf("Cannot read the SMT configuration file: %s\n", $@);
    return 2;
}

my $filename = $ARGV[0];
if (defined $filename and $filename ne '-') {
	$filename = abs_path($filename);
}

chdir '/';

my ($pid, $wfh, $rfh);
my @command = ( 'mysql', '-u', $cfg->val('DB', 'user'), '-D', $dbname, '--skip-column-names', '--silent');
if ($dbhost && $dbhost ne "localhost") {
	push @command, '-h', $dbhost;
	if ($dbport) {
		push @command, '-P', $dbport;
	}
}
push @command, "--password=".$cfg->val('DB', 'pass');
if (not $interactive) {
	push @command, '--batch';
	if ($filename ne "-") {
		push @command, ( '-e', "source $filename" );
	}
}
if ($verbose) {
	print STDERR "Running: @command\n";
}
if ($interactive) {
	exec(@command) or die "young\n";
}
if ($filename eq '-') {
	$wfh = '<&STDIN';
}
if ($select_direct) {
        exec(@command) or die "young\n";
} else {
	$pid = IPC::Open3::open3($wfh, $rfh, '>&STDERR', @command) or return 2;
}
close $wfh;

if ($select_direct) {
	$| = 1;
}
my @out;
while (<$rfh>) {
	if ($select_direct) {
		print;
	} else {
		push @out, $_;
	}
}
close $rfh;
waitpid $pid, 0;
if ($?) {
	my $ret = $? >> 8;
	print STDERR @out;
	exit $ret;
} elsif ($select_mode) {
	print @out;
}
exit;

__END__

=head1 NAME

smt-sql - utility for feeding SQL to SMT's database

=head1 SYNOPSIS

    smt-sql sql-file-to-use.sql
    smt-sql - < sql-file-to-use.sql
    smt-sql -i

    smt-sql --verbose sql-file-to-use.sql
    smt-sql --select-mode - < sql-file-to-use.sql
    smt-sql --verbose --select-mode sql-file-to-use.sql
    smt-sql --select-mode-direct sql-file-to-use.sql

    smt-sql --interactive

=head1 OPTIONS

=over 5

=item --select-mode

By default, no output is printed to standard output because
B<smt-sql> is primarily intended to feed DDL/DML to the
database, not do queries. With this option, upon successful
completion, the output will be printed to standard output. Note that
it will be in the native format.

=item --select-mode-direct

Variant of B<--select-mode> when the output is printed out
immediatelly, without waiting for successful result. This is useful
when you want to log the output and be able to watch it while
the command runs, for example with C<tail -f>.

Note that only one of B<--select-mode> and B<--select-mode-direct>
can be specified.

=item -i | --interactive

Start the interactive session.

This option cannot be used together with the B<--select-mode*>
options.

=item --verbose

If this option is used, the command which will be invoked including
any parameter is printed to standard error output, prior to it
execution. No quoting is done however, so it can only be used to get
rough idea about what is being called.

=back

=head1 DESCRIPTION

Depending on the database backend of Spacewalk, PostgreSQL or
Oracle RDBMS, different client tools have to be used when feeding
native SQL to the databases -- B<psql> or B<sqlplus>. They have
different invocation options.

The B<smt-sql> does the right thing for both database backends.
It fetches the database backend type and the connect information from
Spacewalk config files, selects the correct command line tool, runs it
and feeds it the SQL from file specified as parameter. If single
hyphen sign (B<->) is used for the SQL file parameter, standard input
is used. If the B<-i> option is used, interactive session is started.

No output is printed upon successful operation unless B<--select-mode>.
If any error is reported, the error message and all output generated
is printed on the standard output.

The exit value is the exit value of the B<psql> or B<sqlplus>.

=head1 FILES

=over 5

=item F</etc/smt.conf>

File which holds connect information for the SMT database.

=back

=head1 AUTHORS

Jan Pazdziora

=cut


