-
Notifications
You must be signed in to change notification settings - Fork 411
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support Json unquote function #8407
Changes from 26 commits
aa7e702
0423a18
cfd932b
b523aee
757def7
b8f4649
bd85cb5
efbffc9
890fef7
ee1e017
1c52415
e81918e
e5f0d5e
0068d15
fa71aa7
e9f9977
d1d6fd7
1c010d5
de525af
e00030d
f276079
e5ec942
de65bef
402b16c
9b3e744
28a6233
b7752df
d8cbc35
572fea9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -27,11 +27,14 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <DataTypes/DataTypesNumber.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <Flash/Coprocessor/DAGUtils.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <Functions/FunctionHelpers.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <Functions/FunctionsTiDBConversion.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <Functions/GatherUtils/Sources.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <Functions/IFunction.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <Functions/castTypeToEither.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <Interpreters/Context.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <TiDB/Decode/JsonBinary.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <TiDB/Decode/JsonPathExprRef.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <TiDB/Decode/JsonScanner.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <TiDB/Schema/TiDB.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <common/JSON.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#include <simdjson.h> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -301,6 +304,7 @@ class FunctionJsonUnquote : public IFunction | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t getNumberOfArguments() const override { return 1; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void setNeedValidCheck(bool need_valid_check_) { need_valid_check = need_valid_check_; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bool useDefaultImplementationForConstants() const override { return true; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -327,16 +331,10 @@ class FunctionJsonUnquote : public IFunction | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
offsets_to.resize(rows); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ColumnUInt8::MutablePtr col_null_map = ColumnUInt8::create(rows, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
JsonBinary::JsonBinaryWriteBuffer write_buffer(data_to); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t current_offset = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (size_t i = 0; i < block.rows(); ++i) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t next_offset = offsets_from[i]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t data_length = next_offset - current_offset - 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
JsonBinary::unquoteStringInBuffer(StringRef(&data_from[current_offset], data_length), write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
writeChar(0, write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
offsets_to[i] = write_buffer.count(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
current_offset = next_offset; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (need_valid_check) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
doUnquote<true>(block, data_from, offsets_from, offsets_to, write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
doUnquote<false>(block, data_from, offsets_from, offsets_to, write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_to.resize(write_buffer.count()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
block.getByPosition(result).column = ColumnNullable::create(std::move(col_to), std::move(col_null_map)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -345,21 +343,69 @@ class FunctionJsonUnquote : public IFunction | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
fmt::format("Illegal column {} of argument of function {}", column->getName(), getName()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ErrorCodes::ILLEGAL_COLUMN); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
template <bool validCheck> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void doUnquote( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const Block & block, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const ColumnString::Chars_t & data_from, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const IColumn::Offsets & offsets_from, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
IColumn::Offsets & offsets_to, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
JsonBinary::JsonBinaryWriteBuffer & write_buffer) const | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t current_offset = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (size_t i = 0; i < block.rows(); ++i) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t next_offset = offsets_from[i]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t data_length = next_offset - current_offset - 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if constexpr (validCheck) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
// TODO(hyb): use SIMDJson to check when SIMDJson is proved in practice | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (data_length >= 2 && data_from[current_offset] == '"' && data_from[next_offset - 2] == '"' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
&& unlikely( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
!checkJsonValid(reinterpret_cast<const char *>(&data_from[current_offset]), data_length))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
throw Exception( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Invalid JSON text: The document root must not be followed by other values.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ErrorCodes::ILLEGAL_COLUMN); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
JsonBinary::unquoteStringInBuffer(StringRef(&data_from[current_offset], data_length), write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
writeChar(0, write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
offsets_to[i] = write_buffer.count(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
current_offset = next_offset; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
private: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bool need_valid_check = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
class FunctionCastJsonAsString : public IFunction | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
static constexpr auto name = "cast_json_as_string"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
static FunctionPtr create(const Context &) { return std::make_shared<FunctionCastJsonAsString>(); } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
static FunctionPtr create(const Context & context) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!context.getDAGContext()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
throw Exception("DAGContext should not be nullptr.", ErrorCodes::LOGICAL_ERROR); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return std::make_shared<FunctionCastJsonAsString>(context); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
explicit FunctionCastJsonAsString(const Context & context) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
: context(context) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
String getName() const override { return name; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t getNumberOfArguments() const override { return 1; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
bool useDefaultImplementationForConstants() const override { return true; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void setOutputTiDBFieldType(const tipb::FieldType & tidb_tp_) { tidb_tp = &tidb_tp_; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if unlikely (!arguments[0]->isString()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -386,25 +432,59 @@ class FunctionCastJsonAsString : public IFunction | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ColumnUInt8::MutablePtr col_null_map = ColumnUInt8::create(rows, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ColumnUInt8::Container & vec_null_map = col_null_map->getData(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
JsonBinary::JsonBinaryWriteBuffer write_buffer(data_to); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t current_offset = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (size_t i = 0; i < block.rows(); ++i) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if likely (tidb_tp->flen() < 0) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t next_offset = offsets_from[i]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t json_length = next_offset - current_offset - 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if unlikely (isNullJsonBinary(json_length)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t current_offset = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (size_t i = 0; i < block.rows(); ++i) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
vec_null_map[i] = 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t next_offset = offsets_from[i]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t json_length = next_offset - current_offset - 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if unlikely (isNullJsonBinary(json_length)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
vec_null_map[i] = 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
JsonBinary json_binary( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_from[current_offset], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
StringRef(&data_from[current_offset + 1], json_length - 1)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
json_binary.toStringInBuffer(write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
writeChar(0, write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
offsets_to[i] = write_buffer.count(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
current_offset = next_offset; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ColumnString::Chars_t container_per_element; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t current_offset = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for (size_t i = 0; i < block.rows(); ++i) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
JsonBinary json_binary( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_from[current_offset], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
StringRef(&data_from[current_offset + 1], json_length - 1)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
json_binary.toStringInBuffer(write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t next_offset = offsets_from[i]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t json_length = next_offset - current_offset - 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if unlikely (isNullJsonBinary(json_length)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
vec_null_map[i] = 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
JsonBinary::JsonBinaryWriteBuffer element_write_buffer(container_per_element); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
JsonBinary json_binary( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_from[current_offset], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
StringRef(&data_from[current_offset + 1], json_length - 1)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
json_binary.toStringInBuffer(element_write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size_t orig_length = element_write_buffer.count(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
auto byte_length = charLengthToByteLengthFromUTF8( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
reinterpret_cast<char *>(container_per_element.data()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
orig_length, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tidb_tp->flen()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
byte_length = std::min(byte_length, orig_length); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (byte_length < element_write_buffer.count()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
context.getDAGContext()->handleTruncateError("Data Too Long"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
write_buffer.write(reinterpret_cast<char *>(container_per_element.data()), byte_length); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how about
Suggested change
? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To avoid one more memcpy. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah,you're right. I just think this code path is not common used(because cast json as fixed length char is valid but strange), and even if it is used the performance won't drop significantly, thus choose to use the temporary buffer here to make code more easier. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
writeChar(0, write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
offsets_to[i] = write_buffer.count(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
current_offset = next_offset; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
writeChar(0, write_buffer); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
offsets_to[i] = write_buffer.count(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
current_offset = next_offset; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data_to.resize(write_buffer.count()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
block.getByPosition(result).column = ColumnNullable::create(std::move(col_to), std::move(col_null_map)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -414,8 +494,11 @@ class FunctionCastJsonAsString : public IFunction | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
fmt::format("Illegal column {} of argument of function {}", column->getName(), getName()), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ErrorCodes::ILLEGAL_COLUMN); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
private: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const tipb::FieldType * tidb_tp; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const Context & context; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
class FunctionJsonLength : public IFunction | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -77,30 +77,30 @@ namespace | |
constexpr static Int64 pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; | ||
} | ||
|
||
ALWAYS_INLINE inline size_t charLengthToByteLengthFromUTF8(const char * data, size_t length, size_t char_length) | ||
{ | ||
size_t ret = 0; | ||
for (size_t char_index = 0; char_index < char_length && ret < length; char_index++) | ||
{ | ||
uint8_t c = data[ret]; | ||
if (c < 0x80) | ||
ret += 1; | ||
else if (c < 0xE0) | ||
ret += 2; | ||
else if (c < 0xF0) | ||
ret += 3; | ||
else | ||
ret += 4; | ||
} | ||
return ret; | ||
} | ||
|
||
/// cast int/real/decimal/time as string | ||
template <typename FromDataType, bool return_nullable> | ||
struct TiDBConvertToString | ||
{ | ||
using FromFieldType = typename FromDataType::FieldType; | ||
|
||
static size_t charLengthToByteLengthFromUTF8(const char * data, size_t length, size_t char_length) | ||
{ | ||
size_t ret = 0; | ||
for (size_t char_index = 0; char_index < char_length && ret < length; char_index++) | ||
{ | ||
uint8_t c = data[ret]; | ||
if (c < 0x80) | ||
ret += 1; | ||
else if (c < 0xE0) | ||
ret += 2; | ||
else if (c < 0xF0) | ||
ret += 3; | ||
else | ||
ret += 4; | ||
} | ||
return ret; | ||
} | ||
|
||
static void execute( | ||
Block & block, | ||
const ColumnNumbers & arguments, | ||
|
@@ -148,7 +148,7 @@ struct TiDBConvertToString | |
size_t next_offset = (*offsets_from)[i]; | ||
size_t org_length = next_offset - current_offset - 1; | ||
size_t byte_length = org_length; | ||
if (tp.flen() > 0) | ||
if (tp.flen() >= 0) | ||
{ | ||
byte_length = tp.flen(); | ||
if (tp.charset() == "utf8" || tp.charset() == "utf8mb4") | ||
|
@@ -189,7 +189,7 @@ struct TiDBConvertToString | |
WriteBufferFromVector<ColumnString::Chars_t> element_write_buffer(container_per_element); | ||
FormatImpl<FromDataType>::execute(vec_from[i], element_write_buffer, &type, nullptr); | ||
size_t byte_length = element_write_buffer.count(); | ||
if (tp.flen() > 0) | ||
if (tp.flen() >= 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it a bug fix here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it is a existing bug. |
||
byte_length = std::min(byte_length, tp.flen()); | ||
if (byte_length < element_write_buffer.count()) | ||
context.getDAGContext()->handleTruncateError("Data Too Long"); | ||
|
@@ -235,7 +235,7 @@ struct TiDBConvertToString | |
WriteBufferFromVector<ColumnString::Chars_t> element_write_buffer(container_per_element); | ||
FormatImpl<FromDataType>::execute(vec_from[i], element_write_buffer, &type, nullptr); | ||
size_t byte_length = element_write_buffer.count(); | ||
if (tp.flen() > 0) | ||
if (tp.flen() >= 0) | ||
byte_length = std::min(byte_length, tp.flen()); | ||
if (byte_length < element_write_buffer.count()) | ||
context.getDAGContext()->handleTruncateError("Data Too Long"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is not necessary since
charLengthToByteLengthFromUTF8
should ensure that the return value is less thanorig_length
?