#!/usr/bin/perl

use strict;
use warnings;

=head1 NAME

  direct-clh -- выполнение запросов в ClickHouse из командной строки (через http-интерфейс)

=head1 DESCRIPTION

=head1 OPTIONS

    -h, --help
      справка

    -q, --query <str>
      запрос
      если указан "-" -- читает запрос из stdin

    -f, --file <path>
      файл, в который записать результат запроса
      если не указан -- будет создан временный файл

    -c, --cat
      после выполнения запроса сделать exec "cat $file"

    -l, --less
      после выполнения запроса сделать exec "less $file"

    -f, --format (json|tsv|pretty)
      формат результата
      необязательно, по умолчанию -- tsv
      кроме того, можно указывать формат прямо в запросе

    --conf
      конфиг базы, из которого берётся хост и порт
      например, dt:ppchouse:logs
      можно вместо опции указывать первым позиционным параметром

=head1 EXAMPLES

    direct-clh 'show tables' -f pretty --cat
    direct-clh --cat -q 'show create table ppclog_api_201409'
    direct-clh dt:ppchouse:logs 'show tables'
    direct-clh dt:ppchouse:logs 'show tables'

=head1 TODO

  * --clear-tmp-files
  * --show-my-tmp-files
  * если время выполнения маленькое (несколько секунд) + результат небольшой (по строчкам и по байтам) -- зачитывать в память, писать на stdout, файл удалять
  * вместо всего перечисленного -- каталог с политикой удаления старых файлов
  * перейти на Y::Cl, если он может сразу на диск писать
  * настраиваемый url ClH

=cut

use Getopt::Long;
use LWP::UserAgent;
use File::Temp qw/ tempfile /;
use Time::HiRes qw/gettimeofday tv_interval/;
use Net::INET6Glue::INET_is_INET6;

use ProjectSpecific;

use Yandex::DBTools;
use Yandex::HTTP;

run() unless caller();

sub run
{
    $ENV{TMPDIR} = '/tmp/temp-ttl/ttl_1d' if (-d '/tmp/temp-ttl/ttl_1d');
    my $opt = parse_options();
    my $ua = LWP::UserAgent->new();
    $ua->timeout(10*3600);
    my %request_options = (
        ':content_file' => $opt->{file},
    );
    my $t0 = [gettimeofday];
    my $resp = $ua->post(Yandex::HTTP::make_url($opt->{clh_url}, {query => $opt->{query}}), %request_options);
    my $elapsed = tv_interval ( $t0 );
    die $resp->content."\n".$resp->status_line unless $resp->is_success;
    my $line_count = `wc -l < '$opt->{file}'`;
    chomp $line_count;

    print STDERR "$line_count lines in $elapsed sec\nresult file: $opt->{file}\n\n";
    if( $opt->{cat} ){
        exec "cat '$opt->{file}'";
    } elsif ( $opt->{less} ){
        exec "less '$opt->{file}'";
    }
    exit 0;
} 


sub parse_options
{
    my %O = (
        cat => 1,
    );
    GetOptions(
        "h|help" => sub {
            system("podselect -section NAME -section DESCRIPTION -section OPTIONS -section EXAMPLES $0 | pod2text-utf8");
            exit 0;
        },
        'host=s' => \$O{host},
        'p|port=i' => \$O{port},
        'q|query=s' => \$O{query},
        'f|file=s' => \$O{file},
        'c|cat' => \$O{cat},
        'l|less' => \$O{less},
        'f|format=s' => \$O{format},
        'conf=s' => \$O{conf},
    ) or die "can't parse options, stop\n";

    if (!$O{conf} && !($O{host} || $O{port})) {
        $O{conf} = shift @ARGV;
    }
    if (($O{host} || $O{port}) && $O{conf}) {
        die "can't process both --conf and --host/--port, stop\n";
    }
    if (!$O{host} && !$O{conf}) {
        die "--host or --conf is not specified, stop\n";
    }
    if (!$O{port} && !$O{conf}) {
        die "--port or --conf is not specified, stop\n";
    }

    if (!$O{query}) {
        $O{query} = shift @ARGV;
        die "no query or config specified, stop\n" unless $O{query};
    }
    if ($O{conf}) {
        my ($env, $instance) = ($O{conf} =~ /^([^:]+):(.*)$/);
        $Yandex::DBTools::CONFIG_FILE = ProjectSpecific::get_db_conf_file($env);
        my $db_conf = Yandex::DBTools::get_db_config($instance);
        $O{host} = $db_conf->{host};
        $O{port} = $db_conf->{port};
    }
    if (!$O{host} || !$O{port}) {
        die "could not determine host or port from config '$O{conf}', stop\n";
    }

    if (@ARGV && @ARGV <= 2) {
        die "--query and/or --conf were specified, can't process positional arguments (@ARGV), stop\n";
    } elsif (@ARGV > 2) {
        die "unexpected number of arguments (@ARGV)\n";
    }

    if ($O{query} eq '-'){
        $O{query} = join '\n', <STDIN>;
    }
    if ($O{format}){
        my $clh_format = { json => 'JSON', tsv => 'TabSeparatedRaw', pretty => 'PrettyCompactNoEscapes' }->{ lc $O{format} };
        $O{query} .= " format $clh_format";
    }

    unless ($O{file}){
        (undef, $O{file}) = tempfile( "/tmp/clickhouse-result-XXXXXXXXXX", CLEANUP => 0 );
    }

    if ($O{cat} && $O{less}){
        die "can't process both --cat and --less options\n";
    }

    $O{clh_url} = "http://$O{host}:$O{port}/";
    return \%O;
}


