For example Null can be represented as empty string

```sql
select arrayStringConcat(['x',Null], ';');

┌─arrayStringConcat(['x', Null], ';')─┐
│ x;                                  │
└─────────────────────────────────────┘
```

But mostly it for avoiding a cast in case of Nullable Strings
```
SELECT arrayStringConcat(col0, ';')
FROM
(
    SELECT [toNullable('x')] AS col0
) AS t
```

Also I think arrayStringConcat can support any types not only Strings, it allows to avoid explicit casts.

```
SELECT arrayStringConcat(col0, ';')
FROM
(
    SELECT [1, 2, 3] AS col0
) AS t
```
else
        {
            const ColumnArray & col_arr = assert_cast<const ColumnArray &>(*arguments[0].column);
            auto col_res = ColumnString::create();
            if (WhichDataType(col_arr.getData().getDataType()).isString())
            {
                const ColumnString & col_string = assert_cast<const ColumnString &>(col_arr.getData());
                executeInternal(col_string, col_arr, delimiter, *col_res);
            }
            else
            {
                const ColumnNullable & col_nullable = assert_cast<const ColumnNullable &>(col_arr.getData());
                if (const ColumnString * col_string = typeid_cast<const ColumnString *>(col_nullable.getNestedColumnPtr().get()))
                    executeInternal(*col_string, col_arr, delimiter, *col_res, col_nullable.getNullMapData().data());
                else
                    col_res->insertManyDefaults(col_arr.size());
            }
            return col_res;
        }
    }
};
using FunctionAlphaTokens = FunctionTokens<AlphaTokensImpl>;
using FunctionSplitByNonAlpha = FunctionTokens<SplitByNonAlphaImpl>;
using FunctionSplitByWhitespace = FunctionTokens<SplitByWhitespaceImpl>;
using FunctionSplitByChar = FunctionTokens<SplitByCharImpl>;
using FunctionSplitByString = FunctionTokens<SplitByStringImpl>;
using FunctionSplitByRegexp = FunctionTokens<SplitByRegexpImpl>;
using FunctionExtractAll = FunctionTokens<ExtractAllImpl>;
}