ClickHouse-Encoder

 view release on metacpan or  search on metacpan

t/schema-redirect.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More;
use Config;
use File::Temp qw(tempdir);
use lib 'blib/lib', 'blib/arch', 't/lib';
use ClickHouse::Encoder;

# Keep Enum literals intact and avoid forwarding credentials on redirects.

# Enum label with an unbalanced paren: type must survive verbatim and
# later columns must not be dropped.
{
    my $ddl = q{CREATE TABLE t (`a` Enum8('x)y' = 1, 'z' = 2), b UInt32) ENGINE = Memory};
    my $s = ClickHouse::Encoder->parse_create_table($ddl);
    is_deeply($s->{columns},
        [['a', q{Enum8('x)y' = 1, 'z' = 2)}], ['b', 'UInt32']],
        'paren in Enum label keeps type and later columns');
    is($s->{engine}, 'Memory', 'engine still parsed after Enum fix');
}

# Both ClickHouse literal-escape forms shield their quotes.
{
    my $ddl = q{CREATE TABLE t (a Enum8('it''s (x' = 1), b Int8) ENGINE = Memory};
    my $s = ClickHouse::Encoder->parse_create_table($ddl);
    is_deeply($s->{columns},
        [['a', q{Enum8('it''s (x' = 1)}], ['b', 'Int8']],
        "doubled-quote escape survives parse");
    $ddl = q{CREATE TABLE t (a Enum8('it\'s (x' = 1), b Int8) ENGINE = Memory};
    $s = ClickHouse::Encoder->parse_create_table($ddl);
    is(scalar @{$s->{columns}}, 2, 'backslash-quote escape keeps column count');
    is($s->{columns}[1][0], 'b', 'column after backslash-escaped label kept');
}

# Sibling splitter: Enum comma inside Nested/Tuple type lists.
{
    my $flat = ClickHouse::Encoder->flatten_nested(
        [['n', q{Nested(x UInt8, y Enum8('p,q' = 2))}]]);
    is_deeply($flat, [['n.x', 'Array(UInt8)'], ['n.y', q{Array(Enum8('p,q' = 2))}]],
        'comma in Enum label does not split Nested elements');
}

my $can_fork = $Config{d_fork} && $Config{d_fork} eq 'define';

SKIP: {
    skip 'fork unavailable', 3 unless $can_fork;
    my $has_sock = eval { require IO::Socket::INET; require IO::Select; 1 };
    skip 'IO::Socket::INET unavailable', 3 unless $has_sock;

    # Redirector on port A 302s to target on port B (cross-origin by
    # port). Target records any X-ClickHouse-Key it sees into $seen.
    my $dir = tempdir(CLEANUP => 1);
    my $seen = "$dir/seen.txt";
    my $srv_a = IO::Socket::INET->new(
        LocalAddr => '127.0.0.1:0', Listen => 5, ReuseAddr => 1);
    my $srv_b = IO::Socket::INET->new(
        LocalAddr => '127.0.0.1:0', Listen => 5, ReuseAddr => 1);
    skip 'cannot bind loopback sockets', 3 unless $srv_a && $srv_b;
    my ($pa, $pb) = ($srv_a->sockport, $srv_b->sockport);
    my $pid = fork // die "fork: $!";
    if ($pid == 0) {
        close STDOUT;
        my $c = $srv_a->accept;
        my $req = '';
        $c->recv($req, 65536);
        print $c "HTTP/1.1 302 Found\r\nLocation: http://127.0.0.1:$pb/\r\n"
            . "Content-Length: 0\r\nConnection: close\r\n\r\n";
        close $c;
        if (IO::Select->new($srv_b)->can_read(5)) {



( run in 0.724 second using v1.01-cache-2.11-cpan-3f962061493 )