diff --git a/internal/parser/planparserv2/parser_visitor.go b/internal/parser/planparserv2/parser_visitor.go index 5147144dd3d..14fee3a3170 100644 --- a/internal/parser/planparserv2/parser_visitor.go +++ b/internal/parser/planparserv2/parser_visitor.go @@ -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 { diff --git a/internal/util/indexparamcheck/stl_sort_checker.go b/internal/util/indexparamcheck/stl_sort_checker.go index 908d227ba84..f9735c27ee8 100644 --- a/internal/util/indexparamcheck/stl_sort_checker.go +++ b/internal/util/indexparamcheck/stl_sort_checker.go @@ -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())) } diff --git a/internal/util/indexparamcheck/stl_sort_checker_test.go b/internal/util/indexparamcheck/stl_sort_checker_test.go index 007adaff08e..a71b0c650db 100644 --- a/internal/util/indexparamcheck/stl_sort_checker_test.go +++ b/internal/util/indexparamcheck/stl_sort_checker_test.go @@ -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})) } diff --git a/pkg/util/typeutil/schema.go b/pkg/util/typeutil/schema.go index 29c40d6b5d8..c9e1d793064 100644 --- a/pkg/util/typeutil/schema.go +++ b/pkg/util/typeutil/schema.go @@ -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 {