#include #include #include #include #include #include #include #include #include #include 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 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(); } 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(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 { public: explicit FunctionRandomString(ContextPtr context) : selector(context) { selector.registerImplementation>(); #if USE_MULTITARGET_CODE selector.registerImplementation>(); #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(context); } private: ImplementationSelector selector; }; } REGISTER_FUNCTION(RandomString) { factory.registerFunction(); } }