func (l language) Write(e *bin.Encoder) error {
	e.WriteUint32(uint32(len(l.query)) + 1)
	e.WriteByte(l.status)
	e.WriteString(l.query)
	err := e.Err()
	return err
}
Read unserializes a TdsLanguage struct
package tds
import (
	"fmt"
	"os"
	"reflect"
	"strconv"
	bin "github.com/thda/tds/binary"
	"errors"
)
type messageReader interface {
	Token() token
	Size() uint8
	SizeLen() uint8
	LimitRead() bool
	Read(*bin.Encoder) error
}
type messageReaderWriter interface {
	messageReader
	Write(*bin.Encoder) error
}
type token byte
const (
	noneToken          token = 0x00
	capabilityReqToken token = 0x01
	capabilityResToken token = 0x02
	paramFmt2Token     token = 0x20  
	languageToken      token = 0x21  
	orderBy2Token      token = 0x22  
	wideColumnFmtToken token = 0x61  
	dynamic2Token      token = 0x62  
	msgToken           token = 0x65  
	returnStatusToken  token = 0x79  
	curCloseToken      token = 0x80  
	curDeleteToken     token = 0x81  
	curFetchToken      token = 0x82  
	curFmtToken        token = 0x83  
	curOpenToken       token = 0x84  
	curDeclareToken    token = 0x86  
	logoutToken        token = 0x71  
	tableNameToken     token = 0xa4  
	columnInfoToken    token = 0xa5  
	optionCmdToken     token = 0xa6  
	cmpRowNameToken    token = 0xa7  
	cmpRowFmtToken     token = 0xa8  
	orderByToken       token = 0xa9  
	infoToken          token = 0xab  
	loginAckToken      token = 0xad  
	controlToken       token = 0xae  
	rowToken           token = 0xd1  
	cmpRowToken        token = 0xd3  
	paramToken         token = 0xd7  
	capabilitiesToken  token = 0xe2  
	envChangeToken     token = 0xe3  
	sqlMessageToken    token = 0xe5  
	dbRPCToken         token = 0xe6  
	dynamicToken       token = 0xe7  
	paramFmtToken      token = 0xec  
	authToken          token = 0xed  
	columnFmtToken     token = 0xee  
	doneToken          token = 0xfd  
	doneProcToken      token = 0xfe  
	doneInProcToken    token = 0xff  
)
const (
	noFlag          = 0
	fixedSize uint8 = 1 << iota  
	limitRead
	long   
	short  
	ignoreSize
)
var msgs = map[token]msg{
	noneToken:          {noneToken, noFlag, 0},
	capabilityReqToken: {capabilityReqToken, noFlag, 0},
	capabilityResToken: {capabilityResToken, noFlag, 0},
	paramFmt2Token:     {paramFmt2Token, long, 0},
	languageToken:      {languageToken, ignoreSize, 0},
	orderBy2Token:      {orderBy2Token, long, 0},
	cmpRowFmtToken:     {cmpRowFmtToken, noFlag, 0},
	cmpRowNameToken:    {cmpRowNameToken, noFlag, 0},
	wideColumnFmtToken: {wideColumnFmtToken, long, 0},
	dynamic2Token:      {dynamic2Token, long, 0},
	returnStatusToken:  {returnStatusToken, fixedSize, 4},
	curCloseToken:      {curCloseToken, noFlag, 0},
	curDeleteToken:     {curDeleteToken, noFlag, 0},
	curFetchToken:      {curFetchToken, noFlag, 0},
	curFmtToken:        {curFmtToken, noFlag, 0},
	curOpenToken:       {curOpenToken, noFlag, 0},
	curDeclareToken:    {curDeclareToken, noFlag, 0},
	logoutToken:        {logoutToken, fixedSize, 1},
	tableNameToken:     {tableNameToken, limitRead, 0},
	columnInfoToken:    {columnInfoToken, limitRead, 0},
	optionCmdToken:     {optionCmdToken, noFlag, 0},
	controlToken:       {controlToken, noFlag, 0},
	orderByToken:       {orderByToken, noFlag, 0},
	loginAckToken:      {loginAckToken, noFlag, 0},
	rowToken:           {rowToken, ignoreSize, 0},
	paramToken:         {paramToken, ignoreSize, 0},
	cmpRowToken:        {cmpRowToken, ignoreSize, 0},
	capabilitiesToken:  {capabilitiesToken, noFlag, 0},
	envChangeToken:     {envChangeToken, noFlag, 0},
	sqlMessageToken:    {sqlMessageToken, noFlag, 0},
	infoToken:          {infoToken, noFlag, 0},
	dbRPCToken:         {dbRPCToken, noFlag, 0},
	dynamicToken:       {dynamicToken, noFlag, 0},
	paramFmtToken:      {paramFmtToken, noFlag, 0},
	columnFmtToken:     {columnFmtToken, noFlag, 0},
	doneToken:          {doneToken, fixedSize, 8},
	msgToken:           {msgToken, short, 0},
	doneProcToken:      {doneProcToken, fixedSize, 8},
	doneInProcToken:    {doneInProcToken, fixedSize, 8}}
