Fix UnaryRange expression on integer overflow case (#24893)

Signed-off-by: longjiquan <jiquan.long@zilliz.com>
pull/24909/head
Jiquan Long 2023-06-15 14:06:39 +08:00 committed by GitHub
parent 7f7fe85592
commit 7faf934f91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 104 additions and 27 deletions

View File

@ -101,6 +101,7 @@ Parser::ParseRangeNode(const Json& out_body) {
switch (data_type) {
case DataType::BOOL:
return ParseRangeNodeImpl<bool>(field_name, body);
case DataType::INT8:
return ParseRangeNodeImpl<int8_t>(field_name, body);
case DataType::INT16:
@ -109,6 +110,7 @@ Parser::ParseRangeNode(const Json& out_body) {
return ParseRangeNodeImpl<int32_t>(field_name, body);
case DataType::INT64:
return ParseRangeNodeImpl<int64_t>(field_name, body);
case DataType::FLOAT:
return ParseRangeNodeImpl<float>(field_name, body);
case DataType::DOUBLE:
@ -323,19 +325,32 @@ Parser::ParseRangeNodeImpl(const FieldName& field_name, const Json& body) {
if constexpr (std::is_same_v<T, bool>) {
Assert(item.value().is_boolean());
return std::make_unique<UnaryRangeExprImpl<T>>(
ColumnInfo(schema.get_field_id(field_name),
schema[field_name].get_data_type()),
mapping_.at(op_name),
item.value(),
proto::plan::GenericValue::ValCase::kBoolVal);
} else if constexpr (std::is_integral_v<T>) {
Assert(item.value().is_number_integer());
// see also: https://github.com/milvus-io/milvus/issues/23646.
return std::make_unique<UnaryRangeExprImpl<int64_t>>(
ColumnInfo(schema.get_field_id(field_name),
schema[field_name].get_data_type()),
mapping_.at(op_name),
item.value(),
proto::plan::GenericValue::ValCase::kInt64Val);
} else if constexpr (std::is_floating_point_v<T>) {
Assert(item.value().is_number());
return std::make_unique<UnaryRangeExprImpl<T>>(
ColumnInfo(schema.get_field_id(field_name),
schema[field_name].get_data_type()),
mapping_.at(op_name),
item.value(),
proto::plan::GenericValue::ValCase::kFloatVal);
} else {
static_assert(always_false<T>, "unsupported type");
}
return std::make_unique<UnaryRangeExprImpl<T>>(
ColumnInfo(schema.get_field_id(field_name),
schema[field_name].get_data_type()),
mapping_.at(op_name),
item.value(),
proto::plan::GenericValue::ValCase::VAL_NOT_SET);
} else if (body.size() == 2) {
bool has_lower_value = false;
bool has_upper_value = false;

View File

@ -279,22 +279,16 @@ ProtoParser::ParseUnaryRangeExpr(const proto::plan::UnaryRangeExpr& expr_pb) {
return ExtractUnaryRangeExprImpl<bool>(
field_id, data_type, expr_pb);
}
case DataType::INT8: {
return ExtractUnaryRangeExprImpl<int8_t>(
field_id, data_type, expr_pb);
}
case DataType::INT16: {
return ExtractUnaryRangeExprImpl<int16_t>(
field_id, data_type, expr_pb);
}
case DataType::INT32: {
return ExtractUnaryRangeExprImpl<int32_t>(
field_id, data_type, expr_pb);
}
// see also: https://github.com/milvus-io/milvus/issues/23646.
case DataType::INT8:
case DataType::INT16:
case DataType::INT32:
case DataType::INT64: {
return ExtractUnaryRangeExprImpl<int64_t>(
field_id, data_type, expr_pb);
}
case DataType::FLOAT: {
return ExtractUnaryRangeExprImpl<float>(
field_id, data_type, expr_pb);

View File

@ -53,10 +53,21 @@ Match<std::string_view>(const std::string_view& str,
}
}
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
inline bool
gt_ub(int64_t t) {
return t > std::numeric_limits<T>::max();
}
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
inline bool
lt_lb(int64_t t) {
return t < std::numeric_limits<T>::min();
}
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
inline bool
out_of_range(int64_t t) {
return t > std::numeric_limits<T>::max() ||
t < std::numeric_limits<T>::min();
return gt_ub<T>(t) || lt_lb<T>(t);
}
} // namespace milvus::query

View File

@ -82,6 +82,10 @@ class ExecExprVisitor : public ExprVisitor {
IndexFunc index_func,
ElementFunc element_func) -> BitsetType;
template <typename T>
auto
ExecUnaryRangeVisitorDispatcherImpl(UnaryRangeExpr& expr_raw) -> BitsetType;
template <typename T>
auto
ExecUnaryRangeVisitorDispatcher(UnaryRangeExpr& expr_raw) -> BitsetType;

View File

@ -66,6 +66,10 @@ class ExecExprVisitor : ExprVisitor {
IndexFunc func,
ElementFunc element_func) -> BitsetType;
template <typename T>
auto
ExecUnaryRangeVisitorDispatcherImpl(UnaryRangeExpr& expr_raw) -> BitsetType;
template <typename T>
auto
ExecUnaryRangeVisitorDispatcher(UnaryRangeExpr& expr_raw) -> BitsetType;
@ -351,7 +355,7 @@ ExecExprVisitor::ExecDataRangeVisitorImpl(FieldId field_id,
#pragma ide diagnostic ignored "Simplify"
template <typename T>
auto
ExecExprVisitor::ExecUnaryRangeVisitorDispatcher(UnaryRangeExpr& expr_raw)
ExecExprVisitor::ExecUnaryRangeVisitorDispatcherImpl(UnaryRangeExpr& expr_raw)
-> BitsetType {
typedef std::
conditional_t<std::is_same_v<T, std::string_view>, std::string, T>
@ -423,6 +427,58 @@ ExecExprVisitor::ExecUnaryRangeVisitorDispatcher(UnaryRangeExpr& expr_raw)
}
#pragma clang diagnostic pop
template <typename T>
auto
ExecExprVisitor::ExecUnaryRangeVisitorDispatcher(UnaryRangeExpr& expr_raw)
-> BitsetType {
if constexpr (std::is_integral_v<T>) {
auto& expr = static_cast<UnaryRangeExprImpl<int64_t>&>(expr_raw);
auto val = expr.value_;
if (!out_of_range<T>(val)) {
return ExecUnaryRangeVisitorDispatcherImpl<T>(expr_raw);
}
// see also: https://github.com/milvus-io/milvus/issues/23646.
switch (expr.op_type_) {
case proto::plan::GreaterThan:
case proto::plan::GreaterEqual: {
BitsetType r(row_count_);
if (lt_lb<T>(val)) {
r.set();
}
return r;
}
case proto::plan::LessThan:
case proto::plan::LessEqual: {
BitsetType r(row_count_);
if (gt_ub<T>(val)) {
r.set();
}
return r;
}
case proto::plan::Equal: {
BitsetType r(row_count_);
r.reset();
return r;
}
case proto::plan::NotEqual: {
BitsetType r(row_count_);
r.set();
return r;
}
default: {
PanicInfo("unsupported range node");
}
}
}
return ExecUnaryRangeVisitorDispatcherImpl<T>(expr_raw);
}
template <typename ExprValueType>
auto
ExecExprVisitor::ExecUnaryRangeVisitorDispatcherJson(UnaryRangeExpr& expr_raw)

View File

@ -173,18 +173,15 @@ ShowExprVisitor::visit(UnaryRangeExpr& expr) {
case DataType::BOOL:
json_opt_ = UnaryRangeExtract<bool>(expr);
return;
// see also: https://github.com/milvus-io/milvus/issues/23646.
case DataType::INT8:
json_opt_ = UnaryRangeExtract<int8_t>(expr);
return;
case DataType::INT16:
json_opt_ = UnaryRangeExtract<int16_t>(expr);
return;
case DataType::INT32:
json_opt_ = UnaryRangeExtract<int32_t>(expr);
return;
case DataType::INT64:
json_opt_ = UnaryRangeExtract<int64_t>(expr);
return;
case DataType::DOUBLE:
json_opt_ = UnaryRangeExtract<double>(expr);
return;