diff --git a/internal/proxy/task_query.go b/internal/proxy/task_query.go index 0290ca6191..c013500b9f 100644 --- a/internal/proxy/task_query.go +++ b/internal/proxy/task_query.go @@ -85,11 +85,12 @@ type queryParams struct { } // translateToOutputFieldIDs translates output fields name to output fields id. +// If no output fields specified, return only pk field func translateToOutputFieldIDs(outputFields []string, schema *schemapb.CollectionSchema) ([]UniqueID, error) { outputFieldIDs := make([]UniqueID, 0, len(outputFields)+1) if len(outputFields) == 0 { for _, field := range schema.Fields { - if field.FieldID >= common.StartOfUserFieldID && !typeutil.IsVectorType(field.DataType) { + if field.IsPrimaryKey { outputFieldIDs = append(outputFieldIDs, field.FieldID) } } @@ -270,7 +271,7 @@ func (t *queryTask) createPlan(ctx context.Context) error { metrics.ProxyParseExpressionLatency.WithLabelValues(strconv.FormatInt(paramtable.GetNodeID(), 10), "query", metrics.SuccessLabel).Observe(float64(time.Since(start).Milliseconds())) } - t.request.OutputFields, t.userOutputFields, t.userDynamicFields, err = translateOutputFields(t.request.OutputFields, t.schema, true) + t.request.OutputFields, t.userOutputFields, t.userDynamicFields, _, err = translateOutputFields(t.request.OutputFields, t.schema, false) if err != nil { return err } diff --git a/internal/proxy/task_query_test.go b/internal/proxy/task_query_test.go index ab806c2a5d..e3e6dd99c6 100644 --- a/internal/proxy/task_query_test.go +++ b/internal/proxy/task_query_test.go @@ -404,7 +404,7 @@ func Test_translateToOutputFieldIDs(t *testing.T) { }, }, expectedError: false, - expectedIDs: []int64{100, 101}, + expectedIDs: []int64{100}, }, { name: "nil output fields", @@ -427,7 +427,7 @@ func Test_translateToOutputFieldIDs(t *testing.T) { }, }, expectedError: false, - expectedIDs: []int64{100, 101}, + expectedIDs: []int64{100}, }, { name: "full list", diff --git a/internal/proxy/task_search.go b/internal/proxy/task_search.go index 8dff68401e..d95e98afdf 100644 --- a/internal/proxy/task_search.go +++ b/internal/proxy/task_search.go @@ -88,6 +88,9 @@ type searchTask struct { groupScorer func(group *Group) error isIterator bool + // we always remove pk field from output fields, as search result already contains pk field. + // if the user explicitly set pk field in output fields, we add it back to the result. + userRequestedPkFieldExplicitly bool } func (t *searchTask) CanSkipAllocTimestamp() bool { @@ -163,7 +166,7 @@ func (t *searchTask) PreExecute(ctx context.Context) error { } } - t.request.OutputFields, t.userOutputFields, t.userDynamicFields, err = translateOutputFields(t.request.OutputFields, t.schema, false) + t.request.OutputFields, t.userOutputFields, t.userDynamicFields, t.userRequestedPkFieldExplicitly, err = translateOutputFields(t.request.OutputFields, t.schema, true) if err != nil { log.Warn("translate output fields failed", zap.Error(err)) return err @@ -786,6 +789,33 @@ func (t *searchTask) PostExecute(ctx context.Context) error { t.result.Results.OutputFields = t.userOutputFields t.result.CollectionName = t.request.GetCollectionName() t.result.Results.PrimaryFieldName = primaryFieldSchema.GetName() + if t.userRequestedPkFieldExplicitly { + t.result.Results.OutputFields = append(t.result.Results.OutputFields, primaryFieldSchema.GetName()) + var scalars *schemapb.ScalarField + if primaryFieldSchema.GetDataType() == schemapb.DataType_Int64 { + scalars = &schemapb.ScalarField{ + Data: &schemapb.ScalarField_LongData{ + LongData: t.result.Results.Ids.GetIntId(), + }, + } + } else { + scalars = &schemapb.ScalarField{ + Data: &schemapb.ScalarField_StringData{ + StringData: t.result.Results.Ids.GetStrId(), + }, + } + } + pkFieldData := &schemapb.FieldData{ + FieldName: primaryFieldSchema.GetName(), + FieldId: primaryFieldSchema.GetFieldID(), + Type: primaryFieldSchema.GetDataType(), + IsDynamic: false, + Field: &schemapb.FieldData_Scalars{ + Scalars: scalars, + }, + } + t.result.Results.FieldsData = append(t.result.Results.FieldsData, pkFieldData) + } if t.isIterator && len(t.queryInfos) == 1 && t.queryInfos[0] != nil { if iterInfo := t.queryInfos[0].GetSearchIteratorV2Info(); iterInfo != nil { t.result.Results.SearchIteratorV2Results = &schemapb.SearchIteratorV2Results{ diff --git a/internal/proxy/task_test.go b/internal/proxy/task_test.go index 8a9ff12c69..f1138eb6a9 100644 --- a/internal/proxy/task_test.go +++ b/internal/proxy/task_test.go @@ -472,6 +472,7 @@ func TestTranslateOutputFields(t *testing.T) { var outputFields []string var userOutputFields []string var userDynamicFields []string + var requestedPK bool var err error collSchema := &schemapb.CollectionSchema{ @@ -498,107 +499,124 @@ func TestTranslateOutputFields(t *testing.T) { } schema := newSchemaInfo(collSchema) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{}, schema, false) - assert.Equal(t, nil, err) + // Test empty output fields + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{}, schema, false) + assert.NoError(t, err) assert.ElementsMatch(t, []string{}, outputFields) assert.ElementsMatch(t, []string{}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.False(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName}, schema, false) - assert.Equal(t, nil, err) + // Test single field + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{idFieldName}, schema, false) + assert.NoError(t, err) assert.ElementsMatch(t, []string{idFieldName}, outputFields) assert.ElementsMatch(t, []string{idFieldName}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.True(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName, tsFieldName}, schema, false) - assert.Equal(t, nil, err) + // Test multiple fields + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{idFieldName, tsFieldName}, schema, false) + assert.NoError(t, err) assert.ElementsMatch(t, []string{idFieldName, tsFieldName}, outputFields) assert.ElementsMatch(t, []string{idFieldName, tsFieldName}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.True(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName, tsFieldName, floatVectorFieldName}, schema, false) - assert.Equal(t, nil, err) + // Test with vector field + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{idFieldName, tsFieldName, floatVectorFieldName}, schema, false) + assert.NoError(t, err) assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName}, outputFields) assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.True(t, requestedPK) - // sparse_float_vector is a BM25 function output field, so it should not be included in the output fields - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{"*"}, schema, false) - assert.Equal(t, nil, err) + // Test without id field + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{tsFieldName, floatVectorFieldName}, schema, false) + assert.NoError(t, err) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName}, outputFields) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName}, userOutputFields) + assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.False(t, requestedPK) + + // Test wildcard - should not include function output fields + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{"*"}, schema, false) + assert.NoError(t, err) assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, outputFields) assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.True(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{" * "}, schema, false) - assert.Equal(t, nil, err) + // Test wildcard with spaces + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{" * "}, schema, false) + assert.NoError(t, err) assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, outputFields) assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.True(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{"*", tsFieldName}, schema, false) - assert.Equal(t, nil, err) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, outputFields) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, userOutputFields) - assert.ElementsMatch(t, []string{}, userDynamicFields) - - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{"*", floatVectorFieldName}, schema, false) - assert.Equal(t, nil, err) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, outputFields) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, userOutputFields) - assert.ElementsMatch(t, []string{}, userDynamicFields) - - // sparse_float_vector is a BM25 function output field, so it should not be included in the output fields - _, _, _, err = translateOutputFields([]string{"*", sparseFloatVectorFieldName}, schema, false) + // Test function output field - should error + _, _, _, _, err = translateOutputFields([]string{"*", sparseFloatVectorFieldName}, schema, false) assert.Error(t, err) - _, _, _, err = translateOutputFields([]string{sparseFloatVectorFieldName}, schema, false) + _, _, _, _, err = translateOutputFields([]string{sparseFloatVectorFieldName}, schema, false) assert.Error(t, err) - _, _, _, err = translateOutputFields([]string{sparseFloatVectorFieldName}, schema, true) + _, _, _, _, err = translateOutputFields([]string{sparseFloatVectorFieldName}, schema, true) assert.Error(t, err) - //========================================================================= - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{}, schema, true) - assert.Equal(t, nil, err) - assert.ElementsMatch(t, []string{idFieldName}, outputFields) - assert.ElementsMatch(t, []string{idFieldName}, userOutputFields) + // Test with removePkField=true + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{}, schema, true) + assert.NoError(t, err) + assert.ElementsMatch(t, []string{}, outputFields) + assert.ElementsMatch(t, []string{}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.False(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName}, schema, true) - assert.Equal(t, nil, err) - assert.ElementsMatch(t, []string{idFieldName}, outputFields) - assert.ElementsMatch(t, []string{idFieldName}, userOutputFields) + // if removePkField is true, pk field should be removed from output fields + + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{"*"}, schema, true) + assert.NoError(t, err) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, outputFields) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.True(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName, tsFieldName}, schema, true) + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{idFieldName, tsFieldName}, schema, true) assert.Equal(t, nil, err) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName}, outputFields) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName}, userOutputFields) + assert.ElementsMatch(t, []string{tsFieldName}, outputFields) + assert.ElementsMatch(t, []string{tsFieldName}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.True(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName, tsFieldName, floatVectorFieldName}, schema, true) + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{idFieldName, tsFieldName, floatVectorFieldName}, schema, true) assert.Equal(t, nil, err) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName}, outputFields) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName}, userOutputFields) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName}, outputFields) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.True(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{"*"}, schema, true) + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{"*"}, schema, true) assert.Equal(t, nil, err) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, outputFields) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, userOutputFields) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, outputFields) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.True(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{"*", tsFieldName}, schema, true) + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{"*", tsFieldName}, schema, true) assert.Equal(t, nil, err) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, outputFields) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, userOutputFields) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, outputFields) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.True(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{"*", floatVectorFieldName}, schema, true) + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{"*", floatVectorFieldName}, schema, true) assert.Equal(t, nil, err) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, outputFields) - assert.ElementsMatch(t, []string{idFieldName, tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, userOutputFields) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, outputFields) + assert.ElementsMatch(t, []string{tsFieldName, floatVectorFieldName, binaryVectorFieldName, float16VectorFieldName, bfloat16VectorFieldName}, userOutputFields) assert.ElementsMatch(t, []string{}, userDynamicFields) + assert.True(t, requestedPK) - _, _, _, err = translateOutputFields([]string{"A"}, schema, true) + // Test non-existent field, dynamic field not enabled + _, _, _, _, err = translateOutputFields([]string{"A"}, schema, true) assert.Error(t, err) t.Run("enable dynamic schema", func(t *testing.T) { @@ -617,30 +635,33 @@ func TestTranslateOutputFields(t *testing.T) { } schema := newSchemaInfo(collSchema) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{"A", idFieldName}, schema, true) - assert.Equal(t, nil, err) - assert.ElementsMatch(t, []string{common.MetaFieldName, idFieldName}, outputFields) - assert.ElementsMatch(t, []string{"A", idFieldName}, userOutputFields) + outputFields, userOutputFields, userDynamicFields, requestedPK, err = translateOutputFields([]string{"A", idFieldName}, schema, true) + assert.NoError(t, err) + assert.ElementsMatch(t, []string{common.MetaFieldName}, outputFields) + assert.ElementsMatch(t, []string{"A"}, userOutputFields) + assert.ElementsMatch(t, []string{"A"}, userDynamicFields) + assert.True(t, requestedPK) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "$meta[\"A\"]"}, schema, true) + // Test invalid dynamic field expressions + _, _, _, _, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "$meta[\"A\"]"}, schema, true) assert.Error(t, err) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "$meta[]"}, schema, true) + _, _, _, _, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "$meta[]"}, schema, true) assert.Error(t, err) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "$meta[\"\"]"}, schema, true) + _, _, _, _, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "$meta[\"\"]"}, schema, true) assert.Error(t, err) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "$meta["}, schema, true) + _, _, _, _, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "$meta["}, schema, true) assert.Error(t, err) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "[]"}, schema, true) + _, _, _, _, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "[]"}, schema, true) assert.Error(t, err) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "A > 1"}, schema, true) + _, _, _, _, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, "A > 1"}, schema, true) assert.Error(t, err) - outputFields, userOutputFields, userDynamicFields, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, ""}, schema, true) + _, _, _, _, err = translateOutputFields([]string{idFieldName, floatVectorFieldName, ""}, schema, true) assert.Error(t, err) }) } diff --git a/internal/proxy/util.go b/internal/proxy/util.go index 269d5c4055..e7272b6a49 100644 --- a/internal/proxy/util.go +++ b/internal/proxy/util.go @@ -1308,7 +1308,11 @@ func computeRecall(results *schemapb.SearchResultData, gts *schemapb.SearchResul // output_fields=["*"] ==> [A,B,C,D] // output_fields=["*",A] ==> [A,B,C,D] // output_fields=["*",C] ==> [A,B,C,D] -func translateOutputFields(outputFields []string, schema *schemaInfo, addPrimary bool) ([]string, []string, []string, error) { +// +// 4th return value is true if user requested pk field explicitly or using wildcard. +// if removePkField is true, pk field will not be include in the first(resultFieldNames)/second(userOutputFields) +// return value. +func translateOutputFields(outputFields []string, schema *schemaInfo, removePkField bool) ([]string, []string, []string, bool, error) { var primaryFieldName string var dynamicField *schemapb.FieldSchema allFieldNameMap := make(map[string]*schemapb.FieldSchema) @@ -1329,9 +1333,15 @@ func translateOutputFields(outputFields []string, schema *schemaInfo, addPrimary allFieldNameMap[field.Name] = field } + userRequestedPkFieldExplicitly := false + for _, outputFieldName := range outputFields { outputFieldName = strings.TrimSpace(outputFieldName) + if outputFieldName == primaryFieldName { + userRequestedPkFieldExplicitly = true + } if outputFieldName == "*" { + userRequestedPkFieldExplicitly = true for fieldName, field := range allFieldNameMap { // skip Cold field and fields that can't be output if schema.IsFieldLoaded(field.GetFieldID()) && schema.CanRetrieveRawFieldData(field) { @@ -1343,20 +1353,20 @@ func translateOutputFields(outputFields []string, schema *schemaInfo, addPrimary } else { if field, ok := allFieldNameMap[outputFieldName]; ok { if !schema.CanRetrieveRawFieldData(field) { - return nil, nil, nil, fmt.Errorf("not allowed to retrieve raw data of field %s", outputFieldName) + return nil, nil, nil, false, fmt.Errorf("not allowed to retrieve raw data of field %s", outputFieldName) } if schema.IsFieldLoaded(field.GetFieldID()) { resultFieldNameMap[outputFieldName] = true userOutputFieldsMap[outputFieldName] = true } else { - return nil, nil, nil, fmt.Errorf("field %s is not loaded", outputFieldName) + return nil, nil, nil, false, fmt.Errorf("field %s is not loaded", outputFieldName) } } else { if schema.EnableDynamicField { if schema.IsFieldLoaded(dynamicField.GetFieldID()) { schemaH, err := typeutil.CreateSchemaHelper(schema.CollectionSchema) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, false, err } err = planparserv2.ParseIdentifier(schemaH, outputFieldName, func(expr *planpb.Expr) error { if len(expr.GetColumnExpr().GetInfo().GetNestedPath()) == 1 && @@ -1367,25 +1377,25 @@ func translateOutputFields(outputFields []string, schema *schemaInfo, addPrimary }) if err != nil { log.Info("parse output field name failed", zap.String("field name", outputFieldName)) - return nil, nil, nil, fmt.Errorf("parse output field name failed: %s", outputFieldName) + return nil, nil, nil, false, fmt.Errorf("parse output field name failed: %s", outputFieldName) } resultFieldNameMap[common.MetaFieldName] = true userOutputFieldsMap[outputFieldName] = true userDynamicFieldsMap[outputFieldName] = true } else { // TODO after cold field be able to fetched with chunk cache, this check shall be removed - return nil, nil, nil, fmt.Errorf("field %s cannot be returned since dynamic field not loaded", outputFieldName) + return nil, nil, nil, false, fmt.Errorf("field %s cannot be returned since dynamic field not loaded", outputFieldName) } } else { - return nil, nil, nil, fmt.Errorf("field %s not exist", outputFieldName) + return nil, nil, nil, false, fmt.Errorf("field %s not exist", outputFieldName) } } } } - if addPrimary { - resultFieldNameMap[primaryFieldName] = true - userOutputFieldsMap[primaryFieldName] = true + if removePkField { + delete(resultFieldNameMap, primaryFieldName) + delete(userOutputFieldsMap, primaryFieldName) } for fieldName := range resultFieldNameMap { @@ -1400,7 +1410,7 @@ func translateOutputFields(outputFields []string, schema *schemaInfo, addPrimary } } - return resultFieldNames, userOutputFields, userDynamicFields, nil + return resultFieldNames, userOutputFields, userDynamicFields, userRequestedPkFieldExplicitly, nil } func validateIndexName(indexName string) error {