diff --git a/README.md b/README.md index 0f1c85928..0602d5c5f 100644 --- a/README.md +++ b/README.md @@ -323,8 +323,9 @@ a custom packer/unpacker, but it will work slower. ```go import ( + "fmt" "github.com/tarantool/go-tarantool" - "gopkg.in/vmihailenco/msgpack.v2" + "github.com/vmihailenco/msgpack/v5" ) type Member struct { @@ -349,13 +350,13 @@ type Tuple2 struct { } func (m *Member) EncodeMsgpack(e *msgpack.Encoder) error { - if err := e.EncodeSliceLen(2); err != nil { + if err := e.EncodeArrayLen(2); err != nil { return err } if err := e.EncodeString(m.Name); err != nil { return err } - if err := e.EncodeUint(m.Val); err != nil { + if err := e.EncodeUint(uint64(m.Val)); err != nil { return err } return nil @@ -364,7 +365,7 @@ func (m *Member) EncodeMsgpack(e *msgpack.Encoder) error { func (m *Member) DecodeMsgpack(d *msgpack.Decoder) error { var err error var l int - if l, err = d.DecodeSliceLen(); err != nil { + if l, err = d.DecodeArrayLen(); err != nil { return err } if l != 2 { @@ -380,7 +381,7 @@ func (m *Member) DecodeMsgpack(d *msgpack.Decoder) error { } func (c *Tuple) EncodeMsgpack(e *msgpack.Encoder) error { - if err := e.EncodeSliceLen(3); err != nil { + if err := e.EncodeArrayLen(3); err != nil { return err } if err := e.EncodeUint(c.Cid); err != nil { @@ -506,7 +507,7 @@ func decodeTuple(d *msgpack.Decoder, v reflect.Value) error { ```go package main import ( - "gopkg.in/vmihailenco/msgpack.v2" + "github.com/vmihailenco/msgpack/v5" "github.com/tarantool/go-tarantool" "github.com/tarantool/go-tarantool/queue" "time" diff --git a/client_tools.go b/client_tools.go index ed76ea258..72fe75eb3 100644 --- a/client_tools.go +++ b/client_tools.go @@ -1,7 +1,7 @@ package tarantool import ( - "gopkg.in/vmihailenco/msgpack.v2" + "github.com/vmihailenco/msgpack/v5" ) // IntKey is utility type for passing integer key to Select*, Update* and Delete* @@ -11,8 +11,8 @@ type IntKey struct { } func (k IntKey) EncodeMsgpack(enc *msgpack.Encoder) error { - enc.EncodeSliceLen(1) - enc.EncodeInt(k.I) + enc.EncodeArrayLen(1) + enc.EncodeInt(int64(k.I)) return nil } @@ -23,8 +23,8 @@ type UintKey struct { } func (k UintKey) EncodeMsgpack(enc *msgpack.Encoder) error { - enc.EncodeSliceLen(1) - enc.EncodeUint(k.I) + enc.EncodeArrayLen(1) + enc.EncodeUint(uint64(k.I)) return nil } @@ -35,7 +35,7 @@ type StringKey struct { } func (k StringKey) EncodeMsgpack(enc *msgpack.Encoder) error { - enc.EncodeSliceLen(1) + enc.EncodeArrayLen(1) enc.EncodeString(k.S) return nil } @@ -47,9 +47,9 @@ type IntIntKey struct { } func (k IntIntKey) EncodeMsgpack(enc *msgpack.Encoder) error { - enc.EncodeSliceLen(2) - enc.EncodeInt(k.I1) - enc.EncodeInt(k.I2) + enc.EncodeArrayLen(2) + enc.EncodeInt(int64(k.I1)) + enc.EncodeInt(int64(k.I2)) return nil } @@ -61,9 +61,9 @@ type Op struct { } func (o Op) EncodeMsgpack(enc *msgpack.Encoder) error { - enc.EncodeSliceLen(3) + enc.EncodeArrayLen(3) enc.EncodeString(o.Op) - enc.EncodeInt(o.Field) + enc.EncodeInt(int64(o.Field)) return enc.Encode(o.Arg) } @@ -76,11 +76,11 @@ type OpSplice struct { } func (o OpSplice) EncodeMsgpack(enc *msgpack.Encoder) error { - enc.EncodeSliceLen(5) + enc.EncodeArrayLen(5) enc.EncodeString(o.Op) - enc.EncodeInt(o.Field) - enc.EncodeInt(o.Pos) - enc.EncodeInt(o.Len) + enc.EncodeInt(int64(o.Field)) + enc.EncodeInt(int64(o.Pos)) + enc.EncodeInt(int64(o.Len)) enc.EncodeString(o.Replace) return nil } diff --git a/connection.go b/connection.go index 87d7876c5..a9702f415 100644 --- a/connection.go +++ b/connection.go @@ -13,7 +13,7 @@ import ( "sync/atomic" "time" - "gopkg.in/vmihailenco/msgpack.v2" + "github.com/vmihailenco/msgpack/v5" ) const requestsMap = 128 @@ -228,13 +228,15 @@ type Opts struct { // - If opts.Reconnect is non-zero, then error will be returned only if authorization// fails. But if Tarantool is not reachable, then it will attempt to reconnect later // and will not end attempts on authorization failures. func Connect(addr string, opts Opts) (conn *Connection, err error) { + d := msgpack.NewDecoder(&smallBuf{}) + d.UseLooseInterfaceDecoding(true) conn = &Connection{ addr: addr, requestId: 0, Greeting: &Greeting{}, control: make(chan struct{}), opts: opts, - dec: msgpack.NewDecoder(&smallBuf{}), + dec: d, } maxprocs := uint32(runtime.GOMAXPROCS(-1)) if conn.opts.Concurrency == 0 || conn.opts.Concurrency > maxprocs*128 { @@ -433,7 +435,9 @@ func (conn *Connection) writeAuthRequest(w *bufio.Writer, scramble []byte) (err requestCode: AuthRequest, } var packet smallWBuf - err = request.pack(&packet, msgpack.NewEncoder(&packet), func(enc *msgpack.Encoder) error { + enc := msgpack.NewEncoder(&packet) + enc.UseCompactInts(true) + err = request.pack(&packet, enc, func(enc *msgpack.Encoder) error { return enc.Encode(map[uint32]interface{}{ KeyUserName: conn.opts.User, KeyTuple: []interface{}{string("chap-sha1"), string(scramble)}, @@ -721,6 +725,7 @@ func (conn *Connection) putFuture(fut *Future, body func(*msgpack.Encoder) error if shard.buf.Cap() == 0 { shard.buf.b = make([]byte, 0, 128) shard.enc = msgpack.NewEncoder(&shard.buf) + shard.enc.UseCompactInts(true) } blen := shard.buf.Len() if err := fut.pack(&shard.buf, shard.enc, body); err != nil { diff --git a/go.mod b/go.mod index 80dcee6f9..ad21a0953 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,4 @@ module github.com/tarantool/go-tarantool go 1.11 -require ( - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - google.golang.org/appengine v1.6.6 // indirect - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect - gopkg.in/vmihailenco/msgpack.v2 v2.9.1 -) +require github.com/vmihailenco/msgpack/v5 v5.1.2 diff --git a/go.sum b/go.sum index 838f2f45a..f41de0f31 100644 --- a/go.sum +++ b/go.sum @@ -1,20 +1,15 @@ -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/vmihailenco/msgpack.v2 v2.9.1 h1:kb0VV7NuIojvRfzwslQeP3yArBqJHW9tOl4t38VS1jM= -gopkg.in/vmihailenco/msgpack.v2 v2.9.1/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/vmihailenco/msgpack/v5 v5.1.2 h1:W0PAZV3UT35gi5ZTdhRilgL7IaviXnwJAu++eeMXXF8= +github.com/vmihailenco/msgpack/v5 v5.1.2/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI= +github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc= +github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/queue/queue.go b/queue/queue.go index 69dcf8bcd..9aa246914 100644 --- a/queue/queue.go +++ b/queue/queue.go @@ -5,7 +5,7 @@ import ( "time" "github.com/tarantool/go-tarantool" - msgpack "gopkg.in/vmihailenco/msgpack.v2" + "github.com/vmihailenco/msgpack/v5" ) // Queue is a handle to tarantool queue's tube @@ -326,7 +326,7 @@ type queueData struct { func (qd *queueData) DecodeMsgpack(d *msgpack.Decoder) error { var err error var l int - if l, err = d.DecodeSliceLen(); err != nil { + if l, err = d.DecodeArrayLen(); err != nil { return err } if l > 1 { diff --git a/queue/queue_test.go b/queue/queue_test.go index d1a909120..fbc19ae43 100644 --- a/queue/queue_test.go +++ b/queue/queue_test.go @@ -8,7 +8,7 @@ import ( . "github.com/tarantool/go-tarantool" "github.com/tarantool/go-tarantool/queue" - "gopkg.in/vmihailenco/msgpack.v2" + "github.com/vmihailenco/msgpack/v5" ) var server = "127.0.0.1:3013" diff --git a/queue/task.go b/queue/task.go index 6d8560bd7..32b92e253 100644 --- a/queue/task.go +++ b/queue/task.go @@ -3,7 +3,7 @@ package queue import ( "fmt" - msgpack "gopkg.in/vmihailenco/msgpack.v2" + "github.com/vmihailenco/msgpack/v5" ) // Task represents a task from tarantool queue's tube @@ -17,7 +17,7 @@ type Task struct { func (t *Task) DecodeMsgpack(d *msgpack.Decoder) error { var err error var l int - if l, err = d.DecodeSliceLen(); err != nil { + if l, err = d.DecodeArrayLen(); err != nil { return err } if l < 3 { diff --git a/request.go b/request.go index ae42eb440..b62dae3a0 100644 --- a/request.go +++ b/request.go @@ -4,7 +4,7 @@ import ( "errors" "time" - "gopkg.in/vmihailenco/msgpack.v2" + "github.com/vmihailenco/msgpack/v5" ) // Future is a handle for asynchronous request @@ -24,28 +24,28 @@ func (conn *Connection) Ping() (resp *Response, err error) { return future.send(conn, func(enc *msgpack.Encoder) error { enc.EncodeMapLen(0); return nil }).Get() } -func (req *Future) fillSearch(enc *msgpack.Encoder, spaceNo, indexNo uint32, key interface{}) error { - enc.EncodeUint64(KeySpaceNo) - enc.EncodeUint64(uint64(spaceNo)) - enc.EncodeUint64(KeyIndexNo) - enc.EncodeUint64(uint64(indexNo)) - enc.EncodeUint64(KeyKey) +func (fut *Future) fillSearch(enc *msgpack.Encoder, spaceNo, indexNo uint32, key interface{}) error { + enc.EncodeUint(KeySpaceNo) + enc.EncodeUint32(spaceNo) + enc.EncodeUint(KeyIndexNo) + enc.EncodeUint32(indexNo) + enc.EncodeUint(KeyKey) return enc.Encode(key) } -func (req *Future) fillIterator(enc *msgpack.Encoder, offset, limit, iterator uint32) { - enc.EncodeUint64(KeyIterator) - enc.EncodeUint64(uint64(iterator)) - enc.EncodeUint64(KeyOffset) - enc.EncodeUint64(uint64(offset)) - enc.EncodeUint64(KeyLimit) - enc.EncodeUint64(uint64(limit)) +func (fut *Future) fillIterator(enc *msgpack.Encoder, offset, limit, iterator uint32) { + enc.EncodeUint(KeyIterator) + enc.EncodeUint32(iterator) + enc.EncodeUint(KeyOffset) + enc.EncodeUint32(offset) + enc.EncodeUint(KeyLimit) + enc.EncodeUint32(limit) } -func (req *Future) fillInsert(enc *msgpack.Encoder, spaceNo uint32, tuple interface{}) error { - enc.EncodeUint64(KeySpaceNo) - enc.EncodeUint64(uint64(spaceNo)) - enc.EncodeUint64(KeyTuple) +func (fut *Future) fillInsert(enc *msgpack.Encoder, spaceNo uint32, tuple interface{}) error { + enc.EncodeUint(KeySpaceNo) + enc.EncodeUint32(spaceNo) + enc.EncodeUint(KeyTuple) return enc.Encode(tuple) } @@ -129,7 +129,7 @@ type single struct { func (s *single) DecodeMsgpack(d *msgpack.Decoder) error { var err error var len int - if len, err = d.DecodeSliceLen(); err != nil { + if len, err = d.DecodeArrayLen(); err != nil { return err } if s.found = len >= 1; !s.found { @@ -281,7 +281,7 @@ func (conn *Connection) UpdateAsync(space, index interface{}, key, ops interface if err := future.fillSearch(enc, spaceNo, indexNo, key); err != nil { return err } - enc.EncodeUint64(KeyTuple) + enc.EncodeUint(KeyTuple) return enc.Encode(ops) }) } @@ -296,13 +296,13 @@ func (conn *Connection) UpsertAsync(space interface{}, tuple interface{}, ops in } return future.send(conn, func(enc *msgpack.Encoder) error { enc.EncodeMapLen(3) - enc.EncodeUint64(KeySpaceNo) + enc.EncodeUint(KeySpaceNo) enc.EncodeUint64(uint64(spaceNo)) - enc.EncodeUint64(KeyTuple) + enc.EncodeUint(KeyTuple) if err := enc.Encode(tuple); err != nil { return err } - enc.EncodeUint64(KeyDefTuple) + enc.EncodeUint(KeyDefTuple) return enc.Encode(ops) }) } diff --git a/response.go b/response.go index 6363a4fe4..07b371585 100644 --- a/response.go +++ b/response.go @@ -3,7 +3,7 @@ package tarantool import ( "fmt" - "gopkg.in/vmihailenco/msgpack.v2" + "github.com/vmihailenco/msgpack/v5" ) type Response struct { @@ -64,10 +64,16 @@ func (resp *Response) decodeHeader(d *msgpack.Decoder) (err error) { return nil } +func decodeMap(dec *msgpack.Decoder) (interface{}, error) { + return dec.DecodeUntypedMap() +} + func (resp *Response) decodeBody() (err error) { if resp.buf.Len() > 2 { var l int d := msgpack.NewDecoder(&resp.buf) + d.SetMapDecoder(decodeMap) + d.UseLooseInterfaceDecoding(true) if l, err = d.DecodeMapLen(); err != nil { return err } @@ -108,6 +114,8 @@ func (resp *Response) decodeBodyTyped(res interface{}) (err error) { if resp.buf.Len() > 0 { var l int d := msgpack.NewDecoder(&resp.buf) + d.SetMapDecoder(decodeMap) + d.UseLooseInterfaceDecoding(true) if l, err = d.DecodeMapLen(); err != nil { return err } diff --git a/schema.go b/schema.go index 9b2dfae75..c8be14a23 100644 --- a/schema.go +++ b/schema.go @@ -1,7 +1,10 @@ package tarantool import ( + "errors" "fmt" + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" ) // Schema contains information about spaces and indexes. @@ -18,7 +21,7 @@ type Space struct { Id uint32 Name string Engine string - Temporary bool // Is this space temporaray? + Temporary bool // Is this space temporary? // Field configuration is not mandatory and not checked by tarantool. FieldsCount uint32 Fields map[string]*Field @@ -29,19 +32,203 @@ type Space struct { IndexesById map[uint32]*Index } +func (space *Space) DecodeMsgpack(d *msgpack.Decoder) error { + arrayLen, err := d.DecodeArrayLen() + if err != nil { + return err + } + if space.Id, err = d.DecodeUint32(); err != nil { + return err + } + if err := d.Skip(); err != nil { + return err + } + if space.Name, err = d.DecodeString(); err != nil { + return err + } + if space.Engine, err = d.DecodeString(); err != nil { + return err + } + if space.FieldsCount, err = d.DecodeUint32(); err != nil { + return err + } + if arrayLen >= 6 { + code, err := d.PeekCode() + if err != nil { + return err + } + if msgpcode.IsString(code) { + val, err := d.DecodeString() + if err != nil { + return err + } + space.Temporary = val == "temporary" + } else if code == msgpcode.Map16 || code == msgpcode.Map32 || msgpcode.IsFixedMap(code) { + mapLen, err := d.DecodeMapLen() + if err != nil { + return err + } + for i := 0; i < mapLen; i++ { + key, err := d.DecodeString() + if err != nil { + return err + } + if key == "temporary" { + if space.Temporary, err = d.DecodeBool(); err != nil { + return err + } + } else { + if err = d.Skip(); err != nil { + return err + } + } + } + } else { + return errors.New("unexpected schema format (space flags)") + } + } + space.FieldsById = make(map[uint32]*Field) + space.Fields = make(map[string]*Field) + space.IndexesById = make(map[uint32]*Index) + space.Indexes = make(map[string]*Index) + if arrayLen >= 7 { + fieldCount, err := d.DecodeArrayLen() + if err != nil { + return err + } + for i := 0; i < fieldCount; i++ { + field := &Field{} + if err := field.DecodeMsgpack(d); err != nil { + return err + } + field.Id = uint32(i) + space.FieldsById[field.Id] = field + if field.Name != "" { + space.Fields[field.Name] = field + } + } + } + return nil +} + type Field struct { Id uint32 Name string Type string } +func (field *Field) DecodeMsgpack(d *msgpack.Decoder) error { + l, err := d.DecodeMapLen() + if err != nil { + return err + } + for i := 0; i < l; i++ { + key, err := d.DecodeString() + if err != nil { + return err + } + switch key { + case "name": + if field.Name, err = d.DecodeString(); err != nil { + return err + } + case "type": + if field.Type, err = d.DecodeString(); err != nil { + return err + } + default: + if err := d.Skip(); err != nil { + return err + } + } + } + return nil +} + // Index contains information about index type Index struct { - Id uint32 - Name string - Type string - Unique bool - Fields []*IndexField + Id uint32 + SpaceId uint32 + Name string + Type string + Unique bool + Fields []*IndexField +} + +func (index *Index) DecodeMsgpack(d *msgpack.Decoder) error { + _, err := d.DecodeArrayLen() + if err != nil { + return err + } + + if index.SpaceId, err = d.DecodeUint32(); err != nil { + return err + } + if index.Id, err = d.DecodeUint32(); err != nil { + return err + } + if index.Name, err = d.DecodeString(); err != nil { + return err + } + if index.Type, err = d.DecodeString(); err != nil { + return err + } + + code, err := d.PeekCode() + if err != nil { + return err + } + if code == msgpcode.Uint8 || code == msgpcode.Uint16 || + code == msgpcode.Uint32 || code == msgpcode.Uint64 || + msgpcode.IsFixedNum(code) { + + optsUint64, err := d.DecodeUint64() + if err != nil { + return nil + } + index.Unique = optsUint64 > 0 + } else { + var optsMap map[interface{}]interface{} + if err := d.Decode(&optsMap); err != nil { + return fmt.Errorf("unexpected schema format (index flags): %w", err) + } + + var ok bool + if index.Unique, ok = optsMap["unique"].(bool); !ok { + /* see bug https://github.com/tarantool/tarantool/issues/2060 */ + index.Unique = true + } + } + + code, err = d.PeekCode() + if err != nil { + return err + } + if code == msgpcode.Uint8 || code == msgpcode.Uint16 || + code == msgpcode.Uint32 || code == msgpcode.Uint64 || + msgpcode.IsFixedNum(code) { + + fieldCount, err := d.DecodeUint64() + if err != nil { + return err + } + index.Fields = make([]*IndexField, fieldCount) + for i := 0; i < int(fieldCount); i++ { + index.Fields[i] = new(IndexField) + if index.Fields[i].Id, err = d.DecodeUint32(); err != nil { + return err + } + if index.Fields[i].Type, err = d.DecodeString(); err != nil { + return err + } + } + } else { + if err := d.Decode(&index.Fields); err != nil { + return fmt.Errorf("unexpected schema format (index flags): %w", err) + } + } + + return nil } type IndexField struct { @@ -49,6 +236,62 @@ type IndexField struct { Type string } +func (indexField *IndexField) DecodeMsgpack(d *msgpack.Decoder) error { + code, err := d.PeekCode() + if err != nil { + return err + } + + if code == msgpcode.Map16 || code == msgpcode.Map32 || msgpcode.IsFixedMap(code) { + mapLen, err := d.DecodeMapLen() + if err != nil { + return err + } + for i := 0; i < mapLen; i++ { + key, err := d.DecodeString() + if err != nil { + return err + } + switch key { + case "field": + if indexField.Id, err = d.DecodeUint32(); err != nil { + return err + } + case "type": + if indexField.Type, err = d.DecodeString(); err != nil { + return err + } + default: + if err := d.Skip(); err != nil { + return err + } + } + } + return nil + } + + if code == msgpcode.Array16 || code == msgpcode.Array32 || msgpcode.IsFixedArray(code) { + arrayLen, err := d.DecodeArrayLen() + if err != nil { + return err + } + if indexField.Id, err = d.DecodeUint32(); err != nil { + return err + } + if indexField.Type, err = d.DecodeString(); err != nil { + return err + } + for i := 2; i < arrayLen; i++ { + if err := d.Skip(); err != nil { + return err + } + } + return nil + } + + return errors.New("unexpected schema format (index fields)") +} + const ( maxSchemas = 10000 spaceSpId = 280 @@ -58,117 +301,29 @@ const ( ) func (conn *Connection) loadSchema() (err error) { - var resp *Response - - schema := new(Schema) - schema.SpacesById = make(map[uint32]*Space) - schema.Spaces = make(map[string]*Space) + schema := &Schema{ + SpacesById: make(map[uint32]*Space), + Spaces: make(map[string]*Space), + } // reload spaces - resp, err = conn.Select(vspaceSpId, 0, 0, maxSchemas, IterAll, []interface{}{}) - if err != nil { + var spaces []*Space + if err = conn.SelectTyped(vspaceSpId, 0, 0, maxSchemas, IterAll, []interface{}{}, &spaces); err != nil { return err } - for _, row := range resp.Data { - row := row.([]interface{}) - space := new(Space) - space.Id = uint32(row[0].(uint64)) - space.Name = row[2].(string) - space.Engine = row[3].(string) - space.FieldsCount = uint32(row[4].(uint64)) - if len(row) >= 6 { - switch row5 := row[5].(type) { - case string: - space.Temporary = row5 == "temporary" - case map[interface{}]interface{}: - if temp, ok := row5["temporary"]; ok { - space.Temporary = temp.(bool) - } - default: - panic("unexpected schema format (space flags)") - } - } - space.FieldsById = make(map[uint32]*Field) - space.Fields = make(map[string]*Field) - space.IndexesById = make(map[uint32]*Index) - space.Indexes = make(map[string]*Index) - if len(row) >= 7 { - for i, f := range row[6].([]interface{}) { - if f == nil { - continue - } - f := f.(map[interface{}]interface{}) - field := new(Field) - field.Id = uint32(i) - if name, ok := f["name"]; ok && name != nil { - field.Name = name.(string) - } - if type1, ok := f["type"]; ok && type1 != nil { - field.Type = type1.(string) - } - space.FieldsById[field.Id] = field - if field.Name != "" { - space.Fields[field.Name] = field - } - } - } - + for _, space := range spaces { schema.SpacesById[space.Id] = space schema.Spaces[space.Name] = space } // reload indexes - resp, err = conn.Select(vindexSpId, 0, 0, maxSchemas, IterAll, []interface{}{}) - if err != nil { + var indexes []*Index + if err = conn.SelectTyped(vindexSpId, 0, 0, maxSchemas, IterAll, []interface{}{}, &indexes); err != nil { return err } - for _, row := range resp.Data { - row := row.([]interface{}) - index := new(Index) - index.Id = uint32(row[1].(uint64)) - index.Name = row[2].(string) - index.Type = row[3].(string) - switch row[4].(type) { - case uint64: - index.Unique = row[4].(uint64) > 0 - case map[interface{}]interface{}: - opts := row[4].(map[interface{}]interface{}) - var ok bool - if index.Unique, ok = opts["unique"].(bool); !ok { - /* see bug https://github.com/tarantool/tarantool/issues/2060 */ - index.Unique = true - } - default: - panic("unexpected schema format (index flags)") - } - switch fields := row[5].(type) { - case uint64: - cnt := int(fields) - for i := 0; i < cnt; i++ { - field := new(IndexField) - field.Id = uint32(row[6+i*2].(uint64)) - field.Type = row[7+i*2].(string) - index.Fields = append(index.Fields, field) - } - case []interface{}: - for _, f := range fields { - field := new(IndexField) - switch f := f.(type) { - case []interface{}: - field.Id = uint32(f[0].(uint64)) - field.Type = f[1].(string) - case map[interface{}]interface{}: - field.Id = uint32(f["field"].(uint64)) - field.Type = f["type"].(string) - } - index.Fields = append(index.Fields, field) - } - default: - panic("unexpected schema format (index fields)") - } - spaceId := uint32(row[0].(uint64)) - schema.SpacesById[spaceId].IndexesById[index.Id] = index - schema.SpacesById[spaceId].Indexes[index.Name] = index + for _, index := range indexes { + schema.SpacesById[index.SpaceId].IndexesById[index.Id] = index + schema.SpacesById[index.SpaceId].Indexes[index.Name] = index } conn.Schema = schema return nil diff --git a/tarantool_test.go b/tarantool_test.go index 7c0552138..4e448711a 100644 --- a/tarantool_test.go +++ b/tarantool_test.go @@ -8,7 +8,7 @@ import ( "time" . "github.com/tarantool/go-tarantool" - "gopkg.in/vmihailenco/msgpack.v2" + "github.com/vmihailenco/msgpack/v5" ) type Member struct { @@ -24,16 +24,16 @@ type Tuple2 struct { } func (m *Member) EncodeMsgpack(e *msgpack.Encoder) error { - e.EncodeSliceLen(2) + e.EncodeArrayLen(2) e.EncodeString(m.Name) - e.EncodeUint(m.Val) + e.EncodeUint(uint64(m.Val)) return nil } func (m *Member) DecodeMsgpack(d *msgpack.Decoder) error { var err error var l int - if l, err = d.DecodeSliceLen(); err != nil { + if l, err = d.DecodeArrayLen(); err != nil { return err } if l != 2 { @@ -49,8 +49,8 @@ func (m *Member) DecodeMsgpack(d *msgpack.Decoder) error { } func (c *Tuple2) EncodeMsgpack(e *msgpack.Encoder) error { - e.EncodeSliceLen(3) - e.EncodeUint(c.Cid) + e.EncodeArrayLen(3) + e.EncodeUint(uint64(c.Cid)) e.EncodeString(c.Orig) e.Encode(c.Members) return nil @@ -59,7 +59,7 @@ func (c *Tuple2) EncodeMsgpack(e *msgpack.Encoder) error { func (c *Tuple2) DecodeMsgpack(d *msgpack.Decoder) error { var err error var l int - if l, err = d.DecodeSliceLen(); err != nil { + if l, err = d.DecodeArrayLen(); err != nil { return err } if l != 3 { @@ -71,7 +71,7 @@ func (c *Tuple2) DecodeMsgpack(d *msgpack.Decoder) error { if c.Orig, err = d.DecodeString(); err != nil { return err } - if l, err = d.DecodeSliceLen(); err != nil { + if l, err = d.DecodeArrayLen(); err != nil { return err } c.Members = make([]Member, l) @@ -426,8 +426,8 @@ func TestClient(t *testing.T) { if len(tpl) != 3 { t.Errorf("Unexpected body of Insert (tuple len)") } - if id, ok := tpl[0].(uint64); !ok || id != 1 { - t.Errorf("Unexpected body of Insert (0)") + if id, ok := tpl[0].(int64); !ok || id != 1 { + t.Errorf("Unexpected body of Insert (0): %T\n", tpl[0]) } if h, ok := tpl[1].(string); !ok || h != "hello" { t.Errorf("Unexpected body of Insert (1)") @@ -459,7 +459,7 @@ func TestClient(t *testing.T) { if len(tpl) != 3 { t.Errorf("Unexpected body of Delete (tuple len)") } - if id, ok := tpl[0].(uint64); !ok || id != 1 { + if id, ok := tpl[0].(int64); !ok || id != 1 { t.Errorf("Unexpected body of Delete (0)") } if h, ok := tpl[1].(string); !ok || h != "hello" { @@ -501,7 +501,7 @@ func TestClient(t *testing.T) { if len(tpl) != 3 { t.Errorf("Unexpected body of Replace (tuple len)") } - if id, ok := tpl[0].(uint64); !ok || id != 2 { + if id, ok := tpl[0].(int64); !ok || id != 2 { t.Errorf("Unexpected body of Replace (0)") } if h, ok := tpl[1].(string); !ok || h != "hi" { @@ -526,7 +526,7 @@ func TestClient(t *testing.T) { if len(tpl) != 2 { t.Errorf("Unexpected body of Update (tuple len)") } - if id, ok := tpl[0].(uint64); !ok || id != 2 { + if id, ok := tpl[0].(int64); !ok || id != 2 { t.Errorf("Unexpected body of Update (0)") } if h, ok := tpl[1].(string); !ok || h != "bye" { @@ -572,7 +572,7 @@ func TestClient(t *testing.T) { if tpl, ok := resp.Data[0].([]interface{}); !ok { t.Errorf("Unexpected body of Select") } else { - if id, ok := tpl[0].(uint64); !ok || id != 10 { + if id, ok := tpl[0].(int64); !ok || id != 10 { t.Errorf("Unexpected body of Select (0)") } if h, ok := tpl[1].(string); !ok || h != "val 10" { @@ -664,12 +664,12 @@ func TestClient(t *testing.T) { // Call vs Call17 resp, err = conn.Call("simple_incr", []interface{}{1}) - if resp.Data[0].([]interface{})[0].(uint64) != 2 { + if resp.Data[0].([]interface{})[0].(int64) != 2 { t.Errorf("result is not {{1}} : %v", resp.Data) } resp, err = conn.Call17("simple_incr", []interface{}{1}) - if resp.Data[0].(uint64) != 2 { + if resp.Data[0].(int64) != 2 { t.Errorf("result is not {{1}} : %v", resp.Data) } @@ -684,7 +684,7 @@ func TestClient(t *testing.T) { if len(resp.Data) < 1 { t.Errorf("Response.Data is empty after Eval") } - val := resp.Data[0].(uint64) + val := resp.Data[0].(int64) if val != 11 { t.Errorf("5 + 6 == 11, but got %v", val) }