github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/replication_commands.go (about)

     1  // Copyright 2022 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package plan
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	"gopkg.in/src-d/go-errors.v1"
    22  
    23  	"github.com/dolthub/go-mysql-server/sql"
    24  	"github.com/dolthub/go-mysql-server/sql/binlogreplication"
    25  )
    26  
    27  // ErrNoReplicationController is returned when replication commands are executed without a configured
    28  // replication controller to dispatch the command to.
    29  var ErrNoReplicationController = errors.NewKind("no replication controller available")
    30  
    31  // DynamicPrivilege_ReplicationSlaveAdmin is the dynamic privilege required to execute replication commands.
    32  // https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_replication-slave-admin
    33  const DynamicPrivilege_ReplicationSlaveAdmin = "replication_slave_admin"
    34  
    35  // BinlogReplicaControllerCommand represents a SQL statement that requires a BinlogReplicaController
    36  // (e.g. Start Replica, Show Replica Status).
    37  type BinlogReplicaControllerCommand interface {
    38  	sql.Node
    39  
    40  	// WithBinlogReplicaController returns a new instance of this BinlogReplicaController, with the binlog replica
    41  	// controller configured.
    42  	WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node
    43  }
    44  
    45  // ChangeReplicationSource is the plan node for the "CHANGE REPLICATION SOURCE TO" statement.
    46  // https://dev.mysql.com/doc/refman/8.0/en/change-replication-source-to.html
    47  type ChangeReplicationSource struct {
    48  	ReplicaController binlogreplication.BinlogReplicaController
    49  	Options           []binlogreplication.ReplicationOption
    50  }
    51  
    52  var _ sql.Node = (*ChangeReplicationSource)(nil)
    53  var _ sql.CollationCoercible = (*ChangeReplicationSource)(nil)
    54  var _ BinlogReplicaControllerCommand = (*ChangeReplicationSource)(nil)
    55  
    56  func NewChangeReplicationSource(options []binlogreplication.ReplicationOption) *ChangeReplicationSource {
    57  	return &ChangeReplicationSource{
    58  		Options: options,
    59  	}
    60  }
    61  
    62  // WithBinlogReplicaController implements the BinlogReplicaControllerCommand interface.
    63  func (c *ChangeReplicationSource) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node {
    64  	nc := *c
    65  	nc.ReplicaController = controller
    66  	return &nc
    67  }
    68  
    69  func (c *ChangeReplicationSource) Resolved() bool {
    70  	return true
    71  }
    72  
    73  func (c *ChangeReplicationSource) IsReadOnly() bool {
    74  	return false
    75  }
    76  
    77  func (c *ChangeReplicationSource) String() string {
    78  	sb := strings.Builder{}
    79  	sb.WriteString("CHANGE REPLICATION SOURCE TO ")
    80  	for i, option := range c.Options {
    81  		if i > 0 {
    82  			sb.WriteString(", ")
    83  		}
    84  		sb.WriteString(fmt.Sprintf("%s = %s", option.Name, option.Value))
    85  	}
    86  	return sb.String()
    87  }
    88  
    89  func (c *ChangeReplicationSource) Schema() sql.Schema {
    90  	return nil
    91  }
    92  
    93  func (c *ChangeReplicationSource) Children() []sql.Node {
    94  	return nil
    95  }
    96  
    97  func (c *ChangeReplicationSource) WithChildren(children ...sql.Node) (sql.Node, error) {
    98  	if len(children) != 0 {
    99  		return nil, sql.ErrInvalidChildrenNumber.New(c, len(children), 0)
   100  	}
   101  
   102  	newNode := *c
   103  	return &newNode, nil
   104  }
   105  
   106  func (c *ChangeReplicationSource) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool {
   107  	return opChecker.UserHasPrivileges(ctx,
   108  		sql.NewDynamicPrivilegedOperation(DynamicPrivilege_ReplicationSlaveAdmin))
   109  }
   110  
   111  // CollationCoercibility implements the interface sql.CollationCoercible.
   112  func (*ChangeReplicationSource) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   113  	return sql.Collation_binary, 7
   114  }
   115  
   116  // ChangeReplicationFilter is a plan node for the "CHANGE REPLICATION FILTER" statement.
   117  // https://dev.mysql.com/doc/refman/8.0/en/change-replication-filter.html
   118  type ChangeReplicationFilter struct {
   119  	ReplicaController binlogreplication.BinlogReplicaController
   120  	Options           []binlogreplication.ReplicationOption
   121  }
   122  
   123  var _ sql.Node = (*ChangeReplicationFilter)(nil)
   124  var _ sql.CollationCoercible = (*ChangeReplicationFilter)(nil)
   125  var _ BinlogReplicaControllerCommand = (*ChangeReplicationFilter)(nil)
   126  
   127  func NewChangeReplicationFilter(options []binlogreplication.ReplicationOption) *ChangeReplicationFilter {
   128  	return &ChangeReplicationFilter{
   129  		Options: options,
   130  	}
   131  }
   132  
   133  // WithBinlogReplicaController implements the BinlogReplicaControllerCommand interface.
   134  func (c *ChangeReplicationFilter) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node {
   135  	nc := *c
   136  	nc.ReplicaController = controller
   137  	return &nc
   138  }
   139  
   140  func (c *ChangeReplicationFilter) Resolved() bool {
   141  	return true
   142  }
   143  
   144  func (c *ChangeReplicationFilter) IsReadOnly() bool {
   145  	return false
   146  }
   147  
   148  func (c *ChangeReplicationFilter) String() string {
   149  	sb := strings.Builder{}
   150  	sb.WriteString("CHANGE REPLICATION FILTER ")
   151  	for i, option := range c.Options {
   152  		if i > 0 {
   153  			sb.WriteString(", ")
   154  		}
   155  		sb.WriteString(option.Name)
   156  		sb.WriteString(" = ")
   157  		// TODO: Fix this to use better typing
   158  		sb.WriteString(fmt.Sprintf("%s", option.Value))
   159  	}
   160  	return sb.String()
   161  }
   162  
   163  func (c *ChangeReplicationFilter) Schema() sql.Schema {
   164  	return nil
   165  }
   166  
   167  func (c *ChangeReplicationFilter) Children() []sql.Node {
   168  	return nil
   169  }
   170  
   171  func (c *ChangeReplicationFilter) WithChildren(children ...sql.Node) (sql.Node, error) {
   172  	if len(children) != 0 {
   173  		return nil, sql.ErrInvalidChildrenNumber.New(c, len(children), 0)
   174  	}
   175  
   176  	newNode := *c
   177  	return &newNode, nil
   178  }
   179  
   180  func (c *ChangeReplicationFilter) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool {
   181  	return opChecker.UserHasPrivileges(ctx,
   182  		sql.NewDynamicPrivilegedOperation(DynamicPrivilege_ReplicationSlaveAdmin))
   183  }
   184  
   185  // CollationCoercibility implements the interface sql.CollationCoercible.
   186  func (*ChangeReplicationFilter) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   187  	return sql.Collation_binary, 7
   188  }
   189  
   190  // StartReplica is a plan node for the "START REPLICA" statement.
   191  // https://dev.mysql.com/doc/refman/8.0/en/start-replica.html
   192  type StartReplica struct {
   193  	ReplicaController binlogreplication.BinlogReplicaController
   194  }
   195  
   196  var _ sql.Node = (*StartReplica)(nil)
   197  var _ sql.CollationCoercible = (*StartReplica)(nil)
   198  var _ BinlogReplicaControllerCommand = (*StartReplica)(nil)
   199  
   200  func NewStartReplica() *StartReplica {
   201  	return &StartReplica{}
   202  }
   203  
   204  // WithBinlogReplicaController implements the BinlogReplicaControllerCommand interface.
   205  func (s *StartReplica) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node {
   206  	nc := *s
   207  	nc.ReplicaController = controller
   208  	return &nc
   209  }
   210  
   211  func (s *StartReplica) Resolved() bool {
   212  	return true
   213  }
   214  
   215  func (s *StartReplica) IsReadOnly() bool {
   216  	return false
   217  }
   218  
   219  func (s *StartReplica) String() string {
   220  	return "START REPLICA"
   221  }
   222  
   223  func (s *StartReplica) Schema() sql.Schema {
   224  	return nil
   225  }
   226  
   227  func (s *StartReplica) Children() []sql.Node {
   228  	return nil
   229  }
   230  
   231  func (s *StartReplica) WithChildren(children ...sql.Node) (sql.Node, error) {
   232  	if len(children) != 0 {
   233  		return nil, sql.ErrInvalidChildrenNumber.New(s, len(children), 0)
   234  	}
   235  
   236  	newNode := *s
   237  	return &newNode, nil
   238  }
   239  
   240  func (s *StartReplica) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool {
   241  	return opChecker.UserHasPrivileges(ctx,
   242  		sql.NewDynamicPrivilegedOperation(DynamicPrivilege_ReplicationSlaveAdmin))
   243  }
   244  
   245  // CollationCoercibility implements the interface sql.CollationCoercible.
   246  func (*StartReplica) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   247  	return sql.Collation_binary, 7
   248  }
   249  
   250  // StopReplica is the plan node for the "STOP REPLICA" statement.
   251  // https://dev.mysql.com/doc/refman/8.0/en/stop-replica.html
   252  type StopReplica struct {
   253  	ReplicaController binlogreplication.BinlogReplicaController
   254  }
   255  
   256  var _ sql.Node = (*StopReplica)(nil)
   257  var _ sql.CollationCoercible = (*StopReplica)(nil)
   258  var _ BinlogReplicaControllerCommand = (*StopReplica)(nil)
   259  
   260  func NewStopReplica() *StopReplica {
   261  	return &StopReplica{}
   262  }
   263  
   264  // WithBinlogReplicaController implements the BinlogReplicaControllerCommand interface.
   265  func (s *StopReplica) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node {
   266  	nc := *s
   267  	nc.ReplicaController = controller
   268  	return &nc
   269  }
   270  
   271  func (s *StopReplica) Resolved() bool {
   272  	return true
   273  }
   274  
   275  func (s *StopReplica) IsReadOnly() bool {
   276  	return false
   277  }
   278  
   279  func (s *StopReplica) String() string {
   280  	return "STOP REPLICA"
   281  }
   282  
   283  func (s *StopReplica) Schema() sql.Schema {
   284  	return nil
   285  }
   286  
   287  func (s *StopReplica) Children() []sql.Node {
   288  	return nil
   289  }
   290  
   291  func (s *StopReplica) WithChildren(children ...sql.Node) (sql.Node, error) {
   292  	if len(children) != 0 {
   293  		return nil, sql.ErrInvalidChildrenNumber.New(s, len(children), 0)
   294  	}
   295  
   296  	newNode := *s
   297  	return &newNode, nil
   298  }
   299  
   300  func (s *StopReplica) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool {
   301  	return opChecker.UserHasPrivileges(ctx,
   302  		sql.NewDynamicPrivilegedOperation(DynamicPrivilege_ReplicationSlaveAdmin))
   303  }
   304  
   305  // CollationCoercibility implements the interface sql.CollationCoercible.
   306  func (*StopReplica) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   307  	return sql.Collation_binary, 7
   308  }
   309  
   310  // ResetReplica is a plan node for the "RESET REPLICA" statement.
   311  // https://dev.mysql.com/doc/refman/8.0/en/reset-replica.html
   312  type ResetReplica struct {
   313  	ReplicaController binlogreplication.BinlogReplicaController
   314  	All               bool
   315  }
   316  
   317  var _ sql.Node = (*ResetReplica)(nil)
   318  var _ sql.CollationCoercible = (*ResetReplica)(nil)
   319  var _ BinlogReplicaControllerCommand = (*ResetReplica)(nil)
   320  
   321  func NewResetReplica(all bool) *ResetReplica {
   322  	return &ResetReplica{
   323  		All: all,
   324  	}
   325  }
   326  
   327  // WithBinlogReplicaController implements the BinlogReplicaControllerCommand interface.
   328  func (r *ResetReplica) WithBinlogReplicaController(controller binlogreplication.BinlogReplicaController) sql.Node {
   329  	nc := *r
   330  	nc.ReplicaController = controller
   331  	return &nc
   332  }
   333  
   334  func (r *ResetReplica) Resolved() bool {
   335  	return true
   336  }
   337  
   338  func (r *ResetReplica) IsReadOnly() bool {
   339  	return false
   340  }
   341  
   342  func (r *ResetReplica) String() string {
   343  	sb := strings.Builder{}
   344  	sb.WriteString("RESET REPLICA")
   345  	if r.All {
   346  		sb.WriteString(" ALL")
   347  	}
   348  	return sb.String()
   349  }
   350  
   351  func (r *ResetReplica) Schema() sql.Schema {
   352  	return nil
   353  }
   354  
   355  func (r *ResetReplica) Children() []sql.Node {
   356  	return nil
   357  }
   358  
   359  func (r *ResetReplica) WithChildren(children ...sql.Node) (sql.Node, error) {
   360  	if len(children) != 0 {
   361  		return nil, sql.ErrInvalidChildrenNumber.New(r, len(children), 0)
   362  	}
   363  
   364  	newNode := *r
   365  	return &newNode, nil
   366  }
   367  
   368  func (r *ResetReplica) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool {
   369  	return opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation(sql.PrivilegeCheckSubject{}, sql.PrivilegeType_Reload))
   370  }
   371  
   372  // CollationCoercibility implements the interface sql.CollationCoercible.
   373  func (*ResetReplica) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   374  	return sql.Collation_binary, 7
   375  }