aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Functions/randomString.cpp
blob: 4afd0799d29e1ec939d1f4ea67b7e8db5959a608 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <Columns/ColumnString.h>
#include <DataTypes/DataTypeString.h>
#include <Functions/FunctionFactory.h>
#include <Functions/FunctionHelpers.h>
#include <Functions/IFunction.h>
#include <Functions/FunctionsRandom.h>
#include <Functions/PerformanceAdaptors.h>
#include <pcg_random.hpp>
#include <Common/randomSeed.h>
#include <base/unaligned.h>


namespace DB
{
namespace ErrorCodes
{
    extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
    extern const int ILLEGAL_TYPE_OF_ARGUMENT;
    extern const int TOO_LARGE_STRING_SIZE;
}

namespace
{

/* Generate random string of specified length with fully random bytes (including zero). */
template <typename RandImpl>
class FunctionRandomStringImpl : public IFunction
{
public:
    static constexpr auto name = "randomString";

    String getName() const override { return name; }

    bool isVariadic() const override { return true; }

    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }

    size_t getNumberOfArguments() const override { return 0; }

    DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
    {
        if (arguments.empty())
            throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
                "Function {} requires at least one argument: the size of resulting string", getName());

        if (arguments.size() > 2)
            throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
                "Function {} requires at most two arguments: the size of resulting string and optional disambiguation tag", getName());

        const IDataType & length_type = *arguments[0];
        if (!isNumber(length_type))
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "First argument of function {} must have numeric type", getName());

        return std::make_shared<DataTypeString>();
    }

    bool isDeterministic() const override { return false; }
    bool isDeterministicInScopeOfQuery() const override { return false; }

    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
    {
        auto col_to = ColumnString::create();
        ColumnString::Chars & data_to = col_to->getChars();
        ColumnString::Offsets & offsets_to = col_to->getOffsets();

        if (input_rows_count == 0)
            return col_to;

        /// Fill offsets.
        offsets_to.resize(input_rows_count);
        const IColumn & length_column = *arguments[0].column;

        IColumn::Offset offset = 0;
        for (size_t row_num = 0; row_num < input_rows_count; ++row_num)
        {
            size_t length = length_column.getUInt(row_num);
            if (length > (1 << 30))
                throw Exception(ErrorCodes::TOO_LARGE_STRING_SIZE, "Too large string size in function {}", getName());

            offset += length + 1;
            offsets_to[row_num] = offset;
        }

        /// Fill random bytes.
        data_to.resize(offsets_to.back());
        RandImpl::execute(reinterpret_cast<char *>(data_to.data()), data_to.size());

        /// Put zero bytes in between.
        auto * pos = data_to.data();
        for (size_t row_num = 0; row_num < input_rows_count; ++row_num)
            pos[offsets_to[row_num] - 1] = 0;

        return col_to;
    }
};

class FunctionRandomString : public FunctionRandomStringImpl<TargetSpecific::Default::RandImpl>
{
public:
    explicit FunctionRandomString(ContextPtr context) : selector(context)
    {
        selector.registerImplementation<TargetArch::Default,
            FunctionRandomStringImpl<TargetSpecific::Default::RandImpl>>();

    #if USE_MULTITARGET_CODE
        selector.registerImplementation<TargetArch::AVX2,
            FunctionRandomStringImpl<TargetSpecific::AVX2::RandImpl>>();
    #endif
    }

    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
    {
        return selector.selectAndExecute(arguments, result_type, input_rows_count);
    }

    static FunctionPtr create(ContextPtr context)
    {
        return std::make_shared<FunctionRandomString>(context);
    }

private:
    ImplementationSelector<IFunction> selector;
};

}

REGISTER_FUNCTION(RandomString)
{
    factory.registerFunction<FunctionRandomString>();
}

}