diff --git a/src/Functions/fromReadable.h b/src/Functions/fromReadable.h
index 74c4a8958df..86d64dfa04b 100644
--- a/src/Functions/fromReadable.h
+++ b/src/Functions/fromReadable.h
@@ -1,12 +1,15 @@
#include
#include
+#include
#include
#include
#include
#include
#include
#include
+#include "Common/Exception.h"
+#include "DataTypes/DataTypeNullable.h"
#include
namespace DB
@@ -18,13 +21,20 @@ namespace ErrorCodes
extern const int CANNOT_PARSE_INPUT_ASSERTION_FAILED;
}
-template
+enum class ErrorHandling : uint8_t
+{
+ Exception,
+ Zero,
+ Null
+};
+
+template
class FunctionFromReadable : public IFunction
{
public:
static constexpr auto name = Impl::name;
- static FunctionPtr create(ContextPtr) { return std::make_shared>(); }
+ static FunctionPtr create(ContextPtr) { return std::make_shared>(); }
String getName() const override { return name; }
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return true; }
@@ -38,52 +48,77 @@ public:
{"readable_size", static_cast(&isString), nullptr, "String"},
};
validateFunctionArgumentTypes(*this, arguments, args);
-
- return std::make_shared();
+ DataTypePtr return_type = std::make_shared();
+ if (error_handling == ErrorHandling::Null) {
+ return std::make_shared(return_type);
+ } else {
+ return return_type;
+ }
+
}
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override
{
- auto col_to = ColumnFloat64::create();
- auto & res_data = col_to->getData();
+ auto col_res = ColumnFloat64::create();
+ auto & res_data = col_res->getData();
+
+ ColumnUInt8::MutablePtr col_null_map;
+ if constexpr (error_handling == ErrorHandling::Null)
+ col_null_map = ColumnUInt8::create(input_rows_count, 0);
for (size_t i = 0; i < input_rows_count; ++i)
{
std::string_view str = arguments[0].column->getDataAt(i).toView();
- ReadBufferFromString buf(str);
- // tryReadFloatText does seem to not raise any error when there is leading whitespace so we check it explicitly
- skipWhitespaceIfAny(buf);
- if (buf.getPosition() > 0)
- throw_exception(ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED, "Leading whitespace is not allowed", str);
-
- Float64 base = 0;
- if (!tryReadFloatTextPrecise(base, buf)) // If we use the default (fast) tryReadFloatText this returns True on garbage input
- throw_exception(ErrorCodes::CANNOT_PARSE_NUMBER, "Unable to parse readable size numeric component", str);
-
- skipWhitespaceIfAny(buf);
-
- String unit;
- readStringUntilWhitespace(unit, buf);
- if (!buf.eof())
- throw_exception(ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, "Found trailing characters after readable size string", str);
- boost::algorithm::to_lower(unit);
- Float64 scale_factor = Impl::getScaleFactorForUnit(unit);
- Float64 num_bytes = base * scale_factor;
-
- res_data.emplace_back(num_bytes);
+ try
+ {
+ auto num_bytes = parseReadableFormat(str);
+ res_data.emplace_back(num_bytes);
+ }
+ catch (...)
+ {
+ if constexpr (error_handling == ErrorHandling::Exception)
+ throw;
+ res_data[i] = 0;
+ if constexpr (error_handling == ErrorHandling::Null)
+ col_null_map->getData()[i] = 1;
+ }
}
-
- return col_to;
+ if constexpr (error_handling == ErrorHandling::Null)
+ return ColumnNullable::create(std::move(col_res), std::move(col_null_map));
+ else
+ return col_res;
}
private:
template
- void throw_exception(const int code, const String & msg, Arg arg) const
+ void throwException(const int code, const String & msg, Arg arg) const
{
throw Exception(code, "Invalid expression for function {} - {} (\"{}\")", getName(), msg, arg);
}
+
+ Float64 parseReadableFormat(const std::string_view & str) const
+ {
+ ReadBufferFromString buf(str);
+ // tryReadFloatText does seem to not raise any error when there is leading whitespace so we check it explicitly
+ skipWhitespaceIfAny(buf);
+ if (buf.getPosition() > 0)
+ throwException(ErrorCodes::CANNOT_PARSE_INPUT_ASSERTION_FAILED, "Leading whitespace is not allowed", str);
+
+ Float64 base = 0;
+ if (!tryReadFloatTextPrecise(base, buf)) // If we use the default (fast) tryReadFloatText this returns True on garbage input
+ throwException(ErrorCodes::CANNOT_PARSE_NUMBER, "Unable to parse readable size numeric component", str);
+ skipWhitespaceIfAny(buf);
+
+ String unit;
+ readStringUntilWhitespace(unit, buf);
+ if (!buf.eof())
+ throwException(ErrorCodes::UNEXPECTED_DATA_AFTER_PARSED_VALUE, "Found trailing characters after readable size string", str);
+ boost::algorithm::to_lower(unit);
+ Float64 scale_factor = Impl::getScaleFactorForUnit(unit);
+ return base * scale_factor;
+ }
};
}