finished parse mssql token

This commit is contained in:
solar 2019-03-07 23:08:44 +08:00
parent 04b5a1faa4
commit 35524edfb6
2 changed files with 244 additions and 43 deletions

View File

@ -288,12 +288,14 @@ func (m *stream) resolveServerPacket(p *packet) {
var msg string var msg string
switch p.packetType { switch p.packetType {
case 4: case 4: //response
var b = int32(p.payload[0]) rows, errMsg := parseToken(p.payload)
msg = fmt.Sprintf("【OK】%d", b) if rows == 0 && len(errMsg) != 0 {
msg = fmt.Sprintf("【Err】Effect Rows:%d, message: %s", rows, errMsg)
} else {
msg = fmt.Sprintf("【OK】Effect Rows:%d", rows)
}
} }
// parseToken(p.payload)
fmt.Println(GetNowStr(false), msg) fmt.Println(GetNowStr(false), msg)
} }

View File

@ -2,7 +2,6 @@ package build
import ( import (
"encoding/binary" "encoding/binary"
"fmt"
) )
type token byte type token byte
@ -42,6 +41,10 @@ const (
typeInt8 = 0x7f typeInt8 = 0x7f
) )
const _PLP_NULL = 0xFFFFFFFFFFFFFFFF
const _UNKNOWN_PLP_LEN = 0xFFFFFFFFFFFFFFFE
const _PLP_TERMINATOR = 0x00000000
// variable-length data types // variable-length data types
// http://msdn.microsoft.com/en-us/library/dd358341.aspx // http://msdn.microsoft.com/en-us/library/dd358341.aspx
const ( const (
@ -89,14 +92,17 @@ type columnStruct struct {
ColName string ColName string
Size int Size int
TypeId int TypeId int
Reader func(column *columnStruct, buf []byte) int
} }
func readTypeInfo(pos int, buf []byte, column *columnStruct) (count int) { func readTypeInfo(pos int, buf []byte, column *columnStruct) (count int) {
typeId := buf[pos+1] typeId := buf[pos]
count = 1 count = 1
pos++ pos++
column.TypeId = int(typeId) column.TypeId = int(typeId)
// fmt.Printf("column TypeId %x %x\n", column.TypeId, buf)
switch typeId { switch typeId {
case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4, case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4,
typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8: typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8:
@ -113,6 +119,8 @@ func readTypeInfo(pos int, buf []byte, column *columnStruct) (count int) {
case typeMoney, typeDateTime, typeFlt8, typeInt8: case typeMoney, typeDateTime, typeFlt8, typeInt8:
column.Size = 8 column.Size = 8
} }
column.Reader = readFixedType
// those are fixed length types // those are fixed length types
default: // all others are VARLENTYPE default: // all others are VARLENTYPE
count += readVarLen(int(typeId), pos, buf, column) count += readVarLen(int(typeId), pos, buf, column)
@ -120,11 +128,136 @@ func readTypeInfo(pos int, buf []byte, column *columnStruct) (count int) {
return count return count
} }
func readFixedType(column *columnStruct, buf []byte) int {
return column.Size
}
func readByteLenType(column *columnStruct, buf []byte) int {
size := int(buf[0])
return 1 + size
}
// partially length prefixed stream
// http://msdn.microsoft.com/en-us/library/dd340469.aspx
func readPLPType(column *columnStruct, buf []byte) int {
size := binary.LittleEndian.Uint64(buf[0:8])
valueLength := 0
switch size {
case _PLP_NULL:
valueLength = 0
case _UNKNOWN_PLP_LEN:
valueLength = 1000
default:
valueLength = int(size)
}
return valueLength + 8
}
func readShortLenType(column *columnStruct, buf []byte) int {
size := int(binary.LittleEndian.Uint16(buf[0:2]))
return 2 + size
}
func readLongLenType(column *columnStruct, buf []byte) int {
count := 1
textptrsize := int(buf[0]) //textptrsize
if textptrsize == 0 {
return 1
}
count = textptrsize + 8 + 1
//timestamp 8
size := int(binary.LittleEndian.Uint32(buf[count : count+4]))
if size == -1 {
return count + 4
}
return count + 4 + size
}
// reads variant value
// http://msdn.microsoft.com/en-us/library/dd303302.aspx
func readVariantType(column *columnStruct, buf []byte) int {
count := 0
size := int(binary.LittleEndian.Uint32(buf[count : count+4]))
count = 4
if size == 0 {
return count
}
vartype := int(buf[count])
count += 1
propbytes := int(buf[count])
switch vartype {
case typeGuid:
count = count + size - 2 - propbytes
case typeBit:
count += 1
case typeInt1:
count += 1
case typeInt2:
count += 2
case typeInt4:
count += 4
case typeInt8:
count += 8
case typeDateTime:
count = count + size - 2 - propbytes
case typeDateTim4:
count = count + size - 2 - propbytes
case typeFlt4:
count = count + 4
case typeFlt8:
count = count + 8
case typeMoney4:
count = count + size - 2 - propbytes
case typeMoney:
count = count + size - 2 - propbytes
case typeDateN:
count = count + size - 2 - propbytes
case typeTimeN:
count += 1
count = count + size - 2 - propbytes
case typeDateTime2N:
count += 1
count = count + size - 2 - propbytes
case typeDateTimeOffsetN:
count += 1
count = count + size - 2 - propbytes
case typeBigVarBin, typeBigBinary:
count += 2
count = count + size - 2 - propbytes
case typeDecimalN, typeNumericN:
count += 2
count = count + size - 2 - propbytes
case typeBigVarChar, typeBigChar:
count += 5
count += 2 // max length, ignoring
count = count + size - 2 - propbytes
case typeNVarChar, typeNChar:
count += 5
count += 2 // max length, ignoring
count = count + size - 2 - propbytes
default:
panic("Invalid variant typeid")
}
return count
}
func readVarLen(typeId int, pos int, buf []byte, column *columnStruct) (count int) { func readVarLen(typeId int, pos int, buf []byte, column *columnStruct) (count int) {
count = 0 count = 0
switch typeId { switch typeId {
case typeDateN: case typeDateN:
column.Size = 3 column.Size = 3
column.Reader = readByteLenType
case typeTimeN, typeDateTime2N, typeDateTimeOffsetN: case typeTimeN, typeDateTime2N, typeDateTimeOffsetN:
pos += 1 //Scale pos += 1 //Scale
@ -148,6 +281,8 @@ func readVarLen(typeId int, pos int, buf []byte, column *columnStruct) (count in
column.Size += 5 column.Size += 5
} }
column.Reader = readByteLenType
case typeGuid, typeIntN, typeDecimal, typeNumeric, case typeGuid, typeIntN, typeDecimal, typeNumeric,
typeBitN, typeDecimalN, typeNumericN, typeFltN, typeBitN, typeDecimalN, typeNumericN, typeFltN,
typeMoneyN, typeDateTimeN, typeChar, typeMoneyN, typeDateTimeN, typeChar,
@ -163,6 +298,7 @@ func readVarLen(typeId int, pos int, buf []byte, column *columnStruct) (count in
pos += 2 //byle len types pos += 2 //byle len types
count += 2 count += 2
} }
column.Reader = readByteLenType
case typeXml: case typeXml:
pos += 1 //byle len types pos += 1 //byle len types
count += 1 count += 1
@ -189,6 +325,7 @@ func readVarLen(typeId int, pos int, buf []byte, column *columnStruct) (count in
pos += l * 2 pos += l * 2
count += l * 2 count += l * 2
} }
column.Reader = readPLPType
case typeUdt: case typeUdt:
pos += 1 pos += 1
l := int(binary.LittleEndian.Uint16(buf[pos : pos+2])) l := int(binary.LittleEndian.Uint16(buf[pos : pos+2]))
@ -226,6 +363,7 @@ func readVarLen(typeId int, pos int, buf []byte, column *columnStruct) (count in
pos += l * 2 pos += l * 2
count += l * 2 count += l * 2
column.Reader = readPLPType
case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar, case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar,
typeNVarChar, typeNChar: typeNVarChar, typeNChar:
// short len types // short len types
@ -242,6 +380,12 @@ func readVarLen(typeId int, pos int, buf []byte, column *columnStruct) (count in
count += 5 count += 5
} }
if column.Size == 0xffff {
column.Reader = readPLPType
} else {
column.Reader = readShortLenType
}
case typeText, typeImage, typeNText, typeVariant: case typeText, typeImage, typeNText, typeVariant:
// LONGLEN_TYPE // LONGLEN_TYPE
@ -265,7 +409,7 @@ func readVarLen(typeId int, pos int, buf []byte, column *columnStruct) (count in
pos += l pos += l
count += l count += l
} }
column.Reader = readLongLenType
case typeImage: case typeImage:
// ignore tablenames // ignore tablenames
pos++ pos++
@ -279,6 +423,11 @@ func readVarLen(typeId int, pos int, buf []byte, column *columnStruct) (count in
pos += l pos += l
count += l count += l
} }
column.Reader = readLongLenType
case typeVariant:
column.Reader = readVariantType
} }
default: default:
count += 0 count += 0
@ -286,52 +435,67 @@ func readVarLen(typeId int, pos int, buf []byte, column *columnStruct) (count in
return count return count
} }
func parseToken(buf []byte) int { func parseToken(buf []byte) (int, string) {
var pos = 0 var pos = 0
length := 0 length := 0
rowCount := 0 rowCount := 0
msg := ""
var columns []columnStruct var columns []columnStruct
currentBuf := buf[:]
for { for {
token := token(buf[pos]) if len(currentBuf) == 0 {
break
}
token := token(currentBuf[0])
// fmt.Printf("item... %x\n", currentBuf[0])
currentBuf = currentBuf[1:]
switch token { switch token {
case tokenSSPI: case tokenSSPI:
pos += 1 length = int(binary.LittleEndian.Uint16(currentBuf[0:2]))
length = int(binary.LittleEndian.Uint16(buf[pos : pos+2])) currentBuf = currentBuf[length+2:]
pos += 1
pos += length
case tokenReturnStatus: case tokenReturnStatus:
pos += 4 currentBuf = currentBuf[3:]
case tokenLoginAck: case tokenLoginAck:
pos += 1 length = int(binary.LittleEndian.Uint16(currentBuf[0:2]))
length = int(binary.LittleEndian.Uint16(buf[pos : pos+2])) currentBuf = currentBuf[2+length:]
pos += 1
pos += length
case tokenOrder: case tokenOrder:
pos += 1 length = int(binary.LittleEndian.Uint16(currentBuf[0:2]))
length = int(binary.LittleEndian.Uint16(buf[pos : pos+2])) currentBuf = currentBuf[2+length:]
pos += 1
pos += length
case tokenDoneInProc: case tokenDoneInProc:
pos += 5 currentBuf = currentBuf[4:]
rowCount = int(binary.LittleEndian.Uint64(buf[pos : pos+8])) rowCount = int(binary.LittleEndian.Uint64(currentBuf[0:8]))
pos += 8 currentBuf = currentBuf[8+rowCount:]
pos += rowCount
case tokenDone, tokenDoneProc: case tokenDone, tokenDoneProc:
pos += 5 currentBuf = currentBuf[4:]
rowCount = int(binary.LittleEndian.Uint64(buf[pos : pos+8])) rowCount = int(binary.LittleEndian.Uint64(currentBuf[0:8]))
pos += 8 currentBuf = currentBuf[8:]
pos += rowCount case tokenError:
currentBuf = currentBuf[8:] //length2+Number4+State1+Class1
//message length
msgLength := int(binary.LittleEndian.Uint16(currentBuf[0:2]))
msgLength = msgLength * 2
msg, _ = ucs22str(currentBuf[0:msgLength])
case tokenColMetadata: case tokenColMetadata:
pos += 1
// fmt.Printf("tokenColMetadata1 %x\n", currentBuf)
//http://msdn.microsoft.com/en-us/library/dd357363.aspx //http://msdn.microsoft.com/en-us/library/dd357363.aspx
count := int(binary.LittleEndian.Uint16(buf[pos : pos+2])) count := int(binary.LittleEndian.Uint16(currentBuf[0:2]))
currentBuf = currentBuf[2:]
columns = make([]columnStruct, count) columns = make([]columnStruct, count)
pos += 1
if count > 0 { if count > 0 {
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
@ -339,25 +503,60 @@ func parseToken(buf []byte) int {
// fmt.Printf("colums %d %d", i, count) // fmt.Printf("colums %d %d", i, count)
column := &columns[i] column := &columns[i]
// x := pos // x := pos
pos += 4 //UserType
pos += 2 //Flags currentBuf = currentBuf[6:]
pos += readTypeInfo(pos, buf, column)
pos = readTypeInfo(0, currentBuf, column)
currentBuf = currentBuf[pos:]
//ColName //ColName
pos += 1 // owning schema l := int(currentBuf[0])
l := int(buf[pos]) currentBuf = currentBuf[1:]
pos += l * 2 //name
currentBuf = currentBuf[l*2:]
// fmt.Printf("after name: %x\n", currentBuf)
// fmt.Printf("%d, %d ,%x\n", x, pos, buf[x+1:pos+1]) // fmt.Printf("%d, %d ,%x\n", x, pos, buf[x+1:pos+1])
fmt.Print("%v", column) // fmt.Print("%v", column)
} }
// fmt.Printf("tokenRow %x\n", currentBuf)
} }
case tokenRow: case tokenRow:
count := 0
// fmt.Printf("tokenRow currentBuf %x %v\n", currentBuf)
for _, column := range columns {
count = column.Reader(&column, currentBuf)
currentBuf = currentBuf[count:]
// fmt.Printf("tokenRow %d %x \n", i, currentBuf)
}
case tokenNbcRow:
bitlen := (len(columns) + 7) / 8
pres := currentBuf[0:bitlen]
currentBuf = currentBuf[bitlen:]
count := 0
for i, column := range columns {
if pres[i/8]&(1<<(uint(i)%8)) != 0 {
continue
}
count = column.Reader(&column, currentBuf)
currentBuf = currentBuf[count:]
// fmt.Printf("tokenNbcRow %d %x \n", i, currentBuf)
}
default:
break
} }
break
} }
return rowCount return rowCount, msg
} }