123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- package client
- import (
- "encoding/binary"
- "github.com/juju/errors"
- . "github.com/siddontang/go-mysql/mysql"
- "github.com/siddontang/go/hack"
- )
- func (c *Conn) readUntilEOF() (err error) {
- var data []byte
- for {
- data, err = c.ReadPacket()
- if err != nil {
- return
- }
- // EOF Packet
- if c.isEOFPacket(data) {
- return
- }
- }
- return
- }
- func (c *Conn) isEOFPacket(data []byte) bool {
- return data[0] == EOF_HEADER && len(data) <= 5
- }
- func (c *Conn) handleOKPacket(data []byte) (*Result, error) {
- var n int
- var pos int = 1
- r := new(Result)
- r.AffectedRows, _, n = LengthEncodedInt(data[pos:])
- pos += n
- r.InsertId, _, n = LengthEncodedInt(data[pos:])
- pos += n
- if c.capability&CLIENT_PROTOCOL_41 > 0 {
- r.Status = binary.LittleEndian.Uint16(data[pos:])
- c.status = r.Status
- pos += 2
- //todo:strict_mode, check warnings as error
- //Warnings := binary.LittleEndian.Uint16(data[pos:])
- //pos += 2
- } else if c.capability&CLIENT_TRANSACTIONS > 0 {
- r.Status = binary.LittleEndian.Uint16(data[pos:])
- c.status = r.Status
- pos += 2
- }
- //new ok package will check CLIENT_SESSION_TRACK too, but I don't support it now.
- //skip info
- return r, nil
- }
- func (c *Conn) handleErrorPacket(data []byte) error {
- e := new(MyError)
- var pos int = 1
- e.Code = binary.LittleEndian.Uint16(data[pos:])
- pos += 2
- if c.capability&CLIENT_PROTOCOL_41 > 0 {
- //skip '#'
- pos++
- e.State = hack.String(data[pos : pos+5])
- pos += 5
- }
- e.Message = hack.String(data[pos:])
- return e
- }
- func (c *Conn) readOK() (*Result, error) {
- data, err := c.ReadPacket()
- if err != nil {
- return nil, errors.Trace(err)
- }
- if data[0] == OK_HEADER {
- return c.handleOKPacket(data)
- } else if data[0] == ERR_HEADER {
- return nil, c.handleErrorPacket(data)
- } else {
- return nil, errors.New("invalid ok packet")
- }
- }
- func (c *Conn) readResult(binary bool) (*Result, error) {
- data, err := c.ReadPacket()
- if err != nil {
- return nil, errors.Trace(err)
- }
- if data[0] == OK_HEADER {
- return c.handleOKPacket(data)
- } else if data[0] == ERR_HEADER {
- return nil, c.handleErrorPacket(data)
- } else if data[0] == LocalInFile_HEADER {
- return nil, ErrMalformPacket
- }
- return c.readResultset(data, binary)
- }
- func (c *Conn) readResultset(data []byte, binary bool) (*Result, error) {
- result := &Result{
- Status: 0,
- InsertId: 0,
- AffectedRows: 0,
- Resultset: &Resultset{},
- }
- // column count
- count, _, n := LengthEncodedInt(data)
- if n-len(data) != 0 {
- return nil, ErrMalformPacket
- }
- result.Fields = make([]*Field, count)
- result.FieldNames = make(map[string]int, count)
- if err := c.readResultColumns(result); err != nil {
- return nil, errors.Trace(err)
- }
- if err := c.readResultRows(result, binary); err != nil {
- return nil, errors.Trace(err)
- }
- return result, nil
- }
- func (c *Conn) readResultColumns(result *Result) (err error) {
- var i int = 0
- var data []byte
- for {
- data, err = c.ReadPacket()
- if err != nil {
- return
- }
- // EOF Packet
- if c.isEOFPacket(data) {
- if c.capability&CLIENT_PROTOCOL_41 > 0 {
- //result.Warnings = binary.LittleEndian.Uint16(data[1:])
- //todo add strict_mode, warning will be treat as error
- result.Status = binary.LittleEndian.Uint16(data[3:])
- c.status = result.Status
- }
- if i != len(result.Fields) {
- err = ErrMalformPacket
- }
- return
- }
- result.Fields[i], err = FieldData(data).Parse()
- if err != nil {
- return
- }
- result.FieldNames[hack.String(result.Fields[i].Name)] = i
- i++
- }
- }
- func (c *Conn) readResultRows(result *Result, isBinary bool) (err error) {
- var data []byte
- for {
- data, err = c.ReadPacket()
- if err != nil {
- return
- }
- // EOF Packet
- if c.isEOFPacket(data) {
- if c.capability&CLIENT_PROTOCOL_41 > 0 {
- //result.Warnings = binary.LittleEndian.Uint16(data[1:])
- //todo add strict_mode, warning will be treat as error
- result.Status = binary.LittleEndian.Uint16(data[3:])
- c.status = result.Status
- }
- break
- }
- result.RowDatas = append(result.RowDatas, data)
- }
- result.Values = make([][]interface{}, len(result.RowDatas))
- for i := range result.Values {
- result.Values[i], err = result.RowDatas[i].Parse(result.Fields, isBinary)
- if err != nil {
- return errors.Trace(err)
- }
- }
- return nil
- }
|