-
Notifications
You must be signed in to change notification settings - Fork 56
/
mysql.go
70 lines (63 loc) · 1.63 KB
/
mysql.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package l7
import (
"encoding/binary"
"fmt"
"strconv"
)
const (
MysqlComQuery = 3
MysqlComStmtPrepare = 0x16
MysqlComStmtExecute = 0x17
MysqlComStmtClose = 0x19
mysqlMsgHeaderSize = 4
)
type MysqlParser struct {
preparedStatements map[string]string
}
func NewMysqlParser() *MysqlParser {
return &MysqlParser{preparedStatements: map[string]string{}}
}
func (p *MysqlParser) Parse(payload []byte, statementId uint32) string {
payloadSize := len(payload)
if payloadSize < mysqlMsgHeaderSize+5 {
return ""
}
msgSize := int(payload[0]) | int(payload[1])<<8 | int(payload[2])<<16
cmd := payload[4]
readQuery := func() (query string) {
to := mysqlMsgHeaderSize + msgSize
partial := false
if to > payloadSize {
to = payloadSize
partial = true
}
query = string(payload[mysqlMsgHeaderSize+1 : to])
if partial {
query += "..."
}
return query
}
readStatementId := func() string {
return strconv.FormatUint(uint64(binary.LittleEndian.Uint32(payload[mysqlMsgHeaderSize+1:])), 10)
}
switch cmd {
case MysqlComQuery:
return readQuery()
case MysqlComStmtExecute:
statementIdStr := readStatementId()
statement, ok := p.preparedStatements[statementIdStr]
if !ok {
statement = fmt.Sprintf(`EXECUTE %s /* unknown */`, statementIdStr)
}
return statement
case MysqlComStmtPrepare:
query := readQuery()
statementIdStr := strconv.FormatUint(uint64(statementId), 10)
p.preparedStatements[statementIdStr] = query
return fmt.Sprintf("PREPARE %s FROM %s", statementIdStr, query)
case MysqlComStmtClose:
statementIdStr := readStatementId()
delete(p.preparedStatements, statementIdStr)
}
return ""
}