You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
3.8 KiB
Go
213 lines
3.8 KiB
Go
package mysql
|
|
|
|
import (
|
|
"encoding/binary"
|
|
|
|
"github.com/starainrt/go-mysql/utils"
|
|
)
|
|
|
|
type FieldData []byte
|
|
|
|
type Field struct {
|
|
Data FieldData
|
|
Schema []byte
|
|
Table []byte
|
|
OrgTable []byte
|
|
Name []byte
|
|
OrgName []byte
|
|
Charset uint16
|
|
ColumnLength uint32
|
|
Type uint8
|
|
Flag uint16
|
|
Decimal uint8
|
|
|
|
DefaultValueLength uint64
|
|
DefaultValue []byte
|
|
}
|
|
|
|
type FieldValueType uint8
|
|
|
|
type FieldValue struct {
|
|
Type FieldValueType
|
|
value uint64 // Also for int64 and float64
|
|
str []byte
|
|
}
|
|
|
|
const (
|
|
FieldValueTypeNull = iota
|
|
FieldValueTypeUnsigned
|
|
FieldValueTypeSigned
|
|
FieldValueTypeFloat
|
|
FieldValueTypeString
|
|
)
|
|
|
|
func (f *Field) Parse(p FieldData) (err error) {
|
|
f.Data = p
|
|
|
|
var n int
|
|
pos := 0
|
|
//skip catelog, always def
|
|
n, err = SkipLengthEncodedString(p)
|
|
if err != nil {
|
|
return
|
|
}
|
|
pos += n
|
|
|
|
//schema
|
|
f.Schema, _, n, err = LengthEncodedString(p[pos:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
pos += n
|
|
|
|
//table
|
|
f.Table, _, n, err = LengthEncodedString(p[pos:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
pos += n
|
|
|
|
//org_table
|
|
f.OrgTable, _, n, err = LengthEncodedString(p[pos:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
pos += n
|
|
|
|
//name
|
|
f.Name, _, n, err = LengthEncodedString(p[pos:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
pos += n
|
|
|
|
//org_name
|
|
f.OrgName, _, n, err = LengthEncodedString(p[pos:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
pos += n
|
|
|
|
//skip oc
|
|
pos += 1
|
|
|
|
//charset
|
|
f.Charset = binary.LittleEndian.Uint16(p[pos:])
|
|
pos += 2
|
|
|
|
//column length
|
|
f.ColumnLength = binary.LittleEndian.Uint32(p[pos:])
|
|
pos += 4
|
|
|
|
//type
|
|
f.Type = p[pos]
|
|
pos++
|
|
|
|
//flag
|
|
f.Flag = binary.LittleEndian.Uint16(p[pos:])
|
|
pos += 2
|
|
|
|
//decimals 1
|
|
f.Decimal = p[pos]
|
|
pos++
|
|
|
|
//filter [0x00][0x00]
|
|
pos += 2
|
|
|
|
f.DefaultValue = nil
|
|
//if more data, command was field list
|
|
if len(p) > pos {
|
|
//length of default value lenenc-int
|
|
f.DefaultValueLength, _, n = LengthEncodedInt(p[pos:])
|
|
pos += n
|
|
|
|
if pos+int(f.DefaultValueLength) > len(p) {
|
|
err = ErrMalformPacket
|
|
return
|
|
}
|
|
|
|
//default value string[$len]
|
|
f.DefaultValue = p[pos:(pos + int(f.DefaultValueLength))]
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p FieldData) Parse() (f *Field, err error) {
|
|
f = new(Field)
|
|
if err = f.Parse(p); err != nil {
|
|
return nil, err
|
|
}
|
|
return f, nil
|
|
}
|
|
|
|
func (f *Field) Dump() []byte {
|
|
if f == nil {
|
|
f = &Field{}
|
|
}
|
|
if f.Data != nil {
|
|
return f.Data
|
|
}
|
|
|
|
l := len(f.Schema) + len(f.Table) + len(f.OrgTable) + len(f.Name) + len(f.OrgName) + len(f.DefaultValue) + 48
|
|
|
|
data := make([]byte, 0, l)
|
|
|
|
data = append(data, PutLengthEncodedString([]byte("def"))...)
|
|
|
|
data = append(data, PutLengthEncodedString(f.Schema)...)
|
|
|
|
data = append(data, PutLengthEncodedString(f.Table)...)
|
|
data = append(data, PutLengthEncodedString(f.OrgTable)...)
|
|
|
|
data = append(data, PutLengthEncodedString(f.Name)...)
|
|
data = append(data, PutLengthEncodedString(f.OrgName)...)
|
|
|
|
data = append(data, 0x0c)
|
|
|
|
data = append(data, Uint16ToBytes(f.Charset)...)
|
|
data = append(data, Uint32ToBytes(f.ColumnLength)...)
|
|
data = append(data, f.Type)
|
|
data = append(data, Uint16ToBytes(f.Flag)...)
|
|
data = append(data, f.Decimal)
|
|
data = append(data, 0, 0)
|
|
|
|
if f.DefaultValue != nil {
|
|
data = append(data, Uint64ToBytes(f.DefaultValueLength)...)
|
|
data = append(data, f.DefaultValue...)
|
|
}
|
|
|
|
return data
|
|
}
|
|
|
|
func (fv *FieldValue) AsUint64() uint64 {
|
|
return fv.value
|
|
}
|
|
|
|
func (fv *FieldValue) AsInt64() int64 {
|
|
return utils.Uint64ToInt64(fv.value)
|
|
}
|
|
|
|
func (fv *FieldValue) AsFloat64() float64 {
|
|
return utils.Uint64ToFloat64(fv.value)
|
|
}
|
|
|
|
func (fv *FieldValue) AsString() []byte {
|
|
return fv.str
|
|
}
|
|
|
|
func (fv *FieldValue) Value() interface{} {
|
|
switch fv.Type {
|
|
case FieldValueTypeUnsigned:
|
|
return fv.AsUint64()
|
|
case FieldValueTypeSigned:
|
|
return fv.AsInt64()
|
|
case FieldValueTypeFloat:
|
|
return fv.AsFloat64()
|
|
case FieldValueTypeString:
|
|
return fv.AsString()
|
|
default: // FieldValueTypeNull
|
|
return nil
|
|
}
|
|
}
|