Forbid Nullable for JSONExtract* (JSONExtract() still supports Nullable)

Only JSONExtract() can support Nullable, others JSONExtract*
(JSONExtractString and similar) does not.

And right now this file is pretty complex already,
so adding support of Nullable for others will make it even more complex.

CI: https://clickhouse-test-reports.s3.yandex.net/29680/d0fc26f91a0141b56a0550741219c3dc43630e03/fuzzer_ubsan/report.html#fail1
This commit is contained in:
Azat Khuzhin 2021-10-04 21:07:48 +03:00
parent 613b814e24
commit 20e706766c
3 changed files with 69 additions and 3 deletions

View File

@ -304,19 +304,32 @@ public:
} }
private: private:
template <class Parser>
ColumnPtr
chooseAndRunJSONParserOne(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const
{
/// Only implementations with prepare() can handle NULL.
///
/// (and right now this file is pretty complex already, and adding
/// support of Nullable for others will make it even more complex)
if (null_presence.has_nullable && !Impl<Parser>::supportNullable())
throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "{} does not support Nullable", Name::name);
return FunctionJSONHelpers::Executor<Name, Impl, Parser>::run(arguments, result_type, input_rows_count);
}
ColumnPtr ColumnPtr
chooseAndRunJSONParser(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const chooseAndRunJSONParser(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const
{ {
#if USE_SIMDJSON #if USE_SIMDJSON
if (allow_simdjson) if (allow_simdjson)
return FunctionJSONHelpers::Executor<Name, Impl, SimdJSONParser>::run(arguments, result_type, input_rows_count); return chooseAndRunJSONParserOne<SimdJSONParser>(arguments, result_type, input_rows_count);
#endif #endif
#if USE_RAPIDJSON #if USE_RAPIDJSON
return FunctionJSONHelpers::Executor<Name, Impl, RapidJSONParser>::run(arguments, result_type, input_rows_count); return chooseAndRunJSONParserOne<RapidJSONParser>(arguments, result_type, input_rows_count);
#else #else
return FunctionJSONHelpers::Executor<Name, Impl, DummyJSONParser>::run(arguments, result_type, input_rows_count); return chooseAndRunJSONParserOne<DummyJSONParser>(arguments, result_type, input_rows_count);
#endif #endif
} }
@ -433,6 +446,7 @@ public:
static DataTypePtr getReturnType(const char *, const ColumnsWithTypeAndName &) { return std::make_shared<DataTypeUInt8>(); } static DataTypePtr getReturnType(const char *, const ColumnsWithTypeAndName &) { return std::make_shared<DataTypeUInt8>(); }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; }
static bool supportNullable() { return false; }
static bool insertResultToColumn(IColumn & dest, const Element &, const std::string_view &) static bool insertResultToColumn(IColumn & dest, const Element &, const std::string_view &)
{ {
@ -461,6 +475,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName &) { return 0; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName &) { return 0; }
static bool supportNullable() { return false; }
static bool insertResultToColumn(IColumn & dest, const Element &, const std::string_view &) static bool insertResultToColumn(IColumn & dest, const Element &, const std::string_view &)
{ {
@ -485,6 +500,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; }
static bool supportNullable() { return false; }
static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &) static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &)
{ {
@ -515,6 +531,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; }
static bool supportNullable() { return false; }
static bool insertResultToColumn(IColumn & dest, const Element &, const std::string_view & last_key) static bool insertResultToColumn(IColumn & dest, const Element &, const std::string_view & last_key)
{ {
@ -549,6 +566,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; }
static bool supportNullable() { return false; }
static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &) static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &)
{ {
@ -591,6 +609,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; }
static bool supportNullable() { return false; }
static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &) static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &)
{ {
@ -666,6 +685,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; }
static bool supportNullable() { return false; }
static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &) static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &)
{ {
@ -691,6 +711,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; }
static bool supportNullable() { return false; }
static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &) static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &)
{ {
@ -1090,6 +1111,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 2; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 2; }
static bool supportNullable() { return true; }
void prepare(const char * function_name, const ColumnsWithTypeAndName &, const DataTypePtr & result_type) void prepare(const char * function_name, const ColumnsWithTypeAndName &, const DataTypePtr & result_type)
{ {
@ -1131,6 +1153,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 2; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 2; }
static bool supportNullable() { return true; }
void prepare(const char * function_name, const ColumnsWithTypeAndName &, const DataTypePtr & result_type) void prepare(const char * function_name, const ColumnsWithTypeAndName &, const DataTypePtr & result_type)
{ {
@ -1182,6 +1205,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; }
static bool supportNullable() { return false; }
static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &) static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &)
{ {
@ -1286,6 +1310,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; }
static bool supportNullable() { return false; }
static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &) static bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &)
{ {
@ -1318,6 +1343,7 @@ public:
} }
static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; } static size_t getNumberOfIndexArguments(const ColumnsWithTypeAndName & arguments) { return arguments.size() - 1; }
static bool supportNullable() { return false; }
bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &) bool insertResultToColumn(IColumn & dest, const Element & element, const std::string_view &)
{ {

View File

@ -0,0 +1,19 @@
-- { echoOn }
SELECT JSONExtractInt('[1]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractUInt('[1]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractBool('[1]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractFloat('[1]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractString('["a"]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractArrayRaw('["1"]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractKeysAndValuesRaw('["1"]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractKeysAndValues('["1"]', toNullable(1)); -- { serverError ILLEGAL_COLUMN }
SELECT JSONExtract('[1]', toNullable(1), 'Nullable(Int)');
1
SELECT JSONExtract('[1]', toNullable(1), 'Nullable(UInt8)');
1
SELECT JSONExtract('[1]', toNullable(1), 'Nullable(Bool)');
1
SELECT JSONExtract('[1]', toNullable(1), 'Nullable(Float)');
1
SELECT JSONExtract('["a"]', toNullable(1), 'Nullable(String)');
a

View File

@ -0,0 +1,21 @@
-- Tags: no-fasttest
-- to avoid merging Tags and echoOn
SELECT 1 FORMAT Null;
-- { echoOn }
SELECT JSONExtractInt('[1]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractUInt('[1]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractBool('[1]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractFloat('[1]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractString('["a"]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractArrayRaw('["1"]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractKeysAndValuesRaw('["1"]', toNullable(1)); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
SELECT JSONExtractKeysAndValues('["1"]', toNullable(1)); -- { serverError ILLEGAL_COLUMN }
SELECT JSONExtract('[1]', toNullable(1), 'Nullable(Int)');
SELECT JSONExtract('[1]', toNullable(1), 'Nullable(UInt8)');
SELECT JSONExtract('[1]', toNullable(1), 'Nullable(Bool)');
SELECT JSONExtract('[1]', toNullable(1), 'Nullable(Float)');
SELECT JSONExtract('["a"]', toNullable(1), 'Nullable(String)');