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 }