func isTokenIdentifier(s string, buf *bytes.Buffer) int { buf.Reset() buf.Grow(len(s)) data := buf.Bytes()[:len(s)] for i := 0; i < len(s); i++ { if s[i] >= 'a' && s[i] <= 'z' { data[i] = s[i] + 'A' - 'a' } else { data[i] = s[i] } } tok := tokenMap[hack.String(data)] return tok }
// dispatch handles client request based on command which is the first byte of the data. // It also gets a token from server which is used to limit the concurrently handling clients. // The most frequently used command is ComQuery. func (cc *clientConn) dispatch(data []byte) error { cmd := data[0] data = data[1:] cc.lastCmd = hack.String(data) token := cc.server.getToken() startTS := time.Now() defer func() { cc.server.releaseToken(token) log.Debugf("[TIME_CMD] %v %d", time.Since(startTS), cmd) }() switch cmd { case mysql.ComSleep: // TODO: According to mysql document, this command is supposed to be used only internally. // So it's just a temp fix, not sure if it's done right. // Investigate this command and write test case later. return nil case mysql.ComQuit: return io.EOF case mysql.ComQuery: // Most frequently used command. // For issue 1989 // Input payload may end with byte '\0', we didn't find related mysql document about it, but mysql // implementation accept that case. So trim the last '\0' here as if the payload an EOF string. // See http://dev.mysql.com/doc/internals/en/com-query.html if data[len(data)-1] == 0 { data = data[:len(data)-1] } return cc.handleQuery(hack.String(data)) case mysql.ComPing: return cc.writeOK() case mysql.ComInitDB: log.Debug("init db", hack.String(data)) if err := cc.useDB(hack.String(data)); err != nil { return errors.Trace(err) } return cc.writeOK() case mysql.ComFieldList: return cc.handleFieldList(hack.String(data)) case mysql.ComStmtPrepare: return cc.handleStmtPrepare(hack.String(data)) case mysql.ComStmtExecute: return cc.handleStmtExecute(data) case mysql.ComStmtClose: return cc.handleStmtClose(data) case mysql.ComStmtSendLongData: return cc.handleStmtSendLongData(data) case mysql.ComStmtReset: return cc.handleStmtReset(data) case mysql.ComSetOption: return cc.handleSetOption(data) default: return mysql.NewErrf(mysql.ErrUnknown, "command %d not supported now", cmd) } }
// dispatch handles client request based on command which is the first byte of the data. // It also gets a token from server which is used to limit the concurrently handling clients. // The most frequently used command is ComQuery. func (cc *clientConn) dispatch(data []byte) error { cmd := data[0] data = data[1:] cc.lastCmd = hack.String(data) token := cc.server.getToken() startTS := time.Now() defer func() { cc.server.releaseToken(token) log.Debugf("[TIME_CMD] %v %d", time.Since(startTS), cmd) }() switch cmd { case mysql.ComSleep: // TODO: According to mysql document, this command is supposed to be used only internally. // So it's just a temp fix, not sure if it's done right. // Investigate this command and write test case later. return nil case mysql.ComQuit: return io.EOF case mysql.ComQuery: // Most frequently used command. return cc.handleQuery(hack.String(data)) case mysql.ComPing: return cc.writeOK() case mysql.ComInitDB: log.Debug("init db", hack.String(data)) if err := cc.useDB(hack.String(data)); err != nil { return errors.Trace(err) } return cc.writeOK() case mysql.ComFieldList: return cc.handleFieldList(hack.String(data)) case mysql.ComStmtPrepare: return cc.handleStmtPrepare(hack.String(data)) case mysql.ComStmtExecute: return cc.handleStmtExecute(data) case mysql.ComStmtClose: return cc.handleStmtClose(data) case mysql.ComStmtSendLongData: return cc.handleStmtSendLongData(data) case mysql.ComStmtReset: return cc.handleStmtReset(data) case mysql.ComSetOption: return cc.handleSetOption(data) default: return mysql.NewErrf(mysql.ErrUnknown, "command %d not supported now", cmd) } }
func (cc *clientConn) dispatch(data []byte) error { cmd := data[0] data = data[1:] cc.lastCmd = hack.String(data) token := cc.server.getToken() defer func() { cc.server.releaseToken(token) }() switch cmd { case mysql.ComQuit: return io.EOF case mysql.ComQuery: return cc.handleQuery(hack.String(data)) case mysql.ComPing: return cc.writeOK() case mysql.ComInitDB: log.Debug("init db", hack.String(data)) if err := cc.useDB(hack.String(data)); err != nil { return errors.Trace(err) } return cc.writeOK() case mysql.ComFieldList: return cc.handleFieldList(hack.String(data)) case mysql.ComStmtPrepare: return cc.handleStmtPrepare(hack.String(data)) case mysql.ComStmtExecute: return cc.handleStmtExecute(data) case mysql.ComStmtClose: return cc.handleStmtClose(data) case mysql.ComStmtSendLongData: return cc.handleStmtSendLongData(data) case mysql.ComStmtReset: return cc.handleStmtReset(data) default: msg := fmt.Sprintf("command %d not supported now", cmd) return mysql.NewError(mysql.ErUnknownError, msg) } }
func (d *Datum) compareBytes(b []byte) (int, error) { return d.compareString(hack.String(b)) }
// GetMysqlSet gets mysql.Set value func (d *Datum) GetMysqlSet() mysql.Set { return mysql.Set{Value: uint64(d.i), Name: hack.String(d.b)} }
// GetMysqlEnum gets mysql.Enum value func (d *Datum) GetMysqlEnum() mysql.Enum { return mysql.Enum{Value: uint64(d.i), Name: hack.String(d.b)} }
// GetString gets string value. func (d *Datum) GetString() string { return hack.String(d.b) }
func parseStmtArgs(args []interface{}, boundParams [][]byte, nullBitmap, paramTypes, paramValues []byte) (err error) { pos := 0 var v []byte var n int var isNull bool for i := 0; i < len(args); i++ { if nullBitmap[i>>3]&(1<<(uint(i)%8)) > 0 { args[i] = nil continue } if boundParams[i] != nil { args[i] = boundParams[i] continue } tp := paramTypes[i<<1] isUnsigned := (paramTypes[(i<<1)+1] & 0x80) > 0 switch tp { case mysql.TypeNull: args[i] = nil continue case mysql.TypeTiny: if len(paramValues) < (pos + 1) { err = mysql.ErrMalformPacket return } if isUnsigned { args[i] = uint64(paramValues[pos]) } else { args[i] = int64(paramValues[pos]) } pos++ continue case mysql.TypeShort, mysql.TypeYear: if len(paramValues) < (pos + 2) { err = mysql.ErrMalformPacket return } valU16 := binary.LittleEndian.Uint16(paramValues[pos : pos+2]) if isUnsigned { args[i] = uint64(valU16) } else { args[i] = int64(valU16) } pos += 2 continue case mysql.TypeInt24, mysql.TypeLong: if len(paramValues) < (pos + 4) { err = mysql.ErrMalformPacket return } valU32 := binary.LittleEndian.Uint32(paramValues[pos : pos+4]) if isUnsigned { args[i] = uint64(valU32) } else { args[i] = int64(valU32) } pos += 4 continue case mysql.TypeLonglong: if len(paramValues) < (pos + 8) { err = mysql.ErrMalformPacket return } valU64 := binary.LittleEndian.Uint64(paramValues[pos : pos+8]) if isUnsigned { args[i] = valU64 } else { args[i] = int64(valU64) } pos += 8 continue case mysql.TypeFloat: if len(paramValues) < (pos + 4) { err = mysql.ErrMalformPacket return } args[i] = float64(math.Float32frombits(binary.LittleEndian.Uint32(paramValues[pos : pos+4]))) pos += 4 continue case mysql.TypeDouble: if len(paramValues) < (pos + 8) { err = mysql.ErrMalformPacket return } args[i] = math.Float64frombits(binary.LittleEndian.Uint64(paramValues[pos : pos+8])) pos += 8 continue case mysql.TypeDecimal, mysql.TypeNewDecimal, mysql.TypeVarchar, mysql.TypeBit, mysql.TypeEnum, mysql.TypeSet, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob, mysql.TypeBlob, mysql.TypeVarString, mysql.TypeString, mysql.TypeGeometry, mysql.TypeDate, mysql.TypeNewDate, mysql.TypeTimestamp, mysql.TypeDatetime, mysql.TypeDuration: if len(paramValues) < (pos + 1) { err = mysql.ErrMalformPacket return } v, isNull, n, err = parseLengthEncodedBytes(paramValues[pos:]) pos += n if err != nil { return } if !isNull { args[i] = hack.String(v) } else { args[i] = nil } continue default: err = errUnknownFieldType.Gen("stmt unknown field type %d", tp) return } } return }
func (d *Datum) compareBytes(sc *variable.StatementContext, b []byte) (int, error) { return d.compareString(sc, hack.String(b)) }