From 18f5bc75fa15cece572d5ebea16fd8fb80238455 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Tue, 13 Dec 2022 16:31:43 -0800 Subject: [PATCH 01/23] Adding a gms.Engine reference to the server.Server struct so we can access the engine to start the binlog replication process --- server/server.go | 1 + server/server_config.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/server/server.go b/server/server.go index c84f202bd6..570e11e6ed 100644 --- a/server/server.go +++ b/server/server.go @@ -126,6 +126,7 @@ func newServerFromHandler(cfg Config, e *sqle.Engine, sm *SessionManager, handle Listener: vtListnr, handler: handler, sessionMgr: sm, + Engine: e, }, unixSocketInUse } diff --git a/server/server_config.go b/server/server_config.go index d60256b7bb..892edb8968 100644 --- a/server/server_config.go +++ b/server/server_config.go @@ -21,6 +21,7 @@ import ( "github.com/dolthub/vitess/go/mysql" "go.opentelemetry.io/otel/trace" + gms "github.com/dolthub/go-mysql-server" "github.com/dolthub/go-mysql-server/sql" ) @@ -29,6 +30,7 @@ type Server struct { Listener *mysql.Listener handler mysql.Handler sessionMgr *SessionManager + Engine *gms.Engine } // Config for the mysql server. From aa9ccbca4a5085ec45dcf4c0226d1ff81b740f94 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Mon, 19 Dec 2022 12:05:57 -0800 Subject: [PATCH 02/23] Updating vitess dependency tip of fulghum/binlog-replication dev branch, to pick up replication statement support. --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2162dede9b..e09cb5315d 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/dolthub/go-mysql-server require ( github.com/cespare/xxhash v1.1.0 github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 - github.com/dolthub/vitess v0.0.0-20221208232832-f808d282d629 + github.com/dolthub/vitess v0.0.0-20221219195828-63e6813c39c5 github.com/go-kit/kit v0.10.0 github.com/go-sql-driver/mysql v1.6.0 github.com/gocraft/dbr/v2 v2.7.2 diff --git a/go.sum b/go.sum index 72a24042fb..e2dffca186 100755 --- a/go.sum +++ b/go.sum @@ -67,6 +67,8 @@ github.com/dolthub/vitess v0.0.0-20221207133502-c06d5b3ad108 h1:TeEEz218PqQBsymp github.com/dolthub/vitess v0.0.0-20221207133502-c06d5b3ad108/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= github.com/dolthub/vitess v0.0.0-20221208232832-f808d282d629 h1:U1g143z8/cRhPiAfiWic7gpf+LEu+pgdawJXKWl347c= github.com/dolthub/vitess v0.0.0-20221208232832-f808d282d629/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= +github.com/dolthub/vitess v0.0.0-20221219195828-63e6813c39c5 h1:B/qFPTTBApEbjv5A48TxndG+dvrTfkWoikHv+KlmLIY= +github.com/dolthub/vitess v0.0.0-20221219195828-63e6813c39c5/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= From 6a5cf4f62774f0cfbc1078bc71ba8f5f221e03c4 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Mon, 19 Dec 2022 12:05:57 -0800 Subject: [PATCH 03/23] Updating vitess dependency tip of fulghum/binlog-replication dev branch, to pick up replication statement support. --- go.mod | 2 +- go.sum | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2162dede9b..cbe0b77507 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/dolthub/go-mysql-server require ( github.com/cespare/xxhash v1.1.0 github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 - github.com/dolthub/vitess v0.0.0-20221208232832-f808d282d629 + github.com/dolthub/vitess v0.0.0-20221219201541-7a5989011eee github.com/go-kit/kit v0.10.0 github.com/go-sql-driver/mysql v1.6.0 github.com/gocraft/dbr/v2 v2.7.2 diff --git a/go.sum b/go.sum index 72a24042fb..ee112df2f3 100755 --- a/go.sum +++ b/go.sum @@ -67,6 +67,10 @@ github.com/dolthub/vitess v0.0.0-20221207133502-c06d5b3ad108 h1:TeEEz218PqQBsymp github.com/dolthub/vitess v0.0.0-20221207133502-c06d5b3ad108/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= github.com/dolthub/vitess v0.0.0-20221208232832-f808d282d629 h1:U1g143z8/cRhPiAfiWic7gpf+LEu+pgdawJXKWl347c= github.com/dolthub/vitess v0.0.0-20221208232832-f808d282d629/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= +github.com/dolthub/vitess v0.0.0-20221219195828-63e6813c39c5 h1:B/qFPTTBApEbjv5A48TxndG+dvrTfkWoikHv+KlmLIY= +github.com/dolthub/vitess v0.0.0-20221219195828-63e6813c39c5/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= +github.com/dolthub/vitess v0.0.0-20221219201541-7a5989011eee h1:1OSVD9PGbuM9YQVAW35vOEr9ea2q4DkoQCjmcQiZGkM= +github.com/dolthub/vitess v0.0.0-20221219201541-7a5989011eee/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= From 3ce1391225a76b64a540c90a57c43f2b3f86dee8 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Mon, 19 Dec 2022 13:58:13 -0800 Subject: [PATCH 04/23] First pass on replication plan nodes --- sql/parse/parse.go | 14 +++ sql/plan/binlog_replication.go | 179 +++++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 sql/plan/binlog_replication.go diff --git a/sql/parse/parse.go b/sql/parse/parse.go index 8a37e2d55e..a4be689749 100644 --- a/sql/parse/parse.go +++ b/sql/parse/parse.go @@ -202,6 +202,12 @@ func convert(ctx *sql.Context, stmt sqlparser.Statement, query string) (sql.Node return plan.NewRollbackSavepoint("", n.Identifier), nil case *sqlparser.ReleaseSavepoint: return plan.NewReleaseSavepoint("", n.Identifier), nil + case *sqlparser.ChangeReplicationSource: + return convertChangeReplicationSource(n) + case *sqlparser.StartReplica: + return plan.NewStartReplica(), nil + case *sqlparser.StopReplica: + return plan.NewStopReplica(), nil case *sqlparser.BeginEndBlock: return convertBeginEndBlock(ctx, n, query) case *sqlparser.IfStatement: @@ -442,6 +448,14 @@ func convertSet(ctx *sql.Context, n *sqlparser.Set) (sql.Node, error) { return plan.NewSet(exprs), nil } +func convertChangeReplicationSource(n *sqlparser.ChangeReplicationSource) (sql.Node, error) { + convertedOptions := make([]plan.ReplicationOption, 0, len(n.Options)) + for _, option := range n.Options { + convertedOptions = append(convertedOptions, plan.NewReplicationOption(option.Name, option.Value)) + } + return plan.NewChangeReplicationSource(convertedOptions), nil +} + func isSetNames(exprs sqlparser.SetVarExprs) bool { if len(exprs) != 1 { return false diff --git a/sql/plan/binlog_replication.go b/sql/plan/binlog_replication.go new file mode 100644 index 0000000000..94b315d3ba --- /dev/null +++ b/sql/plan/binlog_replication.go @@ -0,0 +1,179 @@ +// Copyright 2022 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package plan + +import ( + "fmt" + "github.com/dolthub/go-mysql-server/sql" + "strings" +) + +type ReplicationOption struct { + Name string + Value string +} + +func NewReplicationOption(name string, value string) ReplicationOption { + return ReplicationOption{ + Name: name, + Value: value, + } +} + +// ChangeReplicationSource is the plan node for the "CHANGE REPLICATION SOURCE TO" statement. +// https://dev.mysql.com/doc/refman/8.0/en/change-replication-source-to.html +type ChangeReplicationSource struct { + Options []ReplicationOption +} + +var _ sql.Node = (*ChangeReplicationSource)(nil) + +func NewChangeReplicationSource(options []ReplicationOption) *ChangeReplicationSource { + return &ChangeReplicationSource{ + Options: options, + } +} + +func (c *ChangeReplicationSource) Resolved() bool { + return true +} + +func (c *ChangeReplicationSource) String() string { + sb := strings.Builder{} + sb.WriteString("CHANGE REPLICATION SOURCE TO ") + for i, option := range c.Options { + if i > 0 { + sb.WriteString(", ") + } + sb.WriteString(option.Name) + sb.WriteString(" = ") + sb.WriteString(option.Value) + } + return sb.String() +} + +func (c *ChangeReplicationSource) Schema() sql.Schema { + return nil +} + +func (c *ChangeReplicationSource) Children() []sql.Node { + return nil +} + +func (c *ChangeReplicationSource) RowIter(_ *sql.Context, _ sql.Row) (sql.RowIter, error) { + return nil, fmt.Errorf("replication statements not supported") +} + +func (c *ChangeReplicationSource) WithChildren(children ...sql.Node) (sql.Node, error) { + if len(children) != 0 { + return nil, sql.ErrInvalidChildrenNumber.New(c, len(children), 0) + } + + newNode := *c + return &newNode, nil +} + +func (c *ChangeReplicationSource) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperationChecker) bool { + // TODO: implement privilege checks + return true +} + +// StartReplica is a plan node for the "START REPLICA" statement. +// https://dev.mysql.com/doc/refman/8.0/en/start-replica.html +type StartReplica struct{} + +var _ sql.Node = (*StartReplica)(nil) + +func NewStartReplica() *StartReplica { + return &StartReplica{} +} + +func (s *StartReplica) Resolved() bool { + return true +} + +func (s *StartReplica) String() string { + return "START REPLICA" +} + +func (s *StartReplica) Schema() sql.Schema { + return nil +} + +func (s *StartReplica) Children() []sql.Node { + return nil +} + +func (s *StartReplica) RowIter(_ *sql.Context, _ sql.Row) (sql.RowIter, error) { + return nil, fmt.Errorf("replication statements not supported") +} + +func (s *StartReplica) WithChildren(children ...sql.Node) (sql.Node, error) { + if len(children) != 0 { + return nil, sql.ErrInvalidChildrenNumber.New(s, len(children), 0) + } + + newNode := *s + return &newNode, nil +} + +func (s StartReplica) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperationChecker) bool { + // TODO: implement privilege checks + return true +} + +// StopReplica is the plan node for the "STOP REPLICA" statement. +// https://dev.mysql.com/doc/refman/8.0/en/stop-replica.html +type StopReplica struct{} + +var _ sql.Node = (*StopReplica)(nil) + +func NewStopReplica() *StopReplica { + return &StopReplica{} +} + +func (s *StopReplica) Resolved() bool { + return true +} + +func (s *StopReplica) String() string { + return "STOP REPLICA" +} + +func (s *StopReplica) Schema() sql.Schema { + return nil +} + +func (s *StopReplica) Children() []sql.Node { + return nil +} + +func (s *StopReplica) RowIter(_ *sql.Context, _ sql.Row) (sql.RowIter, error) { + return nil, fmt.Errorf("replication statements not supported") +} + +func (s *StopReplica) WithChildren(children ...sql.Node) (sql.Node, error) { + if len(children) != 0 { + return nil, sql.ErrInvalidChildrenNumber.New(s, len(children), 0) + } + + newNode := *s + return &newNode, nil +} + +func (s *StopReplica) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperationChecker) bool { + // TODO: implement privilege checks + return true +} From 8afdf588687adc1d10d00d353e60cf48ab5a191a Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Mon, 19 Dec 2022 17:14:08 -0800 Subject: [PATCH 05/23] First pass on the interface to connect Dolt and GMS for binlog replication coordination --- engine.go | 24 +++++++----- sql/plan/binlog_replication.go | 67 +++++++++++++++++++++++++++++----- 2 files changed, 72 insertions(+), 19 deletions(-) diff --git a/engine.go b/engine.go index d0969ed68b..bbee8ecefe 100644 --- a/engine.go +++ b/engine.go @@ -57,15 +57,16 @@ type TemporaryUser struct { // Engine is a SQL engine. type Engine struct { - Analyzer *analyzer.Analyzer - LS *sql.LockSubsystem - ProcessList sql.ProcessList - MemoryManager *sql.MemoryManager - BackgroundThreads *sql.BackgroundThreads - IsReadOnly bool - IsServerLocked bool - PreparedData map[uint32]PreparedData - mu *sync.Mutex + Analyzer *analyzer.Analyzer + LS *sql.LockSubsystem + ProcessList sql.ProcessList + MemoryManager *sql.MemoryManager + BackgroundThreads *sql.BackgroundThreads + IsReadOnly bool + IsServerLocked bool + PreparedData map[uint32]PreparedData + BinlogReplicaController plan.BinlogReplicaController + mu *sync.Mutex } type ColumnWithRawDefault struct { @@ -180,6 +181,11 @@ func (e *Engine) QueryNodeWithBindings( } } + // TODO: This isn't the right place for this, but hacking it in here for now... + if nn, ok := parsed.(plan.BinlogReplicaControllerCommand); ok { + nn.WithBinlogReplicaController(e.BinlogReplicaController) + } + // Before we begin a transaction, we need to know if the database being operated on is not the one // currently selected transactionDatabase := analyzer.GetTransactionDatabase(ctx, parsed) diff --git a/sql/plan/binlog_replication.go b/sql/plan/binlog_replication.go index 94b315d3ba..85857715e0 100644 --- a/sql/plan/binlog_replication.go +++ b/sql/plan/binlog_replication.go @@ -20,6 +20,14 @@ import ( "strings" ) +// TODO: Move this out to a better package +// TODO: error out if sql-server is not running! +type BinlogReplicaController interface { + StartReplica(ctx *sql.Context) error + StopReplica(ctx *sql.Context) error + SetReplicationOptions(ctx *sql.Context, options []ReplicationOption) error +} + type ReplicationOption struct { Name string Value string @@ -32,13 +40,19 @@ func NewReplicationOption(name string, value string) ReplicationOption { } } +type BinlogReplicaControllerCommand interface { + WithBinlogReplicaController(handler BinlogReplicaController) +} + // ChangeReplicationSource is the plan node for the "CHANGE REPLICATION SOURCE TO" statement. // https://dev.mysql.com/doc/refman/8.0/en/change-replication-source-to.html type ChangeReplicationSource struct { - Options []ReplicationOption + Options []ReplicationOption + replicaHandler BinlogReplicaController // TODO: Could type embed something that does this for all the replication types } var _ sql.Node = (*ChangeReplicationSource)(nil) +var _ BinlogReplicaControllerCommand = (*ChangeReplicationSource)(nil) func NewChangeReplicationSource(options []ReplicationOption) *ChangeReplicationSource { return &ChangeReplicationSource{ @@ -46,6 +60,10 @@ func NewChangeReplicationSource(options []ReplicationOption) *ChangeReplicationS } } +func (c *ChangeReplicationSource) WithBinlogReplicaController(handler BinlogReplicaController) { + c.replicaHandler = handler +} + func (c *ChangeReplicationSource) Resolved() bool { return true } @@ -72,8 +90,13 @@ func (c *ChangeReplicationSource) Children() []sql.Node { return nil } -func (c *ChangeReplicationSource) RowIter(_ *sql.Context, _ sql.Row) (sql.RowIter, error) { - return nil, fmt.Errorf("replication statements not supported") +func (c *ChangeReplicationSource) RowIter(ctx *sql.Context, _ sql.Row) (sql.RowIter, error) { + if c.replicaHandler == nil { + return nil, fmt.Errorf("no replication handler available") + } + + err := c.replicaHandler.SetReplicationOptions(ctx, c.Options) + return sql.RowsToRowIter(), err } func (c *ChangeReplicationSource) WithChildren(children ...sql.Node) (sql.Node, error) { @@ -92,14 +115,21 @@ func (c *ChangeReplicationSource) CheckPrivileges(_ *sql.Context, _ sql.Privileg // StartReplica is a plan node for the "START REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/start-replica.html -type StartReplica struct{} +type StartReplica struct { + replicaHandler BinlogReplicaController +} var _ sql.Node = (*StartReplica)(nil) +var _ BinlogReplicaControllerCommand = (*StartReplica)(nil) func NewStartReplica() *StartReplica { return &StartReplica{} } +func (s *StartReplica) WithBinlogReplicaController(handler BinlogReplicaController) { + s.replicaHandler = handler +} + func (s *StartReplica) Resolved() bool { return true } @@ -116,8 +146,13 @@ func (s *StartReplica) Children() []sql.Node { return nil } -func (s *StartReplica) RowIter(_ *sql.Context, _ sql.Row) (sql.RowIter, error) { - return nil, fmt.Errorf("replication statements not supported") +func (s *StartReplica) RowIter(ctx *sql.Context, _ sql.Row) (sql.RowIter, error) { + if s.replicaHandler == nil { + return nil, fmt.Errorf("no replication handler available") + } + + err := s.replicaHandler.StartReplica(ctx) + return sql.RowsToRowIter(), err } func (s *StartReplica) WithChildren(children ...sql.Node) (sql.Node, error) { @@ -129,21 +164,28 @@ func (s *StartReplica) WithChildren(children ...sql.Node) (sql.Node, error) { return &newNode, nil } -func (s StartReplica) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperationChecker) bool { +func (s *StartReplica) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperationChecker) bool { // TODO: implement privilege checks return true } // StopReplica is the plan node for the "STOP REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/stop-replica.html -type StopReplica struct{} +type StopReplica struct { + replicaHandler BinlogReplicaController +} var _ sql.Node = (*StopReplica)(nil) +var _ BinlogReplicaControllerCommand = (*StopReplica)(nil) func NewStopReplica() *StopReplica { return &StopReplica{} } +func (s *StopReplica) WithBinlogReplicaController(handler BinlogReplicaController) { + s.replicaHandler = handler +} + func (s *StopReplica) Resolved() bool { return true } @@ -160,8 +202,13 @@ func (s *StopReplica) Children() []sql.Node { return nil } -func (s *StopReplica) RowIter(_ *sql.Context, _ sql.Row) (sql.RowIter, error) { - return nil, fmt.Errorf("replication statements not supported") +func (s *StopReplica) RowIter(ctx *sql.Context, _ sql.Row) (sql.RowIter, error) { + if s.replicaHandler == nil { + return nil, fmt.Errorf("no replication handler available") + } + + err := s.replicaHandler.StopReplica(ctx) + return sql.RowsToRowIter(), err } func (s *StopReplica) WithChildren(children ...sql.Node) (sql.Node, error) { From 4625c6426ca18e1c942cee037fda241dfa279586 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Tue, 20 Dec 2022 14:08:05 -0800 Subject: [PATCH 06/23] Adding support for `show replica status` and tidying up --- sql/parse/parse.go | 3 + sql/plan/binlog_replication.go | 94 ++++++++++++++++++------ sql/plan/show_replica_status.go | 122 ++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+), 22 deletions(-) create mode 100644 sql/plan/show_replica_status.go diff --git a/sql/parse/parse.go b/sql/parse/parse.go index a4be689749..a8e5770f8e 100644 --- a/sql/parse/parse.go +++ b/sql/parse/parse.go @@ -866,6 +866,9 @@ func convertShow(ctx *sql.Context, s *sqlparser.Show, query string) (sql.Node, e } return node, nil + case "replica status": + return plan.NewShowReplicaStatus(), nil + default: unsupportedShow := fmt.Sprintf("SHOW %s", s.Type) return nil, sql.ErrUnsupportedFeature.New(unsupportedShow) diff --git a/sql/plan/binlog_replication.go b/sql/plan/binlog_replication.go index 85857715e0..8dcb1f2078 100644 --- a/sql/plan/binlog_replication.go +++ b/sql/plan/binlog_replication.go @@ -16,17 +16,67 @@ package plan import ( "fmt" - "github.com/dolthub/go-mysql-server/sql" "strings" + "time" + + "github.com/dolthub/go-mysql-server/sql" ) // TODO: Move this out to a better package // TODO: error out if sql-server is not running! + +// BinlogReplicaController allows callers to control a binlog replica. Providers built on go-mysql-server may optionally +// implement this interface and use it when constructing a SQL engine in order to receive callbacks when replication +// statements (e.g. START REPLICA, SHOW REPLICA STATUS) are being handled. type BinlogReplicaController interface { + // StartReplica tells the binlog replica controller to start up replication processes for the current replication + // configuration. An error is returned if replication was unable to be started. Note the error response only signals + // whether there was a problem with the initial replication start up. Replication could fail after being started up + // successfully with no error response returned. StartReplica(ctx *sql.Context) error + + // StopReplica tells the binlog replica controller to stop all replication processes. An error is returned if there + // were any problems stopping replication. If no replication processes were running, no error is returned. StopReplica(ctx *sql.Context) error + + // SetReplicationOptions configures the binlog replica controller with the specified options. The replica controller + // must store this configuration. If any errors are encountered processing and storing the configuration options, an + // error is returned. SetReplicationOptions(ctx *sql.Context, options []ReplicationOption) error -} + + // GetReplicaStatus returns the current status of the replica, or nil if no replication processes are running. If + // any problems are encountered assembling the replica's status, an error is returned. + GetReplicaStatus(ctx *sql.Context) (*ReplicaStatus, error) +} + +// ReplicaStatus stores the status of a single binlog replica and is returned by `SHOW REPLICA STATUS`. +// https://dev.mysql.com/doc/refman/8.0/en/show-replica-status.html +type ReplicaStatus struct { + SourceHost string + SourceUser string + SourcePort uint + ReplicaIoRunning string + ReplicaSqlRunning string + LastSqlErrNumber string // Alias for LastErrNumber + LastSqlError string // Alias for LastError + LastIoErrNumber string + LastIoError string + SourceServerId string + SourceServerUuid string + LastSqlErrorTimestamp time.Time + LastIoErrorTimestamp time.Time + RetrievedGtidSet string + ExecutedGtidSet string + AutoPosition bool +} + +const ( + ReplicaIoNotRunning = "No" + ReplicaIoConnecting = "Connecting" + ReplicaIoRunning = "Yes" + ReplicaSqlNotRunning = "No" + ReplicaSqlRunning = "Yes" +) type ReplicationOption struct { Name string @@ -41,14 +91,14 @@ func NewReplicationOption(name string, value string) ReplicationOption { } type BinlogReplicaControllerCommand interface { - WithBinlogReplicaController(handler BinlogReplicaController) + WithBinlogReplicaController(controller BinlogReplicaController) } // ChangeReplicationSource is the plan node for the "CHANGE REPLICATION SOURCE TO" statement. // https://dev.mysql.com/doc/refman/8.0/en/change-replication-source-to.html type ChangeReplicationSource struct { - Options []ReplicationOption - replicaHandler BinlogReplicaController // TODO: Could type embed something that does this for all the replication types + Options []ReplicationOption + replicaController BinlogReplicaController // TODO: Could type embed something that does this for all the replication types } var _ sql.Node = (*ChangeReplicationSource)(nil) @@ -60,8 +110,8 @@ func NewChangeReplicationSource(options []ReplicationOption) *ChangeReplicationS } } -func (c *ChangeReplicationSource) WithBinlogReplicaController(handler BinlogReplicaController) { - c.replicaHandler = handler +func (c *ChangeReplicationSource) WithBinlogReplicaController(controller BinlogReplicaController) { + c.replicaController = controller } func (c *ChangeReplicationSource) Resolved() bool { @@ -91,11 +141,11 @@ func (c *ChangeReplicationSource) Children() []sql.Node { } func (c *ChangeReplicationSource) RowIter(ctx *sql.Context, _ sql.Row) (sql.RowIter, error) { - if c.replicaHandler == nil { - return nil, fmt.Errorf("no replication handler available") + if c.replicaController == nil { + return nil, fmt.Errorf("no replication controller available") } - err := c.replicaHandler.SetReplicationOptions(ctx, c.Options) + err := c.replicaController.SetReplicationOptions(ctx, c.Options) return sql.RowsToRowIter(), err } @@ -116,7 +166,7 @@ func (c *ChangeReplicationSource) CheckPrivileges(_ *sql.Context, _ sql.Privileg // StartReplica is a plan node for the "START REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/start-replica.html type StartReplica struct { - replicaHandler BinlogReplicaController + replicaController BinlogReplicaController } var _ sql.Node = (*StartReplica)(nil) @@ -126,8 +176,8 @@ func NewStartReplica() *StartReplica { return &StartReplica{} } -func (s *StartReplica) WithBinlogReplicaController(handler BinlogReplicaController) { - s.replicaHandler = handler +func (s *StartReplica) WithBinlogReplicaController(controller BinlogReplicaController) { + s.replicaController = controller } func (s *StartReplica) Resolved() bool { @@ -147,11 +197,11 @@ func (s *StartReplica) Children() []sql.Node { } func (s *StartReplica) RowIter(ctx *sql.Context, _ sql.Row) (sql.RowIter, error) { - if s.replicaHandler == nil { - return nil, fmt.Errorf("no replication handler available") + if s.replicaController == nil { + return nil, fmt.Errorf("no replication controller available") } - err := s.replicaHandler.StartReplica(ctx) + err := s.replicaController.StartReplica(ctx) return sql.RowsToRowIter(), err } @@ -172,7 +222,7 @@ func (s *StartReplica) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperation // StopReplica is the plan node for the "STOP REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/stop-replica.html type StopReplica struct { - replicaHandler BinlogReplicaController + replicaController BinlogReplicaController } var _ sql.Node = (*StopReplica)(nil) @@ -182,8 +232,8 @@ func NewStopReplica() *StopReplica { return &StopReplica{} } -func (s *StopReplica) WithBinlogReplicaController(handler BinlogReplicaController) { - s.replicaHandler = handler +func (s *StopReplica) WithBinlogReplicaController(controller BinlogReplicaController) { + s.replicaController = controller } func (s *StopReplica) Resolved() bool { @@ -203,11 +253,11 @@ func (s *StopReplica) Children() []sql.Node { } func (s *StopReplica) RowIter(ctx *sql.Context, _ sql.Row) (sql.RowIter, error) { - if s.replicaHandler == nil { - return nil, fmt.Errorf("no replication handler available") + if s.replicaController == nil { + return nil, fmt.Errorf("no replication controller available") } - err := s.replicaHandler.StopReplica(ctx) + err := s.replicaController.StopReplica(ctx) return sql.RowsToRowIter(), err } diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go new file mode 100644 index 0000000000..d6151f9527 --- /dev/null +++ b/sql/plan/show_replica_status.go @@ -0,0 +1,122 @@ +// Copyright 2022 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package plan + +import ( + "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/vitess/go/sqltypes" +) + +// TODO: Consider an embeddable type +type ShowReplicaStatus struct { + replicaController BinlogReplicaController +} + +var _ sql.Node = (*ShowReplicaStatus)(nil) +var _ BinlogReplicaControllerCommand = (*ShowReplicaStatus)(nil) + +func NewShowReplicaStatus() *ShowReplicaStatus { + return &ShowReplicaStatus{} +} + +func (s *ShowReplicaStatus) WithBinlogReplicaController(controller BinlogReplicaController) { + s.replicaController = controller +} + +func (s *ShowReplicaStatus) Resolved() bool { + return true +} + +func (s *ShowReplicaStatus) String() string { + return "SHOW REPLICA STATUS" +} + +func (s *ShowReplicaStatus) Schema() sql.Schema { + return sql.Schema{ + {Name: "Source_Host", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_User", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Source_Port", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Replica_IO_Running", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Replica_SQL_Running", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Last_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Last_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Last_IO_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Last_IO_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Last_SQL_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Last_SQL_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Source_Server_Id", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Source_UUID", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Last_IO_Error_Timestamp", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Last_SQL_Error_Timestamp", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Retrieved_Gtid_Set", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Executed_Gtid_Set", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Auto_Position", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + } +} + +func (s *ShowReplicaStatus) Children() []sql.Node { + return nil +} + +func (s *ShowReplicaStatus) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { + if s.replicaController == nil { + return sql.RowsToRowIter(), nil + } + + status, err := s.replicaController.GetReplicaStatus(ctx) + if err != nil { + return nil, err + } + if status == nil { + return sql.RowsToRowIter(), nil + } + + row = sql.Row{ + status.SourceHost, + status.SourceUser, + status.SourcePort, + status.ReplicaIoRunning, + status.ReplicaSqlRunning, + status.LastSqlErrNumber, + status.LastSqlError, + status.LastIoErrNumber, + status.LastIoError, + status.LastSqlErrNumber, + status.LastSqlError, + status.SourceServerId, + status.SourceServerUuid, + status.LastSqlErrorTimestamp, + status.LastIoErrorTimestamp, + status.RetrievedGtidSet, + status.ExecutedGtidSet, + status.AutoPosition, + } + + return sql.RowsToRowIter(row), nil +} + +func (s *ShowReplicaStatus) WithChildren(children ...sql.Node) (sql.Node, error) { + if len(children) != 0 { + return nil, sql.ErrInvalidChildrenNumber.New(s, len(children), 0) + } + + newNode := *s + return &newNode, nil +} + +func (s *ShowReplicaStatus) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperationChecker) bool { + // TODO: Implement privilege support + return true +} From af7669ede3ecc37cd40a3fa2738918e8716d7264 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 21 Dec 2022 16:11:50 -0800 Subject: [PATCH 07/23] Adding the rest of the `show replica status` fields to schema and output --- sql/plan/show_replica_status.go | 148 ++++++++++++++++++++++++-------- 1 file changed, 112 insertions(+), 36 deletions(-) diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go index d6151f9527..7483682c66 100644 --- a/sql/plan/show_replica_status.go +++ b/sql/plan/show_replica_status.go @@ -19,8 +19,10 @@ import ( "github.com/dolthub/vitess/go/sqltypes" ) -// TODO: Consider an embeddable type +// ShowReplicaStatus is the plan node for the "SHOW REPLICA STATUS" statement. +// https://dev.mysql.com/doc/refman/8.0/en/show-replica-status.html type ShowReplicaStatus struct { + // TODO: Consider an embeddable type for this replicaController BinlogReplicaController } @@ -45,24 +47,61 @@ func (s *ShowReplicaStatus) String() string { func (s *ShowReplicaStatus) Schema() sql.Schema { return sql.Schema{ + {Name: "Replica_IO_State", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, {Name: "Source_Host", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_User", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Source_Port", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Replica_IO_Running", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Replica_SQL_Running", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Last_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Last_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Last_IO_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Last_IO_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Last_SQL_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Last_SQL_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Source_Server_Id", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Source_UUID", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Last_IO_Error_Timestamp", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Last_SQL_Error_Timestamp", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Retrieved_Gtid_Set", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Executed_Gtid_Set", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, - {Name: "Auto_Position", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2048), Default: nil, Nullable: false}, + {Name: "Source_User", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Port", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Connect_Retry", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Log_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Read_Source_Log_Pos", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Relay_Log_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Relay_Log_Pos", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Relay_Source_Log_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Replica_IO_Running", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replica_SQL_Running", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replicate_Do_DB", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replicate_Ignore_DB", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replicate_Do_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replicate_Ignore_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replicate_Wild_Do_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replicate_Wild_Ignore_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Last_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Skip_Counter", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Exec_Source_Log_Pos", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Relay_Log_Space", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Until_Condition", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Until_Log_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Until_Log_Pos", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_Allowed", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_CA_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_CA_Path", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_Cert", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_Cipher", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_CRL_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_CRL_Path", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_Key", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_Verify_Server_Cert", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Seconds_Behind_Source", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_IO_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_IO_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_SQL_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_SQL_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Replicate_Ignore_Server_Ids", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Server_Id", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_UUID", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Info_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "SQL_Delay", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "SQL_Remaining_Delay", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Replica_SQL_Running_State", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Retry_Count", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Bind", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_IO_Error_Timestamp", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_SQL_Error_Timestamp", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Retrieved_Gtid_Set", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Executed_Gtid_Set", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Auto_Position", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Replicate_Rewrite_DB", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, } } @@ -84,24 +123,61 @@ func (s *ShowReplicaStatus) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, } row = sql.Row{ - status.SourceHost, - status.SourceUser, - status.SourcePort, - status.ReplicaIoRunning, - status.ReplicaSqlRunning, - status.LastSqlErrNumber, - status.LastSqlError, - status.LastIoErrNumber, - status.LastIoError, - status.LastSqlErrNumber, - status.LastSqlError, - status.SourceServerId, - status.SourceServerUuid, - status.LastSqlErrorTimestamp, - status.LastIoErrorTimestamp, - status.RetrievedGtidSet, - status.ExecutedGtidSet, - status.AutoPosition, + "", // Replica_IO_State + status.SourceHost, // Source_Host + status.SourceUser, // Source_User + status.SourcePort, // Source_Port + -1, // Connect_Retry // TODO: default to 60s + "INVALID", // Source_Log_File + 0, // Read_Source_Log_Pos + nil, // Relay_Log_File + nil, // Relay_Log_Pos + "INVALID", // Relay_Source_Log_File + status.ReplicaIoRunning, // Replica_IO_Running + status.ReplicaSqlRunning, // Replica_SQL_Running + nil, // Replicate_Do_DB + nil, // Replicate_Ignore_DB + nil, // Replicate_Do_Table + nil, // Replicate_Ignore_Table + nil, // Replicate_Wild_Do_Table + nil, // Replicate_Wild_Ignore_Table + status.LastSqlErrNumber, // Last_Errno + status.LastSqlError, // Last_Error + nil, // Skip_Counter + 0, // Exec_Source_Log_Pos + nil, // Relay_Log_Space + "None", //Until_Condition + nil, // Until_Log_File + nil, // Until_Log_Pos + "Ignored", // Source_SSL_Allowed + nil, // Source_SSL_CA_File + nil, // Source_SSL_CA_Path + nil, // Source_SSL_Cert + nil, // Source_SSL_Cipher + nil, // Source_SSL_CRL_File + nil, // Source_SSL_CRL_Path + nil, // Source_SSL_Key + nil, // Source_SSL_Verify_Server_Cert + 0, // Seconds_Behind_Source + status.LastIoErrNumber, // Last_IO_Errno + status.LastIoError, // Last_IO_Error + status.LastSqlErrNumber, // Last_SQL_Errno + status.LastSqlError, // Last_SQL_Error + nil, // Replicate_Ignore_Server_Ids + status.SourceServerId, // Source_Server_Id + status.SourceServerUuid, // Source_UUID + nil, // Source_Info_File + 0, // SQL_Delay + 0, // SQL_Remaining_Delay + nil, // Replica_SQL_Running_State + 0, // Source_Retry_Count + nil, // Source_Bind + status.LastSqlErrorTimestamp, // Last_IO_Error_Timestamp + status.LastIoErrorTimestamp, // Last_SQL_Error_Timestamp + status.RetrievedGtidSet, // Retrieved_Gtid_Set + status.ExecutedGtidSet, // Executed_Gtid_Set + status.AutoPosition, // Auto_Position + nil, // Replicate_Rewrite_DB } return sql.RowsToRowIter(row), nil From eb5df349a7ffd55de2f33f727e32c1fa0559d059 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 28 Dec 2022 11:09:41 -0800 Subject: [PATCH 08/23] Refactoring package organization --- engine.go | 3 +- sql/binlogreplication/binlog_replication.go | 88 ++++++++++++++++++ sql/parse/parse.go | 5 +- ...replication.go => replication_commands.go} | 92 +++---------------- sql/plan/show_replica_status.go | 5 +- 5 files changed, 108 insertions(+), 85 deletions(-) create mode 100644 sql/binlogreplication/binlog_replication.go rename sql/plan/{binlog_replication.go => replication_commands.go} (58%) diff --git a/engine.go b/engine.go index bbee8ecefe..1538257488 100644 --- a/engine.go +++ b/engine.go @@ -24,6 +24,7 @@ import ( "github.com/dolthub/go-mysql-server/memory" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/analyzer" + "github.com/dolthub/go-mysql-server/sql/binlogreplication" "github.com/dolthub/go-mysql-server/sql/expression" "github.com/dolthub/go-mysql-server/sql/expression/function" "github.com/dolthub/go-mysql-server/sql/mysql_db" @@ -65,7 +66,7 @@ type Engine struct { IsReadOnly bool IsServerLocked bool PreparedData map[uint32]PreparedData - BinlogReplicaController plan.BinlogReplicaController + BinlogReplicaController binlogreplication.BinlogReplicaController mu *sync.Mutex } diff --git a/sql/binlogreplication/binlog_replication.go b/sql/binlogreplication/binlog_replication.go new file mode 100644 index 0000000000..5f36bcc858 --- /dev/null +++ b/sql/binlogreplication/binlog_replication.go @@ -0,0 +1,88 @@ +// Copyright 2022 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package binlogreplication + +import ( + "time" + + "github.com/dolthub/go-mysql-server/sql" +) + +// TODO: error out if sql-server is not running! + +// BinlogReplicaController allows callers to control a binlog replica. Providers built on go-mysql-server may optionally +// implement this interface and use it when constructing a SQL engine in order to receive callbacks when replication +// statements (e.g. START REPLICA, SHOW REPLICA STATUS) are being handled. +type BinlogReplicaController interface { + // StartReplica tells the binlog replica controller to start up replication processes for the current replication + // configuration. An error is returned if replication was unable to be started. Note the error response only signals + // whether there was a problem with the initial replication start up. Replication could fail after being started up + // successfully with no error response returned. + StartReplica(ctx *sql.Context) error + + // StopReplica tells the binlog replica controller to stop all replication processes. An error is returned if there + // were any problems stopping replication. If no replication processes were running, no error is returned. + StopReplica(ctx *sql.Context) error + + // SetReplicationOptions configures the binlog replica controller with the specified options. The replica controller + // must store this configuration. If any errors are encountered processing and storing the configuration options, an + // error is returned. + SetReplicationOptions(ctx *sql.Context, options []ReplicationOption) error + + // GetReplicaStatus returns the current status of the replica, or nil if no replication processes are running. If + // any problems are encountered assembling the replica's status, an error is returned. + GetReplicaStatus(ctx *sql.Context) (*ReplicaStatus, error) +} + +// ReplicaStatus stores the status of a single binlog replica and is returned by `SHOW REPLICA STATUS`. +// https://dev.mysql.com/doc/refman/8.0/en/show-replica-status.html +type ReplicaStatus struct { + SourceHost string + SourceUser string + SourcePort uint + ReplicaIoRunning string + ReplicaSqlRunning string + LastSqlErrNumber string // Alias for LastErrNumber + LastSqlError string // Alias for LastError + LastIoErrNumber string + LastIoError string + SourceServerId string + SourceServerUuid string + LastSqlErrorTimestamp time.Time + LastIoErrorTimestamp time.Time + RetrievedGtidSet string + ExecutedGtidSet string + AutoPosition bool +} + +const ( + ReplicaIoNotRunning = "No" + ReplicaIoConnecting = "Connecting" + ReplicaIoRunning = "Yes" + ReplicaSqlNotRunning = "No" + ReplicaSqlRunning = "Yes" +) + +type ReplicationOption struct { + Name string + Value string +} + +func NewReplicationOption(name string, value string) ReplicationOption { + return ReplicationOption{ + Name: name, + Value: value, + } +} diff --git a/sql/parse/parse.go b/sql/parse/parse.go index a8e5770f8e..fdf05bfe9d 100644 --- a/sql/parse/parse.go +++ b/sql/parse/parse.go @@ -31,6 +31,7 @@ import ( "gopkg.in/src-d/go-errors.v1" "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/binlogreplication" "github.com/dolthub/go-mysql-server/sql/encodings" "github.com/dolthub/go-mysql-server/sql/expression" "github.com/dolthub/go-mysql-server/sql/expression/function" @@ -449,9 +450,9 @@ func convertSet(ctx *sql.Context, n *sqlparser.Set) (sql.Node, error) { } func convertChangeReplicationSource(n *sqlparser.ChangeReplicationSource) (sql.Node, error) { - convertedOptions := make([]plan.ReplicationOption, 0, len(n.Options)) + convertedOptions := make([]binlogreplication.ReplicationOption, 0, len(n.Options)) for _, option := range n.Options { - convertedOptions = append(convertedOptions, plan.NewReplicationOption(option.Name, option.Value)) + convertedOptions = append(convertedOptions, binlogreplication.NewReplicationOption(option.Name, option.Value)) } return plan.NewChangeReplicationSource(convertedOptions), nil } diff --git a/sql/plan/binlog_replication.go b/sql/plan/replication_commands.go similarity index 58% rename from sql/plan/binlog_replication.go rename to sql/plan/replication_commands.go index 8dcb1f2078..b6d048670c 100644 --- a/sql/plan/binlog_replication.go +++ b/sql/plan/replication_commands.go @@ -16,101 +16,33 @@ package plan import ( "fmt" - "strings" - "time" - "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/binlogreplication" + "strings" ) -// TODO: Move this out to a better package -// TODO: error out if sql-server is not running! - -// BinlogReplicaController allows callers to control a binlog replica. Providers built on go-mysql-server may optionally -// implement this interface and use it when constructing a SQL engine in order to receive callbacks when replication -// statements (e.g. START REPLICA, SHOW REPLICA STATUS) are being handled. -type BinlogReplicaController interface { - // StartReplica tells the binlog replica controller to start up replication processes for the current replication - // configuration. An error is returned if replication was unable to be started. Note the error response only signals - // whether there was a problem with the initial replication start up. Replication could fail after being started up - // successfully with no error response returned. - StartReplica(ctx *sql.Context) error - - // StopReplica tells the binlog replica controller to stop all replication processes. An error is returned if there - // were any problems stopping replication. If no replication processes were running, no error is returned. - StopReplica(ctx *sql.Context) error - - // SetReplicationOptions configures the binlog replica controller with the specified options. The replica controller - // must store this configuration. If any errors are encountered processing and storing the configuration options, an - // error is returned. - SetReplicationOptions(ctx *sql.Context, options []ReplicationOption) error - - // GetReplicaStatus returns the current status of the replica, or nil if no replication processes are running. If - // any problems are encountered assembling the replica's status, an error is returned. - GetReplicaStatus(ctx *sql.Context) (*ReplicaStatus, error) -} - -// ReplicaStatus stores the status of a single binlog replica and is returned by `SHOW REPLICA STATUS`. -// https://dev.mysql.com/doc/refman/8.0/en/show-replica-status.html -type ReplicaStatus struct { - SourceHost string - SourceUser string - SourcePort uint - ReplicaIoRunning string - ReplicaSqlRunning string - LastSqlErrNumber string // Alias for LastErrNumber - LastSqlError string // Alias for LastError - LastIoErrNumber string - LastIoError string - SourceServerId string - SourceServerUuid string - LastSqlErrorTimestamp time.Time - LastIoErrorTimestamp time.Time - RetrievedGtidSet string - ExecutedGtidSet string - AutoPosition bool -} - -const ( - ReplicaIoNotRunning = "No" - ReplicaIoConnecting = "Connecting" - ReplicaIoRunning = "Yes" - ReplicaSqlNotRunning = "No" - ReplicaSqlRunning = "Yes" -) - -type ReplicationOption struct { - Name string - Value string -} - -func NewReplicationOption(name string, value string) ReplicationOption { - return ReplicationOption{ - Name: name, - Value: value, - } -} - type BinlogReplicaControllerCommand interface { - WithBinlogReplicaController(controller BinlogReplicaController) + WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) } // ChangeReplicationSource is the plan node for the "CHANGE REPLICATION SOURCE TO" statement. // https://dev.mysql.com/doc/refman/8.0/en/change-replication-source-to.html type ChangeReplicationSource struct { - Options []ReplicationOption - replicaController BinlogReplicaController // TODO: Could type embed something that does this for all the replication types + Options []binlogreplication.ReplicationOption + // TODO: Could type embed something that does this for all the replication types + replicaController binlogreplication.BinlogReplicaController } var _ sql.Node = (*ChangeReplicationSource)(nil) var _ BinlogReplicaControllerCommand = (*ChangeReplicationSource)(nil) -func NewChangeReplicationSource(options []ReplicationOption) *ChangeReplicationSource { +func NewChangeReplicationSource(options []binlogreplication.ReplicationOption) *ChangeReplicationSource { return &ChangeReplicationSource{ Options: options, } } -func (c *ChangeReplicationSource) WithBinlogReplicaController(controller BinlogReplicaController) { +func (c *ChangeReplicationSource) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { c.replicaController = controller } @@ -166,7 +98,7 @@ func (c *ChangeReplicationSource) CheckPrivileges(_ *sql.Context, _ sql.Privileg // StartReplica is a plan node for the "START REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/start-replica.html type StartReplica struct { - replicaController BinlogReplicaController + replicaController binlogreplication.BinlogReplicaController } var _ sql.Node = (*StartReplica)(nil) @@ -176,7 +108,7 @@ func NewStartReplica() *StartReplica { return &StartReplica{} } -func (s *StartReplica) WithBinlogReplicaController(controller BinlogReplicaController) { +func (s *StartReplica) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { s.replicaController = controller } @@ -222,7 +154,7 @@ func (s *StartReplica) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperation // StopReplica is the plan node for the "STOP REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/stop-replica.html type StopReplica struct { - replicaController BinlogReplicaController + replicaController binlogreplication.BinlogReplicaController } var _ sql.Node = (*StopReplica)(nil) @@ -232,7 +164,7 @@ func NewStopReplica() *StopReplica { return &StopReplica{} } -func (s *StopReplica) WithBinlogReplicaController(controller BinlogReplicaController) { +func (s *StopReplica) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { s.replicaController = controller } diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go index 7483682c66..a97403e727 100644 --- a/sql/plan/show_replica_status.go +++ b/sql/plan/show_replica_status.go @@ -16,6 +16,7 @@ package plan import ( "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/binlogreplication" "github.com/dolthub/vitess/go/sqltypes" ) @@ -23,7 +24,7 @@ import ( // https://dev.mysql.com/doc/refman/8.0/en/show-replica-status.html type ShowReplicaStatus struct { // TODO: Consider an embeddable type for this - replicaController BinlogReplicaController + replicaController binlogreplication.BinlogReplicaController } var _ sql.Node = (*ShowReplicaStatus)(nil) @@ -33,7 +34,7 @@ func NewShowReplicaStatus() *ShowReplicaStatus { return &ShowReplicaStatus{} } -func (s *ShowReplicaStatus) WithBinlogReplicaController(controller BinlogReplicaController) { +func (s *ShowReplicaStatus) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { s.replicaController = controller } From bee2b5fd0b1c6988ffe139dcbf07a8d1385d2aa4 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 28 Dec 2022 17:15:14 -0800 Subject: [PATCH 09/23] Wiring in connection retry attempt limit and connection retry delay configuration --- sql/binlogreplication/binlog_replication.go | 2 ++ sql/plan/show_replica_status.go | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/sql/binlogreplication/binlog_replication.go b/sql/binlogreplication/binlog_replication.go index 5f36bcc858..4c178e665e 100644 --- a/sql/binlogreplication/binlog_replication.go +++ b/sql/binlogreplication/binlog_replication.go @@ -52,6 +52,8 @@ type ReplicaStatus struct { SourceHost string SourceUser string SourcePort uint + ConnectRetry uint + SourceRetryCount uint ReplicaIoRunning string ReplicaSqlRunning string LastSqlErrNumber string // Alias for LastErrNumber diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go index a97403e727..b0e145470d 100644 --- a/sql/plan/show_replica_status.go +++ b/sql/plan/show_replica_status.go @@ -128,7 +128,7 @@ func (s *ShowReplicaStatus) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, status.SourceHost, // Source_Host status.SourceUser, // Source_User status.SourcePort, // Source_Port - -1, // Connect_Retry // TODO: default to 60s + status.ConnectRetry, // Connect_Retry "INVALID", // Source_Log_File 0, // Read_Source_Log_Pos nil, // Relay_Log_File @@ -147,7 +147,7 @@ func (s *ShowReplicaStatus) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, nil, // Skip_Counter 0, // Exec_Source_Log_Pos nil, // Relay_Log_Space - "None", //Until_Condition + "None", // Until_Condition nil, // Until_Log_File nil, // Until_Log_Pos "Ignored", // Source_SSL_Allowed @@ -171,7 +171,7 @@ func (s *ShowReplicaStatus) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, 0, // SQL_Delay 0, // SQL_Remaining_Delay nil, // Replica_SQL_Running_State - 0, // Source_Retry_Count + status.SourceRetryCount, // Source_Retry_Count nil, // Source_Bind status.LastSqlErrorTimestamp, // Last_IO_Error_Timestamp status.LastIoErrorTimestamp, // Last_SQL_Error_Timestamp From 5a0fa1a21fd5fc10b4ba3d87ba7b0a725f348bd1 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Thu, 29 Dec 2022 15:45:23 -0800 Subject: [PATCH 10/23] Updates to ReplicaStatus fields and formatting --- sql/binlogreplication/binlog_replication.go | 10 +- sql/plan/show_replica_status.go | 120 +++++++++++--------- 2 files changed, 69 insertions(+), 61 deletions(-) diff --git a/sql/binlogreplication/binlog_replication.go b/sql/binlogreplication/binlog_replication.go index 4c178e665e..1f9c48d776 100644 --- a/sql/binlogreplication/binlog_replication.go +++ b/sql/binlogreplication/binlog_replication.go @@ -20,8 +20,6 @@ import ( "github.com/dolthub/go-mysql-server/sql" ) -// TODO: error out if sql-server is not running! - // BinlogReplicaController allows callers to control a binlog replica. Providers built on go-mysql-server may optionally // implement this interface and use it when constructing a SQL engine in order to receive callbacks when replication // statements (e.g. START REPLICA, SHOW REPLICA STATUS) are being handled. @@ -56,14 +54,14 @@ type ReplicaStatus struct { SourceRetryCount uint ReplicaIoRunning string ReplicaSqlRunning string - LastSqlErrNumber string // Alias for LastErrNumber + LastSqlErrNumber uint // Alias for LastErrNumber LastSqlError string // Alias for LastError - LastIoErrNumber string + LastIoErrNumber uint LastIoError string SourceServerId string SourceServerUuid string - LastSqlErrorTimestamp time.Time - LastIoErrorTimestamp time.Time + LastSqlErrorTimestamp *time.Time + LastIoErrorTimestamp *time.Time RetrievedGtidSet string ExecutedGtidSet string AutoPosition bool diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go index b0e145470d..b616c511ac 100644 --- a/sql/plan/show_replica_status.go +++ b/sql/plan/show_replica_status.go @@ -15,6 +15,8 @@ package plan import ( + "time" + "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/binlogreplication" "github.com/dolthub/vitess/go/sqltypes" @@ -124,66 +126,74 @@ func (s *ShowReplicaStatus) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, } row = sql.Row{ - "", // Replica_IO_State - status.SourceHost, // Source_Host - status.SourceUser, // Source_User - status.SourcePort, // Source_Port - status.ConnectRetry, // Connect_Retry - "INVALID", // Source_Log_File - 0, // Read_Source_Log_Pos - nil, // Relay_Log_File - nil, // Relay_Log_Pos - "INVALID", // Relay_Source_Log_File - status.ReplicaIoRunning, // Replica_IO_Running - status.ReplicaSqlRunning, // Replica_SQL_Running - nil, // Replicate_Do_DB - nil, // Replicate_Ignore_DB - nil, // Replicate_Do_Table - nil, // Replicate_Ignore_Table - nil, // Replicate_Wild_Do_Table - nil, // Replicate_Wild_Ignore_Table - status.LastSqlErrNumber, // Last_Errno - status.LastSqlError, // Last_Error - nil, // Skip_Counter - 0, // Exec_Source_Log_Pos - nil, // Relay_Log_Space - "None", // Until_Condition - nil, // Until_Log_File - nil, // Until_Log_Pos - "Ignored", // Source_SSL_Allowed - nil, // Source_SSL_CA_File - nil, // Source_SSL_CA_Path - nil, // Source_SSL_Cert - nil, // Source_SSL_Cipher - nil, // Source_SSL_CRL_File - nil, // Source_SSL_CRL_Path - nil, // Source_SSL_Key - nil, // Source_SSL_Verify_Server_Cert - 0, // Seconds_Behind_Source - status.LastIoErrNumber, // Last_IO_Errno - status.LastIoError, // Last_IO_Error - status.LastSqlErrNumber, // Last_SQL_Errno - status.LastSqlError, // Last_SQL_Error - nil, // Replicate_Ignore_Server_Ids - status.SourceServerId, // Source_Server_Id - status.SourceServerUuid, // Source_UUID - nil, // Source_Info_File - 0, // SQL_Delay - 0, // SQL_Remaining_Delay - nil, // Replica_SQL_Running_State - status.SourceRetryCount, // Source_Retry_Count - nil, // Source_Bind - status.LastSqlErrorTimestamp, // Last_IO_Error_Timestamp - status.LastIoErrorTimestamp, // Last_SQL_Error_Timestamp - status.RetrievedGtidSet, // Retrieved_Gtid_Set - status.ExecutedGtidSet, // Executed_Gtid_Set - status.AutoPosition, // Auto_Position - nil, // Replicate_Rewrite_DB + "", // Replica_IO_State + status.SourceHost, // Source_Host + status.SourceUser, // Source_User + status.SourcePort, // Source_Port + status.ConnectRetry, // Connect_Retry + "INVALID", // Source_Log_File + 0, // Read_Source_Log_Pos + nil, // Relay_Log_File + nil, // Relay_Log_Pos + "INVALID", // Relay_Source_Log_File + status.ReplicaIoRunning, // Replica_IO_Running + status.ReplicaSqlRunning, // Replica_SQL_Running + nil, // Replicate_Do_DB + nil, // Replicate_Ignore_DB + nil, // Replicate_Do_Table + nil, // Replicate_Ignore_Table + nil, // Replicate_Wild_Do_Table + nil, // Replicate_Wild_Ignore_Table + status.LastSqlErrNumber, // Last_Errno + status.LastSqlError, // Last_Error + nil, // Skip_Counter + 0, // Exec_Source_Log_Pos + nil, // Relay_Log_Space + "None", // Until_Condition + nil, // Until_Log_File + nil, // Until_Log_Pos + "Ignored", // Source_SSL_Allowed + nil, // Source_SSL_CA_File + nil, // Source_SSL_CA_Path + nil, // Source_SSL_Cert + nil, // Source_SSL_Cipher + nil, // Source_SSL_CRL_File + nil, // Source_SSL_CRL_Path + nil, // Source_SSL_Key + nil, // Source_SSL_Verify_Server_Cert + 0, // Seconds_Behind_Source + status.LastIoErrNumber, // Last_IO_Errno + status.LastIoError, // Last_IO_Error + status.LastSqlErrNumber, // Last_SQL_Errno + status.LastSqlError, // Last_SQL_Error + nil, // Replicate_Ignore_Server_Ids + status.SourceServerId, // Source_Server_Id + status.SourceServerUuid, // Source_UUID + nil, // Source_Info_File + 0, // SQL_Delay + 0, // SQL_Remaining_Delay + nil, // Replica_SQL_Running_State + status.SourceRetryCount, // Source_Retry_Count + nil, // Source_Bind + formatTimestamp(status.LastIoErrorTimestamp), // Last_IO_Error_Timestamp + formatTimestamp(status.LastSqlErrorTimestamp), // Last_SQL_Error_Timestamp + status.RetrievedGtidSet, // Retrieved_Gtid_Set + status.ExecutedGtidSet, // Executed_Gtid_Set + status.AutoPosition, // Auto_Position + nil, // Replicate_Rewrite_DB } return sql.RowsToRowIter(row), nil } +func formatTimestamp(t *time.Time) string { + if t == nil { + return "" + } + + return t.Format(time.UnixDate) +} + func (s *ShowReplicaStatus) WithChildren(children ...sql.Node) (sql.Node, error) { if len(children) != 0 { return nil, sql.ErrInvalidChildrenNumber.New(s, len(children), 0) From 026f839f2e3777f8c33b44003fbe4433d265893e Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 4 Jan 2023 13:11:22 -0800 Subject: [PATCH 11/23] Minor tweaks to tidy up --- engine.go | 23 +++++++++++---------- sql/binlogreplication/binlog_replication.go | 2 ++ sql/plan/replication_commands.go | 14 +++++++------ sql/plan/show_replica_status.go | 17 +++++++-------- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/engine.go b/engine.go index fe11b7ebaf..d337bc3a9b 100644 --- a/engine.go +++ b/engine.go @@ -116,16 +116,16 @@ func (p *PreparedDataCache) UncacheStmt(sessId uint32, query string) { // Engine is a SQL engine. type Engine struct { - Analyzer *analyzer.Analyzer - LS *sql.LockSubsystem - ProcessList sql.ProcessList - MemoryManager *sql.MemoryManager - BackgroundThreads *sql.BackgroundThreads - IsReadOnly bool - IsServerLocked bool - PreparedDataCache *PreparedDataCache + Analyzer *analyzer.Analyzer + LS *sql.LockSubsystem + ProcessList sql.ProcessList + MemoryManager *sql.MemoryManager + BackgroundThreads *sql.BackgroundThreads + IsReadOnly bool + IsServerLocked bool + PreparedDataCache *PreparedDataCache BinlogReplicaController binlogreplication.BinlogReplicaController - mu *sync.Mutex + mu *sync.Mutex } type ColumnWithRawDefault struct { @@ -236,9 +236,10 @@ func (e *Engine) QueryNodeWithBindings( } } - // TODO: This isn't the right place for this, but hacking it in here for now... + // The replica controller reference is held by |Engine|, so for any BinlogReplicaControllerCommands, + // we supply their replica controller here, before the command gets to the analyzer. if nn, ok := parsed.(plan.BinlogReplicaControllerCommand); ok { - nn.WithBinlogReplicaController(e.BinlogReplicaController) + nn.SetBinlogReplicaController(e.BinlogReplicaController) } // Before we begin a transaction, we need to know if the database being operated on is not the one diff --git a/sql/binlogreplication/binlog_replication.go b/sql/binlogreplication/binlog_replication.go index 1f9c48d776..bf770bcc94 100644 --- a/sql/binlogreplication/binlog_replication.go +++ b/sql/binlogreplication/binlog_replication.go @@ -75,6 +75,8 @@ const ( ReplicaSqlRunning = "Yes" ) +// ReplicationOption represents a single option for replication configuration, as specified through the +// CHANGE REPLICATION SOURCE TO command: https://dev.mysql.com/doc/refman/8.0/en/change-replication-source-to.html type ReplicationOption struct { Name string Value string diff --git a/sql/plan/replication_commands.go b/sql/plan/replication_commands.go index b6d048670c..7006236d4b 100644 --- a/sql/plan/replication_commands.go +++ b/sql/plan/replication_commands.go @@ -21,15 +21,17 @@ import ( "strings" ) +// BinlogReplicaControllerCommand represents a SQL statement that requires a BinlogReplicaController +// (e.g. Start Replica, Show Replica Status). type BinlogReplicaControllerCommand interface { - WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) + // SetBinlogReplicaController sets the BinlogReplicaController for this replication command to use. + SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) } // ChangeReplicationSource is the plan node for the "CHANGE REPLICATION SOURCE TO" statement. // https://dev.mysql.com/doc/refman/8.0/en/change-replication-source-to.html type ChangeReplicationSource struct { - Options []binlogreplication.ReplicationOption - // TODO: Could type embed something that does this for all the replication types + Options []binlogreplication.ReplicationOption replicaController binlogreplication.BinlogReplicaController } @@ -42,7 +44,7 @@ func NewChangeReplicationSource(options []binlogreplication.ReplicationOption) * } } -func (c *ChangeReplicationSource) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { +func (c *ChangeReplicationSource) SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { c.replicaController = controller } @@ -108,7 +110,7 @@ func NewStartReplica() *StartReplica { return &StartReplica{} } -func (s *StartReplica) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { +func (s *StartReplica) SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { s.replicaController = controller } @@ -164,7 +166,7 @@ func NewStopReplica() *StopReplica { return &StopReplica{} } -func (s *StopReplica) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { +func (s *StopReplica) SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { s.replicaController = controller } diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go index b616c511ac..189e16af57 100644 --- a/sql/plan/show_replica_status.go +++ b/sql/plan/show_replica_status.go @@ -25,7 +25,6 @@ import ( // ShowReplicaStatus is the plan node for the "SHOW REPLICA STATUS" statement. // https://dev.mysql.com/doc/refman/8.0/en/show-replica-status.html type ShowReplicaStatus struct { - // TODO: Consider an embeddable type for this replicaController binlogreplication.BinlogReplicaController } @@ -36,7 +35,7 @@ func NewShowReplicaStatus() *ShowReplicaStatus { return &ShowReplicaStatus{} } -func (s *ShowReplicaStatus) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { +func (s *ShowReplicaStatus) SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { s.replicaController = controller } @@ -175,18 +174,18 @@ func (s *ShowReplicaStatus) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, nil, // Replica_SQL_Running_State status.SourceRetryCount, // Source_Retry_Count nil, // Source_Bind - formatTimestamp(status.LastIoErrorTimestamp), // Last_IO_Error_Timestamp - formatTimestamp(status.LastSqlErrorTimestamp), // Last_SQL_Error_Timestamp - status.RetrievedGtidSet, // Retrieved_Gtid_Set - status.ExecutedGtidSet, // Executed_Gtid_Set - status.AutoPosition, // Auto_Position - nil, // Replicate_Rewrite_DB + formatReplicaStatusTimestamp(status.LastIoErrorTimestamp), // Last_IO_Error_Timestamp + formatReplicaStatusTimestamp(status.LastSqlErrorTimestamp), // Last_SQL_Error_Timestamp + status.RetrievedGtidSet, // Retrieved_Gtid_Set + status.ExecutedGtidSet, // Executed_Gtid_Set + status.AutoPosition, // Auto_Position + nil, // Replicate_Rewrite_DB } return sql.RowsToRowIter(row), nil } -func formatTimestamp(t *time.Time) string { +func formatReplicaStatusTimestamp(t *time.Time) string { if t == nil { return "" } From 7e906e5014c023fd9f18d2d708f595f29ad4ea9b Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 4 Jan 2023 13:13:06 -0800 Subject: [PATCH 12/23] go mod tidy --- go.sum | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go.sum b/go.sum index 6205cb2ea0..0e3cb5b42f 100755 --- a/go.sum +++ b/go.sum @@ -57,10 +57,6 @@ github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9X github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81/go.mod h1:siLfyv2c92W1eN/R4QqG/+RjjX5W2+gCTRjZxBjI3TY= github.com/dolthub/vitess v0.0.0-20221221215514-0a479c28185a h1:u2q5qV6s3RF7Nqp7NEeNUHfPmsXBEvKz3VBwBOS4YgE= github.com/dolthub/vitess v0.0.0-20221221215514-0a479c28185a/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= -github.com/dolthub/vitess v0.0.0-20221219195828-63e6813c39c5 h1:B/qFPTTBApEbjv5A48TxndG+dvrTfkWoikHv+KlmLIY= -github.com/dolthub/vitess v0.0.0-20221219195828-63e6813c39c5/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= -github.com/dolthub/vitess v0.0.0-20221219201541-7a5989011eee h1:1OSVD9PGbuM9YQVAW35vOEr9ea2q4DkoQCjmcQiZGkM= -github.com/dolthub/vitess v0.0.0-20221219201541-7a5989011eee/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= From f45f2826a7cc2a0e6ca05ad7c11dd5c985598cfa Mon Sep 17 00:00:00 2001 From: fulghum Date: Wed, 4 Jan 2023 23:21:39 +0000 Subject: [PATCH 13/23] [ga-format-pr] Run ./format_repo.sh to fix formatting --- sql/plan/replication_commands.go | 3 ++- sql/plan/show_replica_status.go | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sql/plan/replication_commands.go b/sql/plan/replication_commands.go index 7006236d4b..45a0ba2220 100644 --- a/sql/plan/replication_commands.go +++ b/sql/plan/replication_commands.go @@ -16,9 +16,10 @@ package plan import ( "fmt" + "strings" + "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/binlogreplication" - "strings" ) // BinlogReplicaControllerCommand represents a SQL statement that requires a BinlogReplicaController diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go index 189e16af57..738b5b4919 100644 --- a/sql/plan/show_replica_status.go +++ b/sql/plan/show_replica_status.go @@ -17,9 +17,10 @@ package plan import ( "time" + "github.com/dolthub/vitess/go/sqltypes" + "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/binlogreplication" - "github.com/dolthub/vitess/go/sqltypes" ) // ShowReplicaStatus is the plan node for the "SHOW REPLICA STATUS" statement. From 3d1e722ea0d2609ee3ca6154d611141e469dfdde Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 4 Jan 2023 15:51:39 -0800 Subject: [PATCH 14/23] minor note about privilege checks --- sql/plan/show_replica_status.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go index 189e16af57..9e66d5fde4 100644 --- a/sql/plan/show_replica_status.go +++ b/sql/plan/show_replica_status.go @@ -202,7 +202,8 @@ func (s *ShowReplicaStatus) WithChildren(children ...sql.Node) (sql.Node, error) return &newNode, nil } -func (s *ShowReplicaStatus) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperationChecker) bool { +func (s *ShowReplicaStatus) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { // TODO: Implement privilege support + // CHANGE REPLICATION SOURCE TO requires the REPLICATION_SLAVE_ADMIN privilege (or the deprecated SUPER privilege). return true } From cfb26ed18125118b911b30fc1b6fdd3398979345 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 11 Jan 2023 15:55:59 -0800 Subject: [PATCH 15/23] Embedding the new binlogReplicaControllerCommand type to simplify implementing the BinlogReplicaControllerCommand interface. --- sql/plan/replication_commands.go | 33 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/sql/plan/replication_commands.go b/sql/plan/replication_commands.go index 45a0ba2220..9521b1aa1f 100644 --- a/sql/plan/replication_commands.go +++ b/sql/plan/replication_commands.go @@ -29,11 +29,24 @@ type BinlogReplicaControllerCommand interface { SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) } +// binlogReplicaControllerCommand is a package-internal type embedded into +// BinlogReplicaControllerCommand types to provide the SetBinlogReplicaController function. +type binlogReplicaControllerCommand struct { + replicaController binlogreplication.BinlogReplicaController +} + +var _ BinlogReplicaControllerCommand = (*binlogReplicaControllerCommand)(nil) + +// SetBinlogReplicaController implements the BinlogReplicaControllerCommand interface. +func (c *binlogReplicaControllerCommand) SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { + c.replicaController = controller +} + // ChangeReplicationSource is the plan node for the "CHANGE REPLICATION SOURCE TO" statement. // https://dev.mysql.com/doc/refman/8.0/en/change-replication-source-to.html type ChangeReplicationSource struct { - Options []binlogreplication.ReplicationOption - replicaController binlogreplication.BinlogReplicaController + binlogReplicaControllerCommand + Options []binlogreplication.ReplicationOption } var _ sql.Node = (*ChangeReplicationSource)(nil) @@ -45,10 +58,6 @@ func NewChangeReplicationSource(options []binlogreplication.ReplicationOption) * } } -func (c *ChangeReplicationSource) SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { - c.replicaController = controller -} - func (c *ChangeReplicationSource) Resolved() bool { return true } @@ -101,7 +110,7 @@ func (c *ChangeReplicationSource) CheckPrivileges(_ *sql.Context, _ sql.Privileg // StartReplica is a plan node for the "START REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/start-replica.html type StartReplica struct { - replicaController binlogreplication.BinlogReplicaController + binlogReplicaControllerCommand } var _ sql.Node = (*StartReplica)(nil) @@ -111,10 +120,6 @@ func NewStartReplica() *StartReplica { return &StartReplica{} } -func (s *StartReplica) SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { - s.replicaController = controller -} - func (s *StartReplica) Resolved() bool { return true } @@ -157,7 +162,7 @@ func (s *StartReplica) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperation // StopReplica is the plan node for the "STOP REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/stop-replica.html type StopReplica struct { - replicaController binlogreplication.BinlogReplicaController + binlogReplicaControllerCommand } var _ sql.Node = (*StopReplica)(nil) @@ -167,10 +172,6 @@ func NewStopReplica() *StopReplica { return &StopReplica{} } -func (s *StopReplica) SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { - s.replicaController = controller -} - func (s *StopReplica) Resolved() bool { return true } From 3645701b9f73ee7fc6f16186e357b5d68c26b9cd Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 11 Jan 2023 16:16:48 -0800 Subject: [PATCH 16/23] First pass on adding handling for CHANGE REPLICATION FILTER and RESET REPLICA statements. --- sql/binlogreplication/binlog_replication.go | 27 +++- sql/parse/parse.go | 14 +++ sql/plan/replication_commands.go | 131 +++++++++++++++++++- 3 files changed, 164 insertions(+), 8 deletions(-) diff --git a/sql/binlogreplication/binlog_replication.go b/sql/binlogreplication/binlog_replication.go index bf770bcc94..7c16a4d6aa 100644 --- a/sql/binlogreplication/binlog_replication.go +++ b/sql/binlogreplication/binlog_replication.go @@ -34,14 +34,29 @@ type BinlogReplicaController interface { // were any problems stopping replication. If no replication processes were running, no error is returned. StopReplica(ctx *sql.Context) error - // SetReplicationOptions configures the binlog replica controller with the specified options. The replica controller - // must store this configuration. If any errors are encountered processing and storing the configuration options, an - // error is returned. - SetReplicationOptions(ctx *sql.Context, options []ReplicationOption) error + // SetReplicationSourceOptions configures the binlog replica controller with the specified source options. The + // replica controller must store this configuration. If any errors are encountered processing and storing the + // configuration options, an error is returned. + SetReplicationSourceOptions(ctx *sql.Context, options []ReplicationOption) error + + // SetReplicationFilterOptions configures the binlog replica controller with the specified filter options. Although + // the official MySQL implementation does *NOT* persist these options, the replica controller should persist them. + // (MySQL requires these options to be manually set after every server restart, or to be specified as command line + // arguments when starting the MySQL process.) If any errors are encountered processing and storing the filter + // options, an error is returned. + SetReplicationFilterOptions(ctx *sql.Context, options []ReplicationOption) error // GetReplicaStatus returns the current status of the replica, or nil if no replication processes are running. If // any problems are encountered assembling the replica's status, an error is returned. GetReplicaStatus(ctx *sql.Context) (*ReplicaStatus, error) + + // ResetReplica resets the state for the replica. When the |resetAll| parameter is false, a "soft" or minimal reset + // is performed – replication errors are reset, but connection information and filters are NOT reset. If |resetAll| + // is true, a "hard" reset is performed – replication filters are removed, replication source options are removed, + // and `SHOW REPLICA STATUS` shows no results. If replication is currently running, this function should return an + // error indicating that replication needs to be stopped before it can be reset. If any errors were encountered + // resetting the replica state, an error is returned, otherwise nil is returned if the reset was successful. + ResetReplica(ctx *sql.Context, resetAll bool) error } // ReplicaStatus stores the status of a single binlog replica and is returned by `SHOW REPLICA STATUS`. @@ -79,10 +94,10 @@ const ( // CHANGE REPLICATION SOURCE TO command: https://dev.mysql.com/doc/refman/8.0/en/change-replication-source-to.html type ReplicationOption struct { Name string - Value string + Value interface{} } -func NewReplicationOption(name string, value string) ReplicationOption { +func NewReplicationOption(name string, value interface{}) ReplicationOption { return ReplicationOption{ Name: name, Value: value, diff --git a/sql/parse/parse.go b/sql/parse/parse.go index 155a5e4be4..3fc3166374 100644 --- a/sql/parse/parse.go +++ b/sql/parse/parse.go @@ -205,10 +205,14 @@ func convert(ctx *sql.Context, stmt sqlparser.Statement, query string) (sql.Node return plan.NewReleaseSavepoint(n.Identifier), nil case *sqlparser.ChangeReplicationSource: return convertChangeReplicationSource(n) + case *sqlparser.ChangeReplicationFilter: + return convertChangeReplicationFilter(n) case *sqlparser.StartReplica: return plan.NewStartReplica(), nil case *sqlparser.StopReplica: return plan.NewStopReplica(), nil + case *sqlparser.ResetReplica: + return plan.NewResetReplica(n.All), nil case *sqlparser.BeginEndBlock: return convertBeginEndBlock(ctx, n, query) case *sqlparser.IfStatement: @@ -531,6 +535,16 @@ func convertChangeReplicationSource(n *sqlparser.ChangeReplicationSource) (sql.N return plan.NewChangeReplicationSource(convertedOptions), nil } +func convertChangeReplicationFilter(n *sqlparser.ChangeReplicationFilter) (sql.Node, error) { + convertedOptions := make([]binlogreplication.ReplicationOption, 0, len(n.Options)) + for _, option := range n.Options { + // TODO: Changing ReplicationOption.Value to interface{} breaks this of course + // Is this what we want to do? + convertedOptions = append(convertedOptions, binlogreplication.NewReplicationOption(option.Name, option.Value)) + } + return plan.NewChangeReplicationFilter(convertedOptions), nil +} + func isSetNames(exprs sqlparser.SetVarExprs) bool { if len(exprs) != 1 { return false diff --git a/sql/plan/replication_commands.go b/sql/plan/replication_commands.go index 9521b1aa1f..cb50bf8997 100644 --- a/sql/plan/replication_commands.go +++ b/sql/plan/replication_commands.go @@ -71,7 +71,8 @@ func (c *ChangeReplicationSource) String() string { } sb.WriteString(option.Name) sb.WriteString(" = ") - sb.WriteString(option.Value) + // TODO: Fix this unsafe type cast + sb.WriteString(option.Value.(string)) } return sb.String() } @@ -89,7 +90,7 @@ func (c *ChangeReplicationSource) RowIter(ctx *sql.Context, _ sql.Row) (sql.RowI return nil, fmt.Errorf("no replication controller available") } - err := c.replicaController.SetReplicationOptions(ctx, c.Options) + err := c.replicaController.SetReplicationSourceOptions(ctx, c.Options) return sql.RowsToRowIter(), err } @@ -107,6 +108,72 @@ func (c *ChangeReplicationSource) CheckPrivileges(_ *sql.Context, _ sql.Privileg return true } +// ChangeReplicationFilter is a plan node for the "CHANGE REPLICATION FILTER" statement. +// https://dev.mysql.com/doc/refman/8.0/en/change-replication-filter.html +type ChangeReplicationFilter struct { + binlogReplicaControllerCommand + Options []binlogreplication.ReplicationOption +} + +var _ sql.Node = (*ChangeReplicationFilter)(nil) +var _ BinlogReplicaControllerCommand = (*ChangeReplicationFilter)(nil) + +func NewChangeReplicationFilter(options []binlogreplication.ReplicationOption) *ChangeReplicationFilter { + return &ChangeReplicationFilter{ + Options: options, + } +} + +func (c *ChangeReplicationFilter) Resolved() bool { + return true +} + +func (c *ChangeReplicationFilter) String() string { + sb := strings.Builder{} + sb.WriteString("CHANGE REPLICATION FILTER ") + for i, option := range c.Options { + if i > 0 { + sb.WriteString(", ") + } + sb.WriteString(option.Name) + sb.WriteString(" = ") + // TODO: Fix this to use better typing + sb.WriteString(fmt.Sprintf("%s", option.Value)) + } + return sb.String() +} + +func (c *ChangeReplicationFilter) Schema() sql.Schema { + return nil +} + +func (c *ChangeReplicationFilter) Children() []sql.Node { + return nil +} + +func (c *ChangeReplicationFilter) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { + if c.replicaController == nil { + return nil, fmt.Errorf("no replication controller available") + } + + err := c.replicaController.SetReplicationFilterOptions(ctx, c.Options) + return sql.RowsToRowIter(), err +} + +func (c *ChangeReplicationFilter) WithChildren(children ...sql.Node) (sql.Node, error) { + if len(children) != 0 { + return nil, sql.ErrInvalidChildrenNumber.New(c, len(children), 0) + } + + newNode := *c + return &newNode, nil +} + +func (c *ChangeReplicationFilter) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { + // TODO: implement privilege checks + return true +} + // StartReplica is a plan node for the "START REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/start-replica.html type StartReplica struct { @@ -210,3 +277,63 @@ func (s *StopReplica) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperationC // TODO: implement privilege checks return true } + +// ResetReplica is a plan node for the "RESET REPLICA" statement. +// https://dev.mysql.com/doc/refman/8.0/en/reset-replica.html +type ResetReplica struct { + binlogReplicaControllerCommand + All bool +} + +var _ sql.Node = (*ResetReplica)(nil) +var _ BinlogReplicaControllerCommand = (*ResetReplica)(nil) + +func NewResetReplica(all bool) *ResetReplica { + return &ResetReplica{ + All: all, + } +} + +func (r *ResetReplica) Resolved() bool { + return true +} + +func (r *ResetReplica) String() string { + sb := strings.Builder{} + sb.WriteString("RESET REPLICA") + if r.All { + sb.WriteString(" ALL") + } + return sb.String() +} + +func (r *ResetReplica) Schema() sql.Schema { + return nil +} + +func (r *ResetReplica) Children() []sql.Node { + return nil +} + +func (r *ResetReplica) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { + if r.replicaController == nil { + return nil, fmt.Errorf("no replication controller available") + } + + err := r.replicaController.ResetReplica(ctx, r.All) + return sql.RowsToRowIter(), err +} + +func (r *ResetReplica) WithChildren(children ...sql.Node) (sql.Node, error) { + if len(children) != 0 { + return nil, sql.ErrInvalidChildrenNumber.New(r, len(children), 0) + } + + newNode := *r + return &newNode, nil +} + +func (r *ResetReplica) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { + // TODO: implement privilege checks + return true +} From 68ca7768f81cbe3e7004160858d02fadc02c31a7 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 11 Jan 2023 16:53:17 -0800 Subject: [PATCH 17/23] Adding ConnectRetryInterval and ConnectRetryCount to ReplicaSourceInfo --- sql/mysql_db/fbs/mysql_db.fbs | 2 ++ sql/mysql_db/mysql_db_load.go | 12 ++++++----- sql/mysql_db/mysql_db_serialize.go | 4 +++- sql/mysql_db/replica_source_info.go | 30 +++++++++++++++++---------- sql/mysql_db/serial/mysql_db.go | 32 ++++++++++++++++++++++++++++- 5 files changed, 62 insertions(+), 18 deletions(-) diff --git a/sql/mysql_db/fbs/mysql_db.fbs b/sql/mysql_db/fbs/mysql_db.fbs index fca38d5f50..82e1a4a0dd 100644 --- a/sql/mysql_db/fbs/mysql_db.fbs +++ b/sql/mysql_db/fbs/mysql_db.fbs @@ -64,6 +64,8 @@ table ReplicaSourceInfo { password:string; port:uint16; uuid:string; + connect_retry_interval:uint32; + connect_retry_count:uint64; } // The MySQL Db containing all the tables diff --git a/sql/mysql_db/mysql_db_load.go b/sql/mysql_db/mysql_db_load.go index f1b813a476..b7ca616d6b 100644 --- a/sql/mysql_db/mysql_db_load.go +++ b/sql/mysql_db/mysql_db_load.go @@ -137,10 +137,12 @@ func LoadRoleEdge(serialRoleEdge *serial.RoleEdge) *RoleEdge { func LoadReplicaSourceInfo(serialReplicaSourceInfo *serial.ReplicaSourceInfo) *ReplicaSourceInfo { return &ReplicaSourceInfo{ - Host: string(serialReplicaSourceInfo.Host()), - User: string(serialReplicaSourceInfo.User()), - Password: string(serialReplicaSourceInfo.Password()), - Port: serialReplicaSourceInfo.Port(), - Uuid: string(serialReplicaSourceInfo.Uuid()), + Host: string(serialReplicaSourceInfo.Host()), + User: string(serialReplicaSourceInfo.User()), + Password: string(serialReplicaSourceInfo.Password()), + Port: serialReplicaSourceInfo.Port(), + Uuid: string(serialReplicaSourceInfo.Uuid()), + ConnectRetryInterval: serialReplicaSourceInfo.ConnectRetryInterval(), + ConnectRetryCount: serialReplicaSourceInfo.ConnectRetryCount(), } } diff --git a/sql/mysql_db/mysql_db_serialize.go b/sql/mysql_db/mysql_db_serialize.go index 9d3e088184..52ace01188 100644 --- a/sql/mysql_db/mysql_db_serialize.go +++ b/sql/mysql_db/mysql_db_serialize.go @@ -212,8 +212,10 @@ func serializeReplicaSourceInfo(b *flatbuffers.Builder, replicaSourceInfos []*Re serial.ReplicaSourceInfoAddPassword(b, password) serial.ReplicaSourceInfoAddUuid(b, uuid) - // Write Port (uint value doesn't need offset) + // Write non-string fields (uint value doesn't need offset) serial.ReplicaSourceInfoAddPort(b, replicaSourceInfo.Port) + serial.ReplicaSourceInfoAddConnectRetryInterval(b, replicaSourceInfo.ConnectRetryInterval) + serial.ReplicaSourceInfoAddConnectRetryCount(b, replicaSourceInfo.ConnectRetryCount) // End ReplicaSourceInfo offsets[len(replicaSourceInfos)-i-1] = serial.ReplicaSourceInfoEnd(b) diff --git a/sql/mysql_db/replica_source_info.go b/sql/mysql_db/replica_source_info.go index fcd4536b1b..f35da813db 100644 --- a/sql/mysql_db/replica_source_info.go +++ b/sql/mysql_db/replica_source_info.go @@ -25,11 +25,13 @@ import ( // in the mysql database. // For more details, see: https://dev.mysql.com/doc/refman/8.0/en/replica-logs-status.html type ReplicaSourceInfo struct { - Host string - User string - Password string - Port uint16 - Uuid string + Host string + User string + Password string + Port uint16 + Uuid string + ConnectRetryInterval uint32 + ConnectRetryCount uint64 } var _ in_mem_table.Entry = (*ReplicaSourceInfo)(nil) @@ -41,11 +43,13 @@ func (r *ReplicaSourceInfo) NewFromRow(_ *sql.Context, row sql.Row) (in_mem_tabl } return &ReplicaSourceInfo{ - Host: row[replicaSourceInfoTblColIndex_Host].(string), - User: row[replicaSourceInfoTblColIndex_User_name].(string), - Password: row[replicaSourceInfoTblColIndex_User_password].(string), - Port: row[replicaSourceInfoTblColIndex_Port].(uint16), - Uuid: row[replicaSourceInfoTblColIndex_Uuid].(string), + Host: row[replicaSourceInfoTblColIndex_Host].(string), + User: row[replicaSourceInfoTblColIndex_User_name].(string), + Password: row[replicaSourceInfoTblColIndex_User_password].(string), + Port: row[replicaSourceInfoTblColIndex_Port].(uint16), + Uuid: row[replicaSourceInfoTblColIndex_Uuid].(string), + ConnectRetryInterval: row[replicaSourceInfoTblColIndex_Connect_retry].(uint32), + ConnectRetryCount: row[replicaSourceInfoTblColIndex_Retry_count].(uint64), }, nil } @@ -80,6 +84,8 @@ func (r *ReplicaSourceInfo) ToRow(ctx *sql.Context) sql.Row { } row[replicaSourceInfoTblColIndex_User_password] = r.Password row[replicaSourceInfoTblColIndex_Port] = r.Port + row[replicaSourceInfoTblColIndex_Connect_retry] = r.ConnectRetryInterval + row[replicaSourceInfoTblColIndex_Retry_count] = r.ConnectRetryCount return row } @@ -96,7 +102,9 @@ func (r *ReplicaSourceInfo) Equals(_ *sql.Context, otherEntry in_mem_table.Entry r.Host != other.Host || r.Port != other.Port || r.Password != other.Password || - r.Uuid != other.Uuid { + r.Uuid != other.Uuid || + r.ConnectRetryInterval != other.ConnectRetryInterval || + r.ConnectRetryCount != other.ConnectRetryCount { return false } diff --git a/sql/mysql_db/serial/mysql_db.go b/sql/mysql_db/serial/mysql_db.go index cebc192740..a75461b5af 100644 --- a/sql/mysql_db/serial/mysql_db.go +++ b/sql/mysql_db/serial/mysql_db.go @@ -728,8 +728,32 @@ func (rcv *ReplicaSourceInfo) Uuid() []byte { return nil } +func (rcv *ReplicaSourceInfo) ConnectRetryInterval() uint32 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(14)) + if o != 0 { + return rcv._tab.GetUint32(o + rcv._tab.Pos) + } + return 0 +} + +func (rcv *ReplicaSourceInfo) MutateConnectRetryInterval(n uint32) bool { + return rcv._tab.MutateUint32Slot(14, n) +} + +func (rcv *ReplicaSourceInfo) ConnectRetryCount() uint64 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(16)) + if o != 0 { + return rcv._tab.GetUint64(o + rcv._tab.Pos) + } + return 0 +} + +func (rcv *ReplicaSourceInfo) MutateConnectRetryCount(n uint64) bool { + return rcv._tab.MutateUint64Slot(16, n) +} + func ReplicaSourceInfoStart(builder *flatbuffers.Builder) { - builder.StartObject(5) + builder.StartObject(7) } func ReplicaSourceInfoAddHost(builder *flatbuffers.Builder, host flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(host), 0) @@ -746,6 +770,12 @@ func ReplicaSourceInfoAddPort(builder *flatbuffers.Builder, port uint16) { func ReplicaSourceInfoAddUuid(builder *flatbuffers.Builder, uuid flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(4, flatbuffers.UOffsetT(uuid), 0) } +func ReplicaSourceInfoAddConnectRetryInterval(builder *flatbuffers.Builder, connectRetryInterval uint32) { + builder.PrependUint32Slot(5, connectRetryInterval, 0) +} +func ReplicaSourceInfoAddConnectRetryCount(builder *flatbuffers.Builder, connectRetryCount uint64) { + builder.PrependUint64Slot(6, connectRetryCount, 0) +} func ReplicaSourceInfoEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() } From 0be5df9bff2d6527345c4e4258c3b3655ed269b6 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Thu, 12 Jan 2023 16:32:18 -0800 Subject: [PATCH 18/23] Tidying up --- sql/binlogreplication/binlog_replication.go | 4 ++-- sql/mysql_db/replica_source_info.go | 9 +++++++++ sql/plan/show_replica_status.go | 11 +++-------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/sql/binlogreplication/binlog_replication.go b/sql/binlogreplication/binlog_replication.go index 7c16a4d6aa..c8be19df71 100644 --- a/sql/binlogreplication/binlog_replication.go +++ b/sql/binlogreplication/binlog_replication.go @@ -65,8 +65,8 @@ type ReplicaStatus struct { SourceHost string SourceUser string SourcePort uint - ConnectRetry uint - SourceRetryCount uint + ConnectRetry uint32 + SourceRetryCount uint64 ReplicaIoRunning string ReplicaSqlRunning string LastSqlErrNumber uint // Alias for LastErrNumber diff --git a/sql/mysql_db/replica_source_info.go b/sql/mysql_db/replica_source_info.go index f35da813db..2d2399b4b2 100644 --- a/sql/mysql_db/replica_source_info.go +++ b/sql/mysql_db/replica_source_info.go @@ -36,6 +36,15 @@ type ReplicaSourceInfo struct { var _ in_mem_table.Entry = (*ReplicaSourceInfo)(nil) +// NewReplicaSourceInfo constructs a new ReplicaSourceInfo instance, with defaults applied. +func NewReplicaSourceInfo() *ReplicaSourceInfo { + return &ReplicaSourceInfo{ + Port: 3306, + ConnectRetryInterval: 60, + ConnectRetryCount: 86400, + } +} + // NewFromRow implements the interface in_mem_table.Entry. func (r *ReplicaSourceInfo) NewFromRow(_ *sql.Context, row sql.Row) (in_mem_table.Entry, error) { if err := replicaSourceInfoTblSchema.CheckRow(row); err != nil { diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go index bc494f1cc4..f98959f4fe 100644 --- a/sql/plan/show_replica_status.go +++ b/sql/plan/show_replica_status.go @@ -20,13 +20,12 @@ import ( "github.com/dolthub/vitess/go/sqltypes" "github.com/dolthub/go-mysql-server/sql" - "github.com/dolthub/go-mysql-server/sql/binlogreplication" ) // ShowReplicaStatus is the plan node for the "SHOW REPLICA STATUS" statement. // https://dev.mysql.com/doc/refman/8.0/en/show-replica-status.html type ShowReplicaStatus struct { - replicaController binlogreplication.BinlogReplicaController + binlogReplicaControllerCommand } var _ sql.Node = (*ShowReplicaStatus)(nil) @@ -36,10 +35,6 @@ func NewShowReplicaStatus() *ShowReplicaStatus { return &ShowReplicaStatus{} } -func (s *ShowReplicaStatus) SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { - s.replicaController = controller -} - func (s *ShowReplicaStatus) Resolved() bool { return true } @@ -87,9 +82,9 @@ func (s *ShowReplicaStatus) Schema() sql.Schema { {Name: "Source_SSL_Verify_Server_Cert", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, {Name: "Seconds_Behind_Source", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, {Name: "Last_IO_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Last_IO_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_IO_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, {Name: "Last_SQL_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Last_SQL_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_SQL_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, {Name: "Replicate_Ignore_Server_Ids", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, {Name: "Source_Server_Id", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, {Name: "Source_UUID", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, From 35b177da4aba7821c1b8e65a2622737ad9cf8e19 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 18 Jan 2023 16:13:39 -0800 Subject: [PATCH 19/23] Cleaning up replication option support and including initial replica filtering info in 'SHOW REPLICA STATUS' --- sql/binlogreplication/binlog_replication.go | 96 ++++++++++++++++++++- sql/parse/parse.go | 34 +++++++- sql/plan/replication_commands.go | 5 +- sql/plan/show_replica_status.go | 27 +++--- 4 files changed, 141 insertions(+), 21 deletions(-) diff --git a/sql/binlogreplication/binlog_replication.go b/sql/binlogreplication/binlog_replication.go index c8be19df71..886812ee8d 100644 --- a/sql/binlogreplication/binlog_replication.go +++ b/sql/binlogreplication/binlog_replication.go @@ -15,6 +15,9 @@ package binlogreplication import ( + "fmt" + "strconv" + "strings" "time" "github.com/dolthub/go-mysql-server/sql" @@ -80,6 +83,8 @@ type ReplicaStatus struct { RetrievedGtidSet string ExecutedGtidSet string AutoPosition bool + ReplicateDoTables []string + ReplicateIgnoreTables []string } const ( @@ -94,11 +99,96 @@ const ( // CHANGE REPLICATION SOURCE TO command: https://dev.mysql.com/doc/refman/8.0/en/change-replication-source-to.html type ReplicationOption struct { Name string - Value interface{} + Value ReplicationOptionValue } -func NewReplicationOption(name string, value interface{}) ReplicationOption { - return ReplicationOption{ +// ReplicationOptionValue defines an interface for configuration option values for binlog replication. It holds the +// values of options for configuring the replication source (i.e. "CHANGE REPLICATION SOURCE TO" options) and for +// replication filtering (i.g. "SET REPLICATION FILTER" options). +type ReplicationOptionValue interface { + fmt.Stringer + + // GetValue returns the raw, untyped option value. This method should generally not be used; callers should instead + // find the specific type implementing the ReplicationOptionValue interface and use its functions in order to get + // typed values. + GetValue() interface{} +} + +// StringReplicationOptionValue is a ReplicationOptionValue implementation that holds a string value. +type StringReplicationOptionValue struct { + Value string +} + +var _ ReplicationOptionValue = (*StringReplicationOptionValue)(nil) + +func (ov StringReplicationOptionValue) GetValue() interface{} { + return ov.GetValueAsString() +} + +func (ov StringReplicationOptionValue) GetValueAsString() string { + return ov.Value +} + +// String implements the Stringer interface and returns a string representation of this option value. +func (ov StringReplicationOptionValue) String() string { + return ov.Value +} + +// TableNamesReplicationOptionValue is a ReplicationOptionValue implementation that holds a list of table names for +// its value. +type TableNamesReplicationOptionValue struct { + Value []sql.UnresolvedTable +} + +var _ ReplicationOptionValue = (*TableNamesReplicationOptionValue)(nil) + +func (ov TableNamesReplicationOptionValue) GetValue() interface{} { + return ov.GetValueAsTableList() +} + +func (ov TableNamesReplicationOptionValue) GetValueAsTableList() []sql.UnresolvedTable { + return ov.Value +} + +// String implements the Stringer interface and returns a string representation of this option value. +func (ov TableNamesReplicationOptionValue) String() string { + sb := strings.Builder{} + for i, urt := range ov.Value { + if i > 0 { + sb.WriteString(", ") + } + if urt.Database() != "" { + sb.WriteString(urt.Database()) + sb.WriteString(".") + } + sb.WriteString(urt.Name()) + } + return sb.String() +} + +// IntegerReplicationOptionValue is a ReplicationOptionValue implementation that holds an integer value. +type IntegerReplicationOptionValue struct { + Value int +} + +var _ ReplicationOptionValue = (*IntegerReplicationOptionValue)(nil) + +func (ov IntegerReplicationOptionValue) GetValue() interface{} { + return ov.GetValueAsInt() +} + +func (ov IntegerReplicationOptionValue) GetValueAsInt() int { + return ov.Value +} + +// String implements the Stringer interface and returns a string representation of this option value. +func (ov IntegerReplicationOptionValue) String() string { + return strconv.Itoa(ov.Value) +} + +// NewReplicationOption creates a new ReplicationOption instance, with the specified |name| and |value|. +func NewReplicationOption(name string, value ReplicationOptionValue) *ReplicationOption { + return &ReplicationOption{ Name: name, Value: value, } diff --git a/sql/parse/parse.go b/sql/parse/parse.go index 3fc3166374..3a4714fd43 100644 --- a/sql/parse/parse.go +++ b/sql/parse/parse.go @@ -530,17 +530,43 @@ func convertSet(ctx *sql.Context, n *sqlparser.Set) (sql.Node, error) { func convertChangeReplicationSource(n *sqlparser.ChangeReplicationSource) (sql.Node, error) { convertedOptions := make([]binlogreplication.ReplicationOption, 0, len(n.Options)) for _, option := range n.Options { - convertedOptions = append(convertedOptions, binlogreplication.NewReplicationOption(option.Name, option.Value)) + convertedOption, err := convertReplicationOption(option) + if err != nil { + return nil, err + } + convertedOptions = append(convertedOptions, *convertedOption) } return plan.NewChangeReplicationSource(convertedOptions), nil } +func convertReplicationOption(option *sqlparser.ReplicationOption) (*binlogreplication.ReplicationOption, error) { + if option.Value == nil { + return nil, fmt.Errorf("nil replication option specified for option %q", option.Name) + } + switch vv := option.Value.(type) { + case string: + return binlogreplication.NewReplicationOption(option.Name, binlogreplication.StringReplicationOptionValue{Value: vv}), nil + case int: + return binlogreplication.NewReplicationOption(option.Name, binlogreplication.IntegerReplicationOptionValue{Value: vv}), nil + case sqlparser.TableNames: + urts := make([]sql.UnresolvedTable, len(vv)) + for i, tableName := range vv { + urts[i] = tableNameToUnresolvedTable(tableName) + } + return binlogreplication.NewReplicationOption(option.Name, binlogreplication.TableNamesReplicationOptionValue{Value: urts}), nil + default: + return nil, fmt.Errorf("unsupported option value type '%T' specified for option %q", option.Value, option.Name) + } +} + func convertChangeReplicationFilter(n *sqlparser.ChangeReplicationFilter) (sql.Node, error) { convertedOptions := make([]binlogreplication.ReplicationOption, 0, len(n.Options)) for _, option := range n.Options { - // TODO: Changing ReplicationOption.Value to interface{} breaks this of course - // Is this what we want to do? - convertedOptions = append(convertedOptions, binlogreplication.NewReplicationOption(option.Name, option.Value)) + convertedOption, err := convertReplicationOption(option) + if err != nil { + return nil, err + } + convertedOptions = append(convertedOptions, *convertedOption) } return plan.NewChangeReplicationFilter(convertedOptions), nil } diff --git a/sql/plan/replication_commands.go b/sql/plan/replication_commands.go index cb50bf8997..a7e38c93ee 100644 --- a/sql/plan/replication_commands.go +++ b/sql/plan/replication_commands.go @@ -69,10 +69,7 @@ func (c *ChangeReplicationSource) String() string { if i > 0 { sb.WriteString(", ") } - sb.WriteString(option.Name) - sb.WriteString(" = ") - // TODO: Fix this unsafe type cast - sb.WriteString(option.Value.(string)) + sb.WriteString(fmt.Sprintf("%s = %s", option.Name, option.Value)) } return sb.String() } diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go index f98959f4fe..efdeb4dcfa 100644 --- a/sql/plan/show_replica_status.go +++ b/sql/plan/show_replica_status.go @@ -15,6 +15,7 @@ package plan import ( + "strings" "time" "github.com/dolthub/vitess/go/sqltypes" @@ -59,8 +60,8 @@ func (s *ShowReplicaStatus) Schema() sql.Schema { {Name: "Replica_SQL_Running", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, {Name: "Replicate_Do_DB", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, {Name: "Replicate_Ignore_DB", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, - {Name: "Replicate_Do_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, - {Name: "Replicate_Ignore_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replicate_Do_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, + {Name: "Replicate_Ignore_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, {Name: "Replicate_Wild_Do_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, {Name: "Replicate_Wild_Ignore_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, {Name: "Last_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, @@ -120,6 +121,12 @@ func (s *ShowReplicaStatus) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, return sql.RowsToRowIter(), nil } + replicateDoTables := strings.Join(status.ReplicateDoTables, ",") + replicateIgnoreTables := strings.Join(status.ReplicateIgnoreTables, ",") + + lastIoErrorTimestamp := formatReplicaStatusTimestamp(status.LastIoErrorTimestamp) + lastSqlErrorTimestamp := formatReplicaStatusTimestamp(status.LastSqlErrorTimestamp) + row = sql.Row{ "", // Replica_IO_State status.SourceHost, // Source_Host @@ -135,8 +142,8 @@ func (s *ShowReplicaStatus) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, status.ReplicaSqlRunning, // Replica_SQL_Running nil, // Replicate_Do_DB nil, // Replicate_Ignore_DB - nil, // Replicate_Do_Table - nil, // Replicate_Ignore_Table + replicateDoTables, // Replicate_Do_Table + replicateIgnoreTables, // Replicate_Ignore_Table nil, // Replicate_Wild_Do_Table nil, // Replicate_Wild_Ignore_Table status.LastSqlErrNumber, // Last_Errno @@ -170,12 +177,12 @@ func (s *ShowReplicaStatus) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, nil, // Replica_SQL_Running_State status.SourceRetryCount, // Source_Retry_Count nil, // Source_Bind - formatReplicaStatusTimestamp(status.LastIoErrorTimestamp), // Last_IO_Error_Timestamp - formatReplicaStatusTimestamp(status.LastSqlErrorTimestamp), // Last_SQL_Error_Timestamp - status.RetrievedGtidSet, // Retrieved_Gtid_Set - status.ExecutedGtidSet, // Executed_Gtid_Set - status.AutoPosition, // Auto_Position - nil, // Replicate_Rewrite_DB + lastIoErrorTimestamp, // Last_IO_Error_Timestamp + lastSqlErrorTimestamp, // Last_SQL_Error_Timestamp + status.RetrievedGtidSet, // Retrieved_Gtid_Set + status.ExecutedGtidSet, // Executed_Gtid_Set + status.AutoPosition, // Auto_Position + nil, // Replicate_Rewrite_DB } return sql.RowsToRowIter(row), nil From e181a83027b942107f747d22c901065f84b4194b Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 18 Jan 2023 16:55:35 -0800 Subject: [PATCH 20/23] Bumping to latest vitess version from fulghum/binlog-replication branch --- go.mod | 2 +- go.sum | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 04bf56ae0b..79a697fef5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/dolthub/go-mysql-server require ( github.com/cespare/xxhash v1.1.0 github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 - github.com/dolthub/vitess v0.0.0-20230105173952-b40441dfeb0c + github.com/dolthub/vitess v0.0.0-20230119004230-012c165af84f github.com/go-kit/kit v0.10.0 github.com/go-sql-driver/mysql v1.6.0 github.com/gocraft/dbr/v2 v2.7.2 diff --git a/go.sum b/go.sum index e38fb541c2..6076e950dc 100755 --- a/go.sum +++ b/go.sum @@ -55,8 +55,6 @@ github.com/dolthub/jsonpath v0.0.0-20210609232853-d49537a30474 h1:xTrR+l5l+1Lfq0 github.com/dolthub/jsonpath v0.0.0-20210609232853-d49537a30474/go.mod h1:kMz7uXOXq4qRriCEyZ/LUeTqraLJCjf0WVZcUi6TxUY= github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9XGFa6q5Ap4Z/OhNkAMBaK5YeuEzwJt+NZdhiE= github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81/go.mod h1:siLfyv2c92W1eN/R4QqG/+RjjX5W2+gCTRjZxBjI3TY= -github.com/dolthub/vitess v0.0.0-20230105173952-b40441dfeb0c h1:/Iws14y/fC75qzgTv2s1KuQCgRGbtC2j1UGPrHLb2xE= -github.com/dolthub/vitess v0.0.0-20230105173952-b40441dfeb0c/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= From 0c6830ac00d61334876ceeaf9650fb88b44abcdb Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Wed, 18 Jan 2023 17:02:01 -0800 Subject: [PATCH 21/23] Updating from sql->types refactoring --- go.sum | 2 + sql/plan/show_replica_status.go | 115 ++++++++++++++++---------------- 2 files changed, 60 insertions(+), 57 deletions(-) diff --git a/go.sum b/go.sum index 6076e950dc..3d19078dc9 100644 --- a/go.sum +++ b/go.sum @@ -55,6 +55,8 @@ github.com/dolthub/jsonpath v0.0.0-20210609232853-d49537a30474 h1:xTrR+l5l+1Lfq0 github.com/dolthub/jsonpath v0.0.0-20210609232853-d49537a30474/go.mod h1:kMz7uXOXq4qRriCEyZ/LUeTqraLJCjf0WVZcUi6TxUY= github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9XGFa6q5Ap4Z/OhNkAMBaK5YeuEzwJt+NZdhiE= github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81/go.mod h1:siLfyv2c92W1eN/R4QqG/+RjjX5W2+gCTRjZxBjI3TY= +github.com/dolthub/vitess v0.0.0-20230119004230-012c165af84f h1:I7gdWTiJ6vGk+DCOzDtnDUFx5ihCJgD5WHgiYcGuj44= +github.com/dolthub/vitess v0.0.0-20230119004230-012c165af84f/go.mod h1:oVFIBdqMFEkt4Xz2fzFJBNtzKhDEjwdCF0dzde39iKs= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go index efdeb4dcfa..507fb92bde 100644 --- a/sql/plan/show_replica_status.go +++ b/sql/plan/show_replica_status.go @@ -18,9 +18,10 @@ import ( "strings" "time" - "github.com/dolthub/vitess/go/sqltypes" - "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/types" + + "github.com/dolthub/vitess/go/sqltypes" ) // ShowReplicaStatus is the plan node for the "SHOW REPLICA STATUS" statement. @@ -46,61 +47,61 @@ func (s *ShowReplicaStatus) String() string { func (s *ShowReplicaStatus) Schema() sql.Schema { return sql.Schema{ - {Name: "Replica_IO_State", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_Host", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_User", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_Port", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Connect_Retry", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_Log_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Read_Source_Log_Pos", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Relay_Log_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Relay_Log_Pos", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Relay_Source_Log_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Replica_IO_Running", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, - {Name: "Replica_SQL_Running", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, - {Name: "Replicate_Do_DB", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, - {Name: "Replicate_Ignore_DB", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, - {Name: "Replicate_Do_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, - {Name: "Replicate_Ignore_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, - {Name: "Replicate_Wild_Do_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, - {Name: "Replicate_Wild_Ignore_Table", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, - {Name: "Last_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Last_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Skip_Counter", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Exec_Source_Log_Pos", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Relay_Log_Space", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Until_Condition", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Until_Log_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Until_Log_Pos", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_SSL_Allowed", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_SSL_CA_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_SSL_CA_Path", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_SSL_Cert", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_SSL_Cipher", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_SSL_CRL_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_SSL_CRL_Path", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_SSL_Key", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_SSL_Verify_Server_Cert", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Seconds_Behind_Source", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Last_IO_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Last_IO_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, - {Name: "Last_SQL_Errno", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Last_SQL_Error", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, - {Name: "Replicate_Ignore_Server_Ids", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_Server_Id", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_UUID", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_Info_File", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "SQL_Delay", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "SQL_Remaining_Delay", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Replica_SQL_Running_State", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_Retry_Count", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Source_Bind", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Last_IO_Error_Timestamp", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Last_SQL_Error_Timestamp", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Retrieved_Gtid_Set", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, - {Name: "Executed_Gtid_Set", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, - {Name: "Auto_Position", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, - {Name: "Replicate_Rewrite_DB", Type: sql.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Replica_IO_State", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Host", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_User", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Port", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Connect_Retry", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Log_File", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Read_Source_Log_Pos", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Relay_Log_File", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Relay_Log_Pos", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Relay_Source_Log_File", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Replica_IO_Running", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replica_SQL_Running", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replicate_Do_DB", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replicate_Ignore_DB", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replicate_Do_Table", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, + {Name: "Replicate_Ignore_Table", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, + {Name: "Replicate_Wild_Do_Table", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Replicate_Wild_Ignore_Table", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Last_Errno", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_Error", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Skip_Counter", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Exec_Source_Log_Pos", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Relay_Log_Space", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Until_Condition", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Until_Log_File", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Until_Log_Pos", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_Allowed", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_CA_File", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_CA_Path", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_Cert", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_Cipher", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_CRL_File", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_CRL_Path", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_Key", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_SSL_Verify_Server_Cert", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Seconds_Behind_Source", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_IO_Errno", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_IO_Error", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, + {Name: "Last_SQL_Errno", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_SQL_Error", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 256), Default: nil, Nullable: false}, + {Name: "Replicate_Ignore_Server_Ids", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Server_Id", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_UUID", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Info_File", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "SQL_Delay", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "SQL_Remaining_Delay", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Replica_SQL_Running_State", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Retry_Count", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Source_Bind", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_IO_Error_Timestamp", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Last_SQL_Error_Timestamp", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Retrieved_Gtid_Set", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Executed_Gtid_Set", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 128), Default: nil, Nullable: false}, + {Name: "Auto_Position", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, + {Name: "Replicate_Rewrite_DB", Type: types.MustCreateStringWithDefaults(sqltypes.VarChar, 64), Default: nil, Nullable: false}, } } From 6b94baf1e5f8bcff6b9c368adf70eb9e3719b924 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Thu, 19 Jan 2023 10:51:49 -0800 Subject: [PATCH 22/23] Adding `server_id` sys var --- enginetest/queries/variable_queries.go | 17 +++++++++++++++++ sql/variables/system_variables.go | 8 ++++++++ 2 files changed, 25 insertions(+) diff --git a/enginetest/queries/variable_queries.go b/enginetest/queries/variable_queries.go index 2c52a3b515..f4f85aee26 100644 --- a/enginetest/queries/variable_queries.go +++ b/enginetest/queries/variable_queries.go @@ -48,6 +48,23 @@ var VariableQueries = []ScriptTest{ {uint64(2)}, }, }, + { + Name: "@@server_id", + Assertions: []ScriptTestAssertion{ + { + Query: "select @@server_id;", + Expected: []sql.Row{{0}}, + }, + { + Query: "set @@server_id=123;", + Expected: []sql.Row{{}}, + }, + { + Query: "set @@GLOBAL.server_id=123;", + Expected: []sql.Row{{}}, + }, + }, + }, { Name: "set system variables and user variables", SetUpScript: []string{ diff --git a/sql/variables/system_variables.go b/sql/variables/system_variables.go index c992dc086f..b349c32bd2 100755 --- a/sql/variables/system_variables.go +++ b/sql/variables/system_variables.go @@ -2040,6 +2040,14 @@ var systemVars = map[string]sql.SystemVariable{ Type: types.NewSystemIntType("select_into_disk_sync_delay", 0, 31536000, false), Default: int64(0), }, + "server_id": { + Name: "server_id", + Scope: sql.SystemVariableScope_Persist, + Dynamic: true, + SetVarHintApplies: false, + Type: types.Uint32, + Default: 0, + }, "session_track_gtids": { Name: "session_track_gtids", Scope: sql.SystemVariableScope_Both, From 45e839bfa22a81bdc2a8ceb463b1b87262422ba2 Mon Sep 17 00:00:00 2001 From: Jason Fulghum Date: Tue, 24 Jan 2023 09:45:24 -0800 Subject: [PATCH 23/23] Changing to apply the binlog replica controller through an analyzer rule, instead of directly in the engine code --- engine.go | 26 ++--- sql/analyzer/analyzer.go | 4 + sql/analyzer/apply_binlog_controller.go | 33 ++++++ sql/analyzer/rule_ids.go | 89 +++++++-------- sql/analyzer/ruleid_string.go | 143 ++++++++++++------------ sql/analyzer/rules.go | 1 + sql/plan/replication_commands.go | 69 ++++++++---- sql/plan/show_replica_status.go | 10 +- 8 files changed, 220 insertions(+), 155 deletions(-) create mode 100644 sql/analyzer/apply_binlog_controller.go diff --git a/engine.go b/engine.go index 4af41a90ea..d6b99a0887 100644 --- a/engine.go +++ b/engine.go @@ -24,7 +24,6 @@ import ( "github.com/dolthub/go-mysql-server/memory" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/analyzer" - "github.com/dolthub/go-mysql-server/sql/binlogreplication" "github.com/dolthub/go-mysql-server/sql/expression" "github.com/dolthub/go-mysql-server/sql/expression/function" "github.com/dolthub/go-mysql-server/sql/parse" @@ -117,16 +116,15 @@ func (p *PreparedDataCache) UncacheStmt(sessId uint32, query string) { // Engine is a SQL engine. type Engine struct { - Analyzer *analyzer.Analyzer - LS *sql.LockSubsystem - ProcessList sql.ProcessList - MemoryManager *sql.MemoryManager - BackgroundThreads *sql.BackgroundThreads - IsReadOnly bool - IsServerLocked bool - PreparedDataCache *PreparedDataCache - BinlogReplicaController binlogreplication.BinlogReplicaController - mu *sync.Mutex + Analyzer *analyzer.Analyzer + LS *sql.LockSubsystem + ProcessList sql.ProcessList + MemoryManager *sql.MemoryManager + BackgroundThreads *sql.BackgroundThreads + IsReadOnly bool + IsServerLocked bool + PreparedDataCache *PreparedDataCache + mu *sync.Mutex } type ColumnWithRawDefault struct { @@ -237,12 +235,6 @@ func (e *Engine) QueryNodeWithBindings( } } - // The replica controller reference is held by |Engine|, so for any BinlogReplicaControllerCommands, - // we supply their replica controller here, before the command gets to the analyzer. - if nn, ok := parsed.(plan.BinlogReplicaControllerCommand); ok { - nn.SetBinlogReplicaController(e.BinlogReplicaController) - } - // Before we begin a transaction, we need to know if the database being operated on is not the one // currently selected transactionDatabase := analyzer.GetTransactionDatabase(ctx, parsed) diff --git a/sql/analyzer/analyzer.go b/sql/analyzer/analyzer.go index c90c1da228..294985762c 100644 --- a/sql/analyzer/analyzer.go +++ b/sql/analyzer/analyzer.go @@ -26,6 +26,7 @@ import ( "gopkg.in/src-d/go-errors.v1" "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/binlogreplication" "github.com/dolthub/go-mysql-server/sql/transform" ) @@ -279,6 +280,9 @@ type Analyzer struct { Batches []*Batch // Catalog of databases and registered functions. Catalog *Catalog + // BinlogReplicaController holds an optional controller that receives forwarded binlog + // replication messages (e.g. "start replica"). + BinlogReplicaController binlogreplication.BinlogReplicaController } // NewDefault creates a default Analyzer instance with all default Rules and configuration. diff --git a/sql/analyzer/apply_binlog_controller.go b/sql/analyzer/apply_binlog_controller.go new file mode 100644 index 0000000000..9432e21037 --- /dev/null +++ b/sql/analyzer/apply_binlog_controller.go @@ -0,0 +1,33 @@ +// Copyright 2023 Dolthub, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package analyzer + +import ( + "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/plan" + "github.com/dolthub/go-mysql-server/sql/transform" +) + +// applyBinlogReplicaController configures all BinlogReplicaControllerCommand nodes with the +// BinlogReplicaController that the Analyzer holds. +func applyBinlogReplicaController(_ *sql.Context, a *Analyzer, n sql.Node, _ *Scope, _ RuleSelector) (sql.Node, transform.TreeIdentity, error) { + return transform.Node(n, func(n sql.Node) (sql.Node, transform.TreeIdentity, error) { + if nn, ok := n.(plan.BinlogReplicaControllerCommand); ok { + return nn.WithBinlogReplicaController(a.BinlogReplicaController), transform.NewTree, nil + } else { + return n, transform.SameTree, nil + } + }) +} diff --git a/sql/analyzer/rule_ids.go b/sql/analyzer/rule_ids.go index 7bfc2c24fe..0847d33b0b 100644 --- a/sql/analyzer/rule_ids.go +++ b/sql/analyzer/rule_ids.go @@ -6,50 +6,51 @@ type RuleId int const ( // once before - applyDefaultSelectLimitId RuleId = iota // applyDefaultSelectLimit - validateOffsetAndLimitId //validateOffsetAndLimit - validateCreateTableId // validateCreateTable - validateExprSemId // validateExprSem - resolveVariablesId // resolveVariables - resolveNamedWindowsId // resolveNamedWindows - resolveSetVariablesId // resolveSetVariables - resolveViewsId // resolveViews - liftCtesId // liftCtes - resolveCtesId // resolveCtes - liftRecursiveCtesId // liftRecursiveCtes - resolveDatabasesId // resolveDatabases - resolveTablesId // resolveTables - loadStoredProceduresId // loadStoredProcedures - validateDropTablesId // validateDropTables - setTargetSchemasId // setTargetSchemas - resolveCreateLikeId // resolveCreateLike - parseColumnDefaultsId // parseColumnDefaults - resolveDropConstraintId // resolveDropConstraint - validateDropConstraintId // validateDropConstraint - loadCheckConstraintsId // loadCheckConstraints - assignCatalogId // assignCatalog - resolveAnalyzeTablesId //resolveAnalyzeTables - resolveCreateSelectId // resolveCreateSelect - resolveSubqueriesId // resolveSubqueries - setViewTargetSchemaId // setViewTargetSchema - resolveUnionsId // resolveUnions - resolveDescribeQueryId // resolveDescribeQuery - checkUniqueTableNamesId // checkUniqueTableNames - resolveTableFunctionsId // resolveTableFunctions - resolveDeclarationsId // resolveDeclarations - resolveColumnDefaultsId // resolveColumnDefaults - validateColumnDefaultsId // validateColumnDefaults - validateCreateTriggerId // validateCreateTrigger - validateCreateProcedureId // validateCreateProcedure - loadInfoSchemaId // loadInfoSchema - validateReadOnlyDatabaseId // validateReadOnlyDatabase - validateReadOnlyTransactionId // validateReadOnlyTransaction - validateDatabaseSetId // validateDatabaseSet - validatePrivilegesId // validatePrivileges - reresolveTablesId // reresolveTables - transformJoinApplyId // transformJoinApply - setInsertColumnsId // setInsertColumns - validateJoinComplexityId // validateJoinComplexity + applyDefaultSelectLimitId RuleId = iota // applyDefaultSelectLimit + validateOffsetAndLimitId //validateOffsetAndLimit + validateCreateTableId // validateCreateTable + validateExprSemId // validateExprSem + resolveVariablesId // resolveVariables + resolveNamedWindowsId // resolveNamedWindows + resolveSetVariablesId // resolveSetVariables + resolveViewsId // resolveViews + liftCtesId // liftCtes + resolveCtesId // resolveCtes + liftRecursiveCtesId // liftRecursiveCtes + resolveDatabasesId // resolveDatabases + resolveTablesId // resolveTables + loadStoredProceduresId // loadStoredProcedures + validateDropTablesId // validateDropTables + setTargetSchemasId // setTargetSchemas + resolveCreateLikeId // resolveCreateLike + parseColumnDefaultsId // parseColumnDefaults + resolveDropConstraintId // resolveDropConstraint + validateDropConstraintId // validateDropConstraint + loadCheckConstraintsId // loadCheckConstraints + assignCatalogId // assignCatalog + resolveAnalyzeTablesId //resolveAnalyzeTables + resolveCreateSelectId // resolveCreateSelect + resolveSubqueriesId // resolveSubqueries + setViewTargetSchemaId // setViewTargetSchema + resolveUnionsId // resolveUnions + resolveDescribeQueryId // resolveDescribeQuery + checkUniqueTableNamesId // checkUniqueTableNames + resolveTableFunctionsId // resolveTableFunctions + resolveDeclarationsId // resolveDeclarations + resolveColumnDefaultsId // resolveColumnDefaults + validateColumnDefaultsId // validateColumnDefaults + validateCreateTriggerId // validateCreateTrigger + validateCreateProcedureId // validateCreateProcedure + loadInfoSchemaId // loadInfoSchema + validateReadOnlyDatabaseId // validateReadOnlyDatabase + validateReadOnlyTransactionId // validateReadOnlyTransaction + validateDatabaseSetId // validateDatabaseSet + validatePrivilegesId // validatePrivileges + reresolveTablesId // reresolveTables + transformJoinApplyId // transformJoinApply + setInsertColumnsId // setInsertColumns + validateJoinComplexityId // validateJoinComplexity + applyBinlogReplicaControllerId // applyBinlogReplicaController // default resolveNaturalJoinsId // resolveNaturalJoins diff --git a/sql/analyzer/ruleid_string.go b/sql/analyzer/ruleid_string.go index c63a4765b2..66dacaeee2 100755 --- a/sql/analyzer/ruleid_string.go +++ b/sql/analyzer/ruleid_string.go @@ -52,80 +52,81 @@ func _() { _ = x[transformJoinApplyId-41] _ = x[setInsertColumnsId-42] _ = x[validateJoinComplexityId-43] - _ = x[resolveNaturalJoinsId-44] - _ = x[resolveOrderbyLiteralsId-45] - _ = x[resolveFunctionsId-46] - _ = x[flattenTableAliasesId-47] - _ = x[pushdownSortId-48] - _ = x[pushdownGroupbyAliasesId-49] - _ = x[pushdownSubqueryAliasFiltersId-50] - _ = x[qualifyColumnsId-51] - _ = x[resolveColumnsId-52] - _ = x[validateCheckConstraintId-53] - _ = x[resolveBarewordSetVariablesId-54] - _ = x[expandStarsId-55] - _ = x[transposeRightJoinsId-56] - _ = x[resolveHavingId-57] - _ = x[mergeUnionSchemasId-58] - _ = x[flattenAggregationExprsId-59] - _ = x[reorderProjectionId-60] - _ = x[resolveSubqueryExprsId-61] - _ = x[replaceCrossJoinsId-62] - _ = x[moveJoinCondsToFilterId-63] - _ = x[evalFilterId-64] - _ = x[optimizeDistinctId-65] - _ = x[finalizeSubqueriesId-66] - _ = x[finalizeUnionsId-67] - _ = x[loadTriggersId-68] - _ = x[processTruncateId-69] - _ = x[resolveAlterColumnId-70] - _ = x[resolveGeneratorsId-71] - _ = x[removeUnnecessaryConvertsId-72] - _ = x[pruneColumnsId-73] - _ = x[stripTableNameInDefaultsId-74] - _ = x[hoistSelectExistsId-75] - _ = x[optimizeJoinsId-76] - _ = x[pushdownFiltersId-77] - _ = x[subqueryIndexesId-78] - _ = x[pruneTablesId-79] - _ = x[setJoinScopeLenId-80] - _ = x[eraseProjectionId-81] - _ = x[replaceSortPkId-82] - _ = x[insertTopNId-83] - _ = x[applyHashInId-84] - _ = x[resolveInsertRowsId-85] - _ = x[resolvePreparedInsertId-86] - _ = x[applyTriggersId-87] - _ = x[applyProceduresId-88] - _ = x[assignRoutinesId-89] - _ = x[modifyUpdateExprsForJoinId-90] - _ = x[applyRowUpdateAccumulatorsId-91] - _ = x[wrapWithRollbackId-92] - _ = x[applyFKsId-93] - _ = x[validateResolvedId-94] - _ = x[validateOrderById-95] - _ = x[validateGroupById-96] - _ = x[validateSchemaSourceId-97] - _ = x[validateIndexCreationId-98] - _ = x[validateOperandsId-99] - _ = x[validateCaseResultTypesId-100] - _ = x[validateIntervalUsageId-101] - _ = x[validateExplodeUsageId-102] - _ = x[validateSubqueryColumnsId-103] - _ = x[validateUnionSchemasMatchId-104] - _ = x[validateAggregationsId-105] - _ = x[normalizeSelectSingleRelId-106] - _ = x[cacheSubqueryResultsId-107] - _ = x[cacheSubqueryAliasesInJoinsId-108] - _ = x[AutocommitId-109] - _ = x[TrackProcessId-110] - _ = x[parallelizeId-111] - _ = x[clearWarningsId-112] + _ = x[applyBinlogReplicaControllerId-44] + _ = x[resolveNaturalJoinsId-45] + _ = x[resolveOrderbyLiteralsId-46] + _ = x[resolveFunctionsId-47] + _ = x[flattenTableAliasesId-48] + _ = x[pushdownSortId-49] + _ = x[pushdownGroupbyAliasesId-50] + _ = x[pushdownSubqueryAliasFiltersId-51] + _ = x[qualifyColumnsId-52] + _ = x[resolveColumnsId-53] + _ = x[validateCheckConstraintId-54] + _ = x[resolveBarewordSetVariablesId-55] + _ = x[expandStarsId-56] + _ = x[transposeRightJoinsId-57] + _ = x[resolveHavingId-58] + _ = x[mergeUnionSchemasId-59] + _ = x[flattenAggregationExprsId-60] + _ = x[reorderProjectionId-61] + _ = x[resolveSubqueryExprsId-62] + _ = x[replaceCrossJoinsId-63] + _ = x[moveJoinCondsToFilterId-64] + _ = x[evalFilterId-65] + _ = x[optimizeDistinctId-66] + _ = x[finalizeSubqueriesId-67] + _ = x[finalizeUnionsId-68] + _ = x[loadTriggersId-69] + _ = x[processTruncateId-70] + _ = x[resolveAlterColumnId-71] + _ = x[resolveGeneratorsId-72] + _ = x[removeUnnecessaryConvertsId-73] + _ = x[pruneColumnsId-74] + _ = x[stripTableNameInDefaultsId-75] + _ = x[hoistSelectExistsId-76] + _ = x[optimizeJoinsId-77] + _ = x[pushdownFiltersId-78] + _ = x[subqueryIndexesId-79] + _ = x[pruneTablesId-80] + _ = x[setJoinScopeLenId-81] + _ = x[eraseProjectionId-82] + _ = x[replaceSortPkId-83] + _ = x[insertTopNId-84] + _ = x[applyHashInId-85] + _ = x[resolveInsertRowsId-86] + _ = x[resolvePreparedInsertId-87] + _ = x[applyTriggersId-88] + _ = x[applyProceduresId-89] + _ = x[assignRoutinesId-90] + _ = x[modifyUpdateExprsForJoinId-91] + _ = x[applyRowUpdateAccumulatorsId-92] + _ = x[wrapWithRollbackId-93] + _ = x[applyFKsId-94] + _ = x[validateResolvedId-95] + _ = x[validateOrderById-96] + _ = x[validateGroupById-97] + _ = x[validateSchemaSourceId-98] + _ = x[validateIndexCreationId-99] + _ = x[validateOperandsId-100] + _ = x[validateCaseResultTypesId-101] + _ = x[validateIntervalUsageId-102] + _ = x[validateExplodeUsageId-103] + _ = x[validateSubqueryColumnsId-104] + _ = x[validateUnionSchemasMatchId-105] + _ = x[validateAggregationsId-106] + _ = x[normalizeSelectSingleRelId-107] + _ = x[cacheSubqueryResultsId-108] + _ = x[cacheSubqueryAliasesInJoinsId-109] + _ = x[AutocommitId-110] + _ = x[TrackProcessId-111] + _ = x[parallelizeId-112] + _ = x[clearWarningsId-113] } -const _RuleId_name = "applyDefaultSelectLimitvalidateOffsetAndLimitvalidateCreateTablevalidateExprSemresolveVariablesresolveNamedWindowsresolveSetVariablesresolveViewsliftCtesresolveCtesliftRecursiveCtesresolveDatabasesresolveTablesloadStoredProceduresvalidateDropTablessetTargetSchemasresolveCreateLikeparseColumnDefaultsresolveDropConstraintvalidateDropConstraintloadCheckConstraintsassignCatalogresolveAnalyzeTablesresolveCreateSelectresolveSubqueriessetViewTargetSchemaresolveUnionsresolveDescribeQuerycheckUniqueTableNamesresolveTableFunctionsresolveDeclarationsresolveColumnDefaultsvalidateColumnDefaultsvalidateCreateTriggervalidateCreateProcedureloadInfoSchemavalidateReadOnlyDatabasevalidateReadOnlyTransactionvalidateDatabaseSetvalidatePrivilegesreresolveTablestransformJoinApplysetInsertColumnsvalidateJoinComplexityresolveNaturalJoinsresolveOrderbyLiteralsresolveFunctionsflattenTableAliasespushdownSortpushdownGroupbyAliasespushdownSubqueryAliasFiltersqualifyColumnsresolveColumnsvalidateCheckConstraintresolveBarewordSetVariablesexpandStarstransposeRightJoinsresolveHavingmergeUnionSchemasflattenAggregationExprsreorderProjectionresolveSubqueryExprsreplaceCrossJoinsmoveJoinCondsToFilterevalFilteroptimizeDistinctfinalizeSubqueriesfinalizeUnionsloadTriggersprocessTruncateresolveAlterColumnresolveGeneratorsremoveUnnecessaryConvertspruneColumnsstripTableNamesFromColumnDefaultshoistSelectExistsoptimizeJoinspushdownFilterssubqueryIndexespruneTablessetJoinScopeLeneraseProjectionreplaceSortPkinsertTopNapplyHashInresolveInsertRowsresolvePreparedInsertapplyTriggersapplyProceduresassignRoutinesmodifyUpdateExprsForJoinapplyRowUpdateAccumulatorsrollback triggersapplyFKsvalidateResolvedvalidateOrderByvalidateGroupByvalidateSchemaSourcevalidateIndexCreationvalidateOperandsvalidateCaseResultTypesvalidateIntervalUsagevalidateExplodeUsagevalidateSubqueryColumnsvalidateUnionSchemasMatchvalidateAggregationsnormalizeSelectSingleRelcacheSubqueryResultscacheSubqueryAliasesInJoinsaddAutocommitNodetrackProcessparallelizeclearWarnings" +const _RuleId_name = "applyDefaultSelectLimitvalidateOffsetAndLimitvalidateCreateTablevalidateExprSemresolveVariablesresolveNamedWindowsresolveSetVariablesresolveViewsliftCtesresolveCtesliftRecursiveCtesresolveDatabasesresolveTablesloadStoredProceduresvalidateDropTablessetTargetSchemasresolveCreateLikeparseColumnDefaultsresolveDropConstraintvalidateDropConstraintloadCheckConstraintsassignCatalogresolveAnalyzeTablesresolveCreateSelectresolveSubqueriessetViewTargetSchemaresolveUnionsresolveDescribeQuerycheckUniqueTableNamesresolveTableFunctionsresolveDeclarationsresolveColumnDefaultsvalidateColumnDefaultsvalidateCreateTriggervalidateCreateProcedureloadInfoSchemavalidateReadOnlyDatabasevalidateReadOnlyTransactionvalidateDatabaseSetvalidatePrivilegesreresolveTablestransformJoinApplysetInsertColumnsvalidateJoinComplexityapplyBinlogReplicationControllerresolveNaturalJoinsresolveOrderbyLiteralsresolveFunctionsflattenTableAliasespushdownSortpushdownGroupbyAliasespushdownSubqueryAliasFiltersqualifyColumnsresolveColumnsvalidateCheckConstraintresolveBarewordSetVariablesexpandStarstransposeRightJoinsresolveHavingmergeUnionSchemasflattenAggregationExprsreorderProjectionresolveSubqueryExprsreplaceCrossJoinsmoveJoinCondsToFilterevalFilteroptimizeDistinctfinalizeSubqueriesfinalizeUnionsloadTriggersprocessTruncateresolveAlterColumnresolveGeneratorsremoveUnnecessaryConvertspruneColumnsstripTableNamesFromColumnDefaultshoistSelectExistsoptimizeJoinspushdownFilterssubqueryIndexespruneTablessetJoinScopeLeneraseProjectionreplaceSortPkinsertTopNapplyHashInresolveInsertRowsresolvePreparedInsertapplyTriggersapplyProceduresassignRoutinesmodifyUpdateExprsForJoinapplyRowUpdateAccumulatorsrollback triggersapplyFKsvalidateResolvedvalidateOrderByvalidateGroupByvalidateSchemaSourcevalidateIndexCreationvalidateOperandsvalidateCaseResultTypesvalidateIntervalUsagevalidateExplodeUsagevalidateSubqueryColumnsvalidateUnionSchemasMatchvalidateAggregationsnormalizeSelectSingleRelcacheSubqueryResultscacheSubqueryAliasesInJoinsaddAutocommitNodetrackProcessparallelizeclearWarnings" -var _RuleId_index = [...]uint16{0, 23, 45, 64, 79, 95, 114, 133, 145, 153, 164, 181, 197, 210, 230, 248, 264, 281, 300, 321, 343, 363, 376, 396, 415, 432, 451, 464, 484, 505, 526, 545, 566, 588, 609, 632, 646, 670, 697, 716, 734, 749, 767, 783, 805, 824, 846, 862, 881, 893, 915, 943, 957, 971, 994, 1021, 1032, 1051, 1064, 1081, 1104, 1121, 1141, 1158, 1179, 1189, 1205, 1223, 1237, 1249, 1264, 1282, 1299, 1324, 1336, 1369, 1386, 1399, 1414, 1429, 1440, 1455, 1470, 1483, 1493, 1504, 1521, 1542, 1555, 1570, 1584, 1608, 1634, 1651, 1659, 1675, 1690, 1705, 1725, 1746, 1762, 1785, 1806, 1826, 1849, 1874, 1894, 1918, 1938, 1965, 1982, 1994, 2005, 2018} +var _RuleId_index = [...]uint16{0, 23, 45, 64, 79, 95, 114, 133, 145, 153, 164, 181, 197, 210, 230, 248, 264, 281, 300, 321, 343, 363, 376, 396, 415, 432, 451, 464, 484, 505, 526, 545, 566, 588, 609, 632, 646, 670, 697, 716, 734, 749, 767, 783, 805, 837, 856, 878, 894, 913, 925, 947, 975, 989, 1003, 1026, 1053, 1064, 1083, 1096, 1113, 1136, 1153, 1173, 1190, 1211, 1221, 1237, 1255, 1269, 1281, 1296, 1314, 1331, 1356, 1368, 1401, 1418, 1431, 1446, 1461, 1472, 1487, 1502, 1515, 1525, 1536, 1553, 1574, 1587, 1602, 1616, 1640, 1666, 1683, 1691, 1707, 1722, 1737, 1757, 1778, 1794, 1817, 1838, 1858, 1881, 1906, 1926, 1950, 1970, 1997, 2014, 2026, 2037, 2050} func (i RuleId) String() string { if i < 0 || i >= RuleId(len(_RuleId_index)-1) { diff --git a/sql/analyzer/rules.go b/sql/analyzer/rules.go index d45d831a7b..b3581c7a7a 100755 --- a/sql/analyzer/rules.go +++ b/sql/analyzer/rules.go @@ -22,6 +22,7 @@ import ( // DefaultRules. var OnceBeforeDefault = []Rule{ {applyDefaultSelectLimitId, applyDefaultSelectLimit}, + {applyBinlogReplicaControllerId, applyBinlogReplicaController}, {validateOffsetAndLimitId, validateLimitAndOffset}, {validateCreateTableId, validateCreateTable}, {validateExprSemId, validateExprSem}, diff --git a/sql/plan/replication_commands.go b/sql/plan/replication_commands.go index a7e38c93ee..71edc4a22b 100644 --- a/sql/plan/replication_commands.go +++ b/sql/plan/replication_commands.go @@ -25,28 +25,18 @@ import ( // BinlogReplicaControllerCommand represents a SQL statement that requires a BinlogReplicaController // (e.g. Start Replica, Show Replica Status). type BinlogReplicaControllerCommand interface { - // SetBinlogReplicaController sets the BinlogReplicaController for this replication command to use. - SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) -} - -// binlogReplicaControllerCommand is a package-internal type embedded into -// BinlogReplicaControllerCommand types to provide the SetBinlogReplicaController function. -type binlogReplicaControllerCommand struct { - replicaController binlogreplication.BinlogReplicaController -} - -var _ BinlogReplicaControllerCommand = (*binlogReplicaControllerCommand)(nil) + sql.Node -// SetBinlogReplicaController implements the BinlogReplicaControllerCommand interface. -func (c *binlogReplicaControllerCommand) SetBinlogReplicaController(controller binlogreplication.BinlogReplicaController) { - c.replicaController = controller + // WithBinlogReplicaController returns a new instance of this BinlogReplicaController, with the binlog replica + // controller configured. + WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node } // ChangeReplicationSource is the plan node for the "CHANGE REPLICATION SOURCE TO" statement. // https://dev.mysql.com/doc/refman/8.0/en/change-replication-source-to.html type ChangeReplicationSource struct { - binlogReplicaControllerCommand - Options []binlogreplication.ReplicationOption + replicaController binlogreplication.BinlogReplicaController + Options []binlogreplication.ReplicationOption } var _ sql.Node = (*ChangeReplicationSource)(nil) @@ -58,6 +48,13 @@ func NewChangeReplicationSource(options []binlogreplication.ReplicationOption) * } } +// WithBinlogReplicaController implements the BinlogReplicaControllerCommand interface. +func (c *ChangeReplicationSource) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node { + nc := *c + nc.replicaController = controller + return &nc +} + func (c *ChangeReplicationSource) Resolved() bool { return true } @@ -108,8 +105,8 @@ func (c *ChangeReplicationSource) CheckPrivileges(_ *sql.Context, _ sql.Privileg // ChangeReplicationFilter is a plan node for the "CHANGE REPLICATION FILTER" statement. // https://dev.mysql.com/doc/refman/8.0/en/change-replication-filter.html type ChangeReplicationFilter struct { - binlogReplicaControllerCommand - Options []binlogreplication.ReplicationOption + replicaController binlogreplication.BinlogReplicaController + Options []binlogreplication.ReplicationOption } var _ sql.Node = (*ChangeReplicationFilter)(nil) @@ -121,6 +118,13 @@ func NewChangeReplicationFilter(options []binlogreplication.ReplicationOption) * } } +// WithBinlogReplicaController implements the BinlogReplicaControllerCommand interface. +func (c *ChangeReplicationFilter) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node { + nc := *c + nc.replicaController = controller + return &nc +} + func (c *ChangeReplicationFilter) Resolved() bool { return true } @@ -174,7 +178,7 @@ func (c *ChangeReplicationFilter) CheckPrivileges(ctx *sql.Context, opChecker sq // StartReplica is a plan node for the "START REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/start-replica.html type StartReplica struct { - binlogReplicaControllerCommand + replicaController binlogreplication.BinlogReplicaController } var _ sql.Node = (*StartReplica)(nil) @@ -184,6 +188,13 @@ func NewStartReplica() *StartReplica { return &StartReplica{} } +// WithBinlogReplicaController implements the BinlogReplicaControllerCommand interface. +func (s *StartReplica) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node { + nc := *s + nc.replicaController = controller + return &nc +} + func (s *StartReplica) Resolved() bool { return true } @@ -226,7 +237,7 @@ func (s *StartReplica) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperation // StopReplica is the plan node for the "STOP REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/stop-replica.html type StopReplica struct { - binlogReplicaControllerCommand + replicaController binlogreplication.BinlogReplicaController } var _ sql.Node = (*StopReplica)(nil) @@ -236,6 +247,13 @@ func NewStopReplica() *StopReplica { return &StopReplica{} } +// WithBinlogReplicaController implements the BinlogReplicaControllerCommand interface. +func (s *StopReplica) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node { + nc := *s + nc.replicaController = controller + return &nc +} + func (s *StopReplica) Resolved() bool { return true } @@ -278,8 +296,8 @@ func (s *StopReplica) CheckPrivileges(_ *sql.Context, _ sql.PrivilegedOperationC // ResetReplica is a plan node for the "RESET REPLICA" statement. // https://dev.mysql.com/doc/refman/8.0/en/reset-replica.html type ResetReplica struct { - binlogReplicaControllerCommand - All bool + replicaController binlogreplication.BinlogReplicaController + All bool } var _ sql.Node = (*ResetReplica)(nil) @@ -291,6 +309,13 @@ func NewResetReplica(all bool) *ResetReplica { } } +// WithBinlogReplicaController implements the BinlogReplicaControllerCommand interface. +func (r *ResetReplica) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node { + nc := *r + nc.replicaController = controller + return &nc +} + func (r *ResetReplica) Resolved() bool { return true } diff --git a/sql/plan/show_replica_status.go b/sql/plan/show_replica_status.go index 507fb92bde..9c692cb252 100644 --- a/sql/plan/show_replica_status.go +++ b/sql/plan/show_replica_status.go @@ -19,6 +19,7 @@ import ( "time" "github.com/dolthub/go-mysql-server/sql" + "github.com/dolthub/go-mysql-server/sql/binlogreplication" "github.com/dolthub/go-mysql-server/sql/types" "github.com/dolthub/vitess/go/sqltypes" @@ -27,7 +28,7 @@ import ( // ShowReplicaStatus is the plan node for the "SHOW REPLICA STATUS" statement. // https://dev.mysql.com/doc/refman/8.0/en/show-replica-status.html type ShowReplicaStatus struct { - binlogReplicaControllerCommand + replicaController binlogreplication.BinlogReplicaController } var _ sql.Node = (*ShowReplicaStatus)(nil) @@ -37,6 +38,13 @@ func NewShowReplicaStatus() *ShowReplicaStatus { return &ShowReplicaStatus{} } +// WithBinlogReplicaController implements the BinlogReplicaControllerCommand interface. +func (s *ShowReplicaStatus) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node { + nc := *s + nc.replicaController = controller + return &nc +} + func (s *ShowReplicaStatus) Resolved() bool { return true }