vitess.io/vitess@v0.16.2/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package fakemysqldaemon 18 19 import ( 20 "fmt" 21 "reflect" 22 "strings" 23 "sync" 24 "time" 25 26 "context" 27 28 "vitess.io/vitess/go/mysql" 29 "vitess.io/vitess/go/mysql/fakesqldb" 30 "vitess.io/vitess/go/sqltypes" 31 "vitess.io/vitess/go/sync2" 32 "vitess.io/vitess/go/vt/dbconnpool" 33 "vitess.io/vitess/go/vt/mysqlctl" 34 "vitess.io/vitess/go/vt/mysqlctl/tmutils" 35 36 querypb "vitess.io/vitess/go/vt/proto/query" 37 tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" 38 ) 39 40 // FakeMysqlDaemon implements MysqlDaemon and allows the user to fake 41 // everything. 42 type FakeMysqlDaemon struct { 43 mu sync.Mutex 44 // db is the fake SQL DB we may use for some queries. 45 db *fakesqldb.DB 46 47 // appPool is set if db is set. 48 appPool *dbconnpool.ConnectionPool 49 50 // Running is used by Start / Shutdown 51 Running bool 52 53 // StartupTime is used to simulate mysqlds that take some time to respond 54 // to a "start" command. It is used by Start. 55 StartupTime time.Duration 56 57 // ShutdownTime is used to simulate mysqlds that take some time to respond 58 // to a "stop" request (i.e. a wedged systemd unit). It is used by Shutdown. 59 ShutdownTime time.Duration 60 61 // MysqlPort will be returned by GetMysqlPort(). Set to -1 to 62 // return an error. 63 MysqlPort sync2.AtomicInt32 64 65 // Replicating is updated when calling StartReplication / StopReplication 66 // (it is not used at all when calling ReplicationStatus, it is the 67 // test owner responsibility to have these two match) 68 Replicating bool 69 70 // IOThreadRunning is always true except in one testcase 71 // where we want to test error handling during SetReplicationSource 72 IOThreadRunning bool 73 74 // CurrentPrimaryPosition is returned by PrimaryPosition 75 // and ReplicationStatus 76 CurrentPrimaryPosition mysql.Position 77 78 // CurrentSourceFilePosition is used to determine the executed file based positioning of the replication source. 79 CurrentSourceFilePosition mysql.Position 80 81 // ReplicationStatusError is used by ReplicationStatus 82 ReplicationStatusError error 83 84 // StartReplicationError is used by StartReplication 85 StartReplicationError error 86 87 // PromoteLag is the time for which Promote will stall 88 PromoteLag time.Duration 89 90 // PrimaryStatusError is used by PrimaryStatus 91 PrimaryStatusError error 92 93 // CurrentSourceHost is returned by ReplicationStatus 94 CurrentSourceHost string 95 96 // CurrentSourcePort is returned by ReplicationStatus 97 CurrentSourcePort int 98 99 // ReplicationLagSeconds is returned by ReplicationStatus 100 ReplicationLagSeconds uint 101 102 // ReadOnly is the current value of the flag 103 ReadOnly bool 104 105 // SuperReadOnly is the current value of the flag 106 SuperReadOnly bool 107 108 // SetReplicationPositionPos is matched against the input of SetReplicationPosition. 109 // If it doesn't match, SetReplicationPosition will return an error. 110 SetReplicationPositionPos mysql.Position 111 112 // StartReplicationUntilAfterPos is matched against the input 113 StartReplicationUntilAfterPos mysql.Position 114 115 // SetReplicationSourceInputs are matched against the input of SetReplicationSource 116 // (as "%v:%v"). If all of them don't match, SetReplicationSource will return an error. 117 SetReplicationSourceInputs []string 118 119 // SetReplicationSourceError is used by SetReplicationSource 120 SetReplicationSourceError error 121 122 // WaitPrimaryPositions is checked by WaitSourcePos, if the value is found 123 // in it, then the function returns nil, else the function returns an error 124 WaitPrimaryPositions []mysql.Position 125 126 // PromoteResult is returned by Promote 127 PromoteResult mysql.Position 128 129 // PromoteError is used by Promote 130 PromoteError error 131 132 // SchemaFunc provides the return value for GetSchema. 133 // If not defined, the "Schema" field will be used instead, see below. 134 SchemaFunc func() (*tabletmanagerdatapb.SchemaDefinition, error) 135 136 // Schema will be returned by GetSchema. If nil we'll 137 // return an error. 138 Schema *tabletmanagerdatapb.SchemaDefinition 139 140 // PreflightSchemaChangeResult will be returned by PreflightSchemaChange. 141 // If nil we'll return an error. 142 PreflightSchemaChangeResult []*tabletmanagerdatapb.SchemaChangeResult 143 144 // ApplySchemaChangeResult will be returned by ApplySchemaChange. 145 // If nil we'll return an error. 146 ApplySchemaChangeResult *tabletmanagerdatapb.SchemaChangeResult 147 148 // ExpectedExecuteSuperQueryList is what we expect 149 // ExecuteSuperQueryList to be called with. If it doesn't 150 // match, ExecuteSuperQueryList will return an error. 151 // Note each string is just a substring if it begins with SUB, 152 // so we support partial queries (useful when queries contain 153 // data fields like timestamps) 154 ExpectedExecuteSuperQueryList []string 155 156 // ExpectedExecuteSuperQueryCurrent is the current index of the queries 157 // we expect 158 ExpectedExecuteSuperQueryCurrent int 159 160 // FetchSuperQueryResults is used by FetchSuperQuery 161 FetchSuperQueryMap map[string]*sqltypes.Result 162 163 // BinlogPlayerEnabled is used by {Enable,Disable}BinlogPlayer 164 BinlogPlayerEnabled sync2.AtomicBool 165 166 // SemiSyncPrimaryEnabled represents the state of rpl_semi_sync_master_enabled. 167 SemiSyncPrimaryEnabled bool 168 // SemiSyncReplicaEnabled represents the state of rpl_semi_sync_slave_enabled. 169 SemiSyncReplicaEnabled bool 170 171 // TimeoutHook is a func that can be called at the beginning of any method to fake a timeout. 172 // all a test needs to do is make it { return context.DeadlineExceeded } 173 TimeoutHook func() error 174 } 175 176 // NewFakeMysqlDaemon returns a FakeMysqlDaemon where mysqld appears 177 // to be running, based on a fakesqldb.DB. 178 // 'db' can be nil if the test doesn't use a database at all. 179 func NewFakeMysqlDaemon(db *fakesqldb.DB) *FakeMysqlDaemon { 180 result := &FakeMysqlDaemon{ 181 db: db, 182 Running: true, 183 IOThreadRunning: true, 184 } 185 if db != nil { 186 result.appPool = dbconnpool.NewConnectionPool("AppConnPool", 5, time.Minute, 0, 0) 187 result.appPool.Open(db.ConnParams()) 188 } 189 return result 190 } 191 192 // Start is part of the MysqlDaemon interface 193 func (fmd *FakeMysqlDaemon) Start(ctx context.Context, cnf *mysqlctl.Mycnf, mysqldArgs ...string) error { 194 if fmd.Running { 195 return fmt.Errorf("fake mysql daemon already running") 196 } 197 198 if fmd.StartupTime > 0 { 199 select { 200 case <-time.After(fmd.StartupTime): 201 case <-ctx.Done(): 202 return ctx.Err() 203 } 204 } 205 206 fmd.Running = true 207 return nil 208 } 209 210 // Shutdown is part of the MysqlDaemon interface 211 func (fmd *FakeMysqlDaemon) Shutdown(ctx context.Context, cnf *mysqlctl.Mycnf, waitForMysqld bool) error { 212 if !fmd.Running { 213 return fmt.Errorf("fake mysql daemon not running") 214 } 215 216 if fmd.ShutdownTime > 0 { 217 select { 218 case <-time.After(fmd.ShutdownTime): 219 case <-ctx.Done(): 220 return ctx.Err() 221 } 222 } 223 224 fmd.Running = false 225 return nil 226 } 227 228 // RunMysqlUpgrade is part of the MysqlDaemon interface 229 func (fmd *FakeMysqlDaemon) RunMysqlUpgrade() error { 230 return nil 231 } 232 233 // ReinitConfig is part of the MysqlDaemon interface 234 func (fmd *FakeMysqlDaemon) ReinitConfig(ctx context.Context, cnf *mysqlctl.Mycnf) error { 235 return nil 236 } 237 238 // RefreshConfig is part of the MysqlDaemon interface 239 func (fmd *FakeMysqlDaemon) RefreshConfig(ctx context.Context, cnf *mysqlctl.Mycnf) error { 240 return nil 241 } 242 243 // Wait is part of the MysqlDaemon interface. 244 func (fmd *FakeMysqlDaemon) Wait(ctx context.Context, cnf *mysqlctl.Mycnf) error { 245 return nil 246 } 247 248 // GetMysqlPort is part of the MysqlDaemon interface 249 func (fmd *FakeMysqlDaemon) GetMysqlPort() (int32, error) { 250 if fmd.MysqlPort.Get() == -1 { 251 return 0, fmt.Errorf("FakeMysqlDaemon.GetMysqlPort returns an error") 252 } 253 return fmd.MysqlPort.Get(), nil 254 } 255 256 // GetServerID is part of the MysqlDaemon interface 257 func (fmd *FakeMysqlDaemon) GetServerID(ctx context.Context) (uint32, error) { 258 return 1, nil 259 } 260 261 // GetServerUUID is part of the MysqlDaemon interface 262 func (fmd *FakeMysqlDaemon) GetServerUUID(ctx context.Context) (string, error) { 263 return "000000", nil 264 } 265 266 // CurrentPrimaryPositionLocked is thread-safe 267 func (fmd *FakeMysqlDaemon) CurrentPrimaryPositionLocked(pos mysql.Position) { 268 fmd.mu.Lock() 269 defer fmd.mu.Unlock() 270 fmd.CurrentPrimaryPosition = pos 271 } 272 273 // ReplicationStatus is part of the MysqlDaemon interface 274 func (fmd *FakeMysqlDaemon) ReplicationStatus() (mysql.ReplicationStatus, error) { 275 if fmd.ReplicationStatusError != nil { 276 return mysql.ReplicationStatus{}, fmd.ReplicationStatusError 277 } 278 fmd.mu.Lock() 279 defer fmd.mu.Unlock() 280 return mysql.ReplicationStatus{ 281 Position: fmd.CurrentPrimaryPosition, 282 FilePosition: fmd.CurrentSourceFilePosition, 283 RelayLogSourceBinlogEquivalentPosition: fmd.CurrentSourceFilePosition, 284 ReplicationLagSeconds: fmd.ReplicationLagSeconds, 285 // implemented as AND to avoid changing all tests that were 286 // previously using Replicating = false 287 IOState: mysql.ReplicationStatusToState(fmt.Sprintf("%v", fmd.Replicating && fmd.IOThreadRunning)), 288 SQLState: mysql.ReplicationStatusToState(fmt.Sprintf("%v", fmd.Replicating)), 289 SourceHost: fmd.CurrentSourceHost, 290 SourcePort: fmd.CurrentSourcePort, 291 }, nil 292 } 293 294 // PrimaryStatus is part of the MysqlDaemon interface 295 func (fmd *FakeMysqlDaemon) PrimaryStatus(ctx context.Context) (mysql.PrimaryStatus, error) { 296 if fmd.PrimaryStatusError != nil { 297 return mysql.PrimaryStatus{}, fmd.PrimaryStatusError 298 } 299 return mysql.PrimaryStatus{ 300 Position: fmd.CurrentPrimaryPosition, 301 FilePosition: fmd.CurrentSourceFilePosition, 302 }, nil 303 } 304 305 // GetGTIDPurged is part of the MysqlDaemon interface 306 func (fmd *FakeMysqlDaemon) GetGTIDPurged(ctx context.Context) (mysql.Position, error) { 307 return mysql.Position{}, nil 308 } 309 310 // ResetReplication is part of the MysqlDaemon interface. 311 func (fmd *FakeMysqlDaemon) ResetReplication(ctx context.Context) error { 312 return fmd.ExecuteSuperQueryList(ctx, []string{ 313 "FAKE RESET ALL REPLICATION", 314 }) 315 } 316 317 // ResetReplicationParameters is part of the MysqlDaemon interface. 318 func (fmd *FakeMysqlDaemon) ResetReplicationParameters(ctx context.Context) error { 319 return fmd.ExecuteSuperQueryList(ctx, []string{ 320 "FAKE RESET REPLICA ALL", 321 }) 322 } 323 324 // GetBinlogInformation is part of the MysqlDaemon interface. 325 func (fmd *FakeMysqlDaemon) GetBinlogInformation(ctx context.Context) (binlogFormat string, logEnabled bool, logReplicaUpdate bool, binlogRowImage string, err error) { 326 return "ROW", true, true, "FULL", fmd.ExecuteSuperQueryList(ctx, []string{ 327 "FAKE select @@global", 328 }) 329 } 330 331 // GetGTIDMode is part of the MysqlDaemon interface. 332 func (fmd *FakeMysqlDaemon) GetGTIDMode(ctx context.Context) (gtidMode string, err error) { 333 return "ON", fmd.ExecuteSuperQueryList(ctx, []string{ 334 "FAKE select @@global", 335 }) 336 } 337 338 // FlushBinaryLogs is part of the MysqlDaemon interface. 339 func (fmd *FakeMysqlDaemon) FlushBinaryLogs(ctx context.Context) (err error) { 340 return fmd.ExecuteSuperQueryList(ctx, []string{ 341 "FAKE FLUSH BINARY LOGS", 342 }) 343 } 344 345 // GetBinaryLogs is part of the MysqlDaemon interface. 346 func (fmd *FakeMysqlDaemon) GetBinaryLogs(ctx context.Context) (binaryLogs []string, err error) { 347 return []string{}, fmd.ExecuteSuperQueryList(ctx, []string{ 348 "FAKE SHOW BINARY LOGS", 349 }) 350 } 351 352 // GetPreviousGTIDs is part of the MysqlDaemon interface. 353 func (fmd *FakeMysqlDaemon) GetPreviousGTIDs(ctx context.Context, binlog string) (previousGtids string, err error) { 354 return "", fmd.ExecuteSuperQueryList(ctx, []string{ 355 fmt.Sprintf("FAKE SHOW BINLOG EVENTS IN '%s' LIMIT 2", binlog), 356 }) 357 } 358 359 // PrimaryPosition is part of the MysqlDaemon interface 360 func (fmd *FakeMysqlDaemon) PrimaryPosition() (mysql.Position, error) { 361 return fmd.CurrentPrimaryPosition, nil 362 } 363 364 // IsReadOnly is part of the MysqlDaemon interface 365 func (fmd *FakeMysqlDaemon) IsReadOnly() (bool, error) { 366 return fmd.ReadOnly, nil 367 } 368 369 // SetReadOnly is part of the MysqlDaemon interface 370 func (fmd *FakeMysqlDaemon) SetReadOnly(on bool) error { 371 fmd.ReadOnly = on 372 return nil 373 } 374 375 // SetSuperReadOnly is part of the MysqlDaemon interface 376 func (fmd *FakeMysqlDaemon) SetSuperReadOnly(on bool) error { 377 fmd.SuperReadOnly = on 378 fmd.ReadOnly = on 379 return nil 380 } 381 382 // StartReplication is part of the MysqlDaemon interface. 383 func (fmd *FakeMysqlDaemon) StartReplication(hookExtraEnv map[string]string) error { 384 if fmd.StartReplicationError != nil { 385 return fmd.StartReplicationError 386 } 387 return fmd.ExecuteSuperQueryList(context.Background(), []string{ 388 "START SLAVE", 389 }) 390 } 391 392 // RestartReplication is part of the MysqlDaemon interface. 393 func (fmd *FakeMysqlDaemon) RestartReplication(hookExtraEnv map[string]string) error { 394 return fmd.ExecuteSuperQueryList(context.Background(), []string{ 395 "STOP SLAVE", 396 "RESET SLAVE", 397 "START SLAVE", 398 }) 399 } 400 401 // StartReplicationUntilAfter is part of the MysqlDaemon interface. 402 func (fmd *FakeMysqlDaemon) StartReplicationUntilAfter(ctx context.Context, pos mysql.Position) error { 403 if !reflect.DeepEqual(fmd.StartReplicationUntilAfterPos, pos) { 404 return fmt.Errorf("wrong pos for StartReplicationUntilAfter: expected %v got %v", fmd.SetReplicationPositionPos, pos) 405 } 406 407 return fmd.ExecuteSuperQueryList(context.Background(), []string{ 408 "START SLAVE UNTIL AFTER", 409 }) 410 } 411 412 // StopReplication is part of the MysqlDaemon interface. 413 func (fmd *FakeMysqlDaemon) StopReplication(hookExtraEnv map[string]string) error { 414 return fmd.ExecuteSuperQueryList(context.Background(), []string{ 415 "STOP SLAVE", 416 }) 417 } 418 419 // StopIOThread is part of the MysqlDaemon interface. 420 func (fmd *FakeMysqlDaemon) StopIOThread(ctx context.Context) error { 421 return fmd.ExecuteSuperQueryList(context.Background(), []string{ 422 "STOP SLAVE IO_THREAD", 423 }) 424 } 425 426 // SetReplicationPosition is part of the MysqlDaemon interface. 427 func (fmd *FakeMysqlDaemon) SetReplicationPosition(ctx context.Context, pos mysql.Position) error { 428 if !reflect.DeepEqual(fmd.SetReplicationPositionPos, pos) { 429 return fmt.Errorf("wrong pos for SetReplicationPosition: expected %v got %v", fmd.SetReplicationPositionPos, pos) 430 } 431 return fmd.ExecuteSuperQueryList(ctx, []string{ 432 "FAKE SET SLAVE POSITION", 433 }) 434 } 435 436 // SetReplicationSource is part of the MysqlDaemon interface. 437 func (fmd *FakeMysqlDaemon) SetReplicationSource(ctx context.Context, host string, port int, stopReplicationBefore bool, startReplicationAfter bool) error { 438 input := fmt.Sprintf("%v:%v", host, port) 439 found := false 440 for _, sourceInput := range fmd.SetReplicationSourceInputs { 441 if sourceInput == input { 442 found = true 443 } 444 } 445 if !found { 446 return fmt.Errorf("wrong input for SetReplicationSourceCommands: expected a value in %v got %v", fmd.SetReplicationSourceInputs, input) 447 } 448 if fmd.SetReplicationSourceError != nil { 449 return fmd.SetReplicationSourceError 450 } 451 cmds := []string{} 452 if stopReplicationBefore { 453 cmds = append(cmds, "STOP SLAVE") 454 } 455 cmds = append(cmds, "RESET SLAVE ALL") 456 cmds = append(cmds, "FAKE SET MASTER") 457 if startReplicationAfter { 458 cmds = append(cmds, "START SLAVE") 459 } 460 return fmd.ExecuteSuperQueryList(ctx, cmds) 461 } 462 463 // WaitForReparentJournal is part of the MysqlDaemon interface 464 func (fmd *FakeMysqlDaemon) WaitForReparentJournal(ctx context.Context, timeCreatedNS int64) error { 465 return nil 466 } 467 468 // WaitSourcePos is part of the MysqlDaemon interface 469 func (fmd *FakeMysqlDaemon) WaitSourcePos(_ context.Context, pos mysql.Position) error { 470 if fmd.TimeoutHook != nil { 471 return fmd.TimeoutHook() 472 } 473 for _, position := range fmd.WaitPrimaryPositions { 474 if reflect.DeepEqual(position, pos) { 475 return nil 476 } 477 } 478 return fmt.Errorf("wrong input for WaitSourcePos: expected a value in %v got %v", fmd.WaitPrimaryPositions, pos) 479 } 480 481 // Promote is part of the MysqlDaemon interface 482 func (fmd *FakeMysqlDaemon) Promote(hookExtraEnv map[string]string) (mysql.Position, error) { 483 if fmd.PromoteLag > 0 { 484 time.Sleep(fmd.PromoteLag) 485 } 486 if fmd.PromoteError != nil { 487 return mysql.Position{}, fmd.PromoteError 488 } 489 return fmd.PromoteResult, nil 490 } 491 492 // ExecuteSuperQueryList is part of the MysqlDaemon interface 493 func (fmd *FakeMysqlDaemon) ExecuteSuperQueryList(ctx context.Context, queryList []string) error { 494 for _, query := range queryList { 495 // test we still have a query to compare 496 if fmd.ExpectedExecuteSuperQueryCurrent >= len(fmd.ExpectedExecuteSuperQueryList) { 497 return fmt.Errorf("unexpected extra query in ExecuteSuperQueryList: %v", query) 498 } 499 500 // compare the query 501 expected := fmd.ExpectedExecuteSuperQueryList[fmd.ExpectedExecuteSuperQueryCurrent] 502 fmd.ExpectedExecuteSuperQueryCurrent++ 503 if strings.HasPrefix(expected, "SUB") { 504 // remove the SUB from the expected, 505 // and truncate the query to length(expected) 506 expected = expected[3:] 507 if len(query) > len(expected) { 508 query = query[:len(expected)] 509 } 510 } 511 if expected != query { 512 return fmt.Errorf("wrong query for ExecuteSuperQueryList: expected %v got %v", expected, query) 513 } 514 515 // intercept some queries to update our status 516 switch query { 517 case "START SLAVE": 518 fmd.Replicating = true 519 case "STOP SLAVE": 520 fmd.Replicating = false 521 } 522 } 523 return nil 524 } 525 526 // FetchSuperQuery returns the results from the map, if any 527 func (fmd *FakeMysqlDaemon) FetchSuperQuery(ctx context.Context, query string) (*sqltypes.Result, error) { 528 if fmd.FetchSuperQueryMap == nil { 529 return nil, fmt.Errorf("unexpected query: %v", query) 530 } 531 532 qr, ok := fmd.FetchSuperQueryMap[query] 533 if !ok { 534 return nil, fmt.Errorf("unexpected query: %v", query) 535 } 536 return qr, nil 537 } 538 539 // EnableBinlogPlayback is part of the MysqlDaemon interface 540 func (fmd *FakeMysqlDaemon) EnableBinlogPlayback() error { 541 fmd.BinlogPlayerEnabled.Set(true) 542 return nil 543 } 544 545 // DisableBinlogPlayback disable playback of binlog events 546 func (fmd *FakeMysqlDaemon) DisableBinlogPlayback() error { 547 fmd.BinlogPlayerEnabled.Set(false) 548 return nil 549 } 550 551 // Close is part of the MysqlDaemon interface 552 func (fmd *FakeMysqlDaemon) Close() { 553 if fmd.appPool != nil { 554 fmd.appPool.Close() 555 } 556 } 557 558 // CheckSuperQueryList returns an error if all the queries we expected 559 // haven't been seen. 560 func (fmd *FakeMysqlDaemon) CheckSuperQueryList() error { 561 if fmd.ExpectedExecuteSuperQueryCurrent != len(fmd.ExpectedExecuteSuperQueryList) { 562 return fmt.Errorf("SuperQueryList wasn't consumed, saw %v queries, was expecting %v", fmd.ExpectedExecuteSuperQueryCurrent, len(fmd.ExpectedExecuteSuperQueryList)) 563 } 564 return nil 565 } 566 567 // GetSchema is part of the MysqlDaemon interface 568 func (fmd *FakeMysqlDaemon) GetSchema(ctx context.Context, dbName string, request *tabletmanagerdatapb.GetSchemaRequest) (*tabletmanagerdatapb.SchemaDefinition, error) { 569 if fmd.SchemaFunc != nil { 570 return fmd.SchemaFunc() 571 } 572 if fmd.Schema == nil { 573 return nil, fmt.Errorf("no schema defined") 574 } 575 return tmutils.FilterTables(fmd.Schema, request.Tables, request.ExcludeTables, request.IncludeViews) 576 } 577 578 // GetColumns is part of the MysqlDaemon interface 579 func (fmd *FakeMysqlDaemon) GetColumns(ctx context.Context, dbName, table string) ([]*querypb.Field, []string, error) { 580 return []*querypb.Field{}, []string{}, nil 581 } 582 583 // GetPrimaryKeyColumns is part of the MysqlDaemon interface 584 func (fmd *FakeMysqlDaemon) GetPrimaryKeyColumns(ctx context.Context, dbName, table string) ([]string, error) { 585 return []string{}, nil 586 } 587 588 // GetPrimaryKeyEquivalentColumns is part of the MysqlDaemon interface 589 func (fmd *FakeMysqlDaemon) GetPrimaryKeyEquivalentColumns(ctx context.Context, dbName, table string) ([]string, error) { 590 return []string{}, nil 591 } 592 593 // PreflightSchemaChange is part of the MysqlDaemon interface 594 func (fmd *FakeMysqlDaemon) PreflightSchemaChange(ctx context.Context, dbName string, changes []string) ([]*tabletmanagerdatapb.SchemaChangeResult, error) { 595 if fmd.PreflightSchemaChangeResult == nil { 596 return nil, fmt.Errorf("no preflight result defined") 597 } 598 return fmd.PreflightSchemaChangeResult, nil 599 } 600 601 // ApplySchemaChange is part of the MysqlDaemon interface 602 func (fmd *FakeMysqlDaemon) ApplySchemaChange(ctx context.Context, dbName string, change *tmutils.SchemaChange) (*tabletmanagerdatapb.SchemaChangeResult, error) { 603 beforeSchema, err := fmd.SchemaFunc() 604 if err != nil { 605 return nil, err 606 } 607 608 dbaCon, err := fmd.GetDbaConnection(ctx) 609 if err != nil { 610 return nil, err 611 } 612 if err = fmd.db.HandleQuery(dbaCon.Conn, change.SQL, func(*sqltypes.Result) error { return nil }); err != nil { 613 return nil, err 614 } 615 616 afterSchema, err := fmd.SchemaFunc() 617 if err != nil { 618 return nil, err 619 } 620 621 return &tabletmanagerdatapb.SchemaChangeResult{ 622 BeforeSchema: beforeSchema, 623 AfterSchema: afterSchema}, nil 624 } 625 626 // GetAppConnection is part of the MysqlDaemon interface. 627 func (fmd *FakeMysqlDaemon) GetAppConnection(ctx context.Context) (*dbconnpool.PooledDBConnection, error) { 628 return fmd.appPool.Get(ctx) 629 } 630 631 // GetDbaConnection is part of the MysqlDaemon interface. 632 func (fmd *FakeMysqlDaemon) GetDbaConnection(ctx context.Context) (*dbconnpool.DBConnection, error) { 633 return dbconnpool.NewDBConnection(ctx, fmd.db.ConnParams()) 634 } 635 636 // GetAllPrivsConnection is part of the MysqlDaemon interface. 637 func (fmd *FakeMysqlDaemon) GetAllPrivsConnection(ctx context.Context) (*dbconnpool.DBConnection, error) { 638 return dbconnpool.NewDBConnection(ctx, fmd.db.ConnParams()) 639 } 640 641 // SetSemiSyncEnabled is part of the MysqlDaemon interface. 642 func (fmd *FakeMysqlDaemon) SetSemiSyncEnabled(primary, replica bool) error { 643 fmd.SemiSyncPrimaryEnabled = primary 644 fmd.SemiSyncReplicaEnabled = replica 645 return nil 646 } 647 648 // SemiSyncEnabled is part of the MysqlDaemon interface. 649 func (fmd *FakeMysqlDaemon) SemiSyncEnabled() (primary, replica bool) { 650 return fmd.SemiSyncPrimaryEnabled, fmd.SemiSyncReplicaEnabled 651 } 652 653 // SemiSyncStatus is part of the MysqlDaemon interface. 654 func (fmd *FakeMysqlDaemon) SemiSyncStatus() (bool, bool) { 655 // The fake assumes the status worked. 656 if fmd.SemiSyncPrimaryEnabled { 657 return true, false 658 } 659 return false, fmd.SemiSyncReplicaEnabled 660 } 661 662 // SemiSyncClients is part of the MysqlDaemon interface. 663 func (fmd *FakeMysqlDaemon) SemiSyncClients() uint32 { 664 return 0 665 } 666 667 // SemiSyncSettings is part of the MysqlDaemon interface. 668 func (fmd *FakeMysqlDaemon) SemiSyncSettings() (timeout uint64, numReplicas uint32) { 669 return 10000000, 1 670 } 671 672 // SemiSyncReplicationStatus is part of the MysqlDaemon interface. 673 func (fmd *FakeMysqlDaemon) SemiSyncReplicationStatus() (bool, error) { 674 // The fake assumes the status worked. 675 return fmd.SemiSyncReplicaEnabled, nil 676 } 677 678 // GetVersionString is part of the MysqlDeamon interface. 679 func (fmd *FakeMysqlDaemon) GetVersionString() string { 680 return "" 681 } 682 683 // GetVersionComment is part of the MysqlDeamon interface. 684 func (fmd *FakeMysqlDaemon) GetVersionComment(ctx context.Context) string { 685 return "" 686 }