fix: stl-sort allows struct scalar fields (#47626)

issue: https://github.com/milvus-io/milvus/issues/47620

Signed-off-by: SpadeA <tangchenjie1210@gmail.com>
pull/47670/head
Spade A 2026-02-09 10:31:52 +08:00 committed by GitHub
parent f5713255c0
commit ba29e0ba48
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 25 additions and 2 deletions

View File

@ -826,7 +826,7 @@ func (v *ParserVisitor) getColumnInfoFromStructSubField(tokenText string) (*plan
}
// Construct full field name for struct array field
fullFieldName := v.currentStructArrayField + "[" + fieldName + "]"
fullFieldName := typeutil.ConcatStructFieldName(v.currentStructArrayField, fieldName)
// Get the struct array field info
field, err := v.schema.GetFieldFromName(fullFieldName)
if err != nil {
@ -2202,7 +2202,7 @@ func (v *ParserVisitor) VisitStructSubField(ctx *parser.StructSubFieldContext) i
}
// Construct full field name for struct array field
fullFieldName := v.currentStructArrayField + "[" + fieldName + "]"
fullFieldName := typeutil.ConcatStructFieldName(v.currentStructArrayField, fieldName)
// Get the struct array field info
field, err := v.schema.GetFieldFromName(fullFieldName)
if err != nil {

View File

@ -20,6 +20,13 @@ func (c *STLSORTChecker) CheckTrain(dataType schemapb.DataType, elementType sche
func (c *STLSORTChecker) CheckValidDataType(indexType IndexType, field *schemapb.FieldSchema) error {
dataType := field.GetDataType()
if typeutil.IsArrayType(dataType) && typeutil.IsStructSubField(field.GetName()) {
elemType := field.GetElementType()
if !typeutil.IsArithmetic(elemType) && !typeutil.IsStringType(elemType) && !typeutil.IsTimestamptzType(elemType) {
return errors.New(fmt.Sprintf("STL_SORT are only supported on numeric, varchar or timestamptz field, got struct sub-field of %s", field.GetElementType()))
}
return nil
}
if !typeutil.IsArithmetic(dataType) && !typeutil.IsStringType(dataType) && !typeutil.IsTimestamptzType(dataType) {
return errors.New(fmt.Sprintf("STL_SORT are only supported on numeric, varchar or timestamptz field, got %s", field.GetDataType()))
}

View File

@ -19,4 +19,14 @@ func Test_STLSORTIndexChecker(t *testing.T) {
assert.Error(t, c.CheckValidDataType(IndexSTLSORT, &schemapb.FieldSchema{DataType: schemapb.DataType_Bool}))
assert.Error(t, c.CheckValidDataType(IndexSTLSORT, &schemapb.FieldSchema{DataType: schemapb.DataType_JSON}))
// struct sub-fields: name follows "structName[fieldName]" convention, DataType is Array
assert.NoError(t, c.CheckValidDataType(IndexSTLSORT, &schemapb.FieldSchema{Name: "myStruct[age]", DataType: schemapb.DataType_Array, ElementType: schemapb.DataType_Int64}))
assert.NoError(t, c.CheckValidDataType(IndexSTLSORT, &schemapb.FieldSchema{Name: "myStruct[score]", DataType: schemapb.DataType_Array, ElementType: schemapb.DataType_Float}))
assert.NoError(t, c.CheckValidDataType(IndexSTLSORT, &schemapb.FieldSchema{Name: "myStruct[name]", DataType: schemapb.DataType_Array, ElementType: schemapb.DataType_VarChar}))
assert.Error(t, c.CheckValidDataType(IndexSTLSORT, &schemapb.FieldSchema{Name: "myStruct[flag]", DataType: schemapb.DataType_Array, ElementType: schemapb.DataType_Bool}))
assert.Error(t, c.CheckValidDataType(IndexSTLSORT, &schemapb.FieldSchema{Name: "myStruct[meta]", DataType: schemapb.DataType_Array, ElementType: schemapb.DataType_JSON}))
// regular Array field (not a struct sub-field) should still be rejected
assert.Error(t, c.CheckValidDataType(IndexSTLSORT, &schemapb.FieldSchema{Name: "tags", DataType: schemapb.DataType_Array, ElementType: schemapb.DataType_Int64}))
}

View File

@ -2667,6 +2667,12 @@ func ConcatStructFieldName(structName string, fieldName string) string {
return fmt.Sprintf("%s[%s]", structName, fieldName)
}
// IsStructSubField checks if a field name follows the "structName[fieldName]" convention,
// indicating it is a sub-field within a StructArrayField.
func IsStructSubField(fieldName string) bool {
return strings.Contains(fieldName, "[")
}
func ExtractStructFieldName(fieldName string) (string, error) {
parts := strings.Split(fieldName, "[")
if len(parts) == 1 {