mirror of https://github.com/milvus-io/milvus.git
Support Default Value (#23448)
Signed-off-by: lixinguo <xinguo.li@zilliz.com> Co-authored-by: lixinguo <xinguo.li@zilliz.com>pull/23006/head
parent
849de66be8
commit
8a85dd6869
|
@ -31,7 +31,7 @@ func TestInsertTask_CheckAligned(t *testing.T) {
|
|||
err = case1.insertMsg.CheckAligned()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// checkLengthOfFieldsData was already checked by TestInsertTask_checkLengthOfFieldsData
|
||||
// fillFieldsDataBySchema was already checked by TestInsertTask_fillFieldsDataBySchema
|
||||
|
||||
boolFieldSchema := &schemapb.FieldSchema{DataType: schemapb.DataType_Bool}
|
||||
int8FieldSchema := &schemapb.FieldSchema{DataType: schemapb.DataType_Int8}
|
||||
|
|
|
@ -147,6 +147,7 @@ func (it *upsertTask) insertPreExecute(ctx context.Context) error {
|
|||
log.Error("valid partition name failed", zap.String("partition name", partitionTag), zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
||||
rowNums := uint32(it.upsertMsg.InsertMsg.NRows())
|
||||
// set upsertTask.insertRequest.rowIDs
|
||||
tr := timerecord.NewTimeRecorder("applyPK")
|
||||
|
|
|
@ -59,7 +59,7 @@ func TestUpsertTask_CheckAligned(t *testing.T) {
|
|||
err = case1.upsertMsg.InsertMsg.CheckAligned()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// checkLengthOfFieldsData was already checked by TestUpsertTask_checkLengthOfFieldsData
|
||||
// fillFieldsDataBySchema was already checked by TestUpsertTask_fillFieldsDataBySchema
|
||||
|
||||
boolFieldSchema := &schemapb.FieldSchema{DataType: schemapb.DataType_Bool}
|
||||
int8FieldSchema := &schemapb.FieldSchema{DataType: schemapb.DataType_Int8}
|
||||
|
|
|
@ -892,16 +892,56 @@ func isPartitionLoaded(ctx context.Context, qc types.QueryCoord, collID int64, p
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func checkLengthOfFieldsData(schema *schemapb.CollectionSchema, insertMsg *msgstream.InsertMsg) error {
|
||||
func fillFieldsDataBySchema(schema *schemapb.CollectionSchema, insertMsg *msgstream.InsertMsg) error {
|
||||
neededFieldsNum := 0
|
||||
for _, field := range schema.Fields {
|
||||
if !field.AutoID {
|
||||
isPrimaryKeyNum := 0
|
||||
|
||||
var dataNameSet = typeutil.NewSet[string]()
|
||||
|
||||
for _, data := range insertMsg.FieldsData {
|
||||
dataNameSet.Insert(data.GetFieldName())
|
||||
}
|
||||
|
||||
for _, fieldSchema := range schema.Fields {
|
||||
if fieldSchema.AutoID && !fieldSchema.IsPrimaryKey {
|
||||
log.Error("not primary key field, but set autoID true", zap.String("fieldSchemaName", fieldSchema.GetName()))
|
||||
return merr.WrapErrParameterInvalid("only primary key field can set autoID true", "")
|
||||
}
|
||||
if fieldSchema.GetDefaultValue() != nil && fieldSchema.IsPrimaryKey {
|
||||
return merr.WrapErrParameterInvalid("no default data", "", "pk field schema can not set default value")
|
||||
}
|
||||
if !fieldSchema.AutoID {
|
||||
neededFieldsNum++
|
||||
}
|
||||
// if has no field pass in, consider use default value
|
||||
// so complete it with field schema
|
||||
if _, ok := dataNameSet[fieldSchema.GetName()]; !ok {
|
||||
// primary key can not use default value
|
||||
if fieldSchema.IsPrimaryKey {
|
||||
isPrimaryKeyNum++
|
||||
continue
|
||||
}
|
||||
dataToAppend := &schemapb.FieldData{
|
||||
Type: fieldSchema.GetDataType(),
|
||||
FieldName: fieldSchema.GetName(),
|
||||
}
|
||||
insertMsg.FieldsData = append(insertMsg.FieldsData, dataToAppend)
|
||||
}
|
||||
}
|
||||
|
||||
if len(insertMsg.FieldsData) < neededFieldsNum {
|
||||
return merr.WrapErrParameterInvalid(neededFieldsNum, len(insertMsg.FieldsData), "the length of passed fields is less than needed")
|
||||
if isPrimaryKeyNum > 1 {
|
||||
log.Error("the number of passed primary key fields is more than 1",
|
||||
zap.Int64("primaryKeyNum", int64(isPrimaryKeyNum)),
|
||||
zap.String("CollectionSchemaName", schema.GetName()))
|
||||
return merr.WrapErrParameterInvalid("0 or 1", fmt.Sprint(isPrimaryKeyNum), "the number of passed primary key fields is more than 1")
|
||||
}
|
||||
|
||||
if len(insertMsg.FieldsData) != neededFieldsNum {
|
||||
log.Error("the length of passed fields is not equal to needed",
|
||||
zap.Int("expectFieldNumber", neededFieldsNum),
|
||||
zap.Int("passFieldNumber", len(insertMsg.FieldsData)),
|
||||
zap.String("CollectionSchemaName", schema.GetName()))
|
||||
return merr.WrapErrParameterInvalid(neededFieldsNum, len(insertMsg.FieldsData), "the length of passed fields is equal to needed")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -914,7 +954,7 @@ func checkPrimaryFieldData(schema *schemapb.CollectionSchema, result *milvuspb.M
|
|||
return nil, merr.WrapErrParameterInvalid("invalid num_rows", fmt.Sprint(rowNums), "num_rows should be greater than 0")
|
||||
}
|
||||
|
||||
if err := checkLengthOfFieldsData(schema, insertMsg); err != nil {
|
||||
if err := fillFieldsDataBySchema(schema, insertMsg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -1084,3 +1124,12 @@ func getPartitionProgress(
|
|||
|
||||
return
|
||||
}
|
||||
|
||||
func memsetLoop[T any](v T, numRows int) []T {
|
||||
ret := make([]T, 0, numRows)
|
||||
for i := 0; i < numRows; i++ {
|
||||
ret = append(ret, v)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
"github.com/milvus-io/milvus/pkg/util/merr"
|
||||
"github.com/milvus-io/milvus/pkg/util/tsoutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
@ -1002,14 +1003,14 @@ func Test_isPartitionIsLoaded(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func Test_InsertTaskCheckLengthOfFieldsData(t *testing.T) {
|
||||
func Test_InsertTaskfillFieldsDataBySchema(t *testing.T) {
|
||||
var err error
|
||||
|
||||
// schema is empty, though won't happen in system
|
||||
case1 := insertTask{
|
||||
schema: &schemapb.CollectionSchema{
|
||||
Name: "TestInsertTask_checkLengthOfFieldsData",
|
||||
Description: "TestInsertTask_checkLengthOfFieldsData",
|
||||
Name: "TestInsertTask_fillFieldsDataBySchema",
|
||||
Description: "TestInsertTask_fillFieldsDataBySchema",
|
||||
AutoID: false,
|
||||
Fields: []*schemapb.FieldSchema{},
|
||||
},
|
||||
|
@ -1018,28 +1019,30 @@ func Test_InsertTaskCheckLengthOfFieldsData(t *testing.T) {
|
|||
Base: &commonpb.MsgBase{
|
||||
MsgType: commonpb.MsgType_Insert,
|
||||
},
|
||||
DbName: "TestInsertTask_checkLengthOfFieldsData",
|
||||
CollectionName: "TestInsertTask_checkLengthOfFieldsData",
|
||||
PartitionName: "TestInsertTask_checkLengthOfFieldsData",
|
||||
DbName: "TestInsertTask_fillFieldsDataBySchema",
|
||||
CollectionName: "TestInsertTask_fillFieldsDataBySchema",
|
||||
PartitionName: "TestInsertTask_fillFieldsDataBySchema",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = checkLengthOfFieldsData(case1.schema, case1.insertMsg)
|
||||
err = fillFieldsDataBySchema(case1.schema, case1.insertMsg)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
// schema has two fields, neither of them are autoID
|
||||
// schema has two fields, msg has no field. fields will be filled in
|
||||
case2 := insertTask{
|
||||
schema: &schemapb.CollectionSchema{
|
||||
Name: "TestInsertTask_checkLengthOfFieldsData",
|
||||
Description: "TestInsertTask_checkLengthOfFieldsData",
|
||||
Name: "TestInsertTask_fillFieldsDataBySchema",
|
||||
Description: "TestInsertTask_fillFieldsDataBySchema",
|
||||
AutoID: false,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "a",
|
||||
AutoID: false,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
AutoID: false,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
|
@ -1053,50 +1056,26 @@ func Test_InsertTaskCheckLengthOfFieldsData(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
// passed fields is empty
|
||||
// case2.BaseInsertTask = BaseInsertTask{
|
||||
// InsertRequest: msgpb.InsertRequest{
|
||||
// Base: &commonpb.MsgBase{
|
||||
// MsgType: commonpb.MsgType_Insert,
|
||||
// MsgID: 0,
|
||||
// SourceID: paramtable.GetNodeID(),
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
err = checkLengthOfFieldsData(case2.schema, case2.insertMsg)
|
||||
assert.NotEqual(t, nil, err)
|
||||
// the num of passed fields is less than needed
|
||||
case2.insertMsg.FieldsData = []*schemapb.FieldData{
|
||||
{
|
||||
Type: schemapb.DataType_Int64,
|
||||
},
|
||||
}
|
||||
err = checkLengthOfFieldsData(case2.schema, case2.insertMsg)
|
||||
assert.NotEqual(t, nil, err)
|
||||
// satisfied
|
||||
case2.insertMsg.FieldsData = []*schemapb.FieldData{
|
||||
{
|
||||
Type: schemapb.DataType_Int64,
|
||||
},
|
||||
{
|
||||
Type: schemapb.DataType_Int64,
|
||||
},
|
||||
}
|
||||
err = checkLengthOfFieldsData(case2.schema, case2.insertMsg)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
// schema has two field, one of them are autoID
|
||||
err = fillFieldsDataBySchema(case2.schema, case2.insertMsg)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, len(case2.insertMsg.FieldsData), 2)
|
||||
|
||||
// schema has a pk can't fill in, and another can.
|
||||
case3 := insertTask{
|
||||
schema: &schemapb.CollectionSchema{
|
||||
Name: "TestInsertTask_checkLengthOfFieldsData",
|
||||
Description: "TestInsertTask_checkLengthOfFieldsData",
|
||||
Name: "TestInsertTask_fillFieldsDataBySchema",
|
||||
Description: "TestInsertTask_fillFieldsDataBySchema",
|
||||
AutoID: false,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
AutoID: true,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
Name: "a",
|
||||
AutoID: true,
|
||||
IsPrimaryKey: true,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
AutoID: false,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
|
@ -1110,28 +1089,28 @@ func Test_InsertTaskCheckLengthOfFieldsData(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
// passed fields is empty
|
||||
// case3.req = &milvuspb.InsertRequest{}
|
||||
err = checkLengthOfFieldsData(case3.schema, case3.insertMsg)
|
||||
assert.NotEqual(t, nil, err)
|
||||
// satisfied
|
||||
case3.insertMsg.FieldsData = []*schemapb.FieldData{
|
||||
{
|
||||
Type: schemapb.DataType_Int64,
|
||||
},
|
||||
}
|
||||
err = checkLengthOfFieldsData(case3.schema, case3.insertMsg)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
// schema has one field which is autoID
|
||||
err = fillFieldsDataBySchema(case3.schema, case3.insertMsg)
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, len(case3.insertMsg.FieldsData), 1)
|
||||
|
||||
// schema has a pk can't fill in, and another can, but pk autoid == false
|
||||
// means that data pass less
|
||||
case4 := insertTask{
|
||||
schema: &schemapb.CollectionSchema{
|
||||
Name: "TestInsertTask_checkLengthOfFieldsData",
|
||||
Description: "TestInsertTask_checkLengthOfFieldsData",
|
||||
Name: "TestInsertTask_fillFieldsDataBySchema",
|
||||
Description: "TestInsertTask_fillFieldsDataBySchema",
|
||||
AutoID: false,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
AutoID: true,
|
||||
Name: "a",
|
||||
AutoID: false,
|
||||
IsPrimaryKey: true,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
AutoID: false,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
},
|
||||
|
@ -1144,11 +1123,150 @@ func Test_InsertTaskCheckLengthOfFieldsData(t *testing.T) {
|
|||
},
|
||||
},
|
||||
}
|
||||
// passed fields is empty
|
||||
// satisfied
|
||||
// case4.req = &milvuspb.InsertRequest{}
|
||||
err = checkLengthOfFieldsData(case4.schema, case4.insertMsg)
|
||||
assert.Equal(t, nil, err)
|
||||
|
||||
err = fillFieldsDataBySchema(case4.schema, case4.insertMsg)
|
||||
assert.ErrorIs(t, merr.ErrParameterInvalid, err)
|
||||
assert.Equal(t, len(case4.insertMsg.FieldsData), 1)
|
||||
|
||||
// pass more data field
|
||||
case5 := insertTask{
|
||||
schema: &schemapb.CollectionSchema{
|
||||
Name: "TestInsertTask_fillFieldsDataBySchema",
|
||||
Description: "TestInsertTask_fillFieldsDataBySchema",
|
||||
AutoID: false,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "a",
|
||||
AutoID: false,
|
||||
IsPrimaryKey: false,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
AutoID: false,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
},
|
||||
},
|
||||
insertMsg: &BaseInsertTask{
|
||||
InsertRequest: msgpb.InsertRequest{
|
||||
Base: &commonpb.MsgBase{
|
||||
MsgType: commonpb.MsgType_Insert,
|
||||
},
|
||||
FieldsData: []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "c",
|
||||
Type: schemapb.DataType_Int64,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = fillFieldsDataBySchema(case5.schema, case5.insertMsg)
|
||||
assert.ErrorIs(t, merr.ErrParameterInvalid, err)
|
||||
assert.Equal(t, len(case5.insertMsg.FieldsData), 3)
|
||||
|
||||
// not pk, but autoid == true
|
||||
case6 := insertTask{
|
||||
schema: &schemapb.CollectionSchema{
|
||||
Name: "TestInsertTask_fillFieldsDataBySchema",
|
||||
Description: "TestInsertTask_fillFieldsDataBySchema",
|
||||
AutoID: false,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "a",
|
||||
AutoID: false,
|
||||
IsPrimaryKey: true,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
AutoID: true,
|
||||
IsPrimaryKey: false,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
},
|
||||
},
|
||||
insertMsg: &BaseInsertTask{
|
||||
InsertRequest: msgpb.InsertRequest{
|
||||
Base: &commonpb.MsgBase{
|
||||
MsgType: commonpb.MsgType_Insert,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = fillFieldsDataBySchema(case6.schema, case6.insertMsg)
|
||||
assert.ErrorIs(t, merr.ErrParameterInvalid, err)
|
||||
assert.Equal(t, len(case6.insertMsg.FieldsData), 0)
|
||||
|
||||
// more than one pk
|
||||
case7 := insertTask{
|
||||
schema: &schemapb.CollectionSchema{
|
||||
Name: "TestInsertTask_fillFieldsDataBySchema",
|
||||
Description: "TestInsertTask_fillFieldsDataBySchema",
|
||||
AutoID: false,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "a",
|
||||
AutoID: false,
|
||||
IsPrimaryKey: true,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
AutoID: false,
|
||||
IsPrimaryKey: true,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
},
|
||||
},
|
||||
insertMsg: &BaseInsertTask{
|
||||
InsertRequest: msgpb.InsertRequest{
|
||||
Base: &commonpb.MsgBase{
|
||||
MsgType: commonpb.MsgType_Insert,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = fillFieldsDataBySchema(case7.schema, case7.insertMsg)
|
||||
assert.ErrorIs(t, merr.ErrParameterInvalid, err)
|
||||
assert.Equal(t, len(case7.insertMsg.FieldsData), 0)
|
||||
|
||||
// pk can not set default value
|
||||
case8 := insertTask{
|
||||
schema: &schemapb.CollectionSchema{
|
||||
Name: "TestInsertTask_fillFieldsDataBySchema",
|
||||
Description: "TestInsertTask_fillFieldsDataBySchema",
|
||||
AutoID: false,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "a",
|
||||
AutoID: false,
|
||||
IsPrimaryKey: true,
|
||||
DataType: schemapb.DataType_Int64,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_LongData{
|
||||
LongData: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
insertMsg: &BaseInsertTask{
|
||||
InsertRequest: msgpb.InsertRequest{
|
||||
Base: &commonpb.MsgBase{
|
||||
MsgType: commonpb.MsgType_Insert,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = fillFieldsDataBySchema(case8.schema, case8.insertMsg)
|
||||
assert.ErrorIs(t, merr.ErrParameterInvalid, err)
|
||||
assert.Equal(t, len(case8.insertMsg.FieldsData), 0)
|
||||
}
|
||||
|
||||
func Test_InsertTaskCheckPrimaryFieldData(t *testing.T) {
|
||||
|
@ -1470,8 +1588,8 @@ func Test_UpsertTaskCheckPrimaryFieldData(t *testing.T) {
|
|||
},
|
||||
FieldsData: []*schemapb.FieldData{
|
||||
{
|
||||
Type: schemapb.DataType_Int64,
|
||||
FieldName: "int64Field",
|
||||
Type: schemapb.DataType_Float,
|
||||
FieldName: "floatField",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -4,10 +4,12 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/milvus-io/milvus-proto/go-api/schemapb"
|
||||
"github.com/milvus-io/milvus/pkg/log"
|
||||
"github.com/milvus-io/milvus/pkg/util/funcutil"
|
||||
"github.com/milvus-io/milvus/pkg/util/merr"
|
||||
"github.com/milvus-io/milvus/pkg/util/paramtable"
|
||||
"github.com/milvus-io/milvus/pkg/util/typeutil"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type validateUtil struct {
|
||||
|
@ -41,6 +43,11 @@ func (v *validateUtil) Validate(data []*schemapb.FieldData, schema *schemapb.Col
|
|||
return err
|
||||
}
|
||||
|
||||
err = v.fillWithDefaultValue(data, helper, numRows)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := v.checkAligned(data, helper, numRows); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -139,6 +146,82 @@ func (v *validateUtil) checkAligned(data []*schemapb.FieldData, schema *typeutil
|
|||
return nil
|
||||
}
|
||||
|
||||
func (v *validateUtil) fillWithDefaultValue(data []*schemapb.FieldData, schema *typeutil.SchemaHelper, numRows uint64) error {
|
||||
for _, field := range data {
|
||||
fieldSchema, err := schema.GetFieldFromName(field.GetFieldName())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if default value is not set, continue
|
||||
// compatible with 2.2.x
|
||||
if fieldSchema.GetDefaultValue() == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
switch field.Field.(type) {
|
||||
case *schemapb.FieldData_Scalars:
|
||||
switch sd := field.GetScalars().GetData().(type) {
|
||||
case *schemapb.ScalarField_BoolData:
|
||||
if len(sd.BoolData.Data) == 0 {
|
||||
defaultValue := fieldSchema.GetDefaultValue().GetBoolData()
|
||||
sd.BoolData.Data = memsetLoop(defaultValue, int(numRows))
|
||||
}
|
||||
|
||||
case *schemapb.ScalarField_IntData:
|
||||
if len(sd.IntData.Data) == 0 {
|
||||
defaultValue := fieldSchema.GetDefaultValue().GetIntData()
|
||||
sd.IntData.Data = memsetLoop(defaultValue, int(numRows))
|
||||
}
|
||||
|
||||
case *schemapb.ScalarField_LongData:
|
||||
if len(sd.LongData.Data) == 0 {
|
||||
defaultValue := fieldSchema.GetDefaultValue().GetLongData()
|
||||
sd.LongData.Data = memsetLoop(defaultValue, int(numRows))
|
||||
}
|
||||
|
||||
case *schemapb.ScalarField_FloatData:
|
||||
if len(sd.FloatData.Data) == 0 {
|
||||
defaultValue := fieldSchema.GetDefaultValue().GetFloatData()
|
||||
sd.FloatData.Data = memsetLoop(defaultValue, int(numRows))
|
||||
}
|
||||
|
||||
case *schemapb.ScalarField_DoubleData:
|
||||
if len(sd.DoubleData.Data) == 0 {
|
||||
defaultValue := fieldSchema.GetDefaultValue().GetDoubleData()
|
||||
sd.DoubleData.Data = memsetLoop(defaultValue, int(numRows))
|
||||
}
|
||||
|
||||
case *schemapb.ScalarField_StringData:
|
||||
if len(sd.StringData.Data) == 0 {
|
||||
defaultValue := fieldSchema.GetDefaultValue().GetStringData()
|
||||
sd.StringData.Data = memsetLoop(defaultValue, int(numRows))
|
||||
}
|
||||
|
||||
case *schemapb.ScalarField_ArrayData:
|
||||
log.Error("array type not support default value", zap.String("fieldSchemaName", field.GetFieldName()))
|
||||
return merr.WrapErrParameterInvalid("not set default value", "", "array type not support default value")
|
||||
|
||||
case *schemapb.ScalarField_JsonData:
|
||||
log.Error("json type not support default value", zap.String("fieldSchemaName", field.GetFieldName()))
|
||||
return merr.WrapErrParameterInvalid("not set default value", "", "json type not support default value")
|
||||
|
||||
default:
|
||||
panic("undefined data type " + field.Type.String())
|
||||
}
|
||||
|
||||
case *schemapb.FieldData_Vectors:
|
||||
log.Error("vectors not support default value", zap.String("fieldSchemaName", field.GetFieldName()))
|
||||
return merr.WrapErrParameterInvalid("not set default value", "", "json type not support default value")
|
||||
|
||||
default:
|
||||
panic("undefined data type " + field.Type.String())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *validateUtil) checkFloatVectorFieldData(field *schemapb.FieldData, fieldSchema *schemapb.FieldSchema) error {
|
||||
floatArray := field.GetVectors().GetFloatVector().GetData()
|
||||
if floatArray == nil {
|
||||
|
|
|
@ -956,3 +956,881 @@ func Test_validateUtil_Validate(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func checkFillWithDefaultValueData[T comparable](values []T, v T, length int) bool {
|
||||
if len(values) != length {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
if values[i] != v {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func Test_validateUtil_fillWithDefaultValue(t *testing.T) {
|
||||
t.Run("bool scalars schema not found", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Bool,
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 1)
|
||||
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("bool scalars has no data, and schema default value is legal", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Bool,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_BoolData{
|
||||
BoolData: &schemapb.BoolArray{
|
||||
Data: []bool{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var key bool
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_BinaryVector,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_BoolData{
|
||||
BoolData: key,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetBoolData().Data, schema.Fields[0].GetDefaultValue().GetBoolData(), 10)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
t.Run("bool scalars has data, and schema default value is not set", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Bool,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_BoolData{
|
||||
BoolData: &schemapb.BoolArray{
|
||||
Data: []bool{true},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_BinaryVector,
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("bool scalars has data, and schema default value is legal", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Bool,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_BoolData{
|
||||
BoolData: &schemapb.BoolArray{
|
||||
Data: []bool{true},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_BinaryVector,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_BoolData{
|
||||
BoolData: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetBoolData().Data, true, 1)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
t.Run("int scalars schema not found", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Int32,
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 1)
|
||||
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("int scalars has no data, and schema default value is legal", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Int32,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_IntData{
|
||||
IntData: &schemapb.IntArray{
|
||||
Data: []int32{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Int32,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_IntData{
|
||||
IntData: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetIntData().Data, schema.Fields[0].GetDefaultValue().GetIntData(), 10)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
t.Run("int scalars has data, and schema default value is not set", func(t *testing.T) {
|
||||
intData := []int32{1}
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Int32,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_IntData{
|
||||
IntData: &schemapb.IntArray{
|
||||
Data: intData,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Int32,
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("int scalars has data, and schema default value is legal", func(t *testing.T) {
|
||||
intData := []int32{1}
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Int32,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_IntData{
|
||||
IntData: &schemapb.IntArray{
|
||||
Data: intData,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Int32,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_IntData{
|
||||
IntData: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetIntData().Data, intData[0], 1)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
t.Run("long scalars schema not found", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Int64,
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 1)
|
||||
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("long scalars has no data, and schema default value is legal", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Int64,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_LongData{
|
||||
LongData: &schemapb.LongArray{
|
||||
Data: []int64{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Int32,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_LongData{
|
||||
LongData: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetLongData().Data, schema.Fields[0].GetDefaultValue().GetLongData(), 10)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
t.Run("long scalars has data, and schema default value is not set", func(t *testing.T) {
|
||||
longData := []int64{1}
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Int64,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_LongData{
|
||||
LongData: &schemapb.LongArray{
|
||||
Data: longData,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Int64,
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("long scalars has data, and schema default value is legal", func(t *testing.T) {
|
||||
longData := []int64{1}
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Int64,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_LongData{
|
||||
LongData: &schemapb.LongArray{
|
||||
Data: longData,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Int64,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_LongData{
|
||||
LongData: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetLongData().Data, longData[0], 1)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
t.Run("float scalars schema not found", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Float,
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 1)
|
||||
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("float scalars has no data, and schema default value is legal", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Float,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_FloatData{
|
||||
FloatData: &schemapb.FloatArray{
|
||||
Data: []float32{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Float,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_FloatData{
|
||||
FloatData: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetFloatData().Data, schema.Fields[0].GetDefaultValue().GetFloatData(), 10)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
t.Run("float scalars has data, and schema default value is not set", func(t *testing.T) {
|
||||
floatData := []float32{1}
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Float,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_FloatData{
|
||||
FloatData: &schemapb.FloatArray{
|
||||
Data: floatData,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Float,
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("float scalars has data, and schema default value is legal", func(t *testing.T) {
|
||||
floatData := []float32{1}
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Float,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_FloatData{
|
||||
FloatData: &schemapb.FloatArray{
|
||||
Data: floatData,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Float,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_FloatData{
|
||||
FloatData: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetFloatData().Data, floatData[0], 1)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
t.Run("double scalars schema not found", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Double,
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 1)
|
||||
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("double scalars has no data, and schema default value is legal", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Double,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_DoubleData{
|
||||
DoubleData: &schemapb.DoubleArray{
|
||||
Data: []float64{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Double,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_DoubleData{
|
||||
DoubleData: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetDoubleData().Data, schema.Fields[0].GetDefaultValue().GetDoubleData(), 10)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
t.Run("double scalars has data, and schema default value is not set", func(t *testing.T) {
|
||||
doubleData := []float64{1}
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Double,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_DoubleData{
|
||||
DoubleData: &schemapb.DoubleArray{
|
||||
Data: doubleData,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Double,
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("double scalars has data, and schema default value is legal", func(t *testing.T) {
|
||||
doubleData := []float64{1}
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_Double,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_DoubleData{
|
||||
DoubleData: &schemapb.DoubleArray{
|
||||
Data: doubleData,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_Double,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_DoubleData{
|
||||
DoubleData: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetDoubleData().Data, doubleData[0], 1)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
t.Run("string scalars schema not found", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_VarChar,
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 1)
|
||||
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("string scalars has no data, and schema default value is legal", func(t *testing.T) {
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_VarChar,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_StringData{
|
||||
StringData: &schemapb.StringArray{
|
||||
Data: []string{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_VarChar,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_StringData{
|
||||
StringData: "b",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetStringData().Data, schema.Fields[0].GetDefaultValue().GetStringData(), 10)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
t.Run("string scalars has data, and schema default value is legal", func(t *testing.T) {
|
||||
stringData := []string{"a"}
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_VarChar,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_StringData{
|
||||
StringData: &schemapb.StringArray{
|
||||
Data: stringData,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_VarChar,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_StringData{
|
||||
StringData: "b",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetStringData().Data, stringData[0], 1)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
t.Run("string scalars has data, and schema default value is not set", func(t *testing.T) {
|
||||
stringData := []string{"a"}
|
||||
data := []*schemapb.FieldData{
|
||||
{
|
||||
FieldName: "test",
|
||||
Type: schemapb.DataType_VarChar,
|
||||
Field: &schemapb.FieldData_Scalars{
|
||||
Scalars: &schemapb.ScalarField{
|
||||
Data: &schemapb.ScalarField_StringData{
|
||||
StringData: &schemapb.StringArray{
|
||||
Data: stringData,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
schema := &schemapb.CollectionSchema{
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
Name: "test",
|
||||
DataType: schemapb.DataType_VarChar,
|
||||
},
|
||||
},
|
||||
}
|
||||
h, err := typeutil.CreateSchemaHelper(schema)
|
||||
assert.NoError(t, err)
|
||||
|
||||
v := newValidateUtil()
|
||||
|
||||
err = v.fillWithDefaultValue(data, h, 10)
|
||||
|
||||
assert.NoError(t, err)
|
||||
|
||||
flag := checkFillWithDefaultValueData(data[0].GetScalars().GetStringData().Data, stringData[0], 1)
|
||||
assert.True(t, flag)
|
||||
})
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package rootcoord
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
"github.com/golang/protobuf/proto"
|
||||
|
@ -77,6 +78,56 @@ func (t *createCollectionTask) validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func defaultValueTypeMatch(schema *schemapb.CollectionSchema) error {
|
||||
for _, fieldSchema := range schema.Fields {
|
||||
if fieldSchema.GetDefaultValue() != nil {
|
||||
switch fieldSchema.GetDefaultValue().Data.(type) {
|
||||
case *schemapb.ValueField_BoolData:
|
||||
if fieldSchema.GetDataType() != schemapb.DataType_Bool {
|
||||
return merr.WrapErrParameterInvalid("DataType_Bool", "not match", "default value type mismatches field schema type")
|
||||
}
|
||||
case *schemapb.ValueField_IntData:
|
||||
if fieldSchema.GetDataType() != schemapb.DataType_Int32 &&
|
||||
fieldSchema.GetDataType() != schemapb.DataType_Int16 &&
|
||||
fieldSchema.GetDataType() != schemapb.DataType_Int8 {
|
||||
return merr.WrapErrParameterInvalid("DataType_Int", "not match", "default value type mismatches field schema type")
|
||||
}
|
||||
defaultValue := fieldSchema.GetDefaultValue().GetIntData()
|
||||
if fieldSchema.GetDataType() == schemapb.DataType_Int16 {
|
||||
if defaultValue > math.MaxInt16 || defaultValue < math.MinInt16 {
|
||||
return merr.WrapErrParameterInvalidRange(math.MinInt16, math.MaxInt16, defaultValue, "default value out of range")
|
||||
}
|
||||
}
|
||||
if fieldSchema.GetDataType() == schemapb.DataType_Int8 {
|
||||
if defaultValue > math.MaxInt8 || defaultValue < math.MinInt8 {
|
||||
return merr.WrapErrParameterInvalidRange(math.MinInt8, math.MaxInt8, defaultValue, "default value out of range")
|
||||
}
|
||||
}
|
||||
case *schemapb.ValueField_LongData:
|
||||
if fieldSchema.GetDataType() != schemapb.DataType_Int64 {
|
||||
return merr.WrapErrParameterInvalid("DataType_Int64", "not match", "default value type mismatches field schema type")
|
||||
}
|
||||
case *schemapb.ValueField_FloatData:
|
||||
if fieldSchema.GetDataType() != schemapb.DataType_Float {
|
||||
return merr.WrapErrParameterInvalid("DataType_Float", "not match", "default value type mismatches field schema type")
|
||||
}
|
||||
case *schemapb.ValueField_DoubleData:
|
||||
if fieldSchema.GetDataType() != schemapb.DataType_Double {
|
||||
return merr.WrapErrParameterInvalid("DataType_Double", "not match", "default value type mismatches field schema type")
|
||||
}
|
||||
case *schemapb.ValueField_StringData:
|
||||
if fieldSchema.GetDataType() != schemapb.DataType_VarChar {
|
||||
return merr.WrapErrParameterInvalid("DataType_VarChar", "not match", "default value type mismatches field schema type")
|
||||
}
|
||||
default:
|
||||
panic("default value unsupport data type")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasSystemFields(schema *schemapb.CollectionSchema, systemFields []string) bool {
|
||||
for _, f := range schema.GetFields() {
|
||||
if funcutil.SliceContain(systemFields, f.GetName()) {
|
||||
|
@ -87,11 +138,23 @@ func hasSystemFields(schema *schemapb.CollectionSchema, systemFields []string) b
|
|||
}
|
||||
|
||||
func (t *createCollectionTask) validateSchema(schema *schemapb.CollectionSchema) error {
|
||||
log.With(zap.String("CollectionName", t.Req.CollectionName))
|
||||
if t.Req.GetCollectionName() != schema.GetName() {
|
||||
return fmt.Errorf("collection name = %s, schema.Name=%s", t.Req.GetCollectionName(), schema.Name)
|
||||
log.Error("collection name not matches schema name", zap.String("SchemaName", schema.Name))
|
||||
msg := fmt.Sprintf("collection name = %s, schema.Name=%s", t.Req.GetCollectionName(), schema.Name)
|
||||
return merr.WrapErrParameterInvalid("collection name matches schema name", "don't match", msg)
|
||||
}
|
||||
|
||||
err := defaultValueTypeMatch(schema)
|
||||
if err != nil {
|
||||
log.Error("default value type mismatch field schema type")
|
||||
return err
|
||||
}
|
||||
|
||||
if hasSystemFields(schema, []string{RowIDFieldName, TimeStampFieldName}) {
|
||||
return fmt.Errorf("schema contains system field: %s, %s", RowIDFieldName, TimeStampFieldName)
|
||||
log.Error("schema contains system field", zap.String("RowIDFieldName", RowIDFieldName), zap.String("TimeStampFieldName", TimeStampFieldName))
|
||||
msg := fmt.Sprintf("schema contains system field: %s, %s", RowIDFieldName, TimeStampFieldName)
|
||||
return merr.WrapErrParameterInvalid("schema don't contains system field", "contains", msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package rootcoord
|
|||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -128,6 +129,143 @@ func Test_createCollectionTask_validateSchema(t *testing.T) {
|
|||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("default value type mismatch", func(t *testing.T) {
|
||||
collectionName := funcutil.GenRandomStr()
|
||||
task := createCollectionTask{
|
||||
Req: &milvuspb.CreateCollectionRequest{
|
||||
Base: &commonpb.MsgBase{MsgType: commonpb.MsgType_CreateCollection},
|
||||
CollectionName: collectionName,
|
||||
},
|
||||
}
|
||||
schema1 := &schemapb.CollectionSchema{
|
||||
Name: collectionName,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
DataType: schemapb.DataType_BinaryVector,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_BoolData{
|
||||
BoolData: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err1 := task.validateSchema(schema1)
|
||||
assert.ErrorIs(t, err1, merr.ErrParameterInvalid)
|
||||
|
||||
schema2 := &schemapb.CollectionSchema{
|
||||
Name: collectionName,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
DataType: schemapb.DataType_BinaryVector,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_IntData{
|
||||
IntData: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err2 := task.validateSchema(schema2)
|
||||
assert.ErrorIs(t, err2, merr.ErrParameterInvalid)
|
||||
|
||||
schema3 := &schemapb.CollectionSchema{
|
||||
Name: collectionName,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
DataType: schemapb.DataType_BinaryVector,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_LongData{
|
||||
LongData: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err3 := task.validateSchema(schema3)
|
||||
assert.ErrorIs(t, err3, merr.ErrParameterInvalid)
|
||||
|
||||
schema4 := &schemapb.CollectionSchema{
|
||||
Name: collectionName,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
DataType: schemapb.DataType_BinaryVector,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_FloatData{
|
||||
FloatData: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err4 := task.validateSchema(schema4)
|
||||
assert.ErrorIs(t, err4, merr.ErrParameterInvalid)
|
||||
|
||||
schema5 := &schemapb.CollectionSchema{
|
||||
Name: collectionName,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
DataType: schemapb.DataType_BinaryVector,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_DoubleData{
|
||||
DoubleData: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err5 := task.validateSchema(schema5)
|
||||
assert.ErrorIs(t, err5, merr.ErrParameterInvalid)
|
||||
|
||||
schema6 := &schemapb.CollectionSchema{
|
||||
Name: collectionName,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
DataType: schemapb.DataType_BinaryVector,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_StringData{
|
||||
StringData: "a",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err6 := task.validateSchema(schema6)
|
||||
assert.ErrorIs(t, err6, merr.ErrParameterInvalid)
|
||||
|
||||
schema7 := &schemapb.CollectionSchema{
|
||||
Name: collectionName,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
DataType: schemapb.DataType_Int16,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_IntData{
|
||||
IntData: math.MaxInt32,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err7 := task.validateSchema(schema7)
|
||||
assert.ErrorIs(t, err7, merr.ErrParameterInvalid)
|
||||
|
||||
schema8 := &schemapb.CollectionSchema{
|
||||
Name: collectionName,
|
||||
Fields: []*schemapb.FieldSchema{
|
||||
{
|
||||
DataType: schemapb.DataType_Int8,
|
||||
DefaultValue: &schemapb.ValueField{
|
||||
Data: &schemapb.ValueField_IntData{
|
||||
IntData: math.MaxInt32,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err8 := task.validateSchema(schema8)
|
||||
assert.ErrorIs(t, err8, merr.ErrParameterInvalid)
|
||||
})
|
||||
|
||||
t.Run("normal case", func(t *testing.T) {
|
||||
collectionName := funcutil.GenRandomStr()
|
||||
task := createCollectionTask{
|
||||
|
|
Loading…
Reference in New Issue