type msg struct {
	token token
	flags uint8
	size  uint8  
}
func newMsg(t token) msg {
	attr, _ := safeGetMsg(t)
	return attr
}
func safeGetMsg(t token) (msg, error) {
	attr, ok := msgs[t]
	if !ok {
		return msg{}, fmt.Errorf("tds: unknown token %s", t)
	}
	return attr, nil
}
func (attr msg) Token() token {
	return attr.token
}
func (attr msg) Size() uint8 {
	if attr.flags&fixedSize != 0 {
		return attr.size
	}
	return 0
}
func (attr msg) SizeLen() uint8 {
	if attr.flags&short != 0 {
		return 8
	}
	if attr.flags&long != 0 {
		return 32
	}
	if attr.flags&fixedSize != 0 || attr.flags&ignoreSize != 0 {
		return 0
	}
	return 16
}
func (attr msg) LimitRead() bool {
	return attr.flags&limitRead != 0
}
type emptyMsg struct {
	msg
}
func (e emptyMsg) Write(*bin.Encoder) error {
	return nil
}
func (e emptyMsg) Read(*bin.Encoder) error {
	return nil
}
const defaultcapabilitiesLength = 14
const (
	_ = iota
	reqLang
	reqRPC
	reqEvt
	reqMstmt
	reqBcp
	reqCursor
	reqDynf
	reqMsg
	reqParam
	dataInt1
	dataInt2
	dataInt4
	dataBit
	dataChar
	dataVchar
	dataBin
	dataVbin
	dataMny8
	dataMny4
	dataDate8
	dataDate4
	dataFlt4
	dataFlt8
	dataNum
	dataText
	dataImage
	dataDec
	dataLchar
	dataLbin
	dataIntn
	dataDatetimen
	dataMoneyn
	csrPrev
	csrFirst
	csrLast
	csrAbs
	csrRel
	csrMulti
	conOob
	conInband
	conLogical
	protoText
	protoBulk
	reqUrgevt
	dataSensitivity
	dataBoundary
	protoDynamic
	protoDynproc
	dataFltn
	dataBitn
	dataInt8
	dataVoid
	dolBulk
	objectJava1
	objectChar
	reqReserved1
	objectBinary
	dataColumnstatus
	widetable
	reqReserved2
	dataUint2
	dataUint4
	dataUint8
	dataUintn
	curImplicit
	dataNlbin
	imageNchar
	blobNchar16
	blobNchar8
	blobNcharScsu
	dataDate
	dataTime
	dataInterval
	csrScroll
	csrSensitive
	csrInsensitive
	csrSemisensitive
	csrKeysetdriven
	reqSrvpktsize
	dataUnitext
	capClusterfailover
	dataSint1
	reqLargeident
	reqBlobNchar16
	dataXML
	reqCurinfo3
	reqDbrpc2
	_
	reqMigrate
	multiRequests
	_
	_
	dataBigdatetime
	dataUsecs
	rpcparamLob
	reqInstid
	reqGrid
	reqDynBatch
	reqLangBatch
	reqRPCBatch
	dataLoblocator
	reqRowCountSelect
	reqLogParams
	reqDynNoParamFmt
	reqRO
)
const (
	_ = iota
	resNomsg
	resNoeed
	resNoparam
	dataNoint1
	dataNoint2
	dataNoint4
	dataNobit
	dataNochar
	dataNovchar
	dataNobin
	dataNovbin
	dataNomny8
	dataNomny4
	dataNodate8
	dataNodate4
	dataNoflt4
	dataNoflt8
	dataNonum
	dataNotext
	dataNoimage
	dataNodec
	dataNolchar
	dataNolbin
	dataNointn
	dataNodatetimen
	dataNomoneyn
	conNooob
	conNoinband
	protoNotext
	protoNobulk
	dataNosensitivity
	dataNoboundary
	resNotdsdebug
	resNostripblanks
	dataNoint8
	objectNojava1
	objectNochar
	dataNocolumnstatus
	objectNobinary
	resReserved1
	dataNouint2
	dataNouint4
	dataNouint8
	dataNouintn
	noWidetables
	dataNonlbin
	imageNonchar
	blobNonchar16
	blobNonchar8
	blobNoncharScsu
	dataNodate
	dataNotime
	dataNointerval
	dataNounitext
	dataNosint1
	resNolargeident
	resNoblobNchar16
	noSrvpktsize
	resNodataXML
	nonintReturnValue
	resNoxnldata
	resSuppressFmt
	resSuppressDoneinproc
	resForceRowfmt2
	dataNobigdatetime
	dataNousecs
	resNoTdscontrol
	rpcparamNolob
	_
	dataNoloblocator
)
var defaultReqcapabilities = [...]int{dataLoblocator, reqLangBatch, reqDynBatch,
	rpcparamLob, dataUsecs, dataBigdatetime,
	reqDbrpc2, reqCurinfo3, dataXML, reqLargeident, dataUnitext,
	reqSrvpktsize, csrSemisensitive, csrInsensitive, csrScroll, dataTime,
	dataDate, dataNlbin, curImplicit, dataUintn,
	dataUint8, dataUint4, dataUint2, widetable,
	dolBulk, dataVoid, dataInt8, dataFltn, protoDynproc,
	dataBoundary, dataSensitivity, conInband,
	csrMulti, csrRel, csrAbs, csrLast, csrFirst, csrPrev, dataMoneyn,
	dataDatetimen, dataIntn, dataLbin, dataLchar, dataDec, dataImage, dataText, dataNum,
	dataFlt8, dataFlt4, dataDate4, dataDate8, dataMny4, dataMny8, dataVbin, dataBin,
	dataVchar, dataChar, dataBit, dataInt4, dataInt2, dataInt1, reqParam, reqMsg,
	reqDynf, reqCursor, reqBcp, reqRPC, reqLang}
