Skip to content

Commit 5acb569

Browse files
dveedenlance6716
andauthoredOct 28, 2024··
server: Improve example (#936)
* 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]>
1 parent 5ad36fa commit 5acb569

File tree

6 files changed

+104
-57
lines changed

6 files changed

+104
-57
lines changed
 

‎Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ build:
99
${GO} build -o bin/go-mysqldump cmd/go-mysqldump/main.go
1010
${GO} build -o bin/go-canal cmd/go-canal/main.go
1111
${GO} build -o bin/go-binlogparser cmd/go-binlogparser/main.go
12+
${GO} build -o bin/go-mysqlserver cmd/go-mysqlserver/main.go
1213

1314
test:
1415
${GO} test --race -timeout 2m ./...

‎README.md

-1
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,6 @@ func main() {
305305
}
306306
}
307307
}
308-
309308
```
310309

311310
Another shell

‎cmd/go-mysqlserver/main.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"net"
6+
7+
"github.com/go-mysql-org/go-mysql/server"
8+
)
9+
10+
func main() {
11+
// Listen for connections on localhost port 4000
12+
l, err := net.Listen("tcp", "127.0.0.1:4000")
13+
if err != nil {
14+
log.Fatal(err)
15+
}
16+
17+
log.Println("Listening on port 4000, connect with 'mysql -h 127.0.0.1 -P 4000 -u root'")
18+
19+
// Accept a new connection once
20+
c, err := l.Accept()
21+
if err != nil {
22+
log.Fatal(err)
23+
}
24+
25+
log.Println("Accepted connection")
26+
27+
// Create a connection with user root and an empty password.
28+
// You can use your own handler to handle command here.
29+
conn, err := server.NewConn(c, "root", "", server.EmptyHandler{})
30+
if err != nil {
31+
log.Fatal(err)
32+
}
33+
34+
log.Println("Registered the connection with the server")
35+
36+
// as long as the client keeps sending commands, keep handling them
37+
for {
38+
if err := conn.HandleCommand(); err != nil {
39+
log.Fatal(err)
40+
}
41+
}
42+
}

‎server/command.go

+60
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ package server
33
import (
44
"bytes"
55
"fmt"
6+
"log"
67

8+
"github.com/go-mysql-org/go-mysql/mysql"
79
. "github.com/go-mysql-org/go-mysql/mysql"
810
"github.com/go-mysql-org/go-mysql/replication"
911
"github.com/siddontang/go/hack"
1012
)
1113

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

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

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

187+
// EmptyHandler is a mostly empty implementation for demonstration purposes
181188
type EmptyHandler struct {
182189
}
183190

191+
// EmptyReplicationHandler is a empty handler that implements the replication protocol
184192
type EmptyReplicationHandler struct {
185193
EmptyHandler
186194
}
187195

196+
// UseDB is called for COM_INIT_DB
188197
func (h EmptyHandler) UseDB(dbName string) error {
198+
log.Printf("Received: UseDB %s", dbName)
189199
return nil
190200
}
201+
202+
// HandleQuery is called for COM_QUERY
191203
func (h EmptyHandler) HandleQuery(query string) (*Result, error) {
204+
log.Printf("Received: Query: %s", query)
205+
206+
// These two queries are implemented for minimal support for MySQL Shell
207+
if query == `SET NAMES 'utf8mb4';` {
208+
return nil, nil
209+
}
210+
if query == `select concat(@@version, ' ', @@version_comment)` {
211+
r, err := mysql.BuildSimpleResultset([]string{"concat(@@version, ' ', @@version_comment)"}, [][]interface{}{
212+
{"8.0.11"},
213+
}, false)
214+
if err != nil {
215+
return nil, err
216+
}
217+
return &mysql.Result{
218+
Status: 0,
219+
Warnings: 0,
220+
InsertId: 0,
221+
AffectedRows: 0,
222+
Resultset: r,
223+
}, nil
224+
}
225+
192226
return nil, fmt.Errorf("not supported now")
193227
}
194228

229+
// HandleFieldList is called for COM_FIELD_LIST packets
230+
// Note that COM_FIELD_LIST has been deprecated since MySQL 5.7.11
231+
// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_field_list.html
195232
func (h EmptyHandler) HandleFieldList(table string, fieldWildcard string) ([]*Field, error) {
233+
log.Printf("Received: FieldList: table=%s, fieldWildcard:%s", table, fieldWildcard)
196234
return nil, fmt.Errorf("not supported now")
197235
}
236+
237+
// HandleStmtPrepare is called for COM_STMT_PREPARE
198238
func (h EmptyHandler) HandleStmtPrepare(query string) (int, int, interface{}, error) {
239+
log.Printf("Received: StmtPrepare: %s", query)
199240
return 0, 0, nil, fmt.Errorf("not supported now")
200241
}
242+
243+
// 'context' isn't used but replacing it with `_` would remove important information for who
244+
// wants to extend this later.
245+
//revive:disable:unused-parameter
246+
247+
// HandleStmtExecute is called for COM_STMT_EXECUTE
201248
func (h EmptyHandler) HandleStmtExecute(context interface{}, query string, args []interface{}) (*Result, error) {
249+
log.Printf("Received: StmtExecute: %s (args: %v)", query, args)
202250
return nil, fmt.Errorf("not supported now")
203251
}
204252

253+
// HandleStmtClose is called for COM_STMT_CLOSE
205254
func (h EmptyHandler) HandleStmtClose(context interface{}) error {
255+
log.Println("Received: StmtClose")
206256
return nil
207257
}
208258

259+
//revive:enable:unused-parameter
260+
261+
// HandleRegisterSlave is called for COM_REGISTER_SLAVE
209262
func (h EmptyReplicationHandler) HandleRegisterSlave(data []byte) error {
263+
log.Printf("Received: RegisterSlave: %x", data)
210264
return fmt.Errorf("not supported now")
211265
}
212266

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

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

279+
// HandleOtherCommand is called for commands not handled elsewhere
221280
func (h EmptyHandler) HandleOtherCommand(cmd byte, data []byte) error {
281+
log.Printf("Received: OtherCommand: cmd=%x, data=%x", cmd, data)
222282
return NewError(
223283
ER_UNKNOWN_ERROR,
224284
fmt.Sprintf("command %d is not supported now", cmd),

‎server/example/server_example.go

-55
This file was deleted.

‎server/server_conf.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func NewDefaultServer() *Server {
4848
certPem, keyPem := generateAndSignRSACerts(caPem, caKey)
4949
tlsConf := NewServerTLSConfig(caPem, certPem, keyPem, tls.VerifyClientCertIfGiven)
5050
return &Server{
51-
serverVersion: "5.7.0",
51+
serverVersion: "8.0.11",
5252
protocolVersion: 10,
5353
capability: CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | CLIENT_PROTOCOL_41 |
5454
CLIENT_TRANSACTIONS | CLIENT_SECURE_CONNECTION | CLIENT_PLUGIN_AUTH | CLIENT_SSL | CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA,

0 commit comments

Comments
 (0)
Please sign in to comment.