func TestFractionals(t *testing.T) { client := framework.NewClient() defer client.Execute("delete from vitess_fracts", nil) _, err := client.Execute( "insert into vitess_fracts values(:id, :deci, :num, :f, :d)", map[string]interface{}{ "id": 1, "deci": "1.99", "num": "2.99", "f": 3.99, "d": 4.99, }, ) if err != nil { t.Error(err) return } qr, err := client.Execute("select * from vitess_fracts where id = 1", nil) if err != nil { t.Error(err) return } want := sqltypes.Result{ Fields: []*querypb.Field{ { Name: "id", Type: sqltypes.Int32, }, { Name: "deci", Type: sqltypes.Decimal, }, { Name: "num", Type: sqltypes.Decimal, }, { Name: "f", Type: sqltypes.Float32, }, { Name: "d", Type: sqltypes.Float64, }, }, RowsAffected: 1, Rows: [][]sqltypes.Value{ []sqltypes.Value{ sqltypes.MakeNumeric([]byte("1")), sqltypes.MakeFractional([]byte("1.99")), sqltypes.MakeFractional([]byte("2.99")), sqltypes.MakeFractional([]byte("3.99")), sqltypes.MakeFractional([]byte("4.99")), }, }, } if !reflect.DeepEqual(*qr, want) { t.Errorf("Execute: \n%#v, want \n%#v", *qr, want) } }
func TestLookupHashAutoMapBadData(t *testing.T) { result := &mproto.QueryResult{ Fields: []mproto.Field{{ Type: mproto.VT_INT24, }}, Rows: [][]sqltypes.Value{ []sqltypes.Value{ sqltypes.MakeFractional([]byte("1.1")), }, }, RowsAffected: 1, } vc := &vcursor{result: result} _, err := lha.(planbuilder.NonUnique).Map(vc, []interface{}{1, int32(2)}) want := `lookup.Map: strconv.ParseInt: parsing "1.1": invalid syntax` if err == nil || err.Error() != want { t.Errorf("lha.Map: %v, want %v", err, want) } result.Fields = []mproto.Field{{ Type: mproto.VT_FLOAT, }} vc = &vcursor{result: result} _, err = lha.(planbuilder.NonUnique).Map(vc, []interface{}{1, int32(2)}) want = `lookup.Map: unexpected type for 1.1: float64` if err == nil || err.Error() != want { t.Errorf("lha.Map: %v, want %v", err, want) } }
// makeValueString returns a string that contains all the passed-in rows // as an insert SQL command's parameters. func makeValueString(fields []mproto.Field, rows [][]sqltypes.Value) string { buf := bytes.Buffer{} for i, row := range rows { if i > 0 { buf.Write([]byte(",(")) } else { buf.WriteByte('(') } for j, value := range row { if j > 0 { buf.WriteByte(',') } // convert value back to its original type if !value.IsNull() { switch fields[j].Type { case mproto.VT_TINY, mproto.VT_SHORT, mproto.VT_LONG, mproto.VT_LONGLONG, mproto.VT_INT24: value = sqltypes.MakeNumeric(value.Raw()) case mproto.VT_FLOAT, mproto.VT_DOUBLE: value = sqltypes.MakeFractional(value.Raw()) } } value.EncodeSql(&buf) } buf.WriteByte(')') } return buf.String() }
// makeValueString returns a string that contains all the passed-in rows // as an insert SQL command's parameters. func makeValueString(fields []*query.Field, rows [][]sqltypes.Value) string { buf := bytes.Buffer{} for i, row := range rows { if i > 0 { buf.Write([]byte(",(")) } else { buf.WriteByte('(') } for j, value := range row { if j > 0 { buf.WriteByte(',') } // convert value back to its original type if !value.IsNull() { switch { case sqltypes.IsIntegral(fields[j].Type): value = sqltypes.MakeNumeric(value.Raw()) case sqltypes.IsFloat(fields[j].Type): value = sqltypes.MakeFractional(value.Raw()) } } value.EncodeSQL(&buf) } buf.WriteByte(')') } return buf.String() }
func BuildValue(bytes []byte, fieldType uint32) sqltypes.Value { switch fieldType { case C.MYSQL_TYPE_DECIMAL, C.MYSQL_TYPE_FLOAT, C.MYSQL_TYPE_DOUBLE, C.MYSQL_TYPE_NEWDECIMAL: return sqltypes.MakeFractional(bytes) case C.MYSQL_TYPE_TIMESTAMP: return sqltypes.MakeString(bytes) } // The below condition represents the following list of values: // C.MYSQL_TYPE_TINY, C.MYSQL_TYPE_SHORT, C.MYSQL_TYPE_LONG, C.MYSQL_TYPE_LONGLONG, C.MYSQL_TYPE_INT24, C.MYSQL_TYPE_YEAR: if fieldType <= C.MYSQL_TYPE_INT24 || fieldType == C.MYSQL_TYPE_YEAR { return sqltypes.MakeNumeric(bytes) } return sqltypes.MakeString(bytes) }
// BuildValue returns a sqltypes.Value from the passed in fields func BuildValue(bytes []byte, fieldType uint32) sqltypes.Value { if bytes == nil { return sqltypes.NULL } switch fieldType { case typeDecimal, TypeFloat, TypeDouble, TypeNewDecimal: return sqltypes.MakeFractional(bytes) case TypeTimestamp: return sqltypes.MakeString(bytes) } // The below condition represents the following list of values: // TypeTiny, TypeShort, TypeLong, TypeLonglong, TypeInt24, TypeYear: if fieldType <= TypeInt24 || fieldType == TypeYear { return sqltypes.MakeNumeric(bytes) } return sqltypes.MakeString(bytes) }
func TestCharaterSet(t *testing.T) { qr, err := framework.NewClient().Execute("select * from vitess_test where intval=1", nil) if err != nil { t.Error(err) return } want := mproto.QueryResult{ Fields: []mproto.Field{ { Name: "intval", Type: 3, Flags: 0, }, { Name: "floatval", Type: 4, Flags: 0, }, { Name: "charval", Type: 253, Flags: 0, }, { Name: "binval", Type: 253, Flags: mysql.FlagBinary, }, }, RowsAffected: 1, Rows: [][]sqltypes.Value{ []sqltypes.Value{ sqltypes.MakeNumeric([]byte("1")), sqltypes.MakeFractional([]byte("1.12345")), sqltypes.MakeString([]byte("\xc2\xa2")), sqltypes.MakeString([]byte("\x00\xff")), }, }, } if !reflect.DeepEqual(*qr, want) { t.Errorf("Execute: \n%#v, want \n%#v", *qr, want) } }
func TestLookupHashUniqueAutoMapBadData(t *testing.T) { result := &sqltypes.Result{ Fields: []*query.Field{{ Type: sqltypes.Int24, }}, Rows: [][]sqltypes.Value{ []sqltypes.Value{ sqltypes.MakeFractional([]byte("1.1")), }, }, RowsAffected: 1, } vc := &vcursor{result: result} _, err := lhua.(planbuilder.Unique).Map(vc, []interface{}{1, int32(2)}) want := `lookup.Map: strconv.ParseInt: parsing "1.1": invalid syntax` if err == nil || err.Error() != want { t.Errorf("lhua.Map: %v, want %v", err, want) } result.Fields = []*query.Field{{ Type: sqltypes.Float32, }} vc = &vcursor{result: result} _, err = lhua.(planbuilder.Unique).Map(vc, []interface{}{1, int32(2)}) want = `lookup.Map: unexpected type for 1.1: float64` if err == nil || err.Error() != want { t.Errorf("lhua.Map: %v, want %v", err, want) } vc = &vcursor{numRows: 2} _, err = lhua.(planbuilder.Unique).Map(vc, []interface{}{1, int32(2)}) want = `lookup.Map: unexpected multiple results from vindex t: 1` if err == nil || err.Error() != want { t.Errorf("lhua.Map: %v, want %v", err, want) } }
func TestBindVariablesToProto3(t *testing.T) { testcases := []struct { name string in interface{} out *query.BindVariable }{{ name: "string", in: "aa", out: &query.BindVariable{ Type: sqltypes.VarChar, Value: []byte("aa"), }, }, { name: "[]byte", in: []byte("aa"), out: &query.BindVariable{ Type: sqltypes.VarBinary, Value: []byte("aa"), }, }, { name: "int", in: int(1), out: &query.BindVariable{ Type: sqltypes.Int64, Value: []byte("1"), }, }, { name: "int8", in: int8(-1), out: &query.BindVariable{ Type: sqltypes.Int64, Value: []byte("-1"), }, }, { name: "int16", in: int16(-1), out: &query.BindVariable{ Type: sqltypes.Int64, Value: []byte("-1"), }, }, { name: "int32", in: int32(-1), out: &query.BindVariable{ Type: sqltypes.Int64, Value: []byte("-1"), }, }, { name: "int64", in: int64(-1), out: &query.BindVariable{ Type: sqltypes.Int64, Value: []byte("-1"), }, }, { name: "uint", in: uint(1), out: &query.BindVariable{ Type: sqltypes.Uint64, Value: []byte("1"), }, }, { name: "uint8", in: uint8(1), out: &query.BindVariable{ Type: sqltypes.Uint64, Value: []byte("1"), }, }, { name: "uint16", in: uint16(1), out: &query.BindVariable{ Type: sqltypes.Uint64, Value: []byte("1"), }, }, { name: "uint32", in: uint32(1), out: &query.BindVariable{ Type: sqltypes.Uint64, Value: []byte("1"), }, }, { name: "uint64", in: uint64(1), out: &query.BindVariable{ Type: sqltypes.Uint64, Value: []byte("1"), }, }, { name: "float32", in: float32(1.5), out: &query.BindVariable{ Type: sqltypes.Float64, Value: []byte("1.5"), }, }, { name: "float64", in: float64(1.5), out: &query.BindVariable{ Type: sqltypes.Float64, Value: []byte("1.5"), }, }, { name: "sqltypes.NULL", in: sqltypes.NULL, out: &query.BindVariable{}, }, { name: "nil", in: nil, out: &query.BindVariable{}, }, { name: "sqltypes.Integral", in: sqltypes.MakeNumeric([]byte("1")), out: &query.BindVariable{ Type: sqltypes.Int64, Value: []byte("1"), }, }, { name: "sqltypes.Fractional", in: sqltypes.MakeFractional([]byte("1.5")), out: &query.BindVariable{ Type: sqltypes.Float64, Value: []byte("1.5"), }, }, { name: "sqltypes.String", in: sqltypes.MakeString([]byte("aa")), out: &query.BindVariable{ Type: sqltypes.VarBinary, Value: []byte("aa"), }, }, { name: "[]interface{}", in: []interface{}{1, "aa", sqltypes.MakeFractional([]byte("1.5"))}, out: &query.BindVariable{ Type: sqltypes.Tuple, Values: []*query.Value{ &query.Value{ Type: sqltypes.Int64, Value: []byte("1"), }, &query.Value{ Type: sqltypes.VarChar, Value: []byte("aa"), }, &query.Value{ Type: sqltypes.Float64, Value: []byte("1.5"), }, }, }, }, { name: "[]string", in: []string{"aa", "bb"}, out: &query.BindVariable{ Type: sqltypes.Tuple, Values: []*query.Value{ &query.Value{ Type: sqltypes.VarChar, Value: []byte("aa"), }, &query.Value{ Type: sqltypes.VarChar, Value: []byte("bb"), }, }, }, }, { name: "[][]byte", in: [][]byte{[]byte("aa"), []byte("bb")}, out: &query.BindVariable{ Type: sqltypes.Tuple, Values: []*query.Value{ &query.Value{ Type: sqltypes.VarBinary, Value: []byte("aa"), }, &query.Value{ Type: sqltypes.VarBinary, Value: []byte("bb"), }, }, }, }, { name: "[]int", in: []int{1, 2}, out: &query.BindVariable{ Type: sqltypes.Tuple, Values: []*query.Value{ &query.Value{ Type: sqltypes.Int64, Value: []byte("1"), }, &query.Value{ Type: sqltypes.Int64, Value: []byte("2"), }, }, }, }, { name: "[]int64", in: []int64{1, 2}, out: &query.BindVariable{ Type: sqltypes.Tuple, Values: []*query.Value{ &query.Value{ Type: sqltypes.Int64, Value: []byte("1"), }, &query.Value{ Type: sqltypes.Int64, Value: []byte("2"), }, }, }, }, { name: "[]uint64", in: []uint64{1, 2}, out: &query.BindVariable{ Type: sqltypes.Tuple, Values: []*query.Value{ &query.Value{ Type: sqltypes.Uint64, Value: []byte("1"), }, &query.Value{ Type: sqltypes.Uint64, Value: []byte("2"), }, }, }, }} for _, tcase := range testcases { bv := map[string]interface{}{ "bv": tcase.in, } p3, err := BindVariablesToProto3(bv) if err != nil { t.Errorf("Error on %v: %v", tcase.name, err) } if !reflect.DeepEqual(p3["bv"], tcase.out) { t.Errorf("Mismatch on %v: %+v, want %+v", tcase.name, p3["bv"], tcase.out) } } }
func TestCompareRows(t *testing.T) { table := []struct { fields []*querypb.Field left, right []sqltypes.Value want int }{ { fields: []*querypb.Field{{"a", sqltypes.Int32}}, left: []sqltypes.Value{sqltypes.MakeNumeric([]byte("123"))}, right: []sqltypes.Value{sqltypes.MakeNumeric([]byte("14"))}, want: 1, }, { fields: []*querypb.Field{ {"a", sqltypes.Int32}, {"b", sqltypes.Int32}, }, left: []sqltypes.Value{ sqltypes.MakeNumeric([]byte("555")), sqltypes.MakeNumeric([]byte("12")), }, right: []sqltypes.Value{ sqltypes.MakeNumeric([]byte("555")), sqltypes.MakeNumeric([]byte("144")), }, want: -1, }, { fields: []*querypb.Field{{"a", sqltypes.Int32}}, left: []sqltypes.Value{sqltypes.MakeNumeric([]byte("144"))}, right: []sqltypes.Value{sqltypes.MakeNumeric([]byte("144"))}, want: 0, }, { fields: []*querypb.Field{{"a", sqltypes.Uint64}}, left: []sqltypes.Value{sqltypes.MakeNumeric([]byte("9223372036854775809"))}, right: []sqltypes.Value{sqltypes.MakeNumeric([]byte("9223372036854775810"))}, want: -1, }, { fields: []*querypb.Field{{"a", sqltypes.Uint64}}, left: []sqltypes.Value{sqltypes.MakeNumeric([]byte("9223372036854775819"))}, right: []sqltypes.Value{sqltypes.MakeNumeric([]byte("9223372036854775810"))}, want: 1, }, { fields: []*querypb.Field{{"a", sqltypes.Float64}}, left: []sqltypes.Value{sqltypes.MakeFractional([]byte("3.14"))}, right: []sqltypes.Value{sqltypes.MakeFractional([]byte("3.2"))}, want: -1, }, { fields: []*querypb.Field{{"a", sqltypes.Float64}}, left: []sqltypes.Value{sqltypes.MakeFractional([]byte("123.4"))}, right: []sqltypes.Value{sqltypes.MakeFractional([]byte("123.2"))}, want: 1, }, { fields: []*querypb.Field{{"a", sqltypes.Char}}, left: []sqltypes.Value{sqltypes.MakeString([]byte("abc"))}, right: []sqltypes.Value{sqltypes.MakeString([]byte("abb"))}, want: 1, }, { fields: []*querypb.Field{{"a", sqltypes.Char}}, left: []sqltypes.Value{sqltypes.MakeString([]byte("abc"))}, right: []sqltypes.Value{sqltypes.MakeString([]byte("abd"))}, want: -1, }, } for _, tc := range table { got, err := CompareRows(tc.fields, len(tc.fields), tc.left, tc.right) if err != nil { t.Errorf("CompareRows error: %v", err) continue } if got != tc.want { t.Errorf("CompareRows(%v, %v, %v) = %v, want %v", tc.fields, tc.left, tc.right, got, tc.want) } } }
func TestCompareRows(t *testing.T) { table := []struct { fields []mproto.Field left, right []sqltypes.Value want int }{ { fields: []mproto.Field{{"a", mproto.VT_LONG, mproto.VT_ZEROVALUE_FLAG}}, left: []sqltypes.Value{sqltypes.MakeNumeric([]byte("123"))}, right: []sqltypes.Value{sqltypes.MakeNumeric([]byte("14"))}, want: 1, }, { fields: []mproto.Field{ {"a", mproto.VT_LONG, mproto.VT_ZEROVALUE_FLAG}, {"b", mproto.VT_LONG, mproto.VT_ZEROVALUE_FLAG}, }, left: []sqltypes.Value{ sqltypes.MakeNumeric([]byte("555")), sqltypes.MakeNumeric([]byte("12")), }, right: []sqltypes.Value{ sqltypes.MakeNumeric([]byte("555")), sqltypes.MakeNumeric([]byte("144")), }, want: -1, }, { fields: []mproto.Field{{"a", mproto.VT_LONG, mproto.VT_ZEROVALUE_FLAG}}, left: []sqltypes.Value{sqltypes.MakeNumeric([]byte("144"))}, right: []sqltypes.Value{sqltypes.MakeNumeric([]byte("144"))}, want: 0, }, { fields: []mproto.Field{{"a", mproto.VT_LONGLONG, mproto.VT_UNSIGNED_FLAG}}, left: []sqltypes.Value{sqltypes.MakeNumeric([]byte("9223372036854775809"))}, right: []sqltypes.Value{sqltypes.MakeNumeric([]byte("9223372036854775810"))}, want: -1, }, { fields: []mproto.Field{{"a", mproto.VT_LONGLONG, mproto.VT_UNSIGNED_FLAG}}, left: []sqltypes.Value{sqltypes.MakeNumeric([]byte("9223372036854775819"))}, right: []sqltypes.Value{sqltypes.MakeNumeric([]byte("9223372036854775810"))}, want: 1, }, { fields: []mproto.Field{{"a", mproto.VT_DOUBLE, mproto.VT_ZEROVALUE_FLAG}}, left: []sqltypes.Value{sqltypes.MakeFractional([]byte("3.14"))}, right: []sqltypes.Value{sqltypes.MakeFractional([]byte("3.2"))}, want: -1, }, { fields: []mproto.Field{{"a", mproto.VT_DOUBLE, mproto.VT_ZEROVALUE_FLAG}}, left: []sqltypes.Value{sqltypes.MakeFractional([]byte("123.4"))}, right: []sqltypes.Value{sqltypes.MakeFractional([]byte("123.2"))}, want: 1, }, { fields: []mproto.Field{{"a", mproto.VT_STRING, mproto.VT_ZEROVALUE_FLAG}}, left: []sqltypes.Value{sqltypes.MakeString([]byte("abc"))}, right: []sqltypes.Value{sqltypes.MakeString([]byte("abb"))}, want: 1, }, { fields: []mproto.Field{{"a", mproto.VT_STRING, mproto.VT_ZEROVALUE_FLAG}}, left: []sqltypes.Value{sqltypes.MakeString([]byte("abc"))}, right: []sqltypes.Value{sqltypes.MakeString([]byte("abd"))}, want: -1, }, } for _, tc := range table { got, err := CompareRows(tc.fields, len(tc.fields), tc.left, tc.right) if err != nil { t.Errorf("CompareRows error: %v", err) continue } if got != tc.want { t.Errorf("CompareRows(%v, %v, %v) = %v, want %v", tc.fields, tc.left, tc.right, got, tc.want) } } }
encoded: "E\x00\x00\x00\x04Fields\x00\x05\x00\x00\x00\x00\x12RowsAffected\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12InsertId\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04Rows\x00\x05\x00\x00\x00\x00\x00", }, // Only fields set { qr: QueryResult{ Fields: []Field{ {Name: "foo", Type: 1}, }, }, encoded: "i\x00\x00\x00\x04Fields\x00)\x00\x00\x00\x030\x00!\x00\x00\x00\x05Name\x00\x03\x00\x00\x00\x00foo\x12Type\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12RowsAffected\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12InsertId\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04Rows\x00\x05\x00\x00\x00\x00\x00", }, // Only rows, no fields { qr: QueryResult{ Rows: [][]sqltypes.Value{ {sqltypes.MakeString([]byte("abcd")), sqltypes.MakeNumeric([]byte("1234")), sqltypes.MakeFractional([]byte("1.234"))}, }, }, encoded: "r\x00\x00\x00\x04Fields\x00\x05\x00\x00\x00\x00\x12RowsAffected\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12InsertId\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04Rows\x002\x00\x00\x00\x040\x00*\x00\x00\x00\x050\x00\x04\x00\x00\x00\x00abcd\x051\x00\x04\x00\x00\x00\x001234\x052\x00\x05\x00\x00\x00\x001.234\x00\x00\x00", }, // one row and one field { qr: QueryResult{ Fields: []Field{ {Name: "foo", Type: 1}, }, Rows: [][]sqltypes.Value{ {sqltypes.MakeString([]byte("abcd")), sqltypes.MakeNumeric([]byte("1234")), sqltypes.MakeFractional([]byte("1.234")), sqltypes.Value{}}, }, }, encoded: "",
func TestFractionals(t *testing.T) { client := framework.NewClient() defer client.Execute("delete from vitess_fracts", nil) _, err := client.Execute( "insert into vitess_fracts values(:id, :deci, :num, :f, :d)", map[string]interface{}{ "id": 1, "deci": "1.99", "num": "2.99", "f": 3.99, "d": 4.99, }, ) if err != nil { t.Error(err) return } qr, err := client.Execute("select * from vitess_fracts where id = 1", nil) if err != nil { t.Error(err) return } want := mproto.QueryResult{ Fields: []mproto.Field{ { Name: "id", Type: mysql.TypeLong, Flags: 0, }, { Name: "deci", Type: mysql.TypeNewDecimal, Flags: 0, }, { Name: "num", Type: mysql.TypeNewDecimal, Flags: 0, }, { Name: "f", Type: mysql.TypeFloat, Flags: 0, }, { Name: "d", Type: mysql.TypeDouble, Flags: 0, }, }, RowsAffected: 1, Rows: [][]sqltypes.Value{ []sqltypes.Value{ sqltypes.MakeNumeric([]byte("1")), sqltypes.MakeFractional([]byte("1.99")), sqltypes.MakeFractional([]byte("2.99")), sqltypes.MakeFractional([]byte("3.99")), sqltypes.MakeFractional([]byte("4.99")), }, }, } if !reflect.DeepEqual(*qr, want) { t.Errorf("Execute: \n%#v, want \n%#v", *qr, want) } wantTypes := []query.Type{ sqltypes.Int32, sqltypes.Decimal, sqltypes.Decimal, sqltypes.Float32, sqltypes.Float64, } for i, field := range qr.Fields { got := sqltypes.MySQLToType(field.Type, field.Flags) if got != wantTypes[i] { t.Errorf("Unexpected type: col: %d, %d, want %d", i, got, wantTypes[i]) } } }