ClickHouse-Encoder
view release on metacpan or search on metacpan
t/roundtrip.t view on Meta::CPAN
elsif ($code eq 'FixedString') {
my $n = $type->{n};
for (1..$nrows) { push @vals, substr($$buf, $$off, $n); $$off += $n }
}
elsif ($code eq 'Enum8') { for (1..$nrows) { push @vals, unpack('c', substr($$buf, $$off, 1)); $$off += 1 } }
elsif ($code eq 'Enum16') { for (1..$nrows) { push @vals, unpack('s<', substr($$buf, $$off, 2)); $$off += 2 } }
elsif ($code eq 'Decimal128') {
for (1..$nrows) {
my $lo = unpack('Q<', substr($$buf, $$off, 8));
my $hi = unpack('q<', substr($$buf, $$off + 8, 8));
push @vals, [$lo, $hi];
$$off += 16;
}
}
elsif ($code eq 'Decimal256') {
for (1..$nrows) {
push @vals, [map {
unpack('Q<', substr($$buf, $$off + 8 * $_, 8))
} 0 .. 3];
$$off += 32;
}
}
elsif ($code eq 'Bool' || $code eq 'Boolean') {
for (1..$nrows) { push @vals, unpack('C', substr($$buf, $$off, 1)); $$off += 1 }
}
elsif ($code eq 'UUID') {
for (1..$nrows) { push @vals, substr($$buf, $$off, 16); $$off += 16 }
}
elsif ($code eq 'IPv4') {
for (1..$nrows) {
my $v = unpack('V', substr($$buf, $$off, 4));
$$off += 4;
push @vals, sprintf('%d.%d.%d.%d',
($v>>24)&0xff, ($v>>16)&0xff, ($v>>8)&0xff, $v&0xff);
}
}
elsif ($code eq 'IPv6') {
for (1..$nrows) { push @vals, substr($$buf, $$off, 16); $$off += 16 }
}
elsif ($code eq 'Map') {
# Map(K, V) on the wire is Array(Tuple(K, V)).
my $array_t = { code => 'Array',
inner => { code => 'Tuple', parts => [$type->{key}, $type->{val}] } };
@vals = @{ _decode_column($buf, $off, $array_t, $nrows) };
}
elsif ($code eq 'Variant') {
my $mode = unpack('Q<', substr($$buf, $$off, 8));
$$off += 8;
die "Variant mode != 0" unless $mode == 0;
my @wire_disc;
for (1..$nrows) { push @wire_disc, ord(substr($$buf, $$off, 1)); $$off += 1 }
# wire_disc is in alphabetical-order space; map to declaration idx.
my @parts = @{ $type->{parts} };
my $wire_to_decl = $type->{wire_to_decl};
my @counts; for my $w (@wire_disc) { $counts[$w]++ if $w != 255 }
my @subcols; # subcols[wire_idx] = decoded values for that wire arm
for my $w (0 .. $#parts) {
my $decl = $wire_to_decl->[$w];
$subcols[$w] = _decode_column($buf, $off, $parts[$decl], $counts[$w] // 0);
}
my @cursors = (0) x scalar @parts;
for my $r (0 .. $nrows - 1) {
my $w = $wire_disc[$r];
if ($w == 255) { push @vals, undef; next }
push @vals, [$wire_to_decl->[$w], $subcols[$w][ $cursors[$w]++ ]];
}
}
elsif ($code eq 'LowCardinality') {
my $version = unpack('Q<', substr($$buf, $$off, 8)); $$off += 8;
my $flags = unpack('Q<', substr($$buf, $$off, 8)); $$off += 8;
my $dict_n = unpack('Q<', substr($$buf, $$off, 8)); $$off += 8;
die "LC version != 1" unless $version == 1;
my $idx_type = $flags & 0xff;
my $inner = $type->{inner};
$inner = $inner->{inner} if $inner->{code} eq 'Nullable';
my $dict = _decode_column($buf, $off, $inner, $dict_n);
my $idx_n = unpack('Q<', substr($$buf, $$off, 8)); $$off += 8;
for my $r (1 .. $idx_n) {
my $i;
if ($idx_type == 0) { $i = ord(substr($$buf, $$off, 1)); $$off += 1 }
elsif ($idx_type == 1) { $i = unpack('v', substr($$buf, $$off, 2)); $$off += 2 }
elsif ($idx_type == 2) { $i = unpack('V', substr($$buf, $$off, 4)); $$off += 4 }
else { $i = unpack('Q<', substr($$buf, $$off, 8)); $$off += 8 }
# For Nullable LC, slot 0 is the null sentinel.
if ($type->{inner}{code} eq 'Nullable' && $i == 0) {
push @vals, undef;
} else {
push @vals, $dict->[$i];
}
}
}
elsif ($code eq 'Array') {
my @offsets;
for (1..$nrows) { push @offsets, unpack('Q<', substr($$buf, $$off, 8)); $$off += 8 }
my $total = @offsets ? $offsets[-1] : 0;
my $flat = _decode_column($buf, $off, $type->{inner}, $total);
my $prev = 0;
for my $end (@offsets) {
push @vals, [@$flat[$prev .. $end - 1]];
$prev = $end;
}
}
elsif ($code eq 'Tuple') {
my @cols = map { _decode_column($buf, $off, $_, $nrows) } @{$type->{parts}};
for my $r (0 .. $nrows - 1) {
push @vals, [map { $_->[$r] } @cols];
}
}
elsif ($code eq 'Nullable') {
my @nulls;
for (1..$nrows) { push @nulls, ord(substr($$buf, $$off, 1)); $$off += 1 }
my $inner = _decode_column($buf, $off, $type->{inner}, $nrows);
for my $r (0 .. $nrows - 1) {
push @vals, $nulls[$r] ? undef : $inner->[$r];
}
}
else {
die "Decoder: unsupported $code";
}
return \@vals;
}
sub decode_block {
my ($buf) = @_;
my $off = 0;
( run in 0.542 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )