dbms: fixed error with function positionCaseInsensitiveUTF8 [#METR-20054].

This commit is contained in:
Alexey Milovidov 2016-02-23 06:20:48 +03:00
parent 80fd8aa29b
commit 4c0b0e9c80
6 changed files with 391 additions and 138 deletions

View File

@ -26,10 +26,10 @@ inline bool isContinuationOctet(const UInt8 octet)
return (octet & CONTINUATION_OCTET_MASK) == CONTINUATION_OCTET;
}
/// moves `s` backward until either first non-continuation octet
inline void syncBackward(const UInt8 * & s)
/// moves `s` backward until either first non-continuation octet or begin
inline void syncBackward(const UInt8 * & s, const UInt8 * const begin)
{
while (isContinuationOctet(*s))
while (isContinuationOctet(*s) && s > begin)
--s;
}

View File

@ -56,6 +56,35 @@ protected:
static constexpr auto min_haystack_size_for_algorithm = 20000;
const bool fallback; /// Нужно ли использовать fallback алгоритм.
/// Эти функции эффективнее, чем соответствующие из libc, так как не учитывают локаль (что нам и надо).
bool isascii(char c)
{
return static_cast<unsigned char>(c) < 0x80;
}
bool isalpha(char c)
{
return (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z');
}
/// Работает корректно только при условии isalpha.
char tolower(char c)
{
return c | 0x20;
}
char toupper(char c)
{
return c & (~0x20);
}
char alternate(char c)
{
return c ^ 0x20;
}
public:
/** haystack_size_hint - ожидаемый суммарный размер haystack при вызовах search. Можно не указывать.
* Если указать его достаточно маленьким, то будет использован fallback алгоритм,
@ -64,9 +93,8 @@ public:
VolnitskyBase(const char * const needle, const size_t needle_size, size_t haystack_size_hint = 0)
: needle{reinterpret_cast<const UInt8 *>(needle)}, needle_size{needle_size},
fallback{
needle_size < 2 * sizeof(ngram_t) or needle_size >= std::numeric_limits<offset_t>::max() or
(haystack_size_hint and haystack_size_hint < min_haystack_size_for_algorithm)
}
needle_size < 2 * sizeof(ngram_t) || needle_size >= std::numeric_limits<offset_t>::max() ||
(haystack_size_hint && haystack_size_hint < min_haystack_size_for_algorithm)}
{
if (fallback)
return;
@ -75,7 +103,7 @@ public:
/// int is used here because unsigned can't be used with condition like `i >= 0`, unsigned always >= 0
for (auto i = static_cast<int>(needle_size - sizeof(ngram_t)); i >= 0; --i)
self().putNGram(this->needle + i, i + 1);
self().putNGram(this->needle + i, i + 1, this->needle);
}
@ -134,6 +162,54 @@ protected:
hash[cell_num] = offset;
}
void putNGramASCIICaseInsensitive(const UInt8 * const pos, const int offset)
{
union
{
ngram_t n;
struct Chars
{
UInt8 c0;
UInt8 c1;
} chars;
};
n = toNGram(pos);
const auto c0_al = isalpha(chars.c0);
const auto c1_al = isalpha(chars.c1);
if (c0_al && c1_al)
{
/// 4 combinations: AB, aB, Ab, ab
putNGramBase(n, offset);
chars.c0 = alternate(chars.c0);
putNGramBase(n, offset);
chars.c1 = alternate(chars.c1);
putNGramBase(n, offset);
chars.c0 = alternate(chars.c0);
putNGramBase(n, offset);
}
else if (c0_al)
{
/// 2 combinations: A1, a1
putNGramBase(n, offset);
chars.c0 = alternate(chars.c0);
putNGramBase(n, offset);
}
else if (c1_al)
{
/// 2 combinations: 0B, 0b
putNGramBase(n, offset);
chars.c1 = alternate(chars.c1);
putNGramBase(n, offset);
}
else
/// 1 combination: 01
putNGramBase(n, offset);
}
};
@ -148,7 +224,7 @@ template <bool ASCII> struct VolnitskyImpl<true, ASCII> : VolnitskyBase<Volnitsk
{
}
void putNGram(const UInt8 * const pos, const int offset)
void putNGram(const UInt8 * const pos, const int offset, const UInt8 * const begin)
{
this->putNGramBase(this->toNGram(pos), offset);
}
@ -175,54 +251,9 @@ template <> struct VolnitskyImpl<false, true> : VolnitskyBase<VolnitskyImpl<fals
{
}
void putNGram(const UInt8 * const pos, const int offset)
void putNGram(const UInt8 * const pos, const int offset, const UInt8 * const begin)
{
union {
ngram_t n;
UInt8 c[2];
};
n = toNGram(pos);
const auto c0_alpha = std::isalpha(c[0]);
const auto c1_alpha = std::isalpha(c[1]);
if (c0_alpha && c1_alpha)
{
/// 4 combinations: AB, aB, Ab, ab
c[0] = std::tolower(c[0]);
c[1] = std::tolower(c[1]);
putNGramBase(n, offset);
c[0] = std::toupper(c[0]);
putNGramBase(n, offset);
c[1] = std::toupper(c[1]);
putNGramBase(n, offset);
c[0] = std::tolower(c[0]);
putNGramBase(n, offset);
}
else if (c0_alpha)
{
/// 2 combinations: A1, a1
c[0] = std::tolower(c[0]);
putNGramBase(n, offset);
c[0] = std::toupper(c[0]);
putNGramBase(n, offset);
}
else if (c1_alpha)
{
/// 2 combinations: 0B, 0b
c[1] = std::tolower(c[1]);
putNGramBase(n, offset);
c[1] = std::toupper(c[1]);
putNGramBase(n, offset);
}
else
/// 1 combination: 01
putNGramBase(n, offset);
putNGramASCIICaseInsensitive(pos, offset);
}
bool compare(const UInt8 * const pos) const
@ -246,70 +277,47 @@ template <> struct VolnitskyImpl<false, false> : VolnitskyBase<VolnitskyImpl<fal
{
}
void putNGram(const UInt8 * const pos, const int offset)
void putNGram(const UInt8 * const pos, const int offset, const UInt8 * const begin)
{
union
{
ngram_t n;
UInt8 c[2];
struct Chars
{
UInt8 c0;
UInt8 c1;
} chars;
};
n = toNGram(pos);
if (isascii(c[0]) && isascii(c[1]))
if (isascii(chars.c0) && isascii(chars.c1))
{
const auto c0_al = std::isalpha(c[0]);
const auto c1_al = std::isalpha(c[1]);
if (c0_al && c1_al)
{
/// 4 combinations: AB, aB, Ab, ab
c[0] = std::tolower(c[0]);
c[1] = std::tolower(c[1]);
putNGramBase(n, offset);
c[0] = std::toupper(c[0]);
putNGramBase(n, offset);
c[1] = std::toupper(c[1]);
putNGramBase(n, offset);
c[0] = std::tolower(c[0]);
putNGramBase(n, offset);
}
else if (c0_al)
{
/// 2 combinations: A1, a1
c[0] = std::tolower(c[0]);
putNGramBase(n, offset);
c[0] = std::toupper(c[0]);
putNGramBase(n, offset);
}
else if (c1_al)
{
/// 2 combinations: 0B, 0b
c[1] = std::tolower(c[1]);
putNGramBase(n, offset);
c[1] = std::toupper(c[1]);
putNGramBase(n, offset);
}
else
/// 1 combination: 01
putNGramBase(n, offset);
putNGramASCIICaseInsensitive(pos, offset);
}
else
{
/** n-грам (в случае n = 2)
* может быть целиком расположен внутри одной кодовой точки,
* либо пересекаться с двумя кодовыми точками.
*
* В первом случае, нужно рассматривать до двух альтернатив - эта кодовая точка в верхнем и нижнем регистре,
* а во втором случае - до четырёх альтернатив - фрагменты двух кодовых точек во всех комбинациях регистров.
*
* При этом не учитывается зависимость перевода между регистрами от локали (пример - турецкие Ii)
* а также композиция/декомпозиция и другие особенности.
*/
using Seq = UInt8[6];
static const Poco::UTF8Encoding utf8;
if (UTF8::isContinuationOctet(c[1]))
if (UTF8::isContinuationOctet(chars.c1))
{
/// ngram is inside a sequence
auto seq_pos = pos;
UTF8::syncBackward(seq_pos);
UTF8::syncBackward(seq_pos, begin);
const auto u32 = utf8.convert(seq_pos);
const auto l_u32 = Poco::Unicode::toLower(u32);
@ -327,14 +335,14 @@ template <> struct VolnitskyImpl<false, false> : VolnitskyBase<VolnitskyImpl<fal
/// put ngram from lowercase
utf8.convert(l_u32, seq, sizeof(seq));
c[0] = seq[seq_ngram_offset];
c[1] = seq[seq_ngram_offset + 1];
chars.c0 = seq[seq_ngram_offset];
chars.c1 = seq[seq_ngram_offset + 1];
putNGramBase(n, offset);
/// put ngram for uppercase
utf8.convert(u_u32, seq, sizeof(seq));
c[0] = seq[seq_ngram_offset];
c[1] = seq[seq_ngram_offset + 1];
chars.c0 = seq[seq_ngram_offset];
chars.c1 = seq[seq_ngram_offset + 1];
putNGramBase(n, offset);
}
}
@ -343,7 +351,9 @@ template <> struct VolnitskyImpl<false, false> : VolnitskyBase<VolnitskyImpl<fal
/// ngram is on the boundary of two sequences
/// first sequence may start before u_pos if it is not ASCII
auto first_seq_pos = pos;
UTF8::syncBackward(first_seq_pos);
UTF8::syncBackward(first_seq_pos, begin);
/// where is the given ngram in respect to the first UTF-8 sequence start?
const auto seq_ngram_offset = pos - first_seq_pos;
const auto first_u32 = utf8.convert(first_seq_pos);
const auto first_l_u32 = Poco::Unicode::toLower(first_u32);
@ -352,13 +362,15 @@ template <> struct VolnitskyImpl<false, false> : VolnitskyBase<VolnitskyImpl<fal
/// second sequence always start immediately after u_pos
auto second_seq_pos = pos + 1;
const auto second_u32 = utf8.convert(second_seq_pos);
const auto second_u32 = utf8.convert(second_seq_pos); /// TODO This assumes valid UTF-8 or zero byte after needle.
const auto second_l_u32 = Poco::Unicode::toLower(second_u32);
const auto second_u_u32 = Poco::Unicode::toUpper(second_u32);
/// both symbols are case-independent
if (first_l_u32 == first_u_u32 && second_l_u32 == second_u_u32)
{
putNGramBase(n, offset);
}
else if (first_l_u32 == first_u_u32)
{
/// first symbol is case-independent
@ -366,64 +378,80 @@ template <> struct VolnitskyImpl<false, false> : VolnitskyBase<VolnitskyImpl<fal
/// put ngram for lowercase
utf8.convert(second_l_u32, seq, sizeof(seq));
c[1] = seq[0];
chars.c1 = seq[0];
putNGramBase(n, offset);
/// put ngram from uppercase
/// put ngram from uppercase, if it is different
utf8.convert(second_u_u32, seq, sizeof(seq));
c[1] = seq[0];
putNGramBase(n, offset);
if (chars.c1 != seq[0])
{
chars.c1 = seq[0];
putNGramBase(n, offset);
}
}
else if (second_l_u32 == second_u_u32)
{
/// second symbol is case-independent
/// where is the given ngram in respect to the first UTF-8 sequence start?
const auto seq_ngram_offset = pos - first_seq_pos;
Seq seq;
/// put ngram for lowercase
utf8.convert(second_l_u32, seq, sizeof(seq));
c[0] = seq[seq_ngram_offset];
utf8.convert(first_l_u32, seq, sizeof(seq));
chars.c0 = seq[seq_ngram_offset];
putNGramBase(n, offset);
/// put ngram for uppercase
utf8.convert(second_u_u32, seq, sizeof(seq));
c[0] = seq[seq_ngram_offset];
putNGramBase(n, offset);
/// put ngram for uppercase, if it is different
utf8.convert(first_u_u32, seq, sizeof(seq));
if (chars.c0 != seq[seq_ngram_offset])
{
chars.c0 = seq[seq_ngram_offset];
putNGramBase(n, offset);
}
}
else
{
/// where is the given ngram in respect to the first UTF-8 sequence start?
const auto seq_ngram_offset = pos - first_seq_pos;
Seq first_l_seq, first_u_seq, second_l_seq, second_u_seq;
Seq first_l_seq;
Seq first_u_seq;
Seq second_l_seq;
Seq second_u_seq;
utf8.convert(first_l_u32, first_l_seq, sizeof(first_l_seq));
utf8.convert(first_u_u32, first_u_seq, sizeof(first_u_seq));
utf8.convert(second_l_u32, second_l_seq, sizeof(second_l_seq));
utf8.convert(second_u_u32, second_u_seq, sizeof(second_u_seq));
auto c0l = first_l_seq[seq_ngram_offset];
auto c0u = first_u_seq[seq_ngram_offset];
auto c1l = second_l_seq[0];
auto c1u = second_u_seq[0];
/// ngram for ll
c[0] = first_l_seq[seq_ngram_offset];
c[1] = second_l_seq[0];
chars.c0 = c0l;
chars.c1 = c1l;
putNGramBase(n, offset);
/// ngram for lU
c[0] = first_l_seq[seq_ngram_offset];
c[1] = second_u_seq[0];
putNGramBase(n, offset);
if (c0l != c0u)
{
/// ngram for Ul
chars.c0 = c0u;
chars.c1 = c1l;
putNGramBase(n, offset);
}
/// ngram for Ul
c[0] = first_u_seq[seq_ngram_offset];
c[1] = second_l_seq[0];
putNGramBase(n, offset);
if (c1l != c1u)
{
/// ngram for lU
chars.c0 = c0l;
chars.c1 = c1u;
putNGramBase(n, offset);
}
/// ngram for UU
c[0] = first_u_seq[seq_ngram_offset];
c[1] = second_u_seq[0];
putNGramBase(n, offset);
if (c0l != c0u && c1l != c1u)
{
/// ngram for UU
chars.c0 = c0u;
chars.c1 = c1u;
putNGramBase(n, offset);
}
}
}
}

