mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Simplify template implementation.
This commit is contained in:
parent
76bda0342b
commit
c93bd31695
@ -430,6 +430,13 @@ inline bool_if_safe_conversion<A, B> greaterOrEqualsOp(A a, B b)
|
||||
template <typename From, typename To>
|
||||
inline bool NO_SANITIZE_UNDEFINED convertNumeric(From value, To & result)
|
||||
{
|
||||
/// If the type is actually the same it's not necessary to do any checks.
|
||||
if constexpr (std::is_same_v<From, To>)
|
||||
{
|
||||
result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Note that NaNs doesn't compare equal to anything, but they are still in range of any Float type.
|
||||
if (isNaN(value) && std::is_floating_point_v<To>)
|
||||
{
|
||||
|
46
dbms/src/Functions/DummyJSONParser.h
Normal file
46
dbms/src/Functions/DummyJSONParser.h
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/StringRef.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Core/Types.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/// This class can be used as an argument for the template class FunctionJSON when we unable to parse JSONs.
|
||||
/// It can't do anything useful and just throws an exception.
|
||||
struct DummyJSONParser
|
||||
{
|
||||
static constexpr bool need_preallocate = false;
|
||||
void preallocate(size_t) {}
|
||||
bool parse(const char *, size_t) { throw Exception{"Functions JSON* are not supported without AVX2", ErrorCodes::NOT_IMPLEMENTED}; }
|
||||
|
||||
using Iterator = std::nullptr_t;
|
||||
Iterator getRoot() const { return nullptr; }
|
||||
|
||||
static bool downToArray(Iterator &) { return false; }
|
||||
static bool downToObject(Iterator &) { return false; }
|
||||
static bool downToObject(Iterator &, StringRef &) { return false; }
|
||||
static bool parentScopeIsObject(const Iterator &) { return false; }
|
||||
static bool next(Iterator &) { return false; }
|
||||
static bool nextKeyValue(Iterator &) { return false; }
|
||||
static bool nextKeyValue(Iterator &, StringRef &) { return false; }
|
||||
static bool isInteger(const Iterator &) { return false; }
|
||||
static bool isFloat(const Iterator &) { return false; }
|
||||
static bool isString(const Iterator &) { return false; }
|
||||
static bool isArray(const Iterator &) { return false; }
|
||||
static bool isObject(const Iterator &) { return false; }
|
||||
static bool isBool(const Iterator &) { return false; }
|
||||
static bool isNull(const Iterator &) { return false; }
|
||||
static StringRef getKey(const Iterator &) { return {}; }
|
||||
static StringRef getString(const Iterator &) { return {}; }
|
||||
static Int64 getInteger(const Iterator &) { return 0; }
|
||||
static double getFloat(const Iterator &) { return 0; }
|
||||
static bool getBool(const Iterator &) { return false; }
|
||||
};
|
||||
|
||||
}
|
@ -1,459 +1,7 @@
|
||||
#include <Functions/FunctionsJSON.h>
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Common/config.h>
|
||||
#include <Functions/DummyJSONParser.h>
|
||||
#include <Functions/SimdJSONParser.h>
|
||||
|
||||
#if USE_SIMDJSON
|
||||
#include <DataTypes/DataTypeArray.h>
|
||||
#include <DataTypes/DataTypeNullable.h>
|
||||
#include <DataTypes/DataTypeString.h>
|
||||
#include <DataTypes/DataTypeTuple.h>
|
||||
#include <DataTypes/DataTypesNumber.h>
|
||||
#include <DataTypes/DataTypeEnum.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
template <typename T>
|
||||
class JSONNullableImplBase
|
||||
{
|
||||
public:
|
||||
static DataTypePtr getType() { return std::make_shared<DataTypeNullable>(std::make_shared<T>()); }
|
||||
|
||||
static Field getDefault() { return {}; }
|
||||
};
|
||||
|
||||
class JSONHasImpl : public JSONNullableImplBase<DataTypeUInt8>
|
||||
{
|
||||
public:
|
||||
static constexpr auto name{"JSONHas"};
|
||||
|
||||
static Field getValue(ParsedJson::iterator &) { return {1}; }
|
||||
};
|
||||
|
||||
class JSONLengthImpl : public JSONNullableImplBase<DataTypeUInt64>
|
||||
{
|
||||
public:
|
||||
static constexpr auto name{"JSONLength"};
|
||||
|
||||
static Field getValue(ParsedJson::iterator & pjh)
|
||||
{
|
||||
if (!pjh.is_object_or_array())
|
||||
return getDefault();
|
||||
|
||||
size_t size = 0;
|
||||
|
||||
if (pjh.down())
|
||||
{
|
||||
++size;
|
||||
while (pjh.next())
|
||||
++size;
|
||||
if (pjh.get_scope_type() == '{')
|
||||
size /= 2;
|
||||
}
|
||||
|
||||
return {size};
|
||||
}
|
||||
};
|
||||
|
||||
class JSONTypeImpl
|
||||
{
|
||||
public:
|
||||
static constexpr auto name{"JSONType"};
|
||||
|
||||
static DataTypePtr getType()
|
||||
{
|
||||
static const std::vector<std::pair<String, Int8>> values = {
|
||||
{"Array", '['},
|
||||
{"Object", '{'},
|
||||
{"String", '"'},
|
||||
{"Int", 'l'},
|
||||
{"Float",'d'},
|
||||
{"Bool", 'b'},
|
||||
{"Null",'n'},
|
||||
};
|
||||
return std::make_shared<DataTypeNullable>(std::make_shared<DataTypeEnum<Int8>>(values));
|
||||
}
|
||||
|
||||
static Field getDefault() { return {}; }
|
||||
|
||||
static Field getValue(ParsedJson::iterator & pjh)
|
||||
{
|
||||
switch (pjh.get_type())
|
||||
{
|
||||
case '[':
|
||||
case '{':
|
||||
case '"':
|
||||
case 'l':
|
||||
case 'd':
|
||||
case 'n':
|
||||
return {pjh.get_type()};
|
||||
case 't':
|
||||
case 'f':
|
||||
return {'b'};
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class JSONExtractImpl
|
||||
{
|
||||
public:
|
||||
static constexpr auto name{"JSONExtract"};
|
||||
|
||||
static DataTypePtr getType(const DataTypePtr & type)
|
||||
{
|
||||
WhichDataType which{type};
|
||||
|
||||
if (which.isNativeUInt() || which.isNativeInt() || which.isFloat() || which.isEnum() || which.isDateOrDateTime()
|
||||
|| which.isStringOrFixedString() || which.isInterval())
|
||||
return std::make_shared<DataTypeNullable>(type);
|
||||
|
||||
if (which.isArray())
|
||||
{
|
||||
auto array_type = static_cast<const DataTypeArray *>(type.get());
|
||||
|
||||
return std::make_shared<DataTypeArray>(getType(array_type->getNestedType()));
|
||||
}
|
||||
|
||||
if (which.isTuple())
|
||||
{
|
||||
auto tuple_type = static_cast<const DataTypeTuple *>(type.get());
|
||||
|
||||
DataTypes types;
|
||||
types.reserve(tuple_type->getElements().size());
|
||||
|
||||
for (const DataTypePtr & element : tuple_type->getElements())
|
||||
{
|
||||
types.push_back(getType(element));
|
||||
}
|
||||
|
||||
return std::make_shared<DataTypeTuple>(std::move(types));
|
||||
}
|
||||
|
||||
throw Exception{"Unsupported return type schema: " + type->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
||||
}
|
||||
|
||||
static Field getDefault(const DataTypePtr & type)
|
||||
{
|
||||
WhichDataType which{type};
|
||||
|
||||
if (which.isNativeUInt() || which.isNativeInt() || which.isFloat() || which.isEnum() || which.isDateOrDateTime()
|
||||
|| which.isStringOrFixedString() || which.isInterval())
|
||||
return {};
|
||||
|
||||
if (which.isArray())
|
||||
return {Array{}};
|
||||
|
||||
if (which.isTuple())
|
||||
{
|
||||
auto tuple_type = static_cast<const DataTypeTuple *>(type.get());
|
||||
|
||||
Tuple tuple;
|
||||
tuple.toUnderType().reserve(tuple_type->getElements().size());
|
||||
|
||||
for (const DataTypePtr & element : tuple_type->getElements())
|
||||
tuple.toUnderType().push_back(getDefault(element));
|
||||
|
||||
return {tuple};
|
||||
}
|
||||
|
||||
// should not reach
|
||||
throw Exception{"Unsupported return type schema: " + type->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
||||
}
|
||||
|
||||
static Field getValue(ParsedJson::iterator & pjh, const DataTypePtr & type)
|
||||
{
|
||||
WhichDataType which{type};
|
||||
|
||||
if (which.isNativeUInt() || which.isNativeInt() || which.isEnum() || which.isDateOrDateTime() || which.isInterval())
|
||||
{
|
||||
if (pjh.is_integer())
|
||||
return {pjh.get_integer()};
|
||||
else
|
||||
return getDefault(type);
|
||||
}
|
||||
|
||||
if (which.isFloat())
|
||||
{
|
||||
if (pjh.is_integer())
|
||||
return {static_cast<double>(pjh.get_integer())};
|
||||
else if (pjh.is_double())
|
||||
return {pjh.get_double()};
|
||||
else
|
||||
return getDefault(type);
|
||||
}
|
||||
|
||||
if (which.isStringOrFixedString())
|
||||
{
|
||||
if (pjh.is_string())
|
||||
return {String{pjh.get_string()}};
|
||||
else
|
||||
return getDefault(type);
|
||||
}
|
||||
|
||||
if (which.isArray())
|
||||
{
|
||||
if (!pjh.is_object_or_array())
|
||||
return getDefault(type);
|
||||
|
||||
auto array_type = static_cast<const DataTypeArray *>(type.get());
|
||||
|
||||
Array array;
|
||||
|
||||
bool first = true;
|
||||
|
||||
while (first ? pjh.down() : pjh.next())
|
||||
{
|
||||
first = false;
|
||||
|
||||
ParsedJson::iterator pjh1{pjh};
|
||||
|
||||
array.push_back(getValue(pjh1, array_type->getNestedType()));
|
||||
}
|
||||
|
||||
return {array};
|
||||
}
|
||||
|
||||
if (which.isTuple())
|
||||
{
|
||||
if (!pjh.is_object_or_array())
|
||||
return getDefault(type);
|
||||
|
||||
auto tuple_type = static_cast<const DataTypeTuple *>(type.get());
|
||||
|
||||
Tuple tuple;
|
||||
tuple.toUnderType().reserve(tuple_type->getElements().size());
|
||||
|
||||
bool valid = true;
|
||||
bool first = true;
|
||||
|
||||
for (const DataTypePtr & element : tuple_type->getElements())
|
||||
{
|
||||
if (valid)
|
||||
{
|
||||
valid &= first ? pjh.down() : pjh.next();
|
||||
first = false;
|
||||
|
||||
ParsedJson::iterator pjh1{pjh};
|
||||
|
||||
tuple.toUnderType().push_back(getValue(pjh1, element));
|
||||
}
|
||||
else
|
||||
tuple.toUnderType().push_back(getDefault(element));
|
||||
}
|
||||
|
||||
return {tuple};
|
||||
}
|
||||
|
||||
// should not reach
|
||||
throw Exception{"Unsupported return type schema: " + type->getName(), ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
||||
}
|
||||
};
|
||||
|
||||
class JSONExtractUIntImpl : public JSONNullableImplBase<DataTypeUInt64>
|
||||
{
|
||||
public:
|
||||
static constexpr auto name{"JSONExtractUInt"};
|
||||
|
||||
static Field getValue(ParsedJson::iterator & pjh)
|
||||
{
|
||||
if (pjh.is_integer())
|
||||
return {pjh.get_integer()};
|
||||
else
|
||||
return getDefault();
|
||||
}
|
||||
};
|
||||
|
||||
class JSONExtractIntImpl : public JSONNullableImplBase<DataTypeInt64>
|
||||
{
|
||||
public:
|
||||
static constexpr auto name{"JSONExtractInt"};
|
||||
|
||||
static Field getValue(ParsedJson::iterator & pjh)
|
||||
{
|
||||
if (pjh.is_integer())
|
||||
return {pjh.get_integer()};
|
||||
else
|
||||
return getDefault();
|
||||
}
|
||||
};
|
||||
|
||||
class JSONExtractFloatImpl : public JSONNullableImplBase<DataTypeFloat64>
|
||||
{
|
||||
public:
|
||||
static constexpr auto name{"JSONExtractFloat"};
|
||||
|
||||
static Field getValue(ParsedJson::iterator & pjh)
|
||||
{
|
||||
if (pjh.is_double())
|
||||
return {pjh.get_double()};
|
||||
else
|
||||
return getDefault();
|
||||
}
|
||||
};
|
||||
|
||||
class JSONExtractBoolImpl : public JSONNullableImplBase<DataTypeUInt8>
|
||||
{
|
||||
public:
|
||||
static constexpr auto name{"JSONExtractBool"};
|
||||
|
||||
static Field getValue(ParsedJson::iterator & pjh)
|
||||
{
|
||||
if (pjh.get_type() == 't')
|
||||
return {1};
|
||||
else if (pjh.get_type() == 'f')
|
||||
return {0};
|
||||
else
|
||||
return getDefault();
|
||||
}
|
||||
};
|
||||
|
||||
class JSONExtractRawImpl: public JSONNullableImplBase<DataTypeString>
|
||||
{
|
||||
public:
|
||||
static constexpr auto name {"JSONExtractRaw"};
|
||||
|
||||
static Field getValue(ParsedJson::iterator & pjh)
|
||||
{
|
||||
WriteBufferFromOwnString buf;
|
||||
traverse(pjh, buf);
|
||||
return {std::move(buf.str())};
|
||||
}
|
||||
|
||||
private:
|
||||
static void traverse(ParsedJson::iterator & pjh, WriteBuffer & buf)
|
||||
{
|
||||
switch (pjh.get_type())
|
||||
{
|
||||
case '{':
|
||||
{
|
||||
writeChar('{', buf);
|
||||
if (pjh.down())
|
||||
{
|
||||
writeJSONString(pjh.get_string(), pjh.get_string() + pjh.get_string_length(), buf, format_settings());
|
||||
writeChar(':', buf);
|
||||
pjh.next();
|
||||
traverse(pjh, buf);
|
||||
while (pjh.next())
|
||||
{
|
||||
writeChar(',', buf);
|
||||
writeJSONString(pjh.get_string(), pjh.get_string() + pjh.get_string_length(), buf, format_settings());
|
||||
writeChar(':', buf);
|
||||
pjh.next();
|
||||
traverse(pjh, buf);
|
||||
}
|
||||
pjh.up();
|
||||
}
|
||||
writeChar('}', buf);
|
||||
break;
|
||||
}
|
||||
case '[':
|
||||
{
|
||||
writeChar('[', buf);
|
||||
if (pjh.down())
|
||||
{
|
||||
traverse(pjh, buf);
|
||||
while (pjh.next())
|
||||
{
|
||||
writeChar(',', buf);
|
||||
traverse(pjh, buf);
|
||||
}
|
||||
pjh.up();
|
||||
}
|
||||
writeChar(']', buf);
|
||||
break;
|
||||
}
|
||||
case '"':
|
||||
{
|
||||
writeJSONString(pjh.get_string(), pjh.get_string() + pjh.get_string_length(), buf, format_settings());
|
||||
break;
|
||||
}
|
||||
case 'l':
|
||||
{
|
||||
writeIntText(pjh.get_integer(), buf);
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
{
|
||||
writeFloatText(pjh.get_double(), buf);
|
||||
break;
|
||||
}
|
||||
case 't':
|
||||
{
|
||||
writeCString("true", buf);
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
{
|
||||
writeCString("false", buf);
|
||||
break;
|
||||
}
|
||||
case 'n':
|
||||
{
|
||||
writeCString("null", buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const FormatSettings & format_settings()
|
||||
{
|
||||
static const FormatSettings the_instance = []
|
||||
{
|
||||
FormatSettings settings;
|
||||
settings.json.escape_forward_slashes = false;
|
||||
return settings;
|
||||
}();
|
||||
return the_instance;
|
||||
}
|
||||
};
|
||||
|
||||
class JSONExtractStringImpl : public JSONNullableImplBase<DataTypeString>
|
||||
{
|
||||
public:
|
||||
static constexpr auto name{"JSONExtractString"};
|
||||
|
||||
static Field getValue(ParsedJson::iterator & pjh)
|
||||
{
|
||||
if (pjh.is_string())
|
||||
return {String{pjh.get_string()}};
|
||||
else
|
||||
return getDefault();
|
||||
}
|
||||
};
|
||||
|
||||
class JSONExtractKeyImpl : public JSONNullableImplBase<DataTypeString>
|
||||
{
|
||||
public:
|
||||
static constexpr auto name{"JSONExtractKey"};
|
||||
|
||||
static Field getValue(ParsedJson::iterator & pjh)
|
||||
{
|
||||
if (pjh.get_scope_type() == '{' && pjh.prev() && pjh.is_string())
|
||||
return {String{pjh.get_string()}};
|
||||
else
|
||||
return getDefault();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#else
|
||||
namespace DB
|
||||
{
|
||||
struct JSONHasImpl { static constexpr auto name{"JSONHas"}; };
|
||||
struct JSONLengthImpl { static constexpr auto name{"JSONLength"}; };
|
||||
struct JSONTypeImpl { static constexpr auto name{"JSONType"}; };
|
||||
struct JSONExtractImpl { static constexpr auto name{"JSONExtract"}; };
|
||||
struct JSONExtractUIntImpl { static constexpr auto name{"JSONExtractUInt"}; };
|
||||
struct JSONExtractIntImpl { static constexpr auto name{"JSONExtractInt"}; };
|
||||
struct JSONExtractFloatImpl { static constexpr auto name{"JSONExtractFloat"}; };
|
||||
struct JSONExtractBoolImpl { static constexpr auto name{"JSONExtractBool"}; };
|
||||
struct JSONExtractRawImpl { static constexpr auto name {"JSONExtractRaw"}; };
|
||||
struct JSONExtractStringImpl { static constexpr auto name{"JSONExtractString"}; };
|
||||
struct JSONExtractKeyImpl { static constexpr auto name{"JSONExtractKey"}; };
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace DB
|
||||
{
|
||||
@ -463,31 +11,11 @@ void registerFunctionsJSON(FunctionFactory & factory)
|
||||
#if USE_SIMDJSON
|
||||
if (__builtin_cpu_supports("avx2"))
|
||||
{
|
||||
factory.registerFunction<FunctionJSONBase<JSONHasImpl, false>>();
|
||||
factory.registerFunction<FunctionJSONBase<JSONLengthImpl, false>>();
|
||||
factory.registerFunction<FunctionJSONBase<JSONTypeImpl, false>>();
|
||||
factory.registerFunction<FunctionJSONBase<JSONExtractImpl, true>>();
|
||||
factory.registerFunction<FunctionJSONBase<JSONExtractUIntImpl, false>>();
|
||||
factory.registerFunction<FunctionJSONBase<JSONExtractIntImpl, false>>();
|
||||
factory.registerFunction<FunctionJSONBase<JSONExtractFloatImpl, false>>();
|
||||
factory.registerFunction<FunctionJSONBase<JSONExtractBoolImpl, false>>();
|
||||
factory.registerFunction<FunctionJSONBase<JSONExtractRawImpl, false>>();
|
||||
factory.registerFunction<FunctionJSONBase<JSONExtractStringImpl, false>>();
|
||||
factory.registerFunction<FunctionJSONBase<JSONExtractKeyImpl, false>>();
|
||||
registerFunctionsJSONTemplate<SimdJSONParser>(factory);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
factory.registerFunction<FunctionJSONDummy<JSONHasImpl>>();
|
||||
factory.registerFunction<FunctionJSONDummy<JSONLengthImpl>>();
|
||||
factory.registerFunction<FunctionJSONDummy<JSONTypeImpl>>();
|
||||
factory.registerFunction<FunctionJSONDummy<JSONExtractImpl>>();
|
||||
factory.registerFunction<FunctionJSONDummy<JSONExtractUIntImpl>>();
|
||||
factory.registerFunction<FunctionJSONDummy<JSONExtractIntImpl>>();
|
||||
factory.registerFunction<FunctionJSONDummy<JSONExtractFloatImpl>>();
|
||||
factory.registerFunction<FunctionJSONDummy<JSONExtractBoolImpl>>();
|
||||
factory.registerFunction<FunctionJSONDummy<JSONExtractRawImpl>>();
|
||||
factory.registerFunction<FunctionJSONDummy<JSONExtractStringImpl>>();
|
||||
factory.registerFunction<FunctionJSONDummy<JSONExtractKeyImpl>>();
|
||||
registerFunctionsJSONTemplate<DummyJSONParser>(factory);
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
110
dbms/src/Functions/SimdJSONParser.h
Normal file
110
dbms/src/Functions/SimdJSONParser.h
Normal file
@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#include <Common/config.h>
|
||||
#if USE_SIMDJSON
|
||||
|
||||
#include <common/StringRef.h>
|
||||
#include <Common/Exception.h>
|
||||
#include <Core/Types.h>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wold-style-cast"
|
||||
#pragma clang diagnostic ignored "-Wnewline-eof"
|
||||
#endif
|
||||
|
||||
#include <simdjson/jsonparser.h>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int CANNOT_ALLOCATE_MEMORY;
|
||||
}
|
||||
|
||||
/// This class can be used as an argument for the template class FunctionJSON.
|
||||
/// It provides ability to parse JSONs using simdjson library.
|
||||
struct SimdJSONParser
|
||||
{
|
||||
static constexpr bool need_preallocate = true;
|
||||
|
||||
void preallocate(size_t max_size)
|
||||
{
|
||||
if (!pj.allocateCapacity(max_size))
|
||||
throw Exception{"Can not allocate memory for " + std::to_string(max_size) + " units when parsing JSON",
|
||||
ErrorCodes::CANNOT_ALLOCATE_MEMORY};
|
||||
}
|
||||
|
||||
bool parse(const char * data, size_t size) { return !json_parse(data, size, pj); }
|
||||
|
||||
using Iterator = ParsedJson::iterator;
|
||||
Iterator getRoot() { return Iterator{pj}; }
|
||||
|
||||
static bool downToArray(Iterator & it) { return it.down(); }
|
||||
|
||||
static bool downToObject(Iterator & it) { return it.down() && it.next(); }
|
||||
|
||||
static bool downToObject(Iterator & it, StringRef & first_key)
|
||||
{
|
||||
if (!it.down())
|
||||
return false;
|
||||
first_key.data = it.get_string();
|
||||
first_key.size = it.get_string_length();
|
||||
return it.next();
|
||||
}
|
||||
|
||||
static bool parentScopeIsObject(const Iterator & it) { return it.get_scope_type() == '{'; }
|
||||
|
||||
static bool next(Iterator & it) { return it.next(); }
|
||||
|
||||
static bool nextKeyValue(Iterator & it) { return it.next() && it.next(); }
|
||||
|
||||
static bool nextKeyValue(Iterator & it, StringRef & key)
|
||||
{
|
||||
if (!it.next())
|
||||
return false;
|
||||
key.data = it.get_string();
|
||||
key.size = it.get_string_length();
|
||||
return it.next();
|
||||
}
|
||||
|
||||
static bool isInteger(const Iterator & it) { return it.is_integer(); }
|
||||
|
||||
static bool isFloat(const Iterator & it) { return it.is_double(); }
|
||||
|
||||
static bool isString(const Iterator & it) { return it.is_string(); }
|
||||
|
||||
static bool isArray(const Iterator & it) { return it.is_array(); }
|
||||
|
||||
static bool isObject(const Iterator & it) { return it.is_object(); }
|
||||
|
||||
static bool isBool(const Iterator & it) { return it.get_type() == 't' || it.get_type() == 'f'; }
|
||||
|
||||
static bool isNull(const Iterator & it) { return it.get_type() == 'n'; }
|
||||
|
||||
static StringRef getKey(const Iterator & it)
|
||||
{
|
||||
Iterator it2 = it;
|
||||
it2.prev();
|
||||
return StringRef{it2.get_string(), it2.get_string_length()};
|
||||
}
|
||||
|
||||
static StringRef getString(const Iterator & it) { return StringRef{it.get_string(), it.get_string_length()}; }
|
||||
|
||||
static Int64 getInteger(const Iterator & it) { return it.get_integer(); }
|
||||
|
||||
static double getFloat(const Iterator & it) { return it.get_double(); }
|
||||
|
||||
static bool getBool(const Iterator & it) { return it.get_type() == 't'; }
|
||||
|
||||
private:
|
||||
ParsedJson pj;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
@ -38,18 +38,28 @@ private:
|
||||
working_buffer = internal_buffer;
|
||||
}
|
||||
|
||||
static constexpr size_t initial_size = 32;
|
||||
|
||||
public:
|
||||
WriteBufferFromVector(VectorType & vector_)
|
||||
: WriteBuffer(reinterpret_cast<Position>(vector_.data()), vector_.size()), vector(vector_)
|
||||
{
|
||||
if (vector.empty())
|
||||
{
|
||||
static constexpr size_t initial_size = 32;
|
||||
vector.resize(initial_size);
|
||||
set(reinterpret_cast<Position>(vector.data()), vector.size());
|
||||
}
|
||||
}
|
||||
|
||||
struct AppendModeTag {};
|
||||
WriteBufferFromVector(VectorType & vector_, AppendModeTag)
|
||||
: WriteBuffer(nullptr, 0), vector(vector_)
|
||||
{
|
||||
size_t old_size = vector.size();
|
||||
vector.resize(vector.capacity() < initial_size ? initial_size : vector.capacity());
|
||||
set(reinterpret_cast<Position>(vector.data() + old_size), (vector.size() - old_size) * sizeof(typename VectorType::value_type));
|
||||
}
|
||||
|
||||
void finish()
|
||||
{
|
||||
if (is_finished)
|
||||
|
@ -1,26 +1,52 @@
|
||||
--JSONLength--
|
||||
2
|
||||
Object
|
||||
1
|
||||
1
|
||||
a
|
||||
b
|
||||
b
|
||||
a
|
||||
hello
|
||||
hello
|
||||
3
|
||||
0
|
||||
--JSONHas--
|
||||
1
|
||||
1
|
||||
0
|
||||
--JSONKey--
|
||||
a
|
||||
b
|
||||
b
|
||||
a
|
||||
--JSONType--
|
||||
Object
|
||||
Array
|
||||
--JSONExtract<type>--
|
||||
hello
|
||||
hello
|
||||
-100
|
||||
200
|
||||
300
|
||||
('a','hello','b',[-100,200,300])
|
||||
[-100,NULL,300]
|
||||
['a','hello','b',NULL]
|
||||
[(NULL,NULL,NULL),(NULL,NULL,NULL),(NULL,NULL,NULL),(-100,200,44)]
|
||||
{"a":"hello","b":[-100,200,300],"c":{"d":[121,144]}}
|
||||
1
|
||||
--JSONExtract (generic)--
|
||||
('hello',[-100,200,300])
|
||||
('hello',[-100,200,300])
|
||||
([-100,200,300],'hello')
|
||||
('hello\0',0)
|
||||
hello
|
||||
[-100,200,300]
|
||||
(-100,200,300)
|
||||
[-100,0,0]
|
||||
[-100,NULL,NULL]
|
||||
[0,200,0]
|
||||
[NULL,200,NULL]
|
||||
-100
|
||||
200
|
||||
\N
|
||||
Thursday
|
||||
Friday
|
||||
--JSONExtractRaw--
|
||||
{"a":"hello","b":[-100,200,300]}
|
||||
"hello"
|
||||
[-100,200,300]
|
||||
-100
|
||||
{"a":"hello","b":[-100,200,300],"c":{"d":[121,144]}}
|
||||
{"d":[121,144]}
|
||||
[121,144]
|
||||
144
|
||||
|
||||
{"passed":true}
|
||||
{}
|
||||
|
@ -1,26 +1,58 @@
|
||||
SELECT '--JSONLength--';
|
||||
SELECT JSONLength('{"a": "hello", "b": [-100, 200.0, 300]}');
|
||||
SELECT JSONType('{"a": "hello", "b": [-100, 200.0, 300]}');
|
||||
SELECT JSONLength('{"a": "hello", "b": [-100, 200.0, 300]}', 'b');
|
||||
SELECT JSONLength('{}');
|
||||
|
||||
SELECT '--JSONHas--';
|
||||
SELECT JSONHas('{"a": "hello", "b": [-100, 200.0, 300]}', 'a');
|
||||
SELECT JSONHas('{"a": "hello", "b": [-100, 200.0, 300]}', 'b');
|
||||
SELECT JSONExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', 1);
|
||||
SELECT JSONExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', 2);
|
||||
SELECT JSONExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', -1);
|
||||
SELECT JSONExtractKey('{"a": "hello", "b": [-100, 200.0, 300]}', -2);
|
||||
SELECT JSONExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 1);
|
||||
SELECT JSONExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 'a');
|
||||
SELECT JSONLength('{"a": "hello", "b": [-100, 200.0, 300]}', 'b');
|
||||
SELECT JSONHas('{"a": "hello", "b": [-100, 200.0, 300]}', 'c');
|
||||
|
||||
SELECT '--JSONKey--';
|
||||
SELECT JSONKey('{"a": "hello", "b": [-100, 200.0, 300]}', 1);
|
||||
SELECT JSONKey('{"a": "hello", "b": [-100, 200.0, 300]}', 2);
|
||||
SELECT JSONKey('{"a": "hello", "b": [-100, 200.0, 300]}', -1);
|
||||
SELECT JSONKey('{"a": "hello", "b": [-100, 200.0, 300]}', -2);
|
||||
|
||||
SELECT '--JSONType--';
|
||||
SELECT JSONType('{"a": "hello", "b": [-100, 200.0, 300]}');
|
||||
SELECT JSONType('{"a": "hello", "b": [-100, 200.0, 300]}', 'b');
|
||||
|
||||
SELECT '--JSONExtract<type>--';
|
||||
SELECT JSONExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 'a');
|
||||
SELECT JSONExtractString('{"a": "hello", "b": [-100, 200.0, 300]}', 1);
|
||||
SELECT JSONExtractInt('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 1);
|
||||
SELECT JSONExtractFloat('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 2);
|
||||
SELECT JSONExtractUInt('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', -1);
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Tuple(String, String, String, Array(Float64))');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 'Array(Int32)');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Array(String)');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Array(Tuple(Int16, Float32, UInt8))');
|
||||
SELECT JSONExtractBool('{"passed": true}', 'passed');
|
||||
|
||||
SELECT '--JSONExtract (generic)--';
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Tuple(String, Array(Float64))');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Tuple(a String, b Array(Float64))');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Tuple(b Array(Float64), a String)');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'Tuple(a FixedString(6), c UInt8)');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'a', 'String');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 'Array(Float32)');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 'Tuple(Int8, Float32, UInt16)');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 'Array(Int8)');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 'Array(Nullable(Int8))');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 'Array(UInt8)');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 'Array(Nullable(UInt8))');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 1, 'Int8');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 2, 'Int32');
|
||||
SELECT JSONExtract('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 4, 'Nullable(Int64)');
|
||||
SELECT JSONExtract('{"day": "Thursday"}', 'day', 'Enum8(\'Sunday\' = 0, \'Monday\' = 1, \'Tuesday\' = 2, \'Wednesday\' = 3, \'Thursday\' = 4, \'Friday\' = 5, \'Saturday\' = 6)');
|
||||
SELECT JSONExtract('{"day": 5}', 'day', 'Enum8(\'Sunday\' = 0, \'Monday\' = 1, \'Tuesday\' = 2, \'Wednesday\' = 3, \'Thursday\' = 4, \'Friday\' = 5, \'Saturday\' = 6)');
|
||||
|
||||
SELECT '--JSONExtractRaw--';
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300]}');
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300]}', 'a');
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300]}', 'b');
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300]}', 'b', 1);
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}');
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'a');
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'b');
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'b', 1);
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'c');
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'c', 'd');
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'c', 'd', 2);
|
||||
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300], "c":{"d":[121,144]}}', 'c', 'd', 3);
|
||||
SELECT JSONExtractRaw('{"passed": true}');
|
||||
SELECT JSONExtractRaw('{}');
|
||||
|
Loading…
Reference in New Issue
Block a user