func (s *Server) onConn(c net.Conn) { conn := s.newClientConn(c) //新建一个conn defer func() { err := recover() if err != nil { const size = 4096 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] //获得当前goroutine的stacktrace golog.Error("server", "onConn", "error", 0, "remoteAddr", c.RemoteAddr().String(), "stack", string(buf), ) } conn.Close() }() if allowConnect := conn.IsAllowConnect(); allowConnect == false { err := mysql.NewError(mysql.ER_ACCESS_DENIED_ERROR, "ip address access denied by kingshard.") conn.writeError(err) conn.Close() return } if err := conn.Handshake(); err != nil { golog.Error("server", "onConn", err.Error(), 0) c.Close() return } conn.Run() }
//返回true表示已经处理,false表示未处理 func (c *ClientConn) preHandleShard(sql string) (bool, error) { var rs []*mysql.Result var err error var execNode *backend.Node var fromSlave bool = false if len(sql) == 0 { return false, errors.ErrCmdUnsupport } tokens := strings.Fields(sql) if len(tokens) == 0 { return false, errors.ErrCmdUnsupport } if c.isInTransaction() { execNode, err = c.GetTransExecNode(tokens, sql) } else { execNode, fromSlave, err = c.GetExecNode(tokens, sql) } if err != nil { return false, err } //need shard sql if execNode == nil { return false, nil } //execute in Master DB conn, err := c.getBackendConn(execNode, fromSlave) if err != nil { return false, err } rs, err = c.executeInNode(conn, sql, nil) if err != nil { return false, err } c.closeConn(conn, false) if len(rs) == 0 { msg := fmt.Sprintf("result is empty") golog.Error("ClientConn", "handleUnsupport", msg, c.connectionId) return false, mysql.NewError(mysql.ER_UNKNOWN_ERROR, msg) } if rs[0].Resultset != nil { err = c.writeResultset(c.status, rs[0].Resultset) } else { err = c.writeOK(rs[0]) } if err != nil { return false, err } return true, nil }
func (c *ClientConn) writeError(e error) error { var m *mysql.SqlError var ok bool if m, ok = e.(*mysql.SqlError); !ok { m = mysql.NewError(mysql.ER_UNKNOWN_ERROR, e.Error()) } data := make([]byte, 4, 16+len(m.Message)) data = append(data, mysql.ERR_HEADER) data = append(data, byte(m.Code), byte(m.Code>>8)) if c.capability&mysql.CLIENT_PROTOCOL_41 > 0 { data = append(data, '#') data = append(data, m.State...) } data = append(data, m.Message...) return c.writePacket(data) }
func (c *ClientConn) dispatch(data []byte) error { cmd := data[0] data = data[1:] switch cmd { case mysql.COM_QUIT: c.Close() return nil case mysql.COM_QUERY: return c.handleQuery(hack.String(data)) case mysql.COM_PING: return c.writeOK(nil) case mysql.COM_INIT_DB: if err := c.useDB(hack.String(data)); err != nil { return err } else { return c.writeOK(nil) } case mysql.COM_FIELD_LIST: return c.handleFieldList(data) case mysql.COM_STMT_PREPARE: return c.handleStmtPrepare(hack.String(data)) case mysql.COM_STMT_EXECUTE: return c.handleStmtExecute(data) case mysql.COM_STMT_CLOSE: return c.handleStmtClose(data) case mysql.COM_STMT_SEND_LONG_DATA: return c.handleStmtSendLongData(data) case mysql.COM_STMT_RESET: return c.handleStmtReset(data) default: msg := fmt.Sprintf("command %d not supported now", cmd) return mysql.NewError(mysql.ER_UNKNOWN_ERROR, msg) } return nil }
func (c *ClientConn) handleStmtExecute(data []byte) error { if len(data) < 9 { return mysql.ErrMalformPacket } pos := 0 id := binary.LittleEndian.Uint32(data[0:4]) pos += 4 s, ok := c.stmts[id] if !ok { return mysql.NewDefaultError(mysql.ER_UNKNOWN_STMT_HANDLER, strconv.FormatUint(uint64(id), 10), "stmt_execute") } flag := data[pos] pos++ //now we only support CURSOR_TYPE_NO_CURSOR flag if flag != 0 { return mysql.NewError(mysql.ER_UNKNOWN_ERROR, fmt.Sprintf("unsupported flag %d", flag)) } //skip iteration-count, always 1 pos += 4 var nullBitmaps []byte var paramTypes []byte var paramValues []byte paramNum := s.params if paramNum > 0 { nullBitmapLen := (s.params + 7) >> 3 if len(data) < (pos + nullBitmapLen + 1) { return mysql.ErrMalformPacket } nullBitmaps = data[pos : pos+nullBitmapLen] pos += nullBitmapLen //new param bound flag if data[pos] == 1 { pos++ if len(data) < (pos + (paramNum << 1)) { return mysql.ErrMalformPacket } paramTypes = data[pos : pos+(paramNum<<1)] pos += (paramNum << 1) paramValues = data[pos:] } if err := c.bindStmtArgs(s, nullBitmaps, paramTypes, paramValues); err != nil { return err } } var err error switch stmt := s.s.(type) { case *sqlparser.Select: err = c.handlePrepareSelect(stmt, s.sql, s.args) case *sqlparser.Insert: err = c.handlePrepareExec(s.s, s.sql, s.args) case *sqlparser.Update: err = c.handlePrepareExec(s.s, s.sql, s.args) case *sqlparser.Delete: err = c.handlePrepareExec(s.s, s.sql, s.args) case *sqlparser.Replace: err = c.handlePrepareExec(s.s, s.sql, s.args) default: err = fmt.Errorf("command %T not supported now", stmt) } s.ResetParams() return err }