enhance: forbid two column comparison with json type in parser stage (#43382)

#43381

Signed-off-by: luzhang <luzhang@zilliz.com>
Co-authored-by: luzhang <luzhang@zilliz.com>
This commit is contained in:
zhagnlu
2025-07-24 19:42:54 +08:00
committed by GitHub
co-authored by luzhang
parent fe16de702b
commit c86307aef0
4 changed files with 262 additions and 4 deletions
@@ -173,8 +173,6 @@ func TestExpr_Compare(t *testing.T) {
`Int64Field >= FloatField`,
`FloatField == DoubleField`,
`StringField != VarCharField`,
`JSONField["A"] > Int16Field`,
`$meta["A"] > Int16Field`,
}
for _, exprStr := range exprStrs {
assertValidExpr(t, helper, exprStr)
+5
View File
@@ -399,6 +399,11 @@ func handleCompare(op planpb.OpType, left *ExprWithType, right *ExprWithType) (*
return nil, errors.New("only comparison between two fields is supported")
}
// Check if both left and right are non-JSON types
if typeutil.IsJSONType(leftColumnInfo.GetDataType()) || typeutil.IsJSONType(rightColumnInfo.GetDataType()) {
return nil, errors.New("two column comparison with JSON type is not supported")
}
expr := &planpb.Expr{
Expr: &planpb.Expr_CompareExpr{
CompareExpr: &planpb.CompareExpr{
+255
View File
@@ -335,3 +335,258 @@ func Test_decodeUnicode(t *testing.T) {
assert.NotEqual(t, `A["年份"]["月份"]`, s1)
assert.Equal(t, `A["年份"]["月份"]`, decodeUnicode(s1))
}
func Test_handleCompare(t *testing.T) {
t.Run("normal field comparison", func(t *testing.T) {
left := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: 101,
DataType: schemapb.DataType_Int64,
},
},
},
},
dataType: schemapb.DataType_Int64,
}
right := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: 102,
DataType: schemapb.DataType_Int64,
},
},
},
},
dataType: schemapb.DataType_Int64,
}
result, err := handleCompare(planpb.OpType_GreaterThan, left, right)
assert.NoError(t, err)
assert.NotNil(t, result)
assert.NotNil(t, result.GetCompareExpr())
assert.Equal(t, planpb.OpType_GreaterThan, result.GetCompareExpr().GetOp())
})
t.Run("left field is JSON type", func(t *testing.T) {
left := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: 101,
DataType: schemapb.DataType_JSON,
},
},
},
},
dataType: schemapb.DataType_JSON,
}
right := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: 102,
DataType: schemapb.DataType_Int64,
},
},
},
},
dataType: schemapb.DataType_Int64,
}
result, err := handleCompare(planpb.OpType_GreaterThan, left, right)
assert.Error(t, err)
assert.Nil(t, result)
assert.Contains(t, err.Error(), "two column comparison with JSON type is not supported")
})
t.Run("right field is JSON type", func(t *testing.T) {
left := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: 101,
DataType: schemapb.DataType_Int64,
},
},
},
},
dataType: schemapb.DataType_Int64,
}
right := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: 102,
DataType: schemapb.DataType_JSON,
},
},
},
},
dataType: schemapb.DataType_JSON,
}
result, err := handleCompare(planpb.OpType_GreaterThan, left, right)
assert.Error(t, err)
assert.Nil(t, result)
assert.Contains(t, err.Error(), "two column comparison with JSON type is not supported")
})
t.Run("both fields are JSON type", func(t *testing.T) {
left := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: 101,
DataType: schemapb.DataType_JSON,
},
},
},
},
dataType: schemapb.DataType_JSON,
}
right := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: 102,
DataType: schemapb.DataType_JSON,
},
},
},
},
dataType: schemapb.DataType_JSON,
}
result, err := handleCompare(planpb.OpType_GreaterThan, left, right)
assert.Error(t, err)
assert.Nil(t, result)
assert.Contains(t, err.Error(), "two column comparison with JSON type is not supported")
})
t.Run("left field is nil", func(t *testing.T) {
left := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: &planpb.GenericValue{
Val: &planpb.GenericValue_Int64Val{
Int64Val: 100,
},
},
},
},
},
dataType: schemapb.DataType_Int64,
}
right := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: 102,
DataType: schemapb.DataType_Int64,
},
},
},
},
dataType: schemapb.DataType_Int64,
}
result, err := handleCompare(planpb.OpType_GreaterThan, left, right)
assert.Error(t, err)
assert.Nil(t, result)
assert.Contains(t, err.Error(), "only comparison between two fields is supported")
})
t.Run("right field is nil", func(t *testing.T) {
left := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: 101,
DataType: schemapb.DataType_Int64,
},
},
},
},
dataType: schemapb.DataType_Int64,
}
right := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: &planpb.GenericValue{
Val: &planpb.GenericValue_Int64Val{
Int64Val: 100,
},
},
},
},
},
dataType: schemapb.DataType_Int64,
}
result, err := handleCompare(planpb.OpType_GreaterThan, left, right)
assert.Error(t, err)
assert.Nil(t, result)
assert.Contains(t, err.Error(), "only comparison between two fields is supported")
})
t.Run("template expression", func(t *testing.T) {
left := &ExprWithType{
expr: &planpb.Expr{
IsTemplate: true,
Expr: &planpb.Expr_ValueExpr{
ValueExpr: &planpb.ValueExpr{
Value: &planpb.GenericValue{
Val: &planpb.GenericValue_Int64Val{
Int64Val: 100,
},
},
TemplateVariableName: "var1",
},
},
},
dataType: schemapb.DataType_Int64,
}
right := &ExprWithType{
expr: &planpb.Expr{
Expr: &planpb.Expr_ColumnExpr{
ColumnExpr: &planpb.ColumnExpr{
Info: &planpb.ColumnInfo{
FieldId: 102,
DataType: schemapb.DataType_Int64,
},
},
},
},
dataType: schemapb.DataType_Int64,
}
result, err := handleCompare(planpb.OpType_GreaterThan, left, right)
assert.NoError(t, err)
assert.NotNil(t, result)
assert.NotNil(t, result.GetUnaryRangeExpr())
assert.Equal(t, planpb.OpType_GreaterThan, result.GetUnaryRangeExpr().GetOp())
assert.Equal(t, "var1", result.GetUnaryRangeExpr().GetTemplateVariableName())
})
}
@@ -1280,8 +1280,8 @@ class TestCollectionSearchInvalid(TestcaseBase):
default_search_params, default_limit,
expr,
check_task=CheckTasks.err_res,
check_items={"err_code": 65535,
"err_msg": "query failed: N6milvus21ExecOperatorExceptionE :Operator::GetOutput failed"})
check_items={"err_code": 1100,
"err_msg": "error: two column comparison with JSON type is not supported"})
@pytest.mark.tags(CaseLabel.L2)
def test_search_ef_less_than_limit(self):