View File

@ -251,6 +251,43 @@ public:
};
class FunctionRowNumberInBlock : public IFunction
{
public:
static constexpr auto name = "rowNumberInBlock";
static IFunction * create(const Context & context) { return new FunctionRowNumberInBlock; }
/// Получить имя функции.
String getName() const override
{
return name;
}
/// Получить тип результата по типам аргументов. Если функция неприменима для данных аргументов - кинуть исключение.
DataTypePtr getReturnType(const DataTypes & arguments) const override
{
if (!arguments.empty())
throw Exception("Number of arguments for function " + getName() + " doesn't match: passed "
+ toString(arguments.size()) + ", should be 0.",
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
return new DataTypeUInt64;
}
/// Выполнить функцию над блоком.
void execute(Block & block, const ColumnNumbers & arguments, size_t result) override
{
size_t size = block.rowsInFirstColumn();
auto column = new ColumnUInt64;
block.getByPosition(result).column = column;
auto & data = column->getData();
data.resize(size);
for (size_t i = 0; i < size; ++i)
data[i] = i;
}
};
class FunctionSleep : public IFunction
{
public:

View File

@ -380,6 +380,7 @@ void registerFunctionsMiscellaneous(FunctionFactory & factory)
factory.registerFunction<FunctionVisibleWidth>();
factory.registerFunction<FunctionToTypeName>();
factory.registerFunction<FunctionBlockSize>();
factory.registerFunction<FunctionRowNumberInBlock>();
factory.registerFunction<FunctionSleep>();
factory.registerFunction<FunctionMaterialize>();
factory.registerFunction<FunctionIgnore>();

View File

@ -0,0 +1,92 @@
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

View File

@ -0,0 +1,95 @@
SELECT positionCaseInsensitiveUTF8(concat('иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitiveUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat('иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionCaseInsensitive(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat('иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT positionUTF8(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat('иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;
SELECT position(concat(' иголка.ру', arrayStringConcat(arrayMap(x -> ' ', range(20000)))), 'иголка.ру') AS res;