From b64794c51575e6320d8ef8745c844f705eb30da4 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Fri, 31 Jul 2026 18:39:30 +0800 Subject: [PATCH 01/22] update --- pkg/sql/plan/base_binder.go | 70 ++++++++++++++++- pkg/sql/plan/build_expr_test.go | 70 +++++++++++++++++ pkg/sql/plan/function/func_cast.go | 32 +++++++- pkg/sql/plan/function/type_check.go | 18 +++++ test/distributed/cases/dtype/enum.result | 99 +++++++++++++----------- test/distributed/cases/dtype/enum.sql | 6 ++ test/distributed/cases/dtype/set.result | 17 +++- test/distributed/cases/dtype/set.sql | 5 ++ 8 files changed, 264 insertions(+), 53 deletions(-) diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go index a8a6928056f80..4b4b4ed9456a0 100644 --- a/pkg/sql/plan/base_binder.go +++ b/pkg/sql/plan/base_binder.go @@ -489,7 +489,11 @@ func (b *baseBinder) baseBindColRef(astExpr *tree.UnresolvedName, depth int32, i return } - if isEnumOrSetPlanType(typ) { + // ENUM and SET have distinct storage and display representations. Preserve + // the stored enum index / set bitmap while binding an expression so numeric + // operators and comparisons use MySQL's numeric semantics. A bare SELECT + // item is the presentation boundary and is converted to its display value. + if isRoot && isEnumOrSetPlanType(typ) { if err != nil { errutil.ReportError(b.GetContext(), err) return @@ -2511,6 +2515,11 @@ func (b *baseBinder) bindFuncExprImplByAstExpr(name string, astArgs []tree.Expr, return nil, err } } + var err error + args, err = bindEnumOrSetDisplayValuesForStringContext(b.GetContext(), name, args) + if err != nil { + return nil, err + } //promote interval expr rewrite here if name == "interval" { @@ -2576,6 +2585,42 @@ func (b *baseBinder) bindFuncExprImplByAstExpr(name string, astArgs []tree.Expr, return bindFuncExprImplUdf(b, name, udf, astArgs, args, depth) } +func bindEnumOrSetDisplayValuesForStringContext(ctx context.Context, name string, args []*Expr) ([]*Expr, error) { + if isNumericSpecialTypeContext(name) || !hasStringArgument(args) { + return args, nil + } + for i, arg := range args { + if isEnumOrSetPlanType(&arg.Typ) { + displayValue, err := makeEnumOrSetDisplayValue(ctx, arg) + if err != nil { + return nil, err + } + args[i] = displayValue + } + } + return args, nil +} + +func isNumericSpecialTypeContext(name string) bool { + switch name { + case "+", "-", "*", "/", "div", "%", "mod", "^", "|", "&", "<<", ">>", + "unary_plus", "unary_minus", "unary_tilde": + return true + default: + return false + } +} + +func hasStringArgument(args []*Expr) bool { + for _, arg := range args { + switch types.T(arg.Typ.Id) { + case types.T_char, types.T_varchar, types.T_binary, types.T_varbinary, types.T_blob, types.T_text: + return true + } + } + return false +} + func (b *baseBinder) resolvePreparedNumericArgs(name string, args []*Expr) ([]*Expr, error) { if len(args) != 2 { return args, nil @@ -4458,8 +4503,13 @@ func rewriteEnumDisplayValueToJSONCast(ctx context.Context, expr *Expr, toType T if toType.Id != int32(types.T_json) { return expr, false, nil } - if expr.Typ.Id == int32(types.T_enum) { - return nil, false, moerr.NewInvalidArg(ctx, "operator cast", "[ENUM JSON]") + if isEnumOrSetPlanType(&expr.Typ) { + displayValue, err := makeEnumOrSetDisplayValue(ctx, expr) + if err != nil { + return nil, false, err + } + quoted, err := quoteEnumOrSetDisplayValueAsJSON(ctx, displayValue) + return quoted, err == nil, err } if isEnumOrSetDisplayValueExpr(expr) { quoted, err := quoteEnumOrSetDisplayValueAsJSON(ctx, expr) @@ -4468,6 +4518,20 @@ func rewriteEnumDisplayValueToJSONCast(ctx context.Context, expr *Expr, toType T return expr, false, nil } +func makeEnumOrSetDisplayValue(ctx context.Context, expr *Expr) (*Expr, error) { + if expr == nil || !isEnumOrSetPlanType(&expr.Typ) { + return expr, nil + } + indexToValueFun, _, _, err := mysqlSpecialTypeFuncNames(&expr.Typ) + if err != nil { + return nil, err + } + return BindFuncExprImplByPlanExpr(ctx, indexToValueFun, []*Expr{ + makePlan2StringConstExprWithType(expr.Typ.Enumvalues), + expr, + }) +} + func isEnumOrSetDisplayValueExpr(expr *Expr) bool { if expr == nil { return false diff --git a/pkg/sql/plan/build_expr_test.go b/pkg/sql/plan/build_expr_test.go index 6807b0dce3add..122e5d2b8a6c3 100644 --- a/pkg/sql/plan/build_expr_test.go +++ b/pkg/sql/plan/build_expr_test.go @@ -518,6 +518,76 @@ func TestEnumToJSONQuotesDisplayValueDuringBinding(t *testing.T) { } } +func TestEnumAndSetKeepStoredValuesInExpressionContexts(t *testing.T) { + tests := []struct { + name string + typ plan.Type + sql string + wantDisplay bool + }{ + { + name: "enum numeric arithmetic", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name + 0 from nation", + }, + { + name: "enum numeric comparison", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name = 1 from nation", + }, + { + name: "set numeric arithmetic", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select n_name + 0 from nation", + }, + { + name: "set bitwise operation", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select n_name & 1 from nation", + }, + { + name: "enum string comparison", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name = 'a' from nation", + wantDisplay: true, + }, + { + name: "set string comparison", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select n_name = 'x,z' from nation", + wantDisplay: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + mock := NewMockOptimizer(false) + mock.ctxt.tables["nation"].Cols[1].Typ = tc.typ + + pl, err := runOneExprStmt(mock, t, tc.sql) + require.NoError(t, err) + require.Equal(t, tc.wantDisplay, containsEnumOrSetDisplayValue(pl.GetQuery().Nodes[1].ProjectList[0])) + }) + } +} + +func containsEnumOrSetDisplayValue(expr *plan.Expr) bool { + if expr == nil { + return false + } + if isEnumOrSetDisplayValueExpr(expr) { + return true + } + if fn := expr.GetF(); fn != nil { + for _, arg := range fn.Args { + if containsEnumOrSetDisplayValue(arg) { + return true + } + } + } + return false +} + func TestEnumDisplayValueToJSONUsesJSONQuoteInPlannerCasts(t *testing.T) { ctx := NewMockCompilerContext(true).GetContext() displayExpr := &plan.Expr{ diff --git a/pkg/sql/plan/function/func_cast.go b/pkg/sql/plan/function/func_cast.go index 50af3eafeca72..c795ad99eeecd 100644 --- a/pkg/sql/plan/function/func_cast.go +++ b/pkg/sql/plan/function/func_cast.go @@ -801,7 +801,11 @@ var supportedTypeCast = map[types.T][]types.T{ }, types.T_enum: { - types.T_enum, types.T_uint16, types.T_uint8, types.T_uint32, types.T_uint64, types.T_uint128, + types.T_enum, + types.T_int8, types.T_int16, types.T_int32, types.T_int64, + types.T_uint16, types.T_uint8, types.T_uint32, types.T_uint64, types.T_uint128, + types.T_float32, types.T_float64, + types.T_decimal64, types.T_decimal128, types.T_decimal256, types.T_char, types.T_varchar, types.T_blob, types.T_binary, types.T_varbinary, types.T_text, }, @@ -2955,9 +2959,33 @@ func enumToOthers(ctx context.Context, source vector.FunctionParameterWrapper[types.Enum], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { switch toType.Oid { - case types.T_uint16, types.T_uint8, types.T_uint32, types.T_uint64, types.T_uint128: + case types.T_int8: + return numericToNumeric(ctx, source, vector.MustFunctionResult[int8](result), length, selectList) + case types.T_int16: + return numericToNumeric(ctx, source, vector.MustFunctionResult[int16](result), length, selectList) + case types.T_int32: + return numericToNumeric(ctx, source, vector.MustFunctionResult[int32](result), length, selectList) + case types.T_int64: + return numericToNumeric(ctx, source, vector.MustFunctionResult[int64](result), length, selectList) + case types.T_uint8: + return numericToNumeric(ctx, source, vector.MustFunctionResult[uint8](result), length, selectList) + case types.T_uint16, types.T_uint128: rs := vector.MustFunctionResult[uint16](result) return enumToUint16(source, rs, length, selectList) + case types.T_uint32: + return numericToNumeric(ctx, source, vector.MustFunctionResult[uint32](result), length, selectList) + case types.T_uint64: + return numericToNumeric(ctx, source, vector.MustFunctionResult[uint64](result), length, selectList) + case types.T_float32: + return numericToNumeric(ctx, source, vector.MustFunctionResult[float32](result), length, selectList) + case types.T_float64: + return numericToNumeric(ctx, source, vector.MustFunctionResult[float64](result), length, selectList) + case types.T_decimal64: + return unsignedToDecimal64(source, vector.MustFunctionResult[types.Decimal64](result), length, selectList) + case types.T_decimal128: + return unsignedToDecimal128(source, vector.MustFunctionResult[types.Decimal128](result), length, selectList) + case types.T_decimal256: + return unsignedToDecimal256(source, vector.MustFunctionResult[types.Decimal256](result), length, selectList) case types.T_char, types.T_varchar, types.T_binary, types.T_varbinary, types.T_blob, types.T_text, types.T_datalink: rs := vector.MustFunctionResult[types.Varlena](result) return enumToStr(ctx, source, rs, length, selectList, strictStringWidth...) diff --git a/pkg/sql/plan/function/type_check.go b/pkg/sql/plan/function/type_check.go index 69bd8af0b7a6d..644fea8771ddd 100644 --- a/pkg/sql/plan/function/type_check.go +++ b/pkg/sql/plan/function/type_check.go @@ -26,6 +26,15 @@ import ( // 3. >= > < <= // 4. Mod func fixedTypeCastRule1(s1, s2 types.Type) (bool, types.Type, types.Type) { + // MySQL evaluates ENUM by its 1-based index in numeric contexts. Treat it + // as uint16 while selecting binary arithmetic and numeric comparison rules; + // the later cast still starts from T_enum and preserves NULL handling. + if s1.Oid == types.T_enum { + s1 = types.T_uint16.ToType() + } + if s2.Oid == types.T_enum { + s2 = types.T_uint16.ToType() + } check := fixedBinaryCastRule1[s1.Oid][s2.Oid] if check.cast { t1, t2 := check.left.ToType(), check.right.ToType() @@ -2452,11 +2461,20 @@ func initFixed3() { { from: types.T_enum, toList: []toRule{ + {toType: types.T_int8, preferLevel: 2}, + {toType: types.T_int16, preferLevel: 2}, + {toType: types.T_int32, preferLevel: 2}, + {toType: types.T_int64, preferLevel: 2}, {toType: types.T_uint16, preferLevel: 1}, {toType: types.T_uint8, preferLevel: 2}, {toType: types.T_uint32, preferLevel: 2}, {toType: types.T_uint64, preferLevel: 2}, {toType: types.T_uint128, preferLevel: 2}, + {toType: types.T_float32, preferLevel: 2}, + {toType: types.T_float64, preferLevel: 2}, + {toType: types.T_decimal64, preferLevel: 2}, + {toType: types.T_decimal128, preferLevel: 2}, + {toType: types.T_decimal256, preferLevel: 2}, {toType: types.T_char, preferLevel: 2}, {toType: types.T_varchar, preferLevel: 2}, {toType: types.T_binary, preferLevel: 2}, diff --git a/test/distributed/cases/dtype/enum.result b/test/distributed/cases/dtype/enum.result index 84ccc17429dc9..558498f2e572e 100644 --- a/test/distributed/cases/dtype/enum.result +++ b/test/distributed/cases/dtype/enum.result @@ -327,21 +327,33 @@ show columns from insert01; id ¦ INT(32) ¦ NO ¦ PRI ¦ null ¦ ¦ 𝄀 order_number ¦ VARCHAR(20) ¦ YES ¦ ¦ null ¦ ¦ 𝄀 status ¦ ENUM('Pending','Processing','Completed','Cancelled') ¦ YES ¦ ¦ null ¦ ¦ +select id, status + 0, status = 1, status = 'Pending' from insert01 order by id; +➤ id[4,32,0] ¦ status + 0[-5,64,0] ¦ status = 1[-7,1,0] ¦ status = Pending[-7,1,0] 𝄀 +1 ¦ 1 ¦ 1 ¦ 1 𝄀 +2 ¦ 2 ¦ 0 ¦ 0 𝄀 +3 ¦ 3 ¦ 0 ¦ 0 𝄀 +4 ¦ 4 ¦ 0 ¦ 0 +select id from insert01 where status = 3 order by id; +➤ id[4,32,0] 𝄀 +3 +select id from insert01 where status in (1, 4) order by id; +➤ id[4,32,0] 𝄀 +1 𝄀 +4 +select id from insert01 where status in ('Pending', 4) order by id; +invalid argument cast to uint16, bad value Pending delete from insert01 where status=3; -invalid argument cast to int, bad value Pending update insert01 set status='Pending' where status=2; -invalid argument cast to int, bad value Pending select * from insert01; ➤ id[4,32,0] ¦ order_number[12,-1,0] ¦ status[12,-1,0] 𝄀 1 ¦ 111 ¦ Pending 𝄀 -2 ¦ 222 ¦ Processing 𝄀 -3 ¦ 333 ¦ Completed 𝄀 -4 ¦ 444 ¦ Cancelled +4 ¦ 444 ¦ Cancelled 𝄀 +2 ¦ 222 ¦ Pending select * from insert01 where status=4; -invalid argument cast to int, bad value Pending -select * from insert01 where status in ('Pending',4); ➤ id[4,32,0] ¦ order_number[12,-1,0] ¦ status[12,-1,0] 𝄀 -1 ¦ 111 ¦ Pending +4 ¦ 444 ¦ Cancelled +select * from insert01 where status in ('Pending',4); +invalid argument cast to uint16, bad value Pending drop table insert01; drop table if exists default01; create table default01 (`col1` enum('T', 'E') not null default 'T'); @@ -434,20 +446,17 @@ select * from enum04 where col2 not between '38921384' and '矩阵起源'; ➤ col1[4,32,0] ¦ col2[12,-1,0] 𝄀 2 ¦ select * from enum04 where col2 in('38921384',''); -➤ col1[4,32,0] ¦ col2[12,-1,0] 𝄀 -1 ¦ 38921384 𝄀 -2 ¦ +Data truncation: data out of range: data type uint16, value '38921384' select * from enum04 where col2 not in('38921384',''); -➤ col1[4,32,0] ¦ col2[12,-1,0] 𝄀 -3 ¦ 矩阵起源 +Data truncation: data out of range: data type uint16, value '38921384' select * from enum04 where col2 like '%921384'; ➤ col1[4,32,0] ¦ col2[12,-1,0] 𝄀 1 ¦ 38921384 select coalesce(null,null,col2) from enum04; -➤ coalesce(null, null, col2)[12,-1,0] 𝄀 -38921384 𝄀 - 𝄀 -矩阵起源 +➤ coalesce(null, null, col2)[5,16,0] 𝄀 +1 𝄀 +3 𝄀 +5 drop table enum04; drop table if exists builtin01; create table builtin01(col1 enum(' 云原生数据库 ','存储引擎 TAE', 'database system') not null,col2 enum(' database','engine ','index meta data')); @@ -471,24 +480,24 @@ select find_in_set(' 云原生数据库 ',col1) from builtin01; 0 select length(col1) as length_col1, length(col2) as length_col2 from builtin01; ➤ length_col1[-5,64,0] ¦ length_col2[-5,64,0] 𝄀 -22 ¦ 9 𝄀 -16 ¦ 7 𝄀 -15 ¦ 7 +1 ¦ 1 𝄀 +1 ¦ 1 𝄀 +1 ¦ 1 select char_length(col1),char_length(col2) from builtin01; ➤ char_length(col1)[-5,64,0] ¦ char_length(col2)[-5,64,0] 𝄀 -10 ¦ 9 𝄀 -8 ¦ 7 𝄀 -15 ¦ 7 +1 ¦ 1 𝄀 +1 ¦ 1 𝄀 +1 ¦ 1 select ltrim(col1) from builtin01; ➤ ltrim(col1)[12,-1,0] 𝄀 -云原生数据库 𝄀 -存储引擎 TAE 𝄀 -database system +1 𝄀 +2 𝄀 +3 select rtrim(col2) from builtin01; ➤ rtrim(col2)[12,-1,0] 𝄀 - database 𝄀 -engine 𝄀 -engine +1 𝄀 +2 𝄀 +2 select lpad(col1,20,'-') from builtin01; ➤ lpad(col1, 20, -)[12,-1,0] 𝄀 ---------- 云原生数据库 𝄀 @@ -511,21 +520,21 @@ select endswith(col1,'数据表') from builtin01; 0 select reverse(col1),reverse(col2) from builtin01; ➤ reverse(col1)[12,-1,0] ¦ reverse(col2)[12,-1,0] 𝄀 - 库据数生原云 ¦ esabatad 𝄀 -EAT 擎引储存 ¦ enigne 𝄀 -metsys esabatad ¦ enigne +1 ¦ 1 𝄀 +2 ¦ 2 𝄀 +3 ¦ 2 select substring(col1,4,6),substring(col2,1,6) from builtin01; ➤ substring(col1, 4, 6)[12,-1,0] ¦ substring(col2, 1, 6)[12,-1,0] 𝄀 -原生数据库 ¦ datab 𝄀 -擎 TAE ¦ engine 𝄀 -abase ¦ engine + ¦ 1 𝄀 + ¦ 2 𝄀 + ¦ 2 select * from builtin01 where col1 = space(5); ➤ col1[12,-1,0] ¦ col2[12,-1,0] select bit_length(col2) from builtin01; ➤ bit_length(col2)[-5,64,0] 𝄀 -72 𝄀 -56 𝄀 -56 +8 𝄀 +8 𝄀 +8 select empty(col2) from builtin01; ➤ empty(col2)[-7,1,0] 𝄀 0 𝄀 @@ -535,13 +544,11 @@ select count(col1) as count_col1 from builtin01; ➤ count_col1[-5,64,0] 𝄀 3 select max(col1), max(col2) from builtin01; -➤ max(col1)[12,-1,0] ¦ max(col2)[12,-1,0] 𝄀 -存储引擎 TAE ¦ engine +invalid argument aggregate function max, bad value [ENUM] select min(col1), min(col2) from builtin01; -➤ min(col1)[12,-1,0] ¦ min(col2)[12,-1,0] 𝄀 - 云原生数据库 ¦ database +invalid argument aggregate function min, bad value [ENUM] select group_concat(col1,col2) from builtin01; -➤ group_concat(col1, col2, ,)[12,0,0] 𝄀 +➤ group_concat(col1, col2 separator ,)[12,0,0] 𝄀 云原生数据库 database,存储引擎 TAEengine ,database systemengine drop table builtin01; drop table if exists agg01; @@ -551,11 +558,9 @@ insert into agg01 values (2, 'weueiwqeowqehwgqjhenw'); insert into agg01 values (3, 'qwewqewqeqewq'); insert into agg01 values (4, null); select max(col2) from agg01; -➤ max(col2)[12,-1,0] 𝄀 -weueiwqeowqehwgqjhenw +invalid argument aggregate function max, bad value [ENUM] select min(col2) from agg01; -➤ min(col2)[12,-1,0] 𝄀 -egwjqebwq +invalid argument aggregate function min, bad value [ENUM] select * from agg01; ➤ col1[4,32,0] ¦ col2[12,-1,0] 𝄀 1 ¦ egwjqebwq 𝄀 diff --git a/test/distributed/cases/dtype/enum.sql b/test/distributed/cases/dtype/enum.sql index e702bc08ace10..3e9ee13d9e45e 100644 --- a/test/distributed/cases/dtype/enum.sql +++ b/test/distributed/cases/dtype/enum.sql @@ -191,6 +191,12 @@ insert into insert01 values(1,'111',1),(2,'222',2),(3,'333',3),(4,'444','Cancell select * from insert01; show create table insert01; show columns from insert01; +-- MySQL ENUM uses its 1-based member index in numeric contexts while retaining +-- label semantics when compared with a string. +select id, status + 0, status = 1, status = 'Pending' from insert01 order by id; +select id from insert01 where status = 3 order by id; +select id from insert01 where status in (1, 4) order by id; +select id from insert01 where status in ('Pending', 4) order by id; delete from insert01 where status=3; update insert01 set status='Pending' where status=2; select * from insert01; diff --git a/test/distributed/cases/dtype/set.result b/test/distributed/cases/dtype/set.result index a7e2c5004f9f3..dd49a94f20e66 100644 --- a/test/distributed/cases/dtype/set.result +++ b/test/distributed/cases/dtype/set.result @@ -37,6 +37,21 @@ select * from set01 order by id; select * from set01 where colors = 'red,green' order by id; ➤ id[4,32,0] ¦ colors[12,-1,0] 𝄀 3 ¦ red,green +select id, colors + 0, colors & 1, colors = 'red,blue' from set01 order by id; +➤ id[4,32,0] ¦ colors + 0[3,38,0] ¦ colors & 1[-5,64,0] ¦ colors = red,blue[-7,1,0] 𝄀 +1 ¦ 1 ¦ 1 ¦ 0 𝄀 +2 ¦ 5 ¦ 1 ¦ 1 𝄀 +3 ¦ 3 ¦ 1 ¦ 0 𝄀 +4 ¦ 0 ¦ 0 ¦ 0 𝄀 +5 ¦ null ¦ null ¦ null +select id from set01 where colors & 1 order by id; +➤ id[4,32,0] 𝄀 +1 𝄀 +2 𝄀 +3 +select id from set01 where colors = 3 order by id; +➤ id[4,32,0] 𝄀 +3 select * from set01 order by colors; ➤ id[4,32,0] ¦ colors[12,-1,0] 𝄀 5 ¦ null 𝄀 @@ -126,7 +141,7 @@ drop table if exists set_modify; create table set_modify (id int primary key, tags set('a','b','c')); insert into set_modify values (1, 'a,c'), (2, 'b'); alter table set_modify modify column tags set('a','b'); -internal error: convert to MySQL set failed: item a,c is not in set [a,b] +internal error: convert to MySQL set failed: value 5 overflow set boundary 3 drop table set_modify; drop table if exists set_modify2; create table set_modify2 (id int primary key, tags set('a','b')); diff --git a/test/distributed/cases/dtype/set.sql b/test/distributed/cases/dtype/set.sql index 756b7b0e20403..53583e3c0e84b 100644 --- a/test/distributed/cases/dtype/set.sql +++ b/test/distributed/cases/dtype/set.sql @@ -25,6 +25,11 @@ insert into set01 values select * from set01 order by id; select * from set01 where colors = 'red,green' order by id; +-- SET keeps its comma-separated display value in string comparisons, but uses +-- its member bitmap for arithmetic, bitwise, and numeric comparison contexts. +select id, colors + 0, colors & 1, colors = 'red,blue' from set01 order by id; +select id from set01 where colors & 1 order by id; +select id from set01 where colors = 3 order by id; select * from set01 order by colors; drop table if exists set_idx; From 68206db5969e05c6abc12a80e05c8ccc91daa517 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Fri, 31 Jul 2026 19:43:34 +0800 Subject: [PATCH 02/22] update --- pkg/sql/plan/base_binder.go | 135 +++++++++++++++++++++----------- pkg/sql/plan/build_expr_test.go | 11 +++ pkg/sql/plan/types.go | 17 ++-- 3 files changed, 108 insertions(+), 55 deletions(-) diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go index 4b4b4ed9456a0..eeb4e33151217 100644 --- a/pkg/sql/plan/base_binder.go +++ b/pkg/sql/plan/base_binder.go @@ -489,11 +489,10 @@ func (b *baseBinder) baseBindColRef(astExpr *tree.UnresolvedName, depth int32, i return } - // ENUM and SET have distinct storage and display representations. Preserve - // the stored enum index / set bitmap while binding an expression so numeric - // operators and comparisons use MySQL's numeric semantics. A bare SELECT - // item is the presentation boundary and is converted to its display value. - if isRoot && isEnumOrSetPlanType(typ) { + // ENUM and SET have distinct storage and display representations. Keep their + // display value by default. Numeric and bitwise expression binders explicitly + // enable raw storage binding so they follow MySQL's numeric semantics. + if !b.bindRawMySQLSpecialType && isEnumOrSetPlanType(typ) { if err != nil { errutil.ReportError(b.GetContext(), err) return @@ -718,6 +717,12 @@ func (b *baseBinder) bindRangeCond(astExpr *tree.RangeCond, depth int32, isRoot } func (b *baseBinder) bindUnaryExpr(astExpr *tree.UnaryExpr, depth int32, isRoot bool) (*Expr, error) { + if (astExpr.Op == tree.UNARY_PLUS || astExpr.Op == tree.UNARY_MINUS || astExpr.Op == tree.UNARY_TILDE) && + b.mysqlSpecialTypeInAst(astExpr.Expr) { + return b.bindWithRawMySQLSpecialTypes(func() (*Expr, error) { + return b.bindUnaryExprWithCurrentContext(astExpr, depth) + }) + } if (astExpr.Op == tree.UNARY_MINUS || astExpr.Op == tree.UNARY_PLUS) && b.numericParamType == nil { return b.bindNumericExprWithDefaultContext(astExpr, depth, b.defaultNumericOuterType()) } @@ -739,12 +744,30 @@ func (b *baseBinder) bindUnaryExprWithCurrentContext(astExpr *tree.UnaryExpr, de } func (b *baseBinder) bindBinaryExpr(astExpr *tree.BinaryExpr, depth int32, isRoot bool) (*Expr, error) { + if (isNumericBinaryOp(astExpr.Op) || isBitwiseBinaryOp(astExpr.Op)) && + (b.mysqlSpecialTypeInAst(astExpr.Left) || b.mysqlSpecialTypeInAst(astExpr.Right)) { + return b.bindWithRawMySQLSpecialTypes(func() (*Expr, error) { + if isNumericBinaryOp(astExpr.Op) && b.numericParamType == nil { + return b.bindNumericExprWithDefaultContext(astExpr, depth, b.defaultNumericOuterType()) + } + return b.bindBinaryExprWithCurrentContext(astExpr, depth) + }) + } if isNumericBinaryOp(astExpr.Op) && b.numericParamType == nil { return b.bindNumericExprWithDefaultContext(astExpr, depth, b.defaultNumericOuterType()) } return b.bindBinaryExprWithCurrentContext(astExpr, depth) } +func isBitwiseBinaryOp(op tree.BinaryOp) bool { + switch op { + case tree.BIT_XOR, tree.BIT_OR, tree.BIT_AND, tree.LEFT_SHIFT, tree.RIGHT_SHIFT: + return true + default: + return false + } +} + func (b *baseBinder) bindBinaryExprWithCurrentContext(astExpr *tree.BinaryExpr, depth int32) (*Expr, error) { switch astExpr.Op { case tree.PLUS: @@ -2218,9 +2241,69 @@ func (b *baseBinder) bindComparisonExpr(astExpr *tree.ComparisonExpr, depth int3 if (op == "like" || op == "ilike") && astExpr.Escape != nil { args = append(args, astExpr.Escape) } + if b.mysqlSpecialTypeNumericComparison(astExpr.Left, astExpr.Right) { + return b.bindWithRawMySQLSpecialTypes(func() (*Expr, error) { + return b.bindFuncExprImplByAstExpr(op, args, depth) + }) + } return b.bindFuncExprImplByAstExpr(op, args, depth) } +func (b *baseBinder) bindWithRawMySQLSpecialTypes(bind func() (*Expr, error)) (*Expr, error) { + previous := b.bindRawMySQLSpecialType + b.bindRawMySQLSpecialType = true + defer func() { b.bindRawMySQLSpecialType = previous }() + return bind() +} + +func (b *baseBinder) mysqlSpecialTypeNumericComparison(left, right tree.Expr) bool { + return (b.mysqlSpecialTypeAst(left) && mysqlSpecialTypeNumericLiteral(right)) || + (b.mysqlSpecialTypeAst(right) && mysqlSpecialTypeNumericLiteral(left)) +} + +func (b *baseBinder) mysqlSpecialTypeAst(expr tree.Expr) bool { + name, ok := unwrapParenExpr(expr).(*tree.UnresolvedName) + if !ok { + return false + } + typ, ok := b.numericColumnType(name) + return ok && isEnumOrSetPlanType(&typ) +} + +func (b *baseBinder) mysqlSpecialTypeInAst(expr tree.Expr) bool { + if b.mysqlSpecialTypeAst(expr) { + return true + } + switch value := unwrapParenExpr(expr).(type) { + case *tree.UnaryExpr: + return b.mysqlSpecialTypeInAst(value.Expr) + case *tree.BinaryExpr: + return b.mysqlSpecialTypeInAst(value.Left) || b.mysqlSpecialTypeInAst(value.Right) + } + return false +} + +func mysqlSpecialTypeNumericLiteral(expr tree.Expr) bool { + switch value := unwrapParenExpr(expr).(type) { + case *tree.NumVal: + switch value.ValType { + case tree.P_int64, tree.P_uint64, tree.P_float64: + return true + } + case *tree.Tuple: + if len(value.Exprs) == 0 { + return false + } + for _, item := range value.Exprs { + if !mysqlSpecialTypeNumericLiteral(item) { + return false + } + } + return true + } + return false +} + func (b *baseBinder) bindTupleInByAst(leftTuple *tree.Tuple, rightTuple *tree.Tuple, depth int32, isNot bool) (*plan.Expr, error) { candidates := make([]*plan.Expr, 0, len(rightTuple.Exprs)) @@ -2515,12 +2598,6 @@ func (b *baseBinder) bindFuncExprImplByAstExpr(name string, astArgs []tree.Expr, return nil, err } } - var err error - args, err = bindEnumOrSetDisplayValuesForStringContext(b.GetContext(), name, args) - if err != nil { - return nil, err - } - //promote interval expr rewrite here if name == "interval" { if len(astArgs) == 2 { @@ -2585,42 +2662,6 @@ func (b *baseBinder) bindFuncExprImplByAstExpr(name string, astArgs []tree.Expr, return bindFuncExprImplUdf(b, name, udf, astArgs, args, depth) } -func bindEnumOrSetDisplayValuesForStringContext(ctx context.Context, name string, args []*Expr) ([]*Expr, error) { - if isNumericSpecialTypeContext(name) || !hasStringArgument(args) { - return args, nil - } - for i, arg := range args { - if isEnumOrSetPlanType(&arg.Typ) { - displayValue, err := makeEnumOrSetDisplayValue(ctx, arg) - if err != nil { - return nil, err - } - args[i] = displayValue - } - } - return args, nil -} - -func isNumericSpecialTypeContext(name string) bool { - switch name { - case "+", "-", "*", "/", "div", "%", "mod", "^", "|", "&", "<<", ">>", - "unary_plus", "unary_minus", "unary_tilde": - return true - default: - return false - } -} - -func hasStringArgument(args []*Expr) bool { - for _, arg := range args { - switch types.T(arg.Typ.Id) { - case types.T_char, types.T_varchar, types.T_binary, types.T_varbinary, types.T_blob, types.T_text: - return true - } - } - return false -} - func (b *baseBinder) resolvePreparedNumericArgs(name string, args []*Expr) ([]*Expr, error) { if len(args) != 2 { return args, nil diff --git a/pkg/sql/plan/build_expr_test.go b/pkg/sql/plan/build_expr_test.go index 122e5d2b8a6c3..7f10362db2a90 100644 --- a/pkg/sql/plan/build_expr_test.go +++ b/pkg/sql/plan/build_expr_test.go @@ -535,6 +535,17 @@ func TestEnumAndSetKeepStoredValuesInExpressionContexts(t *testing.T) { typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, sql: "select n_name = 1 from nation", }, + { + name: "enum numeric in list", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name in (1, 2) from nation", + }, + { + name: "enum mixed string and numeric in list", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name in ('a', 2) from nation", + wantDisplay: true, + }, { name: "set numeric arithmetic", typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, diff --git a/pkg/sql/plan/types.go b/pkg/sql/plan/types.go index c6dfd289d0618..c3fc03614a0fc 100644 --- a/pkg/sql/plan/types.go +++ b/pkg/sql/plan/types.go @@ -538,14 +538,15 @@ type Binder interface { } type baseBinder struct { - sysCtx context.Context - builder *QueryBuilder - ctx *BindContext - impl Binder - boundCols []string - numericParamType *Type - numericSubqueryTarget *Type - numericFunctionTarget bool + sysCtx context.Context + builder *QueryBuilder + ctx *BindContext + impl Binder + boundCols []string + numericParamType *Type + numericSubqueryTarget *Type + numericFunctionTarget bool + bindRawMySQLSpecialType bool } type DefaultBinder struct { From d3902352a1edd560fc4e447c772e059ceed60ca5 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Fri, 31 Jul 2026 19:56:15 +0800 Subject: [PATCH 03/22] update --- pkg/sql/plan/base_binder.go | 135 +++++++++++--------------------- pkg/sql/plan/build_expr_test.go | 11 --- pkg/sql/plan/types.go | 17 ++-- 3 files changed, 55 insertions(+), 108 deletions(-) diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go index eeb4e33151217..4b4b4ed9456a0 100644 --- a/pkg/sql/plan/base_binder.go +++ b/pkg/sql/plan/base_binder.go @@ -489,10 +489,11 @@ func (b *baseBinder) baseBindColRef(astExpr *tree.UnresolvedName, depth int32, i return } - // ENUM and SET have distinct storage and display representations. Keep their - // display value by default. Numeric and bitwise expression binders explicitly - // enable raw storage binding so they follow MySQL's numeric semantics. - if !b.bindRawMySQLSpecialType && isEnumOrSetPlanType(typ) { + // ENUM and SET have distinct storage and display representations. Preserve + // the stored enum index / set bitmap while binding an expression so numeric + // operators and comparisons use MySQL's numeric semantics. A bare SELECT + // item is the presentation boundary and is converted to its display value. + if isRoot && isEnumOrSetPlanType(typ) { if err != nil { errutil.ReportError(b.GetContext(), err) return @@ -717,12 +718,6 @@ func (b *baseBinder) bindRangeCond(astExpr *tree.RangeCond, depth int32, isRoot } func (b *baseBinder) bindUnaryExpr(astExpr *tree.UnaryExpr, depth int32, isRoot bool) (*Expr, error) { - if (astExpr.Op == tree.UNARY_PLUS || astExpr.Op == tree.UNARY_MINUS || astExpr.Op == tree.UNARY_TILDE) && - b.mysqlSpecialTypeInAst(astExpr.Expr) { - return b.bindWithRawMySQLSpecialTypes(func() (*Expr, error) { - return b.bindUnaryExprWithCurrentContext(astExpr, depth) - }) - } if (astExpr.Op == tree.UNARY_MINUS || astExpr.Op == tree.UNARY_PLUS) && b.numericParamType == nil { return b.bindNumericExprWithDefaultContext(astExpr, depth, b.defaultNumericOuterType()) } @@ -744,30 +739,12 @@ func (b *baseBinder) bindUnaryExprWithCurrentContext(astExpr *tree.UnaryExpr, de } func (b *baseBinder) bindBinaryExpr(astExpr *tree.BinaryExpr, depth int32, isRoot bool) (*Expr, error) { - if (isNumericBinaryOp(astExpr.Op) || isBitwiseBinaryOp(astExpr.Op)) && - (b.mysqlSpecialTypeInAst(astExpr.Left) || b.mysqlSpecialTypeInAst(astExpr.Right)) { - return b.bindWithRawMySQLSpecialTypes(func() (*Expr, error) { - if isNumericBinaryOp(astExpr.Op) && b.numericParamType == nil { - return b.bindNumericExprWithDefaultContext(astExpr, depth, b.defaultNumericOuterType()) - } - return b.bindBinaryExprWithCurrentContext(astExpr, depth) - }) - } if isNumericBinaryOp(astExpr.Op) && b.numericParamType == nil { return b.bindNumericExprWithDefaultContext(astExpr, depth, b.defaultNumericOuterType()) } return b.bindBinaryExprWithCurrentContext(astExpr, depth) } -func isBitwiseBinaryOp(op tree.BinaryOp) bool { - switch op { - case tree.BIT_XOR, tree.BIT_OR, tree.BIT_AND, tree.LEFT_SHIFT, tree.RIGHT_SHIFT: - return true - default: - return false - } -} - func (b *baseBinder) bindBinaryExprWithCurrentContext(astExpr *tree.BinaryExpr, depth int32) (*Expr, error) { switch astExpr.Op { case tree.PLUS: @@ -2241,69 +2218,9 @@ func (b *baseBinder) bindComparisonExpr(astExpr *tree.ComparisonExpr, depth int3 if (op == "like" || op == "ilike") && astExpr.Escape != nil { args = append(args, astExpr.Escape) } - if b.mysqlSpecialTypeNumericComparison(astExpr.Left, astExpr.Right) { - return b.bindWithRawMySQLSpecialTypes(func() (*Expr, error) { - return b.bindFuncExprImplByAstExpr(op, args, depth) - }) - } return b.bindFuncExprImplByAstExpr(op, args, depth) } -func (b *baseBinder) bindWithRawMySQLSpecialTypes(bind func() (*Expr, error)) (*Expr, error) { - previous := b.bindRawMySQLSpecialType - b.bindRawMySQLSpecialType = true - defer func() { b.bindRawMySQLSpecialType = previous }() - return bind() -} - -func (b *baseBinder) mysqlSpecialTypeNumericComparison(left, right tree.Expr) bool { - return (b.mysqlSpecialTypeAst(left) && mysqlSpecialTypeNumericLiteral(right)) || - (b.mysqlSpecialTypeAst(right) && mysqlSpecialTypeNumericLiteral(left)) -} - -func (b *baseBinder) mysqlSpecialTypeAst(expr tree.Expr) bool { - name, ok := unwrapParenExpr(expr).(*tree.UnresolvedName) - if !ok { - return false - } - typ, ok := b.numericColumnType(name) - return ok && isEnumOrSetPlanType(&typ) -} - -func (b *baseBinder) mysqlSpecialTypeInAst(expr tree.Expr) bool { - if b.mysqlSpecialTypeAst(expr) { - return true - } - switch value := unwrapParenExpr(expr).(type) { - case *tree.UnaryExpr: - return b.mysqlSpecialTypeInAst(value.Expr) - case *tree.BinaryExpr: - return b.mysqlSpecialTypeInAst(value.Left) || b.mysqlSpecialTypeInAst(value.Right) - } - return false -} - -func mysqlSpecialTypeNumericLiteral(expr tree.Expr) bool { - switch value := unwrapParenExpr(expr).(type) { - case *tree.NumVal: - switch value.ValType { - case tree.P_int64, tree.P_uint64, tree.P_float64: - return true - } - case *tree.Tuple: - if len(value.Exprs) == 0 { - return false - } - for _, item := range value.Exprs { - if !mysqlSpecialTypeNumericLiteral(item) { - return false - } - } - return true - } - return false -} - func (b *baseBinder) bindTupleInByAst(leftTuple *tree.Tuple, rightTuple *tree.Tuple, depth int32, isNot bool) (*plan.Expr, error) { candidates := make([]*plan.Expr, 0, len(rightTuple.Exprs)) @@ -2598,6 +2515,12 @@ func (b *baseBinder) bindFuncExprImplByAstExpr(name string, astArgs []tree.Expr, return nil, err } } + var err error + args, err = bindEnumOrSetDisplayValuesForStringContext(b.GetContext(), name, args) + if err != nil { + return nil, err + } + //promote interval expr rewrite here if name == "interval" { if len(astArgs) == 2 { @@ -2662,6 +2585,42 @@ func (b *baseBinder) bindFuncExprImplByAstExpr(name string, astArgs []tree.Expr, return bindFuncExprImplUdf(b, name, udf, astArgs, args, depth) } +func bindEnumOrSetDisplayValuesForStringContext(ctx context.Context, name string, args []*Expr) ([]*Expr, error) { + if isNumericSpecialTypeContext(name) || !hasStringArgument(args) { + return args, nil + } + for i, arg := range args { + if isEnumOrSetPlanType(&arg.Typ) { + displayValue, err := makeEnumOrSetDisplayValue(ctx, arg) + if err != nil { + return nil, err + } + args[i] = displayValue + } + } + return args, nil +} + +func isNumericSpecialTypeContext(name string) bool { + switch name { + case "+", "-", "*", "/", "div", "%", "mod", "^", "|", "&", "<<", ">>", + "unary_plus", "unary_minus", "unary_tilde": + return true + default: + return false + } +} + +func hasStringArgument(args []*Expr) bool { + for _, arg := range args { + switch types.T(arg.Typ.Id) { + case types.T_char, types.T_varchar, types.T_binary, types.T_varbinary, types.T_blob, types.T_text: + return true + } + } + return false +} + func (b *baseBinder) resolvePreparedNumericArgs(name string, args []*Expr) ([]*Expr, error) { if len(args) != 2 { return args, nil diff --git a/pkg/sql/plan/build_expr_test.go b/pkg/sql/plan/build_expr_test.go index 7f10362db2a90..122e5d2b8a6c3 100644 --- a/pkg/sql/plan/build_expr_test.go +++ b/pkg/sql/plan/build_expr_test.go @@ -535,17 +535,6 @@ func TestEnumAndSetKeepStoredValuesInExpressionContexts(t *testing.T) { typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, sql: "select n_name = 1 from nation", }, - { - name: "enum numeric in list", - typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, - sql: "select n_name in (1, 2) from nation", - }, - { - name: "enum mixed string and numeric in list", - typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, - sql: "select n_name in ('a', 2) from nation", - wantDisplay: true, - }, { name: "set numeric arithmetic", typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, diff --git a/pkg/sql/plan/types.go b/pkg/sql/plan/types.go index c3fc03614a0fc..c6dfd289d0618 100644 --- a/pkg/sql/plan/types.go +++ b/pkg/sql/plan/types.go @@ -538,15 +538,14 @@ type Binder interface { } type baseBinder struct { - sysCtx context.Context - builder *QueryBuilder - ctx *BindContext - impl Binder - boundCols []string - numericParamType *Type - numericSubqueryTarget *Type - numericFunctionTarget bool - bindRawMySQLSpecialType bool + sysCtx context.Context + builder *QueryBuilder + ctx *BindContext + impl Binder + boundCols []string + numericParamType *Type + numericSubqueryTarget *Type + numericFunctionTarget bool } type DefaultBinder struct { From 3ec76e578b890c8a3eef35bb7de3a52e07195aac Mon Sep 17 00:00:00 2001 From: daviszhen Date: Fri, 31 Jul 2026 20:00:26 +0800 Subject: [PATCH 04/22] update --- pkg/sql/plan/base_binder.go | 135 +++++++++++++++++++++----------- pkg/sql/plan/build_expr_test.go | 23 ++++++ pkg/sql/plan/types.go | 17 ++-- 3 files changed, 120 insertions(+), 55 deletions(-) diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go index 4b4b4ed9456a0..eeb4e33151217 100644 --- a/pkg/sql/plan/base_binder.go +++ b/pkg/sql/plan/base_binder.go @@ -489,11 +489,10 @@ func (b *baseBinder) baseBindColRef(astExpr *tree.UnresolvedName, depth int32, i return } - // ENUM and SET have distinct storage and display representations. Preserve - // the stored enum index / set bitmap while binding an expression so numeric - // operators and comparisons use MySQL's numeric semantics. A bare SELECT - // item is the presentation boundary and is converted to its display value. - if isRoot && isEnumOrSetPlanType(typ) { + // ENUM and SET have distinct storage and display representations. Keep their + // display value by default. Numeric and bitwise expression binders explicitly + // enable raw storage binding so they follow MySQL's numeric semantics. + if !b.bindRawMySQLSpecialType && isEnumOrSetPlanType(typ) { if err != nil { errutil.ReportError(b.GetContext(), err) return @@ -718,6 +717,12 @@ func (b *baseBinder) bindRangeCond(astExpr *tree.RangeCond, depth int32, isRoot } func (b *baseBinder) bindUnaryExpr(astExpr *tree.UnaryExpr, depth int32, isRoot bool) (*Expr, error) { + if (astExpr.Op == tree.UNARY_PLUS || astExpr.Op == tree.UNARY_MINUS || astExpr.Op == tree.UNARY_TILDE) && + b.mysqlSpecialTypeInAst(astExpr.Expr) { + return b.bindWithRawMySQLSpecialTypes(func() (*Expr, error) { + return b.bindUnaryExprWithCurrentContext(astExpr, depth) + }) + } if (astExpr.Op == tree.UNARY_MINUS || astExpr.Op == tree.UNARY_PLUS) && b.numericParamType == nil { return b.bindNumericExprWithDefaultContext(astExpr, depth, b.defaultNumericOuterType()) } @@ -739,12 +744,30 @@ func (b *baseBinder) bindUnaryExprWithCurrentContext(astExpr *tree.UnaryExpr, de } func (b *baseBinder) bindBinaryExpr(astExpr *tree.BinaryExpr, depth int32, isRoot bool) (*Expr, error) { + if (isNumericBinaryOp(astExpr.Op) || isBitwiseBinaryOp(astExpr.Op)) && + (b.mysqlSpecialTypeInAst(astExpr.Left) || b.mysqlSpecialTypeInAst(astExpr.Right)) { + return b.bindWithRawMySQLSpecialTypes(func() (*Expr, error) { + if isNumericBinaryOp(astExpr.Op) && b.numericParamType == nil { + return b.bindNumericExprWithDefaultContext(astExpr, depth, b.defaultNumericOuterType()) + } + return b.bindBinaryExprWithCurrentContext(astExpr, depth) + }) + } if isNumericBinaryOp(astExpr.Op) && b.numericParamType == nil { return b.bindNumericExprWithDefaultContext(astExpr, depth, b.defaultNumericOuterType()) } return b.bindBinaryExprWithCurrentContext(astExpr, depth) } +func isBitwiseBinaryOp(op tree.BinaryOp) bool { + switch op { + case tree.BIT_XOR, tree.BIT_OR, tree.BIT_AND, tree.LEFT_SHIFT, tree.RIGHT_SHIFT: + return true + default: + return false + } +} + func (b *baseBinder) bindBinaryExprWithCurrentContext(astExpr *tree.BinaryExpr, depth int32) (*Expr, error) { switch astExpr.Op { case tree.PLUS: @@ -2218,9 +2241,69 @@ func (b *baseBinder) bindComparisonExpr(astExpr *tree.ComparisonExpr, depth int3 if (op == "like" || op == "ilike") && astExpr.Escape != nil { args = append(args, astExpr.Escape) } + if b.mysqlSpecialTypeNumericComparison(astExpr.Left, astExpr.Right) { + return b.bindWithRawMySQLSpecialTypes(func() (*Expr, error) { + return b.bindFuncExprImplByAstExpr(op, args, depth) + }) + } return b.bindFuncExprImplByAstExpr(op, args, depth) } +func (b *baseBinder) bindWithRawMySQLSpecialTypes(bind func() (*Expr, error)) (*Expr, error) { + previous := b.bindRawMySQLSpecialType + b.bindRawMySQLSpecialType = true + defer func() { b.bindRawMySQLSpecialType = previous }() + return bind() +} + +func (b *baseBinder) mysqlSpecialTypeNumericComparison(left, right tree.Expr) bool { + return (b.mysqlSpecialTypeAst(left) && mysqlSpecialTypeNumericLiteral(right)) || + (b.mysqlSpecialTypeAst(right) && mysqlSpecialTypeNumericLiteral(left)) +} + +func (b *baseBinder) mysqlSpecialTypeAst(expr tree.Expr) bool { + name, ok := unwrapParenExpr(expr).(*tree.UnresolvedName) + if !ok { + return false + } + typ, ok := b.numericColumnType(name) + return ok && isEnumOrSetPlanType(&typ) +} + +func (b *baseBinder) mysqlSpecialTypeInAst(expr tree.Expr) bool { + if b.mysqlSpecialTypeAst(expr) { + return true + } + switch value := unwrapParenExpr(expr).(type) { + case *tree.UnaryExpr: + return b.mysqlSpecialTypeInAst(value.Expr) + case *tree.BinaryExpr: + return b.mysqlSpecialTypeInAst(value.Left) || b.mysqlSpecialTypeInAst(value.Right) + } + return false +} + +func mysqlSpecialTypeNumericLiteral(expr tree.Expr) bool { + switch value := unwrapParenExpr(expr).(type) { + case *tree.NumVal: + switch value.ValType { + case tree.P_int64, tree.P_uint64, tree.P_float64: + return true + } + case *tree.Tuple: + if len(value.Exprs) == 0 { + return false + } + for _, item := range value.Exprs { + if !mysqlSpecialTypeNumericLiteral(item) { + return false + } + } + return true + } + return false +} + func (b *baseBinder) bindTupleInByAst(leftTuple *tree.Tuple, rightTuple *tree.Tuple, depth int32, isNot bool) (*plan.Expr, error) { candidates := make([]*plan.Expr, 0, len(rightTuple.Exprs)) @@ -2515,12 +2598,6 @@ func (b *baseBinder) bindFuncExprImplByAstExpr(name string, astArgs []tree.Expr, return nil, err } } - var err error - args, err = bindEnumOrSetDisplayValuesForStringContext(b.GetContext(), name, args) - if err != nil { - return nil, err - } - //promote interval expr rewrite here if name == "interval" { if len(astArgs) == 2 { @@ -2585,42 +2662,6 @@ func (b *baseBinder) bindFuncExprImplByAstExpr(name string, astArgs []tree.Expr, return bindFuncExprImplUdf(b, name, udf, astArgs, args, depth) } -func bindEnumOrSetDisplayValuesForStringContext(ctx context.Context, name string, args []*Expr) ([]*Expr, error) { - if isNumericSpecialTypeContext(name) || !hasStringArgument(args) { - return args, nil - } - for i, arg := range args { - if isEnumOrSetPlanType(&arg.Typ) { - displayValue, err := makeEnumOrSetDisplayValue(ctx, arg) - if err != nil { - return nil, err - } - args[i] = displayValue - } - } - return args, nil -} - -func isNumericSpecialTypeContext(name string) bool { - switch name { - case "+", "-", "*", "/", "div", "%", "mod", "^", "|", "&", "<<", ">>", - "unary_plus", "unary_minus", "unary_tilde": - return true - default: - return false - } -} - -func hasStringArgument(args []*Expr) bool { - for _, arg := range args { - switch types.T(arg.Typ.Id) { - case types.T_char, types.T_varchar, types.T_binary, types.T_varbinary, types.T_blob, types.T_text: - return true - } - } - return false -} - func (b *baseBinder) resolvePreparedNumericArgs(name string, args []*Expr) ([]*Expr, error) { if len(args) != 2 { return args, nil diff --git a/pkg/sql/plan/build_expr_test.go b/pkg/sql/plan/build_expr_test.go index 122e5d2b8a6c3..b9a997800f575 100644 --- a/pkg/sql/plan/build_expr_test.go +++ b/pkg/sql/plan/build_expr_test.go @@ -535,6 +535,29 @@ func TestEnumAndSetKeepStoredValuesInExpressionContexts(t *testing.T) { typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, sql: "select n_name = 1 from nation", }, + { + name: "enum numeric in list", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name in (1, 2) from nation", + }, + { + name: "enum mixed string and numeric in list", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name in ('a', 2) from nation", + wantDisplay: true, + }, + { + name: "enum string function", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select length(n_name) from nation", + wantDisplay: true, + }, + { + name: "enum coalesce", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select coalesce(null, n_name) from nation", + wantDisplay: true, + }, { name: "set numeric arithmetic", typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, diff --git a/pkg/sql/plan/types.go b/pkg/sql/plan/types.go index c6dfd289d0618..c3fc03614a0fc 100644 --- a/pkg/sql/plan/types.go +++ b/pkg/sql/plan/types.go @@ -538,14 +538,15 @@ type Binder interface { } type baseBinder struct { - sysCtx context.Context - builder *QueryBuilder - ctx *BindContext - impl Binder - boundCols []string - numericParamType *Type - numericSubqueryTarget *Type - numericFunctionTarget bool + sysCtx context.Context + builder *QueryBuilder + ctx *BindContext + impl Binder + boundCols []string + numericParamType *Type + numericSubqueryTarget *Type + numericFunctionTarget bool + bindRawMySQLSpecialType bool } type DefaultBinder struct { From 6f919cd7bfe2eb6842bd848a35c693565dc598b3 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Mon, 3 Aug 2026 11:57:37 +0800 Subject: [PATCH 05/22] update --- test/distributed/cases/dtype/enum.result | 76 ++++++++++++++---------- test/distributed/cases/dtype/set.result | 2 +- 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/test/distributed/cases/dtype/enum.result b/test/distributed/cases/dtype/enum.result index 558498f2e572e..92c9876620b6b 100644 --- a/test/distributed/cases/dtype/enum.result +++ b/test/distributed/cases/dtype/enum.result @@ -341,7 +341,8 @@ select id from insert01 where status in (1, 4) order by id; 1 𝄀 4 select id from insert01 where status in ('Pending', 4) order by id; -invalid argument cast to uint16, bad value Pending +➤ id[4,32,0] 𝄀 +1 delete from insert01 where status=3; update insert01 set status='Pending' where status=2; select * from insert01; @@ -353,7 +354,9 @@ select * from insert01 where status=4; ➤ id[4,32,0] ¦ order_number[12,-1,0] ¦ status[12,-1,0] 𝄀 4 ¦ 444 ¦ Cancelled select * from insert01 where status in ('Pending',4); -invalid argument cast to uint16, bad value Pending +➤ id[4,32,0] ¦ order_number[12,-1,0] ¦ status[12,-1,0] 𝄀 +1 ¦ 111 ¦ Pending 𝄀 +2 ¦ 222 ¦ Pending drop table insert01; drop table if exists default01; create table default01 (`col1` enum('T', 'E') not null default 'T'); @@ -446,17 +449,20 @@ select * from enum04 where col2 not between '38921384' and '矩阵起源'; ➤ col1[4,32,0] ¦ col2[12,-1,0] 𝄀 2 ¦ select * from enum04 where col2 in('38921384',''); -Data truncation: data out of range: data type uint16, value '38921384' +➤ col1[4,32,0] ¦ col2[12,-1,0] 𝄀 +1 ¦ 38921384 𝄀 +2 ¦ select * from enum04 where col2 not in('38921384',''); -Data truncation: data out of range: data type uint16, value '38921384' +➤ col1[4,32,0] ¦ col2[12,-1,0] 𝄀 +3 ¦ 矩阵起源 select * from enum04 where col2 like '%921384'; ➤ col1[4,32,0] ¦ col2[12,-1,0] 𝄀 1 ¦ 38921384 select coalesce(null,null,col2) from enum04; -➤ coalesce(null, null, col2)[5,16,0] 𝄀 -1 𝄀 -3 𝄀 -5 +➤ coalesce(null, null, col2)[12,-1,0] 𝄀 +38921384 𝄀 + 𝄀 +矩阵起源 drop table enum04; drop table if exists builtin01; create table builtin01(col1 enum(' 云原生数据库 ','存储引擎 TAE', 'database system') not null,col2 enum(' database','engine ','index meta data')); @@ -480,24 +486,24 @@ select find_in_set(' 云原生数据库 ',col1) from builtin01; 0 select length(col1) as length_col1, length(col2) as length_col2 from builtin01; ➤ length_col1[-5,64,0] ¦ length_col2[-5,64,0] 𝄀 -1 ¦ 1 𝄀 -1 ¦ 1 𝄀 -1 ¦ 1 +22 ¦ 9 𝄀 +16 ¦ 7 𝄀 +15 ¦ 7 select char_length(col1),char_length(col2) from builtin01; ➤ char_length(col1)[-5,64,0] ¦ char_length(col2)[-5,64,0] 𝄀 -1 ¦ 1 𝄀 -1 ¦ 1 𝄀 -1 ¦ 1 +10 ¦ 9 𝄀 +8 ¦ 7 𝄀 +15 ¦ 7 select ltrim(col1) from builtin01; ➤ ltrim(col1)[12,-1,0] 𝄀 -1 𝄀 -2 𝄀 -3 +云原生数据库 𝄀 +存储引擎 TAE 𝄀 +database system select rtrim(col2) from builtin01; ➤ rtrim(col2)[12,-1,0] 𝄀 -1 𝄀 -2 𝄀 -2 + database 𝄀 +engine 𝄀 +engine select lpad(col1,20,'-') from builtin01; ➤ lpad(col1, 20, -)[12,-1,0] 𝄀 ---------- 云原生数据库 𝄀 @@ -520,21 +526,21 @@ select endswith(col1,'数据表') from builtin01; 0 select reverse(col1),reverse(col2) from builtin01; ➤ reverse(col1)[12,-1,0] ¦ reverse(col2)[12,-1,0] 𝄀 -1 ¦ 1 𝄀 -2 ¦ 2 𝄀 -3 ¦ 2 + 库据数生原云 ¦ esabatad 𝄀 +EAT 擎引储存 ¦ enigne 𝄀 +metsys esabatad ¦ enigne select substring(col1,4,6),substring(col2,1,6) from builtin01; ➤ substring(col1, 4, 6)[12,-1,0] ¦ substring(col2, 1, 6)[12,-1,0] 𝄀 - ¦ 1 𝄀 - ¦ 2 𝄀 - ¦ 2 +原生数据库 ¦ datab 𝄀 +擎 TAE ¦ engine 𝄀 +abase ¦ engine select * from builtin01 where col1 = space(5); ➤ col1[12,-1,0] ¦ col2[12,-1,0] select bit_length(col2) from builtin01; ➤ bit_length(col2)[-5,64,0] 𝄀 -8 𝄀 -8 𝄀 -8 +72 𝄀 +56 𝄀 +56 select empty(col2) from builtin01; ➤ empty(col2)[-7,1,0] 𝄀 0 𝄀 @@ -544,9 +550,11 @@ select count(col1) as count_col1 from builtin01; ➤ count_col1[-5,64,0] 𝄀 3 select max(col1), max(col2) from builtin01; -invalid argument aggregate function max, bad value [ENUM] +➤ max(col1)[12,-1,0] ¦ max(col2)[12,-1,0] 𝄀 +存储引擎 TAE ¦ engine select min(col1), min(col2) from builtin01; -invalid argument aggregate function min, bad value [ENUM] +➤ min(col1)[12,-1,0] ¦ min(col2)[12,-1,0] 𝄀 + 云原生数据库 ¦ database select group_concat(col1,col2) from builtin01; ➤ group_concat(col1, col2 separator ,)[12,0,0] 𝄀 云原生数据库 database,存储引擎 TAEengine ,database systemengine @@ -558,9 +566,11 @@ insert into agg01 values (2, 'weueiwqeowqehwgqjhenw'); insert into agg01 values (3, 'qwewqewqeqewq'); insert into agg01 values (4, null); select max(col2) from agg01; -invalid argument aggregate function max, bad value [ENUM] +➤ max(col2)[12,-1,0] 𝄀 +weueiwqeowqehwgqjhenw select min(col2) from agg01; -invalid argument aggregate function min, bad value [ENUM] +➤ min(col2)[12,-1,0] 𝄀 +egwjqebwq select * from agg01; ➤ col1[4,32,0] ¦ col2[12,-1,0] 𝄀 1 ¦ egwjqebwq 𝄀 diff --git a/test/distributed/cases/dtype/set.result b/test/distributed/cases/dtype/set.result index dd49a94f20e66..d0345b25f621b 100644 --- a/test/distributed/cases/dtype/set.result +++ b/test/distributed/cases/dtype/set.result @@ -141,7 +141,7 @@ drop table if exists set_modify; create table set_modify (id int primary key, tags set('a','b','c')); insert into set_modify values (1, 'a,c'), (2, 'b'); alter table set_modify modify column tags set('a','b'); -internal error: convert to MySQL set failed: value 5 overflow set boundary 3 +internal error: convert to MySQL set failed: item a,c is not in set [a,b] drop table set_modify; drop table if exists set_modify2; create table set_modify2 (id int primary key, tags set('a','b')); From 55d6bcff3662fac575440290fe1884ac4f7aa2c3 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Mon, 3 Aug 2026 14:35:42 +0800 Subject: [PATCH 06/22] update --- pkg/sql/plan/build_expr_test.go | 50 +++++++++++++++++++++++++ pkg/sql/plan/function/func_cast.go | 3 ++ pkg/sql/plan/function/func_cast_test.go | 40 ++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/pkg/sql/plan/build_expr_test.go b/pkg/sql/plan/build_expr_test.go index 9aca33e71ed98..cb28729440813 100644 --- a/pkg/sql/plan/build_expr_test.go +++ b/pkg/sql/plan/build_expr_test.go @@ -30,6 +30,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql" + "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" "github.com/matrixorigin/matrixone/pkg/sql/plan/rule" "github.com/smartystreets/goconvey/convey" ) @@ -530,6 +531,16 @@ func TestEnumAndSetKeepStoredValuesInExpressionContexts(t *testing.T) { typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, sql: "select n_name + 0 from nation", }, + { + name: "enum numeric unary minus", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select -n_name from nation", + }, + { + name: "set bitwise unary complement", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select ~n_name from nation", + }, { name: "enum numeric comparison", typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, @@ -594,6 +605,19 @@ func TestEnumAndSetKeepStoredValuesInExpressionContexts(t *testing.T) { } } +func TestIsBitwiseBinaryOp(t *testing.T) { + for _, op := range []tree.BinaryOp{ + tree.BIT_XOR, + tree.BIT_OR, + tree.BIT_AND, + tree.LEFT_SHIFT, + tree.RIGHT_SHIFT, + } { + require.True(t, isBitwiseBinaryOp(op)) + } + require.False(t, isBitwiseBinaryOp(tree.PLUS)) +} + func containsEnumOrSetDisplayValue(expr *plan.Expr) bool { if expr == nil { return false @@ -637,6 +661,32 @@ func TestEnumDisplayValueToJSONUsesJSONQuoteInPlannerCasts(t *testing.T) { require.Equal(t, "json_quote", expr.GetF().Func.ObjName) } +func TestRawMySQLSpecialTypeToJSONUsesDisplayValue(t *testing.T) { + ctx := NewMockCompilerContext(true).GetContext() + for _, typ := range []plan.Type{ + {Id: int32(types.T_enum), Enumvalues: "a,b,"}, + {Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + } { + raw := &plan.Expr{ + Typ: typ, + Expr: &plan.Expr_Col{Col: &plan.ColRef{ + RelPos: 1, + ColPos: 2, + Name: "special", + }}, + } + + got, rewritten, err := rewriteMySQLSpecialTypeDisplayCast( + ctx, raw, plan.Type{Id: int32(types.T_json)}, + ) + require.NoError(t, err) + require.True(t, rewritten) + require.Equal(t, "json_quote", got.GetF().Func.ObjName) + require.Len(t, got.GetF().Args, 1) + require.True(t, isEnumOrSetDisplayValueExpr(got.GetF().Args[0])) + } +} + func TestSetDisplayValueToJSONUsesJSONQuoteInPlannerCasts(t *testing.T) { ctx := NewMockCompilerContext(true).GetContext() displayExpr := &plan.Expr{ diff --git a/pkg/sql/plan/function/func_cast.go b/pkg/sql/plan/function/func_cast.go index 27d189615bd31..03a5824f5a93a 100644 --- a/pkg/sql/plan/function/func_cast.go +++ b/pkg/sql/plan/function/func_cast.go @@ -1164,6 +1164,9 @@ func castToDecimal256(proc *process.Process, from *vector.Vector, toType types.T case types.T_uint64: s := vector.GenerateFunctionFixedTypeParameter[uint64](from) return unsignedToDecimal256(s, rs, length, selectList) + case types.T_enum: + s := vector.GenerateFunctionFixedTypeParameter[types.Enum](from) + return enumToOthers(proc.Ctx, s, toType, result, length, selectList) case types.T_float32: s := vector.GenerateFunctionFixedTypeParameter[float32](from) return floatToDecimal256(s, rs, length, selectList) diff --git a/pkg/sql/plan/function/func_cast_test.go b/pkg/sql/plan/function/func_cast_test.go index 74ca9056af5bc..1f5866fca0d05 100644 --- a/pkg/sql/plan/function/func_cast_test.go +++ b/pkg/sql/plan/function/func_cast_test.go @@ -96,6 +96,46 @@ func TestStringToFloat32DefaultCompatibilityRange(t *testing.T) { require.True(t, succeed, info) } +func TestCastEnumToNumericTypes(t *testing.T) { + proc := testutil.NewProcess(t) + source := []types.Enum{1, 3, 0} + nulls := []bool{false, false, true} + + for _, tc := range []struct { + name string + target types.Type + zero any + want any + }{ + {"int8", types.T_int8.ToType(), []int8{}, []int8{1, 3, 0}}, + {"int16", types.T_int16.ToType(), []int16{}, []int16{1, 3, 0}}, + {"int32", types.T_int32.ToType(), []int32{}, []int32{1, 3, 0}}, + {"int64", types.T_int64.ToType(), []int64{}, []int64{1, 3, 0}}, + {"uint8", types.T_uint8.ToType(), []uint8{}, []uint8{1, 3, 0}}, + {"uint16", types.T_uint16.ToType(), []uint16{}, []uint16{1, 3, 0}}, + {"uint32", types.T_uint32.ToType(), []uint32{}, []uint32{1, 3, 0}}, + {"uint64", types.T_uint64.ToType(), []uint64{}, []uint64{1, 3, 0}}, + {"float32", types.T_float32.ToType(), []float32{}, []float32{1, 3, 0}}, + {"float64", types.T_float64.ToType(), []float64{}, []float64{1, 3, 0}}, + {"decimal64", types.New(types.T_decimal64, 18, 0), []types.Decimal64{}, []types.Decimal64{1, 3, 0}}, + {"decimal128", types.New(types.T_decimal128, 38, 0), []types.Decimal128{}, []types.Decimal128{{B0_63: 1}, {B0_63: 3}, {}}}, + {"decimal256", types.New(types.T_decimal256, 65, 0), []types.Decimal256{}, []types.Decimal256{{B0_63: 1}, {B0_63: 3}, {}}}, + } { + t.Run(tc.name, func(t *testing.T) { + testCase := NewFunctionTestCase(proc, + []FunctionTestInput{ + NewFunctionTestInput(types.T_enum.ToType(), source, nulls), + NewFunctionTestInput(tc.target, tc.zero, nil), + }, + NewFunctionTestResult(tc.target, false, tc.want, nulls), + NewCast, + ) + succeed, info := testCase.Run() + require.True(t, succeed, info) + }) + } +} + func TestStringToFixedFloat32PreservesSourcePrecision(t *testing.T) { proc := testutil.NewProcess(t) targetType := types.New(types.T_float32, 5, 2) From e9e627262d12f0c8342620b3c6275ffd7c9a24b9 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Mon, 3 Aug 2026 18:23:12 +0800 Subject: [PATCH 07/22] update --- pkg/sql/plan/base_binder.go | 97 +++++++++++++++++---- pkg/sql/plan/bind_insert.go | 10 +++ pkg/sql/plan/build_constraint_util.go | 12 ++- pkg/sql/plan/build_dml_util_test.go | 60 +++++++++++++ pkg/sql/plan/build_expr_test.go | 60 +++++++++++++ pkg/sql/plan/mysql_special_types.go | 118 ++++++++++++++++++++++++++ pkg/sql/util/eval_expr_util.go | 17 +++- test/distributed/cases/dtype/enum.sql | 37 ++++++++ 8 files changed, 392 insertions(+), 19 deletions(-) diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go index 12c25e7f30a06..345d84ddbad61 100644 --- a/pkg/sql/plan/base_binder.go +++ b/pkg/sql/plan/base_binder.go @@ -152,7 +152,11 @@ func (b *baseBinder) baseBindExpr(astExpr tree.Expr, depth int32, isRoot bool) ( } parentParamType := b.numericParamType b.numericParamType = nil - if isNumericArithmeticRoot(exprImpl.Expr) || + if b.mysqlSpecialTypeInAst(exprImpl.Expr) && makeTypeByPlan2Type(typ).IsNumeric() { + expr, err = b.bindWithRawMySQLSpecialTypes(func() (*Expr, error) { + return b.impl.BindExpr(exprImpl.Expr, depth, false) + }) + } else if isNumericArithmeticRoot(exprImpl.Expr) || b.isGenericNumericFunctionRoot(exprImpl.Expr, depth, &typ) { expr, err = b.bindNumericExprWithContext(exprImpl.Expr, depth, &typ) } else { @@ -700,20 +704,28 @@ func (b *baseBinder) bindCaseExpr(astExpr *tree.CaseExpr, depth int32, isRoot bo } func (b *baseBinder) bindRangeCond(astExpr *tree.RangeCond, depth int32, isRoot bool) (*Expr, error) { - if astExpr.Not { - // rewrite 'col not between 1, 20' to 'col < 1 or col > 20' - newLeftExpr := tree.NewComparisonExpr(tree.LESS_THAN, astExpr.Left, astExpr.From) - newRightExpr := tree.NewComparisonExpr(tree.GREAT_THAN, astExpr.Left, astExpr.To) - return b.bindFuncExprImplByAstExpr("or", []tree.Expr{newLeftExpr, newRightExpr}, depth) - } else { - if _, ok := astExpr.Left.(*tree.Tuple); ok { - newLeftExpr := tree.NewComparisonExpr(tree.GREAT_THAN_EQUAL, astExpr.Left, astExpr.From) - newRightExpr := tree.NewComparisonExpr(tree.LESS_THAN_EQUAL, astExpr.Left, astExpr.To) - return b.bindFuncExprImplByAstExpr("and", []tree.Expr{newLeftExpr, newRightExpr}, depth) - } + bind := func() (*Expr, error) { + if astExpr.Not { + // rewrite 'col not between 1, 20' to 'col < 1 or col > 20' + newLeftExpr := tree.NewComparisonExpr(tree.LESS_THAN, astExpr.Left, astExpr.From) + newRightExpr := tree.NewComparisonExpr(tree.GREAT_THAN, astExpr.Left, astExpr.To) + return b.bindFuncExprImplByAstExpr("or", []tree.Expr{newLeftExpr, newRightExpr}, depth) + } else { + if _, ok := astExpr.Left.(*tree.Tuple); ok { + newLeftExpr := tree.NewComparisonExpr(tree.GREAT_THAN_EQUAL, astExpr.Left, astExpr.From) + newRightExpr := tree.NewComparisonExpr(tree.LESS_THAN_EQUAL, astExpr.Left, astExpr.To) + return b.bindFuncExprImplByAstExpr("and", []tree.Expr{newLeftExpr, newRightExpr}, depth) + } - return b.bindFuncExprImplByAstExpr("between", []tree.Expr{astExpr.Left, astExpr.From, astExpr.To}, depth) + return b.bindFuncExprImplByAstExpr("between", []tree.Expr{astExpr.Left, astExpr.From, astExpr.To}, depth) + } } + if b.mysqlSpecialTypeInAst(astExpr.Left) && + b.mysqlSpecialTypeNumericContext(astExpr.From) && + b.mysqlSpecialTypeNumericContext(astExpr.To) { + return b.bindWithRawMySQLSpecialTypes(bind) + } + return bind() } func (b *baseBinder) bindUnaryExpr(astExpr *tree.UnaryExpr, depth int32, isRoot bool) (*Expr, error) { @@ -2257,8 +2269,51 @@ func (b *baseBinder) bindWithRawMySQLSpecialTypes(bind func() (*Expr, error)) (* } func (b *baseBinder) mysqlSpecialTypeNumericComparison(left, right tree.Expr) bool { - return (b.mysqlSpecialTypeAst(left) && mysqlSpecialTypeNumericLiteral(right)) || - (b.mysqlSpecialTypeAst(right) && mysqlSpecialTypeNumericLiteral(left)) + return (b.mysqlSpecialTypeAst(left) && b.mysqlSpecialTypeNumericContext(right)) || + (b.mysqlSpecialTypeAst(right) && b.mysqlSpecialTypeNumericContext(left)) +} + +// mysqlSpecialTypeNumericContext reports AST expressions whose bound contract +// is numeric. ENUM and SET are normally exposed as display strings, but MySQL +// uses their stored ordinal/bitmap when compared with a numeric operand. +func (b *baseBinder) mysqlSpecialTypeNumericContext(expr tree.Expr) bool { + switch value := unwrapParenExpr(expr).(type) { + case *tree.NumVal: + return mysqlSpecialTypeNumericLiteral(value) + case *tree.UnresolvedName: + typ, ok := b.numericColumnType(value) + return ok && makeTypeByPlan2Type(typ).IsNumeric() + case *tree.UnaryExpr: + return (value.Op == tree.UNARY_PLUS || value.Op == tree.UNARY_MINUS) && + b.mysqlSpecialTypeNumericContext(value.Expr) + case *tree.BinaryExpr: + return isNumericBinaryOp(value.Op) || isBitwiseBinaryOp(value.Op) + case *tree.CastExpr: + typ, err := getTypeFromAst(b.GetContext(), value.Type) + return err == nil && makeTypeByPlan2Type(typ).IsNumeric() + case *tree.FuncExpr: + return supportsGenericNumericFunctionContext(strings.ToLower(numericAstFunctionName(value))) + case *tree.Tuple: + if len(value.Exprs) == 0 { + return false + } + for _, item := range value.Exprs { + if !b.mysqlSpecialTypeNumericContext(item) { + return false + } + } + return true + } + return false +} + +func mysqlSpecialTypeInExprs(b *baseBinder, exprs []tree.Expr) bool { + for _, expr := range exprs { + if b.mysqlSpecialTypeInAst(expr) { + return true + } + } + return false } func (b *baseBinder) mysqlSpecialTypeAst(expr tree.Expr) bool { @@ -2279,6 +2334,12 @@ func (b *baseBinder) mysqlSpecialTypeInAst(expr tree.Expr) bool { return b.mysqlSpecialTypeInAst(value.Expr) case *tree.BinaryExpr: return b.mysqlSpecialTypeInAst(value.Left) || b.mysqlSpecialTypeInAst(value.Right) + case *tree.CastExpr: + return b.mysqlSpecialTypeInAst(value.Expr) + case *tree.FuncExpr: + return mysqlSpecialTypeInExprs(b, value.Exprs) + case *tree.Tuple: + return mysqlSpecialTypeInExprs(b, value.Exprs) } return false } @@ -2381,6 +2442,12 @@ func (b *baseBinder) bindFuncExpr(astExpr *tree.FuncExpr, depth int32, isRoot bo if strings.EqualFold(funcName, "mod") && b.numericParamType == nil { return b.bindNumericExprWithDefaultContext(astExpr, depth, b.defaultNumericOuterType()) } + if supportsGenericNumericFunctionContext(strings.ToLower(funcName)) && + mysqlSpecialTypeInExprs(b, astExpr.Exprs) { + return b.bindWithRawMySQLSpecialTypes(func() (*Expr, error) { + return b.bindFuncExprImplByAstExpr(funcName, astExpr.Exprs, depth) + }) + } if function.GetFunctionIsAggregateByName(funcName) && astExpr.WindowSpec == nil { diff --git a/pkg/sql/plan/bind_insert.go b/pkg/sql/plan/bind_insert.go index 6da4173d13013..0947a842c0893 100644 --- a/pkg/sql/plan/bind_insert.go +++ b/pkg/sql/plan/bind_insert.go @@ -3424,6 +3424,16 @@ func (builder *QueryBuilder) buildValueScan( funcBinder = defaultFuncBinder } for _, r := range stmt.Rows { + if nv, ok := r[i].(*tree.NumVal); ok && builder.isInsertIgnore { + expr, handled, err := makeInsertIgnoreMySQLSpecialTypeConstExpr(builder.GetContext(), nv, col.Typ) + if err != nil { + return 0, err + } + if handled { + rowsetData.Cols[i].Data = append(rowsetData.Cols[i].Data, &plan.RowsetExpr{Expr: expr}) + continue + } + } if nv, ok := r[i].(*tree.NumVal); ok && !isEnumOrSetPlanType(&col.Typ) && !isTypedArrayPlanType(&col.Typ) { expr, err := MakeInsertValueConstExpr(proc, nv, &colTyp, builder.isInsertIgnore) if err != nil { diff --git a/pkg/sql/plan/build_constraint_util.go b/pkg/sql/plan/build_constraint_util.go index 24508bd67c4e5..541d0d467d877 100644 --- a/pkg/sql/plan/build_constraint_util.go +++ b/pkg/sql/plan/build_constraint_util.go @@ -1519,7 +1519,7 @@ func MakeInsertValueConstExpr(proc *process.Process, numVal *tree.NumVal, colTyp return MakePlan2BoolConstExprWithType(num), err case types.T_bit: - canInsert, num, err := util.SetInsertValueBit(proc, numVal, colType) + canInsert, num, err := util.SetInsertValueBit(proc, numVal, colType, isIgnore) if err != nil || !canInsert { return nil, err } @@ -1730,6 +1730,16 @@ func buildValueScan( binder := NewDefaultBinder(builder.GetContext(), nil, nil, col.Typ, nil) binder.builder = builder for _, r := range slt.Rows { + if nv, ok := r[i].(*tree.NumVal); ok && builder.isInsertIgnore { + expr, handled, err := makeInsertIgnoreMySQLSpecialTypeConstExpr(builder.GetContext(), nv, col.Typ) + if err != nil { + return err + } + if handled { + rowsetData.Cols[i].Data = append(rowsetData.Cols[i].Data, &plan.RowsetExpr{Expr: expr}) + continue + } + } if nv, ok := r[i].(*tree.NumVal); ok && !isEnumOrSetPlanType(&col.Typ) && !isTypedArrayPlanType(&col.Typ) { expr, err := MakeInsertValueConstExpr(proc, nv, &colTyp, builder.isInsertIgnore) if err != nil { diff --git a/pkg/sql/plan/build_dml_util_test.go b/pkg/sql/plan/build_dml_util_test.go index 35343e38a5e53..e259abb87a236 100644 --- a/pkg/sql/plan/build_dml_util_test.go +++ b/pkg/sql/plan/build_dml_util_test.go @@ -282,6 +282,66 @@ func TestMakeInsertValueConstExprBinaryHexPadding(t *testing.T) { } } +func TestMakeInsertValueConstExprBitIgnoreTruncates(t *testing.T) { + proc := testutil.NewProcess(t) + colType := types.New(types.T_bit, 4, 0) + numVal := tree.NewNumVal("0b11111", "0b11111", false, tree.P_bit) + + _, err := MakeInsertValueConstExpr(proc, numVal, &colType, false) + require.Error(t, err) + + expr, err := MakeInsertValueConstExpr(proc, numVal, &colType, true) + require.NoError(t, err) + require.Equal(t, uint64(15), expr.GetLit().GetU64Val()) +} + +func TestMakeInsertIgnoreMySQLSpecialTypeConstExpr(t *testing.T) { + ctx := context.Background() + tests := []struct { + name string + target plan.Type + value *tree.NumVal + wantType types.T + wantEnum uint32 + wantSet uint64 + }{ + { + name: "invalid enum becomes error member", + target: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + value: tree.NewNumVal("bad", "bad", false, tree.P_char), + wantType: types.T_enum, + }, + { + name: "invalid set member is dropped", + target: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + value: tree.NewNumVal("x,bad", "x,bad", false, tree.P_char), + wantType: types.T_uint64, + wantSet: 1, + }, + { + name: "invalid year becomes zero", + target: plan.Type{Id: int32(types.T_year)}, + value: tree.NewNumVal(int64(2156), "2156", false, tree.P_int64), + wantType: types.T_year, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + expr, handled, err := makeInsertIgnoreMySQLSpecialTypeConstExpr(ctx, tt.value, tt.target) + require.NoError(t, err) + require.True(t, handled) + require.Equal(t, int32(tt.wantType), expr.Typ.Id) + if tt.wantType == types.T_enum { + require.Equal(t, tt.wantEnum, expr.GetLit().GetEnumVal()) + } + if tt.wantType == types.T_uint64 { + require.Equal(t, tt.wantSet, expr.GetLit().GetU64Val()) + } + }) + } +} + func TestAppendIndexPrefixProjection(t *testing.T) { newBuilder := func(t *testing.T) (*QueryBuilder, *BindContext, int32) { t.Helper() diff --git a/pkg/sql/plan/build_expr_test.go b/pkg/sql/plan/build_expr_test.go index cb28729440813..f5afdb5f96006 100644 --- a/pkg/sql/plan/build_expr_test.go +++ b/pkg/sql/plan/build_expr_test.go @@ -551,6 +551,36 @@ func TestEnumAndSetKeepStoredValuesInExpressionContexts(t *testing.T) { typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, sql: "select n_name in (1, 2) from nation", }, + { + name: "enum explicit numeric cast", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select cast(n_name as signed) from nation", + }, + { + name: "enum numeric function", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select abs(n_name) from nation", + }, + { + name: "enum numeric column comparison", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name = n_regionkey from nation", + }, + { + name: "enum numeric between", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name between n_regionkey and 2 from nation", + }, + { + name: "enum non-literal numeric in list", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name in (n_regionkey) from nation", + }, + { + name: "enum unary numeric comparison", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name = +1 from nation", + }, { name: "enum mixed string and numeric in list", typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, @@ -579,6 +609,36 @@ func TestEnumAndSetKeepStoredValuesInExpressionContexts(t *testing.T) { typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, sql: "select n_name & 1 from nation", }, + { + name: "set explicit numeric cast", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select cast(n_name as signed) from nation", + }, + { + name: "set numeric function", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select abs(n_name) from nation", + }, + { + name: "set numeric column comparison", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select n_name = n_regionkey from nation", + }, + { + name: "set numeric between", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select n_name between n_regionkey and 5 from nation", + }, + { + name: "set non-literal numeric in list", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select n_name in (n_regionkey) from nation", + }, + { + name: "set unary numeric comparison", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select n_name = +1 from nation", + }, { name: "enum string comparison", typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, diff --git a/pkg/sql/plan/mysql_special_types.go b/pkg/sql/plan/mysql_special_types.go index be650f3da46b8..89d05c95eb8af 100644 --- a/pkg/sql/plan/mysql_special_types.go +++ b/pkg/sql/plan/mysql_special_types.go @@ -54,6 +54,124 @@ func isEnumOrSetPlanType(typ *plan.Type) bool { return isEnumPlanType(typ) || isSetPlanType(typ) } +// makeInsertIgnoreMySQLSpecialTypeConstExpr implements MySQL's INSERT IGNORE +// coercion for literal YEAR, ENUM, and SET values. BIT coercion stays in the +// shared literal parser. Regular INSERT keeps the existing strict conversion +// path; only IGNORE reaches this helper. +func makeInsertIgnoreMySQLSpecialTypeConstExpr( + ctx context.Context, + value *tree.NumVal, + targetType plan.Type, +) (*plan.Expr, bool, error) { + if value == nil || value.ValType == tree.P_null || value.ValType == tree.P_nulltext { + return nil, false, nil + } + + if isEnumPlanType(&targetType) { + index, err := mysqlEnumLiteralIndex(targetType.Enumvalues, value) + if err != nil { + index = 0 // invalid ENUM values are stored as the empty-error member + } + return &plan.Expr{ + Typ: targetType, + Expr: &plan.Expr_Lit{Lit: &plan.Literal{ + Value: &plan.Literal_EnumVal{EnumVal: uint32(index)}, + }}, + }, true, nil + } + + if isSetPlanType(&targetType) { + bits := mysqlSetIgnoreLiteralBits(targetType.Enumvalues, value) + return &plan.Expr{ + Typ: targetType, + Expr: &plan.Expr_Lit{Lit: &plan.Literal{ + Value: &plan.Literal_U64Val{U64Val: bits}, + }}, + }, true, nil + } + + if types.T(targetType.Id) == types.T_year && !mysqlYearLiteralIsValid(value) { + zero := makePlan2Int64ConstExprWithType(0) + expr, err := appendCastBeforeExpr(ctx, zero, targetType) + return expr, true, err + } + + return nil, false, nil +} + +func mysqlEnumLiteralIndex(enumValues string, value *tree.NumVal) (types.Enum, error) { + switch value.ValType { + case tree.P_int64: + v, ok := value.Int64() + if !ok || v < 0 || v > int64(^uint16(0)) { + return 0, moerr.NewInvalidInputNoCtx("invalid ENUM index") + } + return types.ParseEnumValue(enumValues, uint16(v)) + case tree.P_uint64: + v, ok := value.Uint64() + if !ok || v > uint64(^uint16(0)) { + return 0, moerr.NewInvalidInputNoCtx("invalid ENUM index") + } + return types.ParseEnumValue(enumValues, uint16(v)) + default: + return types.ParseEnum(enumValues, value.String()) + } +} + +func mysqlSetIgnoreLiteralBits(setValues string, value *tree.NumVal) uint64 { + if value.ValType == tree.P_int64 { + if v, ok := value.Int64(); ok && v >= 0 { + return uint64(v) & mysqlSetValidBitmap(setValues) + } + } + if value.ValType == tree.P_uint64 { + if v, ok := value.Uint64(); ok { + return v & mysqlSetValidBitmap(setValues) + } + } + + bits := uint64(0) + for _, member := range strings.Split(value.String(), ",") { + memberBits, err := types.ParseSet(setValues, member) + if err == nil { + bits |= memberBits + } + } + return bits +} + +func mysqlSetValidBitmap(setValues string) uint64 { + memberCount := len(strings.Split(setValues, ",")) + if memberCount >= types.MaxSetMembers { + return ^uint64(0) + } + return (uint64(1) << uint(memberCount)) - 1 +} + +func mysqlYearLiteralIsValid(value *tree.NumVal) bool { + switch value.ValType { + case tree.P_int64: + v, ok := value.Int64() + if !ok { + return false + } + _, err := types.ParseMoYearFromInt(v) + return err == nil + case tree.P_uint64: + v, ok := value.Uint64() + if !ok || v > uint64(^uint64(0)>>1) { + return false + } + _, err := types.ParseMoYearFromInt(int64(v)) + return err == nil + case tree.P_char: + _, err := types.ParseMoYear(value.String()) + return err == nil + default: + return true + } +} + func isGeometryPlanType(typ *plan.Type) bool { return typ != nil && (typ.Id == int32(types.T_geometry) || typ.Id == int32(types.T_geometry32)) } diff --git a/pkg/sql/util/eval_expr_util.go b/pkg/sql/util/eval_expr_util.go index da58ac7b71d38..0ae78bb624ffb 100644 --- a/pkg/sql/util/eval_expr_util.go +++ b/pkg/sql/util/eval_expr_util.go @@ -993,10 +993,20 @@ func floatNumToFixFloat[T constraints.Float | constraints.Integer]( return T(v), nil } -func SetInsertValueBit(proc *process.Process, numVal *tree.NumVal, colType *types.Type) (canInsert bool, val uint64, err error) { +func SetInsertValueBit(proc *process.Process, numVal *tree.NumVal, colType *types.Type, isIgnore bool) (canInsert bool, val uint64, err error) { var ok bool canInsert = true width := colType.Width + defer func() { + if err == nil || !isIgnore { + return + } + if width < 64 { + val &= (uint64(1) << uint(width)) - 1 + } + canInsert = true + err = nil + }() switch numVal.ValType { case tree.P_bool: @@ -1027,11 +1037,12 @@ func SetInsertValueBit(proc *process.Process, numVal *tree.NumVal, colType *type } else if num < 0 { err = moerr.NewInvalidInputf(proc.Ctx, "unsupported negative value %v", val) return - } else if uint64(math.Round(num)) > uint64(1< uint64(1< Date: Mon, 3 Aug 2026 18:30:18 +0800 Subject: [PATCH 08/22] update --- test/distributed/cases/dtype/enum.result | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/distributed/cases/dtype/enum.result b/test/distributed/cases/dtype/enum.result index 92c9876620b6b..d4647f13912ae 100644 --- a/test/distributed/cases/dtype/enum.result +++ b/test/distributed/cases/dtype/enum.result @@ -358,6 +358,48 @@ select * from insert01 where status in ('Pending',4); 1 ¦ 111 ¦ Pending 𝄀 2 ¦ 222 ¦ Pending drop table insert01; +drop table if exists mysql_compat_special_numeric_context; +create table mysql_compat_special_numeric_context ( +id int primary key, +e enum('a', 'b', ''), +s set('x', 'y', 'z'), +i int +); +insert into mysql_compat_special_numeric_context values +(1, 'a', 'x,z', 1), +(2, 'b', 'y', 2), +(3, '', '', 3); +select id, cast(e as signed), abs(e), e = i, e between 1 and 2, +e in (i), e = +1, e = 'a' +from mysql_compat_special_numeric_context order by id; +➤ id[4,32,0] ¦ cast(e as signed)[-5,64,0] ¦ abs(e)[-5,64,0] ¦ e = i[-7,1,0] ¦ e between 1 and 2[-7,1,0] ¦ e in (i)[-7,1,0] ¦ e = +1[-7,1,0] ¦ e = a[-7,1,0] 𝄀 +1 ¦ 1 ¦ 1 ¦ 1 ¦ 1 ¦ 1 ¦ 1 ¦ 1 𝄀 +2 ¦ 2 ¦ 2 ¦ 1 ¦ 1 ¦ 1 ¦ 0 ¦ 0 𝄀 +3 ¦ 3 ¦ 3 ¦ 1 ¦ 0 ¦ 1 ¦ 0 ¦ 0 +select id, cast(s as signed), abs(s), s = i, s between 1 and 5, +s in (i), s = +5, s = 'x,z' +from mysql_compat_special_numeric_context order by id; +➤ id[4,32,0] ¦ cast(s as signed)[-5,64,0] ¦ abs(s)[-5,64,0] ¦ s = i[-7,1,0] ¦ s between 1 and 5[-7,1,0] ¦ s in (i)[-7,1,0] ¦ s = +5[-7,1,0] ¦ s = x,z[-7,1,0] 𝄀 +1 ¦ 5 ¦ 5 ¦ 0 ¦ 1 ¦ 0 ¦ 1 ¦ 1 𝄀 +2 ¦ 2 ¦ 2 ¦ 1 ¦ 1 ¦ 1 ¦ 0 ¦ 0 𝄀 +3 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ 0 +drop table mysql_compat_special_numeric_context; +drop table if exists mysql_compat_special_ignore; +create table mysql_compat_special_ignore ( +id int primary key, +y year, +b bit(4), +e enum('a', 'b', ''), +s set('x', 'y', 'z') +); +set session sql_mode = 'STRICT_TRANS_TABLES'; +insert ignore into mysql_compat_special_ignore values (1, 2156, b'11111', 'bad', 'x,bad'); +internal error: convert to MySQL enum failed: number 0 overflow enum boundary [1, 3] +select id, y, y + 0, bin(b + 0), e, e + 0, s, s + 0 +from mysql_compat_special_ignore order by id; +➤ id[4,32,0] ¦ y[91,65535,0] ¦ y + 0[-5,64,0] ¦ bin(b + 0)[12,-1,0] ¦ e[12,-1,0] ¦ e + 0[-5,64,0] ¦ s[12,-1,0] ¦ s + 0[3,38,0] +set session sql_mode = ''; +drop table mysql_compat_special_ignore; drop table if exists default01; create table default01 (`col1` enum('T', 'E') not null default 'T'); desc default01; From 3d1a623b5424c4c2f0234a22d9d406a93c426c24 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Mon, 3 Aug 2026 19:01:45 +0800 Subject: [PATCH 09/22] update --- pkg/sql/plan/make.go | 4 ++++ pkg/sql/plan/mysql_special_types_test.go | 15 +++++++++++++++ test/distributed/cases/dtype/enum.sql | 13 +++++++++++++ 3 files changed, 32 insertions(+) diff --git a/pkg/sql/plan/make.go b/pkg/sql/plan/make.go index 9be8b4cafe11d..4d752c7b66cfd 100644 --- a/pkg/sql/plan/make.go +++ b/pkg/sql/plan/make.go @@ -760,6 +760,10 @@ func funcCastForEnumType(ctx context.Context, expr *Expr, targetType Type) (*Exp if targetType.Id != int32(types.T_enum) { return expr, nil } + if isEnumPlanType(&expr.Typ) && expr.Typ.Enumvalues == targetType.Enumvalues { + expr.Typ = targetType + return expr, nil + } sourceExpr := expr astArgs := []tree.Expr{ diff --git a/pkg/sql/plan/mysql_special_types_test.go b/pkg/sql/plan/mysql_special_types_test.go index cb0bde8543a21..2788c8c0469c0 100644 --- a/pkg/sql/plan/mysql_special_types_test.go +++ b/pkg/sql/plan/mysql_special_types_test.go @@ -23,6 +23,21 @@ import ( "github.com/stretchr/testify/require" ) +func TestFuncCastForEnumTypeKeepsMatchingErrorMember(t *testing.T) { + target := plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"} + expr := &plan.Expr{ + Typ: target, + Expr: &plan.Expr_Lit{Lit: &plan.Literal{ + Value: &plan.Literal_EnumVal{EnumVal: 0}, + }}, + } + + got, err := funcCastForEnumType(context.Background(), expr, target) + require.NoError(t, err) + require.Same(t, expr, got) + require.Equal(t, uint32(0), got.GetLit().GetEnumVal()) +} + // TestGeomFromTextSRIDInResultType verifies that a constant SRID argument to // ST_GeomFromText lands in the result type's Width (since geometry cells store // bare WKB and SRID lives in the type). diff --git a/test/distributed/cases/dtype/enum.sql b/test/distributed/cases/dtype/enum.sql index 2994365230730..0443bd73b30e8 100644 --- a/test/distributed/cases/dtype/enum.sql +++ b/test/distributed/cases/dtype/enum.sql @@ -238,6 +238,19 @@ set session sql_mode = 'STRICT_TRANS_TABLES'; insert ignore into mysql_compat_special_ignore values (1, 2156, b'11111', 'bad', 'x,bad'); select id, y, y + 0, bin(b + 0), e, e + 0, s, s + 0 from mysql_compat_special_ignore order by id; + +-- Exercise the zero-valued ENUM error member through a multi-row ValueScan, +-- including string/numeric YEAR input, BIT truncation, and all-invalid SET. +insert ignore into mysql_compat_special_ignore values + (2, '2156', b'10000', 9, 'bad'), + (3, 2024, b'0011', 'a', 'x,z'); +select id, y + 0, bin(b + 0), e, e + 0, s, s + 0 +from mysql_compat_special_ignore order by id; + +-- IGNORE is the adjustment boundary: the equivalent strict insert still fails +-- and must not add a row. +insert into mysql_compat_special_ignore values (4, 2156, b'11111', 'bad', 'x,bad'); +select count(*) from mysql_compat_special_ignore; set session sql_mode = ''; drop table mysql_compat_special_ignore; From 3570ac38ebf44ddd5dd5c9723d645b5966635463 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Mon, 3 Aug 2026 19:06:43 +0800 Subject: [PATCH 10/22] update --- test/distributed/cases/dtype/enum.result | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/test/distributed/cases/dtype/enum.result b/test/distributed/cases/dtype/enum.result index d4647f13912ae..49070e4d5a884 100644 --- a/test/distributed/cases/dtype/enum.result +++ b/test/distributed/cases/dtype/enum.result @@ -135,12 +135,12 @@ create table enum05 (a int,b enum('4','3','2','1')); insert into enum05 values(1,1); select * from enum05; ➤ a[4,32,0] ¦ b[12,-1,0] 𝄀 -1 ¦ 1 +1 ¦ 4 insert into enum05 values(2,'1'); select * from enum05; ➤ a[4,32,0] ¦ b[12,-1,0] 𝄀 -1 ¦ 1 𝄀 -2 ¦ 4 +1 ¦ 4 𝄀 +2 ¦ 1 drop table enum05; drop table if exists pri01; create table pri01 (col1 enum('qy4iujd3wi4fu4h3f', '323242r34df432432', '32e3ewfdewrew')); @@ -394,10 +394,20 @@ s set('x', 'y', 'z') ); set session sql_mode = 'STRICT_TRANS_TABLES'; insert ignore into mysql_compat_special_ignore values (1, 2156, b'11111', 'bad', 'x,bad'); -internal error: convert to MySQL enum failed: number 0 overflow enum boundary [1, 3] select id, y, y + 0, bin(b + 0), e, e + 0, s, s + 0 from mysql_compat_special_ignore order by id; -➤ id[4,32,0] ¦ y[91,65535,0] ¦ y + 0[-5,64,0] ¦ bin(b + 0)[12,-1,0] ¦ e[12,-1,0] ¦ e + 0[-5,64,0] ¦ s[12,-1,0] ¦ s + 0[3,38,0] +internal error: parse MySQL enum failed: index 0 overflow enum boundary [1, 3] +insert ignore into mysql_compat_special_ignore values +(2, '2156', b'10000', 9, 'bad'), +(3, 2024, b'0011', 'a', 'x,z'); +select id, y + 0, bin(b + 0), e, e + 0, s, s + 0 +from mysql_compat_special_ignore order by id; +internal error: parse MySQL enum failed: index 0 overflow enum boundary [1, 3] +insert into mysql_compat_special_ignore values (4, 2156, b'11111', 'bad', 'x,bad'); +invalid input: data too long, type width = 4, val = 11111 +select count(*) from mysql_compat_special_ignore; +➤ count(*)[-5,64,0] 𝄀 +3 set session sql_mode = ''; drop table mysql_compat_special_ignore; drop table if exists default01; From 8fc454c6034f20709ec6710a217deacfe0e9446e Mon Sep 17 00:00:00 2001 From: daviszhen Date: Mon, 3 Aug 2026 19:14:29 +0800 Subject: [PATCH 11/22] update --- pkg/sql/plan/function/func_mo.go | 8 ++++++++ pkg/sql/plan/function/func_mo_test.go | 14 ++++++++++++++ test/distributed/cases/dtype/enum.sql | 10 ++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/pkg/sql/plan/function/func_mo.go b/pkg/sql/plan/function/func_mo.go index 95a16fb82cfee..d3e2794bf43eb 100644 --- a/pkg/sql/plan/function/func_mo.go +++ b/pkg/sql/plan/function/func_mo.go @@ -989,6 +989,14 @@ func CastIndexToValue(ivecs []*vector.Vector, result vector.FunctionResultWrappe return err } } else { + // MySQL stores an invalid ENUM value as index 0. It is distinct from + // NULL and displays as the empty string. + if indexVal == 0 { + if err := rs.AppendBytes([]byte{}, false); err != nil { + return err + } + continue + } typeEnumVal := functionUtil.QuickBytesToStr(typeEnum) var enumVlaue string diff --git a/pkg/sql/plan/function/func_mo_test.go b/pkg/sql/plan/function/func_mo_test.go index c6a223705a9a6..6f2eb6dfd7d7a 100644 --- a/pkg/sql/plan/function/func_mo_test.go +++ b/pkg/sql/plan/function/func_mo_test.go @@ -23,6 +23,20 @@ import ( "github.com/stretchr/testify/require" ) +func TestCastIndexToValueDisplaysEnumErrorMemberAsEmptyString(t *testing.T) { + proc := testutil.NewProcess(t) + testCase := NewFunctionTestCase(proc, + []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{"a,b,"}, nil), + NewFunctionTestInput(types.T_enum.ToType(), []types.Enum{0, 1, 3}, nil), + }, + NewFunctionTestResult(types.T_varchar.ToType(), false, []string{"", "a", ""}, nil), + CastIndexToValue, + ) + succeed, info := testCase.Run() + require.True(t, succeed, info) +} + func TestCastGeometryToSubtype(t *testing.T) { proc := testutil.NewProcess(t) diff --git a/test/distributed/cases/dtype/enum.sql b/test/distributed/cases/dtype/enum.sql index 0443bd73b30e8..5b2073d415596 100644 --- a/test/distributed/cases/dtype/enum.sql +++ b/test/distributed/cases/dtype/enum.sql @@ -243,13 +243,19 @@ from mysql_compat_special_ignore order by id; -- including string/numeric YEAR input, BIT truncation, and all-invalid SET. insert ignore into mysql_compat_special_ignore values (2, '2156', b'10000', 9, 'bad'), - (3, 2024, b'0011', 'a', 'x,z'); + (3, 2024, b'0011', 'a', 'x,z'), + (4, 2024, b'0000', '', ''); select id, y + 0, bin(b + 0), e, e + 0, s, s + 0 from mysql_compat_special_ignore order by id; +-- The ENUM error member (index 0) and an explicit empty member both display +-- as '', but retain distinct numeric values (0 and 3 respectively). +select id, e, e + 0, e = '', length(e) +from mysql_compat_special_ignore order by id; + -- IGNORE is the adjustment boundary: the equivalent strict insert still fails -- and must not add a row. -insert into mysql_compat_special_ignore values (4, 2156, b'11111', 'bad', 'x,bad'); +insert into mysql_compat_special_ignore values (5, 2156, b'11111', 'bad', 'x,bad'); select count(*) from mysql_compat_special_ignore; set session sql_mode = ''; drop table mysql_compat_special_ignore; From b23467f47637ac374b6aa4822490868fd0569e3a Mon Sep 17 00:00:00 2001 From: daviszhen Date: Mon, 3 Aug 2026 19:23:45 +0800 Subject: [PATCH 12/22] update --- pkg/sql/plan/rule/constant_fold.go | 2 +- pkg/sql/plan/rule/constant_fold_test.go | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/pkg/sql/plan/rule/constant_fold.go b/pkg/sql/plan/rule/constant_fold.go index 4ddb5dcbba233..560e55a6f0937 100644 --- a/pkg/sql/plan/rule/constant_fold.go +++ b/pkg/sql/plan/rule/constant_fold.go @@ -629,7 +629,7 @@ func GetConstantValue2(proc *process.Process, expr *plan.Expr, vec *vector.Vecto } case types.T_enum: if val, ok := cExpr.Lit.Value.(*plan.Literal_EnumVal); ok { - val := val.EnumVal + val := types.Enum(val.EnumVal) err = vector.AppendFixed(vec, val, false, proc.GetMPool()) return true, err } else { diff --git a/pkg/sql/plan/rule/constant_fold_test.go b/pkg/sql/plan/rule/constant_fold_test.go index 9a031e9474c8b..a0d40d9798f96 100644 --- a/pkg/sql/plan/rule/constant_fold_test.go +++ b/pkg/sql/plan/rule/constant_fold_test.go @@ -21,11 +21,31 @@ import ( "github.com/stretchr/testify/require" "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/sql/plan/function" "github.com/matrixorigin/matrixone/pkg/testutil" ) +func TestGetConstantValue2AppendsEnumLiteralWithEnumWidth(t *testing.T) { + proc := testutil.NewProcess(t) + vec := vector.NewVec(types.T_enum.ToType()) + defer vec.Free(proc.Mp()) + + for _, value := range []uint32{0, 1, 3} { + expr := &plan.Expr{ + Typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + Expr: &plan.Expr_Lit{Lit: &plan.Literal{ + Value: &plan.Literal_EnumVal{EnumVal: value}, + }}, + } + constant, err := GetConstantValue2(proc, expr, vec) + require.NoError(t, err) + require.True(t, constant) + } + require.Equal(t, []types.Enum{0, 1, 3}, vector.MustFixedColNoTypeCheck[types.Enum](vec)) +} + func makeConstantCastExpr(t *testing.T, name string, sourceType, targetType types.Type, value string) *plan.Expr { t.Helper() f, err := function.GetFunctionByName(context.Background(), name, []types.Type{sourceType, targetType}) From cc8259ce20ebb4195c6272e5d01ae49b7932964b Mon Sep 17 00:00:00 2001 From: daviszhen Date: Mon, 3 Aug 2026 20:07:09 +0800 Subject: [PATCH 13/22] update --- pkg/sql/plan/base_binder.go | 98 +++++++++++++++++++ pkg/sql/plan/build_constraint_util.go | 2 +- pkg/sql/plan/build_expr_test.go | 74 ++++++++++++++ pkg/sql/plan/function/func_cast.go | 70 +++++++------ pkg/sql/plan/function/func_mo.go | 58 ++++++++++- pkg/sql/util/eval_expr_util.go | 53 +++++++--- .../cases/dml/insert/insert_ignore.result | 20 ++++ .../cases/dml/insert/insert_ignore.sql | 20 +++- .../mysql_compat_enum_set_numeric.result | 20 ++++ .../dtype/mysql_compat_enum_set_numeric.sql | 19 ++++ 10 files changed, 382 insertions(+), 52 deletions(-) create mode 100644 test/distributed/cases/dtype/mysql_compat_enum_set_numeric.result create mode 100644 test/distributed/cases/dtype/mysql_compat_enum_set_numeric.sql diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go index 12c25e7f30a06..75162b10db4c8 100644 --- a/pkg/sql/plan/base_binder.go +++ b/pkg/sql/plan/base_binder.go @@ -162,6 +162,12 @@ func (b *baseBinder) baseBindExpr(astExpr tree.Expr, depth int32, isRoot bool) ( if err != nil { return } + // ENUM and SET normally bind as their display strings. An explicit + // numeric cast is, however, a numeric operand contract in MySQL and + // must start from the stored ordinal/bitmap instead of that string. + if makeTypeByPlan2Type(typ).IsNumeric() { + expr, _ = storedMySQLSpecialTypeExpr(expr) + } if b.builder != nil { var rewritten bool expr, rewritten, err = b.builder.rewriteProjectedMySQLSpecialTypeDisplayCast(expr, expr, typ) @@ -2626,6 +2632,7 @@ func (b *baseBinder) bindFuncExprImplByAstExpr(name string, astArgs []tree.Expr, return nil, err } } + args = useStoredMySQLSpecialTypesForNumericContract(b.GetContext(), name, args) //promote interval expr rewrite here if name == "interval" { if len(astArgs) == 2 { @@ -4638,6 +4645,97 @@ func storedSetBitmapExpr(expr *Expr) (*Expr, bool) { return bitmap, true } +// storedMySQLSpecialTypeExpr removes the presentation wrapper that column +// binding adds for ENUM and SET. The wrapper is appropriate for ordinary +// string contexts, but numeric contracts must consume the stored ENUM ordinal +// or SET bitmap. Keep this narrowly structural: only the wrappers made by +// makeEnumOrSetDisplayValue are unwrapped. +func storedMySQLSpecialTypeExpr(expr *Expr) (*Expr, bool) { + if isSetDisplayValueExpr(expr) { + return storedSetBitmapExpr(expr) + } + if expr == nil { + return expr, false + } + fn := expr.GetF() + if fn == nil || fn.Func == nil || fn.Func.ObjName != moEnumCastIndexToValueFun || len(fn.Args) != 2 || fn.Args[1] == nil { + return expr, false + } + return DeepCopyExpr(fn.Args[1]), true +} + +// useStoredMySQLSpecialTypesForNumericContract chooses ENUM/SET storage from +// the function overload's bound operand contract, rather than from a small +// collection of AST shapes. This preserves display labels for string +// functions such as LENGTH while allowing numeric consumers such as ABS, +// comparisons against numeric columns, and IN lists to use MySQL ordinals. +func useStoredMySQLSpecialTypesForNumericContract(ctx context.Context, name string, args []*Expr) []*Expr { + rawArgs := make([]*Expr, len(args)) + hasSpecialArg := false + for i, arg := range args { + raw, unwrapped := storedMySQLSpecialTypeExpr(arg) + rawArgs[i] = raw + if !unwrapped { + continue + } + hasSpecialArg = true + } + if !hasSpecialArg { + return args + } + + // The display-bound operands describe the contract selected for this SQL + // expression. In particular, resolving a raw ENUM against a string can + // itself select a numeric comparison rule, so do not use the raw overload + // to decide whether the caller asked for numeric semantics. + displayTypes := make([]types.Type, len(args)) + for i, arg := range args { + displayTypes[i] = makeTypeByPlan2Expr(arg) + } + resolved, err := function.GetFunctionByName(ctx, name, displayTypes) + if err != nil { + return useStoredMySQLSpecialTypesForNumericInList(name, args, rawArgs) + } + targets, shouldCast := resolved.ShouldDoImplicitTypeCast() + if !shouldCast || len(targets) != len(rawArgs) { + return useStoredMySQLSpecialTypesForNumericInList(name, args, rawArgs) + } + result := args + changed := false + for i, arg := range args { + if _, unwrapped := storedMySQLSpecialTypeExpr(arg); unwrapped && targets[i].IsNumeric() { + if !changed { + result = append([]*Expr(nil), args...) + changed = true + } + result[i] = rawArgs[i] + } + } + return result +} + +// An IN list is represented as a plan.ExprList and is not assigned one scalar +// cast target by the function registry. Its already-bound member types are +// therefore the operand contract: use the stored value only when every member +// is numeric. Mixed lists retain normal string semantics. +func useStoredMySQLSpecialTypesForNumericInList(name string, args, rawArgs []*Expr) []*Expr { + if name != "in" || len(args) != 2 || args[1].GetList() == nil || len(args[1].GetList().List) == 0 { + return args + } + for _, member := range args[1].GetList().List { + if !makeTypeByPlan2Expr(member).IsNumeric() { + return args + } + } + result := append([]*Expr(nil), args...) + for i, arg := range args { + if _, unwrapped := storedMySQLSpecialTypeExpr(arg); unwrapped { + result[i] = rawArgs[i] + } + } + return result +} + func isSetDisplayValueExpr(expr *Expr) bool { if expr == nil { return false diff --git a/pkg/sql/plan/build_constraint_util.go b/pkg/sql/plan/build_constraint_util.go index 24508bd67c4e5..4d78f7115ca19 100644 --- a/pkg/sql/plan/build_constraint_util.go +++ b/pkg/sql/plan/build_constraint_util.go @@ -1519,7 +1519,7 @@ func MakeInsertValueConstExpr(proc *process.Process, numVal *tree.NumVal, colTyp return MakePlan2BoolConstExprWithType(num), err case types.T_bit: - canInsert, num, err := util.SetInsertValueBit(proc, numVal, colType) + canInsert, num, err := util.SetInsertValueBit(proc, numVal, colType, isIgnore) if err != nil || !canInsert { return nil, err } diff --git a/pkg/sql/plan/build_expr_test.go b/pkg/sql/plan/build_expr_test.go index cb28729440813..9d5e7be94185e 100644 --- a/pkg/sql/plan/build_expr_test.go +++ b/pkg/sql/plan/build_expr_test.go @@ -605,6 +605,80 @@ func TestEnumAndSetKeepStoredValuesInExpressionContexts(t *testing.T) { } } +func TestEnumAndSetNumericContractsUseStoredValues(t *testing.T) { + tests := []struct { + name string + typ plan.Type + sql string + wantDisplay bool + }{ + { + name: "enum explicit numeric cast", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select cast(n_name as signed) from nation", + }, + { + name: "enum numeric function", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select abs(n_name) from nation", + }, + { + name: "enum numeric column comparison", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name = n_nationkey from nation", + }, + { + name: "enum between numeric bounds", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name between 1 and 2 from nation", + }, + { + name: "enum in numeric column list", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name in (n_nationkey) from nation", + }, + { + name: "enum comparison unary numeric literal", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name = +1 from nation", + }, + { + name: "enum explicit string cast control", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select cast(n_name as char) from nation", + wantDisplay: true, + }, + { + name: "enum string comparison control", + typ: plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"}, + sql: "select n_name = 'a' from nation", + wantDisplay: true, + }, + { + name: "set numeric function", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select abs(n_name) from nation", + }, + { + name: "set string function control", + typ: plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"}, + sql: "select length(n_name) from nation", + wantDisplay: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + mock := NewMockOptimizer(false) + mock.ctxt.tables["nation"].Cols[1].Typ = tc.typ + + pl, err := runOneExprStmt(mock, t, tc.sql) + require.NoError(t, err) + require.Equal(t, tc.wantDisplay, containsEnumOrSetDisplayValue(pl.GetQuery().Nodes[1].ProjectList[0])) + }) + } +} + func TestIsBitwiseBinaryOp(t *testing.T) { for _, op := range []tree.BinaryOp{ tree.BIT_XOR, diff --git a/pkg/sql/plan/function/func_cast.go b/pkg/sql/plan/function/func_cast.go index 03a5824f5a93a..d799a89c3aab6 100644 --- a/pkg/sql/plan/function/func_cast.go +++ b/pkg/sql/plan/function/func_cast.go @@ -1045,28 +1045,28 @@ func newCast(parameters []*vector.Vector, result vector.FunctionResultWrapper, p err = bitToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_int8: s := vector.GenerateFunctionFixedTypeParameter[int8](from) - err = int8ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = int8ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_int16: s := vector.GenerateFunctionFixedTypeParameter[int16](from) - err = int16ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = int16ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_int32: s := vector.GenerateFunctionFixedTypeParameter[int32](from) - err = int32ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = int32ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_int64: s := vector.GenerateFunctionFixedTypeParameter[int64](from) - err = int64ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = int64ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_uint8: s := vector.GenerateFunctionFixedTypeParameter[uint8](from) - err = uint8ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = uint8ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_uint16: s := vector.GenerateFunctionFixedTypeParameter[uint16](from) - err = uint16ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = uint16ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_uint32: s := vector.GenerateFunctionFixedTypeParameter[uint32](from) - err = uint32ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = uint32ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_uint64: s := vector.GenerateFunctionFixedTypeParameter[uint64](from) - err = uint64ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = uint64ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_float32: s := vector.GenerateFunctionFixedTypeParameter[float32](from) err = float32ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) @@ -1362,9 +1362,10 @@ func bitToOthers(ctx context.Context, // although we can merge the int8ToOthers / int16ToOthers ... into intToOthers (use the generic). // but for extensibility, we didn't do that. // uint and float are the same. -func int8ToOthers(ctx context.Context, +func int8ToOthers(proc *process.Process, source vector.FunctionParameterWrapper[int8], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + ctx := proc.Ctx switch toType.Oid { case types.T_bool: rs := vector.MustFunctionResult[bool](result) @@ -1424,14 +1425,15 @@ func int8ToOthers(ctx context.Context, return integerToTimestamp(source, rs, length, selectList) case types.T_year: rs := vector.MustFunctionResult[types.MoYear](result) - return integerToYear(ctx, source, rs, length, selectList) + return integerToYear(ctx, proc, source, rs, length, selectList) } return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from int8 to %s", toType)) } -func int16ToOthers(ctx context.Context, +func int16ToOthers(proc *process.Process, source vector.FunctionParameterWrapper[int16], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + ctx := proc.Ctx switch toType.Oid { case types.T_bool: rs := vector.MustFunctionResult[bool](result) @@ -1491,14 +1493,15 @@ func int16ToOthers(ctx context.Context, return integerToTimestamp(source, rs, length, selectList) case types.T_year: rs := vector.MustFunctionResult[types.MoYear](result) - return integerToYear(ctx, source, rs, length, selectList) + return integerToYear(ctx, proc, source, rs, length, selectList) } return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from int16 to %s", toType)) } -func int32ToOthers(ctx context.Context, +func int32ToOthers(proc *process.Process, source vector.FunctionParameterWrapper[int32], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + ctx := proc.Ctx switch toType.Oid { case types.T_bool: rs := vector.MustFunctionResult[bool](result) @@ -1558,14 +1561,15 @@ func int32ToOthers(ctx context.Context, return integerToTimestamp(source, rs, length, selectList) case types.T_year: rs := vector.MustFunctionResult[types.MoYear](result) - return integerToYear(ctx, source, rs, length, selectList) + return integerToYear(ctx, proc, source, rs, length, selectList) } return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from int32 to %s", toType)) } -func int64ToOthers(ctx context.Context, +func int64ToOthers(proc *process.Process, source vector.FunctionParameterWrapper[int64], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + ctx := proc.Ctx switch toType.Oid { case types.T_bool: rs := vector.MustFunctionResult[bool](result) @@ -1628,14 +1632,15 @@ func int64ToOthers(ctx context.Context, return integerToEnum(ctx, source, rs, length, selectList) case types.T_year: rs := vector.MustFunctionResult[types.MoYear](result) - return integerToYear(ctx, source, rs, length, selectList) + return integerToYear(ctx, proc, source, rs, length, selectList) } return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from int64 to %s", toType)) } -func uint8ToOthers(ctx context.Context, +func uint8ToOthers(proc *process.Process, source vector.FunctionParameterWrapper[uint8], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + ctx := proc.Ctx switch toType.Oid { case types.T_bool: rs := vector.MustFunctionResult[bool](result) @@ -1697,14 +1702,15 @@ func uint8ToOthers(ctx context.Context, return integerToEnum(ctx, source, rs, length, selectList) case types.T_year: rs := vector.MustFunctionResult[types.MoYear](result) - return integerToYear(ctx, source, rs, length, selectList) + return integerToYear(ctx, proc, source, rs, length, selectList) } return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from uint8 to %s", toType)) } -func uint16ToOthers(ctx context.Context, +func uint16ToOthers(proc *process.Process, source vector.FunctionParameterWrapper[uint16], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + ctx := proc.Ctx switch toType.Oid { case types.T_bool: rs := vector.MustFunctionResult[bool](result) @@ -1766,14 +1772,15 @@ func uint16ToOthers(ctx context.Context, return integerToEnum(ctx, source, rs, length, selectList) case types.T_year: rs := vector.MustFunctionResult[types.MoYear](result) - return integerToYear(ctx, source, rs, length, selectList) + return integerToYear(ctx, proc, source, rs, length, selectList) } return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from uint16 to %s", toType)) } -func uint32ToOthers(ctx context.Context, +func uint32ToOthers(proc *process.Process, source vector.FunctionParameterWrapper[uint32], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + ctx := proc.Ctx switch toType.Oid { case types.T_bool: rs := vector.MustFunctionResult[bool](result) @@ -1835,14 +1842,15 @@ func uint32ToOthers(ctx context.Context, return integerToEnum(ctx, source, rs, length, selectList) case types.T_year: rs := vector.MustFunctionResult[types.MoYear](result) - return integerToYear(ctx, source, rs, length, selectList) + return integerToYear(ctx, proc, source, rs, length, selectList) } return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from uint32 to %s", toType)) } -func uint64ToOthers(ctx context.Context, +func uint64ToOthers(proc *process.Process, source vector.FunctionParameterWrapper[uint64], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + ctx := proc.Ctx switch toType.Oid { case types.T_bool: rs := vector.MustFunctionResult[bool](result) @@ -2650,7 +2658,7 @@ func strTypeToOthers(proc *process.Process, return strToArray[uint8](ctx, source, rs, length, toType) case types.T_year: rs := vector.MustFunctionResult[types.MoYear](result) - return strToYear(ctx, source, rs, length, selectList) + return strToYear(ctx, proc, source, rs, length, selectList) } return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from %s to %s", source.GetType(), toType)) } @@ -8542,7 +8550,7 @@ func yearToNull[T types.FixedSizeT]( } // integerToYear converts integer types to YEAR -func integerToYear[T constraints.Integer](ctx context.Context, +func integerToYear[T constraints.Integer](ctx context.Context, proc *process.Process, source vector.FunctionParameterWrapper[T], rs *vector.FunctionResult[types.MoYear], length int, selectList *FunctionSelectList) error { for i := 0; i < length; i++ { @@ -8554,8 +8562,9 @@ func integerToYear[T constraints.Integer](ctx context.Context, } else { year, err := types.ParseMoYearFromInt(int64(v)) if err != nil { - // MySQL returns NULL for invalid year values - if err := rs.Append(0, true); err != nil { + // INSERT IGNORE adjusts an invalid YEAR to 0000. Ordinary casts + // retain their established NULL-on-invalid behavior. + if err := rs.Append(0, !statementIgnore(proc)); err != nil { return err } } else { @@ -8569,7 +8578,7 @@ func integerToYear[T constraints.Integer](ctx context.Context, } // strToYear converts string to YEAR type -func strToYear(ctx context.Context, +func strToYear(ctx context.Context, proc *process.Process, source vector.FunctionParameterWrapper[types.Varlena], rs *vector.FunctionResult[types.MoYear], length int, selectList *FunctionSelectList) error { for i := 0; i < length; i++ { @@ -8581,8 +8590,9 @@ func strToYear(ctx context.Context, } else { year, err := types.ParseMoYear(string(v)) if err != nil { - // MySQL returns NULL for invalid year values - if err := rs.Append(0, true); err != nil { + // INSERT IGNORE adjusts an invalid YEAR to 0000. Ordinary casts + // retain their established NULL-on-invalid behavior. + if err := rs.Append(0, !statementIgnore(proc)); err != nil { return err } } else { diff --git a/pkg/sql/plan/function/func_mo.go b/pkg/sql/plan/function/func_mo.go index 95a16fb82cfee..89532b9e850a8 100644 --- a/pkg/sql/plan/function/func_mo.go +++ b/pkg/sql/plan/function/func_mo.go @@ -994,6 +994,16 @@ func CastIndexToValue(ivecs []*vector.Vector, result vector.FunctionResultWrappe enumVlaue, err := types.ParseEnumIndex(typeEnumVal, indexVal) if err != nil { + // Ordinal zero is MySQL's ENUM error member. INSERT IGNORE can + // store it for an invalid label and it is displayed as the empty + // string, regardless of whether the declaration also has an empty + // member at a non-zero ordinal. + if indexVal == 0 { + if err = rs.AppendBytes([]byte{}, false); err != nil { + return err + } + continue + } return err } @@ -1026,7 +1036,12 @@ func CastValueToIndex(ivecs []*vector.Vector, result vector.FunctionResultWrappe var index types.Enum index, err := types.ParseEnum(typeEnumVal, enumStr) if err != nil { - return err + if !statementIgnore(proc) { + return err + } + // MySQL INSERT IGNORE stores the ENUM error member (ordinal 0) + // for an unrecognized label instead of rejecting the row. + index = 0 } if err = rs.Append(index, false); err != nil { @@ -1057,7 +1072,11 @@ func CastIndexValueToIndex(ivecs []*vector.Vector, result vector.FunctionResultW index, err := types.ParseEnumValue(typeEnumVal, enumValueIndex) if err != nil { - return err + if !statementIgnore(proc) { + return err + } + // Invalid numeric ENUM input is adjusted to the error member. + index = 0 } if err = rs.Append(index, false); err != nil { @@ -1113,7 +1132,19 @@ func CastSetValueToIndex(ivecs []*vector.Vector, result vector.FunctionResultWra index, err := types.ParseSet(functionUtil.QuickBytesToStr(typeSet), functionUtil.QuickBytesToStr(setValue)) if err != nil { - return err + if !statementIgnore(proc) { + return err + } + // INSERT IGNORE retains the valid SET members and drops invalid + // members, matching MySQL's partial-value adjustment. + index = 0 + setDef := functionUtil.QuickBytesToStr(typeSet) + for _, member := range strings.Split(functionUtil.QuickBytesToStr(setValue), ",") { + memberBits, memberErr := types.ParseSet(setDef, member) + if memberErr == nil { + index |= memberBits + } + } } if err = rs.Append(index, false); err != nil { return err @@ -1122,6 +1153,21 @@ func CastSetValueToIndex(ivecs []*vector.Vector, result vector.FunctionResultWra return nil } +func statementIgnore(proc *process.Process) bool { + return proc != nil && proc.GetStmtProfile() != nil && proc.GetStmtProfile().GetStatementIgnore() +} + +func setMemberBitmap(definition string) uint64 { + var bitmap uint64 + for bit := uint(0); bit < 64; bit++ { + member := uint64(1) << bit + if _, err := types.ParseSetValue(definition, member); err == nil { + bitmap |= member + } + } + return bitmap +} + // set("a","b","c") -> CastSetIndexValueToIndex(3) -> 3 func CastSetIndexValueToIndex(ivecs []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int, selectList *FunctionSelectList) error { rs := vector.MustFunctionResult[uint64](result) @@ -1140,7 +1186,11 @@ func CastSetIndexValueToIndex(ivecs []*vector.Vector, result vector.FunctionResu index, err := types.ParseSetValue(functionUtil.QuickBytesToStr(typeSet), setIndexValue) if err != nil { - return err + if !statementIgnore(proc) { + return err + } + // Numeric SET input keeps only bits represented by declared members. + index = setIndexValue & setMemberBitmap(functionUtil.QuickBytesToStr(typeSet)) } if err = rs.Append(index, false); err != nil { return err diff --git a/pkg/sql/util/eval_expr_util.go b/pkg/sql/util/eval_expr_util.go index da58ac7b71d38..d6bc08a173ec1 100644 --- a/pkg/sql/util/eval_expr_util.go +++ b/pkg/sql/util/eval_expr_util.go @@ -993,10 +993,22 @@ func floatNumToFixFloat[T constraints.Float | constraints.Integer]( return T(v), nil } -func SetInsertValueBit(proc *process.Process, numVal *tree.NumVal, colType *types.Type) (canInsert bool, val uint64, err error) { +func SetInsertValueBit(proc *process.Process, numVal *tree.NumVal, colType *types.Type, isIgnore bool) (canInsert bool, val uint64, err error) { var ok bool canInsert = true width := colType.Width + max := bitMaxValue(width) + adjustOverflow := func(value uint64) bool { + if value <= max { + return false + } + if isIgnore { + val = max + return true + } + err = moerr.NewInvalidInputf(proc.Ctx, "data too long, type width = %d, val = %b", width, value) + return true + } switch numVal.ValType { case tree.P_bool: @@ -1014,8 +1026,7 @@ func SetInsertValueBit(proc *process.Process, numVal *tree.NumVal, colType *type for i := 0; i < len(s); i++ { val = (val << 8) | uint64(s[i]) } - if val > uint64(1< uint64(1< uint64(1< uint64(1< uint64(1< uint64(1< uint64(1<= 64 { + return math.MaxUint64 + } + if width <= 0 { + return 0 + } + return uint64(1)< Date: Mon, 3 Aug 2026 21:46:40 +0800 Subject: [PATCH 14/22] update --- test/distributed/cases/dtype/enum.result | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/test/distributed/cases/dtype/enum.result b/test/distributed/cases/dtype/enum.result index 49070e4d5a884..79c654b517990 100644 --- a/test/distributed/cases/dtype/enum.result +++ b/test/distributed/cases/dtype/enum.result @@ -396,18 +396,31 @@ set session sql_mode = 'STRICT_TRANS_TABLES'; insert ignore into mysql_compat_special_ignore values (1, 2156, b'11111', 'bad', 'x,bad'); select id, y, y + 0, bin(b + 0), e, e + 0, s, s + 0 from mysql_compat_special_ignore order by id; -internal error: parse MySQL enum failed: index 0 overflow enum boundary [1, 3] +➤ id[4,32,0] ¦ y[91,65535,0] ¦ y + 0[-5,64,0] ¦ bin(b + 0)[12,-1,0] ¦ e[12,-1,0] ¦ e + 0[-5,64,0] ¦ s[12,-1,0] ¦ s + 0[3,38,0] 𝄀 +1 ¦ 2000-01-01 ¦ 0 ¦ 1111 ¦ ¦ 0 ¦ x ¦ 1 insert ignore into mysql_compat_special_ignore values (2, '2156', b'10000', 9, 'bad'), -(3, 2024, b'0011', 'a', 'x,z'); +(3, 2024, b'0011', 'a', 'x,z'), +(4, 2024, b'0000', '', ''); select id, y + 0, bin(b + 0), e, e + 0, s, s + 0 from mysql_compat_special_ignore order by id; -internal error: parse MySQL enum failed: index 0 overflow enum boundary [1, 3] -insert into mysql_compat_special_ignore values (4, 2156, b'11111', 'bad', 'x,bad'); +➤ id[4,32,0] ¦ y + 0[-5,64,0] ¦ bin(b + 0)[12,-1,0] ¦ e[12,-1,0] ¦ e + 0[-5,64,0] ¦ s[12,-1,0] ¦ s + 0[3,38,0] 𝄀 +1 ¦ 0 ¦ 1111 ¦ ¦ 0 ¦ x ¦ 1 𝄀 +2 ¦ 0 ¦ 0 ¦ ¦ 0 ¦ ¦ 0 𝄀 +3 ¦ 2024 ¦ 11 ¦ a ¦ 1 ¦ x,z ¦ 5 𝄀 +4 ¦ 2024 ¦ 0 ¦ ¦ 3 ¦ ¦ 0 +select id, e, e + 0, e = '', length(e) +from mysql_compat_special_ignore order by id; +➤ id[4,32,0] ¦ e[12,-1,0] ¦ e + 0[-5,64,0] ¦ e = [-7,1,0] ¦ length(e)[-5,64,0] 𝄀 +1 ¦ ¦ 0 ¦ 1 ¦ 0 𝄀 +2 ¦ ¦ 0 ¦ 1 ¦ 0 𝄀 +3 ¦ a ¦ 1 ¦ 0 ¦ 1 𝄀 +4 ¦ ¦ 3 ¦ 1 ¦ 0 +insert into mysql_compat_special_ignore values (5, 2156, b'11111', 'bad', 'x,bad'); invalid input: data too long, type width = 4, val = 11111 select count(*) from mysql_compat_special_ignore; ➤ count(*)[-5,64,0] 𝄀 -3 +4 set session sql_mode = ''; drop table mysql_compat_special_ignore; drop table if exists default01; From 62a91ec6fc2bacd716be04ba72d4da462981f9dd Mon Sep 17 00:00:00 2001 From: daviszhen Date: Mon, 3 Aug 2026 22:21:58 +0800 Subject: [PATCH 15/22] update --- pkg/sql/plan/base_binder.go | 15 +- pkg/sql/plan/function/func_cast.go | 147 ++++++++++++++++-- .../cases/dml/insert/insert_ignore.result | 12 ++ .../cases/dml/insert/insert_ignore.sql | 9 ++ .../mysql_compat_enum_set_numeric.result | 15 ++ .../dtype/mysql_compat_enum_set_numeric.sql | 12 ++ 6 files changed, 195 insertions(+), 15 deletions(-) diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go index 75162b10db4c8..e83c09f7ece9e 100644 --- a/pkg/sql/plan/base_binder.go +++ b/pkg/sql/plan/base_binder.go @@ -2118,6 +2118,7 @@ func (b *baseBinder) bindComparisonExpr(astExpr *tree.ComparisonExpr, depth int3 } if subquery := rightArg.GetSub(); subquery != nil { + leftArg = useStoredMySQLSpecialTypeForNumericSubquery(leftArg, rightArg) if list := leftArg.GetList(); list != nil { if len(list.List) != int(subquery.RowSize) { return nil, moerr.NewNYIf(b.GetContext(), "subquery should return %d columns", len(list.List)) @@ -2164,6 +2165,7 @@ func (b *baseBinder) bindComparisonExpr(astExpr *tree.ComparisonExpr, depth int3 } if subquery := rightArg.GetSub(); subquery != nil { + leftArg = useStoredMySQLSpecialTypeForNumericSubquery(leftArg, rightArg) if list := leftArg.GetList(); list != nil { if len(list.List) != int(subquery.RowSize) { return nil, moerr.NewInvalidInputf(b.GetContext(), "subquery should return %d columns", len(list.List)) @@ -2212,6 +2214,7 @@ func (b *baseBinder) bindComparisonExpr(astExpr *tree.ComparisonExpr, depth int3 } if subquery := expr.GetSub(); subquery != nil { + child = useStoredMySQLSpecialTypeForNumericSubquery(child, expr) if list := child.GetList(); list != nil { if len(list.List) != int(subquery.RowSize) { return nil, moerr.NewInvalidInputf(b.GetContext(), "subquery should return %d columns", len(list.List)) @@ -4719,7 +4722,7 @@ func useStoredMySQLSpecialTypesForNumericContract(ctx context.Context, name stri // therefore the operand contract: use the stored value only when every member // is numeric. Mixed lists retain normal string semantics. func useStoredMySQLSpecialTypesForNumericInList(name string, args, rawArgs []*Expr) []*Expr { - if name != "in" || len(args) != 2 || args[1].GetList() == nil || len(args[1].GetList().List) == 0 { + if (name != "in" && name != "not_in" && name != "partition_in") || len(args) != 2 || args[1].GetList() == nil || len(args[1].GetList().List) == 0 { return args } for _, member := range args[1].GetList().List { @@ -4736,6 +4739,16 @@ func useStoredMySQLSpecialTypesForNumericInList(name string, args, rawArgs []*Ex return result } +func useStoredMySQLSpecialTypeForNumericSubquery(left, subquery *Expr) *Expr { + if subquery == nil || !makeTypeByPlan2Expr(subquery).IsNumeric() { + return left + } + if raw, ok := storedMySQLSpecialTypeExpr(left); ok { + return raw + } + return left +} + func isSetDisplayValueExpr(expr *Expr) bool { if expr == nil { return false diff --git a/pkg/sql/plan/function/func_cast.go b/pkg/sql/plan/function/func_cast.go index d799a89c3aab6..42de605aeac20 100644 --- a/pkg/sql/plan/function/func_cast.go +++ b/pkg/sql/plan/function/func_cast.go @@ -655,6 +655,7 @@ var supportedTypeCast = map[types.T][]types.T{ types.T_decimal64, types.T_decimal128, types.T_decimal256, types.T_char, types.T_varchar, types.T_blob, types.T_text, types.T_binary, types.T_varbinary, + types.T_year, }, types.T_char: { @@ -1081,7 +1082,7 @@ func newCast(parameters []*vector.Vector, result vector.FunctionResultWrapper, p err = decimal128ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_decimal256: s := vector.GenerateFunctionFixedTypeParameter[types.Decimal256](from) - err = decimal256ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = decimal256ToOthersWithProc(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_date: s := vector.GenerateFunctionFixedTypeParameter[types.Date](from) err = dateToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) @@ -1372,7 +1373,7 @@ func int8ToOthers(proc *process.Process, return numericToBool(source, rs, length, selectList) case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return numericToBit(ctx, source, rs, int(toType.Width), length, selectList) + return numericToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return rs.DupFromParameter(source, length) @@ -1440,7 +1441,7 @@ func int16ToOthers(proc *process.Process, return numericToBool(source, rs, length, selectList) case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return numericToBit(ctx, source, rs, int(toType.Width), length, selectList) + return numericToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return numericToNumeric(ctx, source, rs, length, selectList) @@ -1508,7 +1509,7 @@ func int32ToOthers(proc *process.Process, return numericToBool(source, rs, length, selectList) case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return numericToBit(ctx, source, rs, int(toType.Width), length, selectList) + return numericToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return numericToNumeric(ctx, source, rs, length, selectList) @@ -1576,7 +1577,7 @@ func int64ToOthers(proc *process.Process, return numericToBool(source, rs, length, selectList) case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return numericToBit(ctx, source, rs, int(toType.Width), length, selectList) + return numericToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return numericToNumeric(ctx, source, rs, length, selectList) @@ -1647,7 +1648,7 @@ func uint8ToOthers(proc *process.Process, return numericToBool(source, rs, length, selectList) case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return numericToBit(ctx, source, rs, int(toType.Width), length, selectList) + return numericToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return numericToNumeric(ctx, source, rs, length, selectList) @@ -1717,7 +1718,7 @@ func uint16ToOthers(proc *process.Process, return numericToBool(source, rs, length, selectList) case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return numericToBit(ctx, source, rs, int(toType.Width), length, selectList) + return numericToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return numericToNumeric(ctx, source, rs, length, selectList) @@ -1787,7 +1788,7 @@ func uint32ToOthers(proc *process.Process, return numericToBool(source, rs, length, selectList) case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return numericToBit(ctx, source, rs, int(toType.Width), length, selectList) + return numericToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return numericToNumeric(ctx, source, rs, length, selectList) @@ -2299,7 +2300,7 @@ func decimal64ToOthers(proc *process.Process, return decimal64ToStr(ctx, source, rs, length, toType, strictStringWidth...) case types.T_year: rs := vector.MustFunctionResult[types.MoYear](result) - return decimal64ToYear(ctx, source, rs, length, selectList) + return decimal64ToYear(ctx, proc, source, rs, length, selectList) } return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from decimal64 to %s", toType)) } @@ -2375,12 +2376,27 @@ func decimal128ToOthers(proc *process.Process, return decimal128ToStr(ctx, source, rs, length, toType, strictStringWidth...) case types.T_year: rs := vector.MustFunctionResult[types.MoYear](result) - return decimal128ToYear(ctx, source, rs, length, selectList) + return decimal128ToYear(ctx, proc, source, rs, length, selectList) } return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from decimal128 to %s", toType)) } -func decimal256ToOthers(ctx context.Context, +func decimal256ToOthers( + ctx context.Context, + source vector.FunctionParameterWrapper[types.Decimal256], + toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + return decimal256ToOthersWithContext(ctx, nil, source, toType, result, length, selectList, strictStringWidth...) +} + +func decimal256ToOthersWithProc( + proc *process.Process, + source vector.FunctionParameterWrapper[types.Decimal256], + toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + return decimal256ToOthersWithContext(proc.Ctx, proc, source, toType, result, length, selectList, strictStringWidth...) +} + +func decimal256ToOthersWithContext( + ctx context.Context, proc *process.Process, source vector.FunctionParameterWrapper[types.Decimal256], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { switch toType.Oid { @@ -2428,6 +2444,9 @@ func decimal256ToOthers(ctx context.Context, return nil } return decimal256ToDecimal256(source, rs, length, selectList) + case types.T_year: + rs := vector.MustFunctionResult[types.MoYear](result) + return decimal256ToYear(ctx, proc, source, rs, length, selectList) case types.T_float32: rs := vector.MustFunctionResult[float32](result) return decimal256ToFloat(source, rs, length) @@ -3118,6 +3137,15 @@ func numericToBit[T constraints.Integer | constraints.Float]( from vector.FunctionParameterWrapper[T], to *vector.FunctionResult[uint64], bitSize int, length int, selectList *FunctionSelectList) error { + return numericToBitWithIgnore(ctx, nil, from, to, bitSize, length, selectList) +} + +func numericToBitWithIgnore[T constraints.Integer | constraints.Float]( + ctx context.Context, proc *process.Process, + from vector.FunctionParameterWrapper[T], + to *vector.FunctionResult[uint64], bitSize int, + length int, selectList *FunctionSelectList) error { + max := maxBitValue(bitSize) for i := 0; i < length; i++ { v, null := from.GetValue(uint64(i)) if null { @@ -3125,6 +3153,15 @@ func numericToBit[T constraints.Integer | constraints.Float]( return err } } else { + if float64(v) < 0 { + if !statementIgnore(proc) { + return moerr.NewOutOfRangef(ctx, fmt.Sprintf("int%d", bitSize), "value %v", v) + } + if err := to.Append(0, false); err != nil { + return err + } + continue + } var val uint64 switch any(v).(type) { case float32, float64: @@ -3133,7 +3170,13 @@ func numericToBit[T constraints.Integer | constraints.Float]( val = uint64(v) } - if val > uint64(1< max { + if statementIgnore(proc) { + if err := to.Append(max, false); err != nil { + return err + } + continue + } return moerr.NewOutOfRangef(ctx, fmt.Sprintf("int%d", bitSize), "value %d", val) } if err := to.Append(val, false); err != nil { @@ -3144,6 +3187,16 @@ func numericToBit[T constraints.Integer | constraints.Float]( return nil } +func maxBitValue(bitSize int) uint64 { + if bitSize >= 64 { + return math.MaxUint64 + } + if bitSize <= 0 { + return 0 + } + return uint64(1)< Date: Mon, 3 Aug 2026 22:47:35 +0800 Subject: [PATCH 16/22] update --- pkg/sql/plan/base_binder.go | 82 +++++++++++-- pkg/sql/plan/function/func_cast.go | 109 ++++++++++++++---- .../cases/dml/insert/insert_ignore.result | 32 ++++- .../cases/dml/insert/insert_ignore.sql | 26 ++++- .../mysql_compat_enum_set_numeric.result | 10 ++ .../dtype/mysql_compat_enum_set_numeric.sql | 9 ++ 6 files changed, 232 insertions(+), 36 deletions(-) diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go index e83c09f7ece9e..044b03ef84322 100644 --- a/pkg/sql/plan/base_binder.go +++ b/pkg/sql/plan/base_binder.go @@ -2118,7 +2118,7 @@ func (b *baseBinder) bindComparisonExpr(astExpr *tree.ComparisonExpr, depth int3 } if subquery := rightArg.GetSub(); subquery != nil { - leftArg = useStoredMySQLSpecialTypeForNumericSubquery(leftArg, rightArg) + leftArg = b.useStoredMySQLSpecialTypesForNumericSubquery(leftArg, rightArg) if list := leftArg.GetList(); list != nil { if len(list.List) != int(subquery.RowSize) { return nil, moerr.NewNYIf(b.GetContext(), "subquery should return %d columns", len(list.List)) @@ -2165,7 +2165,7 @@ func (b *baseBinder) bindComparisonExpr(astExpr *tree.ComparisonExpr, depth int3 } if subquery := rightArg.GetSub(); subquery != nil { - leftArg = useStoredMySQLSpecialTypeForNumericSubquery(leftArg, rightArg) + leftArg = b.useStoredMySQLSpecialTypesForNumericSubquery(leftArg, rightArg) if list := leftArg.GetList(); list != nil { if len(list.List) != int(subquery.RowSize) { return nil, moerr.NewInvalidInputf(b.GetContext(), "subquery should return %d columns", len(list.List)) @@ -2214,7 +2214,7 @@ func (b *baseBinder) bindComparisonExpr(astExpr *tree.ComparisonExpr, depth int3 } if subquery := expr.GetSub(); subquery != nil { - child = useStoredMySQLSpecialTypeForNumericSubquery(child, expr) + child = b.useStoredMySQLSpecialTypesForNumericSubquery(child, expr) if list := child.GetList(); list != nil { if len(list.List) != int(subquery.RowSize) { return nil, moerr.NewInvalidInputf(b.GetContext(), "subquery should return %d columns", len(list.List)) @@ -4739,16 +4739,84 @@ func useStoredMySQLSpecialTypesForNumericInList(name string, args, rawArgs []*Ex return result } -func useStoredMySQLSpecialTypeForNumericSubquery(left, subquery *Expr) *Expr { - if subquery == nil || !makeTypeByPlan2Expr(subquery).IsNumeric() { +// useStoredMySQLSpecialTypesForNumericSubquery applies the numeric operand +// contract in both directions. Subquery references expose only one scalar +// type for single-column results, so tuple comparisons must inspect the +// subquery projection position-by-position rather than the tuple type itself. +func (b *baseBinder) useStoredMySQLSpecialTypesForNumericSubquery(left, subqueryExpr *Expr) *Expr { + projectList := b.subqueryProjectList(subqueryExpr) + if len(projectList) == 0 { return left } - if raw, ok := storedMySQLSpecialTypeExpr(left); ok { - return raw + + left = useStoredMySQLSpecialTypeForNumericProjection(left, projectList) + for i, project := range projectList { + if !numericSubqueryOperandAt(left, i) { + continue + } + if raw, ok := storedMySQLSpecialTypeExpr(project); ok { + projectList[i] = raw + } + } + return left +} + +func (b *baseBinder) subqueryProjectList(expr *Expr) []*Expr { + if b.builder == nil || expr == nil || expr.GetSub() == nil { + return nil + } + nodeID := expr.GetSub().NodeId + if nodeID < 0 || int(nodeID) >= len(b.builder.qry.Nodes) { + return nil + } + return b.builder.qry.Nodes[nodeID].ProjectList +} + +func useStoredMySQLSpecialTypeForNumericProjection(left *Expr, projects []*Expr) *Expr { + if left == nil || len(projects) == 0 { + return left + } + if list := left.GetList(); list != nil { + if len(list.List) != len(projects) { + return left + } + var result []*Expr + for i, item := range list.List { + if !makeTypeByPlan2Expr(projects[i]).IsNumeric() { + continue + } + raw, ok := storedMySQLSpecialTypeExpr(item) + if !ok { + continue + } + if result == nil { + result = append([]*Expr(nil), list.List...) + } + result[i] = raw + } + if result == nil { + return left + } + return &Expr{Typ: left.Typ, Expr: &plan.Expr_List{List: &plan.ExprList{List: result}}} + } + if len(projects) == 1 && makeTypeByPlan2Expr(projects[0]).IsNumeric() { + if raw, ok := storedMySQLSpecialTypeExpr(left); ok { + return raw + } } return left } +func numericSubqueryOperandAt(left *Expr, index int) bool { + if left == nil { + return false + } + if list := left.GetList(); list != nil { + return index < len(list.List) && makeTypeByPlan2Expr(list.List[index]).IsNumeric() + } + return index == 0 && makeTypeByPlan2Expr(left).IsNumeric() +} + func isSetDisplayValueExpr(expr *Expr) bool { if expr == nil { return false diff --git a/pkg/sql/plan/function/func_cast.go b/pkg/sql/plan/function/func_cast.go index 42de605aeac20..20a4d94addef0 100644 --- a/pkg/sql/plan/function/func_cast.go +++ b/pkg/sql/plan/function/func_cast.go @@ -1043,7 +1043,7 @@ func newCast(parameters []*vector.Vector, result vector.FunctionResultWrapper, p err = boolToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_bit: s := vector.GenerateFunctionFixedTypeParameter[uint64](from) - err = bitToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = bitToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_int8: s := vector.GenerateFunctionFixedTypeParameter[int8](from) err = int8ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) @@ -1070,10 +1070,10 @@ func newCast(parameters []*vector.Vector, result vector.FunctionResultWrapper, p err = uint64ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_float32: s := vector.GenerateFunctionFixedTypeParameter[float32](from) - err = float32ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = float32ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_float64: s := vector.GenerateFunctionFixedTypeParameter[float64](from) - err = float64ToOthers(execProc.Ctx, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) + err = float64ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) case types.T_decimal64: s := vector.GenerateFunctionFixedTypeParameter[types.Decimal64](from) err = decimal64ToOthers(execProc, s, *toType, result, length, selectList, strictStringWidth, reportDataTooLong) @@ -1294,16 +1294,17 @@ func boolToOthers(ctx context.Context, return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from bool to %s", toType)) } -func bitToOthers(ctx context.Context, +func bitToOthers(proc *process.Process, source vector.FunctionParameterWrapper[uint64], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + ctx := proc.Ctx switch toType.Oid { case types.T_bool: rs := vector.MustFunctionResult[bool](result) return numericToBool(source, rs, length, selectList) case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return numericToBit(ctx, source, rs, int(toType.Width), length, selectList) + return numericToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return numericToNumeric(ctx, source, rs, length, selectList) @@ -1858,7 +1859,7 @@ func uint64ToOthers(proc *process.Process, return numericToBool(source, rs, length, selectList) case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return numericToBit(ctx, source, rs, int(toType.Width), length, selectList) + return numericToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return numericToNumeric(ctx, source, rs, length, selectList) @@ -1915,16 +1916,17 @@ func uint64ToOthers(proc *process.Process, return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from uint64 to %s", toType)) } -func float32ToOthers(ctx context.Context, +func float32ToOthers(proc *process.Process, source vector.FunctionParameterWrapper[float32], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + ctx := proc.Ctx switch toType.Oid { case types.T_bool: rs := vector.MustFunctionResult[bool](result) return numericToBool(source, rs, length, selectList) case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return numericToBit(ctx, source, rs, int(toType.Width), length, selectList) + return numericToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return floatToInteger(ctx, source, rs, length, selectList) @@ -1985,16 +1987,17 @@ func float32ToOthers(ctx context.Context, return moerr.NewInternalError(ctx, fmt.Sprintf("unsupported cast from float32 to %s", toType)) } -func float64ToOthers(ctx context.Context, +func float64ToOthers(proc *process.Process, source vector.FunctionParameterWrapper[float64], toType types.Type, result vector.FunctionResultWrapper, length int, selectList *FunctionSelectList, strictStringWidth ...bool) error { + ctx := proc.Ctx switch toType.Oid { case types.T_bool: rs := vector.MustFunctionResult[bool](result) return numericToBool(source, rs, length, selectList) case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return numericToBit(ctx, source, rs, int(toType.Width), length, selectList) + return numericToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return floatToInteger(ctx, source, rs, length, selectList) @@ -2233,7 +2236,7 @@ func decimal64ToOthers(proc *process.Process, switch toType.Oid { case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return decimal64ToBit(ctx, source, rs, int(toType.Width), length, selectList) + return decimal64ToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_float32: rs := vector.MustFunctionResult[float32](result) return decimal64ToFloat(ctx, source, rs, length, 32) @@ -2312,7 +2315,7 @@ func decimal128ToOthers(proc *process.Process, switch toType.Oid { case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return decimal128ToBit(ctx, source, rs, int(toType.Width), length, selectList) + return decimal128ToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return decimal128ToSigned(ctx, source, rs, 8, length, selectList) @@ -2402,7 +2405,7 @@ func decimal256ToOthersWithContext( switch toType.Oid { case types.T_bit: rs := vector.MustFunctionResult[uint64](result) - return decimal256ToBit(ctx, source, rs, int(toType.Width), length, selectList) + return decimal256ToBitWithIgnore(ctx, proc, source, rs, int(toType.Width), length, selectList) case types.T_int8: rs := vector.MustFunctionResult[int8](result) return decimal256ToSigned(ctx, source, rs, 8, length, selectList) @@ -3153,7 +3156,8 @@ func numericToBitWithIgnore[T constraints.Integer | constraints.Float]( return err } } else { - if float64(v) < 0 { + floatValue := float64(v) + if floatValue < 0 { if !statementIgnore(proc) { return moerr.NewOutOfRangef(ctx, fmt.Sprintf("int%d", bitSize), "value %v", v) } @@ -3165,7 +3169,17 @@ func numericToBitWithIgnore[T constraints.Integer | constraints.Float]( var val uint64 switch any(v).(type) { case float32, float64: - val = uint64(math.Round(float64(v))) + rounded := math.Round(floatValue) + if math.IsNaN(rounded) || floatExceedsBitRange(rounded, bitSize) { + if statementIgnore(proc) { + if err := to.Append(max, false); err != nil { + return err + } + continue + } + return moerr.NewOutOfRangef(ctx, fmt.Sprintf("int%d", bitSize), "value %v", v) + } + val = uint64(rounded) default: val = uint64(v) } @@ -3197,6 +3211,18 @@ func maxBitValue(bitSize int) uint64 { return uint64(1)<= 64 { + // math.MaxUint64 rounds to 2^64 as float64, so use the exclusive + // upper bound rather than comparing with float64(maxBitValue(64)). + return value >= math.Exp2(64) + } + return value > float64(maxBitValue(bitSize)) +} + // XXX do not use it to cast float to integer, please use floatToInteger func floatToInteger[T1 constraints.Float, T2 constraints.Integer]( ctx context.Context, @@ -5982,6 +6008,13 @@ func decimal64ToBit( ctx context.Context, from vector.FunctionParameterWrapper[types.Decimal64], to *vector.FunctionResult[uint64], bitSize int, length int, selectList *FunctionSelectList) error { + return decimal64ToBitWithIgnore(ctx, nil, from, to, bitSize, length, selectList) +} + +func decimal64ToBitWithIgnore( + ctx context.Context, proc *process.Process, + from vector.FunctionParameterWrapper[types.Decimal64], + to *vector.FunctionResult[uint64], bitSize int, length int, selectList *FunctionSelectList) error { for i := 0; i < length; i++ { v, null := from.GetValue(uint64(i)) if null { @@ -5989,12 +6022,11 @@ func decimal64ToBit( return err } } else { - var result uint64 - var err error xStr := v.Format(from.GetType().Scale) xStr = strings.Split(xStr, ".")[0] - if result, err = strconv.ParseUint(xStr, 10, bitSize); err != nil { - return moerr.NewOutOfRangef(ctx, fmt.Sprintf("bit(%d)", bitSize), "value '%v'", xStr) + result, err := decimalStringToBit(ctx, proc, xStr, bitSize) + if err != nil { + return err } if err = to.Append(result, false); err != nil { return err @@ -6008,6 +6040,13 @@ func decimal128ToBit( ctx context.Context, from vector.FunctionParameterWrapper[types.Decimal128], to *vector.FunctionResult[uint64], bitSize int, length int, selectList *FunctionSelectList) error { + return decimal128ToBitWithIgnore(ctx, nil, from, to, bitSize, length, selectList) +} + +func decimal128ToBitWithIgnore( + ctx context.Context, proc *process.Process, + from vector.FunctionParameterWrapper[types.Decimal128], + to *vector.FunctionResult[uint64], bitSize int, length int, selectList *FunctionSelectList) error { for i := 0; i < length; i++ { v, null := from.GetValue(uint64(i)) if null { @@ -6015,12 +6054,11 @@ func decimal128ToBit( return err } } else { - var result uint64 - var err error xStr := v.Format(from.GetType().Scale) xStr = strings.Split(xStr, ".")[0] - if result, err = strconv.ParseUint(xStr, 10, bitSize); err != nil { - return moerr.NewOutOfRangef(ctx, fmt.Sprintf("bit(%d)", bitSize), "value '%v'", xStr) + result, err := decimalStringToBit(ctx, proc, xStr, bitSize) + if err != nil { + return err } if err = to.Append(result, false); err != nil { return err @@ -6034,6 +6072,13 @@ func decimal256ToBit( ctx context.Context, from vector.FunctionParameterWrapper[types.Decimal256], to *vector.FunctionResult[uint64], bitSize int, length int, selectList *FunctionSelectList) error { + return decimal256ToBitWithIgnore(ctx, nil, from, to, bitSize, length, selectList) +} + +func decimal256ToBitWithIgnore( + ctx context.Context, proc *process.Process, + from vector.FunctionParameterWrapper[types.Decimal256], + to *vector.FunctionResult[uint64], bitSize int, length int, selectList *FunctionSelectList) error { for i := 0; i < length; i++ { v, null := from.GetValue(uint64(i)) if null { @@ -6043,9 +6088,9 @@ func decimal256ToBit( } else { xStr := v.Format(from.GetType().Scale) xStr = strings.Split(xStr, ".")[0] - result, err := strconv.ParseUint(xStr, 10, bitSize) + result, err := decimalStringToBit(ctx, proc, xStr, bitSize) if err != nil { - return moerr.NewOutOfRangef(ctx, fmt.Sprintf("bit(%d)", bitSize), "value '%v'", xStr) + return err } if err = to.Append(result, false); err != nil { return err @@ -6055,6 +6100,20 @@ func decimal256ToBit( return nil } +func decimalStringToBit(ctx context.Context, proc *process.Process, value string, bitSize int) (uint64, error) { + result, err := strconv.ParseUint(value, 10, bitSize) + if err == nil { + return result, nil + } + if statementIgnore(proc) { + if strings.HasPrefix(strings.TrimSpace(value), "-") { + return 0, nil + } + return maxBitValue(bitSize), nil + } + return 0, moerr.NewOutOfRangef(ctx, fmt.Sprintf("bit(%d)", bitSize), "value '%v'", value) +} + func strToSigned[T constraints.Signed]( ctx context.Context, from vector.FunctionParameterWrapper[types.Varlena], diff --git a/test/distributed/cases/dml/insert/insert_ignore.result b/test/distributed/cases/dml/insert/insert_ignore.result index 5f8b15caa353b..f839cf4c3e784 100644 --- a/test/distributed/cases/dml/insert/insert_ignore.result +++ b/test/distributed/cases/dml/insert/insert_ignore.result @@ -196,14 +196,38 @@ s set('x', 'y', 'z') insert ignore into insert_ignore_special_types values (1, '2156', b'11111', 'bad', 'x,bad'), (2, '2156', 31, 9, 99); -create table insert_ignore_special_source (v int, d decimal(10, 0), d256 decimal(40, 0)); -insert into insert_ignore_special_source values (31, 2156, 2156); +create table insert_ignore_special_source ( +v int, +u bigint unsigned, +f double, +f64 double, +d decimal(10, 0), +d256 decimal(40, 0), +b bit(5) +); +insert into insert_ignore_special_source values (31, 31, 31, 18446744073709551616, 2156, 2156, b'11111'); insert ignore into insert_ignore_special_types select 3, '2156', v, 9, 99 from insert_ignore_special_source; insert ignore into insert_ignore_special_types select 4, d, 0, 9, 99 from insert_ignore_special_source; insert ignore into insert_ignore_special_types select 5, d256, 0, 9, 99 from insert_ignore_special_source; +insert ignore into insert_ignore_special_types +select 6, 0, u, 1, 1 from insert_ignore_special_source; +insert ignore into insert_ignore_special_types +select 7, 0, f, 1, 1 from insert_ignore_special_source; +insert ignore into insert_ignore_special_types +select 8, 0, d, 1, 1 from insert_ignore_special_source; +insert ignore into insert_ignore_special_types +select 9, 0, b, 1, 1 from insert_ignore_special_source; +drop table if exists insert_ignore_special_bit64; +create table insert_ignore_special_bit64 (b bit(64)); +insert ignore into insert_ignore_special_bit64 +select f64 from insert_ignore_special_source; +select hex(b) from insert_ignore_special_bit64; +hex(b) +FFFFFFFFFFFFFFFF +drop table insert_ignore_special_bit64; select id, y + 0, bin(b + 0), e, e + 0, s, s + 0 from insert_ignore_special_types order by id; id y + 0 bin(b + 0) e e + 0 s s + 0 @@ -212,6 +236,10 @@ id y + 0 bin(b + 0) e e + 0 s s + 0 3 0 1111 0 x,y 3 4 0 0 0 x,y 3 5 0 0 0 x,y 3 +6 0 1111 a 1 x 1 +7 0 1111 a 1 x 1 +8 0 1111 a 1 x 1 +9 0 1111 a 1 x 1 drop table insert_ignore_special_source; drop table insert_ignore_special_types; set session sql_mode = @insert_ignore_sql_mode; diff --git a/test/distributed/cases/dml/insert/insert_ignore.sql b/test/distributed/cases/dml/insert/insert_ignore.sql index ba6c3eabb7736..f3ac8c9ee7d93 100644 --- a/test/distributed/cases/dml/insert/insert_ignore.sql +++ b/test/distributed/cases/dml/insert/insert_ignore.sql @@ -146,14 +146,36 @@ create table insert_ignore_special_types ( insert ignore into insert_ignore_special_types values (1, '2156', b'11111', 'bad', 'x,bad'), (2, '2156', 31, 9, 99); -create table insert_ignore_special_source (v int, d decimal(10, 0), d256 decimal(40, 0)); -insert into insert_ignore_special_source values (31, 2156, 2156); +create table insert_ignore_special_source ( + v int, + u bigint unsigned, + f double, + f64 double, + d decimal(10, 0), + d256 decimal(40, 0), + b bit(5) +); +insert into insert_ignore_special_source values (31, 31, 31, 18446744073709551616, 2156, 2156, b'11111'); insert ignore into insert_ignore_special_types select 3, '2156', v, 9, 99 from insert_ignore_special_source; insert ignore into insert_ignore_special_types select 4, d, 0, 9, 99 from insert_ignore_special_source; insert ignore into insert_ignore_special_types select 5, d256, 0, 9, 99 from insert_ignore_special_source; +insert ignore into insert_ignore_special_types +select 6, 0, u, 1, 1 from insert_ignore_special_source; +insert ignore into insert_ignore_special_types +select 7, 0, f, 1, 1 from insert_ignore_special_source; +insert ignore into insert_ignore_special_types +select 8, 0, d, 1, 1 from insert_ignore_special_source; +insert ignore into insert_ignore_special_types +select 9, 0, b, 1, 1 from insert_ignore_special_source; +drop table if exists insert_ignore_special_bit64; +create table insert_ignore_special_bit64 (b bit(64)); +insert ignore into insert_ignore_special_bit64 +select f64 from insert_ignore_special_source; +select hex(b) from insert_ignore_special_bit64; +drop table insert_ignore_special_bit64; select id, y + 0, bin(b + 0), e, e + 0, s, s + 0 from insert_ignore_special_types order by id; drop table insert_ignore_special_source; diff --git a/test/distributed/cases/dtype/mysql_compat_enum_set_numeric.result b/test/distributed/cases/dtype/mysql_compat_enum_set_numeric.result index 01da8e1a78b09..6b42f1f6789cd 100644 --- a/test/distributed/cases/dtype/mysql_compat_enum_set_numeric.result +++ b/test/distributed/cases/dtype/mysql_compat_enum_set_numeric.result @@ -26,6 +26,16 @@ from mysql_compat_enum_set_numeric order by i; e in (select i from mysql_compat_enum_set_numeric) e not in (select i from mysql_compat_enum_set_numeric) e = any (select i from mysql_compat_enum_set_numeric) s in (select i from mysql_compat_enum_set_numeric) s not in (select i from mysql_compat_enum_set_numeric) 1 0 1 1 0 1 0 1 0 1 +select i in (select e from mysql_compat_enum_set_numeric), +i = any (select e from mysql_compat_enum_set_numeric), +i in (select s from mysql_compat_enum_set_numeric), +(e, i) in (select i, i from mysql_compat_enum_set_numeric), +(e, i) not in (select i, i from mysql_compat_enum_set_numeric), +(e, i) = any (select i, i from mysql_compat_enum_set_numeric) +from mysql_compat_enum_set_numeric order by i; +i in (select e from mysql_compat_enum_set_numeric) i = any (select e from mysql_compat_enum_set_numeric) i in (select s from mysql_compat_enum_set_numeric) (e, i) in (select i, i from mysql_compat_enum_set_numeric) (e, i) not in (select i, i from mysql_compat_enum_set_numeric) (e, i) = any (select i, i from mysql_compat_enum_set_numeric) +1 1 1 1 0 1 +1 1 0 1 0 1 select e in (select cast(i as char) from mysql_compat_enum_set_numeric), s in (select cast(i as char) from mysql_compat_enum_set_numeric) from mysql_compat_enum_set_numeric order by i; diff --git a/test/distributed/cases/dtype/mysql_compat_enum_set_numeric.sql b/test/distributed/cases/dtype/mysql_compat_enum_set_numeric.sql index ebf5f18d275cd..4f920bfdf5c74 100644 --- a/test/distributed/cases/dtype/mysql_compat_enum_set_numeric.sql +++ b/test/distributed/cases/dtype/mysql_compat_enum_set_numeric.sql @@ -23,6 +23,15 @@ select e in (select i from mysql_compat_enum_set_numeric), s not in (select i from mysql_compat_enum_set_numeric) from mysql_compat_enum_set_numeric order by i; +-- Numeric left operands and row constructors also use subquery ordinals/bitmaps. +select i in (select e from mysql_compat_enum_set_numeric), + i = any (select e from mysql_compat_enum_set_numeric), + i in (select s from mysql_compat_enum_set_numeric), + (e, i) in (select i, i from mysql_compat_enum_set_numeric), + (e, i) not in (select i, i from mysql_compat_enum_set_numeric), + (e, i) = any (select i, i from mysql_compat_enum_set_numeric) +from mysql_compat_enum_set_numeric order by i; + -- String-typed subqueries retain label comparison semantics. select e in (select cast(i as char) from mysql_compat_enum_set_numeric), s in (select cast(i as char) from mysql_compat_enum_set_numeric) From 2f4787c0c5656197156d80f5a7070eb6ed420e36 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Tue, 4 Aug 2026 12:41:20 +0800 Subject: [PATCH 17/22] update --- test/distributed/cases/dtype/enum.result | 2 +- test/distributed/cases/dtype/enum_1.result | 162 +++++++++++---------- 2 files changed, 83 insertions(+), 81 deletions(-) diff --git a/test/distributed/cases/dtype/enum.result b/test/distributed/cases/dtype/enum.result index 3b5abe3b574aa..ce92ef3d11049 100644 --- a/test/distributed/cases/dtype/enum.result +++ b/test/distributed/cases/dtype/enum.result @@ -406,7 +406,7 @@ select id, y + 0, bin(b + 0), e, e + 0, s, s + 0 from mysql_compat_special_ignore order by id; ➤ id[4,32,0] ¦ y + 0[-5,64,0] ¦ bin(b + 0)[12,-1,0] ¦ e[12,-1,0] ¦ e + 0[-5,64,0] ¦ s[12,-1,0] ¦ s + 0[3,38,0] 𝄀 1 ¦ 0 ¦ 1111 ¦ ¦ 0 ¦ x ¦ 1 𝄀 -2 ¦ 0 ¦ 0 ¦ ¦ 0 ¦ ¦ 0 𝄀 +2 ¦ 0 ¦ 1111 ¦ ¦ 0 ¦ ¦ 0 𝄀 3 ¦ 2024 ¦ 11 ¦ a ¦ 1 ¦ x,z ¦ 5 𝄀 4 ¦ 2024 ¦ 0 ¦ ¦ 3 ¦ ¦ 0 select id, e, e + 0, e = '', length(e) diff --git a/test/distributed/cases/dtype/enum_1.result b/test/distributed/cases/dtype/enum_1.result index 1d8a583a794ca..0e84943d5cac3 100644 --- a/test/distributed/cases/dtype/enum_1.result +++ b/test/distributed/cases/dtype/enum_1.result @@ -2,9 +2,9 @@ create table typec(a int,b enum('4','3','2','1')); insert into typec values(1,1); insert into typec values(2,'1'); select * from typec; -a b -1 1 -2 4 +➤ a[4,32,0] ¦ b[12,-1,0] 𝄀 +1 ¦ 4 𝄀 +2 ¦ 1 drop table typec; CREATE TABLE orders ( id INT PRIMARY KEY, @@ -13,67 +13,67 @@ status ENUM('Pending', 'Processing', 'Completed', 'Cancelled') ); insert into orders values(1,'111',1),(2,'222',2),(3,'333',3),(4,'444','Cancelled'); select * from orders; -id order_number status -1 111 Pending -2 222 Processing -3 333 Completed -4 444 Cancelled +➤ id[4,32,0] ¦ order_number[12,-1,0] ¦ status[12,-1,0] 𝄀 +1 ¦ 111 ¦ Pending 𝄀 +2 ¦ 222 ¦ Processing 𝄀 +3 ¦ 333 ¦ Completed 𝄀 +4 ¦ 444 ¦ Cancelled update orders set status= 1 where status= 'Processing'; select * from orders; -id order_number status -1 111 Pending -3 333 Completed -4 444 Cancelled -2 222 Pending +➤ id[4,32,0] ¦ order_number[12,-1,0] ¦ status[12,-1,0] 𝄀 +1 ¦ 111 ¦ Pending 𝄀 +3 ¦ 333 ¦ Completed 𝄀 +4 ¦ 444 ¦ Cancelled 𝄀 +2 ¦ 222 ¦ Pending delete from orders where status= 'Completed'; select * from orders; -id order_number status -1 111 Pending -4 444 Cancelled -2 222 Pending +➤ id[4,32,0] ¦ order_number[12,-1,0] ¦ status[12,-1,0] 𝄀 +1 ¦ 111 ¦ Pending 𝄀 +4 ¦ 444 ¦ Cancelled 𝄀 +2 ¦ 222 ¦ Pending update orders set status='Pending' where status = 'Processing'; select * from orders; -id order_number status -1 111 Pending -4 444 Cancelled -2 222 Pending +➤ id[4,32,0] ¦ order_number[12,-1,0] ¦ status[12,-1,0] 𝄀 +1 ¦ 111 ¦ Pending 𝄀 +4 ¦ 444 ¦ Cancelled 𝄀 +2 ¦ 222 ¦ Pending select * from orders where status='Cancelled'; -id order_number status -4 444 Cancelled +➤ id[4,32,0] ¦ order_number[12,-1,0] ¦ status[12,-1,0] 𝄀 +4 ¦ 444 ¦ Cancelled select * from orders where status in ('Pending','Cancelled'); -id order_number status -1 111 Pending -4 444 Cancelled -2 222 Pending +➤ id[4,32,0] ¦ order_number[12,-1,0] ¦ status[12,-1,0] 𝄀 +1 ¦ 111 ¦ Pending 𝄀 +4 ¦ 444 ¦ Cancelled 𝄀 +2 ¦ 222 ¦ Pending insert into orders values(3,'333',null); insert into orders(id,order_number) values(5,'555'); select * from orders; -id order_number status -1 111 Pending -4 444 Cancelled -2 222 Pending -3 333 null -5 555 null +➤ id[4,32,0] ¦ order_number[12,-1,0] ¦ status[12,-1,0] 𝄀 +1 ¦ 111 ¦ Pending 𝄀 +4 ¦ 444 ¦ Cancelled 𝄀 +2 ¦ 222 ¦ Pending 𝄀 +3 ¦ 333 ¦ null 𝄀 +5 ¦ 555 ¦ null insert into orders values(6,'666','New'); internal error: convert to MySQL enum failed: item New is not in enum [Pending Processing Completed Cancelled] select count(*),status from orders group by status; -count(*) status -2 Pending -1 Cancelled -2 null +➤ count(*)[-5,64,0] ¦ status[12,-1,0] 𝄀 +2 ¦ Pending 𝄀 +1 ¦ Cancelled 𝄀 +2 ¦ null select substring(status,2,3) from orders; -substring(status, 2, 3) -end -anc -end -null +➤ substring(status, 2, 3)[12,-1,0] 𝄀 +end 𝄀 +anc 𝄀 +end 𝄀 +null 𝄀 null select length(status) from orders; -length(status) -7 -9 -7 -null +➤ length(status)[-5,64,0] 𝄀 +7 𝄀 +9 𝄀 +7 𝄀 +null 𝄀 null drop table orders; create table t4 (a enum('abc', 'def')); @@ -82,8 +82,8 @@ internal error: convert to MySQL enum failed: number 0 overflow enum boundary [1 insert into t4 values (1); insert into t4 values (2); select * from t4; -a -abc +➤ a[12,-1,0] 𝄀 +abc 𝄀 def drop table t4; create table t4 (a enum('abc', 'def')); @@ -93,16 +93,16 @@ insert into t5 values(1); insert into t5 values(2); insert into t4 select * from t5; select * from t4; -a -abc +➤ a[12,-1,0] 𝄀 +abc 𝄀 def delete from t4; insert into t6 values ('abc'); insert into t6 values ('def'); insert into t4 select * from t6; select * from t4; -a -abc +➤ a[12,-1,0] 𝄀 +abc 𝄀 def delete from t4; insert into t5 values(3); @@ -135,60 +135,62 @@ insert into table01 (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10 create table table02 as select * from table01; insert into table02 values (12, 'Value1', 123, 45.67, '2023-10-23', TRUE, 'apple', 'This is a text', '2019-01-01 01:01:01.000', 'Some binary data', 'C'); select * from table02; -id col1 col2 col3 col4 col5 col6 col7 col8 col9 col10 -1 Value2 456 78.90 2023-10-24 0 banana Another text 2022-01-01 01:01:01 More binary data D -2 Value3 789 12.34 2023-10-25 1 orange Yet another text 1979-01-01 01:01:01 Even more binary data E -12 Value1 123 45.67 2023-10-23 1 apple This is a text 2019-01-01 01:01:01 Some binary data C +➤ id[4,32,0] ¦ col1[12,-1,0] ¦ col2[4,32,0] ¦ col3[3,10,2] ¦ col4[91,64,0] ¦ col5[-7,1,0] ¦ col6[12,-1,0] ¦ col7[12,0,0] ¦ col8[93,64,0] ¦ col9[12,0,0] ¦ col10[1,1,0] 𝄀 +1 ¦ Value2 ¦ 456 ¦ 78.90 ¦ 2023-10-24 ¦ 0 ¦ banana ¦ Another text ¦ 2022-01-01 01:01:01 ¦ More binary data ¦ D 𝄀 +2 ¦ Value3 ¦ 789 ¦ 12.34 ¦ 2023-10-25 ¦ 1 ¦ orange ¦ Yet another text ¦ 1979-01-01 01:01:01 ¦ Even more binary data ¦ E 𝄀 +12 ¦ Value1 ¦ 123 ¦ 45.67 ¦ 2023-10-23 ¦ 1 ¦ apple ¦ This is a text ¦ 2019-01-01 01:01:01 ¦ Some binary data ¦ C update table02 set col1 = 'newvalue' where col2 = 456; select * from table02; -id col1 col2 col3 col4 col5 col6 col7 col8 col9 col10 -2 Value3 789 12.34 2023-10-25 1 orange Yet another text 1979-01-01 01:01:01 Even more binary data E -12 Value1 123 45.67 2023-10-23 1 apple This is a text 2019-01-01 01:01:01 Some binary data C -1 newvalue 456 78.90 2023-10-24 0 banana Another text 2022-01-01 01:01:01 More binary data D +➤ id[4,32,0] ¦ col1[12,-1,0] ¦ col2[4,32,0] ¦ col3[3,10,2] ¦ col4[91,64,0] ¦ col5[-7,1,0] ¦ col6[12,-1,0] ¦ col7[12,0,0] ¦ col8[93,64,0] ¦ col9[12,0,0] ¦ col10[1,1,0] 𝄀 +2 ¦ Value3 ¦ 789 ¦ 12.34 ¦ 2023-10-25 ¦ 1 ¦ orange ¦ Yet another text ¦ 1979-01-01 01:01:01 ¦ Even more binary data ¦ E 𝄀 +12 ¦ Value1 ¦ 123 ¦ 45.67 ¦ 2023-10-23 ¦ 1 ¦ apple ¦ This is a text ¦ 2019-01-01 01:01:01 ¦ Some binary data ¦ C 𝄀 +1 ¦ newvalue ¦ 456 ¦ 78.90 ¦ 2023-10-24 ¦ 0 ¦ banana ¦ Another text ¦ 2022-01-01 01:01:01 ¦ More binary data ¦ D update table02 set col6 = 'apple' where col2 = 789; select * from table02; -id col1 col2 col3 col4 col5 col6 col7 col8 col9 col10 -12 Value1 123 45.67 2023-10-23 1 apple This is a text 2019-01-01 01:01:01 Some binary data C -1 newvalue 456 78.90 2023-10-24 0 banana Another text 2022-01-01 01:01:01 More binary data D -2 Value3 789 12.34 2023-10-25 1 apple Yet another text 1979-01-01 01:01:01 Even more binary data E +➤ id[4,32,0] ¦ col1[12,-1,0] ¦ col2[4,32,0] ¦ col3[3,10,2] ¦ col4[91,64,0] ¦ col5[-7,1,0] ¦ col6[12,-1,0] ¦ col7[12,0,0] ¦ col8[93,64,0] ¦ col9[12,0,0] ¦ col10[1,1,0] 𝄀 +12 ¦ Value1 ¦ 123 ¦ 45.67 ¦ 2023-10-23 ¦ 1 ¦ apple ¦ This is a text ¦ 2019-01-01 01:01:01 ¦ Some binary data ¦ C 𝄀 +1 ¦ newvalue ¦ 456 ¦ 78.90 ¦ 2023-10-24 ¦ 0 ¦ banana ¦ Another text ¦ 2022-01-01 01:01:01 ¦ More binary data ¦ D 𝄀 +2 ¦ Value3 ¦ 789 ¦ 12.34 ¦ 2023-10-25 ¦ 1 ¦ apple ¦ Yet another text ¦ 1979-01-01 01:01:01 ¦ Even more binary data ¦ E drop table table01; drop table table02; drop table if exists table01; create table table03(type enum('1','2','3','4','5') not null comment 'type'); show create table table03; -Table Create Table -table03 CREATE TABLE `table03` (\n `type` enum('1','2','3','4','5') NOT NULL COMMENT 'type'\n) +➤ Table[12,-1,0] ¦ Create Table[12,-1,0] 𝄀 +table03 ¦ CREATE TABLE `table03` ( + `type` enum('1','2','3','4','5') NOT NULL COMMENT 'type' +) desc table03; -Field Type Null Key Default Extra Comment -type ENUM('1','2','3','4','5') NO null type +➤ Field[1,0,0] ¦ Type[1,0,0] ¦ Null[1,0,0] ¦ Key[1,0,0] ¦ Default[1,0,0] ¦ Extra[1,0,0] ¦ Comment[1,0,0] 𝄀 +type ¦ ENUM('1','2','3','4','5') ¦ NO ¦ ¦ null ¦ ¦ type drop table table03; create table t3 (id int); insert into t3 values (1); alter table t3 add column name enum ('A','B','C'); select * from t3; -id name -1 null +➤ id[4,32,0] ¦ name[12,-1,0] 𝄀 +1 ¦ null insert into t3 values (2,'B'); insert into t3 values (3,'D'); internal error: convert to MySQL enum failed: item D is not in enum [A B C] select * from t3; -id name -1 null -2 B +➤ id[4,32,0] ¦ name[12,-1,0] 𝄀 +1 ¦ null 𝄀 +2 ¦ B drop table t3; create table t1(name varchar(25)); insert into t1 values ('A'),('B'),('C'); select * from t1; -name -A -B +➤ name[12,-1,0] 𝄀 +A 𝄀 +B 𝄀 C alter table t1 modify column name enum('A','B'); internal error: convert to MySQL enum failed: item C is not in enum [A B] alter table t1 modify column name enum('A','B','C'); select * from t1; -name -A -B +➤ name[12,-1,0] 𝄀 +A 𝄀 +B 𝄀 C drop table t1; From c968c6795533c1aa5b8655424ab94ce47caa04f9 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Tue, 4 Aug 2026 12:55:11 +0800 Subject: [PATCH 18/22] update --- pkg/sql/plan/function/func_cast.go | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/pkg/sql/plan/function/func_cast.go b/pkg/sql/plan/function/func_cast.go index 20a4d94addef0..4de577048fad4 100644 --- a/pkg/sql/plan/function/func_cast.go +++ b/pkg/sql/plan/function/func_cast.go @@ -3135,14 +3135,6 @@ func numericToNumeric[T1, T2 constraints.Integer | constraints.Float]( return nil } -func numericToBit[T constraints.Integer | constraints.Float]( - ctx context.Context, - from vector.FunctionParameterWrapper[T], - to *vector.FunctionResult[uint64], bitSize int, - length int, selectList *FunctionSelectList) error { - return numericToBitWithIgnore(ctx, nil, from, to, bitSize, length, selectList) -} - func numericToBitWithIgnore[T constraints.Integer | constraints.Float]( ctx context.Context, proc *process.Process, from vector.FunctionParameterWrapper[T], @@ -6004,13 +5996,6 @@ func decimal256ToStr( return nil } -func decimal64ToBit( - ctx context.Context, - from vector.FunctionParameterWrapper[types.Decimal64], - to *vector.FunctionResult[uint64], bitSize int, length int, selectList *FunctionSelectList) error { - return decimal64ToBitWithIgnore(ctx, nil, from, to, bitSize, length, selectList) -} - func decimal64ToBitWithIgnore( ctx context.Context, proc *process.Process, from vector.FunctionParameterWrapper[types.Decimal64], @@ -6036,13 +6021,6 @@ func decimal64ToBitWithIgnore( return nil } -func decimal128ToBit( - ctx context.Context, - from vector.FunctionParameterWrapper[types.Decimal128], - to *vector.FunctionResult[uint64], bitSize int, length int, selectList *FunctionSelectList) error { - return decimal128ToBitWithIgnore(ctx, nil, from, to, bitSize, length, selectList) -} - func decimal128ToBitWithIgnore( ctx context.Context, proc *process.Process, from vector.FunctionParameterWrapper[types.Decimal128], From 39cb6b703e949a202c614c07ecfd34bb48b85f33 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Tue, 4 Aug 2026 14:50:05 +0800 Subject: [PATCH 19/22] update --- .../cases/dtype/mysql_compat_cast_convert_matrix.result | 1 + .../distributed/cases/dtype/mysql_compat_cast_convert_matrix.sql | 1 + 2 files changed, 2 insertions(+) diff --git a/test/distributed/cases/dtype/mysql_compat_cast_convert_matrix.result b/test/distributed/cases/dtype/mysql_compat_cast_convert_matrix.result index c2e6d1848b0dd..dc65e3899956d 100644 --- a/test/distributed/cases/dtype/mysql_compat_cast_convert_matrix.result +++ b/test/distributed/cases/dtype/mysql_compat_cast_convert_matrix.result @@ -1,3 +1,4 @@ +set session sql_mode = default; drop database if exists mysql_compat_cast_convert_matrix; create database mysql_compat_cast_convert_matrix; use mysql_compat_cast_convert_matrix; diff --git a/test/distributed/cases/dtype/mysql_compat_cast_convert_matrix.sql b/test/distributed/cases/dtype/mysql_compat_cast_convert_matrix.sql index 33bf0498f5e75..72df44068c906 100644 --- a/test/distributed/cases/dtype/mysql_compat_cast_convert_matrix.sql +++ b/test/distributed/cases/dtype/mysql_compat_cast_convert_matrix.sql @@ -4,6 +4,7 @@ -- @desc: MySQL compatibility cases for CAST/CONVERT target type matrix -- @label:bvt +set session sql_mode = default; drop database if exists mysql_compat_cast_convert_matrix; create database mysql_compat_cast_convert_matrix; use mysql_compat_cast_convert_matrix; From fcf5052594ce1fcfc99a66a18ce355f36f95ea89 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Tue, 4 Aug 2026 15:54:27 +0800 Subject: [PATCH 20/22] update ut --- pkg/sql/plan/function/func_cast_test.go | 55 ++++++++ pkg/sql/plan/function/func_mo_test.go | 40 ++++++ pkg/sql/plan/mysql_special_types_test.go | 69 ++++++++++ pkg/sql/util/eval_expr_util_test.go | 159 +++++++++++++++++++++++ 4 files changed, 323 insertions(+) diff --git a/pkg/sql/plan/function/func_cast_test.go b/pkg/sql/plan/function/func_cast_test.go index 1f5866fca0d05..1785a302021d8 100644 --- a/pkg/sql/plan/function/func_cast_test.go +++ b/pkg/sql/plan/function/func_cast_test.go @@ -136,6 +136,61 @@ func TestCastEnumToNumericTypes(t *testing.T) { } } +func TestInsertIgnoreCastsSpecialValues(t *testing.T) { + proc := testutil.NewProcess(t) + proc.SetStmtProfile(&process.StmtProfile{}) + proc.GetStmtProfile().SetStatementRuntimeProfile("Insert", "DML", true) + bit4 := types.New(types.T_bit, 4, 0) + bit64 := types.New(types.T_bit, 64, 0) + + runBitCast := func(name string, input FunctionTestInput, target types.Type, want uint64) { + t.Helper() + t.Run(name, func(t *testing.T) { + tcc := NewFunctionTestCase(proc, + []FunctionTestInput{input, NewFunctionTestInput(target, []uint64{}, nil)}, + NewFunctionTestResult(target, false, []uint64{want}, nil), NewCast) + succeed, info := tcc.Run() + require.True(t, succeed, info) + }) + } + + runBitCast("int8 saturates", NewFunctionTestInput(types.T_int8.ToType(), []int8{31}, nil), bit4, 15) + runBitCast("int16 saturates", NewFunctionTestInput(types.T_int16.ToType(), []int16{31}, nil), bit4, 15) + runBitCast("int32 saturates", NewFunctionTestInput(types.T_int32.ToType(), []int32{31}, nil), bit4, 15) + runBitCast("int64 saturates", NewFunctionTestInput(types.T_int64.ToType(), []int64{31}, nil), bit4, 15) + runBitCast("uint8 saturates", NewFunctionTestInput(types.T_uint8.ToType(), []uint8{31}, nil), bit4, 15) + runBitCast("uint16 saturates", NewFunctionTestInput(types.T_uint16.ToType(), []uint16{31}, nil), bit4, 15) + runBitCast("uint32 saturates", NewFunctionTestInput(types.T_uint32.ToType(), []uint32{31}, nil), bit4, 15) + runBitCast("uint64 saturates", NewFunctionTestInput(types.T_uint64.ToType(), []uint64{31}, nil), bit4, 15) + runBitCast("float32 saturates", NewFunctionTestInput(types.T_float32.ToType(), []float32{31}, nil), bit4, 15) + runBitCast("float64 bit64 upper bound saturates", NewFunctionTestInput(types.T_float64.ToType(), []float64{math.Exp2(64)}, nil), bit64, math.MaxUint64) + runBitCast("decimal64 saturates", NewFunctionTestInput(types.New(types.T_decimal64, 10, 0), []types.Decimal64{31}, nil), bit4, 15) + runBitCast("decimal128 saturates", NewFunctionTestInput(types.New(types.T_decimal128, 20, 0), []types.Decimal128{{B0_63: 31}}, nil), bit4, 15) + runBitCast("decimal256 saturates", NewFunctionTestInput(types.New(types.T_decimal256, 40, 0), []types.Decimal256{{B0_63: 31}}, nil), bit4, 15) + + runYearCast := func(name string, input FunctionTestInput) { + t.Helper() + t.Run(name, func(t *testing.T) { + year := types.T_year.ToType() + tcc := NewFunctionTestCase(proc, + []FunctionTestInput{input, NewFunctionTestInput(year, []types.MoYear{}, nil)}, + NewFunctionTestResult(year, false, []types.MoYear{0}, nil), NewCast) + require.NoError(t, tcc.result.PreExtendAndReset(1)) + result, err := tcc.DebugRun() + require.NoError(t, err) + got, isNull := vector.GenerateFunctionFixedTypeParameter[types.MoYear](result).GetValue(0) + require.False(t, isNull) + require.Equal(t, types.MoYear(0), got) + }) + } + + runYearCast("integer invalid year becomes zero", NewFunctionTestInput(types.T_int64.ToType(), []int64{2156}, nil)) + runYearCast("string invalid year becomes zero", NewFunctionTestInput(types.T_varchar.ToType(), []string{"2156"}, nil)) + runYearCast("decimal64 invalid year becomes zero", NewFunctionTestInput(types.New(types.T_decimal64, 10, 0), []types.Decimal64{2156}, nil)) + runYearCast("decimal128 invalid year becomes zero", NewFunctionTestInput(types.New(types.T_decimal128, 20, 0), []types.Decimal128{{B0_63: 2156}}, nil)) + runYearCast("decimal256 invalid year becomes zero", NewFunctionTestInput(types.New(types.T_decimal256, 40, 0), []types.Decimal256{{B0_63: 2156}}, nil)) +} + func TestStringToFixedFloat32PreservesSourcePrecision(t *testing.T) { proc := testutil.NewProcess(t) targetType := types.New(types.T_float32, 5, 2) diff --git a/pkg/sql/plan/function/func_mo_test.go b/pkg/sql/plan/function/func_mo_test.go index dc9ff2a1a92c3..39b8fb70344de 100644 --- a/pkg/sql/plan/function/func_mo_test.go +++ b/pkg/sql/plan/function/func_mo_test.go @@ -21,7 +21,9 @@ import ( "github.com/matrixorigin/matrixone/pkg/container/bytejson" "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" "github.com/matrixorigin/matrixone/pkg/testutil" + "github.com/matrixorigin/matrixone/pkg/vm/process" "github.com/stretchr/testify/require" ) @@ -102,6 +104,44 @@ func TestCastValueToIndexConstDefinition(t *testing.T) { require.True(t, succeed, info) } +func TestInsertIgnoreAdjustsMySQLSpecialTypeValues(t *testing.T) { + ignoreProc := testutil.NewProcess(t) + ignoreProc.SetStmtProfile(&process.StmtProfile{}) + ignoreProc.GetStmtProfile().SetStatementRuntimeProfile("Insert", "DML", true) + + run := func(name string, inputs []FunctionTestInput, expect FunctionTestResult, fn func([]*vector.Vector, vector.FunctionResultWrapper, *process.Process, int, *FunctionSelectList) error) { + t.Helper() + t.Run(name, func(t *testing.T) { + tcc := NewFunctionTestCase(ignoreProc, inputs, expect, fn) + succeed, info := tcc.Run() + require.True(t, succeed, info) + }) + } + + run("enum labels use error member", []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{"a,b", "a,b"}, nil), + NewFunctionTestInput(types.T_varchar.ToType(), []string{"bad", "b"}, nil), + }, NewFunctionTestResult(types.T_enum.ToType(), false, []types.Enum{0, 2}, nil), CastValueToIndex) + + run("enum numeric values use error member", []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{"a,b", "a,b", "a,b"}, nil), + NewFunctionTestInput(types.T_uint16.ToType(), []uint16{9, 1, 1}, []bool{false, false, true}), + }, NewFunctionTestResult(types.T_enum.ToType(), false, []types.Enum{0, 1, 0}, []bool{false, false, true}), CastIndexValueToIndex) + + run("set labels retain valid members", []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{"x,y,z", "x,y,z", "x,y,z"}, nil), + NewFunctionTestInput(types.T_varchar.ToType(), []string{"x,bad", "bad", "x"}, []bool{false, false, true}), + }, NewFunctionTestResult(types.T_uint64.ToType(), false, []uint64{1, 0, 0}, []bool{false, false, true}), CastSetValueToIndex) + + run("set numeric values retain declared bits", []FunctionTestInput{ + NewFunctionTestInput(types.T_varchar.ToType(), []string{"x,y,z", "x,y,z", "x,y,z"}, nil), + NewFunctionTestInput(types.T_uint64.ToType(), []uint64{99, 4, 1}, []bool{false, false, true}), + }, NewFunctionTestResult(types.T_uint64.ToType(), false, []uint64{3, 4, 0}, []bool{false, false, true}), CastSetIndexValueToIndex) + + require.Equal(t, uint64(7), setMemberBitmap("x,y,z")) + require.False(t, statementIgnore(nil)) +} + func TestEnumValueIndexPreservesParseEnumSemantics(t *testing.T) { for _, definition := range []string{ "low,LOW,2,high,high", diff --git a/pkg/sql/plan/mysql_special_types_test.go b/pkg/sql/plan/mysql_special_types_test.go index 2788c8c0469c0..ec02a09457d93 100644 --- a/pkg/sql/plan/mysql_special_types_test.go +++ b/pkg/sql/plan/mysql_special_types_test.go @@ -16,10 +16,12 @@ package plan import ( "context" + "strings" "testing" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/pb/plan" + "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" "github.com/stretchr/testify/require" ) @@ -38,6 +40,73 @@ func TestFuncCastForEnumTypeKeepsMatchingErrorMember(t *testing.T) { require.Equal(t, uint32(0), got.GetLit().GetEnumVal()) } +func TestInsertIgnoreMySQLSpecialTypeLiteralHelpers(t *testing.T) { + ctx := context.Background() + enumType := plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,"} + setType := plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y,z"} + yearType := plan.Type{Id: int32(types.T_year)} + + for _, tc := range []struct { + name string + target plan.Type + value *tree.NumVal + wantEnum uint32 + wantSet uint64 + handled bool + }{ + {"enum valid label", enumType, tree.NewNumVal("b", "b", false, tree.P_char), 2, 0, true}, + {"enum invalid label", enumType, tree.NewNumVal("bad", "bad", false, tree.P_char), 0, 0, true}, + {"enum numeric ordinal", enumType, tree.NewNumVal(int64(1), "1", false, tree.P_int64), 1, 0, true}, + {"enum invalid numeric ordinal", enumType, tree.NewNumVal(uint64(9), "9", false, tree.P_uint64), 0, 0, true}, + {"set label drops invalid member", setType, tree.NewNumVal("x,bad", "x,bad", false, tree.P_char), 0, 1, true}, + {"set numeric masks unknown bits", setType, tree.NewNumVal(uint64(99), "99", false, tree.P_uint64), 0, 3, true}, + {"set negative numeric becomes empty", setType, tree.NewNumVal(int64(-1), "-1", false, tree.P_int64), 0, 0, true}, + {"invalid year becomes zero", yearType, tree.NewNumVal("2156", "2156", false, tree.P_char), 0, 0, true}, + {"valid year uses normal conversion", yearType, tree.NewNumVal("2024", "2024", false, tree.P_char), 0, 0, false}, + {"null uses normal conversion", enumType, tree.NewNumVal("", "", false, tree.P_null), 0, 0, false}, + } { + t.Run(tc.name, func(t *testing.T) { + expr, handled, err := makeInsertIgnoreMySQLSpecialTypeConstExpr(ctx, tc.value, tc.target) + require.NoError(t, err) + require.Equal(t, tc.handled, handled) + if !handled { + require.Nil(t, expr) + return + } + require.NotNil(t, expr) + if tc.target.Id == int32(types.T_enum) { + require.Equal(t, tc.wantEnum, expr.GetLit().GetEnumVal()) + } + if tc.target.Id == int32(types.T_uint64) { + require.Equal(t, tc.wantSet, expr.GetLit().GetU64Val()) + } + }) + } + + require.True(t, mysqlYearLiteralIsValid(tree.NewNumVal(int64(2024), "2024", false, tree.P_int64))) + require.False(t, mysqlYearLiteralIsValid(tree.NewNumVal(uint64(^uint64(0)), "18446744073709551615", false, tree.P_uint64))) + require.True(t, mysqlYearLiteralIsValid(tree.NewNumVal("ignored", "ignored", false, tree.P_hexnum))) + require.Equal(t, uint64(7), mysqlSetValidBitmap("x,y,z")) + require.Equal(t, ^uint64(0), mysqlSetValidBitmap(strings.Repeat("x,", types.MaxSetMembers-1)+"x")) +} + +func TestMySQLSpecialOrderTypeReversibility(t *testing.T) { + enum := &plan.Type{Id: int32(types.T_enum), Enumvalues: "a,b,c"} + duplicateEnum := &plan.Type{Id: int32(types.T_enum), Enumvalues: "a,A"} + set := &plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,y"} + ambiguousSet := &plan.Type{Id: int32(types.T_uint64), Enumvalues: "x,"} + + require.True(t, mysqlSpecialOrderTypeReversible(enum)) + require.False(t, mysqlSpecialOrderTypeReversible(duplicateEnum)) + require.True(t, mysqlSpecialOrderTypeReversible(set)) + require.False(t, mysqlSpecialOrderTypeReversible(ambiguousSet)) + require.False(t, mysqlSpecialOrderTypeReversible(&plan.Type{Id: int32(types.T_varchar)})) + require.Equal(t, enumFoldKey("K"), enumFoldKey("K")) + require.True(t, mysqlSpecialOrderTypesCompatible(enum, DeepCopyType(enum))) + require.False(t, mysqlSpecialOrderTypesCompatible(enum, set)) + require.Error(t, newNonReversibleMySQLSpecialOrderError(context.Background())) +} + // TestGeomFromTextSRIDInResultType verifies that a constant SRID argument to // ST_GeomFromText lands in the result type's Width (since geometry cells store // bare WKB and SRID lives in the type). diff --git a/pkg/sql/util/eval_expr_util_test.go b/pkg/sql/util/eval_expr_util_test.go index 679c5c1d738e9..96b76c0df8a76 100644 --- a/pkg/sql/util/eval_expr_util_test.go +++ b/pkg/sql/util/eval_expr_util_test.go @@ -16,6 +16,7 @@ package util import ( "errors" + "math" "testing" "time" @@ -139,6 +140,164 @@ func TestBinaryToInt(t *testing.T) { require.Error(t, err) } +func TestSetInsertValueBitIgnoreAdjustment(t *testing.T) { + proc := testutil.NewProcess(t) + bit4 := types.New(types.T_bit, 4, 0) + bit64 := types.New(types.T_bit, 64, 0) + + tests := []struct { + name string + value *tree.NumVal + typ *types.Type + ignore bool + want uint64 + wantErr bool + }{ + { + name: "boolean converts to one", + value: tree.NewNumVal(true, "true", false, tree.P_bool), + typ: &bit4, + want: 1, + }, + { + name: "character bytes convert within width", + value: tree.NewNumVal("A", "A", false, tree.P_char), + typ: &bit4, + want: 15, + ignore: true, + }, + { + name: "positive integer converts within width", + value: tree.NewNumVal(int64(7), "7", false, tree.P_int64), + typ: &bit4, + want: 7, + }, + { + name: "unsigned integer converts within width", + value: tree.NewNumVal(uint64(8), "8", false, tree.P_uint64), + typ: &bit4, + want: 8, + }, + { + name: "hexadecimal literal converts", + value: tree.NewNumVal("0x0f", "0x0f", false, tree.P_hexnum), + typ: &bit4, + want: 15, + }, + { + name: "score binary converts", + value: tree.NewNumVal("1", "1", false, tree.P_ScoreBinary), + typ: &bit64, + want: 49, + }, + { + name: "floating value rounds within width", + value: tree.NewNumVal(7.6, "7.6", false, tree.P_float64), + typ: &bit4, + want: 8, + }, + { + name: "strict bit literal overflow fails", + value: tree.NewNumVal("0b11111", "0b11111", false, tree.P_bit), + typ: &bit4, + wantErr: true, + }, + { + name: "ignore bit literal overflow saturates", + value: tree.NewNumVal("0b11111", "0b11111", false, tree.P_bit), + typ: &bit4, + ignore: true, + want: 15, + }, + { + name: "ignore negative integer becomes zero", + value: tree.NewNumVal(int64(-1), "-1", false, tree.P_int64), + typ: &bit4, + ignore: true, + want: 0, + }, + { + name: "ignore bit64 floating upper boundary saturates", + value: tree.NewNumVal(math.Exp2(64), "18446744073709551616", false, tree.P_float64), + typ: &bit64, + ignore: true, + want: math.MaxUint64, + }, + { + name: "ignore negative floating value becomes zero", + value: tree.NewNumVal(-1.5, "-1.5", false, tree.P_float64), + typ: &bit4, + ignore: true, + want: 0, + }, + { + name: "false boolean converts to zero", + value: tree.NewNumVal(false, "false", false, tree.P_bool), + typ: &bit4, + want: 0, + }, + { + name: "character bytes convert without adjustment", + value: tree.NewNumVal("A", "A", false, tree.P_char), + typ: func() *types.Type { + typ := types.New(types.T_bit, 8, 0) + return &typ + }(), + want: 65, + }, + { + name: "long character literal fails", + value: tree.NewNumVal("123456789", "123456789", false, tree.P_char), + typ: &bit64, + wantErr: true, + }, + { + name: "strict integer overflow fails", + value: tree.NewNumVal(int64(16), "16", false, tree.P_int64), + typ: &bit4, + wantErr: true, + }, + { + name: "strict unsigned overflow fails", + value: tree.NewNumVal(uint64(16), "16", false, tree.P_uint64), + typ: &bit4, + wantErr: true, + }, + { + name: "strict hexadecimal overflow fails", + value: tree.NewNumVal("0x10", "0x10", false, tree.P_hexnum), + typ: &bit4, + wantErr: true, + }, + { + name: "strict score binary overflow fails", + value: tree.NewNumVal("1", "1", false, tree.P_ScoreBinary), + typ: &bit4, + wantErr: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + canInsert, got, err := SetInsertValueBit(proc, tc.value, tc.typ, tc.ignore) + if tc.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + require.True(t, canInsert) + require.Equal(t, tc.want, got) + }) + } + + require.Equal(t, uint64(0), bitMaxValue(0)) + require.Equal(t, uint64(15), bitMaxValue(4)) + require.Equal(t, uint64(math.MaxUint64), bitMaxValue(64)) + require.True(t, bitFloatOutOfRange(math.Inf(1), 4)) + require.True(t, bitFloatOutOfRange(math.Exp2(64), 64)) + require.False(t, bitFloatOutOfRange(15, 4)) +} + func TestScoreBinaryToInt(t *testing.T) { var val uint64 var err error From 106af34fdb2c5bdc804857fb55b239dd0deadde1 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Tue, 4 Aug 2026 17:34:36 +0800 Subject: [PATCH 21/22] update --- pkg/pb/pipeline/pipeline.pb.go | 1008 +++++++++-------- pkg/sql/compile/remoterunServer.go | 30 +- pkg/sql/compile/remoterunServer_test.go | 24 +- pkg/tests/dml/dml_test.go | 39 + pkg/vm/process/process_codec.go | 8 + pkg/vm/process/process_codec_test.go | 7 + proto/pipeline.proto | 3 + .../cases/dml/insert/insert_ignore.result | 182 +-- .../cases/dml/insert/insert_ignore.sql | 13 + 9 files changed, 719 insertions(+), 595 deletions(-) diff --git a/pkg/pb/pipeline/pipeline.pb.go b/pkg/pb/pipeline/pipeline.pb.go index 9025de3bb79f6..871f4ab42d173 100644 --- a/pkg/pb/pipeline/pipeline.pb.go +++ b/pkg/pb/pipeline/pipeline.pb.go @@ -5378,10 +5378,13 @@ type ProcessInfo struct { RemoteFragmentCounts map[string]uint32 `protobuf:"bytes,11,rep,name=remote_fragment_counts,json=remoteFragmentCounts,proto3" json:"remote_fragment_counts,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` // Unique physical execution attempt. Unlike the SQL statement ID, this // changes across retries and prepared-statement executions. - RemoteExecutionId []byte `protobuf:"bytes,12,opt,name=remote_execution_id,json=remoteExecutionId,proto3" json:"remote_execution_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + RemoteExecutionId []byte `protobuf:"bytes,12,opt,name=remote_execution_id,json=remoteExecutionId,proto3" json:"remote_execution_id,omitempty"` + // Statement-level INSERT IGNORE semantics used by casts in remote pipelines. + // Absent in messages from older CNs, which safely decodes as false. + StatementRuntimeIgnore bool `protobuf:"varint,13,opt,name=statement_runtime_ignore,json=statementRuntimeIgnore,proto3" json:"statement_runtime_ignore,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *ProcessInfo) Reset() { *m = ProcessInfo{} } @@ -5501,6 +5504,13 @@ func (m *ProcessInfo) GetRemoteExecutionId() []byte { return nil } +func (m *ProcessInfo) GetStatementRuntimeIgnore() bool { + if m != nil { + return m.StatementRuntimeIgnore + } + return false +} + type SessionInfo struct { User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` Host string `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"` @@ -6135,486 +6145,487 @@ func init() { func init() { proto.RegisterFile("pipeline.proto", fileDescriptor_7ac67a7adf3df9c7) } var fileDescriptor_7ac67a7adf3df9c7 = []byte{ - // 7656 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7c, 0x4d, 0x6f, 0x1c, 0xc9, - 0x92, 0xd8, 0x34, 0xfb, 0x3b, 0xba, 0x9b, 0x6c, 0x26, 0x29, 0xaa, 0x25, 0xcd, 0x8c, 0x34, 0x3d, - 0x23, 0x0d, 0x9f, 0x46, 0x43, 0x49, 0x9c, 0x99, 0xf7, 0x66, 0xdf, 0xdb, 0xb7, 0x6f, 0x29, 0x4a, - 0x9a, 0xe1, 0x7b, 0xa2, 0xc4, 0x2d, 0x52, 0x1e, 0x60, 0x00, 0xbb, 0x50, 0xac, 0xca, 0xee, 0xae, - 0x61, 0x75, 0x65, 0xa9, 0x32, 0x4b, 0x22, 0x75, 0xb1, 0x0f, 0x3e, 0xf9, 0xe2, 0xe3, 0xee, 0x71, - 0x01, 0xfb, 0xb0, 0xb6, 0x01, 0xfb, 0x60, 0x3c, 0xff, 0x04, 0x63, 0x61, 0xfb, 0xb0, 0xf0, 0xc1, - 0x47, 0xc3, 0x78, 0x7b, 0x34, 0x60, 0x18, 0x06, 0x6c, 0x2c, 0x60, 0x18, 0x30, 0x22, 0x32, 0xb3, - 0xaa, 0xba, 0x9b, 0x94, 0x66, 0xc6, 0xc6, 0x5e, 0x76, 0x4f, 0x5d, 0x19, 0x11, 0x99, 0x95, 0x15, - 0x19, 0x19, 0x11, 0x19, 0x11, 0xd9, 0xb0, 0x9c, 0x84, 0x09, 0x8f, 0xc2, 0x98, 0x6f, 0x25, 0xa9, - 0x50, 0x82, 0xb5, 0x6c, 0xfb, 0xea, 0xa7, 0xe3, 0x50, 0x4d, 0xb2, 0xe3, 0x2d, 0x5f, 0x4c, 0xef, - 0x8e, 0xc5, 0x58, 0xdc, 0x25, 0x82, 0xe3, 0x6c, 0x44, 0x2d, 0x6a, 0xd0, 0x93, 0xee, 0x78, 0x15, - 0x22, 0xe1, 0x9f, 0xd8, 0xe7, 0x24, 0xf2, 0x62, 0xf3, 0xbc, 0xa2, 0xc2, 0x29, 0x97, 0xca, 0x9b, - 0x26, 0x06, 0xd0, 0x56, 0xa7, 0x06, 0x37, 0xfc, 0xf7, 0x55, 0x68, 0xee, 0x73, 0x29, 0xbd, 0x31, - 0x67, 0x43, 0xa8, 0xca, 0x30, 0x18, 0x54, 0x6e, 0x54, 0x36, 0x97, 0xb7, 0xfb, 0x5b, 0xf9, 0xb4, - 0x0e, 0x95, 0xa7, 0x32, 0xe9, 0x20, 0x12, 0x69, 0xfc, 0x69, 0x30, 0x58, 0x9a, 0xa7, 0xd9, 0xe7, - 0x6a, 0x22, 0x02, 0x07, 0x91, 0xac, 0x0f, 0x55, 0x9e, 0xa6, 0x83, 0xea, 0x8d, 0xca, 0x66, 0xd7, - 0xc1, 0x47, 0xc6, 0xa0, 0x16, 0x78, 0xca, 0x1b, 0xd4, 0x08, 0x44, 0xcf, 0xec, 0x23, 0x58, 0x4e, - 0x52, 0xe1, 0xbb, 0x61, 0x3c, 0x12, 0x2e, 0x61, 0xeb, 0x84, 0xed, 0x22, 0x74, 0x2f, 0x1e, 0x89, - 0x87, 0x48, 0x35, 0x80, 0xa6, 0x17, 0x7b, 0xd1, 0x99, 0xe4, 0x83, 0x06, 0xa1, 0x6d, 0x93, 0x2d, - 0xc3, 0x52, 0x18, 0x0c, 0x9a, 0x37, 0x2a, 0x9b, 0x35, 0x67, 0x29, 0x0c, 0xf0, 0x1d, 0x59, 0x16, - 0x06, 0x83, 0x96, 0x7e, 0x07, 0x3e, 0xb3, 0x21, 0x74, 0x63, 0xce, 0x83, 0xa7, 0x42, 0x39, 0x3c, - 0x89, 0xce, 0x06, 0xed, 0x1b, 0x95, 0xcd, 0x96, 0x33, 0x03, 0x63, 0x57, 0xa1, 0x15, 0xf0, 0xe3, - 0x6c, 0xbc, 0x2f, 0xc7, 0x03, 0xb8, 0x51, 0xd9, 0x6c, 0x3b, 0x79, 0x9b, 0x1d, 0xc1, 0xe5, 0x94, - 0xbf, 0xc8, 0xb8, 0x54, 0x3c, 0x70, 0x15, 0xf7, 0xd2, 0x40, 0xbc, 0x8a, 0xdd, 0xa9, 0x08, 0xf8, - 0xa0, 0x43, 0x1c, 0x78, 0xb7, 0xcc, 0xa5, 0x94, 0x7b, 0xd3, 0x23, 0x43, 0xb4, 0x2f, 0x02, 0xee, - 0x5c, 0xca, 0x3b, 0x97, 0xc1, 0xcc, 0x81, 0x0d, 0xcf, 0xf7, 0x79, 0xb2, 0x38, 0x68, 0xf7, 0x7b, - 0x0c, 0xba, 0x6e, 0xfb, 0x96, 0xa1, 0x3f, 0xaf, 0xfd, 0xc9, 0x9f, 0x5e, 0x7f, 0x67, 0xf8, 0x1c, - 0xda, 0xbb, 0x22, 0x8e, 0xb9, 0xaf, 0x44, 0xca, 0xae, 0x43, 0xc7, 0x8e, 0xe3, 0x9a, 0x65, 0xad, - 0x3b, 0x60, 0x41, 0x7b, 0x01, 0xfb, 0x18, 0x56, 0x7c, 0x4b, 0xed, 0x86, 0x71, 0xc0, 0x4f, 0x69, - 0x5d, 0xeb, 0xce, 0x72, 0x0e, 0xde, 0x43, 0xe8, 0xf0, 0xdf, 0x56, 0xa1, 0x79, 0x38, 0xc9, 0x46, - 0xa3, 0x88, 0xb3, 0x8f, 0xa0, 0x67, 0x1e, 0x77, 0x45, 0xb4, 0x17, 0x9c, 0x9a, 0x71, 0x67, 0x81, - 0xec, 0x06, 0x74, 0x0c, 0xe0, 0xe8, 0x2c, 0xe1, 0x66, 0xd8, 0x32, 0x68, 0x76, 0x9c, 0xfd, 0x30, - 0x26, 0x71, 0xa9, 0x3a, 0xb3, 0xc0, 0x39, 0x2a, 0xef, 0x94, 0x24, 0x68, 0x96, 0xca, 0xa3, 0xb7, - 0xed, 0x44, 0xe1, 0x4b, 0xee, 0xf0, 0xf1, 0x6e, 0xac, 0x48, 0x8e, 0xea, 0x4e, 0x19, 0xc4, 0xb6, - 0xe1, 0x92, 0xd4, 0x5d, 0xdc, 0xd4, 0x8b, 0xc7, 0x5c, 0xba, 0x59, 0x18, 0xab, 0x9f, 0x7e, 0x3e, - 0x68, 0xdc, 0xa8, 0x6e, 0xd6, 0x9c, 0x35, 0x83, 0x74, 0x08, 0xf7, 0x9c, 0x50, 0xec, 0x1e, 0xac, - 0xcf, 0xf5, 0xd1, 0x5d, 0x9a, 0x37, 0xaa, 0x9b, 0x55, 0x87, 0xcd, 0x74, 0xd9, 0xa3, 0x1e, 0x8f, - 0x60, 0x35, 0xcd, 0x62, 0xdc, 0x6d, 0x8f, 0xc3, 0x48, 0xf1, 0xf4, 0x30, 0xe1, 0x3e, 0xc9, 0x63, - 0x67, 0xfb, 0xf2, 0x16, 0x6d, 0x48, 0x67, 0x1e, 0xed, 0x2c, 0xf6, 0x60, 0x77, 0x72, 0xe6, 0x3d, - 0x3a, 0x4d, 0x52, 0x12, 0xda, 0xce, 0x36, 0xe8, 0x01, 0x10, 0xe2, 0x94, 0xd1, 0xec, 0x36, 0xac, - 0x06, 0xa9, 0x17, 0xc6, 0xae, 0x17, 0x45, 0xee, 0x71, 0xe6, 0x9f, 0x70, 0x25, 0x49, 0x90, 0x5b, - 0xce, 0x0a, 0x21, 0x76, 0xa2, 0xe8, 0x81, 0x06, 0x0f, 0xff, 0x6a, 0x09, 0x5a, 0x0f, 0x43, 0x99, - 0x78, 0xca, 0x9f, 0xb0, 0xcb, 0xd0, 0x1c, 0x65, 0xb1, 0x5f, 0xc8, 0x46, 0x03, 0x9b, 0x7b, 0x01, - 0xfb, 0x7d, 0x58, 0x89, 0x84, 0xef, 0x45, 0x6e, 0x2e, 0x06, 0x83, 0xa5, 0x1b, 0xd5, 0xcd, 0xce, - 0xf6, 0x5a, 0x21, 0x98, 0xb9, 0x98, 0x39, 0xcb, 0x44, 0x5b, 0x88, 0xdd, 0x2f, 0xa1, 0x9f, 0xf2, - 0xa9, 0x50, 0xbc, 0xd4, 0xbd, 0x4a, 0xdd, 0x59, 0xd1, 0xfd, 0x9b, 0xd4, 0x4b, 0x9e, 0xa2, 0x34, - 0xaf, 0x68, 0xda, 0xa2, 0xfb, 0xfd, 0xd2, 0x4a, 0xf1, 0xb1, 0x1b, 0x06, 0xa7, 0x2e, 0xbd, 0x60, - 0x50, 0xbb, 0x51, 0xdd, 0xac, 0x17, 0x6c, 0xe7, 0xe3, 0xbd, 0xe0, 0xf4, 0x09, 0x62, 0xd8, 0x67, - 0xb0, 0x31, 0xdf, 0x45, 0x8f, 0x3a, 0xa8, 0x53, 0x9f, 0xb5, 0x99, 0x3e, 0x0e, 0xa1, 0xd8, 0x07, - 0xd0, 0xb5, 0x9d, 0x14, 0x8a, 0x68, 0x43, 0x0b, 0x8d, 0x2c, 0x89, 0xe8, 0x65, 0x68, 0x86, 0xd2, - 0x95, 0x61, 0x7c, 0x42, 0x6a, 0xa6, 0xe5, 0x34, 0x42, 0x79, 0x18, 0xc6, 0x27, 0xec, 0x0a, 0xb4, - 0x52, 0xee, 0x6b, 0x4c, 0x8b, 0x30, 0xcd, 0x94, 0xfb, 0x84, 0xba, 0x0c, 0xf8, 0xe8, 0xfa, 0x8a, - 0x1b, 0x65, 0xd3, 0x48, 0xb9, 0xbf, 0xab, 0xf8, 0x50, 0x42, 0x7d, 0x9f, 0xa7, 0x63, 0x8e, 0xfa, - 0x06, 0x3b, 0x1e, 0xfa, 0x5e, 0x4c, 0x7c, 0x6f, 0x39, 0x79, 0x1b, 0xb5, 0x5d, 0xe2, 0xa5, 0x2a, - 0xf4, 0x22, 0xda, 0x32, 0x2d, 0xc7, 0x36, 0xd9, 0x35, 0x68, 0x4b, 0xe5, 0xa5, 0x0a, 0xbf, 0x8e, - 0xb6, 0x4a, 0xdd, 0x69, 0x11, 0x00, 0x77, 0xdb, 0x65, 0x68, 0xf2, 0x38, 0x20, 0x54, 0x4d, 0xaf, - 0x24, 0x8f, 0x83, 0xbd, 0xe0, 0x74, 0xf8, 0xaf, 0x2b, 0xd0, 0xdb, 0xcf, 0x22, 0x15, 0xee, 0xa4, - 0xe3, 0x8c, 0x4f, 0x63, 0x85, 0x5a, 0xf2, 0x61, 0x28, 0x95, 0x79, 0x33, 0x3d, 0xb3, 0x4d, 0x68, - 0x7f, 0x95, 0x8a, 0x2c, 0x21, 0x69, 0xd3, 0x2b, 0x5d, 0x96, 0xb6, 0x02, 0x89, 0x92, 0xf9, 0x2c, - 0x0d, 0x78, 0xfa, 0xe0, 0x8c, 0x68, 0xab, 0x0b, 0xb4, 0x65, 0x34, 0x7b, 0x17, 0xda, 0x87, 0x3c, - 0xf1, 0x52, 0x0f, 0x45, 0xa0, 0x46, 0xaa, 0xb5, 0x00, 0xe0, 0xb7, 0x12, 0xf1, 0x5e, 0x60, 0x36, - 0xac, 0x6d, 0x0e, 0xff, 0x49, 0x05, 0xda, 0x3b, 0xe3, 0x71, 0xca, 0xc7, 0x9e, 0x22, 0x3d, 0x2f, - 0x12, 0x9a, 0x6f, 0xd5, 0x59, 0x12, 0x09, 0xd9, 0x12, 0xfc, 0x02, 0xcd, 0x20, 0x7a, 0x66, 0xef, - 0x43, 0x8d, 0x9f, 0x3f, 0x21, 0x82, 0xb3, 0x0d, 0x68, 0xf8, 0x22, 0x1e, 0x85, 0x63, 0x63, 0x81, - 0x4c, 0x8b, 0xfd, 0x1c, 0x3a, 0xfa, 0x49, 0xcb, 0x40, 0x9d, 0xd4, 0xef, 0x15, 0xdd, 0x3d, 0x9f, - 0xc1, 0x2e, 0x51, 0xa0, 0x44, 0x38, 0xe0, 0xe7, 0xcf, 0xc3, 0x7f, 0x5e, 0x85, 0x3a, 0x71, 0x06, - 0xd7, 0x06, 0x2d, 0x8a, 0xcb, 0x5f, 0x7a, 0x91, 0x5d, 0x52, 0x04, 0x3c, 0x7a, 0xe9, 0x45, 0xec, - 0x06, 0xd4, 0x71, 0x0a, 0xf2, 0x1c, 0xc6, 0x6a, 0x04, 0xbb, 0x05, 0x75, 0x7c, 0xbb, 0x9c, 0x9d, - 0x3d, 0xbe, 0xe3, 0x41, 0xed, 0xcf, 0xff, 0xf3, 0xf5, 0x77, 0x1c, 0x8d, 0x66, 0x1f, 0x43, 0xcd, - 0x1b, 0x8f, 0x25, 0x6d, 0x84, 0x99, 0xbd, 0x98, 0xcf, 0xd4, 0x21, 0x02, 0xf6, 0x05, 0xb4, 0xf5, - 0xa2, 0x23, 0x75, 0x9d, 0xa8, 0x2f, 0x97, 0x2c, 0x75, 0x59, 0x1e, 0x9c, 0x82, 0x12, 0x97, 0x2b, - 0x94, 0x46, 0xb3, 0xd0, 0x76, 0x68, 0x39, 0x05, 0x00, 0x4d, 0x69, 0x92, 0xf2, 0x9d, 0x28, 0x12, - 0xfe, 0x61, 0xf8, 0x9a, 0x1b, 0xc3, 0x3b, 0x03, 0x63, 0xb7, 0x60, 0xf9, 0x40, 0xcb, 0xab, 0xc3, - 0x65, 0x16, 0x29, 0x69, 0x8c, 0xf1, 0x1c, 0x94, 0x6d, 0x01, 0x9b, 0x81, 0x1c, 0xd1, 0xe7, 0xb7, - 0x6f, 0x54, 0x37, 0x7b, 0xce, 0x39, 0x18, 0xf6, 0x21, 0xf4, 0xc6, 0xc8, 0xe9, 0x30, 0x1e, 0xbb, - 0xa3, 0xc8, 0x43, 0x3b, 0x5d, 0x45, 0x3b, 0x6e, 0x81, 0x8f, 0x23, 0x6f, 0x4c, 0x3b, 0x24, 0x09, - 0xa3, 0xc8, 0x9d, 0xf2, 0x29, 0x59, 0xe7, 0xaa, 0xd3, 0x22, 0xc0, 0x3e, 0x9f, 0x0e, 0xff, 0x45, - 0x0d, 0x1a, 0x7b, 0xb1, 0xe4, 0xa9, 0xc2, 0xfd, 0xe7, 0x8d, 0x46, 0xdc, 0x57, 0x5c, 0xeb, 0xbd, - 0x9a, 0x93, 0xb7, 0x91, 0x05, 0x47, 0xe2, 0x9b, 0x34, 0x54, 0xfc, 0xf0, 0x33, 0x23, 0x60, 0x05, - 0x00, 0x35, 0xad, 0x17, 0x04, 0xae, 0xa5, 0x76, 0x53, 0xf1, 0x4a, 0xd2, 0x5e, 0x6c, 0x39, 0x2b, - 0x5e, 0x10, 0xec, 0x18, 0xb8, 0x23, 0x5e, 0x49, 0xf6, 0x01, 0x54, 0x53, 0x3e, 0x22, 0x71, 0xeb, - 0x6c, 0xaf, 0xe8, 0x25, 0x7d, 0x76, 0xfc, 0x1d, 0xf7, 0x95, 0xc3, 0x47, 0x0e, 0xe2, 0xd8, 0x3a, - 0xd4, 0x3d, 0xa5, 0x52, 0xbd, 0x44, 0x6d, 0x47, 0x37, 0xd8, 0x16, 0xac, 0xd1, 0x9e, 0x57, 0xa1, - 0x88, 0x5d, 0xe5, 0x1d, 0x47, 0x68, 0xbc, 0xa5, 0xb1, 0x53, 0xab, 0x39, 0xea, 0x08, 0x31, 0x7b, - 0x81, 0x44, 0xcb, 0x36, 0x4f, 0x1f, 0x7b, 0x53, 0x2e, 0xc9, 0x4c, 0xb5, 0x9d, 0xb5, 0xd9, 0x1e, - 0x4f, 0x11, 0x85, 0xfc, 0x2c, 0xfa, 0xa0, 0xd6, 0x68, 0xd1, 0x06, 0xec, 0xe6, 0x40, 0x54, 0x2a, - 0x97, 0xa0, 0x11, 0x4a, 0x97, 0xc7, 0x81, 0x51, 0x64, 0xf5, 0x50, 0x3e, 0x8a, 0x03, 0xf6, 0x09, - 0xb4, 0xf5, 0x5b, 0x02, 0x3e, 0x22, 0x33, 0xd3, 0xd9, 0x5e, 0x36, 0x12, 0x8b, 0xe0, 0x87, 0x7c, - 0xe4, 0xb4, 0x94, 0x79, 0x42, 0x17, 0x44, 0x09, 0x97, 0x9f, 0x2a, 0x9e, 0xc6, 0x5e, 0x44, 0xab, - 0xd2, 0x72, 0x40, 0x89, 0x47, 0x06, 0xc2, 0xbe, 0x80, 0xcb, 0x16, 0xeb, 0x4a, 0x35, 0x55, 0x6e, - 0x16, 0x87, 0xa7, 0x6e, 0xec, 0xc5, 0x82, 0x7c, 0xa1, 0xaa, 0xb3, 0x6e, 0xd1, 0x87, 0x6a, 0xaa, - 0x9e, 0xc7, 0xe1, 0xe9, 0x53, 0x2f, 0x16, 0x6c, 0x13, 0xfa, 0x79, 0x37, 0xf5, 0x9a, 0x3e, 0x78, - 0xd0, 0x23, 0x05, 0xb3, 0x6c, 0xe1, 0x47, 0xaf, 0xf1, 0x5b, 0xd1, 0x36, 0x94, 0x29, 0xc5, 0x68, - 0x24, 0xb9, 0x72, 0x25, 0xf7, 0x07, 0xcb, 0xf4, 0xcd, 0x6b, 0x05, 0xfd, 0x33, 0xc2, 0x1d, 0x72, - 0x7f, 0xf8, 0xdb, 0x0a, 0x74, 0x68, 0x5f, 0x3c, 0x4f, 0x02, 0x54, 0x41, 0x1f, 0x42, 0x6f, 0x76, - 0xd1, 0xb5, 0xdc, 0x74, 0xbd, 0xf2, 0x8a, 0x6f, 0x40, 0x63, 0xc7, 0x47, 0xe6, 0x91, 0xe0, 0xf4, - 0x1c, 0xd3, 0x62, 0x3f, 0x83, 0x95, 0x8c, 0x86, 0x71, 0x7d, 0x75, 0xea, 0x46, 0xa8, 0xba, 0xf4, - 0x46, 0x37, 0x52, 0xa1, 0xdf, 0xb1, 0xab, 0x4e, 0x9d, 0x5e, 0x66, 0x1f, 0x9f, 0xa0, 0x52, 0xbb, - 0x07, 0xeb, 0x29, 0x47, 0x89, 0x71, 0x5f, 0xf3, 0x54, 0xb8, 0x8a, 0x4f, 0x13, 0x91, 0x92, 0x21, - 0x44, 0x2e, 0x32, 0x8d, 0xfb, 0x96, 0xa7, 0xe2, 0xc8, 0x60, 0x86, 0xef, 0x41, 0x7d, 0x27, 0x4d, - 0xbd, 0x33, 0x12, 0x2d, 0x7c, 0x18, 0x54, 0xc8, 0x00, 0xea, 0xc6, 0xd0, 0x87, 0xea, 0xbe, 0x97, - 0xb0, 0x9b, 0xb0, 0x34, 0x4d, 0x08, 0xd3, 0xd9, 0xbe, 0x54, 0xd2, 0x0b, 0x5e, 0xb2, 0xb5, 0x9f, - 0x3c, 0x8a, 0x55, 0x7a, 0xe6, 0x2c, 0x4d, 0x93, 0xab, 0x5f, 0x40, 0xd3, 0x34, 0xd1, 0xa1, 0x3f, - 0xe1, 0x67, 0xf4, 0xd5, 0x6d, 0x07, 0x1f, 0xf1, 0x05, 0x2f, 0xbd, 0x28, 0xb3, 0x9e, 0x9d, 0x6e, - 0xfc, 0x7c, 0xe9, 0xcb, 0xca, 0xf0, 0x7f, 0xd6, 0xa0, 0xf5, 0x90, 0x47, 0x9c, 0xbe, 0x7d, 0x08, - 0xdd, 0xf2, 0xae, 0xb0, 0x7c, 0x9b, 0xd9, 0x29, 0x43, 0xe8, 0x6a, 0x93, 0x4c, 0xbd, 0xb8, 0xd9, - 0x76, 0x33, 0x30, 0xb4, 0x15, 0x7b, 0xda, 0x87, 0xa1, 0xfd, 0xd6, 0x73, 0x6c, 0x13, 0x31, 0x4f, - 0x0d, 0xa6, 0xa6, 0x31, 0xa6, 0xc9, 0xde, 0x05, 0x48, 0xc5, 0x2b, 0x37, 0xd4, 0x76, 0x51, 0x9b, - 0x98, 0x56, 0x2a, 0x5e, 0xed, 0xa1, 0x65, 0xfc, 0x6b, 0xd9, 0x66, 0x3f, 0x83, 0x41, 0x69, 0x9b, - 0xa1, 0x27, 0xed, 0x86, 0xb1, 0x7b, 0x8c, 0xce, 0x97, 0xd9, 0x71, 0xc5, 0x98, 0xe4, 0x68, 0xef, - 0xc5, 0x0f, 0xc8, 0x33, 0x33, 0xca, 0xa3, 0xfd, 0x06, 0xe5, 0x71, 0xae, 0x2e, 0x82, 0xf3, 0x75, - 0xd1, 0x03, 0x80, 0x43, 0x3e, 0x9e, 0xf2, 0x58, 0xed, 0x7b, 0xc9, 0xa0, 0x43, 0x0b, 0x3f, 0x2c, - 0x16, 0xde, 0xae, 0xd6, 0x56, 0x41, 0xa4, 0xa5, 0xa0, 0xd4, 0x0b, 0xdd, 0x25, 0xdf, 0x8b, 0x5d, - 0x95, 0x66, 0xb1, 0xef, 0x29, 0x7d, 0x52, 0x69, 0x39, 0x1d, 0xdf, 0x8b, 0x8f, 0x0c, 0xa8, 0xa4, - 0x30, 0x7a, 0x65, 0x85, 0x71, 0x0b, 0x56, 0x92, 0x34, 0x9c, 0x7a, 0xe9, 0x99, 0x7b, 0xc2, 0xcf, - 0x68, 0x31, 0xf4, 0xd6, 0xeb, 0x19, 0xf0, 0x6f, 0xf8, 0xd9, 0x5e, 0x70, 0x7a, 0xf5, 0x97, 0xb0, - 0x32, 0x37, 0x81, 0x1f, 0x24, 0x77, 0xff, 0xb1, 0x0a, 0xed, 0x83, 0x94, 0x1b, 0x25, 0x7f, 0x1d, - 0x3a, 0xd2, 0x9f, 0xf0, 0xa9, 0xa7, 0x75, 0x83, 0x1e, 0x01, 0x34, 0x88, 0xf4, 0xc2, 0x8c, 0x1a, - 0x5b, 0x7a, 0x8b, 0x1a, 0xeb, 0x43, 0x55, 0xbb, 0x5d, 0xb8, 0x99, 0xf0, 0xb1, 0xd0, 0xdd, 0xb5, - 0xb2, 0xee, 0xbe, 0x01, 0xdd, 0x89, 0x27, 0x5d, 0x2f, 0x53, 0xc2, 0xf5, 0x45, 0x44, 0x42, 0xd7, - 0x72, 0x60, 0xe2, 0xc9, 0x9d, 0x4c, 0x89, 0x5d, 0x11, 0xb1, 0xf7, 0x00, 0x7c, 0x11, 0x19, 0x35, - 0x64, 0x7c, 0xce, 0xb6, 0x2f, 0x22, 0xad, 0x7b, 0x50, 0x2a, 0xb9, 0x54, 0xe1, 0xd4, 0x33, 0x4b, - 0xea, 0xfa, 0x22, 0x8b, 0x15, 0xd9, 0xda, 0xaa, 0xb3, 0x9a, 0xa3, 0x1c, 0xf1, 0x6a, 0x17, 0x11, - 0xec, 0x1e, 0x2c, 0xfb, 0x62, 0x9a, 0xb8, 0x09, 0x72, 0x96, 0x3c, 0xa0, 0xd6, 0xc2, 0x61, 0xa1, - 0x8b, 0x14, 0x07, 0x27, 0x5c, 0xfb, 0x64, 0xdb, 0xb0, 0xe2, 0x47, 0x99, 0x54, 0x3c, 0x75, 0x8f, - 0x4d, 0x97, 0xc5, 0xf3, 0x45, 0xcf, 0x90, 0x18, 0x3f, 0x6e, 0x08, 0xbd, 0x50, 0xba, 0x22, 0x0a, - 0x5c, 0xad, 0xa0, 0x8c, 0x9c, 0x75, 0x42, 0xf9, 0x2c, 0x0a, 0x8c, 0x8a, 0xd4, 0x34, 0x31, 0x7f, - 0x65, 0x69, 0x3a, 0x96, 0xe6, 0x29, 0x7f, 0x65, 0x68, 0x2e, 0x52, 0x68, 0xdd, 0x0b, 0x15, 0xda, - 0x7f, 0x5a, 0x82, 0xe6, 0x81, 0x90, 0xea, 0xe1, 0x34, 0xb2, 0x9b, 0xa2, 0xf2, 0x43, 0x37, 0xc5, - 0xd2, 0xf9, 0x9b, 0xe2, 0x1c, 0xb1, 0xac, 0x9e, 0x23, 0x96, 0x68, 0x6a, 0xca, 0x74, 0x24, 0x4e, - 0xda, 0x97, 0x5d, 0x2e, 0x08, 0x49, 0xa4, 0xae, 0xa1, 0xff, 0xe4, 0x06, 0x5a, 0x8b, 0xe9, 0xa5, - 0x6f, 0x85, 0xd2, 0x68, 0x30, 0x8d, 0x0c, 0x49, 0x3a, 0x8d, 0x73, 0xd5, 0x0a, 0xa5, 0x91, 0xd6, - 0xdf, 0x83, 0x2b, 0x79, 0x4f, 0xf7, 0x55, 0xa8, 0x26, 0x22, 0x53, 0xee, 0x88, 0x0e, 0x84, 0xd2, - 0x1c, 0x3d, 0x36, 0xec, 0x48, 0xdf, 0x68, 0xb4, 0x3e, 0x2e, 0x92, 0xaf, 0x37, 0xca, 0xa2, 0xc8, - 0x55, 0xfc, 0x54, 0x99, 0xc5, 0x1f, 0x68, 0xde, 0x18, 0xbe, 0x3d, 0xce, 0xa2, 0xe8, 0x88, 0x9f, - 0x2a, 0x34, 0x30, 0xad, 0x91, 0x69, 0x0c, 0xff, 0xb8, 0x06, 0xf0, 0x44, 0xf8, 0x27, 0x47, 0x5e, - 0x3a, 0xe6, 0x0a, 0x0f, 0x34, 0x56, 0x07, 0x1a, 0x1d, 0xdd, 0x54, 0x5a, 0xf3, 0xb1, 0x6d, 0xd8, - 0xb0, 0xdf, 0x8f, 0x92, 0x8b, 0x87, 0x2b, 0xad, 0xc4, 0xcc, 0x16, 0x64, 0x06, 0xab, 0x0f, 0xfe, - 0xa4, 0xc1, 0xd8, 0x97, 0x05, 0x6f, 0xb1, 0x8f, 0x3a, 0x4b, 0x88, 0xb7, 0xe7, 0xf9, 0xb6, 0xbd, - 0xa2, 0xfb, 0xd1, 0x59, 0xc2, 0xee, 0xc1, 0xa5, 0x94, 0x8f, 0x52, 0x2e, 0x27, 0xae, 0x92, 0xe5, - 0x97, 0xe9, 0x73, 0xcd, 0xaa, 0x41, 0x1e, 0xc9, 0xfc, 0x5d, 0xf7, 0xe0, 0x92, 0xe6, 0xd4, 0xfc, - 0xf4, 0xb4, 0xc6, 0x5f, 0xd5, 0xc8, 0xf2, 0xec, 0xde, 0x03, 0x0a, 0x94, 0x69, 0x2d, 0x6e, 0x1d, - 0xdd, 0x88, 0x98, 0x71, 0x1c, 0x71, 0xf4, 0x01, 0x77, 0x27, 0x78, 0xa8, 0x7f, 0xc8, 0x47, 0x86, - 0xf9, 0x05, 0x80, 0x0d, 0xa1, 0xb6, 0x2f, 0x02, 0x4e, 0xac, 0x5e, 0xde, 0x5e, 0xde, 0xa2, 0x90, - 0x1b, 0x72, 0x92, 0x62, 0x33, 0x84, 0x63, 0x1f, 0x03, 0x0d, 0xa7, 0xc5, 0x6f, 0x71, 0x77, 0xb5, - 0x10, 0x49, 0x32, 0x78, 0x0f, 0x2e, 0x15, 0x33, 0x71, 0x3d, 0xe5, 0xaa, 0x09, 0x27, 0x05, 0xaa, - 0x37, 0xd8, 0x6a, 0x3e, 0xa9, 0x1d, 0x75, 0x34, 0xe1, 0xa8, 0x4c, 0x37, 0xa1, 0x29, 0x8e, 0xbf, - 0x73, 0x71, 0x23, 0x74, 0xce, 0xdf, 0x08, 0x0d, 0x71, 0xfc, 0x9d, 0xc3, 0x47, 0xec, 0xa7, 0x65, - 0xe3, 0x33, 0xc7, 0x9a, 0x2e, 0xb1, 0x66, 0x3d, 0xc7, 0x97, 0xb8, 0x33, 0xfc, 0x12, 0x1a, 0xf8, - 0x39, 0xcf, 0x12, 0xb6, 0x05, 0x4d, 0x45, 0xe2, 0x21, 0x8d, 0xb3, 0xb0, 0x5e, 0xd8, 0x8c, 0x42, - 0x76, 0x1c, 0x4b, 0x34, 0x74, 0x60, 0x25, 0x57, 0xc0, 0xcf, 0xe3, 0xf0, 0x45, 0xc6, 0xd9, 0xaf, - 0x60, 0x35, 0x49, 0xb9, 0x11, 0x7b, 0x37, 0x3b, 0x41, 0x17, 0xc8, 0xec, 0xe0, 0x75, 0x23, 0xa5, - 0x79, 0x8f, 0x13, 0x94, 0xd0, 0xe5, 0x64, 0xa6, 0x3d, 0xfc, 0x16, 0x2e, 0xe7, 0x14, 0x87, 0xdc, - 0x17, 0x71, 0xe0, 0xa5, 0x67, 0x64, 0x2b, 0xe7, 0xc6, 0x96, 0x3f, 0x64, 0xec, 0x43, 0x1a, 0xfb, - 0xbf, 0x57, 0xa0, 0xf3, 0x38, 0x7b, 0xfd, 0xfa, 0x4c, 0xef, 0x25, 0xd6, 0x85, 0xca, 0x53, 0x1a, - 0x60, 0xc9, 0xa9, 0x3c, 0x45, 0x77, 0xee, 0xe0, 0x04, 0xf7, 0x35, 0xc9, 0x79, 0xdb, 0x31, 0x2d, - 0x3c, 0xad, 0x1d, 0x9c, 0x1c, 0xbd, 0x41, 0xa2, 0x35, 0x1a, 0x8f, 0x19, 0x0f, 0xb2, 0x30, 0x42, - 0x67, 0xc3, 0x08, 0x6f, 0xde, 0xc6, 0xf3, 0xcf, 0xde, 0x48, 0x4f, 0xe5, 0x71, 0x2a, 0xa6, 0x9a, - 0x59, 0x46, 0x65, 0x9c, 0x83, 0x61, 0x5f, 0xc1, 0x9a, 0x89, 0x12, 0x19, 0xad, 0xe0, 0xca, 0x84, - 0xfb, 0x24, 0xba, 0x3f, 0x28, 0xb2, 0x34, 0xfc, 0xab, 0x1a, 0xb4, 0xbe, 0xf6, 0xe4, 0xe4, 0xd7, - 0x22, 0x8c, 0xd9, 0x3d, 0x68, 0x7f, 0x27, 0xc2, 0x58, 0x1f, 0x7d, 0x75, 0xd0, 0x77, 0x4d, 0x8f, - 0xf5, 0x54, 0x04, 0x7c, 0x0b, 0x69, 0xe8, 0xd0, 0xdb, 0xfa, 0xce, 0x3c, 0x19, 0x25, 0x9f, 0x86, - 0xe3, 0x89, 0x72, 0x11, 0x68, 0x74, 0x6b, 0x27, 0x94, 0x0e, 0xc2, 0x68, 0xd4, 0x77, 0x01, 0xed, - 0xdd, 0xc4, 0x15, 0xb1, 0x9b, 0x9c, 0x98, 0xd3, 0x51, 0x0b, 0x21, 0xcf, 0xe2, 0x83, 0x13, 0xdc, - 0x7b, 0xa1, 0x74, 0x4d, 0x90, 0xc5, 0x78, 0xb2, 0xa5, 0x43, 0xe6, 0x47, 0xb0, 0x8c, 0x5e, 0x86, - 0x3c, 0x09, 0x13, 0x37, 0x49, 0xc5, 0xb1, 0x65, 0x0a, 0xfa, 0x1e, 0x87, 0x27, 0x61, 0x72, 0x80, - 0x30, 0x32, 0xee, 0x26, 0x74, 0x83, 0x6a, 0x5b, 0x5b, 0x51, 0x30, 0x20, 0xe4, 0x2f, 0xc5, 0x67, - 0x22, 0xed, 0x6b, 0x37, 0xc9, 0x68, 0x37, 0x53, 0x1e, 0x91, 0x53, 0x7d, 0x05, 0x5a, 0xb8, 0x19, - 0x08, 0xd5, 0xd2, 0x28, 0x5f, 0x68, 0xd4, 0x4f, 0x00, 0x22, 0x3e, 0x52, 0x2e, 0x4a, 0x99, 0x3e, - 0x8d, 0xce, 0xc5, 0x41, 0x10, 0xbb, 0x8b, 0x48, 0xf6, 0x09, 0x74, 0x34, 0x17, 0x34, 0x2d, 0x2c, - 0xd0, 0x02, 0xa1, 0x35, 0xf1, 0x6d, 0xe8, 0xc4, 0x22, 0x76, 0xf9, 0x0b, 0xa2, 0x36, 0xfb, 0x76, + // 7679 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7c, 0xcf, 0x6f, 0x1c, 0xc7, + 0x9a, 0x98, 0x87, 0xf3, 0xfb, 0x9b, 0x19, 0x72, 0x58, 0xa4, 0xa8, 0x91, 0x64, 0x5b, 0xf2, 0xd8, + 0x92, 0xf9, 0x64, 0x99, 0x92, 0x68, 0xfb, 0x3d, 0xef, 0x7b, 0xfb, 0xf6, 0x2d, 0x45, 0x49, 0x36, + 0xdf, 0x13, 0x25, 0x6e, 0x93, 0x8a, 0x01, 0x03, 0x49, 0xa3, 0xd9, 0x5d, 0x33, 0xd3, 0x66, 0x4f, + 0x57, 0xab, 0xab, 0x5a, 0x22, 0x75, 0x49, 0x0e, 0x39, 0xe5, 0x92, 0xe3, 0xee, 0x71, 0x81, 0xe4, + 0xb0, 0x49, 0x0e, 0x39, 0x04, 0x2f, 0x7f, 0x42, 0xb0, 0x48, 0x72, 0x58, 0xe4, 0x90, 0x63, 0x10, + 0xbc, 0xbd, 0x04, 0x08, 0x10, 0x04, 0x01, 0x12, 0x2c, 0x10, 0x04, 0x08, 0xbe, 0xaf, 0xaa, 0xba, + 0x7b, 0x66, 0x48, 0xc9, 0x76, 0x82, 0xbd, 0xec, 0x9e, 0xa6, 0xeb, 0xfb, 0xbe, 0xaa, 0xae, 0xae, + 0xfa, 0xea, 0xfb, 0x5d, 0x03, 0xcb, 0x49, 0x98, 0xf0, 0x28, 0x8c, 0xf9, 0x56, 0x92, 0x0a, 0x25, + 0x58, 0xcb, 0xb6, 0xaf, 0x7e, 0x3a, 0x0e, 0xd5, 0x24, 0x3b, 0xde, 0xf2, 0xc5, 0xf4, 0xee, 0x58, + 0x8c, 0xc5, 0x5d, 0x22, 0x38, 0xce, 0x46, 0xd4, 0xa2, 0x06, 0x3d, 0xe9, 0x8e, 0x57, 0x21, 0x12, + 0xfe, 0x89, 0x7d, 0x4e, 0x22, 0x2f, 0x36, 0xcf, 0x2b, 0x2a, 0x9c, 0x72, 0xa9, 0xbc, 0x69, 0x62, + 0x00, 0x6d, 0x75, 0x6a, 0x70, 0xc3, 0x7f, 0x57, 0x85, 0xe6, 0x3e, 0x97, 0xd2, 0x1b, 0x73, 0x36, + 0x84, 0xaa, 0x0c, 0x83, 0x41, 0xe5, 0x46, 0x65, 0x73, 0x79, 0xbb, 0xbf, 0x95, 0x4f, 0xeb, 0x50, + 0x79, 0x2a, 0x93, 0x0e, 0x22, 0x91, 0xc6, 0x9f, 0x06, 0x83, 0xa5, 0x79, 0x9a, 0x7d, 0xae, 0x26, + 0x22, 0x70, 0x10, 0xc9, 0xfa, 0x50, 0xe5, 0x69, 0x3a, 0xa8, 0xde, 0xa8, 0x6c, 0x76, 0x1d, 0x7c, + 0x64, 0x0c, 0x6a, 0x81, 0xa7, 0xbc, 0x41, 0x8d, 0x40, 0xf4, 0xcc, 0x3e, 0x82, 0xe5, 0x24, 0x15, + 0xbe, 0x1b, 0xc6, 0x23, 0xe1, 0x12, 0xb6, 0x4e, 0xd8, 0x2e, 0x42, 0xf7, 0xe2, 0x91, 0x78, 0x88, + 0x54, 0x03, 0x68, 0x7a, 0xb1, 0x17, 0x9d, 0x49, 0x3e, 0x68, 0x10, 0xda, 0x36, 0xd9, 0x32, 0x2c, + 0x85, 0xc1, 0xa0, 0x79, 0xa3, 0xb2, 0x59, 0x73, 0x96, 0xc2, 0x00, 0xdf, 0x91, 0x65, 0x61, 0x30, + 0x68, 0xe9, 0x77, 0xe0, 0x33, 0x1b, 0x42, 0x37, 0xe6, 0x3c, 0x78, 0x2a, 0x94, 0xc3, 0x93, 0xe8, + 0x6c, 0xd0, 0xbe, 0x51, 0xd9, 0x6c, 0x39, 0x33, 0x30, 0x76, 0x15, 0x5a, 0x01, 0x3f, 0xce, 0xc6, + 0xfb, 0x72, 0x3c, 0x80, 0x1b, 0x95, 0xcd, 0xb6, 0x93, 0xb7, 0xd9, 0x11, 0x5c, 0x4e, 0xf9, 0x8b, + 0x8c, 0x4b, 0xc5, 0x03, 0x57, 0x71, 0x2f, 0x0d, 0xc4, 0xab, 0xd8, 0x9d, 0x8a, 0x80, 0x0f, 0x3a, + 0xb4, 0x02, 0xef, 0x96, 0x57, 0x29, 0xe5, 0xde, 0xf4, 0xc8, 0x10, 0xed, 0x8b, 0x80, 0x3b, 0x97, + 0xf2, 0xce, 0x65, 0x30, 0x73, 0x60, 0xc3, 0xf3, 0x7d, 0x9e, 0x2c, 0x0e, 0xda, 0xfd, 0x1e, 0x83, + 0xae, 0xdb, 0xbe, 0x65, 0xe8, 0xcf, 0x6b, 0x7f, 0xf2, 0xa7, 0xd7, 0xdf, 0x19, 0x3e, 0x87, 0xf6, + 0xae, 0x88, 0x63, 0xee, 0x2b, 0x91, 0xb2, 0xeb, 0xd0, 0xb1, 0xe3, 0xb8, 0x66, 0x5b, 0xeb, 0x0e, + 0x58, 0xd0, 0x5e, 0xc0, 0x3e, 0x86, 0x15, 0xdf, 0x52, 0xbb, 0x61, 0x1c, 0xf0, 0x53, 0xda, 0xd7, + 0xba, 0xb3, 0x9c, 0x83, 0xf7, 0x10, 0x3a, 0xfc, 0x37, 0x55, 0x68, 0x1e, 0x4e, 0xb2, 0xd1, 0x28, + 0xe2, 0xec, 0x23, 0xe8, 0x99, 0xc7, 0x5d, 0x11, 0xed, 0x05, 0xa7, 0x66, 0xdc, 0x59, 0x20, 0xbb, + 0x01, 0x1d, 0x03, 0x38, 0x3a, 0x4b, 0xb8, 0x19, 0xb6, 0x0c, 0x9a, 0x1d, 0x67, 0x3f, 0x8c, 0x89, + 0x5d, 0xaa, 0xce, 0x2c, 0x70, 0x8e, 0xca, 0x3b, 0x25, 0x0e, 0x9a, 0xa5, 0xf2, 0xe8, 0x6d, 0x3b, + 0x51, 0xf8, 0x92, 0x3b, 0x7c, 0xbc, 0x1b, 0x2b, 0xe2, 0xa3, 0xba, 0x53, 0x06, 0xb1, 0x6d, 0xb8, + 0x24, 0x75, 0x17, 0x37, 0xf5, 0xe2, 0x31, 0x97, 0x6e, 0x16, 0xc6, 0xea, 0xa7, 0x9f, 0x0f, 0x1a, + 0x37, 0xaa, 0x9b, 0x35, 0x67, 0xcd, 0x20, 0x1d, 0xc2, 0x3d, 0x27, 0x14, 0xbb, 0x07, 0xeb, 0x73, + 0x7d, 0x74, 0x97, 0xe6, 0x8d, 0xea, 0x66, 0xd5, 0x61, 0x33, 0x5d, 0xf6, 0xa8, 0xc7, 0x23, 0x58, + 0x4d, 0xb3, 0x18, 0x4f, 0xdb, 0xe3, 0x30, 0x52, 0x3c, 0x3d, 0x4c, 0xb8, 0x4f, 0xfc, 0xd8, 0xd9, + 0xbe, 0xbc, 0x45, 0x07, 0xd2, 0x99, 0x47, 0x3b, 0x8b, 0x3d, 0xd8, 0x9d, 0x7c, 0xf1, 0x1e, 0x9d, + 0x26, 0x29, 0x31, 0x6d, 0x67, 0x1b, 0xf4, 0x00, 0x08, 0x71, 0xca, 0x68, 0x76, 0x1b, 0x56, 0x83, + 0xd4, 0x0b, 0x63, 0xd7, 0x8b, 0x22, 0xf7, 0x38, 0xf3, 0x4f, 0xb8, 0x92, 0xc4, 0xc8, 0x2d, 0x67, + 0x85, 0x10, 0x3b, 0x51, 0xf4, 0x40, 0x83, 0x87, 0x7f, 0xb5, 0x04, 0xad, 0x87, 0xa1, 0x4c, 0x3c, + 0xe5, 0x4f, 0xd8, 0x65, 0x68, 0x8e, 0xb2, 0xd8, 0x2f, 0x78, 0xa3, 0x81, 0xcd, 0xbd, 0x80, 0xfd, + 0x3e, 0xac, 0x44, 0xc2, 0xf7, 0x22, 0x37, 0x67, 0x83, 0xc1, 0xd2, 0x8d, 0xea, 0x66, 0x67, 0x7b, + 0xad, 0x60, 0xcc, 0x9c, 0xcd, 0x9c, 0x65, 0xa2, 0x2d, 0xd8, 0xee, 0x97, 0xd0, 0x4f, 0xf9, 0x54, + 0x28, 0x5e, 0xea, 0x5e, 0xa5, 0xee, 0xac, 0xe8, 0xfe, 0x4d, 0xea, 0x25, 0x4f, 0x91, 0x9b, 0x57, + 0x34, 0x6d, 0xd1, 0xfd, 0x7e, 0x69, 0xa7, 0xf8, 0xd8, 0x0d, 0x83, 0x53, 0x97, 0x5e, 0x30, 0xa8, + 0xdd, 0xa8, 0x6e, 0xd6, 0x8b, 0x65, 0xe7, 0xe3, 0xbd, 0xe0, 0xf4, 0x09, 0x62, 0xd8, 0x67, 0xb0, + 0x31, 0xdf, 0x45, 0x8f, 0x3a, 0xa8, 0x53, 0x9f, 0xb5, 0x99, 0x3e, 0x0e, 0xa1, 0xd8, 0x07, 0xd0, + 0xb5, 0x9d, 0x14, 0xb2, 0x68, 0x43, 0x33, 0x8d, 0x2c, 0xb1, 0xe8, 0x65, 0x68, 0x86, 0xd2, 0x95, + 0x61, 0x7c, 0x42, 0x62, 0xa6, 0xe5, 0x34, 0x42, 0x79, 0x18, 0xc6, 0x27, 0xec, 0x0a, 0xb4, 0x52, + 0xee, 0x6b, 0x4c, 0x8b, 0x30, 0xcd, 0x94, 0xfb, 0x84, 0xba, 0x0c, 0xf8, 0xe8, 0xfa, 0x8a, 0x1b, + 0x61, 0xd3, 0x48, 0xb9, 0xbf, 0xab, 0xf8, 0x50, 0x42, 0x7d, 0x9f, 0xa7, 0x63, 0x8e, 0xf2, 0x06, + 0x3b, 0x1e, 0xfa, 0x5e, 0x4c, 0xeb, 0xde, 0x72, 0xf2, 0x36, 0x4a, 0xbb, 0xc4, 0x4b, 0x55, 0xe8, + 0x45, 0x74, 0x64, 0x5a, 0x8e, 0x6d, 0xb2, 0x6b, 0xd0, 0x96, 0xca, 0x4b, 0x15, 0x7e, 0x1d, 0x1d, + 0x95, 0xba, 0xd3, 0x22, 0x00, 0x9e, 0xb6, 0xcb, 0xd0, 0xe4, 0x71, 0x40, 0xa8, 0x9a, 0xde, 0x49, + 0x1e, 0x07, 0x7b, 0xc1, 0xe9, 0xf0, 0x5f, 0x55, 0xa0, 0xb7, 0x9f, 0x45, 0x2a, 0xdc, 0x49, 0xc7, + 0x19, 0x9f, 0xc6, 0x0a, 0xa5, 0xe4, 0xc3, 0x50, 0x2a, 0xf3, 0x66, 0x7a, 0x66, 0x9b, 0xd0, 0xfe, + 0x2a, 0x15, 0x59, 0x42, 0xdc, 0xa6, 0x77, 0xba, 0xcc, 0x6d, 0x05, 0x12, 0x39, 0xf3, 0x59, 0x1a, + 0xf0, 0xf4, 0xc1, 0x19, 0xd1, 0x56, 0x17, 0x68, 0xcb, 0x68, 0xf6, 0x2e, 0xb4, 0x0f, 0x79, 0xe2, + 0xa5, 0x1e, 0xb2, 0x40, 0x8d, 0x44, 0x6b, 0x01, 0xc0, 0x6f, 0x25, 0xe2, 0xbd, 0xc0, 0x1c, 0x58, + 0xdb, 0x1c, 0xfe, 0x93, 0x0a, 0xb4, 0x77, 0xc6, 0xe3, 0x94, 0x8f, 0x3d, 0x45, 0x72, 0x5e, 0x24, + 0x34, 0xdf, 0xaa, 0xb3, 0x24, 0x12, 0xd2, 0x25, 0xf8, 0x05, 0x7a, 0x81, 0xe8, 0x99, 0xbd, 0x0f, + 0x35, 0x7e, 0xfe, 0x84, 0x08, 0xce, 0x36, 0xa0, 0xe1, 0x8b, 0x78, 0x14, 0x8e, 0x8d, 0x06, 0x32, + 0x2d, 0xf6, 0x73, 0xe8, 0xe8, 0x27, 0xcd, 0x03, 0x75, 0x12, 0xbf, 0x57, 0x74, 0xf7, 0x7c, 0x06, + 0xbb, 0x44, 0x81, 0x1c, 0xe1, 0x80, 0x9f, 0x3f, 0x0f, 0xff, 0x79, 0x15, 0xea, 0xb4, 0x32, 0xb8, + 0x37, 0xa8, 0x51, 0x5c, 0xfe, 0xd2, 0x8b, 0xec, 0x96, 0x22, 0xe0, 0xd1, 0x4b, 0x2f, 0x62, 0x37, + 0xa0, 0x8e, 0x53, 0x90, 0xe7, 0x2c, 0xac, 0x46, 0xb0, 0x5b, 0x50, 0xc7, 0xb7, 0xcb, 0xd9, 0xd9, + 0xe3, 0x3b, 0x1e, 0xd4, 0xfe, 0xfc, 0x3f, 0x5d, 0x7f, 0xc7, 0xd1, 0x68, 0xf6, 0x31, 0xd4, 0xbc, + 0xf1, 0x58, 0xd2, 0x41, 0x98, 0x39, 0x8b, 0xf9, 0x4c, 0x1d, 0x22, 0x60, 0x5f, 0x40, 0x5b, 0x6f, + 0x3a, 0x52, 0xd7, 0x89, 0xfa, 0x72, 0x49, 0x53, 0x97, 0xf9, 0xc1, 0x29, 0x28, 0x71, 0xbb, 0x42, + 0x69, 0x24, 0x0b, 0x1d, 0x87, 0x96, 0x53, 0x00, 0x50, 0x95, 0x26, 0x29, 0xdf, 0x89, 0x22, 0xe1, + 0x1f, 0x86, 0xaf, 0xb9, 0x51, 0xbc, 0x33, 0x30, 0x76, 0x0b, 0x96, 0x0f, 0x34, 0xbf, 0x3a, 0x5c, + 0x66, 0x91, 0x92, 0x46, 0x19, 0xcf, 0x41, 0xd9, 0x16, 0xb0, 0x19, 0xc8, 0x11, 0x7d, 0x7e, 0xfb, + 0x46, 0x75, 0xb3, 0xe7, 0x9c, 0x83, 0x61, 0x1f, 0x42, 0x6f, 0x8c, 0x2b, 0x1d, 0xc6, 0x63, 0x77, + 0x14, 0x79, 0xa8, 0xa7, 0xab, 0xa8, 0xc7, 0x2d, 0xf0, 0x71, 0xe4, 0x8d, 0xe9, 0x84, 0x24, 0x61, + 0x14, 0xb9, 0x53, 0x3e, 0x25, 0xed, 0x5c, 0x75, 0x5a, 0x04, 0xd8, 0xe7, 0xd3, 0xe1, 0xbf, 0xa8, + 0x41, 0x63, 0x2f, 0x96, 0x3c, 0x55, 0x78, 0xfe, 0xbc, 0xd1, 0x88, 0xfb, 0x8a, 0x6b, 0xb9, 0x57, + 0x73, 0xf2, 0x36, 0x2e, 0xc1, 0x91, 0xf8, 0x26, 0x0d, 0x15, 0x3f, 0xfc, 0xcc, 0x30, 0x58, 0x01, + 0x40, 0x49, 0xeb, 0x05, 0x81, 0x6b, 0xa9, 0xdd, 0x54, 0xbc, 0x92, 0x74, 0x16, 0x5b, 0xce, 0x8a, + 0x17, 0x04, 0x3b, 0x06, 0xee, 0x88, 0x57, 0x92, 0x7d, 0x00, 0xd5, 0x94, 0x8f, 0x88, 0xdd, 0x3a, + 0xdb, 0x2b, 0x7a, 0x4b, 0x9f, 0x1d, 0x7f, 0xc7, 0x7d, 0xe5, 0xf0, 0x91, 0x83, 0x38, 0xb6, 0x0e, + 0x75, 0x4f, 0xa9, 0x54, 0x6f, 0x51, 0xdb, 0xd1, 0x0d, 0xb6, 0x05, 0x6b, 0x74, 0xe6, 0x55, 0x28, + 0x62, 0x57, 0x79, 0xc7, 0x11, 0x2a, 0x6f, 0x69, 0xf4, 0xd4, 0x6a, 0x8e, 0x3a, 0x42, 0xcc, 0x5e, + 0x20, 0x51, 0xb3, 0xcd, 0xd3, 0xc7, 0xde, 0x94, 0x4b, 0x52, 0x53, 0x6d, 0x67, 0x6d, 0xb6, 0xc7, + 0x53, 0x44, 0xe1, 0x7a, 0x16, 0x7d, 0x50, 0x6a, 0xb4, 0xe8, 0x00, 0x76, 0x73, 0x20, 0x0a, 0x95, + 0x4b, 0xd0, 0x08, 0xa5, 0xcb, 0xe3, 0xc0, 0x08, 0xb2, 0x7a, 0x28, 0x1f, 0xc5, 0x01, 0xfb, 0x04, + 0xda, 0xfa, 0x2d, 0x01, 0x1f, 0x91, 0x9a, 0xe9, 0x6c, 0x2f, 0x1b, 0x8e, 0x45, 0xf0, 0x43, 0x3e, + 0x72, 0x5a, 0xca, 0x3c, 0xa1, 0x09, 0xa2, 0x84, 0xcb, 0x4f, 0x15, 0x4f, 0x63, 0x2f, 0xa2, 0x5d, + 0x69, 0x39, 0xa0, 0xc4, 0x23, 0x03, 0x61, 0x5f, 0xc0, 0x65, 0x8b, 0x75, 0xa5, 0x9a, 0x2a, 0x37, + 0x8b, 0xc3, 0x53, 0x37, 0xf6, 0x62, 0x41, 0xb6, 0x50, 0xd5, 0x59, 0xb7, 0xe8, 0x43, 0x35, 0x55, + 0xcf, 0xe3, 0xf0, 0xf4, 0xa9, 0x17, 0x0b, 0xb6, 0x09, 0xfd, 0xbc, 0x9b, 0x7a, 0x4d, 0x1f, 0x3c, + 0xe8, 0x91, 0x80, 0x59, 0xb6, 0xf0, 0xa3, 0xd7, 0xf8, 0xad, 0xa8, 0x1b, 0xca, 0x94, 0x62, 0x34, + 0x92, 0x5c, 0xb9, 0x92, 0xfb, 0x83, 0x65, 0xfa, 0xe6, 0xb5, 0x82, 0xfe, 0x19, 0xe1, 0x0e, 0xb9, + 0x3f, 0xfc, 0x6d, 0x05, 0x3a, 0x74, 0x2e, 0x9e, 0x27, 0x01, 0x8a, 0xa0, 0x0f, 0xa1, 0x37, 0xbb, + 0xe9, 0x9a, 0x6f, 0xba, 0x5e, 0x79, 0xc7, 0x37, 0xa0, 0xb1, 0xe3, 0xe3, 0xe2, 0x11, 0xe3, 0xf4, + 0x1c, 0xd3, 0x62, 0x3f, 0x83, 0x95, 0x8c, 0x86, 0x71, 0x7d, 0x75, 0xea, 0x46, 0x28, 0xba, 0xf4, + 0x41, 0x37, 0x5c, 0xa1, 0xdf, 0xb1, 0xab, 0x4e, 0x9d, 0x5e, 0x66, 0x1f, 0x9f, 0xa0, 0x50, 0xbb, + 0x07, 0xeb, 0x29, 0x47, 0x8e, 0x71, 0x5f, 0xf3, 0x54, 0xb8, 0x8a, 0x4f, 0x13, 0x91, 0x92, 0x22, + 0xc4, 0x55, 0x64, 0x1a, 0xf7, 0x2d, 0x4f, 0xc5, 0x91, 0xc1, 0x0c, 0xdf, 0x83, 0xfa, 0x4e, 0x9a, + 0x7a, 0x67, 0xc4, 0x5a, 0xf8, 0x30, 0xa8, 0x90, 0x02, 0xd4, 0x8d, 0xa1, 0x0f, 0xd5, 0x7d, 0x2f, + 0x61, 0x37, 0x61, 0x69, 0x9a, 0x10, 0xa6, 0xb3, 0x7d, 0xa9, 0x24, 0x17, 0xbc, 0x64, 0x6b, 0x3f, + 0x79, 0x14, 0xab, 0xf4, 0xcc, 0x59, 0x9a, 0x26, 0x57, 0xbf, 0x80, 0xa6, 0x69, 0xa2, 0x41, 0x7f, + 0xc2, 0xcf, 0xe8, 0xab, 0xdb, 0x0e, 0x3e, 0xe2, 0x0b, 0x5e, 0x7a, 0x51, 0x66, 0x2d, 0x3b, 0xdd, + 0xf8, 0xf9, 0xd2, 0x97, 0x95, 0xe1, 0xff, 0xac, 0x41, 0xeb, 0x21, 0x8f, 0x38, 0x7d, 0xfb, 0x10, + 0xba, 0xe5, 0x53, 0x61, 0xd7, 0x6d, 0xe6, 0xa4, 0x0c, 0xa1, 0xab, 0x55, 0x32, 0xf5, 0xe2, 0xe6, + 0xd8, 0xcd, 0xc0, 0x50, 0x57, 0xec, 0x69, 0x1b, 0x86, 0xce, 0x5b, 0xcf, 0xb1, 0x4d, 0xc4, 0x3c, + 0x35, 0x98, 0x9a, 0xc6, 0x98, 0x26, 0x7b, 0x17, 0x20, 0x15, 0xaf, 0xdc, 0x50, 0xeb, 0x45, 0xad, + 0x62, 0x5a, 0xa9, 0x78, 0xb5, 0x87, 0x9a, 0xf1, 0xaf, 0xe5, 0x98, 0xfd, 0x0c, 0x06, 0xa5, 0x63, + 0x86, 0x96, 0xb4, 0x1b, 0xc6, 0xee, 0x31, 0x1a, 0x5f, 0xe6, 0xc4, 0x15, 0x63, 0x92, 0xa1, 0xbd, + 0x17, 0x3f, 0x20, 0xcb, 0xcc, 0x08, 0x8f, 0xf6, 0x1b, 0x84, 0xc7, 0xb9, 0xb2, 0x08, 0xce, 0x97, + 0x45, 0x0f, 0x00, 0x0e, 0xf9, 0x78, 0xca, 0x63, 0xb5, 0xef, 0x25, 0x83, 0x0e, 0x6d, 0xfc, 0xb0, + 0xd8, 0x78, 0xbb, 0x5b, 0x5b, 0x05, 0x91, 0xe6, 0x82, 0x52, 0x2f, 0x34, 0x97, 0x7c, 0x2f, 0x76, + 0x55, 0x9a, 0xc5, 0xbe, 0xa7, 0xb4, 0xa7, 0xd2, 0x72, 0x3a, 0xbe, 0x17, 0x1f, 0x19, 0x50, 0x49, + 0x60, 0xf4, 0xca, 0x02, 0xe3, 0x16, 0xac, 0x24, 0x69, 0x38, 0xf5, 0xd2, 0x33, 0xf7, 0x84, 0x9f, + 0xd1, 0x66, 0xe8, 0xa3, 0xd7, 0x33, 0xe0, 0xdf, 0xf0, 0xb3, 0xbd, 0xe0, 0xf4, 0xea, 0x2f, 0x61, + 0x65, 0x6e, 0x02, 0x3f, 0x88, 0xef, 0xfe, 0x43, 0x15, 0xda, 0x07, 0x29, 0x37, 0x42, 0xfe, 0x3a, + 0x74, 0xa4, 0x3f, 0xe1, 0x53, 0x4f, 0xcb, 0x06, 0x3d, 0x02, 0x68, 0x10, 0xc9, 0x85, 0x19, 0x31, + 0xb6, 0xf4, 0x16, 0x31, 0xd6, 0x87, 0xaa, 0x36, 0xbb, 0xf0, 0x30, 0xe1, 0x63, 0x21, 0xbb, 0x6b, + 0x65, 0xd9, 0x7d, 0x03, 0xba, 0x13, 0x4f, 0xba, 0x5e, 0xa6, 0x84, 0xeb, 0x8b, 0x88, 0x98, 0xae, + 0xe5, 0xc0, 0xc4, 0x93, 0x3b, 0x99, 0x12, 0xbb, 0x22, 0x62, 0xef, 0x01, 0xf8, 0x22, 0x32, 0x62, + 0xc8, 0xd8, 0x9c, 0x6d, 0x5f, 0x44, 0x5a, 0xf6, 0x20, 0x57, 0x72, 0xa9, 0xc2, 0xa9, 0x67, 0xb6, + 0xd4, 0xf5, 0x45, 0x16, 0x2b, 0xd2, 0xb5, 0x55, 0x67, 0x35, 0x47, 0x39, 0xe2, 0xd5, 0x2e, 0x22, + 0xd8, 0x3d, 0x58, 0xf6, 0xc5, 0x34, 0x71, 0x13, 0x5c, 0x59, 0xb2, 0x80, 0x5a, 0x0b, 0xce, 0x42, + 0x17, 0x29, 0x0e, 0x4e, 0xb8, 0xb6, 0xc9, 0xb6, 0x61, 0xc5, 0x8f, 0x32, 0xa9, 0x78, 0xea, 0x1e, + 0x9b, 0x2e, 0x8b, 0xfe, 0x45, 0xcf, 0x90, 0x18, 0x3b, 0x6e, 0x08, 0xbd, 0x50, 0xba, 0x22, 0x0a, + 0x5c, 0x2d, 0xa0, 0x0c, 0x9f, 0x75, 0x42, 0xf9, 0x2c, 0x0a, 0x8c, 0x88, 0xd4, 0x34, 0x31, 0x7f, + 0x65, 0x69, 0x3a, 0x96, 0xe6, 0x29, 0x7f, 0x65, 0x68, 0x2e, 0x12, 0x68, 0xdd, 0x0b, 0x05, 0xda, + 0x7f, 0x5c, 0x82, 0xe6, 0x81, 0x90, 0xea, 0xe1, 0x34, 0xb2, 0x87, 0xa2, 0xf2, 0x43, 0x0f, 0xc5, + 0xd2, 0xf9, 0x87, 0xe2, 0x1c, 0xb6, 0xac, 0x9e, 0xc3, 0x96, 0xa8, 0x6a, 0xca, 0x74, 0xc4, 0x4e, + 0xda, 0x96, 0x5d, 0x2e, 0x08, 0x89, 0xa5, 0xae, 0xa1, 0xfd, 0xe4, 0x06, 0x5a, 0x8a, 0xe9, 0xad, + 0x6f, 0x85, 0xd2, 0x48, 0x30, 0x8d, 0x0c, 0x89, 0x3b, 0x8d, 0x71, 0xd5, 0x0a, 0xa5, 0xe1, 0xd6, + 0xdf, 0x83, 0x2b, 0x79, 0x4f, 0xf7, 0x55, 0xa8, 0x26, 0x22, 0x53, 0xee, 0x88, 0x1c, 0x42, 0x69, + 0x5c, 0x8f, 0x0d, 0x3b, 0xd2, 0x37, 0x1a, 0xad, 0xdd, 0x45, 0xb2, 0xf5, 0x46, 0x59, 0x14, 0xb9, + 0x8a, 0x9f, 0x2a, 0xb3, 0xf9, 0x03, 0xbd, 0x36, 0x66, 0xdd, 0x1e, 0x67, 0x51, 0x74, 0xc4, 0x4f, + 0x15, 0x2a, 0x98, 0xd6, 0xc8, 0x34, 0x86, 0x7f, 0x5c, 0x03, 0x78, 0x22, 0xfc, 0x93, 0x23, 0x2f, + 0x1d, 0x73, 0x85, 0x0e, 0x8d, 0x95, 0x81, 0x46, 0x46, 0x37, 0x95, 0x96, 0x7c, 0x6c, 0x1b, 0x36, + 0xec, 0xf7, 0x23, 0xe7, 0xa2, 0x73, 0xa5, 0x85, 0x98, 0x39, 0x82, 0xcc, 0x60, 0xb5, 0xe3, 0x4f, + 0x12, 0x8c, 0x7d, 0x59, 0xac, 0x2d, 0xf6, 0x51, 0x67, 0x09, 0xad, 0xed, 0x79, 0xb6, 0x6d, 0xaf, + 0xe8, 0x7e, 0x74, 0x96, 0xb0, 0x7b, 0x70, 0x29, 0xe5, 0xa3, 0x94, 0xcb, 0x89, 0xab, 0x64, 0xf9, + 0x65, 0xda, 0xaf, 0x59, 0x35, 0xc8, 0x23, 0x99, 0xbf, 0xeb, 0x1e, 0x5c, 0xd2, 0x2b, 0x35, 0x3f, + 0x3d, 0x2d, 0xf1, 0x57, 0x35, 0xb2, 0x3c, 0xbb, 0xf7, 0x80, 0x02, 0x65, 0x5a, 0x8a, 0x5b, 0x43, + 0x37, 0xa2, 0xc5, 0x38, 0x8e, 0x38, 0xda, 0x80, 0xbb, 0x13, 0x74, 0xea, 0x1f, 0xf2, 0x91, 0x59, + 0xfc, 0x02, 0xc0, 0x86, 0x50, 0xdb, 0x17, 0x01, 0xa7, 0xa5, 0x5e, 0xde, 0x5e, 0xde, 0xa2, 0x90, + 0x1b, 0xae, 0x24, 0xc5, 0x66, 0x08, 0xc7, 0x3e, 0x06, 0x1a, 0x4e, 0xb3, 0xdf, 0xe2, 0xe9, 0x6a, + 0x21, 0x92, 0x78, 0xf0, 0x1e, 0x5c, 0x2a, 0x66, 0xe2, 0x7a, 0xca, 0x55, 0x13, 0x4e, 0x02, 0x54, + 0x1f, 0xb0, 0xd5, 0x7c, 0x52, 0x3b, 0xea, 0x68, 0xc2, 0x51, 0x98, 0x6e, 0x42, 0x53, 0x1c, 0x7f, + 0xe7, 0xe2, 0x41, 0xe8, 0x9c, 0x7f, 0x10, 0x1a, 0xe2, 0xf8, 0x3b, 0x87, 0x8f, 0xd8, 0x4f, 0xcb, + 0xca, 0x67, 0x6e, 0x69, 0xba, 0xb4, 0x34, 0xeb, 0x39, 0xbe, 0xb4, 0x3a, 0xc3, 0x2f, 0xa1, 0x81, + 0x9f, 0xf3, 0x2c, 0x61, 0x5b, 0xd0, 0x54, 0xc4, 0x1e, 0xd2, 0x18, 0x0b, 0xeb, 0x85, 0xce, 0x28, + 0x78, 0xc7, 0xb1, 0x44, 0x43, 0x07, 0x56, 0x72, 0x01, 0xfc, 0x3c, 0x0e, 0x5f, 0x64, 0x9c, 0xfd, + 0x0a, 0x56, 0x93, 0x94, 0x1b, 0xb6, 0x77, 0xb3, 0x13, 0x34, 0x81, 0xcc, 0x09, 0x5e, 0x37, 0x5c, + 0x9a, 0xf7, 0x38, 0x41, 0x0e, 0x5d, 0x4e, 0x66, 0xda, 0xc3, 0x6f, 0xe1, 0x72, 0x4e, 0x71, 0xc8, + 0x7d, 0x11, 0x07, 0x5e, 0x7a, 0x46, 0xba, 0x72, 0x6e, 0x6c, 0xf9, 0x43, 0xc6, 0x3e, 0xa4, 0xb1, + 0xff, 0x7b, 0x05, 0x3a, 0x8f, 0xb3, 0xd7, 0xaf, 0xcf, 0xf4, 0x59, 0x62, 0x5d, 0xa8, 0x3c, 0xa5, + 0x01, 0x96, 0x9c, 0xca, 0x53, 0x34, 0xe7, 0x0e, 0x4e, 0xf0, 0x5c, 0x13, 0x9f, 0xb7, 0x1d, 0xd3, + 0x42, 0x6f, 0xed, 0xe0, 0xe4, 0xe8, 0x0d, 0x1c, 0xad, 0xd1, 0xe8, 0x66, 0x3c, 0xc8, 0xc2, 0x08, + 0x8d, 0x0d, 0xc3, 0xbc, 0x79, 0x1b, 0xfd, 0x9f, 0xbd, 0x91, 0x9e, 0xca, 0xe3, 0x54, 0x4c, 0xf5, + 0x62, 0x19, 0x91, 0x71, 0x0e, 0x86, 0x7d, 0x05, 0x6b, 0x26, 0x4a, 0x64, 0xa4, 0x82, 0x2b, 0x13, + 0xee, 0x13, 0xeb, 0xfe, 0xa0, 0xc8, 0xd2, 0xf0, 0xaf, 0x6a, 0xd0, 0xfa, 0xda, 0x93, 0x93, 0x5f, + 0x8b, 0x30, 0x66, 0xf7, 0xa0, 0xfd, 0x9d, 0x08, 0x63, 0xed, 0xfa, 0xea, 0xa0, 0xef, 0x9a, 0x1e, + 0xeb, 0xa9, 0x08, 0xf8, 0x16, 0xd2, 0x90, 0xd3, 0xdb, 0xfa, 0xce, 0x3c, 0x19, 0x21, 0x9f, 0x86, + 0xe3, 0x89, 0x72, 0x11, 0x68, 0x64, 0x6b, 0x27, 0x94, 0x0e, 0xc2, 0x68, 0xd4, 0x77, 0x01, 0xf5, + 0xdd, 0xc4, 0x15, 0xb1, 0x9b, 0x9c, 0x18, 0xef, 0xa8, 0x85, 0x90, 0x67, 0xf1, 0xc1, 0x09, 0x9e, + 0xbd, 0x50, 0xba, 0x26, 0xc8, 0x62, 0x2c, 0xd9, 0x92, 0x93, 0xf9, 0x11, 0x2c, 0xa3, 0x95, 0x21, + 0x4f, 0xc2, 0xc4, 0x4d, 0x52, 0x71, 0x6c, 0x17, 0x05, 0x6d, 0x8f, 0xc3, 0x93, 0x30, 0x39, 0x40, + 0x18, 0x29, 0x77, 0x13, 0xba, 0x41, 0xb1, 0xad, 0xb5, 0x28, 0x18, 0x10, 0xae, 0x2f, 0xc5, 0x67, + 0x22, 0x6d, 0x6b, 0x37, 0x49, 0x69, 0x37, 0x53, 0x1e, 0x91, 0x51, 0x7d, 0x05, 0x5a, 0x78, 0x18, + 0x08, 0xd5, 0xd2, 0x28, 0x5f, 0x68, 0xd4, 0x4f, 0x00, 0x22, 0x3e, 0x52, 0x2e, 0x72, 0x99, 0xf6, + 0x46, 0xe7, 0xe2, 0x20, 0x88, 0xdd, 0x45, 0x24, 0xfb, 0x04, 0x3a, 0x7a, 0x15, 0x34, 0x2d, 0x2c, + 0xd0, 0x02, 0xa1, 0x35, 0xf1, 0x6d, 0xe8, 0xc4, 0x22, 0x76, 0xf9, 0x0b, 0xa2, 0x36, 0xe7, 0x76, 0x66, 0xe0, 0x58, 0xc4, 0x8f, 0x5e, 0x20, 0x31, 0xbb, 0x6b, 0xe6, 0xa0, 0x03, 0x02, 0xdd, 0x0b, - 0x02, 0x02, 0x34, 0x13, 0x7d, 0x34, 0xbe, 0x6f, 0x67, 0xa2, 0x7b, 0xf4, 0x2e, 0xe8, 0xa1, 0xe7, - 0xa3, 0xbb, 0xdc, 0x80, 0x2e, 0xad, 0xfb, 0xd4, 0x4b, 0x5c, 0xe5, 0x8d, 0x8d, 0x37, 0x06, 0x08, - 0xdb, 0xf7, 0x92, 0x23, 0x6f, 0xcc, 0x1c, 0xb8, 0x32, 0x27, 0x6f, 0xc7, 0x28, 0xba, 0x9a, 0x6b, - 0x2b, 0x36, 0xa0, 0x70, 0xbe, 0xd4, 0x6d, 0xcc, 0x48, 0x1d, 0x89, 0x3c, 0x72, 0x77, 0xf8, 0x4f, - 0x97, 0xa0, 0xf5, 0x44, 0x88, 0xe4, 0x47, 0x8a, 0x5e, 0x79, 0x49, 0x97, 0x2e, 0x5e, 0xd2, 0xea, - 0xec, 0x92, 0xce, 0xb1, 0xbe, 0xf6, 0xfd, 0x59, 0x5f, 0xff, 0xc1, 0xac, 0x6f, 0xfc, 0x08, 0xd6, - 0x37, 0xe7, 0x59, 0x3f, 0x6c, 0x42, 0xfd, 0x90, 0xab, 0x67, 0xc9, 0xf0, 0x5f, 0xb5, 0xa0, 0xfd, - 0x90, 0x07, 0x99, 0x66, 0x58, 0xf9, 0xf3, 0x2b, 0x17, 0x7f, 0xfe, 0xd2, 0xec, 0xe7, 0xa3, 0x21, - 0xb2, 0x12, 0x7d, 0x4e, 0x6c, 0xac, 0x65, 0x05, 0x1a, 0x45, 0xbf, 0x90, 0x67, 0x13, 0x60, 0x9a, - 0x61, 0x53, 0x2e, 0xce, 0x6f, 0x96, 0x8d, 0xfa, 0x8f, 0x92, 0x8d, 0x39, 0xad, 0xb0, 0x10, 0x7a, - 0x7a, 0x2b, 0xd7, 0xe6, 0x35, 0x42, 0x6b, 0x41, 0x23, 0x3c, 0x81, 0x35, 0x11, 0xbb, 0x41, 0x96, - 0x44, 0x21, 0x9e, 0x55, 0x5c, 0x4f, 0x9f, 0xd4, 0xdb, 0x36, 0xdf, 0x92, 0x8b, 0xde, 0xb3, 0xf8, - 0xa1, 0x25, 0xd2, 0xe7, 0x77, 0x67, 0x55, 0xcc, 0x83, 0x50, 0x4d, 0x05, 0xb8, 0x34, 0x64, 0x57, - 0xc9, 0x23, 0xd4, 0x89, 0xa3, 0x2e, 0x41, 0x77, 0x45, 0x44, 0x96, 0xe2, 0x4b, 0x58, 0x29, 0xa8, - 0xb4, 0x8c, 0x74, 0x2e, 0x90, 0x91, 0x9e, 0xed, 0xa8, 0xc5, 0xe4, 0xaf, 0x43, 0x0b, 0x7c, 0x0a, - 0x6b, 0x36, 0x2c, 0x61, 0x9c, 0x03, 0x5a, 0xc1, 0x65, 0x92, 0xa0, 0xbe, 0x89, 0x44, 0x90, 0x5f, - 0x40, 0x4b, 0xf4, 0x0b, 0x58, 0x2f, 0x91, 0xe3, 0xb9, 0xa1, 0xac, 0x0d, 0xca, 0xb2, 0xb2, 0x9a, - 0xf7, 0xc5, 0xe6, 0x13, 0x1d, 0x9e, 0xed, 0x04, 0x3c, 0xb2, 0x2f, 0x1a, 0xf4, 0xf5, 0xb1, 0x27, - 0xe0, 0x91, 0xc9, 0x16, 0xed, 0xc3, 0x47, 0x78, 0xba, 0x40, 0xbc, 0xef, 0x25, 0x2a, 0x4b, 0xb9, - 0x9b, 0x44, 0x9e, 0xcf, 0x27, 0x22, 0x0a, 0x78, 0x5a, 0x4c, 0x6e, 0x95, 0x26, 0x77, 0x5d, 0x44, - 0xc1, 0xae, 0x88, 0x76, 0x35, 0xe5, 0x41, 0x41, 0x68, 0xe7, 0xba, 0x03, 0xef, 0x2f, 0x0c, 0x87, - 0x86, 0xa3, 0x18, 0x88, 0xd1, 0x40, 0x57, 0x66, 0x07, 0x42, 0x12, 0x3b, 0xc4, 0x7d, 0xb8, 0xa4, - 0xd7, 0x4e, 0x0b, 0xf7, 0x09, 0xe7, 0x89, 0x1b, 0x79, 0x52, 0x0d, 0xd6, 0xb4, 0x91, 0x26, 0x24, - 0x09, 0xf0, 0x6f, 0x38, 0x4f, 0x9e, 0x78, 0xfa, 0xad, 0xba, 0x8b, 0xf1, 0xe3, 0xa9, 0xcf, 0x0c, - 0x6f, 0xd7, 0xf5, 0x5b, 0x89, 0x4a, 0x3b, 0xf3, 0xd8, 0xb9, 0xc4, 0xe4, 0xdf, 0x87, 0x6b, 0x33, - 0x43, 0x4c, 0xbd, 0xf4, 0xa4, 0x70, 0x6c, 0x07, 0x97, 0x88, 0x6f, 0x97, 0x4b, 0xfd, 0xf7, 0x89, - 0x40, 0x8f, 0x30, 0xfc, 0x6f, 0x75, 0x58, 0x26, 0x3b, 0xfc, 0xb7, 0x6a, 0xe3, 0x6f, 0xd5, 0xc6, - 0xdf, 0x00, 0xb5, 0x31, 0xfc, 0x07, 0x15, 0x68, 0x1e, 0xa4, 0x22, 0xc8, 0x7c, 0xf5, 0x23, 0x25, - 0x7d, 0x56, 0x82, 0xaa, 0x6f, 0x93, 0xa0, 0xda, 0x82, 0xb9, 0xfe, 0x67, 0x15, 0x68, 0x9b, 0x29, - 0x3c, 0xd9, 0xfe, 0x91, 0x93, 0x28, 0x92, 0x57, 0x95, 0x73, 0x93, 0x57, 0x6f, 0x9d, 0x05, 0x0a, - 0xd6, 0x4b, 0x9d, 0xc5, 0x17, 0x49, 0x91, 0xc9, 0x6a, 0x3b, 0x5d, 0x0d, 0x7d, 0x96, 0x50, 0xc2, - 0xea, 0x15, 0xb4, 0xe9, 0xe4, 0x44, 0x9a, 0x61, 0x03, 0x1a, 0x29, 0x65, 0x58, 0xcc, 0x44, 0x4d, - 0xeb, 0xcd, 0xfb, 0x74, 0xe9, 0xc7, 0xb9, 0x7e, 0xff, 0x6e, 0x09, 0x7a, 0x74, 0x8c, 0x7d, 0x9c, - 0xc5, 0x7a, 0x27, 0xe4, 0xe1, 0xb3, 0xca, 0x6c, 0xf8, 0xac, 0x96, 0xe2, 0x69, 0x53, 0xbf, 0xa6, - 0xab, 0x5f, 0xb3, 0x2b, 0xa2, 0x87, 0x7c, 0xe4, 0x10, 0x06, 0x59, 0xe5, 0xa5, 0x63, 0x79, 0x5e, - 0x9e, 0x0f, 0xe1, 0xf8, 0x55, 0x89, 0x97, 0x7a, 0x53, 0x69, 0xf3, 0x7c, 0xba, 0xc5, 0x18, 0xd4, - 0x68, 0xbf, 0x69, 0xb6, 0xd0, 0xb3, 0x89, 0xc8, 0xc8, 0x30, 0x1e, 0xe7, 0xca, 0xa3, 0x45, 0xf9, - 0xdd, 0x71, 0xc4, 0xd9, 0x43, 0x60, 0x3a, 0x60, 0x9b, 0x72, 0x0f, 0x4d, 0x10, 0x8d, 0x43, 0x1a, - 0xa4, 0xb3, 0xbd, 0xa1, 0x5f, 0x4b, 0xbc, 0x74, 0x08, 0x7d, 0x80, 0x58, 0xa7, 0x1f, 0xce, 0x41, - 0xce, 0x61, 0xa6, 0xb6, 0x43, 0xf9, 0xe9, 0xe3, 0x7b, 0x33, 0x93, 0x8c, 0x13, 0x31, 0x73, 0x07, - 0x2e, 0xd9, 0xec, 0x09, 0xaa, 0x8b, 0x6d, 0xdc, 0x0b, 0x74, 0x1e, 0xb6, 0xdf, 0x58, 0x29, 0x7d, - 0xe3, 0x3a, 0xd4, 0xcb, 0x75, 0x1d, 0xba, 0x31, 0xbc, 0x09, 0x9d, 0x51, 0x18, 0x71, 0x13, 0x85, - 0x44, 0xa6, 0x99, 0x78, 0x64, 0x85, 0x2a, 0x1b, 0x4c, 0x6b, 0xf8, 0xdb, 0x0a, 0x5c, 0x4e, 0xbc, - 0xf4, 0x45, 0xc6, 0x15, 0xc5, 0x22, 0x29, 0xdb, 0xe6, 0xca, 0x89, 0x97, 0x06, 0xb8, 0x71, 0x68, - 0x08, 0x3d, 0xba, 0x2e, 0x1f, 0x68, 0x23, 0x44, 0xcf, 0xe5, 0x16, 0xac, 0x94, 0x7a, 0x28, 0x2f, - 0xb5, 0xd1, 0xa2, 0x5e, 0x2a, 0x5e, 0x51, 0xd2, 0xf4, 0x10, 0x81, 0x78, 0xa0, 0x2c, 0xe8, 0x38, - 0x59, 0x1b, 0xca, 0xc2, 0x5b, 0xaa, 0x47, 0x71, 0x80, 0x3b, 0x27, 0xce, 0xa6, 0x3a, 0x98, 0xa2, - 0xab, 0x3f, 0x9a, 0x71, 0x36, 0xa5, 0xf8, 0xc9, 0x3a, 0xd4, 0x8f, 0xcf, 0x14, 0x79, 0xeb, 0x08, - 0xd7, 0x8d, 0xe1, 0x5f, 0xd4, 0x61, 0x6d, 0xcf, 0xe7, 0xc7, 0x3c, 0x1d, 0x3f, 0xf4, 0x94, 0xf7, - 0x38, 0x8c, 0xf8, 0x91, 0x27, 0x4f, 0x70, 0xc1, 0x69, 0xce, 0x89, 0xa7, 0x26, 0x86, 0x4b, 0x2d, - 0x04, 0x1c, 0x78, 0x6a, 0x82, 0xa6, 0x80, 0x90, 0x23, 0x91, 0x4e, 0x4d, 0x6c, 0xab, 0xed, 0xd0, - 0x37, 0x3e, 0x26, 0x48, 0xde, 0x5b, 0x86, 0xaf, 0xb9, 0xa9, 0x55, 0xa1, 0xde, 0x94, 0xf8, 0xfc, - 0x00, 0xba, 0x29, 0xf7, 0x45, 0x1a, 0x98, 0x80, 0xad, 0x9e, 0x67, 0x47, 0xc3, 0x74, 0xa8, 0xf6, - 0x36, 0x14, 0x59, 0x05, 0x3a, 0xbe, 0xbb, 0xa1, 0x4d, 0x7c, 0xaf, 0xe4, 0x08, 0x5c, 0xf9, 0xbd, - 0x80, 0xfd, 0x5d, 0xe8, 0x17, 0xb4, 0x14, 0xe2, 0xb6, 0xc7, 0x8b, 0xed, 0x22, 0x04, 0x73, 0xce, - 0x27, 0x6e, 0x1d, 0xd8, 0x5e, 0x7f, 0x87, 0x3a, 0xe9, 0x30, 0x7e, 0x31, 0xbc, 0x86, 0xb2, 0x0f, - 0xa1, 0x27, 0x93, 0x28, 0x54, 0x46, 0x00, 0xa4, 0xa9, 0x68, 0xe9, 0x12, 0x50, 0x47, 0xa2, 0xe5, - 0x79, 0x4b, 0xd8, 0xfa, 0x5e, 0x4b, 0xd8, 0x5e, 0x5c, 0xc2, 0x9f, 0x40, 0xdf, 0x4f, 0x79, 0xc0, - 0x63, 0x15, 0x7a, 0x91, 0x2b, 0x7d, 0x91, 0x58, 0xd3, 0xb7, 0x52, 0xc0, 0x0f, 0x11, 0xcc, 0x7e, - 0x0a, 0x97, 0x7d, 0x11, 0x2b, 0x1e, 0x2b, 0x57, 0xf2, 0x17, 0x19, 0x8f, 0x7d, 0xee, 0xc6, 0xd9, - 0xf4, 0x98, 0xa7, 0x26, 0xa7, 0x7b, 0xc9, 0xa0, 0x0f, 0x0d, 0xf6, 0x29, 0x21, 0xd9, 0x3d, 0x58, - 0xd7, 0xcb, 0x33, 0xd7, 0x49, 0x67, 0x11, 0x19, 0xad, 0xd4, 0x6c, 0x8f, 0x2d, 0x58, 0x9b, 0x78, - 0xd2, 0x4d, 0xb9, 0x0c, 0x83, 0xcc, 0x8b, 0xcc, 0x0e, 0x35, 0xb9, 0x8b, 0xd5, 0x89, 0x27, 0x1d, - 0x83, 0x31, 0xe1, 0x21, 0x8a, 0x5e, 0xcf, 0xd0, 0xba, 0x13, 0x4f, 0x4e, 0xe8, 0xf8, 0xdc, 0x76, - 0x58, 0x3a, 0x43, 0xfd, 0xb5, 0x27, 0x27, 0x57, 0x1f, 0xc0, 0xfa, 0x79, 0x0b, 0xf2, 0xb6, 0xb4, - 0x46, 0xbb, 0x94, 0xd6, 0x30, 0x75, 0x5d, 0xff, 0x63, 0x09, 0x2e, 0xd9, 0xf5, 0x26, 0xc7, 0x2f, - 0x17, 0xea, 0xeb, 0x64, 0x23, 0xd1, 0x59, 0xcc, 0xcf, 0xd2, 0x6d, 0x07, 0x34, 0x88, 0x0e, 0xce, - 0x9b, 0xd0, 0x37, 0x04, 0x85, 0xf0, 0xeb, 0xb7, 0x2c, 0x07, 0xf9, 0x50, 0xb4, 0x05, 0xe8, 0x03, - 0x47, 0x3c, 0x45, 0x1e, 0x05, 0x54, 0x91, 0x47, 0x5d, 0x48, 0xd8, 0xe9, 0x03, 0x2d, 0xce, 0x8a, - 0x1c, 0xbb, 0x03, 0x8c, 0xbf, 0xc8, 0xbc, 0x28, 0x54, 0x67, 0xee, 0x28, 0xe4, 0x51, 0x40, 0x39, - 0x34, 0x5d, 0xa8, 0xd3, 0xb7, 0x98, 0xc7, 0x88, 0xd8, 0x0b, 0x64, 0x69, 0x26, 0x26, 0x35, 0x93, - 0x6f, 0x00, 0x33, 0x93, 0x43, 0x02, 0xef, 0x05, 0xe7, 0xef, 0x95, 0xc6, 0xf9, 0x7b, 0xe5, 0x63, - 0x58, 0x99, 0x5f, 0x73, 0x9d, 0x2e, 0x59, 0x96, 0xb3, 0xeb, 0x7d, 0x9e, 0x10, 0xb6, 0xce, 0x15, - 0x42, 0xc3, 0xf4, 0xff, 0xb5, 0x04, 0xeb, 0x86, 0xe9, 0xbb, 0x22, 0xca, 0xa6, 0x68, 0x6d, 0x93, - 0x30, 0x1e, 0xa3, 0x41, 0x9e, 0x0a, 0xed, 0x96, 0x94, 0xd4, 0x1f, 0x4c, 0x45, 0xae, 0x8b, 0x37, - 0xa1, 0x1f, 0xea, 0x9e, 0x39, 0x5f, 0x6c, 0x69, 0x9d, 0x81, 0x1b, 0xae, 0xa0, 0x14, 0xca, 0xd8, - 0x4b, 0xe4, 0x44, 0x28, 0x43, 0x4a, 0x4a, 0x5c, 0xf3, 0x7c, 0xd5, 0xa2, 0x88, 0x9a, 0xbc, 0xc3, - 0x3b, 0xc0, 0xfc, 0x2c, 0x4d, 0x71, 0x7f, 0x94, 0xc8, 0x75, 0x42, 0xa2, 0x6f, 0x30, 0x05, 0xf5, - 0x87, 0xd0, 0x9c, 0x8a, 0xc2, 0x23, 0x98, 0x71, 0xee, 0x9c, 0xc6, 0x54, 0x90, 0x84, 0x5c, 0x45, - 0xaf, 0xe5, 0x45, 0x16, 0xa6, 0x3c, 0xb0, 0x76, 0xd0, 0xb6, 0x8d, 0x91, 0x9c, 0x84, 0x41, 0xc0, - 0x63, 0x13, 0x0c, 0x6f, 0x85, 0xf2, 0x6b, 0x6a, 0x53, 0xe5, 0x19, 0x1f, 0x79, 0x59, 0xa4, 0xdc, - 0x38, 0x8b, 0x68, 0x57, 0x44, 0xa6, 0x1e, 0x6a, 0xc5, 0x20, 0x9e, 0x66, 0x11, 0xee, 0x88, 0xc8, - 0x2c, 0x29, 0xd9, 0x12, 0x14, 0x41, 0x77, 0x12, 0xc6, 0x8a, 0x54, 0x45, 0x9b, 0x96, 0x14, 0x11, - 0x28, 0x84, 0x5f, 0x87, 0xb1, 0x1a, 0xfe, 0xd9, 0x12, 0x6c, 0x18, 0xc6, 0x1f, 0x1a, 0x06, 0x18, - 0xfb, 0x48, 0x1e, 0xbb, 0x65, 0x97, 0xc9, 0x55, 0x54, 0x1d, 0xb0, 0xa0, 0x3d, 0x9a, 0x70, 0x21, - 0x5d, 0x4b, 0xa6, 0x4e, 0xca, 0xca, 0xd5, 0x1d, 0x60, 0x0b, 0x72, 0x25, 0x4d, 0xcc, 0xa8, 0x3f, - 0x27, 0x58, 0x92, 0x7d, 0x0e, 0x1b, 0x53, 0xae, 0x3c, 0xda, 0x08, 0x91, 0xf0, 0x3d, 0xea, 0x45, - 0x5b, 0x5e, 0xb3, 0x7b, 0xdd, 0x62, 0x9f, 0x18, 0x24, 0x6e, 0x7a, 0x7c, 0xc7, 0xd4, 0x8b, 0xc3, - 0x11, 0x97, 0x8a, 0xec, 0xbc, 0xee, 0xa1, 0x1d, 0x8f, 0xbe, 0xc5, 0xa0, 0x25, 0x27, 0x6a, 0xf2, - 0x18, 0x47, 0x7a, 0x11, 0x1b, 0x44, 0xd3, 0x4c, 0xf9, 0xc8, 0xac, 0x5d, 0x0f, 0xd7, 0x2a, 0x0e, - 0xe3, 0xb1, 0x2e, 0x0e, 0x6d, 0x6a, 0x9f, 0xce, 0x02, 0xf7, 0x45, 0xc0, 0x87, 0x7f, 0x52, 0xcb, - 0x65, 0xf4, 0xc0, 0xc0, 0x0f, 0x95, 0xa7, 0x24, 0xbb, 0x09, 0xcb, 0xf9, 0xe4, 0xb5, 0x8d, 0xd4, - 0xbc, 0xea, 0x59, 0xe8, 0x03, 0x04, 0xa2, 0xf8, 0xcd, 0xce, 0x56, 0xd3, 0x2e, 0xe9, 0x84, 0x63, - 0x79, 0xba, 0x9a, 0x1e, 0x87, 0xb5, 0xf4, 0x9a, 0xd4, 0x94, 0x6d, 0x5a, 0xa8, 0x26, 0xfb, 0xb4, - 0x60, 0x82, 0x74, 0x25, 0x8f, 0x74, 0xb5, 0x4d, 0x6d, 0x76, 0x54, 0x79, 0x68, 0x10, 0xb8, 0x35, - 0x0b, 0xf2, 0x24, 0xcd, 0x62, 0x1e, 0x18, 0x93, 0xbe, 0x92, 0xc3, 0x0f, 0x08, 0x8c, 0x13, 0xce, - 0x35, 0x53, 0x69, 0xe8, 0x86, 0x1e, 0x3a, 0x30, 0x9a, 0xa9, 0x18, 0x1a, 0x65, 0xb4, 0xa0, 0x37, - 0x63, 0x6b, 0x05, 0xb1, 0x92, 0x53, 0x9b, 0xb1, 0x7f, 0x06, 0x83, 0x9c, 0x56, 0x7f, 0x5d, 0xf1, - 0x82, 0x96, 0x36, 0x3e, 0xb6, 0x0b, 0x7d, 0x66, 0xfe, 0x92, 0xcf, 0x60, 0x63, 0xbe, 0xa3, 0x79, - 0x53, 0x9b, 0xba, 0xad, 0xcd, 0x74, 0x2b, 0xbe, 0x24, 0x5f, 0x5f, 0xdf, 0xf3, 0x27, 0xdc, 0x9d, - 0x84, 0xa6, 0x72, 0xb3, 0xea, 0xac, 0x5a, 0xd4, 0x2e, 0x62, 0xbe, 0x0e, 0x95, 0x3c, 0x87, 0x7e, - 0x1a, 0x4a, 0x69, 0xac, 0xe2, 0x2c, 0xfd, 0x7e, 0x28, 0xe5, 0xf0, 0x1f, 0x03, 0x74, 0xad, 0xa7, - 0x48, 0xc5, 0x85, 0x77, 0xca, 0x4e, 0x77, 0x67, 0xbb, 0x6f, 0xbd, 0x67, 0x24, 0xd9, 0x51, 0x2a, - 0xb5, 0xf9, 0x0b, 0xed, 0x8c, 0xcf, 0xf8, 0x3b, 0x4b, 0xe4, 0x20, 0x14, 0xfe, 0xce, 0x0e, 0xac, - 0x96, 0x3c, 0x48, 0x57, 0x09, 0xe5, 0x45, 0xc6, 0x29, 0x2f, 0x55, 0x94, 0x94, 0x48, 0x9c, 0x15, - 0x6c, 0x68, 0xdf, 0xe2, 0x08, 0xa9, 0xd1, 0xd9, 0xf7, 0x45, 0x64, 0xab, 0xd9, 0xe6, 0x9c, 0x7d, - 0xc4, 0x50, 0xae, 0x3c, 0xe5, 0x78, 0x76, 0x94, 0x2f, 0x22, 0xb3, 0x83, 0xda, 0x1a, 0x72, 0xf8, - 0x22, 0xca, 0x27, 0x48, 0xce, 0x74, 0x83, 0xce, 0x11, 0x34, 0x41, 0x3a, 0x53, 0x7d, 0x0a, 0x1d, - 0x91, 0x86, 0xe3, 0x90, 0x52, 0x5f, 0xda, 0xc1, 0x99, 0x7f, 0x09, 0x68, 0x82, 0x5d, 0x7c, 0xd5, - 0x10, 0x1a, 0xc6, 0xfc, 0x2f, 0xe6, 0xcf, 0x0d, 0x06, 0x1d, 0x22, 0xa9, 0xd2, 0xd0, 0x57, 0x38, - 0x1d, 0xbd, 0x23, 0x75, 0x61, 0x54, 0x4f, 0x83, 0x0f, 0x5f, 0x44, 0x94, 0xfd, 0xbb, 0x05, 0x2b, - 0x3e, 0x99, 0x0b, 0xbd, 0xa1, 0x22, 0x1e, 0xd3, 0x9a, 0xd6, 0x9d, 0x9e, 0x06, 0xe3, 0xfc, 0x9e, - 0xf0, 0xd8, 0x14, 0x61, 0x79, 0x51, 0x84, 0x27, 0x46, 0xe1, 0x05, 0x26, 0x63, 0xde, 0xb5, 0xc0, - 0x27, 0xc2, 0x0b, 0xd8, 0xcf, 0xe1, 0x2a, 0xe2, 0x5c, 0x3e, 0x4d, 0xd4, 0x19, 0xda, 0x37, 0x9e, - 0x86, 0xbe, 0xeb, 0x49, 0xca, 0xa0, 0x9b, 0xc4, 0xf9, 0x06, 0x52, 0x3c, 0x42, 0x82, 0xa7, 0x1a, - 0xbf, 0x23, 0xbf, 0xe5, 0xa9, 0x60, 0xdf, 0x52, 0x06, 0xf0, 0x3c, 0xf7, 0xdd, 0x1e, 0xf5, 0x3f, - 0x28, 0xd6, 0xea, 0x02, 0x4a, 0xaa, 0x50, 0x41, 0x84, 0x63, 0x9d, 0x3e, 0xea, 0xcf, 0x7e, 0x03, - 0xcc, 0x1a, 0x38, 0x92, 0x7c, 0xe5, 0xc9, 0x13, 0x49, 0x51, 0x80, 0xce, 0xf6, 0x7b, 0x6f, 0xf4, - 0x51, 0x1d, 0x6b, 0x19, 0x11, 0x88, 0x00, 0xc9, 0xfe, 0x08, 0xd6, 0xf3, 0xc1, 0x8c, 0x2f, 0x43, - 0xc3, 0xe9, 0x20, 0xc1, 0xf5, 0xc5, 0xe1, 0x66, 0x5c, 0x20, 0xc7, 0xce, 0x44, 0x83, 0xf5, 0x90, - 0x5f, 0xc1, 0x8a, 0x1d, 0x52, 0x73, 0x5d, 0x0e, 0xfa, 0x34, 0xda, 0xfb, 0x0b, 0xa3, 0xcd, 0xd8, - 0xf6, 0xdc, 0x3e, 0x6b, 0x28, 0x7e, 0x68, 0x6e, 0xc9, 0xad, 0x95, 0x19, 0xac, 0x92, 0x8c, 0xdc, - 0x58, 0x18, 0x69, 0xce, 0x58, 0x39, 0x76, 0x0a, 0x16, 0xce, 0xee, 0xc3, 0x25, 0x3b, 0x98, 0xa0, - 0x84, 0xad, 0x1b, 0x0a, 0xca, 0xe5, 0x32, 0xed, 0x62, 0x19, 0xa4, 0x4e, 0xe6, 0xee, 0x09, 0x87, - 0x8f, 0xd8, 0x2f, 0xe1, 0x9a, 0xed, 0xa2, 0xad, 0x30, 0x9d, 0x48, 0xf3, 0x8f, 0x5a, 0x23, 0xdb, - 0x35, 0x30, 0x24, 0xda, 0x2e, 0xe3, 0x09, 0xd4, 0x4e, 0x7f, 0x13, 0xfa, 0x54, 0x9a, 0x8a, 0xcb, - 0x2a, 0xd2, 0x20, 0x8c, 0xbd, 0x68, 0xb0, 0x4e, 0x52, 0xb3, 0x8c, 0x70, 0x47, 0xbc, 0x7a, 0xa6, - 0xa1, 0xec, 0x08, 0x36, 0xec, 0x8b, 0x72, 0x35, 0x23, 0xd1, 0x94, 0x50, 0xd8, 0xf1, 0x3c, 0xc6, - 0xcd, 0x18, 0x1c, 0xc7, 0x2e, 0xe1, 0xac, 0x19, 0x7a, 0x08, 0xd7, 0xe7, 0x96, 0x76, 0xea, 0x9d, - 0xba, 0x53, 0x3e, 0x15, 0xe9, 0x99, 0x31, 0x20, 0x1b, 0xa4, 0xc0, 0xae, 0xcd, 0x2c, 0xe2, 0xbe, - 0x77, 0xba, 0x4f, 0x34, 0xda, 0x9c, 0xfc, 0x0a, 0xde, 0x9d, 0x1b, 0x45, 0x57, 0x7a, 0xf2, 0xd8, - 0x3b, 0x8e, 0x78, 0x30, 0xb8, 0x4c, 0x5f, 0x74, 0x65, 0x66, 0x88, 0x43, 0xa4, 0x78, 0xa4, 0x09, - 0x8c, 0x43, 0x77, 0x0c, 0x6d, 0x0a, 0x43, 0x90, 0x36, 0xcc, 0xab, 0x6e, 0x2b, 0x6f, 0xae, 0xba, - 0xfd, 0x14, 0xba, 0xc6, 0xdb, 0xbf, 0xa8, 0x8c, 0xb7, 0xa3, 0xf1, 0xf8, 0x2c, 0x87, 0x77, 0xa0, - 0x4d, 0xae, 0x3e, 0xbd, 0xe3, 0x3a, 0x74, 0xa8, 0xda, 0xcb, 0x3d, 0x8e, 0x84, 0x7f, 0x62, 0x9d, - 0x73, 0x02, 0x3d, 0x40, 0xc8, 0x10, 0xa0, 0xf5, 0x3c, 0x0e, 0x45, 0xbc, 0x13, 0x45, 0xc3, 0xbf, - 0x6c, 0x40, 0x1b, 0x7d, 0x02, 0x8a, 0x9b, 0xe0, 0xb1, 0x8a, 0x16, 0x8e, 0x72, 0xa9, 0x53, 0x2f, - 0x31, 0x75, 0xc5, 0x1d, 0x04, 0x22, 0xd5, 0xbe, 0x97, 0xcc, 0xa5, 0x5a, 0x97, 0xe6, 0x52, 0xad, - 0x1f, 0xe8, 0xbb, 0x2f, 0xba, 0xde, 0x8c, 0xdb, 0x42, 0x55, 0x1a, 0xe0, 0x81, 0x06, 0xa1, 0xaf, - 0x42, 0x24, 0x5e, 0x44, 0xfe, 0x0d, 0x9e, 0x9e, 0x22, 0x69, 0xb2, 0xb2, 0x24, 0x37, 0x3b, 0x06, - 0x71, 0xc8, 0xb5, 0x3e, 0x2e, 0x05, 0xcb, 0xea, 0xf3, 0xc1, 0xb2, 0xdb, 0x00, 0xbe, 0x88, 0x03, - 0x72, 0xa1, 0xe6, 0xb2, 0x61, 0x3a, 0x25, 0x5a, 0x60, 0xbf, 0x47, 0x68, 0xf6, 0x63, 0xe8, 0xe7, - 0x14, 0xe8, 0x21, 0xf9, 0x71, 0x7e, 0xfe, 0x34, 0x54, 0x0e, 0x1f, 0xed, 0xc6, 0x6a, 0x3e, 0x86, - 0xdb, 0x5e, 0x88, 0xe1, 0x5e, 0x90, 0x3c, 0x87, 0x1f, 0x7c, 0x2d, 0xe3, 0x0a, 0xb4, 0xa8, 0x4a, - 0x27, 0xc8, 0x12, 0xa3, 0xab, 0x9b, 0xa1, 0xa4, 0x58, 0xfb, 0x45, 0x71, 0xe2, 0xee, 0xff, 0xaf, - 0x38, 0x71, 0xef, 0xfb, 0xc5, 0x89, 0x97, 0xbf, 0x5f, 0x9c, 0x78, 0x2e, 0xae, 0xba, 0x32, 0x9f, - 0x8e, 0xb9, 0x30, 0xf9, 0xd1, 0xbf, 0x30, 0xf9, 0xf1, 0x96, 0xcc, 0xc5, 0xea, 0x1b, 0x33, 0x17, - 0xdf, 0x23, 0x75, 0xc2, 0xde, 0x96, 0x3a, 0xb9, 0x05, 0x2b, 0x2a, 0xf5, 0xfc, 0x13, 0x7d, 0x12, - 0x39, 0xe1, 0x67, 0xd2, 0xa4, 0x6a, 0x7a, 0x04, 0xc6, 0x73, 0xc8, 0x6f, 0xf8, 0x99, 0x1c, 0x3e, - 0x07, 0xa0, 0x23, 0x1a, 0x7d, 0xda, 0x45, 0xb2, 0x51, 0xf9, 0xc1, 0x85, 0x15, 0xff, 0xa7, 0x02, - 0x70, 0xe8, 0x4d, 0x13, 0x1d, 0xe3, 0x64, 0x7f, 0x08, 0x1d, 0x49, 0xad, 0x72, 0x86, 0xbb, 0x64, - 0xc8, 0x0a, 0x52, 0xf3, 0xa8, 0x6f, 0x17, 0xc8, 0xfc, 0x99, 0xc4, 0x5a, 0x8f, 0x90, 0x17, 0xb1, - 0xd5, 0x2d, 0x01, 0xc5, 0xbe, 0x6e, 0xc2, 0xb2, 0x21, 0x48, 0x78, 0xea, 0xf3, 0x58, 0x57, 0xc6, - 0x56, 0x9c, 0x9e, 0x86, 0x1e, 0x68, 0x20, 0xbb, 0x9f, 0x93, 0x59, 0x93, 0xb1, 0x98, 0xa6, 0x31, - 0x5d, 0x8c, 0xcd, 0x18, 0x6e, 0xdb, 0x4f, 0xa1, 0x89, 0xb4, 0xa0, 0x86, 0xef, 0xeb, 0xbf, 0xc3, - 0x3a, 0xd0, 0x34, 0xa3, 0xf6, 0x2b, 0xac, 0x07, 0x6d, 0xba, 0xce, 0x42, 0xb8, 0xa5, 0xe1, 0x1f, - 0xaf, 0x42, 0x67, 0x2f, 0x96, 0x2a, 0xcd, 0xb4, 0x08, 0x17, 0x97, 0x36, 0xea, 0x74, 0x69, 0xc3, - 0x54, 0x50, 0xea, 0xcf, 0xa0, 0x0a, 0xca, 0x4f, 0xa1, 0x69, 0xee, 0x07, 0x99, 0xc0, 0xf7, 0xb9, - 0x97, 0x8b, 0x2c, 0x0d, 0xdb, 0x82, 0x56, 0x60, 0x2e, 0x2e, 0x99, 0x34, 0x7e, 0xe9, 0x36, 0x91, - 0xbd, 0xd2, 0xe4, 0xe4, 0x34, 0xec, 0x03, 0xa8, 0x7a, 0xe3, 0xb1, 0x39, 0xf5, 0xae, 0x14, 0xa4, - 0xe4, 0xc4, 0x38, 0x88, 0x63, 0x77, 0xa1, 0x4d, 0xea, 0x93, 0x2a, 0x59, 0x1a, 0xf3, 0x63, 0xda, - 0x32, 0x19, 0xad, 0x51, 0x29, 0x66, 0x7e, 0x17, 0xda, 0x91, 0x10, 0x89, 0xee, 0xd0, 0x9c, 0xef, - 0x60, 0x8b, 0x1b, 0x9c, 0x56, 0x64, 0xcb, 0x1c, 0x6e, 0x41, 0x03, 0xdd, 0x63, 0x91, 0x18, 0xb7, - 0xb2, 0x34, 0x0f, 0x4a, 0xf2, 0x3b, 0x75, 0x89, 0x3f, 0x6c, 0x1b, 0x40, 0xcb, 0x3f, 0x8d, 0xdc, - 0x9e, 0x67, 0x47, 0x9e, 0xcf, 0xc3, 0x4d, 0x6a, 0x53, 0x7b, 0x0f, 0xa0, 0xaf, 0x73, 0x37, 0xa5, - 0x9e, 0x60, 0xeb, 0xff, 0x6c, 0xcf, 0xd9, 0x74, 0xa0, 0xb3, 0x9c, 0xce, 0xa6, 0x07, 0x3f, 0x81, - 0x66, 0xa2, 0x93, 0x17, 0xa4, 0x61, 0x3a, 0xdb, 0xab, 0x45, 0x57, 0x93, 0xd5, 0x70, 0x2c, 0x05, - 0xfb, 0x03, 0x58, 0xd6, 0x75, 0x6a, 0x23, 0x13, 0xc5, 0xa7, 0xc8, 0xd7, 0xcc, 0xd5, 0x92, 0x99, - 0x20, 0xbf, 0xd3, 0x53, 0x33, 0x31, 0xff, 0x5f, 0x40, 0xaf, 0x28, 0xf5, 0xf7, 0xbd, 0x98, 0xf4, - 0x0e, 0x45, 0xd3, 0x6d, 0xf7, 0xf2, 0x69, 0xc5, 0xe9, 0xf2, 0xf2, 0xd9, 0x65, 0x13, 0x1a, 0xa6, - 0x76, 0xb2, 0x4f, 0xbd, 0x4a, 0x37, 0x4f, 0x75, 0xb5, 0x94, 0x63, 0xf0, 0xc8, 0xcb, 0xa2, 0x2c, - 0x8c, 0x1c, 0xab, 0x19, 0x5e, 0xe6, 0x35, 0x61, 0x4e, 0x3b, 0x2f, 0x07, 0x63, 0x8f, 0x66, 0xcb, - 0xd4, 0x74, 0x39, 0xd6, 0x1a, 0x75, 0xbd, 0x72, 0x4e, 0x57, 0x5d, 0x95, 0xe5, 0xac, 0x24, 0x73, - 0xd5, 0x6e, 0x77, 0xa0, 0x25, 0xd2, 0x80, 0x2a, 0x6b, 0x29, 0xd7, 0x4b, 0xfc, 0xa4, 0xea, 0x3c, - 0x7d, 0x29, 0x8a, 0x94, 0x47, 0x53, 0xe8, 0x06, 0x3a, 0x16, 0x49, 0x2a, 0xc8, 0x0b, 0x24, 0x15, - 0x77, 0x69, 0xd1, 0xb1, 0x30, 0x78, 0x52, 0x70, 0x1f, 0x41, 0xd3, 0x56, 0x84, 0x6e, 0x2c, 0x50, - 0x5a, 0x14, 0xfb, 0x0c, 0x56, 0x66, 0x15, 0x9a, 0x1c, 0x5c, 0x5e, 0xa0, 0x5e, 0x9e, 0xd1, 0x5f, - 0x68, 0x8d, 0xeb, 0x51, 0x38, 0x0d, 0xd5, 0x60, 0xb0, 0x70, 0xf8, 0xd1, 0x08, 0x3c, 0x1f, 0x99, - 0x14, 0xc1, 0x95, 0xc5, 0xf3, 0x91, 0x49, 0x23, 0x0c, 0xa0, 0x19, 0xca, 0xc7, 0x61, 0x2a, 0xd5, - 0xe0, 0xaa, 0xb5, 0x8e, 0xd4, 0x64, 0x1b, 0xd0, 0x08, 0x25, 0x9a, 0x89, 0xc1, 0x35, 0x7b, 0x8d, - 0x8e, 0x8c, 0xc6, 0x6d, 0x68, 0x98, 0x6a, 0xd9, 0x1b, 0x0b, 0x3b, 0xda, 0xd4, 0xa4, 0x3b, 0x86, - 0x82, 0xfd, 0x04, 0x9a, 0x54, 0x2a, 0x29, 0x92, 0xc1, 0x07, 0xf3, 0x12, 0xa0, 0xeb, 0x15, 0x9d, - 0x46, 0xa4, 0xeb, 0x16, 0x3f, 0x81, 0xa6, 0x75, 0x52, 0x86, 0xf3, 0x52, 0x6d, 0x9c, 0x15, 0xc7, - 0x52, 0xb0, 0x9b, 0x50, 0x9f, 0xa2, 0x1e, 0x1b, 0x7c, 0x38, 0xbf, 0x43, 0xb5, 0x7a, 0xd3, 0x58, - 0xf6, 0xf7, 0xe0, 0x6a, 0xb9, 0xd8, 0xd0, 0x56, 0x22, 0x9a, 0x00, 0xe0, 0x4d, 0xea, 0xfb, 0xc1, - 0x39, 0xa2, 0x32, 0x5b, 0xb3, 0xe8, 0x5c, 0x4e, 0x2e, 0x28, 0x66, 0xfc, 0x22, 0x57, 0xf7, 0xb8, - 0xbb, 0x06, 0xb7, 0x6c, 0x19, 0xe3, 0xa2, 0xc1, 0xb0, 0x46, 0x80, 0xec, 0xcc, 0x97, 0xd0, 0x1d, - 0x65, 0xaf, 0x5f, 0x9f, 0xd9, 0xe0, 0xf5, 0xc7, 0xd4, 0xaf, 0x74, 0x04, 0x2f, 0xd5, 0x37, 0x3a, - 0x9d, 0x51, 0xa9, 0xd8, 0xf1, 0x32, 0x34, 0xfd, 0xd8, 0xf5, 0x82, 0x20, 0x1d, 0x6c, 0xea, 0xfa, - 0x46, 0x3f, 0xde, 0x09, 0x02, 0xba, 0x35, 0x2c, 0x12, 0x4e, 0x57, 0xf4, 0xdc, 0x30, 0x18, 0xfc, - 0x44, 0x1b, 0x1e, 0x0b, 0xda, 0x0b, 0xe8, 0x5a, 0xb1, 0x3d, 0xb7, 0x86, 0xc1, 0xe0, 0xb6, 0xb9, - 0x56, 0x6c, 0x40, 0x7b, 0x01, 0x3a, 0x9e, 0xe8, 0xe4, 0x5b, 0xc8, 0xe0, 0x13, 0x9d, 0x10, 0x98, - 0x7a, 0xa7, 0x07, 0x06, 0x84, 0x9b, 0x54, 0xa7, 0xd7, 0x48, 0x6d, 0xdd, 0x99, 0xdf, 0xa4, 0x79, - 0x9a, 0xd2, 0x69, 0x87, 0x79, 0xc6, 0x92, 0x36, 0x36, 0xa9, 0x22, 0x37, 0xda, 0x1e, 0x7c, 0xba, - 0xb8, 0xb1, 0x4d, 0x16, 0x16, 0x37, 0xb6, 0x4d, 0xc8, 0x6e, 0x03, 0x68, 0x9d, 0x45, 0x0a, 0x67, - 0x6b, 0xbe, 0x4f, 0x7e, 0x1a, 0x70, 0xf4, 0x65, 0x00, 0x52, 0x35, 0xdb, 0x00, 0x14, 0x7e, 0xd7, - 0x7d, 0xee, 0xce, 0xf7, 0xc9, 0xbd, 0x7b, 0xa7, 0xfd, 0x32, 0x77, 0xf4, 0xef, 0x42, 0x3b, 0x43, - 0x3f, 0x1e, 0x3d, 0xe9, 0xc1, 0xbd, 0x79, 0x61, 0xb6, 0x2e, 0xbe, 0xd3, 0xca, 0xcc, 0x13, 0xbe, - 0x84, 0x6c, 0x0f, 0xb9, 0x21, 0x83, 0xfb, 0xf3, 0x2f, 0xc9, 0xcf, 0x01, 0x0e, 0x99, 0x28, 0x7d, - 0x24, 0xf8, 0x02, 0x3a, 0x9a, 0x69, 0xba, 0xd3, 0xf6, 0xbc, 0x8c, 0x14, 0x7e, 0x8d, 0xa3, 0xb9, - 0xab, 0xbb, 0xdd, 0x84, 0xba, 0x97, 0x24, 0xd1, 0xd9, 0xe0, 0xb3, 0x79, 0x09, 0xdf, 0x41, 0xb0, - 0xa3, 0xb1, 0x28, 0x4a, 0xd3, 0x2c, 0x52, 0xa1, 0xad, 0xdf, 0xff, 0x7c, 0x5e, 0x94, 0x4a, 0x17, - 0xa2, 0x9c, 0xce, 0xb4, 0x74, 0x3b, 0xea, 0x0e, 0xb4, 0x12, 0x21, 0x95, 0x1b, 0x4c, 0xa3, 0xc1, - 0x17, 0x0b, 0x66, 0x44, 0x57, 0xa1, 0x3b, 0xcd, 0xc4, 0x94, 0xf1, 0xcf, 0x5c, 0xd3, 0xfb, 0xe9, - 0xec, 0x35, 0x3d, 0xb6, 0x0d, 0xdd, 0xa9, 0x88, 0xc7, 0x22, 0x38, 0xd6, 0xdc, 0xff, 0x59, 0xb9, - 0xc6, 0x79, 0x1f, 0x31, 0xc4, 0xf9, 0x8e, 0x21, 0xc2, 0x86, 0x3e, 0xdb, 0xfd, 0xba, 0xd6, 0x5a, + 0x02, 0x02, 0x34, 0x13, 0xed, 0x1a, 0xdf, 0xb7, 0x33, 0xd1, 0x3d, 0x7a, 0x17, 0xf4, 0xd0, 0xf3, + 0xd1, 0x5d, 0x6e, 0x40, 0x97, 0xf6, 0x7d, 0xea, 0x25, 0xae, 0xf2, 0xc6, 0xc6, 0x1a, 0x03, 0x84, + 0xed, 0x7b, 0xc9, 0x91, 0x37, 0x66, 0x0e, 0x5c, 0x99, 0xe3, 0xb7, 0x63, 0x64, 0x5d, 0xbd, 0x6a, + 0x2b, 0x36, 0xa0, 0x70, 0x3e, 0xd7, 0x6d, 0xcc, 0x70, 0x1d, 0xb1, 0x3c, 0xae, 0xee, 0xf0, 0x9f, + 0x2e, 0x41, 0xeb, 0x89, 0x10, 0xc9, 0x8f, 0x64, 0xbd, 0xf2, 0x96, 0x2e, 0x5d, 0xbc, 0xa5, 0xd5, + 0xd9, 0x2d, 0x9d, 0x5b, 0xfa, 0xda, 0xf7, 0x5f, 0xfa, 0xfa, 0x0f, 0x5e, 0xfa, 0xc6, 0x8f, 0x58, + 0xfa, 0xe6, 0xfc, 0xd2, 0x0f, 0x9b, 0x50, 0x3f, 0xe4, 0xea, 0x59, 0x32, 0xfc, 0x97, 0x2d, 0x68, + 0x3f, 0xe4, 0x41, 0xa6, 0x17, 0xac, 0xfc, 0xf9, 0x95, 0x8b, 0x3f, 0x7f, 0x69, 0xf6, 0xf3, 0x51, + 0x11, 0x59, 0x8e, 0x3e, 0x27, 0x36, 0xd6, 0xb2, 0x0c, 0x8d, 0xac, 0x5f, 0xf0, 0xb3, 0x09, 0x30, + 0xcd, 0x2c, 0x53, 0xce, 0xce, 0x6f, 0xe6, 0x8d, 0xfa, 0x8f, 0xe2, 0x8d, 0x39, 0xa9, 0xb0, 0x10, + 0x7a, 0x7a, 0xeb, 0xaa, 0xcd, 0x4b, 0x84, 0xd6, 0x82, 0x44, 0x78, 0x02, 0x6b, 0x22, 0x76, 0x83, + 0x2c, 0x89, 0x42, 0xf4, 0x55, 0x5c, 0x4f, 0x7b, 0xea, 0x6d, 0x9b, 0x6f, 0xc9, 0x59, 0xef, 0x59, + 0xfc, 0xd0, 0x12, 0x69, 0xff, 0xdd, 0x59, 0x15, 0xf3, 0x20, 0x14, 0x53, 0x01, 0x6e, 0x0d, 0xe9, + 0x55, 0xb2, 0x08, 0x75, 0xe2, 0xa8, 0x4b, 0xd0, 0x5d, 0x11, 0x91, 0xa6, 0xf8, 0x12, 0x56, 0x0a, + 0x2a, 0xcd, 0x23, 0x9d, 0x0b, 0x78, 0xa4, 0x67, 0x3b, 0x6a, 0x36, 0xf9, 0xeb, 0x90, 0x02, 0x9f, + 0xc2, 0x9a, 0x0d, 0x4b, 0x18, 0xe3, 0x80, 0x76, 0x70, 0x99, 0x38, 0xa8, 0x6f, 0x22, 0x11, 0x64, + 0x17, 0xd0, 0x16, 0xfd, 0x02, 0xd6, 0x4b, 0xe4, 0xe8, 0x37, 0x94, 0xa5, 0x41, 0x99, 0x57, 0x56, + 0xf3, 0xbe, 0xd8, 0x7c, 0xa2, 0xc3, 0xb3, 0x9d, 0x80, 0x47, 0xf6, 0x45, 0x83, 0xbe, 0x76, 0x7b, + 0x02, 0x1e, 0x99, 0x6c, 0xd1, 0x3e, 0x7c, 0x84, 0xde, 0x05, 0xe2, 0x7d, 0x2f, 0x51, 0x59, 0xca, + 0xdd, 0x24, 0xf2, 0x7c, 0x3e, 0x11, 0x51, 0xc0, 0xd3, 0x62, 0x72, 0xab, 0x34, 0xb9, 0xeb, 0x22, + 0x0a, 0x76, 0x45, 0xb4, 0xab, 0x29, 0x0f, 0x0a, 0x42, 0x3b, 0xd7, 0x1d, 0x78, 0x7f, 0x61, 0x38, + 0x54, 0x1c, 0xc5, 0x40, 0x8c, 0x06, 0xba, 0x32, 0x3b, 0x10, 0x92, 0xd8, 0x21, 0xee, 0xc3, 0x25, + 0xbd, 0x77, 0x9a, 0xb9, 0x4f, 0x38, 0x4f, 0xdc, 0xc8, 0x93, 0x6a, 0xb0, 0xa6, 0x95, 0x34, 0x21, + 0x89, 0x81, 0x7f, 0xc3, 0x79, 0xf2, 0xc4, 0xd3, 0x6f, 0xd5, 0x5d, 0x8c, 0x1d, 0x4f, 0x7d, 0x66, + 0xd6, 0x76, 0x5d, 0xbf, 0x95, 0xa8, 0xb4, 0x31, 0x8f, 0x9d, 0x4b, 0x8b, 0xfc, 0xfb, 0x70, 0x6d, + 0x66, 0x88, 0xa9, 0x97, 0x9e, 0x14, 0x86, 0xed, 0xe0, 0x12, 0xad, 0xdb, 0xe5, 0x52, 0xff, 0x7d, + 0x22, 0xd0, 0x23, 0x0c, 0xff, 0x5b, 0x1d, 0x96, 0x49, 0x0f, 0xff, 0xad, 0xd8, 0xf8, 0x5b, 0xb1, + 0xf1, 0x37, 0x40, 0x6c, 0x0c, 0xff, 0x41, 0x05, 0x9a, 0x07, 0xa9, 0x08, 0x32, 0x5f, 0xfd, 0x48, + 0x4e, 0x9f, 0xe5, 0xa0, 0xea, 0xdb, 0x38, 0xa8, 0xb6, 0xa0, 0xae, 0xff, 0x59, 0x05, 0xda, 0x66, + 0x0a, 0x4f, 0xb6, 0x7f, 0xe4, 0x24, 0x8a, 0xe4, 0x55, 0xe5, 0xdc, 0xe4, 0xd5, 0x5b, 0x67, 0x81, + 0x8c, 0xf5, 0x52, 0x67, 0xf1, 0x45, 0x52, 0x64, 0xb2, 0xda, 0x4e, 0x57, 0x43, 0x9f, 0x25, 0x94, + 0xb0, 0x7a, 0x05, 0x6d, 0xf2, 0x9c, 0x48, 0x32, 0x6c, 0x40, 0x23, 0xa5, 0x0c, 0x8b, 0x99, 0xa8, + 0x69, 0xbd, 0xf9, 0x9c, 0x2e, 0xfd, 0x38, 0xd3, 0xef, 0xdf, 0x2e, 0x41, 0x8f, 0xdc, 0xd8, 0xc7, + 0x59, 0xac, 0x4f, 0x42, 0x1e, 0x3e, 0xab, 0xcc, 0x86, 0xcf, 0x6a, 0x29, 0x7a, 0x9b, 0xfa, 0x35, + 0x5d, 0xfd, 0x9a, 0x5d, 0x11, 0x3d, 0xe4, 0x23, 0x87, 0x30, 0xb8, 0x54, 0x5e, 0x3a, 0x96, 0xe7, + 0xe5, 0xf9, 0x10, 0x8e, 0x5f, 0x95, 0x78, 0xa9, 0x37, 0x95, 0x36, 0xcf, 0xa7, 0x5b, 0x8c, 0x41, + 0x8d, 0xce, 0x9b, 0x5e, 0x16, 0x7a, 0x36, 0x11, 0x19, 0x19, 0xc6, 0xe3, 0x5c, 0x78, 0xb4, 0x28, + 0xbf, 0x3b, 0x8e, 0x38, 0x7b, 0x08, 0x4c, 0x07, 0x6c, 0x53, 0xee, 0xa1, 0x0a, 0xa2, 0x71, 0x48, + 0x82, 0x74, 0xb6, 0x37, 0xf4, 0x6b, 0x69, 0x2d, 0x1d, 0x42, 0x1f, 0x20, 0xd6, 0xe9, 0x87, 0x73, + 0x90, 0x73, 0x16, 0x53, 0xeb, 0xa1, 0xdc, 0xfb, 0xf8, 0xde, 0x8b, 0x49, 0xca, 0x89, 0x16, 0x73, + 0x07, 0x2e, 0xd9, 0xec, 0x09, 0x8a, 0x8b, 0x6d, 0x3c, 0x0b, 0xe4, 0x0f, 0xdb, 0x6f, 0xac, 0x94, + 0xbe, 0x71, 0x1d, 0xea, 0xe5, 0xba, 0x0e, 0xdd, 0x18, 0xde, 0x84, 0xce, 0x28, 0x8c, 0xb8, 0x89, + 0x42, 0xe2, 0xa2, 0x99, 0x78, 0x64, 0x85, 0x2a, 0x1b, 0x4c, 0x6b, 0xf8, 0xdb, 0x0a, 0x5c, 0x4e, + 0xbc, 0xf4, 0x45, 0xc6, 0x15, 0xc5, 0x22, 0x29, 0xdb, 0xe6, 0xca, 0x89, 0x97, 0x06, 0x78, 0x70, + 0x68, 0x08, 0x3d, 0xba, 0x2e, 0x1f, 0x68, 0x23, 0x44, 0xcf, 0xe5, 0x16, 0xac, 0x94, 0x7a, 0x28, + 0x2f, 0xb5, 0xd1, 0xa2, 0x5e, 0x2a, 0x5e, 0x51, 0xd2, 0xf4, 0x10, 0x81, 0xe8, 0x50, 0x16, 0x74, + 0x9c, 0xb4, 0x0d, 0x65, 0xe1, 0x2d, 0xd5, 0xa3, 0x38, 0xc0, 0x93, 0x13, 0x67, 0x53, 0x1d, 0x4c, + 0xd1, 0xd5, 0x1f, 0xcd, 0x38, 0x9b, 0x52, 0xfc, 0x64, 0x1d, 0xea, 0xc7, 0x67, 0x8a, 0xac, 0x75, + 0x84, 0xeb, 0xc6, 0xf0, 0x2f, 0xea, 0xb0, 0xb6, 0xe7, 0xf3, 0x63, 0x9e, 0x8e, 0x1f, 0x7a, 0xca, + 0x7b, 0x1c, 0x46, 0xfc, 0xc8, 0x93, 0x27, 0xb8, 0xe1, 0x34, 0xe7, 0xc4, 0x53, 0x13, 0xb3, 0x4a, + 0x2d, 0x04, 0x1c, 0x78, 0x6a, 0x82, 0xaa, 0x80, 0x90, 0x23, 0x91, 0x4e, 0x4d, 0x6c, 0xab, 0xed, + 0xd0, 0x37, 0x3e, 0x26, 0x48, 0xde, 0x5b, 0x86, 0xaf, 0xb9, 0xa9, 0x55, 0xa1, 0xde, 0x94, 0xf8, + 0xfc, 0x00, 0xba, 0x29, 0xf7, 0x45, 0x1a, 0x98, 0x80, 0xad, 0x9e, 0x67, 0x47, 0xc3, 0x74, 0xa8, + 0xf6, 0x36, 0x14, 0x59, 0x05, 0x72, 0xdf, 0xdd, 0xd0, 0x26, 0xbe, 0x57, 0x72, 0x04, 0xee, 0xfc, + 0x5e, 0xc0, 0xfe, 0x2e, 0xf4, 0x0b, 0x5a, 0x0a, 0x71, 0x5b, 0xf7, 0x62, 0xbb, 0x08, 0xc1, 0x9c, + 0xf3, 0x89, 0x5b, 0x07, 0xb6, 0xd7, 0xdf, 0xa1, 0x4e, 0x3a, 0x8c, 0x5f, 0x0c, 0xaf, 0xa1, 0xec, + 0x43, 0xe8, 0xc9, 0x24, 0x0a, 0x95, 0x61, 0x00, 0x69, 0x2a, 0x5a, 0xba, 0x04, 0xd4, 0x91, 0x68, + 0x79, 0xde, 0x16, 0xb6, 0xbe, 0xd7, 0x16, 0xb6, 0x17, 0xb7, 0xf0, 0x27, 0xd0, 0xf7, 0x53, 0x1e, + 0xf0, 0x58, 0x85, 0x5e, 0xe4, 0x4a, 0x5f, 0x24, 0x56, 0xf5, 0xad, 0x14, 0xf0, 0x43, 0x04, 0xb3, + 0x9f, 0xc2, 0x65, 0x5f, 0xc4, 0x8a, 0xc7, 0xca, 0x95, 0xfc, 0x45, 0xc6, 0x63, 0x9f, 0xbb, 0x71, + 0x36, 0x3d, 0xe6, 0xa9, 0xc9, 0xe9, 0x5e, 0x32, 0xe8, 0x43, 0x83, 0x7d, 0x4a, 0x48, 0x76, 0x0f, + 0xd6, 0xf5, 0xf6, 0xcc, 0x75, 0xd2, 0x59, 0x44, 0x46, 0x3b, 0x35, 0xdb, 0x63, 0x0b, 0xd6, 0x26, + 0x9e, 0x74, 0x53, 0x2e, 0xc3, 0x20, 0xf3, 0x22, 0x73, 0x42, 0x4d, 0xee, 0x62, 0x75, 0xe2, 0x49, + 0xc7, 0x60, 0x4c, 0x78, 0x88, 0xa2, 0xd7, 0x33, 0xb4, 0xee, 0xc4, 0x93, 0x13, 0x72, 0x9f, 0xdb, + 0x0e, 0x4b, 0x67, 0xa8, 0xbf, 0xf6, 0xe4, 0xe4, 0xea, 0x03, 0x58, 0x3f, 0x6f, 0x43, 0xde, 0x96, + 0xd6, 0x68, 0x97, 0xd2, 0x1a, 0xa6, 0xae, 0xeb, 0x7f, 0x2c, 0xc1, 0x25, 0xbb, 0xdf, 0x64, 0xf8, + 0xe5, 0x4c, 0x7d, 0x9d, 0x74, 0x24, 0x1a, 0x8b, 0xb9, 0x2f, 0xdd, 0x76, 0x40, 0x83, 0xc8, 0x71, + 0xde, 0x84, 0xbe, 0x21, 0x28, 0x98, 0x5f, 0xbf, 0x65, 0x39, 0xc8, 0x87, 0xa2, 0x23, 0x40, 0x1f, + 0x38, 0xe2, 0x29, 0xae, 0x51, 0x40, 0x15, 0x79, 0xd4, 0x85, 0x98, 0x9d, 0x3e, 0xd0, 0xe2, 0x2c, + 0xcb, 0xb1, 0x3b, 0xc0, 0xf8, 0x8b, 0xcc, 0x8b, 0x42, 0x75, 0xe6, 0x8e, 0x42, 0x1e, 0x05, 0x94, + 0x43, 0xd3, 0x85, 0x3a, 0x7d, 0x8b, 0x79, 0x8c, 0x88, 0xbd, 0x40, 0x96, 0x66, 0x62, 0x52, 0x33, + 0xf9, 0x01, 0x30, 0x33, 0x39, 0x24, 0xf0, 0x5e, 0x70, 0xfe, 0x59, 0x69, 0x9c, 0x7f, 0x56, 0x3e, + 0x86, 0x95, 0xf9, 0x3d, 0xd7, 0xe9, 0x92, 0x65, 0x39, 0xbb, 0xdf, 0xe7, 0x31, 0x61, 0xeb, 0x5c, + 0x26, 0x34, 0x8b, 0xfe, 0xbf, 0x96, 0x60, 0xdd, 0x2c, 0xfa, 0xae, 0x88, 0xb2, 0x29, 0x6a, 0xdb, + 0x24, 0x8c, 0xc7, 0xa8, 0x90, 0xa7, 0x42, 0x9b, 0x25, 0x25, 0xf1, 0x07, 0x53, 0x91, 0xcb, 0xe2, + 0x4d, 0xe8, 0x87, 0xba, 0x67, 0xbe, 0x2e, 0xb6, 0xb4, 0xce, 0xc0, 0xcd, 0xaa, 0x20, 0x17, 0xca, + 0xd8, 0x4b, 0xe4, 0x44, 0x28, 0x43, 0x4a, 0x42, 0x5c, 0xaf, 0xf9, 0xaa, 0x45, 0x11, 0x35, 0x59, + 0x87, 0x77, 0x80, 0xf9, 0x59, 0x9a, 0xe2, 0xf9, 0x28, 0x91, 0xeb, 0x84, 0x44, 0xdf, 0x60, 0x0a, + 0xea, 0x0f, 0xa1, 0x39, 0x15, 0x85, 0x45, 0x30, 0x63, 0xdc, 0x39, 0x8d, 0xa9, 0x20, 0x0e, 0xb9, + 0x8a, 0x56, 0xcb, 0x8b, 0x2c, 0x4c, 0x79, 0x60, 0xf5, 0xa0, 0x6d, 0x1b, 0x25, 0x39, 0x09, 0x83, + 0x80, 0xc7, 0x26, 0x18, 0xde, 0x0a, 0xe5, 0xd7, 0xd4, 0xa6, 0xca, 0x33, 0x3e, 0xf2, 0xb2, 0x48, + 0xb9, 0x71, 0x16, 0xd1, 0xa9, 0x88, 0x4c, 0x3d, 0xd4, 0x8a, 0x41, 0x3c, 0xcd, 0x22, 0x3c, 0x11, + 0x91, 0xd9, 0x52, 0xd2, 0x25, 0xc8, 0x82, 0xee, 0x24, 0x8c, 0x15, 0x89, 0x8a, 0x36, 0x6d, 0x29, + 0x22, 0x90, 0x09, 0xbf, 0x0e, 0x63, 0x35, 0xfc, 0xb3, 0x25, 0xd8, 0x30, 0x0b, 0x7f, 0x68, 0x16, + 0xc0, 0xe8, 0x47, 0xb2, 0xd8, 0xed, 0x72, 0x99, 0x5c, 0x45, 0xd5, 0x01, 0x0b, 0xda, 0xa3, 0x09, + 0x17, 0xdc, 0xb5, 0x64, 0xea, 0xa4, 0x2c, 0x5f, 0xdd, 0x01, 0xb6, 0xc0, 0x57, 0xd2, 0xc4, 0x8c, + 0xfa, 0x73, 0x8c, 0x25, 0xd9, 0xe7, 0xb0, 0x31, 0xe5, 0xca, 0xa3, 0x83, 0x10, 0x09, 0xdf, 0xa3, + 0x5e, 0x74, 0xe4, 0xf5, 0x72, 0xaf, 0x5b, 0xec, 0x13, 0x83, 0xc4, 0x43, 0x8f, 0xef, 0x98, 0x7a, + 0x71, 0x38, 0xe2, 0x52, 0x91, 0x9e, 0xd7, 0x3d, 0xb4, 0xe1, 0xd1, 0xb7, 0x18, 0xd4, 0xe4, 0x44, + 0x4d, 0x16, 0xe3, 0x48, 0x6f, 0x62, 0x83, 0x68, 0x9a, 0x29, 0x1f, 0x99, 0xbd, 0xeb, 0xe1, 0x5e, + 0xc5, 0x61, 0x3c, 0xd6, 0xc5, 0xa1, 0x4d, 0x6d, 0xd3, 0x59, 0xe0, 0xbe, 0x08, 0xf8, 0xf0, 0x4f, + 0x6a, 0x39, 0x8f, 0x1e, 0x18, 0xf8, 0xa1, 0xf2, 0x94, 0x64, 0x37, 0x61, 0x39, 0x9f, 0xbc, 0xd6, + 0x91, 0x7a, 0xad, 0x7a, 0x16, 0xfa, 0x00, 0x81, 0xc8, 0x7e, 0xb3, 0xb3, 0xd5, 0xb4, 0x4b, 0x3a, + 0xe1, 0x58, 0x9e, 0xae, 0xa6, 0xc7, 0x61, 0x2d, 0xbd, 0x26, 0x35, 0x65, 0x9b, 0x16, 0xaa, 0xc9, + 0x3e, 0x2d, 0x16, 0x41, 0xba, 0x92, 0x47, 0xba, 0xda, 0xa6, 0x36, 0x3b, 0xaa, 0x3c, 0x34, 0x08, + 0x3c, 0x9a, 0x05, 0x79, 0x92, 0x66, 0x31, 0x0f, 0x8c, 0x4a, 0x5f, 0xc9, 0xe1, 0x07, 0x04, 0xc6, + 0x09, 0xe7, 0x92, 0xa9, 0x34, 0x74, 0x43, 0x0f, 0x1d, 0x18, 0xc9, 0x54, 0x0c, 0x8d, 0x3c, 0x5a, + 0xd0, 0x9b, 0xb1, 0xb5, 0x80, 0x58, 0xc9, 0xa9, 0xcd, 0xd8, 0x3f, 0x83, 0x41, 0x4e, 0xab, 0xbf, + 0xae, 0x78, 0x41, 0x4b, 0x2b, 0x1f, 0xdb, 0x85, 0x3e, 0x33, 0x7f, 0xc9, 0x67, 0xb0, 0x31, 0xdf, + 0xd1, 0xbc, 0xa9, 0x4d, 0xdd, 0xd6, 0x66, 0xba, 0x15, 0x5f, 0x92, 0xef, 0xaf, 0xef, 0xf9, 0x13, + 0xee, 0x4e, 0x42, 0x53, 0xb9, 0x59, 0x75, 0x56, 0x2d, 0x6a, 0x17, 0x31, 0x5f, 0x87, 0x4a, 0x9e, + 0x43, 0x3f, 0x0d, 0xa5, 0x34, 0x5a, 0x71, 0x96, 0x7e, 0x3f, 0x94, 0x72, 0xf8, 0x8f, 0x01, 0xba, + 0xd6, 0x52, 0xa4, 0xe2, 0xc2, 0x3b, 0x65, 0xa3, 0xbb, 0xb3, 0xdd, 0xb7, 0xd6, 0x33, 0x92, 0xec, + 0x28, 0x95, 0xda, 0xfc, 0x85, 0x36, 0xc6, 0x67, 0xec, 0x9d, 0x25, 0x32, 0x10, 0x0a, 0x7b, 0x67, + 0x07, 0x56, 0x4b, 0x16, 0xa4, 0xab, 0x84, 0xf2, 0x22, 0x63, 0x94, 0x97, 0x2a, 0x4a, 0x4a, 0x24, + 0xce, 0x0a, 0x36, 0xb4, 0x6d, 0x71, 0x84, 0xd4, 0x68, 0xec, 0xfb, 0x22, 0xb2, 0xd5, 0x6c, 0x73, + 0xc6, 0x3e, 0x62, 0x28, 0x57, 0x9e, 0x72, 0xf4, 0x1d, 0xe5, 0x8b, 0xc8, 0x9c, 0xa0, 0xb6, 0x86, + 0x1c, 0xbe, 0x88, 0xf2, 0x09, 0x92, 0x31, 0xdd, 0x20, 0x3f, 0x82, 0x26, 0x48, 0x3e, 0xd5, 0xa7, + 0xd0, 0x11, 0x69, 0x38, 0x0e, 0x29, 0xf5, 0xa5, 0x0d, 0x9c, 0xf9, 0x97, 0x80, 0x26, 0xd8, 0xc5, + 0x57, 0x0d, 0xa1, 0x61, 0xd4, 0xff, 0x62, 0xfe, 0xdc, 0x60, 0xd0, 0x20, 0x92, 0x2a, 0x0d, 0x7d, + 0x85, 0xd3, 0xd1, 0x27, 0x52, 0x17, 0x46, 0xf5, 0x34, 0xf8, 0xf0, 0x45, 0x44, 0xd9, 0xbf, 0x5b, + 0xb0, 0xe2, 0x93, 0xba, 0xd0, 0x07, 0x2a, 0xe2, 0x31, 0xed, 0x69, 0xdd, 0xe9, 0x69, 0x30, 0xce, + 0xef, 0x09, 0x8f, 0x4d, 0x11, 0x96, 0x17, 0x45, 0xe8, 0x31, 0x0a, 0x2f, 0x30, 0x19, 0xf3, 0xae, + 0x05, 0x3e, 0x11, 0x5e, 0xc0, 0x7e, 0x0e, 0x57, 0x11, 0xe7, 0xf2, 0x69, 0xa2, 0xce, 0x50, 0xbf, + 0xf1, 0x34, 0xf4, 0x5d, 0x4f, 0x52, 0x06, 0xdd, 0x24, 0xce, 0x37, 0x90, 0xe2, 0x11, 0x12, 0x3c, + 0xd5, 0xf8, 0x1d, 0xf9, 0x2d, 0x4f, 0x05, 0xfb, 0x96, 0x32, 0x80, 0xe7, 0x99, 0xef, 0xd6, 0xd5, + 0xff, 0xa0, 0xd8, 0xab, 0x0b, 0x28, 0xa9, 0x42, 0x05, 0x11, 0x8e, 0x35, 0xfa, 0xa8, 0x3f, 0xfb, + 0x0d, 0x30, 0xab, 0xe0, 0x88, 0xf3, 0x95, 0x27, 0x4f, 0x24, 0x45, 0x01, 0x3a, 0xdb, 0xef, 0xbd, + 0xd1, 0x46, 0x75, 0xac, 0x66, 0x44, 0x20, 0x02, 0x24, 0xfb, 0x23, 0x58, 0xcf, 0x07, 0x33, 0xb6, + 0x0c, 0x0d, 0xa7, 0x83, 0x04, 0xd7, 0x17, 0x87, 0x9b, 0x31, 0x81, 0x1c, 0x3b, 0x13, 0x0d, 0xd6, + 0x43, 0x7e, 0x05, 0x2b, 0x76, 0x48, 0xbd, 0xea, 0x72, 0xd0, 0xa7, 0xd1, 0xde, 0x5f, 0x18, 0x6d, + 0x46, 0xb7, 0xe7, 0xfa, 0x59, 0x43, 0xf1, 0x43, 0x73, 0x4d, 0x6e, 0xb5, 0xcc, 0x60, 0x95, 0x78, + 0xe4, 0xc6, 0xc2, 0x48, 0x73, 0xca, 0xca, 0xb1, 0x53, 0xb0, 0x70, 0x76, 0x1f, 0x2e, 0xd9, 0xc1, + 0x04, 0x25, 0x6c, 0xdd, 0x50, 0x50, 0x2e, 0x97, 0x69, 0x13, 0xcb, 0x20, 0x75, 0x32, 0x77, 0x4f, + 0x38, 0x7c, 0xc4, 0x7e, 0x09, 0xd7, 0x6c, 0x17, 0xad, 0x85, 0xc9, 0x23, 0xcd, 0x3f, 0x6a, 0x8d, + 0x74, 0xd7, 0xc0, 0x90, 0x68, 0xbd, 0x8c, 0x1e, 0xa8, 0x9d, 0xfe, 0x26, 0xf4, 0xa9, 0x34, 0x15, + 0xb7, 0x55, 0xa4, 0x41, 0x18, 0x7b, 0xd1, 0x60, 0x9d, 0xb8, 0x66, 0x19, 0xe1, 0x8e, 0x78, 0xf5, + 0x4c, 0x43, 0xd9, 0x11, 0x6c, 0xd8, 0x17, 0xe5, 0x62, 0x46, 0xa2, 0x2a, 0xa1, 0xb0, 0xe3, 0x79, + 0x0b, 0x37, 0xa3, 0x70, 0x1c, 0xbb, 0x85, 0xb3, 0x6a, 0xe8, 0x21, 0x5c, 0x9f, 0xdb, 0xda, 0xa9, + 0x77, 0xea, 0x4e, 0xf9, 0x54, 0xa4, 0x67, 0x46, 0x81, 0x6c, 0x90, 0x00, 0xbb, 0x36, 0xb3, 0x89, + 0xfb, 0xde, 0xe9, 0x3e, 0xd1, 0x68, 0x75, 0xf2, 0x2b, 0x78, 0x77, 0x6e, 0x14, 0x5d, 0xe9, 0xc9, + 0x63, 0xef, 0x38, 0xe2, 0xc1, 0xe0, 0x32, 0x7d, 0xd1, 0x95, 0x99, 0x21, 0x0e, 0x91, 0xe2, 0x91, + 0x26, 0x30, 0x06, 0xdd, 0x31, 0xb4, 0x29, 0x0c, 0x41, 0xd2, 0x30, 0xaf, 0xba, 0xad, 0xbc, 0xb9, + 0xea, 0xf6, 0x53, 0xe8, 0x1a, 0x6b, 0xff, 0xa2, 0x32, 0xde, 0x8e, 0xc6, 0xe3, 0xb3, 0x1c, 0xde, + 0x81, 0x36, 0x99, 0xfa, 0xf4, 0x8e, 0xeb, 0xd0, 0xa1, 0x6a, 0x2f, 0xf7, 0x38, 0x12, 0xfe, 0x89, + 0x35, 0xce, 0x09, 0xf4, 0x00, 0x21, 0x43, 0x80, 0xd6, 0xf3, 0x38, 0x14, 0xf1, 0x4e, 0x14, 0x0d, + 0xff, 0xb2, 0x01, 0x6d, 0xb4, 0x09, 0x28, 0x6e, 0x82, 0x6e, 0x15, 0x6d, 0x1c, 0xe5, 0x52, 0xa7, + 0x5e, 0x62, 0xea, 0x8a, 0x3b, 0x08, 0x44, 0xaa, 0x7d, 0x2f, 0x99, 0x4b, 0xb5, 0x2e, 0xcd, 0xa5, + 0x5a, 0x3f, 0xd0, 0x77, 0x5f, 0x74, 0xbd, 0x19, 0xb7, 0x85, 0xaa, 0x34, 0xc0, 0x03, 0x0d, 0x42, + 0x5b, 0x85, 0x48, 0xbc, 0x88, 0xec, 0x1b, 0xf4, 0x9e, 0x22, 0x69, 0xb2, 0xb2, 0xc4, 0x37, 0x3b, + 0x06, 0x71, 0xc8, 0xb5, 0x3c, 0x2e, 0x05, 0xcb, 0xea, 0xf3, 0xc1, 0xb2, 0xdb, 0x00, 0xbe, 0x88, + 0x03, 0x32, 0xa1, 0xe6, 0xb2, 0x61, 0x3a, 0x25, 0x5a, 0x60, 0xbf, 0x47, 0x68, 0xf6, 0x63, 0xe8, + 0xe7, 0x14, 0x68, 0x21, 0xf9, 0x71, 0xee, 0x7f, 0x1a, 0x2a, 0x87, 0x8f, 0x76, 0x63, 0x35, 0x1f, + 0xc3, 0x6d, 0x2f, 0xc4, 0x70, 0x2f, 0x48, 0x9e, 0xc3, 0x0f, 0xbe, 0x96, 0x71, 0x05, 0x5a, 0x54, + 0xa5, 0x13, 0x64, 0x89, 0x91, 0xd5, 0xcd, 0x50, 0x52, 0xac, 0xfd, 0xa2, 0x38, 0x71, 0xf7, 0xff, + 0x57, 0x9c, 0xb8, 0xf7, 0xfd, 0xe2, 0xc4, 0xcb, 0xdf, 0x2f, 0x4e, 0x3c, 0x17, 0x57, 0x5d, 0x99, + 0x4f, 0xc7, 0x5c, 0x98, 0xfc, 0xe8, 0x5f, 0x98, 0xfc, 0x78, 0x4b, 0xe6, 0x62, 0xf5, 0x8d, 0x99, + 0x8b, 0xef, 0x91, 0x3a, 0x61, 0x6f, 0x4b, 0x9d, 0xdc, 0x82, 0x15, 0x95, 0x7a, 0xfe, 0x89, 0xf6, + 0x44, 0x4e, 0xf8, 0x99, 0x34, 0xa9, 0x9a, 0x1e, 0x81, 0xd1, 0x0f, 0xf9, 0x0d, 0x3f, 0x93, 0xc3, + 0xe7, 0x00, 0xe4, 0xa2, 0xd1, 0xa7, 0x5d, 0xc4, 0x1b, 0x95, 0x1f, 0x5c, 0x58, 0xf1, 0x7f, 0x2a, + 0x00, 0x87, 0xde, 0x34, 0xd1, 0x31, 0x4e, 0xf6, 0x87, 0xd0, 0x91, 0xd4, 0x2a, 0x67, 0xb8, 0x4b, + 0x8a, 0xac, 0x20, 0x35, 0x8f, 0xfa, 0x76, 0x81, 0xcc, 0x9f, 0x89, 0xad, 0xf5, 0x08, 0x79, 0x11, + 0x5b, 0xdd, 0x12, 0x50, 0xec, 0xeb, 0x26, 0x2c, 0x1b, 0x82, 0x84, 0xa7, 0x3e, 0x8f, 0x75, 0x65, + 0x6c, 0xc5, 0xe9, 0x69, 0xe8, 0x81, 0x06, 0xb2, 0xfb, 0x39, 0x99, 0x55, 0x19, 0x8b, 0x69, 0x1a, + 0xd3, 0xc5, 0xe8, 0x8c, 0xe1, 0xb6, 0xfd, 0x14, 0x9a, 0x48, 0x0b, 0x6a, 0xf8, 0xbe, 0xfe, 0x3b, + 0xac, 0x03, 0x4d, 0x33, 0x6a, 0xbf, 0xc2, 0x7a, 0xd0, 0xa6, 0xeb, 0x2c, 0x84, 0x5b, 0x1a, 0xfe, + 0xf1, 0x2a, 0x74, 0xf6, 0x62, 0xa9, 0xd2, 0x4c, 0xb3, 0x70, 0x71, 0x69, 0xa3, 0x4e, 0x97, 0x36, + 0x4c, 0x05, 0xa5, 0xfe, 0x0c, 0xaa, 0xa0, 0xfc, 0x14, 0x9a, 0xe6, 0x7e, 0x90, 0x09, 0x7c, 0x9f, + 0x7b, 0xb9, 0xc8, 0xd2, 0xb0, 0x2d, 0x68, 0x05, 0xe6, 0xe2, 0x92, 0x49, 0xe3, 0x97, 0x6e, 0x13, + 0xd9, 0x2b, 0x4d, 0x4e, 0x4e, 0xc3, 0x3e, 0x80, 0xaa, 0x37, 0x1e, 0x1b, 0xaf, 0x77, 0xa5, 0x20, + 0x25, 0x23, 0xc6, 0x41, 0x1c, 0xbb, 0x0b, 0x6d, 0x12, 0x9f, 0x54, 0xc9, 0xd2, 0x98, 0x1f, 0xd3, + 0x96, 0xc9, 0x68, 0x89, 0x4a, 0x31, 0xf3, 0xbb, 0xd0, 0x8e, 0x84, 0x48, 0x74, 0x87, 0xe6, 0x7c, + 0x07, 0x5b, 0xdc, 0xe0, 0xb4, 0x22, 0x5b, 0xe6, 0x70, 0x0b, 0x1a, 0x68, 0x1e, 0x8b, 0xc4, 0x98, + 0x95, 0xa5, 0x79, 0x50, 0x92, 0xdf, 0xa9, 0x4b, 0xfc, 0x61, 0xdb, 0x00, 0x9a, 0xff, 0x69, 0xe4, + 0xf6, 0xfc, 0x72, 0xe4, 0xf9, 0x3c, 0x3c, 0xa4, 0x36, 0xb5, 0xf7, 0x00, 0xfa, 0x3a, 0x77, 0x53, + 0xea, 0x09, 0xb6, 0xfe, 0xcf, 0xf6, 0x9c, 0x4d, 0x07, 0x3a, 0xcb, 0xe9, 0x6c, 0x7a, 0xf0, 0x13, + 0x68, 0x26, 0x3a, 0x79, 0x41, 0x12, 0xa6, 0xb3, 0xbd, 0x5a, 0x74, 0x35, 0x59, 0x0d, 0xc7, 0x52, + 0xb0, 0x3f, 0x80, 0x65, 0x5d, 0xa7, 0x36, 0x32, 0x51, 0x7c, 0x8a, 0x7c, 0xcd, 0x5c, 0x2d, 0x99, + 0x09, 0xf2, 0x3b, 0x3d, 0x35, 0x13, 0xf3, 0xff, 0x05, 0xf4, 0x8a, 0x52, 0x7f, 0xdf, 0x8b, 0x49, + 0xee, 0x50, 0x34, 0xdd, 0x76, 0x2f, 0x7b, 0x2b, 0x4e, 0x97, 0x97, 0x7d, 0x97, 0x4d, 0x68, 0x98, + 0xda, 0xc9, 0x3e, 0xf5, 0x2a, 0xdd, 0x3c, 0xd5, 0xd5, 0x52, 0x8e, 0xc1, 0xe3, 0x5a, 0x16, 0x65, + 0x61, 0x64, 0x58, 0xcd, 0xac, 0x65, 0x5e, 0x13, 0xe6, 0xb4, 0xf3, 0x72, 0x30, 0xf6, 0x68, 0xb6, + 0x4c, 0x4d, 0x97, 0x63, 0xad, 0x51, 0xd7, 0x2b, 0xe7, 0x74, 0xd5, 0x55, 0x59, 0xce, 0x4a, 0x32, + 0x57, 0xed, 0x76, 0x07, 0x5a, 0x22, 0x0d, 0xa8, 0xb2, 0x96, 0x72, 0xbd, 0xb4, 0x9e, 0x54, 0x9d, + 0xa7, 0x2f, 0x45, 0x91, 0xf0, 0x68, 0x0a, 0xdd, 0x40, 0xc3, 0x22, 0x49, 0x05, 0x59, 0x81, 0x24, + 0xe2, 0x2e, 0x2d, 0x1a, 0x16, 0x06, 0x4f, 0x02, 0xee, 0x23, 0x68, 0xda, 0x8a, 0xd0, 0x8d, 0x05, + 0x4a, 0x8b, 0x62, 0x9f, 0xc1, 0xca, 0xac, 0x40, 0x93, 0x83, 0xcb, 0x0b, 0xd4, 0xcb, 0x33, 0xf2, + 0x0b, 0xb5, 0x71, 0x3d, 0x0a, 0xa7, 0xa1, 0x1a, 0x0c, 0x16, 0x9c, 0x1f, 0x8d, 0x40, 0xff, 0xc8, + 0xa4, 0x08, 0xae, 0x2c, 0xfa, 0x47, 0x26, 0x8d, 0x30, 0x80, 0x66, 0x28, 0x1f, 0x87, 0xa9, 0x54, + 0x83, 0xab, 0x56, 0x3b, 0x52, 0x93, 0x6d, 0x40, 0x23, 0x94, 0xa8, 0x26, 0x06, 0xd7, 0xec, 0x35, + 0x3a, 0x52, 0x1a, 0xb7, 0xa1, 0x61, 0xaa, 0x65, 0x6f, 0x2c, 0x9c, 0x68, 0x53, 0x93, 0xee, 0x18, + 0x0a, 0xf6, 0x13, 0x68, 0x52, 0xa9, 0xa4, 0x48, 0x06, 0x1f, 0xcc, 0x73, 0x80, 0xae, 0x57, 0x74, + 0x1a, 0x91, 0xae, 0x5b, 0xfc, 0x04, 0x9a, 0xd6, 0x48, 0x19, 0xce, 0x73, 0xb5, 0x31, 0x56, 0x1c, + 0x4b, 0xc1, 0x6e, 0x42, 0x7d, 0x8a, 0x72, 0x6c, 0xf0, 0xe1, 0xfc, 0x09, 0xd5, 0xe2, 0x4d, 0x63, + 0xd9, 0xdf, 0x83, 0xab, 0xe5, 0x62, 0x43, 0x5b, 0x89, 0x68, 0x02, 0x80, 0x37, 0xa9, 0xef, 0x07, + 0xe7, 0xb0, 0xca, 0x6c, 0xcd, 0xa2, 0x73, 0x39, 0xb9, 0xa0, 0x98, 0xf1, 0x8b, 0x5c, 0xdc, 0xe3, + 0xe9, 0x1a, 0xdc, 0xb2, 0x65, 0x8c, 0x8b, 0x0a, 0xc3, 0x2a, 0x01, 0xd2, 0x33, 0x5f, 0x42, 0x77, + 0x94, 0xbd, 0x7e, 0x7d, 0x66, 0x83, 0xd7, 0x1f, 0x53, 0xbf, 0x92, 0x0b, 0x5e, 0xaa, 0x6f, 0x74, + 0x3a, 0xa3, 0x52, 0xb1, 0xe3, 0x65, 0x68, 0xfa, 0xb1, 0xeb, 0x05, 0x41, 0x3a, 0xd8, 0xd4, 0xf5, + 0x8d, 0x7e, 0xbc, 0x13, 0x04, 0x74, 0x6b, 0x58, 0x24, 0x9c, 0xae, 0xe8, 0xb9, 0x61, 0x30, 0xf8, + 0x89, 0x56, 0x3c, 0x16, 0xb4, 0x17, 0xd0, 0xb5, 0x62, 0xeb, 0xb7, 0x86, 0xc1, 0xe0, 0xb6, 0xb9, + 0x56, 0x6c, 0x40, 0x7b, 0x01, 0x1a, 0x9e, 0x68, 0xe4, 0x5b, 0xc8, 0xe0, 0x13, 0x9d, 0x10, 0x98, + 0x7a, 0xa7, 0x07, 0x06, 0x84, 0x87, 0x54, 0xa7, 0xd7, 0x48, 0x6c, 0xdd, 0x99, 0x3f, 0xa4, 0x79, + 0x9a, 0xd2, 0x69, 0x87, 0x79, 0xc6, 0x92, 0x0e, 0x36, 0x89, 0x22, 0x37, 0xda, 0x1e, 0x7c, 0xba, + 0x78, 0xb0, 0x4d, 0x16, 0x16, 0x0f, 0xb6, 0x4d, 0xc8, 0x6e, 0x03, 0x68, 0x99, 0x45, 0x02, 0x67, + 0x6b, 0xbe, 0x4f, 0xee, 0x0d, 0x38, 0xfa, 0x32, 0x00, 0x89, 0x9a, 0x6d, 0x00, 0x0a, 0xbf, 0xeb, + 0x3e, 0x77, 0xe7, 0xfb, 0xe4, 0xd6, 0xbd, 0xd3, 0x7e, 0x99, 0x1b, 0xfa, 0x77, 0xa1, 0x9d, 0xa1, + 0x1d, 0x8f, 0x96, 0xf4, 0xe0, 0xde, 0x3c, 0x33, 0x5b, 0x13, 0xdf, 0x69, 0x65, 0xe6, 0x09, 0x5f, + 0x42, 0xba, 0x87, 0xcc, 0x90, 0xc1, 0xfd, 0xf9, 0x97, 0xe4, 0x7e, 0x80, 0x43, 0x2a, 0x4a, 0xbb, + 0x04, 0x5f, 0x40, 0x47, 0x2f, 0x9a, 0xee, 0xb4, 0x3d, 0xcf, 0x23, 0x85, 0x5d, 0xe3, 0xe8, 0xd5, + 0xd5, 0xdd, 0x6e, 0x42, 0xdd, 0x4b, 0x92, 0xe8, 0x6c, 0xf0, 0xd9, 0x3c, 0x87, 0xef, 0x20, 0xd8, + 0xd1, 0x58, 0x64, 0xa5, 0x69, 0x16, 0xa9, 0xd0, 0xd6, 0xef, 0x7f, 0x3e, 0xcf, 0x4a, 0xa5, 0x0b, + 0x51, 0x4e, 0x67, 0x5a, 0xba, 0x1d, 0x75, 0x07, 0x5a, 0x89, 0x90, 0xca, 0x0d, 0xa6, 0xd1, 0xe0, + 0x8b, 0x05, 0x35, 0xa2, 0xab, 0xd0, 0x9d, 0x66, 0x62, 0xca, 0xf8, 0x67, 0xae, 0xe9, 0xfd, 0x74, + 0xf6, 0x9a, 0x1e, 0xdb, 0x86, 0xee, 0x54, 0xc4, 0x63, 0x11, 0x1c, 0xeb, 0xd5, 0xff, 0x59, 0xb9, + 0xc6, 0x79, 0x1f, 0x31, 0xb4, 0xf2, 0x1d, 0x43, 0x84, 0x0d, 0xed, 0xdb, 0xfd, 0xba, 0xd6, 0x5a, 0xed, 0xb3, 0x5f, 0xd7, 0x5a, 0x1f, 0xf5, 0x6f, 0x3a, 0x1d, 0x49, 0xb7, 0xe6, 0x69, 0x88, 0xe1, - 0x17, 0xd0, 0xdd, 0xa1, 0x7f, 0x0c, 0x08, 0x25, 0xe9, 0xd1, 0x9b, 0x50, 0xcb, 0xf3, 0xf3, 0xb9, - 0x82, 0x26, 0x8a, 0xd7, 0x7c, 0x2f, 0x1e, 0x09, 0x87, 0xd0, 0xc3, 0x7f, 0x53, 0x83, 0xc6, 0xa1, - 0xc8, 0x52, 0x9f, 0xbf, 0xfd, 0x2e, 0xc9, 0x7b, 0x56, 0xca, 0xe2, 0xa2, 0x5c, 0x58, 0x0b, 0x14, - 0xa1, 0xe7, 0xeb, 0x13, 0xdb, 0x45, 0xea, 0x7f, 0x1d, 0xea, 0xfa, 0x68, 0xa8, 0x23, 0xca, 0xba, - 0x41, 0x3b, 0x2c, 0x93, 0x13, 0xfa, 0x5b, 0x00, 0x93, 0x23, 0xa9, 0x39, 0x60, 0x41, 0x7b, 0x01, - 0x85, 0x8e, 0x2c, 0x01, 0x6d, 0xe1, 0x86, 0x09, 0x0d, 0x1b, 0x20, 0x6d, 0x64, 0x5b, 0x56, 0xd0, - 0xbc, 0xa0, 0xac, 0xe0, 0x7d, 0xa8, 0xc5, 0xb6, 0x92, 0x3d, 0xc7, 0xd3, 0x9d, 0x6c, 0x82, 0xb3, - 0xdb, 0x90, 0x5f, 0x80, 0x31, 0x2e, 0xc9, 0xc5, 0x17, 0x64, 0xb6, 0xa1, 0x9d, 0xff, 0xc7, 0x84, - 0xf1, 0x42, 0xd6, 0xb7, 0x8a, 0x7f, 0x9d, 0x38, 0xb2, 0x4f, 0x4e, 0x41, 0xf6, 0xe6, 0xe4, 0x78, - 0xe7, 0x47, 0x25, 0xc7, 0xcd, 0x11, 0xcd, 0x17, 0xb1, 0x54, 0x26, 0x38, 0xd6, 0x0c, 0xe5, 0x2e, - 0x36, 0xd9, 0xef, 0x41, 0x2f, 0xe5, 0xfe, 0x4b, 0x77, 0x2a, 0xc7, 0xfa, 0x15, 0xbd, 0xf2, 0x25, - 0xbc, 0xa9, 0x1c, 0x7f, 0x4d, 0x89, 0x7b, 0x73, 0x62, 0xea, 0x20, 0xed, 0xbe, 0x1c, 0xd3, 0xa8, - 0x9f, 0xc0, 0xea, 0x94, 0x4f, 0x8f, 0x79, 0x2a, 0x27, 0x61, 0x62, 0x55, 0xed, 0x32, 0x15, 0x18, - 0xf4, 0x0b, 0x84, 0x9e, 0xcb, 0xf0, 0x1f, 0x55, 0xa0, 0x85, 0x5c, 0x44, 0x59, 0x62, 0x0c, 0x6a, - 0x53, 0x3f, 0xc9, 0x8c, 0x23, 0x4c, 0xcf, 0xe6, 0x7f, 0x2b, 0xb4, 0x94, 0x98, 0xff, 0xad, 0xa0, - 0x35, 0xd4, 0x29, 0x1f, 0x7a, 0xd6, 0xf7, 0xc0, 0xcf, 0x28, 0x2a, 0xa8, 0x25, 0xc3, 0x36, 0xd9, - 0x25, 0x68, 0xf8, 0x31, 0x9d, 0x86, 0x75, 0xea, 0xac, 0xee, 0xc7, 0x78, 0x0a, 0xd6, 0xe0, 0xa2, - 0x1a, 0xba, 0xee, 0xc7, 0x7b, 0xc1, 0xe9, 0xf0, 0x3f, 0x54, 0x60, 0xf5, 0x20, 0x15, 0x3e, 0x97, - 0xf2, 0x09, 0x1a, 0x72, 0x4a, 0x53, 0xe0, 0x1b, 0x29, 0xaa, 0xab, 0x33, 0x02, 0xf4, 0x8c, 0x32, - 0xac, 0x43, 0x15, 0xf9, 0x71, 0xa3, 0xea, 0xb4, 0x09, 0x42, 0xa7, 0x8d, 0x1c, 0x5d, 0x4a, 0x7f, - 0x6b, 0x34, 0xc5, 0x83, 0x6f, 0xc2, 0x72, 0x91, 0x58, 0x29, 0x65, 0xea, 0x8b, 0x6b, 0xa6, 0x34, - 0xca, 0x75, 0xe8, 0x98, 0x7a, 0x0a, 0x1a, 0x46, 0x87, 0xf8, 0x41, 0x83, 0x0e, 0xcd, 0x2c, 0xb4, - 0x72, 0x20, 0xbc, 0x0e, 0xea, 0x6b, 0x75, 0x81, 0xe8, 0xe1, 0xdf, 0x87, 0xfe, 0x41, 0xca, 0x13, - 0x2f, 0xe5, 0x54, 0x5f, 0x41, 0x2c, 0xde, 0x80, 0x46, 0xc4, 0xe3, 0xb1, 0x49, 0xe9, 0x57, 0x1d, - 0xd3, 0xca, 0xff, 0x72, 0x64, 0xa9, 0xf4, 0x97, 0x23, 0xc8, 0xea, 0x94, 0x7b, 0xe6, 0x9f, 0x49, - 0xe8, 0x19, 0xb7, 0x20, 0x1e, 0x19, 0xf5, 0xb9, 0xa8, 0xe5, 0xe8, 0x86, 0xb9, 0xcb, 0x76, 0x1c, - 0xc6, 0x54, 0x9b, 0x46, 0x77, 0xd9, 0x1e, 0x84, 0xf1, 0xf0, 0x5f, 0xd6, 0xa1, 0x63, 0xf8, 0x49, - 0x2f, 0xd7, 0x6b, 0x59, 0xc9, 0xd7, 0xb2, 0x0f, 0x55, 0xf9, 0x22, 0x32, 0x8b, 0x8b, 0x8f, 0xec, - 0x33, 0xa8, 0x46, 0xe1, 0xd4, 0x1c, 0x71, 0xae, 0xcd, 0x98, 0xab, 0xd9, 0x55, 0x31, 0x82, 0x87, - 0xd4, 0xa8, 0x23, 0xe9, 0x1e, 0x2c, 0x8a, 0xb8, 0xe1, 0x24, 0x9a, 0x8e, 0x53, 0xdc, 0x47, 0xc8, - 0x23, 0xcf, 0xa7, 0x32, 0x03, 0xab, 0x1c, 0x7a, 0x4e, 0xdb, 0x40, 0xf6, 0x02, 0xf6, 0x39, 0xb4, - 0xf2, 0x40, 0xa5, 0x3d, 0xd4, 0xa8, 0xd3, 0x78, 0x6b, 0xf7, 0xe9, 0xd1, 0x69, 0x6c, 0x23, 0x91, - 0xe6, 0x65, 0x39, 0x25, 0xfb, 0x03, 0xe8, 0x4a, 0x2e, 0xa5, 0xbe, 0xa8, 0x38, 0x12, 0x46, 0x69, - 0x5c, 0x2a, 0x9f, 0x57, 0x08, 0x8b, 0x5f, 0x6d, 0xb7, 0x88, 0x2c, 0x40, 0xec, 0x6b, 0x58, 0xb6, - 0xfd, 0x23, 0x31, 0x1e, 0xe7, 0x81, 0xf4, 0x6b, 0x0b, 0x23, 0x3c, 0x21, 0x74, 0x69, 0x9c, 0x9e, - 0x2c, 0x23, 0xd8, 0x57, 0xb0, 0x9c, 0xe8, 0x35, 0x76, 0x4d, 0x29, 0x8f, 0x56, 0x3e, 0x57, 0x67, - 0xbc, 0xab, 0x19, 0x19, 0x28, 0xae, 0x12, 0x15, 0x70, 0xb9, 0x78, 0x69, 0x57, 0x67, 0x56, 0x66, - 0x2f, 0xed, 0x72, 0xd8, 0x30, 0x7f, 0x56, 0x31, 0x4a, 0x3d, 0xba, 0x7c, 0xa8, 0x2b, 0x38, 0x6c, - 0xcd, 0xdd, 0xdd, 0x85, 0x15, 0xc3, 0x17, 0x6e, 0xe9, 0xcb, 0xa9, 0x8f, 0x4d, 0x17, 0x2a, 0xf0, - 0x30, 0xc5, 0x16, 0xeb, 0xe9, 0x39, 0x28, 0xb6, 0x05, 0x6b, 0xe6, 0x35, 0xfc, 0x94, 0xfb, 0x99, - 0xb9, 0x77, 0x4d, 0x2a, 0xaa, 0xeb, 0xac, 0x6a, 0xd4, 0x23, 0x8b, 0xd9, 0x0b, 0xae, 0x7e, 0x05, - 0x57, 0x2e, 0x7c, 0xc5, 0xdb, 0xca, 0x07, 0x7a, 0xe5, 0x5b, 0x91, 0xff, 0xbb, 0x0a, 0x9d, 0xd2, - 0xd2, 0xd1, 0x9f, 0xe4, 0x48, 0x9e, 0xda, 0x22, 0x21, 0x7c, 0x46, 0xd8, 0x44, 0x48, 0x5b, 0xf3, - 0x42, 0xcf, 0x08, 0x4b, 0x45, 0x9e, 0xfb, 0xa7, 0x67, 0x64, 0xa8, 0x39, 0x8d, 0x9b, 0xe9, 0xd7, - 0xf4, 0x6d, 0xde, 0x02, 0xb8, 0x17, 0xd0, 0xbf, 0xe9, 0x78, 0xca, 0x3b, 0xf6, 0xa4, 0xad, 0xb6, - 0xca, 0xdb, 0xa8, 0xd5, 0x5e, 0xf2, 0x14, 0xe7, 0x62, 0x73, 0x9d, 0xa6, 0x89, 0x02, 0x4f, 0x86, - 0xe0, 0xb5, 0x88, 0x75, 0x9e, 0xb3, 0xeb, 0xb4, 0x10, 0xf0, 0xad, 0x88, 0xa9, 0x9b, 0x11, 0x6f, - 0x93, 0xaf, 0xb7, 0x4d, 0x54, 0xf7, 0x2f, 0x32, 0x8e, 0x6e, 0x78, 0x40, 0xf7, 0x35, 0xda, 0x4e, - 0x93, 0xda, 0xba, 0x84, 0x80, 0xce, 0x0b, 0xaf, 0xbc, 0x50, 0xd1, 0x3e, 0x12, 0x99, 0x32, 0x12, - 0xb0, 0x82, 0x88, 0x6f, 0xbc, 0x50, 0x1d, 0x69, 0x30, 0xbb, 0x6f, 0xae, 0x61, 0x95, 0x69, 0x5d, - 0x3c, 0xec, 0xe8, 0x28, 0x1f, 0x9b, 0xa3, 0x3f, 0xe4, 0xf4, 0x7f, 0x32, 0x53, 0x4f, 0xa5, 0xe1, - 0xa9, 0x88, 0xd1, 0xec, 0xab, 0xf0, 0x25, 0x2f, 0xfe, 0xc1, 0xa7, 0xe5, 0xac, 0xe5, 0xc8, 0xa7, - 0x84, 0xa3, 0xc4, 0xd0, 0x73, 0xd8, 0xe4, 0xa7, 0x49, 0x14, 0xfa, 0xe1, 0xdc, 0x05, 0x48, 0xd7, - 0xf7, 0xa4, 0x72, 0x53, 0xae, 0xb2, 0x34, 0x96, 0x14, 0xc0, 0x32, 0x55, 0x28, 0x1f, 0x5a, 0xfa, - 0xf2, 0xa5, 0xc8, 0x5d, 0x4f, 0x2a, 0x47, 0xd3, 0x3e, 0xcd, 0xa2, 0x08, 0x99, 0x90, 0x27, 0xa4, - 0x74, 0x2d, 0x4a, 0x53, 0xea, 0x54, 0xd4, 0xf0, 0xbf, 0x56, 0x60, 0x75, 0x61, 0xdb, 0xa1, 0xeb, - 0x8f, 0x5b, 0xce, 0xe6, 0xcf, 0xbb, 0x4e, 0x03, 0x9b, 0x7b, 0x01, 0x21, 0xd4, 0x54, 0xd9, 0xcc, - 0x39, 0x22, 0xd4, 0x14, 0x75, 0xca, 0x25, 0x68, 0xa8, 0x53, 0x5a, 0x72, 0xad, 0x39, 0xeb, 0xea, - 0x14, 0xd7, 0x7a, 0x07, 0xda, 0x91, 0x18, 0xbb, 0x11, 0x7f, 0xc9, 0xf5, 0xad, 0xf4, 0xe5, 0xed, - 0x8f, 0xde, 0xb0, 0xdf, 0xb7, 0x9e, 0x88, 0xf1, 0x13, 0xa4, 0x75, 0x5a, 0x91, 0x79, 0x1a, 0xfe, - 0x1a, 0x5a, 0x16, 0xca, 0xda, 0x50, 0x7f, 0xc8, 0x8f, 0xb3, 0x71, 0xff, 0x1d, 0xd6, 0x82, 0x1a, - 0xf6, 0xe8, 0x57, 0xf0, 0xe9, 0x1b, 0x2f, 0x8d, 0xfb, 0x4b, 0x88, 0x7e, 0x94, 0xa6, 0x22, 0xed, - 0x57, 0xf1, 0xf1, 0xc0, 0x8b, 0x43, 0xbf, 0x5f, 0xc3, 0xc7, 0xc7, 0x9e, 0xf2, 0xa2, 0x7e, 0x7d, - 0xf8, 0xdb, 0x3a, 0xb4, 0x0e, 0xcc, 0xdb, 0xd9, 0x43, 0xe8, 0xe5, 0x7f, 0x7e, 0x74, 0x7e, 0x0c, - 0xee, 0x60, 0xfe, 0x81, 0x62, 0x70, 0xdd, 0xa4, 0xd4, 0x9a, 0xff, 0x0b, 0xa5, 0xa5, 0x85, 0xbf, - 0x50, 0x7a, 0x17, 0xaa, 0x2f, 0xd2, 0xb3, 0xd9, 0xd2, 0xcd, 0x83, 0xc8, 0x8b, 0x1d, 0x04, 0xb3, - 0xfb, 0xd0, 0xa1, 0xec, 0x98, 0x24, 0x47, 0xd2, 0xc4, 0xad, 0xca, 0x7f, 0xac, 0x45, 0x70, 0x07, - 0x90, 0xc8, 0x38, 0x9b, 0x5b, 0xd0, 0xf2, 0x27, 0x61, 0x14, 0xa4, 0x3c, 0x36, 0x65, 0xd1, 0x6c, - 0x71, 0xca, 0x4e, 0x4e, 0xc3, 0xfe, 0x10, 0xfa, 0x61, 0x11, 0x77, 0x2b, 0x92, 0xa1, 0x33, 0xca, - 0xbb, 0x14, 0x99, 0x73, 0x56, 0x4a, 0xe4, 0xe4, 0xdd, 0x14, 0xd7, 0xb6, 0x9b, 0xe5, 0x6b, 0xdb, - 0xfa, 0xcf, 0x6f, 0xc8, 0x05, 0x69, 0xe5, 0xa7, 0x76, 0xf4, 0x40, 0x6e, 0x19, 0xbf, 0xb1, 0x3d, - 0x7f, 0xcc, 0xb1, 0x5e, 0x8f, 0xf1, 0x1f, 0x3f, 0x82, 0x65, 0xf4, 0x47, 0x5d, 0xed, 0xc6, 0xa2, - 0x51, 0x01, 0xf3, 0x2f, 0x13, 0x99, 0x9c, 0x3c, 0x44, 0x47, 0x16, 0x85, 0xf1, 0x26, 0x2c, 0xdb, - 0x6f, 0x31, 0xb5, 0x73, 0x1d, 0x93, 0x2c, 0x35, 0x50, 0x5d, 0x3d, 0xb7, 0x05, 0x6b, 0xfe, 0xc4, - 0x8b, 0x63, 0x1e, 0xb9, 0xc7, 0xd9, 0x68, 0x64, 0x3d, 0x88, 0x2e, 0x85, 0x85, 0x57, 0x0d, 0xea, - 0x01, 0x61, 0xc8, 0x91, 0x18, 0x42, 0x2f, 0x0e, 0x23, 0x9d, 0xfb, 0x20, 0x6f, 0xa9, 0x47, 0x94, - 0x9d, 0x38, 0x8c, 0x28, 0xf9, 0x81, 0x3e, 0xd3, 0xaf, 0xa0, 0x9f, 0x65, 0x61, 0x20, 0x5d, 0x25, - 0xec, 0xff, 0x06, 0x99, 0x08, 0x7a, 0x29, 0x26, 0xf5, 0x3c, 0x0b, 0x83, 0x23, 0x61, 0xfe, 0x39, - 0xa8, 0x47, 0xf4, 0xb6, 0x39, 0xfc, 0x15, 0x74, 0xcb, 0xb2, 0x83, 0xb2, 0x48, 0x41, 0x83, 0xfe, - 0x3b, 0x0c, 0xa0, 0xf1, 0x54, 0xa4, 0x53, 0x2f, 0xea, 0x57, 0xf0, 0x59, 0x2b, 0xf3, 0xfe, 0x12, - 0xeb, 0x42, 0xcb, 0x1e, 0x82, 0xfb, 0x55, 0x93, 0x96, 0xfa, 0x05, 0xb4, 0xec, 0xdf, 0x21, 0xd1, - 0x5f, 0xc9, 0x88, 0x80, 0x6b, 0xaf, 0xde, 0xd4, 0x28, 0x22, 0x80, 0x3c, 0x7a, 0xfb, 0x0f, 0x67, - 0x4b, 0xc5, 0x3f, 0x9c, 0x0d, 0xff, 0x08, 0xba, 0xe5, 0x29, 0xda, 0x40, 0x6b, 0xa5, 0x08, 0xb4, - 0x9e, 0xd3, 0x8b, 0x72, 0xe7, 0xa9, 0x98, 0xba, 0x25, 0xc7, 0xb3, 0x85, 0x00, 0x7c, 0xcd, 0xf0, - 0x1f, 0x56, 0xa0, 0x4e, 0x47, 0x43, 0x72, 0x35, 0xf0, 0xa1, 0xd8, 0x41, 0x75, 0xa7, 0x4d, 0x90, - 0xff, 0x87, 0x3b, 0x59, 0x79, 0xe2, 0xad, 0xf6, 0xc6, 0xc4, 0xdb, 0xed, 0x3f, 0xab, 0x40, 0x43, - 0xff, 0xab, 0x1c, 0x5b, 0x85, 0xde, 0xf3, 0xf8, 0x24, 0x16, 0xaf, 0x62, 0x0d, 0xe8, 0xbf, 0xc3, - 0xd6, 0x60, 0xc5, 0xf2, 0xde, 0xfc, 0x7d, 0x5d, 0xbf, 0xc2, 0xfa, 0xd0, 0xa5, 0xd5, 0xb5, 0x90, - 0x25, 0xf6, 0x2e, 0x0c, 0x8c, 0xb7, 0xf0, 0x10, 0x95, 0xb1, 0x50, 0xe1, 0xe8, 0xcc, 0x62, 0xab, - 0x6c, 0x05, 0x3a, 0x87, 0x4a, 0x24, 0x87, 0x3c, 0x0e, 0xc2, 0x78, 0xdc, 0xaf, 0xb1, 0x01, 0xac, - 0xdb, 0x51, 0xf5, 0x3f, 0xaf, 0x3d, 0x0e, 0xe3, 0x50, 0x4e, 0xfa, 0x75, 0x76, 0x0d, 0x2e, 0x9f, - 0x87, 0xd9, 0xf1, 0x4f, 0xfa, 0x8d, 0xdb, 0x9f, 0x03, 0x5b, 0xfc, 0xa3, 0x36, 0x1c, 0xfd, 0x09, - 0x1f, 0x7b, 0xfe, 0xd9, 0x6e, 0x24, 0x24, 0x0a, 0x45, 0x0f, 0xda, 0x45, 0xaf, 0xca, 0xed, 0xc7, - 0xd0, 0xd0, 0xff, 0xac, 0x57, 0xfa, 0x3e, 0x0d, 0xe8, 0xbf, 0x83, 0x9d, 0xd1, 0xe4, 0x84, 0xf1, - 0xf8, 0x29, 0x3f, 0x55, 0x5a, 0x11, 0x3e, 0xf1, 0xa4, 0xea, 0x2f, 0xb1, 0x65, 0x00, 0xf3, 0x09, - 0x8f, 0xe2, 0xa0, 0x5f, 0x7d, 0xb0, 0xfb, 0xe7, 0xbf, 0x7b, 0xbf, 0xf2, 0x17, 0xbf, 0x7b, 0xbf, - 0xf2, 0x5f, 0x7e, 0xf7, 0xfe, 0x3b, 0x7f, 0xfa, 0x97, 0xef, 0x57, 0xbe, 0xbd, 0x5f, 0xfa, 0xdf, - 0x40, 0x63, 0x89, 0xa8, 0xd6, 0xe1, 0x6e, 0x6e, 0x96, 0xee, 0x26, 0x27, 0xe3, 0xbb, 0xc9, 0xf1, - 0x5d, 0x2b, 0xe7, 0xc7, 0x0d, 0xfa, 0x3b, 0xc0, 0xcf, 0xfe, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x8e, 0x30, 0xc6, 0xcd, 0x8d, 0x50, 0x00, 0x00, + 0x17, 0xd0, 0xdd, 0xa1, 0x7f, 0x0c, 0x08, 0x25, 0xc9, 0xd1, 0x9b, 0x50, 0xcb, 0xf3, 0xf3, 0xb9, + 0x80, 0x26, 0x8a, 0xd7, 0x7c, 0x2f, 0x1e, 0x09, 0x87, 0xd0, 0xc3, 0x7f, 0x5d, 0x83, 0xc6, 0xa1, + 0xc8, 0x52, 0x9f, 0xbf, 0xfd, 0x2e, 0xc9, 0x7b, 0x96, 0xcb, 0xe2, 0xa2, 0x5c, 0x58, 0x33, 0x14, + 0xa1, 0xe7, 0xeb, 0x13, 0xdb, 0x45, 0xea, 0x7f, 0x1d, 0xea, 0xda, 0x35, 0xd4, 0x11, 0x65, 0xdd, + 0xa0, 0x13, 0x96, 0xc9, 0x09, 0xfd, 0x2d, 0x80, 0xc9, 0x91, 0xd4, 0x1c, 0xb0, 0xa0, 0xbd, 0x80, + 0x42, 0x47, 0x96, 0x80, 0x8e, 0x70, 0xc3, 0x84, 0x86, 0x0d, 0x90, 0x0e, 0xb2, 0x2d, 0x2b, 0x68, + 0x5e, 0x50, 0x56, 0xf0, 0x3e, 0xd4, 0x62, 0x5b, 0xc9, 0x9e, 0xe3, 0xe9, 0x4e, 0x36, 0xc1, 0xd9, + 0x6d, 0xc8, 0x2f, 0xc0, 0x18, 0x93, 0xe4, 0xe2, 0x0b, 0x32, 0xdb, 0xd0, 0xce, 0xff, 0x63, 0xc2, + 0x58, 0x21, 0xeb, 0x5b, 0xc5, 0xbf, 0x4e, 0x1c, 0xd9, 0x27, 0xa7, 0x20, 0x7b, 0x73, 0x72, 0xbc, + 0xf3, 0xa3, 0x92, 0xe3, 0xc6, 0x45, 0xf3, 0x45, 0x2c, 0x95, 0x09, 0x8e, 0x35, 0x43, 0xb9, 0x8b, + 0x4d, 0xf6, 0x7b, 0xd0, 0x4b, 0xb9, 0xff, 0xd2, 0x9d, 0xca, 0xb1, 0x7e, 0x45, 0xaf, 0x7c, 0x09, + 0x6f, 0x2a, 0xc7, 0x5f, 0x53, 0xe2, 0xde, 0x78, 0x4c, 0x1d, 0xa4, 0xdd, 0x97, 0x63, 0x1a, 0xf5, + 0x13, 0x58, 0x9d, 0xf2, 0xe9, 0x31, 0x4f, 0xe5, 0x24, 0x4c, 0xac, 0xa8, 0x5d, 0xa6, 0x02, 0x83, + 0x7e, 0x81, 0xd0, 0x73, 0x19, 0xfe, 0xa3, 0x0a, 0xb4, 0x70, 0x15, 0x91, 0x97, 0x18, 0x83, 0xda, + 0xd4, 0x4f, 0x32, 0x63, 0x08, 0xd3, 0xb3, 0xf9, 0xdf, 0x0a, 0xcd, 0x25, 0xe6, 0x7f, 0x2b, 0x68, + 0x0f, 0x75, 0xca, 0x87, 0x9e, 0xf5, 0x3d, 0xf0, 0x33, 0x8a, 0x0a, 0x6a, 0xce, 0xb0, 0x4d, 0x76, + 0x09, 0x1a, 0x7e, 0x4c, 0xde, 0xb0, 0x4e, 0x9d, 0xd5, 0xfd, 0x18, 0xbd, 0x60, 0x0d, 0x2e, 0xaa, + 0xa1, 0xeb, 0x7e, 0xbc, 0x17, 0x9c, 0x0e, 0xff, 0x7d, 0x05, 0x56, 0x0f, 0x52, 0xe1, 0x73, 0x29, + 0x9f, 0xa0, 0x22, 0xa7, 0x34, 0x05, 0xbe, 0x91, 0xa2, 0xba, 0x3a, 0x23, 0x40, 0xcf, 0xc8, 0xc3, + 0x3a, 0x54, 0x91, 0xbb, 0x1b, 0x55, 0xa7, 0x4d, 0x10, 0xf2, 0x36, 0x72, 0x74, 0x29, 0xfd, 0xad, + 0xd1, 0x14, 0x0f, 0xbe, 0x09, 0xcb, 0x45, 0x62, 0xa5, 0x94, 0xa9, 0x2f, 0xae, 0x99, 0xd2, 0x28, + 0xd7, 0xa1, 0x63, 0xea, 0x29, 0x68, 0x18, 0x1d, 0xe2, 0x07, 0x0d, 0x3a, 0x34, 0xb3, 0xd0, 0xc2, + 0x81, 0xf0, 0x3a, 0xa8, 0xaf, 0xc5, 0x05, 0xa2, 0x87, 0x7f, 0x1f, 0xfa, 0x07, 0x29, 0x4f, 0xbc, + 0x94, 0x53, 0x7d, 0x05, 0x2d, 0xf1, 0x06, 0x34, 0x22, 0x1e, 0x8f, 0x4d, 0x4a, 0xbf, 0xea, 0x98, + 0x56, 0xfe, 0x97, 0x23, 0x4b, 0xa5, 0xbf, 0x1c, 0xc1, 0xa5, 0x4e, 0xb9, 0x67, 0xfe, 0x99, 0x84, + 0x9e, 0xf1, 0x08, 0xa2, 0xcb, 0xa8, 0xfd, 0xa2, 0x96, 0xa3, 0x1b, 0xe6, 0x2e, 0xdb, 0x71, 0x18, + 0x53, 0x6d, 0x1a, 0xdd, 0x65, 0x7b, 0x10, 0xc6, 0xc3, 0xff, 0x52, 0x87, 0x8e, 0x59, 0x4f, 0x7a, + 0xb9, 0xde, 0xcb, 0x4a, 0xbe, 0x97, 0x7d, 0xa8, 0xca, 0x17, 0x91, 0xd9, 0x5c, 0x7c, 0x64, 0x9f, + 0x41, 0x35, 0x0a, 0xa7, 0xc6, 0xc5, 0xb9, 0x36, 0xa3, 0xae, 0x66, 0x77, 0xc5, 0x30, 0x1e, 0x52, + 0xa3, 0x8c, 0xa4, 0x7b, 0xb0, 0xc8, 0xe2, 0x66, 0x25, 0x51, 0x75, 0x9c, 0xe2, 0x39, 0xc2, 0x35, + 0xf2, 0x7c, 0x2a, 0x33, 0xb0, 0xc2, 0xa1, 0xe7, 0xb4, 0x0d, 0x64, 0x2f, 0x60, 0x9f, 0x43, 0x2b, + 0x0f, 0x54, 0x5a, 0xa7, 0x46, 0x9d, 0xc6, 0x5b, 0xbb, 0x4f, 0x8f, 0x4e, 0x63, 0x1b, 0x89, 0x34, + 0x2f, 0xcb, 0x29, 0xd9, 0x1f, 0x40, 0x57, 0x72, 0x29, 0xf5, 0x45, 0xc5, 0x91, 0x30, 0x42, 0xe3, + 0x52, 0xd9, 0x5f, 0x21, 0x2c, 0x7e, 0xb5, 0x3d, 0x22, 0xb2, 0x00, 0xb1, 0xaf, 0x61, 0xd9, 0xf6, + 0x8f, 0xc4, 0x78, 0x9c, 0x07, 0xd2, 0xaf, 0x2d, 0x8c, 0xf0, 0x84, 0xd0, 0xa5, 0x71, 0x7a, 0xb2, + 0x8c, 0x60, 0x5f, 0xc1, 0x72, 0xa2, 0xf7, 0xd8, 0x35, 0xa5, 0x3c, 0x5a, 0xf8, 0x5c, 0x9d, 0xb1, + 0xae, 0x66, 0x78, 0xa0, 0xb8, 0x4a, 0x54, 0xc0, 0xe5, 0xe2, 0xa5, 0x5d, 0x9d, 0x59, 0x99, 0xbd, + 0xb4, 0xcb, 0x61, 0xc3, 0xfc, 0x59, 0xc5, 0x28, 0xf5, 0xe8, 0xf2, 0xa1, 0xae, 0xe0, 0xb0, 0x35, + 0x77, 0x77, 0x17, 0x76, 0x0c, 0x5f, 0xb8, 0xa5, 0x2f, 0xa7, 0x3e, 0x36, 0x5d, 0xa8, 0xc0, 0xc3, + 0x14, 0x5b, 0xac, 0xa7, 0xe7, 0xa0, 0xd8, 0x16, 0xac, 0x99, 0xd7, 0xf0, 0x53, 0xee, 0x67, 0xe6, + 0xde, 0x35, 0x89, 0xa8, 0xae, 0xb3, 0xaa, 0x51, 0x8f, 0x2c, 0x66, 0x2f, 0x60, 0x5f, 0xc2, 0x40, + 0x2a, 0x4f, 0x71, 0x9a, 0x90, 0x95, 0x92, 0xe1, 0x38, 0x16, 0x29, 0x37, 0x05, 0x0a, 0x1b, 0x39, + 0xde, 0x48, 0xc7, 0x3d, 0xc2, 0x5e, 0xfd, 0x0a, 0xae, 0x5c, 0x38, 0xb9, 0xb7, 0x15, 0x1e, 0xf4, + 0xca, 0xf7, 0x29, 0xff, 0x77, 0x15, 0x3a, 0xa5, 0x4d, 0xa7, 0xbf, 0xd7, 0x91, 0x3c, 0xb5, 0xe5, + 0x45, 0xf8, 0x8c, 0xb0, 0x89, 0x90, 0xb6, 0x5a, 0x86, 0x9e, 0x11, 0x96, 0x8a, 0xbc, 0x6a, 0x80, + 0x9e, 0x71, 0x2b, 0x8c, 0x1f, 0x6f, 0x3e, 0xbc, 0xa6, 0xef, 0x01, 0x17, 0xc0, 0xbd, 0x80, 0xfe, + 0x87, 0xc7, 0x53, 0xde, 0xb1, 0x27, 0x6d, 0x9d, 0x56, 0xde, 0x46, 0x79, 0xf8, 0x92, 0xa7, 0x38, + 0x17, 0x9b, 0x25, 0x35, 0x4d, 0x3c, 0x2a, 0xb4, 0x38, 0xaf, 0x45, 0xac, 0x33, 0xa4, 0x5d, 0xa7, + 0x85, 0x80, 0x6f, 0x45, 0x4c, 0xdd, 0xcc, 0xc1, 0x30, 0x99, 0x7e, 0xdb, 0x44, 0x45, 0xf1, 0x22, + 0xe3, 0x68, 0xc0, 0x07, 0x74, 0xd3, 0xa3, 0xed, 0x34, 0xa9, 0xad, 0x8b, 0x0f, 0xc8, 0xd3, 0x78, + 0xe5, 0x85, 0x8a, 0x4e, 0xa0, 0xc8, 0x94, 0xe1, 0x9d, 0x15, 0x44, 0x7c, 0xe3, 0x85, 0xea, 0x48, + 0x83, 0xd9, 0x7d, 0x73, 0x81, 0xab, 0x4c, 0xeb, 0xa2, 0x9b, 0xa4, 0xe3, 0x83, 0x6c, 0x8e, 0xfe, + 0x90, 0xd3, 0x3f, 0xd1, 0x4c, 0x3d, 0x95, 0x86, 0xa7, 0x22, 0x46, 0x83, 0x41, 0x85, 0x2f, 0x79, + 0xf1, 0xdf, 0x3f, 0x2d, 0x67, 0x2d, 0x47, 0x3e, 0x25, 0x1c, 0xa5, 0x94, 0x9e, 0xc3, 0x26, 0x3f, + 0x4d, 0xa2, 0xd0, 0x0f, 0xe7, 0xae, 0x4e, 0xba, 0xbe, 0x27, 0x95, 0x9b, 0x72, 0x95, 0xa5, 0xb1, + 0xa4, 0xd0, 0x97, 0x61, 0x8f, 0x0f, 0x2d, 0x7d, 0xf9, 0x3a, 0xe5, 0xae, 0x27, 0x95, 0xa3, 0x69, + 0x9f, 0x66, 0x51, 0x84, 0x8b, 0x90, 0xa7, 0xb2, 0x74, 0x15, 0x4b, 0x53, 0xea, 0x24, 0xd6, 0xf0, + 0xbf, 0x56, 0x60, 0x75, 0xe1, 0xc0, 0xa2, 0xd3, 0x80, 0x87, 0xd5, 0x66, 0xde, 0xbb, 0x4e, 0x03, + 0x9b, 0x7b, 0x01, 0x21, 0xd4, 0x54, 0xd9, 0x9c, 0x3b, 0x22, 0xd4, 0x14, 0xa5, 0xd1, 0x25, 0x68, + 0xa8, 0x53, 0xda, 0x72, 0x2d, 0x73, 0xeb, 0xea, 0x14, 0xf7, 0x7a, 0x07, 0xda, 0x91, 0x18, 0xbb, + 0x11, 0x7f, 0xc9, 0xf5, 0x7d, 0xf6, 0xe5, 0xed, 0x8f, 0xde, 0x20, 0x29, 0xb6, 0x9e, 0x88, 0xf1, + 0x13, 0xa4, 0x75, 0x5a, 0x91, 0x79, 0x1a, 0xfe, 0x1a, 0x5a, 0x16, 0xca, 0xda, 0x50, 0x7f, 0xc8, + 0x8f, 0xb3, 0x71, 0xff, 0x1d, 0xd6, 0x82, 0x1a, 0xf6, 0xe8, 0x57, 0xf0, 0xe9, 0x1b, 0x2f, 0x8d, + 0xfb, 0x4b, 0x88, 0x7e, 0x94, 0xa6, 0x22, 0xed, 0x57, 0xf1, 0xf1, 0xc0, 0x8b, 0x43, 0xbf, 0x5f, + 0xc3, 0xc7, 0xc7, 0x9e, 0xf2, 0xa2, 0x7e, 0x7d, 0xf8, 0xdb, 0x3a, 0xb4, 0x0e, 0xcc, 0xdb, 0xd9, + 0x43, 0xe8, 0xe5, 0x7f, 0x9b, 0x74, 0x7e, 0xf4, 0xee, 0x60, 0xfe, 0x81, 0xa2, 0x77, 0xdd, 0xa4, + 0xd4, 0x9a, 0xff, 0xf3, 0xa5, 0xa5, 0x85, 0x3f, 0x5f, 0x7a, 0x17, 0xaa, 0x2f, 0xd2, 0xb3, 0xd9, + 0xa2, 0xcf, 0x83, 0xc8, 0x8b, 0x1d, 0x04, 0xb3, 0xfb, 0xd0, 0xa1, 0xbc, 0x9a, 0x24, 0x13, 0xd4, + 0x44, 0xbc, 0xca, 0x7f, 0xc9, 0x45, 0x70, 0x07, 0x90, 0xc8, 0x98, 0xa9, 0x5b, 0xd0, 0xf2, 0x27, + 0x61, 0x14, 0xa4, 0x3c, 0x36, 0x05, 0xd5, 0x6c, 0x71, 0xca, 0x4e, 0x4e, 0xc3, 0xfe, 0x10, 0xfa, + 0x61, 0x11, 0xb1, 0x2b, 0xd2, 0xa8, 0x33, 0x62, 0xbf, 0x14, 0xd3, 0x73, 0x56, 0x4a, 0xe4, 0x64, + 0x17, 0x15, 0x17, 0xbe, 0x9b, 0xe5, 0x0b, 0xdf, 0xfa, 0x6f, 0x73, 0xc8, 0x78, 0x69, 0xe5, 0xfe, + 0x3e, 0xda, 0x2e, 0xb7, 0x8c, 0xc5, 0xd9, 0x9e, 0x77, 0x90, 0xac, 0xbd, 0x64, 0x2c, 0xcf, 0x8f, + 0x60, 0x19, 0x2d, 0x59, 0x57, 0x1b, 0xc0, 0xa8, 0x8e, 0xc0, 0xfc, 0x3f, 0x45, 0x26, 0x27, 0x0f, + 0xd1, 0x04, 0x46, 0x66, 0xbc, 0x09, 0xcb, 0xf6, 0x5b, 0x4c, 0xd5, 0x5d, 0xc7, 0xa4, 0x59, 0x0d, + 0x54, 0xd7, 0xdd, 0x6d, 0xc1, 0x9a, 0x3f, 0xf1, 0xe2, 0x98, 0x47, 0xee, 0x71, 0x36, 0x1a, 0x59, + 0xdb, 0xa3, 0x4b, 0x01, 0xe5, 0x55, 0x83, 0x7a, 0x40, 0x18, 0x32, 0x41, 0x86, 0xd0, 0x8b, 0xc3, + 0x48, 0x67, 0x4d, 0xc8, 0xce, 0xea, 0x11, 0x65, 0x27, 0x0e, 0x23, 0x4a, 0x9b, 0xa0, 0xb5, 0xf5, + 0x2b, 0xe8, 0x67, 0x59, 0x18, 0x48, 0x57, 0x09, 0xfb, 0x8f, 0x43, 0x26, 0xf6, 0x5e, 0x8a, 0x66, + 0x3d, 0xcf, 0xc2, 0xe0, 0x48, 0x98, 0xff, 0x1c, 0xea, 0x11, 0xbd, 0x6d, 0x0e, 0x7f, 0x05, 0xdd, + 0x32, 0xef, 0x20, 0x2f, 0x52, 0xb8, 0xa1, 0xff, 0x0e, 0x03, 0x68, 0x3c, 0x15, 0xe9, 0xd4, 0x8b, + 0xfa, 0x15, 0x7c, 0xd6, 0xc2, 0xbc, 0xbf, 0xc4, 0xba, 0xd0, 0xb2, 0xee, 0x73, 0xbf, 0x6a, 0x12, + 0x5a, 0xbf, 0x80, 0x96, 0xfd, 0x23, 0x25, 0xfa, 0x13, 0x1a, 0x11, 0x70, 0xed, 0x0f, 0x98, 0xea, + 0x46, 0x04, 0x90, 0x2f, 0x60, 0xff, 0x1b, 0x6d, 0xa9, 0xf8, 0x6f, 0xb4, 0xe1, 0x1f, 0x41, 0xb7, + 0x3c, 0x45, 0x1b, 0xa2, 0xad, 0x14, 0x21, 0xda, 0x73, 0x7a, 0x51, 0xd6, 0x3d, 0x15, 0x53, 0xb7, + 0x64, 0xb2, 0xb6, 0x10, 0x80, 0xaf, 0x19, 0xfe, 0xc3, 0x0a, 0xd4, 0xc9, 0xa9, 0x24, 0x23, 0x05, + 0x1f, 0x8a, 0x13, 0x54, 0x77, 0xda, 0x04, 0xf9, 0x7f, 0xb8, 0xcd, 0x95, 0xa7, 0xec, 0x6a, 0x6f, + 0x4c, 0xd9, 0xdd, 0xfe, 0xb3, 0x0a, 0x34, 0xf4, 0xff, 0xd1, 0xb1, 0x55, 0xe8, 0x3d, 0x8f, 0x4f, + 0x62, 0xf1, 0x2a, 0xd6, 0x80, 0xfe, 0x3b, 0x6c, 0x0d, 0x56, 0xec, 0xda, 0x9b, 0x3f, 0xbe, 0xeb, + 0x57, 0x58, 0x1f, 0xba, 0xb4, 0xbb, 0x16, 0xb2, 0xc4, 0xde, 0x85, 0x81, 0xb1, 0x33, 0x1e, 0xa2, + 0x30, 0x16, 0x2a, 0x1c, 0x9d, 0x59, 0x6c, 0x95, 0xad, 0x40, 0xe7, 0x50, 0x89, 0xe4, 0x90, 0xc7, + 0x41, 0x18, 0x8f, 0xfb, 0x35, 0x36, 0x80, 0x75, 0x3b, 0xaa, 0xfe, 0xcf, 0xb6, 0xc7, 0x61, 0x1c, + 0xca, 0x49, 0xbf, 0xce, 0xae, 0xc1, 0xe5, 0xf3, 0x30, 0x3b, 0xfe, 0x49, 0xbf, 0x71, 0xfb, 0x73, + 0x60, 0x8b, 0x7f, 0xf1, 0x86, 0xa3, 0x3f, 0xe1, 0x63, 0xcf, 0x3f, 0xdb, 0x8d, 0x84, 0x44, 0xa6, + 0xe8, 0x41, 0xbb, 0xe8, 0x55, 0xb9, 0xfd, 0x18, 0x1a, 0xfa, 0x3f, 0xf9, 0x4a, 0xdf, 0xa7, 0x01, + 0xfd, 0x77, 0xb0, 0x33, 0xaa, 0x9c, 0x30, 0x1e, 0x3f, 0xe5, 0xa7, 0x4a, 0x0b, 0xc2, 0x27, 0x9e, + 0x54, 0xfd, 0x25, 0xb6, 0x0c, 0x60, 0x3e, 0xe1, 0x51, 0x1c, 0xf4, 0xab, 0x0f, 0x76, 0xff, 0xfc, + 0x77, 0xef, 0x57, 0xfe, 0xe2, 0x77, 0xef, 0x57, 0xfe, 0xf3, 0xef, 0xde, 0x7f, 0xe7, 0x4f, 0xff, + 0xf2, 0xfd, 0xca, 0xb7, 0xf7, 0x4b, 0xff, 0x38, 0x68, 0x34, 0x11, 0x55, 0x49, 0xdc, 0xcd, 0xd5, + 0xd2, 0xdd, 0xe4, 0x64, 0x7c, 0x37, 0x39, 0xbe, 0x6b, 0xf9, 0xfc, 0xb8, 0x41, 0x7f, 0x24, 0xf8, + 0xd9, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x89, 0x6f, 0x1d, 0xfb, 0xc7, 0x50, 0x00, 0x00, } func (m *Message) Marshal() (dAtA []byte, err error) { @@ -12004,6 +12015,16 @@ func (m *ProcessInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.StatementRuntimeIgnore { + i-- + if m.StatementRuntimeIgnore { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x68 + } if len(m.RemoteExecutionId) > 0 { i -= len(m.RemoteExecutionId) copy(dAtA[i:], m.RemoteExecutionId) @@ -14946,6 +14967,9 @@ func (m *ProcessInfo) ProtoSize() (n int) { if l > 0 { n += 1 + l + sovPipeline(uint64(l)) } + if m.StatementRuntimeIgnore { + n += 2 + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -30878,6 +30902,26 @@ func (m *ProcessInfo) Unmarshal(dAtA []byte) error { m.RemoteExecutionId = []byte{} } iNdEx = postIndex + case 13: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StatementRuntimeIgnore", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPipeline + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.StatementRuntimeIgnore = bool(v != 0) default: iNdEx = preIndex skippy, err := skipPipeline(dAtA[iNdEx:]) diff --git a/pkg/sql/compile/remoterunServer.go b/pkg/sql/compile/remoterunServer.go index 680d31f7050b9..cf99c70ad266b 100644 --- a/pkg/sql/compile/remoterunServer.go +++ b/pkg/sql/compile/remoterunServer.go @@ -680,11 +680,12 @@ type processHelper struct { txnClient client.TxnClient sessionInfo process.SessionInfo //analysisNodeList []int32 - StmtId uuid.UUID - prepareParams pipeline.PrepareParamInfo - affectedRows int64 - remoteFragmentCounts map[string]uint32 - remoteExecutionID uuid.UUID + StmtId uuid.UUID + statementRuntimeIgnore bool + prepareParams pipeline.PrepareParamInfo + affectedRows int64 + remoteFragmentCounts map[string]uint32 + remoteExecutionID uuid.UUID } // messageReceiverOnServer supported a series methods to write back results. @@ -869,7 +870,9 @@ func (receiver *messageReceiverOnServer) newCompile() (*Compile, error) { { txn := proc.GetTxnOperator().Txn() txnId := txn.GetID() - proc.Base.StmtProfile = process.NewStmtProfile(uuid.UUID(txnId), pHelper.StmtId) + stmtProfile := process.NewStmtProfile(uuid.UUID(txnId), pHelper.StmtId) + stmtProfile.SetStatementRuntimeProfile("", "", pHelper.statementRuntimeIgnore) + proc.Base.StmtProfile = stmtProfile } c := allocateNewCompile(proc) @@ -1052,13 +1055,14 @@ func generateProcessHelper(ctx context.Context, data []byte, cli client.TxnClien } result := processHelper{ - id: procInfo.Id, - lim: process.ConvertToProcessLimitation(procInfo.Lim), - unixTime: procInfo.UnixTime, - accountId: procInfo.AccountId, - txnClient: cli, - affectedRows: procInfo.AffectedRows, - remoteFragmentCounts: maps.Clone(procInfo.RemoteFragmentCounts), + id: procInfo.Id, + lim: process.ConvertToProcessLimitation(procInfo.Lim), + unixTime: procInfo.UnixTime, + accountId: procInfo.AccountId, + txnClient: cli, + affectedRows: procInfo.AffectedRows, + statementRuntimeIgnore: procInfo.StatementRuntimeIgnore, + remoteFragmentCounts: maps.Clone(procInfo.RemoteFragmentCounts), } if len(procInfo.RemoteExecutionId) > 0 { result.remoteExecutionID, err = uuid.FromBytes(procInfo.RemoteExecutionId) diff --git a/pkg/sql/compile/remoterunServer_test.go b/pkg/sql/compile/remoterunServer_test.go index 0fdd5dc2331ec..daa095d279351 100644 --- a/pkg/sql/compile/remoterunServer_test.go +++ b/pkg/sql/compile/remoterunServer_test.go @@ -235,12 +235,13 @@ func TestNewCompile_CreatesCorrectStructure(t *testing.T) { storeEngine: mockEngine, }, procBuildHelper: processHelper{ - id: "test-proc-id", - accountId: catalog.System_Account, - unixTime: time.Now().Unix(), - affectedRows: 42, - txnClient: txnClient, - txnOperator: txnOperator, + id: "test-proc-id", + accountId: catalog.System_Account, + unixTime: time.Now().Unix(), + affectedRows: 42, + statementRuntimeIgnore: true, + txnClient: txnClient, + txnOperator: txnOperator, prepareParams: pipeline.PrepareParamInfo{ Length: 2, Data: append([]byte(nil), params.GetData()...), @@ -265,6 +266,7 @@ func TestNewCompile_CreatesCorrectStructure(t *testing.T) { require.True(t, compile.proc.GetPrepareParamIsBin(0)) require.False(t, compile.proc.GetPrepareParamIsBin(1)) require.Equal(t, int64(42), compile.proc.GetAffectedRows()) + require.True(t, compile.proc.GetStmtProfile().GetStatementIgnore()) require.NotNil(t, compile.fill, "fill callback should be set") remoteParams := compile.proc.GetPrepareParams() require.NotPanics(t, compile.Release) @@ -342,10 +344,11 @@ func TestGenerateProcessHelper_WithSnapshot(t *testing.T) { t.Cleanup(func() { params.Free(proc.Mp()) }) procInfo := &pipeline.ProcessInfo{ - Id: "test-proc-id", - AccountId: catalog.System_Account, - UnixTime: time.Now().Unix(), - AffectedRows: 42, + Id: "test-proc-id", + AccountId: catalog.System_Account, + UnixTime: time.Now().Unix(), + AffectedRows: 42, + StatementRuntimeIgnore: true, Snapshot: txn.CNTxnSnapshot{ Txn: txn.TxnMeta{ ID: []byte("test-txn-id"), @@ -371,6 +374,7 @@ func TestGenerateProcessHelper_WithSnapshot(t *testing.T) { require.Equal(t, procInfo.PrepareParams.Data, helper.prepareParams.Data) require.Equal(t, procInfo.PrepareParams.Area, helper.prepareParams.Area) require.Equal(t, int64(42), helper.affectedRows) + require.True(t, helper.statementRuntimeIgnore) require.NotNil(t, helper.txnOperator, "txnOperator should be created from snapshot") // Verify that rebuilt txnOperator has nil workspace (key point for remote run) require.Nil(t, helper.txnOperator.GetWorkspace(), "rebuilt txnOperator should have nil workspace initially") diff --git a/pkg/tests/dml/dml_test.go b/pkg/tests/dml/dml_test.go index da74e7efe6f70..0c827b233e16e 100644 --- a/pkg/tests/dml/dml_test.go +++ b/pkg/tests/dml/dml_test.go @@ -112,6 +112,45 @@ func TestDeleteAndSelect(t *testing.T) { ) } +func TestInsertIgnoreSpecialTypeOnRemoteCN(t *testing.T) { + embed.RunBaseClusterTests(t, func(c embed.Cluster) { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + + cn, err := c.GetCNService(0) + require.NoError(t, err) + port := cn.GetServiceConfig().CN.Frontend.Port + db, err := sql.Open("mysql", fmt.Sprintf("dump:111@tcp(127.0.0.1:%d)/", port)) + require.NoError(t, err) + defer db.Close() + + dbName := testutils.GetDatabaseName(t) + execSQLDB(t, ctx, db, "create database `"+dbName+"`") + defer func() { + execSQLDB(t, ctx, db, "use mo_catalog") + execSQLDB(t, ctx, db, "drop database if exists `"+dbName+"`") + }() + execSQLDB(t, ctx, db, "use `"+dbName+"`") + execSQLDB(t, ctx, db, "set session sql_mode = 'STRICT_TRANS_TABLES'") + execSQLDB(t, ctx, db, "create table src (v int)") + // Multiple source blocks ensure the forced AP multi-CN scan evaluates + // assignment casts on remote scan scopes, not only on the coordinator. + execSQLDB(t, ctx, db, "insert into src select 31 from generate_series(1, 24576) g") + execSQLDB(t, ctx, db, "create table dst (b bit(4))") + + plan.SetForceScanOnMultiCN(true) + defer plan.SetForceScanOnMultiCN(false) + execSQLDB(t, ctx, db, "insert ignore into dst select v from src") + + var count, min, max int + err = db.QueryRowContext(ctx, "select count(*), min(b + 0), max(b + 0) from dst").Scan(&count, &min, &max) + require.NoError(t, err) + require.Equal(t, 24576, count) + require.Equal(t, 15, min) + require.Equal(t, 15, max) + }) +} + func TestDataBranchDiffAsFile(t *testing.T) { embed.RunBaseClusterTests(t, func(c embed.Cluster) { diff --git a/pkg/vm/process/process_codec.go b/pkg/vm/process/process_codec.go index 4e0aab0ab1272..aa18e7f8c2d8d 100644 --- a/pkg/vm/process/process_codec.go +++ b/pkg/vm/process/process_codec.go @@ -19,6 +19,7 @@ import ( "math" "time" + "github.com/google/uuid" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -63,6 +64,10 @@ func (proc *Process) BuildProcessInfo( // Carry ROW_COUNT() state so it is correct when an expression that reads // it (e.g. row_count() in a projection) is pushed down to a remote CN. procInfo.AffectedRows = proc.GetAffectedRows() + // Assignment casts can run in a remote scan scope. Carry INSERT IGNORE + // semantics with the process so those casts take the same adjustment + // path as they do on the coordinating CN. + procInfo.StatementRuntimeIgnore = proc.GetStmtProfile().GetStatementIgnore() snapshot, err := proc.GetTxnOperator().Snapshot() if err != nil { return procInfo, err @@ -231,6 +236,9 @@ func (c *codecService) Decode( proc.Base.SessionInfo = sessionInfo proc.Base.SessionInfo.StorageEngine = c.engine proc.SetAffectedRows(value.AffectedRows) + stmtProfile := NewStmtProfile(uuid.Nil, uuid.Nil) + stmtProfile.SetStatementRuntimeProfile("", "", value.StatementRuntimeIgnore) + proc.Base.StmtProfile = stmtProfile if value.PrepareParams.Length > 0 { prepareParams, err := vector.NewVecWithDataCopy( types.T_text.ToType(), diff --git a/pkg/vm/process/process_codec_test.go b/pkg/vm/process/process_codec_test.go index 18cdaaeafc0aa..786c63fb677e2 100644 --- a/pkg/vm/process/process_codec_test.go +++ b/pkg/vm/process/process_codec_test.go @@ -97,6 +97,7 @@ func newCodecTestProcess(t *testing.T) (*Process, client.TxnOperator) { sp := NewStmtProfile(uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"), uuid.MustParse("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb")) sp.SetTxnId([]byte("txn-profile-123456")) sp.SetStmtId(uuid.MustParse("cccccccc-cccc-cccc-cccc-cccccccccccc")) + sp.SetStatementRuntimeProfile("Insert", "DML", true) proc.SetStmtProfile(sp) vec := vector.NewVec(types.T_text.ToType()) @@ -243,6 +244,7 @@ func TestBuildProcessInfoAndMockProcessInfoWithPro(t *testing.T) { require.Equal(t, []bool{false, true}, info.PrepareParams.Nulls) require.Equal(t, []bool{true, false}, info.PrepareParams.IsBin) require.Equal(t, int64(42), info.AffectedRows) + require.True(t, info.StatementRuntimeIgnore) require.Equal(t, uint64(99), info.SessionInfo.ConnectionId) require.Equal(t, int64(7), info.SessionInfo.LockWaitTimeout) require.True(t, info.SessionInfo.MatrixoneNativeMode) @@ -304,6 +306,7 @@ func TestCodecServiceEncodeDecodeAndLookup(t *testing.T) { require.True(t, decodedProc.GetPrepareParamIsBin(0)) require.False(t, decodedProc.GetPrepareParamIsBin(1)) require.Equal(t, int64(42), decodedProc.GetAffectedRows()) + require.True(t, decodedProc.GetStmtProfile().GetStatementIgnore()) decodedParams := decodedProc.GetPrepareParams() require.NotPanics(t, decodedProc.Free) require.Nil(t, decodedParams.GetData()) @@ -349,6 +352,9 @@ func TestCodecServiceDecodesLegacyPrepareParamsWithoutBinaryFlags(t *testing.T) info, err := proc.BuildProcessInfo("select ?") require.NoError(t, err) info.PrepareParams.IsBin = nil + // An old coordinator does not send the new field. Protobuf decodes that + // absence as false, preserving the prior strict-mode behavior remotely. + info.StatementRuntimeIgnore = false payload, err := info.Marshal() require.NoError(t, err) @@ -363,6 +369,7 @@ func TestCodecServiceDecodesLegacyPrepareParamsWithoutBinaryFlags(t *testing.T) require.Equal(t, 2, decodedProc.GetPrepareParams().Length()) require.False(t, decodedProc.GetPrepareParamIsBin(0)) require.False(t, decodedProc.GetPrepareParamIsBin(1)) + require.False(t, decodedProc.GetStmtProfile().GetStatementIgnore()) decodedProc.Free() } diff --git a/proto/pipeline.proto b/proto/pipeline.proto index 0339ea23ac174..59cf7e37eb2cf 100644 --- a/proto/pipeline.proto +++ b/proto/pipeline.proto @@ -651,6 +651,9 @@ message ProcessInfo { // Unique physical execution attempt. Unlike the SQL statement ID, this // changes across retries and prepared-statement executions. bytes remote_execution_id = 12; + // Statement-level INSERT IGNORE semantics used by casts in remote pipelines. + // Absent in messages from older CNs, which safely decodes as false. + bool statement_runtime_ignore = 13; } message SessionInfo { diff --git a/test/distributed/cases/dml/insert/insert_ignore.result b/test/distributed/cases/dml/insert/insert_ignore.result index f839cf4c3e784..f4b547493df73 100644 --- a/test/distributed/cases/dml/insert/insert_ignore.result +++ b/test/distributed/cases/dml/insert/insert_ignore.result @@ -4,139 +4,141 @@ insert ignore into insert_ignore_01 values(3,"e"),(6,"f"),(1,"g"); insert ignore into insert_ignore_01(c2) values("h"),("g"),("k"); insert ignore into insert_ignore_01 values(NULL,NULL); select * from insert_ignore_01; -c1 c2 -1 a -2 b -3 c -4 d -6 f -7 h -8 g -9 k -10 null +➤ c1[4,32,0] ¦ c2[12,-1,0] 𝄀 +1 ¦ a 𝄀 +2 ¦ b 𝄀 +3 ¦ c 𝄀 +4 ¦ d 𝄀 +6 ¦ f 𝄀 +7 ¦ h 𝄀 +8 ¦ g 𝄀 +9 ¦ k 𝄀 +10 ¦ null drop table insert_ignore_01; create table insert_ignore_01 (part_id INT NOT NULL,color VARCHAR(20) NOT NULL,quantity INT,PRIMARY KEY (part_id, color)); insert ignore into insert_ignore_01 (part_id, color, quantity)values(1, 'Red', 10),(1, 'Blue', 20),(2, 'Green', 15),(1, 'Red', 5); select * from insert_ignore_01; -part_id color quantity -1 Blue 20 -1 Red 10 -2 Green 15 +➤ part_id[4,32,0] ¦ color[12,-1,0] ¦ quantity[4,32,0] 𝄀 +1 ¦ Red ¦ 10 𝄀 +1 ¦ Blue ¦ 20 𝄀 +2 ¦ Green ¦ 15 create table insert_ignore_02(c1 int,c2 decimal(6,2),unique key(c1)); insert into insert_ignore_02 values(100,1234.56),(200,2345.67),(300,3456.78),(400,4567.89),(NULL,33.00); insert ignore into insert_ignore_02 values(100,1234.56),(200,23.7),(500,56.7),(600,6.9); insert ignore into insert_ignore_02 values(700,1.56),(800,3.7); insert ignore into insert_ignore_02 values(NULL,44.56); select * from insert_ignore_02; -c1 c2 -100 1234.56 -200 2345.67 -300 3456.78 -400 4567.89 -null 33.00 -500 56.70 -600 6.90 -700 1.56 -800 3.70 -null 44.56 +➤ c1[4,32,0] ¦ c2[3,6,2] 𝄀 +100 ¦ 1234.56 𝄀 +200 ¦ 2345.67 𝄀 +300 ¦ 3456.78 𝄀 +400 ¦ 4567.89 𝄀 +null ¦ 33.00 𝄀 +500 ¦ 56.70 𝄀 +600 ¦ 6.90 𝄀 +700 ¦ 1.56 𝄀 +800 ¦ 3.70 𝄀 +null ¦ 44.56 create table insert_ignore_03(c1 int auto_increment primary key,c2 int,key(c2)); insert into insert_ignore_03(c2) values(2),(2),(5),(10),(12),(NULL); insert ignore into insert_ignore_03(c2) values(7),(2),(5),(10),(12),(NULL); select * from insert_ignore_03; -c1 c2 -6 null -12 null -1 2 -2 2 -8 2 -3 5 -9 5 -7 7 -4 10 -10 10 -5 12 -11 12 +➤ c1[4,32,0] ¦ c2[4,32,0] 𝄀 +1 ¦ 2 𝄀 +2 ¦ 2 𝄀 +3 ¦ 5 𝄀 +4 ¦ 10 𝄀 +5 ¦ 12 𝄀 +6 ¦ null 𝄀 +7 ¦ 7 𝄀 +8 ¦ 2 𝄀 +9 ¦ 5 𝄀 +10 ¦ 10 𝄀 +11 ¦ 12 𝄀 +12 ¦ null create table insert_ignore_04 (product_id INT NOT NULL AUTO_INCREMENT,product_name VARCHAR(255) NOT NULL,quantity_in_stock INT DEFAULT 0,price DECIMAL(10, 2) NOT NULL,PRIMARY KEY (product_id)); insert ignore into insert_ignore_04(product_name, price) VALUES('Laptop', 1200.00),('Monitor', 150.00),('Keyboard', NULL),('Mouse', 15.00); constraint violation: Column 'price' cannot be null insert ignore into insert_ignore_04(product_name, quantity_in_stock,price) VALUES(NULL, 5,1200.00),('board',6, NULL),('phone',NULL,1500.00); +[unknown result because it is related to issue#15345] select * from insert_ignore_04; -product_id product_name quantity_in_stock price -1 Laptop 0 1200.00 -2 Monitor 0 150.00 -3 Keyboard 0 0.00 -4 Mouse 0 15.00 -5 5 1200.00 -6 board 6 0.00 -7 phone null 1500.00 +[unknown result because it is related to issue#15345] create table parent_table(parent_id INT AUTO_INCREMENT PRIMARY KEY,parent_name VARCHAR(255) NOT NULL); +[unknown result because it is related to issue#15345] create table child_table(child_id INT AUTO_INCREMENT PRIMARY KEY,child_name VARCHAR(255) NOT NULL,parent_id INT,FOREIGN KEY (parent_id) REFERENCES parent_table(parent_id) ); +[unknown result because it is related to issue#15345] insert ignore into parent_table (parent_name) VALUES ('Parent 1'), ('Parent 2'), ('Parent 3'); +[unknown result because it is related to issue#15345] insert ignore into child_table (child_name, parent_id) VALUES('Child 1', 1),('Child 2', 2),('Child 3', 4),('Child 4', 1); +[unknown result because it is related to issue#15345] select * from parent_table; -parent_id parent_name -1 Parent 1 -2 Parent 2 -3 Parent 3 +[unknown result because it is related to issue#15345] select * from child_table; -child_id child_name parent_id -1 Child 1 1 -2 Child 2 2 -3 Child 4 1 +[unknown result because it is related to issue#15345] insert ignore into insert_ignore_02 values(1234.56); Column count doesn't match value count at row 1 insert ignore into insert_ignore_02 values("abc",1234.56); +[unknown result because it is related to issue#15345] insert ignore into insert_ignore_02 select "abc",34.22; +[unknown result because it is related to issue#15345] insert ignore into insert_ignore values("abc",1234.56); no such table insert_ignore.insert_ignore create table insert_ignore_05(id TINYINT,created_at DATETIME); +[unknown result because it is related to issue#15345] insert ignore INTO insert_ignore_05 (id, created_at) VALUES(130, '2024-04-03 10:00:00'),(-129, '2024-04-03 11:00:00'),(100, '2024-04-03 12:00:00'); +[unknown result because it is related to issue#15345] insert ignore INTO insert_ignore_05 (id, created_at) VALUES(50, '9999-12-31 23:59:59'), (50, '2000-02-29 10:00:00'),(50, '2024-04-03 13:00:00'); +[unknown result because it is related to issue#15345] select * from insert_ignore_05; -id created_at -127 2024-04-03 10:00:00 --128 2024-04-03 11:00:00 -100 2024-04-03 12:00:00 -50 9999-12-31 23:59:59 -50 2000-02-29 10:00:00 -50 2024-04-03 13:00:00 +[unknown result because it is related to issue#15345] create table insert_ignore_06 (sale_id INT AUTO_INCREMENT,product_id INT,sale_amount DECIMAL(10, 2),sale_date DATE,PRIMARY KEY (sale_id, sale_date))PARTITION BY RANGE (year(sale_date)) (PARTITION p0 VALUES LESS THAN (1991),PARTITION p1 VALUES LESS THAN (1992),PARTITION p2 VALUES LESS THAN (1993),PARTITION p3 VALUES LESS THAN (1994)); insert ignore into insert_ignore_06 (product_id, sale_amount, sale_date) VALUES(1, 1000.00, '1990-04-01'),(2, 1500.00, '1992-05-01'),(3, 500.00, '1995-06-01'),(1, 2000.00, '1991-07-01'); invalid input: Table has no partition for value from column_list select * from insert_ignore_06; -sale_id product_id sale_amount sale_date +➤ sale_id[4,32,0] ¦ product_id[4,32,0] ¦ sale_amount[3,10,2] ¦ sale_date[91,64,0] create table insert_ignore_07(c1 int primary key auto_increment, c2 int); insert into insert_ignore_07(c2) select result from generate_series(1,100000) g; create table insert_ignore_08(c1 int primary key, c2 int); insert into insert_ignore_08 values(20,45),(21,55),(1,45),(6,22),(5,1),(1000,222),(99999,19); insert ignore into insert_ignore_08 select * from insert_ignore_07; select count(*) from insert_ignore_08; -count(*) +➤ count(*)[-5,64,0] 𝄀 100000 select * from insert_ignore_08 where c2 in (45,55,22,1,222,19); -c1 c2 -20 45 -21 55 -1 45 -6 22 -5 1 -1000 222 -99999 19 -19 19 -22 22 -45 45 -55 55 -222 222 +➤ c1[4,32,0] ¦ c2[4,32,0] 𝄀 +20 ¦ 45 𝄀 +21 ¦ 55 𝄀 +1 ¦ 45 𝄀 +6 ¦ 22 𝄀 +5 ¦ 1 𝄀 +1000 ¦ 222 𝄀 +99999 ¦ 19 𝄀 +19 ¦ 19 𝄀 +22 ¦ 22 𝄀 +45 ¦ 45 𝄀 +55 ¦ 55 𝄀 +222 ¦ 222 create table insert_ignore_09(c1 int primary key, c2 int); insert into insert_ignore_09 values(20,45),(21,55),(1,45),(6,22),(5,1),(1000,222),(99999,19); insert ignore into insert_ignore_09 select result, result from generate_series(1,10000000) g; select count(*) from insert_ignore_09; -count(*) +➤ count(*)[-5,64,0] 𝄀 10000000 select count(*) from insert_ignore_09 where c1 != c2; -count(*) +➤ count(*)[-5,64,0] 𝄀 7 +set @insert_ignore_remote_sql_mode = @@session.sql_mode; +set session sql_mode = 'STRICT_TRANS_TABLES'; +drop table if exists insert_ignore_remote_special_bit; +create table insert_ignore_remote_special_bit (b bit(4)); +insert ignore into insert_ignore_remote_special_bit +select c1 from insert_ignore_09 where c1 between 1 and 100000; +select count(*), min(b + 0), max(b + 0) from insert_ignore_remote_special_bit; +➤ count(*)[-5,64,0] ¦ min(b + 0)[-5,64,0] ¦ max(b + 0)[-5,64,0] 𝄀 +100000 ¦ 1 ¦ 15 +drop table insert_ignore_remote_special_bit; +set session sql_mode = @insert_ignore_remote_sql_mode; drop table if exists t_insert_ignore_panic; create table t_insert_ignore_panic ( pk varchar(50) not null, @@ -181,7 +183,7 @@ insert ignore into t_insert_ignore_panic (pk, col1) values ('pk011', 'dup11'), -- duplicate ('pk012', 'dup12'); -- duplicate select count(*) from t_insert_ignore_panic; -count(*) +➤ count(*)[-5,64,0] 𝄀 23 set @insert_ignore_sql_mode = @@session.sql_mode; set session sql_mode = 'STRICT_TRANS_TABLES'; @@ -225,21 +227,21 @@ create table insert_ignore_special_bit64 (b bit(64)); insert ignore into insert_ignore_special_bit64 select f64 from insert_ignore_special_source; select hex(b) from insert_ignore_special_bit64; -hex(b) +➤ hex(b)[12,-1,0] 𝄀 FFFFFFFFFFFFFFFF drop table insert_ignore_special_bit64; select id, y + 0, bin(b + 0), e, e + 0, s, s + 0 from insert_ignore_special_types order by id; -id y + 0 bin(b + 0) e e + 0 s s + 0 -1 0 1111 0 x 1 -2 0 1111 0 x,y 3 -3 0 1111 0 x,y 3 -4 0 0 0 x,y 3 -5 0 0 0 x,y 3 -6 0 1111 a 1 x 1 -7 0 1111 a 1 x 1 -8 0 1111 a 1 x 1 -9 0 1111 a 1 x 1 +➤ id[4,32,0] ¦ y + 0[-5,64,0] ¦ bin(b + 0)[12,-1,0] ¦ e[12,-1,0] ¦ e + 0[-5,64,0] ¦ s[12,-1,0] ¦ s + 0[3,38,0] 𝄀 +1 ¦ 0 ¦ 1111 ¦ ¦ 0 ¦ x ¦ 1 𝄀 +2 ¦ 0 ¦ 1111 ¦ ¦ 0 ¦ x,y ¦ 3 𝄀 +3 ¦ 0 ¦ 1111 ¦ ¦ 0 ¦ x,y ¦ 3 𝄀 +4 ¦ 0 ¦ 0 ¦ ¦ 0 ¦ x,y ¦ 3 𝄀 +5 ¦ 0 ¦ 0 ¦ ¦ 0 ¦ x,y ¦ 3 𝄀 +6 ¦ 0 ¦ 1111 ¦ a ¦ 1 ¦ x ¦ 1 𝄀 +7 ¦ 0 ¦ 1111 ¦ a ¦ 1 ¦ x ¦ 1 𝄀 +8 ¦ 0 ¦ 1111 ¦ a ¦ 1 ¦ x ¦ 1 𝄀 +9 ¦ 0 ¦ 1111 ¦ a ¦ 1 ¦ x ¦ 1 drop table insert_ignore_special_source; drop table insert_ignore_special_types; set session sql_mode = @insert_ignore_sql_mode; diff --git a/test/distributed/cases/dml/insert/insert_ignore.sql b/test/distributed/cases/dml/insert/insert_ignore.sql index f3ac8c9ee7d93..4ee21bf6add64 100644 --- a/test/distributed/cases/dml/insert/insert_ignore.sql +++ b/test/distributed/cases/dml/insert/insert_ignore.sql @@ -77,6 +77,19 @@ insert ignore into insert_ignore_09 select result, result from generate_series(1 select count(*) from insert_ignore_09; select count(*) from insert_ignore_09 where c1 != c2; +-- The preceding large materialized source makes the source PROJECT eligible +-- for remote-CN execution. INSERT IGNORE must retain its adjustment semantics +-- when the BIT assignment cast is evaluated in that remote pipeline. +set @insert_ignore_remote_sql_mode = @@session.sql_mode; +set session sql_mode = 'STRICT_TRANS_TABLES'; +drop table if exists insert_ignore_remote_special_bit; +create table insert_ignore_remote_special_bit (b bit(4)); +insert ignore into insert_ignore_remote_special_bit +select c1 from insert_ignore_09 where c1 between 1 and 100000; +select count(*), min(b + 0), max(b + 0) from insert_ignore_remote_special_bit; +drop table insert_ignore_remote_special_bit; +set session sql_mode = @insert_ignore_remote_sql_mode; + -- Test case for INSERT IGNORE with many duplicate primary keys -- This test reproduces the index out of range panic issue -- Root cause: InputBatchRowCount not updated after Batches.Shrink removes duplicates in hashmap builder From f1a90e72a107a623e3a35633bf9a6220f920eb63 Mon Sep 17 00:00:00 2001 From: daviszhen Date: Tue, 4 Aug 2026 17:53:08 +0800 Subject: [PATCH 22/22] update --- pkg/vm/process/process_codec_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vm/process/process_codec_test.go b/pkg/vm/process/process_codec_test.go index 786c63fb677e2..1091abfa90264 100644 --- a/pkg/vm/process/process_codec_test.go +++ b/pkg/vm/process/process_codec_test.go @@ -97,8 +97,8 @@ func newCodecTestProcess(t *testing.T) (*Process, client.TxnOperator) { sp := NewStmtProfile(uuid.MustParse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"), uuid.MustParse("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb")) sp.SetTxnId([]byte("txn-profile-123456")) sp.SetStmtId(uuid.MustParse("cccccccc-cccc-cccc-cccc-cccccccccccc")) - sp.SetStatementRuntimeProfile("Insert", "DML", true) proc.SetStmtProfile(sp) + sp.SetStatementRuntimeProfile("Insert", "DML", true) vec := vector.NewVec(types.T_text.ToType()) require.NoError(t, vector.AppendBytes(vec, []byte("a"), false, proc.Mp()))