func TestNull(t *testing.T) { client := framework.NewClient() qr, err := client.Execute("select null from dual", nil) if err != nil { t.Error(err) return } want := mproto.QueryResult{ Fields: []mproto.Field{ { Name: "NULL", Type: mysql.TypeNull, Flags: mysql.FlagBinary, }, }, RowsAffected: 1, Rows: [][]sqltypes.Value{ []sqltypes.Value{ sqltypes.Value{}, }, }, } if !reflect.DeepEqual(*qr, want) { t.Errorf("Execute: \n%#v, want \n%#v", *qr, want) } wantTypes := []query.Type{ sqltypes.Null, } 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]) } } }
// FetchNext returns the next row for a query func (conn *Connection) FetchNext() (row []sqltypes.Value, err error) { vtrow := C.vt_fetch_next(&conn.c) if vtrow.has_error != 0 { return nil, conn.lastError("") } rowPtr := (*[maxSize]*[maxSize]byte)(unsafe.Pointer(vtrow.mysql_row)) if rowPtr == nil { return nil, nil } colCount := int(conn.c.num_fields) cfields := (*[maxSize]C.MYSQL_FIELD)(unsafe.Pointer(conn.c.fields)) row = make([]sqltypes.Value, colCount) lengths := (*[maxSize]uint64)(unsafe.Pointer(vtrow.lengths)) totalLength := uint64(0) for i := 0; i < colCount; i++ { totalLength += lengths[i] } arena := make([]byte, 0, int(totalLength)) for i := 0; i < colCount; i++ { colLength := lengths[i] colPtr := rowPtr[i] if colPtr == nil { continue } start := len(arena) arena = append(arena, colPtr[:colLength]...) // MySQL values can be trusted. row[i] = sqltypes.MakeTrusted( sqltypes.MySQLToType(int64(cfields[i]._type), int64(cfields[i].flags)), arena[start:start+int(colLength)], ) } return row, nil }
// FieldsToProto3 converts an internal []Field to the proto3 version func FieldsToProto3(f []Field) []*pbq.Field { if len(f) == 0 { return nil } result := make([]*pbq.Field, len(f)) for i, f := range f { result[i] = &pbq.Field{ Name: f.Name, Type: sqltypes.MySQLToType(f.Type, f.Flags), } } return result }
// FieldsToProto3 converts an internal []Field to the proto3 version func FieldsToProto3(f []Field) ([]*pbq.Field, error) { if len(f) == 0 { return nil, nil } result := make([]*pbq.Field, len(f)) for i, f := range f { vitessType, err := sqltypes.MySQLToType(f.Type, f.Flags) if err != nil { return nil, err } result[i] = &pbq.Field{ Name: f.Name, Type: vitessType, } } return result, nil }
// Fields returns the current fields description for the query func (conn *Connection) Fields() (fields []*querypb.Field) { nfields := int(conn.c.num_fields) if nfields == 0 { return nil } cfields := (*[maxSize]C.MYSQL_FIELD)(unsafe.Pointer(conn.c.fields)) totalLength := uint64(0) for i := 0; i < nfields; i++ { totalLength += uint64(cfields[i].name_length) } fields = make([]*querypb.Field, nfields) fvals := make([]querypb.Field, nfields) for i := 0; i < nfields; i++ { length := cfields[i].name_length fname := (*[maxSize]byte)(unsafe.Pointer(cfields[i].name))[:length] fvals[i].Name = string(fname) fvals[i].Type = sqltypes.MySQLToType(int64(cfields[i]._type), int64(cfields[i].flags)) fields[i] = &fvals[i] } return fields }
func (ti *TableInfo) fetchColumns(conn *DBConn) error { qr, err := conn.Exec(context.Background(), fmt.Sprintf("select * from `%s` where 1 != 1", ti.Name), 10000, true) if err != nil { return err } fieldTypes := make(map[string]query.Type, len(qr.Fields)) for _, field := range qr.Fields { fieldTypes[field.Name] = sqltypes.MySQLToType(field.Type, field.Flags) } columns, err := conn.Exec(context.Background(), fmt.Sprintf("describe `%s`", ti.Name), 10000, false) if err != nil { return err } for _, row := range columns.Rows { name := row[0].String() columnType, ok := fieldTypes[name] if !ok { log.Warningf("Table: %s, column %s not found in select list, skipping.", ti.Name, name) continue } ti.AddColumn(name, columnType, row[4], row[5].String()) } return nil }
func TestInts(t *testing.T) { client := framework.NewClient() defer client.Execute("delete from vitess_ints", nil) _, err := client.Execute( "insert into vitess_ints values(:tiny, :tinyu, :small, "+ ":smallu, :medium, :mediumu, :normal, :normalu, :big, :bigu, :year)", map[string]interface{}{ "tiny": int32(-128), "tinyu": uint32(255), "small": int32(-32768), "smallu": uint32(65535), "medium": int32(-8388608), "mediumu": uint32(16777215), "normal": int64(-2147483648), "normalu": uint64(4294967295), "big": int64(-9223372036854775808), "bigu": uint64(18446744073709551615), "year": 2012, }, ) if err != nil { t.Error(err) return } qr, err := client.Execute("select * from vitess_ints where tiny = -128", nil) if err != nil { t.Error(err) return } want := mproto.QueryResult{ Fields: []mproto.Field{ { Name: "tiny", Type: mysql.TypeTiny, Flags: 0, }, { Name: "tinyu", Type: mysql.TypeTiny, Flags: mysql.FlagUnsigned, }, { Name: "small", Type: mysql.TypeShort, Flags: 0, }, { Name: "smallu", Type: mysql.TypeShort, Flags: mysql.FlagUnsigned, }, { Name: "medium", Type: mysql.TypeInt24, Flags: 0, }, { Name: "mediumu", Type: mysql.TypeInt24, Flags: mysql.FlagUnsigned, }, { Name: "normal", Type: mysql.TypeLong, Flags: 0, }, { Name: "normalu", Type: mysql.TypeLong, Flags: mysql.FlagUnsigned, }, { Name: "big", Type: mysql.TypeLonglong, Flags: 0, }, { Name: "bigu", Type: mysql.TypeLonglong, Flags: mysql.FlagUnsigned, }, { Name: "y", Type: mysql.TypeYear, Flags: mysql.FlagUnsigned, }, }, RowsAffected: 1, Rows: [][]sqltypes.Value{ []sqltypes.Value{ sqltypes.MakeNumeric([]byte("-128")), sqltypes.MakeNumeric([]byte("255")), sqltypes.MakeNumeric([]byte("-32768")), sqltypes.MakeNumeric([]byte("65535")), sqltypes.MakeNumeric([]byte("-8388608")), sqltypes.MakeNumeric([]byte("16777215")), sqltypes.MakeNumeric([]byte("-2147483648")), sqltypes.MakeNumeric([]byte("4294967295")), sqltypes.MakeNumeric([]byte("-9223372036854775808")), sqltypes.MakeNumeric([]byte("18446744073709551615")), sqltypes.MakeNumeric([]byte("2012")), }, }, } if !reflect.DeepEqual(*qr, want) { t.Errorf("Execute: \n%#v, want \n%#v", *qr, want) } wantTypes := []query.Type{ sqltypes.Int8, sqltypes.Uint8, sqltypes.Int16, sqltypes.Uint16, sqltypes.Int24, sqltypes.Uint24, sqltypes.Int32, sqltypes.Uint32, sqltypes.Int64, sqltypes.Uint64, sqltypes.Year, } 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]) } } }
func TestMiscTypes(t *testing.T) { client := framework.NewClient() defer client.Execute("delete from vitess_misc", nil) _, err := client.Execute( "insert into vitess_misc values(:id, :b, :d, :dt, :t)", map[string]interface{}{ "id": 1, "b": "\x01", "d": "2012-01-01", "dt": "2012-01-01 15:45:45", "t": "15:45:45", }, ) if err != nil { t.Error(err) return } qr, err := client.Execute("select * from vitess_misc 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: "b", Type: mysql.TypeBit, Flags: mysql.FlagUnsigned, }, { Name: "d", Type: mysql.TypeDate, Flags: mysql.FlagBinary, }, { Name: "dt", Type: mysql.TypeDatetime, Flags: mysql.FlagBinary, }, { Name: "t", Type: mysql.TypeTime, Flags: mysql.FlagBinary, }, }, RowsAffected: 1, Rows: [][]sqltypes.Value{ []sqltypes.Value{ sqltypes.MakeNumeric([]byte("1")), sqltypes.MakeString([]byte("\x01")), sqltypes.MakeString([]byte("2012-01-01")), sqltypes.MakeString([]byte("2012-01-01 15:45:45")), sqltypes.MakeString([]byte("15:45:45")), }, }, } if !reflect.DeepEqual(*qr, want) { t.Errorf("Execute: \n%#v, want \n%#v", *qr, want) } wantTypes := []query.Type{ sqltypes.Int32, sqltypes.Bit, sqltypes.Date, sqltypes.Datetime, sqltypes.Time, } 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]) } } }
func TestStrings(t *testing.T) { client := framework.NewClient() defer client.Execute("delete from vitess_strings", nil) _, err := client.Execute( "insert into vitess_strings values "+ "(:vb, :c, :vc, :b, :tb, :bl, :ttx, :tx, :en, :s)", map[string]interface{}{ "vb": "a", "c": "b", "vc": "c", "b": "d", "tb": "e", "bl": "f", "ttx": "g", "tx": "h", "en": "a", "s": "a,b", }, ) if err != nil { t.Error(err) return } qr, err := client.Execute("select * from vitess_strings where vb = 'a'", nil) if err != nil { t.Error(err) return } want := mproto.QueryResult{ Fields: []mproto.Field{ { Name: "vb", Type: mysql.TypeVarString, Flags: mysql.FlagBinary, }, { Name: "c", Type: mysql.TypeString, Flags: 0, }, { Name: "vc", Type: mysql.TypeVarString, Flags: 0, }, { Name: "b", Type: mysql.TypeString, Flags: mysql.FlagBinary, }, { Name: "tb", Type: mysql.TypeBlob, Flags: mysql.FlagBinary, }, { Name: "bl", Type: mysql.TypeBlob, Flags: mysql.FlagBinary, }, { Name: "ttx", Type: mysql.TypeBlob, Flags: 0, }, { Name: "tx", Type: mysql.TypeBlob, Flags: 0, }, { Name: "en", Type: mysql.TypeString, Flags: mysql.FlagEnum, }, { Name: "s", Type: mysql.TypeString, Flags: mysql.FlagSet, }, }, RowsAffected: 1, Rows: [][]sqltypes.Value{ []sqltypes.Value{ sqltypes.MakeString([]byte("a")), sqltypes.MakeString([]byte("b")), sqltypes.MakeString([]byte("c")), sqltypes.MakeString([]byte("d\x00\x00\x00")), sqltypes.MakeString([]byte("e")), sqltypes.MakeString([]byte("f")), sqltypes.MakeString([]byte("g")), sqltypes.MakeString([]byte("h")), sqltypes.MakeString([]byte("a")), sqltypes.MakeString([]byte("a,b")), }, }, } if !reflect.DeepEqual(*qr, want) { t.Errorf("Execute: \n%#v, want \n%#v", *qr, want) } wantTypes := []query.Type{ sqltypes.VarBinary, sqltypes.Char, sqltypes.VarChar, sqltypes.Binary, sqltypes.Blob, sqltypes.Blob, sqltypes.Text, sqltypes.Text, sqltypes.Enum, sqltypes.Set, } 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]) } } }
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]) } } }
// UnmarshalBson bson-decodes into QueryResult. func (queryResult *QueryResult) UnmarshalBson(buf *bytes.Buffer, kind byte) { switch kind { case bson.EOO, bson.Object: // valid case bson.Null: return default: panic(bson.NewBsonError("unexpected kind %v for QueryResult", kind)) } bson.Next(buf, 4) for kind := bson.NextByte(buf); kind != bson.EOO; kind = bson.NextByte(buf) { switch bson.ReadCString(buf) { case "Fields": // []*query.Field if kind != bson.Null { if kind != bson.Array { panic(bson.NewBsonError("unexpected kind %v for queryResult.Fields", kind)) } bson.Next(buf, 4) queryResult.Fields = make([]*querypb.Field, 0, 8) var f BSONField for kind := bson.NextByte(buf); kind != bson.EOO; kind = bson.NextByte(buf) { bson.SkipIndex(buf) var _v1 *querypb.Field // *query.Field _v1 = new(querypb.Field) bson.UnmarshalFromBuffer(buf, &f) _v1.Name = f.Name _v1.Type = sqltypes.MySQLToType(f.Type, f.Flags) queryResult.Fields = append(queryResult.Fields, _v1) } } case "RowsAffected": queryResult.RowsAffected = bson.DecodeUint64(buf, kind) case "InsertId": queryResult.InsertId = bson.DecodeUint64(buf, kind) case "Rows": // [][]sqltypes.Value if kind != bson.Null { if kind != bson.Array { panic(bson.NewBsonError("unexpected kind %v for queryResult.Rows", kind)) } bson.Next(buf, 4) queryResult.Rows = make([][]sqltypes.Value, 0, 8) for kind := bson.NextByte(buf); kind != bson.EOO; kind = bson.NextByte(buf) { bson.SkipIndex(buf) var _v2 []sqltypes.Value // []sqltypes.Value if kind != bson.Null { if kind != bson.Array { panic(bson.NewBsonError("unexpected kind %v for _v2", kind)) } bson.Next(buf, 4) _v2 = make([]sqltypes.Value, 0, 8) for kind := bson.NextByte(buf); kind != bson.EOO; kind = bson.NextByte(buf) { bson.SkipIndex(buf) var _v3 sqltypes.Value _v3.UnmarshalBson(buf, kind) _v2 = append(_v2, _v3) } } queryResult.Rows = append(queryResult.Rows, _v2) } } case "Err": // *RPCError if kind != bson.Null { queryResult.Err = new(RPCError) (*queryResult.Err).UnmarshalBson(buf, kind) } default: bson.Skip(buf, kind) } } }