DBIO-ClickHouse
view release on metacpan or search on metacpan
lib/DBIO/ClickHouse/Storage.pm view on Meta::CPAN
}
my %RANGE;
# True when the integer string $value does not fit the native type.
sub _outside_range {
my ($value, $type) = @_;
my ($min, $max) = @{ $RANGE{$type} ||= do {
my ($u, $bits) = $type =~ /\A(U?)Int(\d+)\z/;
$u ? [ Math::BigInt->bzero, Math::BigInt->new(2)->bpow($bits)->bdec ]
: [ Math::BigInt->new(2)->bpow($bits - 1)->bneg,
Math::BigInt->new(2)->bpow($bits - 1)->bdec ];
} };
my $n = Math::BigInt->new($value =~ s/\A\+//r);
return ($n < $min or $n > $max) ? 1 : 0;
}
sub _refuse_non_numeric_binds {
my ($self, $ident, $bind) = @_;
for my $item (@{ $bind || [] }) {
my ($attrs, $value) = @$item;
next unless defined $value and not ref $value;
next unless ref $attrs eq 'HASH' and defined $attrs->{dbic_colname};
my $kind = _numeric_kind($attrs->{sqlt_datatype}) or next;
my $table = Scalar::Util::blessed($ident) && $ident->can('name') ? $ident->name : undef;
if ($value =~ $NUMBER->{$kind}) {
next unless $kind eq 'integer';
my $native = _integer_type($ident, $attrs);
next unless defined $native and _outside_range($value, $native);
$self->throw_exception(sprintf
'DBIO::ClickHouse: table %s, column %s: the value is refused, it is '
. 'outside the range of %s. ClickHouse accepts such a number and stores '
. 'NULL (a Nullable column) or a wrapped-around number (any other) '
. 'without an error. Nothing was sent',
(defined $table and not ref $table) ? $table : '(statement)',
$attrs->{dbic_colname},
$native,
);
}
$self->throw_exception(sprintf
'DBIO::ClickHouse: table %s, column %s: the value is refused, it is not '
. 'a%s number. ClickHouse accepts such a string for a %s column and stores '
. 'NULL without an error. Nothing was sent',
(defined $table and not ref $table) ? $table : '(statement)',
$attrs->{dbic_colname},
$kind eq 'integer' ? 'n integer' : '',
$attrs->{sqlt_datatype},
);
}
}
sub update {
my $self = shift;
$self->next::method(@_);
return -1;
}
sub delete {
my $self = shift;
$self->next::method(@_);
return -1;
}
sub _dbio_sql_maker_option_names {
my $self = shift;
return ($self->next::method(@_), 'mutations_sync');
}
sub _adjust_select_args_for_complex_prefetch {
my $self = shift;
my $outer_attrs = $self->next::method(@_);
delete @{$outer_attrs}{qw( final prewhere limit_by )};
return $outer_attrs;
}
# ADR 0039. This is the case ADR 0037 section 3 predicted and ADR 0039
# recorded as never having turned up -- a second engine that *spells* a set
# operation differently rather than lacking it. It is not one operation but
# three, and the reason is sharper than Oracle's MINUS: ClickHouse does not
# disagree about the word for an operation, it disagrees about what the word
# without a modifier means. A bare keyword there is resolved from a session
# setting -- union_default_mode ships empty (a bare UNION throws, changed to
# throw in 21.1), intersect_default_mode and except_default_mode ship 'ALL'
# (a bare INTERSECT/EXCEPT keeps duplicates). So core's ANSI spelling is a
# hard error for one operation and a silently different result set for two.
# Spelling all three explicitly is also what makes the statement immune to
# those settings.
my %SET_OPERATION_KEYWORD = (
union => 'UNION DISTINCT',
intersect => 'INTERSECT DISTINCT',
except => 'EXCEPT DISTINCT',
);
sub _set_operation_keyword {
my ($self, $op) = @_;
return $SET_OPERATION_KEYWORD{$op}
if defined $op and exists $SET_OPERATION_KEYWORD{$op};
# Everything this driver has no opinion about -- including an unknown $op,
# which is a core programming error and belongs to core's throw.
return $self->next::method($op);
}
# The value this returns is never seen by anyone: core drops the string into
# an order_by literal and nowhere else, so only the induced ORDER is
# observable and a uniform UInt32 orders as uniformly as randCanonical()'s
# Float64 would -- while working on every ClickHouse back to 1.1 instead of
( run in 0.801 second using v1.01-cache-2.11-cpan-145b269f2f3 )