ClickHouse/tests/queries/0_stateless/00746_sql_fuzzy.pl

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

153 lines
5.0 KiB
Perl
Raw Normal View History

#!/usr/bin/env perl
#
# Generate some random sql queries
#
package sqlfuzz;
use 5.16.0;
use strict;
use warnings;
no if $] >= 5.017011, warnings => 'experimental::smartmatch';
use Data::Dumper;
sub shuffle(@) { #@$deck = map{ splice @$deck, rand(@$deck), 1 } 0..$#$deck;
my $deck = shift;
$deck = [$deck, @_] unless ref $deck eq 'ARRAY';
my $i = @$deck;
while ($i--) {
my $j = int rand($i + 1);
@$deck[$i, $j] = @$deck[$j, $i];
}
return wantarray ? @$deck : $deck;
}
sub rand_pick ($) {
my ($arr) = @_;
return $arr->[rand(@$arr)];
}
sub rand_word {
my ($l) = shift || 8;
my $minl = 1;
@_ = ('a' .. 'z') unless @_;
join '', @_[map { rand @_ } $minl .. $minl + rand($l)];
}
sub rand_string {
my ($w) = shift || 5;
join ' ', map { rand_word((), @_) } 1 .. rand($w);
}
sub one ($$) {
my ($state, $value) = @_;
return ref $value ~~ 'CODE' ? $value->() : $value;
}
sub one_of ($$) {
my ($state, $hash) = @_;
#state $last_selected;
#my $last_n = $last_selected->{"$hash"};
my $value;
if ('ARRAY' ~~ ref $hash) {
$value = rand_pick $hash;
} else {
my $keys_array = [sort keys %$hash];
$value = $hash->{rand_pick $keys_array};
}
#$last_selected->{"$hash"} = !exists $last_selected->{"$hash"} ? 0 : $last_selected->{"$hash"} < @keys_array - 1 ? $last_selected->{"$hash"} + 1 : 0;
##warn join ' : ',$last_selected->{"$hash"}, $keys_array[$last_selected->{"$hash"}], $hash->{$keys_array[$last_selected->{"$hash"}]};
#my $value = $hash->{$keys_array[$last_selected->{"$hash"}]};
return one($state, $value);
}
sub list_of ($$@) {
my ($state, $opt) = (shift, shift);
my $max = ($opt->{min} // 1) + int rand($opt->{max} || 4);
my @ret;
while (@ret < $max) {
for my $hash (shuffle \@_) {
push @ret, one_of($state, $hash);
}
}
return join ', ', @ret;
}
sub file_read ($) {
open my $f, '<', $_[0] or return;
local $/ = undef;
my $ret = <$f>;
close $f;
return $ret;
}
our ($query, $query_select, $expression_cast, $expression, $type, $type_cast, $functions, $table_functions);
$type_cast = {map { $_ => $_ } qw(DateTime Date String)};
$type = {%$type_cast, (map { $_ => $_ } qw(Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64 Float32 Float64))};
$type->{"Nullable($_)"} = "Nullable($_)" for values %$type;
# AS, LIKE, NOT LIKE, IN, NOT IN, GLOBAL IN, GLOBAL NOT IN, BETWEEN, IS, ClosingRoundBracket, Comma, Dot, Arrow, QuestionMark, OR, AND
$expression_cast = {
'CAST' => sub { my ($state) = @_; '(CAST((' . one_of($state, $expression_cast) . ') AS ' . one_of($state, $type_cast) . '))' },
'SELECT' => sub {
my ($state) = @_;
list_of(
$state, {max => 2},
#[sub { '( ' . $query->{SELECT}->() . ' ) AS ' . rand_word() }, sub { '( ' . $query->{SELECT}->() . ' ) ' }]
[sub { '( ' . one_of($state, $query_select) . ' ) AS ' . rand_word() }, sub { '( ' . one_of($state, $query_select) . ' ) ' }]
);
},
'number' => sub { my ($state) = @_; return rand_pick(['', '-']) . rand_word(8, 0 .. 9) . rand_pick(['', '.' . rand_word(6, 0 .. 9)]) },
'string' => sub {
my ($state) = @_;
return q{'} . rand_word(8, map { $_ ~~ q{'} ? '\\' . $_ : $_ } map {chr} 32 .. 127) . q{'};
},
'[]' => '[]',
'[x]' => sub { my ($state) = @_; return '[' . one_of($state, $expression) . ']' },
'function()' =>
sub { my ($state) = @_; return one_of($state, $functions) . '(' . list_of($state, {min => 0, max => 3}, $expression) . ')' },
"'\\0'" => "'\\0'",
"''" => "''",
'NULL' => 'NULL',
};
$expression = {
%$expression_cast,
};
$query_select = {
'SELECT' => sub { my ($state) = @_; return 'SELECT ' . list_of($state, {max => 5}, $expression) },
'SELECT function()' => sub { my ($state) = @_; return 'SELECT ' . one($state, $expression->{'function()'}) },
'SELECT table_function()' => sub {
my ($state) = @_;
return 'SELECT * FROM ' . one_of($state, $table_functions) . '(' . list_of($state, {min => 0, max => 3}, $expression) . ')';
},
};
$query = {%$query_select};
sub main {
srand($ENV{SQL_FUZZY_SRAND} + $ENV{SQL_FUZZY_RUN}) if $ENV{SQL_FUZZY_SRAND};
# select name from system.functions format TSV;
$functions = [
split /[\s;,]+/,
$ENV{SQL_FUZZY_FUNCTIONS}
|| file_read($ENV{SQL_FUZZY_FILE_FUNCTIONS} || 'clickhouse-functions')
];
# $functions = [grep { not $_ ~~ [qw( )] } @$functions]; # will be removed
# select name from system.table_functions format TSV;
$table_functions = [
split /[\s;,]+/,
$ENV{SQL_FUZZY_TABLE_FUNCTIONS}
|| file_read($ENV{SQL_FUZZY_FILE_TABLE_FUNCTIONS} || 'clickhouse-table-functions')
];
$table_functions = [grep { not $_ ~~ [qw(numbers)] } @$table_functions]; # too slow
say one_of({}, $query), ';' for 1 .. ($ENV{SQL_FUZZY_LINES} || 100);
}
main() unless caller;
#say rand_word() for 1..10000;
#say rand_word(8, 0..9) for 1..1000;