**Use case**

I want to estimate better parameters for fulltext (`ngrambf_v1`) index.

**Describe the solution you'd like**

Implement it as SQL function:

`ngrams(string, N)`

that returns array of FixedString.

**Describe alternatives you've considered**

It can be done with less efficient and more cumbersome way:

```
WITH 3 AS n, extractAll(text, '.') AS chars 
SELECT 
  arrayMap(x -> arrayStringConcat(x), 
    arrayFilter(x -> length(x) = n, 
      arrayMap(x, i -> arraySlice(chars, i, n), 
        chars, arrayEnumerate(chars)))) AS ngrams
```

**Additional context**

`ngramsUTF8` can also be implemented to extract ngrams of Unicode code points.
<< "\n\t=> \"" << param.source.substr(token_start, token_len) << "\""
            << "\n\t" << token_start << ", " << token_len << ", " << pos << ", " << data->size();
}
INSTANTIATE_TEST_SUITE_P(NoTokens,
    SplitTokenExtractorTest,
    ::testing::ValuesIn(std::initializer_list<SplitTokenExtractorTestCase>{
        {
            "Empty input sequence produces no tokens.",
            "",
            {}
        },
        {
            "Whitespace only",
            " ",
            {}
        },
        {
            "Whitespace only large string",
            " \t\v\n\r \t\v\n\r \t\v\n\r \t\v\n\r \t\v\n\r \t\v\n\r \t\v\n\r \t\v\n\r \t\v\n\r \t\v\n\r",
            {}
        }
    })
);
INSTANTIATE_TEST_SUITE_P(ShortSingleToken,
    SplitTokenExtractorTest,
    ::testing::ValuesIn(std::initializer_list<SplitTokenExtractorTestCase>{
        {
            "Short single token",
            "foo",
            {"foo"}