Skip to content

Commit

Permalink
server: Improve example (go-mysql-org#936)
Browse files Browse the repository at this point in the history
* server: Improve example

1. Use the example from the `README.md` and turn it into
   a `go-mysqlserver` binary that users can run.
2. Add more logging to make it easier to understand what it is doing.
   This is done both in `go-mysqlserver` as well as the `EmptyHandler`
3. Remove the `server/example` as we already have a example now.
4. Support the minimal set of queries that MySQL Shell `mysqlsh` needs
   to be able to connect. (tested with MySQL Shell 9.1.0)
5. Change the default version from 5.7.0 to 8.0.11 (first 8.0 GA
   version)

* Update server/command.go

Co-authored-by: lance6716 <[email protected]>

* Update based on review

---------

Co-authored-by: lance6716 <[email protected]>
  • Loading branch information
dveeden and lance6716 authored Oct 28, 2024
1 parent 5ad36fa commit 5acb569
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 57 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ build:
${GO} build -o bin/go-mysqldump cmd/go-mysqldump/main.go
${GO} build -o bin/go-canal cmd/go-canal/main.go
${GO} build -o bin/go-binlogparser cmd/go-binlogparser/main.go
${GO} build -o bin/go-mysqlserver cmd/go-mysqlserver/main.go

test:
${GO} test --race -timeout 2m ./...
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,6 @@ func main() {
}
}
}

