From b0ba7f09debae83e9736646025ba4fbdbb180db5 Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Tue, 23 Apr 2024 16:40:24 +0200 Subject: [PATCH] Introduce type and use pointer to reduce size Signed-off-by: Dirkjan Bussink --- go/vt/vtgate/engine/aggregations.go | 2 +- go/vt/vtgate/engine/cached_size.go | 25 +++++++------ go/vt/vtgate/engine/hash_join.go | 6 +-- go/vt/vtgate/evalengine/api_aggregation.go | 4 +- go/vt/vtgate/evalengine/api_compare.go | 4 +- go/vt/vtgate/evalengine/api_compare_test.go | 16 ++++---- go/vt/vtgate/evalengine/api_hash.go | 6 +-- go/vt/vtgate/evalengine/arena.go | 8 ++-- go/vt/vtgate/evalengine/cached_size.go | 39 +++++++++++--------- go/vt/vtgate/evalengine/compiler.go | 32 +++++++++++----- go/vt/vtgate/evalengine/compiler_asm_push.go | 8 ++-- go/vt/vtgate/evalengine/eval.go | 4 +- go/vt/vtgate/evalengine/eval_enum.go | 9 +++-- go/vt/vtgate/evalengine/eval_set.go | 6 +-- go/vt/vtgate/evalengine/expr_column.go | 2 +- go/vt/vtgate/evalengine/weights.go | 4 +- go/vt/vtgate/evalengine/weights_test.go | 12 +++--- go/vt/vtgate/vindexes/vschema.go | 3 +- go/vt/wrangler/vdiff.go | 15 ++++---- 19 files changed, 111 insertions(+), 94 deletions(-) diff --git a/go/vt/vtgate/engine/aggregations.go b/go/vt/vtgate/engine/aggregations.go index b033e9fbb0e..4673a2717e5 100644 --- a/go/vt/vtgate/engine/aggregations.go +++ b/go/vt/vtgate/engine/aggregations.go @@ -107,7 +107,7 @@ type aggregatorDistinct struct { last sqltypes.Value coll collations.ID collationEnv *collations.Environment - values []string + values *evalengine.EnumSetValues } func (a *aggregatorDistinct) shouldReturn(row []sqltypes.Value) (bool, error) { diff --git a/go/vt/vtgate/engine/cached_size.go b/go/vt/vtgate/engine/cached_size.go index 410f024149c..22b3a38a990 100644 --- a/go/vt/vtgate/engine/cached_size.go +++ b/go/vt/vtgate/engine/cached_size.go @@ -35,7 +35,7 @@ func (cached *AggregateParams) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(128) + size += int64(112) } // field Type vitess.io/vitess/go/vt/vtgate/evalengine.Type size += cached.Type.CachedSize(false) @@ -71,7 +71,7 @@ func (cached *CheckCol) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(64) + size += int64(48) } // field WsCol *int size += hack.RuntimeAllocSize(int64(8)) @@ -239,7 +239,7 @@ func (cached *Distinct) CachedSize(alloc bool) int64 { } // field CheckCols []vitess.io/vitess/go/vt/vtgate/engine.CheckCol { - size += hack.RuntimeAllocSize(int64(cap(cached.CheckCols)) * int64(64)) + size += hack.RuntimeAllocSize(int64(cap(cached.CheckCols)) * int64(48)) for _, elem := range cached.CheckCols { size += elem.CachedSize(false) } @@ -386,7 +386,7 @@ func (cached *GroupByParams) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(96) + size += int64(80) } // field Expr vitess.io/vitess/go/vt/sqlparser.Expr if cc, ok := cached.Expr.(cachedObject); ok { @@ -404,7 +404,7 @@ func (cached *HashJoin) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(144) + size += int64(128) } // field Left vitess.io/vitess/go/vt/vtgate/engine.Primitive if cc, ok := cached.Left.(cachedObject); ok { @@ -424,10 +424,11 @@ func (cached *HashJoin) CachedSize(alloc bool) int64 { } // field CollationEnv *vitess.io/vitess/go/mysql/collations.Environment size += cached.CollationEnv.CachedSize(true) - // field Values []string - { - size += hack.RuntimeAllocSize(int64(cap(cached.Values)) * int64(16)) - for _, elem := range cached.Values { + // field Values *vitess.io/vitess/go/vt/vtgate/evalengine.EnumSetValues + if cached.Values != nil { + size += int64(24) + size += hack.RuntimeAllocSize(int64(cap(*cached.Values)) * int64(16)) + for _, elem := range *cached.Values { size += hack.RuntimeAllocSize(int64(len(elem))) } } @@ -670,7 +671,7 @@ func (cached *MemorySort) CachedSize(alloc bool) int64 { } // field OrderBy vitess.io/vitess/go/vt/vtgate/evalengine.Comparison { - size += hack.RuntimeAllocSize(int64(cap(cached.OrderBy)) * int64(72)) + size += hack.RuntimeAllocSize(int64(cap(cached.OrderBy)) * int64(56)) for _, elem := range cached.OrderBy { size += elem.CachedSize(false) } @@ -700,7 +701,7 @@ func (cached *MergeSort) CachedSize(alloc bool) int64 { } // field OrderBy vitess.io/vitess/go/vt/vtgate/evalengine.Comparison { - size += hack.RuntimeAllocSize(int64(cap(cached.OrderBy)) * int64(72)) + size += hack.RuntimeAllocSize(int64(cap(cached.OrderBy)) * int64(56)) for _, elem := range cached.OrderBy { size += elem.CachedSize(false) } @@ -910,7 +911,7 @@ func (cached *Route) CachedSize(alloc bool) int64 { size += hack.RuntimeAllocSize(int64(len(cached.FieldQuery))) // field OrderBy vitess.io/vitess/go/vt/vtgate/evalengine.Comparison { - size += hack.RuntimeAllocSize(int64(cap(cached.OrderBy)) * int64(72)) + size += hack.RuntimeAllocSize(int64(cap(cached.OrderBy)) * int64(56)) for _, elem := range cached.OrderBy { size += elem.CachedSize(false) } diff --git a/go/vt/vtgate/engine/hash_join.go b/go/vt/vtgate/engine/hash_join.go index 89dbf1190ae..6ac34e1ab79 100644 --- a/go/vt/vtgate/engine/hash_join.go +++ b/go/vt/vtgate/engine/hash_join.go @@ -69,7 +69,7 @@ type ( CollationEnv *collations.Environment // Values for enum and set types - Values []string + Values *evalengine.EnumSetValues } hashJoinProbeTable struct { @@ -81,7 +81,7 @@ type ( cols []int hasher vthash.Hasher sqlmode evalengine.SQLMode - values []string + values *evalengine.EnumSetValues } probeTableEntry struct { @@ -264,7 +264,7 @@ func (hj *HashJoin) description() PrimitiveDescription { } } -func newHashJoinProbeTable(coll collations.ID, typ querypb.Type, lhsKey, rhsKey int, cols []int, values []string) *hashJoinProbeTable { +func newHashJoinProbeTable(coll collations.ID, typ querypb.Type, lhsKey, rhsKey int, cols []int, values *evalengine.EnumSetValues) *hashJoinProbeTable { return &hashJoinProbeTable{ innerMap: map[vthash.Hash]*probeTableEntry{}, coll: coll, diff --git a/go/vt/vtgate/evalengine/api_aggregation.go b/go/vt/vtgate/evalengine/api_aggregation.go index 8584261b654..78ab8335d6d 100644 --- a/go/vt/vtgate/evalengine/api_aggregation.go +++ b/go/vt/vtgate/evalengine/api_aggregation.go @@ -448,7 +448,7 @@ type aggregationMinMax struct { current sqltypes.Value collation collations.ID collationEnv *collations.Environment - values []string + values *EnumSetValues } func (a *aggregationMinMax) minmax(value sqltypes.Value, max bool) (err error) { @@ -485,7 +485,7 @@ func (a *aggregationMinMax) Reset() { a.current = sqltypes.NULL } -func NewAggregationMinMax(typ sqltypes.Type, collationEnv *collations.Environment, collation collations.ID, values []string) MinMax { +func NewAggregationMinMax(typ sqltypes.Type, collationEnv *collations.Environment, collation collations.ID, values *EnumSetValues) MinMax { switch { case sqltypes.IsSigned(typ): return &aggregationInt{t: typ} diff --git a/go/vt/vtgate/evalengine/api_compare.go b/go/vt/vtgate/evalengine/api_compare.go index e890e7c83fd..6873ad40143 100644 --- a/go/vt/vtgate/evalengine/api_compare.go +++ b/go/vt/vtgate/evalengine/api_compare.go @@ -43,7 +43,7 @@ func (err UnsupportedCollationError) Error() string { // UnsupportedCollationHashError is returned when we try to get the hash value and are missing the collation to use var UnsupportedCollationHashError = vterrors.Errorf(vtrpcpb.Code_INTERNAL, "text type with an unknown/unsupported collation cannot be hashed") -func compare(v1, v2 sqltypes.Value, collationEnv *collations.Environment, collationID collations.ID, values []string) (int, error) { +func compare(v1, v2 sqltypes.Value, collationEnv *collations.Environment, collationID collations.ID, values *EnumSetValues) (int, error) { v1t := v1.Type() // We have a fast path here for the case where both values are @@ -147,7 +147,7 @@ func compare(v1, v2 sqltypes.Value, collationEnv *collations.Environment, collat // numeric, then a numeric comparison is performed after // necessary conversions. If none are numeric, then it's // a simple binary comparison. Uncomparable values return an error. -func NullsafeCompare(v1, v2 sqltypes.Value, collationEnv *collations.Environment, collationID collations.ID, values []string) (int, error) { +func NullsafeCompare(v1, v2 sqltypes.Value, collationEnv *collations.Environment, collationID collations.ID, values *EnumSetValues) (int, error) { // Based on the categorization defined for the types, // we're going to allow comparison of the following: // Null, isNumber, IsBinary. This will exclude IsQuoted diff --git a/go/vt/vtgate/evalengine/api_compare_test.go b/go/vt/vtgate/evalengine/api_compare_test.go index 778a252e2d8..106b111cafc 100644 --- a/go/vt/vtgate/evalengine/api_compare_test.go +++ b/go/vt/vtgate/evalengine/api_compare_test.go @@ -30,14 +30,12 @@ import ( "github.com/stretchr/testify/require" "vitess.io/vitess/go/mysql/collations" + "vitess.io/vitess/go/sqltypes" + querypb "vitess.io/vitess/go/vt/proto/query" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vtenv" "vitess.io/vitess/go/vt/vterrors" - - "vitess.io/vitess/go/sqltypes" - - querypb "vitess.io/vitess/go/vt/proto/query" ) type testCase struct { @@ -1114,7 +1112,7 @@ func TestNullsafeCompare(t *testing.T) { v1, v2 sqltypes.Value out int err error - values []string + values *EnumSetValues }{ { v1: NULL, @@ -1145,7 +1143,7 @@ func TestNullsafeCompare(t *testing.T) { v1: TestValue(sqltypes.Enum, "foo"), v2: TestValue(sqltypes.Enum, "bar"), out: -1, - values: []string{"'foo'", "'bar'"}, + values: &EnumSetValues{"'foo'", "'bar'"}, }, { v1: TestValue(sqltypes.Enum, "foo"), @@ -1156,7 +1154,7 @@ func TestNullsafeCompare(t *testing.T) { v1: TestValue(sqltypes.Enum, "foo"), v2: TestValue(sqltypes.VarChar, "bar"), out: 1, - values: []string{"'foo'", "'bar'"}, + values: &EnumSetValues{"'foo'", "'bar'"}, }, { v1: TestValue(sqltypes.VarChar, "foo"), @@ -1167,7 +1165,7 @@ func TestNullsafeCompare(t *testing.T) { v1: TestValue(sqltypes.Set, "bar"), v2: TestValue(sqltypes.Set, "foo,bar"), out: -1, - values: []string{"'foo'", "'bar'"}, + values: &EnumSetValues{"'foo'", "'bar'"}, }, { v1: TestValue(sqltypes.Set, "bar"), @@ -1178,7 +1176,7 @@ func TestNullsafeCompare(t *testing.T) { v1: TestValue(sqltypes.VarChar, "bar"), v2: TestValue(sqltypes.Set, "foo,bar"), out: -1, - values: []string{"'foo'", "'bar'"}, + values: &EnumSetValues{"'foo'", "'bar'"}, }, { v1: TestValue(sqltypes.Set, "bar"), diff --git a/go/vt/vtgate/evalengine/api_hash.go b/go/vt/vtgate/evalengine/api_hash.go index 0ed3e0c4146..a5e5d1778dd 100644 --- a/go/vt/vtgate/evalengine/api_hash.go +++ b/go/vt/vtgate/evalengine/api_hash.go @@ -34,7 +34,7 @@ type HashCode = uint64 // NullsafeHashcode returns an int64 hashcode that is guaranteed to be the same // for two values that are considered equal by `NullsafeCompare`. -func NullsafeHashcode(v sqltypes.Value, collation collations.ID, coerceType sqltypes.Type, sqlmode SQLMode, values []string) (HashCode, error) { +func NullsafeHashcode(v sqltypes.Value, collation collations.ID, coerceType sqltypes.Type, sqlmode SQLMode, values *EnumSetValues) (HashCode, error) { e, err := valueToEvalCast(v, coerceType, collation, values, sqlmode) if err != nil { return 0, err @@ -75,7 +75,7 @@ var ErrHashCoercionIsNotExact = vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, " // for two values that are considered equal by `NullsafeCompare`. // This can be used to avoid having to do comparison checks after a hash, // since we consider the 128 bits of entropy enough to guarantee uniqueness. -func NullsafeHashcode128(hash *vthash.Hasher, v sqltypes.Value, collation collations.ID, coerceTo sqltypes.Type, sqlmode SQLMode, values []string) error { +func NullsafeHashcode128(hash *vthash.Hasher, v sqltypes.Value, collation collations.ID, coerceTo sqltypes.Type, sqlmode SQLMode, values *EnumSetValues) error { switch { case v.IsNull(), sqltypes.IsNull(coerceTo): hash.Write16(hashPrefixNil) @@ -233,7 +233,7 @@ func NullsafeHashcode128(hash *vthash.Hasher, v sqltypes.Value, collation collat return nil } -func nullsafeHashcode128Default(hash *vthash.Hasher, v sqltypes.Value, collation collations.ID, coerceTo sqltypes.Type, sqlmode SQLMode, values []string) error { +func nullsafeHashcode128Default(hash *vthash.Hasher, v sqltypes.Value, collation collations.ID, coerceTo sqltypes.Type, sqlmode SQLMode, values *EnumSetValues) error { // Slow path to handle all other types. This uses the generic // logic for value casting to ensure we match MySQL here. e, err := valueToEvalCast(v, coerceTo, collation, values, sqlmode) diff --git a/go/vt/vtgate/evalengine/arena.go b/go/vt/vtgate/evalengine/arena.go index 0b01a485dc3..ccfe63f514f 100644 --- a/go/vt/vtgate/evalengine/arena.go +++ b/go/vt/vtgate/evalengine/arena.go @@ -17,8 +17,6 @@ limitations under the License. package evalengine import ( - "slices" - "vitess.io/vitess/go/mysql/collations" "vitess.io/vitess/go/mysql/datetime" "vitess.io/vitess/go/mysql/decimal" @@ -67,7 +65,7 @@ func (a *Arena) newEvalDecimal(dec decimal.Decimal, m, d int32) *evalDecimal { return a.newEvalDecimalWithPrec(dec.Clamp(m-d, d), d) } -func (a *Arena) newEvalEnum(raw []byte, values []string) *evalEnum { +func (a *Arena) newEvalEnum(raw []byte, values *EnumSetValues) *evalEnum { if cap(a.aEnum) > len(a.aEnum) { a.aEnum = a.aEnum[:len(a.aEnum)+1] } else { @@ -76,11 +74,11 @@ func (a *Arena) newEvalEnum(raw []byte, values []string) *evalEnum { val := &a.aEnum[len(a.aInt64)-1] s := string(raw) val.string = s - val.value = slices.Index(values, s) + val.value = valueIdx(values, s) return val } -func (a *Arena) newEvalSet(raw []byte, values []string) *evalSet { +func (a *Arena) newEvalSet(raw []byte, values *EnumSetValues) *evalSet { if cap(a.aSet) > len(a.aSet) { a.aSet = a.aSet[:len(a.aSet)+1] } else { diff --git a/go/vt/vtgate/evalengine/cached_size.go b/go/vt/vtgate/evalengine/cached_size.go index abe7bdc473f..4854795779e 100644 --- a/go/vt/vtgate/evalengine/cached_size.go +++ b/go/vt/vtgate/evalengine/cached_size.go @@ -159,16 +159,17 @@ func (cached *Column) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(80) + size += int64(64) } // field Original vitess.io/vitess/go/vt/sqlparser.Expr if cc, ok := cached.Original.(cachedObject); ok { size += cc.CachedSize(true) } - // field Values []string - { - size += hack.RuntimeAllocSize(int64(cap(cached.Values)) * int64(16)) - for _, elem := range cached.Values { + // field Values *vitess.io/vitess/go/vt/vtgate/evalengine.EnumSetValues + if cached.Values != nil { + size += int64(24) + size += hack.RuntimeAllocSize(int64(cap(*cached.Values)) * int64(16)) + for _, elem := range *cached.Values { size += hack.RuntimeAllocSize(int64(len(elem))) } } @@ -196,7 +197,7 @@ func (cached *CompiledExpr) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(96) + size += int64(80) } // field code []vitess.io/vitess/go/vt/vtgate/evalengine.frame { @@ -370,7 +371,7 @@ func (cached *OrderByParams) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(80) + size += int64(64) } // field Type vitess.io/vitess/go/vt/vtgate/evalengine.Type size += cached.Type.CachedSize(false) @@ -396,12 +397,13 @@ func (cached *Type) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(48) + size += int64(24) } - // field values []string - { - size += hack.RuntimeAllocSize(int64(cap(cached.values)) * int64(16)) - for _, elem := range cached.values { + // field values *vitess.io/vitess/go/vt/vtgate/evalengine.EnumSetValues + if cached.values != nil { + size += int64(24) + size += hack.RuntimeAllocSize(int64(cap(*cached.values)) * int64(16)) + for _, elem := range *cached.values { size += hack.RuntimeAllocSize(int64(len(elem))) } } @@ -1933,12 +1935,13 @@ func (cached *ctype) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(48) + size += int64(32) } - // field Values []string - { - size += hack.RuntimeAllocSize(int64(cap(cached.Values)) * int64(16)) - for _, elem := range cached.Values { + // field Values *vitess.io/vitess/go/vt/vtgate/evalengine.EnumSetValues + if cached.Values != nil { + size += int64(24) + size += hack.RuntimeAllocSize(int64(cap(*cached.Values)) * int64(16)) + for _, elem := range *cached.Values { size += hack.RuntimeAllocSize(int64(len(elem))) } } @@ -2063,7 +2066,7 @@ func (cached *typedExpr) CachedSize(alloc bool) int64 { } // field types []vitess.io/vitess/go/vt/vtgate/evalengine.ctype { - size += hack.RuntimeAllocSize(int64(cap(cached.types)) * int64(48)) + size += hack.RuntimeAllocSize(int64(cap(cached.types)) * int64(32)) for _, elem := range cached.types { size += elem.CachedSize(false) } diff --git a/go/vt/vtgate/evalengine/compiler.go b/go/vt/vtgate/evalengine/compiler.go index 344798f6abb..d9de15aa571 100644 --- a/go/vt/vtgate/evalengine/compiler.go +++ b/go/vt/vtgate/evalengine/compiler.go @@ -52,12 +52,14 @@ type compiledCoercion struct { right colldata.Coercion } +type EnumSetValues []string + type ctype struct { Type sqltypes.Type Flag typeFlag Size, Scale int32 Col collations.TypedCollation - Values []string + Values *EnumSetValues } type Type struct { @@ -66,7 +68,17 @@ type Type struct { nullable bool init bool size, scale int32 - values []string + values *EnumSetValues +} + +func (v *EnumSetValues) Equal(other *EnumSetValues) bool { + if v == nil && other == nil { + return true + } + if v == nil || other == nil { + return false + } + return slices.Equal(*v, *other) } func NewType(t sqltypes.Type, collation collations.ID) Type { @@ -74,7 +86,7 @@ func NewType(t sqltypes.Type, collation collations.ID) Type { return NewTypeEx(t, collation, true, 0, 0, nil) } -func NewTypeEx(t sqltypes.Type, collation collations.ID, nullable bool, size, scale int32, values []string) Type { +func NewTypeEx(t sqltypes.Type, collation collations.ID, nullable bool, size, scale int32, values *EnumSetValues) Type { return Type{ typ: t, collation: collation, @@ -144,7 +156,7 @@ func (t *Type) Nullable() bool { return true // nullable by default for unknown types } -func (t *Type) Values() []string { +func (t *Type) Values() *EnumSetValues { return t.values } @@ -158,27 +170,27 @@ func (t *Type) Equal(other *Type) bool { t.nullable == other.nullable && t.size == other.size && t.scale == other.scale && - slices.Equal(t.values, other.values) + t.values.Equal(other.values) } -func (ct ctype) equal(other ctype) bool { +func (ct *ctype) equal(other ctype) bool { return ct.Type == other.Type && ct.Flag == other.Flag && ct.Size == other.Size && ct.Scale == other.Scale && ct.Col == other.Col && - slices.Equal(ct.Values, other.Values) + ct.Values.Equal(other.Values) } -func (ct ctype) nullable() bool { +func (ct *ctype) nullable() bool { return ct.Flag&flagNullable != 0 } -func (ct ctype) isTextual() bool { +func (ct *ctype) isTextual() bool { return sqltypes.IsTextOrBinary(ct.Type) } -func (ct ctype) isHexOrBitLiteral() bool { +func (ct *ctype) isHexOrBitLiteral() bool { return ct.Flag&flagBit != 0 || ct.Flag&flagHex != 0 } diff --git a/go/vt/vtgate/evalengine/compiler_asm_push.go b/go/vt/vtgate/evalengine/compiler_asm_push.go index ff8adb168ff..87d2ee9af9b 100644 --- a/go/vt/vtgate/evalengine/compiler_asm_push.go +++ b/go/vt/vtgate/evalengine/compiler_asm_push.go @@ -105,13 +105,13 @@ func push_d(env *ExpressionEnv, raw []byte) int { return 1 } -func push_enum(env *ExpressionEnv, raw []byte, values []string) int { +func push_enum(env *ExpressionEnv, raw []byte, values *EnumSetValues) int { env.vm.stack[env.vm.sp] = env.vm.arena.newEvalEnum(raw, values) env.vm.sp++ return 1 } -func push_set(env *ExpressionEnv, raw []byte, values []string) int { +func push_set(env *ExpressionEnv, raw []byte, values *EnumSetValues) int { env.vm.stack[env.vm.sp] = env.vm.arena.newEvalSet(raw, values) env.vm.sp++ return 1 @@ -129,7 +129,7 @@ func (asm *assembler) PushColumn_d(offset int) { }, "PUSH DECIMAL(:%d)", offset) } -func (asm *assembler) PushColumn_enum(offset int, values []string) { +func (asm *assembler) PushColumn_enum(offset int, values *EnumSetValues) { asm.adjustStack(1) asm.emit(func(env *ExpressionEnv) int { @@ -141,7 +141,7 @@ func (asm *assembler) PushColumn_enum(offset int, values []string) { }, "PUSH ENUM(:%d)", offset) } -func (asm *assembler) PushColumn_set(offset int, values []string) { +func (asm *assembler) PushColumn_set(offset int, values *EnumSetValues) { asm.adjustStack(1) asm.emit(func(env *ExpressionEnv) int { diff --git a/go/vt/vtgate/evalengine/eval.go b/go/vt/vtgate/evalengine/eval.go index eeefa351894..90b1add541a 100644 --- a/go/vt/vtgate/evalengine/eval.go +++ b/go/vt/vtgate/evalengine/eval.go @@ -212,7 +212,7 @@ func evalCoerce(e eval, typ sqltypes.Type, col collations.ID, now time.Time, all } } -func valueToEvalCast(v sqltypes.Value, typ sqltypes.Type, collation collations.ID, values []string, sqlmode SQLMode) (eval, error) { +func valueToEvalCast(v sqltypes.Value, typ sqltypes.Type, collation collations.ID, values *EnumSetValues, sqlmode SQLMode) (eval, error) { switch { case typ == sqltypes.Null: return nil, nil @@ -367,7 +367,7 @@ func valueToEvalCast(v sqltypes.Value, typ sqltypes.Type, collation collations.I return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "coercion should not try to coerce this value: %v", v) } -func valueToEval(value sqltypes.Value, collation collations.TypedCollation, values []string) (eval, error) { +func valueToEval(value sqltypes.Value, collation collations.TypedCollation, values *EnumSetValues) (eval, error) { wrap := func(err error) error { if err == nil { return nil diff --git a/go/vt/vtgate/evalengine/eval_enum.go b/go/vt/vtgate/evalengine/eval_enum.go index b89abd15429..a0d349314da 100644 --- a/go/vt/vtgate/evalengine/eval_enum.go +++ b/go/vt/vtgate/evalengine/eval_enum.go @@ -10,7 +10,7 @@ type evalEnum struct { string string } -func newEvalEnum(val []byte, values []string) *evalEnum { +func newEvalEnum(val []byte, values *EnumSetValues) *evalEnum { s := string(val) return &evalEnum{ value: valueIdx(values, s), @@ -26,8 +26,11 @@ func (e *evalEnum) SQLType() sqltypes.Type { return sqltypes.Enum } -func valueIdx(values []string, value string) int { - for i, v := range values { +func valueIdx(values *EnumSetValues, value string) int { + if values == nil { + return -1 + } + for i, v := range *values { v, _ = sqltypes.DecodeStringSQL(v) if v == value { return i diff --git a/go/vt/vtgate/evalengine/eval_set.go b/go/vt/vtgate/evalengine/eval_set.go index 47fe29607df..6a9de2eff14 100644 --- a/go/vt/vtgate/evalengine/eval_set.go +++ b/go/vt/vtgate/evalengine/eval_set.go @@ -12,7 +12,7 @@ type evalSet struct { string string } -func newEvalSet(val []byte, values []string) *evalSet { +func newEvalSet(val []byte, values *EnumSetValues) *evalSet { value := string(val) return &evalSet{ @@ -29,8 +29,8 @@ func (e *evalSet) SQLType() sqltypes.Type { return sqltypes.Set } -func evalSetBits(values []string, value string) uint64 { - if len(values) > 64 { +func evalSetBits(values *EnumSetValues, value string) uint64 { + if values != nil && len(*values) > 64 { // This never would happen as MySQL limits SET // to 64 elements. Safeguard here just in case though. panic("too many values for set") diff --git a/go/vt/vtgate/evalengine/expr_column.go b/go/vt/vtgate/evalengine/expr_column.go index cbdb1775f88..d53585ceb8b 100644 --- a/go/vt/vtgate/evalengine/expr_column.go +++ b/go/vt/vtgate/evalengine/expr_column.go @@ -34,7 +34,7 @@ type ( Collation collations.TypedCollation Original sqlparser.Expr Nullable bool - Values []string // For ENUM and SET types + Values *EnumSetValues // For ENUM and SET types // dynamicTypeOffset is set when the type of this column cannot be calculated // at translation time. Since expressions with dynamic types cannot be compiled ahead of time, diff --git a/go/vt/vtgate/evalengine/weights.go b/go/vt/vtgate/evalengine/weights.go index 37286af7ddc..3eb9aa290c5 100644 --- a/go/vt/vtgate/evalengine/weights.go +++ b/go/vt/vtgate/evalengine/weights.go @@ -41,7 +41,7 @@ import ( // externally communicates with the `WEIGHT_STRING` function, so that we // can also use this to order / sort other types like Float and Decimal // as well. -func WeightString(dst []byte, v sqltypes.Value, coerceTo sqltypes.Type, col collations.ID, length, precision int, values []string, sqlmode SQLMode) ([]byte, bool, error) { +func WeightString(dst []byte, v sqltypes.Value, coerceTo sqltypes.Type, col collations.ID, length, precision int, values *EnumSetValues, sqlmode SQLMode) ([]byte, bool, error) { // We optimize here for the case where we already have the desired type. // Otherwise, we fall back to the general evalengine conversion logic. if v.Type() != coerceTo { @@ -125,7 +125,7 @@ func WeightString(dst []byte, v sqltypes.Value, coerceTo sqltypes.Type, col coll } } -func fallbackWeightString(dst []byte, v sqltypes.Value, coerceTo sqltypes.Type, col collations.ID, length, precision int, values []string, sqlmode SQLMode) ([]byte, bool, error) { +func fallbackWeightString(dst []byte, v sqltypes.Value, coerceTo sqltypes.Type, col collations.ID, length, precision int, values *EnumSetValues, sqlmode SQLMode) ([]byte, bool, error) { e, err := valueToEvalCast(v, coerceTo, col, values, sqlmode) if err != nil { return dst, false, err diff --git a/go/vt/vtgate/evalengine/weights_test.go b/go/vt/vtgate/evalengine/weights_test.go index b059142163a..95764d3c3a4 100644 --- a/go/vt/vtgate/evalengine/weights_test.go +++ b/go/vt/vtgate/evalengine/weights_test.go @@ -37,7 +37,7 @@ func TestTinyWeightStrings(t *testing.T) { col collations.ID len int prec int - values []string + values *EnumSetValues }{ {typ: sqltypes.Int32, gen: sqltypes.RandomGenerators[sqltypes.Int32], col: collations.CollationBinaryID}, {typ: sqltypes.Int64, gen: sqltypes.RandomGenerators[sqltypes.Int64], col: collations.CollationBinaryID}, @@ -48,8 +48,8 @@ func TestTinyWeightStrings(t *testing.T) { {typ: sqltypes.VarBinary, gen: sqltypes.RandomGenerators[sqltypes.VarBinary], col: collations.CollationBinaryID}, {typ: sqltypes.Decimal, gen: sqltypes.RandomGenerators[sqltypes.Decimal], col: collations.CollationBinaryID, len: 20, prec: 10}, {typ: sqltypes.TypeJSON, gen: sqltypes.RandomGenerators[sqltypes.TypeJSON], col: collations.CollationBinaryID}, - {typ: sqltypes.Enum, gen: sqltypes.RandomGenerators[sqltypes.Enum], col: collations.CollationBinaryID, values: []string{"'xxsmall'", "'xsmall'", "'small'", "'medium'", "'large'", "'xlarge'", "'xxlarge'"}}, - {typ: sqltypes.Set, gen: sqltypes.RandomGenerators[sqltypes.Set], col: collations.CollationBinaryID, values: []string{"'a'", "'b'", "'c'", "'d'", "'e'", "'f'", "'g'"}}, + {typ: sqltypes.Enum, gen: sqltypes.RandomGenerators[sqltypes.Enum], col: collations.CollationBinaryID, values: &EnumSetValues{"'xxsmall'", "'xsmall'", "'small'", "'medium'", "'large'", "'xlarge'", "'xxlarge'"}}, + {typ: sqltypes.Set, gen: sqltypes.RandomGenerators[sqltypes.Set], col: collations.CollationBinaryID, values: &EnumSetValues{"'a'", "'b'", "'c'", "'d'", "'e'", "'f'", "'g'"}}, } for _, tc := range cases { @@ -119,7 +119,7 @@ func TestWeightStrings(t *testing.T) { col collations.ID len int prec int - values []string + values *EnumSetValues }{ {name: "int64", gen: sqltypes.RandomGenerators[sqltypes.Int64], types: []sqltypes.Type{sqltypes.Int64, sqltypes.VarChar, sqltypes.TypeJSON}, col: collations.CollationBinaryID}, {name: "uint64", gen: sqltypes.RandomGenerators[sqltypes.Uint64], types: []sqltypes.Type{sqltypes.Uint64, sqltypes.VarChar, sqltypes.TypeJSON}, col: collations.CollationBinaryID}, @@ -132,8 +132,8 @@ func TestWeightStrings(t *testing.T) { {name: "datetime", gen: sqltypes.RandomGenerators[sqltypes.Datetime], types: []sqltypes.Type{sqltypes.Datetime, sqltypes.VarChar, sqltypes.TypeJSON}, col: collations.CollationBinaryID}, {name: "timestamp", gen: sqltypes.RandomGenerators[sqltypes.Timestamp], types: []sqltypes.Type{sqltypes.Timestamp, sqltypes.VarChar, sqltypes.TypeJSON}, col: collations.CollationBinaryID}, {name: "time", gen: sqltypes.RandomGenerators[sqltypes.Time], types: []sqltypes.Type{sqltypes.Time, sqltypes.VarChar, sqltypes.TypeJSON}, col: collations.CollationBinaryID}, - {name: "enum", gen: sqltypes.RandomGenerators[sqltypes.Enum], types: []sqltypes.Type{sqltypes.Enum, sqltypes.VarChar, sqltypes.TypeJSON}, col: collations.CollationBinaryID, values: []string{"'xxsmall'", "'xsmall'", "'small'", "'medium'", "'large'", "'xlarge'", "'xxlarge'"}}, - {name: "set", gen: sqltypes.RandomGenerators[sqltypes.Set], types: []sqltypes.Type{sqltypes.Set, sqltypes.VarChar, sqltypes.TypeJSON}, col: collations.CollationBinaryID, values: []string{"'a'", "'b'", "'c'", "'d'", "'e'", "'f'", "'g'"}}, + {name: "enum", gen: sqltypes.RandomGenerators[sqltypes.Enum], types: []sqltypes.Type{sqltypes.Enum, sqltypes.VarChar, sqltypes.TypeJSON}, col: collations.CollationBinaryID, values: &EnumSetValues{"'xxsmall'", "'xsmall'", "'small'", "'medium'", "'large'", "'xlarge'", "'xxlarge'"}}, + {name: "set", gen: sqltypes.RandomGenerators[sqltypes.Set], types: []sqltypes.Type{sqltypes.Set, sqltypes.VarChar, sqltypes.TypeJSON}, col: collations.CollationBinaryID, values: &EnumSetValues{"'a'", "'b'", "'c'", "'d'", "'e'", "'f'", "'g'"}}, } for _, tc := range cases { diff --git a/go/vt/vtgate/vindexes/vschema.go b/go/vt/vtgate/vindexes/vschema.go index 6506cdee09c..8e5e8b547a6 100644 --- a/go/vt/vtgate/vindexes/vschema.go +++ b/go/vt/vtgate/vindexes/vschema.go @@ -25,6 +25,7 @@ import ( "strings" "time" + "vitess.io/vitess/go/ptr" "vitess.io/vitess/go/vt/topotools" "vitess.io/vitess/go/json2" @@ -233,7 +234,7 @@ func (col *Column) ToEvalengineType(collationEnv *collations.Environment) evalen } else { collation = collations.CollationForType(col.Type, collationEnv.DefaultConnectionCharset()) } - return evalengine.NewTypeEx(col.Type, collation, col.Nullable, col.Size, col.Scale, col.Values) + return evalengine.NewTypeEx(col.Type, collation, col.Nullable, col.Size, col.Scale, ptr.Of(evalengine.EnumSetValues(col.Values))) } // KeyspaceSchema contains the schema(table) for a keyspace. diff --git a/go/vt/wrangler/vdiff.go b/go/vt/wrangler/vdiff.go index a698bad290a..ba16b399dae 100644 --- a/go/vt/wrangler/vdiff.go +++ b/go/vt/wrangler/vdiff.go @@ -31,6 +31,7 @@ import ( "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/ptr" "vitess.io/vitess/go/vt/vtenv" "vitess.io/vitess/go/mysql/collations" @@ -116,10 +117,10 @@ type vdiff struct { // compareColInfo contains the metadata for a column of the table being diffed type compareColInfo struct { - colIndex int // index of the column in the filter's select - collation collations.ID // is the collation of the column, if any - values []string // is the list of enum or set values for the column, if any - isPK bool // is this column part of the primary key + colIndex int // index of the column in the filter's select + collation collations.ID // is the collation of the column, if any + values *evalengine.EnumSetValues // is the list of enum or set values for the column, if any + isPK bool // is this column part of the primary key } // tableDiffer performs a diff for one table in the workflow. @@ -538,7 +539,7 @@ func findPKs(env *vtenv.Environment, table *tabletmanagerdatapb.TableDefinition, // getColumnCollations determines the proper collation to use for each // column in the table definition leveraging MySQL's collation inheritance // rules. -func getColumnCollations(venv *vtenv.Environment, table *tabletmanagerdatapb.TableDefinition) (map[string]collations.ID, map[string][]string, error) { +func getColumnCollations(venv *vtenv.Environment, table *tabletmanagerdatapb.TableDefinition) (map[string]collations.ID, map[string]*evalengine.EnumSetValues, error) { createstmt, err := venv.Parser().Parse(table.Schema) if err != nil { return nil, nil, err @@ -581,7 +582,7 @@ func getColumnCollations(venv *vtenv.Environment, table *tabletmanagerdatapb.Tab } columnCollations := make(map[string]collations.ID) - columnValues := make(map[string][]string) + columnValues := make(map[string]*evalengine.EnumSetValues) for _, column := range tableschema.TableSpec.Columns { // If it's not a character based type then no collation is used. if !sqltypes.IsQuoted(column.Type.SQLType()) { @@ -589,7 +590,7 @@ func getColumnCollations(venv *vtenv.Environment, table *tabletmanagerdatapb.Tab continue } columnCollations[column.Name.Lowered()] = getColumnCollation(column) - columnValues[column.Name.Lowered()] = column.Type.EnumValues + columnValues[column.Name.Lowered()] = ptr.Of(evalengine.EnumSetValues(column.Type.EnumValues)) } return columnCollations, columnValues, nil }