var defaultRescapabilities = [...]int{resNoTdscontrol, resSuppressFmt,
	resNoxnldata, resNotdsdebug, objectNojava1}
type capabilities struct {
	msg
	reqToken    byte
	e           int8
	req         []byte
	resToken    byte
	resFieldLen int8
	res         []byte
}
func newCapabilities() *capabilities {
	c := &capabilities{reqToken: byte(capabilityReqToken), resToken: byte(capabilityResToken)}
	c.req = make([]byte, defaultcapabilitiesLength)
	c.res = make([]byte, defaultcapabilitiesLength)
	for _, capability := range &defaultReqcapabilities {
		c.setcapabilities(capabilityReqToken, capability)
	}
	for _, capability := range &defaultRescapabilities {
		c.setcapabilities(capabilityResToken, capability)
	}
	return c
}
func (c *capabilities) setcapabilities(capabilityType token, capabilities ...int) error {
	var target []byte
	var length int
	switch capabilityType {
	case capabilityReqToken:
		target = c.req[:]
	case capabilityResToken:
		target = c.res[:]
	default:
		return errors.New("tds: invalid capability type. Should be capabilityReqToken or capabilityResToken")
	}
	length = len(target)
	for _, capability := range capabilities[:] {
		capIndex := length - 1 - capability/8
		pos := uint(capability) % 8
		if capIndex >= length {
			return fmt.Errorf("tds: trying to write above the capacity array length, %d > %d", length, capIndex)
		}
		target[capIndex] |= (1 << pos)
	}
	return nil
}
func (c *capabilities) isSet(capabilityType token, capability int) bool {
	var target []byte
	var length int
	switch capabilityType {
	case capabilityReqToken:
		target = c.req[:]
	case capabilityResToken:
		target = c.res[:]
	default:
		return false
	}
	length = len(target)
	capIndex := length - 1 - capability/8
	pos := capability % 8
	return capIndex < length && target[capIndex]&(1<<uint(pos)) != 0
}
func (c capabilities) Write(e *bin.Encoder) error {
	e.WriteByte(c.reqToken)
	e.WriteInt8(int8(len(c.req)))
	e.Write(c.req[:])
	e.WriteByte(c.resToken)
	e.WriteInt8(int8(len(c.res)))
	e.Write(c.res[:])
	err := e.Err()
	return err
}
func (c *capabilities) Read(e *bin.Encoder) error {
	c.reqToken = e.ReadByte()
	c.e = e.Int8()
	c.req = make([]byte, c.e)
	e.Read(c.req[:])
	c.resToken = e.ReadByte()
	c.resFieldLen = e.Int8()
	c.res = make([]byte, c.resFieldLen)
	e.Read(c.res[:])
	err := e.Err()
	return err
}
const (
	doneNoTran       = iota  
	doneTranSucceed          
	doneTranProgress         
	doneTranAbort            
)
const (
	doneFinal       = 0x0000
	doneMoreResults = 0x0001
	doneError       = 0x0002
	doneProc        = 0x0008
	doneCount       = 0x0010
	doneProcCount   = 0x0040
	doneCancel      = 0x0020
)
type done struct {
	msg
	status    int16
	tranState int16
	count     int32
}
func (d done) Write(e *bin.Encoder) error {
	e.WriteInt16(d.status)
	e.WriteInt16(d.tranState)
	e.WriteInt32(d.count)
	err := e.Err()
	return err
}
func (d *done) Read(e *bin.Encoder) error {
	d.status = e.Int16()
	d.tranState = e.Int16()
	d.count = e.Int32()
	err := e.Err()
	return err
}
const (
	dynamicPrepare = 0x01 << iota
	dynamicExec
	dynamicDealloc
	dynamicExecImmediate
	dynamicProcname
	dynamicAck
	dynamicDescIn
	dynamicDescOut
)
const (
	dynamicHasArgs = 0x01 << iota
	dynamicSuppressParamFmt
	dynamicBatchParams
)
type dynamic struct {
	msg
	operation byte
	status    byte
	name      string  
	statement string  
}
func (d *dynamic) Read(e *bin.Encoder) error {
	d.operation = e.ReadByte()
	d.status = e.ReadByte()
	d.name, _ = e.ReadString(8)
	if d.operation&dynamicPrepare > 0 {
		d.statement, _ = e.ReadString(32)
	}
	err := e.Err()
	return err
}
func (d dynamic) Write(e *bin.Encoder) error {
	e.WriteByte(d.operation)
	e.WriteByte(d.status)
	e.WriteStringWithLen(8, d.name)
	if d.operation&dynamicPrepare > 0 {
		e.WriteStringWithLen(32, d.statement)
	}
	err := e.Err()
	return err
}
type changeType byte
const (
	dbChange         changeType = 0x01
	langChange       changeType = 0x02
	charsetChange    changeType = 0x03
	packetSizeChange changeType = 0x04
)
type envChange struct {
	msg
	changeType changeType
	newValue   string  
	oldValue   string  
}
func (env envChange) Write(e *bin.Encoder) error {
	e.WriteByte(byte(env.changeType))
	e.WriteStringWithLen(8, env.newValue)
	e.WriteStringWithLen(8, env.oldValue)
	err := e.Err()
	return err
}
func (env *envChange) Read(e *bin.Encoder) error {
	env.changeType = changeType(e.ReadByte())
	env.newValue, _ = e.ReadString(8)
	env.oldValue, _ = e.ReadString(8)
	err := e.Err()
	return err
}
func (env envChange) String() string {
	return "env change: " + fmt.Sprint(env.changeType) +
		"\nold value: " + env.oldValue + "\nnew value: " + env.newValue
}
type language struct {
	msg
	messageLen uint32
	status     byte
	query      string
}
func (l *language) Read(e *bin.Encoder) error {
	l.messageLen = e.Uint32()
	l.status = e.ReadByte()
	l.query = e.ReadStringWithLen(int(l.messageLen - 1))
	err := e.Err()
	return err
}