```

Another shell
Expand Down
42 changes: 42 additions & 0 deletions cmd/go-mysqlserver/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package main

import (
"log"
"net"

"github.com/go-mysql-org/go-mysql/server"
)

func main() {
// Listen for connections on localhost port 4000
l, err := net.Listen("tcp", "127.0.0.1:4000")
if err != nil {
log.Fatal(err)
}

log.Println("Listening on port 4000, connect with 'mysql -h 127.0.0.1 -P 4000 -u root'")

// Accept a new connection once
c, err := l.Accept()
if err != nil {
log.Fatal(err)
}

log.Println("Accepted connection")

// Create a connection with user root and an empty password.
// You can use your own handler to handle command here.
conn, err := server.NewConn(c, "root", "", server.EmptyHandler{})
if err != nil {
log.Fatal(err)
}

log.Println("Registered the connection with the server")

// as long as the client keeps sending commands, keep handling them
for {
if err := conn.HandleCommand(); err != nil {
log.Fatal(err)
}
}
}
60 changes: 60 additions & 0 deletions server/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ package server
import (
"bytes"
"fmt"
"log"

"github.com/go-mysql-org/go-mysql/mysql"
. "github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/replication"
"github.com/siddontang/go/hack"
)

// Handler is what a server needs to implement the client-server protocol
type Handler interface {
//handle COM_INIT_DB command, you can check whether the dbName is valid, or other.
UseDB(dbName string) error
Expand All @@ -31,13 +34,16 @@ type Handler interface {
HandleOtherCommand(cmd byte, data []byte) error
}

// ReplicationHandler is for handlers that want to implement the replication protocol
type ReplicationHandler interface {
// handle Replication command
HandleRegisterSlave(data []byte) error
HandleBinlogDump(pos Position) (*replication.BinlogStreamer, error)
HandleBinlogDumpGTID(gtidSet *MysqlGTIDSet) (*replication.BinlogStreamer, error)
}

// HandleCommand is handling commands received by the server
// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_command_phase.html
func (c *Conn) HandleCommand() error {
if c.Conn == nil {
return fmt.Errorf("connection closed")
Expand Down Expand Up @@ -178,47 +184,101 @@ func (c *Conn) dispatch(data []byte) interface{} {
}
}

// EmptyHandler is a mostly empty implementation for demonstration purposes
type EmptyHandler struct {
}

// EmptyReplicationHandler is a empty handler that implements the replication protocol
type EmptyReplicationHandler struct {
EmptyHandler
}

// UseDB is called for COM_INIT_DB
func (h EmptyHandler) UseDB(dbName string) error {
log.Printf("Received: UseDB %s", dbName)
return nil
}

// HandleQuery is called for COM_QUERY
func (h EmptyHandler) HandleQuery(query string) (*Result, error) {
log.Printf("Received: Query: %s", query)

// These two queries are implemented for minimal support for MySQL Shell
if query == `SET NAMES 'utf8mb4';` {
return nil, nil
}
if query == `select concat(@@version, ' ', @@version_comment)` {
r, err := mysql.BuildSimpleResultset([]string{"concat(@@version, ' ', @@version_comment)"}, [][]interface{}{
{"8.0.11"},
}, false)
if err != nil {
return nil, err
}
return &mysql.Result{
Status: 0,
Warnings: 0,
InsertId: 0,
AffectedRows: 0,
Resultset: r,
}, nil
}

return nil, fmt.Errorf("not supported now")
}

// HandleFieldList is called for COM_FIELD_LIST packets
// Note that COM_FIELD_LIST has been deprecated since MySQL 5.7.11
// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_field_list.html
func (h EmptyHandler) HandleFieldList(table string, fieldWildcard string) ([]*Field, error) {
log.Printf("Received: FieldList: table=%s, fieldWildcard:%s", table, fieldWildcard)
return nil, fmt.Errorf("not supported now")
}

// HandleStmtPrepare is called for COM_STMT_PREPARE
func (h EmptyHandler) HandleStmtPrepare(query string) (int, int, interface{}, error) {
log.Printf("Received: StmtPrepare: %s", query)
return 0, 0, nil, fmt.Errorf("not supported now")
}

// 'context' isn't used but replacing it with `_` would remove important information for who
// wants to extend this later.
//revive:disable:unused-parameter

// HandleStmtExecute is called for COM_STMT_EXECUTE
func (h EmptyHandler) HandleStmtExecute(context interface{}, query string, args []interface{}) (*Result, error) {
log.Printf("Received: StmtExecute: %s (args: %v)", query, args)
return nil, fmt.Errorf("not supported now")
}

// HandleStmtClose is called for COM_STMT_CLOSE
func (h EmptyHandler) HandleStmtClose(context interface{}) error {
log.Println("Received: StmtClose")
return nil
}

//revive:enable:unused-parameter

// HandleRegisterSlave is called for COM_REGISTER_SLAVE
func (h EmptyReplicationHandler) HandleRegisterSlave(data []byte) error {
log.Printf("Received: RegisterSlave: %x", data)
return fmt.Errorf("not supported now")
}

// HandleBinlogDump is called for COM_BINLOG_DUMP (non-GTID)
func (h EmptyReplicationHandler) HandleBinlogDump(pos Position) (*replication.BinlogStreamer, error) {
log.Printf("Received: BinlogDump: pos=%s", pos.String())
return nil, fmt.Errorf("not supported now")
}

// HandleBinlogDumpGTID is called for COM_BINLOG_DUMP_GTID
func (h EmptyReplicationHandler) HandleBinlogDumpGTID(gtidSet *MysqlGTIDSet) (*replication.BinlogStreamer, error) {
log.Printf("Received: BinlogDumpGTID: gtidSet=%s", gtidSet.String())
return nil, fmt.Errorf("not supported now")
}

// HandleOtherCommand is called for commands not handled elsewhere
func (h EmptyHandler) HandleOtherCommand(cmd byte, data []byte) error {
log.Printf("Received: OtherCommand: cmd=%x, data=%x", cmd, data)
return NewError(
ER_UNKNOWN_ERROR,
fmt.Sprintf("command %d is not supported now", cmd),
Expand Down
55 changes: 0 additions & 55 deletions server/example/server_example.go

This file was deleted.

2 changes: 1 addition & 1 deletion server/server_conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func NewDefaultServer() *Server {
certPem, keyPem := generateAndSignRSACerts(caPem, caKey)
tlsConf := NewServerTLSConfig(caPem, certPem, keyPem, tls.VerifyClientCertIfGiven)
return &Server{
serverVersion: "5.7.0",
serverVersion: "8.0.11",
protocolVersion: 10,
capability: CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | CLIENT_PROTOCOL_41 |
CLIENT_TRANSACTIONS | CLIENT_SECURE_CONNECTION | CLIENT_PLUGIN_AUTH | CLIENT_SSL | CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA,
Expand Down

0 comments on commit 5acb569

Please sign in to comment.