From 0665325a63cc9274a29a739166c400456b11d282 Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Wed, 2 Aug 2023 13:12:34 +0200 Subject: [PATCH 1/3] mysql: Refactor dependencies This starts splitting up the large `mysql` package into various subpackages that can handle more specific cases. The first is to extract replication concerns and sqlerror. These two packages now deal with parsing of GTIDs, positions and replication status and the latter with all the MySQL level error types. With this split, `vtorc` can actually build without loading in all the collations information as it doesn't actually need any of that. Before it was pulled in because it would need `go/mysql` for replication and error information. We can still further split off some main concerns, such as a `go/mysql/flavor` package and a `go/mysql/conn` package to split off specific bits for flavor detection and the actual MySQL connection. Signed-off-by: Dirkjan Bussink --- go/cmd/mysqlctl/mysqlctl.go | 13 +- go/cmd/vtbackup/vtbackup.go | 25 +- go/cmd/vtcombo/main.go | 5 +- go/cmd/vtctldclient/cli/shards.go | 6 +- go/cmd/vtctldclient/command/keyspaces.go | 4 +- go/mysql/auth_server.go | 11 +- go/mysql/auth_server_static.go | 16 +- go/mysql/binlog_dump.go | 5 +- go/mysql/binlog_event.go | 5 +- go/mysql/binlog_event_filepos.go | 24 +- go/mysql/binlog_event_make.go | 4 +- go/mysql/binlog_event_make_test.go | 10 +- go/mysql/binlog_event_mariadb.go | 9 +- go/mysql/binlog_event_mariadb_test.go | 6 +- go/mysql/binlog_event_mysql56.go | 15 +- go/mysql/binlog_event_mysql56_test.go | 33 +- go/mysql/client.go | 73 +-- go/mysql/client_test.go | 12 +- go/mysql/conn.go | 43 +- go/mysql/conn_flaky_test.go | 14 +- go/mysql/constants.go | 507 ------------------ go/mysql/constants_test.go | 26 +- go/mysql/endtoend/client_test.go | 10 +- go/mysql/endtoend/main_test.go | 6 +- go/mysql/endtoend/replication_test.go | 8 +- go/mysql/fakesqldb/server.go | 3 +- go/mysql/flavor.go | 152 ++---- go/mysql/flavor_filepos.go | 73 +-- go/mysql/flavor_filepos_test.go | 80 --- go/mysql/flavor_mariadb.go | 55 +- go/mysql/flavor_mariadb_test.go | 50 -- go/mysql/flavor_mysql.go | 86 +-- go/mysql/flavor_mysql_test.go | 72 --- go/mysql/flavor_mysqlgr.go | 35 +- go/mysql/flavor_mysqlgr_test.go | 10 +- go/mysql/query.go | 97 ++-- go/mysql/query_test.go | 4 +- go/mysql/replication.go | 9 +- go/mysql/{ => replication}/filepos_gtid.go | 61 ++- .../{ => replication}/filepos_gtid_test.go | 26 +- go/mysql/{ => replication}/gtid.go | 2 +- go/mysql/{ => replication}/gtid_set.go | 2 +- go/mysql/{ => replication}/gtid_test.go | 2 +- go/mysql/{ => replication}/mariadb_gtid.go | 8 +- .../{ => replication}/mariadb_gtid_test.go | 12 +- go/mysql/{ => replication}/mysql56_gtid.go | 2 +- .../{ => replication}/mysql56_gtid_set.go | 2 +- .../mysql56_gtid_set_test.go | 2 +- .../{ => replication}/mysql56_gtid_test.go | 14 +- go/mysql/{ => replication}/primary_status.go | 35 +- .../{ => replication}/replication_position.go | 4 +- .../replication_position_test.go | 2 +- .../{ => replication}/replication_status.go | 125 ++++- .../replication/replication_status_test.go | 292 ++++++++++ go/mysql/replication/state.go | 33 ++ go/mysql/replication_status_test.go | 115 ---- go/mysql/server.go | 11 +- go/mysql/server_flaky_test.go | 43 +- go/mysql/sqlerror/constants.go | 480 +++++++++++++++++ go/mysql/{ => sqlerror}/sql_error.go | 2 +- go/mysql/{ => sqlerror}/sql_error_test.go | 2 +- go/mysql/streaming_query.go | 13 +- go/mysql/vault/auth_server_vault.go | 8 +- .../backup/vtctlbackup/backup_utils.go | 13 +- .../backup/vtctlbackup/pitr_test_framework.go | 19 +- .../endtoend/mysqlserver/mysql_server_test.go | 10 +- .../onlineddl_vrepl_stress_suite_test.go | 5 +- .../reparent/plannedreparent/reparent_test.go | 7 +- go/test/endtoend/vreplication/helper_test.go | 3 +- .../vtgate/errors_as_warnings/main_test.go | 5 +- go/test/endtoend/vtgate/lookup_test.go | 6 +- go/test/endtoend/vtgate/misc_test.go | 6 +- .../vtgate/queries/random/random_test.go | 4 +- .../vtgate/reservedconn/sysvar_test.go | 7 +- go/test/endtoend/vtgate/sequence/seq_test.go | 5 +- go/vt/binlog/binlog_connection.go | 13 +- go/vt/binlog/binlog_streamer.go | 16 +- go/vt/binlog/binlog_streamer_rbr_test.go | 21 +- go/vt/binlog/binlog_streamer_test.go | 154 +++--- go/vt/binlog/binlogplayer/binlog_player.go | 33 +- .../binlog/binlogplayer/binlog_player_test.go | 16 +- go/vt/binlog/binlogplayer/dbclient.go | 3 +- go/vt/binlog/event_streamer.go | 7 +- go/vt/binlog/eventtoken/compare.go | 6 +- go/vt/binlog/updatestreamctl.go | 9 +- go/vt/dbconnpool/connection.go | 3 +- go/vt/mysqlctl/backup_test.go | 4 +- go/vt/mysqlctl/backupengine.go | 10 +- go/vt/mysqlctl/binlogs_gtid.go | 22 +- go/vt/mysqlctl/binlogs_gtid_test.go | 32 +- go/vt/mysqlctl/builtinbackupengine.go | 44 +- go/vt/mysqlctl/builtinbackupengine_test.go | 4 +- go/vt/mysqlctl/fakemysqldaemon.go | 48 +- go/vt/mysqlctl/mysql_daemon.go | 18 +- go/vt/mysqlctl/mysqld.go | 4 +- go/vt/mysqlctl/query.go | 4 +- go/vt/mysqlctl/reparent.go | 16 +- go/vt/mysqlctl/replication.go | 28 +- go/vt/mysqlctl/schema.go | 6 +- go/vt/mysqlctl/xtrabackupengine.go | 15 +- go/vt/sidecardb/sidecardb.go | 4 +- go/vt/vtadmin/cluster/cluster_test.go | 27 +- .../grpcvtctldserver/server_slow_test.go | 6 +- go/vt/vtctl/grpcvtctldserver/server_test.go | 3 +- .../reparentutil/emergency_reparenter.go | 9 +- .../reparentutil/emergency_reparenter_test.go | 178 +++--- .../vtctl/reparentutil/planned_reparenter.go | 7 +- go/vt/vtctl/reparentutil/reparent_sorter.go | 8 +- .../reparentutil/reparent_sorter_test.go | 33 +- go/vt/vtctl/reparentutil/replication.go | 35 +- go/vt/vtctl/reparentutil/replication_test.go | 110 ++-- go/vt/vtctl/reparentutil/util.go | 27 +- go/vt/vtctl/reparentutil/util_test.go | 30 +- go/vt/vtctl/workflow/server.go | 7 +- go/vt/vtctl/workflow/stream_migrator.go | 21 +- go/vt/vtctl/workflow/switcher_dry_run.go | 6 +- go/vt/vtctl/workflow/vreplication_stream.go | 4 +- go/vt/vterrors/vterrorsgen/main.go | 6 +- go/vt/vtgate/endtoend/lookup_test.go | 6 +- go/vt/vtgate/engine/merge_sort.go | 4 +- go/vt/vtgate/engine/route.go | 6 +- go/vt/vtgate/engine/route_test.go | 7 +- go/vt/vtgate/executor_dml_test.go | 5 +- go/vt/vtgate/executor_set_test.go | 8 +- go/vt/vtgate/executor_test.go | 16 +- go/vt/vtgate/plugin_mysql_server.go | 19 +- go/vt/vtgate/plugin_mysql_server_test.go | 4 +- go/vt/vtgate/scatter_conn.go | 8 +- go/vt/vtgate/scatter_conn_test.go | 22 +- go/vt/vtgate/schema/update_controller.go | 6 +- go/vt/vtgate/vcursor_impl.go | 7 +- go/vt/vtgate/vindexes/consistent_lookup.go | 6 +- .../vtgate/vindexes/consistent_lookup_test.go | 5 +- go/vt/vtorc/inst/instance_dao.go | 15 +- go/vt/vtorc/inst/replication_thread_state.go | 12 +- go/vt/vttablet/onlineddl/executor.go | 27 +- go/vt/vttablet/tabletmanager/restore.go | 26 +- .../vttablet/tabletmanager/rpc_replication.go | 45 +- go/vt/vttablet/tabletmanager/rpc_schema.go | 4 +- .../tabletmanager/vdiff/controller.go | 4 +- go/vt/vttablet/tabletmanager/vdiff/engine.go | 6 +- .../tabletmanager/vdiff/engine_test.go | 7 +- .../tabletmanager/vdiff/table_differ.go | 7 +- .../tabletmanager/vreplication/engine.go | 5 +- .../vreplication/framework_test.go | 3 +- .../tabletmanager/vreplication/stats_test.go | 5 +- .../tabletmanager/vreplication/utils.go | 158 +++--- .../tabletmanager/vreplication/vcopier.go | 7 +- .../tabletmanager/vreplication/vdbclient.go | 7 +- .../tabletmanager/vreplication/vplayer.go | 12 +- .../vreplication/vplayer_flaky_test.go | 6 +- .../tabletmanager/vreplication/vreplicator.go | 9 +- .../vttablet/tabletserver/connpool/dbconn.go | 10 +- .../tabletserver/connpool/dbconn_test.go | 7 +- go/vt/vttablet/tabletserver/gc/tablegc.go | 6 +- .../tabletserver/messager/message_manager.go | 11 +- go/vt/vttablet/tabletserver/query_engine.go | 4 +- go/vt/vttablet/tabletserver/query_executor.go | 10 +- go/vt/vttablet/tabletserver/schema/engine.go | 15 +- .../tabletserver/schema/engine_test.go | 13 +- .../vttablet/tabletserver/schema/historian.go | 12 +- go/vt/vttablet/tabletserver/schema/tracker.go | 8 +- .../tabletserver/stateful_connection.go | 4 +- go/vt/vttablet/tabletserver/tabletserver.go | 77 +-- .../tabletserver/tabletserver_test.go | 11 +- go/vt/vttablet/tabletserver/vstreamer/copy.go | 14 +- .../tabletserver/vstreamer/rowstreamer.go | 4 +- .../tabletserver/vstreamer/snapshot_conn.go | 8 +- .../tabletserver/vstreamer/uvstreamer.go | 22 +- .../tabletserver/vstreamer/vstreamer.go | 22 +- .../vstreamer/vstreamer_flaky_test.go | 3 +- go/vt/vttablet/tmrpctest/test_tm_rpc.go | 7 +- go/vt/wrangler/switcher_dry_run.go | 6 +- go/vt/wrangler/testlib/backup_test.go | 86 +-- .../testlib/emergency_reparent_shard_test.go | 68 +-- .../testlib/planned_reparent_shard_test.go | 85 +-- go/vt/wrangler/testlib/reparent_utils_test.go | 15 +- go/vt/wrangler/traffic_switcher_env_test.go | 15 +- go/vt/wrangler/vdiff.go | 12 +- go/vt/wrangler/vexec.go | 4 +- go/vt/wrangler/workflow.go | 6 +- tools/rowlog/rowlog.go | 4 +- 182 files changed, 2633 insertions(+), 2491 deletions(-) delete mode 100644 go/mysql/flavor_filepos_test.go rename go/mysql/{ => replication}/filepos_gtid.go (68%) rename go/mysql/{ => replication}/filepos_gtid_test.go (77%) rename go/mysql/{ => replication}/gtid.go (99%) rename go/mysql/{ => replication}/gtid_set.go (99%) rename go/mysql/{ => replication}/gtid_test.go (99%) rename go/mysql/{ => replication}/mariadb_gtid.go (97%) rename go/mysql/{ => replication}/mariadb_gtid_test.go (98%) rename go/mysql/{ => replication}/mysql56_gtid.go (99%) rename go/mysql/{ => replication}/mysql56_gtid_set.go (99%) rename go/mysql/{ => replication}/mysql56_gtid_set_test.go (99%) rename go/mysql/{ => replication}/mysql56_gtid_test.go (90%) rename go/mysql/{ => replication}/primary_status.go (53%) rename go/mysql/{ => replication}/replication_position.go (99%) rename go/mysql/{ => replication}/replication_position_test.go (99%) rename go/mysql/{ => replication}/replication_status.go (63%) create mode 100644 go/mysql/replication/replication_status_test.go create mode 100644 go/mysql/replication/state.go delete mode 100644 go/mysql/replication_status_test.go create mode 100644 go/mysql/sqlerror/constants.go rename go/mysql/{ => sqlerror}/sql_error.go (99%) rename go/mysql/{ => sqlerror}/sql_error_test.go (99%) diff --git a/go/cmd/mysqlctl/mysqlctl.go b/go/cmd/mysqlctl/mysqlctl.go index 6873cc2bf56..ba59309e981 100644 --- a/go/cmd/mysqlctl/mysqlctl.go +++ b/go/cmd/mysqlctl/mysqlctl.go @@ -25,11 +25,12 @@ import ( "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/acl" "vitess.io/vitess/go/cmd" "vitess.io/vitess/go/exit" "vitess.io/vitess/go/flagutil" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" @@ -175,30 +176,30 @@ func positionCmd(subFlags *pflag.FlagSet, args []string) error { return fmt.Errorf("not enough arguments for position operation") } - pos1, err := mysql.DecodePosition(args[1]) + pos1, err := replication.DecodePosition(args[1]) if err != nil { return err } switch args[0] { case "equal": - pos2, err := mysql.DecodePosition(args[2]) + pos2, err := replication.DecodePosition(args[2]) if err != nil { return err } fmt.Println(pos1.Equal(pos2)) case "at_least": - pos2, err := mysql.DecodePosition(args[2]) + pos2, err := replication.DecodePosition(args[2]) if err != nil { return err } fmt.Println(pos1.AtLeast(pos2)) case "append": - gtid, err := mysql.DecodeGTID(args[2]) + gtid, err := replication.DecodeGTID(args[2]) if err != nil { return err } - fmt.Println(mysql.AppendGTID(pos1, gtid)) + fmt.Println(replication.AppendGTID(pos1, gtid)) } return nil diff --git a/go/cmd/vtbackup/vtbackup.go b/go/cmd/vtbackup/vtbackup.go index 9c413b81a19..31b7a4dc596 100644 --- a/go/cmd/vtbackup/vtbackup.go +++ b/go/cmd/vtbackup/vtbackup.go @@ -70,10 +70,11 @@ import ( "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/acl" "vitess.io/vitess/go/cmd" "vitess.io/vitess/go/exit" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/stats" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" @@ -359,7 +360,7 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back Stats: backupstats.RestoreStats(), } backupManifest, err := mysqlctl.Restore(ctx, params) - var restorePos mysql.Position + var restorePos replication.Position switch err { case nil: // if err is nil, we expect backupManifest to be non-nil @@ -370,7 +371,7 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back if !allowFirstBackup { return fmt.Errorf("no backup found; not starting up empty since --initial_backup flag was not enabled") } - restorePos = mysql.Position{} + restorePos = replication.Position{} default: return fmt.Errorf("can't restore from backup: %v", err) } @@ -408,7 +409,7 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back tmc := tmclient.NewTabletManagerClient() // Keep retrying if we can't contact the primary. The primary might be // changing, moving, or down temporarily. - var primaryPos mysql.Position + var primaryPos replication.Position err = retryOnError(ctx, func() error { // Add a per-operation timeout so we re-read topo if the primary is unreachable. opCtx, optCancel := context.WithTimeout(ctx, operationTimeout) @@ -516,7 +517,7 @@ func takeBackup(ctx context.Context, topoServer *topo.Server, backupStorage back return nil } -func resetReplication(ctx context.Context, pos mysql.Position, mysqld mysqlctl.MysqlDaemon) error { +func resetReplication(ctx context.Context, pos replication.Position, mysqld mysqlctl.MysqlDaemon) error { cmds := []string{ "STOP SLAVE", "RESET SLAVE ALL", // "ALL" makes it forget replication source host:port. @@ -563,27 +564,27 @@ func startReplication(ctx context.Context, mysqld mysqlctl.MysqlDaemon, topoServ return nil } -func getPrimaryPosition(ctx context.Context, tmc tmclient.TabletManagerClient, ts *topo.Server) (mysql.Position, error) { +func getPrimaryPosition(ctx context.Context, tmc tmclient.TabletManagerClient, ts *topo.Server) (replication.Position, error) { si, err := ts.GetShard(ctx, initKeyspace, initShard) if err != nil { - return mysql.Position{}, vterrors.Wrap(err, "can't read shard") + return replication.Position{}, vterrors.Wrap(err, "can't read shard") } if topoproto.TabletAliasIsZero(si.PrimaryAlias) { // Normal tablets will sit around waiting to be reparented in this case. // Since vtbackup is a batch job, we just have to fail. - return mysql.Position{}, fmt.Errorf("shard %v/%v has no primary", initKeyspace, initShard) + return replication.Position{}, fmt.Errorf("shard %v/%v has no primary", initKeyspace, initShard) } ti, err := ts.GetTablet(ctx, si.PrimaryAlias) if err != nil { - return mysql.Position{}, fmt.Errorf("can't get primary tablet record %v: %v", topoproto.TabletAliasString(si.PrimaryAlias), err) + return replication.Position{}, fmt.Errorf("can't get primary tablet record %v: %v", topoproto.TabletAliasString(si.PrimaryAlias), err) } posStr, err := tmc.PrimaryPosition(ctx, ti.Tablet) if err != nil { - return mysql.Position{}, fmt.Errorf("can't get primary replication position: %v", err) + return replication.Position{}, fmt.Errorf("can't get primary replication position: %v", err) } - pos, err := mysql.DecodePosition(posStr) + pos, err := replication.DecodePosition(posStr) if err != nil { - return mysql.Position{}, fmt.Errorf("can't decode primary replication position %q: %v", posStr, err) + return replication.Position{}, fmt.Errorf("can't decode primary replication position %q: %v", posStr, err) } return pos, nil } diff --git a/go/cmd/vtcombo/main.go b/go/cmd/vtcombo/main.go index abdd20453cf..1e2483428d7 100644 --- a/go/cmd/vtcombo/main.go +++ b/go/cmd/vtcombo/main.go @@ -30,9 +30,10 @@ import ( "github.com/spf13/pflag" "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/acl" "vitess.io/vitess/go/exit" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" @@ -342,7 +343,7 @@ func (mysqld *vtcomboMysqld) RestartReplication(hookExtraEnv map[string]string) } // StartReplicationUntilAfter implements the MysqlDaemon interface -func (mysqld *vtcomboMysqld) StartReplicationUntilAfter(ctx context.Context, pos mysql.Position) error { +func (mysqld *vtcomboMysqld) StartReplicationUntilAfter(ctx context.Context, pos replication.Position) error { return nil } diff --git a/go/cmd/vtctldclient/cli/shards.go b/go/cmd/vtctldclient/cli/shards.go index 93d7529d9a8..8ee38eff0d4 100644 --- a/go/cmd/vtctldclient/cli/shards.go +++ b/go/cmd/vtctldclient/cli/shards.go @@ -19,7 +19,7 @@ package cli import ( "sort" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/topo/topoproto" replicationdatapb "vitess.io/vitess/go/vt/proto/replicationdata" @@ -83,12 +83,12 @@ func (rts rTablets) Less(i, j int) bool { } // then compare replication positions - lpos, err := mysql.DecodePosition(l.Status.Position) + lpos, err := replication.DecodePosition(l.Status.Position) if err != nil { return true } - rpos, err := mysql.DecodePosition(r.Status.Position) + rpos, err := replication.DecodePosition(r.Status.Position) if err != nil { return false } diff --git a/go/cmd/vtctldclient/command/keyspaces.go b/go/cmd/vtctldclient/command/keyspaces.go index c224e3eb26b..8b98e661fb6 100644 --- a/go/cmd/vtctldclient/command/keyspaces.go +++ b/go/cmd/vtctldclient/command/keyspaces.go @@ -24,6 +24,8 @@ import ( "github.com/spf13/cobra" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/cmd/vtctldclient/cli" "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/mysql" @@ -184,7 +186,7 @@ func commandCreateKeyspace(cmd *cobra.Command, args []string) error { return errors.New("--sidecar-db-name cannot be empty when creating a keyspace") } if len(createKeyspaceOptions.SidecarDBName) > mysql.MaxIdentifierLength { - return mysql.NewSQLError(mysql.ERTooLongIdent, mysql.SSDataTooLong, "--sidecar-db-name identifier value of %q is too long (%d chars), max length for database identifiers is %d characters", + return sqlerror.NewSQLError(sqlerror.ERTooLongIdent, sqlerror.SSDataTooLong, "--sidecar-db-name identifier value of %q is too long (%d chars), max length for database identifiers is %d characters", createKeyspaceOptions.SidecarDBName, len(createKeyspaceOptions.SidecarDBName), mysql.MaxIdentifierLength) } diff --git a/go/mysql/auth_server.go b/go/mysql/auth_server.go index 18fa2ac2785..f4bda2655a5 100644 --- a/go/mysql/auth_server.go +++ b/go/mysql/auth_server.go @@ -26,6 +26,7 @@ import ( "net" "sync" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" @@ -427,7 +428,7 @@ func (n *mysqlNativePasswordAuthMethod) AllowClearTextWithoutTLS() bool { func (n *mysqlNativePasswordAuthMethod) HandleAuthPluginData(conn *Conn, user string, serverAuthPluginData []byte, clientAuthPluginData []byte, remoteAddr net.Addr) (Getter, error) { if serverAuthPluginData[len(serverAuthPluginData)-1] != 0x00 { - return nil, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return nil, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } salt := serverAuthPluginData[:len(serverAuthPluginData)-1] @@ -519,7 +520,7 @@ func (n *mysqlCachingSha2AuthMethod) AllowClearTextWithoutTLS() bool { func (n *mysqlCachingSha2AuthMethod) HandleAuthPluginData(c *Conn, user string, serverAuthPluginData []byte, clientAuthPluginData []byte, remoteAddr net.Addr) (Getter, error) { if serverAuthPluginData[len(serverAuthPluginData)-1] != 0x00 { - return nil, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return nil, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } salt := serverAuthPluginData[:len(serverAuthPluginData)-1] @@ -531,7 +532,7 @@ func (n *mysqlCachingSha2AuthMethod) HandleAuthPluginData(c *Conn, user string, switch cacheState { case AuthRejected: - return nil, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return nil, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) case AuthAccepted: // We need to write a more data packet to indicate the // handshake completed properly. This will be followed @@ -546,7 +547,7 @@ func (n *mysqlCachingSha2AuthMethod) HandleAuthPluginData(c *Conn, user string, return result, nil case AuthNeedMoreData: if !c.TLSEnabled() && !c.IsUnixSocket() { - return nil, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return nil, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } data, pos := c.startEphemeralPacketWithHeader(2) @@ -562,7 +563,7 @@ func (n *mysqlCachingSha2AuthMethod) HandleAuthPluginData(c *Conn, user string, return n.storage.UserEntryWithPassword(c, user, password, remoteAddr) default: // Somehow someone returned an unknown state, let's error with access denied. - return nil, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return nil, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } } diff --git a/go/mysql/auth_server_static.go b/go/mysql/auth_server_static.go index d01bab23cdd..fae886039f0 100644 --- a/go/mysql/auth_server_static.go +++ b/go/mysql/auth_server_static.go @@ -29,6 +29,8 @@ import ( "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/vterrors" @@ -179,7 +181,7 @@ func (a *AuthServerStatic) UserEntryWithPassword(conn *Conn, user string, passwo a.mu.Unlock() if !ok { - return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return &StaticUserData{}, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } for _, entry := range entries { @@ -188,7 +190,7 @@ func (a *AuthServerStatic) UserEntryWithPassword(conn *Conn, user string, passwo return &StaticUserData{entry.UserData, entry.Groups}, nil } } - return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return &StaticUserData{}, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } // UserEntryWithHash implements password lookup based on a @@ -199,14 +201,14 @@ func (a *AuthServerStatic) UserEntryWithHash(conn *Conn, salt []byte, user strin a.mu.Unlock() if !ok { - return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return &StaticUserData{}, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } for _, entry := range entries { if entry.MysqlNativePassword != "" { hash, err := DecodeMysqlNativePasswordHex(entry.MysqlNativePassword) if err != nil { - return &StaticUserData{entry.UserData, entry.Groups}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return &StaticUserData{entry.UserData, entry.Groups}, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } isPass := VerifyHashedMysqlNativePassword(authResponse, salt, hash) @@ -221,7 +223,7 @@ func (a *AuthServerStatic) UserEntryWithHash(conn *Conn, salt []byte, user strin } } } - return &StaticUserData{}, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return &StaticUserData{}, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } // UserEntryWithCacheHash implements password lookup based on a @@ -232,7 +234,7 @@ func (a *AuthServerStatic) UserEntryWithCacheHash(conn *Conn, salt []byte, user a.mu.Unlock() if !ok { - return &StaticUserData{}, AuthRejected, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return &StaticUserData{}, AuthRejected, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } for _, entry := range entries { @@ -243,7 +245,7 @@ func (a *AuthServerStatic) UserEntryWithCacheHash(conn *Conn, salt []byte, user return &StaticUserData{entry.UserData, entry.Groups}, AuthAccepted, nil } } - return &StaticUserData{}, AuthRejected, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "Access denied for user '%v'", user) + return &StaticUserData{}, AuthRejected, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } // AuthMethods returns the AuthMethod instances this auth server can handle. diff --git a/go/mysql/binlog_dump.go b/go/mysql/binlog_dump.go index 8383a590c5e..d6768056974 100644 --- a/go/mysql/binlog_dump.go +++ b/go/mysql/binlog_dump.go @@ -20,6 +20,7 @@ import ( "encoding/binary" "io" + "vitess.io/vitess/go/mysql/replication" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" ) @@ -51,7 +52,7 @@ func (c *Conn) parseComBinlogDump(data []byte) (logFile string, binlogPos uint32 return logFile, binlogPos, nil } -func (c *Conn) parseComBinlogDumpGTID(data []byte) (logFile string, logPos uint64, position Position, err error) { +func (c *Conn) parseComBinlogDumpGTID(data []byte) (logFile string, logPos uint64, position replication.Position, err error) { // see https://dev.mysql.com/doc/internals/en/com-binlog-dump-gtid.html pos := 1 @@ -80,7 +81,7 @@ func (c *Conn) parseComBinlogDumpGTID(data []byte) (logFile string, logPos uint6 return logFile, logPos, position, readPacketErr } if gtid := string(data[pos : pos+int(dataSize)]); gtid != "" { - position, err = DecodePosition(gtid) + position, err = replication.DecodePosition(gtid) if err != nil { return logFile, logPos, position, err } diff --git a/go/mysql/binlog_event.go b/go/mysql/binlog_event.go index 0e9bfc1f155..e58cb9b254c 100644 --- a/go/mysql/binlog_event.go +++ b/go/mysql/binlog_event.go @@ -19,6 +19,7 @@ package mysql import ( "fmt" + "vitess.io/vitess/go/mysql/replication" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" ) @@ -95,7 +96,7 @@ type BinlogEvent interface { // GTID returns the GTID from the event, and if this event // also serves as a BEGIN statement. // This is only valid if IsGTID() returns true. - GTID(BinlogFormat) (GTID, bool, error) + GTID(BinlogFormat) (replication.GTID, bool, error) // Query returns a Query struct representing data from a QUERY_EVENT. // This is only valid if IsQuery() returns true. Query(BinlogFormat) (Query, error) @@ -107,7 +108,7 @@ type BinlogEvent interface { Rand(BinlogFormat) (uint64, uint64, error) // PreviousGTIDs returns the Position from the event. // This is only valid if IsPreviousGTIDs() returns true. - PreviousGTIDs(BinlogFormat) (Position, error) + PreviousGTIDs(BinlogFormat) (replication.Position, error) // TableID returns the table ID for a TableMap, UpdateRows, // WriteRows or DeleteRows event. diff --git a/go/mysql/binlog_event_filepos.go b/go/mysql/binlog_event_filepos.go index 8cf7ea11db9..4edc4bb91ff 100644 --- a/go/mysql/binlog_event_filepos.go +++ b/go/mysql/binlog_event_filepos.go @@ -19,6 +19,8 @@ package mysql import ( "encoding/binary" "fmt" + + "vitess.io/vitess/go/mysql/replication" ) // filePosBinlogEvent wraps a raw packet buffer and provides methods to examine @@ -38,7 +40,7 @@ func newFilePosBinlogEvent(buf []byte) *filePosBinlogEvent { return &filePosBinlogEvent{binlogEvent: binlogEvent(buf)} } -func (*filePosBinlogEvent) GTID(BinlogFormat) (GTID, bool, error) { +func (*filePosBinlogEvent) GTID(BinlogFormat) (replication.GTID, bool, error) { return nil, false, nil } @@ -51,8 +53,8 @@ func (*filePosBinlogEvent) IsGTID() bool { return false } -func (*filePosBinlogEvent) PreviousGTIDs(BinlogFormat) (Position, error) { - return Position{}, fmt.Errorf("filePos should not provide PREVIOUS_GTIDS_EVENT events") +func (*filePosBinlogEvent) PreviousGTIDs(BinlogFormat) (replication.Position, error) { + return replication.Position{}, fmt.Errorf("filePos should not provide PREVIOUS_GTIDS_EVENT events") } // StripChecksum implements BinlogEvent.StripChecksum(). @@ -213,7 +215,7 @@ func (ev filePosFakeEvent) Format() (BinlogFormat, error) { return BinlogFormat{}, nil } -func (ev filePosFakeEvent) GTID(BinlogFormat) (GTID, bool, error) { +func (ev filePosFakeEvent) GTID(BinlogFormat) (replication.GTID, bool, error) { return nil, false, nil } @@ -229,8 +231,8 @@ func (ev filePosFakeEvent) Rand(BinlogFormat) (uint64, uint64, error) { return 0, 0, nil } -func (ev filePosFakeEvent) PreviousGTIDs(BinlogFormat) (Position, error) { - return Position{}, nil +func (ev filePosFakeEvent) PreviousGTIDs(BinlogFormat) (replication.Position, error) { + return replication.Position{}, nil } func (ev filePosFakeEvent) TableID(BinlogFormat) uint64 { @@ -270,7 +272,7 @@ func (ev filePosFakeEvent) Bytes() []byte { // filePosGTIDEvent is a fake GTID event for filePos. type filePosGTIDEvent struct { filePosFakeEvent - gtid filePosGTID + gtid replication.FilePosGTID } func newFilePosGTIDEvent(file string, pos uint32, timestamp uint32) filePosGTIDEvent { @@ -278,9 +280,9 @@ func newFilePosGTIDEvent(file string, pos uint32, timestamp uint32) filePosGTIDE filePosFakeEvent: filePosFakeEvent{ timestamp: timestamp, }, - gtid: filePosGTID{ - file: file, - pos: pos, + gtid: replication.FilePosGTID{ + File: file, + Pos: pos, }, } } @@ -293,6 +295,6 @@ func (ev filePosGTIDEvent) StripChecksum(f BinlogFormat) (BinlogEvent, []byte, e return ev, nil, nil } -func (ev filePosGTIDEvent) GTID(BinlogFormat) (GTID, bool, error) { +func (ev filePosGTIDEvent) GTID(BinlogFormat) (replication.GTID, bool, error) { return ev.gtid, false, nil } diff --git a/go/mysql/binlog_event_make.go b/go/mysql/binlog_event_make.go index 0688fa9540b..52a8c453517 100644 --- a/go/mysql/binlog_event_make.go +++ b/go/mysql/binlog_event_make.go @@ -19,6 +19,8 @@ package mysql import ( "encoding/binary" "hash/crc32" + + "vitess.io/vitess/go/mysql/replication" ) const ( @@ -292,7 +294,7 @@ func NewIntVarEvent(f BinlogFormat, s *FakeBinlogStream, typ byte, value uint64) // NewMariaDBGTIDEvent returns a MariaDB specific GTID event. // It ignores the Server in the gtid, instead uses the FakeBinlogStream.ServerID. -func NewMariaDBGTIDEvent(f BinlogFormat, s *FakeBinlogStream, gtid MariadbGTID, hasBegin bool) BinlogEvent { +func NewMariaDBGTIDEvent(f BinlogFormat, s *FakeBinlogStream, gtid replication.MariadbGTID, hasBegin bool) BinlogEvent { length := 8 + // sequence 4 + // domain 1 // flags2 diff --git a/go/mysql/binlog_event_make_test.go b/go/mysql/binlog_event_make_test.go index 7eb94fef848..12d8a54ff97 100644 --- a/go/mysql/binlog_event_make_test.go +++ b/go/mysql/binlog_event_make_test.go @@ -23,6 +23,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/binlog" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" ) @@ -149,7 +151,7 @@ func TestMariadDBGTIDEVent(t *testing.T) { s.ServerID = 0x87654321 // With built-in begin. - event := NewMariaDBGTIDEvent(f, s, MariadbGTID{Domain: 0, Sequence: 0x123456789abcdef0}, true) + event := NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0x123456789abcdef0}, true) require.True(t, event.IsValid(), "NewMariaDBGTIDEvent().IsValid() is false") require.True(t, event.IsGTID(), "NewMariaDBGTIDEvent().IsGTID() if false") @@ -160,7 +162,7 @@ func TestMariadDBGTIDEVent(t *testing.T) { require.NoError(t, err, "NewMariaDBGTIDEvent().GTID() returned error: %v", err) require.True(t, hasBegin, "NewMariaDBGTIDEvent() didn't store hasBegin properly.") - mgtid, ok := gtid.(MariadbGTID) + mgtid, ok := gtid.(replication.MariadbGTID) require.True(t, ok, "NewMariaDBGTIDEvent().GTID() returned a non-MariaDBGTID GTID") if mgtid.Domain != 0 || mgtid.Server != 0x87654321 || mgtid.Sequence != 0x123456789abcdef0 { @@ -168,7 +170,7 @@ func TestMariadDBGTIDEVent(t *testing.T) { } // Without built-in begin. - event = NewMariaDBGTIDEvent(f, s, MariadbGTID{Domain: 0, Sequence: 0x123456789abcdef0}, false) + event = NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0x123456789abcdef0}, false) require.True(t, event.IsValid(), "NewMariaDBGTIDEvent().IsValid() is false") require.True(t, event.IsGTID(), "NewMariaDBGTIDEvent().IsGTID() if false") @@ -179,7 +181,7 @@ func TestMariadDBGTIDEVent(t *testing.T) { require.NoError(t, err, "NewMariaDBGTIDEvent().GTID() returned error: %v", err) require.False(t, hasBegin, "NewMariaDBGTIDEvent() didn't store hasBegin properly.") - mgtid, ok = gtid.(MariadbGTID) + mgtid, ok = gtid.(replication.MariadbGTID) require.True(t, ok, "NewMariaDBGTIDEvent().GTID() returned a non-MariaDBGTID GTID") if mgtid.Domain != 0 || mgtid.Server != 0x87654321 || mgtid.Sequence != 0x123456789abcdef0 { diff --git a/go/mysql/binlog_event_mariadb.go b/go/mysql/binlog_event_mariadb.go index 33f858c2f36..f2c0ec8f369 100644 --- a/go/mysql/binlog_event_mariadb.go +++ b/go/mysql/binlog_event_mariadb.go @@ -19,6 +19,7 @@ package mysql import ( "encoding/binary" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" ) @@ -59,13 +60,13 @@ func (ev mariadbBinlogEvent) IsGTID() bool { // 8 sequence number // 4 domain ID // 1 flags2 -func (ev mariadbBinlogEvent) GTID(f BinlogFormat) (GTID, bool, error) { +func (ev mariadbBinlogEvent) GTID(f BinlogFormat) (replication.GTID, bool, error) { const FLStandalone = 1 data := ev.Bytes()[f.HeaderLength:] flags2 := data[8+4] - return MariadbGTID{ + return replication.MariadbGTID{ Sequence: binary.LittleEndian.Uint64(data[:8]), Domain: binary.LittleEndian.Uint32(data[8 : 8+4]), Server: ev.ServerID(), @@ -73,8 +74,8 @@ func (ev mariadbBinlogEvent) GTID(f BinlogFormat) (GTID, bool, error) { } // PreviousGTIDs implements BinlogEvent.PreviousGTIDs(). -func (ev mariadbBinlogEvent) PreviousGTIDs(f BinlogFormat) (Position, error) { - return Position{}, vterrors.Errorf(vtrpc.Code_INTERNAL, "MariaDB should not provide PREVIOUS_GTIDS_EVENT events") +func (ev mariadbBinlogEvent) PreviousGTIDs(f BinlogFormat) (replication.Position, error) { + return replication.Position{}, vterrors.Errorf(vtrpc.Code_INTERNAL, "MariaDB should not provide PREVIOUS_GTIDS_EVENT events") } // StripChecksum implements BinlogEvent.StripChecksum(). diff --git a/go/mysql/binlog_event_mariadb_test.go b/go/mysql/binlog_event_mariadb_test.go index 1464da0e573..c4eeac39c38 100644 --- a/go/mysql/binlog_event_mariadb_test.go +++ b/go/mysql/binlog_event_mariadb_test.go @@ -22,6 +22,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/mysql/replication" ) // sample event data @@ -99,7 +101,7 @@ func TestMariadbStandaloneBinlogEventGTID(t *testing.T) { } input := mariadbBinlogEvent{binlogEvent: binlogEvent(mariadbStandaloneGTIDEvent)} - want := MariadbGTID{Domain: 0, Server: 62344, Sequence: 9} + want := replication.MariadbGTID{Domain: 0, Server: 62344, Sequence: 9} got, hasBegin, err := input.GTID(f) assert.NoError(t, err, "unexpected error: %v", err) assert.False(t, hasBegin, "unexpected hasBegin") @@ -115,7 +117,7 @@ func TestMariadbBinlogEventGTID(t *testing.T) { } input := mariadbBinlogEvent{binlogEvent: binlogEvent(mariadbBeginGTIDEvent)} - want := MariadbGTID{Domain: 0, Server: 62344, Sequence: 10} + want := replication.MariadbGTID{Domain: 0, Server: 62344, Sequence: 10} got, hasBegin, err := input.GTID(f) assert.NoError(t, err, "unexpected error: %v", err) assert.True(t, hasBegin, "unexpected !hasBegin") diff --git a/go/mysql/binlog_event_mysql56.go b/go/mysql/binlog_event_mysql56.go index 2e6cfec2dfa..3f931310ba9 100644 --- a/go/mysql/binlog_event_mysql56.go +++ b/go/mysql/binlog_event_mysql56.go @@ -19,6 +19,7 @@ package mysql import ( "encoding/binary" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" ) @@ -59,22 +60,22 @@ func (ev mysql56BinlogEvent) IsGTID() bool { // 1 flags // 16 SID (server UUID) // 8 GNO (sequence number, signed int) -func (ev mysql56BinlogEvent) GTID(f BinlogFormat) (GTID, bool, error) { +func (ev mysql56BinlogEvent) GTID(f BinlogFormat) (replication.GTID, bool, error) { data := ev.Bytes()[f.HeaderLength:] - var sid SID + var sid replication.SID copy(sid[:], data[1:1+16]) gno := int64(binary.LittleEndian.Uint64(data[1+16 : 1+16+8])) - return Mysql56GTID{Server: sid, Sequence: gno}, false /* hasBegin */, nil + return replication.Mysql56GTID{Server: sid, Sequence: gno}, false /* hasBegin */, nil } // PreviousGTIDs implements BinlogEvent.PreviousGTIDs(). -func (ev mysql56BinlogEvent) PreviousGTIDs(f BinlogFormat) (Position, error) { +func (ev mysql56BinlogEvent) PreviousGTIDs(f BinlogFormat) (replication.Position, error) { data := ev.Bytes()[f.HeaderLength:] - set, err := NewMysql56GTIDSetFromSIDBlock(data) + set, err := replication.NewMysql56GTIDSetFromSIDBlock(data) if err != nil { - return Position{}, err + return replication.Position{}, err } - return Position{ + return replication.Position{ GTIDSet: set, }, nil } diff --git a/go/mysql/binlog_event_mysql56_test.go b/go/mysql/binlog_event_mysql56_test.go index 86b58862ef9..e5fa3545278 100644 --- a/go/mysql/binlog_event_mysql56_test.go +++ b/go/mysql/binlog_event_mysql56_test.go @@ -23,6 +23,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/mysql/replication" ) // Sample event data for MySQL 5.6. @@ -79,25 +81,14 @@ func TestMysql56GTID(t *testing.T) { require.NoError(t, err, "StripChecksum() error: %v", err) require.True(t, input.IsGTID(), "IsGTID() = false, want true") - want, _ := parseMysql56GTID("439192bd-f37c-11e4-bbeb-0242ac11035a:4") + want := replication.Mysql56GTID{ + Server: replication.SID{0x43, 0x91, 0x92, 0xbd, 0xf3, 0x7c, 0x11, 0xe4, 0xbb, 0xeb, 0x2, 0x42, 0xac, 0x11, 0x3, 0x5a}, + Sequence: 4, + } got, hasBegin, err := input.GTID(format) require.NoError(t, err, "GTID() error: %v", err) assert.False(t, hasBegin, "GTID() returned hasBegin") assert.Equal(t, want, got, "GTID() = %#v, want %#v", got, want) - -} - -func TestMysql56ParseGTID(t *testing.T) { - input := "00010203-0405-0607-0809-0A0B0C0D0E0F:56789" - want := Mysql56GTID{ - Server: SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, - Sequence: 56789, - } - - got, err := parseMysql56GTID(input) - require.NoError(t, err, "unexpected error: %v", err) - assert.Equal(t, want, got, "(&mysql56{}).ParseGTID(%#v) = %#v, want %#v", input, got, want) - } func TestMysql56DecodeTransactionPayload(t *testing.T) { @@ -148,13 +139,13 @@ func TestMysql56DecodeTransactionPayload(t *testing.T) { func TestMysql56ParsePosition(t *testing.T) { input := "00010203-0405-0607-0809-0a0b0c0d0e0f:1-2" - sid := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - var set GTIDSet = Mysql56GTIDSet{} - set = set.AddGTID(Mysql56GTID{Server: sid, Sequence: 1}) - set = set.AddGTID(Mysql56GTID{Server: sid, Sequence: 2}) - want := Position{GTIDSet: set} + sid := replication.SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + var set replication.GTIDSet = replication.Mysql56GTIDSet{} + set = set.AddGTID(replication.Mysql56GTID{Server: sid, Sequence: 1}) + set = set.AddGTID(replication.Mysql56GTID{Server: sid, Sequence: 2}) + want := replication.Position{GTIDSet: set} - got, err := ParsePosition(Mysql56FlavorID, input) + got, err := replication.ParsePosition(replication.Mysql56FlavorID, input) assert.NoError(t, err, "unexpected error: %v", err) assert.True(t, got.Equal(want), "(&mysql56{}).ParsePosition(%#v) = %#v, want %#v", input, got, want) diff --git a/go/mysql/client.go b/go/mysql/client.go index 2780ad0dfd9..c4dd87d95cc 100644 --- a/go/mysql/client.go +++ b/go/mysql/client.go @@ -27,6 +27,7 @@ import ( "time" "vitess.io/vitess/go/mysql/collations" + "vitess.io/vitess/go/mysql/sqlerror" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttls" @@ -94,11 +95,11 @@ func Connect(ctx context.Context, params *ConnParams) (*Conn, error) { // should return a 2003. if netProto == "tcp" { status <- connectResult{ - err: NewSQLError(CRConnHostError, SSUnknownSQLState, "net.Dial(%v) failed: %v", addr, err), + err: sqlerror.NewSQLError(sqlerror.CRConnHostError, sqlerror.SSUnknownSQLState, "net.Dial(%v) failed: %v", addr, err), } } else { status <- connectResult{ - err: NewSQLError(CRConnectionError, SSUnknownSQLState, "net.Dial(%v) to local server failed: %v", addr, err), + err: sqlerror.NewSQLError(sqlerror.CRConnectionError, sqlerror.SSUnknownSQLState, "net.Dial(%v) to local server failed: %v", addr, err), } } return @@ -178,11 +179,11 @@ func (c *Conn) Ping() error { data[pos] = ComPing if err := c.writeEphemeralPacket(); err != nil { - return NewSQLError(CRServerGone, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSUnknownSQLState, "%v", err) } data, err := c.readEphemeralPacket() if err != nil { - return NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } defer c.recycleReadPacket() switch data[0] { @@ -207,7 +208,7 @@ func (c *Conn) clientHandshake(params *ConnParams) error { // Wait for the server initial handshake packet, and parse it. data, err := c.readPacket() if err != nil { - return NewSQLError(CRServerLost, "", "initial packet read failed: %v", err) + return sqlerror.NewSQLError(sqlerror.CRServerLost, "", "initial packet read failed: %v", err) } capabilities, salt, err := c.parseInitialHandshakePacket(data) if err != nil { @@ -218,7 +219,7 @@ func (c *Conn) clientHandshake(params *ConnParams) error { // Sanity check. if capabilities&CapabilityClientProtocol41 == 0 { - return NewSQLError(CRVersionError, SSUnknownSQLState, "cannot connect to servers earlier than 4.1") + return sqlerror.NewSQLError(sqlerror.CRVersionError, sqlerror.SSUnknownSQLState, "cannot connect to servers earlier than 4.1") } // Remember a subset of the capabilities, so we can use them @@ -238,7 +239,7 @@ func (c *Conn) clientHandshake(params *ConnParams) error { // If client asked for SSL, but server doesn't support it, // stop right here. if params.SslRequired() && capabilities&CapabilityClientSSL == 0 { - return NewSQLError(CRSSLConnectionError, SSUnknownSQLState, "server doesn't support SSL but client asked for it") + return sqlerror.NewSQLError(sqlerror.CRSSLConnectionError, sqlerror.SSUnknownSQLState, "server doesn't support SSL but client asked for it") } // The ServerName to verify depends on what the hostname is. @@ -259,13 +260,13 @@ func (c *Conn) clientHandshake(params *ConnParams) error { tlsVersion, err := vttls.TLSVersionToNumber(params.TLSMinVersion) if err != nil { - return NewSQLError(CRSSLConnectionError, SSUnknownSQLState, "error parsing minimal TLS version: %v", err) + return sqlerror.NewSQLError(sqlerror.CRSSLConnectionError, sqlerror.SSUnknownSQLState, "error parsing minimal TLS version: %v", err) } // Build the TLS config. clientConfig, err := vttls.ClientConfig(params.EffectiveSslMode(), params.SslCert, params.SslKey, params.SslCa, params.SslCrl, serverName, tlsVersion) if err != nil { - return NewSQLError(CRSSLConnectionError, SSUnknownSQLState, "error loading client cert and ca: %v", err) + return sqlerror.NewSQLError(sqlerror.CRSSLConnectionError, sqlerror.SSUnknownSQLState, "error loading client cert and ca: %v", err) } // Send the SSLRequest packet. @@ -296,7 +297,7 @@ func (c *Conn) clientHandshake(params *ConnParams) error { } else if params.Flags&CapabilityClientSessionTrack == CapabilityClientSessionTrack { // If client asked for ClientSessionTrack, but server doesn't support it, // stop right here. - return NewSQLError(CRSSLConnectionError, SSUnknownSQLState, "server doesn't support ClientSessionTrack but client asked for it") + return sqlerror.NewSQLError(sqlerror.CRSSLConnectionError, sqlerror.SSUnknownSQLState, "server doesn't support ClientSessionTrack but client asked for it") } // Build and send our handshake response 41. @@ -321,7 +322,7 @@ func (c *Conn) clientHandshake(params *ConnParams) error { // Wait for response, should be OK. response, err := c.readPacket() if err != nil { - return NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } switch response[0] { case OKPacket: @@ -331,7 +332,7 @@ func (c *Conn) clientHandshake(params *ConnParams) error { return ParseErrorPacket(response) default: // FIXME(alainjobart) handle extra auth cases and so on. - return NewSQLError(CRServerHandshakeErr, SSUnknownSQLState, "initial server response is asking for more information, not implemented yet: %v", response) + return sqlerror.NewSQLError(sqlerror.CRServerHandshakeErr, sqlerror.SSUnknownSQLState, "initial server response is asking for more information, not implemented yet: %v", response) } } @@ -346,7 +347,7 @@ func (c *Conn) parseInitialHandshakePacket(data []byte) (uint32, []byte, error) // Protocol version. pver, pos, ok := readByte(data, pos) if !ok { - return 0, nil, NewSQLError(CRVersionError, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no protocol version") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRVersionError, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no protocol version") } // Server is allowed to immediately send ERR packet @@ -355,41 +356,41 @@ func (c *Conn) parseInitialHandshakePacket(data []byte) (uint32, []byte, error) // Normally there would be a 1-byte sql_state_marker field and a 5-byte // sql_state field here, but docs say these will not be present in this case. errorMsg, _, _ := readEOFString(data, pos) - return 0, nil, NewSQLError(CRServerHandshakeErr, SSUnknownSQLState, "immediate error from server errorCode=%v errorMsg=%v", errorCode, errorMsg) + return 0, nil, sqlerror.NewSQLError(sqlerror.CRServerHandshakeErr, sqlerror.SSUnknownSQLState, "immediate error from server errorCode=%v errorMsg=%v", errorCode, errorMsg) } if pver != protocolVersion { - return 0, nil, NewSQLError(CRVersionError, SSUnknownSQLState, "bad protocol version: %v", pver) + return 0, nil, sqlerror.NewSQLError(sqlerror.CRVersionError, sqlerror.SSUnknownSQLState, "bad protocol version: %v", pver) } // Read the server version. c.ServerVersion, pos, ok = readNullString(data, pos) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no server version") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no server version") } // Read the connection id. c.ConnectionID, pos, ok = readUint32(data, pos) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no connection id") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no connection id") } // Read the first part of the auth-plugin-data authPluginData, pos, ok := readBytes(data, pos, 8) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no auth-plugin-data-part-1") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no auth-plugin-data-part-1") } // One byte filler, 0. We don't really care about the value. _, pos, ok = readByte(data, pos) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no filler") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no filler") } // Lower 2 bytes of the capability flags. capLower, pos, ok := readUint16(data, pos) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no capability flags (lower 2 bytes)") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no capability flags (lower 2 bytes)") } var capabilities = uint32(capLower) @@ -401,20 +402,20 @@ func (c *Conn) parseInitialHandshakePacket(data []byte) (uint32, []byte, error) // Character set. characterSet, pos, ok := readByte(data, pos) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no character set") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no character set") } c.CharacterSet = collations.ID(characterSet) // Status flags. Ignored. _, pos, ok = readUint16(data, pos) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no status flags") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no status flags") } // Upper 2 bytes of the capability flags. capUpper, pos, ok := readUint16(data, pos) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no capability flags (upper 2 bytes)") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no capability flags (upper 2 bytes)") } capabilities += uint32(capUpper) << 16 @@ -424,13 +425,13 @@ func (c *Conn) parseInitialHandshakePacket(data []byte) (uint32, []byte, error) if capabilities&CapabilityClientPluginAuth != 0 { authPluginDataLength, pos, ok = readByte(data, pos) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no length of auth-plugin-data") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no length of auth-plugin-data") } } else { // One byte filler, 0. We don't really care about the value. _, pos, ok = readByte(data, pos) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no length of auth-plugin-data filler") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no length of auth-plugin-data filler") } } @@ -447,12 +448,12 @@ func (c *Conn) parseInitialHandshakePacket(data []byte) (uint32, []byte, error) var authPluginDataPart2 []byte authPluginDataPart2, pos, ok = readBytes(data, pos, l) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: packet has no auth-plugin-data-part-2") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: packet has no auth-plugin-data-part-2") } // The last byte has to be 0, and is not part of the data. if authPluginDataPart2[l-1] != 0 { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "parseInitialHandshakePacket: auth-plugin-data-part-2 is not 0 terminated") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "parseInitialHandshakePacket: auth-plugin-data-part-2 is not 0 terminated") } authPluginData = append(authPluginData, authPluginDataPart2[0:l-1]...) } @@ -509,7 +510,7 @@ func (c *Conn) writeSSLRequest(capabilities uint32, characterSet uint8, params * // And send it as is. if err := c.writeEphemeralPacket(); err != nil { - return NewSQLError(CRServerLost, SSUnknownSQLState, "cannot send SSLRequest: %v", err) + return sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "cannot send SSLRequest: %v", err) } return nil } @@ -606,11 +607,11 @@ func (c *Conn) writeHandshakeResponse41(capabilities uint32, scrambledPassword [ // Sanity-check the length. if pos != len(data) { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "writeHandshakeResponse41: only packed %v bytes, out of %v allocated", pos, len(data)) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "writeHandshakeResponse41: only packed %v bytes, out of %v allocated", pos, len(data)) } if err := c.writeEphemeralPacket(); err != nil { - return NewSQLError(CRServerLost, SSUnknownSQLState, "cannot send HandshakeResponse41: %v", err) + return sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "cannot send HandshakeResponse41: %v", err) } return nil } @@ -620,7 +621,7 @@ func (c *Conn) writeHandshakeResponse41(capabilities uint32, scrambledPassword [ func (c *Conn) handleAuthResponse(params *ConnParams) error { response, err := c.readPacket() if err != nil { - return NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } switch response[0] { @@ -640,7 +641,7 @@ func (c *Conn) handleAuthResponse(params *ConnParams) error { case ErrPacket: return ParseErrorPacket(response) default: - return NewSQLError(CRServerHandshakeErr, SSUnknownSQLState, "initial server response cannot be parsed: %v", response) + return sqlerror.NewSQLError(sqlerror.CRServerHandshakeErr, sqlerror.SSUnknownSQLState, "initial server response cannot be parsed: %v", response) } return nil @@ -652,7 +653,7 @@ func (c *Conn) handleAuthSwitchPacket(params *ConnParams, response []byte) error var salt []byte c.authPluginName, salt, err = parseAuthSwitchRequest(response) if err != nil { - return NewSQLError(CRServerHandshakeErr, SSUnknownSQLState, "cannot parse auth switch request: %v", err) + return sqlerror.NewSQLError(sqlerror.CRServerHandshakeErr, sqlerror.SSUnknownSQLState, "cannot parse auth switch request: %v", err) } if salt != nil { c.salt = salt @@ -673,7 +674,7 @@ func (c *Conn) handleAuthSwitchPacket(params *ConnParams, response []byte) error return err } default: - return NewSQLError(CRServerHandshakeErr, SSUnknownSQLState, "server asked for unsupported auth method: %v", c.authPluginName) + return sqlerror.NewSQLError(sqlerror.CRServerHandshakeErr, sqlerror.SSUnknownSQLState, "server asked for unsupported auth method: %v", c.authPluginName) } // The response could be an OKPacket, AuthMoreDataPacket or ErrPacket @@ -715,7 +716,7 @@ func (c *Conn) handleAuthMoreDataPacket(data byte, params *ConnParams) error { // Next packet should either be an OKPacket or ErrPacket return c.handleAuthResponse(params) default: - return NewSQLError(CRServerHandshakeErr, SSUnknownSQLState, "cannot parse AuthMoreDataPacket: %v", data) + return sqlerror.NewSQLError(sqlerror.CRServerHandshakeErr, sqlerror.SSUnknownSQLState, "cannot parse AuthMoreDataPacket: %v", data) } } @@ -745,7 +746,7 @@ func (c *Conn) requestPublicKey() (rsaKey *rsa.PublicKey, err error) { response, err := c.readPacket() if err != nil { - return nil, NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return nil, sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } // Server should respond with a AuthMoreDataPacket containing the public key diff --git a/go/mysql/client_test.go b/go/mysql/client_test.go index ddbb7f19f06..c349cdcd531 100644 --- a/go/mysql/client_test.go +++ b/go/mysql/client_test.go @@ -32,16 +32,18 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/vt/tlstest" "vitess.io/vitess/go/vt/vttls" ) // assertSQLError makes sure we get the right error. -func assertSQLError(t *testing.T, err error, code ErrorCode, sqlState, subtext, query, pattern string) { +func assertSQLError(t *testing.T, err error, code sqlerror.ErrorCode, sqlState, subtext, query, pattern string) { t.Helper() require.Error(t, err, "was expecting SQLError %v / %v / %v but got no error.", code, sqlState, subtext) - serr, ok := err.(*SQLError) + serr, ok := err.(*sqlerror.SQLError) require.True(t, ok, "was expecting SQLError %v / %v / %v but got: %v", code, sqlState, subtext, err) require.Equal(t, code, serr.Num, "was expecting SQLError %v / %v / %v but got code %v", code, sqlState, subtext, serr.Num) require.Equal(t, sqlState, serr.State, "was expecting SQLError %v / %v / %v but got state %v", code, sqlState, subtext, serr.State) @@ -110,14 +112,14 @@ func TestConnectTimeout(t *testing.T) { }() ctx = context.Background() _, err = Connect(ctx, params) - assertSQLError(t, err, CRServerLost, SSUnknownSQLState, "initial packet read failed", "", "") + assertSQLError(t, err, sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "initial packet read failed", "", "") // Now close the listener. Connect should fail right away, // check the error. listener.Close() wg.Wait() _, err = Connect(ctx, params) - assertSQLError(t, err, CRConnHostError, SSUnknownSQLState, "connection refused", "", "") + assertSQLError(t, err, sqlerror.CRConnHostError, sqlerror.SSUnknownSQLState, "connection refused", "", "") // Tests a connection where Dial to a unix socket fails // properly returns the right error. To simulate exactly the @@ -131,7 +133,7 @@ func TestConnectTimeout(t *testing.T) { _, err = Connect(ctx, params) os.Remove(name) t.Log(err) - assertSQLError(t, err, CRConnectionError, SSUnknownSQLState, "connection refused", "", "net\\.Dial\\(([a-z0-9A-Z_\\/]*)\\) to local server failed:") + assertSQLError(t, err, sqlerror.CRConnectionError, sqlerror.SSUnknownSQLState, "connection refused", "", "net\\.Dial\\(([a-z0-9A-Z_\\/]*)\\) to local server failed:") } // TestTLSClientDisabled creates a Server with TLS support, then connects diff --git a/go/mysql/conn.go b/go/mysql/conn.go index 4b22e99e480..6f3643ebc7f 100644 --- a/go/mysql/conn.go +++ b/go/mysql/conn.go @@ -32,6 +32,7 @@ import ( "vitess.io/vitess/go/bucketpool" "vitess.io/vitess/go/mysql/collations" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqlescape" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/log" @@ -598,7 +599,7 @@ func (c *Conn) readPacket() ([]byte, error) { func (c *Conn) ReadPacket() ([]byte, error) { result, err := c.readPacket() if err != nil { - return nil, NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return nil, sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } return result, err } @@ -722,7 +723,7 @@ func (c *Conn) writeComQuit() error { data, pos := c.startEphemeralPacketWithHeader(1) data[pos] = ComQuit if err := c.writeEphemeralPacket(); err != nil { - return NewSQLError(CRServerGone, SSUnknownSQLState, err.Error()) + return sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSUnknownSQLState, err.Error()) } return nil } @@ -856,10 +857,10 @@ func getLenEncInt(i uint64) []byte { } func (c *Conn) WriteErrorAndLog(format string, args ...interface{}) bool { - return c.writeErrorAndLog(ERUnknownComError, SSNetError, format, args...) + return c.writeErrorAndLog(sqlerror.ERUnknownComError, sqlerror.SSNetError, format, args...) } -func (c *Conn) writeErrorAndLog(errorCode ErrorCode, sqlState string, format string, args ...any) bool { +func (c *Conn) writeErrorAndLog(errorCode sqlerror.ErrorCode, sqlState string, format string, args ...any) bool { if err := c.writeErrorPacket(errorCode, sqlState, format, args...); err != nil { log.Errorf("Error writing error to %s: %v", c, err) return false @@ -879,7 +880,7 @@ func (c *Conn) writeErrorPacketFromErrorAndLog(err error) bool { // writeErrorPacket writes an error packet. // Server -> Client. // This method returns a generic error, not a SQLError. -func (c *Conn) writeErrorPacket(errorCode ErrorCode, sqlState string, format string, args ...any) error { +func (c *Conn) writeErrorPacket(errorCode sqlerror.ErrorCode, sqlState string, format string, args ...any) error { errorMessage := fmt.Sprintf(format, args...) length := 1 + 2 + 1 + 5 + len(errorMessage) data, pos := c.startEphemeralPacketWithHeader(length) @@ -887,7 +888,7 @@ func (c *Conn) writeErrorPacket(errorCode ErrorCode, sqlState string, format str pos = writeUint16(data, pos, uint16(errorCode)) pos = writeByte(data, pos, '#') if sqlState == "" { - sqlState = SSUnknownSQLState + sqlState = sqlerror.SSUnknownSQLState } if len(sqlState) != 5 { panic("sqlState has to be 5 characters long") @@ -901,11 +902,11 @@ func (c *Conn) writeErrorPacket(errorCode ErrorCode, sqlState string, format str // writeErrorPacketFromError writes an error packet, from a regular error. // See writeErrorPacket for other info. func (c *Conn) writeErrorPacketFromError(err error) error { - if se, ok := err.(*SQLError); ok { + if se, ok := err.(*sqlerror.SQLError); ok { return c.writeErrorPacket(se.Num, se.State, "%v", se.Message) } - return c.writeErrorPacket(ERUnknownError, SSUnknownSQLState, "unknown error: %v", err) + return c.writeErrorPacket(sqlerror.ERUnknownError, sqlerror.SSUnknownSQLState, "unknown error: %v", err) } // writeEOFPacket writes an EOF packet, through the buffer, and @@ -974,7 +975,7 @@ func (c *Conn) handleNextCommand(handler Handler) bool { return true case ComFieldList: c.recycleReadPacket() - if !c.writeErrorAndLog(ERUnknownComError, SSNetError, "command handling not implemented yet: %v", data[0]) { + if !c.writeErrorAndLog(sqlerror.ERUnknownComError, sqlerror.SSNetError, "command handling not implemented yet: %v", data[0]) { return false } case ComBinlogDump: @@ -986,7 +987,7 @@ func (c *Conn) handleNextCommand(handler Handler) bool { default: log.Errorf("Got unhandled packet (default) from %s, returning error: %v", c, data) c.recycleReadPacket() - if !c.writeErrorAndLog(ERUnknownComError, SSNetError, "command handling not implemented yet: %v", data[0]) { + if !c.writeErrorAndLog(sqlerror.ERUnknownComError, sqlerror.SSNetError, "command handling not implemented yet: %v", data[0]) { return false } } @@ -1077,7 +1078,7 @@ func (c *Conn) handleComStmtReset(data []byte) bool { c.recycleReadPacket() if !ok { log.Error("Got unhandled packet from client %v, returning error: %v", c.ConnectionID, data) - if !c.writeErrorAndLog(ERUnknownComError, SSNetError, "error handling packet: %v", data) { + if !c.writeErrorAndLog(sqlerror.ERUnknownComError, sqlerror.SSNetError, "error handling packet: %v", data) { return false } } @@ -1085,7 +1086,7 @@ func (c *Conn) handleComStmtReset(data []byte) bool { prepare, ok := c.PrepareData[stmtID] if !ok { log.Error("Commands were executed in an improper order from client %v, packet: %v", c.ConnectionID, data) - if !c.writeErrorAndLog(CRCommandsOutOfSync, SSNetError, "commands were executed in an improper order: %v", data) { + if !c.writeErrorAndLog(sqlerror.CRCommandsOutOfSync, sqlerror.SSNetError, "commands were executed in an improper order: %v", data) { return false } } @@ -1195,7 +1196,7 @@ func (c *Conn) handleComStmtExecute(handler Handler, data []byte) (kontinue bool if !fieldSent { // This is just a failsafe. Should never happen. if err == nil || err == io.EOF { - err = NewSQLErrorFromError(errors.New("unexpected: query ended without no results and no error")) + err = sqlerror.NewSQLErrorFromError(errors.New("unexpected: query ended without no results and no error")) } if !c.writeErrorPacketFromErrorAndLog(err) { return false @@ -1315,7 +1316,7 @@ func (c *Conn) handleComSetOption(data []byte) bool { c.Capabilities &^= CapabilityClientMultiStatements default: log.Errorf("Got unhandled packet (ComSetOption default) from client %v, returning error: %v", c.ConnectionID, data) - if !c.writeErrorAndLog(ERUnknownComError, SSNetError, "error handling packet: %v", data) { + if !c.writeErrorAndLog(sqlerror.ERUnknownComError, sqlerror.SSNetError, "error handling packet: %v", data) { return false } } @@ -1325,7 +1326,7 @@ func (c *Conn) handleComSetOption(data []byte) bool { } } else { log.Errorf("Got unhandled packet (ComSetOption else) from client %v, returning error: %v", c.ConnectionID, data) - if !c.writeErrorAndLog(ERUnknownComError, SSNetError, "error handling packet: %v", data) { + if !c.writeErrorAndLog(sqlerror.ERUnknownComError, sqlerror.SSNetError, "error handling packet: %v", data) { return false } } @@ -1336,7 +1337,7 @@ func (c *Conn) handleComPing() bool { c.recycleReadPacket() // Return error if listener was shut down and OK otherwise if c.listener.shutdown.Load() { - if !c.writeErrorAndLog(ERServerShutdown, SSNetError, "Server shutdown in progress") { + if !c.writeErrorAndLog(sqlerror.ERServerShutdown, sqlerror.SSNetError, "Server shutdown in progress") { return false } } else { @@ -1348,7 +1349,7 @@ func (c *Conn) handleComPing() bool { return true } -var errEmptyStatement = NewSQLError(EREmptyQuery, SSClientError, "Query was empty") +var errEmptyStatement = sqlerror.NewSQLError(sqlerror.EREmptyQuery, sqlerror.SSClientError, "Query was empty") func (c *Conn) handleComQuery(handler Handler, data []byte) (kontinue bool) { c.startWriterBuffering() @@ -1443,7 +1444,7 @@ func (c *Conn) execQuery(query string, handler Handler, more bool) execResult { if !callbackCalled { // This is just a failsafe. Should never happen. if err == nil || err == io.EOF { - err = NewSQLErrorFromError(errors.New("unexpected: query ended without no results and no error")) + err = sqlerror.NewSQLErrorFromError(errors.New("unexpected: query ended without no results and no error")) } if !c.writeErrorPacketFromErrorAndLog(err) { return connErr @@ -1634,7 +1635,7 @@ func ParseErrorPacket(data []byte) error { // Error code is 2 bytes. code, pos, ok := readUint16(data, pos) if !ok { - return NewSQLError(CRUnknownError, SSUnknownSQLState, "invalid error packet code: %v", data) + return sqlerror.NewSQLError(sqlerror.CRUnknownError, sqlerror.SSUnknownSQLState, "invalid error packet code: %v", data) } // '#' marker of the SQL state is 1 byte. Ignored. @@ -1643,13 +1644,13 @@ func ParseErrorPacket(data []byte) error { // SQL state is 5 bytes sqlState, pos, ok := readBytes(data, pos, 5) if !ok { - return NewSQLError(CRUnknownError, SSUnknownSQLState, "invalid error packet sqlState: %v", data) + return sqlerror.NewSQLError(sqlerror.CRUnknownError, sqlerror.SSUnknownSQLState, "invalid error packet sqlState: %v", data) } // Human readable error message is the rest. msg := string(data[pos:]) - return NewSQLError(ErrorCode(code), string(sqlState), "%v", msg) + return sqlerror.NewSQLError(sqlerror.ErrorCode(code), string(sqlState), "%v", msg) } // GetTLSClientCerts gets TLS certificates. diff --git a/go/mysql/conn_flaky_test.go b/go/mysql/conn_flaky_test.go index a22cdfd8700..9df52a47589 100644 --- a/go/mysql/conn_flaky_test.go +++ b/go/mysql/conn_flaky_test.go @@ -31,6 +31,8 @@ import ( "testing" "time" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/sqlparser" "github.com/stretchr/testify/assert" @@ -304,7 +306,7 @@ func TestBasicPackets(t *testing.T) { assert.EqualValues(78, packetOk.warnings) // Write error packet, read it, compare. - err = sConn.writeErrorPacket(ERAccessDeniedError, SSAccessDeniedError, "access denied: %v", "reason") + err = sConn.writeErrorPacket(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "access denied: %v", "reason") require.NoError(err) data, err = cConn.ReadPacket() require.NoError(err) @@ -312,10 +314,10 @@ func TestBasicPackets(t *testing.T) { assert.EqualValues(data[0], ErrPacket, "ErrPacket") err = ParseErrorPacket(data) - utils.MustMatch(t, err, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "access denied: reason"), "") + utils.MustMatch(t, err, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "access denied: reason"), "") // Write error packet from error, read it, compare. - err = sConn.writeErrorPacketFromError(NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "access denied")) + err = sConn.writeErrorPacketFromError(sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "access denied")) require.NoError(err) data, err = cConn.ReadPacket() @@ -324,7 +326,7 @@ func TestBasicPackets(t *testing.T) { assert.EqualValues(data[0], ErrPacket, "ErrPacket") err = ParseErrorPacket(data) - utils.MustMatch(t, err, NewSQLError(ERAccessDeniedError, SSAccessDeniedError, "access denied"), "") + utils.MustMatch(t, err, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "access denied"), "") // Write EOF packet, read it, compare first byte. Payload is always ignored. err = sConn.writeEOFPacket(0x8912, 0xabba) @@ -840,7 +842,7 @@ func TestMultiStatement(t *testing.T) { // this handler will return results according to the query. In case the query contains "error" it will return an error // panic if the query contains "panic" and it will return selectRowsResult in case of any other query - handler := &testRun{t: t, err: NewSQLError(CRMalformedPacket, SSUnknownSQLState, "cannot get column number")} + handler := &testRun{t: t, err: sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "cannot get column number")} res := sConn.handleNextCommand(handler) // The queries run will be select 1; and select 2; These queries do not return any errors, so the connection should still be open require.True(t, res, "we should not break the connection in case of no errors") @@ -1108,7 +1110,7 @@ func (t testRun) ComBinlogDump(c *Conn, logFile string, binlogPos uint32) error panic("implement me") } -func (t testRun) ComBinlogDumpGTID(c *Conn, logFile string, logPos uint64, gtidSet GTIDSet) error { +func (t testRun) ComBinlogDumpGTID(c *Conn, logFile string, logPos uint64, gtidSet replication.GTIDSet) error { panic("implement me") } diff --git a/go/mysql/constants.go b/go/mysql/constants.go index 50806147af4..194ed568b39 100644 --- a/go/mysql/constants.go +++ b/go/mysql/constants.go @@ -17,9 +17,6 @@ limitations under the License. package mysql import ( - "strconv" - "strings" - "vitess.io/vitess/go/mysql/binlog" ) @@ -277,385 +274,6 @@ const ( AuthSwitchRequestPacket = 0xfe ) -// Error codes for client-side errors. -// Originally found in include/mysql/errmsg.h and -// https://dev.mysql.com/doc/mysql-errors/en/client-error-reference.html -const ( - // CRUnknownError is CR_UNKNOWN_ERROR - CRUnknownError = ErrorCode(2000) - - // CRConnectionError is CR_CONNECTION_ERROR - // This is returned if a connection via a Unix socket fails. - CRConnectionError = ErrorCode(2002) - - // CRConnHostError is CR_CONN_HOST_ERROR - // This is returned if a connection via a TCP socket fails. - CRConnHostError = ErrorCode(2003) - - // CRUnknownHost is CR_UNKNOWN_HOST - // This is returned if the host name cannot be resolved. - CRUnknownHost = ErrorCode(2005) - - // CRServerGone is CR_SERVER_GONE_ERROR. - // This is returned if the client tries to send a command but it fails. - CRServerGone = ErrorCode(2006) - - // CRVersionError is CR_VERSION_ERROR - // This is returned if the server versions don't match what we support. - CRVersionError = ErrorCode(2007) - - // CRServerHandshakeErr is CR_SERVER_HANDSHAKE_ERR - CRServerHandshakeErr = ErrorCode(2012) - - // CRServerLost is CR_SERVER_LOST. - // Used when: - // - the client cannot write an initial auth packet. - // - the client cannot read an initial auth packet. - // - the client cannot read a response from the server. - // This happens when a running query is killed. - CRServerLost = ErrorCode(2013) - - // CRCommandsOutOfSync is CR_COMMANDS_OUT_OF_SYNC - // Sent when the streaming calls are not done in the right order. - CRCommandsOutOfSync = ErrorCode(2014) - - // CRNamedPipeStateError is CR_NAMEDPIPESETSTATE_ERROR. - // This is the highest possible number for a connection error. - CRNamedPipeStateError = ErrorCode(2018) - - // CRCantReadCharset is CR_CANT_READ_CHARSET - CRCantReadCharset = ErrorCode(2019) - - // CRSSLConnectionError is CR_SSL_CONNECTION_ERROR - CRSSLConnectionError = ErrorCode(2026) - - // CRMalformedPacket is CR_MALFORMED_PACKET - CRMalformedPacket = ErrorCode(2027) -) - -type ErrorCode uint16 - -func (e ErrorCode) ToString() string { - return strconv.FormatUint(uint64(e), 10) -} - -// Error codes for server-side errors. -// Originally found in include/mysql/mysqld_error.h and -// https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html -// The below are in sorted order by value, grouped by vterror code they should be bucketed into. -// See above reference for more information on each code. -const ( - // Vitess specific errors, (100-999) - ERNotReplica = ErrorCode(100) - - // unknown - ERUnknownError = ErrorCode(1105) - - // internal - ERInternalError = ErrorCode(1815) - - // unimplemented - ERNotSupportedYet = ErrorCode(1235) - ERUnsupportedPS = ErrorCode(1295) - - // resource exhausted - ERDiskFull = ErrorCode(1021) - EROutOfMemory = ErrorCode(1037) - EROutOfSortMemory = ErrorCode(1038) - ERConCount = ErrorCode(1040) - EROutOfResources = ErrorCode(1041) - ERRecordFileFull = ErrorCode(1114) - ERHostIsBlocked = ErrorCode(1129) - ERCantCreateThread = ErrorCode(1135) - ERTooManyDelayedThreads = ErrorCode(1151) - ERNetPacketTooLarge = ErrorCode(1153) - ERTooManyUserConnections = ErrorCode(1203) - ERLockTableFull = ErrorCode(1206) - ERUserLimitReached = ErrorCode(1226) - - // deadline exceeded - ERLockWaitTimeout = ErrorCode(1205) - - // unavailable - ERServerShutdown = ErrorCode(1053) - - // not found - ERDbDropExists = ErrorCode(1008) - ERCantFindFile = ErrorCode(1017) - ERFormNotFound = ErrorCode(1029) - ERKeyNotFound = ErrorCode(1032) - ERBadFieldError = ErrorCode(1054) - ERNoSuchThread = ErrorCode(1094) - ERUnknownTable = ErrorCode(1109) - ERCantFindUDF = ErrorCode(1122) - ERNonExistingGrant = ErrorCode(1141) - ERNoSuchTable = ErrorCode(1146) - ERNonExistingTableGrant = ErrorCode(1147) - ERKeyDoesNotExist = ErrorCode(1176) - - // permissions - ERDBAccessDenied = ErrorCode(1044) - ERAccessDeniedError = ErrorCode(1045) - ERKillDenied = ErrorCode(1095) - ERNoPermissionToCreateUsers = ErrorCode(1211) - ERSpecifiedAccessDenied = ErrorCode(1227) - - // failed precondition - ERNoDb = ErrorCode(1046) - ERNoSuchIndex = ErrorCode(1082) - ERCantDropFieldOrKey = ErrorCode(1091) - ERTableNotLockedForWrite = ErrorCode(1099) - ERTableNotLocked = ErrorCode(1100) - ERTooBigSelect = ErrorCode(1104) - ERNotAllowedCommand = ErrorCode(1148) - ERTooLongString = ErrorCode(1162) - ERDelayedInsertTableLocked = ErrorCode(1165) - ERDupUnique = ErrorCode(1169) - ERRequiresPrimaryKey = ErrorCode(1173) - ERCantDoThisDuringAnTransaction = ErrorCode(1179) - ERReadOnlyTransaction = ErrorCode(1207) - ERCannotAddForeign = ErrorCode(1215) - ERNoReferencedRow = ErrorCode(1216) - ERRowIsReferenced = ErrorCode(1217) - ERCantUpdateWithReadLock = ErrorCode(1223) - ERNoDefault = ErrorCode(1230) - ERMasterFatalReadingBinlog = ErrorCode(1236) - EROperandColumns = ErrorCode(1241) - ERSubqueryNo1Row = ErrorCode(1242) - ERUnknownStmtHandler = ErrorCode(1243) - ERWarnDataOutOfRange = ErrorCode(1264) - ERNonUpdateableTable = ErrorCode(1288) - ERFeatureDisabled = ErrorCode(1289) - EROptionPreventsStatement = ErrorCode(1290) - ERDuplicatedValueInType = ErrorCode(1291) - ERSPDoesNotExist = ErrorCode(1305) - ERNoDefaultForField = ErrorCode(1364) - ErSPNotVarArg = ErrorCode(1414) - ERRowIsReferenced2 = ErrorCode(1451) - ErNoReferencedRow2 = ErrorCode(1452) - ERDupIndex = ErrorCode(1831) - ERInnodbReadOnly = ErrorCode(1874) - - // already exists - ERDbCreateExists = ErrorCode(1007) - ERTableExists = ErrorCode(1050) - ERDupEntry = ErrorCode(1062) - ERFileExists = ErrorCode(1086) - ERUDFExists = ErrorCode(1125) - - // aborted - ERGotSignal = ErrorCode(1078) - ERForcingClose = ErrorCode(1080) - ERAbortingConnection = ErrorCode(1152) - ERLockDeadlock = ErrorCode(1213) - - // invalid arg - ERUnknownComError = ErrorCode(1047) - ERBadNullError = ErrorCode(1048) - ERBadDb = ErrorCode(1049) - ERBadTable = ErrorCode(1051) - ERNonUniq = ErrorCode(1052) - ERWrongFieldWithGroup = ErrorCode(1055) - ERWrongGroupField = ErrorCode(1056) - ERWrongSumSelect = ErrorCode(1057) - ERWrongValueCount = ErrorCode(1058) - ERTooLongIdent = ErrorCode(1059) - ERDupFieldName = ErrorCode(1060) - ERDupKeyName = ErrorCode(1061) - ERWrongFieldSpec = ErrorCode(1063) - ERParseError = ErrorCode(1064) - EREmptyQuery = ErrorCode(1065) - ERNonUniqTable = ErrorCode(1066) - ERInvalidDefault = ErrorCode(1067) - ERMultiplePriKey = ErrorCode(1068) - ERTooManyKeys = ErrorCode(1069) - ERTooManyKeyParts = ErrorCode(1070) - ERTooLongKey = ErrorCode(1071) - ERKeyColumnDoesNotExist = ErrorCode(1072) - ERBlobUsedAsKey = ErrorCode(1073) - ERTooBigFieldLength = ErrorCode(1074) - ERWrongAutoKey = ErrorCode(1075) - ERWrongFieldTerminators = ErrorCode(1083) - ERBlobsAndNoTerminated = ErrorCode(1084) - ERTextFileNotReadable = ErrorCode(1085) - ERWrongSubKey = ErrorCode(1089) - ERCantRemoveAllFields = ErrorCode(1090) - ERUpdateTableUsed = ErrorCode(1093) - ERNoTablesUsed = ErrorCode(1096) - ERTooBigSet = ErrorCode(1097) - ERBlobCantHaveDefault = ErrorCode(1101) - ERWrongDbName = ErrorCode(1102) - ERWrongTableName = ErrorCode(1103) - ERUnknownProcedure = ErrorCode(1106) - ERWrongParamCountToProcedure = ErrorCode(1107) - ERWrongParametersToProcedure = ErrorCode(1108) - ERFieldSpecifiedTwice = ErrorCode(1110) - ERInvalidGroupFuncUse = ErrorCode(1111) - ERTableMustHaveColumns = ErrorCode(1113) - ERUnknownCharacterSet = ErrorCode(1115) - ERTooManyTables = ErrorCode(1116) - ERTooManyFields = ErrorCode(1117) - ERTooBigRowSize = ErrorCode(1118) - ERWrongOuterJoin = ErrorCode(1120) - ERNullColumnInIndex = ErrorCode(1121) - ERFunctionNotDefined = ErrorCode(1128) - ERWrongValueCountOnRow = ErrorCode(1136) - ERInvalidUseOfNull = ErrorCode(1138) - ERRegexpError = ErrorCode(1139) - ERMixOfGroupFuncAndFields = ErrorCode(1140) - ERIllegalGrantForTable = ErrorCode(1144) - ERSyntaxError = ErrorCode(1149) - ERWrongColumnName = ErrorCode(1166) - ERWrongKeyColumn = ErrorCode(1167) - ERBlobKeyWithoutLength = ErrorCode(1170) - ERPrimaryCantHaveNull = ErrorCode(1171) - ERTooManyRows = ErrorCode(1172) - ERLockOrActiveTransaction = ErrorCode(1192) - ERUnknownSystemVariable = ErrorCode(1193) - ERSetConstantsOnly = ErrorCode(1204) - ERWrongArguments = ErrorCode(1210) - ERWrongUsage = ErrorCode(1221) - ERWrongNumberOfColumnsInSelect = ErrorCode(1222) - ERDupArgument = ErrorCode(1225) - ERLocalVariable = ErrorCode(1228) - ERGlobalVariable = ErrorCode(1229) - ERWrongValueForVar = ErrorCode(1231) - ERWrongTypeForVar = ErrorCode(1232) - ERVarCantBeRead = ErrorCode(1233) - ERCantUseOptionHere = ErrorCode(1234) - ERIncorrectGlobalLocalVar = ErrorCode(1238) - ERWrongFKDef = ErrorCode(1239) - ERKeyRefDoNotMatchTableRef = ErrorCode(1240) - ERCyclicReference = ErrorCode(1245) - ERIllegalReference = ErrorCode(1247) - ERDerivedMustHaveAlias = ErrorCode(1248) - ERTableNameNotAllowedHere = ErrorCode(1250) - ERCollationCharsetMismatch = ErrorCode(1253) - ERWarnDataTruncated = ErrorCode(1265) - ERCantAggregate2Collations = ErrorCode(1267) - ERCantAggregate3Collations = ErrorCode(1270) - ERCantAggregateNCollations = ErrorCode(1271) - ERVariableIsNotStruct = ErrorCode(1272) - ERUnknownCollation = ErrorCode(1273) - ERWrongNameForIndex = ErrorCode(1280) - ERWrongNameForCatalog = ErrorCode(1281) - ERBadFTColumn = ErrorCode(1283) - ERTruncatedWrongValue = ErrorCode(1292) - ERTooMuchAutoTimestampCols = ErrorCode(1293) - ERInvalidOnUpdate = ErrorCode(1294) - ERUnknownTimeZone = ErrorCode(1298) - ERInvalidCharacterString = ErrorCode(1300) - ERQueryInterrupted = ErrorCode(1317) - ERTruncatedWrongValueForField = ErrorCode(1366) - ERIllegalValueForType = ErrorCode(1367) - ERDataTooLong = ErrorCode(1406) - ErrWrongValueForType = ErrorCode(1411) - ERNoSuchUser = ErrorCode(1449) - ERForbidSchemaChange = ErrorCode(1450) - ERWrongValue = ErrorCode(1525) - ERDataOutOfRange = ErrorCode(1690) - ERInvalidJSONText = ErrorCode(3140) - ERInvalidJSONTextInParams = ErrorCode(3141) - ERInvalidJSONBinaryData = ErrorCode(3142) - ERInvalidJSONCharset = ErrorCode(3144) - ERInvalidCastToJSON = ErrorCode(3147) - ERJSONValueTooBig = ErrorCode(3150) - ERJSONDocumentTooDeep = ErrorCode(3157) - - ERRegexpStringNotTerminated = ErrorCode(3684) - ERRegexpBufferOverflow = ErrorCode(3684) - ERRegexpIllegalArgument = ErrorCode(3685) - ERRegexpIndexOutOfBounds = ErrorCode(3686) - ERRegexpInternal = ErrorCode(3687) - ERRegexpRuleSyntax = ErrorCode(3688) - ERRegexpBadEscapeSequence = ErrorCode(3689) - ERRegexpUnimplemented = ErrorCode(3690) - ERRegexpMismatchParen = ErrorCode(3691) - ERRegexpBadInterval = ErrorCode(3692) - ERRRegexpMaxLtMin = ErrorCode(3693) - ERRegexpInvalidBackRef = ErrorCode(3694) - ERRegexpLookBehindLimit = ErrorCode(3695) - ERRegexpMissingCloseBracket = ErrorCode(3696) - ERRegexpInvalidRange = ErrorCode(3697) - ERRegexpStackOverflow = ErrorCode(3698) - ERRegexpTimeOut = ErrorCode(3699) - ERRegexpPatternTooBig = ErrorCode(3700) - ERRegexpInvalidCaptureGroup = ErrorCode(3887) - ERRegexpInvalidFlag = ErrorCode(3900) - - ERCharacterSetMismatch = ErrorCode(3995) - - ERWrongParametersToNativeFct = ErrorCode(1583) - - // max execution time exceeded - ERQueryTimeout = ErrorCode(3024) - - ErrCantCreateGeometryObject = ErrorCode(1416) - ErrGISDataWrongEndianess = ErrorCode(3055) - ErrNotImplementedForCartesianSRS = ErrorCode(3704) - ErrNotImplementedForProjectedSRS = ErrorCode(3705) - ErrNonPositiveRadius = ErrorCode(3706) - - // server not available - ERServerIsntAvailable = ErrorCode(3168) -) - -// Sql states for errors. -// Originally found in include/mysql/sql_state.h -const ( - // SSUnknownSqlstate is ER_SIGNAL_EXCEPTION in - // include/mysql/sql_state.h, but: - // const char *unknown_sqlstate= "HY000" - // in client.c. So using that one. - SSUnknownSQLState = "HY000" - - // SSNetError is network related error - SSNetError = "08S01" - - // SSWrongNumberOfColumns is related to columns error - SSWrongNumberOfColumns = "21000" - - // SSWrongValueCountOnRow is related to columns count mismatch error - SSWrongValueCountOnRow = "21S01" - - // SSDataTooLong is ER_DATA_TOO_LONG - SSDataTooLong = "22001" - - // SSDataOutOfRange is ER_DATA_OUT_OF_RANGE - SSDataOutOfRange = "22003" - - // SSConstraintViolation is constraint violation - SSConstraintViolation = "23000" - - // SSCantDoThisDuringAnTransaction is - // ER_CANT_DO_THIS_DURING_AN_TRANSACTION - SSCantDoThisDuringAnTransaction = "25000" - - // SSAccessDeniedError is ER_ACCESS_DENIED_ERROR - SSAccessDeniedError = "28000" - - // SSNoDB is ER_NO_DB_ERROR - SSNoDB = "3D000" - - // SSLockDeadlock is ER_LOCK_DEADLOCK - SSLockDeadlock = "40001" - - // SSClientError is the state on client errors - SSClientError = "42000" - - // SSDupFieldName is ER_DUP_FIELD_NAME - SSDupFieldName = "42S21" - - // SSBadFieldError is ER_BAD_FIELD_ERROR - SSBadFieldError = "42S22" - - // SSUnknownTable is ER_UNKNOWN_TABLE - SSUnknownTable = "42S02" - - // SSQueryInterrupted is ER_QUERY_INTERRUPTED; - SSQueryInterrupted = "70100" -) - // IsNum returns true if a MySQL type is a numeric value. // It is the same as IS_NUM defined in mysql.h. func IsNum(typ uint8) bool { @@ -663,128 +281,3 @@ func IsNum(typ uint8) bool { typ == binlog.TypeYear || typ == binlog.TypeNewDecimal } - -// IsConnErr returns true if the error is a connection error. -func IsConnErr(err error) bool { - if IsTooManyConnectionsErr(err) { - return false - } - if sqlErr, ok := err.(*SQLError); ok { - num := sqlErr.Number() - return (num >= CRUnknownError && num <= CRNamedPipeStateError) || num == ERQueryInterrupted - } - return false -} - -// IsConnLostDuringQuery returns true if the error is a CRServerLost error. -// Happens most commonly when a query is killed MySQL server-side. -func IsConnLostDuringQuery(err error) bool { - if sqlErr, ok := err.(*SQLError); ok { - num := sqlErr.Number() - return (num == CRServerLost) - } - return false -} - -// IsEphemeralError returns true if the error is ephemeral and the caller should -// retry if possible. Note: non-SQL errors are always treated as ephemeral. -func IsEphemeralError(err error) bool { - if sqlErr, ok := err.(*SQLError); ok { - en := sqlErr.Number() - switch en { - case - CRConnectionError, - CRConnHostError, - CRMalformedPacket, - CRNamedPipeStateError, - CRServerHandshakeErr, - CRServerGone, - CRServerLost, - CRSSLConnectionError, - CRUnknownError, - CRUnknownHost, - ERCantCreateThread, - ERDiskFull, - ERForcingClose, - ERGotSignal, - ERHostIsBlocked, - ERLockTableFull, - ERInnodbReadOnly, - ERInternalError, - ERLockDeadlock, - ERLockWaitTimeout, - ERQueryTimeout, - EROutOfMemory, - EROutOfResources, - EROutOfSortMemory, - ERQueryInterrupted, - ERServerIsntAvailable, - ERServerShutdown, - ERTooManyUserConnections, - ERUnknownError, - ERUserLimitReached: - return true - default: - return false - } - } - // If it's not an sqlError then we assume it's ephemeral - return true -} - -// IsTooManyConnectionsErr returns true if the error is due to too many connections. -func IsTooManyConnectionsErr(err error) bool { - if sqlErr, ok := err.(*SQLError); ok { - if sqlErr.Number() == CRServerHandshakeErr && strings.Contains(sqlErr.Message, "Too many connections") { - return true - } - } - return false -} - -// IsSchemaApplyError returns true when given error is a MySQL error applying schema change -func IsSchemaApplyError(err error) bool { - merr, isSQLErr := err.(*SQLError) - if !isSQLErr { - return false - } - switch merr.Num { - case - ERDupKeyName, - ERCantDropFieldOrKey, - ERTableExists, - ERDupFieldName: - return true - } - return false -} - -type ReplicationState int32 - -const ( - ReplicationStateUnknown ReplicationState = iota - ReplicationStateStopped - ReplicationStateConnecting - ReplicationStateRunning -) - -// ReplicationStatusToState converts a value you have for the IO thread(s) or SQL -// thread(s) or Group Replication applier thread(s) from MySQL or intermediate -// layers to a mysql.ReplicationState. -// on,yes,true == ReplicationStateRunning -// off,no,false == ReplicationStateStopped -// connecting == ReplicationStateConnecting -// anything else == ReplicationStateUnknown -func ReplicationStatusToState(s string) ReplicationState { - // Group Replication uses ON instead of Yes - switch strings.ToLower(s) { - case "yes", "on", "true": - return ReplicationStateRunning - case "no", "off", "false": - return ReplicationStateStopped - case "connecting": - return ReplicationStateConnecting - default: - return ReplicationStateUnknown - } -} diff --git a/go/mysql/constants_test.go b/go/mysql/constants_test.go index 34d8c09ca54..1a54aad4c02 100644 --- a/go/mysql/constants_test.go +++ b/go/mysql/constants_test.go @@ -21,6 +21,8 @@ import ( "testing" "github.com/stretchr/testify/assert" + + "vitess.io/vitess/go/mysql/sqlerror" ) func TestIsConnErr(t *testing.T) { @@ -31,23 +33,23 @@ func TestIsConnErr(t *testing.T) { in: errors.New("t"), want: false, }, { - in: NewSQLError(5, "", ""), + in: sqlerror.NewSQLError(5, "", ""), want: false, }, { - in: NewSQLError(CRServerGone, "", ""), + in: sqlerror.NewSQLError(sqlerror.CRServerGone, "", ""), want: true, }, { - in: NewSQLError(CRServerLost, "", ""), + in: sqlerror.NewSQLError(sqlerror.CRServerLost, "", ""), want: true, }, { - in: NewSQLError(ERQueryInterrupted, "", ""), + in: sqlerror.NewSQLError(sqlerror.ERQueryInterrupted, "", ""), want: true, }, { - in: NewSQLError(CRCantReadCharset, "", ""), + in: sqlerror.NewSQLError(sqlerror.CRCantReadCharset, "", ""), want: false, }} for _, tcase := range testcases { - got := IsConnErr(tcase.in) + got := sqlerror.IsConnErr(tcase.in) assert.Equal(t, tcase.want, got, "IsConnErr(%#v): %v, want %v", tcase.in, got, tcase.want) } @@ -61,23 +63,23 @@ func TestIsConnLostDuringQuery(t *testing.T) { in: errors.New("t"), want: false, }, { - in: NewSQLError(5, "", ""), + in: sqlerror.NewSQLError(5, "", ""), want: false, }, { - in: NewSQLError(CRServerGone, "", ""), + in: sqlerror.NewSQLError(sqlerror.CRServerGone, "", ""), want: false, }, { - in: NewSQLError(CRServerLost, "", ""), + in: sqlerror.NewSQLError(sqlerror.CRServerLost, "", ""), want: true, }, { - in: NewSQLError(ERQueryInterrupted, "", ""), + in: sqlerror.NewSQLError(sqlerror.ERQueryInterrupted, "", ""), want: false, }, { - in: NewSQLError(CRCantReadCharset, "", ""), + in: sqlerror.NewSQLError(sqlerror.CRCantReadCharset, "", ""), want: false, }} for _, tcase := range testcases { - got := IsConnLostDuringQuery(tcase.in) + got := sqlerror.IsConnLostDuringQuery(tcase.in) assert.Equal(t, tcase.want, got, "IsConnLostDuringQuery(%#v): %v, want %v", tcase.in, got, tcase.want) } diff --git a/go/mysql/endtoend/client_test.go b/go/mysql/endtoend/client_test.go index a48c9629d51..6591c454e8a 100644 --- a/go/mysql/endtoend/client_test.go +++ b/go/mysql/endtoend/client_test.go @@ -25,6 +25,8 @@ import ( "github.com/stretchr/testify/assert" + "vitess.io/vitess/go/mysql/sqlerror" + "github.com/stretchr/testify/require" "vitess.io/vitess/go/mysql" @@ -73,9 +75,9 @@ func TestKill(t *testing.T) { // will differ. err = <-errChan if strings.Contains(err.Error(), "EOF") { - assertSQLError(t, err, mysql.CRServerLost, mysql.SSUnknownSQLState, "EOF", "select sleep(10) from dual") + assertSQLError(t, err, sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "EOF", "select sleep(10) from dual") } else { - assertSQLError(t, err, mysql.CRServerLost, mysql.SSUnknownSQLState, "", "connection reset by peer") + assertSQLError(t, err, sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "", "connection reset by peer") } } @@ -104,7 +106,7 @@ func TestKill2006(t *testing.T) { // unix socket, we will get a broken pipe when the server // closes the connection and we are trying to write the command. _, err = conn.ExecuteFetch("select sleep(10) from dual", 1000, false) - assertSQLError(t, err, mysql.CRServerGone, mysql.SSUnknownSQLState, "broken pipe", "select sleep(10) from dual") + assertSQLError(t, err, sqlerror.CRServerGone, sqlerror.SSUnknownSQLState, "broken pipe", "select sleep(10) from dual") } // TestDupEntry tests a duplicate key is properly raised. @@ -123,7 +125,7 @@ func TestDupEntry(t *testing.T) { t.Fatalf("first insert failed: %v", err) } _, err = conn.ExecuteFetch("insert into dup_entry(id, name) values(2, 10)", 0, false) - assertSQLError(t, err, mysql.ERDupEntry, mysql.SSConstraintViolation, "Duplicate entry", "insert into dup_entry(id, name) values(2, 10)") + assertSQLError(t, err, sqlerror.ERDupEntry, sqlerror.SSConstraintViolation, "Duplicate entry", "insert into dup_entry(id, name) values(2, 10)") } // TestClientFoundRows tests if the CLIENT_FOUND_ROWS flag works. diff --git a/go/mysql/endtoend/main_test.go b/go/mysql/endtoend/main_test.go index ef7cb671c33..466735c02e4 100644 --- a/go/mysql/endtoend/main_test.go +++ b/go/mysql/endtoend/main_test.go @@ -27,6 +27,8 @@ import ( "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql" vtenv "vitess.io/vitess/go/vt/env" "vitess.io/vitess/go/vt/mysqlctl" @@ -41,11 +43,11 @@ var ( ) // assertSQLError makes sure we get the right error. -func assertSQLError(t *testing.T, err error, code mysql.ErrorCode, sqlState string, subtext string, query string) { +func assertSQLError(t *testing.T, err error, code sqlerror.ErrorCode, sqlState string, subtext string, query string) { t.Helper() require.Error(t, err, "was expecting SQLError %v / %v / %v but got no error.", code, sqlState, subtext) - serr, ok := err.(*mysql.SQLError) + serr, ok := err.(*sqlerror.SQLError) require.True(t, ok, "was expecting SQLError %v / %v / %v but got: %v", code, sqlState, subtext, err) require.Equal(t, code, serr.Num, "was expecting SQLError %v / %v / %v but got code %v", code, sqlState, subtext, serr.Num) require.Equal(t, sqlState, serr.State, "was expecting SQLError %v / %v / %v but got state %v", code, sqlState, subtext, serr.State) diff --git a/go/mysql/endtoend/replication_test.go b/go/mysql/endtoend/replication_test.go index 15b966e1feb..d5c1997007e 100644 --- a/go/mysql/endtoend/replication_test.go +++ b/go/mysql/endtoend/replication_test.go @@ -29,6 +29,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/mysql/binlog" "vitess.io/vitess/go/sqltypes" @@ -126,9 +128,9 @@ func TestReplicationConnectionClosing(t *testing.T) { for { data, err := conn.ReadPacket() if err != nil { - serr, ok := err.(*mysql.SQLError) - assert.True(t, ok, "Got a non mysql.SQLError error: %v", err) - assert.Equal(t, mysql.CRServerLost, serr.Num, "Got an unexpected mysql.SQLError error: %v", serr) + serr, ok := err.(*sqlerror.SQLError) + assert.True(t, ok, "Got a non sqlerror.SQLError error: %v", err) + assert.Equal(t, sqlerror.CRServerLost, serr.Num, "Got an unexpected sqlerror.SQLError error: %v", serr) // we got the right error, all good. return diff --git a/go/mysql/fakesqldb/server.go b/go/mysql/fakesqldb/server.go index 746f82aed2a..cb3d20ae04b 100644 --- a/go/mysql/fakesqldb/server.go +++ b/go/mysql/fakesqldb/server.go @@ -29,6 +29,7 @@ import ( "testing" "time" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/log" @@ -527,7 +528,7 @@ func (db *DB) ComBinlogDump(c *mysql.Conn, logFile string, binlogPos uint32) err } // ComBinlogDumpGTID is part of the mysql.Handler interface. -func (db *DB) ComBinlogDumpGTID(c *mysql.Conn, logFile string, logPos uint64, gtidSet mysql.GTIDSet) error { +func (db *DB) ComBinlogDumpGTID(c *mysql.Conn, logFile string, logPos uint64, gtidSet replication.GTIDSet) error { return nil } diff --git a/go/mysql/flavor.go b/go/mysql/flavor.go index a8ab1dbbcb7..edb64913c31 100644 --- a/go/mysql/flavor.go +++ b/go/mysql/flavor.go @@ -23,6 +23,8 @@ import ( "strconv" "strings" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" @@ -31,7 +33,7 @@ import ( var ( // ErrNotReplica means there is no replication status. // Returned by ShowReplicationStatus(). - ErrNotReplica = NewSQLError(ERNotReplica, SSUnknownSQLState, "no replication status") + ErrNotReplica = sqlerror.NewSQLError(sqlerror.ERNotReplica, sqlerror.SSUnknownSQLState, "no replication status") // ErrNoPrimaryStatus means no status was returned by ShowPrimaryStatus(). ErrNoPrimaryStatus = errors.New("no master status") @@ -75,10 +77,10 @@ const ( // 2. MariaDB 10.X type flavor interface { // primaryGTIDSet returns the current GTIDSet of a server. - primaryGTIDSet(c *Conn) (GTIDSet, error) + primaryGTIDSet(c *Conn) (replication.GTIDSet, error) // purgedGTIDSet returns the purged GTIDSet of a server. - purgedGTIDSet(c *Conn) (GTIDSet, error) + purgedGTIDSet(c *Conn) (replication.GTIDSet, error) // gtidMode returns the gtid mode of a server. gtidMode(c *Conn) (string, error) @@ -94,11 +96,11 @@ type flavor interface { // startReplicationUntilAfter will start replication, but only allow it // to run until `pos` is reached. After reaching pos, replication will be stopped again - startReplicationUntilAfter(pos Position) string + startReplicationUntilAfter(pos replication.Position) string // startSQLThreadUntilAfter will start replication's sql thread(s), but only allow it // to run until `pos` is reached. After reaching pos, it will be stopped again - startSQLThreadUntilAfter(pos Position) string + startSQLThreadUntilAfter(pos replication.Position) string // stopReplicationCommand returns the command to stop the replication. stopReplicationCommand() string @@ -114,7 +116,7 @@ type flavor interface { // sendBinlogDumpCommand sends the packet required to start // dumping binlogs from the specified location. - sendBinlogDumpCommand(c *Conn, serverID uint32, binlogFilename string, startPos Position) error + sendBinlogDumpCommand(c *Conn, serverID uint32, binlogFilename string, startPos replication.Position) error // readBinlogEvent reads the next BinlogEvent from the connection. readBinlogEvent(c *Conn) (BinlogEvent, error) @@ -129,7 +131,7 @@ type flavor interface { // setReplicationPositionCommands returns the commands to set the // replication position at which the replica will resume. - setReplicationPositionCommands(pos Position) []string + setReplicationPositionCommands(pos replication.Position) []string // changeReplicationSourceArg returns the specific parameter to add to // a "change primary" command. @@ -137,17 +139,17 @@ type flavor interface { // status returns the result of the appropriate status command, // with parsed replication position. - status(c *Conn) (ReplicationStatus, error) + status(c *Conn) (replication.ReplicationStatus, error) // primaryStatus returns the result of 'SHOW MASTER STATUS', // with parsed executed position. - primaryStatus(c *Conn) (PrimaryStatus, error) + primaryStatus(c *Conn) (replication.PrimaryStatus, error) // waitUntilPositionCommand returns the SQL command to issue // to wait until the given position, until the context // expires. The command returns -1 if it times out. It // returns NULL if GTIDs are not enabled. - waitUntilPositionCommand(ctx context.Context, pos Position) (string, error) + waitUntilPositionCommand(ctx context.Context, pos replication.Position) (string, error) baseShowTables() string baseShowTablesWithSizes() string @@ -265,23 +267,23 @@ func (c *Conn) IsMariaDB() bool { } // PrimaryPosition returns the current primary's replication position. -func (c *Conn) PrimaryPosition() (Position, error) { +func (c *Conn) PrimaryPosition() (replication.Position, error) { gtidSet, err := c.flavor.primaryGTIDSet(c) if err != nil { - return Position{}, err + return replication.Position{}, err } - return Position{ + return replication.Position{ GTIDSet: gtidSet, }, nil } // GetGTIDPurged returns the tablet's GTIDs which are purged. -func (c *Conn) GetGTIDPurged() (Position, error) { +func (c *Conn) GetGTIDPurged() (replication.Position, error) { gtidSet, err := c.flavor.purgedGTIDSet(c) if err != nil { - return Position{}, err + return replication.Position{}, err } - return Position{ + return replication.Position{ GTIDSet: gtidSet, }, nil } @@ -297,13 +299,13 @@ func (c *Conn) GetServerUUID() (string, error) { } // PrimaryFilePosition returns the current primary's file based replication position. -func (c *Conn) PrimaryFilePosition() (Position, error) { +func (c *Conn) PrimaryFilePosition() (replication.Position, error) { filePosFlavor := filePosFlavor{} gtidSet, err := filePosFlavor.primaryGTIDSet(c) if err != nil { - return Position{}, err + return replication.Position{}, err } - return Position{ + return replication.Position{ GTIDSet: gtidSet, }, nil } @@ -319,14 +321,14 @@ func (c *Conn) RestartReplicationCommands() []string { } // StartReplicationUntilAfterCommand returns the command to start replication. -func (c *Conn) StartReplicationUntilAfterCommand(pos Position) string { +func (c *Conn) StartReplicationUntilAfterCommand(pos replication.Position) string { return c.flavor.startReplicationUntilAfter(pos) } // StartSQLThreadUntilAfterCommand returns the command to start the replica's SQL // thread(s) and have it run until it has reached the given position, at which point // it will stop. -func (c *Conn) StartSQLThreadUntilAfterCommand(pos Position) string { +func (c *Conn) StartSQLThreadUntilAfterCommand(pos replication.Position) string { return c.flavor.startSQLThreadUntilAfter(pos) } @@ -353,7 +355,7 @@ func (c *Conn) StartSQLThreadCommand() string { // SendBinlogDumpCommand sends the flavor-specific version of // the COM_BINLOG_DUMP command to start dumping raw binlog // events over a server connection, starting at a given GTID. -func (c *Conn) SendBinlogDumpCommand(serverID uint32, binlogFilename string, startPos Position) error { +func (c *Conn) SendBinlogDumpCommand(serverID uint32, binlogFilename string, startPos replication.Position) error { return c.flavor.sendBinlogDumpCommand(c, serverID, binlogFilename, startPos) } @@ -378,7 +380,7 @@ func (c *Conn) ResetReplicationParametersCommands() []string { // SetReplicationPositionCommands returns the commands to set the // replication position at which the replica will resume // when it is later reparented with SetReplicationSourceCommand. -func (c *Conn) SetReplicationPositionCommands(pos Position) []string { +func (c *Conn) SetReplicationPositionCommands(pos replication.Position) []string { return c.flavor.setReplicationPositionCommands(pos) } @@ -433,107 +435,15 @@ func resultToMap(qr *sqltypes.Result) (map[string]string, error) { return result, nil } -// parseReplicationStatus parses the common (non-flavor-specific) fields of ReplicationStatus -func parseReplicationStatus(fields map[string]string) ReplicationStatus { - // The field names in the map are identical to what we receive from the database - // Hence the names still contain Master - status := ReplicationStatus{ - SourceHost: fields["Master_Host"], - SourceUser: fields["Master_User"], - SSLAllowed: fields["Master_SSL_Allowed"] == "Yes", - AutoPosition: fields["Auto_Position"] == "1", - UsingGTID: fields["Using_Gtid"] != "No" && fields["Using_Gtid"] != "", - HasReplicationFilters: (fields["Replicate_Do_DB"] != "") || (fields["Replicate_Ignore_DB"] != "") || (fields["Replicate_Do_Table"] != "") || (fields["Replicate_Ignore_Table"] != "") || (fields["Replicate_Wild_Do_Table"] != "") || (fields["Replicate_Wild_Ignore_Table"] != ""), - // These fields are returned from the underlying DB and cannot be renamed - IOState: ReplicationStatusToState(fields["Slave_IO_Running"]), - LastIOError: fields["Last_IO_Error"], - SQLState: ReplicationStatusToState(fields["Slave_SQL_Running"]), - LastSQLError: fields["Last_SQL_Error"], - } - parseInt, _ := strconv.ParseInt(fields["Master_Port"], 10, 32) - status.SourcePort = int32(parseInt) - parseInt, _ = strconv.ParseInt(fields["Connect_Retry"], 10, 32) - status.ConnectRetry = int32(parseInt) - parseUint, err := strconv.ParseUint(fields["Seconds_Behind_Master"], 10, 32) - if err != nil { - // we could not parse the value into a valid uint32 -- most commonly because the value is NULL from the - // database -- so let's reflect that the underlying value was unknown on our last check - status.ReplicationLagUnknown = true - } else { - status.ReplicationLagUnknown = false - status.ReplicationLagSeconds = uint32(parseUint) - } - parseUint, _ = strconv.ParseUint(fields["Master_Server_Id"], 10, 32) - status.SourceServerID = uint32(parseUint) - parseUint, _ = strconv.ParseUint(fields["SQL_Delay"], 10, 32) - status.SQLDelay = uint32(parseUint) - - executedPosStr := fields["Exec_Master_Log_Pos"] - file := fields["Relay_Master_Log_File"] - if file != "" && executedPosStr != "" { - filePos, err := strconv.ParseUint(executedPosStr, 10, 32) - if err == nil { - status.FilePosition.GTIDSet = filePosGTID{ - file: file, - pos: uint32(filePos), - } - } - } - - readPosStr := fields["Read_Master_Log_Pos"] - file = fields["Master_Log_File"] - if file != "" && readPosStr != "" { - fileRelayPos, err := strconv.ParseUint(readPosStr, 10, 32) - if err == nil { - status.RelayLogSourceBinlogEquivalentPosition.GTIDSet = filePosGTID{ - file: file, - pos: uint32(fileRelayPos), - } - } - } - - relayPosStr := fields["Relay_Log_Pos"] - file = fields["Relay_Log_File"] - if file != "" && relayPosStr != "" { - relayFilePos, err := strconv.ParseUint(relayPosStr, 10, 32) - if err == nil { - status.RelayLogFilePosition.GTIDSet = filePosGTID{ - file: file, - pos: uint32(relayFilePos), - } - } - } - return status -} - // ShowReplicationStatus executes the right command to fetch replication status, // and returns a parsed Position with other fields. -func (c *Conn) ShowReplicationStatus() (ReplicationStatus, error) { +func (c *Conn) ShowReplicationStatus() (replication.ReplicationStatus, error) { return c.flavor.status(c) } -// parsePrimaryStatus parses the common fields of SHOW MASTER STATUS. -func parsePrimaryStatus(fields map[string]string) PrimaryStatus { - status := PrimaryStatus{} - - fileExecPosStr := fields["Position"] - file := fields["File"] - if file != "" && fileExecPosStr != "" { - filePos, err := strconv.ParseUint(fileExecPosStr, 10, 32) - if err == nil { - status.FilePosition.GTIDSet = filePosGTID{ - file: file, - pos: uint32(filePos), - } - } - } - - return status -} - // ShowPrimaryStatus executes the right SHOW MASTER STATUS command, // and returns a parsed executed Position, as well as file based Position. -func (c *Conn) ShowPrimaryStatus() (PrimaryStatus, error) { +func (c *Conn) ShowPrimaryStatus() (replication.PrimaryStatus, error) { return c.flavor.primaryStatus(c) } @@ -541,7 +451,7 @@ func (c *Conn) ShowPrimaryStatus() (PrimaryStatus, error) { // to wait until the given position, until the context // expires. The command returns -1 if it times out. It // returns NULL if GTIDs are not enabled. -func (c *Conn) WaitUntilPositionCommand(ctx context.Context, pos Position) (string, error) { +func (c *Conn) WaitUntilPositionCommand(ctx context.Context, pos replication.Position) (string, error) { return c.flavor.waitUntilPositionCommand(ctx, pos) } @@ -549,7 +459,7 @@ func (c *Conn) WaitUntilPositionCommand(ctx context.Context, pos Position) (stri // to wait until the given position, until the context // expires for the file position flavor. The command returns -1 if it times out. It // returns NULL if GTIDs are not enabled. -func (c *Conn) WaitUntilFilePositionCommand(ctx context.Context, pos Position) (string, error) { +func (c *Conn) WaitUntilFilePositionCommand(ctx context.Context, pos replication.Position) (string, error) { filePosFlavor := filePosFlavor{} return filePosFlavor.waitUntilPositionCommand(ctx, pos) } @@ -568,3 +478,7 @@ func (c *Conn) BaseShowTablesWithSizes() string { func (c *Conn) SupportsCapability(capability FlavorCapability) (bool, error) { return c.flavor.supportsCapability(c.ServerVersion, capability) } + +func init() { + flavors[replication.FilePosFlavorID] = newFilePosFlavor +} diff --git a/go/mysql/flavor_filepos.go b/go/mysql/flavor_filepos.go index 9c2bdeb7407..d89e9ff9da4 100644 --- a/go/mysql/flavor_filepos.go +++ b/go/mysql/flavor_filepos.go @@ -20,10 +20,11 @@ import ( "context" "fmt" "io" - "strconv" "strings" "time" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" ) @@ -40,7 +41,7 @@ func newFilePosFlavor() flavor { } // primaryGTIDSet is part of the Flavor interface. -func (flv *filePosFlavor) primaryGTIDSet(c *Conn) (GTIDSet, error) { +func (flv *filePosFlavor) primaryGTIDSet(c *Conn) (replication.GTIDSet, error) { qr, err := c.ExecuteFetch("SHOW MASTER STATUS", 100, true /* wantfields */) if err != nil { return nil, err @@ -53,19 +54,11 @@ func (flv *filePosFlavor) primaryGTIDSet(c *Conn) (GTIDSet, error) { if err != nil { return nil, err } - pos, err := strconv.ParseUint(resultMap["Position"], 0, 32) - if err != nil { - return nil, fmt.Errorf("invalid FilePos GTID (%v): expecting pos to be an integer", resultMap["Position"]) - } - - return filePosGTID{ - file: resultMap["File"], - pos: uint32(pos), - }, nil + return replication.ParseFilePosGTIDSet(fmt.Sprintf("%s:%s", resultMap["File"], resultMap["Position"])) } // purgedGTIDSet is part of the Flavor interface. -func (flv *filePosFlavor) purgedGTIDSet(c *Conn) (GTIDSet, error) { +func (flv *filePosFlavor) purgedGTIDSet(c *Conn) (replication.GTIDSet, error) { return nil, nil } @@ -119,14 +112,14 @@ func (flv *filePosFlavor) startSQLThreadCommand() string { } // sendBinlogDumpCommand is part of the Flavor interface. -func (flv *filePosFlavor) sendBinlogDumpCommand(c *Conn, serverID uint32, binlogFilename string, startPos Position) error { - rpos, ok := startPos.GTIDSet.(filePosGTID) +func (flv *filePosFlavor) sendBinlogDumpCommand(c *Conn, serverID uint32, binlogFilename string, startPos replication.Position) error { + rpos, ok := startPos.GTIDSet.(replication.FilePosGTID) if !ok { return fmt.Errorf("startPos.GTIDSet is wrong type - expected filePosGTID, got: %#v", startPos.GTIDSet) } - flv.file = rpos.file - return c.WriteComBinlogDump(serverID, rpos.file, rpos.pos, 0) + flv.file = rpos.File + return c.WriteComBinlogDump(serverID, rpos.File, rpos.Pos, 0) } // readBinlogEvent is part of the Flavor interface. @@ -143,7 +136,7 @@ func (flv *filePosFlavor) readBinlogEvent(c *Conn) (BinlogEvent, error) { } switch result[0] { case EOFPacket: - return nil, NewSQLError(CRServerLost, SSUnknownSQLState, "%v", io.EOF) + return nil, sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", io.EOF) case ErrPacket: return nil, ParseErrorPacket(result) } @@ -223,7 +216,7 @@ func (flv *filePosFlavor) resetReplicationParametersCommands(c *Conn) []string { } // setReplicationPositionCommands is part of the Flavor interface. -func (flv *filePosFlavor) setReplicationPositionCommands(pos Position) []string { +func (flv *filePosFlavor) setReplicationPositionCommands(pos replication.Position) []string { return []string{ "unsupported", } @@ -235,27 +228,27 @@ func (flv *filePosFlavor) changeReplicationSourceArg() string { } // status is part of the Flavor interface. -func (flv *filePosFlavor) status(c *Conn) (ReplicationStatus, error) { +func (flv *filePosFlavor) status(c *Conn) (replication.ReplicationStatus, error) { qr, err := c.ExecuteFetch("SHOW SLAVE STATUS", 100, true /* wantfields */) if err != nil { - return ReplicationStatus{}, err + return replication.ReplicationStatus{}, err } if len(qr.Rows) == 0 { // The query returned no data, meaning the server // is not configured as a replica. - return ReplicationStatus{}, ErrNotReplica + return replication.ReplicationStatus{}, ErrNotReplica } resultMap, err := resultToMap(qr) if err != nil { - return ReplicationStatus{}, err + return replication.ReplicationStatus{}, err } - return parseFilePosReplicationStatus(resultMap) + return replication.ParseFilePosReplicationStatus(resultMap) } -func parseFilePosReplicationStatus(resultMap map[string]string) (ReplicationStatus, error) { - status := parseReplicationStatus(resultMap) +func parseFilePosReplicationStatus(resultMap map[string]string) (replication.ReplicationStatus, error) { + status := replication.ParseReplicationStatus(resultMap) status.Position = status.FilePosition status.RelayLogPosition = status.RelayLogSourceBinlogEquivalentPosition @@ -264,35 +257,27 @@ func parseFilePosReplicationStatus(resultMap map[string]string) (ReplicationStat } // primaryStatus is part of the Flavor interface. -func (flv *filePosFlavor) primaryStatus(c *Conn) (PrimaryStatus, error) { +func (flv *filePosFlavor) primaryStatus(c *Conn) (replication.PrimaryStatus, error) { qr, err := c.ExecuteFetch("SHOW MASTER STATUS", 100, true /* wantfields */) if err != nil { - return PrimaryStatus{}, err + return replication.PrimaryStatus{}, err } if len(qr.Rows) == 0 { // The query returned no data. We don't know how this could happen. - return PrimaryStatus{}, ErrNoPrimaryStatus + return replication.PrimaryStatus{}, ErrNoPrimaryStatus } resultMap, err := resultToMap(qr) if err != nil { - return PrimaryStatus{}, err + return replication.PrimaryStatus{}, err } - return parseFilePosPrimaryStatus(resultMap) -} - -func parseFilePosPrimaryStatus(resultMap map[string]string) (PrimaryStatus, error) { - status := parsePrimaryStatus(resultMap) - - status.Position = status.FilePosition - - return status, nil + return replication.ParseFilePosPrimaryStatus(resultMap) } // waitUntilPositionCommand is part of the Flavor interface. -func (flv *filePosFlavor) waitUntilPositionCommand(ctx context.Context, pos Position) (string, error) { - filePosPos, ok := pos.GTIDSet.(filePosGTID) +func (flv *filePosFlavor) waitUntilPositionCommand(ctx context.Context, pos replication.Position) (string, error) { + filePosPos, ok := pos.GTIDSet.(replication.FilePosGTID) if !ok { return "", fmt.Errorf("Position is not filePos compatible: %#v", pos.GTIDSet) } @@ -302,17 +287,17 @@ func (flv *filePosFlavor) waitUntilPositionCommand(ctx context.Context, pos Posi if timeout <= 0 { return "", fmt.Errorf("timed out waiting for position %v", pos) } - return fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %d, %.6f)", filePosPos.file, filePosPos.pos, timeout.Seconds()), nil + return fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %d, %.6f)", filePosPos.File, filePosPos.Pos, timeout.Seconds()), nil } - return fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %d)", filePosPos.file, filePosPos.pos), nil + return fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %d)", filePosPos.File, filePosPos.Pos), nil } -func (*filePosFlavor) startReplicationUntilAfter(pos Position) string { +func (*filePosFlavor) startReplicationUntilAfter(pos replication.Position) string { return "unsupported" } -func (*filePosFlavor) startSQLThreadUntilAfter(pos Position) string { +func (*filePosFlavor) startSQLThreadUntilAfter(pos replication.Position) string { return "unsupported" } diff --git a/go/mysql/flavor_filepos_test.go b/go/mysql/flavor_filepos_test.go deleted file mode 100644 index be60f6a95a6..00000000000 --- a/go/mysql/flavor_filepos_test.go +++ /dev/null @@ -1,80 +0,0 @@ -/* -Copyright 2020 The Vitess Authors. - -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 mysql - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestFilePosRetrieveSourceServerId(t *testing.T) { - resultMap := map[string]string{ - "Master_Server_Id": "1", - } - - want := ReplicationStatus{SourceServerID: 1} - got, err := parseFilePosReplicationStatus(resultMap) - require.NoError(t, err) - assert.Equalf(t, got.SourceServerID, want.SourceServerID, "got SourceServerID: %v; want SourceServerID: %v", got.SourceServerID, want.SourceServerID) -} - -func TestFilePosRetrieveExecutedPosition(t *testing.T) { - resultMap := map[string]string{ - "Exec_Master_Log_Pos": "1307", - "Relay_Master_Log_File": "master-bin.000002", - "Read_Master_Log_Pos": "1308", - "Master_Log_File": "master-bin.000003", - "Relay_Log_Pos": "1309", - "Relay_Log_File": "relay-bin.000004", - } - - want := ReplicationStatus{ - Position: Position{GTIDSet: filePosGTID{file: "master-bin.000002", pos: 1307}}, - RelayLogPosition: Position{GTIDSet: filePosGTID{file: "master-bin.000003", pos: 1308}}, - FilePosition: Position{GTIDSet: filePosGTID{file: "master-bin.000002", pos: 1307}}, - RelayLogSourceBinlogEquivalentPosition: Position{GTIDSet: filePosGTID{file: "master-bin.000003", pos: 1308}}, - RelayLogFilePosition: Position{GTIDSet: filePosGTID{file: "relay-bin.000004", pos: 1309}}, - } - got, err := parseFilePosReplicationStatus(resultMap) - require.NoError(t, err) - assert.Equalf(t, got.Position.GTIDSet, want.Position.GTIDSet, "got Position: %v; want Position: %v", got.Position.GTIDSet, want.Position.GTIDSet) - assert.Equalf(t, got.RelayLogPosition.GTIDSet, want.RelayLogPosition.GTIDSet, "got RelayLogPosition: %v; want RelayLogPosition: %v", got.RelayLogPosition.GTIDSet, want.RelayLogPosition.GTIDSet) - assert.Equalf(t, got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet, "got RelayLogFilePosition: %v; want RelayLogFilePosition: %v", got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet) - assert.Equalf(t, got.FilePosition.GTIDSet, want.FilePosition.GTIDSet, "got FilePosition: %v; want FilePosition: %v", got.FilePosition.GTIDSet, want.FilePosition.GTIDSet) - assert.Equalf(t, got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet, "got RelayLogSourceBinlogEquivalentPosition: %v; want RelayLogSourceBinlogEquivalentPosition: %v", got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet) - assert.Equalf(t, got.Position.GTIDSet, got.FilePosition.GTIDSet, "FilePosition and Position don't match when they should for the FilePos flavor") - assert.Equalf(t, got.RelayLogPosition.GTIDSet, got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, "RelayLogPosition and RelayLogSourceBinlogEquivalentPosition don't match when they should for the FilePos flavor") -} - -func TestFilePosShouldGetPosition(t *testing.T) { - resultMap := map[string]string{ - "Position": "1307", - "File": "source-bin.000003", - } - - want := PrimaryStatus{ - Position: Position{GTIDSet: filePosGTID{file: "source-bin.000003", pos: 1307}}, - FilePosition: Position{GTIDSet: filePosGTID{file: "source-bin.000003", pos: 1307}}, - } - got, err := parseFilePosPrimaryStatus(resultMap) - require.NoError(t, err) - assert.Equalf(t, got.Position.GTIDSet, want.Position.GTIDSet, "got Position: %v; want Position: %v", got.Position.GTIDSet, want.Position.GTIDSet) - assert.Equalf(t, got.FilePosition.GTIDSet, want.FilePosition.GTIDSet, "got FilePosition: %v; want FilePosition: %v", got.FilePosition.GTIDSet, want.FilePosition.GTIDSet) - assert.Equalf(t, got.Position.GTIDSet, got.FilePosition.GTIDSet, "FilePosition and Position don't match when they should for the FilePos flavor") -} diff --git a/go/mysql/flavor_mariadb.go b/go/mysql/flavor_mariadb.go index 377ede1ecc8..15718542b45 100644 --- a/go/mysql/flavor_mariadb.go +++ b/go/mysql/flavor_mariadb.go @@ -18,12 +18,13 @@ limitations under the License. package mysql import ( + "context" "fmt" "io" "time" - "context" - + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" ) @@ -41,7 +42,7 @@ var _ flavor = (*mariadbFlavor101)(nil) var _ flavor = (*mariadbFlavor102)(nil) // primaryGTIDSet is part of the Flavor interface. -func (mariadbFlavor) primaryGTIDSet(c *Conn) (GTIDSet, error) { +func (mariadbFlavor) primaryGTIDSet(c *Conn) (replication.GTIDSet, error) { qr, err := c.ExecuteFetch("SELECT @@GLOBAL.gtid_binlog_pos", 1, false) if err != nil { return nil, err @@ -50,11 +51,11 @@ func (mariadbFlavor) primaryGTIDSet(c *Conn) (GTIDSet, error) { return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected result format for gtid_binlog_pos: %#v", qr) } - return parseMariadbGTIDSet(qr.Rows[0][0].ToString()) + return replication.ParseMariadbGTIDSet(qr.Rows[0][0].ToString()) } // purgedGTIDSet is part of the Flavor interface. -func (mariadbFlavor) purgedGTIDSet(c *Conn) (GTIDSet, error) { +func (mariadbFlavor) purgedGTIDSet(c *Conn) (replication.GTIDSet, error) { return nil, nil } @@ -68,11 +69,11 @@ func (mariadbFlavor) gtidMode(c *Conn) (string, error) { return "", nil } -func (mariadbFlavor) startReplicationUntilAfter(pos Position) string { +func (mariadbFlavor) startReplicationUntilAfter(pos replication.Position) string { return fmt.Sprintf("START SLAVE UNTIL master_gtid_pos = \"%s\"", pos) } -func (mariadbFlavor) startSQLThreadUntilAfter(pos Position) string { +func (mariadbFlavor) startSQLThreadUntilAfter(pos replication.Position) string { return fmt.Sprintf("START SLAVE SQL_THREAD UNTIL master_gtid_pos = \"%s\"", pos) } @@ -105,7 +106,7 @@ func (mariadbFlavor) startSQLThreadCommand() string { } // sendBinlogDumpCommand is part of the Flavor interface. -func (mariadbFlavor) sendBinlogDumpCommand(c *Conn, serverID uint32, binlogFilename string, startPos Position) error { +func (mariadbFlavor) sendBinlogDumpCommand(c *Conn, serverID uint32, binlogFilename string, startPos replication.Position) error { // Tell the server that we understand GTIDs by setting // mariadb_slave_capability to MARIA_SLAVE_CAPABILITY_GTID = 4 (MariaDB >= 10.0.1). if _, err := c.ExecuteFetch("SET @mariadb_slave_capability=4", 0, false); err != nil { @@ -154,7 +155,7 @@ func (mariadbFlavor) resetReplicationParametersCommands(c *Conn) []string { } // setReplicationPositionCommands is part of the Flavor interface. -func (mariadbFlavor) setReplicationPositionCommands(pos Position) []string { +func (mariadbFlavor) setReplicationPositionCommands(pos replication.Position) []string { return []string{ // RESET MASTER will clear out gtid_binlog_pos, // which then guarantees that gtid_current_pos = gtid_slave_pos, @@ -182,54 +183,42 @@ func (mariadbFlavor) changeReplicationSourceArg() string { } // status is part of the Flavor interface. -func (mariadbFlavor) status(c *Conn) (ReplicationStatus, error) { +func (mariadbFlavor) status(c *Conn) (replication.ReplicationStatus, error) { qr, err := c.ExecuteFetch("SHOW ALL SLAVES STATUS", 100, true /* wantfields */) if err != nil { - return ReplicationStatus{}, err + return replication.ReplicationStatus{}, err } if len(qr.Rows) == 0 { // The query returned no data, meaning the server // is not configured as a replica. - return ReplicationStatus{}, ErrNotReplica + return replication.ReplicationStatus{}, ErrNotReplica } resultMap, err := resultToMap(qr) if err != nil { - return ReplicationStatus{}, err - } - - return parseMariadbReplicationStatus(resultMap) -} - -func parseMariadbReplicationStatus(resultMap map[string]string) (ReplicationStatus, error) { - status := parseReplicationStatus(resultMap) - - var err error - status.Position.GTIDSet, err = parseMariadbGTIDSet(resultMap["Gtid_Slave_Pos"]) - if err != nil { - return ReplicationStatus{}, vterrors.Wrapf(err, "ReplicationStatus can't parse MariaDB GTID (Gtid_Slave_Pos: %#v)", resultMap["Gtid_Slave_Pos"]) + return replication.ReplicationStatus{}, err } - return status, nil + return replication.ParseMariadbReplicationStatus(resultMap) } // primaryStatus is part of the Flavor interface. -func (m mariadbFlavor) primaryStatus(c *Conn) (PrimaryStatus, error) { +func (m mariadbFlavor) primaryStatus(c *Conn) (replication.PrimaryStatus, error) { qr, err := c.ExecuteFetch("SHOW MASTER STATUS", 100, true /* wantfields */) if err != nil { - return PrimaryStatus{}, err + return replication.PrimaryStatus{}, err } if len(qr.Rows) == 0 { // The query returned no data. We don't know how this could happen. - return PrimaryStatus{}, ErrNoPrimaryStatus + return replication.PrimaryStatus{}, ErrNoPrimaryStatus } resultMap, err := resultToMap(qr) if err != nil { - return PrimaryStatus{}, err + return replication.PrimaryStatus{}, err } - status := parsePrimaryStatus(resultMap) + status := replication.ParsePrimaryStatus(resultMap) status.Position.GTIDSet, err = m.primaryGTIDSet(c) return status, err } @@ -238,7 +227,7 @@ func (m mariadbFlavor) primaryStatus(c *Conn) (PrimaryStatus, error) { // // Note: Unlike MASTER_POS_WAIT(), MASTER_GTID_WAIT() will continue waiting even // if the sql thread stops. If that is a problem, we'll have to change this. -func (mariadbFlavor) waitUntilPositionCommand(ctx context.Context, pos Position) (string, error) { +func (mariadbFlavor) waitUntilPositionCommand(ctx context.Context, pos replication.Position) (string, error) { if deadline, ok := ctx.Deadline(); ok { timeout := time.Until(deadline) if timeout <= 0 { @@ -260,7 +249,7 @@ func (mariadbFlavor) readBinlogEvent(c *Conn) (BinlogEvent, error) { } switch result[0] { case EOFPacket: - return nil, NewSQLError(CRServerLost, SSUnknownSQLState, "%v", io.EOF) + return nil, sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", io.EOF) case ErrPacket: return nil, ParseErrorPacket(result) } diff --git a/go/mysql/flavor_mariadb_test.go b/go/mysql/flavor_mariadb_test.go index a2741c27148..250d664e4af 100644 --- a/go/mysql/flavor_mariadb_test.go +++ b/go/mysql/flavor_mariadb_test.go @@ -17,11 +17,9 @@ limitations under the License. package mysql import ( - "fmt" "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestMariadbSetReplicationSourceCommand(t *testing.T) { @@ -77,51 +75,3 @@ func TestMariadbSetReplicationSourceCommandSSL(t *testing.T) { assert.Equal(t, want, got, "mariadbFlavor.SetReplicationSourceCommand(%#v, %#v, %#v, %#v) = %#v, want %#v", params, host, port, connectRetry, got, want) } - -func TestMariadbRetrieveSourceServerId(t *testing.T) { - resultMap := map[string]string{ - "Master_Server_Id": "1", - "Gtid_Slave_Pos": "0-101-2320", - } - - want := ReplicationStatus{SourceServerID: 1} - got, err := parseMariadbReplicationStatus(resultMap) - require.NoError(t, err) - assert.Equal(t, got.SourceServerID, want.SourceServerID, fmt.Sprintf("got SourceServerID: %v; want SourceServerID: %v", got.SourceServerID, want.SourceServerID)) -} - -func TestMariadbRetrieveFileBasedPositions(t *testing.T) { - resultMap := map[string]string{ - "Exec_Master_Log_Pos": "1307", - "Relay_Master_Log_File": "master-bin.000002", - "Read_Master_Log_Pos": "1308", - "Master_Log_File": "master-bin.000003", - "Gtid_Slave_Pos": "0-101-2320", - "Relay_Log_Pos": "1309", - "Relay_Log_File": "relay-bin.000004", - } - - want := ReplicationStatus{ - FilePosition: Position{GTIDSet: filePosGTID{file: "master-bin.000002", pos: 1307}}, - RelayLogSourceBinlogEquivalentPosition: Position{GTIDSet: filePosGTID{file: "master-bin.000003", pos: 1308}}, - RelayLogFilePosition: Position{GTIDSet: filePosGTID{file: "relay-bin.000004", pos: 1309}}, - } - got, err := parseMariadbReplicationStatus(resultMap) - require.NoError(t, err) - assert.Equalf(t, got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet, "got RelayLogFilePosition: %v; want RelayLogFilePosition: %v", got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet) - assert.Equal(t, got.FilePosition.GTIDSet, want.FilePosition.GTIDSet, fmt.Sprintf("got FilePosition: %v; want FilePosition: %v", got.FilePosition.GTIDSet, want.FilePosition.GTIDSet)) - assert.Equal(t, got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet, fmt.Sprintf("got RelayLogSourceBinlogEquivalentPosition: %v; want RelayLogSourceBinlogEquivalentPosition: %v", got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet)) -} - -func TestMariadbShouldGetNilRelayLogPosition(t *testing.T) { - resultMap := map[string]string{ - "Exec_Master_Log_Pos": "1307", - "Relay_Master_Log_File": "master-bin.000002", - "Read_Master_Log_Pos": "1308", - "Master_Log_File": "master-bin.000003", - "Gtid_Slave_Pos": "0-101-2320", - } - got, err := parseMariadbReplicationStatus(resultMap) - require.NoError(t, err) - assert.Truef(t, got.RelayLogPosition.IsZero(), "Got a filled in RelayLogPosition. For MariaDB we should get back nil, because MariaDB does not return the retrieved GTIDSet. got: %#v", got.RelayLogPosition) -} diff --git a/go/mysql/flavor_mysql.go b/go/mysql/flavor_mysql.go index 820d7eb99ab..bc5f31006e5 100644 --- a/go/mysql/flavor_mysql.go +++ b/go/mysql/flavor_mysql.go @@ -22,6 +22,8 @@ import ( "io" "time" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" ) @@ -43,7 +45,7 @@ var _ flavor = (*mysqlFlavor57)(nil) var _ flavor = (*mysqlFlavor80)(nil) // primaryGTIDSet is part of the Flavor interface. -func (mysqlFlavor) primaryGTIDSet(c *Conn) (GTIDSet, error) { +func (mysqlFlavor) primaryGTIDSet(c *Conn) (replication.GTIDSet, error) { // keep @@global as lowercase, as some servers like the Ripple binlog server only honors a lowercase `global` value qr, err := c.ExecuteFetch("SELECT @@global.gtid_executed", 1, false) if err != nil { @@ -52,11 +54,11 @@ func (mysqlFlavor) primaryGTIDSet(c *Conn) (GTIDSet, error) { if len(qr.Rows) != 1 || len(qr.Rows[0]) != 1 { return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected result format for gtid_executed: %#v", qr) } - return ParseMysql56GTIDSet(qr.Rows[0][0].ToString()) + return replication.ParseMysql56GTIDSet(qr.Rows[0][0].ToString()) } // purgedGTIDSet is part of the Flavor interface. -func (mysqlFlavor) purgedGTIDSet(c *Conn) (GTIDSet, error) { +func (mysqlFlavor) purgedGTIDSet(c *Conn) (replication.GTIDSet, error) { // keep @@global as lowercase, as some servers like the Ripple binlog server only honors a lowercase `global` value qr, err := c.ExecuteFetch("SELECT @@global.gtid_purged", 1, false) if err != nil { @@ -65,7 +67,7 @@ func (mysqlFlavor) purgedGTIDSet(c *Conn) (GTIDSet, error) { if len(qr.Rows) != 1 || len(qr.Rows[0]) != 1 { return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected result format for gtid_purged: %#v", qr) } - return ParseMysql56GTIDSet(qr.Rows[0][0].ToString()) + return replication.ParseMysql56GTIDSet(qr.Rows[0][0].ToString()) } // serverUUID is part of the Flavor interface. @@ -105,11 +107,11 @@ func (mysqlFlavor) restartReplicationCommands() []string { } } -func (mysqlFlavor) startReplicationUntilAfter(pos Position) string { +func (mysqlFlavor) startReplicationUntilAfter(pos replication.Position) string { return fmt.Sprintf("START SLAVE UNTIL SQL_AFTER_GTIDS = '%s'", pos) } -func (mysqlFlavor) startSQLThreadUntilAfter(pos Position) string { +func (mysqlFlavor) startSQLThreadUntilAfter(pos replication.Position) string { return fmt.Sprintf("START SLAVE SQL_THREAD UNTIL SQL_AFTER_GTIDS = '%s'", pos) } @@ -130,8 +132,8 @@ func (mysqlFlavor) startSQLThreadCommand() string { } // sendBinlogDumpCommand is part of the Flavor interface. -func (mysqlFlavor) sendBinlogDumpCommand(c *Conn, serverID uint32, binlogFilename string, startPos Position) error { - gtidSet, ok := startPos.GTIDSet.(Mysql56GTIDSet) +func (mysqlFlavor) sendBinlogDumpCommand(c *Conn, serverID uint32, binlogFilename string, startPos replication.Position) error { + gtidSet, ok := startPos.GTIDSet.(replication.Mysql56GTIDSet) if !ok { return vterrors.Errorf(vtrpc.Code_INTERNAL, "startPos.GTIDSet is wrong type - expected Mysql56GTIDSet, got: %#v", startPos.GTIDSet) } @@ -163,7 +165,7 @@ func (mysqlFlavor) resetReplicationParametersCommands(c *Conn) []string { } // setReplicationPositionCommands is part of the Flavor interface. -func (mysqlFlavor) setReplicationPositionCommands(pos Position) []string { +func (mysqlFlavor) setReplicationPositionCommands(pos replication.Position) []string { return []string{ "RESET MASTER", // We must clear gtid_executed before setting gtid_purged. fmt.Sprintf("SET GLOBAL gtid_purged = '%s'", pos), @@ -176,88 +178,46 @@ func (mysqlFlavor) changeReplicationSourceArg() string { } // status is part of the Flavor interface. -func (mysqlFlavor) status(c *Conn) (ReplicationStatus, error) { +func (mysqlFlavor) status(c *Conn) (replication.ReplicationStatus, error) { qr, err := c.ExecuteFetch("SHOW SLAVE STATUS", 100, true /* wantfields */) if err != nil { - return ReplicationStatus{}, err + return replication.ReplicationStatus{}, err } if len(qr.Rows) == 0 { // The query returned no data, meaning the server // is not configured as a replica. - return ReplicationStatus{}, ErrNotReplica + return replication.ReplicationStatus{}, ErrNotReplica } resultMap, err := resultToMap(qr) if err != nil { - return ReplicationStatus{}, err + return replication.ReplicationStatus{}, err } - return parseMysqlReplicationStatus(resultMap) -} - -func parseMysqlReplicationStatus(resultMap map[string]string) (ReplicationStatus, error) { - status := parseReplicationStatus(resultMap) - uuidString := resultMap["Master_UUID"] - if uuidString != "" { - sid, err := ParseSID(uuidString) - if err != nil { - return ReplicationStatus{}, vterrors.Wrapf(err, "cannot decode SourceUUID") - } - status.SourceUUID = sid - } - - var err error - status.Position.GTIDSet, err = ParseMysql56GTIDSet(resultMap["Executed_Gtid_Set"]) - if err != nil { - return ReplicationStatus{}, vterrors.Wrapf(err, "ReplicationStatus can't parse MySQL 5.6 GTID (Executed_Gtid_Set: %#v)", resultMap["Executed_Gtid_Set"]) - } - relayLogGTIDSet, err := ParseMysql56GTIDSet(resultMap["Retrieved_Gtid_Set"]) - if err != nil { - return ReplicationStatus{}, vterrors.Wrapf(err, "ReplicationStatus can't parse MySQL 5.6 GTID (Retrieved_Gtid_Set: %#v)", resultMap["Retrieved_Gtid_Set"]) - } - // We take the union of the executed and retrieved gtidset, because the retrieved gtidset only represents GTIDs since - // the relay log has been reset. To get the full Position, we need to take a union of executed GTIDSets, since these would - // have been in the relay log's GTIDSet in the past, prior to a reset. - status.RelayLogPosition.GTIDSet = status.Position.GTIDSet.Union(relayLogGTIDSet) - - return status, nil + return replication.ParseMysqlReplicationStatus(resultMap) } // primaryStatus is part of the Flavor interface. -func (mysqlFlavor) primaryStatus(c *Conn) (PrimaryStatus, error) { +func (mysqlFlavor) primaryStatus(c *Conn) (replication.PrimaryStatus, error) { qr, err := c.ExecuteFetch("SHOW MASTER STATUS", 100, true /* wantfields */) if err != nil { - return PrimaryStatus{}, err + return replication.PrimaryStatus{}, err } if len(qr.Rows) == 0 { // The query returned no data. We don't know how this could happen. - return PrimaryStatus{}, ErrNoPrimaryStatus + return replication.PrimaryStatus{}, ErrNoPrimaryStatus } resultMap, err := resultToMap(qr) if err != nil { - return PrimaryStatus{}, err + return replication.PrimaryStatus{}, err } - return parseMysqlPrimaryStatus(resultMap) + return replication.ParseMysqlPrimaryStatus(resultMap) } -func parseMysqlPrimaryStatus(resultMap map[string]string) (PrimaryStatus, error) { - status := parsePrimaryStatus(resultMap) - - var err error - status.Position.GTIDSet, err = ParseMysql56GTIDSet(resultMap["Executed_Gtid_Set"]) - if err != nil { - return PrimaryStatus{}, vterrors.Wrapf(err, "PrimaryStatus can't parse MySQL 5.6 GTID (Executed_Gtid_Set: %#v)", resultMap["Executed_Gtid_Set"]) - } - - return status, nil -} - -// waitUntilPositionCommand is part of the Flavor interface. - // waitUntilPositionCommand is part of the Flavor interface. -func (mysqlFlavor) waitUntilPositionCommand(ctx context.Context, pos Position) (string, error) { +func (mysqlFlavor) waitUntilPositionCommand(ctx context.Context, pos replication.Position) (string, error) { // A timeout of 0 means wait indefinitely. timeoutSeconds := 0 if deadline, ok := ctx.Deadline(); ok { @@ -285,7 +245,7 @@ func (mysqlFlavor) readBinlogEvent(c *Conn) (BinlogEvent, error) { } switch result[0] { case EOFPacket: - return nil, NewSQLError(CRServerLost, SSUnknownSQLState, "%v", io.EOF) + return nil, sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", io.EOF) case ErrPacket: return nil, ParseErrorPacket(result) } diff --git a/go/mysql/flavor_mysql_test.go b/go/mysql/flavor_mysql_test.go index 75d6a3ebc65..0e1b749633a 100644 --- a/go/mysql/flavor_mysql_test.go +++ b/go/mysql/flavor_mysql_test.go @@ -20,7 +20,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) func TestMysql56SetReplicationSourceCommand(t *testing.T) { @@ -76,74 +75,3 @@ func TestMysql56SetReplicationSourceCommandSSL(t *testing.T) { assert.Equal(t, want, got, "mysqlFlavor.SetReplicationSourceCommand(%#v, %#v, %#v, %#v) = %#v, want %#v", params, host, port, connectRetry, got, want) } - -func TestMysqlRetrieveSourceServerId(t *testing.T) { - resultMap := map[string]string{ - "Master_Server_Id": "1", - } - - want := ReplicationStatus{SourceServerID: 1} - got, err := parseMysqlReplicationStatus(resultMap) - require.NoError(t, err) - assert.Equalf(t, got.SourceServerID, want.SourceServerID, "got SourceServerID: %v; want SourceServerID: %v", got.SourceServerID, want.SourceServerID) -} - -func TestMysqlRetrieveFileBasedPositions(t *testing.T) { - resultMap := map[string]string{ - "Exec_Master_Log_Pos": "1307", - "Relay_Master_Log_File": "master-bin.000002", - "Read_Master_Log_Pos": "1308", - "Master_Log_File": "master-bin.000003", - "Relay_Log_Pos": "1309", - "Relay_Log_File": "relay-bin.000004", - } - - want := ReplicationStatus{ - FilePosition: Position{GTIDSet: filePosGTID{file: "master-bin.000002", pos: 1307}}, - RelayLogSourceBinlogEquivalentPosition: Position{GTIDSet: filePosGTID{file: "master-bin.000003", pos: 1308}}, - RelayLogFilePosition: Position{GTIDSet: filePosGTID{file: "relay-bin.000004", pos: 1309}}, - } - got, err := parseMysqlReplicationStatus(resultMap) - require.NoError(t, err) - assert.Equalf(t, got.FilePosition.GTIDSet, want.FilePosition.GTIDSet, "got FilePosition: %v; want FilePosition: %v", got.FilePosition.GTIDSet, want.FilePosition.GTIDSet) - assert.Equalf(t, got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet, "got RelayLogFilePosition: %v; want RelayLogFilePosition: %v", got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet) - assert.Equalf(t, got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet, "got RelayLogSourceBinlogEquivalentPosition: %v; want RelayLogSourceBinlogEquivalentPosition: %v", got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet) -} - -func TestMysqlShouldGetRelayLogPosition(t *testing.T) { - resultMap := map[string]string{ - "Executed_Gtid_Set": "3e11fa47-71ca-11e1-9e33-c80aa9429562:1-5", - "Retrieved_Gtid_Set": "3e11fa47-71ca-11e1-9e33-c80aa9429562:6-9", - "Exec_Master_Log_Pos": "1307", - "Relay_Master_Log_File": "master-bin.000002", - "Read_Master_Log_Pos": "1308", - "Master_Log_File": "master-bin.000003", - } - - sid, _ := ParseSID("3e11fa47-71ca-11e1-9e33-c80aa9429562") - want := ReplicationStatus{ - Position: Position{GTIDSet: Mysql56GTIDSet{sid: []interval{{start: 1, end: 5}}}}, - RelayLogPosition: Position{GTIDSet: Mysql56GTIDSet{sid: []interval{{start: 1, end: 9}}}}, - } - got, err := parseMysqlReplicationStatus(resultMap) - require.NoError(t, err) - assert.Equalf(t, got.RelayLogPosition.GTIDSet.String(), want.RelayLogPosition.GTIDSet.String(), "got RelayLogPosition: %v; want RelayLogPosition: %v", got.RelayLogPosition.GTIDSet, want.RelayLogPosition.GTIDSet) -} - -func TestMysqlShouldGetPosition(t *testing.T) { - resultMap := map[string]string{ - "Executed_Gtid_Set": "3e11fa47-71ca-11e1-9e33-c80aa9429562:1-5", - "Position": "1307", - "File": "source-bin.000003", - } - - sid, _ := ParseSID("3e11fa47-71ca-11e1-9e33-c80aa9429562") - want := PrimaryStatus{ - Position: Position{GTIDSet: Mysql56GTIDSet{sid: []interval{{start: 1, end: 5}}}}, - FilePosition: Position{GTIDSet: filePosGTID{file: "source-bin.000003", pos: 1307}}, - } - got, err := parseMysqlPrimaryStatus(resultMap) - require.NoError(t, err) - assert.Equalf(t, got.Position.GTIDSet.String(), want.Position.GTIDSet.String(), "got Position: %v; want Position: %v", got.Position.GTIDSet, want.Position.GTIDSet) - assert.Equalf(t, got.FilePosition.GTIDSet.String(), want.FilePosition.GTIDSet.String(), "got FilePosition: %v; want FilePosition: %v", got.FilePosition.GTIDSet, want.FilePosition.GTIDSet) -} diff --git a/go/mysql/flavor_mysqlgr.go b/go/mysql/flavor_mysqlgr.go index 33bd1e6e3e1..e96a6433f73 100644 --- a/go/mysql/flavor_mysqlgr.go +++ b/go/mysql/flavor_mysqlgr.go @@ -21,6 +21,7 @@ import ( "fmt" "math" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" @@ -57,12 +58,12 @@ func (mysqlGRFlavor) restartReplicationCommands() []string { } // startReplicationUntilAfter is disabled in mysqlGRFlavor -func (mysqlGRFlavor) startReplicationUntilAfter(pos Position) string { +func (mysqlGRFlavor) startReplicationUntilAfter(pos replication.Position) string { return "" } // startSQLThreadUntilAfter is disabled in mysqlGRFlavor -func (mysqlGRFlavor) startSQLThreadUntilAfter(pos Position) string { +func (mysqlGRFlavor) startSQLThreadUntilAfter(pos replication.Position) string { return "" } @@ -99,7 +100,7 @@ func (mysqlGRFlavor) resetReplicationParametersCommands(c *Conn) []string { } // setReplicationPositionCommands is disabled in mysqlGRFlavor -func (mysqlGRFlavor) setReplicationPositionCommands(pos Position) []string { +func (mysqlGRFlavor) setReplicationPositionCommands(pos replication.Position) []string { return []string{} } @@ -110,8 +111,8 @@ func (mysqlGRFlavor) setReplicationPositionCommands(pos Position) []string { // TODO: Right now the GR's lag is defined as the lag between a node processing a txn // and the time the txn was committed. We should consider reporting lag between current queueing txn timestamp // from replication_connection_status and the current processing txn's commit timestamp -func (mysqlGRFlavor) status(c *Conn) (ReplicationStatus, error) { - res := ReplicationStatus{} +func (mysqlGRFlavor) status(c *Conn) (replication.ReplicationStatus, error) { + res := replication.ReplicationStatus{} // Get primary node information query := `SELECT MEMBER_HOST, @@ -125,7 +126,7 @@ func (mysqlGRFlavor) status(c *Conn) (ReplicationStatus, error) { return nil }) if err != nil { - return ReplicationStatus{}, err + return replication.ReplicationStatus{}, err } query = `SELECT @@ -148,7 +149,7 @@ func (mysqlGRFlavor) status(c *Conn) (ReplicationStatus, error) { return nil }) if err != nil { - return ReplicationStatus{}, err + return replication.ReplicationStatus{}, err } // if chanel is not set, it means the state is not ONLINE or RECOVERING // return partial result early @@ -160,26 +161,26 @@ func (mysqlGRFlavor) status(c *Conn) (ReplicationStatus, error) { query = fmt.Sprintf(`SELECT SERVICE_STATE FROM performance_schema.replication_connection_status WHERE CHANNEL_NAME='%s'`, chanel) - var connectionState ReplicationState + var connectionState replication.ReplicationState err = fetchStatusForGroupReplication(c, query, func(values []sqltypes.Value) error { - connectionState = ReplicationStatusToState(values[0].ToString()) + connectionState = replication.ReplicationStatusToState(values[0].ToString()) return nil }) if err != nil { - return ReplicationStatus{}, err + return replication.ReplicationStatus{}, err } res.IOState = connectionState // Populate SQLState from replication_connection_status - var applierState ReplicationState + var applierState replication.ReplicationState query = fmt.Sprintf(`SELECT SERVICE_STATE FROM performance_schema.replication_applier_status_by_coordinator WHERE CHANNEL_NAME='%s'`, chanel) err = fetchStatusForGroupReplication(c, query, func(values []sqltypes.Value) error { - applierState = ReplicationStatusToState(values[0].ToString()) + applierState = replication.ReplicationStatusToState(values[0].ToString()) return nil }) if err != nil { - return ReplicationStatus{}, err + return replication.ReplicationStatus{}, err } res.SQLState = applierState @@ -197,17 +198,17 @@ func (mysqlGRFlavor) status(c *Conn) (ReplicationStatus, error) { return nil }) if err != nil { - return ReplicationStatus{}, err + return replication.ReplicationStatus{}, err } return res, nil } -func parsePrimaryGroupMember(res *ReplicationStatus, row []sqltypes.Value) { +func parsePrimaryGroupMember(res *replication.ReplicationStatus, row []sqltypes.Value) { res.SourceHost = row[0].ToString() /* MEMBER_HOST */ res.SourcePort, _ = row[1].ToInt32() /* MEMBER_PORT */ } -func parseReplicationApplierLag(res *ReplicationStatus, row []sqltypes.Value) { +func parseReplicationApplierLag(res *replication.ReplicationStatus, row []sqltypes.Value) { lagSec, err := row[0].ToUint32() // if the error is not nil, ReplicationLagSeconds will remain to be MaxUint32 if err == nil { @@ -234,7 +235,7 @@ func fetchStatusForGroupReplication(c *Conn, query string, onResult func([]sqlty // primaryStatus returns the result of 'SHOW MASTER STATUS', // with parsed executed position. -func (mysqlGRFlavor) primaryStatus(c *Conn) (PrimaryStatus, error) { +func (mysqlGRFlavor) primaryStatus(c *Conn) (replication.PrimaryStatus, error) { return mysqlFlavor{}.primaryStatus(c) } diff --git a/go/mysql/flavor_mysqlgr_test.go b/go/mysql/flavor_mysqlgr_test.go index 6b15ee5048e..df7876eca1c 100644 --- a/go/mysql/flavor_mysqlgr_test.go +++ b/go/mysql/flavor_mysqlgr_test.go @@ -20,12 +20,14 @@ import ( "gotest.tools/assert" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" ) func TestMysqlGRParsePrimaryGroupMember(t *testing.T) { - res := ReplicationStatus{} + res := replication.ReplicationStatus{} rows := []sqltypes.Value{ sqltypes.MakeTrusted(querypb.Type_VARCHAR, []byte("host1")), sqltypes.MakeTrusted(querypb.Type_INT32, []byte("10")), @@ -33,12 +35,12 @@ func TestMysqlGRParsePrimaryGroupMember(t *testing.T) { parsePrimaryGroupMember(&res, rows) assert.Equal(t, "host1", res.SourceHost) assert.Equal(t, int32(10), res.SourcePort) - assert.Equal(t, ReplicationStateUnknown, res.IOState) - assert.Equal(t, ReplicationStateUnknown, res.SQLState) + assert.Equal(t, replication.ReplicationStateUnknown, res.IOState) + assert.Equal(t, replication.ReplicationStateUnknown, res.SQLState) } func TestMysqlGRReplicationApplierLagParse(t *testing.T) { - res := ReplicationStatus{} + res := replication.ReplicationStatus{} row := []sqltypes.Value{ sqltypes.MakeTrusted(querypb.Type_INT32, []byte("NULL")), } diff --git a/go/mysql/query.go b/go/mysql/query.go index 8a4291bc85f..7cfeafd258f 100644 --- a/go/mysql/query.go +++ b/go/mysql/query.go @@ -23,6 +23,7 @@ import ( "strings" "vitess.io/vitess/go/mysql/collations" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" @@ -48,7 +49,7 @@ func (c *Conn) WriteComQuery(query string) error { pos++ copy(data[pos:], query) if err := c.writeEphemeralPacket(); err != nil { - return NewSQLError(CRServerGone, SSUnknownSQLState, err.Error()) + return sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSUnknownSQLState, err.Error()) } return nil } @@ -62,7 +63,7 @@ func (c *Conn) writeComInitDB(db string) error { pos++ copy(data[pos:], db) if err := c.writeEphemeralPacket(); err != nil { - return NewSQLError(CRServerGone, SSUnknownSQLState, err.Error()) + return sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSUnknownSQLState, err.Error()) } return nil } @@ -75,7 +76,7 @@ func (c *Conn) writeComSetOption(operation uint16) error { pos++ writeUint16(data, pos, operation) if err := c.writeEphemeralPacket(); err != nil { - return NewSQLError(CRServerGone, SSUnknownSQLState, err.Error()) + return sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSUnknownSQLState, err.Error()) } return nil } @@ -85,36 +86,36 @@ func (c *Conn) writeComSetOption(operation uint16) error { func (c *Conn) readColumnDefinition(field *querypb.Field, index int) error { colDef, err := c.readEphemeralPacket() if err != nil { - return NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } defer c.recycleReadPacket() // Catalog is ignored, always set to "def" pos, ok := skipLenEncString(colDef, 0) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "skipping col %v catalog failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "skipping col %v catalog failed", index) } // schema, table, orgTable, name and OrgName are strings. field.Database, pos, ok = readLenEncString(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v schema failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v schema failed", index) } field.Table, pos, ok = readLenEncString(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v table failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v table failed", index) } field.OrgTable, pos, ok = readLenEncString(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v org_table failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v org_table failed", index) } field.Name, pos, ok = readLenEncString(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v name failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v name failed", index) } field.OrgName, pos, ok = readLenEncString(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v org_name failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v org_name failed", index) } // Skip length of fixed-length fields. @@ -123,37 +124,37 @@ func (c *Conn) readColumnDefinition(field *querypb.Field, index int) error { // characterSet is a uint16. characterSet, pos, ok := readUint16(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v characterSet failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v characterSet failed", index) } field.Charset = uint32(characterSet) // columnLength is a uint32. field.ColumnLength, pos, ok = readUint32(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v columnLength failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v columnLength failed", index) } // type is one byte. t, pos, ok := readByte(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v type failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v type failed", index) } // flags is 2 bytes. flags, pos, ok := readUint16(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v flags failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v flags failed", index) } // Convert MySQL type to Vitess type. field.Type, err = sqltypes.MySQLToType(int64(t), int64(flags)) if err != nil { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "MySQLToType(%v,%v) failed for column %v: %v", t, flags, index, err) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "MySQLToType(%v,%v) failed for column %v: %v", t, flags, index, err) } // Decimals is a byte. decimals, _, ok := readByte(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v decimals failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v decimals failed", index) } field.Decimals = uint32(decimals) @@ -183,7 +184,7 @@ func (c *Conn) readColumnDefinition(field *querypb.Field, index int) error { func (c *Conn) readColumnDefinitionType(field *querypb.Field, index int) error { colDef, err := c.readEphemeralPacket() if err != nil { - return NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } defer c.recycleReadPacket() @@ -191,27 +192,27 @@ func (c *Conn) readColumnDefinitionType(field *querypb.Field, index int) error { // strings, all skipped. pos, ok := skipLenEncString(colDef, 0) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "skipping col %v catalog failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "skipping col %v catalog failed", index) } pos, ok = skipLenEncString(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "skipping col %v schema failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "skipping col %v schema failed", index) } pos, ok = skipLenEncString(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "skipping col %v table failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "skipping col %v table failed", index) } pos, ok = skipLenEncString(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "skipping col %v org_table failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "skipping col %v org_table failed", index) } pos, ok = skipLenEncString(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "skipping col %v name failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "skipping col %v name failed", index) } pos, ok = skipLenEncString(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "skipping col %v org_name failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "skipping col %v org_name failed", index) } // Skip length of fixed-length fields. @@ -220,31 +221,31 @@ func (c *Conn) readColumnDefinitionType(field *querypb.Field, index int) error { // characterSet is a uint16. _, pos, ok = readUint16(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v characterSet failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v characterSet failed", index) } // columnLength is a uint32. _, pos, ok = readUint32(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v columnLength failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v columnLength failed", index) } // type is one byte t, pos, ok := readByte(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v type failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v type failed", index) } // flags is 2 bytes flags, _, ok := readUint16(colDef, pos) if !ok { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v flags failed", index) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extracting col %v flags failed", index) } // Convert MySQL type to Vitess type. field.Type, err = sqltypes.MySQLToType(int64(t), int64(flags)) if err != nil { - return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "MySQLToType(%v,%v) failed for column %v: %v", t, flags, index, err) + return sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "MySQLToType(%v,%v) failed for column %v: %v", t, flags, index, err) } // skip decimals @@ -270,7 +271,7 @@ func (c *Conn) parseRow(data []byte, fields []*querypb.Field, reader func([]byte var ok bool s, pos, ok = reader(data, pos) if !ok { - return nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "decoding string failed") + return nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "decoding string failed") } result = append(result, sqltypes.MakeTrusted(fields[i].Type, s)) } @@ -311,7 +312,7 @@ func (c *Conn) ExecuteFetch(query string, maxrows int, wantfields bool) (result func (c *Conn) ExecuteFetchMulti(query string, maxrows int, wantfields bool) (result *sqltypes.Result, more bool, err error) { defer func() { if err != nil { - if sqlerr, ok := err.(*SQLError); ok { + if sqlerr, ok := err.(*sqlerror.SQLError); ok { sqlerr.Query = query } } @@ -335,7 +336,7 @@ func (c *Conn) ExecuteFetchMulti(query string, maxrows int, wantfields bool) (re func (c *Conn) ExecuteFetchWithWarningCount(query string, maxrows int, wantfields bool) (result *sqltypes.Result, warnings uint16, err error) { defer func() { if err != nil { - if sqlerr, ok := err.(*SQLError); ok { + if sqlerr, ok := err.(*sqlerror.SQLError); ok { sqlerr.Query = query } } @@ -395,7 +396,7 @@ func (c *Conn) ReadQueryResult(maxrows int, wantfields bool) (*sqltypes.Result, // EOF is only present here if it's not deprecated. data, err := c.readEphemeralPacket() if err != nil { - return nil, false, 0, NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return nil, false, 0, sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } if c.isEOFPacket(data) { @@ -417,7 +418,7 @@ func (c *Conn) ReadQueryResult(maxrows int, wantfields bool) (*sqltypes.Result, for { data, err := c.readEphemeralPacket() if err != nil { - return nil, false, 0, NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return nil, false, 0, sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } if c.isEOFPacket(data) { @@ -482,7 +483,7 @@ func (c *Conn) drainResults() error { for { data, err := c.readEphemeralPacket() if err != nil { - return NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } if c.isEOFPacket(data) { c.recycleReadPacket() @@ -498,11 +499,11 @@ func (c *Conn) drainResults() error { func (c *Conn) readComQueryResponse() (int, *PacketOK, error) { data, err := c.readEphemeralPacket() if err != nil { - return 0, nil, NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return 0, nil, sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } defer c.recycleReadPacket() if len(data) == 0 { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "invalid empty COM_QUERY response packet") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "invalid empty COM_QUERY response packet") } switch data[0] { @@ -518,10 +519,10 @@ func (c *Conn) readComQueryResponse() (int, *PacketOK, error) { } n, pos, ok := readLenEncInt(data, 0) if !ok { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "cannot get column number") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "cannot get column number") } if pos != len(data) { - return 0, nil, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extra data in COM_QUERY response") + return 0, nil, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "extra data in COM_QUERY response") } return int(n), &PacketOK{}, nil } @@ -551,32 +552,32 @@ func (c *Conn) parseComStmtExecute(prepareData map[uint32]*PrepareData, data []b // statement ID stmtID, pos, ok := readUint32(payload, 0) if !ok { - return 0, 0, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "reading statement ID failed") + return 0, 0, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "reading statement ID failed") } prepare, ok := prepareData[stmtID] if !ok { - return 0, 0, NewSQLError(CRCommandsOutOfSync, SSUnknownSQLState, "statement ID is not found from record") + return 0, 0, sqlerror.NewSQLError(sqlerror.CRCommandsOutOfSync, sqlerror.SSUnknownSQLState, "statement ID is not found from record") } // cursor type flags cursorType, pos, ok := readByte(payload, pos) if !ok { - return stmtID, 0, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "reading cursor type flags failed") + return stmtID, 0, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "reading cursor type flags failed") } // iteration count iterCount, pos, ok := readUint32(payload, pos) if !ok { - return stmtID, 0, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "reading iteration count failed") + return stmtID, 0, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "reading iteration count failed") } if iterCount != uint32(1) { - return stmtID, 0, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "iteration count is not equal to 1") + return stmtID, 0, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "iteration count is not equal to 1") } if prepare.ParamsCount > 0 { bitMap, pos, ok = readBytes(payload, pos, (int(prepare.ParamsCount)+7)/8) if !ok { - return stmtID, 0, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "reading NULL-bitmap failed") + return stmtID, 0, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "reading NULL-bitmap failed") } } @@ -586,18 +587,18 @@ func (c *Conn) parseComStmtExecute(prepareData map[uint32]*PrepareData, data []b for i := uint16(0); i < prepare.ParamsCount; i++ { mysqlType, pos, ok = readByte(payload, pos) if !ok { - return stmtID, 0, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "reading parameter type failed") + return stmtID, 0, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "reading parameter type failed") } flags, pos, ok = readByte(payload, pos) if !ok { - return stmtID, 0, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "reading parameter flags failed") + return stmtID, 0, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "reading parameter flags failed") } // convert MySQL type to internal type. valType, err := sqltypes.MySQLToType(int64(mysqlType), int64(flags)) if err != nil { - return stmtID, 0, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "MySQLToType(%v,%v) failed: %v", mysqlType, flags, err) + return stmtID, 0, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "MySQLToType(%v,%v) failed: %v", mysqlType, flags, err) } prepare.ParamsType[i] = int32(valType) @@ -619,7 +620,7 @@ func (c *Conn) parseComStmtExecute(prepareData map[uint32]*PrepareData, data []b val, pos, ok = c.parseStmtArgs(payload, querypb.Type(prepare.ParamsType[i]), pos) } if !ok { - return stmtID, 0, NewSQLError(CRMalformedPacket, SSUnknownSQLState, "decoding parameter value failed: %v", prepare.ParamsType[i]) + return stmtID, 0, sqlerror.NewSQLError(sqlerror.CRMalformedPacket, sqlerror.SSUnknownSQLState, "decoding parameter value failed: %v", prepare.ParamsType[i]) } prepare.BindVars[parameterID] = sqltypes.ValueBindVariable(val) diff --git a/go/mysql/query_test.go b/go/mysql/query_test.go index bf902b5165f..07012f83b9f 100644 --- a/go/mysql/query_test.go +++ b/go/mysql/query_test.go @@ -24,6 +24,8 @@ import ( "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql/collations" "github.com/stretchr/testify/assert" @@ -378,7 +380,7 @@ func TestSQLErrorOnServerClose(t *testing.T) { // We should be getting a Connection lost error. _, _, _, err = cConn.ReadQueryResult(100, true) require.Error(t, err) - require.True(t, IsConnLostDuringQuery(err), err.Error()) + require.True(t, sqlerror.IsConnLostDuringQuery(err), err.Error()) } func TestQueries(t *testing.T) { diff --git a/go/mysql/replication.go b/go/mysql/replication.go index 33f24860266..399698d6a2a 100644 --- a/go/mysql/replication.go +++ b/go/mysql/replication.go @@ -17,6 +17,7 @@ limitations under the License. package mysql import ( + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" ) @@ -45,7 +46,7 @@ func (c *Conn) WriteComBinlogDump(serverID uint32, binlogFilename string, binlog pos = writeUint32(data, pos, serverID) _ = writeEOFString(data, pos, binlogFilename) if err := c.writeEphemeralPacket(); err != nil { - return NewSQLError(CRServerGone, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSUnknownSQLState, "%v", err) } return nil } @@ -92,7 +93,7 @@ func (c *Conn) WriteComBinlogDumpGTID(serverID uint32, binlogFilename string, bi pos = writeUint32(data, pos, uint32(len(gtidSet))) //nolint pos += copy(data[pos:], gtidSet) //nolint if err := c.writeEphemeralPacket(); err != nil { - return NewSQLError(CRServerGone, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSUnknownSQLState, "%v", err) } return nil } @@ -110,7 +111,7 @@ func (c *Conn) SendSemiSyncAck(binlogFilename string, binlogPos uint64) error { pos = writeUint64(data, pos, binlogPos) _ = writeEOFString(data, pos, binlogFilename) if err := c.writeEphemeralPacket(); err != nil { - return NewSQLError(CRServerGone, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSUnknownSQLState, "%v", err) } return nil @@ -132,7 +133,7 @@ func (c *Conn) WriteBinlogEvent(ev BinlogEvent, semiSyncEnabled bool) error { } _ = writeEOFString(data, pos, string(ev.Bytes())) if err := c.writeEphemeralPacket(); err != nil { - return NewSQLError(CRServerGone, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSUnknownSQLState, "%v", err) } return nil } diff --git a/go/mysql/filepos_gtid.go b/go/mysql/replication/filepos_gtid.go similarity index 68% rename from go/mysql/filepos_gtid.go rename to go/mysql/replication/filepos_gtid.go index e5bfd055bee..850fb421915 100644 --- a/go/mysql/filepos_gtid.go +++ b/go/mysql/replication/filepos_gtid.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "fmt" @@ -38,9 +38,9 @@ func parseFilePosGTID(s string) (GTID, error) { return nil, fmt.Errorf("invalid FilePos GTID (%v): expecting pos to be an integer", s) } - return filePosGTID{ - file: parts[0], - pos: uint32(pos), + return FilePosGTID{ + File: parts[0], + Pos: uint32(pos), }, nil } @@ -50,69 +50,69 @@ func ParseFilePosGTIDSet(s string) (GTIDSet, error) { if err != nil { return nil, err } - return gtid.(filePosGTID), err + return gtid.(FilePosGTID), err } -// filePosGTID implements GTID. -type filePosGTID struct { - file string - pos uint32 +// FilePosGTID implements GTID. +type FilePosGTID struct { + File string + Pos uint32 } // String implements GTID.String(). -func (gtid filePosGTID) String() string { - return fmt.Sprintf("%s:%d", gtid.file, gtid.pos) +func (gtid FilePosGTID) String() string { + return fmt.Sprintf("%s:%d", gtid.File, gtid.Pos) } // Flavor implements GTID.Flavor(). -func (gtid filePosGTID) Flavor() string { +func (gtid FilePosGTID) Flavor() string { return FilePosFlavorID } // SequenceDomain implements GTID.SequenceDomain(). -func (gtid filePosGTID) SequenceDomain() any { +func (gtid FilePosGTID) SequenceDomain() any { return nil } // SourceServer implements GTID.SourceServer(). -func (gtid filePosGTID) SourceServer() any { +func (gtid FilePosGTID) SourceServer() any { return nil } // SequenceNumber implements GTID.SequenceNumber(). -func (gtid filePosGTID) SequenceNumber() any { +func (gtid FilePosGTID) SequenceNumber() any { return nil } // GTIDSet implements GTID.GTIDSet(). -func (gtid filePosGTID) GTIDSet() GTIDSet { +func (gtid FilePosGTID) GTIDSet() GTIDSet { return gtid } // ContainsGTID implements GTIDSet.ContainsGTID(). -func (gtid filePosGTID) ContainsGTID(other GTID) bool { +func (gtid FilePosGTID) ContainsGTID(other GTID) bool { if other == nil { return true } - filePosOther, ok := other.(filePosGTID) + filePosOther, ok := other.(FilePosGTID) if !ok { return false } - if filePosOther.file < gtid.file { + if filePosOther.File < gtid.File { return true } - if filePosOther.file > gtid.file { + if filePosOther.File > gtid.File { return false } - return filePosOther.pos <= gtid.pos + return filePosOther.Pos <= gtid.Pos } // Contains implements GTIDSet.Contains(). -func (gtid filePosGTID) Contains(other GTIDSet) bool { +func (gtid FilePosGTID) Contains(other GTIDSet) bool { if other == nil { return false } - filePosOther, ok := other.(filePosGTID) + filePosOther, ok := other.(FilePosGTID) if !ok { return false } @@ -120,8 +120,8 @@ func (gtid filePosGTID) Contains(other GTIDSet) bool { } // Equal implements GTIDSet.Equal(). -func (gtid filePosGTID) Equal(other GTIDSet) bool { - filePosOther, ok := other.(filePosGTID) +func (gtid FilePosGTID) Equal(other GTIDSet) bool { + filePosOther, ok := other.(FilePosGTID) if !ok { return false } @@ -129,8 +129,8 @@ func (gtid filePosGTID) Equal(other GTIDSet) bool { } // AddGTID implements GTIDSet.AddGTID(). -func (gtid filePosGTID) AddGTID(other GTID) GTIDSet { - filePosOther, ok := other.(filePosGTID) +func (gtid FilePosGTID) AddGTID(other GTID) GTIDSet { + filePosOther, ok := other.(FilePosGTID) if !ok { return gtid } @@ -138,8 +138,8 @@ func (gtid filePosGTID) AddGTID(other GTID) GTIDSet { } // Union implements GTIDSet.Union(). -func (gtid filePosGTID) Union(other GTIDSet) GTIDSet { - filePosOther, ok := other.(filePosGTID) +func (gtid FilePosGTID) Union(other GTIDSet) GTIDSet { + filePosOther, ok := other.(FilePosGTID) if !ok || gtid.Contains(other) { return gtid } @@ -150,12 +150,11 @@ func (gtid filePosGTID) Union(other GTIDSet) GTIDSet { // Last returns last filePosition // For filePos based GTID we have only one position // here we will just return the current filePos -func (gtid filePosGTID) Last() string { +func (gtid FilePosGTID) Last() string { return gtid.String() } func init() { gtidParsers[FilePosFlavorID] = parseFilePosGTID gtidSetParsers[FilePosFlavorID] = ParseFilePosGTIDSet - flavors[FilePosFlavorID] = newFilePosFlavor } diff --git a/go/mysql/filepos_gtid_test.go b/go/mysql/replication/filepos_gtid_test.go similarity index 77% rename from go/mysql/filepos_gtid_test.go rename to go/mysql/replication/filepos_gtid_test.go index ec7f9d33142..174aed6ccf9 100644 --- a/go/mysql/filepos_gtid_test.go +++ b/go/mysql/replication/filepos_gtid_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "testing" @@ -38,12 +38,12 @@ func Test_filePosGTID_String(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gtid := filePosGTID{ - file: tt.fields.file, - pos: tt.fields.pos, + gtid := FilePosGTID{ + File: tt.fields.file, + Pos: tt.fields.pos, } if got := gtid.String(); got != tt.want { - t.Errorf("filePosGTID.String() = %v, want %v", got, tt.want) + t.Errorf("FilePosGTID.String() = %v, want %v", got, tt.want) } }) } @@ -66,36 +66,36 @@ func Test_filePosGTID_ContainsGTID(t *testing.T) { { "returns true when the position is equal", fields{file: "testfile", pos: 1234}, - args{other: filePosGTID{file: "testfile", pos: 1234}}, + args{other: FilePosGTID{File: "testfile", Pos: 1234}}, true, }, { "returns true when the position is less than equal", fields{file: "testfile", pos: 1234}, - args{other: filePosGTID{file: "testfile", pos: 1233}}, + args{other: FilePosGTID{File: "testfile", Pos: 1233}}, true, }, { "returns false when the position is less than equal", fields{file: "testfile", pos: 1234}, - args{other: filePosGTID{file: "testfile", pos: 1235}}, + args{other: FilePosGTID{File: "testfile", Pos: 1235}}, false, }, { "it uses integer value for comparison (it is not lexicographical order)", fields{file: "testfile", pos: 99761227}, - args{other: filePosGTID{file: "testfile", pos: 103939867}}, + args{other: FilePosGTID{File: "testfile", Pos: 103939867}}, false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gtid := filePosGTID{ - file: tt.fields.file, - pos: tt.fields.pos, + gtid := FilePosGTID{ + File: tt.fields.file, + Pos: tt.fields.pos, } if got := gtid.ContainsGTID(tt.args.other); got != tt.want { - t.Errorf("filePosGTID.ContainsGTID() = %v, want %v", got, tt.want) + t.Errorf("FilePosGTID.ContainsGTID() = %v, want %v", got, tt.want) } }) } diff --git a/go/mysql/gtid.go b/go/mysql/replication/gtid.go similarity index 99% rename from go/mysql/gtid.go rename to go/mysql/replication/gtid.go index d5f6a44df74..14e781a714f 100644 --- a/go/mysql/gtid.go +++ b/go/mysql/replication/gtid.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "fmt" diff --git a/go/mysql/gtid_set.go b/go/mysql/replication/gtid_set.go similarity index 99% rename from go/mysql/gtid_set.go rename to go/mysql/replication/gtid_set.go index 812b7f33caf..1e4ca29b42e 100644 --- a/go/mysql/gtid_set.go +++ b/go/mysql/replication/gtid_set.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication // GTIDSet represents the set of transactions received or applied by a server. // In some flavors, a single GTID is enough to specify the set of all diff --git a/go/mysql/gtid_test.go b/go/mysql/replication/gtid_test.go similarity index 99% rename from go/mysql/gtid_test.go rename to go/mysql/replication/gtid_test.go index 8dfea641727..8713f94b115 100644 --- a/go/mysql/gtid_test.go +++ b/go/mysql/replication/gtid_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "strings" diff --git a/go/mysql/mariadb_gtid.go b/go/mysql/replication/mariadb_gtid.go similarity index 97% rename from go/mysql/mariadb_gtid.go rename to go/mysql/replication/mariadb_gtid.go index 713ef2c72b4..ff63964bbf1 100644 --- a/go/mysql/mariadb_gtid.go +++ b/go/mysql/replication/mariadb_gtid.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "fmt" @@ -62,8 +62,8 @@ func parseMariadbGTID(s string) (GTID, error) { }, nil } -// parseMariadbGTIDSet is registered as a GTIDSet parser. -func parseMariadbGTIDSet(s string) (GTIDSet, error) { +// ParseMariadbGTIDSet is registered as a GTIDSet parser. +func ParseMariadbGTIDSet(s string) (GTIDSet, error) { gtidStrings := strings.Split(s, ",") gtidSet := make(MariadbGTIDSet, len(gtidStrings)) for _, gtidString := range gtidStrings { @@ -272,5 +272,5 @@ func (gtidSet MariadbGTIDSet) addGTID(otherGTID MariadbGTID) { func init() { gtidParsers[MariadbFlavorID] = parseMariadbGTID - gtidSetParsers[MariadbFlavorID] = parseMariadbGTIDSet + gtidSetParsers[MariadbFlavorID] = ParseMariadbGTIDSet } diff --git a/go/mysql/mariadb_gtid_test.go b/go/mysql/replication/mariadb_gtid_test.go similarity index 98% rename from go/mysql/mariadb_gtid_test.go rename to go/mysql/replication/mariadb_gtid_test.go index 49472ab8d33..3fe02b31822 100644 --- a/go/mysql/mariadb_gtid_test.go +++ b/go/mysql/replication/mariadb_gtid_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "strings" @@ -81,9 +81,9 @@ func TestParseMariaGTIDSet(t *testing.T) { 11: MariadbGTID{Domain: 11, Server: 22, Sequence: 3333}, } - got, err := parseMariadbGTIDSet(input) + got, err := ParseMariadbGTIDSet(input) assert.NoError(t, err, "%v", err) - assert.True(t, got.Equal(want), "parseMariadbGTIDSet(%#v) = %#v, want %#v", input, got, want) + assert.True(t, got.Equal(want), "ParseMariadbGTIDSet(%#v) = %#v, want %#v", input, got, want) } @@ -91,13 +91,13 @@ func TestParseInvalidMariaGTIDSet(t *testing.T) { input := "12-34-5678,11-22-33e33" want := "invalid MariaDB GTID Sequence number" - _, err := parseMariadbGTIDSet(input) + _, err := ParseMariadbGTIDSet(input) if err == nil { t.Errorf("expected error for invalid input (%#v)", input) return } if got := err.Error(); !strings.HasPrefix(got, want) { - t.Errorf("parseMariadbGTIDSet(%#v) error = %#v, want %#v", input, got, want) + t.Errorf("ParseMariadbGTIDSet(%#v) error = %#v, want %#v", input, got, want) } } @@ -621,7 +621,7 @@ func TestMariaGTIDSetLast(t *testing.T) { "12-34-5678": "12-34-5678", } for input, want := range testCases { - got, err := parseMariadbGTIDSet(input) + got, err := ParseMariadbGTIDSet(input) require.NoError(t, err) assert.Equal(t, want, got.Last()) } diff --git a/go/mysql/mysql56_gtid.go b/go/mysql/replication/mysql56_gtid.go similarity index 99% rename from go/mysql/mysql56_gtid.go rename to go/mysql/replication/mysql56_gtid.go index 0aae3d54336..4ec861b84e5 100644 --- a/go/mysql/mysql56_gtid.go +++ b/go/mysql/replication/mysql56_gtid.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "encoding/hex" diff --git a/go/mysql/mysql56_gtid_set.go b/go/mysql/replication/mysql56_gtid_set.go similarity index 99% rename from go/mysql/mysql56_gtid_set.go rename to go/mysql/replication/mysql56_gtid_set.go index 10148f41c90..e997a325e00 100644 --- a/go/mysql/mysql56_gtid_set.go +++ b/go/mysql/replication/mysql56_gtid_set.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "bytes" diff --git a/go/mysql/mysql56_gtid_set_test.go b/go/mysql/replication/mysql56_gtid_set_test.go similarity index 99% rename from go/mysql/mysql56_gtid_set_test.go rename to go/mysql/replication/mysql56_gtid_set_test.go index 03082bc736e..323baae3885 100644 --- a/go/mysql/mysql56_gtid_set_test.go +++ b/go/mysql/replication/mysql56_gtid_set_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "fmt" diff --git a/go/mysql/mysql56_gtid_test.go b/go/mysql/replication/mysql56_gtid_test.go similarity index 90% rename from go/mysql/mysql56_gtid_test.go rename to go/mysql/replication/mysql56_gtid_test.go index 335835d8199..7a4bc9862a8 100644 --- a/go/mysql/mysql56_gtid_test.go +++ b/go/mysql/replication/mysql56_gtid_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "strings" @@ -141,3 +141,15 @@ func TestMysql56GTIDGTIDSet(t *testing.T) { t.Errorf("%#v.GTIDSet() = %#v, want %#v", input, got, want) } } + +func TestMysql56ParseGTID(t *testing.T) { + input := "00010203-0405-0607-0809-0A0B0C0D0E0F:56789" + want := Mysql56GTID{ + Server: SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + Sequence: 56789, + } + + got, err := parseMysql56GTID(input) + require.NoError(t, err, "unexpected error: %v", err) + assert.Equal(t, want, got, "(&mysql56{}).ParseGTID(%#v) = %#v, want %#v", input, got, want) +} diff --git a/go/mysql/primary_status.go b/go/mysql/replication/primary_status.go similarity index 53% rename from go/mysql/primary_status.go rename to go/mysql/replication/primary_status.go index e8524862917..679b152f9d4 100644 --- a/go/mysql/primary_status.go +++ b/go/mysql/replication/primary_status.go @@ -14,10 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( + "fmt" + + "vitess.io/vitess/go/vt/log" replicationdatapb "vitess.io/vitess/go/vt/proto/replicationdata" + "vitess.io/vitess/go/vt/vterrors" ) // PrimaryStatus holds replication information from SHOW MASTER STATUS. @@ -35,3 +39,32 @@ func PrimaryStatusToProto(s PrimaryStatus) *replicationdatapb.PrimaryStatus { FilePosition: EncodePosition(s.FilePosition), } } + +func ParseMysqlPrimaryStatus(resultMap map[string]string) (PrimaryStatus, error) { + status := ParsePrimaryStatus(resultMap) + + var err error + status.Position.GTIDSet, err = ParseMysql56GTIDSet(resultMap["Executed_Gtid_Set"]) + if err != nil { + return PrimaryStatus{}, vterrors.Wrapf(err, "PrimaryStatus can't parse MySQL 5.6 GTID (Executed_Gtid_Set: %#v)", resultMap["Executed_Gtid_Set"]) + } + + return status, nil +} + +// ParsePrimaryStatus parses the common fields of SHOW MASTER STATUS. +func ParsePrimaryStatus(fields map[string]string) PrimaryStatus { + status := PrimaryStatus{} + + fileExecPosStr := fields["Position"] + file := fields["File"] + if file != "" && fileExecPosStr != "" { + var err error + status.FilePosition.GTIDSet, err = ParseFilePosGTIDSet(fmt.Sprintf("%s:%s", file, fileExecPosStr)) + if err != nil { + log.Warningf("Error parsing GTID set %s:%s: %v", file, fileExecPosStr, err) + } + } + + return status +} diff --git a/go/mysql/replication_position.go b/go/mysql/replication/replication_position.go similarity index 99% rename from go/mysql/replication_position.go rename to go/mysql/replication/replication_position.go index d8b296a2484..240321f2c6f 100644 --- a/go/mysql/replication_position.go +++ b/go/mysql/replication/replication_position.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "encoding/json" @@ -209,7 +209,7 @@ func (rp *Position) MatchesFlavor(flavor string) bool { _, matches := rp.GTIDSet.(MariadbGTIDSet) return matches case FilePosFlavorID: - _, matches := rp.GTIDSet.(filePosGTID) + _, matches := rp.GTIDSet.(FilePosGTID) return matches } return false diff --git a/go/mysql/replication_position_test.go b/go/mysql/replication/replication_position_test.go similarity index 99% rename from go/mysql/replication_position_test.go rename to go/mysql/replication/replication_position_test.go index 721fb166dac..125f5929bbe 100644 --- a/go/mysql/replication_position_test.go +++ b/go/mysql/replication/replication_position_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "encoding/json" diff --git a/go/mysql/replication_status.go b/go/mysql/replication/replication_status.go similarity index 63% rename from go/mysql/replication_status.go rename to go/mysql/replication/replication_status.go index ff06d559a56..6b3d1bf2214 100644 --- a/go/mysql/replication_status.go +++ b/go/mysql/replication/replication_status.go @@ -14,11 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package replication import ( "fmt" + "strconv" + "vitess.io/vitess/go/vt/log" replicationdatapb "vitess.io/vitess/go/vt/proto/replicationdata" "vitess.io/vitess/go/vt/vterrors" ) @@ -219,3 +221,124 @@ func (s *ReplicationStatus) FindErrantGTIDs(otherReplicaStatuses []*ReplicationS return diffSet, nil } + +func ParseMysqlReplicationStatus(resultMap map[string]string) (ReplicationStatus, error) { + status := ParseReplicationStatus(resultMap) + uuidString := resultMap["Master_UUID"] + if uuidString != "" { + sid, err := ParseSID(uuidString) + if err != nil { + return ReplicationStatus{}, vterrors.Wrapf(err, "cannot decode SourceUUID") + } + status.SourceUUID = sid + } + + var err error + status.Position.GTIDSet, err = ParseMysql56GTIDSet(resultMap["Executed_Gtid_Set"]) + if err != nil { + return ReplicationStatus{}, vterrors.Wrapf(err, "ReplicationStatus can't parse MySQL 5.6 GTID (Executed_Gtid_Set: %#v)", resultMap["Executed_Gtid_Set"]) + } + relayLogGTIDSet, err := ParseMysql56GTIDSet(resultMap["Retrieved_Gtid_Set"]) + if err != nil { + return ReplicationStatus{}, vterrors.Wrapf(err, "ReplicationStatus can't parse MySQL 5.6 GTID (Retrieved_Gtid_Set: %#v)", resultMap["Retrieved_Gtid_Set"]) + } + // We take the union of the executed and retrieved gtidset, because the retrieved gtidset only represents GTIDs since + // the relay log has been reset. To get the full Position, we need to take a union of executed GTIDSets, since these would + // have been in the relay log's GTIDSet in the past, prior to a reset. + status.RelayLogPosition.GTIDSet = status.Position.GTIDSet.Union(relayLogGTIDSet) + + return status, nil +} + +func ParseMariadbReplicationStatus(resultMap map[string]string) (ReplicationStatus, error) { + status := ParseReplicationStatus(resultMap) + + var err error + status.Position.GTIDSet, err = ParseMariadbGTIDSet(resultMap["Gtid_Slave_Pos"]) + if err != nil { + return ReplicationStatus{}, vterrors.Wrapf(err, "ReplicationStatus can't parse MariaDB GTID (Gtid_Slave_Pos: %#v)", resultMap["Gtid_Slave_Pos"]) + } + + return status, nil +} + +func ParseFilePosReplicationStatus(resultMap map[string]string) (ReplicationStatus, error) { + status := ParseReplicationStatus(resultMap) + + status.Position = status.FilePosition + status.RelayLogPosition = status.RelayLogSourceBinlogEquivalentPosition + + return status, nil +} + +func ParseFilePosPrimaryStatus(resultMap map[string]string) (PrimaryStatus, error) { + status := ParsePrimaryStatus(resultMap) + + status.Position = status.FilePosition + + return status, nil +} + +// ParseReplicationStatus parses the common (non-flavor-specific) fields of ReplicationStatus +func ParseReplicationStatus(fields map[string]string) ReplicationStatus { + // The field names in the map are identical to what we receive from the database + // Hence the names still contain Master + status := ReplicationStatus{ + SourceHost: fields["Master_Host"], + SourceUser: fields["Master_User"], + SSLAllowed: fields["Master_SSL_Allowed"] == "Yes", + AutoPosition: fields["Auto_Position"] == "1", + UsingGTID: fields["Using_Gtid"] != "No" && fields["Using_Gtid"] != "", + HasReplicationFilters: (fields["Replicate_Do_DB"] != "") || (fields["Replicate_Ignore_DB"] != "") || (fields["Replicate_Do_Table"] != "") || (fields["Replicate_Ignore_Table"] != "") || (fields["Replicate_Wild_Do_Table"] != "") || (fields["Replicate_Wild_Ignore_Table"] != ""), + // These fields are returned from the underlying DB and cannot be renamed + IOState: ReplicationStatusToState(fields["Slave_IO_Running"]), + LastIOError: fields["Last_IO_Error"], + SQLState: ReplicationStatusToState(fields["Slave_SQL_Running"]), + LastSQLError: fields["Last_SQL_Error"], + } + parseInt, _ := strconv.ParseInt(fields["Master_Port"], 10, 32) + status.SourcePort = int32(parseInt) + parseInt, _ = strconv.ParseInt(fields["Connect_Retry"], 10, 32) + status.ConnectRetry = int32(parseInt) + parseUint, err := strconv.ParseUint(fields["Seconds_Behind_Master"], 10, 32) + if err != nil { + // we could not parse the value into a valid uint32 -- most commonly because the value is NULL from the + // database -- so let's reflect that the underlying value was unknown on our last check + status.ReplicationLagUnknown = true + } else { + status.ReplicationLagUnknown = false + status.ReplicationLagSeconds = uint32(parseUint) + } + parseUint, _ = strconv.ParseUint(fields["Master_Server_Id"], 10, 32) + status.SourceServerID = uint32(parseUint) + parseUint, _ = strconv.ParseUint(fields["SQL_Delay"], 10, 32) + status.SQLDelay = uint32(parseUint) + + executedPosStr := fields["Exec_Master_Log_Pos"] + file := fields["Relay_Master_Log_File"] + if file != "" && executedPosStr != "" { + status.FilePosition.GTIDSet, err = ParseFilePosGTIDSet(fmt.Sprintf("%s:%s", file, executedPosStr)) + if err != nil { + log.Warningf("Error parsing GTID set %s:%s: %v", file, executedPosStr, err) + } + } + + readPosStr := fields["Read_Master_Log_Pos"] + file = fields["Master_Log_File"] + if file != "" && readPosStr != "" { + status.RelayLogSourceBinlogEquivalentPosition.GTIDSet, err = ParseFilePosGTIDSet(fmt.Sprintf("%s:%s", file, readPosStr)) + if err != nil { + log.Warningf("Error parsing GTID set %s:%s: %v", file, readPosStr, err) + } + } + + relayPosStr := fields["Relay_Log_Pos"] + file = fields["Relay_Log_File"] + if file != "" && relayPosStr != "" { + status.RelayLogFilePosition.GTIDSet, err = ParseFilePosGTIDSet(fmt.Sprintf("%s:%s", file, relayPosStr)) + if err != nil { + log.Warningf("Error parsing GTID set %s:%s: %v", file, relayPosStr, err) + } + } + return status +} diff --git a/go/mysql/replication/replication_status_test.go b/go/mysql/replication/replication_status_test.go new file mode 100644 index 00000000000..c1f5991f253 --- /dev/null +++ b/go/mysql/replication/replication_status_test.go @@ -0,0 +1,292 @@ +/* +Copyright 2019 The Vitess Authors. + +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 replication + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestStatusReplicationRunning(t *testing.T) { + input := &ReplicationStatus{ + IOState: ReplicationStatusToState("yes"), + SQLState: ReplicationStatusToState("yes"), + } + want := true + if got := input.Running(); got != want { + t.Errorf("%#v.Running() = %v, want %v", input, got, want) + } +} + +func TestStatusIOThreadNotRunning(t *testing.T) { + input := &ReplicationStatus{ + IOState: ReplicationStatusToState("no"), + SQLState: ReplicationStatusToState("yes"), + } + want := false + if got := input.Running(); got != want { + t.Errorf("%#v.Running() = %v, want %v", input, got, want) + } +} + +func TestStatusSQLThreadNotRunning(t *testing.T) { + input := &ReplicationStatus{ + IOState: ReplicationStatusToState("yes"), + SQLState: ReplicationStatusToState("no"), + } + want := false + if got := input.Running(); got != want { + t.Errorf("%#v.Running() = %v, want %v", input, got, want) + } +} + +func TestFindErrantGTIDs(t *testing.T) { + sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16} + sid3 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17} + sid4 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 18} + sourceSID := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 19} + + set1 := Mysql56GTIDSet{ + sid1: []interval{{20, 30}, {35, 39}, {40, 53}, {55, 75}}, + sid2: []interval{{1, 7}, {20, 50}, {60, 70}}, + sid4: []interval{{1, 30}}, + sourceSID: []interval{{1, 7}, {20, 30}}, + } + + set2 := Mysql56GTIDSet{ + sid1: []interval{{20, 30}, {35, 37}, {50, 60}}, + sid2: []interval{{3, 5}, {22, 25}, {32, 37}, {67, 70}}, + sid3: []interval{{1, 45}}, + sourceSID: []interval{{2, 6}, {15, 40}}, + } + + set3 := Mysql56GTIDSet{ + sid1: []interval{{20, 30}, {35, 38}, {50, 70}}, + sid2: []interval{{3, 5}, {22, 25}, {32, 37}, {67, 70}}, + sid3: []interval{{1, 45}}, + sourceSID: []interval{{2, 6}, {15, 45}}, + } + + testcases := []struct { + mainRepStatus *ReplicationStatus + otherRepStatuses []*ReplicationStatus + want Mysql56GTIDSet + }{{ + mainRepStatus: &ReplicationStatus{SourceUUID: sourceSID, RelayLogPosition: Position{GTIDSet: set1}}, + otherRepStatuses: []*ReplicationStatus{ + {SourceUUID: sourceSID, RelayLogPosition: Position{GTIDSet: set2}}, + {SourceUUID: sourceSID, RelayLogPosition: Position{GTIDSet: set3}}, + }, + want: Mysql56GTIDSet{ + sid1: []interval{{39, 39}, {40, 49}, {71, 75}}, + sid2: []interval{{1, 2}, {6, 7}, {20, 21}, {26, 31}, {38, 50}, {60, 66}}, + sid4: []interval{{1, 30}}, + }, + }, { + mainRepStatus: &ReplicationStatus{SourceUUID: sourceSID, RelayLogPosition: Position{GTIDSet: set1}}, + otherRepStatuses: []*ReplicationStatus{{SourceUUID: sid1, RelayLogPosition: Position{GTIDSet: set1}}}, + // servers with the same GTID sets should not be diagnosed with errant GTIDs + want: nil, + }} + + for _, testcase := range testcases { + t.Run("", func(t *testing.T) { + got, err := testcase.mainRepStatus.FindErrantGTIDs(testcase.otherRepStatuses) + require.NoError(t, err) + require.Equal(t, testcase.want, got) + }) + } +} + +func TestMysqlShouldGetPosition(t *testing.T) { + resultMap := map[string]string{ + "Executed_Gtid_Set": "3e11fa47-71ca-11e1-9e33-c80aa9429562:1-5", + "Position": "1307", + "File": "source-bin.000003", + } + + sid, _ := ParseSID("3e11fa47-71ca-11e1-9e33-c80aa9429562") + want := PrimaryStatus{ + Position: Position{GTIDSet: Mysql56GTIDSet{sid: []interval{{start: 1, end: 5}}}}, + FilePosition: Position{GTIDSet: FilePosGTID{File: "source-bin.000003", Pos: 1307}}, + } + got, err := ParseMysqlPrimaryStatus(resultMap) + require.NoError(t, err) + assert.Equalf(t, got.Position.GTIDSet.String(), want.Position.GTIDSet.String(), "got Position: %v; want Position: %v", got.Position.GTIDSet, want.Position.GTIDSet) + assert.Equalf(t, got.FilePosition.GTIDSet.String(), want.FilePosition.GTIDSet.String(), "got FilePosition: %v; want FilePosition: %v", got.FilePosition.GTIDSet, want.FilePosition.GTIDSet) +} + +func TestMysqlRetrieveSourceServerId(t *testing.T) { + resultMap := map[string]string{ + "Master_Server_Id": "1", + } + + want := ReplicationStatus{SourceServerID: 1} + got, err := ParseMysqlReplicationStatus(resultMap) + require.NoError(t, err) + assert.Equalf(t, got.SourceServerID, want.SourceServerID, "got SourceServerID: %v; want SourceServerID: %v", got.SourceServerID, want.SourceServerID) +} + +func TestMysqlRetrieveFileBasedPositions(t *testing.T) { + resultMap := map[string]string{ + "Exec_Master_Log_Pos": "1307", + "Relay_Master_Log_File": "master-bin.000002", + "Read_Master_Log_Pos": "1308", + "Master_Log_File": "master-bin.000003", + "Relay_Log_Pos": "1309", + "Relay_Log_File": "relay-bin.000004", + } + + want := ReplicationStatus{ + FilePosition: Position{GTIDSet: FilePosGTID{File: "master-bin.000002", Pos: 1307}}, + RelayLogSourceBinlogEquivalentPosition: Position{GTIDSet: FilePosGTID{File: "master-bin.000003", Pos: 1308}}, + RelayLogFilePosition: Position{GTIDSet: FilePosGTID{File: "relay-bin.000004", Pos: 1309}}, + } + got, err := ParseMysqlReplicationStatus(resultMap) + require.NoError(t, err) + assert.Equalf(t, got.FilePosition.GTIDSet, want.FilePosition.GTIDSet, "got FilePosition: %v; want FilePosition: %v", got.FilePosition.GTIDSet, want.FilePosition.GTIDSet) + assert.Equalf(t, got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet, "got RelayLogFilePosition: %v; want RelayLogFilePosition: %v", got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet) + assert.Equalf(t, got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet, "got RelayLogSourceBinlogEquivalentPosition: %v; want RelayLogSourceBinlogEquivalentPosition: %v", got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet) +} + +func TestMysqlShouldGetRelayLogPosition(t *testing.T) { + resultMap := map[string]string{ + "Executed_Gtid_Set": "3e11fa47-71ca-11e1-9e33-c80aa9429562:1-5", + "Retrieved_Gtid_Set": "3e11fa47-71ca-11e1-9e33-c80aa9429562:6-9", + "Exec_Master_Log_Pos": "1307", + "Relay_Master_Log_File": "master-bin.000002", + "Read_Master_Log_Pos": "1308", + "Master_Log_File": "master-bin.000003", + } + + sid, _ := ParseSID("3e11fa47-71ca-11e1-9e33-c80aa9429562") + want := ReplicationStatus{ + Position: Position{GTIDSet: Mysql56GTIDSet{sid: []interval{{start: 1, end: 5}}}}, + RelayLogPosition: Position{GTIDSet: Mysql56GTIDSet{sid: []interval{{start: 1, end: 9}}}}, + } + got, err := ParseMysqlReplicationStatus(resultMap) + require.NoError(t, err) + assert.Equalf(t, got.RelayLogPosition.GTIDSet.String(), want.RelayLogPosition.GTIDSet.String(), "got RelayLogPosition: %v; want RelayLogPosition: %v", got.RelayLogPosition.GTIDSet, want.RelayLogPosition.GTIDSet) +} + +func TestMariadbRetrieveSourceServerId(t *testing.T) { + resultMap := map[string]string{ + "Master_Server_Id": "1", + "Gtid_Slave_Pos": "0-101-2320", + } + + want := ReplicationStatus{SourceServerID: 1} + got, err := ParseMariadbReplicationStatus(resultMap) + require.NoError(t, err) + assert.Equal(t, got.SourceServerID, want.SourceServerID, fmt.Sprintf("got SourceServerID: %v; want SourceServerID: %v", got.SourceServerID, want.SourceServerID)) +} + +func TestMariadbRetrieveFileBasedPositions(t *testing.T) { + resultMap := map[string]string{ + "Exec_Master_Log_Pos": "1307", + "Relay_Master_Log_File": "master-bin.000002", + "Read_Master_Log_Pos": "1308", + "Master_Log_File": "master-bin.000003", + "Gtid_Slave_Pos": "0-101-2320", + "Relay_Log_Pos": "1309", + "Relay_Log_File": "relay-bin.000004", + } + + want := ReplicationStatus{ + FilePosition: Position{GTIDSet: FilePosGTID{File: "master-bin.000002", Pos: 1307}}, + RelayLogSourceBinlogEquivalentPosition: Position{GTIDSet: FilePosGTID{File: "master-bin.000003", Pos: 1308}}, + RelayLogFilePosition: Position{GTIDSet: FilePosGTID{File: "relay-bin.000004", Pos: 1309}}, + } + got, err := ParseMariadbReplicationStatus(resultMap) + require.NoError(t, err) + assert.Equalf(t, got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet, "got RelayLogFilePosition: %v; want RelayLogFilePosition: %v", got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet) + assert.Equal(t, got.FilePosition.GTIDSet, want.FilePosition.GTIDSet, fmt.Sprintf("got FilePosition: %v; want FilePosition: %v", got.FilePosition.GTIDSet, want.FilePosition.GTIDSet)) + assert.Equal(t, got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet, fmt.Sprintf("got RelayLogSourceBinlogEquivalentPosition: %v; want RelayLogSourceBinlogEquivalentPosition: %v", got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet)) +} + +func TestMariadbShouldGetNilRelayLogPosition(t *testing.T) { + resultMap := map[string]string{ + "Exec_Master_Log_Pos": "1307", + "Relay_Master_Log_File": "master-bin.000002", + "Read_Master_Log_Pos": "1308", + "Master_Log_File": "master-bin.000003", + "Gtid_Slave_Pos": "0-101-2320", + } + got, err := ParseMariadbReplicationStatus(resultMap) + require.NoError(t, err) + assert.Truef(t, got.RelayLogPosition.IsZero(), "Got a filled in RelayLogPosition. For MariaDB we should get back nil, because MariaDB does not return the retrieved GTIDSet. got: %#v", got.RelayLogPosition) +} + +func TestFilePosRetrieveSourceServerId(t *testing.T) { + resultMap := map[string]string{ + "Master_Server_Id": "1", + } + + want := ReplicationStatus{SourceServerID: 1} + got, err := ParseFilePosReplicationStatus(resultMap) + require.NoError(t, err) + assert.Equalf(t, got.SourceServerID, want.SourceServerID, "got SourceServerID: %v; want SourceServerID: %v", got.SourceServerID, want.SourceServerID) +} + +func TestFilePosRetrieveExecutedPosition(t *testing.T) { + resultMap := map[string]string{ + "Exec_Master_Log_Pos": "1307", + "Relay_Master_Log_File": "master-bin.000002", + "Read_Master_Log_Pos": "1308", + "Master_Log_File": "master-bin.000003", + "Relay_Log_Pos": "1309", + "Relay_Log_File": "relay-bin.000004", + } + + want := ReplicationStatus{ + Position: Position{GTIDSet: FilePosGTID{File: "master-bin.000002", Pos: 1307}}, + RelayLogPosition: Position{GTIDSet: FilePosGTID{File: "master-bin.000003", Pos: 1308}}, + FilePosition: Position{GTIDSet: FilePosGTID{File: "master-bin.000002", Pos: 1307}}, + RelayLogSourceBinlogEquivalentPosition: Position{GTIDSet: FilePosGTID{File: "master-bin.000003", Pos: 1308}}, + RelayLogFilePosition: Position{GTIDSet: FilePosGTID{File: "relay-bin.000004", Pos: 1309}}, + } + got, err := ParseFilePosReplicationStatus(resultMap) + require.NoError(t, err) + assert.Equalf(t, got.Position.GTIDSet, want.Position.GTIDSet, "got Position: %v; want Position: %v", got.Position.GTIDSet, want.Position.GTIDSet) + assert.Equalf(t, got.RelayLogPosition.GTIDSet, want.RelayLogPosition.GTIDSet, "got RelayLogPosition: %v; want RelayLogPosition: %v", got.RelayLogPosition.GTIDSet, want.RelayLogPosition.GTIDSet) + assert.Equalf(t, got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet, "got RelayLogFilePosition: %v; want RelayLogFilePosition: %v", got.RelayLogFilePosition.GTIDSet, want.RelayLogFilePosition.GTIDSet) + assert.Equalf(t, got.FilePosition.GTIDSet, want.FilePosition.GTIDSet, "got FilePosition: %v; want FilePosition: %v", got.FilePosition.GTIDSet, want.FilePosition.GTIDSet) + assert.Equalf(t, got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet, "got RelayLogSourceBinlogEquivalentPosition: %v; want RelayLogSourceBinlogEquivalentPosition: %v", got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, want.RelayLogSourceBinlogEquivalentPosition.GTIDSet) + assert.Equalf(t, got.Position.GTIDSet, got.FilePosition.GTIDSet, "FilePosition and Position don't match when they should for the FilePos flavor") + assert.Equalf(t, got.RelayLogPosition.GTIDSet, got.RelayLogSourceBinlogEquivalentPosition.GTIDSet, "RelayLogPosition and RelayLogSourceBinlogEquivalentPosition don't match when they should for the FilePos flavor") +} + +func TestFilePosShouldGetPosition(t *testing.T) { + resultMap := map[string]string{ + "Position": "1307", + "File": "source-bin.000003", + } + + want := PrimaryStatus{ + Position: Position{GTIDSet: FilePosGTID{File: "source-bin.000003", Pos: 1307}}, + FilePosition: Position{GTIDSet: FilePosGTID{File: "source-bin.000003", Pos: 1307}}, + } + got, err := ParseFilePosPrimaryStatus(resultMap) + require.NoError(t, err) + assert.Equalf(t, got.Position.GTIDSet, want.Position.GTIDSet, "got Position: %v; want Position: %v", got.Position.GTIDSet, want.Position.GTIDSet) + assert.Equalf(t, got.FilePosition.GTIDSet, want.FilePosition.GTIDSet, "got FilePosition: %v; want FilePosition: %v", got.FilePosition.GTIDSet, want.FilePosition.GTIDSet) + assert.Equalf(t, got.Position.GTIDSet, got.FilePosition.GTIDSet, "FilePosition and Position don't match when they should for the FilePos flavor") +} diff --git a/go/mysql/replication/state.go b/go/mysql/replication/state.go new file mode 100644 index 00000000000..15f94d80338 --- /dev/null +++ b/go/mysql/replication/state.go @@ -0,0 +1,33 @@ +package replication + +import "strings" + +type ReplicationState int32 + +const ( + ReplicationStateUnknown ReplicationState = iota + ReplicationStateStopped + ReplicationStateConnecting + ReplicationStateRunning +) + +// ReplicationStatusToState converts a value you have for the IO thread(s) or SQL +// thread(s) or Group Replication applier thread(s) from MySQL or intermediate +// layers to a ReplicationState. +// on,yes,true == ReplicationStateRunning +// off,no,false == ReplicationStateStopped +// connecting == ReplicationStateConnecting +// anything else == ReplicationStateUnknown +func ReplicationStatusToState(s string) ReplicationState { + // Group Replication uses ON instead of Yes + switch strings.ToLower(s) { + case "yes", "on", "true": + return ReplicationStateRunning + case "no", "off", "false": + return ReplicationStateStopped + case "connecting": + return ReplicationStateConnecting + default: + return ReplicationStateUnknown + } +} diff --git a/go/mysql/replication_status_test.go b/go/mysql/replication_status_test.go deleted file mode 100644 index 556f2cfaaeb..00000000000 --- a/go/mysql/replication_status_test.go +++ /dev/null @@ -1,115 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -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 mysql - -import ( - "testing" - - "github.com/stretchr/testify/require" -) - -func TestStatusReplicationRunning(t *testing.T) { - input := &ReplicationStatus{ - IOState: ReplicationStatusToState("yes"), - SQLState: ReplicationStatusToState("yes"), - } - want := true - if got := input.Running(); got != want { - t.Errorf("%#v.Running() = %v, want %v", input, got, want) - } -} - -func TestStatusIOThreadNotRunning(t *testing.T) { - input := &ReplicationStatus{ - IOState: ReplicationStatusToState("no"), - SQLState: ReplicationStatusToState("yes"), - } - want := false - if got := input.Running(); got != want { - t.Errorf("%#v.Running() = %v, want %v", input, got, want) - } -} - -func TestStatusSQLThreadNotRunning(t *testing.T) { - input := &ReplicationStatus{ - IOState: ReplicationStatusToState("yes"), - SQLState: ReplicationStatusToState("no"), - } - want := false - if got := input.Running(); got != want { - t.Errorf("%#v.Running() = %v, want %v", input, got, want) - } -} - -func TestFindErrantGTIDs(t *testing.T) { - sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16} - sid3 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17} - sid4 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 18} - sourceSID := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 19} - - set1 := Mysql56GTIDSet{ - sid1: []interval{{20, 30}, {35, 39}, {40, 53}, {55, 75}}, - sid2: []interval{{1, 7}, {20, 50}, {60, 70}}, - sid4: []interval{{1, 30}}, - sourceSID: []interval{{1, 7}, {20, 30}}, - } - - set2 := Mysql56GTIDSet{ - sid1: []interval{{20, 30}, {35, 37}, {50, 60}}, - sid2: []interval{{3, 5}, {22, 25}, {32, 37}, {67, 70}}, - sid3: []interval{{1, 45}}, - sourceSID: []interval{{2, 6}, {15, 40}}, - } - - set3 := Mysql56GTIDSet{ - sid1: []interval{{20, 30}, {35, 38}, {50, 70}}, - sid2: []interval{{3, 5}, {22, 25}, {32, 37}, {67, 70}}, - sid3: []interval{{1, 45}}, - sourceSID: []interval{{2, 6}, {15, 45}}, - } - - testcases := []struct { - mainRepStatus *ReplicationStatus - otherRepStatuses []*ReplicationStatus - want Mysql56GTIDSet - }{{ - mainRepStatus: &ReplicationStatus{SourceUUID: sourceSID, RelayLogPosition: Position{GTIDSet: set1}}, - otherRepStatuses: []*ReplicationStatus{ - {SourceUUID: sourceSID, RelayLogPosition: Position{GTIDSet: set2}}, - {SourceUUID: sourceSID, RelayLogPosition: Position{GTIDSet: set3}}, - }, - want: Mysql56GTIDSet{ - sid1: []interval{{39, 39}, {40, 49}, {71, 75}}, - sid2: []interval{{1, 2}, {6, 7}, {20, 21}, {26, 31}, {38, 50}, {60, 66}}, - sid4: []interval{{1, 30}}, - }, - }, { - mainRepStatus: &ReplicationStatus{SourceUUID: sourceSID, RelayLogPosition: Position{GTIDSet: set1}}, - otherRepStatuses: []*ReplicationStatus{{SourceUUID: sid1, RelayLogPosition: Position{GTIDSet: set1}}}, - // servers with the same GTID sets should not be diagnosed with errant GTIDs - want: nil, - }} - - for _, testcase := range testcases { - t.Run("", func(t *testing.T) { - got, err := testcase.mainRepStatus.FindErrantGTIDs(testcase.otherRepStatuses) - require.NoError(t, err) - require.Equal(t, testcase.want, got) - }) - } -} diff --git a/go/mysql/server.go b/go/mysql/server.go index 1ebebb56342..ec2d7538daa 100644 --- a/go/mysql/server.go +++ b/go/mysql/server.go @@ -25,7 +25,10 @@ import ( "sync/atomic" "time" - proxyproto "github.com/pires/go-proxyproto" + "github.com/pires/go-proxyproto" + + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/mysql/collations" "vitess.io/vitess/go/netutil" @@ -120,7 +123,7 @@ type Handler interface { ComBinlogDump(c *Conn, logFile string, binlogPos uint32) error // ComBinlogDumpGTID is called when a connection receives a ComBinlogDumpGTID request - ComBinlogDumpGTID(c *Conn, logFile string, logPos uint64, gtidSet GTIDSet) error + ComBinlogDumpGTID(c *Conn, logFile string, logPos uint64, gtidSet replication.GTIDSet) error // WarningCount is called at the end of each query to obtain // the value to be returned to the client in the EOF packet. @@ -455,12 +458,12 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti } if negotiatedAuthMethod == nil { - c.writeErrorPacket(CRServerHandshakeErr, SSUnknownSQLState, "No authentication methods available for authentication.") + c.writeErrorPacket(sqlerror.CRServerHandshakeErr, sqlerror.SSUnknownSQLState, "No authentication methods available for authentication.") return } if !l.AllowClearTextWithoutTLS.Load() && !c.TLSEnabled() && !negotiatedAuthMethod.AllowClearTextWithoutTLS() { - c.writeErrorPacket(CRServerHandshakeErr, SSUnknownSQLState, "Cannot use clear text authentication over non-SSL connections.") + c.writeErrorPacket(sqlerror.CRServerHandshakeErr, sqlerror.SSUnknownSQLState, "Cannot use clear text authentication over non-SSL connections.") return } diff --git a/go/mysql/server_flaky_test.go b/go/mysql/server_flaky_test.go index 3e10ef0d0ed..509fccaa47a 100644 --- a/go/mysql/server_flaky_test.go +++ b/go/mysql/server_flaky_test.go @@ -32,6 +32,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql/collations" "vitess.io/vitess/go/sqltypes" @@ -243,7 +246,7 @@ func (th *testHandler) ComRegisterReplica(c *Conn, replicaHost string, replicaPo func (th *testHandler) ComBinlogDump(c *Conn, logFile string, binlogPos uint32) error { return nil } -func (th *testHandler) ComBinlogDumpGTID(c *Conn, logFile string, logPos uint64, gtidSet GTIDSet) error { +func (th *testHandler) ComBinlogDumpGTID(c *Conn, logFile string, logPos uint64, gtidSet replication.GTIDSet) error { return nil } @@ -576,7 +579,7 @@ func TestServer(t *testing.T) { // If there's an error after streaming has started, // we should get a 2013 - th.SetErr(NewSQLError(ERUnknownComError, SSNetError, "forced error after send")) + th.SetErr(sqlerror.NewSQLError(sqlerror.ERUnknownComError, sqlerror.SSNetError, "forced error after send")) output, err = runMysqlWithErr(t, params, "error after send") require.Error(t, err) assert.Contains(t, output, "ERROR 2013 (HY000)", "Unexpected output for 'panic'") @@ -662,7 +665,7 @@ func TestServerStats(t *testing.T) { connRefuse.Reset() // Run an 'error' command. - th.SetErr(NewSQLError(ERUnknownComError, SSNetError, "forced query error")) + th.SetErr(sqlerror.NewSQLError(sqlerror.ERUnknownComError, sqlerror.SSNetError, "forced query error")) output, ok := runMysql(t, params, "error") require.False(t, ok, "mysql should have failed: %v", output) @@ -1244,7 +1247,7 @@ func TestErrorCodes(t *testing.T) { // internal vitess errors tests := []struct { err error - code ErrorCode + code sqlerror.ErrorCode sqlState string text string }{ @@ -1252,48 +1255,48 @@ func TestErrorCodes(t *testing.T) { err: vterrors.Errorf( vtrpcpb.Code_INVALID_ARGUMENT, "invalid argument"), - code: ERUnknownError, - sqlState: SSUnknownSQLState, + code: sqlerror.ERUnknownError, + sqlState: sqlerror.SSUnknownSQLState, text: "invalid argument", }, { err: vterrors.Errorf( vtrpcpb.Code_INVALID_ARGUMENT, - "(errno %v) (sqlstate %v) invalid argument with errno", ERDupEntry, SSConstraintViolation), - code: ERDupEntry, - sqlState: SSConstraintViolation, + "(errno %v) (sqlstate %v) invalid argument with errno", sqlerror.ERDupEntry, sqlerror.SSConstraintViolation), + code: sqlerror.ERDupEntry, + sqlState: sqlerror.SSConstraintViolation, text: "invalid argument with errno", }, { err: vterrors.Errorf( vtrpcpb.Code_DEADLINE_EXCEEDED, "connection deadline exceeded"), - code: ERQueryInterrupted, - sqlState: SSQueryInterrupted, + code: sqlerror.ERQueryInterrupted, + sqlState: sqlerror.SSQueryInterrupted, text: "deadline exceeded", }, { err: vterrors.Errorf( vtrpcpb.Code_RESOURCE_EXHAUSTED, "query pool timeout"), - code: ERTooManyUserConnections, - sqlState: SSClientError, + code: sqlerror.ERTooManyUserConnections, + sqlState: sqlerror.SSClientError, text: "resource exhausted", }, { err: vterrors.Wrap(vterrors.Errorf(vtrpcpb.Code_ABORTED, "Row count exceeded 10000"), "wrapped"), - code: ERQueryInterrupted, - sqlState: SSQueryInterrupted, + code: sqlerror.ERQueryInterrupted, + sqlState: sqlerror.SSQueryInterrupted, text: "aborted", }, } for _, test := range tests { t.Run(test.err.Error(), func(t *testing.T) { - th.SetErr(NewSQLErrorFromError(test.err)) + th.SetErr(sqlerror.NewSQLErrorFromError(test.err)) rs, err := client.ExecuteFetch("error", 100, false) require.Error(t, err, "mysql should have failed but returned: %v", rs) - serr, ok := err.(*SQLError) + serr, ok := err.(*sqlerror.SQLError) require.True(t, ok, "mysql should have returned a SQLError") assert.Equal(t, test.code, serr.Number(), "error in %s: want code %v got %v", test.text, test.code, serr.Number()) @@ -1430,11 +1433,11 @@ func TestListenerShutdown(t *testing.T) { err = conn.Ping() require.EqualError(t, err, "Server shutdown in progress (errno 1053) (sqlstate 08S01)") - sqlErr, ok := err.(*SQLError) + sqlErr, ok := err.(*sqlerror.SQLError) require.True(t, ok, "Wrong error type: %T", err) - require.Equal(t, ERServerShutdown, sqlErr.Number()) - require.Equal(t, SSNetError, sqlErr.SQLState()) + require.Equal(t, sqlerror.ERServerShutdown, sqlErr.Number()) + require.Equal(t, sqlerror.SSNetError, sqlErr.SQLState()) require.Equal(t, "Server shutdown in progress", sqlErr.Message) } diff --git a/go/mysql/sqlerror/constants.go b/go/mysql/sqlerror/constants.go new file mode 100644 index 00000000000..7d229ef67f6 --- /dev/null +++ b/go/mysql/sqlerror/constants.go @@ -0,0 +1,480 @@ +package sqlerror + +import ( + "strconv" + "strings" +) + +type ErrorCode uint16 + +func (e ErrorCode) ToString() string { + return strconv.FormatUint(uint64(e), 10) +} + +// Error codes for server-side errors. +// Originally found in include/mysql/mysqld_error.h and +// https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html +// The below are in sorted order by value, grouped by vterror code they should be bucketed into. +// See above reference for more information on each code. +const ( + // Vitess specific errors, (100-999) + ERNotReplica = ErrorCode(100) + + // unknown + ERUnknownError = ErrorCode(1105) + + // internal + ERInternalError = ErrorCode(1815) + + // unimplemented + ERNotSupportedYet = ErrorCode(1235) + ERUnsupportedPS = ErrorCode(1295) + + // resource exhausted + ERDiskFull = ErrorCode(1021) + EROutOfMemory = ErrorCode(1037) + EROutOfSortMemory = ErrorCode(1038) + ERConCount = ErrorCode(1040) + EROutOfResources = ErrorCode(1041) + ERRecordFileFull = ErrorCode(1114) + ERHostIsBlocked = ErrorCode(1129) + ERCantCreateThread = ErrorCode(1135) + ERTooManyDelayedThreads = ErrorCode(1151) + ERNetPacketTooLarge = ErrorCode(1153) + ERTooManyUserConnections = ErrorCode(1203) + ERLockTableFull = ErrorCode(1206) + ERUserLimitReached = ErrorCode(1226) + + // deadline exceeded + ERLockWaitTimeout = ErrorCode(1205) + + // unavailable + ERServerShutdown = ErrorCode(1053) + + // not found + ERDbDropExists = ErrorCode(1008) + ERCantFindFile = ErrorCode(1017) + ERFormNotFound = ErrorCode(1029) + ERKeyNotFound = ErrorCode(1032) + ERBadFieldError = ErrorCode(1054) + ERNoSuchThread = ErrorCode(1094) + ERUnknownTable = ErrorCode(1109) + ERCantFindUDF = ErrorCode(1122) + ERNonExistingGrant = ErrorCode(1141) + ERNoSuchTable = ErrorCode(1146) + ERNonExistingTableGrant = ErrorCode(1147) + ERKeyDoesNotExist = ErrorCode(1176) + + // permissions + ERDBAccessDenied = ErrorCode(1044) + ERAccessDeniedError = ErrorCode(1045) + ERKillDenied = ErrorCode(1095) + ERNoPermissionToCreateUsers = ErrorCode(1211) + ERSpecifiedAccessDenied = ErrorCode(1227) + + // failed precondition + ERNoDb = ErrorCode(1046) + ERNoSuchIndex = ErrorCode(1082) + ERCantDropFieldOrKey = ErrorCode(1091) + ERTableNotLockedForWrite = ErrorCode(1099) + ERTableNotLocked = ErrorCode(1100) + ERTooBigSelect = ErrorCode(1104) + ERNotAllowedCommand = ErrorCode(1148) + ERTooLongString = ErrorCode(1162) + ERDelayedInsertTableLocked = ErrorCode(1165) + ERDupUnique = ErrorCode(1169) + ERRequiresPrimaryKey = ErrorCode(1173) + ERCantDoThisDuringAnTransaction = ErrorCode(1179) + ERReadOnlyTransaction = ErrorCode(1207) + ERCannotAddForeign = ErrorCode(1215) + ERNoReferencedRow = ErrorCode(1216) + ERRowIsReferenced = ErrorCode(1217) + ERCantUpdateWithReadLock = ErrorCode(1223) + ERNoDefault = ErrorCode(1230) + ERMasterFatalReadingBinlog = ErrorCode(1236) + EROperandColumns = ErrorCode(1241) + ERSubqueryNo1Row = ErrorCode(1242) + ERUnknownStmtHandler = ErrorCode(1243) + ERWarnDataOutOfRange = ErrorCode(1264) + ERNonUpdateableTable = ErrorCode(1288) + ERFeatureDisabled = ErrorCode(1289) + EROptionPreventsStatement = ErrorCode(1290) + ERDuplicatedValueInType = ErrorCode(1291) + ERSPDoesNotExist = ErrorCode(1305) + ERNoDefaultForField = ErrorCode(1364) + ErSPNotVarArg = ErrorCode(1414) + ERRowIsReferenced2 = ErrorCode(1451) + ErNoReferencedRow2 = ErrorCode(1452) + ERDupIndex = ErrorCode(1831) + ERInnodbReadOnly = ErrorCode(1874) + + // already exists + ERDbCreateExists = ErrorCode(1007) + ERTableExists = ErrorCode(1050) + ERDupEntry = ErrorCode(1062) + ERFileExists = ErrorCode(1086) + ERUDFExists = ErrorCode(1125) + + // aborted + ERGotSignal = ErrorCode(1078) + ERForcingClose = ErrorCode(1080) + ERAbortingConnection = ErrorCode(1152) + ERLockDeadlock = ErrorCode(1213) + + // invalid arg + ERUnknownComError = ErrorCode(1047) + ERBadNullError = ErrorCode(1048) + ERBadDb = ErrorCode(1049) + ERBadTable = ErrorCode(1051) + ERNonUniq = ErrorCode(1052) + ERWrongFieldWithGroup = ErrorCode(1055) + ERWrongGroupField = ErrorCode(1056) + ERWrongSumSelect = ErrorCode(1057) + ERWrongValueCount = ErrorCode(1058) + ERTooLongIdent = ErrorCode(1059) + ERDupFieldName = ErrorCode(1060) + ERDupKeyName = ErrorCode(1061) + ERWrongFieldSpec = ErrorCode(1063) + ERParseError = ErrorCode(1064) + EREmptyQuery = ErrorCode(1065) + ERNonUniqTable = ErrorCode(1066) + ERInvalidDefault = ErrorCode(1067) + ERMultiplePriKey = ErrorCode(1068) + ERTooManyKeys = ErrorCode(1069) + ERTooManyKeyParts = ErrorCode(1070) + ERTooLongKey = ErrorCode(1071) + ERKeyColumnDoesNotExist = ErrorCode(1072) + ERBlobUsedAsKey = ErrorCode(1073) + ERTooBigFieldLength = ErrorCode(1074) + ERWrongAutoKey = ErrorCode(1075) + ERWrongFieldTerminators = ErrorCode(1083) + ERBlobsAndNoTerminated = ErrorCode(1084) + ERTextFileNotReadable = ErrorCode(1085) + ERWrongSubKey = ErrorCode(1089) + ERCantRemoveAllFields = ErrorCode(1090) + ERUpdateTableUsed = ErrorCode(1093) + ERNoTablesUsed = ErrorCode(1096) + ERTooBigSet = ErrorCode(1097) + ERBlobCantHaveDefault = ErrorCode(1101) + ERWrongDbName = ErrorCode(1102) + ERWrongTableName = ErrorCode(1103) + ERUnknownProcedure = ErrorCode(1106) + ERWrongParamCountToProcedure = ErrorCode(1107) + ERWrongParametersToProcedure = ErrorCode(1108) + ERFieldSpecifiedTwice = ErrorCode(1110) + ERInvalidGroupFuncUse = ErrorCode(1111) + ERTableMustHaveColumns = ErrorCode(1113) + ERUnknownCharacterSet = ErrorCode(1115) + ERTooManyTables = ErrorCode(1116) + ERTooManyFields = ErrorCode(1117) + ERTooBigRowSize = ErrorCode(1118) + ERWrongOuterJoin = ErrorCode(1120) + ERNullColumnInIndex = ErrorCode(1121) + ERFunctionNotDefined = ErrorCode(1128) + ERWrongValueCountOnRow = ErrorCode(1136) + ERInvalidUseOfNull = ErrorCode(1138) + ERRegexpError = ErrorCode(1139) + ERMixOfGroupFuncAndFields = ErrorCode(1140) + ERIllegalGrantForTable = ErrorCode(1144) + ERSyntaxError = ErrorCode(1149) + ERWrongColumnName = ErrorCode(1166) + ERWrongKeyColumn = ErrorCode(1167) + ERBlobKeyWithoutLength = ErrorCode(1170) + ERPrimaryCantHaveNull = ErrorCode(1171) + ERTooManyRows = ErrorCode(1172) + ERLockOrActiveTransaction = ErrorCode(1192) + ERUnknownSystemVariable = ErrorCode(1193) + ERSetConstantsOnly = ErrorCode(1204) + ERWrongArguments = ErrorCode(1210) + ERWrongUsage = ErrorCode(1221) + ERWrongNumberOfColumnsInSelect = ErrorCode(1222) + ERDupArgument = ErrorCode(1225) + ERLocalVariable = ErrorCode(1228) + ERGlobalVariable = ErrorCode(1229) + ERWrongValueForVar = ErrorCode(1231) + ERWrongTypeForVar = ErrorCode(1232) + ERVarCantBeRead = ErrorCode(1233) + ERCantUseOptionHere = ErrorCode(1234) + ERIncorrectGlobalLocalVar = ErrorCode(1238) + ERWrongFKDef = ErrorCode(1239) + ERKeyRefDoNotMatchTableRef = ErrorCode(1240) + ERCyclicReference = ErrorCode(1245) + ERIllegalReference = ErrorCode(1247) + ERDerivedMustHaveAlias = ErrorCode(1248) + ERTableNameNotAllowedHere = ErrorCode(1250) + ERCollationCharsetMismatch = ErrorCode(1253) + ERWarnDataTruncated = ErrorCode(1265) + ERCantAggregate2Collations = ErrorCode(1267) + ERCantAggregate3Collations = ErrorCode(1270) + ERCantAggregateNCollations = ErrorCode(1271) + ERVariableIsNotStruct = ErrorCode(1272) + ERUnknownCollation = ErrorCode(1273) + ERWrongNameForIndex = ErrorCode(1280) + ERWrongNameForCatalog = ErrorCode(1281) + ERBadFTColumn = ErrorCode(1283) + ERTruncatedWrongValue = ErrorCode(1292) + ERTooMuchAutoTimestampCols = ErrorCode(1293) + ERInvalidOnUpdate = ErrorCode(1294) + ERUnknownTimeZone = ErrorCode(1298) + ERInvalidCharacterString = ErrorCode(1300) + ERQueryInterrupted = ErrorCode(1317) + ERTruncatedWrongValueForField = ErrorCode(1366) + ERIllegalValueForType = ErrorCode(1367) + ERDataTooLong = ErrorCode(1406) + ErrWrongValueForType = ErrorCode(1411) + ERNoSuchUser = ErrorCode(1449) + ERForbidSchemaChange = ErrorCode(1450) + ERWrongValue = ErrorCode(1525) + ERDataOutOfRange = ErrorCode(1690) + ERInvalidJSONText = ErrorCode(3140) + ERInvalidJSONTextInParams = ErrorCode(3141) + ERInvalidJSONBinaryData = ErrorCode(3142) + ERInvalidJSONCharset = ErrorCode(3144) + ERInvalidCastToJSON = ErrorCode(3147) + ERJSONValueTooBig = ErrorCode(3150) + ERJSONDocumentTooDeep = ErrorCode(3157) + + ERRegexpStringNotTerminated = ErrorCode(3684) + ERRegexpBufferOverflow = ErrorCode(3684) + ERRegexpIllegalArgument = ErrorCode(3685) + ERRegexpIndexOutOfBounds = ErrorCode(3686) + ERRegexpInternal = ErrorCode(3687) + ERRegexpRuleSyntax = ErrorCode(3688) + ERRegexpBadEscapeSequence = ErrorCode(3689) + ERRegexpUnimplemented = ErrorCode(3690) + ERRegexpMismatchParen = ErrorCode(3691) + ERRegexpBadInterval = ErrorCode(3692) + ERRRegexpMaxLtMin = ErrorCode(3693) + ERRegexpInvalidBackRef = ErrorCode(3694) + ERRegexpLookBehindLimit = ErrorCode(3695) + ERRegexpMissingCloseBracket = ErrorCode(3696) + ERRegexpInvalidRange = ErrorCode(3697) + ERRegexpStackOverflow = ErrorCode(3698) + ERRegexpTimeOut = ErrorCode(3699) + ERRegexpPatternTooBig = ErrorCode(3700) + ERRegexpInvalidCaptureGroup = ErrorCode(3887) + ERRegexpInvalidFlag = ErrorCode(3900) + + ERCharacterSetMismatch = ErrorCode(3995) + + ERWrongParametersToNativeFct = ErrorCode(1583) + + // max execution time exceeded + ERQueryTimeout = ErrorCode(3024) + + ErrCantCreateGeometryObject = ErrorCode(1416) + ErrGISDataWrongEndianess = ErrorCode(3055) + ErrNotImplementedForCartesianSRS = ErrorCode(3704) + ErrNotImplementedForProjectedSRS = ErrorCode(3705) + ErrNonPositiveRadius = ErrorCode(3706) + + // server not available + ERServerIsntAvailable = ErrorCode(3168) +) + +// Sql states for errors. +// Originally found in include/mysql/sql_state.h +const ( + // SSUnknownSqlstate is ER_SIGNAL_EXCEPTION in + // include/mysql/sql_state.h, but: + // const char *unknown_sqlstate= "HY000" + // in client.c. So using that one. + SSUnknownSQLState = "HY000" + + // SSNetError is network related error + SSNetError = "08S01" + + // SSWrongNumberOfColumns is related to columns error + SSWrongNumberOfColumns = "21000" + + // SSWrongValueCountOnRow is related to columns count mismatch error + SSWrongValueCountOnRow = "21S01" + + // SSDataTooLong is ER_DATA_TOO_LONG + SSDataTooLong = "22001" + + // SSDataOutOfRange is ER_DATA_OUT_OF_RANGE + SSDataOutOfRange = "22003" + + // SSConstraintViolation is constraint violation + SSConstraintViolation = "23000" + + // SSCantDoThisDuringAnTransaction is + // ER_CANT_DO_THIS_DURING_AN_TRANSACTION + SSCantDoThisDuringAnTransaction = "25000" + + // SSAccessDeniedError is ER_ACCESS_DENIED_ERROR + SSAccessDeniedError = "28000" + + // SSNoDB is ER_NO_DB_ERROR + SSNoDB = "3D000" + + // SSLockDeadlock is ER_LOCK_DEADLOCK + SSLockDeadlock = "40001" + + // SSClientError is the state on client errors + SSClientError = "42000" + + // SSDupFieldName is ER_DUP_FIELD_NAME + SSDupFieldName = "42S21" + + // SSBadFieldError is ER_BAD_FIELD_ERROR + SSBadFieldError = "42S22" + + // SSUnknownTable is ER_UNKNOWN_TABLE + SSUnknownTable = "42S02" + + // SSQueryInterrupted is ER_QUERY_INTERRUPTED; + SSQueryInterrupted = "70100" +) + +// IsConnErr returns true if the error is a connection error. +func IsConnErr(err error) bool { + if IsTooManyConnectionsErr(err) { + return false + } + if sqlErr, ok := err.(*SQLError); ok { + num := sqlErr.Number() + return (num >= CRUnknownError && num <= CRNamedPipeStateError) || num == ERQueryInterrupted + } + return false +} + +// IsConnLostDuringQuery returns true if the error is a CRServerLost error. +// Happens most commonly when a query is killed MySQL server-side. +func IsConnLostDuringQuery(err error) bool { + if sqlErr, ok := err.(*SQLError); ok { + num := sqlErr.Number() + return (num == CRServerLost) + } + return false +} + +// IsEphemeralError returns true if the error is ephemeral and the caller should +// retry if possible. Note: non-SQL errors are always treated as ephemeral. +func IsEphemeralError(err error) bool { + if sqlErr, ok := err.(*SQLError); ok { + en := sqlErr.Number() + switch en { + case + CRConnectionError, + CRConnHostError, + CRMalformedPacket, + CRNamedPipeStateError, + CRServerHandshakeErr, + CRServerGone, + CRServerLost, + CRSSLConnectionError, + CRUnknownError, + CRUnknownHost, + ERCantCreateThread, + ERDiskFull, + ERForcingClose, + ERGotSignal, + ERHostIsBlocked, + ERLockTableFull, + ERInnodbReadOnly, + ERInternalError, + ERLockDeadlock, + ERLockWaitTimeout, + ERQueryTimeout, + EROutOfMemory, + EROutOfResources, + EROutOfSortMemory, + ERQueryInterrupted, + ERServerIsntAvailable, + ERServerShutdown, + ERTooManyUserConnections, + ERUnknownError, + ERUserLimitReached: + return true + default: + return false + } + } + // If it's not an sqlError then we assume it's ephemeral + return true +} + +// IsTooManyConnectionsErr returns true if the error is due to too many connections. +func IsTooManyConnectionsErr(err error) bool { + if sqlErr, ok := err.(*SQLError); ok { + if sqlErr.Number() == CRServerHandshakeErr && strings.Contains(sqlErr.Message, "Too many connections") { + return true + } + } + return false +} + +// IsSchemaApplyError returns true when given error is a MySQL error applying schema change +func IsSchemaApplyError(err error) bool { + merr, isSQLErr := err.(*SQLError) + if !isSQLErr { + return false + } + switch merr.Num { + case + ERDupKeyName, + ERCantDropFieldOrKey, + ERTableExists, + ERDupFieldName: + return true + } + return false +} + +// Error codes for client-side errors. +// Originally found in include/mysql/errmsg.h and +// https://dev.mysql.com/doc/mysql-errors/en/client-error-reference.html +const ( + // CRUnknownError is CR_UNKNOWN_ERROR + CRUnknownError = ErrorCode(2000) + + // CRConnectionError is CR_CONNECTION_ERROR + // This is returned if a connection via a Unix socket fails. + CRConnectionError = ErrorCode(2002) + + // CRConnHostError is CR_CONN_HOST_ERROR + // This is returned if a connection via a TCP socket fails. + CRConnHostError = ErrorCode(2003) + + // CRUnknownHost is CR_UNKNOWN_HOST + // This is returned if the host name cannot be resolved. + CRUnknownHost = ErrorCode(2005) + + // CRServerGone is CR_SERVER_GONE_ERROR. + // This is returned if the client tries to send a command but it fails. + CRServerGone = ErrorCode(2006) + + // CRVersionError is CR_VERSION_ERROR + // This is returned if the server versions don't match what we support. + CRVersionError = ErrorCode(2007) + + // CRServerHandshakeErr is CR_SERVER_HANDSHAKE_ERR + CRServerHandshakeErr = ErrorCode(2012) + + // CRServerLost is CR_SERVER_LOST. + // Used when: + // - the client cannot write an initial auth packet. + // - the client cannot read an initial auth packet. + // - the client cannot read a response from the server. + // This happens when a running query is killed. + CRServerLost = ErrorCode(2013) + + // CRCommandsOutOfSync is CR_COMMANDS_OUT_OF_SYNC + // Sent when the streaming calls are not done in the right order. + CRCommandsOutOfSync = ErrorCode(2014) + + // CRNamedPipeStateError is CR_NAMEDPIPESETSTATE_ERROR. + // This is the highest possible number for a connection error. + CRNamedPipeStateError = ErrorCode(2018) + + // CRCantReadCharset is CR_CANT_READ_CHARSET + CRCantReadCharset = ErrorCode(2019) + + // CRSSLConnectionError is CR_SSL_CONNECTION_ERROR + CRSSLConnectionError = ErrorCode(2026) + + // CRMalformedPacket is CR_MALFORMED_PACKET + CRMalformedPacket = ErrorCode(2027) +) diff --git a/go/mysql/sql_error.go b/go/mysql/sqlerror/sql_error.go similarity index 99% rename from go/mysql/sql_error.go rename to go/mysql/sqlerror/sql_error.go index da093b75bd7..7d9093661c9 100644 --- a/go/mysql/sql_error.go +++ b/go/mysql/sqlerror/sql_error.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package sqlerror import ( "bytes" diff --git a/go/mysql/sql_error_test.go b/go/mysql/sqlerror/sql_error_test.go similarity index 99% rename from go/mysql/sql_error_test.go rename to go/mysql/sqlerror/sql_error_test.go index d0a248d3599..3c7f3114b68 100644 --- a/go/mysql/sql_error_test.go +++ b/go/mysql/sqlerror/sql_error_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package mysql +package sqlerror import ( "fmt" diff --git a/go/mysql/streaming_query.go b/go/mysql/streaming_query.go index 9e023150455..257c56e076f 100644 --- a/go/mysql/streaming_query.go +++ b/go/mysql/streaming_query.go @@ -17,6 +17,7 @@ limitations under the License. package mysql import ( + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" @@ -30,7 +31,7 @@ import ( func (c *Conn) ExecuteStreamFetch(query string) (err error) { defer func() { if err != nil { - if sqlerr, ok := err.(*SQLError); ok { + if sqlerr, ok := err.(*sqlerror.SQLError); ok { sqlerr.Query = query } } @@ -38,7 +39,7 @@ func (c *Conn) ExecuteStreamFetch(query string) (err error) { // Sanity check. if c.fields != nil { - return NewSQLError(CRCommandsOutOfSync, SSUnknownSQLState, "streaming query already in progress") + return sqlerror.NewSQLError(sqlerror.CRCommandsOutOfSync, sqlerror.SSUnknownSQLState, "streaming query already in progress") } // Send the query as a COM_QUERY packet. @@ -75,7 +76,7 @@ func (c *Conn) ExecuteStreamFetch(query string) (err error) { // EOF is only present here if it's not deprecated. data, err := c.readEphemeralPacket() if err != nil { - return NewSQLError(CRServerLost, SSUnknownSQLState, "%v", err) + return sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSUnknownSQLState, "%v", err) } defer c.recycleReadPacket() if c.isEOFPacket(data) { @@ -85,7 +86,7 @@ func (c *Conn) ExecuteStreamFetch(query string) (err error) { } else if isErrorPacket(data) { return ParseErrorPacket(data) } else { - return NewSQLError(CRCommandsOutOfSync, SSUnknownSQLState, "unexpected packet after fields: %v", data) + return sqlerror.NewSQLError(sqlerror.CRCommandsOutOfSync, sqlerror.SSUnknownSQLState, "unexpected packet after fields: %v", data) } } @@ -96,7 +97,7 @@ func (c *Conn) ExecuteStreamFetch(query string) (err error) { // Fields returns the fields for an ongoing streaming query. func (c *Conn) Fields() ([]*querypb.Field, error) { if c.fields == nil { - return nil, NewSQLError(CRCommandsOutOfSync, SSUnknownSQLState, "no streaming query in progress") + return nil, sqlerror.NewSQLError(sqlerror.CRCommandsOutOfSync, sqlerror.SSUnknownSQLState, "no streaming query in progress") } if len(c.fields) == 0 { // The query returned an empty field list. @@ -110,7 +111,7 @@ func (c *Conn) Fields() ([]*querypb.Field, error) { func (c *Conn) FetchNext(in []sqltypes.Value) ([]sqltypes.Value, error) { if c.fields == nil { // We are already done, and the result was closed. - return nil, NewSQLError(CRCommandsOutOfSync, SSUnknownSQLState, "no streaming query in progress") + return nil, sqlerror.NewSQLError(sqlerror.CRCommandsOutOfSync, sqlerror.SSUnknownSQLState, "no streaming query in progress") } if len(c.fields) == 0 { diff --git a/go/mysql/vault/auth_server_vault.go b/go/mysql/vault/auth_server_vault.go index 8d6f566b6d4..ccdef9f1d53 100644 --- a/go/mysql/vault/auth_server_vault.go +++ b/go/mysql/vault/auth_server_vault.go @@ -30,6 +30,8 @@ import ( vaultapi "github.com/aquarapid/vaultlib" "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/servenv" @@ -186,14 +188,14 @@ func (a *AuthServerVault) UserEntryWithHash(conn *mysql.Conn, salt []byte, user a.mu.Unlock() if !ok { - return &mysql.StaticUserData{}, mysql.NewSQLError(mysql.ERAccessDeniedError, mysql.SSAccessDeniedError, "Access denied for user '%v'", user) + return &mysql.StaticUserData{}, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } for _, entry := range userEntries { if entry.MysqlNativePassword != "" { hash, err := mysql.DecodeMysqlNativePasswordHex(entry.MysqlNativePassword) if err != nil { - return &mysql.StaticUserData{Username: entry.UserData, Groups: entry.Groups}, mysql.NewSQLError(mysql.ERAccessDeniedError, mysql.SSAccessDeniedError, "Access denied for user '%v'", user) + return &mysql.StaticUserData{Username: entry.UserData, Groups: entry.Groups}, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } isPass := mysql.VerifyHashedMysqlNativePassword(authResponse, salt, hash) if mysql.MatchSourceHost(remoteAddr, entry.SourceHost) && isPass { @@ -207,7 +209,7 @@ func (a *AuthServerVault) UserEntryWithHash(conn *mysql.Conn, salt []byte, user } } } - return &mysql.StaticUserData{}, mysql.NewSQLError(mysql.ERAccessDeniedError, mysql.SSAccessDeniedError, "Access denied for user '%v'", user) + return &mysql.StaticUserData{}, sqlerror.NewSQLError(sqlerror.ERAccessDeniedError, sqlerror.SSAccessDeniedError, "Access denied for user '%v'", user) } func (a *AuthServerVault) setTTLTicker(ttl time.Duration) { diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index 0acbdb70050..af2b52f67ea 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -32,8 +32,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/json2" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/test/endtoend/cluster" "vitess.io/vitess/go/test/endtoend/utils" @@ -1157,10 +1158,10 @@ func TestReplicaFullBackup(t *testing.T) (manifest *mysqlctl.BackupManifest, des return readManifestFile(t, backupLocation), destroy } -func TestReplicaIncrementalBackup(t *testing.T, incrementalFromPos mysql.Position, expectError string) (manifest *mysqlctl.BackupManifest, backupName string) { +func TestReplicaIncrementalBackup(t *testing.T, incrementalFromPos replication.Position, expectError string) (manifest *mysqlctl.BackupManifest, backupName string) { incrementalFromPosArg := "auto" if !incrementalFromPos.IsZero() { - incrementalFromPosArg = mysql.EncodePosition(incrementalFromPos) + incrementalFromPosArg = replication.EncodePosition(incrementalFromPos) } output, err := localCluster.VtctldClientProcess.ExecuteCommandWithOutput("Backup", "--incremental-from-pos", incrementalFromPosArg, replica1.Alias) if expectError != "" { @@ -1178,9 +1179,9 @@ func TestReplicaIncrementalBackup(t *testing.T, incrementalFromPos mysql.Positio return readManifestFile(t, backupLocation), backupName } -func TestReplicaRestoreToPos(t *testing.T, restoreToPos mysql.Position, expectError string) { +func TestReplicaRestoreToPos(t *testing.T, restoreToPos replication.Position, expectError string) { require.False(t, restoreToPos.IsZero()) - restoreToPosArg := mysql.EncodePosition(restoreToPos) + restoreToPosArg := replication.EncodePosition(restoreToPos) output, err := localCluster.VtctldClientProcess.ExecuteCommandWithOutput("RestoreFromBackup", "--restore-to-pos", restoreToPosArg, replica1.Alias) if expectError != "" { require.Errorf(t, err, "expected: %v", expectError) @@ -1257,7 +1258,7 @@ func verifyRestorePositionAndTimeStats(t *testing.T, vars map[string]any) { require.Contains(t, vars, "RestorePosition") require.NotEqual(t, "", backupPosition) require.NotEqual(t, "", backupTime) - rp, err := mysql.DecodePosition(backupPosition) + rp, err := replication.DecodePosition(backupPosition) require.NoError(t, err) require.False(t, rp.IsZero()) } diff --git a/go/test/endtoend/backup/vtctlbackup/pitr_test_framework.go b/go/test/endtoend/backup/vtctlbackup/pitr_test_framework.go index 5eac50cd3d7..a109440b53b 100644 --- a/go/test/endtoend/backup/vtctlbackup/pitr_test_framework.go +++ b/go/test/endtoend/backup/vtctlbackup/pitr_test_framework.go @@ -26,7 +26,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/test/endtoend/cluster" "vitess.io/vitess/go/vt/mysqlctl" ) @@ -91,7 +92,7 @@ func ExecTestIncrementalBackupAndRestoreToPos(t *testing.T, tcase *PITRTestCase) } } - var fullBackupPos mysql.Position + var fullBackupPos replication.Position t.Run("full backup", func(t *testing.T) { InsertRowOnPrimary(t, "before-full-backup") waitForReplica(t) @@ -101,7 +102,7 @@ func ExecTestIncrementalBackupAndRestoreToPos(t *testing.T, tcase *PITRTestCase) require.False(t, fullBackupPos.IsZero()) // msgs := ReadRowsFromReplica(t) - pos := mysql.EncodePosition(fullBackupPos) + pos := replication.EncodePosition(fullBackupPos) backupPositions = append(backupPositions, pos) rowsPerPosition[pos] = len(msgs) }) @@ -168,7 +169,7 @@ func ExecTestIncrementalBackupAndRestoreToPos(t *testing.T, tcase *PITRTestCase) // - auto // - explicit last backup pos // - back in history to the original full backup - var incrementalFromPos mysql.Position + var incrementalFromPos replication.Position if !tc.autoPosition { incrementalFromPos = lastBackupPos if tc.fromFullPosition { @@ -189,7 +190,7 @@ func ExecTestIncrementalBackupAndRestoreToPos(t *testing.T, tcase *PITRTestCase) require.NotEqual(t, manifest.Position, manifest.FromPosition) require.True(t, manifest.Position.GTIDSet.Union(manifest.PurgedPosition.GTIDSet).Contains(manifest.FromPosition.GTIDSet)) - gtidPurgedPos, err := mysql.ParsePosition(mysql.Mysql56FlavorID, GetReplicaGtidPurged(t)) + gtidPurgedPos, err := replication.ParsePosition(replication.Mysql56FlavorID, GetReplicaGtidPurged(t)) require.NoError(t, err) fromPositionIncludingPurged := manifest.FromPosition.GTIDSet.Union(gtidPurgedPos.GTIDSet) @@ -206,7 +207,7 @@ func ExecTestIncrementalBackupAndRestoreToPos(t *testing.T, tcase *PITRTestCase) pos := backupPositions[r] testName := fmt.Sprintf("%s, %d records", pos, rowsPerPosition[pos]) t.Run(testName, func(t *testing.T) { - restoreToPos, err := mysql.DecodePosition(pos) + restoreToPos, err := replication.DecodePosition(pos) require.NoError(t, err) TestReplicaRestoreToPos(t, restoreToPos, "") msgs := ReadRowsFromReplica(t) @@ -253,7 +254,7 @@ func ExecTestIncrementalBackupAndRestoreToTimestamp(t *testing.T, tcase *PITRTes testedBackups := []testedBackupTimestampInfo{} - var fullBackupPos mysql.Position + var fullBackupPos replication.Position t.Run("full backup", func(t *testing.T) { insertRowOnPrimary(t, "before-full-backup") waitForReplica(t) @@ -328,7 +329,7 @@ func ExecTestIncrementalBackupAndRestoreToTimestamp(t *testing.T, tcase *PITRTes // - auto // - explicit last backup pos // - back in history to the original full backup - var incrementalFromPos mysql.Position + var incrementalFromPos replication.Position if !tc.autoPosition { incrementalFromPos = lastBackupPos if tc.fromFullPosition { @@ -371,7 +372,7 @@ func ExecTestIncrementalBackupAndRestoreToTimestamp(t *testing.T, tcase *PITRTes } } - gtidPurgedPos, err := mysql.ParsePosition(mysql.Mysql56FlavorID, GetReplicaGtidPurged(t)) + gtidPurgedPos, err := replication.ParsePosition(replication.Mysql56FlavorID, GetReplicaGtidPurged(t)) require.NoError(t, err) fromPositionIncludingPurged := manifest.FromPosition.GTIDSet.Union(gtidPurgedPos.GTIDSet) diff --git a/go/test/endtoend/mysqlserver/mysql_server_test.go b/go/test/endtoend/mysqlserver/mysql_server_test.go index 6cc2d091d0e..caed342688d 100644 --- a/go/test/endtoend/mysqlserver/mysql_server_test.go +++ b/go/test/endtoend/mysqlserver/mysql_server_test.go @@ -32,6 +32,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/test/endtoend/cluster" @@ -116,9 +118,9 @@ func TestTimeout(t *testing.T) { _, err = conn.ExecuteFetch("SELECT SLEEP(5);", 1, false) require.NotNilf(t, err, "quiry timeout error expected") - mysqlErr, ok := err.(*mysql.SQLError) + mysqlErr, ok := err.(*sqlerror.SQLError) require.Truef(t, ok, "invalid error type") - assert.Equal(t, mysql.ERQueryInterrupted, mysqlErr.Number(), err) + assert.Equal(t, sqlerror.ERQueryInterrupted, mysqlErr.Number(), err) } // TestInvalidField tries to fetch invalid column and verifies the error. @@ -132,9 +134,9 @@ func TestInvalidField(t *testing.T) { _, err = conn.ExecuteFetch("SELECT invalid_field from vt_insert_test;", 1, false) require.NotNil(t, err, "invalid field error expected") - mysqlErr, ok := err.(*mysql.SQLError) + mysqlErr, ok := err.(*sqlerror.SQLError) require.Truef(t, ok, "invalid error type") - assert.Equal(t, mysql.ERBadFieldError, mysqlErr.Number(), err) + assert.Equal(t, sqlerror.ERBadFieldError, mysqlErr.Number(), err) } // TestWarnings validates the behaviour of SHOW WARNINGS. diff --git a/go/test/endtoend/onlineddl/vrepl_stress_suite/onlineddl_vrepl_stress_suite_test.go b/go/test/endtoend/onlineddl/vrepl_stress_suite/onlineddl_vrepl_stress_suite_test.go index 92fb7cf13e5..bac59241cf2 100644 --- a/go/test/endtoend/onlineddl/vrepl_stress_suite/onlineddl_vrepl_stress_suite_test.go +++ b/go/test/endtoend/onlineddl/vrepl_stress_suite/onlineddl_vrepl_stress_suite_test.go @@ -41,6 +41,7 @@ import ( "time" "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/timer" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/schema" @@ -706,9 +707,9 @@ func runSingleConnection(ctx context.Context, t *testing.T, autoIncInsert bool, // Table renamed to _before, due to -vreplication-test-suite flag err = nil } - if sqlErr, ok := err.(*mysql.SQLError); ok { + if sqlErr, ok := err.(*sqlerror.SQLError); ok { switch sqlErr.Number() { - case mysql.ERLockDeadlock: + case sqlerror.ERLockDeadlock: // That's fine. We create a lot of contention; some transactions will deadlock and // rollback. It happens, and we can ignore those and keep on going. err = nil diff --git a/go/test/endtoend/reparent/plannedreparent/reparent_test.go b/go/test/endtoend/reparent/plannedreparent/reparent_test.go index 7a0b16f5890..c66e550a835 100644 --- a/go/test/endtoend/reparent/plannedreparent/reparent_test.go +++ b/go/test/endtoend/reparent/plannedreparent/reparent_test.go @@ -26,9 +26,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "google.golang.org/protobuf/encoding/protojson" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/test/endtoend/cluster" "vitess.io/vitess/go/test/endtoend/reparent/utils" "vitess.io/vitess/go/vt/log" @@ -483,8 +484,8 @@ func TestFullStatus(t *testing.T) { assert.NotEmpty(t, replicaStatus.ServerUuid) assert.NotEmpty(t, replicaStatus.ServerId) assert.Contains(t, replicaStatus.ReplicationStatus.Position, "MySQL56/"+replicaStatus.ReplicationStatus.SourceUuid) - assert.EqualValues(t, mysql.ReplicationStateRunning, replicaStatus.ReplicationStatus.IoState) - assert.EqualValues(t, mysql.ReplicationStateRunning, replicaStatus.ReplicationStatus.SqlState) + assert.EqualValues(t, replication.ReplicationStateRunning, replicaStatus.ReplicationStatus.IoState) + assert.EqualValues(t, replication.ReplicationStateRunning, replicaStatus.ReplicationStatus.SqlState) assert.Equal(t, fileNameFromPosition(replicaStatus.ReplicationStatus.FilePosition), fileNameFromPosition(primaryStatus.PrimaryStatus.FilePosition)) assert.LessOrEqual(t, rowNumberFromPosition(replicaStatus.ReplicationStatus.FilePosition), rowNumberFromPosition(primaryStatus.PrimaryStatus.FilePosition)) assert.Equal(t, replicaStatus.ReplicationStatus.RelayLogSourceBinlogEquivalentPosition, primaryStatus.PrimaryStatus.FilePosition) diff --git a/go/test/endtoend/vreplication/helper_test.go b/go/test/endtoend/vreplication/helper_test.go index 20d31948e26..017ed9fbbb5 100644 --- a/go/test/endtoend/vreplication/helper_test.go +++ b/go/test/endtoend/vreplication/helper_test.go @@ -40,6 +40,7 @@ import ( "github.com/tidwall/gjson" "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqlescape" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/test/endtoend/cluster" @@ -762,7 +763,7 @@ func (lg *loadGenerator) start() { _, err := conn.ExecuteFetch(query, 1, false) atomic.AddInt64(&totalQueries, 1) if err != nil { - sqlErr := err.(*mysql.SQLError) + sqlErr := err.(*sqlerror.SQLError) if strings.Contains(strings.ToLower(err.Error()), "denied tables") { log.Infof("startLoad: denied tables error executing query: %d:%v", sqlErr.Number(), err) atomic.AddInt64(&deniedErrors, 1) diff --git a/go/test/endtoend/vtgate/errors_as_warnings/main_test.go b/go/test/endtoend/vtgate/errors_as_warnings/main_test.go index 97c73f5f458..a2446c1df87 100644 --- a/go/test/endtoend/vtgate/errors_as_warnings/main_test.go +++ b/go/test/endtoend/vtgate/errors_as_warnings/main_test.go @@ -24,6 +24,7 @@ import ( "strings" "testing" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/test/endtoend/utils" "github.com/stretchr/testify/require" @@ -147,8 +148,8 @@ func TestScatterErrsAsWarns(t *testing.T) { // invalid_field should throw error and not warning _, err = mode.conn.ExecuteFetch("SELECT /*vt+ PLANNER=Gen4 SCATTER_ERRORS_AS_WARNINGS */ invalid_field from t1;", 1, false) require.Error(t, err) - serr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) - require.Equal(t, mysql.ERBadFieldError, serr.Number(), serr.Error()) + serr := sqlerror.NewSQLErrorFromError(err).(*sqlerror.SQLError) + require.Equal(t, sqlerror.ERBadFieldError, serr.Number(), serr.Error()) }) } } diff --git a/go/test/endtoend/vtgate/lookup_test.go b/go/test/endtoend/vtgate/lookup_test.go index a95201ca87f..b4b53295d8d 100644 --- a/go/test/endtoend/vtgate/lookup_test.go +++ b/go/test/endtoend/vtgate/lookup_test.go @@ -24,6 +24,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/test/endtoend/utils" ) @@ -126,8 +128,8 @@ func TestConsistentLookup(t *testing.T) { _, err = conn.ExecuteFetch("insert into t1(id1, id2) values(1, 4)", 1000, false) utils.Exec(t, conn, "rollback") require.Error(t, err) - mysqlErr := err.(*mysql.SQLError) - assert.Equal(t, mysql.ERDupEntry, mysqlErr.Num) + mysqlErr := err.(*sqlerror.SQLError) + assert.Equal(t, sqlerror.ERDupEntry, mysqlErr.Num) assert.Equal(t, "23000", mysqlErr.State) assert.Contains(t, mysqlErr.Message, "reverted partial DML execution") diff --git a/go/test/endtoend/vtgate/misc_test.go b/go/test/endtoend/vtgate/misc_test.go index e24db73547d..7a6693bffbb 100644 --- a/go/test/endtoend/vtgate/misc_test.go +++ b/go/test/endtoend/vtgate/misc_test.go @@ -20,7 +20,7 @@ import ( "fmt" "testing" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/test/endtoend/utils" "github.com/stretchr/testify/assert" @@ -694,8 +694,8 @@ func TestDescribeVindex(t *testing.T) { _, err := conn.ExecuteFetch("describe hash", 1000, false) require.Error(t, err) - mysqlErr := err.(*mysql.SQLError) - assert.Equal(t, mysql.ERNoSuchTable, mysqlErr.Num) + mysqlErr := err.(*sqlerror.SQLError) + assert.Equal(t, sqlerror.ERNoSuchTable, mysqlErr.Num) assert.Equal(t, "42S02", mysqlErr.State) assert.Contains(t, mysqlErr.Message, "NotFound desc") } diff --git a/go/test/endtoend/vtgate/queries/random/random_test.go b/go/test/endtoend/vtgate/queries/random/random_test.go index a51b919e0dc..f2d9fcc0050 100644 --- a/go/test/endtoend/vtgate/queries/random/random_test.go +++ b/go/test/endtoend/vtgate/queries/random/random_test.go @@ -22,7 +22,7 @@ import ( "testing" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/sqlparser" "github.com/stretchr/testify/require" @@ -239,7 +239,7 @@ func TestRandom(t *testing.T) { if stopOnMustFixError { // EOF - if sqlError, ok := vtErr.(*mysql.SQLError); ok && strings.Contains(sqlError.Message, "EOF") { + if sqlError, ok := vtErr.(*sqlerror.SQLError); ok && strings.Contains(sqlError.Message, "EOF") { break } // mismatched results diff --git a/go/test/endtoend/vtgate/reservedconn/sysvar_test.go b/go/test/endtoend/vtgate/reservedconn/sysvar_test.go index 0dc2261c7ba..564cc671d5f 100644 --- a/go/test/endtoend/vtgate/reservedconn/sysvar_test.go +++ b/go/test/endtoend/vtgate/reservedconn/sysvar_test.go @@ -22,6 +22,7 @@ import ( "testing" "time" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/test/endtoend/utils" "github.com/stretchr/testify/assert" @@ -344,10 +345,10 @@ func TestSysvarSocket(t *testing.T) { _, err = utils.ExecAllowError(t, conn, "set socket = '/any/path'") require.Error(t, err) - sqlErr, ok := err.(*mysql.SQLError) + sqlErr, ok := err.(*sqlerror.SQLError) require.True(t, ok, "not a mysql error: %T", err) - assert.Equal(t, mysql.ERIncorrectGlobalLocalVar, sqlErr.Number()) - assert.Equal(t, mysql.SSUnknownSQLState, sqlErr.SQLState()) + assert.Equal(t, sqlerror.ERIncorrectGlobalLocalVar, sqlErr.Number()) + assert.Equal(t, sqlerror.SSUnknownSQLState, sqlErr.SQLState()) assert.Equal(t, "VT03010: variable 'socket' is a read only variable (errno 1238) (sqlstate HY000) during query: set socket = '/any/path'", sqlErr.Error()) } diff --git a/go/test/endtoend/vtgate/sequence/seq_test.go b/go/test/endtoend/vtgate/sequence/seq_test.go index 918a463ca33..dd7542becc5 100644 --- a/go/test/endtoend/vtgate/sequence/seq_test.go +++ b/go/test/endtoend/vtgate/sequence/seq_test.go @@ -24,6 +24,7 @@ import ( "strings" "testing" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/test/endtoend/utils" "github.com/stretchr/testify/assert" @@ -289,8 +290,8 @@ func TestDotTableSeq(t *testing.T) { _, err = conn.ExecuteFetch("insert into `dotted.tablename` (c1,c2) values (10,10)", 1000, true) require.Error(t, err) - mysqlErr := err.(*mysql.SQLError) - assert.Equal(t, mysql.ERDupEntry, mysqlErr.Num) + mysqlErr := err.(*sqlerror.SQLError) + assert.Equal(t, sqlerror.ERDupEntry, mysqlErr.Num) assert.Equal(t, "23000", mysqlErr.State) assert.Contains(t, mysqlErr.Message, "Duplicate entry") } diff --git a/go/vt/binlog/binlog_connection.go b/go/vt/binlog/binlog_connection.go index 1cdb2d6cacc..f7c7acd8e9c 100644 --- a/go/vt/binlog/binlog_connection.go +++ b/go/vt/binlog/binlog_connection.go @@ -17,15 +17,16 @@ limitations under the License. package binlog import ( + "context" crand "crypto/rand" "fmt" "math" "math/big" "sync" - "context" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/pools" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" @@ -99,12 +100,12 @@ func connectForReplication(cp dbconfigs.Connector) (*mysql.Conn, error) { // StartBinlogDumpFromCurrent requests a replication binlog dump from // the current position. -func (bc *BinlogConnection) StartBinlogDumpFromCurrent(ctx context.Context) (mysql.Position, <-chan mysql.BinlogEvent, <-chan error, error) { +func (bc *BinlogConnection) StartBinlogDumpFromCurrent(ctx context.Context) (replication.Position, <-chan mysql.BinlogEvent, <-chan error, error) { ctx, bc.cancel = context.WithCancel(ctx) position, err := bc.Conn.PrimaryPosition() if err != nil { - return mysql.Position{}, nil, nil, fmt.Errorf("failed to get primary position: %v", err) + return replication.Position{}, nil, nil, fmt.Errorf("failed to get primary position: %v", err) } c, e, err := bc.StartBinlogDumpFromPosition(ctx, "", position) @@ -120,7 +121,7 @@ func (bc *BinlogConnection) StartBinlogDumpFromCurrent(ctx context.Context) (mys // by canceling the context. // // Note the context is valid and used until eventChan is closed. -func (bc *BinlogConnection) StartBinlogDumpFromPosition(ctx context.Context, binlogFilename string, startPos mysql.Position) (<-chan mysql.BinlogEvent, <-chan error, error) { +func (bc *BinlogConnection) StartBinlogDumpFromPosition(ctx context.Context, binlogFilename string, startPos replication.Position) (<-chan mysql.BinlogEvent, <-chan error, error) { ctx, bc.cancel = context.WithCancel(ctx) log.Infof("sending binlog dump command: startPos=%v, serverID=%v", startPos, bc.serverID) @@ -156,7 +157,7 @@ func (bc *BinlogConnection) streamEvents(ctx context.Context) (chan mysql.Binlog case errChan <- err: case <-ctx.Done(): } - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.CRServerLost { + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Number() == sqlerror.CRServerLost { // CRServerLost = Lost connection to MySQL server during query // This is not necessarily an error. It could just be that we closed // the connection from outside. diff --git a/go/vt/binlog/binlog_streamer.go b/go/vt/binlog/binlog_streamer.go index b3116083c65..abbf73ba506 100644 --- a/go/vt/binlog/binlog_streamer.go +++ b/go/vt/binlog/binlog_streamer.go @@ -25,6 +25,8 @@ import ( "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/mysql/binlog" "vitess.io/vitess/go/sqltypes" @@ -141,7 +143,7 @@ type Streamer struct { extractPK bool clientCharset *binlogdatapb.Charset - startPos mysql.Position + startPos replication.Position timestamp int64 sendTransaction sendTransactionFunc usePreviousGTIDs bool @@ -157,7 +159,7 @@ type Streamer struct { // startPos is the position to start streaming at. Incompatible with timestamp. // timestamp is the timestamp to start streaming at. Incompatible with startPos. // sendTransaction is called each time a transaction is committed or rolled back. -func NewStreamer(cp dbconfigs.Connector, se *schema.Engine, clientCharset *binlogdatapb.Charset, startPos mysql.Position, timestamp int64, sendTransaction sendTransactionFunc) *Streamer { +func NewStreamer(cp dbconfigs.Connector, se *schema.Engine, clientCharset *binlogdatapb.Charset, startPos replication.Position, timestamp int64, sendTransaction sendTransactionFunc) *Streamer { return &Streamer{ cp: cp, se: se, @@ -245,10 +247,10 @@ func (bls *Streamer) Stream(ctx context.Context) (err error) { // If the sendTransaction func returns io.EOF, parseEvents returns ErrClientEOF. // If the events channel is closed, parseEvents returns ErrServerEOF. // If the context is done, returns ctx.Err(). -func (bls *Streamer) parseEvents(ctx context.Context, events <-chan mysql.BinlogEvent, errs <-chan error) (mysql.Position, error) { +func (bls *Streamer) parseEvents(ctx context.Context, events <-chan mysql.BinlogEvent, errs <-chan error) (replication.Position, error) { var statements []FullBinlogStatement var format mysql.BinlogFormat - var gtid mysql.GTID + var gtid replication.GTID var pos = bls.startPos var autocommit = true var err error @@ -273,7 +275,7 @@ func (bls *Streamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog if int64(timestamp) >= bls.timestamp { eventToken := &querypb.EventToken{ Timestamp: int64(timestamp), - Position: mysql.EncodePosition(pos), + Position: replication.EncodePosition(pos), } if err = bls.sendTransaction(eventToken, statements); err != nil { if err == io.EOF { @@ -347,7 +349,7 @@ func (bls *Streamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog return pos, fmt.Errorf("can't get GTID from binlog event: %v, event data: %#v", err, ev) } oldpos := pos - pos = mysql.AppendGTID(pos, gtid) + pos = replication.AppendGTID(pos, gtid) // If the event is received outside of a transaction, it must // be sent. Otherwise, it will get lost and the targets will go out // of sync. @@ -362,7 +364,7 @@ func (bls *Streamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog if err != nil { return pos, fmt.Errorf("can't get GTID from binlog event: %v, event data: %#v", err, ev) } - pos = mysql.AppendGTID(pos, gtid) + pos = replication.AppendGTID(pos, gtid) if hasBegin { begin() } diff --git a/go/vt/binlog/binlog_streamer_rbr_test.go b/go/vt/binlog/binlog_streamer_rbr_test.go index 93f70026eba..d8481ca0665 100644 --- a/go/vt/binlog/binlog_streamer_rbr_test.go +++ b/go/vt/binlog/binlog_streamer_rbr_test.go @@ -24,6 +24,7 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/mysql/binlog" "vitess.io/vitess/go/mysql/collations" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vttablet/tabletserver/schema" @@ -167,7 +168,7 @@ func TestStreamerParseRBREvents(t *testing.T) { mysql.NewRotateEvent(f, s, 0, ""), mysql.NewFormatDescriptionEvent(f, s), mysql.NewTableMapEvent(f, s, tableID, tm), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Database: "vt_test_keyspace", SQL: "BEGIN"}), @@ -239,9 +240,9 @@ func TestStreamerParseRBREvents(t *testing.T) { }, eventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -265,7 +266,7 @@ func TestStreamerParseRBREvents(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, se, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, se, nil, replication.Position{}, 0, sendTransaction) go sendTestEvents(events, input) _, err := bls.parseEvents(context.Background(), events, errs) @@ -416,7 +417,7 @@ func TestStreamerParseRBRNameEscapes(t *testing.T) { mysql.NewRotateEvent(f, s, 0, ""), mysql.NewFormatDescriptionEvent(f, s), mysql.NewTableMapEvent(f, s, tableID, tm), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Database: "vt_test_keyspace", SQL: "BEGIN"}), @@ -488,9 +489,9 @@ func TestStreamerParseRBRNameEscapes(t *testing.T) { }, eventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -514,7 +515,7 @@ func TestStreamerParseRBRNameEscapes(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, se, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, se, nil, replication.Position{}, 0, sendTransaction) go sendTestEvents(events, input) _, err := bls.parseEvents(context.Background(), events, errs) diff --git a/go/vt/binlog/binlog_streamer_test.go b/go/vt/binlog/binlog_streamer_test.go index df2af984e21..47be1e27b11 100644 --- a/go/vt/binlog/binlog_streamer_test.go +++ b/go/vt/binlog/binlog_streamer_test.go @@ -17,6 +17,7 @@ limitations under the License. package binlog import ( + "context" "fmt" "io" "strings" @@ -26,7 +27,8 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" - "context" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/mysql" @@ -85,7 +87,7 @@ func TestStreamerParseEventsXID(t *testing.T) { input := []mysql.BinlogEvent{ mysql.NewRotateEvent(f, s, 0, ""), mysql.NewFormatDescriptionEvent(f, s), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Database: "vt_test_keyspace", SQL: "BEGIN"}), @@ -106,9 +108,9 @@ func TestStreamerParseEventsXID(t *testing.T) { }, EventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -126,7 +128,7 @@ func TestStreamerParseEventsXID(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, (&got).sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, (&got).sendTransaction) go sendTestEvents(events, input) _, err := bls.parseEvents(context.Background(), events, errs) @@ -147,7 +149,7 @@ func TestStreamerParseEventsCommit(t *testing.T) { input := []mysql.BinlogEvent{ mysql.NewRotateEvent(f, s, 0, ""), mysql.NewFormatDescriptionEvent(f, s), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Database: "vt_test_keyspace", SQL: "BEGIN"}), @@ -170,9 +172,9 @@ func TestStreamerParseEventsCommit(t *testing.T) { }, EventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -189,7 +191,7 @@ func TestStreamerParseEventsCommit(t *testing.T) { dbcfgs := dbconfigs.New(mcp) var got binlogStatements - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, (&got).sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, (&got).sendTransaction) go sendTestEvents(events, input) _, err := bls.parseEvents(context.Background(), events, errs) @@ -216,7 +218,7 @@ func TestStreamerStop(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) // Start parseEvents(), but don't send it anything, so it just waits. ctx, cancel := context.WithCancel(context.Background()) @@ -269,7 +271,7 @@ func TestStreamerParseEventsClientEOF(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) go sendTestEvents(events, input) _, err := bls.parseEvents(context.Background(), events, errs) @@ -294,7 +296,7 @@ func TestStreamerParseEventsServerEOF(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) _, err := bls.parseEvents(context.Background(), events, errs) if err != want { t.Errorf("wrong error, got %#v, want %#v", err, want) @@ -308,7 +310,7 @@ func TestStreamerParseEventsServerEOF(t *testing.T) { func TestStreamerParseEventsGTIDPurged(t *testing.T) { events := make(chan mysql.BinlogEvent) errs := make(chan error) - expectedStreamErr := mysql.NewSQLError(mysql.ERMasterFatalReadingBinlog, mysql.SSUnknownSQLState, + expectedStreamErr := sqlerror.NewSQLError(sqlerror.ERMasterFatalReadingBinlog, sqlerror.SSUnknownSQLState, "Cannot replicate because the master purged required binary logs.") sendTransaction := func(eventToken *querypb.EventToken, statements []FullBinlogStatement) error { @@ -330,13 +332,13 @@ func TestStreamerParseEventsGTIDPurged(t *testing.T) { } }() - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) _, err := bls.parseEvents(context.Background(), events, errs) require.Error(t, err) - sqlErr, ok := err.(*mysql.SQLError) + sqlErr, ok := err.(*sqlerror.SQLError) require.True(t, ok, "expected SQLError, got %T", err) - require.True(t, sqlErr.Num == mysql.ERMasterFatalReadingBinlog, "expected ERMasterFatalReadingBinlog (%d), got %d", - mysql.ERMasterFatalReadingBinlog, sqlErr.Num) + require.True(t, sqlErr.Num == sqlerror.ERMasterFatalReadingBinlog, "expected ERMasterFatalReadingBinlog (%d), got %d", + sqlerror.ERMasterFatalReadingBinlog, sqlErr.Num) } func TestStreamerParseEventsSendErrorXID(t *testing.T) { @@ -369,7 +371,7 @@ func TestStreamerParseEventsSendErrorXID(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) go sendTestEvents(events, input) @@ -415,7 +417,7 @@ func TestStreamerParseEventsSendErrorCommit(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) go sendTestEvents(events, input) _, err := bls.parseEvents(context.Background(), events, errs) @@ -456,7 +458,7 @@ func TestStreamerParseEventsInvalid(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) go sendTestEvents(events, input) _, err := bls.parseEvents(context.Background(), events, errs) @@ -499,7 +501,7 @@ func TestStreamerParseEventsInvalidFormat(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) go sendTestEvents(events, input) _, err := bls.parseEvents(context.Background(), events, errs) @@ -542,7 +544,7 @@ func TestStreamerParseEventsNoFormat(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) go sendTestEvents(events, input) _, err := bls.parseEvents(context.Background(), events, errs) @@ -583,7 +585,7 @@ func TestStreamerParseEventsInvalidQuery(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) go sendTestEvents(events, input) _, err := bls.parseEvents(context.Background(), events, errs) @@ -604,7 +606,7 @@ func TestStreamerParseEventsRollback(t *testing.T) { input := []mysql.BinlogEvent{ mysql.NewRotateEvent(f, s, 0, ""), mysql.NewFormatDescriptionEvent(f, s), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Database: "vt_test_keyspace", SQL: "BEGIN"}), @@ -634,9 +636,9 @@ func TestStreamerParseEventsRollback(t *testing.T) { Statements: nil, EventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -652,9 +654,9 @@ func TestStreamerParseEventsRollback(t *testing.T) { }, EventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -671,7 +673,7 @@ func TestStreamerParseEventsRollback(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, (&got).sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, (&got).sendTransaction) go sendTestEvents(events, input) if _, err := bls.parseEvents(context.Background(), events, errs); err != ErrServerEOF { @@ -691,7 +693,7 @@ func TestStreamerParseEventsDMLWithoutBegin(t *testing.T) { input := []mysql.BinlogEvent{ mysql.NewRotateEvent(f, s, 0, ""), mysql.NewFormatDescriptionEvent(f, s), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Database: "vt_test_keyspace", SQL: "insert into vt_a(eid, id) values (1, 1) /* _stream vt_a (eid id ) (1 1 ); */"}), @@ -709,9 +711,9 @@ func TestStreamerParseEventsDMLWithoutBegin(t *testing.T) { }, EventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -724,9 +726,9 @@ func TestStreamerParseEventsDMLWithoutBegin(t *testing.T) { Statements: nil, EventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -744,7 +746,7 @@ func TestStreamerParseEventsDMLWithoutBegin(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, (&got).sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, (&got).sendTransaction) go sendTestEvents(events, input) if _, err := bls.parseEvents(context.Background(), events, errs); err != ErrServerEOF { @@ -764,7 +766,7 @@ func TestStreamerParseEventsBeginWithoutCommit(t *testing.T) { input := []mysql.BinlogEvent{ mysql.NewRotateEvent(f, s, 0, ""), mysql.NewFormatDescriptionEvent(f, s), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Database: "vt_test_keyspace", SQL: "insert into vt_a(eid, id) values (1, 1) /* _stream vt_a (eid id ) (1 1 ); */"}), @@ -785,9 +787,9 @@ func TestStreamerParseEventsBeginWithoutCommit(t *testing.T) { }, EventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -800,9 +802,9 @@ func TestStreamerParseEventsBeginWithoutCommit(t *testing.T) { Statements: nil, EventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -820,7 +822,7 @@ func TestStreamerParseEventsBeginWithoutCommit(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, (&got).sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, (&got).sendTransaction) go sendTestEvents(events, input) if _, err := bls.parseEvents(context.Background(), events, errs); err != ErrServerEOF { @@ -840,7 +842,7 @@ func TestStreamerParseEventsSetInsertID(t *testing.T) { input := []mysql.BinlogEvent{ mysql.NewRotateEvent(f, s, 0, ""), mysql.NewFormatDescriptionEvent(f, s), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Database: "vt_test_keyspace", SQL: "BEGIN"}), @@ -863,9 +865,9 @@ func TestStreamerParseEventsSetInsertID(t *testing.T) { }, EventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -882,7 +884,7 @@ func TestStreamerParseEventsSetInsertID(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, (&got).sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, (&got).sendTransaction) go sendTestEvents(events, input) if _, err := bls.parseEvents(context.Background(), events, errs); err != ErrServerEOF { @@ -924,7 +926,7 @@ func TestStreamerParseEventsInvalidIntVar(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) go sendTestEvents(events, input) _, err := bls.parseEvents(context.Background(), events, errs) @@ -945,7 +947,7 @@ func TestStreamerParseEventsOtherDB(t *testing.T) { input := []mysql.BinlogEvent{ mysql.NewRotateEvent(f, s, 0, ""), mysql.NewFormatDescriptionEvent(f, s), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Database: "vt_test_keyspace", SQL: "BEGIN"}), @@ -969,9 +971,9 @@ func TestStreamerParseEventsOtherDB(t *testing.T) { }, EventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -988,7 +990,7 @@ func TestStreamerParseEventsOtherDB(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, (&got).sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, (&got).sendTransaction) go sendTestEvents(events, input) if _, err := bls.parseEvents(context.Background(), events, errs); err != ErrServerEOF { @@ -1008,7 +1010,7 @@ func TestStreamerParseEventsOtherDBBegin(t *testing.T) { input := []mysql.BinlogEvent{ mysql.NewRotateEvent(f, s, 0, ""), mysql.NewFormatDescriptionEvent(f, s), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 0xd}, false /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Database: "other", SQL: "BEGIN"}), // Check that this doesn't get filtered out. @@ -1032,9 +1034,9 @@ func TestStreamerParseEventsOtherDBBegin(t *testing.T) { }, EventToken: &querypb.EventToken{ Timestamp: 1407805592, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 0x0d, @@ -1051,7 +1053,7 @@ func TestStreamerParseEventsOtherDBBegin(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, (&got).sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, (&got).sendTransaction) go sendTestEvents(events, input) if _, err := bls.parseEvents(context.Background(), events, errs); err != ErrServerEOF { @@ -1093,7 +1095,7 @@ func TestStreamerParseEventsBeginAgain(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, sendTransaction) before := binlogStreamerErrors.Counts()["ParseEvents"] go sendTestEvents(events, input) @@ -1117,7 +1119,7 @@ func TestStreamerParseEventsMariadbBeginGTID(t *testing.T) { input := []mysql.BinlogEvent{ mysql.NewRotateEvent(f, s, 4, "filename.0001"), mysql.NewFormatDescriptionEvent(f, s), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 10}, true /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 10}, true /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Charset: &binlogdatapb.Charset{Client: 33, Conn: 33, Server: 33}, SQL: "insert into vt_insert_test(msg) values ('test 0') /* _stream vt_insert_test (id ) (null ); */", @@ -1144,9 +1146,9 @@ func TestStreamerParseEventsMariadbBeginGTID(t *testing.T) { }, EventToken: &querypb.EventToken{ Timestamp: 1409892744, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 10, @@ -1163,7 +1165,7 @@ func TestStreamerParseEventsMariadbBeginGTID(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, (&got).sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, (&got).sendTransaction) go sendTestEvents(events, input) if _, err := bls.parseEvents(context.Background(), events, errs); err != ErrServerEOF { @@ -1186,7 +1188,7 @@ func TestStreamerParseEventsMariadbStandaloneGTID(t *testing.T) { input := []mysql.BinlogEvent{ mysql.NewRotateEvent(f, s, 4, "filename.0001"), mysql.NewFormatDescriptionEvent(f, s), - mysql.NewMariaDBGTIDEvent(f, s, mysql.MariadbGTID{Domain: 0, Sequence: 9}, false /* hasBegin */), + mysql.NewMariaDBGTIDEvent(f, s, replication.MariadbGTID{Domain: 0, Sequence: 9}, false /* hasBegin */), mysql.NewQueryEvent(f, s, mysql.Query{ Charset: &binlogdatapb.Charset{Client: 8, Conn: 8, Server: 33}, SQL: "create table if not exists vt_insert_test (\nid bigint auto_increment,\nmsg varchar(64),\nprimary key (id)\n) Engine=InnoDB", @@ -1204,9 +1206,9 @@ func TestStreamerParseEventsMariadbStandaloneGTID(t *testing.T) { }, EventToken: &querypb.EventToken{ Timestamp: 1409892744, - Position: mysql.EncodePosition(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 0: mysql.MariadbGTID{ + Position: replication.EncodePosition(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 0: replication.MariadbGTID{ Domain: 0, Server: 62344, Sequence: 9, @@ -1223,7 +1225,7 @@ func TestStreamerParseEventsMariadbStandaloneGTID(t *testing.T) { } dbcfgs := dbconfigs.New(mcp) - bls := NewStreamer(dbcfgs, nil, nil, mysql.Position{}, 0, (&got).sendTransaction) + bls := NewStreamer(dbcfgs, nil, nil, replication.Position{}, 0, (&got).sendTransaction) go sendTestEvents(events, input) if _, err := bls.parseEvents(context.Background(), events, errs); err != ErrServerEOF { diff --git a/go/vt/binlog/binlogplayer/binlog_player.go b/go/vt/binlog/binlogplayer/binlog_player.go index 45d7338d705..f32462602be 100644 --- a/go/vt/binlog/binlogplayer/binlog_player.go +++ b/go/vt/binlog/binlogplayer/binlog_player.go @@ -35,6 +35,9 @@ import ( "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" + "google.golang.org/protobuf/proto" "vitess.io/vitess/go/history" @@ -71,7 +74,7 @@ type Stats struct { // Last saved status lastPositionMutex sync.Mutex - lastPosition mysql.Position + lastPosition replication.Position heartbeatMutex sync.Mutex heartbeat int64 @@ -114,14 +117,14 @@ func (bps *Stats) Heartbeat() int64 { } // SetLastPosition sets the last replication position. -func (bps *Stats) SetLastPosition(pos mysql.Position) { +func (bps *Stats) SetLastPosition(pos replication.Position) { bps.lastPositionMutex.Lock() defer bps.lastPositionMutex.Unlock() bps.lastPosition = pos } // LastPosition gets the last replication position. -func (bps *Stats) LastPosition() mysql.Position { +func (bps *Stats) LastPosition() replication.Position { bps.lastPositionMutex.Lock() defer bps.lastPositionMutex.Unlock() return bps.lastPosition @@ -175,8 +178,8 @@ type BinlogPlayer struct { // common to all uid int32 - position mysql.Position - stopPosition mysql.Position + position replication.Position + stopPosition replication.Position blplStats *Stats defaultCharset *binlogdatapb.Charset currentCharset *binlogdatapb.Charset @@ -337,9 +340,9 @@ func (blp *BinlogPlayer) applyEvents(ctx context.Context) error { var stream BinlogTransactionStream if len(blp.tables) > 0 { - stream, err = blplClient.StreamTables(ctx, mysql.EncodePosition(blp.position), blp.tables, blp.defaultCharset) + stream, err = blplClient.StreamTables(ctx, replication.EncodePosition(blp.position), blp.tables, blp.defaultCharset) } else { - stream, err = blplClient.StreamKeyRange(ctx, mysql.EncodePosition(blp.position), blp.keyRange, blp.defaultCharset) + stream, err = blplClient.StreamKeyRange(ctx, replication.EncodePosition(blp.position), blp.keyRange, blp.defaultCharset) } if err != nil { err := fmt.Errorf("error sending streaming query to binlog server: %v", err) @@ -434,7 +437,7 @@ func (blp *BinlogPlayer) processTransaction(tx *binlogdatapb.BinlogTransaction) if _, err = blp.exec(string(stmt.Sql)); err == nil { continue } - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERLockDeadlock { + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Number() == sqlerror.ERLockDeadlock { // Deadlock: ask for retry log.Infof("Deadlock: %v", err) if err = blp.dbClient.Rollback(); err != nil { @@ -520,8 +523,8 @@ func (blp *BinlogPlayer) setVReplicationState(state binlogdatapb.VReplicationWor // VRSettings contains the settings of a vreplication table. type VRSettings struct { - StartPos mysql.Position - StopPos mysql.Position + StartPos replication.Position + StopPos replication.Position MaxTPS int64 MaxReplicationLag int64 State binlogdatapb.VReplicationWorkflowState @@ -557,7 +560,7 @@ func ReadVRSettings(dbClient DBClient, uid int32) (VRSettings, error) { if err != nil { return VRSettings{}, fmt.Errorf("failed to parse pos column: %v", err) } - stopPos, err := mysql.DecodePosition(vrRow.AsString("stop_pos", "")) + stopPos, err := replication.DecodePosition(vrRow.AsString("stop_pos", "")) if err != nil { return VRSettings{}, fmt.Errorf("failed to parse stop_pos column: %v", err) } @@ -609,8 +612,8 @@ func CreateVReplicationState(workflow string, source *binlogdatapb.BinlogSource, } // GenerateUpdatePos returns a statement to record the latest processed gtid in the _vt.vreplication table. -func GenerateUpdatePos(uid int32, pos mysql.Position, timeUpdated int64, txTimestamp int64, rowsCopied int64, compress bool) string { - strGTID := encodeString(mysql.EncodePosition(pos)) +func GenerateUpdatePos(uid int32, pos replication.Position, timeUpdated int64, txTimestamp int64, rowsCopied int64, compress bool) string { + strGTID := encodeString(replication.EncodePosition(pos)) if compress { strGTID = fmt.Sprintf("compress(%s)", strGTID) } @@ -731,12 +734,12 @@ func MysqlUncompress(input string) []byte { } // DecodePosition attempts to uncompress the passed value first and if it fails tries to decode it as a valid GTID -func DecodePosition(gtid string) (mysql.Position, error) { +func DecodePosition(gtid string) (replication.Position, error) { b := MysqlUncompress(gtid) if b != nil { gtid = string(b) } - return mysql.DecodePosition(gtid) + return replication.DecodePosition(gtid) } // StatsHistoryRecord is used to store a Message with timestamp diff --git a/go/vt/binlog/binlogplayer/binlog_player_test.go b/go/vt/binlog/binlogplayer/binlog_player_test.go index e8dd93ef46e..db091139331 100644 --- a/go/vt/binlog/binlogplayer/binlog_player_test.go +++ b/go/vt/binlog/binlogplayer/binlog_player_test.go @@ -17,15 +17,15 @@ limitations under the License. package binlogplayer import ( + "context" "errors" "testing" "time" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" querypb "vitess.io/vitess/go/vt/proto/query" - "context" - - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/throttler" @@ -326,7 +326,7 @@ func TestRetryOnDeadlock(t *testing.T) { dbClient := NewMockDBClient(t) dbClient.ExpectRequest("update _vt.vreplication set state='Running', message='' where id=1", testDMLResponse, nil) dbClient.ExpectRequest("select pos, stop_pos, max_tps, max_replication_lag, state, workflow_type, workflow, workflow_sub_type, defer_secondary_keys from _vt.vreplication where id=1", testSettingsResponse, nil) - deadlocked := &mysql.SQLError{Num: 1213, Message: "deadlocked"} + deadlocked := &sqlerror.SQLError{Num: 1213, Message: "deadlocked"} dbClient.ExpectRequest("begin", nil, nil) dbClient.ExpectRequest("insert into t values(1)", nil, deadlocked) dbClient.ExpectRequest("rollback", nil, nil) @@ -400,24 +400,24 @@ func TestCreateVReplicationTables(t *testing.T) { } func TestUpdateVReplicationPos(t *testing.T) { - gtid := mysql.MustParseGTID("MariaDB", "0-1-8283") + gtid := replication.MustParseGTID("MariaDB", "0-1-8283") want := "update _vt.vreplication " + "set pos='MariaDB/0-1-8283', time_updated=88822, rows_copied=0, message='' " + "where id=78522" - got := GenerateUpdatePos(78522, mysql.Position{GTIDSet: gtid.GTIDSet()}, 88822, 0, 0, false) + got := GenerateUpdatePos(78522, replication.Position{GTIDSet: gtid.GTIDSet()}, 88822, 0, 0, false) if got != want { t.Errorf("updateVReplicationPos() = %#v, want %#v", got, want) } } func TestUpdateVReplicationTimestamp(t *testing.T) { - gtid := mysql.MustParseGTID("MariaDB", "0-2-582") + gtid := replication.MustParseGTID("MariaDB", "0-2-582") want := "update _vt.vreplication " + "set pos='MariaDB/0-2-582', time_updated=88822, transaction_timestamp=481828, rows_copied=0, message='' " + "where id=78522" - got := GenerateUpdatePos(78522, mysql.Position{GTIDSet: gtid.GTIDSet()}, 88822, 481828, 0, false) + got := GenerateUpdatePos(78522, replication.Position{GTIDSet: gtid.GTIDSet()}, 88822, 481828, 0, false) if got != want { t.Errorf("updateVReplicationPos() = %#v, want %#v", got, want) } diff --git a/go/vt/binlog/binlogplayer/dbclient.go b/go/vt/binlog/binlogplayer/dbclient.go index 594a0639473..f9cd03691a5 100644 --- a/go/vt/binlog/binlogplayer/dbclient.go +++ b/go/vt/binlog/binlogplayer/dbclient.go @@ -22,6 +22,7 @@ import ( "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" @@ -66,7 +67,7 @@ func NewDBClient(params dbconfigs.Connector) DBClient { } func (dc *dbClientImpl) handleError(err error) { - if mysql.IsConnErr(err) { + if sqlerror.IsConnErr(err) { dc.Close() } } diff --git a/go/vt/binlog/event_streamer.go b/go/vt/binlog/event_streamer.go index a8cce64a0c9..a872b089bff 100644 --- a/go/vt/binlog/event_streamer.go +++ b/go/vt/binlog/event_streamer.go @@ -17,14 +17,13 @@ limitations under the License. package binlog import ( + "context" "encoding/base64" "fmt" "strconv" "strings" - "context" - - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" @@ -52,7 +51,7 @@ type EventStreamer struct { } // NewEventStreamer returns a new EventStreamer on top of a Streamer -func NewEventStreamer(cp dbconfigs.Connector, se *schema.Engine, startPos mysql.Position, timestamp int64, sendEvent sendEventFunc) *EventStreamer { +func NewEventStreamer(cp dbconfigs.Connector, se *schema.Engine, startPos replication.Position, timestamp int64, sendEvent sendEventFunc) *EventStreamer { evs := &EventStreamer{ sendEvent: sendEvent, } diff --git a/go/vt/binlog/eventtoken/compare.go b/go/vt/binlog/eventtoken/compare.go index 2fe908527d2..e1c9501a8dc 100644 --- a/go/vt/binlog/eventtoken/compare.go +++ b/go/vt/binlog/eventtoken/compare.go @@ -19,7 +19,7 @@ limitations under the License. package eventtoken import ( - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" querypb "vitess.io/vitess/go/vt/proto/query" ) @@ -45,11 +45,11 @@ func Fresher(ev1, ev2 *querypb.EventToken) int { } // We can parse them. - pos1, err := mysql.DecodePosition(ev1.Position) + pos1, err := replication.DecodePosition(ev1.Position) if err != nil { return -1 } - pos2, err := mysql.DecodePosition(ev2.Position) + pos2, err := replication.DecodePosition(ev2.Position) if err != nil { return -1 } diff --git a/go/vt/binlog/updatestreamctl.go b/go/vt/binlog/updatestreamctl.go index 7ece45cda9c..78d61c0860c 100644 --- a/go/vt/binlog/updatestreamctl.go +++ b/go/vt/binlog/updatestreamctl.go @@ -17,13 +17,12 @@ limitations under the License. package binlog import ( + "context" "fmt" "sync" "sync/atomic" - "context" - - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/stats" "vitess.io/vitess/go/tb" "vitess.io/vitess/go/vt/dbconfigs" @@ -250,7 +249,7 @@ func (updateStream *UpdateStreamImpl) IsEnabled() bool { // StreamKeyRange is part of the UpdateStream interface func (updateStream *UpdateStreamImpl) StreamKeyRange(ctx context.Context, position string, keyRange *topodatapb.KeyRange, charset *binlogdatapb.Charset, callback func(trans *binlogdatapb.BinlogTransaction) error) (err error) { - pos, err := mysql.DecodePosition(position) + pos, err := replication.DecodePosition(position) if err != nil { return err } @@ -290,7 +289,7 @@ func (updateStream *UpdateStreamImpl) StreamKeyRange(ctx context.Context, positi // StreamTables is part of the UpdateStream interface func (updateStream *UpdateStreamImpl) StreamTables(ctx context.Context, position string, tables []string, charset *binlogdatapb.Charset, callback func(trans *binlogdatapb.BinlogTransaction) error) (err error) { - pos, err := mysql.DecodePosition(position) + pos, err := replication.DecodePosition(position) if err != nil { return err } diff --git a/go/vt/dbconnpool/connection.go b/go/vt/dbconnpool/connection.go index bdf74b8a429..8e9a0f4a5c0 100644 --- a/go/vt/dbconnpool/connection.go +++ b/go/vt/dbconnpool/connection.go @@ -21,6 +21,7 @@ import ( "fmt" "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/dbconfigs" ) @@ -112,7 +113,7 @@ func (dbc *DBConnection) ExecuteStreamFetch(query string, callback func(*sqltype } func (dbc *DBConnection) handleError(err error) { - if mysql.IsConnErr(err) { + if sqlerror.IsConnErr(err) { dbc.Close() } } diff --git a/go/vt/mysqlctl/backup_test.go b/go/vt/mysqlctl/backup_test.go index ad69b9c6d08..75f54ebe66b 100644 --- a/go/vt/mysqlctl/backup_test.go +++ b/go/vt/mysqlctl/backup_test.go @@ -31,6 +31,8 @@ import ( "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/mysql/fakesqldb" "vitess.io/vitess/go/vt/logutil" @@ -609,7 +611,7 @@ func createFakeBackupRestoreEnv(t *testing.T) (*fakeBackupRestoreEnv, func()) { Keyspace: "test", Shard: "-", StartTime: time.Now(), - RestoreToPos: mysql.Position{}, + RestoreToPos: replication.Position{}, DryRun: false, Stats: stats, } diff --git a/go/vt/mysqlctl/backupengine.go b/go/vt/mysqlctl/backupengine.go index 8d6a92f705f..f0255f82b49 100644 --- a/go/vt/mysqlctl/backupengine.go +++ b/go/vt/mysqlctl/backupengine.go @@ -28,6 +28,8 @@ import ( "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/mysqlctl/backupstats" @@ -119,7 +121,7 @@ type RestoreParams struct { StartTime time.Time // RestoreToPos hints that a point in time recovery is requested, to recover up to the specific given pos. // When empty, the restore is a normal from full backup - RestoreToPos mysql.Position + RestoreToPos replication.Position // RestoreToTimestamp hints that a point in time recovery is requested, to recover up to, and excluding, the // given timestamp. // RestoreToTimestamp and RestoreToPos are mutually exclusive. @@ -268,14 +270,14 @@ type BackupManifest struct { BackupMethod string // Position is the replication position at which the backup was taken. - Position mysql.Position + Position replication.Position // PurgedPosition stands for purged GTIDs, information that is necessary for PITR recovery. This is specific to MySQL56 - PurgedPosition mysql.Position + PurgedPosition replication.Position // FromPosition is only applicable to incremental backups, and stands for the position from // which incremental changes are backed up. - FromPosition mysql.Position + FromPosition replication.Position // Incremental indicates whether this is an incremental backup Incremental bool diff --git a/go/vt/mysqlctl/binlogs_gtid.go b/go/vt/mysqlctl/binlogs_gtid.go index 9ecbf8c8ffc..20fc3dcd32e 100644 --- a/go/vt/mysqlctl/binlogs_gtid.go +++ b/go/vt/mysqlctl/binlogs_gtid.go @@ -23,7 +23,7 @@ import ( "strings" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" ) @@ -55,8 +55,8 @@ func (p *BackupManifestPath) String() string { // possible, or is empty. func ChooseBinlogsForIncrementalBackup( ctx context.Context, - backupFromGTIDSet mysql.GTIDSet, - purgedGTIDSet mysql.GTIDSet, + backupFromGTIDSet replication.GTIDSet, + purgedGTIDSet replication.GTIDSet, binaryLogs []string, pgtids func(ctx context.Context, binlog string) (gtids string, err error), ) ( @@ -65,13 +65,13 @@ func ChooseBinlogsForIncrementalBackup( incrementalBackupToGTID string, err error, ) { - var prevGTIDsUnion mysql.GTIDSet + var prevGTIDsUnion replication.GTIDSet for i, binlog := range binaryLogs { previousGtids, err := pgtids(ctx, binlog) if err != nil { return nil, "", "", vterrors.Wrapf(err, "cannot get previous gtids for binlog %v", binlog) } - previousGTIDsPos, err := mysql.ParsePosition(mysql.Mysql56FlavorID, previousGtids) + previousGTIDsPos, err := replication.ParsePosition(replication.Mysql56FlavorID, previousGtids) if err != nil { return nil, "", "", vterrors.Wrapf(err, "cannot decode binlog %s position in incremental backup: %v", binlog, previousGTIDsPos) } @@ -131,7 +131,7 @@ func ChooseBinlogsForIncrementalBackup( // IsValidIncrementalBakcup determines whether the given manifest can be used to extend a backup // based on baseGTIDSet. The manifest must be able to pick up from baseGTIDSet, and must extend it by at least // one entry. -func IsValidIncrementalBakcup(baseGTIDSet mysql.GTIDSet, purgedGTIDSet mysql.GTIDSet, manifest *BackupManifest) bool { +func IsValidIncrementalBakcup(baseGTIDSet replication.GTIDSet, purgedGTIDSet replication.GTIDSet, manifest *BackupManifest) bool { if manifest == nil { return false } @@ -160,7 +160,7 @@ func IsValidIncrementalBakcup(baseGTIDSet mysql.GTIDSet, purgedGTIDSet mysql.GTI // - zero or more incremental backups // The path ends with restoreToGTIDSet or goes beyond it. No shorter path will do the same. // The function returns an error when a path cannot be found. -func FindPITRPath(restoreToGTIDSet mysql.GTIDSet, manifests [](*BackupManifest)) (shortestPath [](*BackupManifest), err error) { +func FindPITRPath(restoreToGTIDSet replication.GTIDSet, manifests [](*BackupManifest)) (shortestPath [](*BackupManifest), err error) { sortedManifests := make([](*BackupManifest), 0, len(manifests)) for _, m := range manifests { if m != nil { @@ -200,8 +200,8 @@ func FindPITRPath(restoreToGTIDSet mysql.GTIDSet, manifests [](*BackupManifest)) var validRestorePaths []BackupManifestPath // recursive function that searches for all possible paths: - var findPaths func(baseGTIDSet mysql.GTIDSet, pathManifests []*BackupManifest, remainingManifests []*BackupManifest) - findPaths = func(baseGTIDSet mysql.GTIDSet, pathManifests []*BackupManifest, remainingManifests []*BackupManifest) { + var findPaths func(baseGTIDSet replication.GTIDSet, pathManifests []*BackupManifest, remainingManifests []*BackupManifest) + findPaths = func(baseGTIDSet replication.GTIDSet, pathManifests []*BackupManifest, remainingManifests []*BackupManifest) { // The algorithm was first designed to find all possible paths. But then we recognized that it will be // doing excessive work. At this time we choose to end the search once we find the first valid path, even if // it's not the most optimal. The next "if" statement is the addition to the algorithm, where we suffice with @@ -322,8 +322,8 @@ func FindPITRToTimePath(restoreToTime time.Time, manifests [](*BackupManifest)) var validRestorePaths []BackupManifestPath // recursive function that searches for all possible paths: - var findPaths func(baseGTIDSet mysql.GTIDSet, pathManifests []*BackupManifest, remainingManifests []*BackupManifest) error - findPaths = func(baseGTIDSet mysql.GTIDSet, pathManifests []*BackupManifest, remainingManifests []*BackupManifest) error { + var findPaths func(baseGTIDSet replication.GTIDSet, pathManifests []*BackupManifest, remainingManifests []*BackupManifest) error + findPaths = func(baseGTIDSet replication.GTIDSet, pathManifests []*BackupManifest, remainingManifests []*BackupManifest) error { // The algorithm was first designed to find all possible paths. But then we recognized that it will be // doing excessive work. At this time we choose to end the search once we find the first valid path, even if // it's not the most optimal. The next "if" statement is the addition to the algorithm, where we suffice with diff --git a/go/vt/mysqlctl/binlogs_gtid_test.go b/go/vt/mysqlctl/binlogs_gtid_test.go index 5102c2efc27..0d57928c49e 100644 --- a/go/vt/mysqlctl/binlogs_gtid_test.go +++ b/go/vt/mysqlctl/binlogs_gtid_test.go @@ -29,7 +29,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" ) func TestChooseBinlogsForIncrementalBackup(t *testing.T) { @@ -231,9 +231,9 @@ func TestChooseBinlogsForIncrementalBackup(t *testing.T) { } for _, tc := range tt { t.Run(tc.name, func(t *testing.T) { - backupPos, err := mysql.ParsePosition(mysql.Mysql56FlavorID, tc.backupPos) + backupPos, err := replication.ParsePosition(replication.Mysql56FlavorID, tc.backupPos) require.NoError(t, err) - gtidPurged, err := mysql.ParsePosition(mysql.Mysql56FlavorID, tc.gtidPurged) + gtidPurged, err := replication.ParsePosition(replication.Mysql56FlavorID, tc.gtidPurged) require.NoError(t, err) binlogsToBackup, fromGTID, toGTID, err := ChooseBinlogsForIncrementalBackup( context.Background(), @@ -268,8 +268,8 @@ func TestChooseBinlogsForIncrementalBackup(t *testing.T) { func TestIsValidIncrementalBakcup(t *testing.T) { incrementalManifest := func(backupPos string, backupFromPos string) *BackupManifest { return &BackupManifest{ - Position: mysql.MustParsePosition(mysql.Mysql56FlavorID, fmt.Sprintf("16b1039f-22b6-11ed-b765-0a43f95f28a3:%s", backupPos)), - FromPosition: mysql.MustParsePosition(mysql.Mysql56FlavorID, fmt.Sprintf("16b1039f-22b6-11ed-b765-0a43f95f28a3:%s", backupFromPos)), + Position: replication.MustParsePosition(replication.Mysql56FlavorID, fmt.Sprintf("16b1039f-22b6-11ed-b765-0a43f95f28a3:%s", backupPos)), + FromPosition: replication.MustParsePosition(replication.Mysql56FlavorID, fmt.Sprintf("16b1039f-22b6-11ed-b765-0a43f95f28a3:%s", backupFromPos)), Incremental: true, } } @@ -345,9 +345,9 @@ func TestIsValidIncrementalBakcup(t *testing.T) { } for i, tc := range tt { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { - basePos, err := mysql.ParsePosition(mysql.Mysql56FlavorID, tc.baseGTID) + basePos, err := replication.ParsePosition(replication.Mysql56FlavorID, tc.baseGTID) require.NoError(t, err) - purgedPos, err := mysql.ParsePosition(mysql.Mysql56FlavorID, tc.purgedGTID) + purgedPos, err := replication.ParsePosition(replication.Mysql56FlavorID, tc.purgedGTID) require.NoError(t, err) isValid := IsValidIncrementalBakcup(basePos.GTIDSet, purgedPos.GTIDSet, incrementalManifest(tc.backupPos, tc.backupFromPos)) assert.Equal(t, tc.expectIsValid, isValid) @@ -356,8 +356,8 @@ func TestIsValidIncrementalBakcup(t *testing.T) { } func TestFindPITRPath(t *testing.T) { - generatePosition := func(posRange string) mysql.Position { - return mysql.MustParsePosition(mysql.Mysql56FlavorID, fmt.Sprintf("16b1039f-22b6-11ed-b765-0a43f95f28a3:%s", posRange)) + generatePosition := func(posRange string) replication.Position { + return replication.MustParsePosition(replication.Mysql56FlavorID, fmt.Sprintf("16b1039f-22b6-11ed-b765-0a43f95f28a3:%s", posRange)) } fullManifest := func(backupPos string) *BackupManifest { return &BackupManifest{ @@ -547,17 +547,17 @@ func TestFindPITRPath(t *testing.T) { for i := range fullBackups { var err error fullBackup := fullBackups[i] - fullBackup.PurgedPosition, err = mysql.ParsePosition(mysql.Mysql56FlavorID, tc.purgedGTID) + fullBackup.PurgedPosition, err = replication.ParsePosition(replication.Mysql56FlavorID, tc.purgedGTID) require.NoError(t, err) defer func() { - fullBackup.PurgedPosition = mysql.Position{} + fullBackup.PurgedPosition = replication.Position{} }() } var manifests []*BackupManifest manifests = append(manifests, fullBackups...) manifests = append(manifests, tc.incrementalBackups...) - restorePos, err := mysql.ParsePosition(mysql.Mysql56FlavorID, tc.restoreGTID) + restorePos, err := replication.ParsePosition(replication.Mysql56FlavorID, tc.restoreGTID) require.NoErrorf(t, err, "%v", err) path, err := FindPITRPath(restorePos.GTIDSet, manifests) if tc.expectError != "" { @@ -585,8 +585,8 @@ func TestFindPITRPath(t *testing.T) { } func TestFindPITRToTimePath(t *testing.T) { - generatePosition := func(posRange string) mysql.Position { - return mysql.MustParsePosition(mysql.Mysql56FlavorID, fmt.Sprintf("16b1039f-22b6-11ed-b765-0a43f95f28a3:%s", posRange)) + generatePosition := func(posRange string) replication.Position { + return replication.MustParsePosition(replication.Mysql56FlavorID, fmt.Sprintf("16b1039f-22b6-11ed-b765-0a43f95f28a3:%s", posRange)) } fullManifest := func(backupPos string, timeStr string) *BackupManifest { _, err := ParseRFC3339(timeStr) @@ -811,10 +811,10 @@ func TestFindPITRToTimePath(t *testing.T) { for i := range fullBackups { var err error fullBackup := fullBackups[i] - fullBackup.PurgedPosition, err = mysql.ParsePosition(mysql.Mysql56FlavorID, tc.purgedGTID) + fullBackup.PurgedPosition, err = replication.ParsePosition(replication.Mysql56FlavorID, tc.purgedGTID) require.NoError(t, err) defer func() { - fullBackup.PurgedPosition = mysql.Position{} + fullBackup.PurgedPosition = replication.Position{} }() } var manifests []*BackupManifest diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go index 6f43255f9c1..b1593a815b2 100644 --- a/go/vt/mysqlctl/builtinbackupengine.go +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -35,6 +35,8 @@ import ( "github.com/spf13/pflag" "golang.org/x/sync/semaphore" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/ioutil" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/concurrency" @@ -211,15 +213,15 @@ func (be *BuiltinBackupEngine) ExecuteBackup(ctx context.Context, params BackupP } // getIncrementalFromPosGTIDSet turns the given string into a valid Mysql56GTIDSet -func getIncrementalFromPosGTIDSet(incrementalFromPos string) (mysql.Mysql56GTIDSet, error) { - pos, err := mysql.DecodePositionDefaultFlavor(incrementalFromPos, mysql.Mysql56FlavorID) +func getIncrementalFromPosGTIDSet(incrementalFromPos string) (replication.Mysql56GTIDSet, error) { + pos, err := replication.DecodePositionDefaultFlavor(incrementalFromPos, replication.Mysql56FlavorID) if err != nil { return nil, vterrors.Wrapf(err, "cannot decode position in incremental backup: %v", incrementalFromPos) } - if !pos.MatchesFlavor(mysql.Mysql56FlavorID) { + if !pos.MatchesFlavor(replication.Mysql56FlavorID) { return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "incremental backup only supports MySQL GTID positions. Got: %v", incrementalFromPos) } - ifPosGTIDSet, ok := pos.GTIDSet.(mysql.Mysql56GTIDSet) + ifPosGTIDSet, ok := pos.GTIDSet.(replication.Mysql56GTIDSet) if !ok { return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot get MySQL GTID value: %v", pos) } @@ -242,12 +244,12 @@ func (be *BuiltinBackupEngine) executeIncrementalBackup(ctx context.Context, par } // @@gtid_purged - getPurgedGTIDSet := func() (mysql.Position, mysql.Mysql56GTIDSet, error) { + getPurgedGTIDSet := func() (replication.Position, replication.Mysql56GTIDSet, error) { gtidPurged, err := params.Mysqld.GetGTIDPurged(ctx) if err != nil { return gtidPurged, nil, vterrors.Wrap(err, "can't get @@gtid_purged") } - purgedGTIDSet, ok := gtidPurged.GTIDSet.(mysql.Mysql56GTIDSet) + purgedGTIDSet, ok := gtidPurged.GTIDSet.(replication.Mysql56GTIDSet) if !ok { return gtidPurged, nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot get MySQL GTID purged value: %v", gtidPurged) } @@ -277,7 +279,7 @@ func (be *BuiltinBackupEngine) executeIncrementalBackup(ctx context.Context, par if err != nil { return false, vterrors.Wrap(err, "FindLatestSuccessfulBackup failed") } - params.IncrementalFromPos = mysql.EncodePosition(manifest.Position) + params.IncrementalFromPos = replication.EncodePosition(manifest.Position) params.Logger.Infof("auto evaluated incremental_from_pos: %s", params.IncrementalFromPos) } @@ -320,11 +322,11 @@ func (be *BuiltinBackupEngine) executeIncrementalBackup(ctx context.Context, par if err != nil { return false, vterrors.Wrapf(err, "cannot get binary logs to backup in incremental backup") } - incrementalBackupFromPosition, err := mysql.ParsePosition(mysql.Mysql56FlavorID, incrementalBackupFromGTID) + incrementalBackupFromPosition, err := replication.ParsePosition(replication.Mysql56FlavorID, incrementalBackupFromGTID) if err != nil { return false, vterrors.Wrapf(err, "cannot parse position %v", incrementalBackupFromGTID) } - incrementalBackupToPosition, err := mysql.ParsePosition(mysql.Mysql56FlavorID, incrementalBackupToGTID) + incrementalBackupToPosition, err := replication.ParsePosition(replication.Mysql56FlavorID, incrementalBackupToGTID) if err != nil { return false, vterrors.Wrapf(err, "cannot parse position %v", incrementalBackupToGTID) } @@ -378,7 +380,7 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac sourceIsPrimary := false superReadOnly := true //nolint readOnly := true //nolint - var replicationPosition mysql.Position + var replicationPosition replication.Position semiSyncSource, semiSyncReplica := params.Mysqld.SemiSyncEnabled() // See if we need to restart replication after backup. @@ -470,7 +472,7 @@ func (be *BuiltinBackupEngine) executeFullBackup(ctx context.Context, params Bac } // Backup everything, capture the error. - backupErr := be.backupFiles(ctx, params, bh, replicationPosition, gtidPurgedPosition, mysql.Position{}, nil, serverUUID, mysqlVersion, nil) + backupErr := be.backupFiles(ctx, params, bh, replicationPosition, gtidPurgedPosition, replication.Position{}, nil, serverUUID, mysqlVersion, nil) usable := backupErr == nil // Try to restart mysqld, use background context in case we timed out the original context @@ -550,9 +552,9 @@ func (be *BuiltinBackupEngine) backupFiles( ctx context.Context, params BackupParams, bh backupstorage.BackupHandle, - replicationPosition mysql.Position, - purgedPosition mysql.Position, - fromPosition mysql.Position, + replicationPosition replication.Position, + purgedPosition replication.Position, + fromPosition replication.Position, binlogFiles []string, serverUUID string, mysqlVersion string, @@ -1139,25 +1141,25 @@ func (be *BuiltinBackupEngine) ShouldDrainForBackup() bool { return true } -func getPrimaryPosition(ctx context.Context, tmc tmclient.TabletManagerClient, ts *topo.Server, keyspace, shard string) (mysql.Position, error) { +func getPrimaryPosition(ctx context.Context, tmc tmclient.TabletManagerClient, ts *topo.Server, keyspace, shard string) (replication.Position, error) { si, err := ts.GetShard(ctx, keyspace, shard) if err != nil { - return mysql.Position{}, vterrors.Wrap(err, "can't read shard") + return replication.Position{}, vterrors.Wrap(err, "can't read shard") } if topoproto.TabletAliasIsZero(si.PrimaryAlias) { - return mysql.Position{}, fmt.Errorf("shard %v/%v has no primary", keyspace, shard) + return replication.Position{}, fmt.Errorf("shard %v/%v has no primary", keyspace, shard) } ti, err := ts.GetTablet(ctx, si.PrimaryAlias) if err != nil { - return mysql.Position{}, fmt.Errorf("can't get primary tablet record %v: %v", topoproto.TabletAliasString(si.PrimaryAlias), err) + return replication.Position{}, fmt.Errorf("can't get primary tablet record %v: %v", topoproto.TabletAliasString(si.PrimaryAlias), err) } posStr, err := tmc.PrimaryPosition(ctx, ti.Tablet) if err != nil { - return mysql.Position{}, fmt.Errorf("can't get primary replication position: %v", err) + return replication.Position{}, fmt.Errorf("can't get primary replication position: %v", err) } - pos, err := mysql.DecodePosition(posStr) + pos, err := replication.DecodePosition(posStr) if err != nil { - return mysql.Position{}, fmt.Errorf("can't decode primary replication position %q: %v", posStr, err) + return replication.Position{}, fmt.Errorf("can't decode primary replication position %q: %v", posStr, err) } return pos, nil } diff --git a/go/vt/mysqlctl/builtinbackupengine_test.go b/go/vt/mysqlctl/builtinbackupengine_test.go index 906e250ecaf..f7af0cdc306 100644 --- a/go/vt/mysqlctl/builtinbackupengine_test.go +++ b/go/vt/mysqlctl/builtinbackupengine_test.go @@ -29,6 +29,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/mysql" @@ -487,7 +489,7 @@ func TestExecuteRestoreWithTimedOutContext(t *testing.T) { Keyspace: "test", Shard: "-", StartTime: time.Now(), - RestoreToPos: mysql.Position{}, + RestoreToPos: replication.Position{}, RestoreToTimestamp: time.Time{}, DryRun: false, Stats: fakeStats, diff --git a/go/vt/mysqlctl/fakemysqldaemon.go b/go/vt/mysqlctl/fakemysqldaemon.go index f7077d32b76..39ecca84156 100644 --- a/go/vt/mysqlctl/fakemysqldaemon.go +++ b/go/vt/mysqlctl/fakemysqldaemon.go @@ -26,8 +26,8 @@ import ( "sync/atomic" "time" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/mysql/fakesqldb" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/dbconnpool" "vitess.io/vitess/go/vt/mysqlctl/tmutils" @@ -73,10 +73,10 @@ type FakeMysqlDaemon struct { // CurrentPrimaryPosition is returned by PrimaryPosition // and ReplicationStatus - CurrentPrimaryPosition mysql.Position + CurrentPrimaryPosition replication.Position // CurrentSourceFilePosition is used to determine the executed file based positioning of the replication source. - CurrentSourceFilePosition mysql.Position + CurrentSourceFilePosition replication.Position // ReplicationStatusError is used by ReplicationStatus ReplicationStatusError error @@ -107,10 +107,10 @@ type FakeMysqlDaemon struct { // SetReplicationPositionPos is matched against the input of SetReplicationPosition. // If it doesn't match, SetReplicationPosition will return an error. - SetReplicationPositionPos mysql.Position + SetReplicationPositionPos replication.Position // StartReplicationUntilAfterPos is matched against the input - StartReplicationUntilAfterPos mysql.Position + StartReplicationUntilAfterPos replication.Position // SetReplicationSourceInputs are matched against the input of SetReplicationSource // (as "%v:%v"). If all of them don't match, SetReplicationSource will return an error. @@ -124,10 +124,10 @@ type FakeMysqlDaemon struct { // WaitPrimaryPositions is checked by WaitSourcePos, if the value is found // in it, then the function returns nil, else the function returns an error - WaitPrimaryPositions []mysql.Position + WaitPrimaryPositions []replication.Position // PromoteResult is returned by Promote - PromoteResult mysql.Position + PromoteResult replication.Position // PromoteError is used by Promote PromoteError error @@ -278,47 +278,47 @@ func (fmd *FakeMysqlDaemon) GetServerUUID(ctx context.Context) (string, error) { } // CurrentPrimaryPositionLocked is thread-safe -func (fmd *FakeMysqlDaemon) CurrentPrimaryPositionLocked(pos mysql.Position) { +func (fmd *FakeMysqlDaemon) CurrentPrimaryPositionLocked(pos replication.Position) { fmd.mu.Lock() defer fmd.mu.Unlock() fmd.CurrentPrimaryPosition = pos } // ReplicationStatus is part of the MysqlDaemon interface -func (fmd *FakeMysqlDaemon) ReplicationStatus() (mysql.ReplicationStatus, error) { +func (fmd *FakeMysqlDaemon) ReplicationStatus() (replication.ReplicationStatus, error) { if fmd.ReplicationStatusError != nil { - return mysql.ReplicationStatus{}, fmd.ReplicationStatusError + return replication.ReplicationStatus{}, fmd.ReplicationStatusError } fmd.mu.Lock() defer fmd.mu.Unlock() - return mysql.ReplicationStatus{ + return replication.ReplicationStatus{ Position: fmd.CurrentPrimaryPosition, FilePosition: fmd.CurrentSourceFilePosition, RelayLogSourceBinlogEquivalentPosition: fmd.CurrentSourceFilePosition, ReplicationLagSeconds: fmd.ReplicationLagSeconds, // implemented as AND to avoid changing all tests that were // previously using Replicating = false - IOState: mysql.ReplicationStatusToState(fmt.Sprintf("%v", fmd.Replicating && fmd.IOThreadRunning)), - SQLState: mysql.ReplicationStatusToState(fmt.Sprintf("%v", fmd.Replicating)), + IOState: replication.ReplicationStatusToState(fmt.Sprintf("%v", fmd.Replicating && fmd.IOThreadRunning)), + SQLState: replication.ReplicationStatusToState(fmt.Sprintf("%v", fmd.Replicating)), SourceHost: fmd.CurrentSourceHost, SourcePort: fmd.CurrentSourcePort, }, nil } // PrimaryStatus is part of the MysqlDaemon interface -func (fmd *FakeMysqlDaemon) PrimaryStatus(ctx context.Context) (mysql.PrimaryStatus, error) { +func (fmd *FakeMysqlDaemon) PrimaryStatus(ctx context.Context) (replication.PrimaryStatus, error) { if fmd.PrimaryStatusError != nil { - return mysql.PrimaryStatus{}, fmd.PrimaryStatusError + return replication.PrimaryStatus{}, fmd.PrimaryStatusError } - return mysql.PrimaryStatus{ + return replication.PrimaryStatus{ Position: fmd.CurrentPrimaryPosition, FilePosition: fmd.CurrentSourceFilePosition, }, nil } // GetGTIDPurged is part of the MysqlDaemon interface -func (fmd *FakeMysqlDaemon) GetGTIDPurged(ctx context.Context) (mysql.Position, error) { - return mysql.Position{}, nil +func (fmd *FakeMysqlDaemon) GetGTIDPurged(ctx context.Context) (replication.Position, error) { + return replication.Position{}, nil } // ResetReplication is part of the MysqlDaemon interface. @@ -371,7 +371,7 @@ func (fmd *FakeMysqlDaemon) GetPreviousGTIDs(ctx context.Context, binlog string) } // PrimaryPosition is part of the MysqlDaemon interface -func (fmd *FakeMysqlDaemon) PrimaryPosition() (mysql.Position, error) { +func (fmd *FakeMysqlDaemon) PrimaryPosition() (replication.Position, error) { return fmd.CurrentPrimaryPosition, nil } @@ -418,7 +418,7 @@ func (fmd *FakeMysqlDaemon) RestartReplication(hookExtraEnv map[string]string) e } // StartReplicationUntilAfter is part of the MysqlDaemon interface. -func (fmd *FakeMysqlDaemon) StartReplicationUntilAfter(ctx context.Context, pos mysql.Position) error { +func (fmd *FakeMysqlDaemon) StartReplicationUntilAfter(ctx context.Context, pos replication.Position) error { if !reflect.DeepEqual(fmd.StartReplicationUntilAfterPos, pos) { return fmt.Errorf("wrong pos for StartReplicationUntilAfter: expected %v got %v", fmd.SetReplicationPositionPos, pos) } @@ -446,7 +446,7 @@ func (fmd *FakeMysqlDaemon) StopIOThread(ctx context.Context) error { } // SetReplicationPosition is part of the MysqlDaemon interface. -func (fmd *FakeMysqlDaemon) SetReplicationPosition(ctx context.Context, pos mysql.Position) error { +func (fmd *FakeMysqlDaemon) SetReplicationPosition(ctx context.Context, pos replication.Position) error { if !reflect.DeepEqual(fmd.SetReplicationPositionPos, pos) { return fmt.Errorf("wrong pos for SetReplicationPosition: expected %v got %v", fmd.SetReplicationPositionPos, pos) } @@ -489,7 +489,7 @@ func (fmd *FakeMysqlDaemon) WaitForReparentJournal(ctx context.Context, timeCrea } // WaitSourcePos is part of the MysqlDaemon interface -func (fmd *FakeMysqlDaemon) WaitSourcePos(_ context.Context, pos mysql.Position) error { +func (fmd *FakeMysqlDaemon) WaitSourcePos(_ context.Context, pos replication.Position) error { if fmd.TimeoutHook != nil { return fmd.TimeoutHook() } @@ -502,12 +502,12 @@ func (fmd *FakeMysqlDaemon) WaitSourcePos(_ context.Context, pos mysql.Position) } // Promote is part of the MysqlDaemon interface -func (fmd *FakeMysqlDaemon) Promote(hookExtraEnv map[string]string) (mysql.Position, error) { +func (fmd *FakeMysqlDaemon) Promote(hookExtraEnv map[string]string) (replication.Position, error) { if fmd.PromoteLag > 0 { time.Sleep(fmd.PromoteLag) } if fmd.PromoteError != nil { - return mysql.Position{}, fmd.PromoteError + return replication.Position{}, fmd.PromoteError } return fmd.PromoteResult, nil } diff --git a/go/vt/mysqlctl/mysql_daemon.go b/go/vt/mysqlctl/mysql_daemon.go index 7633eac93bf..c0f97d438e6 100644 --- a/go/vt/mysqlctl/mysql_daemon.go +++ b/go/vt/mysqlctl/mysql_daemon.go @@ -19,7 +19,7 @@ package mysqlctl import ( "context" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/dbconnpool" "vitess.io/vitess/go/vt/mysqlctl/tmutils" @@ -52,12 +52,12 @@ type MysqlDaemon interface { // replication related methods StartReplication(hookExtraEnv map[string]string) error RestartReplication(hookExtraEnv map[string]string) error - StartReplicationUntilAfter(ctx context.Context, pos mysql.Position) error + StartReplicationUntilAfter(ctx context.Context, pos replication.Position) error StopReplication(hookExtraEnv map[string]string) error StopIOThread(ctx context.Context) error - ReplicationStatus() (mysql.ReplicationStatus, error) - PrimaryStatus(ctx context.Context) (mysql.PrimaryStatus, error) - GetGTIDPurged(ctx context.Context) (mysql.Position, error) + ReplicationStatus() (replication.ReplicationStatus, error) + PrimaryStatus(ctx context.Context) (replication.PrimaryStatus, error) + GetGTIDPurged(ctx context.Context) (replication.Position, error) SetSemiSyncEnabled(source, replica bool) error SemiSyncEnabled() (source, replica bool) SemiSyncExtensionLoaded() (bool, error) @@ -74,20 +74,20 @@ type MysqlDaemon interface { // reparenting related methods ResetReplication(ctx context.Context) error - PrimaryPosition() (mysql.Position, error) + PrimaryPosition() (replication.Position, error) IsReadOnly() (bool, error) IsSuperReadOnly() (bool, error) SetReadOnly(on bool) error SetSuperReadOnly(on bool) (ResetSuperReadOnlyFunc, error) - SetReplicationPosition(ctx context.Context, pos mysql.Position) error + SetReplicationPosition(ctx context.Context, pos replication.Position) error SetReplicationSource(ctx context.Context, host string, port int32, stopReplicationBefore bool, startReplicationAfter bool) error WaitForReparentJournal(ctx context.Context, timeCreatedNS int64) error - WaitSourcePos(context.Context, mysql.Position) error + WaitSourcePos(context.Context, replication.Position) error // Promote makes the current server the primary. It will not change // the read_only state of the server. - Promote(map[string]string) (mysql.Position, error) + Promote(map[string]string) (replication.Position, error) // Schema related methods GetSchema(ctx context.Context, dbName string, request *tabletmanagerdatapb.GetSchemaRequest) (*tabletmanagerdatapb.SchemaDefinition, error) diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index 15ced99bfa8..1f8c03a4d92 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -42,6 +42,8 @@ import ( "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/config" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" @@ -1244,7 +1246,7 @@ func (mysqld *Mysqld) ApplyBinlogFile(ctx context.Context, req *mysqlctlpb.Apply log.Infof("ApplyBinlogFile: disabling super_read_only") resetFunc, err := mysqld.SetSuperReadOnly(false) if err != nil { - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERUnknownSystemVariable { + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Number() == sqlerror.ERUnknownSystemVariable { log.Warningf("ApplyBinlogFile: server does not know about super_read_only, continuing anyway...") } else { log.Errorf("ApplyBinlogFile: unexpected error while trying to set super_read_only: %v", err) diff --git a/go/vt/mysqlctl/query.go b/go/vt/mysqlctl/query.go index 1063d1a20b7..ceed3f58e03 100644 --- a/go/vt/mysqlctl/query.go +++ b/go/vt/mysqlctl/query.go @@ -22,7 +22,7 @@ import ( "strings" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/dbconnpool" "vitess.io/vitess/go/vt/log" @@ -38,7 +38,7 @@ func getPoolReconnect(ctx context.Context, pool *dbconnpool.ConnectionPool) (*db // Run a test query to see if this connection is still good. if _, err := conn.ExecuteFetch("SELECT 1", 1, false); err != nil { // If we get a connection error, try to reconnect. - if sqlErr, ok := err.(*mysql.SQLError); ok && (sqlErr.Number() == mysql.CRServerGone || sqlErr.Number() == mysql.CRServerLost) { + if sqlErr, ok := err.(*sqlerror.SQLError); ok && (sqlErr.Number() == sqlerror.CRServerGone || sqlErr.Number() == sqlerror.CRServerLost) { if err := conn.Reconnect(ctx); err != nil { conn.Recycle() return nil, err diff --git a/go/vt/mysqlctl/reparent.go b/go/vt/mysqlctl/reparent.go index c75db53ace9..b5aba32ddfc 100644 --- a/go/vt/mysqlctl/reparent.go +++ b/go/vt/mysqlctl/reparent.go @@ -24,10 +24,10 @@ import ( "context" "time" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/log" ) @@ -42,10 +42,10 @@ func GenerateInitialBinlogEntry() string { // PopulateReparentJournal returns the SQL command to use to populate // the reparent_journal table, as well as the time_created_ns // value used. -func PopulateReparentJournal(timeCreatedNS int64, actionName, primaryAlias string, pos mysql.Position) string { - posStr := mysql.EncodePosition(pos) - if len(posStr) > mysql.MaximumPositionSize { - posStr = posStr[:mysql.MaximumPositionSize] +func PopulateReparentJournal(timeCreatedNS int64, actionName, primaryAlias string, pos replication.Position) string { + posStr := replication.EncodePosition(pos) + if len(posStr) > replication.MaximumPositionSize { + posStr = posStr[:replication.MaximumPositionSize] } return sqlparser.BuildParsedQuery("INSERT INTO %s.reparent_journal "+ "(time_created_ns, action_name, primary_alias, replication_position) "+ @@ -85,11 +85,11 @@ func (mysqld *Mysqld) WaitForReparentJournal(ctx context.Context, timeCreatedNS } // Promote will promote this server to be the new primary. -func (mysqld *Mysqld) Promote(hookExtraEnv map[string]string) (mysql.Position, error) { +func (mysqld *Mysqld) Promote(hookExtraEnv map[string]string) (replication.Position, error) { ctx := context.TODO() conn, err := getPoolReconnect(ctx, mysqld.dbaPool) if err != nil { - return mysql.Position{}, err + return replication.Position{}, err } defer conn.Recycle() @@ -106,7 +106,7 @@ func (mysqld *Mysqld) Promote(hookExtraEnv map[string]string) (mysql.Position, e } if err := mysqld.executeSuperQueryListConn(ctx, conn, cmds); err != nil { - return mysql.Position{}, err + return replication.Position{}, err } return conn.PrimaryPosition() } diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index c7588e9e12c..c343a222c5a 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -29,9 +29,9 @@ import ( "strings" "time" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/netutil" "vitess.io/vitess/go/vt/hook" "vitess.io/vitess/go/vt/log" @@ -87,7 +87,7 @@ func (mysqld *Mysqld) StartReplication(hookExtraEnv map[string]string) error { } // StartReplicationUntilAfter starts replication until replication has come to `targetPos`, then it stops replication -func (mysqld *Mysqld) StartReplicationUntilAfter(ctx context.Context, targetPos mysql.Position) error { +func (mysqld *Mysqld) StartReplicationUntilAfter(ctx context.Context, targetPos replication.Position) error { conn, err := getPoolReconnect(ctx, mysqld.dbaPool) if err != nil { return err @@ -100,7 +100,7 @@ func (mysqld *Mysqld) StartReplicationUntilAfter(ctx context.Context, targetPos } // StartSQLThreadUntilAfter starts replication's SQL thread(s) until replication has come to `targetPos`, then it stops it -func (mysqld *Mysqld) StartSQLThreadUntilAfter(ctx context.Context, targetPos mysql.Position) error { +func (mysqld *Mysqld) StartSQLThreadUntilAfter(ctx context.Context, targetPos replication.Position) error { conn, err := getPoolReconnect(ctx, mysqld.dbaPool) if err != nil { return err @@ -318,7 +318,7 @@ func (mysqld *Mysqld) SetSuperReadOnly(on bool) (ResetSuperReadOnlyFunc, error) } // WaitSourcePos lets replicas wait to given replication position -func (mysqld *Mysqld) WaitSourcePos(ctx context.Context, targetPos mysql.Position) error { +func (mysqld *Mysqld) WaitSourcePos(ctx context.Context, targetPos replication.Position) error { // Get a connection. conn, err := getPoolReconnect(ctx, mysqld.dbaPool) if err != nil { @@ -330,7 +330,7 @@ func (mysqld *Mysqld) WaitSourcePos(ctx context.Context, targetPos mysql.Positio // unless that flavor is also filePos. waitCommandName := "WaitUntilPositionCommand" var query string - if targetPos.MatchesFlavor(mysql.FilePosFlavorID) { + if targetPos.MatchesFlavor(replication.FilePosFlavorID) { // If we are the primary, WaitUntilFilePositionCommand will fail. // But position is most likely reached. So, check the position // first. @@ -386,10 +386,10 @@ func (mysqld *Mysqld) WaitSourcePos(ctx context.Context, targetPos mysql.Positio } // ReplicationStatus returns the server replication status -func (mysqld *Mysqld) ReplicationStatus() (mysql.ReplicationStatus, error) { +func (mysqld *Mysqld) ReplicationStatus() (replication.ReplicationStatus, error) { conn, err := getPoolReconnect(context.TODO(), mysqld.dbaPool) if err != nil { - return mysql.ReplicationStatus{}, err + return replication.ReplicationStatus{}, err } defer conn.Recycle() @@ -397,10 +397,10 @@ func (mysqld *Mysqld) ReplicationStatus() (mysql.ReplicationStatus, error) { } // PrimaryStatus returns the primary replication statuses -func (mysqld *Mysqld) PrimaryStatus(ctx context.Context) (mysql.PrimaryStatus, error) { +func (mysqld *Mysqld) PrimaryStatus(ctx context.Context) (replication.PrimaryStatus, error) { conn, err := getPoolReconnect(ctx, mysqld.dbaPool) if err != nil { - return mysql.PrimaryStatus{}, err + return replication.PrimaryStatus{}, err } defer conn.Recycle() @@ -408,10 +408,10 @@ func (mysqld *Mysqld) PrimaryStatus(ctx context.Context) (mysql.PrimaryStatus, e } // GetGTIDPurged returns the gtid purged statuses -func (mysqld *Mysqld) GetGTIDPurged(ctx context.Context) (mysql.Position, error) { +func (mysqld *Mysqld) GetGTIDPurged(ctx context.Context) (replication.Position, error) { conn, err := getPoolReconnect(ctx, mysqld.dbaPool) if err != nil { - return mysql.Position{}, err + return replication.Position{}, err } defer conn.Recycle() @@ -419,10 +419,10 @@ func (mysqld *Mysqld) GetGTIDPurged(ctx context.Context) (mysql.Position, error) } // PrimaryPosition returns the primary replication position. -func (mysqld *Mysqld) PrimaryPosition() (mysql.Position, error) { +func (mysqld *Mysqld) PrimaryPosition() (replication.Position, error) { conn, err := getPoolReconnect(context.TODO(), mysqld.dbaPool) if err != nil { - return mysql.Position{}, err + return replication.Position{}, err } defer conn.Recycle() @@ -431,7 +431,7 @@ func (mysqld *Mysqld) PrimaryPosition() (mysql.Position, error) { // SetReplicationPosition sets the replication position at which the replica will resume // when its replication is started. -func (mysqld *Mysqld) SetReplicationPosition(ctx context.Context, pos mysql.Position) error { +func (mysqld *Mysqld) SetReplicationPosition(ctx context.Context, pos replication.Position) error { conn, err := getPoolReconnect(ctx, mysqld.dbaPool) if err != nil { return err diff --git a/go/vt/mysqlctl/schema.go b/go/vt/mysqlctl/schema.go index 4097fdc6ac8..dc9590474d5 100644 --- a/go/vt/mysqlctl/schema.go +++ b/go/vt/mysqlctl/schema.go @@ -25,7 +25,7 @@ import ( "golang.org/x/sync/errgroup" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqlescape" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/concurrency" @@ -128,8 +128,8 @@ func (mysqld *Mysqld) GetSchema(ctx context.Context, dbName string, request *tab // the list of tables (collectBasicTableData(), earlier) and the point above where we investigate // the table. // This is fine. We identify the situation and keep the table without any fields/columns/key information - sqlErr, isSQLErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) - if isSQLErr && sqlErr != nil && sqlErr.Number() == mysql.ERNoSuchTable { + sqlErr, isSQLErr := sqlerror.NewSQLErrorFromError(err).(*sqlerror.SQLError) + if isSQLErr && sqlErr != nil && sqlErr.Number() == sqlerror.ERNoSuchTable { return nil } diff --git a/go/vt/mysqlctl/xtrabackupengine.go b/go/vt/mysqlctl/xtrabackupengine.go index eb7d228a6fa..59cd4cb9d95 100644 --- a/go/vt/mysqlctl/xtrabackupengine.go +++ b/go/vt/mysqlctl/xtrabackupengine.go @@ -32,7 +32,8 @@ import ( "github.com/spf13/pflag" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/mysqlctl/backupstorage" "vitess.io/vitess/go/vt/proto/vtrpc" @@ -291,7 +292,7 @@ func (be *XtrabackupEngine) backupFiles( backupFileName string, numStripes int, flavor string, -) (replicationPosition mysql.Position, finalErr error) { +) (replicationPosition replication.Position, finalErr error) { backupProgram := path.Join(xtrabackupEnginePath, xtrabackupBinaryName) flagsToExec := []string{"--defaults-file=" + params.Cnf.Path, @@ -753,10 +754,10 @@ func (be *XtrabackupEngine) extractFiles(ctx context.Context, logger logutil.Log var xtrabackupReplicationPositionRegexp = regexp.MustCompile(`GTID of the last change '([^']*)'`) -func findReplicationPosition(input, flavor string, logger logutil.Logger) (mysql.Position, error) { +func findReplicationPosition(input, flavor string, logger logutil.Logger) (replication.Position, error) { match := xtrabackupReplicationPositionRegexp.FindStringSubmatch(input) if match == nil || len(match) != 2 { - return mysql.Position{}, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "couldn't find replication position in xtrabackup stderr output") + return replication.Position{}, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "couldn't find replication position in xtrabackup stderr output") } position := match[1] // Remove all spaces, tabs, and newlines. @@ -765,13 +766,13 @@ func findReplicationPosition(input, flavor string, logger logutil.Logger) (mysql position = strings.Replace(position, "\n", "", -1) logger.Infof("Found position: %v", position) if position == "" { - return mysql.Position{}, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "empty replication position from xtrabackup") + return replication.Position{}, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "empty replication position from xtrabackup") } // flavor is required to parse a string into a mysql.Position - replicationPosition, err := mysql.ParsePosition(flavor, position) + replicationPosition, err := replication.ParsePosition(flavor, position) if err != nil { - return mysql.Position{}, vterrors.Wrapf(err, "can't parse replication position from xtrabackup: %v", position) + return replication.Position{}, vterrors.Wrapf(err, "can't parse replication position from xtrabackup: %v", position) } return replicationPosition, nil } diff --git a/go/vt/sidecardb/sidecardb.go b/go/vt/sidecardb/sidecardb.go index 19bed3e5340..f88ebb7a667 100644 --- a/go/vt/sidecardb/sidecardb.go +++ b/go/vt/sidecardb/sidecardb.go @@ -29,7 +29,7 @@ import ( "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/history" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/mysql/fakesqldb" @@ -362,7 +362,7 @@ func (si *schemaInit) getCurrentSchema(tableName string) (string, error) { escapedTableName := sqlparser.String(sqlparser.NewIdentifierCS(tableName)) rs, err := si.exec(si.ctx, sqlparser.BuildParsedQuery(showCreateTableQuery, GetIdentifier(), escapedTableName).Query, 1, false) if err != nil { - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERNoSuchTable { + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Number() == sqlerror.ERNoSuchTable { // table does not exist in the sidecar database return "", nil } diff --git a/go/vt/vtadmin/cluster/cluster_test.go b/go/vt/vtadmin/cluster/cluster_test.go index 202937bb95f..cc37d65c487 100644 --- a/go/vt/vtadmin/cluster/cluster_test.go +++ b/go/vt/vtadmin/cluster/cluster_test.go @@ -29,7 +29,8 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/protoutil" "vitess.io/vitess/go/sets" "vitess.io/vitess/go/test/utils" @@ -2772,18 +2773,18 @@ func TestGetShardReplicationPositions(t *testing.T) { Response: &vtctldatapb.ShardReplicationPositionsResponse{ ReplicationStatuses: map[string]*replicationdatapb.Status{ "zone1-001": { - IoState: int32(mysql.ReplicationStateStopped), - SqlState: int32(mysql.ReplicationStateStopped), + IoState: int32(replication.ReplicationStateStopped), + SqlState: int32(replication.ReplicationStateStopped), Position: "MySQL56/08d0dbbb-be29-11eb-9fea-0aafb9701138:1-109848265", }, "zone1-002": { // Note: in reality other fields will be set on replicating hosts as well, but this is sufficient to illustrate in the testing. - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), Position: "MySQL56/08d0dbbb-be29-11eb-9fea-0aafb9701138:1-109848265", }, "zone1-003": { - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), Position: "MySQL56/08d0dbbb-be29-11eb-9fea-0aafb9701138:1-109848265", }, }, @@ -2835,18 +2836,18 @@ func TestGetShardReplicationPositions(t *testing.T) { PositionInfo: &vtctldatapb.ShardReplicationPositionsResponse{ ReplicationStatuses: map[string]*replicationdatapb.Status{ "zone1-001": { - IoState: int32(mysql.ReplicationStateStopped), - SqlState: int32(mysql.ReplicationStateStopped), + IoState: int32(replication.ReplicationStateStopped), + SqlState: int32(replication.ReplicationStateStopped), Position: "MySQL56/08d0dbbb-be29-11eb-9fea-0aafb9701138:1-109848265", }, "zone1-002": { - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), Position: "MySQL56/08d0dbbb-be29-11eb-9fea-0aafb9701138:1-109848265", }, "zone1-003": { - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), Position: "MySQL56/08d0dbbb-be29-11eb-9fea-0aafb9701138:1-109848265", }, }, diff --git a/go/vt/vtctl/grpcvtctldserver/server_slow_test.go b/go/vt/vtctl/grpcvtctldserver/server_slow_test.go index 50ca8ea82be..9e38d936c42 100644 --- a/go/vt/vtctl/grpcvtctldserver/server_slow_test.go +++ b/go/vt/vtctl/grpcvtctldserver/server_slow_test.go @@ -24,6 +24,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/protoutil" "vitess.io/vitess/go/vt/topo" @@ -140,7 +142,7 @@ func TestEmergencyReparentShardSlow(t *testing.T) { }, "zone1-0000000200": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5", @@ -258,7 +260,7 @@ func TestEmergencyReparentShardSlow(t *testing.T) { }, "zone1-0000000200": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5", diff --git a/go/vt/vtctl/grpcvtctldserver/server_test.go b/go/vt/vtctl/grpcvtctldserver/server_test.go index 5a25e074290..01d6c4beca3 100644 --- a/go/vt/vtctl/grpcvtctldserver/server_test.go +++ b/go/vt/vtctl/grpcvtctldserver/server_test.go @@ -27,6 +27,7 @@ import ( "time" _flag "vitess.io/vitess/go/internal/flag" + "vitess.io/vitess/go/mysql/replication" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -3442,7 +3443,7 @@ func TestEmergencyReparentShard(t *testing.T) { }, "zone1-0000000200": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5", diff --git a/go/vt/vtctl/reparentutil/emergency_reparenter.go b/go/vt/vtctl/reparentutil/emergency_reparenter.go index ad467782a38..1c31372f365 100644 --- a/go/vt/vtctl/reparentutil/emergency_reparenter.go +++ b/go/vt/vtctl/reparentutil/emergency_reparenter.go @@ -24,8 +24,9 @@ import ( "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/event" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sets" "vitess.io/vitess/go/stats" "vitess.io/vitess/go/vt/concurrency" @@ -150,7 +151,7 @@ func (erp *EmergencyReparenter) reparentShardLocked(ctx context.Context, ev *eve shardInfo *topo.ShardInfo prevPrimary *topodatapb.Tablet tabletMap map[string]*topo.TabletInfo - validCandidates map[string]mysql.Position + validCandidates map[string]replication.Position intermediateSource *topodatapb.Tablet validCandidateTablets []*topodatapb.Tablet validReplacementCandidates []*topodatapb.Tablet @@ -308,7 +309,7 @@ func (erp *EmergencyReparenter) reparentShardLocked(ctx context.Context, ev *eve func (erp *EmergencyReparenter) waitForAllRelayLogsToApply( ctx context.Context, - validCandidates map[string]mysql.Position, + validCandidates map[string]replication.Position, tabletMap map[string]*topo.TabletInfo, statusMap map[string]*replicationdatapb.StopReplicationStatus, waitReplicasTimeout time.Duration, @@ -374,7 +375,7 @@ func (erp *EmergencyReparenter) waitForAllRelayLogsToApply( // findMostAdvanced finds the intermediate source for ERS. We always choose the most advanced one from our valid candidates list. Further ties are broken by looking at the promotion rules. func (erp *EmergencyReparenter) findMostAdvanced( - validCandidates map[string]mysql.Position, + validCandidates map[string]replication.Position, tabletMap map[string]*topo.TabletInfo, opts EmergencyReparentOptions, ) (*topodatapb.Tablet, []*topodatapb.Tablet, error) { diff --git a/go/vt/vtctl/reparentutil/emergency_reparenter_test.go b/go/vt/vtctl/reparentutil/emergency_reparenter_test.go index fad4dfeb15b..5d03b60affa 100644 --- a/go/vt/vtctl/reparentutil/emergency_reparenter_test.go +++ b/go/vt/vtctl/reparentutil/emergency_reparenter_test.go @@ -25,6 +25,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sets" "vitess.io/vitess/go/vt/logutil" @@ -161,7 +163,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -170,7 +172,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -179,7 +181,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-26", @@ -278,7 +280,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -287,7 +289,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -296,7 +298,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-26", @@ -423,7 +425,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -432,7 +434,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -441,7 +443,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -552,7 +554,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -561,7 +563,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-26", @@ -705,13 +707,13 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { Error error }{ "zone1-0000000100": { - StopStatus: &replicationdatapb.StopReplicationStatus{Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}}, + StopStatus: &replicationdatapb.StopReplicationStatus{Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}}, }, "zone1-0000000101": { - StopStatus: &replicationdatapb.StopReplicationStatus{Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}}, + StopStatus: &replicationdatapb.StopReplicationStatus{Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}}, }, "zone1-0000000102": { - StopStatus: &replicationdatapb.StopReplicationStatus{Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}}, + StopStatus: &replicationdatapb.StopReplicationStatus{Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}}, }, }, }, @@ -765,7 +767,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -774,7 +776,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -783,7 +785,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{}, }, }, @@ -859,7 +861,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -868,7 +870,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -877,7 +879,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -954,7 +956,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -963,7 +965,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -972,7 +974,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1076,7 +1078,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1085,7 +1087,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-20", @@ -1094,7 +1096,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-20", @@ -1189,7 +1191,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1198,7 +1200,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1207,7 +1209,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1312,7 +1314,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1321,7 +1323,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1330,7 +1332,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-26", @@ -1432,7 +1434,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1441,7 +1443,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1450,7 +1452,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-26", @@ -1547,7 +1549,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1556,7 +1558,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1565,7 +1567,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-26", @@ -1680,7 +1682,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1689,7 +1691,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1698,7 +1700,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-26", @@ -1812,7 +1814,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1821,7 +1823,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -1830,7 +1832,7 @@ func TestEmergencyReparenter_reparentShardLocked(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-26", @@ -2032,14 +2034,14 @@ func TestEmergencyReparenter_promoteNewPrimary(t *testing.T) { statusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000101": { // forceStart = false Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateStopped), - SqlState: int32(mysql.ReplicationStateStopped), + IoState: int32(replication.ReplicationStateStopped), + SqlState: int32(replication.ReplicationStateStopped), }, }, "zone1-0000000102": { // forceStart = true Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), }, }, }, @@ -2410,14 +2412,14 @@ func TestEmergencyReparenter_promoteNewPrimary(t *testing.T) { statusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000101": { // forceStart = false Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateStopped), - SqlState: int32(mysql.ReplicationStateStopped), + IoState: int32(replication.ReplicationStateStopped), + SqlState: int32(replication.ReplicationStateStopped), }, }, "zone1-0000000102": { // forceStart = true Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), }, }, }, @@ -2494,7 +2496,7 @@ func TestEmergencyReparenter_waitForAllRelayLogsToApply(t *testing.T) { tests := []struct { name string tmc *testutil.TabletManagerClient - candidates map[string]mysql.Position + candidates map[string]replication.Position tabletMap map[string]*topo.TabletInfo statusMap map[string]*replicationdatapb.StopReplicationStatus shouldErr bool @@ -2511,7 +2513,7 @@ func TestEmergencyReparenter_waitForAllRelayLogsToApply(t *testing.T) { }, }, }, - candidates: map[string]mysql.Position{ + candidates: map[string]replication.Position{ "zone1-0000000100": {}, "zone1-0000000101": {}, }, @@ -2559,7 +2561,7 @@ func TestEmergencyReparenter_waitForAllRelayLogsToApply(t *testing.T) { }, }, }, - candidates: map[string]mysql.Position{ + candidates: map[string]replication.Position{ "zone1-0000000100": {}, "zone1-0000000101": {}, }, @@ -2610,7 +2612,7 @@ func TestEmergencyReparenter_waitForAllRelayLogsToApply(t *testing.T) { }, }, }, - candidates: map[string]mysql.Position{ + candidates: map[string]replication.Position{ "zone1-0000000100": {}, "zone1-0000000101": {}, "zone1-0000000102": {}, @@ -2675,7 +2677,7 @@ func TestEmergencyReparenter_waitForAllRelayLogsToApply(t *testing.T) { }, }, }, - candidates: map[string]mysql.Position{ + candidates: map[string]replication.Position{ "zone1-0000000100": {}, "zone1-0000000101": {}, }, @@ -2768,7 +2770,7 @@ func TestEmergencyReparenterCounters(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -2777,7 +2779,7 @@ func TestEmergencyReparenterCounters(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-21", @@ -2786,7 +2788,7 @@ func TestEmergencyReparenterCounters(t *testing.T) { }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{ SourceUuid: "3E11FA47-71CA-11E1-9E33-C80AA9429562", RelayLogPosition: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429562:1-26", @@ -2883,40 +2885,40 @@ func TestEmergencyReparenterCounters(t *testing.T) { } func TestEmergencyReparenter_findMostAdvanced(t *testing.T) { - sid1 := mysql.SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - mysqlGTID1 := mysql.Mysql56GTID{ + sid1 := replication.SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + mysqlGTID1 := replication.Mysql56GTID{ Server: sid1, Sequence: 9, } - mysqlGTID2 := mysql.Mysql56GTID{ + mysqlGTID2 := replication.Mysql56GTID{ Server: sid1, Sequence: 10, } - mysqlGTID3 := mysql.Mysql56GTID{ + mysqlGTID3 := replication.Mysql56GTID{ Server: sid1, Sequence: 11, } - positionMostAdvanced := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionMostAdvanced := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} positionMostAdvanced.GTIDSet = positionMostAdvanced.GTIDSet.AddGTID(mysqlGTID1) positionMostAdvanced.GTIDSet = positionMostAdvanced.GTIDSet.AddGTID(mysqlGTID2) positionMostAdvanced.GTIDSet = positionMostAdvanced.GTIDSet.AddGTID(mysqlGTID3) - positionIntermediate1 := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionIntermediate1 := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} positionIntermediate1.GTIDSet = positionIntermediate1.GTIDSet.AddGTID(mysqlGTID1) - positionIntermediate2 := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionIntermediate2 := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} positionIntermediate2.GTIDSet = positionIntermediate2.GTIDSet.AddGTID(mysqlGTID1) positionIntermediate2.GTIDSet = positionIntermediate2.GTIDSet.AddGTID(mysqlGTID2) - positionOnly2 := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionOnly2 := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} positionOnly2.GTIDSet = positionOnly2.GTIDSet.AddGTID(mysqlGTID2) - positionEmpty := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionEmpty := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} tests := []struct { name string - validCandidates map[string]mysql.Position + validCandidates map[string]replication.Position tabletMap map[string]*topo.TabletInfo emergencyReparentOps EmergencyReparentOptions result *topodatapb.Tablet @@ -2924,7 +2926,7 @@ func TestEmergencyReparenter_findMostAdvanced(t *testing.T) { }{ { name: "choose most advanced", - validCandidates: map[string]mysql.Position{ + validCandidates: map[string]replication.Position{ "zone1-0000000100": positionMostAdvanced, "zone1-0000000101": positionIntermediate1, "zone1-0000000102": positionIntermediate2, @@ -2972,7 +2974,7 @@ func TestEmergencyReparenter_findMostAdvanced(t *testing.T) { }, }, { name: "choose most advanced with the best promotion rule", - validCandidates: map[string]mysql.Position{ + validCandidates: map[string]replication.Position{ "zone1-0000000100": positionMostAdvanced, "zone1-0000000101": positionIntermediate1, "zone1-0000000102": positionMostAdvanced, @@ -3026,7 +3028,7 @@ func TestEmergencyReparenter_findMostAdvanced(t *testing.T) { Cell: "zone1", Uid: 102, }}, - validCandidates: map[string]mysql.Position{ + validCandidates: map[string]replication.Position{ "zone1-0000000100": positionMostAdvanced, "zone1-0000000101": positionIntermediate1, "zone1-0000000102": positionMostAdvanced, @@ -3080,7 +3082,7 @@ func TestEmergencyReparenter_findMostAdvanced(t *testing.T) { Cell: "zone1", Uid: 102, }}, - validCandidates: map[string]mysql.Position{ + validCandidates: map[string]replication.Position{ "zone1-0000000100": positionOnly2, "zone1-0000000101": positionIntermediate1, "zone1-0000000102": positionEmpty, @@ -3225,14 +3227,14 @@ func TestEmergencyReparenter_reparentReplicas(t *testing.T) { statusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000101": { // forceStart = false Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateStopped), - SqlState: int32(mysql.ReplicationStateStopped), + IoState: int32(replication.ReplicationStateStopped), + SqlState: int32(replication.ReplicationStateStopped), }, }, "zone1-0000000102": { // forceStart = true Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), }, }, }, @@ -3664,14 +3666,14 @@ func TestEmergencyReparenter_promoteIntermediateSource(t *testing.T) { statusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000101": { // forceStart = false Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateStopped), - SqlState: int32(mysql.ReplicationStateStopped), + IoState: int32(replication.ReplicationStateStopped), + SqlState: int32(replication.ReplicationStateStopped), }, }, "zone1-0000000102": { // forceStart = true Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), }, }, }, @@ -3938,14 +3940,14 @@ func TestEmergencyReparenter_promoteIntermediateSource(t *testing.T) { statusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000101": { // forceStart = false Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateStopped), - SqlState: int32(mysql.ReplicationStateStopped), + IoState: int32(replication.ReplicationStateStopped), + SqlState: int32(replication.ReplicationStateStopped), }, }, "zone1-0000000102": { // forceStart = true Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), }, }, }, @@ -4289,8 +4291,8 @@ func TestParentContextCancelled(t *testing.T) { statusMap := map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000101": { Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), }, }, } diff --git a/go/vt/vtctl/reparentutil/planned_reparenter.go b/go/vt/vtctl/reparentutil/planned_reparenter.go index 8a27fd8c4c2..242d1e973ef 100644 --- a/go/vt/vtctl/reparentutil/planned_reparenter.go +++ b/go/vt/vtctl/reparentutil/planned_reparenter.go @@ -25,8 +25,9 @@ import ( "golang.org/x/sync/errgroup" "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/event" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" @@ -376,7 +377,7 @@ func (pr *PlannedReparenter) performPotentialPromotion( type tabletPos struct { alias string tablet *topodatapb.Tablet - pos mysql.Position + pos replication.Position } positions := make(chan tabletPos, len(tabletMap)) @@ -423,7 +424,7 @@ func (pr *PlannedReparenter) performPotentialPromotion( return } - pos, err := mysql.DecodePosition(primaryStatus.Position) + pos, err := replication.DecodePosition(primaryStatus.Position) if err != nil { rec.RecordError(vterrors.Wrapf(err, "cannot decode replication position (%v) for demoted tablet %v", primaryStatus.Position, alias)) diff --git a/go/vt/vtctl/reparentutil/reparent_sorter.go b/go/vt/vtctl/reparentutil/reparent_sorter.go index 77547827d37..e4461b78064 100644 --- a/go/vt/vtctl/reparentutil/reparent_sorter.go +++ b/go/vt/vtctl/reparentutil/reparent_sorter.go @@ -19,7 +19,7 @@ package reparentutil import ( "sort" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/vterrors" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -30,12 +30,12 @@ import ( // candidate for intermediate promotion in emergency reparent shard, and the new primary in planned reparent shard type reparentSorter struct { tablets []*topodatapb.Tablet - positions []mysql.Position + positions []replication.Position durability Durabler } // newReparentSorter creates a new reparentSorter -func newReparentSorter(tablets []*topodatapb.Tablet, positions []mysql.Position, durability Durabler) *reparentSorter { +func newReparentSorter(tablets []*topodatapb.Tablet, positions []replication.Position, durability Durabler) *reparentSorter { return &reparentSorter{ tablets: tablets, positions: positions, @@ -84,7 +84,7 @@ func (rs *reparentSorter) Less(i, j int) bool { // sortTabletsForReparent sorts the tablets, given their positions for emergency reparent shard and planned reparent shard. // Tablets are sorted first by their replication positions, with ties broken by the promotion rules. -func sortTabletsForReparent(tablets []*topodatapb.Tablet, positions []mysql.Position, durability Durabler) error { +func sortTabletsForReparent(tablets []*topodatapb.Tablet, positions []replication.Position, durability Durabler) error { // throw an error internal error in case of unequal number of tablets and positions // fail-safe code prevents panic in sorting in case the lengths are unequal if len(tablets) != len(positions) { diff --git a/go/vt/vtctl/reparentutil/reparent_sorter_test.go b/go/vt/vtctl/reparentutil/reparent_sorter_test.go index 469d9ac2c88..c21c95ad22b 100644 --- a/go/vt/vtctl/reparentutil/reparent_sorter_test.go +++ b/go/vt/vtctl/reparentutil/reparent_sorter_test.go @@ -21,14 +21,15 @@ import ( "github.com/stretchr/testify/require" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) // TestReparentSorter tests that the sorting for tablets works correctly func TestReparentSorter(t *testing.T) { - sid1 := mysql.SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - sid2 := mysql.SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16} + sid1 := replication.SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + sid2 := replication.SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16} cell1 := "cell1" cell2 := "cell2" tabletReplica1_100 := &topodatapb.Tablet{ @@ -60,64 +61,64 @@ func TestReparentSorter(t *testing.T) { Type: topodatapb.TabletType_RDONLY, } - mysqlGTID1 := mysql.Mysql56GTID{ + mysqlGTID1 := replication.Mysql56GTID{ Server: sid1, Sequence: 9, } - mysqlGTID2 := mysql.Mysql56GTID{ + mysqlGTID2 := replication.Mysql56GTID{ Server: sid2, Sequence: 10, } - mysqlGTID3 := mysql.Mysql56GTID{ + mysqlGTID3 := replication.Mysql56GTID{ Server: sid1, Sequence: 11, } - positionMostAdvanced := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionMostAdvanced := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} positionMostAdvanced.GTIDSet = positionMostAdvanced.GTIDSet.AddGTID(mysqlGTID1) positionMostAdvanced.GTIDSet = positionMostAdvanced.GTIDSet.AddGTID(mysqlGTID2) positionMostAdvanced.GTIDSet = positionMostAdvanced.GTIDSet.AddGTID(mysqlGTID3) - positionEmpty := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionEmpty := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} - positionIntermediate1 := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionIntermediate1 := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} positionIntermediate1.GTIDSet = positionIntermediate1.GTIDSet.AddGTID(mysqlGTID1) - positionIntermediate2 := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionIntermediate2 := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} positionIntermediate2.GTIDSet = positionIntermediate2.GTIDSet.AddGTID(mysqlGTID1) positionIntermediate2.GTIDSet = positionIntermediate2.GTIDSet.AddGTID(mysqlGTID2) testcases := []struct { name string tablets []*topodatapb.Tablet - positions []mysql.Position + positions []replication.Position containsErr string sortedTablets []*topodatapb.Tablet }{ { name: "all advanced, sort via promotion rules", tablets: []*topodatapb.Tablet{nil, tabletReplica1_100, tabletRdonly1_102}, - positions: []mysql.Position{positionMostAdvanced, positionMostAdvanced, positionMostAdvanced}, + positions: []replication.Position{positionMostAdvanced, positionMostAdvanced, positionMostAdvanced}, sortedTablets: []*topodatapb.Tablet{tabletReplica1_100, tabletRdonly1_102, nil}, }, { name: "ordering by position", tablets: []*topodatapb.Tablet{tabletReplica1_101, tabletReplica2_100, tabletReplica1_100, tabletRdonly1_102}, - positions: []mysql.Position{positionEmpty, positionIntermediate1, positionIntermediate2, positionMostAdvanced}, + positions: []replication.Position{positionEmpty, positionIntermediate1, positionIntermediate2, positionMostAdvanced}, sortedTablets: []*topodatapb.Tablet{tabletRdonly1_102, tabletReplica1_100, tabletReplica2_100, tabletReplica1_101}, }, { name: "tablets and positions count error", tablets: []*topodatapb.Tablet{tabletReplica1_101, tabletReplica2_100}, - positions: []mysql.Position{positionEmpty, positionIntermediate1, positionMostAdvanced}, + positions: []replication.Position{positionEmpty, positionIntermediate1, positionMostAdvanced}, containsErr: "unequal number of tablets and positions", }, { name: "promotion rule check", tablets: []*topodatapb.Tablet{tabletReplica1_101, tabletRdonly1_102}, - positions: []mysql.Position{positionMostAdvanced, positionMostAdvanced}, + positions: []replication.Position{positionMostAdvanced, positionMostAdvanced}, sortedTablets: []*topodatapb.Tablet{tabletReplica1_101, tabletRdonly1_102}, }, { name: "mixed", tablets: []*topodatapb.Tablet{tabletReplica1_101, tabletReplica2_100, tabletReplica1_100, tabletRdonly1_102}, - positions: []mysql.Position{positionEmpty, positionIntermediate1, positionMostAdvanced, positionIntermediate1}, + positions: []replication.Position{positionEmpty, positionIntermediate1, positionMostAdvanced, positionIntermediate1}, sortedTablets: []*topodatapb.Tablet{tabletReplica1_100, tabletReplica2_100, tabletRdonly1_102, tabletReplica1_101}, }, } diff --git a/go/vt/vtctl/reparentutil/replication.go b/go/vt/vtctl/reparentutil/replication.go index 6d14ba853ac..9b33a5b0536 100644 --- a/go/vt/vtctl/reparentutil/replication.go +++ b/go/vt/vtctl/reparentutil/replication.go @@ -22,7 +22,8 @@ import ( "time" "vitess.io/vitess/go/event" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sets" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/log" @@ -44,13 +45,13 @@ import ( func FindValidEmergencyReparentCandidates( statusMap map[string]*replicationdatapb.StopReplicationStatus, primaryStatusMap map[string]*replicationdatapb.PrimaryStatus, -) (map[string]mysql.Position, error) { - replicationStatusMap := make(map[string]*mysql.ReplicationStatus, len(statusMap)) - positionMap := make(map[string]mysql.Position) +) (map[string]replication.Position, error) { + replicationStatusMap := make(map[string]*replication.ReplicationStatus, len(statusMap)) + positionMap := make(map[string]replication.Position) // Build out replication status list from proto types. for alias, statuspb := range statusMap { - status := mysql.ProtoToReplicationStatus(statuspb.After) + status := replication.ProtoToReplicationStatus(statuspb.After) replicationStatusMap[alias] = &status } @@ -63,7 +64,7 @@ func FindValidEmergencyReparentCandidates( ) for alias, status := range replicationStatusMap { - if _, ok := status.RelayLogPosition.GTIDSet.(mysql.Mysql56GTIDSet); ok { + if _, ok := status.RelayLogPosition.GTIDSet.(replication.Mysql56GTIDSet); ok { isGTIDBased = true } else { isNonGTIDBased = true @@ -98,14 +99,14 @@ func FindValidEmergencyReparentCandidates( // This condition should really never happen, since we did the same cast // in the earlier loop, but let's be doubly sure. - relayLogGTIDSet, ok := status.RelayLogPosition.GTIDSet.(mysql.Mysql56GTIDSet) + relayLogGTIDSet, ok := status.RelayLogPosition.GTIDSet.(replication.Mysql56GTIDSet) if !ok { return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "we got a filled-in relay log position, but it's not of type Mysql56GTIDSet, even though we've determined we need to use GTID based assesment") } // We need to remove this alias's status from the list, otherwise the // GTID diff will always be empty. - statusList := make([]*mysql.ReplicationStatus, 0, len(replicationStatusMap)-1) + statusList := make([]*replication.ReplicationStatus, 0, len(replicationStatusMap)-1) for a, s := range replicationStatusMap { if a != alias { @@ -126,12 +127,12 @@ func FindValidEmergencyReparentCandidates( continue } - pos := mysql.Position{GTIDSet: relayLogGTIDSet} + pos := replication.Position{GTIDSet: relayLogGTIDSet} positionMap[alias] = pos } for alias, primaryStatus := range primaryStatusMap { - executedPosition, err := mysql.DecodePosition(primaryStatus.Position) + executedPosition, err := replication.DecodePosition(primaryStatus.Position) if err != nil { return nil, vterrors.Wrapf(err, "could not decode a primary status executed position for tablet %v: %v", alias, err) } @@ -150,9 +151,9 @@ func ReplicaWasRunning(stopStatus *replicationdatapb.StopReplicationStatus) (boo return false, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "could not determine Before state of StopReplicationStatus %v", stopStatus) } - replStatus := mysql.ProtoToReplicationStatus(stopStatus.Before) - return (replStatus.IOState == mysql.ReplicationStateRunning) || - (replStatus.SQLState == mysql.ReplicationStateRunning), nil + replStatus := replication.ProtoToReplicationStatus(stopStatus.Before) + return (replStatus.IOState == replication.ReplicationStateRunning) || + (replStatus.SQLState == replication.ReplicationStateRunning), nil } // SQLThreadWasRunning returns true if a StopReplicationStatus indicates that the @@ -163,8 +164,8 @@ func SQLThreadWasRunning(stopStatus *replicationdatapb.StopReplicationStatus) (b return false, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "could not determine Before state of StopReplicationStatus %v", stopStatus) } - replStatus := mysql.ProtoToReplicationStatus(stopStatus.Before) - return replStatus.SQLState == mysql.ReplicationStateRunning, nil + replStatus := replication.ProtoToReplicationStatus(stopStatus.Before) + return replStatus.SQLState == replication.ReplicationStateRunning, nil } // SetReplicationSource is used to set the replication source on the specified @@ -249,8 +250,8 @@ func stopReplicationAndBuildStatusMaps( stopReplicationStatus, err := tmc.StopReplicationAndGetStatus(groupCtx, tabletInfo.Tablet, replicationdatapb.StopReplicationMode_IOTHREADONLY) if err != nil { - sqlErr, isSQLErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) - if isSQLErr && sqlErr != nil && sqlErr.Number() == mysql.ERNotReplica { + sqlErr, isSQLErr := sqlerror.NewSQLErrorFromError(err).(*sqlerror.SQLError) + if isSQLErr && sqlErr != nil && sqlErr.Number() == sqlerror.ERNotReplica { var primaryStatus *replicationdatapb.PrimaryStatus primaryStatus, err = tmc.DemotePrimary(groupCtx, tabletInfo.Tablet) diff --git a/go/vt/vtctl/reparentutil/replication_test.go b/go/vt/vtctl/reparentutil/replication_test.go index 1030205f192..ed7bd152e9c 100644 --- a/go/vt/vtctl/reparentutil/replication_test.go +++ b/go/vt/vtctl/reparentutil/replication_test.go @@ -25,6 +25,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + _flag "vitess.io/vitess/go/internal/flag" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sets" @@ -316,13 +318,13 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -351,11 +353,11 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { ignoredTablets: sets.New[string](), expectedStatusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000100": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, "zone1-0000000101": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -384,13 +386,13 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -419,11 +421,11 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { ignoredTablets: sets.New[string](), expectedStatusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000100": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, "zone1-0000000101": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -453,13 +455,13 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -503,11 +505,11 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { ignoredTablets: sets.New[string](), expectedStatusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000100": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, "zone1-0000000101": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -538,13 +540,13 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -597,11 +599,11 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { ignoredTablets: sets.New[string](), expectedStatusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000100": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, "zone1-0000000101": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -631,13 +633,13 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -690,11 +692,11 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { ignoredTablets: sets.New[string](), expectedStatusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000100": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, "zone1-0000000101": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -724,13 +726,13 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -759,7 +761,7 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { ignoredTablets: sets.New[string]("zone1-0000000100"), expectedStatusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000101": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -798,7 +800,7 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -827,7 +829,7 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { ignoredTablets: sets.New[string](), expectedStatusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000101": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -872,7 +874,7 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -901,7 +903,7 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { ignoredTablets: sets.New[string](), expectedStatusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000101": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -981,13 +983,13 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -1017,7 +1019,7 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { ignoredTablets: sets.New[string](), expectedStatusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000101": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -1044,7 +1046,7 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -1073,7 +1075,7 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { ignoredTablets: sets.New[string](), expectedStatusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000101": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, @@ -1186,19 +1188,19 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { }{ "zone1-0000000100": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, }, "zone1-0000000101": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, }, "zone1-0000000102": { StopStatus: &replicationdatapb.StopReplicationStatus{ - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429102:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429102:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429102:1-9"}, }, }, @@ -1240,15 +1242,15 @@ func Test_stopReplicationAndBuildStatusMaps(t *testing.T) { ignoredTablets: sets.New[string](), expectedStatusMap: map[string]*replicationdatapb.StopReplicationStatus{ "zone1-0000000100": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429100:1-9"}, }, "zone1-0000000101": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429101:1-9"}, }, "zone1-0000000102": { - Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429102:1-5", IoState: int32(mysql.ReplicationStateRunning), SqlState: int32(mysql.ReplicationStateRunning)}, + Before: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429102:1-5", IoState: int32(replication.ReplicationStateRunning), SqlState: int32(replication.ReplicationStateRunning)}, After: &replicationdatapb.Status{Position: "MySQL56/3E11FA47-71CA-11E1-9E33-C80AA9429102:1-9"}, }, }, @@ -1318,8 +1320,8 @@ func TestReplicaWasRunning(t *testing.T) { name: "io thread running", in: &replicationdatapb.StopReplicationStatus{ Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateStopped), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateStopped), }, }, expected: true, @@ -1329,8 +1331,8 @@ func TestReplicaWasRunning(t *testing.T) { name: "sql thread running", in: &replicationdatapb.StopReplicationStatus{ Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateStopped), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateStopped), + SqlState: int32(replication.ReplicationStateRunning), }, }, expected: true, @@ -1340,8 +1342,8 @@ func TestReplicaWasRunning(t *testing.T) { name: "io and sql threads running", in: &replicationdatapb.StopReplicationStatus{ Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), }, }, expected: true, @@ -1351,8 +1353,8 @@ func TestReplicaWasRunning(t *testing.T) { name: "no replication threads running", in: &replicationdatapb.StopReplicationStatus{ Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateStopped), - SqlState: int32(mysql.ReplicationStateStopped), + IoState: int32(replication.ReplicationStateStopped), + SqlState: int32(replication.ReplicationStateStopped), }, }, expected: false, @@ -1406,8 +1408,8 @@ func TestSQLThreadWasRunning(t *testing.T) { name: "io thread running", in: &replicationdatapb.StopReplicationStatus{ Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateStopped), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateStopped), }, }, expected: false, @@ -1417,8 +1419,8 @@ func TestSQLThreadWasRunning(t *testing.T) { name: "sql thread running", in: &replicationdatapb.StopReplicationStatus{ Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateStopped), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateStopped), + SqlState: int32(replication.ReplicationStateRunning), }, }, expected: true, @@ -1428,8 +1430,8 @@ func TestSQLThreadWasRunning(t *testing.T) { name: "io and sql threads running", in: &replicationdatapb.StopReplicationStatus{ Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), }, }, expected: true, @@ -1439,8 +1441,8 @@ func TestSQLThreadWasRunning(t *testing.T) { name: "no replication threads running", in: &replicationdatapb.StopReplicationStatus{ Before: &replicationdatapb.Status{ - IoState: int32(mysql.ReplicationStateStopped), - SqlState: int32(mysql.ReplicationStateStopped), + IoState: int32(replication.ReplicationStateStopped), + SqlState: int32(replication.ReplicationStateStopped), }, }, expected: false, diff --git a/go/vt/vtctl/reparentutil/util.go b/go/vt/vtctl/reparentutil/util.go index ee1bb36236c..c3499c7a1a4 100644 --- a/go/vt/vtctl/reparentutil/util.go +++ b/go/vt/vtctl/reparentutil/util.go @@ -24,7 +24,8 @@ import ( "golang.org/x/sync/errgroup" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" @@ -72,7 +73,7 @@ func ChooseNewPrimary( mu sync.Mutex // tablets that are possible candidates to be the new primary and their positions validTablets []*topodatapb.Tablet - tabletPositions []mysql.Position + tabletPositions []replication.Position errorGroup, groupCtx = errgroup.WithContext(ctx) ) @@ -121,7 +122,7 @@ func ChooseNewPrimary( // findPositionForTablet processes the replication position for a single tablet and // returns it. It is safe to call from multiple goroutines. -func findPositionForTablet(ctx context.Context, tablet *topodatapb.Tablet, logger logutil.Logger, tmc tmclient.TabletManagerClient, waitTimeout time.Duration) (mysql.Position, error) { +func findPositionForTablet(ctx context.Context, tablet *topodatapb.Tablet, logger logutil.Logger, tmc tmclient.TabletManagerClient, waitTimeout time.Duration) (replication.Position, error) { logger.Infof("getting replication position from %v", topoproto.TabletAliasString(tablet.Alias)) ctx, cancel := context.WithTimeout(ctx, waitTimeout) @@ -129,13 +130,13 @@ func findPositionForTablet(ctx context.Context, tablet *topodatapb.Tablet, logge status, err := tmc.ReplicationStatus(ctx, tablet) if err != nil { - sqlErr, isSQLErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) - if isSQLErr && sqlErr != nil && sqlErr.Number() == mysql.ERNotReplica { + sqlErr, isSQLErr := sqlerror.NewSQLErrorFromError(err).(*sqlerror.SQLError) + if isSQLErr && sqlErr != nil && sqlErr.Number() == sqlerror.ERNotReplica { logger.Warningf("no replication statue from %v, using empty gtid set", topoproto.TabletAliasString(tablet.Alias)) - return mysql.Position{}, nil + return replication.Position{}, nil } logger.Warningf("failed to get replication status from %v, ignoring tablet: %v", topoproto.TabletAliasString(tablet.Alias), err) - return mysql.Position{}, err + return replication.Position{}, err } // Use the relay log position if available, otherwise use the executed GTID set (binary log position). @@ -143,10 +144,10 @@ func findPositionForTablet(ctx context.Context, tablet *topodatapb.Tablet, logge if status.RelayLogPosition != "" { positionString = status.RelayLogPosition } - pos, err := mysql.DecodePosition(positionString) + pos, err := replication.DecodePosition(positionString) if err != nil { logger.Warningf("cannot decode replica position %v for tablet %v, ignoring tablet: %v", positionString, topoproto.TabletAliasString(tablet.Alias), err) - return mysql.Position{}, err + return replication.Position{}, err } return pos, nil @@ -251,9 +252,9 @@ func ShardReplicationStatuses(ctx context.Context, ts *topo.Server, tmc tmclient } // getValidCandidatesAndPositionsAsList converts the valid candidates from a map to a list of tablets, making it easier to sort -func getValidCandidatesAndPositionsAsList(validCandidates map[string]mysql.Position, tabletMap map[string]*topo.TabletInfo) ([]*topodatapb.Tablet, []mysql.Position, error) { +func getValidCandidatesAndPositionsAsList(validCandidates map[string]replication.Position, tabletMap map[string]*topo.TabletInfo) ([]*topodatapb.Tablet, []replication.Position, error) { var validTablets []*topodatapb.Tablet - var tabletPositions []mysql.Position + var tabletPositions []replication.Position for tabletAlias, position := range validCandidates { tablet, isFound := tabletMap[tabletAlias] if !isFound { @@ -266,8 +267,8 @@ func getValidCandidatesAndPositionsAsList(validCandidates map[string]mysql.Posit } // restrictValidCandidates is used to restrict some candidates from being considered eligible for becoming the intermediate source or the final promotion candidate -func restrictValidCandidates(validCandidates map[string]mysql.Position, tabletMap map[string]*topo.TabletInfo) (map[string]mysql.Position, error) { - restrictedValidCandidates := make(map[string]mysql.Position) +func restrictValidCandidates(validCandidates map[string]replication.Position, tabletMap map[string]*topo.TabletInfo) (map[string]replication.Position, error) { + restrictedValidCandidates := make(map[string]replication.Position) for candidate, position := range validCandidates { candidateInfo, ok := tabletMap[candidate] if !ok { diff --git a/go/vt/vtctl/reparentutil/util_test.go b/go/vt/vtctl/reparentutil/util_test.go index 29f7bb4ab7d..a9e6274d490 100644 --- a/go/vt/vtctl/reparentutil/util_test.go +++ b/go/vt/vtctl/reparentutil/util_test.go @@ -25,6 +25,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/test/utils" "vitess.io/vitess/go/vt/logutil" @@ -559,7 +561,7 @@ func TestFindPositionForTablet(t *testing.T) { return } require.NoError(t, err) - posString := mysql.EncodePosition(pos) + posString := replication.EncodePosition(pos) require.Equal(t, test.expectedPosition, posString) }) } @@ -736,41 +738,41 @@ func TestFindCurrentPrimary(t *testing.T) { } func TestGetValidCandidatesAndPositionsAsList(t *testing.T) { - sid1 := mysql.SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} - mysqlGTID1 := mysql.Mysql56GTID{ + sid1 := replication.SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + mysqlGTID1 := replication.Mysql56GTID{ Server: sid1, Sequence: 9, } - mysqlGTID2 := mysql.Mysql56GTID{ + mysqlGTID2 := replication.Mysql56GTID{ Server: sid1, Sequence: 10, } - mysqlGTID3 := mysql.Mysql56GTID{ + mysqlGTID3 := replication.Mysql56GTID{ Server: sid1, Sequence: 11, } - positionMostAdvanced := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionMostAdvanced := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} positionMostAdvanced.GTIDSet = positionMostAdvanced.GTIDSet.AddGTID(mysqlGTID1) positionMostAdvanced.GTIDSet = positionMostAdvanced.GTIDSet.AddGTID(mysqlGTID2) positionMostAdvanced.GTIDSet = positionMostAdvanced.GTIDSet.AddGTID(mysqlGTID3) - positionIntermediate1 := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionIntermediate1 := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} positionIntermediate1.GTIDSet = positionIntermediate1.GTIDSet.AddGTID(mysqlGTID1) - positionIntermediate2 := mysql.Position{GTIDSet: mysql.Mysql56GTIDSet{}} + positionIntermediate2 := replication.Position{GTIDSet: replication.Mysql56GTIDSet{}} positionIntermediate2.GTIDSet = positionIntermediate2.GTIDSet.AddGTID(mysqlGTID1) positionIntermediate2.GTIDSet = positionIntermediate2.GTIDSet.AddGTID(mysqlGTID2) tests := []struct { name string - validCandidates map[string]mysql.Position + validCandidates map[string]replication.Position tabletMap map[string]*topo.TabletInfo tabletRes []*topodatapb.Tablet }{ { name: "test conversion", - validCandidates: map[string]mysql.Position{ + validCandidates: map[string]replication.Position{ "zone1-0000000100": positionMostAdvanced, "zone1-0000000101": positionIntermediate1, "zone1-0000000102": positionIntermediate2, @@ -968,13 +970,13 @@ func TestWaitForCatchUp(t *testing.T) { func TestRestrictValidCandidates(t *testing.T) { tests := []struct { name string - validCandidates map[string]mysql.Position + validCandidates map[string]replication.Position tabletMap map[string]*topo.TabletInfo - result map[string]mysql.Position + result map[string]replication.Position }{ { name: "remove invalid tablets", - validCandidates: map[string]mysql.Position{ + validCandidates: map[string]replication.Position{ "zone1-0000000100": {}, "zone1-0000000101": {}, "zone1-0000000102": {}, @@ -1038,7 +1040,7 @@ func TestRestrictValidCandidates(t *testing.T) { }, }, }, - result: map[string]mysql.Position{ + result: map[string]replication.Position{ "zone1-0000000100": {}, "zone1-0000000101": {}, "zone1-0000000104": {}, diff --git a/go/vt/vtctl/workflow/server.go b/go/vt/vtctl/workflow/server.go index b0200a3c95a..f514198f3c8 100644 --- a/go/vt/vtctl/workflow/server.go +++ b/go/vt/vtctl/workflow/server.go @@ -29,7 +29,8 @@ import ( "golang.org/x/sync/semaphore" "google.golang.org/protobuf/encoding/prototext" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/protoutil" "vitess.io/vitess/go/sets" "vitess.io/vitess/go/sqltypes" @@ -1662,7 +1663,7 @@ func (s *Server) deleteWorkflowVDiffData(ctx context.Context, tablet *topodatapb Query: []byte(query), MaxRows: uint64(rows), }); err != nil { - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Num != mysql.ERNoSuchTable { // the tables may not exist if no vdiffs have been run + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Num != sqlerror.ERNoSuchTable { // the tables may not exist if no vdiffs have been run log.Errorf("Error deleting vdiff data for %s.%s workflow: %v", tablet.Keyspace, workflow, err) } } @@ -1702,7 +1703,7 @@ func (s *Server) optimizeCopyStateTable(tablet *topodatapb.Tablet) { Query: []byte(sqlOptimizeTable), MaxRows: uint64(100), // always produces 1+rows with notes and status }); err != nil { - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Num == mysql.ERNoSuchTable { // the table may not exist + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Num == sqlerror.ERNoSuchTable { // the table may not exist return } log.Warningf("Failed to optimize the copy_state table on %q: %v", tablet.Alias.String(), err) diff --git a/go/vt/vtctl/workflow/stream_migrator.go b/go/vt/vtctl/workflow/stream_migrator.go index aa004b0bd23..75d509614b7 100644 --- a/go/vt/vtctl/workflow/stream_migrator.go +++ b/go/vt/vtctl/workflow/stream_migrator.go @@ -25,7 +25,8 @@ import ( "google.golang.org/protobuf/encoding/prototext" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/key" @@ -261,7 +262,7 @@ func (sm *StreamMigrator) readTabletStreams(ctx context.Context, ti *topo.Tablet continue } - pos, err := mysql.DecodePosition(row["pos"].ToString()) + pos, err := replication.DecodePosition(row["pos"].ToString()) if err != nil { return nil, err } @@ -425,8 +426,8 @@ func (sm *StreamMigrator) stopSourceStreams(ctx context.Context) error { return nil } -func (sm *StreamMigrator) syncSourceStreams(ctx context.Context) (map[string]mysql.Position, error) { - stopPositions := make(map[string]mysql.Position) +func (sm *StreamMigrator) syncSourceStreams(ctx context.Context) (map[string]replication.Position, error) { + stopPositions := make(map[string]replication.Position) for _, tabletStreams := range sm.streams { for _, vrs := range tabletStreams { @@ -454,7 +455,7 @@ func (sm *StreamMigrator) syncSourceStreams(ctx context.Context) (map[string]mys } wg.Add(1) - go func(vrs *VReplicationStream, shard string, pos mysql.Position) { + go func(vrs *VReplicationStream, shard string, pos replication.Position) { defer wg.Done() sm.ts.Logger().Infof("syncSourceStreams beginning of go func %s %s %+v %d", shard, vrs.BinlogSource.Shard, pos, vrs.ID) @@ -470,14 +471,14 @@ func (sm *StreamMigrator) syncSourceStreams(ctx context.Context) (map[string]mys return } - query := fmt.Sprintf("update _vt.vreplication set state='Running', stop_pos='%s', message='synchronizing for cutover' where id=%d", mysql.EncodePosition(pos), vrs.ID) + query := fmt.Sprintf("update _vt.vreplication set state='Running', stop_pos='%s', message='synchronizing for cutover' where id=%d", replication.EncodePosition(pos), vrs.ID) if _, err := sm.ts.TabletManagerClient().VReplicationExec(ctx, primary.Tablet, query); err != nil { allErrors.RecordError(err) return } sm.ts.Logger().Infof("Waiting for keyspace:shard: %v:%v, position %v", sm.ts.SourceKeyspaceName(), shard, pos) - if err := sm.ts.TabletManagerClient().VReplicationWaitForPos(ctx, primary.Tablet, vrs.ID, mysql.EncodePosition(pos)); err != nil { + if err := sm.ts.TabletManagerClient().VReplicationWaitForPos(ctx, primary.Tablet, vrs.ID, replication.EncodePosition(pos)); err != nil { allErrors.RecordError(err) return } @@ -492,7 +493,7 @@ func (sm *StreamMigrator) syncSourceStreams(ctx context.Context) (map[string]mys return stopPositions, allErrors.AggrError(vterrors.Aggregate) } -func (sm *StreamMigrator) verifyStreamPositions(ctx context.Context, stopPositions map[string]mysql.Position) ([]string, error) { +func (sm *StreamMigrator) verifyStreamPositions(ctx context.Context, stopPositions map[string]replication.Position) ([]string, error) { var ( mu sync.Mutex stoppedStreams = make(map[string][]*VReplicationStream) @@ -537,7 +538,7 @@ func (sm *StreamMigrator) verifyStreamPositions(ctx context.Context, stopPositio for _, vrs := range tabletStreams { key := fmt.Sprintf("%s:%s", vrs.BinlogSource.Keyspace, vrs.BinlogSource.Shard) if pos := stopPositions[key]; !vrs.Position.Equal(pos) { - allErrors.RecordError(fmt.Errorf("%s: stream %d position: %s does not match %s", key, vrs.ID, mysql.EncodePosition(vrs.Position), mysql.EncodePosition(pos))) + allErrors.RecordError(fmt.Errorf("%s: stream %d position: %s does not match %s", key, vrs.ID, replication.EncodePosition(vrs.Position), replication.EncodePosition(pos))) } } } @@ -578,7 +579,7 @@ func (sm *StreamMigrator) createTargetStreams(ctx context.Context, tmpl []*VRepl rule.Filter = buf.String() } - ig.AddRow(vrs.Workflow, vrs.BinlogSource, mysql.EncodePosition(vrs.Position), "", "", + ig.AddRow(vrs.Workflow, vrs.BinlogSource, replication.EncodePosition(vrs.Position), "", "", vrs.WorkflowType, vrs.WorkflowSubType, vrs.DeferSecondaryKeys) } diff --git a/go/vt/vtctl/workflow/switcher_dry_run.go b/go/vt/vtctl/workflow/switcher_dry_run.go index 05bee1246b9..40a7d3dda98 100644 --- a/go/vt/vtctl/workflow/switcher_dry_run.go +++ b/go/vt/vtctl/workflow/switcher_dry_run.go @@ -23,7 +23,7 @@ import ( "strings" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -159,7 +159,7 @@ func (dr *switcherDryRun) migrateStreams(ctx context.Context, sm *StreamMigrator dr.drLog.Logf("Migrate streams to %s:", dr.ts.TargetKeyspaceName()) for key, streams := range sm.Streams() { for _, stream := range streams { - logs = append(logs, fmt.Sprintf("shard:%s;id:%d;workflow:%s;position:%s;binlogsource:%v", key, stream.ID, stream.Workflow, mysql.EncodePosition(stream.Position), stream.BinlogSource)) + logs = append(logs, fmt.Sprintf("shard:%s;id:%d;workflow:%s;position:%s;binlogsource:%v", key, stream.ID, stream.Workflow, replication.EncodePosition(stream.Position), stream.BinlogSource)) } } if len(logs) > 0 { @@ -170,7 +170,7 @@ func (dr *switcherDryRun) migrateStreams(ctx context.Context, sm *StreamMigrator tabletStreams := templates for _, vrs := range tabletStreams { logs = append(logs, fmt.Sprintf("keyspace:%s;shard:%s;tablet:%d;workflow:%s;id:%d,position:%v;binlogsource:%s", - vrs.BinlogSource.Keyspace, vrs.BinlogSource.Shard, target.GetPrimary().Alias.Uid, vrs.Workflow, vrs.ID, mysql.EncodePosition(vrs.Position), vrs.BinlogSource)) + vrs.BinlogSource.Keyspace, vrs.BinlogSource.Shard, target.GetPrimary().Alias.Uid, vrs.Workflow, vrs.ID, replication.EncodePosition(vrs.Position), vrs.BinlogSource)) } } if len(logs) > 0 { diff --git a/go/vt/vtctl/workflow/vreplication_stream.go b/go/vt/vtctl/workflow/vreplication_stream.go index 7d3c2b94145..f3da6a85236 100644 --- a/go/vt/vtctl/workflow/vreplication_stream.go +++ b/go/vt/vtctl/workflow/vreplication_stream.go @@ -23,7 +23,7 @@ import ( "google.golang.org/protobuf/proto" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" ) @@ -33,7 +33,7 @@ type VReplicationStream struct { ID int32 Workflow string BinlogSource *binlogdatapb.BinlogSource - Position mysql.Position + Position replication.Position WorkflowType binlogdatapb.VReplicationWorkflowType WorkflowSubType binlogdatapb.VReplicationWorkflowSubType DeferSecondaryKeys bool diff --git a/go/vt/vterrors/vterrorsgen/main.go b/go/vt/vterrors/vterrorsgen/main.go index f705813af8c..2aafee509e6 100644 --- a/go/vt/vterrors/vterrorsgen/main.go +++ b/go/vt/vterrors/vterrorsgen/main.go @@ -22,7 +22,7 @@ import ( "strings" "text/template" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/vterrors" ) @@ -44,8 +44,8 @@ const ( func main() { t := template.New("template") t.Funcs(map[string]any{ - "ConvertStateToMySQLErrorCode": mysql.ConvertStateToMySQLErrorCode, - "ConvertStateToMySQLState": mysql.ConvertStateToMySQLState, + "ConvertStateToMySQLErrorCode": sqlerror.ConvertStateToMySQLErrorCode, + "ConvertStateToMySQLState": sqlerror.ConvertStateToMySQLState, "FormatError": func(err error) string { s := err.Error() return strings.TrimSpace(strings.Join(strings.Split(s, ":")[1:], ":")) diff --git a/go/vt/vtgate/endtoend/lookup_test.go b/go/vt/vtgate/endtoend/lookup_test.go index 01fc3aee32d..d69bec8c0c6 100644 --- a/go/vt/vtgate/endtoend/lookup_test.go +++ b/go/vt/vtgate/endtoend/lookup_test.go @@ -23,6 +23,8 @@ import ( "github.com/stretchr/testify/assert" + "vitess.io/vitess/go/mysql/sqlerror" + "github.com/stretchr/testify/require" "vitess.io/vitess/go/mysql" @@ -61,8 +63,8 @@ func TestConsistentLookup(t *testing.T) { _, err = conn.ExecuteFetch("insert into t1(id1, id2) values(1, 4)", 1000, false) exec(t, conn, "rollback") require.Error(t, err) - mysqlErr := err.(*mysql.SQLError) - assert.Equal(t, mysql.ERDupEntry, mysqlErr.Num) + mysqlErr := err.(*sqlerror.SQLError) + assert.Equal(t, sqlerror.ERDupEntry, mysqlErr.Num) assert.Equal(t, "23000", mysqlErr.State) // Simple delete. diff --git a/go/vt/vtgate/engine/merge_sort.go b/go/vt/vtgate/engine/merge_sort.go index 1ff4ca7e736..6c694ae9e37 100644 --- a/go/vt/vtgate/engine/merge_sort.go +++ b/go/vt/vtgate/engine/merge_sort.go @@ -21,7 +21,7 @@ import ( "context" "io" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" @@ -167,7 +167,7 @@ func (ms *MergeSort) TryStreamExecute(ctx context.Context, vcursor VCursor, bind if err != nil && ms.ScatterErrorsAsWarnings && len(errs) < len(handles) { // we got errors, but not all shards failed, so we can hide the error and just warn instead partialSuccessScatterQueries.Add(1) - sErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) + sErr := sqlerror.NewSQLErrorFromError(err).(*sqlerror.SQLError) vcursor.Session().RecordWarning(&querypb.QueryWarning{Code: uint32(sErr.Num), Message: err.Error()}) return nil } diff --git a/go/vt/vtgate/engine/route.go b/go/vt/vtgate/engine/route.go index 744aab42fb1..70c5b7b4380 100644 --- a/go/vt/vtgate/engine/route.go +++ b/go/vt/vtgate/engine/route.go @@ -25,9 +25,9 @@ import ( "time" "vitess.io/vitess/go/mysql/collations" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/stats" "vitess.io/vitess/go/vt/key" @@ -250,7 +250,7 @@ func (route *Route) executeShards( partialSuccessScatterQueries.Add(1) for _, err := range errs { - serr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) + serr := sqlerror.NewSQLErrorFromError(err).(*sqlerror.SQLError) vcursor.Session().RecordWarning(&querypb.QueryWarning{Code: uint32(serr.Num), Message: err.Error()}) } } @@ -339,7 +339,7 @@ func (route *Route) streamExecuteShards( } partialSuccessScatterQueries.Add(1) for _, err := range errs { - sErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) + sErr := sqlerror.NewSQLErrorFromError(err).(*sqlerror.SQLError) vcursor.Session().RecordWarning(&querypb.QueryWarning{Code: uint32(sErr.Num), Message: err.Error()}) } } diff --git a/go/vt/vtgate/engine/route_test.go b/go/vt/vtgate/engine/route_test.go index 7317ac913fb..7d5b1d1bbea 100644 --- a/go/vt/vtgate/engine/route_test.go +++ b/go/vt/vtgate/engine/route_test.go @@ -25,6 +25,8 @@ import ( "github.com/stretchr/testify/assert" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql/collations" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/servenv" @@ -36,7 +38,6 @@ import ( "github.com/stretchr/testify/require" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" "vitess.io/vitess/go/vt/vtgate/vindexes" @@ -1441,7 +1442,7 @@ func TestExecFail(t *testing.T) { expectResult(t, "sel.Execute", result, defaultSelectResult) vc.Rewind() - vc.resultErr = mysql.NewSQLError(mysql.ERQueryInterrupted, "", "query timeout -20") + vc.resultErr = sqlerror.NewSQLError(sqlerror.ERQueryInterrupted, "", "query timeout -20") // test when there is order by column sel.OrderBy = []OrderByParams{{ WeightStringCol: -1, @@ -1449,7 +1450,7 @@ func TestExecFail(t *testing.T) { }} _, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err, "unexpected ScatterErrorsAsWarnings error %v", err) - vc.ExpectWarnings(t, []*querypb.QueryWarning{{Code: uint32(mysql.ERQueryInterrupted), Message: "query timeout -20 (errno 1317) (sqlstate HY000)"}}) + vc.ExpectWarnings(t, []*querypb.QueryWarning{{Code: uint32(sqlerror.ERQueryInterrupted), Message: "query timeout -20 (errno 1317) (sqlstate HY000)"}}) }) } diff --git a/go/vt/vtgate/executor_dml_test.go b/go/vt/vtgate/executor_dml_test.go index 0ff37071a3e..4ef0a0e5bfc 100644 --- a/go/vt/vtgate/executor_dml_test.go +++ b/go/vt/vtgate/executor_dml_test.go @@ -25,7 +25,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/test/utils" querypb "vitess.io/vitess/go/vt/proto/query" @@ -2486,7 +2487,7 @@ func TestReservedConnDML(t *testing.T) { _, err = executor.Execute(ctx, nil, "TestReservedConnDML", session, "begin", nil) require.NoError(t, err) - sbc.EphemeralShardErr = mysql.NewSQLError(mysql.CRServerGone, mysql.SSNetError, "connection gone") + sbc.EphemeralShardErr = sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSNetError, "connection gone") // as the first time the query fails due to connection loss i.e. reserved conn lost. It will be recreated to set statement will be executed again. wantQueries = append(wantQueries, &querypb.BoundQuery{Sql: "set default_week_format = 1", BindVariables: map[string]*querypb.BindVariable{}}, diff --git a/go/vt/vtgate/executor_set_test.go b/go/vt/vtgate/executor_set_test.go index 8e297aa98d8..5810d70b768 100644 --- a/go/vt/vtgate/executor_set_test.go +++ b/go/vt/vtgate/executor_set_test.go @@ -21,7 +21,7 @@ import ( "fmt" "testing" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/sqlparser" querypb "vitess.io/vitess/go/vt/proto/query" @@ -228,14 +228,14 @@ func TestExecutorSet(t *testing.T) { in: "set transaction isolation level serializable", out: &vtgatepb.Session{ Autocommit: true, - Warnings: []*querypb.QueryWarning{{Code: uint32(mysql.ERNotSupportedYet), Message: "converted 'next transaction' scope to 'session' scope"}}, + Warnings: []*querypb.QueryWarning{{Code: uint32(sqlerror.ERNotSupportedYet), Message: "converted 'next transaction' scope to 'session' scope"}}, }, }, { in: "set transaction read only", - out: &vtgatepb.Session{Autocommit: true, Warnings: []*querypb.QueryWarning{{Code: uint32(mysql.ERNotSupportedYet), Message: "converted 'next transaction' scope to 'session' scope"}}}, + out: &vtgatepb.Session{Autocommit: true, Warnings: []*querypb.QueryWarning{{Code: uint32(sqlerror.ERNotSupportedYet), Message: "converted 'next transaction' scope to 'session' scope"}}}, }, { in: "set transaction read write", - out: &vtgatepb.Session{Autocommit: true, Warnings: []*querypb.QueryWarning{{Code: uint32(mysql.ERNotSupportedYet), Message: "converted 'next transaction' scope to 'session' scope"}}}, + out: &vtgatepb.Session{Autocommit: true, Warnings: []*querypb.QueryWarning{{Code: uint32(sqlerror.ERNotSupportedYet), Message: "converted 'next transaction' scope to 'session' scope"}}}, }, { in: "set session transaction read write", out: &vtgatepb.Session{Autocommit: true}, diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go index 4710cb8f53c..ae1c983fc06 100644 --- a/go/vt/vtgate/executor_test.go +++ b/go/vt/vtgate/executor_test.go @@ -35,12 +35,9 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" - "vitess.io/vitess/go/vt/vtgate/buffer" - - "vitess.io/vitess/go/mysql/collations" - "vitess.io/vitess/go/cache" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/collations" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/test/utils" "vitess.io/vitess/go/vt/callerid" @@ -52,6 +49,7 @@ import ( vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/vtgate/buffer" "vitess.io/vitess/go/vt/vtgate/engine" "vitess.io/vitess/go/vt/vtgate/logstats" "vitess.io/vitess/go/vt/vtgate/vindexes" @@ -980,8 +978,8 @@ func TestExecutorShow(t *testing.T) { query = "show warnings" session.Warnings = []*querypb.QueryWarning{ - {Code: uint32(mysql.ERBadTable), Message: "bad table"}, - {Code: uint32(mysql.EROutOfResources), Message: "ks/-40: query timed out"}, + {Code: uint32(sqlerror.ERBadTable), Message: "bad table"}, + {Code: uint32(sqlerror.EROutOfResources), Message: "ks/-40: query timed out"}, } qr, err = executor.Execute(ctx, nil, "TestExecute", session, query, nil) require.NoError(t, err) @@ -993,8 +991,8 @@ func TestExecutorShow(t *testing.T) { }, Rows: [][]sqltypes.Value{ - {sqltypes.NewVarChar("Warning"), sqltypes.NewUint32(uint32(mysql.ERBadTable)), sqltypes.NewVarChar("bad table")}, - {sqltypes.NewVarChar("Warning"), sqltypes.NewUint32(uint32(mysql.EROutOfResources)), sqltypes.NewVarChar("ks/-40: query timed out")}, + {sqltypes.NewVarChar("Warning"), sqltypes.NewUint32(uint32(sqlerror.ERBadTable)), sqltypes.NewVarChar("bad table")}, + {sqltypes.NewVarChar("Warning"), sqltypes.NewUint32(uint32(sqlerror.EROutOfResources)), sqltypes.NewVarChar("ks/-40: query timed out")}, }, } utils.MustMatch(t, wantqr, qr, query) diff --git a/go/vt/vtgate/plugin_mysql_server.go b/go/vt/vtgate/plugin_mysql_server.go index 88841c670a4..066922dbc6e 100644 --- a/go/vt/vtgate/plugin_mysql_server.go +++ b/go/vt/vtgate/plugin_mysql_server.go @@ -32,6 +32,9 @@ import ( "github.com/google/uuid" "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/trace" @@ -239,14 +242,14 @@ func (vh *vtgateHandler) ComQuery(c *mysql.Conn, query string, callback func(*sq if session.Options.Workload == querypb.ExecuteOptions_OLAP { session, err := vh.vtg.StreamExecute(ctx, vh, session, query, make(map[string]*querypb.BindVariable), callback) if err != nil { - return mysql.NewSQLErrorFromError(err) + return sqlerror.NewSQLErrorFromError(err) } fillInTxStatusFlags(c, session) return nil } session, result, err := vh.vtg.Execute(ctx, vh, session, query, make(map[string]*querypb.BindVariable)) - if err := mysql.NewSQLErrorFromError(err); err != nil { + if err := sqlerror.NewSQLErrorFromError(err); err != nil { return err } fillInTxStatusFlags(c, session) @@ -302,7 +305,7 @@ func (vh *vtgateHandler) ComPrepare(c *mysql.Conn, query string, bindVars map[st }() session, fld, err := vh.vtg.Prepare(ctx, session, query, bindVars) - err = mysql.NewSQLErrorFromError(err) + err = sqlerror.NewSQLErrorFromError(err) if err != nil { return nil, err } @@ -345,14 +348,14 @@ func (vh *vtgateHandler) ComStmtExecute(c *mysql.Conn, prepare *mysql.PrepareDat if session.Options.Workload == querypb.ExecuteOptions_OLAP { _, err := vh.vtg.StreamExecute(ctx, vh, session, prepare.PrepareStmt, prepare.BindVars, callback) if err != nil { - return mysql.NewSQLErrorFromError(err) + return sqlerror.NewSQLErrorFromError(err) } fillInTxStatusFlags(c, session) return nil } _, qr, err := vh.vtg.Execute(ctx, vh, session, prepare.PrepareStmt, prepare.BindVars) if err != nil { - return mysql.NewSQLErrorFromError(err) + return sqlerror.NewSQLErrorFromError(err) } fillInTxStatusFlags(c, session) @@ -374,7 +377,7 @@ func (vh *vtgateHandler) ComBinlogDump(c *mysql.Conn, logFile string, binlogPos } // ComBinlogDumpGTID is part of the mysql.Handler interface. -func (vh *vtgateHandler) ComBinlogDumpGTID(c *mysql.Conn, logFile string, logPos uint64, gtidSet mysql.GTIDSet) error { +func (vh *vtgateHandler) ComBinlogDumpGTID(c *mysql.Conn, logFile string, logPos uint64, gtidSet replication.GTIDSet) error { return vterrors.VT12001("ComBinlogDumpGTID for the VTGate handler") } @@ -385,7 +388,7 @@ func (vh *vtgateHandler) KillConnection(ctx context.Context, connectionID uint32 c, exists := vh.connections[connectionID] if !exists { - return mysql.NewSQLError(mysql.ERNoSuchThread, mysql.SSUnknownSQLState, "Unknown thread id: %d", connectionID) + return sqlerror.NewSQLError(sqlerror.ERNoSuchThread, sqlerror.SSUnknownSQLState, "Unknown thread id: %d", connectionID) } // First, we mark the connection for close, so that even when the context is cancelled, while returning the response back to client, @@ -403,7 +406,7 @@ func (vh *vtgateHandler) KillQuery(connectionID uint32) error { defer vh.mu.Unlock() c, exists := vh.connections[connectionID] if !exists { - return mysql.NewSQLError(mysql.ERNoSuchThread, mysql.SSUnknownSQLState, "Unknown thread id: %d", connectionID) + return sqlerror.NewSQLError(sqlerror.ERNoSuchThread, sqlerror.SSUnknownSQLState, "Unknown thread id: %d", connectionID) } c.CancelCtx() return nil diff --git a/go/vt/vtgate/plugin_mysql_server_test.go b/go/vt/vtgate/plugin_mysql_server_test.go index dc57bc7763a..ed8d5b8c2fa 100644 --- a/go/vt/vtgate/plugin_mysql_server_test.go +++ b/go/vt/vtgate/plugin_mysql_server_test.go @@ -30,6 +30,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/trace" @@ -71,7 +73,7 @@ func (th *testHandler) ComBinlogDump(c *mysql.Conn, logFile string, binlogPos ui return nil } -func (th *testHandler) ComBinlogDumpGTID(c *mysql.Conn, logFile string, logPos uint64, gtidSet mysql.GTIDSet) error { +func (th *testHandler) ComBinlogDumpGTID(c *mysql.Conn, logFile string, logPos uint64, gtidSet replication.GTIDSet) error { return nil } diff --git a/go/vt/vtgate/scatter_conn.go b/go/vt/vtgate/scatter_conn.go index 7b89872ca67..ede88e2d9b8 100644 --- a/go/vt/vtgate/scatter_conn.go +++ b/go/vt/vtgate/scatter_conn.go @@ -22,11 +22,11 @@ import ( "sync" "time" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/sqlparser" "google.golang.org/protobuf/proto" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/stats" "vitess.io/vitess/go/vt/concurrency" @@ -755,13 +755,13 @@ func (stc *ScatterConn) ExecuteLock(ctx context.Context, rs *srvtopo.ResolvedSha } func wasConnectionClosed(err error) bool { - sqlErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) + sqlErr := sqlerror.NewSQLErrorFromError(err).(*sqlerror.SQLError) message := sqlErr.Error() switch sqlErr.Number() { - case mysql.CRServerGone, mysql.CRServerLost: + case sqlerror.CRServerGone, sqlerror.CRServerLost: return true - case mysql.ERQueryInterrupted: + case sqlerror.ERQueryInterrupted: return vterrors.TxClosed.MatchString(message) default: return false diff --git a/go/vt/vtgate/scatter_conn_test.go b/go/vt/vtgate/scatter_conn_test.go index 7fe751c9a00..33b6798b187 100644 --- a/go/vt/vtgate/scatter_conn_test.go +++ b/go/vt/vtgate/scatter_conn_test.go @@ -19,11 +19,11 @@ package vtgate import ( "testing" + "vitess.io/vitess/go/mysql/sqlerror" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "github.com/stretchr/testify/assert" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/test/utils" @@ -302,7 +302,7 @@ func TestReservedConnFail(t *testing.T) { assert.Equal(t, 1, len(session.ShardSessions)) oldRId := session.Session.ShardSessions[0].ReservedId - sbc0.EphemeralShardErr = mysql.NewSQLError(mysql.CRServerGone, mysql.SSUnknownSQLState, "lost connection") + sbc0.EphemeralShardErr = sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSUnknownSQLState, "lost connection") _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) assert.Equal(t, 3, len(sbc0.Queries), "1 for the successful run, one for the failed attempt, and one for the retry") require.Equal(t, 1, len(session.ShardSessions)) @@ -310,7 +310,7 @@ func TestReservedConnFail(t *testing.T) { oldRId = session.Session.ShardSessions[0].ReservedId sbc0.Queries = nil - sbc0.EphemeralShardErr = mysql.NewSQLError(mysql.ERQueryInterrupted, mysql.SSUnknownSQLState, "transaction 123 not found") + sbc0.EphemeralShardErr = sqlerror.NewSQLError(sqlerror.ERQueryInterrupted, sqlerror.SSUnknownSQLState, "transaction 123 not found") _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) assert.Equal(t, 2, len(sbc0.Queries), "one for the failed attempt, and one for the retry") require.Equal(t, 1, len(session.ShardSessions)) @@ -318,7 +318,7 @@ func TestReservedConnFail(t *testing.T) { oldRId = session.Session.ShardSessions[0].ReservedId sbc0.Queries = nil - sbc0.EphemeralShardErr = mysql.NewSQLError(mysql.ERQueryInterrupted, mysql.SSUnknownSQLState, "transaction 123 ended at 2020-01-20") + sbc0.EphemeralShardErr = sqlerror.NewSQLError(sqlerror.ERQueryInterrupted, sqlerror.SSUnknownSQLState, "transaction 123 ended at 2020-01-20") _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) assert.Equal(t, 2, len(sbc0.Queries), "one for the failed attempt, and one for the retry") require.Equal(t, 1, len(session.ShardSessions)) @@ -326,7 +326,7 @@ func TestReservedConnFail(t *testing.T) { oldRId = session.Session.ShardSessions[0].ReservedId sbc0.Queries = nil - sbc0.EphemeralShardErr = mysql.NewSQLError(mysql.ERQueryInterrupted, mysql.SSUnknownSQLState, "transaction 123 in use: for tx killer rollback") + sbc0.EphemeralShardErr = sqlerror.NewSQLError(sqlerror.ERQueryInterrupted, sqlerror.SSUnknownSQLState, "transaction 123 in use: for tx killer rollback") _ = executeOnShardsReturnsErr(t, res, keyspace, sc, session, destinations) assert.Equal(t, 2, len(sbc0.Queries), "one for the failed attempt, and one for the retry") require.Equal(t, 1, len(session.ShardSessions)) @@ -410,27 +410,27 @@ func TestIsConnClosed(t *testing.T) { conClosed bool }{{ "server gone", - mysql.NewSQLError(mysql.CRServerGone, mysql.SSNetError, ""), + sqlerror.NewSQLError(sqlerror.CRServerGone, sqlerror.SSNetError, ""), true, }, { "connection lost", - mysql.NewSQLError(mysql.CRServerLost, mysql.SSNetError, ""), + sqlerror.NewSQLError(sqlerror.CRServerLost, sqlerror.SSNetError, ""), true, }, { "tx ended", - mysql.NewSQLError(mysql.ERQueryInterrupted, mysql.SSUnknownSQLState, "transaction 111 ended at ..."), + sqlerror.NewSQLError(sqlerror.ERQueryInterrupted, sqlerror.SSUnknownSQLState, "transaction 111 ended at ..."), true, }, { "tx not found", - mysql.NewSQLError(mysql.ERQueryInterrupted, mysql.SSUnknownSQLState, "transaction 111 not found ..."), + sqlerror.NewSQLError(sqlerror.ERQueryInterrupted, sqlerror.SSUnknownSQLState, "transaction 111 not found ..."), true, }, { "tx not found missing tx id", - mysql.NewSQLError(mysql.ERQueryInterrupted, mysql.SSUnknownSQLState, "transaction not found"), + sqlerror.NewSQLError(sqlerror.ERQueryInterrupted, sqlerror.SSUnknownSQLState, "transaction not found"), false, }, { "tx getting killed by tx killer", - mysql.NewSQLError(mysql.ERQueryInterrupted, mysql.SSUnknownSQLState, "transaction 111 in use: for tx killer rollback"), + sqlerror.NewSQLError(sqlerror.ERQueryInterrupted, sqlerror.SSUnknownSQLState, "transaction 111 in use: for tx killer rollback"), true, }} diff --git a/go/vt/vtgate/schema/update_controller.go b/go/vt/vtgate/schema/update_controller.go index 0d595a0897d..f68a9448d55 100644 --- a/go/vt/vtgate/schema/update_controller.go +++ b/go/vt/vtgate/schema/update_controller.go @@ -20,7 +20,7 @@ import ( "sync" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -84,8 +84,8 @@ func (u *updateController) consume() { // checkIfWeShouldIgnoreKeyspace inspects an error and // will mark a keyspace as failed and won't try to load more information from it func checkIfWeShouldIgnoreKeyspace(err error) bool { - sqlErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) - if sqlErr.Num == mysql.ERBadDb || sqlErr.Num == mysql.ERNoSuchTable { + sqlErr := sqlerror.NewSQLErrorFromError(err).(*sqlerror.SQLError) + if sqlErr.Num == sqlerror.ERBadDb || sqlErr.Num == sqlerror.ERNoSuchTable { // if we are missing the db or table, no point in retrying return true } diff --git a/go/vt/vtgate/vcursor_impl.go b/go/vt/vtgate/vcursor_impl.go index d54c68b1692..3d4778d430d 100644 --- a/go/vt/vtgate/vcursor_impl.go +++ b/go/vt/vtgate/vcursor_impl.go @@ -27,7 +27,8 @@ import ( "github.com/google/uuid" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql/collations" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/callerid" @@ -992,7 +993,7 @@ func (vc *vcursorImpl) ErrorIfShardedF(ks *vindexes.Keyspace, warn, errFormat st func (vc *vcursorImpl) WarnUnshardedOnly(format string, params ...any) { if vc.warnShardedOnly { vc.warnings = append(vc.warnings, &querypb.QueryWarning{ - Code: uint32(mysql.ERNotSupportedYet), + Code: uint32(sqlerror.ERNotSupportedYet), Message: fmt.Sprintf(format, params...), }) } @@ -1004,7 +1005,7 @@ func (vc *vcursorImpl) PlannerWarning(message string) { return } vc.warnings = append(vc.warnings, &querypb.QueryWarning{ - Code: uint32(mysql.ERNotSupportedYet), + Code: uint32(sqlerror.ERNotSupportedYet), Message: message, }) } diff --git a/go/vt/vtgate/vindexes/consistent_lookup.go b/go/vt/vtgate/vindexes/consistent_lookup.go index 4836b0d6502..6a338d75a3e 100644 --- a/go/vt/vtgate/vindexes/consistent_lookup.go +++ b/go/vt/vtgate/vindexes/consistent_lookup.go @@ -22,7 +22,7 @@ import ( "encoding/json" "fmt" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/vtgate/evalengine" "vitess.io/vitess/go/sqltypes" @@ -346,10 +346,10 @@ func (lu *clCommon) Create(ctx context.Context, vcursor VCursor, rowsColValues [ return nil } // Try and convert the error to a MySQL error - sqlErr, isSQLErr := mysql.NewSQLErrorFromError(origErr).(*mysql.SQLError) + sqlErr, isSQLErr := sqlerror.NewSQLErrorFromError(origErr).(*sqlerror.SQLError) // If it is a MySQL error and its code is of duplicate entry, then we would like to continue // Otherwise, we return the error - if !(isSQLErr && sqlErr != nil && sqlErr.Number() == mysql.ERDupEntry) { + if !(isSQLErr && sqlErr != nil && sqlErr.Number() == sqlerror.ERDupEntry) { return origErr } for i, row := range rowsColValues { diff --git a/go/vt/vtgate/vindexes/consistent_lookup_test.go b/go/vt/vtgate/vindexes/consistent_lookup_test.go index 59035776edd..deecc23ebdd 100644 --- a/go/vt/vtgate/vindexes/consistent_lookup_test.go +++ b/go/vt/vtgate/vindexes/consistent_lookup_test.go @@ -29,9 +29,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql/collations" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" querypb "vitess.io/vitess/go/vt/proto/query" @@ -279,7 +280,7 @@ func TestConsistentLookupCreateSimple(t *testing.T) { func TestConsistentLookupCreateThenRecreate(t *testing.T) { lookup := createConsistentLookup(t, "consistent_lookup", false) vc := &loggingVCursor{} - vc.AddResult(nil, mysql.NewSQLError(mysql.ERDupEntry, mysql.SSConstraintViolation, "Duplicate entry")) + vc.AddResult(nil, sqlerror.NewSQLError(sqlerror.ERDupEntry, sqlerror.SSConstraintViolation, "Duplicate entry")) vc.AddResult(&sqltypes.Result{}, nil) vc.AddResult(&sqltypes.Result{}, nil) diff --git a/go/vt/vtorc/inst/instance_dao.go b/go/vt/vtorc/inst/instance_dao.go index abe233bf96e..ba47950d8cf 100644 --- a/go/vt/vtorc/inst/instance_dao.go +++ b/go/vt/vtorc/inst/instance_dao.go @@ -32,10 +32,11 @@ import ( "github.com/rcrowley/go-metrics" "github.com/sjmudd/stopwatch" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/stats" "vitess.io/vitess/go/vt/external/golib/sqlutils" - vitessmysql "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/tb" "vitess.io/vitess/go/vt/log" replicationdatapb "vitess.io/vitess/go/vt/proto/replicationdata" @@ -244,13 +245,13 @@ func ReadTopologyInstanceBufferable(tabletAlias string, latency *stopwatch.Named instance.GTIDMode = fullStatus.GtidMode instance.ServerUUID = fullStatus.ServerUuid if fullStatus.PrimaryStatus != nil { - GtidExecutedPos, err := vitessmysql.DecodePosition(fullStatus.PrimaryStatus.Position) + GtidExecutedPos, err := replication.DecodePosition(fullStatus.PrimaryStatus.Position) errorChan <- err if err == nil && GtidExecutedPos.GTIDSet != nil { instance.ExecutedGtidSet = GtidExecutedPos.GTIDSet.String() } } - GtidPurgedPos, err := vitessmysql.DecodePosition(fullStatus.GtidPurged) + GtidPurgedPos, err := replication.DecodePosition(fullStatus.GtidPurged) errorChan <- err if err == nil && GtidPurgedPos.GTIDSet != nil { instance.GtidPurged = GtidPurgedPos.GTIDSet.String() @@ -268,8 +269,8 @@ func ReadTopologyInstanceBufferable(tabletAlias string, latency *stopwatch.Named if fullStatus.ReplicationStatus != nil { instance.HasReplicationCredentials = fullStatus.ReplicationStatus.SourceUser != "" - instance.ReplicationIOThreadState = ReplicationThreadStateFromReplicationState(vitessmysql.ReplicationState(fullStatus.ReplicationStatus.IoState)) - instance.ReplicationSQLThreadState = ReplicationThreadStateFromReplicationState(vitessmysql.ReplicationState(fullStatus.ReplicationStatus.SqlState)) + instance.ReplicationIOThreadState = ReplicationThreadStateFromReplicationState(replication.ReplicationState(fullStatus.ReplicationStatus.IoState)) + instance.ReplicationSQLThreadState = ReplicationThreadStateFromReplicationState(replication.ReplicationState(fullStatus.ReplicationStatus.SqlState)) instance.ReplicationIOThreadRuning = instance.ReplicationIOThreadState.IsRunning() instance.ReplicationSQLThreadRuning = instance.ReplicationSQLThreadState.IsRunning() @@ -379,7 +380,7 @@ Cleanup: redactedPrimaryExecutedGtidSet, _ := NewOracleGtidSet(instance.primaryExecutedGtidSet) redactedPrimaryExecutedGtidSet.RemoveUUID(instance.SourceUUID) - instance.GtidErrant, err = vitessmysql.Subtract(redactedExecutedGtidSet.String(), redactedPrimaryExecutedGtidSet.String()) + instance.GtidErrant, err = replication.Subtract(redactedExecutedGtidSet.String(), redactedPrimaryExecutedGtidSet.String()) } } } @@ -414,7 +415,7 @@ func getKeyspaceShardName(keyspace, shard string) string { } func getBinlogCoordinatesFromPositionString(position string) (BinlogCoordinates, error) { - pos, err := vitessmysql.DecodePosition(position) + pos, err := replication.DecodePosition(position) if err != nil || pos.GTIDSet == nil { return BinlogCoordinates{}, err } diff --git a/go/vt/vtorc/inst/replication_thread_state.go b/go/vt/vtorc/inst/replication_thread_state.go index 85b968ac7bc..a95e65ca8ec 100644 --- a/go/vt/vtorc/inst/replication_thread_state.go +++ b/go/vt/vtorc/inst/replication_thread_state.go @@ -16,7 +16,9 @@ package inst -import "vitess.io/vitess/go/mysql" +import ( + "vitess.io/vitess/go/mysql/replication" +) type ReplicationThreadState int @@ -29,13 +31,13 @@ const ( // ReplicationThreadStateFromReplicationState gets the replication thread state from replication state // TODO: Merge these two into one -func ReplicationThreadStateFromReplicationState(state mysql.ReplicationState) ReplicationThreadState { +func ReplicationThreadStateFromReplicationState(state replication.ReplicationState) ReplicationThreadState { switch state { - case mysql.ReplicationStateStopped: + case replication.ReplicationStateStopped: return ReplicationThreadStateStopped - case mysql.ReplicationStateRunning: + case replication.ReplicationStateRunning: return ReplicationThreadStateRunning - case mysql.ReplicationStateConnecting: + case replication.ReplicationStateConnecting: return ReplicationThreadStateOther default: return ReplicationThreadStateNoThread diff --git a/go/vt/vttablet/onlineddl/executor.go b/go/vt/vttablet/onlineddl/executor.go index 46eb4e05470..5ac7f98e8f6 100644 --- a/go/vt/vttablet/onlineddl/executor.go +++ b/go/vt/vttablet/onlineddl/executor.go @@ -36,6 +36,9 @@ import ( "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" + "google.golang.org/protobuf/proto" "google.golang.org/protobuf/encoding/prototext" @@ -77,7 +80,7 @@ var ( ) var emptyResult = &sqltypes.Result{} -var acceptableDropTableIfExistsErrorCodes = []mysql.ErrorCode{mysql.ERCantFindFile, mysql.ERNoSuchTable} +var acceptableDropTableIfExistsErrorCodes = []sqlerror.ErrorCode{sqlerror.ERCantFindFile, sqlerror.ERNoSuchTable} var copyAlgorithm = sqlparser.AlgorithmValue(sqlparser.CopyStr) var ( @@ -620,7 +623,7 @@ func (e *Executor) parseAlterOptions(ctx context.Context, onlineDDL *schema.Onli } // executeDirectly runs a DDL query directly on the backend MySQL server -func (e *Executor) executeDirectly(ctx context.Context, onlineDDL *schema.OnlineDDL, acceptableMySQLErrorCodes ...mysql.ErrorCode) (acceptableErrorCodeFound bool, err error) { +func (e *Executor) executeDirectly(ctx context.Context, onlineDDL *schema.OnlineDDL, acceptableMySQLErrorCodes ...sqlerror.ErrorCode) (acceptableErrorCodeFound bool, err error) { conn, err := dbconnpool.NewDBConnection(ctx, e.env.Config().DB.DbaWithDB()) if err != nil { return false, err @@ -638,7 +641,7 @@ func (e *Executor) executeDirectly(ctx context.Context, onlineDDL *schema.Online if err != nil { // let's see if this error is actually acceptable - if merr, ok := err.(*mysql.SQLError); ok { + if merr, ok := err.(*sqlerror.SQLError); ok { for _, acceptableCode := range acceptableMySQLErrorCodes { if merr.Num == acceptableCode { // we don't consider this to be an error. @@ -716,7 +719,7 @@ func (e *Executor) validateTableForAlterAction(ctx context.Context, onlineDDL *s } // primaryPosition returns the MySQL/MariaDB position (typically GTID pos) on the tablet -func (e *Executor) primaryPosition(ctx context.Context) (pos mysql.Position, err error) { +func (e *Executor) primaryPosition(ctx context.Context) (pos replication.Position, err error) { conn, err := dbconnpool.NewDBConnection(ctx, e.env.Config().DB.DbaWithDB()) if err != nil { return pos, err @@ -787,11 +790,11 @@ func (e *Executor) cutOverVReplMigration(ctx context.Context, s *VReplStream) er migrationCutOverThreshold := getMigrationCutOverThreshold(onlineDDL) - waitForPos := func(s *VReplStream, pos mysql.Position) error { + waitForPos := func(s *VReplStream, pos replication.Position) error { ctx, cancel := context.WithTimeout(ctx, migrationCutOverThreshold) defer cancel() // Wait for target to reach the up-to-date pos - if err := tmClient.VReplicationWaitForPos(ctx, tablet.Tablet, s.id, mysql.EncodePosition(pos)); err != nil { + if err := tmClient.VReplicationWaitForPos(ctx, tablet.Tablet, s.id, replication.EncodePosition(pos)); err != nil { return err } // Target is now in sync with source! @@ -845,7 +848,7 @@ func (e *Executor) cutOverVReplMigration(ctx context.Context, s *VReplStream) er if err != nil { return err } - e.updateMigrationStage(ctx, onlineDDL.UUID, "waiting for post-sentry pos: %v", mysql.EncodePosition(postSentryPos)) + e.updateMigrationStage(ctx, onlineDDL.UUID, "waiting for post-sentry pos: %v", replication.EncodePosition(postSentryPos)) if err := waitForPos(s, postSentryPos); err != nil { return err } @@ -998,12 +1001,12 @@ func (e *Executor) cutOverVReplMigration(ctx context.Context, s *VReplStream) er return err } - e.updateMigrationStage(ctx, onlineDDL.UUID, "waiting for post-lock pos: %v", mysql.EncodePosition(postWritesPos)) + e.updateMigrationStage(ctx, onlineDDL.UUID, "waiting for post-lock pos: %v", replication.EncodePosition(postWritesPos)) if err := waitForPos(s, postWritesPos); err != nil { e.updateMigrationStage(ctx, onlineDDL.UUID, "timeout while waiting for post-lock pos: %v", err) return err } - go log.Infof("cutOverVReplMigration %v: done waiting for position %v", s.workflow, mysql.EncodePosition(postWritesPos)) + go log.Infof("cutOverVReplMigration %v: done waiting for position %v", s.workflow, replication.EncodePosition(postWritesPos)) // Stop vreplication e.updateMigrationStage(ctx, onlineDDL.UUID, "stopping vreplication") if _, err := e.vreplicationExec(ctx, tablet.Tablet, binlogplayer.StopVReplication(s.id, "stopped for online DDL cutover")); err != nil { @@ -2704,7 +2707,7 @@ func (e *Executor) executeDropDDLActionMigration(ctx context.Context, onlineDDL return err } - acceptableErrorCodes := []mysql.ErrorCode{} + acceptableErrorCodes := []sqlerror.ErrorCode{} if ddlStmt.GetIfExists() { acceptableErrorCodes = acceptableDropTableIfExistsErrorCodes } @@ -3581,9 +3584,9 @@ func (e *Executor) reviewRunningMigrations(ctx context.Context) (countRunnning i if err := e.cutOverVReplMigration(ctx, s); err != nil { _ = e.updateMigrationMessage(ctx, uuid, err.Error()) log.Errorf("cutOverVReplMigration failed: err=%v", err) - if merr, ok := err.(*mysql.SQLError); ok { + if merr, ok := err.(*sqlerror.SQLError); ok { switch merr.Num { - case mysql.ERTooLongIdent: + case sqlerror.ERTooLongIdent: go e.CancelMigration(ctx, uuid, err.Error(), false) } } diff --git a/go/vt/vttablet/tabletmanager/restore.go b/go/vt/vttablet/tabletmanager/restore.go index 1c1473180cf..881897dba10 100644 --- a/go/vt/vttablet/tabletmanager/restore.go +++ b/go/vt/vttablet/tabletmanager/restore.go @@ -24,6 +24,8 @@ import ( "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/stats" "vitess.io/vitess/go/mysql" @@ -208,7 +210,7 @@ func (tm *TabletManager) restoreDataLocked(ctx context.Context, logger logutil.L return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "--restore_to_pos and --restore_to_timestamp are mutually exclusive") } if request.RestoreToPos != "" { - pos, err := mysql.DecodePosition(request.RestoreToPos) + pos, err := replication.DecodePosition(request.RestoreToPos) if err != nil { return vterrors.Wrapf(err, "restore failed: unable to decode --restore_to_pos: %s", request.RestoreToPos) } @@ -243,7 +245,7 @@ func (tm *TabletManager) restoreDataLocked(ctx context.Context, logger logutil.L for { backupManifest, err = mysqlctl.Restore(ctx, params) if backupManifest != nil { - statsRestoreBackupPosition.Set(mysql.EncodePosition(backupManifest.Position)) + statsRestoreBackupPosition.Set(replication.EncodePosition(backupManifest.Position)) statsRestoreBackupTime.Set(backupManifest.BackupTime) } params.Logger.Infof("Restore: got a restore manifest: %v, err=%v, waitForBackupInterval=%v", backupManifest, err, waitForBackupInterval) @@ -263,10 +265,10 @@ func (tm *TabletManager) restoreDataLocked(ctx context.Context, logger logutil.L } } - var pos mysql.Position + var pos replication.Position if backupManifest != nil { pos = backupManifest.Position - params.Logger.Infof("Restore: pos=%v", mysql.EncodePosition(pos)) + params.Logger.Infof("Restore: pos=%v", replication.EncodePosition(pos)) } // If SnapshotTime is set , then apply the incremental change if keyspaceInfo.SnapshotTime != nil { @@ -336,7 +338,7 @@ func (tm *TabletManager) restoreDataLocked(ctx context.Context, logger logutil.L // restoreToTimeFromBinlog restores to the snapshot time of the keyspace // currently this works with mysql based database only (as it uses mysql specific queries for restoring) -func (tm *TabletManager) restoreToTimeFromBinlog(ctx context.Context, pos mysql.Position, restoreTime *vttime.Time) error { +func (tm *TabletManager) restoreToTimeFromBinlog(ctx context.Context, pos replication.Position, restoreTime *vttime.Time) error { // validate the minimal settings necessary for connecting to binlog server if binlogHost == "" || binlogPort <= 0 || binlogUser == "" { log.Warning("invalid binlog server setting, restoring to last available backup.") @@ -376,7 +378,7 @@ func (tm *TabletManager) restoreToTimeFromBinlog(ctx context.Context, pos mysql. // beforePos is the GTID of the last event before restoreTime. This is the GTID upto which replication will be applied // afterPos can be used directly in the query `START SLAVE UNTIL SQL_BEFORE_GTIDS = ”` // beforePos will be used to check if replication was able to catch up from the binlog server -func (tm *TabletManager) getGTIDFromTimestamp(ctx context.Context, pos mysql.Position, restoreTime int64) (afterPos string, beforePos string, err error) { +func (tm *TabletManager) getGTIDFromTimestamp(ctx context.Context, pos replication.Position, restoreTime int64) (afterPos string, beforePos string, err error) { connParams := &mysql.ConnParams{ Host: binlogHost, Port: binlogPort, @@ -419,11 +421,11 @@ func (tm *TabletManager) getGTIDFromTimestamp(ctx context.Context, pos mysql.Pos gtidsChan := make(chan []string, 1) go func() { - err := vsClient.VStream(ctx, mysql.EncodePosition(pos), filter, func(events []*binlogdatapb.VEvent) error { + err := vsClient.VStream(ctx, replication.EncodePosition(pos), filter, func(events []*binlogdatapb.VEvent) error { for _, event := range events { if event.Gtid != "" { // check if we reached the lastPos then return - eventPos, err := mysql.DecodePosition(event.Gtid) + eventPos, err := replication.DecodePosition(event.Gtid) if err != nil { return err } @@ -466,14 +468,14 @@ func (tm *TabletManager) getGTIDFromTimestamp(ctx context.Context, pos mysql.Pos func (tm *TabletManager) catchupToGTID(ctx context.Context, afterGTIDPos string, beforeGTIDPos string) error { var afterGTIDStr string if afterGTIDPos != "" { - afterGTIDParsed, err := mysql.DecodePosition(afterGTIDPos) + afterGTIDParsed, err := replication.DecodePosition(afterGTIDPos) if err != nil { return err } afterGTIDStr = afterGTIDParsed.GTIDSet.Last() } - beforeGTIDPosParsed, err := mysql.DecodePosition(beforeGTIDPos) + beforeGTIDPosParsed, err := replication.DecodePosition(beforeGTIDPos) if err != nil { return err } @@ -572,7 +574,7 @@ func (tm *TabletManager) disableReplication(ctx context.Context) error { return nil } -func (tm *TabletManager) startReplication(ctx context.Context, pos mysql.Position, tabletType topodatapb.TabletType) error { +func (tm *TabletManager) startReplication(ctx context.Context, pos replication.Position, tabletType topodatapb.TabletType) error { cmds := []string{ "STOP SLAVE", "RESET SLAVE ALL", // "ALL" makes it forget primary host:port. @@ -612,7 +614,7 @@ func (tm *TabletManager) startReplication(ctx context.Context, pos mysql.Positio log.Warningf("Can't get primary replication position after restore: %v", err) return nil } - primaryPos, err := mysql.DecodePosition(posStr) + primaryPos, err := replication.DecodePosition(posStr) if err != nil { return vterrors.Wrapf(err, "can't decode primary replication position: %q", posStr) } diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index fd2e8a17c28..17fae1810a2 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -24,6 +24,9 @@ import ( "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" @@ -57,7 +60,7 @@ func (tm *TabletManager) ReplicationStatus(ctx context.Context) (*replicationdat if err != nil { return nil, err } - return mysql.ReplicationStatusToProto(status), nil + return replication.ReplicationStatusToProto(status), nil } // FullStatus returns the full status of MySQL including the replication information, semi-sync information, GTID information among others @@ -81,7 +84,7 @@ func (tm *TabletManager) FullStatus(ctx context.Context) (*replicationdatapb.Ful return nil, err } if err == nil { - replicationStatusProto = mysql.ReplicationStatusToProto(replicationStatus) + replicationStatusProto = replication.ReplicationStatusToProto(replicationStatus) } // Primary status - "SHOW MASTER STATUS" @@ -91,7 +94,7 @@ func (tm *TabletManager) FullStatus(ctx context.Context) (*replicationdatapb.Ful return nil, err } if err == nil { - primaryStatusProto = mysql.PrimaryStatusToProto(primaryStatus) + primaryStatusProto = replication.PrimaryStatusToProto(primaryStatus) } // Purged GTID set @@ -158,7 +161,7 @@ func (tm *TabletManager) FullStatus(ctx context.Context) (*replicationdatapb.Ful ServerUuid: serverUUID, ReplicationStatus: replicationStatusProto, PrimaryStatus: primaryStatusProto, - GtidPurged: mysql.EncodePosition(purgedGTIDs), + GtidPurged: replication.EncodePosition(purgedGTIDs), Version: version, VersionComment: versionComment, ReadOnly: readOnly, @@ -184,7 +187,7 @@ func (tm *TabletManager) PrimaryStatus(ctx context.Context) (*replicationdatapb. if err != nil { return nil, err } - return mysql.PrimaryStatusToProto(status), nil + return replication.PrimaryStatusToProto(status), nil } // PrimaryPosition returns the position of a primary database @@ -193,13 +196,13 @@ func (tm *TabletManager) PrimaryPosition(ctx context.Context) (string, error) { if err != nil { return "", err } - return mysql.EncodePosition(pos), nil + return replication.EncodePosition(pos), nil } // WaitForPosition waits until replication reaches the desired position func (tm *TabletManager) WaitForPosition(ctx context.Context, pos string) error { log.Infof("WaitForPosition: %v", pos) - mpos, err := mysql.DecodePosition(pos) + mpos, err := replication.DecodePosition(pos) if err != nil { return err } @@ -236,7 +239,7 @@ func (tm *TabletManager) StopReplicationMinimum(ctx context.Context, position st } defer tm.unlock() - pos, err := mysql.DecodePosition(position) + pos, err := replication.DecodePosition(position) if err != nil { return "", err } @@ -252,7 +255,7 @@ func (tm *TabletManager) StopReplicationMinimum(ctx context.Context, position st if err != nil { return "", err } - return mysql.EncodePosition(pos), nil + return replication.EncodePosition(pos), nil } // StartReplication will start the mysql. Works both when Vitess manages @@ -287,7 +290,7 @@ func (tm *TabletManager) StartReplicationUntilAfter(ctx context.Context, positio waitCtx, cancel := context.WithTimeout(ctx, waitTime) defer cancel() - pos, err := mysql.DecodePosition(position) + pos, err := replication.DecodePosition(position) if err != nil { return err } @@ -322,7 +325,7 @@ func (tm *TabletManager) InitPrimary(ctx context.Context, semiSync bool) (string // Setting super_read_only `OFF` so that we can run the DDL commands if _, err := tm.MysqlDaemon.SetSuperReadOnly(false); err != nil { - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERUnknownSystemVariable { + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Number() == sqlerror.ERUnknownSystemVariable { log.Warningf("server does not know about super_read_only, continuing anyway...") } else { return "", err @@ -359,14 +362,14 @@ func (tm *TabletManager) InitPrimary(ctx context.Context, semiSync bool) (string return "", err } - return mysql.EncodePosition(pos), nil + return replication.EncodePosition(pos), nil } // PopulateReparentJournal adds an entry into the reparent_journal table. func (tm *TabletManager) PopulateReparentJournal(ctx context.Context, timeCreatedNS int64, actionName string, primaryAlias *topodatapb.TabletAlias, position string) error { log.Infof("PopulateReparentJournal: action: %v parent: %v position: %v timeCreatedNS: %d actionName: %s primaryAlias: %s", actionName, primaryAlias, position, timeCreatedNS, actionName, primaryAlias) - pos, err := mysql.DecodePosition(position) + pos, err := replication.DecodePosition(position) if err != nil { return err } @@ -399,7 +402,7 @@ func (tm *TabletManager) InitReplica(ctx context.Context, parent *topodatapb.Tab } } - pos, err := mysql.DecodePosition(position) + pos, err := replication.DecodePosition(position) if err != nil { return err } @@ -498,7 +501,7 @@ func (tm *TabletManager) demotePrimary(ctx context.Context, revertPartialFailure // previous demotion, or because we are not primary anyway, this should be // idempotent. if _, err := tm.MysqlDaemon.SetSuperReadOnly(true); err != nil { - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERUnknownSystemVariable { + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Number() == sqlerror.ERUnknownSystemVariable { log.Warningf("server does not know about super_read_only, continuing anyway...") } else { return nil, err @@ -536,7 +539,7 @@ func (tm *TabletManager) demotePrimary(ctx context.Context, revertPartialFailure if err != nil { return nil, err } - return mysql.PrimaryStatusToProto(status), nil + return replication.PrimaryStatusToProto(status), nil } // UndoDemotePrimary reverts a previous call to DemotePrimary @@ -674,7 +677,7 @@ func (tm *TabletManager) setReplicationSourceLocked(ctx context.Context, parentA shouldbeReplicating = true // Since we continue in the case of this error, make sure 'status' is // in a known, empty state. - status = mysql.ReplicationStatus{} + status = replication.ReplicationStatus{} } else if err != nil { // Abort on any other non-nil error. return err @@ -741,7 +744,7 @@ func (tm *TabletManager) setReplicationSourceLocked(ctx context.Context, parentA if shouldbeReplicating { log.Infof("Set up MySQL replication; should now be replicating from %s at %s", parentAlias, waitPosition) if waitPosition != "" { - pos, err := mysql.DecodePosition(waitPosition) + pos, err := replication.DecodePosition(waitPosition) if err != nil { return err } @@ -792,7 +795,7 @@ func (tm *TabletManager) StopReplicationAndGetStatus(ctx context.Context, stopRe if err != nil { return StopReplicationAndGetStatusResponse{}, vterrors.Wrap(err, "before status failed") } - before := mysql.ReplicationStatusToProto(rs) + before := replication.ReplicationStatusToProto(rs) if stopReplicationMode == replicationdatapb.StopReplicationMode_IOTHREADONLY { if !rs.IOHealthy() { @@ -838,7 +841,7 @@ func (tm *TabletManager) StopReplicationAndGetStatus(ctx context.Context, stopRe }, }, vterrors.Wrap(err, "acquiring replication status failed") } - after := mysql.ReplicationStatusToProto(rsAfter) + after := replication.ReplicationStatusToProto(rsAfter) rs.Position = rsAfter.Position rs.RelayLogPosition = rsAfter.RelayLogPosition @@ -886,7 +889,7 @@ func (tm *TabletManager) PromoteReplica(ctx context.Context, semiSync bool) (str if err := tm.changeTypeLocked(ctx, topodatapb.TabletType_PRIMARY, DBActionSetReadWrite, SemiSyncActionNone); err != nil { return "", err } - return mysql.EncodePosition(pos), nil + return replication.EncodePosition(pos), nil } func isPrimaryEligible(tabletType topodatapb.TabletType) bool { diff --git a/go/vt/vttablet/tabletmanager/rpc_schema.go b/go/vt/vttablet/tabletmanager/rpc_schema.go index 8bebb419cae..9fe8ce27170 100644 --- a/go/vt/vttablet/tabletmanager/rpc_schema.go +++ b/go/vt/vttablet/tabletmanager/rpc_schema.go @@ -17,11 +17,11 @@ limitations under the License. package tabletmanager import ( + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/vterrors" "context" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/mysqlctl/tmutils" "vitess.io/vitess/go/vt/topo/topoproto" @@ -44,7 +44,7 @@ func (tm *TabletManager) ReloadSchema(ctx context.Context, waitPosition string) } if waitPosition != "" { - pos, err := mysql.DecodePosition(waitPosition) + pos, err := replication.DecodePosition(waitPosition) if err != nil { return vterrors.Wrapf(err, "ReloadSchema: can't parse wait position (%q)", waitPosition) } diff --git a/go/vt/vttablet/tabletmanager/vdiff/controller.go b/go/vt/vttablet/tabletmanager/vdiff/controller.go index a98b5481343..ef8d8a6ba86 100644 --- a/go/vt/vttablet/tabletmanager/vdiff/controller.go +++ b/go/vt/vttablet/tabletmanager/vdiff/controller.go @@ -23,13 +23,13 @@ import ( "strings" "time" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/proto/tabletmanagerdata" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vterrors" "google.golang.org/protobuf/encoding/prototext" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/log" @@ -150,7 +150,7 @@ type migrationSource struct { *shardStreamer vrID int32 - position mysql.Position + position replication.Position } func (ct *controller) updateState(dbClient binlogplayer.DBClient, state VDiffState, err error) error { diff --git a/go/vt/vttablet/tabletmanager/vdiff/engine.go b/go/vt/vttablet/tabletmanager/vdiff/engine.go index c0ee5bcad51..72098eb52be 100644 --- a/go/vt/vttablet/tabletmanager/vdiff/engine.go +++ b/go/vt/vttablet/tabletmanager/vdiff/engine.go @@ -24,7 +24,7 @@ import ( "sync" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/proto/tabletmanagerdata" "vitess.io/vitess/go/vt/proto/topodata" "vitess.io/vitess/go/vt/sqlparser" @@ -335,8 +335,8 @@ func (vde *Engine) retryVDiffs(ctx context.Context) error { return ctx.Err() default: } - lastError := mysql.NewSQLErrorFromError(errors.New(row.AsString("last_error", ""))) - if !mysql.IsEphemeralError(lastError) { + lastError := sqlerror.NewSQLErrorFromError(errors.New(row.AsString("last_error", ""))) + if !sqlerror.IsEphemeralError(lastError) { continue } uuid := row.AsString("vdiff_uuid", "") diff --git a/go/vt/vttablet/tabletmanager/vdiff/engine_test.go b/go/vt/vttablet/tabletmanager/vdiff/engine_test.go index a1fe2c219c3..fda37187031 100644 --- a/go/vt/vttablet/tabletmanager/vdiff/engine_test.go +++ b/go/vt/vttablet/tabletmanager/vdiff/engine_test.go @@ -25,7 +25,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" @@ -224,7 +225,7 @@ func TestEngineRetryErroredVDiffs(t *testing.T) { vdiffTestColTypes, ), fmt.Sprintf("1|%s|%s|%s|%s|%s|error|%s|%v", UUID, vdiffenv.workflow, tstenv.KeyspaceName, tstenv.ShardName, vdiffDBName, optionsJS, - mysql.NewSQLError(mysql.ERNoSuchTable, "42S02", "Table 'foo' doesn't exist")), + sqlerror.NewSQLError(sqlerror.ERNoSuchTable, "42S02", "Table 'foo' doesn't exist")), ), }, { @@ -234,7 +235,7 @@ func TestEngineRetryErroredVDiffs(t *testing.T) { vdiffTestColTypes, ), fmt.Sprintf("1|%s|%s|%s|%s|%s|error|%s|%v", UUID, vdiffenv.workflow, tstenv.KeyspaceName, tstenv.ShardName, vdiffDBName, optionsJS, - mysql.NewSQLError(mysql.ERLockWaitTimeout, "HY000", "Lock wait timeout exceeded; try restarting transaction")), + sqlerror.NewSQLError(sqlerror.ERLockWaitTimeout, "HY000", "Lock wait timeout exceeded; try restarting transaction")), ), expectRetry: true, }, diff --git a/go/vt/vttablet/tabletmanager/vdiff/table_differ.go b/go/vt/vttablet/tabletmanager/vdiff/table_differ.go index c3c80d28d40..bab857a29b7 100644 --- a/go/vt/vttablet/tabletmanager/vdiff/table_differ.go +++ b/go/vt/vttablet/tabletmanager/vdiff/table_differ.go @@ -23,6 +23,8 @@ import ( "sync" "time" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/proto/topodata" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/sqlparser" @@ -31,7 +33,6 @@ import ( "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/mysql/collations" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" @@ -264,7 +265,7 @@ func (td *tableDiffer) syncSourceStreams(ctx context.Context) error { if err := td.forEachSource(func(source *migrationSource) error { log.Flush() - if err := ct.tmc.WaitForPosition(waitCtx, source.tablet, mysql.EncodePosition(source.position)); err != nil { + if err := ct.tmc.WaitForPosition(waitCtx, source.tablet, replication.EncodePosition(source.position)); err != nil { return vterrors.Wrapf(err, "WaitForPosition for tablet %v", topoproto.TabletAliasString(source.tablet.Alias)) } return nil @@ -337,7 +338,7 @@ func (td *tableDiffer) restartTargetVReplicationStreams(ctx context.Context) err // Let's retry a few times if we get a retryable error. for i := 1; i <= 3; i++ { _, err := ct.tmc.VReplicationExec(ctx, ct.vde.thisTablet, query) - if err == nil || !mysql.IsEphemeralError(err) { + if err == nil || !sqlerror.IsEphemeralError(err) { break } log.Warningf("Encountered the following error while restarting the %q VReplication workflow, will retry (attempt #%d): %v", diff --git a/go/vt/vttablet/tabletmanager/vreplication/engine.go b/go/vt/vttablet/tabletmanager/vreplication/engine.go index 0f413679fdf..ce431fb65ad 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/engine.go +++ b/go/vt/vttablet/tabletmanager/vreplication/engine.go @@ -29,7 +29,8 @@ import ( "google.golang.org/protobuf/proto" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/dbconfigs" @@ -779,7 +780,7 @@ func (vre *Engine) WaitForPos(ctx context.Context, id int32, pos string) error { // The full error we get back from MySQL in that case is: // Deadlock found when trying to get lock; try restarting transaction (errno 1213) (sqlstate 40001) // Docs: https://dev.mysql.com/doc/mysql-errors/en/server-error-reference.html#error_er_lock_deadlock - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERLockDeadlock { + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Number() == sqlerror.ERLockDeadlock { log.Infof("Deadlock detected waiting for pos %s: %v; will retry", pos, err) } else { return err diff --git a/go/vt/vttablet/tabletmanager/vreplication/framework_test.go b/go/vt/vttablet/tabletmanager/vreplication/framework_test.go index 8260d95b462..8484c71576a 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/framework_test.go +++ b/go/vt/vttablet/tabletmanager/vreplication/framework_test.go @@ -28,6 +28,7 @@ import ( "testing" "time" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/vttablet" "vitess.io/vitess/go/test/utils" @@ -212,7 +213,7 @@ func primaryPosition(t *testing.T) string { if err != nil { t.Fatal(err) } - return mysql.EncodePosition(pos) + return replication.EncodePosition(pos) } func execStatements(t *testing.T, queries []string) { diff --git a/go/vt/vttablet/tabletmanager/vreplication/stats_test.go b/go/vt/vttablet/tabletmanager/vreplication/stats_test.go index 3c9ae4f283c..1dc771f1fc3 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/stats_test.go +++ b/go/vt/vttablet/tabletmanager/vreplication/stats_test.go @@ -25,7 +25,8 @@ import ( "github.com/google/safehtml/template" "github.com/stretchr/testify/require" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/proto/binlogdata" @@ -74,7 +75,7 @@ VReplication state: Open
` func TestStatusHtml(t *testing.T) { - pos, err := mysql.DecodePosition("MariaDB/1-2-3") + pos, err := replication.DecodePosition("MariaDB/1-2-3") if err != nil { t.Fatal(err) } diff --git a/go/vt/vttablet/tabletmanager/vreplication/utils.go b/go/vt/vttablet/tabletmanager/vreplication/utils.go index 1e26687e147..ac26c84fbae 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/utils.go +++ b/go/vt/vttablet/tabletmanager/vreplication/utils.go @@ -21,7 +21,7 @@ import ( "fmt" "strconv" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/sidecardb" @@ -124,92 +124,92 @@ func isUnrecoverableError(err error) bool { if err == nil { return false } - sqlErr, isSQLErr := mysql.NewSQLErrorFromError(err).(*mysql.SQLError) + sqlErr, isSQLErr := sqlerror.NewSQLErrorFromError(err).(*sqlerror.SQLError) if !isSQLErr { return false } - if sqlErr.Num == mysql.ERUnknownError { + if sqlErr.Num == sqlerror.ERUnknownError { return false } switch sqlErr.Num { case // in case-insensitive alphabetical order - mysql.ERAccessDeniedError, - mysql.ERBadFieldError, - mysql.ERBadNullError, - mysql.ERCantDropFieldOrKey, - mysql.ERDataOutOfRange, - mysql.ERDataTooLong, - mysql.ERDBAccessDenied, - mysql.ERDupEntry, - mysql.ERDupFieldName, - mysql.ERDupKeyName, - mysql.ERDupUnique, - mysql.ERFeatureDisabled, - mysql.ERFunctionNotDefined, - mysql.ERIllegalValueForType, - mysql.ERInvalidCastToJSON, - mysql.ERInvalidJSONBinaryData, - mysql.ERInvalidJSONCharset, - mysql.ERInvalidJSONText, - mysql.ERInvalidJSONTextInParams, - mysql.ERJSONDocumentTooDeep, - mysql.ERJSONValueTooBig, - mysql.ERRegexpError, - mysql.ERRegexpStringNotTerminated, - mysql.ERRegexpIllegalArgument, - mysql.ERRegexpIndexOutOfBounds, - mysql.ERRegexpInternal, - mysql.ERRegexpRuleSyntax, - mysql.ERRegexpBadEscapeSequence, - mysql.ERRegexpUnimplemented, - mysql.ERRegexpMismatchParen, - mysql.ERRegexpBadInterval, - mysql.ERRRegexpMaxLtMin, - mysql.ERRegexpInvalidBackRef, - mysql.ERRegexpLookBehindLimit, - mysql.ERRegexpMissingCloseBracket, - mysql.ERRegexpInvalidRange, - mysql.ERRegexpStackOverflow, - mysql.ERRegexpTimeOut, - mysql.ERRegexpPatternTooBig, - mysql.ERRegexpInvalidCaptureGroup, - mysql.ERRegexpInvalidFlag, - mysql.ERNoDefault, - mysql.ERNoDefaultForField, - mysql.ERNonUniq, - mysql.ERNonUpdateableTable, - mysql.ERNoSuchTable, - mysql.ERNotAllowedCommand, - mysql.ERNotSupportedYet, - mysql.EROptionPreventsStatement, - mysql.ERParseError, - mysql.ERPrimaryCantHaveNull, - mysql.ErrCantCreateGeometryObject, - mysql.ErrGISDataWrongEndianess, - mysql.ErrNonPositiveRadius, - mysql.ErrNotImplementedForCartesianSRS, - mysql.ErrNotImplementedForProjectedSRS, - mysql.ErrWrongValueForType, - mysql.ERSPDoesNotExist, - mysql.ERSpecifiedAccessDenied, - mysql.ERSyntaxError, - mysql.ERTooBigRowSize, - mysql.ERTooBigSet, - mysql.ERTruncatedWrongValue, - mysql.ERTruncatedWrongValueForField, - mysql.ERUnknownCollation, - mysql.ERUnknownProcedure, - mysql.ERUnknownTable, - mysql.ERWarnDataOutOfRange, - mysql.ERWarnDataTruncated, - mysql.ERWrongFKDef, - mysql.ERWrongFieldSpec, - mysql.ERWrongParamCountToProcedure, - mysql.ERWrongParametersToProcedure, - mysql.ERWrongUsage, - mysql.ERWrongValue, - mysql.ERWrongValueCountOnRow: + sqlerror.ERAccessDeniedError, + sqlerror.ERBadFieldError, + sqlerror.ERBadNullError, + sqlerror.ERCantDropFieldOrKey, + sqlerror.ERDataOutOfRange, + sqlerror.ERDataTooLong, + sqlerror.ERDBAccessDenied, + sqlerror.ERDupEntry, + sqlerror.ERDupFieldName, + sqlerror.ERDupKeyName, + sqlerror.ERDupUnique, + sqlerror.ERFeatureDisabled, + sqlerror.ERFunctionNotDefined, + sqlerror.ERIllegalValueForType, + sqlerror.ERInvalidCastToJSON, + sqlerror.ERInvalidJSONBinaryData, + sqlerror.ERInvalidJSONCharset, + sqlerror.ERInvalidJSONText, + sqlerror.ERInvalidJSONTextInParams, + sqlerror.ERJSONDocumentTooDeep, + sqlerror.ERJSONValueTooBig, + sqlerror.ERRegexpError, + sqlerror.ERRegexpStringNotTerminated, + sqlerror.ERRegexpIllegalArgument, + sqlerror.ERRegexpIndexOutOfBounds, + sqlerror.ERRegexpInternal, + sqlerror.ERRegexpRuleSyntax, + sqlerror.ERRegexpBadEscapeSequence, + sqlerror.ERRegexpUnimplemented, + sqlerror.ERRegexpMismatchParen, + sqlerror.ERRegexpBadInterval, + sqlerror.ERRRegexpMaxLtMin, + sqlerror.ERRegexpInvalidBackRef, + sqlerror.ERRegexpLookBehindLimit, + sqlerror.ERRegexpMissingCloseBracket, + sqlerror.ERRegexpInvalidRange, + sqlerror.ERRegexpStackOverflow, + sqlerror.ERRegexpTimeOut, + sqlerror.ERRegexpPatternTooBig, + sqlerror.ERRegexpInvalidCaptureGroup, + sqlerror.ERRegexpInvalidFlag, + sqlerror.ERNoDefault, + sqlerror.ERNoDefaultForField, + sqlerror.ERNonUniq, + sqlerror.ERNonUpdateableTable, + sqlerror.ERNoSuchTable, + sqlerror.ERNotAllowedCommand, + sqlerror.ERNotSupportedYet, + sqlerror.EROptionPreventsStatement, + sqlerror.ERParseError, + sqlerror.ERPrimaryCantHaveNull, + sqlerror.ErrCantCreateGeometryObject, + sqlerror.ErrGISDataWrongEndianess, + sqlerror.ErrNonPositiveRadius, + sqlerror.ErrNotImplementedForCartesianSRS, + sqlerror.ErrNotImplementedForProjectedSRS, + sqlerror.ErrWrongValueForType, + sqlerror.ERSPDoesNotExist, + sqlerror.ERSpecifiedAccessDenied, + sqlerror.ERSyntaxError, + sqlerror.ERTooBigRowSize, + sqlerror.ERTooBigSet, + sqlerror.ERTruncatedWrongValue, + sqlerror.ERTruncatedWrongValueForField, + sqlerror.ERUnknownCollation, + sqlerror.ERUnknownProcedure, + sqlerror.ERUnknownTable, + sqlerror.ERWarnDataOutOfRange, + sqlerror.ERWarnDataTruncated, + sqlerror.ERWrongFKDef, + sqlerror.ERWrongFieldSpec, + sqlerror.ERWrongParamCountToProcedure, + sqlerror.ERWrongParametersToProcedure, + sqlerror.ERWrongUsage, + sqlerror.ERWrongValue, + sqlerror.ERWrongValueCountOnRow: log.Errorf("Got unrecoverable error: %v", sqlErr) return true } diff --git a/go/vt/vttablet/tabletmanager/vreplication/vcopier.go b/go/vt/vttablet/tabletmanager/vreplication/vcopier.go index 4dfd4c129a3..a5f580c219d 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vcopier.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vcopier.go @@ -28,8 +28,9 @@ import ( "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/bytes2" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/pools" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" @@ -344,7 +345,7 @@ func (vc *vcopier) catchup(ctx context.Context, copyState map[string]*sqltypes.R // Start vreplication. errch := make(chan error, 1) go func() { - errch <- newVPlayer(vc.vr, settings, copyState, mysql.Position{}, "catchup").play(ctx) + errch <- newVPlayer(vc.vr, settings, copyState, replication.Position{}, "catchup").play(ctx) }() // Wait for catchup. @@ -670,7 +671,7 @@ func (vc *vcopier) copyTable(ctx context.Context, tableName string, copyState ma func (vc *vcopier) fastForward(ctx context.Context, copyState map[string]*sqltypes.Result, gtid string) error { defer vc.vr.stats.PhaseTimings.Record("fastforward", time.Now()) - pos, err := mysql.DecodePosition(gtid) + pos, err := replication.DecodePosition(gtid) if err != nil { return err } diff --git a/go/vt/vttablet/tabletmanager/vreplication/vdbclient.go b/go/vt/vttablet/tabletmanager/vreplication/vdbclient.go index cc7776720ba..c3941b0f1bb 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vdbclient.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vdbclient.go @@ -17,12 +17,11 @@ limitations under the License. package vreplication import ( + "context" "io" "time" - "context" - - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/log" @@ -100,7 +99,7 @@ func (vc *vdbClient) Execute(query string) (*sqltypes.Result, error) { func (vc *vdbClient) ExecuteWithRetry(ctx context.Context, query string) (*sqltypes.Result, error) { qr, err := vc.Execute(query) for err != nil { - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERLockDeadlock || sqlErr.Number() == mysql.ERLockWaitTimeout { + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Number() == sqlerror.ERLockDeadlock || sqlErr.Number() == sqlerror.ERLockWaitTimeout { log.Infof("retryable error: %v, waiting for %v and retrying", sqlErr, dbLockRetryDelay) if err := vc.Rollback(); err != nil { return nil, err diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go index 94287aff785..998fca634a7 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go @@ -26,7 +26,7 @@ import ( "strings" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" @@ -39,15 +39,15 @@ import ( // vplayer replays binlog events by pulling them from a vstreamer. type vplayer struct { vr *vreplicator - startPos mysql.Position - stopPos mysql.Position + startPos replication.Position + stopPos replication.Position saveStop bool copyState map[string]*sqltypes.Result replicatorPlan *ReplicatorPlan tablePlans map[string]*TablePlan - pos mysql.Position + pos replication.Position // unsavedEvent is set any time we skip an event without // saving, which is on an empty commit. // If nothing else happens for idleTimeout since timeLastSaved, @@ -84,7 +84,7 @@ type vplayer struct { // pausePos: if set, replication will stop at that position without updating the state to "Stopped". // // This is used by the fastForward function during copying. -func newVPlayer(vr *vreplicator, settings binlogplayer.VRSettings, copyState map[string]*sqltypes.Result, pausePos mysql.Position, phase string) *vplayer { +func newVPlayer(vr *vreplicator, settings binlogplayer.VRSettings, copyState map[string]*sqltypes.Result, pausePos replication.Position, phase string) *vplayer { saveStop := true if !pausePos.IsZero() { settings.StopPos = pausePos @@ -153,7 +153,7 @@ func (vp *vplayer) fetchAndApply(ctx context.Context) (err error) { streamErr := make(chan error, 1) go func() { - streamErr <- vp.vr.sourceVStreamer.VStream(ctx, mysql.EncodePosition(vp.startPos), nil, vp.replicatorPlan.VStreamFilter, func(events []*binlogdatapb.VEvent) error { + streamErr <- vp.vr.sourceVStreamer.VStream(ctx, replication.EncodePosition(vp.startPos), nil, vp.replicatorPlan.VStreamFilter, func(events []*binlogdatapb.VEvent) error { return relay.Send(events) }) }() diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go index 98e6954c0b6..369080d6312 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go @@ -27,6 +27,7 @@ import ( "testing" "time" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/vttablet/tabletserver/vstreamer/testenv" "vitess.io/vitess/go/vt/vttablet" @@ -34,7 +35,6 @@ import ( "github.com/nsf/jsondiff" "github.com/stretchr/testify/require" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/log" @@ -1780,13 +1780,13 @@ func TestGTIDCompress(t *testing.T) { require.NotNil(t, qr) require.Equal(t, 1, len(qr.Rows)) gotGTID := qr.Rows[0][0].ToString() - pos, err := mysql.DecodePosition(gotGTID) + pos, err := replication.DecodePosition(gotGTID) if tCase.compress { require.True(t, pos.IsZero()) pos, err = binlogplayer.DecodePosition(gotGTID) require.NoError(t, err) require.NotNil(t, pos) - tpos, err := mysql.DecodePosition(tCase.gtid) + tpos, err := replication.DecodePosition(tCase.gtid) require.NoError(t, err) require.Equal(t, tpos.String(), pos.String()) } else { diff --git a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go index 3a1e1cc4acd..40480ca07d7 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go @@ -26,6 +26,8 @@ import ( "strings" "time" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/timer" "vitess.io/vitess/go/vt/schema" "vitess.io/vitess/go/vt/sqlparser" @@ -37,7 +39,6 @@ import ( "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/log" @@ -302,7 +303,7 @@ func (vr *vreplicator) replicate(ctx context.Context) error { vr.stats.ErrorCounts.Add([]string{"Replicate"}, 1) return err } - return newVPlayer(vr, settings, nil, mysql.Position{}, "replicate").play(ctx) + return newVPlayer(vr, settings, nil, replication.Position{}, "replicate").play(ctx) } } } @@ -691,7 +692,7 @@ func (vr *vreplicator) stashSecondaryKeys(ctx context.Context, tableName string) if _, err := dbClient.ExecuteFetch(sqlparser.String(alterDrop), 1); err != nil { // If they've already been dropped, e.g. by another controller running on the tablet // when doing a shard merge, then we can ignore the error. - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Num == mysql.ERCantDropFieldOrKey { + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Num == sqlerror.ERCantDropFieldOrKey { secondaryKeys, err := vr.getTableSecondaryKeys(ctx, tableName) if err == nil && len(secondaryKeys) == 0 { return nil @@ -944,7 +945,7 @@ func (vr *vreplicator) execPostCopyActions(ctx context.Context, tableName string // index definitions that we would have added already exist in // the table schema and if so move forward and delete the // post_copy_action record. - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERDupKeyName { + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Number() == sqlerror.ERDupKeyName { stmt, err := sqlparser.ParseStrictDDL(action.Task) if err != nil { return failedAlterErr diff --git a/go/vt/vttablet/tabletserver/connpool/dbconn.go b/go/vt/vttablet/tabletserver/connpool/dbconn.go index 13d0479fd0c..cc81bf39910 100644 --- a/go/vt/vttablet/tabletserver/connpool/dbconn.go +++ b/go/vt/vttablet/tabletserver/connpool/dbconn.go @@ -24,12 +24,12 @@ import ( "sync/atomic" "time" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/pools" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/trace" "vitess.io/vitess/go/vt/dbconnpool" @@ -130,10 +130,10 @@ func (dbc *DBConn) Exec(ctx context.Context, query string, maxrows int, wantfiel case err == nil: // Success. return r, nil - case mysql.IsConnLostDuringQuery(err): + case sqlerror.IsConnLostDuringQuery(err): // Query probably killed. Don't retry. return nil, err - case !mysql.IsConnErr(err): + case !sqlerror.IsConnErr(err): // Not a connection error. Don't retry. return nil, err case attempt == 2: @@ -233,10 +233,10 @@ func (dbc *DBConn) Stream(ctx context.Context, query string, callback func(*sqlt case err == nil: // Success. return nil - case mysql.IsConnLostDuringQuery(err): + case sqlerror.IsConnLostDuringQuery(err): // Query probably killed. Don't retry. return err - case !mysql.IsConnErr(err): + case !sqlerror.IsConnErr(err): // Not a connection error. Don't retry. return err case attempt == 2: diff --git a/go/vt/vttablet/tabletserver/connpool/dbconn_test.go b/go/vt/vttablet/tabletserver/connpool/dbconn_test.go index 62ec0b6d12e..54792e17fa5 100644 --- a/go/vt/vttablet/tabletserver/connpool/dbconn_test.go +++ b/go/vt/vttablet/tabletserver/connpool/dbconn_test.go @@ -27,7 +27,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql/fakesqldb" "vitess.io/vitess/go/pools" "vitess.io/vitess/go/sqltypes" @@ -87,7 +88,7 @@ func TestDBConnExec(t *testing.T) { startCounts = mysqlTimings.Counts() // Exec fail due to client side error - db.AddRejectedQuery(sql, &mysql.SQLError{ + db.AddRejectedQuery(sql, &sqlerror.SQLError{ Num: 2012, Message: "connection fail", Query: "", @@ -159,7 +160,7 @@ func TestDBConnExecLost(t *testing.T) { // Exec fail due to server side error (e.g. query kill) startCounts = mysqlTimings.Counts() - db.AddRejectedQuery(sql, &mysql.SQLError{ + db.AddRejectedQuery(sql, &sqlerror.SQLError{ Num: 2013, Message: "Lost connection to MySQL server during query", Query: "", diff --git a/go/vt/vttablet/tabletserver/gc/tablegc.go b/go/vt/vttablet/tabletserver/gc/tablegc.go index 829d97039a1..80d6f6242b3 100644 --- a/go/vt/vttablet/tabletserver/gc/tablegc.go +++ b/go/vt/vttablet/tabletserver/gc/tablegc.go @@ -28,6 +28,8 @@ import ( "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/timer" "vitess.io/vitess/go/vt/dbconnpool" @@ -474,8 +476,8 @@ func (collector *TableGC) purge(ctx context.Context) (tableName string, err erro if err == nil { return true, nil } - if merr, ok := err.(*mysql.SQLError); ok { - if merr.Num == mysql.ERSpecifiedAccessDenied { + if merr, ok := err.(*sqlerror.SQLError); ok { + if merr.Num == sqlerror.ERSpecifiedAccessDenied { // We do not have privileges to disable binary logging. That's fine, we're on best effort, // so we're going to silently ignore this error. return false, nil diff --git a/go/vt/vttablet/tabletserver/messager/message_manager.go b/go/vt/vttablet/tabletserver/messager/message_manager.go index 5c925150322..135f20f7793 100644 --- a/go/vt/vttablet/tabletserver/messager/message_manager.go +++ b/go/vt/vttablet/tabletserver/messager/message_manager.go @@ -27,7 +27,8 @@ import ( "golang.org/x/sync/semaphore" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/stats" "vitess.io/vitess/go/timer" @@ -223,7 +224,7 @@ type messageManager struct { // where a replica could have received and processed a GTID that the primary // may not have yet commited; but this is harmless because any events missed // will be picked up during the next poller run. - lastPollPosition *mysql.Position + lastPollPosition *replication.Position // wg is for ensuring all running goroutines have returned // before we can close the manager. You need to Add before @@ -703,7 +704,7 @@ func (mm *messageManager) runOneVStream(ctx context.Context) error { if curPos == "" { return true, nil } - cur, err := mysql.DecodePosition(curPos) + cur, err := replication.DecodePosition(curPos) if err != nil { return false, err } @@ -948,7 +949,7 @@ func (mm *messageManager) readPending(ctx context.Context, bindVars map[string]* qr.Fields = response.Fields } if response.Gtid != "" { - pos, err := mysql.DecodePosition(response.Gtid) + pos, err := replication.DecodePosition(response.Gtid) if err != nil { return err } @@ -971,7 +972,7 @@ func (mm *messageManager) getReceiverCount() int { return len(mm.receivers) } -func (mm *messageManager) getLastPollPosition() *mysql.Position { +func (mm *messageManager) getLastPollPosition() *replication.Position { mm.cacheManagementMu.Lock() defer mm.cacheManagementMu.Unlock() return mm.lastPollPosition diff --git a/go/vt/vttablet/tabletserver/query_engine.go b/go/vt/vttablet/tabletserver/query_engine.go index 5722b95003f..a59665450a1 100644 --- a/go/vt/vttablet/tabletserver/query_engine.go +++ b/go/vt/vttablet/tabletserver/query_engine.go @@ -27,12 +27,12 @@ import ( "sync/atomic" "time" + "vitess.io/vitess/go/mysql/sqlerror" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/acl" "vitess.io/vitess/go/cache" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/pools" "vitess.io/vitess/go/stats" "vitess.io/vitess/go/streamlog" @@ -427,7 +427,7 @@ func (qe *QueryEngine) ClearQueryPlanCache() { func (qe *QueryEngine) IsMySQLReachable() error { conn, err := dbconnpool.NewDBConnection(context.TODO(), qe.env.Config().DB.AppWithDB()) if err != nil { - if mysql.IsTooManyConnectionsErr(err) { + if sqlerror.IsTooManyConnectionsErr(err) { return nil } return err diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index daf018cd4ed..3462be4f410 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -26,9 +26,11 @@ import ( "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql/collations" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/pools" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/trace" @@ -554,7 +556,7 @@ func (qre *QueryExecutor) execDDL(conn *StatefulConnection) (*sqltypes.Result, e // Instead of synchronously recalculating table size stats // after every DDL, let them be outdated until the periodic // schema reload fixes it. - if err := qre.tsv.se.ReloadAtEx(qre.ctx, mysql.Position{}, false); err != nil { + if err := qre.tsv.se.ReloadAtEx(qre.ctx, replication.Position{}, false); err != nil { log.Errorf("failed to reload schema %v", err) } }() @@ -849,11 +851,11 @@ func (qre *QueryExecutor) generateFinalSQL(parsedQuery *sqlparser.ParsedQuery, b } func rewriteOUTParamError(err error) error { - sqlErr, ok := err.(*mysql.SQLError) + sqlErr, ok := err.(*sqlerror.SQLError) if !ok { return err } - if sqlErr.Num == mysql.ErSPNotVarArg { + if sqlErr.Num == sqlerror.ErSPNotVarArg { return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "OUT and INOUT parameters are not supported") } return err diff --git a/go/vt/vttablet/tabletserver/schema/engine.go b/go/vt/vttablet/tabletserver/schema/engine.go index 5026e14b1ed..08e3bdced8c 100644 --- a/go/vt/vttablet/tabletserver/schema/engine.go +++ b/go/vt/vttablet/tabletserver/schema/engine.go @@ -28,6 +28,9 @@ import ( "golang.org/x/exp/maps" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/acl" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" @@ -68,7 +71,7 @@ type Engine struct { tables map[string]*Table lastChange int64 // the position at which the schema was last loaded. it is only used in conjunction with ReloadAt - reloadAtPos mysql.Position + reloadAtPos replication.Position notifierMu sync.Mutex notifiers map[string]notifier // isServingPrimary stores if this tablet is currently the serving primary or not. @@ -193,7 +196,7 @@ func (se *Engine) EnsureConnectionAndDB(tabletType topodatapb.TabletType) error if tabletType != topodatapb.TabletType_PRIMARY { return err } - if merr, isSQLErr := err.(*mysql.SQLError); !isSQLErr || merr.Num != mysql.ERBadDb { + if merr, isSQLErr := err.(*sqlerror.SQLError); !isSQLErr || merr.Num != sqlerror.ERBadDb { return err } @@ -353,14 +356,14 @@ func (se *Engine) EnableHistorian(enabled bool) error { // The includeStats argument controls whether table size statistics should be // emitted, as they can be expensive to calculate for a large number of tables func (se *Engine) Reload(ctx context.Context) error { - return se.ReloadAt(ctx, mysql.Position{}) + return se.ReloadAt(ctx, replication.Position{}) } // ReloadAt reloads the schema info from the db. // Any tables that have changed since the last load are updated. // It maintains the position at which the schema was reloaded and if the same position is provided // (say by multiple vstreams) it returns the cached schema. In case of a newer or empty pos it always reloads the schema -func (se *Engine) ReloadAt(ctx context.Context, pos mysql.Position) error { +func (se *Engine) ReloadAt(ctx context.Context, pos replication.Position) error { return se.ReloadAtEx(ctx, pos, true) } @@ -370,7 +373,7 @@ func (se *Engine) ReloadAt(ctx context.Context, pos mysql.Position) error { // (say by multiple vstreams) it returns the cached schema. In case of a newer or empty pos it always reloads the schema // The includeStats argument controls whether table size statistics should be // emitted, as they can be expensive to calculate for a large number of tables -func (se *Engine) ReloadAtEx(ctx context.Context, pos mysql.Position, includeStats bool) error { +func (se *Engine) ReloadAtEx(ctx context.Context, pos replication.Position, includeStats bool) error { se.mu.Lock() defer se.mu.Unlock() if !se.isOpen { @@ -378,7 +381,7 @@ func (se *Engine) ReloadAtEx(ctx context.Context, pos mysql.Position, includeSta return nil } if !pos.IsZero() && se.reloadAtPos.AtLeast(pos) { - log.V(2).Infof("ReloadAtEx: found cached schema at %s", mysql.EncodePosition(pos)) + log.V(2).Infof("ReloadAtEx: found cached schema at %s", replication.EncodePosition(pos)) return nil } if err := se.reload(ctx, includeStats); err != nil { diff --git a/go/vt/vttablet/tabletserver/schema/engine_test.go b/go/vt/vttablet/tabletserver/schema/engine_test.go index 950619f95de..278b9637a2a 100644 --- a/go/vt/vttablet/tabletserver/schema/engine_test.go +++ b/go/vt/vttablet/tabletserver/schema/engine_test.go @@ -31,6 +31,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/event/syslogger" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/mysql/fakesqldb" @@ -205,13 +208,13 @@ func TestOpenAndReload(t *testing.T) { assert.Equal(t, int64(0), se.tableFileSizeGauge.Counts()["msg"]) // ReloadAt tests - pos1, err := mysql.DecodePosition("MariaDB/0-41983-20") + pos1, err := replication.DecodePosition("MariaDB/0-41983-20") require.NoError(t, err) - pos2, err := mysql.DecodePosition("MariaDB/0-41983-40") + pos2, err := replication.DecodePosition("MariaDB/0-41983-40") require.NoError(t, err) se.UnregisterNotifier("test") - err = se.ReloadAt(context.Background(), mysql.Position{}) + err = se.ReloadAt(context.Background(), replication.Position{}) require.NoError(t, err) assert.Equal(t, want, se.GetSchema()) @@ -447,7 +450,7 @@ func TestOpenFailedDueToLoadTableErr(t *testing.T) { db.AddQueryPattern(fmt.Sprintf(mysql.GetColumnNamesQueryPatternForTable, "test_view"), sqltypes.MakeTestResult(sqltypes.MakeTestFields("column_name", "varchar"), "")) // rejecting the impossible query - db.AddRejectedQuery("SELECT * FROM `fakesqldb`.`test_view` WHERE 1 != 1", mysql.NewSQLErrorFromError(errors.New("The user specified as a definer ('root'@'%') does not exist (errno 1449) (sqlstate HY000)"))) + db.AddRejectedQuery("SELECT * FROM `fakesqldb`.`test_view` WHERE 1 != 1", sqlerror.NewSQLErrorFromError(errors.New("The user specified as a definer ('root'@'%') does not exist (errno 1449) (sqlstate HY000)"))) AddFakeInnoDBReadRowsResult(db, 0) se := newEngine(10, 1*time.Second, 1*time.Second, 0, db) @@ -482,7 +485,7 @@ func TestOpenNoErrorDueToInvalidViews(t *testing.T) { db.AddQueryPattern(fmt.Sprintf(mysql.GetColumnNamesQueryPatternForTable, "bar_view"), sqltypes.MakeTestResult(sqltypes.MakeTestFields("column_name", "varchar"), "col1", "col2")) // rejecting the impossible query - db.AddRejectedQuery("SELECT `col1`, `col2` FROM `fakesqldb`.`bar_view` WHERE 1 != 1", mysql.NewSQLError(mysql.ERWrongFieldWithGroup, mysql.SSClientError, "random error for table bar_view")) + db.AddRejectedQuery("SELECT `col1`, `col2` FROM `fakesqldb`.`bar_view` WHERE 1 != 1", sqlerror.NewSQLError(sqlerror.ERWrongFieldWithGroup, sqlerror.SSClientError, "random error for table bar_view")) AddFakeInnoDBReadRowsResult(db, 0) se := newEngine(10, 1*time.Second, 1*time.Second, 0, db) diff --git a/go/vt/vttablet/tabletserver/schema/historian.go b/go/vt/vttablet/tabletserver/schema/historian.go index 4cd83b4d48f..3dacd53a48e 100644 --- a/go/vt/vttablet/tabletserver/schema/historian.go +++ b/go/vt/vttablet/tabletserver/schema/historian.go @@ -22,7 +22,7 @@ import ( "sync" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/log" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" @@ -43,7 +43,7 @@ const vl = 10 // trackedSchema has the snapshot of the table at a given pos (reached by ddl) type trackedSchema struct { schema map[string]*binlogdatapb.MinimalTable - pos mysql.Position + pos replication.Position ddl string timeUpdated int64 } @@ -146,7 +146,7 @@ func (h *historian) GetTableForPos(tableName sqlparser.IdentifierCS, gtid string if gtid == "" { return nil, nil } - pos, err := mysql.DecodePosition(gtid) + pos, err := replication.DecodePosition(gtid) if err != nil { return nil, err } @@ -210,7 +210,7 @@ func (h *historian) readRow(row []sqltypes.Value) (*trackedSchema, int64, error) if err != nil { return nil, 0, err } - pos, err := mysql.DecodePosition(string(rowBytes)) + pos, err := replication.DecodePosition(string(rowBytes)) if err != nil { return nil, 0, err } @@ -232,7 +232,7 @@ func (h *historian) readRow(row []sqltypes.Value) (*trackedSchema, int64, error) return nil, 0, err } log.V(vl).Infof("Read tracked schema from db: id %d, pos %v, ddl %s, schema len %d, time_updated %d \n", - id, mysql.EncodePosition(pos), ddl, len(sch.Tables), timeUpdated) + id, replication.EncodePosition(pos), ddl, len(sch.Tables), timeUpdated) tables := map[string]*binlogdatapb.MinimalTable{} for _, t := range sch.Tables { @@ -281,7 +281,7 @@ func (h *historian) sortSchemas() { } // getTableFromHistoryForPos looks in the cache for a schema for a specific gtid -func (h *historian) getTableFromHistoryForPos(tableName sqlparser.IdentifierCS, pos mysql.Position) *binlogdatapb.MinimalTable { +func (h *historian) getTableFromHistoryForPos(tableName sqlparser.IdentifierCS, pos replication.Position) *binlogdatapb.MinimalTable { idx := sort.Search(len(h.schemas), func(i int) bool { return pos.Equal(h.schemas[i].pos) || !pos.AtLeast(h.schemas[i].pos) }) diff --git a/go/vt/vttablet/tabletserver/schema/tracker.go b/go/vt/vttablet/tabletserver/schema/tracker.go index 415b4fcedda..ba297d26c18 100644 --- a/go/vt/vttablet/tabletserver/schema/tracker.go +++ b/go/vt/vttablet/tabletserver/schema/tracker.go @@ -23,7 +23,7 @@ import ( "sync" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/schema" "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" @@ -155,10 +155,10 @@ func (tr *Tracker) process(ctx context.Context) { } } -func (tr *Tracker) currentPosition(ctx context.Context) (mysql.Position, error) { +func (tr *Tracker) currentPosition(ctx context.Context) (replication.Position, error) { conn, err := tr.engine.cp.Connect(ctx) if err != nil { - return mysql.Position{}, err + return replication.Position{}, err } defer conn.Close() return conn.PrimaryPosition() @@ -202,7 +202,7 @@ func (tr *Tracker) possiblyInsertInitialSchema(ctx context.Context) error { if err != nil { return err } - gtid := mysql.EncodePosition(pos) + gtid := replication.EncodePosition(pos) log.Infof("Saving initial schema for gtid %s", gtid) return tr.saveCurrentSchemaToDb(ctx, gtid, ddl, timestamp) diff --git a/go/vt/vttablet/tabletserver/stateful_connection.go b/go/vt/vttablet/tabletserver/stateful_connection.go index 490f5275e3b..84552ee4c6a 100644 --- a/go/vt/vttablet/tabletserver/stateful_connection.go +++ b/go/vt/vttablet/tabletserver/stateful_connection.go @@ -21,7 +21,7 @@ import ( "fmt" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/pools" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/callerid" @@ -97,7 +97,7 @@ func (sc *StatefulConnection) Exec(ctx context.Context, query string, maxrows in } r, err := sc.dbConn.ExecOnce(ctx, query, maxrows, wantfields) if err != nil { - if mysql.IsConnErr(err) { + if sqlerror.IsConnErr(err) { select { case <-ctx.Done(): // If the context is done, the query was killed. diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go index b9b2e3fac90..09091023168 100644 --- a/go/vt/vttablet/tabletserver/tabletserver.go +++ b/go/vt/vttablet/tabletserver/tabletserver.go @@ -35,8 +35,9 @@ import ( "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/acl" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/pools" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/stats" @@ -1561,7 +1562,7 @@ func (tsv *TabletServer) convertAndLogError(ctx context.Context, sql string, bin // If so, we don't want to suppress the error. This will allow VTGate to // detect and perform buffering during failovers. var message string - sqlErr, ok := err.(*mysql.SQLError) + sqlErr, ok := err.(*sqlerror.SQLError) if ok { sqlState := sqlErr.SQLState() errnum := sqlErr.Number() @@ -1596,64 +1597,64 @@ func (tsv *TabletServer) convertAndLogError(ctx context.Context, sql string, bin func convertErrorCode(err error) vtrpcpb.Code { errCode := vterrors.Code(err) - sqlErr, ok := err.(*mysql.SQLError) + sqlErr, ok := err.(*sqlerror.SQLError) if !ok { return errCode } switch sqlErr.Number() { - case mysql.ERNotSupportedYet: + case sqlerror.ERNotSupportedYet: errCode = vtrpcpb.Code_UNIMPLEMENTED - case mysql.ERDiskFull, mysql.EROutOfMemory, mysql.EROutOfSortMemory, mysql.ERConCount, mysql.EROutOfResources, mysql.ERRecordFileFull, mysql.ERHostIsBlocked, - mysql.ERCantCreateThread, mysql.ERTooManyDelayedThreads, mysql.ERNetPacketTooLarge, mysql.ERTooManyUserConnections, mysql.ERLockTableFull, mysql.ERUserLimitReached: + case sqlerror.ERDiskFull, sqlerror.EROutOfMemory, sqlerror.EROutOfSortMemory, sqlerror.ERConCount, sqlerror.EROutOfResources, sqlerror.ERRecordFileFull, sqlerror.ERHostIsBlocked, + sqlerror.ERCantCreateThread, sqlerror.ERTooManyDelayedThreads, sqlerror.ERNetPacketTooLarge, sqlerror.ERTooManyUserConnections, sqlerror.ERLockTableFull, sqlerror.ERUserLimitReached: errCode = vtrpcpb.Code_RESOURCE_EXHAUSTED - case mysql.ERLockWaitTimeout: + case sqlerror.ERLockWaitTimeout: errCode = vtrpcpb.Code_DEADLINE_EXCEEDED - case mysql.CRServerGone, mysql.ERServerShutdown, mysql.ERServerIsntAvailable, mysql.CRConnectionError, mysql.CRConnHostError: + case sqlerror.CRServerGone, sqlerror.ERServerShutdown, sqlerror.ERServerIsntAvailable, sqlerror.CRConnectionError, sqlerror.CRConnHostError: errCode = vtrpcpb.Code_UNAVAILABLE - case mysql.ERFormNotFound, mysql.ERKeyNotFound, mysql.ERBadFieldError, mysql.ERNoSuchThread, mysql.ERUnknownTable, mysql.ERCantFindUDF, mysql.ERNonExistingGrant, - mysql.ERNoSuchTable, mysql.ERNonExistingTableGrant, mysql.ERKeyDoesNotExist: + case sqlerror.ERFormNotFound, sqlerror.ERKeyNotFound, sqlerror.ERBadFieldError, sqlerror.ERNoSuchThread, sqlerror.ERUnknownTable, sqlerror.ERCantFindUDF, sqlerror.ERNonExistingGrant, + sqlerror.ERNoSuchTable, sqlerror.ERNonExistingTableGrant, sqlerror.ERKeyDoesNotExist: errCode = vtrpcpb.Code_NOT_FOUND - case mysql.ERDBAccessDenied, mysql.ERAccessDeniedError, mysql.ERKillDenied, mysql.ERNoPermissionToCreateUsers: + case sqlerror.ERDBAccessDenied, sqlerror.ERAccessDeniedError, sqlerror.ERKillDenied, sqlerror.ERNoPermissionToCreateUsers: errCode = vtrpcpb.Code_PERMISSION_DENIED - case mysql.ERNoDb, mysql.ERNoSuchIndex, mysql.ERCantDropFieldOrKey, mysql.ERTableNotLockedForWrite, mysql.ERTableNotLocked, mysql.ERTooBigSelect, mysql.ERNotAllowedCommand, - mysql.ERTooLongString, mysql.ERDelayedInsertTableLocked, mysql.ERDupUnique, mysql.ERRequiresPrimaryKey, mysql.ERCantDoThisDuringAnTransaction, mysql.ERReadOnlyTransaction, - mysql.ERCannotAddForeign, mysql.ERNoReferencedRow, mysql.ERRowIsReferenced, mysql.ERCantUpdateWithReadLock, mysql.ERNoDefault, mysql.EROperandColumns, - mysql.ERSubqueryNo1Row, mysql.ERNonUpdateableTable, mysql.ERFeatureDisabled, mysql.ERDuplicatedValueInType, mysql.ERRowIsReferenced2, - mysql.ErNoReferencedRow2, mysql.ERWarnDataOutOfRange: + case sqlerror.ERNoDb, sqlerror.ERNoSuchIndex, sqlerror.ERCantDropFieldOrKey, sqlerror.ERTableNotLockedForWrite, sqlerror.ERTableNotLocked, sqlerror.ERTooBigSelect, sqlerror.ERNotAllowedCommand, + sqlerror.ERTooLongString, sqlerror.ERDelayedInsertTableLocked, sqlerror.ERDupUnique, sqlerror.ERRequiresPrimaryKey, sqlerror.ERCantDoThisDuringAnTransaction, sqlerror.ERReadOnlyTransaction, + sqlerror.ERCannotAddForeign, sqlerror.ERNoReferencedRow, sqlerror.ERRowIsReferenced, sqlerror.ERCantUpdateWithReadLock, sqlerror.ERNoDefault, sqlerror.EROperandColumns, + sqlerror.ERSubqueryNo1Row, sqlerror.ERNonUpdateableTable, sqlerror.ERFeatureDisabled, sqlerror.ERDuplicatedValueInType, sqlerror.ERRowIsReferenced2, + sqlerror.ErNoReferencedRow2, sqlerror.ERWarnDataOutOfRange: errCode = vtrpcpb.Code_FAILED_PRECONDITION - case mysql.EROptionPreventsStatement: + case sqlerror.EROptionPreventsStatement: errCode = vtrpcpb.Code_CLUSTER_EVENT - case mysql.ERTableExists, mysql.ERDupEntry, mysql.ERFileExists, mysql.ERUDFExists: + case sqlerror.ERTableExists, sqlerror.ERDupEntry, sqlerror.ERFileExists, sqlerror.ERUDFExists: errCode = vtrpcpb.Code_ALREADY_EXISTS - case mysql.ERGotSignal, mysql.ERForcingClose, mysql.ERAbortingConnection, mysql.ERLockDeadlock: + case sqlerror.ERGotSignal, sqlerror.ERForcingClose, sqlerror.ERAbortingConnection, sqlerror.ERLockDeadlock: // For ERLockDeadlock, a deadlock rolls back the transaction. errCode = vtrpcpb.Code_ABORTED - case mysql.ERUnknownComError, mysql.ERBadNullError, mysql.ERBadDb, mysql.ERBadTable, mysql.ERNonUniq, mysql.ERWrongFieldWithGroup, mysql.ERWrongGroupField, - mysql.ERWrongSumSelect, mysql.ERWrongValueCount, mysql.ERTooLongIdent, mysql.ERDupFieldName, mysql.ERDupKeyName, mysql.ERWrongFieldSpec, mysql.ERParseError, - mysql.EREmptyQuery, mysql.ERNonUniqTable, mysql.ERInvalidDefault, mysql.ERMultiplePriKey, mysql.ERTooManyKeys, mysql.ERTooManyKeyParts, mysql.ERTooLongKey, - mysql.ERKeyColumnDoesNotExist, mysql.ERBlobUsedAsKey, mysql.ERTooBigFieldLength, mysql.ERWrongAutoKey, mysql.ERWrongFieldTerminators, mysql.ERBlobsAndNoTerminated, - mysql.ERTextFileNotReadable, mysql.ERWrongSubKey, mysql.ERCantRemoveAllFields, mysql.ERUpdateTableUsed, mysql.ERNoTablesUsed, mysql.ERTooBigSet, - mysql.ERBlobCantHaveDefault, mysql.ERWrongDbName, mysql.ERWrongTableName, mysql.ERUnknownProcedure, mysql.ERWrongParamCountToProcedure, - mysql.ERWrongParametersToProcedure, mysql.ERFieldSpecifiedTwice, mysql.ERInvalidGroupFuncUse, mysql.ERTableMustHaveColumns, mysql.ERUnknownCharacterSet, - mysql.ERTooManyTables, mysql.ERTooManyFields, mysql.ERTooBigRowSize, mysql.ERWrongOuterJoin, mysql.ERNullColumnInIndex, mysql.ERFunctionNotDefined, - mysql.ERWrongValueCountOnRow, mysql.ERInvalidUseOfNull, mysql.ERRegexpError, mysql.ERMixOfGroupFuncAndFields, mysql.ERIllegalGrantForTable, mysql.ERSyntaxError, - mysql.ERWrongColumnName, mysql.ERWrongKeyColumn, mysql.ERBlobKeyWithoutLength, mysql.ERPrimaryCantHaveNull, mysql.ERTooManyRows, mysql.ERUnknownSystemVariable, - mysql.ERSetConstantsOnly, mysql.ERWrongArguments, mysql.ERWrongUsage, mysql.ERWrongNumberOfColumnsInSelect, mysql.ERDupArgument, mysql.ERLocalVariable, - mysql.ERGlobalVariable, mysql.ERWrongValueForVar, mysql.ERWrongTypeForVar, mysql.ERVarCantBeRead, mysql.ERCantUseOptionHere, mysql.ERIncorrectGlobalLocalVar, - mysql.ERWrongFKDef, mysql.ERKeyRefDoNotMatchTableRef, mysql.ERCyclicReference, mysql.ERCollationCharsetMismatch, mysql.ERCantAggregate2Collations, - mysql.ERCantAggregate3Collations, mysql.ERCantAggregateNCollations, mysql.ERVariableIsNotStruct, mysql.ERUnknownCollation, mysql.ERWrongNameForIndex, - mysql.ERWrongNameForCatalog, mysql.ERBadFTColumn, mysql.ERTruncatedWrongValue, mysql.ERTooMuchAutoTimestampCols, mysql.ERInvalidOnUpdate, mysql.ERUnknownTimeZone, - mysql.ERInvalidCharacterString, mysql.ERIllegalReference, mysql.ERDerivedMustHaveAlias, mysql.ERTableNameNotAllowedHere, mysql.ERDataTooLong, mysql.ERDataOutOfRange, - mysql.ERTruncatedWrongValueForField, mysql.ERIllegalValueForType: + case sqlerror.ERUnknownComError, sqlerror.ERBadNullError, sqlerror.ERBadDb, sqlerror.ERBadTable, sqlerror.ERNonUniq, sqlerror.ERWrongFieldWithGroup, sqlerror.ERWrongGroupField, + sqlerror.ERWrongSumSelect, sqlerror.ERWrongValueCount, sqlerror.ERTooLongIdent, sqlerror.ERDupFieldName, sqlerror.ERDupKeyName, sqlerror.ERWrongFieldSpec, sqlerror.ERParseError, + sqlerror.EREmptyQuery, sqlerror.ERNonUniqTable, sqlerror.ERInvalidDefault, sqlerror.ERMultiplePriKey, sqlerror.ERTooManyKeys, sqlerror.ERTooManyKeyParts, sqlerror.ERTooLongKey, + sqlerror.ERKeyColumnDoesNotExist, sqlerror.ERBlobUsedAsKey, sqlerror.ERTooBigFieldLength, sqlerror.ERWrongAutoKey, sqlerror.ERWrongFieldTerminators, sqlerror.ERBlobsAndNoTerminated, + sqlerror.ERTextFileNotReadable, sqlerror.ERWrongSubKey, sqlerror.ERCantRemoveAllFields, sqlerror.ERUpdateTableUsed, sqlerror.ERNoTablesUsed, sqlerror.ERTooBigSet, + sqlerror.ERBlobCantHaveDefault, sqlerror.ERWrongDbName, sqlerror.ERWrongTableName, sqlerror.ERUnknownProcedure, sqlerror.ERWrongParamCountToProcedure, + sqlerror.ERWrongParametersToProcedure, sqlerror.ERFieldSpecifiedTwice, sqlerror.ERInvalidGroupFuncUse, sqlerror.ERTableMustHaveColumns, sqlerror.ERUnknownCharacterSet, + sqlerror.ERTooManyTables, sqlerror.ERTooManyFields, sqlerror.ERTooBigRowSize, sqlerror.ERWrongOuterJoin, sqlerror.ERNullColumnInIndex, sqlerror.ERFunctionNotDefined, + sqlerror.ERWrongValueCountOnRow, sqlerror.ERInvalidUseOfNull, sqlerror.ERRegexpError, sqlerror.ERMixOfGroupFuncAndFields, sqlerror.ERIllegalGrantForTable, sqlerror.ERSyntaxError, + sqlerror.ERWrongColumnName, sqlerror.ERWrongKeyColumn, sqlerror.ERBlobKeyWithoutLength, sqlerror.ERPrimaryCantHaveNull, sqlerror.ERTooManyRows, sqlerror.ERUnknownSystemVariable, + sqlerror.ERSetConstantsOnly, sqlerror.ERWrongArguments, sqlerror.ERWrongUsage, sqlerror.ERWrongNumberOfColumnsInSelect, sqlerror.ERDupArgument, sqlerror.ERLocalVariable, + sqlerror.ERGlobalVariable, sqlerror.ERWrongValueForVar, sqlerror.ERWrongTypeForVar, sqlerror.ERVarCantBeRead, sqlerror.ERCantUseOptionHere, sqlerror.ERIncorrectGlobalLocalVar, + sqlerror.ERWrongFKDef, sqlerror.ERKeyRefDoNotMatchTableRef, sqlerror.ERCyclicReference, sqlerror.ERCollationCharsetMismatch, sqlerror.ERCantAggregate2Collations, + sqlerror.ERCantAggregate3Collations, sqlerror.ERCantAggregateNCollations, sqlerror.ERVariableIsNotStruct, sqlerror.ERUnknownCollation, sqlerror.ERWrongNameForIndex, + sqlerror.ERWrongNameForCatalog, sqlerror.ERBadFTColumn, sqlerror.ERTruncatedWrongValue, sqlerror.ERTooMuchAutoTimestampCols, sqlerror.ERInvalidOnUpdate, sqlerror.ERUnknownTimeZone, + sqlerror.ERInvalidCharacterString, sqlerror.ERIllegalReference, sqlerror.ERDerivedMustHaveAlias, sqlerror.ERTableNameNotAllowedHere, sqlerror.ERDataTooLong, sqlerror.ERDataOutOfRange, + sqlerror.ERTruncatedWrongValueForField, sqlerror.ERIllegalValueForType: errCode = vtrpcpb.Code_INVALID_ARGUMENT - case mysql.ERSpecifiedAccessDenied: + case sqlerror.ERSpecifiedAccessDenied: errCode = vtrpcpb.Code_PERMISSION_DENIED // This code is also utilized for Google internal failover error code. if strings.Contains(err.Error(), "failover in progress") { errCode = vtrpcpb.Code_FAILED_PRECONDITION } - case mysql.CRServerLost: + case sqlerror.CRServerLost: // Query was killed. errCode = vtrpcpb.Code_CANCELED } diff --git a/go/vt/vttablet/tabletserver/tabletserver_test.go b/go/vt/vttablet/tabletserver/tabletserver_test.go index b26baa35cac..0781904ae2a 100644 --- a/go/vt/vttablet/tabletserver/tabletserver_test.go +++ b/go/vt/vttablet/tabletserver/tabletserver_test.go @@ -32,6 +32,7 @@ import ( "testing" "time" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/callerid" @@ -1605,7 +1606,7 @@ func TestTerseErrors(t *testing.T) { defer tl.Close() sql := "select * from test_table where xyz = :vtg1 order by abc desc" - sqlErr := mysql.NewSQLError(10, "HY000", "sensitive message") + sqlErr := sqlerror.NewSQLError(10, "HY000", "sensitive message") sqlErr.Query = "select * from test_table where xyz = 'this is kinda long eh'" err := tsv.convertAndLogError( ctx, @@ -1637,7 +1638,7 @@ func TestSanitizeLogMessages(t *testing.T) { defer tl.Close() sql := "select * from test_table where xyz = :vtg1 order by abc desc" - sqlErr := mysql.NewSQLError(10, "HY000", "sensitive message") + sqlErr := sqlerror.NewSQLError(10, "HY000", "sensitive message") sqlErr.Query = "select * from test_table where xyz = 'this is pretty rad my doo, getting swole'" err := tsv.convertAndLogError( ctx, @@ -1713,7 +1714,7 @@ func TestSanitizeMessagesBindVars(t *testing.T) { tl := newTestLogger() defer tl.Close() - sqlErr := mysql.NewSQLError(10, "HY000", "sensitive message") + sqlErr := sqlerror.NewSQLError(10, "HY000", "sensitive message") sqlErr.Query = "select * from test_table where a = 1" err := tsv.convertAndLogError( @@ -1784,7 +1785,7 @@ func TestTruncateMessages(t *testing.T) { sqlparser.SetTruncateErrLen(52) sql := "select * from test_table where xyz = :vtg1 order by abc desc" - sqlErr := mysql.NewSQLError(10, "HY000", "sensitive message") + sqlErr := sqlerror.NewSQLError(10, "HY000", "sensitive message") sqlErr.Query = "select * from test_table where xyz = 'this is kinda long eh'" err := tsv.convertAndLogError( ctx, @@ -1837,7 +1838,7 @@ func TestTerseErrorsIgnoreFailoverInProgress(t *testing.T) { defer tl.Close() err := tsv.convertAndLogError(ctx, "select * from test_table where id = :a", map[string]*querypb.BindVariable{"a": sqltypes.Int64BindVariable(1)}, - mysql.NewSQLError(1227, mysql.SSClientError, "failover in progress"), + sqlerror.NewSQLError(1227, sqlerror.SSClientError, "failover in progress"), nil, ) if got, want := err.Error(), "failover in progress (errno 1227) (sqlstate 42000)"; !strings.HasPrefix(got, want) { diff --git a/go/vt/vttablet/tabletserver/vstreamer/copy.go b/go/vt/vttablet/tabletserver/vstreamer/copy.go index 06e90688482..be2063ba0ce 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/copy.go +++ b/go/vt/vttablet/tabletserver/vstreamer/copy.go @@ -23,7 +23,7 @@ import ( "math" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/log" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" @@ -72,7 +72,7 @@ func (uvs *uvstreamer) catchup(ctx context.Context) error { errch := make(chan error, 1) go func() { - startPos := mysql.EncodePosition(uvs.pos) + startPos := replication.EncodePosition(uvs.pos) vs := newVStreamer(ctx, uvs.cp, uvs.se, startPos, "", uvs.filter, uvs.getVSchema(), uvs.throttlerApp, uvs.send2, "catchup", uvs.vse) uvs.setVs(vs) errch <- vs.Stream() @@ -225,7 +225,7 @@ func (uvs *uvstreamer) copyTable(ctx context.Context, tableName string) error { if len(rows.Fields) == 0 { return fmt.Errorf("expecting field event first, got: %v", rows) } - pos, _ := mysql.DecodePosition(rows.Gtid) + pos, _ := replication.DecodePosition(rows.Gtid) if !uvs.pos.IsZero() && !uvs.pos.AtLeast(pos) { if err := uvs.fastForward(rows.Gtid); err != nil { uvs.setVs(nil) @@ -233,7 +233,7 @@ func (uvs *uvstreamer) copyTable(ctx context.Context, tableName string) error { return err } uvs.setVs(nil) - if mysql.EncodePosition(uvs.pos) != rows.Gtid { + if replication.EncodePosition(uvs.pos) != rows.Gtid { return fmt.Errorf("position after fastforward was %s but stopPos was %s", uvs.pos, rows.Gtid) } if err := uvs.setPosition(rows.Gtid, false); err != nil { @@ -316,9 +316,9 @@ func (uvs *uvstreamer) fastForward(stopPos string) error { defer func() { uvs.vse.vstreamerPhaseTimings.Record("fastforward", time.Now()) }() - log.Infof("starting fastForward from %s upto pos %s", mysql.EncodePosition(uvs.pos), stopPos) - uvs.stopPos, _ = mysql.DecodePosition(stopPos) - vs := newVStreamer(uvs.ctx, uvs.cp, uvs.se, mysql.EncodePosition(uvs.pos), "", uvs.filter, uvs.getVSchema(), uvs.throttlerApp, uvs.send2, "fastforward", uvs.vse) + log.Infof("starting fastForward from %s upto pos %s", replication.EncodePosition(uvs.pos), stopPos) + uvs.stopPos, _ = replication.DecodePosition(stopPos) + vs := newVStreamer(uvs.ctx, uvs.cp, uvs.se, replication.EncodePosition(uvs.pos), "", uvs.filter, uvs.getVSchema(), uvs.throttlerApp, uvs.send2, "fastforward", uvs.vse) uvs.setVs(vs) return vs.Stream() } diff --git a/go/vt/vttablet/tabletserver/vstreamer/rowstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/rowstreamer.go index 31e13427af3..7fcbbb65735 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/rowstreamer.go +++ b/go/vt/vttablet/tabletserver/vstreamer/rowstreamer.go @@ -22,8 +22,8 @@ import ( "sync" "time" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/mysql/collations" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/textutil" "vitess.io/vitess/go/timer" @@ -143,7 +143,7 @@ func (rs *rowStreamer) buildPlan() error { // where it in fact does exist. // For this reason we give vstreamer a "second chance" to review the up-to-date state of the schema. // In the future, we will reduce this operation to reading a single table rather than the entire schema. - rs.se.ReloadAt(context.Background(), mysql.Position{}) + rs.se.ReloadAt(context.Background(), replication.Position{}) st, err = rs.se.GetTableForPos(fromTable, "") } if err != nil { diff --git a/go/vt/vttablet/tabletserver/vstreamer/snapshot_conn.go b/go/vt/vttablet/tabletserver/vstreamer/snapshot_conn.go index ce71bb48a90..3b4bb8f3d8c 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/snapshot_conn.go +++ b/go/vt/vttablet/tabletserver/vstreamer/snapshot_conn.go @@ -23,6 +23,8 @@ import ( "github.com/spf13/pflag" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/log" @@ -139,7 +141,7 @@ func (conn *snapshotConn) startSnapshot(ctx context.Context, table string) (gtid if _, err := conn.ExecuteFetch("set @@session.time_zone = '+00:00'", 1, false); err != nil { return "", err } - return mysql.EncodePosition(mpos), nil + return replication.EncodePosition(mpos), nil } // startSnapshotWithConsistentGTID performs the snapshotting without locking tables. This assumes @@ -155,14 +157,14 @@ func (conn *snapshotConn) startSnapshotWithConsistentGTID(ctx context.Context) ( } // The "session_track_gtids = START_GTID" patch is only applicable to MySQL56 GTID, which is // why we hardcode the position as mysql.Mysql56FlavorID - mpos, err := mysql.ParsePosition(mysql.Mysql56FlavorID, result.SessionStateChanges) + mpos, err := replication.ParsePosition(replication.Mysql56FlavorID, result.SessionStateChanges) if err != nil { return "", err } if _, err := conn.ExecuteFetch("set @@session.time_zone = '+00:00'", 1, false); err != nil { return "", err } - return mysql.EncodePosition(mpos), nil + return replication.EncodePosition(mpos), nil } // Close rollsback any open transactions and closes the connection. diff --git a/go/vt/vttablet/tabletserver/vstreamer/uvstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/uvstreamer.go index a1ea07a92fa..2b770c1d4f4 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/uvstreamer.go +++ b/go/vt/vttablet/tabletserver/vstreamer/uvstreamer.go @@ -26,9 +26,9 @@ import ( "sync" "time" + "vitess.io/vitess/go/mysql/replication" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/log" @@ -76,10 +76,10 @@ type uvstreamer struct { pkfields []*querypb.Field // current position in the binlog for this streamer - pos mysql.Position + pos replication.Position // fast forward uses this to stop replicating upto the point of the last snapshot - stopPos mysql.Position + stopPos replication.Position // lastTimestampNs is the last timestamp seen so far. lastTimestampNs int64 @@ -324,7 +324,7 @@ func (uvs *uvstreamer) send2(evs []*binlogdatapb.VEvent) error { } for _, ev := range evs2 { if ev.Type == binlogdatapb.VEventType_GTID { - uvs.pos, _ = mysql.DecodePosition(ev.Gtid) + uvs.pos, _ = replication.DecodePosition(ev.Gtid) if !uvs.stopPos.IsZero() && uvs.pos.AtLeast(uvs.stopPos) { err = io.EOF } @@ -340,7 +340,7 @@ func (uvs *uvstreamer) sendEventsForCurrentPos() error { log.Infof("sendEventsForCurrentPos") evs := []*binlogdatapb.VEvent{{ Type: binlogdatapb.VEventType_GTID, - Gtid: mysql.EncodePosition(uvs.pos), + Gtid: replication.EncodePosition(uvs.pos), }, { Type: binlogdatapb.VEventType_OTHER, }} @@ -362,7 +362,7 @@ func (uvs *uvstreamer) setStreamStartPosition() error { } return nil } - pos, err := mysql.DecodePosition(uvs.startPos) + pos, err := replication.DecodePosition(uvs.startPos) if err != nil { return vterrors.Wrap(err, "could not decode position") } @@ -370,16 +370,16 @@ func (uvs *uvstreamer) setStreamStartPosition() error { uvs.vse.errorCounts.Add("GTIDSet Mismatch", 1) return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "GTIDSet Mismatch: requested source position:%v, current target vrep position: %v", - mysql.EncodePosition(pos), mysql.EncodePosition(curPos)) + replication.EncodePosition(pos), replication.EncodePosition(curPos)) } uvs.pos = pos return nil } -func (uvs *uvstreamer) currentPosition() (mysql.Position, error) { +func (uvs *uvstreamer) currentPosition() (replication.Position, error) { conn, err := uvs.cp.Connect(uvs.ctx) if err != nil { - return mysql.Position{}, err + return replication.Position{}, err } defer conn.Close() return conn.PrimaryPosition() @@ -424,7 +424,7 @@ func (uvs *uvstreamer) Stream() error { return err } } - vs := newVStreamer(uvs.ctx, uvs.cp, uvs.se, mysql.EncodePosition(uvs.pos), mysql.EncodePosition(uvs.stopPos), + vs := newVStreamer(uvs.ctx, uvs.cp, uvs.se, replication.EncodePosition(uvs.pos), replication.EncodePosition(uvs.stopPos), uvs.filter, uvs.getVSchema(), uvs.throttlerApp, uvs.send, "replicate", uvs.vse) uvs.setVs(vs) @@ -519,7 +519,7 @@ func (uvs *uvstreamer) setPosition(gtid string, isInTx bool) error { if gtid == "" { return fmt.Errorf("empty gtid passed to setPosition") } - pos, err := mysql.DecodePosition(gtid) + pos, err := replication.DecodePosition(gtid) if err != nil { return err } diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go index e8a3055dae8..d327be05394 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go +++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go @@ -26,6 +26,8 @@ import ( "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/mysql" mysqlbinlog "vitess.io/vitess/go/mysql/binlog" @@ -78,7 +80,7 @@ type vstreamer struct { // format and pos are updated by parseEvent. format mysql.BinlogFormat - pos mysql.Position + pos replication.Position stopPos string phase string @@ -167,7 +169,7 @@ func (vs *vstreamer) Stream() error { }() vs.vse.vstreamersCreated.Add(1) log.Infof("Starting Stream() with startPos %s", vs.startPos) - pos, err := mysql.DecodePosition(vs.startPos) + pos, err := replication.DecodePosition(vs.startPos) if err != nil { vs.vse.errorCounts.Add("StreamRows", 1) vs.vse.vstreamersEndedWithErrors.Add(1) @@ -448,11 +450,11 @@ func (vs *vstreamer) parseEvent(ev mysql.BinlogEvent) ([]*binlogdatapb.VEvent, e Type: binlogdatapb.VEventType_BEGIN, }) } - vs.pos = mysql.AppendGTID(vs.pos, gtid) + vs.pos = replication.AppendGTID(vs.pos, gtid) case ev.IsXID(): vevents = append(vevents, &binlogdatapb.VEvent{ Type: binlogdatapb.VEventType_GTID, - Gtid: mysql.EncodePosition(vs.pos), + Gtid: replication.EncodePosition(vs.pos), }, &binlogdatapb.VEvent{ Type: binlogdatapb.VEventType_COMMIT, }) @@ -509,7 +511,7 @@ func (vs *vstreamer) parseEvent(ev mysql.BinlogEvent) ([]*binlogdatapb.VEvent, e if mustSendDDL(q, vs.cp.DBName(), vs.filter) { vevents = append(vevents, &binlogdatapb.VEvent{ Type: binlogdatapb.VEventType_GTID, - Gtid: mysql.EncodePosition(vs.pos), + Gtid: replication.EncodePosition(vs.pos), }, &binlogdatapb.VEvent{ Type: binlogdatapb.VEventType_DDL, Statement: q.SQL, @@ -518,7 +520,7 @@ func (vs *vstreamer) parseEvent(ev mysql.BinlogEvent) ([]*binlogdatapb.VEvent, e // If the DDL need not be sent, send a dummy OTHER event. vevents = append(vevents, &binlogdatapb.VEvent{ Type: binlogdatapb.VEventType_GTID, - Gtid: mysql.EncodePosition(vs.pos), + Gtid: replication.EncodePosition(vs.pos), }, &binlogdatapb.VEvent{ Type: binlogdatapb.VEventType_OTHER, }) @@ -543,7 +545,7 @@ func (vs *vstreamer) parseEvent(ev mysql.BinlogEvent) ([]*binlogdatapb.VEvent, e // that we want to keep out of the stream for now. vevents = append(vevents, &binlogdatapb.VEvent{ Type: binlogdatapb.VEventType_GTID, - Gtid: mysql.EncodePosition(vs.pos), + Gtid: replication.EncodePosition(vs.pos), }, &binlogdatapb.VEvent{ Type: binlogdatapb.VEventType_OTHER, }) @@ -635,7 +637,7 @@ func (vs *vstreamer) parseEvent(ev mysql.BinlogEvent) ([]*binlogdatapb.VEvent, e return nil, err } case ev.IsTransactionPayload(): - if !vs.pos.MatchesFlavor(mysql.Mysql56FlavorID) { + if !vs.pos.MatchesFlavor(replication.Mysql56FlavorID) { return nil, fmt.Errorf("compressed transaction payload events are not supported with database flavor %s", vs.vse.env.Config().DB.Flavor) } @@ -778,7 +780,7 @@ func (vs *vstreamer) buildTableColumns(tm *mysql.TableMap) ([]*querypb.Field, er Flags: mysql.FlagsForColumn(t, collations.DefaultCollationForType(t)), }) } - st, err := vs.se.GetTableForPos(sqlparser.NewIdentifierCS(tm.Name), mysql.EncodePosition(vs.pos)) + st, err := vs.se.GetTableForPos(sqlparser.NewIdentifierCS(tm.Name), replication.EncodePosition(vs.pos)) if err != nil { if vs.filter.FieldEventMode == binlogdatapb.Filter_ERR_ON_MISMATCH { log.Infof("No schema found for table %s", tm.Name) @@ -1016,7 +1018,7 @@ func (vs *vstreamer) extractRowAndFilter(plan *streamerPlan, data []byte, dataCo return ok, filtered, partial, err } -func wrapError(err error, stopPos mysql.Position, vse *Engine) error { +func wrapError(err error, stopPos replication.Position, vse *Engine) error { if err != nil { vse.vstreamersEndedWithErrors.Add(1) vse.errorCounts.Add("StreamEnded", 1) diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_flaky_test.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_flaky_test.go index 8eafad07e01..0c9eda07752 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_flaky_test.go +++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_flaky_test.go @@ -26,6 +26,7 @@ import ( "testing" "time" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/throttlerapp" "vitess.io/vitess/go/vt/vttablet/tabletserver/vstreamer/testenv" @@ -2361,7 +2362,7 @@ func primaryPosition(t *testing.T) string { if err != nil { t.Fatal(err) } - return mysql.EncodePosition(pos) + return replication.EncodePosition(pos) } func setVSchema(t *testing.T, vschema string) { diff --git a/go/vt/vttablet/tmrpctest/test_tm_rpc.go b/go/vt/vttablet/tmrpctest/test_tm_rpc.go index 3c7b8bb987c..00a59315b9b 100644 --- a/go/vt/vttablet/tmrpctest/test_tm_rpc.go +++ b/go/vt/vttablet/tmrpctest/test_tm_rpc.go @@ -28,7 +28,8 @@ import ( "google.golang.org/protobuf/proto" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/protoutil" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/hook" @@ -752,8 +753,8 @@ func tmRPCTestExecuteFetchPanic(ctx context.Context, t *testing.T, client tmclie var testReplicationStatus = &replicationdatapb.Status{ Position: "MariaDB/1-345-789", - IoState: int32(mysql.ReplicationStateRunning), - SqlState: int32(mysql.ReplicationStateRunning), + IoState: int32(replication.ReplicationStateRunning), + SqlState: int32(replication.ReplicationStateRunning), ReplicationLagSeconds: 654, SourceHost: "source.host", SourcePort: 3366, diff --git a/go/vt/wrangler/switcher_dry_run.go b/go/vt/wrangler/switcher_dry_run.go index 231f6846928..2cb2f382a35 100644 --- a/go/vt/wrangler/switcher_dry_run.go +++ b/go/vt/wrangler/switcher_dry_run.go @@ -23,7 +23,7 @@ import ( "strings" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/vtctl/workflow" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" @@ -166,7 +166,7 @@ func (dr *switcherDryRun) migrateStreams(ctx context.Context, sm *workflow.Strea dr.drLog.Log(fmt.Sprintf("Migrate streams to %s:", dr.ts.TargetKeyspaceName())) for key, streams := range sm.Streams() { for _, stream := range streams { - logs = append(logs, fmt.Sprintf("\tShard %s Id %d, Workflow %s, Pos %s, BinLogSource %v", key, stream.ID, stream.Workflow, mysql.EncodePosition(stream.Position), stream.BinlogSource)) + logs = append(logs, fmt.Sprintf("\tShard %s Id %d, Workflow %s, Pos %s, BinLogSource %v", key, stream.ID, stream.Workflow, replication.EncodePosition(stream.Position), stream.BinlogSource)) } } if len(logs) > 0 { @@ -178,7 +178,7 @@ func (dr *switcherDryRun) migrateStreams(ctx context.Context, sm *workflow.Strea tabletStreams := templates for _, vrs := range tabletStreams { logs = append(logs, fmt.Sprintf("\t Keyspace %s, Shard %s, Tablet %d, Workflow %s, Id %d, Pos %v, BinLogSource %s", - vrs.BinlogSource.Keyspace, vrs.BinlogSource.Shard, target.GetPrimary().Alias.Uid, vrs.Workflow, vrs.ID, mysql.EncodePosition(vrs.Position), vrs.BinlogSource)) + vrs.BinlogSource.Keyspace, vrs.BinlogSource.Shard, target.GetPrimary().Alias.Uid, vrs.Workflow, vrs.ID, replication.EncodePosition(vrs.Position), vrs.BinlogSource)) } } if len(logs) > 0 { diff --git a/go/vt/wrangler/testlib/backup_test.go b/go/vt/wrangler/testlib/backup_test.go index 65bd7ab62a1..2af9984261f 100644 --- a/go/vt/wrangler/testlib/backup_test.go +++ b/go/vt/wrangler/testlib/backup_test.go @@ -27,6 +27,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/mysql" @@ -145,9 +147,9 @@ func testBackupRestore(t *testing.T, cDetails *compressionDetails) error { primary := NewFakeTablet(t, wr, "cell1", 0, topodatapb.TabletType_PRIMARY, db) primary.FakeMysqlDaemon.ReadOnly = false primary.FakeMysqlDaemon.Replicating = false - primary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + primary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, @@ -165,9 +167,9 @@ func testBackupRestore(t *testing.T, cDetails *compressionDetails) error { sourceTablet.FakeMysqlDaemon.ReadOnly = true sourceTablet.FakeMysqlDaemon.Replicating = true sourceTablet.FakeMysqlDaemon.SetReplicationSourceInputs = []string{fmt.Sprintf("%s:%d", primary.Tablet.MysqlHostname, primary.Tablet.MysqlPort)} - sourceTablet.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + sourceTablet.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, @@ -218,9 +220,9 @@ func testBackupRestore(t *testing.T, cDetails *compressionDetails) error { destTablet := NewFakeTablet(t, wr, "cell1", 2, topodatapb.TabletType_REPLICA, db) destTablet.FakeMysqlDaemon.ReadOnly = true destTablet.FakeMysqlDaemon.Replicating = true - destTablet.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + destTablet.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, @@ -382,9 +384,9 @@ func TestBackupRestoreLagged(t *testing.T) { primary := NewFakeTablet(t, wr, "cell1", 0, topodatapb.TabletType_PRIMARY, db) primary.FakeMysqlDaemon.ReadOnly = false primary.FakeMysqlDaemon.Replicating = false - primary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + primary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, @@ -401,9 +403,9 @@ func TestBackupRestoreLagged(t *testing.T) { sourceTablet := NewFakeTablet(t, wr, "cell1", 1, topodatapb.TabletType_REPLICA, db) sourceTablet.FakeMysqlDaemon.ReadOnly = true sourceTablet.FakeMysqlDaemon.Replicating = true - sourceTablet.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + sourceTablet.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 456, @@ -443,9 +445,9 @@ func TestBackupRestoreLagged(t *testing.T) { timer := time.NewTicker(1 * time.Second) <-timer.C - sourceTablet.FakeMysqlDaemon.CurrentPrimaryPositionLocked(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + sourceTablet.FakeMysqlDaemon.CurrentPrimaryPositionLocked(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, @@ -471,9 +473,9 @@ func TestBackupRestoreLagged(t *testing.T) { destTablet := NewFakeTablet(t, wr, "cell1", 2, topodatapb.TabletType_REPLICA, db) destTablet.FakeMysqlDaemon.ReadOnly = true destTablet.FakeMysqlDaemon.Replicating = true - destTablet.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + destTablet.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 456, @@ -520,9 +522,9 @@ func TestBackupRestoreLagged(t *testing.T) { timer = time.NewTicker(1 * time.Second) <-timer.C - destTablet.FakeMysqlDaemon.CurrentPrimaryPositionLocked(mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + destTablet.FakeMysqlDaemon.CurrentPrimaryPositionLocked(replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, @@ -600,9 +602,9 @@ func TestRestoreUnreachablePrimary(t *testing.T) { primary := NewFakeTablet(t, wr, "cell1", 0, topodatapb.TabletType_PRIMARY, db) primary.FakeMysqlDaemon.ReadOnly = false primary.FakeMysqlDaemon.Replicating = false - primary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + primary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, @@ -618,9 +620,9 @@ func TestRestoreUnreachablePrimary(t *testing.T) { sourceTablet := NewFakeTablet(t, wr, "cell1", 1, topodatapb.TabletType_REPLICA, db) sourceTablet.FakeMysqlDaemon.ReadOnly = true sourceTablet.FakeMysqlDaemon.Replicating = true - sourceTablet.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + sourceTablet.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, @@ -660,9 +662,9 @@ func TestRestoreUnreachablePrimary(t *testing.T) { destTablet := NewFakeTablet(t, wr, "cell1", 2, topodatapb.TabletType_REPLICA, db) destTablet.FakeMysqlDaemon.ReadOnly = true destTablet.FakeMysqlDaemon.Replicating = true - destTablet.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + destTablet.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, @@ -774,9 +776,9 @@ func TestDisableActiveReparents(t *testing.T) { primary := NewFakeTablet(t, wr, "cell1", 0, topodatapb.TabletType_PRIMARY, db) primary.FakeMysqlDaemon.ReadOnly = false primary.FakeMysqlDaemon.Replicating = false - primary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + primary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, @@ -793,9 +795,9 @@ func TestDisableActiveReparents(t *testing.T) { sourceTablet := NewFakeTablet(t, wr, "cell1", 1, topodatapb.TabletType_REPLICA, db) sourceTablet.FakeMysqlDaemon.ReadOnly = true sourceTablet.FakeMysqlDaemon.Replicating = true - sourceTablet.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + sourceTablet.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, @@ -826,9 +828,9 @@ func TestDisableActiveReparents(t *testing.T) { destTablet := NewFakeTablet(t, wr, "cell1", 2, topodatapb.TabletType_REPLICA, db) destTablet.FakeMysqlDaemon.ReadOnly = true destTablet.FakeMysqlDaemon.Replicating = true - destTablet.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + destTablet.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, diff --git a/go/vt/wrangler/testlib/emergency_reparent_shard_test.go b/go/vt/wrangler/testlib/emergency_reparent_shard_test.go index 2fb88f80816..3ef9513e1ed 100644 --- a/go/vt/wrangler/testlib/emergency_reparent_shard_test.go +++ b/go/vt/wrangler/testlib/emergency_reparent_shard_test.go @@ -25,6 +25,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sets" "vitess.io/vitess/go/vt/discovery" @@ -58,34 +60,34 @@ func TestEmergencyReparentShard(t *testing.T) { reparenttestutil.SetKeyspaceDurability(context.Background(), t, ts, "test_keyspace", "semi_sync") oldPrimary.FakeMysqlDaemon.Replicating = false - oldPrimary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + oldPrimary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 456, }, }, } - currentPrimaryFilePosition, _ := mysql.ParseFilePosGTIDSet("mariadb-bin.000010:456") - oldPrimary.FakeMysqlDaemon.CurrentSourceFilePosition = mysql.Position{ + currentPrimaryFilePosition, _ := replication.ParseFilePosGTIDSet("mariadb-bin.000010:456") + oldPrimary.FakeMysqlDaemon.CurrentSourceFilePosition = replication.Position{ GTIDSet: currentPrimaryFilePosition, } // new primary newPrimary.FakeMysqlDaemon.ReadOnly = true newPrimary.FakeMysqlDaemon.Replicating = true - newPrimary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 456, }, }, } - newPrimaryRelayLogPos, _ := mysql.ParseFilePosGTIDSet("relay-bin.000004:456") - newPrimary.FakeMysqlDaemon.CurrentSourceFilePosition = mysql.Position{ + newPrimaryRelayLogPos, _ := replication.ParseFilePosGTIDSet("relay-bin.000004:456") + newPrimary.FakeMysqlDaemon.CurrentSourceFilePosition = replication.Position{ GTIDSet: newPrimaryRelayLogPos, } newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = append(newPrimary.FakeMysqlDaemon.WaitPrimaryPositions, newPrimary.FakeMysqlDaemon.CurrentSourceFilePosition) @@ -93,9 +95,9 @@ func TestEmergencyReparentShard(t *testing.T) { "STOP SLAVE IO_THREAD", "SUBINSERT INTO _vt.reparent_journal (time_created_ns, action_name, primary_alias, replication_position) VALUES", } - newPrimary.FakeMysqlDaemon.PromoteResult = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.PromoteResult = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 456, @@ -118,17 +120,17 @@ func TestEmergencyReparentShard(t *testing.T) { // good replica 1 is replicating goodReplica1.FakeMysqlDaemon.ReadOnly = true goodReplica1.FakeMysqlDaemon.Replicating = true - goodReplica1.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + goodReplica1.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 455, }, }, } - goodReplica1RelayLogPos, _ := mysql.ParseFilePosGTIDSet("relay-bin.000004:455") - goodReplica1.FakeMysqlDaemon.CurrentSourceFilePosition = mysql.Position{ + goodReplica1RelayLogPos, _ := replication.ParseFilePosGTIDSet("relay-bin.000004:455") + goodReplica1.FakeMysqlDaemon.CurrentSourceFilePosition = replication.Position{ GTIDSet: goodReplica1RelayLogPos, } goodReplica1.FakeMysqlDaemon.WaitPrimaryPositions = append(goodReplica1.FakeMysqlDaemon.WaitPrimaryPositions, goodReplica1.FakeMysqlDaemon.CurrentSourceFilePosition) @@ -149,17 +151,17 @@ func TestEmergencyReparentShard(t *testing.T) { // good replica 2 is not replicating goodReplica2.FakeMysqlDaemon.ReadOnly = true goodReplica2.FakeMysqlDaemon.Replicating = false - goodReplica2.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + goodReplica2.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 454, }, }, } - goodReplica2RelayLogPos, _ := mysql.ParseFilePosGTIDSet("relay-bin.000004:454") - goodReplica2.FakeMysqlDaemon.CurrentSourceFilePosition = mysql.Position{ + goodReplica2RelayLogPos, _ := replication.ParseFilePosGTIDSet("relay-bin.000004:454") + goodReplica2.FakeMysqlDaemon.CurrentSourceFilePosition = replication.Position{ GTIDSet: goodReplica2RelayLogPos, } goodReplica2.FakeMysqlDaemon.WaitPrimaryPositions = append(goodReplica2.FakeMysqlDaemon.WaitPrimaryPositions, goodReplica2.FakeMysqlDaemon.CurrentSourceFilePosition) @@ -212,17 +214,17 @@ func TestEmergencyReparentShardPrimaryElectNotBest(t *testing.T) { newPrimary.FakeMysqlDaemon.Replicating = true // It has transactions in its relay log, but not as many as // moreAdvancedReplica - newPrimary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 456, }, }, } - newPrimaryRelayLogPos, _ := mysql.ParseFilePosGTIDSet("relay-bin.000004:456") - newPrimary.FakeMysqlDaemon.CurrentSourceFilePosition = mysql.Position{ + newPrimaryRelayLogPos, _ := replication.ParseFilePosGTIDSet("relay-bin.000004:456") + newPrimary.FakeMysqlDaemon.CurrentSourceFilePosition = replication.Position{ GTIDSet: newPrimaryRelayLogPos, } newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = append(newPrimary.FakeMysqlDaemon.WaitPrimaryPositions, newPrimary.FakeMysqlDaemon.CurrentSourceFilePosition) @@ -245,17 +247,17 @@ func TestEmergencyReparentShardPrimaryElectNotBest(t *testing.T) { // more advanced replica moreAdvancedReplica.FakeMysqlDaemon.Replicating = true // relay log position is more advanced than desired new primary - moreAdvancedReplica.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 2: mysql.MariadbGTID{ + moreAdvancedReplica.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 2: replication.MariadbGTID{ Domain: 2, Server: 123, Sequence: 457, }, }, } - moreAdvancedReplicaLogPos, _ := mysql.ParseFilePosGTIDSet("relay-bin.000004:457") - moreAdvancedReplica.FakeMysqlDaemon.CurrentSourceFilePosition = mysql.Position{ + moreAdvancedReplicaLogPos, _ := replication.ParseFilePosGTIDSet("relay-bin.000004:457") + moreAdvancedReplica.FakeMysqlDaemon.CurrentSourceFilePosition = replication.Position{ GTIDSet: moreAdvancedReplicaLogPos, } moreAdvancedReplica.FakeMysqlDaemon.SetReplicationSourceInputs = append(moreAdvancedReplica.FakeMysqlDaemon.SetReplicationSourceInputs, topoproto.MysqlAddr(newPrimary.Tablet), topoproto.MysqlAddr(oldPrimary.Tablet)) diff --git a/go/vt/wrangler/testlib/planned_reparent_shard_test.go b/go/vt/wrangler/testlib/planned_reparent_shard_test.go index 67c6defef35..e123727b4fb 100644 --- a/go/vt/wrangler/testlib/planned_reparent_shard_test.go +++ b/go/vt/wrangler/testlib/planned_reparent_shard_test.go @@ -22,6 +22,7 @@ import ( "testing" "time" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/mysqlctl" "github.com/stretchr/testify/assert" @@ -61,18 +62,18 @@ func TestPlannedReparentShardNoPrimaryProvided(t *testing.T) { // new primary newPrimary.FakeMysqlDaemon.ReadOnly = true newPrimary.FakeMysqlDaemon.Replicating = true - newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = []mysql.Position{{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = []replication.Position{{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 123, Sequence: 990, }, }, }} - newPrimary.FakeMysqlDaemon.PromoteResult = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.PromoteResult = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 456, Sequence: 991, @@ -176,18 +177,18 @@ func TestPlannedReparentShardNoError(t *testing.T) { // new primary newPrimary.FakeMysqlDaemon.ReadOnly = true newPrimary.FakeMysqlDaemon.Replicating = true - newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = []mysql.Position{{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = []replication.Position{{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 123, Sequence: 990, }, }, }} - newPrimary.FakeMysqlDaemon.PromoteResult = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.PromoteResult = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 456, Sequence: 991, @@ -309,9 +310,9 @@ func TestPlannedReparentInitialization(t *testing.T) { // new primary newPrimary.FakeMysqlDaemon.ReadOnly = true newPrimary.FakeMysqlDaemon.Replicating = true - newPrimary.FakeMysqlDaemon.PromoteResult = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.PromoteResult = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 456, Sequence: 991, @@ -393,18 +394,18 @@ func TestPlannedReparentShardWaitForPositionFail(t *testing.T) { // new primary newPrimary.FakeMysqlDaemon.ReadOnly = true newPrimary.FakeMysqlDaemon.Replicating = true - newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = []mysql.Position{{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = []replication.Position{{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 123, Sequence: 990, }, }, }} - newPrimary.FakeMysqlDaemon.PromoteResult = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.PromoteResult = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 456, Sequence: 991, @@ -500,18 +501,18 @@ func TestPlannedReparentShardWaitForPositionTimeout(t *testing.T) { newPrimary.FakeMysqlDaemon.TimeoutHook = func() error { return context.DeadlineExceeded } newPrimary.FakeMysqlDaemon.ReadOnly = true newPrimary.FakeMysqlDaemon.Replicating = true - newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = []mysql.Position{{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = []replication.Position{{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 123, Sequence: 990, }, }, }} - newPrimary.FakeMysqlDaemon.PromoteResult = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.PromoteResult = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 456, Sequence: 991, @@ -602,9 +603,9 @@ func TestPlannedReparentShardRelayLogError(t *testing.T) { primary.FakeMysqlDaemon.ReadOnly = false primary.FakeMysqlDaemon.Replicating = false primary.FakeMysqlDaemon.ReplicationStatusError = mysql.ErrNotReplica - primary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + primary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 123, Sequence: 990, @@ -681,9 +682,9 @@ func TestPlannedReparentShardRelayLogErrorStartReplication(t *testing.T) { primary.FakeMysqlDaemon.ReadOnly = false primary.FakeMysqlDaemon.Replicating = false primary.FakeMysqlDaemon.ReplicationStatusError = mysql.ErrNotReplica - primary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + primary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 123, Sequence: 990, @@ -766,18 +767,18 @@ func TestPlannedReparentShardPromoteReplicaFail(t *testing.T) { newPrimary.FakeMysqlDaemon.Replicating = true // make promote fail newPrimary.FakeMysqlDaemon.PromoteError = errors.New("some error") - newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = []mysql.Position{{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.WaitPrimaryPositions = []replication.Position{{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 123, Sequence: 990, }, }, }} - newPrimary.FakeMysqlDaemon.PromoteResult = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + newPrimary.FakeMysqlDaemon.PromoteResult = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 456, Sequence: 991, @@ -902,9 +903,9 @@ func TestPlannedReparentShardSamePrimary(t *testing.T) { oldPrimary.FakeMysqlDaemon.ReadOnly = true oldPrimary.FakeMysqlDaemon.Replicating = false oldPrimary.FakeMysqlDaemon.ReplicationStatusError = mysql.ErrNotReplica - oldPrimary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 7: mysql.MariadbGTID{ + oldPrimary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 7: replication.MariadbGTID{ Domain: 7, Server: 123, Sequence: 990, diff --git a/go/vt/wrangler/testlib/reparent_utils_test.go b/go/vt/wrangler/testlib/reparent_utils_test.go index c375e078253..d667c7ca9df 100644 --- a/go/vt/wrangler/testlib/reparent_utils_test.go +++ b/go/vt/wrangler/testlib/reparent_utils_test.go @@ -24,12 +24,13 @@ import ( "github.com/stretchr/testify/require" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/vt/vtctl/reparentutil/reparenttestutil" "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/vtctl/reparentutil" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/memorytopo" @@ -67,9 +68,9 @@ func TestShardReplicationStatuses(t *testing.T) { } // primary action loop (to initialize host and port) - primary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 5: mysql.MariadbGTID{ + primary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 5: replication.MariadbGTID{ Domain: 5, Server: 456, Sequence: 892, @@ -80,9 +81,9 @@ func TestShardReplicationStatuses(t *testing.T) { defer primary.StopActionLoop(t) // replica loop - replica.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 5: mysql.MariadbGTID{ + replica.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 5: replication.MariadbGTID{ Domain: 5, Server: 456, Sequence: 890, diff --git a/go/vt/wrangler/traffic_switcher_env_test.go b/go/vt/wrangler/traffic_switcher_env_test.go index 6da0e386487..18b2e6d54c4 100644 --- a/go/vt/wrangler/traffic_switcher_env_test.go +++ b/go/vt/wrangler/traffic_switcher_env_test.go @@ -27,7 +27,8 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/sync/semaphore" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/fakesqldb" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" @@ -654,9 +655,9 @@ func (tme *testMigraterEnv) createDBClients(ctx context.Context, t *testing.T) { func (tme *testMigraterEnv) setPrimaryPositions() { for _, primary := range tme.sourcePrimaries { - primary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 5: mysql.MariadbGTID{ + primary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 5: replication.MariadbGTID{ Domain: 5, Server: 456, Sequence: 892, @@ -665,9 +666,9 @@ func (tme *testMigraterEnv) setPrimaryPositions() { } } for _, primary := range tme.targetPrimaries { - primary.FakeMysqlDaemon.CurrentPrimaryPosition = mysql.Position{ - GTIDSet: mysql.MariadbGTIDSet{ - 5: mysql.MariadbGTID{ + primary.FakeMysqlDaemon.CurrentPrimaryPosition = replication.Position{ + GTIDSet: replication.MariadbGTIDSet{ + 5: replication.MariadbGTID{ Domain: 5, Server: 456, Sequence: 893, diff --git a/go/vt/wrangler/vdiff.go b/go/vt/wrangler/vdiff.go index 119a1bc5367..fb3e9e133df 100644 --- a/go/vt/wrangler/vdiff.go +++ b/go/vt/wrangler/vdiff.go @@ -29,7 +29,9 @@ import ( "google.golang.org/protobuf/encoding/prototext" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" + "vitess.io/vitess/go/mysql/sqlerror" + "vitess.io/vitess/go/mysql/collations" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" @@ -152,7 +154,7 @@ type tableDiffer struct { type shardStreamer struct { primary *topo.TabletInfo tablet *topodatapb.Tablet - position mysql.Position + position replication.Position snapshotPosition string result chan *sqltypes.Result err error @@ -911,8 +913,8 @@ func (df *vdiff) startQueryStreams(ctx context.Context, keyspace string, partici if participant.position.IsZero() { return fmt.Errorf("workflow %s.%s: stream has not started on tablet %s", df.targetKeyspace, df.workflow, participant.primary.Alias.String()) } - log.Infof("WaitForPosition: tablet %s should reach position %s", participant.tablet.Alias.String(), mysql.EncodePosition(participant.position)) - if err := df.ts.TabletManagerClient().WaitForPosition(waitCtx, participant.tablet, mysql.EncodePosition(participant.position)); err != nil { + log.Infof("WaitForPosition: tablet %s should reach position %s", participant.tablet.Alias.String(), replication.EncodePosition(participant.position)) + if err := df.ts.TabletManagerClient().WaitForPosition(waitCtx, participant.tablet, replication.EncodePosition(participant.position)); err != nil { log.Errorf("WaitForPosition error: %s", err) return vterrors.Wrapf(err, "WaitForPosition for tablet %v", topoproto.TabletAliasString(participant.tablet.Alias)) } @@ -1029,7 +1031,7 @@ func (df *vdiff) restartTargets(ctx context.Context) error { // Let's retry a few times if we get a retryable error. for i := 1; i <= 3; i++ { _, err = df.ts.TabletManagerClient().VReplicationExec(ctx, target.primary.Tablet, query) - if err == nil || !mysql.IsEphemeralError(err) { + if err == nil || !sqlerror.IsEphemeralError(err) { break } log.Warningf("Encountered the following error while restarting the %q VReplication workflow on %q, will retry (attempt #%d): %v", diff --git a/go/vt/wrangler/vexec.go b/go/vt/wrangler/vexec.go index ba840d50ca0..40e4425c976 100644 --- a/go/vt/wrangler/vexec.go +++ b/go/vt/wrangler/vexec.go @@ -26,6 +26,7 @@ import ( "sync" "time" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/textutil" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/topo/topoproto" @@ -33,7 +34,6 @@ import ( "google.golang.org/protobuf/encoding/prototext" - "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sets" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" @@ -559,7 +559,7 @@ func (wr *Wrangler) getReplicationStatusFromRow(ctx context.Context, row sqltype var workflowType, workflowSubType int32 var deferSecondaryKeys bool var bls binlogdatapb.BinlogSource - var mpos mysql.Position + var mpos replication.Position var rowsCopied int64 id, err = row.ToInt32("id") if err != nil { diff --git a/go/vt/wrangler/workflow.go b/go/vt/wrangler/workflow.go index 40acaf1f55d..8e2481bac8f 100644 --- a/go/vt/wrangler/workflow.go +++ b/go/vt/wrangler/workflow.go @@ -8,7 +8,7 @@ import ( "sync" "time" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/log" @@ -715,7 +715,7 @@ func (wr *Wrangler) deleteWorkflowVDiffData(ctx context.Context, tablet *topodat Query: []byte(query), MaxRows: uint64(rows), }); err != nil { - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Num != mysql.ERNoSuchTable { // the tables may not exist if no vdiffs have been run + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Num != sqlerror.ERNoSuchTable { // the tables may not exist if no vdiffs have been run wr.Logger().Errorf("Error deleting vdiff data for %s.%s workflow: %v", tablet.Keyspace, workflow, err) } } @@ -755,7 +755,7 @@ func (wr *Wrangler) optimizeCopyStateTable(tablet *topodatapb.Tablet) { Query: []byte(sqlOptimizeTable), MaxRows: uint64(100), // always produces 1+rows with notes and status }); err != nil { - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Num == mysql.ERNoSuchTable { // the table may not exist + if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Num == sqlerror.ERNoSuchTable { // the table may not exist return } log.Warningf("Failed to optimize the copy_state table on %q: %v", tablet.Alias.String(), err) diff --git a/tools/rowlog/rowlog.go b/tools/rowlog/rowlog.go index 831998580c5..475006b2b59 100644 --- a/tools/rowlog/rowlog.go +++ b/tools/rowlog/rowlog.go @@ -15,7 +15,7 @@ import ( "github.com/spf13/pflag" - "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/discovery" @@ -199,7 +199,7 @@ func startStreaming(ctx context.Context, vtgate, vtctld, keyspace, tablet, table } } var err error - var currentPosition, stopPosition mysql.Position + var currentPosition, stopPosition replication.Position currentPosition, err = binlogplayer.DecodePosition(gtid) if err != nil { fmt.Printf("Error decoding position for %s:%vs\n", gtid, err.Error()) From 5ffd09ede0df5793c715d3f02d0e0309fdfc7161 Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Thu, 3 Aug 2023 11:23:31 +0200 Subject: [PATCH 2/3] evalengine: Refactor out int conversion functions The `ToInt64` and `ToUint64` conversion functions end up loading the whole evalengine in many places, even though only the conversion is needed. Instead we move this as a function to `sqltypes.Value` itself. The casting logic to best effort convert a type to those is the same as depending on the full `evalengine` logic to do it. It's much simpler though and removes the dependency from many places. Additionally this moves a few more bits to the sidecar constants with some utility functions. This allows us to decouple `mysqlctl` fully from the `evalengine` as well. Signed-off-by: Dirkjan Bussink --- go/constants/sidecar/queries.go | 39 +++ go/mysql/endtoend/replication_test.go | 3 +- go/mysql/endtoend/schema_change_test.go | 8 +- go/mysql/hex/hex.go | 4 +- go/sqltypes/cast.go | 38 +++ go/sqltypes/cast_test.go | 107 ++++++ go/sqltypes/value.go | 10 + go/test/endtoend/messaging/message_test.go | 5 +- go/test/endtoend/vreplication/vstream_test.go | 5 +- go/vt/mysqlctl/compression_benchmark_test.go | 3 + go/vt/mysqlctl/reparent.go | 8 +- go/vt/mysqlctl/replication.go | 6 +- go/vt/mysqlctl/schema.go | 5 +- go/vt/sidecardb/sidecardb.go | 53 +-- go/vt/sidecardb/sidecardb_test.go | 8 +- go/vt/sqlparser/literal.go | 107 ++++++ go/vt/vitessdriver/convert.go | 30 +- go/vt/vitessdriver/convert_test.go | 184 +++++++++-- go/vt/vitessdriver/time.go | 8 +- go/vt/vitessdriver/time_test.go | 16 +- go/vt/vtctl/workflow/server.go | 19 +- go/vt/vtctl/workflow/vexec/vexec.go | 3 +- go/vt/vtexplain/vtexplain_vttablet.go | 4 +- go/vt/vtgate/endtoend/last_insert_id_test.go | 5 +- go/vt/vtgate/engine/aggregations.go | 4 +- go/vt/vtgate/engine/insert.go | 6 +- go/vt/vtgate/engine/sql_calc_found_rows.go | 5 +- go/vt/vtgate/engine/update.go | 2 +- go/vt/vtgate/engine/vindex_func.go | 2 +- .../vtgate/evalengine/api_arithmetic_test.go | 311 +----------------- go/vt/vtgate/evalengine/api_literal.go | 16 +- go/vt/vtgate/evalengine/api_types.go | 136 -------- go/vt/vtgate/evalengine/compiler_asm.go | 4 +- go/vt/vtgate/evalengine/fn_hex.go | 16 +- go/vt/vtgate/vindexes/hash.go | 6 +- go/vt/vtgate/vindexes/hash_test.go | 2 +- go/vt/vtgate/vindexes/lookup_hash.go | 6 +- .../vindexes/lookup_unicodeloosemd5_hash.go | 6 +- go/vt/vtgate/vindexes/numeric.go | 4 +- go/vt/vtgate/vindexes/numeric_static_map.go | 8 +- .../vindexes/numeric_static_map_test.go | 4 +- go/vt/vtgate/vindexes/numeric_test.go | 2 +- go/vt/vtgate/vindexes/region_experimental.go | 10 +- go/vt/vtgate/vindexes/region_json.go | 4 +- go/vt/vtgate/vindexes/reverse_bits.go | 4 +- go/vt/vtgate/vindexes/reverse_bits_test.go | 2 +- .../tabletmanager/rpc_vreplication.go | 11 +- .../vreplication/controller_plan.go | 9 +- .../tabletmanager/vreplication/engine.go | 5 +- .../tabletmanager/vreplication/fuzz.go | 4 +- .../tabletmanager/vreplication/utils.go | 11 +- .../tabletmanager/vreplication/vreplicator.go | 6 +- .../vttablet/tabletserver/health_streamer.go | 7 +- .../tabletserver/health_streamer_test.go | 11 +- .../tabletserver/messager/message_manager.go | 9 +- .../messager/message_manager_test.go | 3 +- go/vt/vttablet/tabletserver/query_executor.go | 4 +- .../tabletserver/repltracker/reader.go | 8 +- .../tabletserver/repltracker/writer.go | 5 +- go/vt/vttablet/tabletserver/rules/rules.go | 6 +- go/vt/vttablet/tabletserver/schema/db.go | 8 +- go/vt/vttablet/tabletserver/schema/db_test.go | 7 +- go/vt/vttablet/tabletserver/schema/engine.go | 15 +- .../tabletserver/schema/engine_test.go | 5 +- .../vttablet/tabletserver/schema/historian.go | 11 +- go/vt/vttablet/tabletserver/schema/tracker.go | 6 +- .../tabletserver/throttle/throttler.go | 7 +- go/vt/vttablet/tabletserver/twopc.go | 22 +- .../tabletserver/vstreamer/vstreamer.go | 9 +- go/vt/vttest/local_cluster.go | 4 +- go/vt/wrangler/materializer.go | 5 +- go/vt/wrangler/workflow.go | 12 +- 72 files changed, 693 insertions(+), 755 deletions(-) create mode 100644 go/constants/sidecar/queries.go create mode 100644 go/sqltypes/cast.go create mode 100644 go/sqltypes/cast_test.go create mode 100644 go/vt/sqlparser/literal.go delete mode 100644 go/vt/vtgate/evalengine/api_types.go diff --git a/go/constants/sidecar/queries.go b/go/constants/sidecar/queries.go new file mode 100644 index 00000000000..6cfa171ec8c --- /dev/null +++ b/go/constants/sidecar/queries.go @@ -0,0 +1,39 @@ +package sidecar + +import "vitess.io/vitess/go/vt/sqlparser" + +// region unit-test-only +// This section uses helpers used in tests, but also in +// go/vt/vtexplain/vtexplain_vttablet.go. +// Hence, it is here and not in the _test.go file. +const ( + createDBQuery = "create database if not exists %s" + createTableRegexp = "(?i)CREATE TABLE .* `?\\_vt\\`?..*" + alterTableRegexp = "(?i)ALTER TABLE `?\\_vt\\`?..*" +) + +var ( + DBInitQueries = []string{ + "use %s", + createDBQuery, + } + // Query patterns to handle in mocks. + DBInitQueryPatterns = []string{ + createTableRegexp, + alterTableRegexp, + } +) + +// GetCreateQuery returns the CREATE DATABASE SQL statement +// used to create the sidecar database. +func GetCreateQuery() string { + return sqlparser.BuildParsedQuery(createDBQuery, GetIdentifier()).Query +} + +// GetIdentifier returns the sidecar database name as an SQL +// identifier string, most importantly this means that it will +// be properly escaped if/as needed. +func GetIdentifier() string { + ident := sqlparser.NewIdentifierCS(GetName()) + return sqlparser.String(ident) +} diff --git a/go/mysql/endtoend/replication_test.go b/go/mysql/endtoend/replication_test.go index d5c1997007e..0c1fa006347 100644 --- a/go/mysql/endtoend/replication_test.go +++ b/go/mysql/endtoend/replication_test.go @@ -35,7 +35,6 @@ import ( "vitess.io/vitess/go/mysql/binlog" "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" - "vitess.io/vitess/go/vt/vtgate/evalengine" ) // connectForReplication is a helper method to connect for replication @@ -72,7 +71,7 @@ func connectForReplication(t *testing.T, rbr bool) (*mysql.Conn, mysql.BinlogFor t.Fatalf("SHOW MASTER STATUS returned unexpected result: %v", result) } file := result.Rows[0][0].ToString() - position, err := evalengine.ToUint64(result.Rows[0][1]) + position, err := result.Rows[0][1].ToCastUint64() require.NoError(t, err, "SHOW MASTER STATUS returned invalid position: %v", result.Rows[0][1]) // Tell the server that we understand the format of events diff --git a/go/mysql/endtoend/schema_change_test.go b/go/mysql/endtoend/schema_change_test.go index 5fc90e37935..a9e72aaef5b 100644 --- a/go/mysql/endtoend/schema_change_test.go +++ b/go/mysql/endtoend/schema_change_test.go @@ -22,7 +22,7 @@ import ( "strings" "testing" - "vitess.io/vitess/go/vt/sidecardb" + "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/vt/sqlparser" "github.com/stretchr/testify/require" @@ -42,9 +42,9 @@ func TestChangeSchemaIsNoticed(t *testing.T) { require.NoError(t, err) defer conn.Close() - clearQuery := sqlparser.BuildParsedQuery(mysql.ClearSchemaCopy, sidecardb.GetIdentifier()).Query - insertQuery := sqlparser.BuildParsedQuery(mysql.InsertIntoSchemaCopy, sidecardb.GetIdentifier()).Query - detectQuery := sqlparser.BuildParsedQuery(mysql.DetectSchemaChange, sidecardb.GetIdentifier()).Query + clearQuery := sqlparser.BuildParsedQuery(mysql.ClearSchemaCopy, sidecar.GetIdentifier()).Query + insertQuery := sqlparser.BuildParsedQuery(mysql.InsertIntoSchemaCopy, sidecar.GetIdentifier()).Query + detectQuery := sqlparser.BuildParsedQuery(mysql.DetectSchemaChange, sidecar.GetIdentifier()).Query tests := []struct { name string diff --git a/go/mysql/hex/hex.go b/go/mysql/hex/hex.go index 941cc08e5b5..d2aa00d592e 100644 --- a/go/mysql/hex/hex.go +++ b/go/mysql/hex/hex.go @@ -71,10 +71,10 @@ func DecodedLen(src []byte) int { return (len(src) + 1) / 2 } -func DecodeBytes(dst, src []byte) bool { +func DecodeBytes(dst, src []byte) error { if len(src)&1 == 1 { src = append([]byte{'0'}, src...) } _, err := hex.Decode(dst, src) - return err == nil + return err } diff --git a/go/sqltypes/cast.go b/go/sqltypes/cast.go new file mode 100644 index 00000000000..43a94b2dfdb --- /dev/null +++ b/go/sqltypes/cast.go @@ -0,0 +1,38 @@ +package sqltypes + +import ( + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" +) + +// Cast converts a Value to the target type. +func Cast(v Value, typ Type) (Value, error) { + if v.Type() == typ || v.IsNull() { + return v, nil + } + vBytes, err := v.ToBytes() + if err != nil { + return v, err + } + if IsSigned(typ) && v.IsSigned() { + return MakeTrusted(typ, vBytes), nil + } + if IsUnsigned(typ) && v.IsUnsigned() { + return MakeTrusted(typ, vBytes), nil + } + if (IsFloat(typ) || typ == Decimal) && (v.IsIntegral() || v.IsFloat() || v.Type() == Decimal) { + return MakeTrusted(typ, vBytes), nil + } + if IsQuoted(typ) && (v.IsIntegral() || v.IsFloat() || v.Type() == Decimal || v.IsQuoted()) { + return MakeTrusted(typ, vBytes), nil + } + + // Explicitly disallow Expression. + if v.Type() == Expression { + return NULL, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v cannot be cast to %v", v, typ) + } + + // If the above fast-paths were not possible, + // go through full validation. + return NewValue(typ, vBytes) +} diff --git a/go/sqltypes/cast_test.go b/go/sqltypes/cast_test.go new file mode 100644 index 00000000000..3dcf6175279 --- /dev/null +++ b/go/sqltypes/cast_test.go @@ -0,0 +1,107 @@ +package sqltypes + +import ( + "reflect" + "testing" + + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" +) + +func TestCast(t *testing.T) { + tcases := []struct { + typ Type + v Value + out Value + err error + }{{ + typ: VarChar, + v: NULL, + out: NULL, + }, { + typ: VarChar, + v: TestValue(VarChar, "exact types"), + out: TestValue(VarChar, "exact types"), + }, { + typ: Int64, + v: TestValue(Int32, "32"), + out: TestValue(Int64, "32"), + }, { + typ: Int24, + v: TestValue(Uint64, "64"), + out: TestValue(Int24, "64"), + }, { + typ: Int24, + v: TestValue(VarChar, "bad int"), + err: vterrors.New(vtrpcpb.Code_UNKNOWN, `cannot parse int64 from "bad int"`), + }, { + typ: Uint64, + v: TestValue(Uint32, "32"), + out: TestValue(Uint64, "32"), + }, { + typ: Uint24, + v: TestValue(Int64, "64"), + out: TestValue(Uint24, "64"), + }, { + typ: Uint24, + v: TestValue(Int64, "-1"), + err: vterrors.New(vtrpcpb.Code_UNKNOWN, `cannot parse uint64 from "-1"`), + }, { + typ: Float64, + v: TestValue(Int64, "64"), + out: TestValue(Float64, "64"), + }, { + typ: Float32, + v: TestValue(Float64, "64"), + out: TestValue(Float32, "64"), + }, { + typ: Float32, + v: TestValue(Decimal, "1.24"), + out: TestValue(Float32, "1.24"), + }, { + typ: Float64, + v: TestValue(VarChar, "1.25"), + out: TestValue(Float64, "1.25"), + }, { + typ: Float64, + v: TestValue(VarChar, "bad float"), + err: vterrors.New(vtrpcpb.Code_UNKNOWN, `unparsed tail left after parsing float64 from "bad float": "bad float"`), + }, { + typ: VarChar, + v: TestValue(Int64, "64"), + out: TestValue(VarChar, "64"), + }, { + typ: VarBinary, + v: TestValue(Float64, "64"), + out: TestValue(VarBinary, "64"), + }, { + typ: VarBinary, + v: TestValue(Decimal, "1.24"), + out: TestValue(VarBinary, "1.24"), + }, { + typ: VarBinary, + v: TestValue(VarChar, "1.25"), + out: TestValue(VarBinary, "1.25"), + }, { + typ: VarChar, + v: TestValue(VarBinary, "valid string"), + out: TestValue(VarChar, "valid string"), + }, { + typ: VarChar, + v: TestValue(Expression, "bad string"), + err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "expression cannot be converted to bytes"), + }} + for _, tcase := range tcases { + got, err := Cast(tcase.v, tcase.typ) + if !vterrors.Equals(err, tcase.err) { + t.Errorf("Cast(%v) error: %v, want %v", tcase.v, vterrors.Print(err), vterrors.Print(tcase.err)) + } + if tcase.err != nil { + continue + } + + if !reflect.DeepEqual(got, tcase.out) { + t.Errorf("Cast(%v): %v, want %v", tcase.v, got, tcase.out) + } + } +} diff --git a/go/sqltypes/value.go b/go/sqltypes/value.go index 4544e1a47ac..61ac8239123 100644 --- a/go/sqltypes/value.go +++ b/go/sqltypes/value.go @@ -295,6 +295,11 @@ func (v Value) ToInt64() (int64, error) { return fastparse.ParseInt64(v.RawStr(), 10) } +// ToCastInt64 returns the best effort value as MySQL would return it as a int64. +func (v Value) ToCastInt64() (int64, error) { + return fastparse.ParseInt64(v.RawStr(), 10) +} + func (v Value) ToInt32() (int32, error) { if !v.IsIntegral() { return 0, ErrIncompatibleTypeCast @@ -341,6 +346,11 @@ func (v Value) ToUint64() (uint64, error) { return fastparse.ParseUint64(v.RawStr(), 10) } +// ToCastUint64 returns the best effort value as MySQL would return it as a uint64. +func (v Value) ToCastUint64() (uint64, error) { + return fastparse.ParseUint64(v.RawStr(), 10) +} + func (v Value) ToUint32() (uint32, error) { if !v.IsIntegral() { return 0, ErrIncompatibleTypeCast diff --git a/go/test/endtoend/messaging/message_test.go b/go/test/endtoend/messaging/message_test.go index 95ee0b3022f..51238f10892 100644 --- a/go/test/endtoend/messaging/message_test.go +++ b/go/test/endtoend/messaging/message_test.go @@ -37,7 +37,6 @@ import ( "vitess.io/vitess/go/vt/proto/query" querypb "vitess.io/vitess/go/vt/proto/query" "vitess.io/vitess/go/vt/proto/topodata" - "vitess.io/vitess/go/vt/vtgate/evalengine" "vitess.io/vitess/go/vt/vtgate/vtgateconn" ) @@ -358,8 +357,8 @@ func getTimeEpoch(qr *sqltypes.Result) (int64, int64) { if len(qr.Rows) != 1 { return 0, 0 } - t, _ := evalengine.ToInt64(qr.Rows[0][0]) - e, _ := evalengine.ToInt64(qr.Rows[0][1]) + t, _ := qr.Rows[0][0].ToCastInt64() + e, _ := qr.Rows[0][1].ToCastInt64() return t, e } diff --git a/go/test/endtoend/vreplication/vstream_test.go b/go/test/endtoend/vreplication/vstream_test.go index 63c6655cf5c..5c5e6a80130 100644 --- a/go/test/endtoend/vreplication/vstream_test.go +++ b/go/test/endtoend/vreplication/vstream_test.go @@ -33,7 +33,6 @@ import ( topodatapb "vitess.io/vitess/go/vt/proto/topodata" vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" _ "vitess.io/vitess/go/vt/vtctl/grpcvtctlclient" - "vitess.io/vitess/go/vt/vtgate/evalengine" _ "vitess.io/vitess/go/vt/vtgate/grpcvtgateconn" "vitess.io/vitess/go/vt/vtgate/vtgateconn" @@ -171,7 +170,7 @@ func testVStreamWithFailover(t *testing.T, failover bool) { qr := execVtgateQuery(t, vtgateConn, "product", "select count(*) from customer") require.NotNil(t, qr) // total number of row events found by the VStream API should match the rows inserted - insertedRows, err := evalengine.ToInt64(qr.Rows[0][0]) + insertedRows, err := qr.Rows[0][0].ToCastInt64() require.NoError(t, err) require.Equal(t, insertedRows, numRowEvents) } @@ -521,7 +520,7 @@ func testVStreamCopyMultiKeyspaceReshard(t *testing.T, baseTabletID int) numEven // We believe that checking the number of row events for the unsharded keyspace, which should always be greater than 0 before and after resharding, // is sufficient to confirm that the resharding of one keyspace does not affect another keyspace, while keeping the test straightforward. customerResult := execVtgateQuery(t, vtgateConn, "sharded", "select count(*) from customer") - insertedCustomerRows, err := evalengine.ToInt64(customerResult.Rows[0][0]) + insertedCustomerRows, err := customerResult.Rows[0][0].ToCastInt64() require.NoError(t, err) require.Equal(t, insertedCustomerRows, ne.numLessThan80Events+ne.numGreaterThan80Events+ne.numLessThan40Events+ne.numGreaterThan40Events) return ne diff --git a/go/vt/mysqlctl/compression_benchmark_test.go b/go/vt/mysqlctl/compression_benchmark_test.go index 73cd684c719..de52519fa57 100644 --- a/go/vt/mysqlctl/compression_benchmark_test.go +++ b/go/vt/mysqlctl/compression_benchmark_test.go @@ -19,6 +19,8 @@ import ( "github.com/klauspost/compress/zstd" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/hack" + "vitess.io/vitess/go/vt/logutil" ) @@ -372,6 +374,7 @@ func (tw *timedWriter) Write(p []byte) (nbytes int, err error) { } func TestMain(m *testing.M) { + hack.DisableProtoBufRandomness() code := m.Run() u, _ := dataURL() diff --git a/go/vt/mysqlctl/reparent.go b/go/vt/mysqlctl/reparent.go index b5aba32ddfc..b76e342d0cd 100644 --- a/go/vt/mysqlctl/reparent.go +++ b/go/vt/mysqlctl/reparent.go @@ -24,8 +24,8 @@ import ( "context" "time" + "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/mysql/replication" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/log" @@ -36,7 +36,7 @@ import ( // can set it as the starting position for replicas to start MySQL // Replication from. func GenerateInitialBinlogEntry() string { - return sidecardb.GetCreateQuery() + return sidecar.GetCreateQuery() } // PopulateReparentJournal returns the SQL command to use to populate @@ -49,7 +49,7 @@ func PopulateReparentJournal(timeCreatedNS int64, actionName, primaryAlias strin } return sqlparser.BuildParsedQuery("INSERT INTO %s.reparent_journal "+ "(time_created_ns, action_name, primary_alias, replication_position) "+ - "VALUES (%d, '%s', '%s', '%s')", sidecardb.GetIdentifier(), + "VALUES (%d, '%s', '%s', '%s')", sidecar.GetIdentifier(), timeCreatedNS, actionName, primaryAlias, posStr).Query } @@ -57,7 +57,7 @@ func PopulateReparentJournal(timeCreatedNS int64, actionName, primaryAlias strin // for a reparent_journal row. func queryReparentJournal(timeCreatedNS int64) string { return sqlparser.BuildParsedQuery("SELECT action_name, primary_alias, replication_position FROM %s.reparent_journal WHERE time_created_ns=%d", - sidecardb.GetIdentifier(), timeCreatedNS).Query + sidecar.GetIdentifier(), timeCreatedNS).Query } // WaitForReparentJournal will wait until the context is done for diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index c343a222c5a..2b92f5d961d 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -30,8 +30,6 @@ import ( "time" "vitess.io/vitess/go/mysql/replication" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/netutil" "vitess.io/vitess/go/vt/hook" "vitess.io/vitess/go/vt/log" @@ -183,7 +181,7 @@ func (mysqld *Mysqld) GetMysqlPort() (int32, error) { if len(qr.Rows) != 1 { return 0, errors.New("no port variable in mysql") } - utemp, err := evalengine.ToUint64(qr.Rows[0][1]) + utemp, err := qr.Rows[0][1].ToCastUint64() if err != nil { return 0, err } @@ -199,7 +197,7 @@ func (mysqld *Mysqld) GetServerID(ctx context.Context) (uint32, error) { if len(qr.Rows) != 1 { return 0, errors.New("no server_id in mysql") } - utemp, err := evalengine.ToUint64(qr.Rows[0][0]) + utemp, err := qr.Rows[0][0].ToCastUint64() if err != nil { return 0, err } diff --git a/go/vt/mysqlctl/schema.go b/go/vt/mysqlctl/schema.go index dc9590474d5..397668145ef 100644 --- a/go/vt/mysqlctl/schema.go +++ b/go/vt/mysqlctl/schema.go @@ -35,7 +35,6 @@ import ( tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/vt/vtgate/evalengine" ) const ( @@ -207,7 +206,7 @@ func (mysqld *Mysqld) collectBasicTableData(ctx context.Context, dbName string, var dataLength uint64 if !row[2].IsNull() { // dataLength is NULL for views, then we use 0 - dataLength, err = evalengine.ToUint64(row[2]) + dataLength, err = row[2].ToCastUint64() if err != nil { return nil, err } @@ -216,7 +215,7 @@ func (mysqld *Mysqld) collectBasicTableData(ctx context.Context, dbName string, // get row count var rowCount uint64 if !row[3].IsNull() { - rowCount, err = evalengine.ToUint64(row[3]) + rowCount, err = row[3].ToCastUint64() if err != nil { return nil, err } diff --git a/go/vt/sidecardb/sidecardb.go b/go/vt/sidecardb/sidecardb.go index f88ebb7a667..0bb64611607 100644 --- a/go/vt/sidecardb/sidecardb.go +++ b/go/vt/sidecardb/sidecardb.go @@ -45,7 +45,6 @@ import ( ) const ( - createSidecarDBQuery = "create database if not exists %s" sidecarDBExistsQuery = "select 'true' as 'dbexists' from information_schema.SCHEMATA where SCHEMA_NAME = %a" showCreateTableQuery = "show create table %s.%s" @@ -203,20 +202,6 @@ type schemaInit struct { // execute the specified query within the database. type Exec func(ctx context.Context, query string, maxRows int, useDB bool) (*sqltypes.Result, error) -// GetIdentifier returns the sidecar database name as an SQL -// identifier string, most importantly this means that it will -// be properly escaped if/as needed. -func GetIdentifier() string { - ident := sqlparser.NewIdentifierCS(sidecar.GetName()) - return sqlparser.String(ident) -} - -// GetCreateQuery returns the CREATE DATABASE SQL statement -// used to create the sidecar database. -func GetCreateQuery() string { - return sqlparser.BuildParsedQuery(createSidecarDBQuery, GetIdentifier()).Query -} - // GetDDLCount metric returns the count of sidecardb DDLs that // have been run as part of this vttablet's init process. func getDDLCount() int64 { @@ -269,7 +254,7 @@ func Init(ctx context.Context, exec Exec) error { si.dbCreated = true } - if err := si.setCurrentDatabase(GetIdentifier()); err != nil { + if err := si.setCurrentDatabase(sidecar.GetIdentifier()); err != nil { return err } @@ -337,7 +322,7 @@ func (si *schemaInit) doesSidecarDBExist() (bool, error) { } func (si *schemaInit) createSidecarDB() error { - _, err := si.exec(si.ctx, GetCreateQuery(), 1, false) + _, err := si.exec(si.ctx, sidecar.GetCreateQuery(), 1, false) if err != nil { log.Error(err) return err @@ -360,7 +345,7 @@ func (si *schemaInit) getCurrentSchema(tableName string) (string, error) { // Converting the tableName to a case-sensitive identifier and converting back to a string using the // sqlparser package, ensures that the table name is escaped with backticks if required. escapedTableName := sqlparser.String(sqlparser.NewIdentifierCS(tableName)) - rs, err := si.exec(si.ctx, sqlparser.BuildParsedQuery(showCreateTableQuery, GetIdentifier(), escapedTableName).Query, 1, false) + rs, err := si.exec(si.ctx, sqlparser.BuildParsedQuery(showCreateTableQuery, sidecar.GetIdentifier(), escapedTableName).Query, 1, false) if err != nil { if sqlErr, ok := err.(*sqlerror.SQLError); ok && sqlErr.Number() == sqlerror.ERNoSuchTable { // table does not exist in the sidecar database @@ -462,29 +447,13 @@ func recordDDLError(tableName string, err error) { } func (t *sidecarTable) String() string { - return fmt.Sprintf("%s.%s (%s)", GetIdentifier(), sqlparser.String(sqlparser.NewIdentifierCS(t.name)), t.module) + return fmt.Sprintf("%s.%s (%s)", sidecar.GetIdentifier(), sqlparser.String(sqlparser.NewIdentifierCS(t.name)), t.module) } // region unit-test-only // This section uses helpers used in tests, but also in // go/vt/vtexplain/vtexplain_vttablet.go. // Hence, it is here and not in the _test.go file. -const ( - createTableRegexp = "(?i)CREATE TABLE .* `?\\_vt\\`?..*" - alterTableRegexp = "(?i)ALTER TABLE `?\\_vt\\`?..*" -) - -var ( - sidecarDBInitQueries = []string{ - "use %s", - createSidecarDBQuery, - } - // Query patterns to handle in mocks. - sidecarDBInitQueryPatterns = []string{ - createTableRegexp, - alterTableRegexp, - } -) // AddSchemaInitQueries adds sidecar database schema related // queries to a mock db. @@ -492,11 +461,11 @@ var ( func AddSchemaInitQueries(db *fakesqldb.DB, populateTables bool) { once.Do(loadSchemaDefinitions) result := &sqltypes.Result{} - for _, q := range sidecarDBInitQueryPatterns { + for _, q := range sidecar.DBInitQueryPatterns { db.AddQueryPattern(q, result) } - for _, q := range sidecarDBInitQueries { - db.AddQuery(sqlparser.BuildParsedQuery(q, GetIdentifier()).Query, result) + for _, q := range sidecar.DBInitQueries { + db.AddQuery(sqlparser.BuildParsedQuery(q, sidecar.GetIdentifier()).Query, result) } sdbe, _ := sqlparser.ParseAndBind(sidecarDBExistsQuery, sqltypes.StringBindVariable(sidecar.GetName())) db.AddQuery(sdbe, result) @@ -509,7 +478,7 @@ func AddSchemaInitQueries(db *fakesqldb.DB, populateTables bool) { fmt.Sprintf("%s|%s", table.name, table.schema), ) } - db.AddQuery(sqlparser.BuildParsedQuery(showCreateTableQuery, GetIdentifier(), + db.AddQuery(sqlparser.BuildParsedQuery(showCreateTableQuery, sidecar.GetIdentifier(), sqlparser.String(sqlparser.NewIdentifierCS(table.name))).Query, result) } @@ -528,8 +497,8 @@ func AddSchemaInitQueries(db *fakesqldb.DB, populateTables bool) { // This is for unit tests only! func MatchesInitQuery(query string) bool { query = strings.ToLower(query) - for _, q := range sidecarDBInitQueries { - if strings.EqualFold(sqlparser.BuildParsedQuery(q, GetIdentifier()).Query, query) { + for _, q := range sidecar.DBInitQueries { + if strings.EqualFold(sqlparser.BuildParsedQuery(q, sidecar.GetIdentifier()).Query, query) { return true } } @@ -537,7 +506,7 @@ func MatchesInitQuery(query string) bool { if strings.EqualFold(sdbe, query) { return true } - for _, q := range sidecarDBInitQueryPatterns { + for _, q := range sidecar.DBInitQueryPatterns { q = strings.ToLower(q) if strings.Contains(query, q) { return true diff --git a/go/vt/sidecardb/sidecardb_test.go b/go/vt/sidecardb/sidecardb_test.go index d65115c2c20..22147c960e9 100644 --- a/go/vt/sidecardb/sidecardb_test.go +++ b/go/vt/sidecardb/sidecardb_test.go @@ -63,7 +63,7 @@ func TestInitErrors(t *testing.T) { exec := func(ctx context.Context, query string, maxRows int, useDB bool) (*sqltypes.Result, error) { if useDB { - if _, err := conn.ExecuteFetch(fmt.Sprintf("use %s", GetIdentifier()), maxRows, true); err != nil { + if _, err := conn.ExecuteFetch(fmt.Sprintf("use %s", sidecar.GetIdentifier()), maxRows, true); err != nil { return nil, err } } @@ -133,7 +133,7 @@ func TestMiscSidecarDB(t *testing.T) { require.NoError(t, err) exec := func(ctx context.Context, query string, maxRows int, useDB bool) (*sqltypes.Result, error) { if useDB { - if _, err := conn.ExecuteFetch(fmt.Sprintf("use %s", GetIdentifier()), maxRows, true); err != nil { + if _, err := conn.ExecuteFetch(fmt.Sprintf("use %s", sidecar.GetIdentifier()), maxRows, true); err != nil { return nil, err } } @@ -148,7 +148,7 @@ func TestMiscSidecarDB(t *testing.T) { dbeq, err := sqlparser.ParseAndBind(sidecarDBExistsQuery, sqltypes.StringBindVariable(sidecar.GetName())) require.NoError(t, err) db.AddQuery(dbeq, result) - db.AddQuery(sqlparser.BuildParsedQuery(createSidecarDBQuery, GetIdentifier()).Query, &sqltypes.Result{}) + db.AddQuery(sidecar.GetCreateQuery(), &sqltypes.Result{}) AddSchemaInitQueries(db, false) // tests init on empty db @@ -174,7 +174,7 @@ func TestMiscSidecarDB(t *testing.T) { exec: exec, } - err = si.setCurrentDatabase(GetIdentifier()) + err = si.setCurrentDatabase(sidecar.GetIdentifier()) require.NoError(t, err) require.False(t, MatchesInitQuery("abc")) diff --git a/go/vt/sqlparser/literal.go b/go/vt/sqlparser/literal.go new file mode 100644 index 00000000000..37816f8c654 --- /dev/null +++ b/go/vt/sqlparser/literal.go @@ -0,0 +1,107 @@ +package sqlparser + +import ( + "errors" + "fmt" + "math" + "math/big" + + "vitess.io/vitess/go/hack" + "vitess.io/vitess/go/mysql/datetime" + "vitess.io/vitess/go/mysql/decimal" + "vitess.io/vitess/go/mysql/fastparse" + "vitess.io/vitess/go/mysql/hex" + "vitess.io/vitess/go/sqltypes" +) + +func LiteralToValue(lit *Literal) (sqltypes.Value, error) { + switch lit.Type { + case IntVal: + uval, err := fastparse.ParseUint64(lit.Val, 10) + if err != nil { + if errors.Is(err, fastparse.ErrOverflow) { + return sqltypes.NewDecimal(lit.Val), nil + } + return sqltypes.Value{}, err + } + if uval <= math.MaxInt64 { + return sqltypes.NewInt64(int64(uval)), nil + } + return sqltypes.NewUint64(uval), nil + case FloatVal: + fval, err := fastparse.ParseFloat64(lit.Val) + if err != nil { + return sqltypes.Value{}, err + } + return sqltypes.NewFloat64(fval), nil + case DecimalVal: + dec, err := decimal.NewFromMySQL(lit.Bytes()) + if err != nil { + return sqltypes.Value{}, err + } + return sqltypes.NewDecimal(hack.String(dec.FormatMySQL(0))), nil + case StrVal: + return sqltypes.NewVarChar(lit.Val), nil + case HexNum: + b := lit.Bytes() + if b[0] != '0' || b[1] != 'x' { + return sqltypes.Value{}, fmt.Errorf("invalid hex literal: %v", lit.Val) + } + if len(lit.Val)%2 == 0 { + return parseHexLiteral(b[2:]) + } + // If the hex literal doesn't have an even amount of hex digits, we need + // to pad it with a '0' in the left. Instead of allocating a new slice + // for padding pad in-place by replacing the 'x' in the original slice with + // a '0', and clean it up after parsing. + b[1] = '0' + defer func() { + b[1] = 'x' + }() + return parseHexLiteral(b[1:]) + case HexVal: + return parseHexLiteral(lit.Bytes()) + case BitVal: + return parseBitLiteral(lit.Bytes()) + case DateVal: + d, ok := datetime.ParseDate(lit.Val) + if !ok { + return sqltypes.Value{}, fmt.Errorf("invalid time literal: %v", lit.Val) + } + buf := datetime.Date_YYYY_MM_DD.Format(datetime.DateTime{Date: d}, 0) + return sqltypes.NewDate(hack.String(buf)), nil + case TimeVal: + t, l, ok := datetime.ParseTime(lit.Val, -1) + if !ok { + return sqltypes.Value{}, fmt.Errorf("invalid time literal: %v", lit.Val) + } + buf := datetime.Time_hh_mm_ss.Format(datetime.DateTime{Time: t}, uint8(l)) + return sqltypes.NewTime(hack.String(buf)), nil + case TimestampVal: + dt, l, ok := datetime.ParseDateTime(lit.Val, -1) + if !ok { + return sqltypes.Value{}, fmt.Errorf("invalid time literal: %v", lit.Val) + } + buf := datetime.DateTime_YYYY_MM_DD_hh_mm_ss.Format(dt, uint8(l)) + return sqltypes.NewDatetime(hack.String(buf)), nil + default: + return sqltypes.Value{}, fmt.Errorf("unsupported literal type: %v", lit.Type) + } +} + +func parseHexLiteral(val []byte) (sqltypes.Value, error) { + raw := make([]byte, hex.DecodedLen(val)) + if err := hex.DecodeBytes(raw, val); err != nil { + return sqltypes.Value{}, err + } + return sqltypes.NewVarBinary(hack.String(raw)), nil +} + +func parseBitLiteral(val []byte) (sqltypes.Value, error) { + var i big.Int + _, ok := i.SetString(string(val), 2) + if !ok { + return sqltypes.Value{}, fmt.Errorf("invalid bit literal: %v", val) + } + return sqltypes.NewVarBinary(hack.String(i.Bytes())), nil +} diff --git a/go/vt/vitessdriver/convert.go b/go/vt/vitessdriver/convert.go index abb25beb000..3bcd33cd594 100644 --- a/go/vt/vitessdriver/convert.go +++ b/go/vt/vitessdriver/convert.go @@ -21,10 +21,10 @@ import ( "fmt" "time" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) type converter struct { @@ -32,13 +32,27 @@ type converter struct { } func (cv *converter) ToNative(v sqltypes.Value) (any, error) { - switch v.Type() { - case sqltypes.Datetime, sqltypes.Timestamp: - return DatetimeToNative(v, cv.location) - case sqltypes.Date: - return DateToNative(v, cv.location) + var out any + var err error + switch { + case v.Type() == sqltypes.Null: + // no-op + case v.IsSigned(): + return v.ToInt64() + case v.IsUnsigned(): + return v.ToUint64() + case v.IsFloat(): + return v.ToFloat64() + case v.Type() == sqltypes.Datetime, v.Type() == sqltypes.Timestamp: + return datetimeToNative(v, cv.location) + case v.Type() == sqltypes.Date: + return dateToNative(v, cv.location) + case v.IsQuoted() || v.Type() == sqltypes.Bit || v.Type() == sqltypes.Decimal: + out, err = v.ToBytes() + case v.Type() == sqltypes.Expression: + err = vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v cannot be converted to a go type", v) } - return evalengine.ToNative(v) + return out, err } func (cv *converter) BuildBindVariable(v any) (*querypb.BindVariable, error) { diff --git a/go/vt/vitessdriver/convert_test.go b/go/vt/vitessdriver/convert_test.go index 2e6734e8da0..c1d5f46b247 100644 --- a/go/vt/vitessdriver/convert_test.go +++ b/go/vt/vitessdriver/convert_test.go @@ -33,35 +33,161 @@ func TestToNative(t *testing.T) { convert *converter in sqltypes.Value out any - }{{ - convert: &converter{}, - in: sqltypes.TestValue(sqltypes.Int32, "1"), - out: int64(1), - }, { - convert: &converter{}, - in: sqltypes.TestValue(sqltypes.Timestamp, "2012-02-24 23:19:43"), - out: time.Date(2012, 02, 24, 23, 19, 43, 0, time.UTC), - }, { - convert: &converter{}, - in: sqltypes.TestValue(sqltypes.Time, "23:19:43"), - out: []byte("23:19:43"), // TIME is not handled - }, { - convert: &converter{}, - in: sqltypes.TestValue(sqltypes.Date, "2012-02-24"), - out: time.Date(2012, 02, 24, 0, 0, 0, 0, time.UTC), - }, { - convert: &converter{}, - in: sqltypes.TestValue(sqltypes.Datetime, "2012-02-24 23:19:43"), - out: time.Date(2012, 02, 24, 23, 19, 43, 0, time.UTC), - }, { - convert: convertTimeLocal, - in: sqltypes.TestValue(sqltypes.Datetime, "2012-02-24 23:19:43"), - out: time.Date(2012, 02, 24, 23, 19, 43, 0, time.Local), - }, { - convert: convertTimeLocal, - in: sqltypes.TestValue(sqltypes.Date, "2012-02-24"), - out: time.Date(2012, 02, 24, 0, 0, 0, 0, time.Local), - }} + }{ + { + convert: &converter{}, + in: sqltypes.NULL, + out: nil, + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Int8, "1"), + out: int64(1), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Int16, "1"), + out: int64(1), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Int24, "1"), + out: int64(1), + }, { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Int32, "1"), + out: int64(1), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Int64, "1"), + out: int64(1), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Uint8, "1"), + out: uint64(1), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Uint16, "1"), + out: uint64(1), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Uint24, "1"), + out: uint64(1), + }, { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Uint32, "1"), + out: uint64(1), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Uint64, "1"), + out: uint64(1), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Float32, "1.1"), + out: float64(1.1), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Float64, "1.1"), + out: float64(1.1), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Timestamp, "2012-02-24 23:19:43"), + out: time.Date(2012, 02, 24, 23, 19, 43, 0, time.UTC), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Time, "23:19:43"), + out: []byte("23:19:43"), // TIME is not handled + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Date, "2012-02-24"), + out: time.Date(2012, 02, 24, 0, 0, 0, 0, time.UTC), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Datetime, "2012-02-24 23:19:43"), + out: time.Date(2012, 02, 24, 23, 19, 43, 0, time.UTC), + }, + { + convert: convertTimeLocal, + in: sqltypes.TestValue(sqltypes.Datetime, "2012-02-24 23:19:43"), + out: time.Date(2012, 02, 24, 23, 19, 43, 0, time.Local), + }, + { + convert: convertTimeLocal, + in: sqltypes.TestValue(sqltypes.Date, "2012-02-24"), + out: time.Date(2012, 02, 24, 0, 0, 0, 0, time.Local), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Year, "1"), + out: uint64(1), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Decimal, "1"), + out: []byte("1"), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Text, "a"), + out: []byte("a"), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Blob, "a"), + out: []byte("a"), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.VarChar, "a"), + out: []byte("a"), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.VarBinary, "a"), + out: []byte("a"), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Char, "a"), + out: []byte("a"), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Binary, "a"), + out: []byte("a"), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.VarChar, "a"), + out: []byte("a"), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Bit, "a"), + out: []byte("a"), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Enum, "a"), + out: []byte("a"), + }, + { + convert: &converter{}, + in: sqltypes.TestValue(sqltypes.Set, "a"), + out: []byte("a"), + }, + } for _, tcase := range testcases { v, err := tcase.convert.ToNative(tcase.in) diff --git a/go/vt/vitessdriver/time.go b/go/vt/vitessdriver/time.go index dc2d4453c31..70ec2d679ae 100644 --- a/go/vt/vitessdriver/time.go +++ b/go/vt/vitessdriver/time.go @@ -74,8 +74,8 @@ func parseISOTime(tstr string, loc *time.Location, minLen, maxLen int) (t time.T return time.ParseInLocation(isoTimeFormat[:tlen], tstr, loc) } -// DatetimeToNative converts a Datetime Value into a time.Time -func DatetimeToNative(v sqltypes.Value, loc *time.Location) (time.Time, error) { +// datetimeToNative converts a Datetime Value into a time.Time +func datetimeToNative(v sqltypes.Value, loc *time.Location) (time.Time, error) { // Valid format string offsets for a DATETIME // |DATETIME |19+ // |------------------|------| @@ -83,11 +83,11 @@ func DatetimeToNative(v sqltypes.Value, loc *time.Location) (time.Time, error) { return parseISOTime(v.ToString(), loc, 19, isoTimeLength) } -// DateToNative converts a Date Value into a time.Time. +// dateToNative converts a Date Value into a time.Time. // Note that there's no specific type in the Go stdlib to represent // dates without time components, so the returned Time will have // their hours/mins/seconds zeroed out. -func DateToNative(v sqltypes.Value, loc *time.Location) (time.Time, error) { +func dateToNative(v sqltypes.Value, loc *time.Location) (time.Time, error) { // Valid format string offsets for a DATE // |DATE |10 // |---------| diff --git a/go/vt/vitessdriver/time_test.go b/go/vt/vitessdriver/time_test.go index d2924fa343a..949d8f43354 100644 --- a/go/vt/vitessdriver/time_test.go +++ b/go/vt/vitessdriver/time_test.go @@ -113,15 +113,15 @@ func TestDatetimeToNative(t *testing.T) { }} for _, tcase := range tcases { - got, err := DatetimeToNative(tcase.val, tcase.loc) + got, err := datetimeToNative(tcase.val, tcase.loc) if tcase.err && err == nil { - t.Errorf("DatetimeToNative(%v, %#v) succeeded; expected error", tcase.val, tcase.loc) + t.Errorf("datetimeToNative(%v, %#v) succeeded; expected error", tcase.val, tcase.loc) } if !tcase.err && err != nil { - t.Errorf("DatetimeToNative(%v, %#v) failed: %v", tcase.val, tcase.loc, err) + t.Errorf("datetimeToNative(%v, %#v) failed: %v", tcase.val, tcase.loc, err) } if !reflect.DeepEqual(got, tcase.out) { - t.Errorf("DatetimeToNative(%v, %#v): %v, want %v", tcase.val, tcase.loc, got, tcase.out) + t.Errorf("datetimeToNative(%v, %#v): %v, want %v", tcase.val, tcase.loc, got, tcase.out) } } } @@ -161,15 +161,15 @@ func TestDateToNative(t *testing.T) { }} for _, tcase := range tcases { - got, err := DateToNative(tcase.val, tcase.loc) + got, err := dateToNative(tcase.val, tcase.loc) if tcase.err && err == nil { - t.Errorf("DateToNative(%v, %#v) succeeded; expected error", tcase.val, tcase.loc) + t.Errorf("dateToNative(%v, %#v) succeeded; expected error", tcase.val, tcase.loc) } if !tcase.err && err != nil { - t.Errorf("DateToNative(%v, %#v) failed: %v", tcase.val, tcase.loc, err) + t.Errorf("dateToNative(%v, %#v) failed: %v", tcase.val, tcase.loc, err) } if !reflect.DeepEqual(got, tcase.out) { - t.Errorf("DateToNative(%v, %#v): %v, want %v", tcase.val, tcase.loc, got, tcase.out) + t.Errorf("dateToNative(%v, %#v): %v, want %v", tcase.val, tcase.loc, got, tcase.out) } } } diff --git a/go/vt/vtctl/workflow/server.go b/go/vt/vtctl/workflow/server.go index f514198f3c8..c55c5889b03 100644 --- a/go/vt/vtctl/workflow/server.go +++ b/go/vt/vtctl/workflow/server.go @@ -46,7 +46,6 @@ import ( "vitess.io/vitess/go/vt/topotools" "vitess.io/vitess/go/vt/vtctl/workflow/vexec" "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/vt/vtgate/evalengine" "vitess.io/vitess/go/vt/vtgate/vindexes" "vitess.io/vitess/go/vt/vttablet/tmclient" @@ -395,7 +394,7 @@ func (s *Server) GetWorkflows(ctx context.Context, req *vtctldatapb.GetWorkflows span.Annotate("workflow", workflow.Name) span.Annotate("tablet_alias", tablet.AliasString()) - id, err := evalengine.ToInt64(row["id"]) + id, err := row["id"].ToCastInt64() if err != nil { return err } @@ -414,12 +413,12 @@ func (s *Server) GetWorkflows(ctx context.Context, req *vtctldatapb.GetWorkflows state := row["state"].ToString() dbName := row["db_name"].ToString() - timeUpdatedSeconds, err := evalengine.ToInt64(row["time_updated"]) + timeUpdatedSeconds, err := row["time_updated"].ToCastInt64() if err != nil { return err } - transactionTimeSeconds, err := evalengine.ToInt64(row["transaction_timestamp"]) + transactionTimeSeconds, err := row["transaction_timestamp"].ToCastInt64() if err != nil { return err } @@ -638,13 +637,13 @@ ORDER BY } for _, row := range qr.Rows { - id, err := evalengine.ToInt64(row[0]) + id, err := row[0].ToCastInt64() if err != nil { markErrors(err) continue } - streamID, err := evalengine.ToInt64(row[1]) + streamID, err := row[1].ToCastInt64() if err != nil { markErrors(err) continue @@ -666,7 +665,7 @@ ORDER BY continue } - count, err := evalengine.ToInt64(row[7]) + count, err := row[7].ToCastInt64() if err != nil { markErrors(err) continue @@ -1401,11 +1400,11 @@ func (s *Server) GetCopyProgress(ctx context.Context, ts *trafficSwitcher, state qr := sqltypes.Proto3ToResult(p3qr) for i := 0; i < len(qr.Rows); i++ { table := qr.Rows[i][0].ToString() - rowCount, err := evalengine.ToInt64(qr.Rows[i][1]) + rowCount, err := qr.Rows[i][1].ToCastInt64() if err != nil { return err } - tableSize, err := evalengine.ToInt64(qr.Rows[i][2]) + tableSize, err := qr.Rows[i][2].ToCastInt64() if err != nil { return err } @@ -1589,7 +1588,7 @@ func (s *Server) collectTargetStreams(ctx context.Context, mz *materializer) ([] } qr := sqltypes.Proto3ToResult(qrproto) for i := 0; i < len(qr.Rows); i++ { - id, err = evalengine.ToInt64(qr.Rows[i][0]) + id, err = qr.Rows[i][0].ToCastInt64() if err != nil { return err } diff --git a/go/vt/vtctl/workflow/vexec/vexec.go b/go/vt/vtctl/workflow/vexec/vexec.go index aa55a168380..477b81a1a03 100644 --- a/go/vt/vtctl/workflow/vexec/vexec.go +++ b/go/vt/vtctl/workflow/vexec/vexec.go @@ -29,7 +29,6 @@ import ( "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/vt/vtgate/evalengine" "vitess.io/vitess/go/vt/vttablet/tmclient" querypb "vitess.io/vitess/go/vt/proto/query" @@ -277,7 +276,7 @@ func (vx *VExec) getPlanner(ctx context.Context, table string) (QueryPlanner, er tabletStreamIDMap[aliasStr] = make([]int64, len(qr.Rows)) for i, row := range qr.Rows { - id, err := evalengine.ToInt64(row[0]) + id, err := row[0].ToCastInt64() if err != nil { return nil, err } diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 14349dd05f1..98da79b75d7 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -720,13 +720,13 @@ func (t *explainTablet) analyzeWhere(selStmt *sqlparser.Select, tableColumnMap m if !ok { continue } - value, err := evalengine.LiteralToValue(lit) + value, err := sqlparser.LiteralToValue(lit) if err != nil { return "", nil, 0, nil, err } // Cast the value in the tuple to the expected value of the column - castedValue, err := evalengine.Cast(value, colType) + castedValue, err := sqltypes.Cast(value, colType) if err != nil { return "", nil, 0, nil, err } diff --git a/go/vt/vtgate/endtoend/last_insert_id_test.go b/go/vt/vtgate/endtoend/last_insert_id_test.go index 6d841fadd07..e3fbcdaa2dd 100644 --- a/go/vt/vtgate/endtoend/last_insert_id_test.go +++ b/go/vt/vtgate/endtoend/last_insert_id_test.go @@ -26,7 +26,6 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/test/endtoend/utils" - "vitess.io/vitess/go/vt/vtgate/evalengine" ) func TestLastInsertId(t *testing.T) { @@ -40,7 +39,7 @@ func TestLastInsertId(t *testing.T) { // figure out the last inserted id before we run change anything qr := exec(t, conn, "select max(id) from t1_last_insert_id") - oldLastID, err := evalengine.ToUint64(qr.Rows[0][0]) + oldLastID, err := qr.Rows[0][0].ToCastUint64() require.NoError(t, err) exec(t, conn, "insert into t1_last_insert_id(id1) values(42)") @@ -66,7 +65,7 @@ func TestLastInsertIdWithRollback(t *testing.T) { // figure out the last inserted id before we run our tests qr := exec(t, conn, "select max(id) from t1_last_insert_id") - oldLastID, err := evalengine.ToUint64(qr.Rows[0][0]) + oldLastID, err := qr.Rows[0][0].ToCastUint64() require.NoError(t, err) // add row inside explicit transaction diff --git a/go/vt/vtgate/engine/aggregations.go b/go/vt/vtgate/engine/aggregations.go index 725e1882757..d00addf362b 100644 --- a/go/vt/vtgate/engine/aggregations.go +++ b/go/vt/vtgate/engine/aggregations.go @@ -130,14 +130,14 @@ func convertRow( break } var err error - newRow[aggr.Col], err = evalengine.Cast(row[aggr.Col], fields[aggr.Col].Type) + newRow[aggr.Col], err = sqltypes.Cast(row[aggr.Col], fields[aggr.Col].Type) if err != nil { newRow[aggr.Col] = sumZero } case AggregateSumDistinct: curDistincts[index] = findComparableCurrentDistinct(row, aggr) var err error - newRow[aggr.Col], err = evalengine.Cast(row[aggr.Col], fields[aggr.Col].Type) + newRow[aggr.Col], err = sqltypes.Cast(row[aggr.Col], fields[aggr.Col].Type) if err != nil { newRow[aggr.Col] = sumZero } diff --git a/go/vt/vtgate/engine/insert.go b/go/vt/vtgate/engine/insert.go index 4100879fbd8..c7afd5aaf5b 100644 --- a/go/vt/vtgate/engine/insert.go +++ b/go/vt/vtgate/engine/insert.go @@ -502,7 +502,7 @@ func shouldGenerate(v sqltypes.Value) bool { // Unless the NO_AUTO_VALUE_ON_ZERO sql mode is active in mysql, it also // treats 0 as a value that should generate a new sequence. - n, err := evalengine.ToUint64(v) + n, err := v.ToCastUint64() if err == nil && n == 0 { return true } @@ -553,7 +553,7 @@ func (ins *Insert) processGenerateFromValues( } // If no rows are returned, it's an internal error, and the code // must panic, which will be caught and reported. - insertID, err = evalengine.ToInt64(qr.Rows[0][0]) + insertID, err = qr.Rows[0][0].ToCastInt64() if err != nil { return 0, err } @@ -615,7 +615,7 @@ func (ins *Insert) processGenerateFromRows( } // If no rows are returned, it's an internal error, and the code // must panic, which will be caught and reported. - insertID, err = evalengine.ToInt64(qr.Rows[0][0]) + insertID, err = qr.Rows[0][0].ToCastInt64() if err != nil { return 0, err } diff --git a/go/vt/vtgate/engine/sql_calc_found_rows.go b/go/vt/vtgate/engine/sql_calc_found_rows.go index 9553023069c..6a215214246 100644 --- a/go/vt/vtgate/engine/sql_calc_found_rows.go +++ b/go/vt/vtgate/engine/sql_calc_found_rows.go @@ -23,7 +23,6 @@ import ( querypb "vitess.io/vitess/go/vt/proto/query" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/vt/vtgate/evalengine" ) var _ Primitive = (*SQLCalcFoundRows)(nil) @@ -62,7 +61,7 @@ func (s SQLCalcFoundRows) TryExecute(ctx context.Context, vcursor VCursor, bindV if len(countQr.Rows) != 1 || len(countQr.Rows[0]) != 1 { return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "count query is not a scalar") } - fr, err := evalengine.ToUint64(countQr.Rows[0][0]) + fr, err := countQr.Rows[0][0].ToCastUint64() if err != nil { return nil, err } @@ -87,7 +86,7 @@ func (s SQLCalcFoundRows) TryStreamExecute(ctx context.Context, vcursor VCursor, if len(countQr.Rows) != 1 || len(countQr.Rows[0]) != 1 { return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "count query is not a scalar") } - toUint64, err := evalengine.ToUint64(countQr.Rows[0][0]) + toUint64, err := countQr.Rows[0][0].ToCastUint64() if err != nil { return err } diff --git a/go/vt/vtgate/engine/update.go b/go/vt/vtgate/engine/update.go index 9ba06c6e0ee..093d0a73b80 100644 --- a/go/vt/vtgate/engine/update.go +++ b/go/vt/vtgate/engine/update.go @@ -137,7 +137,7 @@ func (upd *Update) updateVindexEntries(ctx context.Context, vcursor VCursor, bin offset := updColValues.Offset if !row[offset].IsNull() { - val, err := evalengine.ToInt64(row[offset]) + val, err := row[offset].ToCastInt64() if err != nil { return err } diff --git a/go/vt/vtgate/engine/vindex_func.go b/go/vt/vtgate/engine/vindex_func.go index eb55ff32d8c..918bc9240ad 100644 --- a/go/vt/vtgate/engine/vindex_func.go +++ b/go/vt/vtgate/engine/vindex_func.go @@ -136,7 +136,7 @@ func (vf *VindexFunc) mapVindex(ctx context.Context, vcursor VCursor, bindVars m len(values), len(destinations)) } for i, value := range values { - vkey, err := evalengine.Cast(value, sqltypes.VarBinary) + vkey, err := sqltypes.Cast(value, sqltypes.VarBinary) if err != nil { return nil, err } diff --git a/go/vt/vtgate/evalengine/api_arithmetic_test.go b/go/vt/vtgate/evalengine/api_arithmetic_test.go index 7d5a6e00c71..10199206755 100644 --- a/go/vt/vtgate/evalengine/api_arithmetic_test.go +++ b/go/vt/vtgate/evalengine/api_arithmetic_test.go @@ -515,313 +515,6 @@ func TestNullSafeAdd(t *testing.T) { } } -func TestCast(t *testing.T) { - tcases := []struct { - typ sqltypes.Type - v sqltypes.Value - out sqltypes.Value - err error - }{{ - typ: sqltypes.VarChar, - v: NULL, - out: NULL, - }, { - typ: sqltypes.VarChar, - v: TestValue(sqltypes.VarChar, "exact types"), - out: TestValue(sqltypes.VarChar, "exact types"), - }, { - typ: sqltypes.Int64, - v: TestValue(sqltypes.Int32, "32"), - out: TestValue(sqltypes.Int64, "32"), - }, { - typ: sqltypes.Int24, - v: TestValue(sqltypes.Uint64, "64"), - out: TestValue(sqltypes.Int24, "64"), - }, { - typ: sqltypes.Int24, - v: TestValue(sqltypes.VarChar, "bad int"), - err: vterrors.New(vtrpcpb.Code_UNKNOWN, `cannot parse int64 from "bad int"`), - }, { - typ: sqltypes.Uint64, - v: TestValue(sqltypes.Uint32, "32"), - out: TestValue(sqltypes.Uint64, "32"), - }, { - typ: sqltypes.Uint24, - v: TestValue(sqltypes.Int64, "64"), - out: TestValue(sqltypes.Uint24, "64"), - }, { - typ: sqltypes.Uint24, - v: TestValue(sqltypes.Int64, "-1"), - err: vterrors.New(vtrpcpb.Code_UNKNOWN, `cannot parse uint64 from "-1"`), - }, { - typ: sqltypes.Float64, - v: TestValue(sqltypes.Int64, "64"), - out: TestValue(sqltypes.Float64, "64"), - }, { - typ: sqltypes.Float32, - v: TestValue(sqltypes.Float64, "64"), - out: TestValue(sqltypes.Float32, "64"), - }, { - typ: sqltypes.Float32, - v: TestValue(sqltypes.Decimal, "1.24"), - out: TestValue(sqltypes.Float32, "1.24"), - }, { - typ: sqltypes.Float64, - v: TestValue(sqltypes.VarChar, "1.25"), - out: TestValue(sqltypes.Float64, "1.25"), - }, { - typ: sqltypes.Float64, - v: TestValue(sqltypes.VarChar, "bad float"), - err: vterrors.New(vtrpcpb.Code_UNKNOWN, `unparsed tail left after parsing float64 from "bad float": "bad float"`), - }, { - typ: sqltypes.VarChar, - v: TestValue(sqltypes.Int64, "64"), - out: TestValue(sqltypes.VarChar, "64"), - }, { - typ: sqltypes.VarBinary, - v: TestValue(sqltypes.Float64, "64"), - out: TestValue(sqltypes.VarBinary, "64"), - }, { - typ: sqltypes.VarBinary, - v: TestValue(sqltypes.Decimal, "1.24"), - out: TestValue(sqltypes.VarBinary, "1.24"), - }, { - typ: sqltypes.VarBinary, - v: TestValue(sqltypes.VarChar, "1.25"), - out: TestValue(sqltypes.VarBinary, "1.25"), - }, { - typ: sqltypes.VarChar, - v: TestValue(sqltypes.VarBinary, "valid string"), - out: TestValue(sqltypes.VarChar, "valid string"), - }, { - typ: sqltypes.VarChar, - v: TestValue(sqltypes.Expression, "bad string"), - err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "expression cannot be converted to bytes"), - }} - for _, tcase := range tcases { - got, err := Cast(tcase.v, tcase.typ) - if !vterrors.Equals(err, tcase.err) { - t.Errorf("Cast(%v) error: %v, want %v", tcase.v, vterrors.Print(err), vterrors.Print(tcase.err)) - } - if tcase.err != nil { - continue - } - - if !reflect.DeepEqual(got, tcase.out) { - t.Errorf("Cast(%v): %v, want %v", tcase.v, got, tcase.out) - } - } -} - -func TestToUint64(t *testing.T) { - tcases := []struct { - v sqltypes.Value - out uint64 - err error - }{{ - v: TestValue(sqltypes.VarChar, "abcd"), - err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "could not parse value: 'abcd'"), - }, { - v: NewInt64(-1), - err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "negative number cannot be converted to unsigned: -1"), - }, { - v: NewInt64(1), - out: 1, - }, { - v: NewUint64(1), - out: 1, - }} - for _, tcase := range tcases { - got, err := ToUint64(tcase.v) - if !vterrors.Equals(err, tcase.err) { - t.Errorf("ToUint64(%v) error: %v, want %v", tcase.v, vterrors.Print(err), vterrors.Print(tcase.err)) - } - if tcase.err != nil { - continue - } - - if got != tcase.out { - t.Errorf("ToUint64(%v): %v, want %v", tcase.v, got, tcase.out) - } - } -} - -func TestToInt64(t *testing.T) { - tcases := []struct { - v sqltypes.Value - out int64 - err error - }{{ - v: TestValue(sqltypes.VarChar, "abcd"), - err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "could not parse value: 'abcd'"), - }, { - v: NewUint64(18446744073709551615), - err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "unsigned number overflows int64 value: 18446744073709551615"), - }, { - v: NewInt64(1), - out: 1, - }, { - v: NewUint64(1), - out: 1, - }} - for _, tcase := range tcases { - got, err := ToInt64(tcase.v) - if !vterrors.Equals(err, tcase.err) { - t.Errorf("ToInt64(%v) error: %v, want %v", tcase.v, vterrors.Print(err), vterrors.Print(tcase.err)) - } - if tcase.err != nil { - continue - } - - if got != tcase.out { - t.Errorf("ToInt64(%v): %v, want %v", tcase.v, got, tcase.out) - } - } -} - -func TestToFloat64(t *testing.T) { - tcases := []struct { - v sqltypes.Value - out float64 - err error - }{{ - v: TestValue(sqltypes.VarChar, "abcd"), - out: 0, - }, { - v: TestValue(sqltypes.VarChar, "1.2"), - out: 1.2, - }, { - v: NewInt64(1), - out: 1, - }, { - v: NewUint64(1), - out: 1, - }, { - v: NewFloat64(1.2), - out: 1.2, - }, { - v: TestValue(sqltypes.Int64, "1.2"), - err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "unparsed tail left after parsing int64 from \"1.2\": \".2\""), - }} - for _, tcase := range tcases { - t.Run(tcase.v.String(), func(t *testing.T) { - got, err := ToFloat64(tcase.v) - if tcase.err != nil { - require.EqualError(t, err, tcase.err.Error()) - } else { - require.Equal(t, tcase.out, got) - } - }) - } -} - -func TestToNative(t *testing.T) { - testcases := []struct { - in sqltypes.Value - out any - }{{ - in: NULL, - out: nil, - }, { - in: TestValue(sqltypes.Int8, "1"), - out: int64(1), - }, { - in: TestValue(sqltypes.Int16, "1"), - out: int64(1), - }, { - in: TestValue(sqltypes.Int24, "1"), - out: int64(1), - }, { - in: TestValue(sqltypes.Int32, "1"), - out: int64(1), - }, { - in: TestValue(sqltypes.Int64, "1"), - out: int64(1), - }, { - in: TestValue(sqltypes.Uint8, "1"), - out: uint64(1), - }, { - in: TestValue(sqltypes.Uint16, "1"), - out: uint64(1), - }, { - in: TestValue(sqltypes.Uint24, "1"), - out: uint64(1), - }, { - in: TestValue(sqltypes.Uint32, "1"), - out: uint64(1), - }, { - in: TestValue(sqltypes.Uint64, "1"), - out: uint64(1), - }, { - in: TestValue(sqltypes.Float32, "1"), - out: float64(1), - }, { - in: TestValue(sqltypes.Float64, "1"), - out: float64(1), - }, { - in: TestValue(sqltypes.Timestamp, "2012-02-24 23:19:43"), - out: []byte("2012-02-24 23:19:43"), - }, { - in: TestValue(sqltypes.Date, "2012-02-24"), - out: []byte("2012-02-24"), - }, { - in: TestValue(sqltypes.Time, "23:19:43"), - out: []byte("23:19:43"), - }, { - in: TestValue(sqltypes.Datetime, "2012-02-24 23:19:43"), - out: []byte("2012-02-24 23:19:43"), - }, { - in: TestValue(sqltypes.Year, "1"), - out: uint64(1), - }, { - in: TestValue(sqltypes.Decimal, "1"), - out: []byte("1"), - }, { - in: TestValue(sqltypes.Text, "a"), - out: []byte("a"), - }, { - in: TestValue(sqltypes.Blob, "a"), - out: []byte("a"), - }, { - in: TestValue(sqltypes.VarChar, "a"), - out: []byte("a"), - }, { - in: TestValue(sqltypes.VarBinary, "a"), - out: []byte("a"), - }, { - in: TestValue(sqltypes.Char, "a"), - out: []byte("a"), - }, { - in: TestValue(sqltypes.Binary, "a"), - out: []byte("a"), - }, { - in: TestValue(sqltypes.Bit, "1"), - out: []byte("1"), - }, { - in: TestValue(sqltypes.Enum, "a"), - out: []byte("a"), - }, { - in: TestValue(sqltypes.Set, "a"), - out: []byte("a"), - }} - for _, tcase := range testcases { - v, err := ToNative(tcase.in) - if err != nil { - t.Error(err) - } - if !reflect.DeepEqual(v, tcase.out) { - t.Errorf("%v.ToNative = %#v, want %#v", tcase.in, v, tcase.out) - } - } - - // Test Expression failure. - _, err := ToNative(TestValue(sqltypes.Expression, "aa")) - want := vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "EXPRESSION(aa) cannot be converted to a go type") - if !vterrors.Equals(err, want) { - t.Errorf("ToNative(EXPRESSION): %v, want %v", vterrors.Print(err), vterrors.Print(want)) - } -} - func TestNewIntegralNumeric(t *testing.T) { tcases := []struct { v sqltypes.Value @@ -1388,8 +1081,8 @@ func BenchmarkAddNoNative(b *testing.B) { v1 := sqltypes.MakeTrusted(sqltypes.Int64, []byte("1")) v2 := sqltypes.MakeTrusted(sqltypes.Int64, []byte("12")) for i := 0; i < b.N; i++ { - iv1, _ := ToInt64(v1) - iv2, _ := ToInt64(v2) + iv1, _ := v1.ToInt64() + iv2, _ := v2.ToInt64() v1 = sqltypes.MakeTrusted(sqltypes.Int64, strconv.AppendInt(nil, iv1+iv2, 10)) } } diff --git a/go/vt/vtgate/evalengine/api_literal.go b/go/vt/vtgate/evalengine/api_literal.go index 00c033d1d2f..1b2ba6e2da2 100644 --- a/go/vt/vtgate/evalengine/api_literal.go +++ b/go/vt/vtgate/evalengine/api_literal.go @@ -17,14 +17,16 @@ limitations under the License. package evalengine import ( - "encoding/hex" + "errors" "math" "math/big" - "strconv" "unicode/utf8" + "vitess.io/vitess/go/hack" "vitess.io/vitess/go/mysql/collations" "vitess.io/vitess/go/mysql/decimal" + "vitess.io/vitess/go/mysql/fastparse" + "vitess.io/vitess/go/mysql/hex" "vitess.io/vitess/go/sqltypes" ) @@ -38,9 +40,9 @@ func NewLiteralIntegralFromBytes(val []byte) (*Literal, error) { panic("NewLiteralIntegralFromBytes: negative value") } - uval, err := strconv.ParseUint(string(val), 10, 64) + uval, err := fastparse.ParseUint64(hack.String(val), 10) if err != nil { - if numError, ok := err.(*strconv.NumError); ok && numError.Err == strconv.ErrRange { + if errors.Is(err, fastparse.ErrOverflow) { return NewLiteralDecimalFromBytes(val) } return nil, err @@ -72,7 +74,7 @@ func NewLiteralFloat(val float64) *Literal { // NewLiteralFloatFromBytes returns a float literal expression from a slice of bytes func NewLiteralFloatFromBytes(val []byte) (*Literal, error) { - fval, err := strconv.ParseFloat(string(val), 64) + fval, err := fastparse.ParseFloat64(hack.String(val)) if err != nil { return nil, err } @@ -129,8 +131,8 @@ func NewLiteralDatetimeFromBytes(val []byte) (*Literal, error) { } func parseHexLiteral(val []byte) ([]byte, error) { - raw := make([]byte, hex.DecodedLen(len(val))) - if _, err := hex.Decode(raw, val); err != nil { + raw := make([]byte, hex.DecodedLen(val)) + if err := hex.DecodeBytes(raw, val); err != nil { return nil, err } return raw, nil diff --git a/go/vt/vtgate/evalengine/api_types.go b/go/vt/vtgate/evalengine/api_types.go deleted file mode 100644 index c0334da5784..00000000000 --- a/go/vt/vtgate/evalengine/api_types.go +++ /dev/null @@ -1,136 +0,0 @@ -/* -Copyright 2023 The Vitess Authors. - -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 evalengine - -import ( - "vitess.io/vitess/go/mysql/collations" - "vitess.io/vitess/go/sqltypes" - vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" - "vitess.io/vitess/go/vt/sqlparser" - "vitess.io/vitess/go/vt/vterrors" -) - -// Cast converts a Value to the target type. -func Cast(v sqltypes.Value, typ sqltypes.Type) (sqltypes.Value, error) { - if v.Type() == typ || v.IsNull() { - return v, nil - } - vBytes, err := v.ToBytes() - if err != nil { - return v, err - } - if sqltypes.IsSigned(typ) && v.IsSigned() { - return sqltypes.MakeTrusted(typ, vBytes), nil - } - if sqltypes.IsUnsigned(typ) && v.IsUnsigned() { - return sqltypes.MakeTrusted(typ, vBytes), nil - } - if (sqltypes.IsFloat(typ) || typ == sqltypes.Decimal) && (v.IsIntegral() || v.IsFloat() || v.Type() == sqltypes.Decimal) { - return sqltypes.MakeTrusted(typ, vBytes), nil - } - if sqltypes.IsQuoted(typ) && (v.IsIntegral() || v.IsFloat() || v.Type() == sqltypes.Decimal || v.IsQuoted()) { - return sqltypes.MakeTrusted(typ, vBytes), nil - } - - // Explicitly disallow Expression. - if v.Type() == sqltypes.Expression { - return sqltypes.NULL, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v cannot be cast to %v", v, typ) - } - - // If the above fast-paths were not possible, - // go through full validation. - return sqltypes.NewValue(typ, vBytes) -} - -// ToUint64 converts Value to uint64. -func ToUint64(v sqltypes.Value) (uint64, error) { - num, err := valueToEvalNumeric(v) - if err != nil { - return 0, err - } - switch num := num.(type) { - case *evalInt64: - if num.i < 0 { - return 0, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "negative number cannot be converted to unsigned: %d", num.i) - } - return uint64(num.i), nil - case *evalUint64: - return num.u, nil - default: - return 0, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "unexpected return from numeric evaluation (%T)", num) - } -} - -// ToInt64 converts Value to int64. -func ToInt64(v sqltypes.Value) (int64, error) { - num, err := valueToEvalNumeric(v) - if err != nil { - return 0, err - } - switch num := num.(type) { - case *evalInt64: - return num.i, nil - case *evalUint64: - ival := int64(num.u) - if ival < 0 { - return 0, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unsigned number overflows int64 value: %d", num.u) - } - return ival, nil - default: - return 0, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "unexpected return from numeric evaluation (%T)", num) - } -} - -// ToFloat64 converts Value to float64. -func ToFloat64(v sqltypes.Value) (float64, error) { - num, err := valueToEval(v, collationNumeric) - if err != nil { - return 0, err - } - f, _ := evalToFloat(num) - return f.f, nil -} - -func LiteralToValue(literal *sqlparser.Literal) (sqltypes.Value, error) { - lit, err := translateLiteral(literal, collations.Default()) - if err != nil { - return sqltypes.Value{}, err - } - return evalToSQLValue(lit.inner), nil -} - -// ToNative converts Value to a native go type. -// Decimal is returned as []byte. -func ToNative(v sqltypes.Value) (any, error) { - var out any - var err error - switch { - case v.Type() == sqltypes.Null: - // no-op - case v.IsSigned(): - return ToInt64(v) - case v.IsUnsigned(): - return ToUint64(v) - case v.IsFloat(): - return ToFloat64(v) - case v.IsQuoted() || v.Type() == sqltypes.Bit || v.Type() == sqltypes.Decimal: - out, err = v.ToBytes() - case v.Type() == sqltypes.Expression: - err = vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v cannot be converted to a go type", v) - } - return out, err -} diff --git a/go/vt/vtgate/evalengine/compiler_asm.go b/go/vt/vtgate/evalengine/compiler_asm.go index 544dacfdad0..4567d8f3a6a 100644 --- a/go/vt/vtgate/evalengine/compiler_asm.go +++ b/go/vt/vtgate/evalengine/compiler_asm.go @@ -2102,8 +2102,8 @@ func (asm *assembler) Fn_UNHEX_b(tt sqltypes.Type) { arg := env.vm.stack[env.vm.sp-1].(*evalBytes) decoded := make([]byte, hex.DecodedLen(arg.bytes)) - ok := hex.DecodeBytes(decoded, arg.bytes) - if !ok { + err := hex.DecodeBytes(decoded, arg.bytes) + if err != nil { env.vm.stack[env.vm.sp-1] = nil return 1 } diff --git a/go/vt/vtgate/evalengine/fn_hex.go b/go/vt/vtgate/evalengine/fn_hex.go index 3aa395f74cc..0045bfd6688 100644 --- a/go/vt/vtgate/evalengine/fn_hex.go +++ b/go/vt/vtgate/evalengine/fn_hex.go @@ -109,8 +109,8 @@ func hexDecodeJSON(j *evalJSON) ([]byte, bool) { default: b := j.ToRawBytes() decoded := make([]byte, hex.DecodedLen(b)) - ok := hex.DecodeBytes(decoded, b) - if !ok { + err := hex.DecodeBytes(decoded, b) + if err != nil { return nil, false } return decoded, true @@ -130,8 +130,8 @@ func (call *builtinUnhex) eval(env *ExpressionEnv) (eval, error) { switch arg := arg.(type) { case *evalBytes: decoded = make([]byte, hex.DecodedLen(arg.bytes)) - ok := hex.DecodeBytes(decoded, arg.bytes) - if !ok { + err := hex.DecodeBytes(decoded, arg.bytes) + if err != nil { return nil, nil } case *evalInt64: @@ -144,8 +144,8 @@ func (call *builtinUnhex) eval(env *ExpressionEnv) (eval, error) { case *evalDecimal: b := arg.ToRawBytes() decoded = make([]byte, hex.DecodedLen(b)) - ok := hex.DecodeBytes(decoded, b) - if !ok { + err := hex.DecodeBytes(decoded, b) + if err != nil { return nil, nil } case *evalFloat: @@ -163,8 +163,8 @@ func (call *builtinUnhex) eval(env *ExpressionEnv) (eval, error) { default: b := evalToBinary(arg) decoded = make([]byte, hex.DecodedLen(b.bytes)) - ok := hex.DecodeBytes(decoded, b.bytes) - if !ok { + err := hex.DecodeBytes(decoded, b.bytes) + if err != nil { return nil, nil } } diff --git a/go/vt/vtgate/vindexes/hash.go b/go/vt/vtgate/vindexes/hash.go index e523c873fe8..d30895be48a 100644 --- a/go/vt/vtgate/vindexes/hash.go +++ b/go/vt/vtgate/vindexes/hash.go @@ -26,8 +26,6 @@ import ( "fmt" "strconv" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" ) @@ -95,7 +93,7 @@ func (vind *Hash) Map(ctx context.Context, vcursor VCursor, ids []sqltypes.Value func (vind *Hash) Verify(ctx context.Context, vcursor VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, error) { out := make([]bool, len(ids)) for i := range ids { - num, err := evalengine.ToUint64(ids[i]) + num, err := ids[i].ToCastUint64() if err != nil { return nil, err } @@ -128,7 +126,7 @@ func (vind *Hash) Hash(id sqltypes.Value) ([]byte, error) { ival, err = strconv.ParseInt(str, 10, 64) num = uint64(ival) } else { - num, err = evalengine.ToUint64(id) + num, err = id.ToCastUint64() } if err != nil { diff --git a/go/vt/vtgate/vindexes/hash_test.go b/go/vt/vtgate/vindexes/hash_test.go index 04749092358..4a9df88180d 100644 --- a/go/vt/vtgate/vindexes/hash_test.go +++ b/go/vt/vtgate/vindexes/hash_test.go @@ -143,7 +143,7 @@ func TestHashVerify(t *testing.T) { // Failure test _, err = hash.Verify(context.Background(), nil, []sqltypes.Value{sqltypes.NewVarBinary("aa")}, [][]byte{nil}) - require.EqualError(t, err, "could not parse value: 'aa'") + require.EqualError(t, err, "cannot parse uint64 from \"aa\"") } func TestHashReverseMap(t *testing.T) { diff --git a/go/vt/vtgate/vindexes/lookup_hash.go b/go/vt/vtgate/vindexes/lookup_hash.go index a6fedb4c9a0..de3d078f556 100644 --- a/go/vt/vtgate/vindexes/lookup_hash.go +++ b/go/vt/vtgate/vindexes/lookup_hash.go @@ -21,8 +21,6 @@ import ( "encoding/json" "fmt" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -163,7 +161,7 @@ func (lh *LookupHash) MapResult(ids []sqltypes.Value, results []*sqltypes.Result } ksids := make([][]byte, 0, len(result.Rows)) for _, row := range result.Rows { - num, err := evalengine.ToUint64(row[0]) + num, err := row[0].ToCastUint64() if err != nil { // A failure to convert is equivalent to not being // able to map. @@ -360,7 +358,7 @@ func (lhu *LookupHashUnique) MapResult(ids []sqltypes.Value, results []*sqltypes case 0: out = append(out, key.DestinationNone{}) case 1: - num, err := evalengine.ToUint64(result.Rows[0][0]) + num, err := result.Rows[0][0].ToCastUint64() if err != nil { out = append(out, key.DestinationNone{}) continue diff --git a/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go b/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go index 5659aed6212..74cbe1423a0 100644 --- a/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go +++ b/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash.go @@ -22,8 +22,6 @@ import ( "encoding/json" "fmt" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -152,7 +150,7 @@ func (lh *LookupUnicodeLooseMD5Hash) Map(ctx context.Context, vcursor VCursor, i } ksids := make([][]byte, 0, len(result.Rows)) for _, row := range result.Rows { - num, err := evalengine.ToUint64(row[0]) + num, err := row[0].ToCastUint64() if err != nil { // A failure to convert is equivalent to not being // able to map. @@ -332,7 +330,7 @@ func (lhu *LookupUnicodeLooseMD5HashUnique) Map(ctx context.Context, vcursor VCu case 0: out = append(out, key.DestinationNone{}) case 1: - num, err := evalengine.ToUint64(result.Rows[0][0]) + num, err := result.Rows[0][0].ToCastUint64() if err != nil { out = append(out, key.DestinationNone{}) continue diff --git a/go/vt/vtgate/vindexes/numeric.go b/go/vt/vtgate/vindexes/numeric.go index c99663b72e7..091807ec2cc 100644 --- a/go/vt/vtgate/vindexes/numeric.go +++ b/go/vt/vtgate/vindexes/numeric.go @@ -22,8 +22,6 @@ import ( "encoding/binary" "fmt" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" ) @@ -116,7 +114,7 @@ func (vind *Numeric) UnknownParams() []string { } func (*Numeric) Hash(id sqltypes.Value) ([]byte, error) { - num, err := evalengine.ToUint64(id) + num, err := id.ToCastUint64() if err != nil { return nil, err } diff --git a/go/vt/vtgate/vindexes/numeric_static_map.go b/go/vt/vtgate/vindexes/numeric_static_map.go index 5f6dd1ff1ff..f97016d915f 100644 --- a/go/vt/vtgate/vindexes/numeric_static_map.go +++ b/go/vt/vtgate/vindexes/numeric_static_map.go @@ -24,12 +24,10 @@ import ( "os" "strconv" - "vitess.io/vitess/go/vt/proto/vtrpc" - "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) const ( @@ -162,7 +160,7 @@ func (vind *NumericStaticMap) Map(ctx context.Context, vcursor VCursor, ids []sq } func (vind *NumericStaticMap) Hash(id sqltypes.Value) ([]byte, error) { - num, err := evalengine.ToUint64(id) + num, err := id.ToCastUint64() if err != nil { return nil, err } diff --git a/go/vt/vtgate/vindexes/numeric_static_map_test.go b/go/vt/vtgate/vindexes/numeric_static_map_test.go index d6e3f5b38c3..7a373060f16 100644 --- a/go/vt/vtgate/vindexes/numeric_static_map_test.go +++ b/go/vt/vtgate/vindexes/numeric_static_map_test.go @@ -196,7 +196,7 @@ func TestNumericStaticMapVerify(t *testing.T) { // Failure test _, err = numericStaticMap.Verify(context.Background(), nil, []sqltypes.Value{sqltypes.NewVarBinary("aa")}, [][]byte{nil}) - require.EqualError(t, err, "could not parse value: 'aa'") + require.EqualError(t, err, "cannot parse uint64 from \"aa\"") } func TestNumericStaticMapWithJsonVdx(t *testing.T) { @@ -313,5 +313,5 @@ func TestNumericStaticMapWithFallbackVerify(t *testing.T) { // Failure test _, err = singleCol.Verify(context.Background(), nil, []sqltypes.Value{sqltypes.NewVarBinary("aa")}, [][]byte{nil}) - require.EqualError(t, err, "could not parse value: 'aa'") + require.EqualError(t, err, "cannot parse uint64 from \"aa\"") } diff --git a/go/vt/vtgate/vindexes/numeric_test.go b/go/vt/vtgate/vindexes/numeric_test.go index 974d589dca6..612c0f3c5e7 100644 --- a/go/vt/vtgate/vindexes/numeric_test.go +++ b/go/vt/vtgate/vindexes/numeric_test.go @@ -127,7 +127,7 @@ func TestNumericVerify(t *testing.T) { // Failure test _, err = numeric.Verify(context.Background(), nil, []sqltypes.Value{sqltypes.NewVarBinary("aa")}, [][]byte{nil}) - require.EqualError(t, err, "could not parse value: 'aa'") + require.EqualError(t, err, "cannot parse uint64 from \"aa\"") } func TestNumericReverseMap(t *testing.T) { diff --git a/go/vt/vtgate/vindexes/region_experimental.go b/go/vt/vtgate/vindexes/region_experimental.go index 676a38e5c77..c116e9bd84d 100644 --- a/go/vt/vtgate/vindexes/region_experimental.go +++ b/go/vt/vtgate/vindexes/region_experimental.go @@ -22,12 +22,10 @@ import ( "encoding/binary" "fmt" - "vitess.io/vitess/go/vt/proto/vtrpc" - "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) const ( @@ -110,7 +108,7 @@ func (ge *RegionExperimental) Map(ctx context.Context, vcursor VCursor, rowsColV continue } // Compute region prefix. - rn, err := evalengine.ToUint64(row[0]) + rn, err := row[0].ToCastUint64() if err != nil { destinations = append(destinations, key.DestinationNone{}) continue @@ -126,7 +124,7 @@ func (ge *RegionExperimental) Map(ctx context.Context, vcursor VCursor, rowsColV dest := r if len(row) == 2 { // Compute hash. - hn, err := evalengine.ToUint64(row[1]) + hn, err := row[1].ToCastUint64() if err != nil { destinations = append(destinations, key.DestinationNone{}) continue diff --git a/go/vt/vtgate/vindexes/region_json.go b/go/vt/vtgate/vindexes/region_json.go index 1a28354261a..f0ac2ef18fa 100644 --- a/go/vt/vtgate/vindexes/region_json.go +++ b/go/vt/vtgate/vindexes/region_json.go @@ -25,8 +25,6 @@ import ( "os" "strconv" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/log" @@ -128,7 +126,7 @@ func (rv *RegionJSON) Map(ctx context.Context, vcursor VCursor, rowsColValues [] continue } // Compute hash. - hn, err := evalengine.ToUint64(row[0]) + hn, err := row[0].ToCastUint64() if err != nil { destinations = append(destinations, key.DestinationNone{}) continue diff --git a/go/vt/vtgate/vindexes/reverse_bits.go b/go/vt/vtgate/vindexes/reverse_bits.go index 184e62de5a0..80c72ca6924 100644 --- a/go/vt/vtgate/vindexes/reverse_bits.go +++ b/go/vt/vtgate/vindexes/reverse_bits.go @@ -24,8 +24,6 @@ import ( "fmt" "math/bits" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" ) @@ -117,7 +115,7 @@ func (vind *ReverseBits) UnknownParams() []string { } func (vind *ReverseBits) Hash(id sqltypes.Value) ([]byte, error) { - num, err := evalengine.ToUint64(id) + num, err := id.ToCastUint64() if err != nil { return nil, err } diff --git a/go/vt/vtgate/vindexes/reverse_bits_test.go b/go/vt/vtgate/vindexes/reverse_bits_test.go index 9f5d2b56b15..dbc2d207919 100644 --- a/go/vt/vtgate/vindexes/reverse_bits_test.go +++ b/go/vt/vtgate/vindexes/reverse_bits_test.go @@ -129,7 +129,7 @@ func TestReverseBitsVerify(t *testing.T) { // Failure test _, err = reverseBits.Verify(context.Background(), nil, []sqltypes.Value{sqltypes.NewVarBinary("aa")}, [][]byte{nil}) - require.EqualError(t, err, "could not parse value: 'aa'") + require.EqualError(t, err, "cannot parse uint64 from \"aa\"") } func TestReverseBitsReverseMap(t *testing.T) { diff --git a/go/vt/vttablet/tabletmanager/rpc_vreplication.go b/go/vt/vttablet/tabletmanager/rpc_vreplication.go index 969433a7568..49d8f3ad7a7 100644 --- a/go/vt/vttablet/tabletmanager/rpc_vreplication.go +++ b/go/vt/vttablet/tabletmanager/rpc_vreplication.go @@ -27,7 +27,6 @@ import ( "vitess.io/vitess/go/textutil" "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/proto/vttime" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/vtctl/workflow" @@ -83,7 +82,7 @@ func (tm *TabletManager) CreateVReplicationWorkflow(ctx context.Context, req *ta "workflowSubType": sqltypes.Int64BindVariable(int64(req.WorkflowSubType)), "deferSecondaryKeys": sqltypes.BoolBindVariable(req.DeferSecondaryKeys), } - parsed := sqlparser.BuildParsedQuery(sqlCreateVReplicationWorkflow, sidecardb.GetIdentifier(), + parsed := sqlparser.BuildParsedQuery(sqlCreateVReplicationWorkflow, sidecar.GetIdentifier(), ":workflow", ":source", ":cells", ":tabletTypes", ":state", ":dbname", ":workflowType", ":workflowSubType", ":deferSecondaryKeys", ) stmt, err := parsed.GenerateQuery(bindVars, nil) @@ -109,7 +108,7 @@ func (tm *TabletManager) DeleteVReplicationWorkflow(ctx context.Context, req *ta "wf": sqltypes.StringBindVariable(req.Workflow), "db": sqltypes.StringBindVariable(tm.DBConfigs.DBName), } - parsed := sqlparser.BuildParsedQuery(sqlDeleteVReplicationWorkflow, sidecardb.GetIdentifier(), ":wf", ":db") + parsed := sqlparser.BuildParsedQuery(sqlDeleteVReplicationWorkflow, sidecar.GetIdentifier(), ":wf", ":db") stmt, err := parsed.GenerateQuery(bindVars, nil) if err != nil { return nil, err @@ -132,7 +131,7 @@ func (tm *TabletManager) ReadVReplicationWorkflow(ctx context.Context, req *tabl "wf": sqltypes.StringBindVariable(req.Workflow), "db": sqltypes.StringBindVariable(tm.DBConfigs.DBName), } - parsed := sqlparser.BuildParsedQuery(sqlReadVReplicationWorkflow, sidecardb.GetIdentifier(), ":wf", ":db") + parsed := sqlparser.BuildParsedQuery(sqlReadVReplicationWorkflow, sidecar.GetIdentifier(), ":wf", ":db") stmt, err := parsed.GenerateQuery(bindVars, nil) if err != nil { return nil, err @@ -242,7 +241,7 @@ func (tm *TabletManager) UpdateVReplicationWorkflow(ctx context.Context, req *ta bindVars := map[string]*querypb.BindVariable{ "wf": sqltypes.StringBindVariable(req.Workflow), } - parsed := sqlparser.BuildParsedQuery(sqlSelectVReplicationWorkflowConfig, sidecardb.GetIdentifier(), ":wf") + parsed := sqlparser.BuildParsedQuery(sqlSelectVReplicationWorkflowConfig, sidecar.GetIdentifier(), ":wf") stmt, err := parsed.GenerateQuery(bindVars, nil) if err != nil { return nil, err @@ -310,7 +309,7 @@ func (tm *TabletManager) UpdateVReplicationWorkflow(ctx context.Context, req *ta "tt": sqltypes.StringBindVariable(tabletTypesStr), "id": sqltypes.Int64BindVariable(id), } - parsed = sqlparser.BuildParsedQuery(sqlUpdateVReplicationWorkflowConfig, sidecardb.GetIdentifier(), ":st", ":sc", ":cl", ":tt", ":id") + parsed = sqlparser.BuildParsedQuery(sqlUpdateVReplicationWorkflowConfig, sidecar.GetIdentifier(), ":st", ":sc", ":cl", ":tt", ":id") stmt, err = parsed.GenerateQuery(bindVars, nil) if err != nil { return nil, err diff --git a/go/vt/vttablet/tabletmanager/vreplication/controller_plan.go b/go/vt/vttablet/tabletmanager/vreplication/controller_plan.go index 463b5b53a9f..b168625d20a 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/controller_plan.go +++ b/go/vt/vttablet/tabletmanager/vreplication/controller_plan.go @@ -20,7 +20,6 @@ import ( "fmt" "vitess.io/vitess/go/constants/sidecar" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" ) @@ -178,7 +177,7 @@ func buildUpdatePlan(upd *sqlparser.Update) (*controllerPlan, error) { } buf1 := sqlparser.NewTrackedBuffer(nil) - buf1.Myprintf("select id from %s.%s%v", sidecardb.GetIdentifier(), vreplicationTableName, upd.Where) + buf1.Myprintf("select id from %s.%s%v", sidecar.GetIdentifier(), vreplicationTableName, upd.Where) upd.Where = &sqlparser.Where{ Type: sqlparser.WhereClause, Expr: &sqlparser.ComparisonExpr{ @@ -236,7 +235,7 @@ func buildDeletePlan(del *sqlparser.Delete) (*controllerPlan, error) { } buf1 := sqlparser.NewTrackedBuffer(nil) - buf1.Myprintf("select id from %s.%s%v", sidecardb.GetIdentifier(), vreplicationTableName, del.Where) + buf1.Myprintf("select id from %s.%s%v", sidecar.GetIdentifier(), vreplicationTableName, del.Where) del.Where = &sqlparser.Where{ Type: sqlparser.WhereClause, Expr: &sqlparser.ComparisonExpr{ @@ -258,10 +257,10 @@ func buildDeletePlan(del *sqlparser.Delete) (*controllerPlan, error) { }, } buf3 := sqlparser.NewTrackedBuffer(nil) - buf3.Myprintf("delete from %s.%s%v", sidecardb.GetIdentifier(), copyStateTableName, copyStateWhere) + buf3.Myprintf("delete from %s.%s%v", sidecar.GetIdentifier(), copyStateTableName, copyStateWhere) buf4 := sqlparser.NewTrackedBuffer(nil) - buf4.Myprintf("delete from %s.%s%v", sidecardb.GetIdentifier(), postCopyActionTableName, copyStateWhere) + buf4.Myprintf("delete from %s.%s%v", sidecar.GetIdentifier(), postCopyActionTableName, copyStateWhere) return &controllerPlan{ opcode: deleteQuery, diff --git a/go/vt/vttablet/tabletmanager/vreplication/engine.go b/go/vt/vttablet/tabletmanager/vreplication/engine.go index ce431fb65ad..d838e2c2471 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/engine.go +++ b/go/vt/vttablet/tabletmanager/vreplication/engine.go @@ -29,6 +29,8 @@ import ( "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/constants/sidecar" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" @@ -39,7 +41,6 @@ import ( binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" querypb "vitess.io/vitess/go/vt/proto/query" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" @@ -377,7 +378,7 @@ func (vre *Engine) exec(query string, runAsAdmin bool) (*sqltypes.Result, error) // Change the database to ensure that these events don't get // replicated by another vreplication. This can happen when // we reverse replication. - if _, err := dbClient.ExecuteFetch(fmt.Sprintf("use %s", sidecardb.GetIdentifier()), 1); err != nil { + if _, err := dbClient.ExecuteFetch(fmt.Sprintf("use %s", sidecar.GetIdentifier()), 1); err != nil { return nil, err } diff --git a/go/vt/vttablet/tabletmanager/vreplication/fuzz.go b/go/vt/vttablet/tabletmanager/vreplication/fuzz.go index ef04d479c6d..98183e726df 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/fuzz.go +++ b/go/vt/vttablet/tabletmanager/vreplication/fuzz.go @@ -22,10 +22,10 @@ import ( "sync" "testing" + "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/mysqlctl" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/topo/memorytopo" @@ -102,7 +102,7 @@ func FuzzEngine(data []byte) int { // Fuzzer fails if this expectation is not made first: dbClient.ExpectRequest(sqlparser.BuildParsedQuery("select * from %s.vreplication where db_name='db'", - sidecardb.GetIdentifier()).Query, &sqltypes.Result{}, nil) + sidecar.GetIdentifier()).Query, &sqltypes.Result{}, nil) err = makeExpectations(dbClient, f) if err != nil { return 0 diff --git a/go/vt/vttablet/tabletmanager/vreplication/utils.go b/go/vt/vttablet/tabletmanager/vreplication/utils.go index ac26c84fbae..42aa4351647 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/utils.go +++ b/go/vt/vttablet/tabletmanager/vreplication/utils.go @@ -21,12 +21,11 @@ import ( "fmt" "strconv" + "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/log" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" - "vitess.io/vitess/go/vt/vtgate/evalengine" ) const ( @@ -65,7 +64,7 @@ const ( func getLastLog(dbClient *vdbClient, vreplID int32) (id int64, typ, state, message string, err error) { var qr *sqltypes.Result query := fmt.Sprintf("select id, type, state, message from %s.vreplication_log where vrepl_id = %d order by id desc limit 1", - sidecardb.GetIdentifier(), vreplID) + sidecar.GetIdentifier(), vreplID) if qr, err = dbClient.Execute(query); err != nil { return 0, "", "", "", err } @@ -73,7 +72,7 @@ func getLastLog(dbClient *vdbClient, vreplID int32) (id int64, typ, state, messa return 0, "", "", "", nil } row := qr.Rows[0] - id, _ = evalengine.ToInt64(row[0]) + id, _ = row[0].ToCastInt64() typ = row[1].ToString() state = row[2].ToString() message = row[3].ToString() @@ -93,11 +92,11 @@ func insertLog(dbClient *vdbClient, typ string, vreplID int32, state, message st } var query string if id > 0 && message == lastLogMessage { - query = fmt.Sprintf("update %s.vreplication_log set count = count + 1 where id = %d", sidecardb.GetIdentifier(), id) + query = fmt.Sprintf("update %s.vreplication_log set count = count + 1 where id = %d", sidecar.GetIdentifier(), id) } else { buf := sqlparser.NewTrackedBuffer(nil) buf.Myprintf("insert into %s.vreplication_log(vrepl_id, type, state, message) values(%s, %s, %s, %s)", - sidecardb.GetIdentifier(), strconv.Itoa(int(vreplID)), encodeString(typ), encodeString(state), encodeString(message)) + sidecar.GetIdentifier(), strconv.Itoa(int(vreplID)), encodeString(typ), encodeString(state), encodeString(message)) query = buf.ParsedQuery().Query } if _, err = dbClient.ExecuteFetch(query, 10000); err != nil { diff --git a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go index 40480ca07d7..daed5a58147 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go @@ -37,8 +37,6 @@ import ( querypb "vitess.io/vitess/go/vt/proto/query" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/log" @@ -427,7 +425,7 @@ func (vr *vreplicator) readSettings(ctx context.Context, dbClient *vdbClient) (s if len(qr.Rows) == 0 || len(qr.Rows[0]) == 0 { return settings, numTablesToCopy, fmt.Errorf("unexpected result from %s: %v", query, qr) } - numTablesToCopy, err = evalengine.ToInt64(qr.Rows[0][0]) + numTablesToCopy, err = qr.Rows[0][0].ToCastInt64() if err != nil { return settings, numTablesToCopy, err } @@ -493,7 +491,7 @@ func (vr *vreplicator) getSettingFKCheck() error { if len(qr.Rows) != 1 || len(qr.Fields) != 1 { return fmt.Errorf("unable to select @@foreign_key_checks") } - vr.originalFKCheckSetting, err = evalengine.ToInt64(qr.Rows[0][0]) + vr.originalFKCheckSetting, err = qr.Rows[0][0].ToCastInt64() if err != nil { return err } diff --git a/go/vt/vttablet/tabletserver/health_streamer.go b/go/vt/vttablet/tabletserver/health_streamer.go index 67e9a5852bb..1170e4fbc39 100644 --- a/go/vt/vttablet/tabletserver/health_streamer.go +++ b/go/vt/vttablet/tabletserver/health_streamer.go @@ -27,7 +27,8 @@ import ( "github.com/spf13/pflag" - "vitess.io/vitess/go/vt/sidecardb" + "vitess.io/vitess/go/constants/sidecar" + "vitess.io/vitess/go/vt/vttablet/tabletserver/schema" "vitess.io/vitess/go/vt/servenv" @@ -401,8 +402,8 @@ func (hs *healthStreamer) reloadTables(ctx context.Context, conn *connpool.DBCon } tableNamePredicate := fmt.Sprintf("table_name IN (%s)", strings.Join(escapedTableNames, ", ")) - del := fmt.Sprintf("%s AND %s", sqlparser.BuildParsedQuery(mysql.ClearSchemaCopy, sidecardb.GetIdentifier()).Query, tableNamePredicate) - upd := fmt.Sprintf("%s AND %s", sqlparser.BuildParsedQuery(mysql.InsertIntoSchemaCopy, sidecardb.GetIdentifier()).Query, tableNamePredicate) + del := fmt.Sprintf("%s AND %s", sqlparser.BuildParsedQuery(mysql.ClearSchemaCopy, sidecar.GetIdentifier()).Query, tableNamePredicate) + upd := fmt.Sprintf("%s AND %s", sqlparser.BuildParsedQuery(mysql.InsertIntoSchemaCopy, sidecar.GetIdentifier()).Query, tableNamePredicate) // Reload the schema in a transaction. _, err := conn.Exec(ctx, "begin", 1, false) diff --git a/go/vt/vttablet/tabletserver/health_streamer_test.go b/go/vt/vttablet/tabletserver/health_streamer_test.go index 756feb25453..98982b31c25 100644 --- a/go/vt/vttablet/tabletserver/health_streamer_test.go +++ b/go/vt/vttablet/tabletserver/health_streamer_test.go @@ -29,12 +29,13 @@ import ( "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/constants/sidecar" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/mysql/fakesqldb" "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" topodatapb "vitess.io/vitess/go/vt/proto/topodata" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vttablet/tabletserver/schema" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" @@ -227,8 +228,8 @@ func TestReloadSchema(t *testing.T) { target := &querypb.Target{TabletType: topodatapb.TabletType_PRIMARY} configs := config.DB - db.AddQueryPattern(sqlparser.BuildParsedQuery(mysql.ClearSchemaCopy, sidecardb.GetIdentifier()).Query+".*", &sqltypes.Result{}) - db.AddQueryPattern(sqlparser.BuildParsedQuery(mysql.InsertIntoSchemaCopy, sidecardb.GetIdentifier()).Query+".*", &sqltypes.Result{}) + db.AddQueryPattern(sqlparser.BuildParsedQuery(mysql.ClearSchemaCopy, sidecar.GetIdentifier()).Query+".*", &sqltypes.Result{}) + db.AddQueryPattern(sqlparser.BuildParsedQuery(mysql.InsertIntoSchemaCopy, sidecar.GetIdentifier()).Query+".*", &sqltypes.Result{}) db.AddQueryPattern("SELECT UNIX_TIMESTAMP()"+".*", sqltypes.MakeTestResult( sqltypes.MakeTestFields( "UNIX_TIMESTAMP(now())", @@ -339,8 +340,8 @@ func TestReloadView(t *testing.T) { target := &querypb.Target{TabletType: topodatapb.TabletType_PRIMARY} configs := config.DB - db.AddQueryPattern(sqlparser.BuildParsedQuery(mysql.ClearSchemaCopy, sidecardb.GetIdentifier()).Query+".*", &sqltypes.Result{}) - db.AddQueryPattern(sqlparser.BuildParsedQuery(mysql.InsertIntoSchemaCopy, sidecardb.GetIdentifier()).Query+".*", &sqltypes.Result{}) + db.AddQueryPattern(sqlparser.BuildParsedQuery(mysql.ClearSchemaCopy, sidecar.GetIdentifier()).Query+".*", &sqltypes.Result{}) + db.AddQueryPattern(sqlparser.BuildParsedQuery(mysql.InsertIntoSchemaCopy, sidecar.GetIdentifier()).Query+".*", &sqltypes.Result{}) db.AddQueryPattern("SELECT UNIX_TIMESTAMP()"+".*", sqltypes.MakeTestResult( sqltypes.MakeTestFields( "UNIX_TIMESTAMP(now())", diff --git a/go/vt/vttablet/tabletserver/messager/message_manager.go b/go/vt/vttablet/tabletserver/messager/message_manager.go index 135f20f7793..3d47ebc93a2 100644 --- a/go/vt/vttablet/tabletserver/messager/message_manager.go +++ b/go/vt/vttablet/tabletserver/messager/message_manager.go @@ -36,7 +36,6 @@ import ( binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" querypb "vitess.io/vitess/go/vt/proto/query" "vitess.io/vitess/go/vt/sqlparser" - "vitess.io/vitess/go/vt/vtgate/evalengine" "vitess.io/vitess/go/vt/vttablet/tabletserver/schema" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" "vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/throttlerapp" @@ -906,28 +905,28 @@ func (mm *messageManager) GeneratePurgeQuery(timeCutoff int64) (string, map[stri func BuildMessageRow(row []sqltypes.Value) (*MessageRow, error) { mr := &MessageRow{Row: row[4:]} if !row[0].IsNull() { - v, err := evalengine.ToInt64(row[0]) + v, err := row[0].ToCastInt64() if err != nil { return nil, err } mr.Priority = v } if !row[1].IsNull() { - v, err := evalengine.ToInt64(row[1]) + v, err := row[1].ToCastInt64() if err != nil { return nil, err } mr.TimeNext = v } if !row[2].IsNull() { - v, err := evalengine.ToInt64(row[2]) + v, err := row[2].ToCastInt64() if err != nil { return nil, err } mr.Epoch = v } if !row[3].IsNull() { - v, err := evalengine.ToInt64(row[3]) + v, err := row[3].ToCastInt64() if err != nil { return nil, err } diff --git a/go/vt/vttablet/tabletserver/messager/message_manager_test.go b/go/vt/vttablet/tabletserver/messager/message_manager_test.go index 59286403885..b8ca47ae46d 100644 --- a/go/vt/vttablet/tabletserver/messager/message_manager_test.go +++ b/go/vt/vttablet/tabletserver/messager/message_manager_test.go @@ -34,7 +34,6 @@ import ( "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/test/utils" "vitess.io/vitess/go/vt/sqlparser" - "vitess.io/vitess/go/vt/vtgate/evalengine" "vitess.io/vitess/go/vt/vttablet/tabletserver/schema" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" "vitess.io/vitess/go/vt/vttablet/tabletserver/throttle/throttlerapp" @@ -741,7 +740,7 @@ func TestMMGenerate(t *testing.T) { t.Errorf("GenerateAckQuery query: %s, want %s", query, wantQuery) } bvv, _ := sqltypes.BindVariableToValue(bv["time_acked"]) - gotAcked, _ := evalengine.ToInt64(bvv) + gotAcked, _ := bvv.ToCastInt64() wantAcked := time.Now().UnixNano() if wantAcked-gotAcked > 10e9 { t.Errorf("gotAcked: %d, should be with 10s of %d", gotAcked, wantAcked) diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index 3462be4f410..8dd35d32db7 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -634,7 +634,7 @@ func (qre *QueryExecutor) execNextval() (*sqltypes.Result, error) { if len(qr.Rows) != 1 { return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unexpected rows from reading sequence %s (possible mis-route): %d", tableName, len(qr.Rows)) } - nextID, err := evalengine.ToInt64(qr.Rows[0][0]) + nextID, err := qr.Rows[0][0].ToCastInt64() if err != nil { return nil, vterrors.Wrapf(err, "error loading sequence %s", tableName) } @@ -649,7 +649,7 @@ func (qre *QueryExecutor) execNextval() (*sqltypes.Result, error) { t.SequenceInfo.NextVal = nextID t.SequenceInfo.LastVal = nextID } - cache, err := evalengine.ToInt64(qr.Rows[0][1]) + cache, err := qr.Rows[0][1].ToCastInt64() if err != nil { return nil, vterrors.Wrapf(err, "error loading sequence %s", tableName) } diff --git a/go/vt/vttablet/tabletserver/repltracker/reader.go b/go/vt/vttablet/tabletserver/repltracker/reader.go index ebe4938dd12..fc42a367989 100644 --- a/go/vt/vttablet/tabletserver/repltracker/reader.go +++ b/go/vt/vttablet/tabletserver/repltracker/reader.go @@ -22,9 +22,7 @@ import ( "sync" "time" - "vitess.io/vitess/go/vt/sidecardb" - "vitess.io/vitess/go/vt/vtgate/evalengine" - + "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/sqltypes" @@ -192,7 +190,7 @@ func (r *heartbeatReader) bindHeartbeatFetch() (string, error) { bindVars := map[string]*querypb.BindVariable{ "ks": sqltypes.StringBindVariable(r.keyspaceShard), } - parsed := sqlparser.BuildParsedQuery(sqlFetchMostRecentHeartbeat, sidecardb.GetIdentifier(), ":ks") + parsed := sqlparser.BuildParsedQuery(sqlFetchMostRecentHeartbeat, sidecar.GetIdentifier(), ":ks") bound, err := parsed.GenerateQuery(bindVars, nil) if err != nil { return "", err @@ -205,7 +203,7 @@ func parseHeartbeatResult(res *sqltypes.Result) (int64, error) { if len(res.Rows) != 1 { return 0, fmt.Errorf("failed to read heartbeat: writer query did not result in 1 row. Got %v", len(res.Rows)) } - ts, err := evalengine.ToInt64(res.Rows[0][0]) + ts, err := res.Rows[0][0].ToCastInt64() if err != nil { return 0, err } diff --git a/go/vt/vttablet/tabletserver/repltracker/writer.go b/go/vt/vttablet/tabletserver/repltracker/writer.go index c742cbb29fd..a5d3be84781 100644 --- a/go/vt/vttablet/tabletserver/repltracker/writer.go +++ b/go/vt/vttablet/tabletserver/repltracker/writer.go @@ -25,13 +25,14 @@ import ( "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/constants/sidecar" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/timer" "vitess.io/vitess/go/vt/dbconnpool" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/mysqlctl" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" @@ -172,7 +173,7 @@ func (w *heartbeatWriter) bindHeartbeatVars(query string) (string, error) { "ts": sqltypes.Int64BindVariable(w.now().UnixNano()), "uid": sqltypes.Int64BindVariable(int64(w.tabletAlias.Uid)), } - parsed := sqlparser.BuildParsedQuery(query, sidecardb.GetIdentifier(), ":ts", ":uid", ":ks") + parsed := sqlparser.BuildParsedQuery(query, sidecar.GetIdentifier(), ":ts", ":uid", ":ks") bound, err := parsed.GenerateQuery(bindVars, nil) if err != nil { return "", err diff --git a/go/vt/vttablet/tabletserver/rules/rules.go b/go/vt/vttablet/tabletserver/rules/rules.go index 14ac632d778..efbfcdf87e4 100644 --- a/go/vt/vttablet/tabletserver/rules/rules.go +++ b/go/vt/vttablet/tabletserver/rules/rules.go @@ -26,8 +26,6 @@ import ( "strconv" "time" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vterrors" @@ -832,7 +830,7 @@ func getuint64(val *querypb.BindVariable) (uv uint64, status int) { if err != nil { return 0, QROutOfRange } - v, err := evalengine.ToUint64(bv) + v, err := bv.ToCastUint64() if err != nil { return 0, QROutOfRange } @@ -845,7 +843,7 @@ func getint64(val *querypb.BindVariable) (iv int64, status int) { if err != nil { return 0, QROutOfRange } - v, err := evalengine.ToInt64(bv) + v, err := bv.ToCastInt64() if err != nil { return 0, QROutOfRange } diff --git a/go/vt/vttablet/tabletserver/schema/db.go b/go/vt/vttablet/tabletserver/schema/db.go index c8a33c17be0..85ebf3b1457 100644 --- a/go/vt/vttablet/tabletserver/schema/db.go +++ b/go/vt/vttablet/tabletserver/schema/db.go @@ -19,9 +19,9 @@ package schema import ( "context" + "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool" ) @@ -164,7 +164,7 @@ func reloadTablesDataInDB(ctx context.Context, conn *connpool.DBConn, tables []* // generateFullQuery generates the full query from the query as a string. func generateFullQuery(query string) (*sqlparser.ParsedQuery, error) { stmt, err := sqlparser.Parse( - sqlparser.BuildParsedQuery(query, sidecardb.GetIdentifier(), sidecardb.GetIdentifier()).Query) + sqlparser.BuildParsedQuery(query, sidecar.GetIdentifier(), sidecar.GetIdentifier()).Query) if err != nil { return nil, err } @@ -304,7 +304,7 @@ func getChangedViewNames(ctx context.Context, conn *connpool.DBConn, isServingPr alloc := func() *sqltypes.Result { return &sqltypes.Result{} } bufferSize := 1000 - viewChangeQuery := sqlparser.BuildParsedQuery(detectViewChange, sidecardb.GetIdentifier()).Query + viewChangeQuery := sqlparser.BuildParsedQuery(detectViewChange, sidecar.GetIdentifier()).Query err := conn.Stream(ctx, viewChangeQuery, callback, alloc, bufferSize, 0) if err != nil { return nil, err @@ -337,7 +337,7 @@ func (se *Engine) getMismatchedTableNames(ctx context.Context, conn *connpool.DB } alloc := func() *sqltypes.Result { return &sqltypes.Result{} } bufferSize := 1000 - readTableCreateTimesQuery := sqlparser.BuildParsedQuery(readTableCreateTimes, sidecardb.GetIdentifier()).Query + readTableCreateTimesQuery := sqlparser.BuildParsedQuery(readTableCreateTimes, sidecar.GetIdentifier()).Query err := conn.Stream(ctx, readTableCreateTimesQuery, callback, alloc, bufferSize, 0) if err != nil { return nil, err diff --git a/go/vt/vttablet/tabletserver/schema/db_test.go b/go/vt/vttablet/tabletserver/schema/db_test.go index a066b50a8c9..d7ef2608fbe 100644 --- a/go/vt/vttablet/tabletserver/schema/db_test.go +++ b/go/vt/vttablet/tabletserver/schema/db_test.go @@ -25,10 +25,11 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/exp/maps" + "vitess.io/vitess/go/constants/sidecar" + "vitess.io/vitess/go/mysql/fakesqldb" "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool" ) @@ -134,7 +135,7 @@ func TestGetChangedViewNames(t *testing.T) { require.NoError(t, err) // Success - query := fmt.Sprintf(detectViewChange, sidecardb.GetIdentifier()) + query := fmt.Sprintf(detectViewChange, sidecar.GetIdentifier()) db.AddQuery(query, sqltypes.MakeTestResult( sqltypes.MakeTestFields("table_name", "varchar"), "lead", @@ -331,7 +332,7 @@ func TestGetMismatchedTableNames(t *testing.T) { }, } - query := fmt.Sprintf(readTableCreateTimes, sidecardb.GetIdentifier()) + query := fmt.Sprintf(readTableCreateTimes, sidecar.GetIdentifier()) for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { db := fakesqldb.New(t) diff --git a/go/vt/vttablet/tabletserver/schema/engine.go b/go/vt/vttablet/tabletserver/schema/engine.go index 08e3bdced8c..4385988ed4a 100644 --- a/go/vt/vttablet/tabletserver/schema/engine.go +++ b/go/vt/vttablet/tabletserver/schema/engine.go @@ -28,6 +28,8 @@ import ( "golang.org/x/exp/maps" + "vitess.io/vitess/go/constants/sidecar" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/mysql/sqlerror" @@ -46,7 +48,6 @@ import ( "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/vt/vtgate/evalengine" "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" @@ -154,7 +155,7 @@ func (se *Engine) syncSidecarDB(ctx context.Context, conn *dbconnpool.DBConnecti var exec sidecardb.Exec = func(ctx context.Context, query string, maxRows int, useDB bool) (*sqltypes.Result, error) { if useDB { - _, err := conn.ExecuteFetch(sqlparser.BuildParsedQuery("use %s", sidecardb.GetIdentifier()).Query, maxRows, false) + _, err := conn.ExecuteFetch(sqlparser.BuildParsedQuery("use %s", sidecar.GetIdentifier()).Query, maxRows, false) if err != nil { return nil, err } @@ -456,12 +457,12 @@ func (se *Engine) reload(ctx context.Context, includeStats bool) error { for _, row := range tableData.Rows { tableName := row[0].ToString() curTables[tableName] = true - createTime, _ := evalengine.ToInt64(row[2]) + createTime, _ := row[2].ToCastInt64() var fileSize, allocatedSize uint64 if includeStats { - fileSize, _ = evalengine.ToUint64(row[4]) - allocatedSize, _ = evalengine.ToUint64(row[5]) + fileSize, _ = row[4].ToCastUint64() + allocatedSize, _ = row[5].ToCastUint64() // publish the size metrics se.tableFileSizeGauge.Set(tableName, int64(fileSize)) se.tableAllocatedSizeGauge.Set(tableName, int64(allocatedSize)) @@ -607,7 +608,7 @@ func (se *Engine) updateInnoDBRowsRead(ctx context.Context, conn *connpool.DBCon } if len(readRowsData.Rows) == 1 && len(readRowsData.Rows[0]) == 2 { - value, err := evalengine.ToInt64(readRowsData.Rows[0][1]) + value, err := readRowsData.Rows[0][1].ToCastInt64() if err != nil { return err } @@ -628,7 +629,7 @@ func (se *Engine) mysqlTime(ctx context.Context, conn *connpool.DBConn) (int64, if len(tm.Rows) != 1 || len(tm.Rows[0]) != 1 || tm.Rows[0][0].IsNull() { return 0, vterrors.Errorf(vtrpcpb.Code_UNKNOWN, "unexpected result for MySQL time: %+v", tm.Rows) } - t, err := evalengine.ToInt64(tm.Rows[0][0]) + t, err := tm.Rows[0][0].ToCastInt64() if err != nil { return 0, vterrors.Errorf(vtrpcpb.Code_UNKNOWN, "could not parse time %v: %v", tm, err) } diff --git a/go/vt/vttablet/tabletserver/schema/engine_test.go b/go/vt/vttablet/tabletserver/schema/engine_test.go index 278b9637a2a..78b43fd1e0e 100644 --- a/go/vt/vttablet/tabletserver/schema/engine_test.go +++ b/go/vt/vttablet/tabletserver/schema/engine_test.go @@ -31,6 +31,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "vitess.io/vitess/go/constants/sidecar" + "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/mysql/sqlerror" @@ -42,7 +44,6 @@ import ( "vitess.io/vitess/go/test/utils" "vitess.io/vitess/go/vt/dbconfigs" querypb "vitess.io/vitess/go/vt/proto/query" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool" "vitess.io/vitess/go/vt/vttablet/tabletserver/schema/schematest" @@ -1176,7 +1177,7 @@ func TestEngineReload(t *testing.T) { // Detecting view changes. // According to the database, v2, v3, v4, and v5 require updating. - db.AddQuery(fmt.Sprintf(detectViewChange, sidecardb.GetIdentifier()), sqltypes.MakeTestResult(sqltypes.MakeTestFields("table_name", "varchar"), + db.AddQuery(fmt.Sprintf(detectViewChange, sidecar.GetIdentifier()), sqltypes.MakeTestResult(sqltypes.MakeTestFields("table_name", "varchar"), "v2", "v3", "v4", diff --git a/go/vt/vttablet/tabletserver/schema/historian.go b/go/vt/vttablet/tabletserver/schema/historian.go index 3dacd53a48e..e40777c6fe5 100644 --- a/go/vt/vttablet/tabletserver/schema/historian.go +++ b/go/vt/vttablet/tabletserver/schema/historian.go @@ -22,12 +22,11 @@ import ( "sync" "time" + "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/log" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" - "vitess.io/vitess/go/vt/sidecardb" - "vitess.io/vitess/go/vt/vtgate/evalengine" "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool" "vitess.io/vitess/go/vt/vttablet/tabletserver/tabletenv" @@ -172,10 +171,10 @@ func (h *historian) loadFromDB(ctx context.Context) error { var tableData *sqltypes.Result if h.lastID == 0 && h.schemaMaxAgeSeconds > 0 { // only at vttablet start schemaMaxAge := time.Now().UTC().Add(time.Duration(-h.schemaMaxAgeSeconds) * time.Second) - tableData, err = conn.Exec(ctx, sqlparser.BuildParsedQuery(getInitialSchemaVersions, sidecardb.GetIdentifier(), + tableData, err = conn.Exec(ctx, sqlparser.BuildParsedQuery(getInitialSchemaVersions, sidecar.GetIdentifier(), schemaMaxAge.Unix()).Query, 10000, true) } else { - tableData, err = conn.Exec(ctx, sqlparser.BuildParsedQuery(getNextSchemaVersions, sidecardb.GetIdentifier(), + tableData, err = conn.Exec(ctx, sqlparser.BuildParsedQuery(getNextSchemaVersions, sidecar.GetIdentifier(), h.lastID).Query, 10000, true) } @@ -205,7 +204,7 @@ func (h *historian) loadFromDB(ctx context.Context) error { // readRow converts a row from the schema_version table to a trackedSchema func (h *historian) readRow(row []sqltypes.Value) (*trackedSchema, int64, error) { - id, _ := evalengine.ToInt64(row[0]) + id, _ := row[0].ToCastInt64() rowBytes, err := row[1].ToBytes() if err != nil { return nil, 0, err @@ -219,7 +218,7 @@ func (h *historian) readRow(row []sqltypes.Value) (*trackedSchema, int64, error) return nil, 0, err } ddl := string(rowBytes) - timeUpdated, err := evalengine.ToInt64(row[3]) + timeUpdated, err := row[3].ToCastInt64() if err != nil { return nil, 0, err } diff --git a/go/vt/vttablet/tabletserver/schema/tracker.go b/go/vt/vttablet/tabletserver/schema/tracker.go index ba297d26c18..9e036bb5139 100644 --- a/go/vt/vttablet/tabletserver/schema/tracker.go +++ b/go/vt/vttablet/tabletserver/schema/tracker.go @@ -23,9 +23,9 @@ import ( "sync" "time" + "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/mysql/replication" "vitess.io/vitess/go/vt/schema" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/sqltypes" @@ -171,7 +171,7 @@ func (tr *Tracker) isSchemaVersionTableEmpty(ctx context.Context) (bool, error) } defer conn.Recycle() result, err := conn.Exec(ctx, sqlparser.BuildParsedQuery("select id from %s.schema_version limit 1", - sidecardb.GetIdentifier()).Query, 1, false) + sidecar.GetIdentifier()).Query, 1, false) if err != nil { return false, err } @@ -232,7 +232,7 @@ func (tr *Tracker) saveCurrentSchemaToDb(ctx context.Context, gtid, ddl string, query := sqlparser.BuildParsedQuery("insert into %s.schema_version "+ "(pos, ddl, schemax, time_updated) "+ - "values (%s, %s, %s, %d)", sidecardb.GetIdentifier(), encodeString(gtid), + "values (%s, %s, %s, %d)", sidecar.GetIdentifier(), encodeString(gtid), encodeString(ddl), encodeString(string(blob)), timestamp).Query _, err = conn.Exec(ctx, query, 1, false) if err != nil { diff --git a/go/vt/vttablet/tabletserver/throttle/throttler.go b/go/vt/vttablet/tabletserver/throttle/throttler.go index d492472959f..c703bce8c51 100644 --- a/go/vt/vttablet/tabletserver/throttle/throttler.go +++ b/go/vt/vttablet/tabletserver/throttle/throttler.go @@ -24,6 +24,8 @@ import ( "github.com/patrickmn/go-cache" "github.com/spf13/pflag" + "vitess.io/vitess/go/constants/sidecar" + "vitess.io/vitess/go/textutil" "vitess.io/vitess/go/timer" "vitess.io/vitess/go/vt/log" @@ -31,7 +33,6 @@ import ( tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" topodatapb "vitess.io/vitess/go/vt/proto/topodata" "vitess.io/vitess/go/vt/servenv" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/srvtopo" "vitess.io/vitess/go/vt/topo" @@ -341,7 +342,7 @@ func (throttler *Throttler) WatchSrvKeyspaceCallback(srvks *topodatapb.SrvKeyspa func (throttler *Throttler) applyThrottlerConfig(ctx context.Context, throttlerConfig *topodatapb.ThrottlerConfig) { log.Infof("Throttler: applying topo config: %+v", throttlerConfig) if throttlerConfig.CustomQuery == "" { - throttler.metricsQuery.Store(sqlparser.BuildParsedQuery(defaultReplicationLagQuery, sidecardb.GetIdentifier()).Query) + throttler.metricsQuery.Store(sqlparser.BuildParsedQuery(defaultReplicationLagQuery, sidecar.GetIdentifier()).Query) } else { throttler.metricsQuery.Store(throttlerConfig.CustomQuery) } @@ -440,7 +441,7 @@ func (throttler *Throttler) Open() error { // The query needs to be dynamically built because the sidecar database name // is not known when the TabletServer is created, which in turn creates the // Throttler. - throttler.metricsQuery.Store(sqlparser.BuildParsedQuery(defaultReplicationLagQuery, sidecardb.GetIdentifier()).Query) // default + throttler.metricsQuery.Store(sqlparser.BuildParsedQuery(defaultReplicationLagQuery, sidecar.GetIdentifier()).Query) // default throttler.initConfig() throttler.pool.Open(throttler.env.Config().DB.AppWithDB(), throttler.env.Config().DB.DbaWithDB(), throttler.env.Config().DB.AppDebugWithDB()) atomic.StoreInt64(&throttler.isOpen, 1) diff --git a/go/vt/vttablet/tabletserver/twopc.go b/go/vt/vttablet/tabletserver/twopc.go index 11dea639d25..7784f7f1702 100644 --- a/go/vt/vttablet/tabletserver/twopc.go +++ b/go/vt/vttablet/tabletserver/twopc.go @@ -21,11 +21,9 @@ import ( "fmt" "time" - "vitess.io/vitess/go/vt/sidecardb" + "vitess.io/vitess/go/constants/sidecar" "vitess.io/vitess/go/vt/vttablet/tabletserver/tx" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/dbconnpool" @@ -88,7 +86,7 @@ type TwoPC struct { // NewTwoPC creates a TwoPC variable. func NewTwoPC(readPool *connpool.Pool) *TwoPC { tpc := &TwoPC{readPool: readPool} - dbname := sidecardb.GetIdentifier() + dbname := sidecar.GetIdentifier() tpc.insertRedoTx = sqlparser.BuildParsedQuery( "insert into %s.redo_state(dtid, state, time_created) values (%a, %a, %a)", dbname, ":dtid", ":state", ":time_created") @@ -228,12 +226,12 @@ func (tpc *TwoPC) ReadAllRedo(ctx context.Context) (prepared, failed []*tx.Prepa // Initialize the new element. // A failure in time parsing will show up as a very old time, // which is harmless. - tm, _ := evalengine.ToInt64(row[2]) + tm, _ := row[2].ToCastInt64() curTx = &tx.PreparedTx{ Dtid: dtid, Time: time.Unix(0, tm), } - st, err := evalengine.ToInt64(row[1]) + st, err := row[1].ToCastInt64() if err != nil { log.Errorf("Error parsing state for dtid %s: %v.", dtid, err) } @@ -270,7 +268,7 @@ func (tpc *TwoPC) CountUnresolvedRedo(ctx context.Context, unresolvedTime time.T if len(qr.Rows) < 1 { return 0, nil } - v, _ := evalengine.ToInt64(qr.Rows[0][0]) + v, _ := qr.Rows[0][0].ToCastInt64() return v, nil } @@ -357,7 +355,7 @@ func (tpc *TwoPC) ReadTransaction(ctx context.Context, dtid string) (*querypb.Tr return result, nil } result.Dtid = qr.Rows[0][0].ToString() - st, err := evalengine.ToInt64(qr.Rows[0][1]) + st, err := qr.Rows[0][1].ToCastInt64() if err != nil { return nil, vterrors.Wrapf(err, "error parsing state for dtid %s", dtid) } @@ -367,7 +365,7 @@ func (tpc *TwoPC) ReadTransaction(ctx context.Context, dtid string) (*querypb.Tr } // A failure in time parsing will show up as a very old time, // which is harmless. - tm, _ := evalengine.ToInt64(qr.Rows[0][2]) + tm, _ := qr.Rows[0][2].ToCastInt64() result.TimeCreated = tm qr, err = tpc.read(ctx, conn, tpc.readParticipants, bindVars) @@ -404,7 +402,7 @@ func (tpc *TwoPC) ReadAbandoned(ctx context.Context, abandonTime time.Time) (map } txs := make(map[string]time.Time, len(qr.Rows)) for _, row := range qr.Rows { - t, err := evalengine.ToInt64(row[1]) + t, err := row[1].ToCastInt64() if err != nil { return nil, err } @@ -434,8 +432,8 @@ func (tpc *TwoPC) ReadAllTransactions(ctx context.Context) ([]*tx.DistributedTx, // Initialize the new element. // A failure in time parsing will show up as a very old time, // which is harmless. - tm, _ := evalengine.ToInt64(row[2]) - st, err := evalengine.ToInt64(row[1]) + tm, _ := row[2].ToCastInt64() + st, err := row[1].ToCastInt64() // Just log on error and continue. The state will show up as UNKNOWN // on the display. if err != nil { diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go index d327be05394..275805f3ec5 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go +++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go @@ -41,7 +41,6 @@ import ( querypb "vitess.io/vitess/go/vt/proto/query" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" vtschema "vitess.io/vitess/go/vt/schema" - "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet" @@ -672,7 +671,7 @@ func (vs *vstreamer) buildJournalPlan(id uint64, tm *mysql.TableMap) error { } defer conn.Close() qr, err := conn.ExecuteFetch(sqlparser.BuildParsedQuery("select * from %s.resharding_journal where 1 != 1", - sidecardb.GetIdentifier()).Query, 1, true) + sidecar.GetIdentifier()).Query, 1, true) if err != nil { return err } @@ -681,7 +680,7 @@ func (vs *vstreamer) buildJournalPlan(id uint64, tm *mysql.TableMap) error { return fmt.Errorf("cannot determine table columns for %s: event has %v, schema has %v", tm.Name, tm.Types, fields) } table := &Table{ - Name: fmt.Sprintf("%s.resharding_journal", sidecardb.GetIdentifier()), + Name: fmt.Sprintf("%s.resharding_journal", sidecar.GetIdentifier()), Fields: fields[:len(tm.Types)], } // Build a normal table plan, which means, return all rows @@ -706,7 +705,7 @@ func (vs *vstreamer) buildVersionPlan(id uint64, tm *mysql.TableMap) error { } defer conn.Close() qr, err := conn.ExecuteFetch(sqlparser.BuildParsedQuery("select * from %s.schema_version where 1 != 1", - sidecardb.GetIdentifier()).Query, 1, true) + sidecar.GetIdentifier()).Query, 1, true) if err != nil { return err } @@ -715,7 +714,7 @@ func (vs *vstreamer) buildVersionPlan(id uint64, tm *mysql.TableMap) error { return fmt.Errorf("cannot determine table columns for %s: event has %v, schema has %v", tm.Name, tm.Types, fields) } table := &Table{ - Name: fmt.Sprintf("%s.schema_version", sidecardb.GetIdentifier()), + Name: fmt.Sprintf("%s.schema_version", sidecar.GetIdentifier()), Fields: fields[:len(tm.Types)], } // Build a normal table plan, which means, return all rows diff --git a/go/vt/vttest/local_cluster.go b/go/vt/vttest/local_cluster.go index 9a4466bce29..fc9a455ba6f 100644 --- a/go/vt/vttest/local_cluster.go +++ b/go/vt/vttest/local_cluster.go @@ -36,6 +36,8 @@ import ( "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" + "vitess.io/vitess/go/constants/sidecar" + "vitess.io/vitess/go/vt/sidecardb" "vitess.io/vitess/go/mysql" @@ -528,7 +530,7 @@ func (db *LocalCluster) loadSchema(shouldRunDatabaseMigrations bool) error { func (db *LocalCluster) createVTSchema() error { var sidecardbExec sidecardb.Exec = func(ctx context.Context, query string, maxRows int, useDB bool) (*sqltypes.Result, error) { if useDB { - if err := db.Execute([]string{fmt.Sprintf("use %s", sidecardb.GetIdentifier())}, ""); err != nil { + if err := db.Execute([]string{fmt.Sprintf("use %s", sidecar.GetIdentifier())}, ""); err != nil { return nil, err } } diff --git a/go/vt/wrangler/materializer.go b/go/vt/wrangler/materializer.go index de0b0225144..2edc06aa607 100644 --- a/go/vt/wrangler/materializer.go +++ b/go/vt/wrangler/materializer.go @@ -46,7 +46,6 @@ import ( "vitess.io/vitess/go/vt/vtctl/schematools" "vitess.io/vitess/go/vt/vtctl/workflow" "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/vt/vtgate/evalengine" "vitess.io/vitess/go/vt/vtgate/vindexes" "vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication" @@ -816,7 +815,7 @@ func (wr *Wrangler) ExternalizeVindex(ctx context.Context, qualifiedVindexName s } qr := sqltypes.Proto3ToResult(p3qr) for _, row := range qr.Rows { - id, err := evalengine.ToInt64(row[0]) + id, err := row[0].ToCastInt64() if err != nil { return err } @@ -893,7 +892,7 @@ func (wr *Wrangler) collectTargetStreams(ctx context.Context, mz *materializer) } qr := sqltypes.Proto3ToResult(qrproto) for i := 0; i < len(qr.Rows); i++ { - id, err = evalengine.ToInt64(qr.Rows[i][0]) + id, err = qr.Rows[i][0].ToCastInt64() if err != nil { return err } diff --git a/go/vt/wrangler/workflow.go b/go/vt/wrangler/workflow.go index 8e2481bac8f..f2b352691bd 100644 --- a/go/vt/wrangler/workflow.go +++ b/go/vt/wrangler/workflow.go @@ -12,14 +12,12 @@ import ( "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/log" - "vitess.io/vitess/go/vt/topo" - "vitess.io/vitess/go/vt/topotools" - "vitess.io/vitess/go/vt/vtctl/workflow" - "vitess.io/vitess/go/vt/vtgate/evalengine" - binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" topodatapb "vitess.io/vitess/go/vt/proto/topodata" + "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/topotools" + "vitess.io/vitess/go/vt/vtctl/workflow" ) // VReplicationWorkflowType specifies whether workflow is MoveTables or Reshard @@ -637,11 +635,11 @@ func (vrw *VReplicationWorkflow) GetCopyProgress() (*CopyProgress, error) { qr := sqltypes.Proto3ToResult(p3qr) for i := 0; i < len(qr.Rows); i++ { table := qr.Rows[i][0].ToString() - rowCount, err := evalengine.ToInt64(qr.Rows[i][1]) + rowCount, err := qr.Rows[i][1].ToCastInt64() if err != nil { return err } - tableSize, err := evalengine.ToInt64(qr.Rows[i][2]) + tableSize, err := qr.Rows[i][2].ToCastInt64() if err != nil { return err } From f1a1ef6458777ffd5c77faf59f2a8e84470a2f12 Mon Sep 17 00:00:00 2001 From: Dirkjan Bussink Date: Fri, 4 Aug 2023 13:16:53 +0200 Subject: [PATCH 3/3] Fix licenses Signed-off-by: Dirkjan Bussink --- go/constants/sidecar/queries.go | 16 ++++++++++++++++ go/mysql/replication/state.go | 16 ++++++++++++++++ go/mysql/sqlerror/constants.go | 16 ++++++++++++++++ go/sqltypes/cast.go | 16 ++++++++++++++++ go/sqltypes/cast_test.go | 16 ++++++++++++++++ go/vt/sqlparser/literal.go | 16 ++++++++++++++++ 6 files changed, 96 insertions(+) diff --git a/go/constants/sidecar/queries.go b/go/constants/sidecar/queries.go index 6cfa171ec8c..97fa30ebecc 100644 --- a/go/constants/sidecar/queries.go +++ b/go/constants/sidecar/queries.go @@ -1,3 +1,19 @@ +/* +Copyright 2023 The Vitess Authors. + +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 sidecar import "vitess.io/vitess/go/vt/sqlparser" diff --git a/go/mysql/replication/state.go b/go/mysql/replication/state.go index 15f94d80338..d08965a6fb6 100644 --- a/go/mysql/replication/state.go +++ b/go/mysql/replication/state.go @@ -1,3 +1,19 @@ +/* +Copyright 2023 The Vitess Authors. + +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 replication import "strings" diff --git a/go/mysql/sqlerror/constants.go b/go/mysql/sqlerror/constants.go index 7d229ef67f6..0074e904e4a 100644 --- a/go/mysql/sqlerror/constants.go +++ b/go/mysql/sqlerror/constants.go @@ -1,3 +1,19 @@ +/* +Copyright 2023 The Vitess Authors. + +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 sqlerror import ( diff --git a/go/sqltypes/cast.go b/go/sqltypes/cast.go index 43a94b2dfdb..e97e47ea17c 100644 --- a/go/sqltypes/cast.go +++ b/go/sqltypes/cast.go @@ -1,3 +1,19 @@ +/* +Copyright 2023 The Vitess Authors. + +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 sqltypes import ( diff --git a/go/sqltypes/cast_test.go b/go/sqltypes/cast_test.go index 3dcf6175279..f2a7d24e88a 100644 --- a/go/sqltypes/cast_test.go +++ b/go/sqltypes/cast_test.go @@ -1,3 +1,19 @@ +/* +Copyright 2023 The Vitess Authors. + +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 sqltypes import ( diff --git a/go/vt/sqlparser/literal.go b/go/vt/sqlparser/literal.go index 37816f8c654..24613ff6e05 100644 --- a/go/vt/sqlparser/literal.go +++ b/go/vt/sqlparser/literal.go @@ -1,3 +1,19 @@ +/* +Copyright 2023 The Vitess Authors. + +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 sqlparser import (