123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- package mysql
- import (
- "fmt"
- "strconv"
- "github.com/juju/errors"
- "github.com/siddontang/go/hack"
- )
- type RowData []byte
- func (p RowData) Parse(f []*Field, binary bool) ([]interface{}, error) {
- if binary {
- return p.ParseBinary(f)
- } else {
- return p.ParseText(f)
- }
- }
- func (p RowData) ParseText(f []*Field) ([]interface{}, error) {
- data := make([]interface{}, len(f))
- var err error
- var v []byte
- var isNull bool
- var pos int = 0
- var n int = 0
- for i := range f {
- v, isNull, n, err = LengthEnodedString(p[pos:])
- if err != nil {
- return nil, errors.Trace(err)
- }
- pos += n
- if isNull {
- data[i] = nil
- } else {
- isUnsigned := f[i].Flag&UNSIGNED_FLAG != 0
- switch f[i].Type {
- case MYSQL_TYPE_TINY, MYSQL_TYPE_SHORT, MYSQL_TYPE_INT24,
- MYSQL_TYPE_LONGLONG, MYSQL_TYPE_YEAR:
- if isUnsigned {
- data[i], err = strconv.ParseUint(string(v), 10, 64)
- } else {
- data[i], err = strconv.ParseInt(string(v), 10, 64)
- }
- case MYSQL_TYPE_FLOAT, MYSQL_TYPE_DOUBLE:
- data[i], err = strconv.ParseFloat(string(v), 64)
- default:
- data[i] = v
- }
- if err != nil {
- return nil, errors.Trace(err)
- }
- }
- }
- return data, nil
- }
- func (p RowData) ParseBinary(f []*Field) ([]interface{}, error) {
- data := make([]interface{}, len(f))
- if p[0] != OK_HEADER {
- return nil, ErrMalformPacket
- }
- pos := 1 + ((len(f) + 7 + 2) >> 3)
- nullBitmap := p[1:pos]
- var isNull bool
- var n int
- var err error
- var v []byte
- for i := range data {
- if nullBitmap[(i+2)/8]&(1<<(uint(i+2)%8)) > 0 {
- data[i] = nil
- continue
- }
- isUnsigned := f[i].Flag&UNSIGNED_FLAG != 0
- switch f[i].Type {
- case MYSQL_TYPE_NULL:
- data[i] = nil
- continue
- case MYSQL_TYPE_TINY:
- if isUnsigned {
- data[i] = ParseBinaryUint8(p[pos : pos+1])
- } else {
- data[i] = ParseBinaryInt8(p[pos : pos+1])
- }
- pos++
- continue
- case MYSQL_TYPE_SHORT, MYSQL_TYPE_YEAR:
- if isUnsigned {
- data[i] = ParseBinaryUint16(p[pos : pos+2])
- } else {
- data[i] = ParseBinaryInt16(p[pos : pos+2])
- }
- pos += 2
- continue
- case MYSQL_TYPE_INT24:
- if isUnsigned {
- data[i] = ParseBinaryUint24(p[pos : pos+3])
- } else {
- data[i] = ParseBinaryInt24(p[pos : pos+3])
- }
- pos += 4
- continue
- case MYSQL_TYPE_LONG:
- if isUnsigned {
- data[i] = ParseBinaryUint32(p[pos : pos+4])
- } else {
- data[i] = ParseBinaryInt32(p[pos : pos+4])
- }
- pos += 4
- continue
- case MYSQL_TYPE_LONGLONG:
- if isUnsigned {
- data[i] = ParseBinaryUint64(p[pos : pos+8])
- } else {
- data[i] = ParseBinaryInt64(p[pos : pos+8])
- }
- pos += 8
- continue
- case MYSQL_TYPE_FLOAT:
- data[i] = ParseBinaryFloat32(p[pos : pos+4])
- pos += 4
- continue
- case MYSQL_TYPE_DOUBLE:
- data[i] = ParseBinaryFloat64(p[pos : pos+8])
- pos += 8
- continue
- case MYSQL_TYPE_DECIMAL, MYSQL_TYPE_NEWDECIMAL, MYSQL_TYPE_VARCHAR,
- MYSQL_TYPE_BIT, MYSQL_TYPE_ENUM, MYSQL_TYPE_SET, MYSQL_TYPE_TINY_BLOB,
- MYSQL_TYPE_MEDIUM_BLOB, MYSQL_TYPE_LONG_BLOB, MYSQL_TYPE_BLOB,
- MYSQL_TYPE_VAR_STRING, MYSQL_TYPE_STRING, MYSQL_TYPE_GEOMETRY:
- v, isNull, n, err = LengthEnodedString(p[pos:])
- pos += n
- if err != nil {
- return nil, errors.Trace(err)
- }
- if !isNull {
- data[i] = v
- continue
- } else {
- data[i] = nil
- continue
- }
- case MYSQL_TYPE_DATE, MYSQL_TYPE_NEWDATE:
- var num uint64
- num, isNull, n = LengthEncodedInt(p[pos:])
- pos += n
- if isNull {
- data[i] = nil
- continue
- }
- data[i], err = FormatBinaryDate(int(num), p[pos:])
- pos += int(num)
- if err != nil {
- return nil, errors.Trace(err)
- }
- case MYSQL_TYPE_TIMESTAMP, MYSQL_TYPE_DATETIME:
- var num uint64
- num, isNull, n = LengthEncodedInt(p[pos:])
- pos += n
- if isNull {
- data[i] = nil
- continue
- }
- data[i], err = FormatBinaryDateTime(int(num), p[pos:])
- pos += int(num)
- if err != nil {
- return nil, errors.Trace(err)
- }
- case MYSQL_TYPE_TIME:
- var num uint64
- num, isNull, n = LengthEncodedInt(p[pos:])
- pos += n
- if isNull {
- data[i] = nil
- continue
- }
- data[i], err = FormatBinaryTime(int(num), p[pos:])
- pos += int(num)
- if err != nil {
- return nil, errors.Trace(err)
- }
- default:
- return nil, errors.Errorf("Stmt Unknown FieldType %d %s", f[i].Type, f[i].Name)
- }
- }
- return data, nil
- }
- type Resultset struct {
- Fields []*Field
- FieldNames map[string]int
- Values [][]interface{}
- RowDatas []RowData
- }
- func (r *Resultset) RowNumber() int {
- return len(r.Values)
- }
- func (r *Resultset) ColumnNumber() int {
- return len(r.Fields)
- }
- func (r *Resultset) GetValue(row, column int) (interface{}, error) {
- if row >= len(r.Values) || row < 0 {
- return nil, errors.Errorf("invalid row index %d", row)
- }
- if column >= len(r.Fields) || column < 0 {
- return nil, errors.Errorf("invalid column index %d", column)
- }
- return r.Values[row][column], nil
- }
- func (r *Resultset) NameIndex(name string) (int, error) {
- if column, ok := r.FieldNames[name]; ok {
- return column, nil
- } else {
- return 0, errors.Errorf("invalid field name %s", name)
- }
- }
- func (r *Resultset) GetValueByName(row int, name string) (interface{}, error) {
- if column, err := r.NameIndex(name); err != nil {
- return nil, errors.Trace(err)
- } else {
- return r.GetValue(row, column)
- }
- }
- func (r *Resultset) IsNull(row, column int) (bool, error) {
- d, err := r.GetValue(row, column)
- if err != nil {
- return false, err
- }
- return d == nil, nil
- }
- func (r *Resultset) IsNullByName(row int, name string) (bool, error) {
- if column, err := r.NameIndex(name); err != nil {
- return false, err
- } else {
- return r.IsNull(row, column)
- }
- }
- func (r *Resultset) GetUint(row, column int) (uint64, error) {
- d, err := r.GetValue(row, column)
- if err != nil {
- return 0, err
- }
- switch v := d.(type) {
- case int:
- return uint64(v), nil
- case int8:
- return uint64(v), nil
- case int16:
- return uint64(v), nil
- case int32:
- return uint64(v), nil
- case int64:
- return uint64(v), nil
- case uint:
- return uint64(v), nil
- case uint8:
- return uint64(v), nil
- case uint16:
- return uint64(v), nil
- case uint32:
- return uint64(v), nil
- case uint64:
- return uint64(v), nil
- case float32:
- return uint64(v), nil
- case float64:
- return uint64(v), nil
- case string:
- return strconv.ParseUint(v, 10, 64)
- case []byte:
- return strconv.ParseUint(string(v), 10, 64)
- case nil:
- return 0, nil
- default:
- return 0, errors.Errorf("data type is %T", v)
- }
- }
- func (r *Resultset) GetUintByName(row int, name string) (uint64, error) {
- if column, err := r.NameIndex(name); err != nil {
- return 0, err
- } else {
- return r.GetUint(row, column)
- }
- }
- func (r *Resultset) GetInt(row, column int) (int64, error) {
- v, err := r.GetUint(row, column)
- if err != nil {
- return 0, err
- }
- return int64(v), nil
- }
- func (r *Resultset) GetIntByName(row int, name string) (int64, error) {
- v, err := r.GetUintByName(row, name)
- if err != nil {
- return 0, err
- }
- return int64(v), nil
- }
- func (r *Resultset) GetFloat(row, column int) (float64, error) {
- d, err := r.GetValue(row, column)
- if err != nil {
- return 0, err
- }
- switch v := d.(type) {
- case int:
- return float64(v), nil
- case int8:
- return float64(v), nil
- case int16:
- return float64(v), nil
- case int32:
- return float64(v), nil
- case int64:
- return float64(v), nil
- case uint:
- return float64(v), nil
- case uint8:
- return float64(v), nil
- case uint16:
- return float64(v), nil
- case uint32:
- return float64(v), nil
- case uint64:
- return float64(v), nil
- case float32:
- return float64(v), nil
- case float64:
- return v, nil
- case string:
- return strconv.ParseFloat(v, 64)
- case []byte:
- return strconv.ParseFloat(string(v), 64)
- case nil:
- return 0, nil
- default:
- return 0, errors.Errorf("data type is %T", v)
- }
- }
- func (r *Resultset) GetFloatByName(row int, name string) (float64, error) {
- if column, err := r.NameIndex(name); err != nil {
- return 0, err
- } else {
- return r.GetFloat(row, column)
- }
- }
- func (r *Resultset) GetString(row, column int) (string, error) {
- d, err := r.GetValue(row, column)
- if err != nil {
- return "", err
- }
- switch v := d.(type) {
- case string:
- return v, nil
- case []byte:
- return hack.String(v), nil
- case int, int8, int16, int32, int64,
- uint, uint8, uint16, uint32, uint64:
- return fmt.Sprintf("%d", v), nil
- case float32:
- return strconv.FormatFloat(float64(v), 'f', -1, 64), nil
- case float64:
- return strconv.FormatFloat(v, 'f', -1, 64), nil
- case nil:
- return "", nil
- default:
- return "", errors.Errorf("data type is %T", v)
- }
- }
- func (r *Resultset) GetStringByName(row int, name string) (string, error) {
- if column, err := r.NameIndex(name); err != nil {
- return "", err
- } else {
- return r.GetString(row, column)
- }
- }
|