ClickHouse
392 строки · 18.0 Кб
1#include <DataTypes/DataTypeFactory.h>2#include <DataTypes/DataTypeNullable.h>3#include <DataTypes/DataTypeString.h>4#include <DataTypes/DataTypesNumber.h>5#include <DataTypes/DataTypesDecimal.h>6#include <DataTypes/DataTypeDate.h>7#include <DataTypes/DataTypeDate32.h>8#include <DataTypes/DataTypeDateTime.h>9#include <DataTypes/DataTypeDateTime64.h>10#include <DataTypes/DataTypeUUID.h>11#include <DataTypes/DataTypeIPv4andIPv6.h>12#include <Columns/ColumnString.h>13#include <Columns/ColumnConst.h>14#include <Columns/ColumnNullable.h>15
16#include <Interpreters/Context.h>17#include <Interpreters/castColumn.h>18
19#include <Functions/IFunction.h>20#include <Functions/FunctionHelpers.h>21#include <Functions/FunctionFactory.h>22#include <Functions/extractTimeZoneFromFunctionArguments.h>23
24namespace DB25{
26
27namespace ErrorCodes28{
29extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;30extern const int BAD_ARGUMENTS;31extern const int ILLEGAL_TYPE_OF_ARGUMENT;32}
33
34class FunctionCastOrDefault final : public IFunction35{
36public:37static constexpr auto name = "accurateCastOrDefault";38
39static FunctionPtr create(ContextPtr context)40{41return std::make_shared<FunctionCastOrDefault>(context);42}43
44explicit FunctionCastOrDefault(ContextPtr context_)45: keep_nullable(context_->getSettingsRef().cast_keep_nullable)46{47}48
49String getName() const override { return name; }50
51size_t getNumberOfArguments() const override { return 0; }52bool isVariadic() const override { return true; }53ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }54
55bool useDefaultImplementationForNulls() const override { return false; }56bool useDefaultImplementationForNothing() const override { return false; }57bool useDefaultImplementationForConstants() const override { return false; }58bool useDefaultImplementationForLowCardinalityColumns() const override { return true; }59bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }60
61DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override62{63size_t arguments_size = arguments.size();64if (arguments_size != 2 && arguments_size != 3)65throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,66"Function {} expected 2 or 3 arguments. Actual {}",67getName(),68arguments_size);69
70const auto & type_column = arguments[1].column;71const auto * type_column_typed = checkAndGetColumnConst<ColumnString>(type_column.get());72
73if (!type_column_typed)74throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,75"Second argument to {} must be a constant string describing type. Actual {}",76getName(),77arguments[1].type->getName());78
79DataTypePtr result_type = DataTypeFactory::instance().get(type_column_typed->getValue<String>());80
81if (keep_nullable && arguments.front().type->isNullable())82result_type = makeNullable(result_type);83
84if (arguments.size() == 3)85{86auto default_value_type = arguments[2].type;87
88if (!result_type->equals(*default_value_type))89{90throw Exception(ErrorCodes::BAD_ARGUMENTS,91"Default value type should be same as cast type. Expected {}. Actual {}",92result_type->getName(),93default_value_type->getName());94}95}96
97return result_type;98}99
100ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & return_type, size_t) const override101{102const ColumnWithTypeAndName & column_to_cast = arguments[0];103auto non_const_column_to_cast = column_to_cast.column->convertToFullColumnIfConst();104ColumnWithTypeAndName column_to_cast_non_const { non_const_column_to_cast, column_to_cast.type, column_to_cast.name };105
106auto cast_result = castColumnAccurateOrNull(column_to_cast_non_const, return_type);107
108const auto & cast_result_nullable = assert_cast<const ColumnNullable &>(*cast_result);109const auto & null_map_data = cast_result_nullable.getNullMapData();110size_t null_map_data_size = null_map_data.size();111const auto & nested_column = cast_result_nullable.getNestedColumn();112auto result = return_type->createColumn();113result->reserve(null_map_data_size);114
115ColumnNullable * result_nullable = nullptr;116if (result->isNullable())117result_nullable = assert_cast<ColumnNullable *>(&*result);118
119size_t start_insert_index = 0;120
121Field default_value;122ColumnPtr default_column;123
124if (arguments.size() == 3)125{126auto default_values_column = arguments[2].column;127
128if (isColumnConst(*default_values_column))129default_value = (*default_values_column)[0];130else131default_column = default_values_column->convertToFullColumnIfConst();132}133else134{135default_value = return_type->getDefault();136}137
138for (size_t i = 0; i < null_map_data_size; ++i)139{140bool is_current_index_null = null_map_data[i];141if (!is_current_index_null)142continue;143
144if (i != start_insert_index)145{146if (result_nullable)147result_nullable->insertRangeFromNotNullable(nested_column, start_insert_index, i - start_insert_index);148else149result->insertRangeFrom(nested_column, start_insert_index, i - start_insert_index);150}151
152if (default_column)153result->insertFrom(*default_column, i);154else155result->insert(default_value);156
157start_insert_index = i + 1;158}159
160if (null_map_data_size != start_insert_index)161{162if (result_nullable)163result_nullable->insertRangeFromNotNullable(nested_column, start_insert_index, null_map_data_size - start_insert_index);164else165result->insertRangeFrom(nested_column, start_insert_index, null_map_data_size - start_insert_index);166}167
168return result;169}170
171private:172
173bool keep_nullable;174};175
176class FunctionCastOrDefaultTyped final : public IFunction177{
178public:179explicit FunctionCastOrDefaultTyped(ContextPtr context_, String name_, DataTypePtr type_)180: impl(context_), name(std::move(name_)), type(std::move(type_)), which(type)181{182}183
184String getName() const override { return name; }185
186private:187FunctionCastOrDefault impl;188String name;189DataTypePtr type;190WhichDataType which;191
192size_t getNumberOfArguments() const override { return 0; }193bool isVariadic() const override { return true; }194
195bool useDefaultImplementationForNulls() const override { return impl.useDefaultImplementationForNulls(); }196bool useDefaultImplementationForNothing() const override { return impl.useDefaultImplementationForNothing(); }197bool useDefaultImplementationForLowCardinalityColumns() const override { return impl.useDefaultImplementationForLowCardinalityColumns();}198bool useDefaultImplementationForConstants() const override { return impl.useDefaultImplementationForConstants();}199bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & arguments) const override200{201return impl.isSuitableForShortCircuitArgumentsExecution(arguments);202}203
204DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override205{206FunctionArgumentDescriptors mandatory_args = {{"Value", nullptr, nullptr, nullptr}};207FunctionArgumentDescriptors optional_args;208
209if (isDecimal(type) || isDateTime64(type))210mandatory_args.push_back({"scale", static_cast<FunctionArgumentDescriptor::TypeValidator>(&isNativeInteger), &isColumnConst, "const Integer"});211
212if (isDateTimeOrDateTime64(type))213optional_args.push_back({"timezone", static_cast<FunctionArgumentDescriptor::TypeValidator>(&isString), isColumnConst, "const String"});214
215optional_args.push_back({"default_value", nullptr, nullptr, nullptr});216
217validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);218
219size_t additional_argument_index = 1;220
221size_t scale = 0;222std::string time_zone;223
224if (isDecimal(type) || isDateTime64(type))225{226const auto & scale_argument = arguments[additional_argument_index];227
228WhichDataType scale_argument_type(scale_argument.type);229
230if (!scale_argument_type.isNativeUInt())231{232throw Exception(ErrorCodes::BAD_ARGUMENTS,233"Function {} decimal scale should have native UInt type. Actual {}",234getName(), scale_argument.type->getName());235}236
237scale = arguments[additional_argument_index].column->getUInt(0);238++additional_argument_index;239}240
241if (isDateTimeOrDateTime64(type))242{243if (additional_argument_index < arguments.size())244{245time_zone = extractTimeZoneNameFromColumn(arguments[additional_argument_index].column.get(),246arguments[additional_argument_index].name);247++additional_argument_index;248}249}250
251DataTypePtr cast_type;252
253if (which.isDateTime64())254cast_type = std::make_shared<DataTypeDateTime64>(scale, time_zone);255else if (which.isDateTime())256cast_type = std::make_shared<DataTypeDateTime>(time_zone);257else if (which.isDecimal32())258cast_type = createDecimalMaxPrecision<Decimal32>(scale);259else if (which.isDecimal64())260cast_type = createDecimalMaxPrecision<Decimal64>(scale);261else if (which.isDecimal128())262cast_type = createDecimalMaxPrecision<Decimal128>(scale);263else if (which.isDecimal256())264cast_type = createDecimalMaxPrecision<Decimal256>(scale);265else266cast_type = type;267
268ColumnWithTypeAndName type_argument =269{270DataTypeString().createColumnConst(1, cast_type->getName()),271std::make_shared<DataTypeString>(),272""273};274
275ColumnsWithTypeAndName arguments_with_cast_type;276arguments_with_cast_type.reserve(arguments.size());277
278arguments_with_cast_type.emplace_back(arguments[0]);279arguments_with_cast_type.emplace_back(type_argument);280
281if (additional_argument_index < arguments.size())282{283arguments_with_cast_type.emplace_back(arguments[additional_argument_index]);284++additional_argument_index;285}286
287if (additional_argument_index < arguments.size())288throw Exception(ErrorCodes::BAD_ARGUMENTS, "{} wrong arguments size", getName());289
290return impl.getReturnTypeImpl(arguments_with_cast_type);291}292
293ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_size) const override294{295/// Scale and time zone296size_t additional_arguments_size = (which.isDecimal() || which.isDateTime64()) + which.isDateTimeOrDateTime64();297
298ColumnWithTypeAndName second_argument =299{300DataTypeString().createColumnConst(arguments.begin()->column->size(), result_type->getName()),301std::make_shared<DataTypeString>(),302""303};304
305ColumnsWithTypeAndName arguments_with_cast_type;306arguments_with_cast_type.reserve(arguments.size() + 1);307
308arguments_with_cast_type.emplace_back(arguments[0]);309arguments_with_cast_type.emplace_back(second_argument);310
311size_t default_column_argument = 1 + additional_arguments_size;312if (default_column_argument < arguments.size())313arguments_with_cast_type.emplace_back(arguments[default_column_argument]);314
315return impl.executeImpl(arguments_with_cast_type, result_type, input_rows_size);316}317};318
319REGISTER_FUNCTION(CastOrDefault)320{
321factory.registerFunction<FunctionCastOrDefault>();322
323factory.registerFunction("toUInt8OrDefault", [](ContextPtr context)324{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toUInt8OrDefault", std::make_shared<DataTypeUInt8>()); });325factory.registerFunction("toUInt16OrDefault", [](ContextPtr context)326{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toUInt16OrDefault", std::make_shared<DataTypeUInt16>()); });327factory.registerFunction("toUInt32OrDefault", [](ContextPtr context)328{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toUInt32OrDefault", std::make_shared<DataTypeUInt32>()); });329factory.registerFunction("toUInt64OrDefault", [](ContextPtr context)330{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toUInt64OrDefault", std::make_shared<DataTypeUInt64>()); });331factory.registerFunction("toUInt128OrDefault", [](ContextPtr context)332{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toUInt128OrDefault", std::make_shared<DataTypeUInt128>()); },333FunctionDocumentation{334.description=R"(335Converts a string in the first argument of the function to UInt128 by parsing it.
336If it cannot parse the value, returns the default value, which can be provided as the second function argument, and if provided, must be of UInt128 type.
337If the default value is not provided in the second argument, it is assumed to be zero.
338)",339.examples{340{"Successful conversion", "SELECT toUInt128OrDefault('1', 2::UInt128)", "1"},341{"Default value", "SELECT toUInt128OrDefault('upyachka', 123456789012345678901234567890::UInt128)", "123456789012345678901234567890"},342{"Implicit default value", "SELECT toUInt128OrDefault('upyachka')", "0"}},343.categories{"ConversionFunctions"}344});345factory.registerFunction("toUInt256OrDefault", [](ContextPtr context)346{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toUInt256OrDefault", std::make_shared<DataTypeUInt256>()); });347
348factory.registerFunction("toInt8OrDefault", [](ContextPtr context)349{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toInt8OrDefault", std::make_shared<DataTypeInt8>()); });350factory.registerFunction("toInt16OrDefault", [](ContextPtr context)351{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toInt16OrDefault", std::make_shared<DataTypeInt16>()); });352factory.registerFunction("toInt32OrDefault", [](ContextPtr context)353{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toInt32OrDefault", std::make_shared<DataTypeInt32>()); });354factory.registerFunction("toInt64OrDefault", [](ContextPtr context)355{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toInt64OrDefault", std::make_shared<DataTypeInt64>()); });356factory.registerFunction("toInt128OrDefault", [](ContextPtr context)357{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toInt128OrDefault", std::make_shared<DataTypeInt128>()); });358factory.registerFunction("toInt256OrDefault", [](ContextPtr context)359{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toInt256OrDefault", std::make_shared<DataTypeInt256>()); });360
361factory.registerFunction("toFloat32OrDefault", [](ContextPtr context)362{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toFloat32OrDefault", std::make_shared<DataTypeFloat32>()); });363factory.registerFunction("toFloat64OrDefault", [](ContextPtr context)364{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toFloat64OrDefault", std::make_shared<DataTypeFloat64>()); });365
366factory.registerFunction("toDateOrDefault", [](ContextPtr context)367{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toDateOrDefault", std::make_shared<DataTypeDate>()); });368factory.registerFunction("toDate32OrDefault", [](ContextPtr context)369{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toDate32OrDefault", std::make_shared<DataTypeDate32>()); });370factory.registerFunction("toDateTimeOrDefault", [](ContextPtr context)371{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toDateTimeOrDefault", std::make_shared<DataTypeDateTime>()); });372factory.registerFunction("toDateTime64OrDefault", [](ContextPtr context)373{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toDateTime64OrDefault", std::make_shared<DataTypeDateTime64>(3 /* default scale */)); });374
375factory.registerFunction("toDecimal32OrDefault", [](ContextPtr context)376{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toDecimal32OrDefault", createDecimalMaxPrecision<Decimal32>(0)); });377factory.registerFunction("toDecimal64OrDefault", [](ContextPtr context)378{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toDecimal64OrDefault", createDecimalMaxPrecision<Decimal64>(0)); });379factory.registerFunction("toDecimal128OrDefault", [](ContextPtr context)380{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toDecimal128OrDefault", createDecimalMaxPrecision<Decimal128>(0)); });381factory.registerFunction("toDecimal256OrDefault", [](ContextPtr context)382{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toDecimal256OrDefault", createDecimalMaxPrecision<Decimal256>(0)); });383
384factory.registerFunction("toUUIDOrDefault", [](ContextPtr context)385{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toUUIDOrDefault", std::make_shared<DataTypeUUID>()); });386factory.registerFunction("toIPv4OrDefault", [](ContextPtr context)387{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toIPv4OrDefault", std::make_shared<DataTypeIPv4>()); });388factory.registerFunction("toIPv6OrDefault", [](ContextPtr context)389{ return std::make_shared<FunctionCastOrDefaultTyped>(context, "toIPv6OrDefault", std::make_shared<DataTypeIPv6>()); });390}
391
392}
393