Repository: vitessio/vitess
Pull request #6638 (2020-08-27 15:48:47)

Rewrite information_schema queries to use mysql db name instead of keyspace name


Patch:
diff --git a/doc/releasenotes/7_0_1_release_notes.md b/doc/releasenotes/7_0_1_release_notes.md
deleted file mode 100644
index 5b0d3f30a6..0000000000
--- a/doc/releasenotes/7_0_1_release_notes.md
+++ /dev/null
@@ -1,19 +0,0 @@
-This update fixes several regressions that were deemed significant enough to be backported to the release branch.
-In addition, the experimental feature to set system variables is now behind a flag that disables it by default.
-
-## Configuration Changes
-* Vtgate: added flag enable_system_settings to enable passthrough system settings, defaults to false #6562
-
-## Bugs Fixed
-* Vreplication: Materialize should only get schema from source tablets if target is missing tables #6623
-* Vtctld UI: mysql port is not displayed in tablet list #6597 #6600
-* Vtgate: transaction killer was closing reserved connection after the specified time. Only idle connections should be closed. Idle transactions should be rolled back. #6583
-* Vtcompose: docker-compose example was broken by tabletmanager changes #6587
-* Vreplication: tablet_picker should respect canceled context. Also, keep trying to find a tablet until context expires. #6567
-* Vtgate: vindex update/delete by destination #6541 #6572
-* Vtgate: some usages of EXPLAIN were broken #6574 #6581
-* Vtgate: handle multiple settings in single SET statement #6504
-* Vtgate: cleanup shard session for reserved connection on failure #6563
-* Vtgate: if executing DDL on reserved connection, start transaction if needed #6555
-* Vtgate: make sure lookup vindexes use same transaction if one is open #6505
-* Healthcheck: add diagnostic logging, do not add tablet if it is shutting down #6512 
diff --git a/go/sync2/semaphore.go b/go/sync2/semaphore.go
index c0d1fd2ce4..536399824c 100644
--- a/go/sync2/semaphore.go
+++ b/go/sync2/semaphore.go
@@ -21,7 +21,6 @@ package sync2
 // cases, you just want a familiar API.
 
 import (
-	"context"
 	"time"
 )
 
@@ -62,17 +61,6 @@ func (sem *Semaphore) Acquire() bool {
 	}
 }
 
-// AcquireContext returns true on successful acquisition, and
-// false on context expiry. Timeout is ignored.
-func (sem *Semaphore) AcquireContext(ctx context.Context) bool {
-	select {
-	case <-sem.slots:
-		return true
-	case <-ctx.Done():
-		return false
-	}
-}
-
 // TryAcquire acquires a semaphore if it's immediately available.
 // It returns false otherwise.
 func (sem *Semaphore) TryAcquire() bool {
diff --git a/go/vt/binlog/binlogplayer/binlog_player.go b/go/vt/binlog/binlogplayer/binlog_player.go
index 892eb97a9e..e231e503c7 100644
--- a/go/vt/binlog/binlogplayer/binlog_player.go
+++ b/go/vt/binlog/binlogplayer/binlog_player.go
@@ -531,7 +531,6 @@ func CreateVReplicationTable() []string {
 // AlterVReplicationTable adds new columns to vreplication table
 var AlterVReplicationTable = []string{
 	"ALTER TABLE _vt.vreplication ADD COLUMN db_name VARBINARY(255) NOT NULL",
-	"ALTER TABLE _vt.vreplication MODIFY source BLOB NOT NULL",
 }
 
 // VRSettings contains the settings of a vreplication table.
diff --git a/go/vt/servenv/grpc_server.go b/go/vt/servenv/grpc_server.go
index 842f583bbd..1905d89bf0 100644
--- a/go/vt/servenv/grpc_server.go
+++ b/go/vt/servenv/grpc_server.go
@@ -86,7 +86,7 @@ var (
 
 	// EnforcementPolicy MinTime that sets the keepalive enforcement policy on the server.
 	// This is the minimum amount of time a client should wait before sending a keepalive ping.
-	GRPCKeepAliveEnforcementPolicyMinTime = flag.Duration("grpc_server_keepalive_enforcement_policy_min_time", 10*time.Second, "gRPC server minimum keepalive time")
+	GRPCKeepAliveEnforcementPolicyMinTime = flag.Duration("grpc_server_keepalive_enforcement_policy_min_time", 5*time.Minute, "gRPC server minimum keepalive time")
 
 	// EnforcementPolicy PermitWithoutStream - If true, server allows keepalive pings
 	// even when there are no active streams (RPCs). If false, and client sends ping when
diff --git a/go/vt/sqlparser/ast_funcs.go b/go/vt/sqlparser/ast_funcs.go
index 2e606d3814..cd966f8242 100644
--- a/go/vt/sqlparser/ast_funcs.go
+++ b/go/vt/sqlparser/ast_funcs.go
@@ -508,13 +508,6 @@ func NewColIdent(str string) ColIdent {
 	}
 }
 
-// NewColName makes a new ColName
-func NewColName(str string) *ColName {
-	return &ColName{
-		Name: NewColIdent(str),
-	}
-}
-
 //NewSelect is used to create a select statement
 func NewSelect(comments Comments, exprs SelectExprs, selectOptions []string, from TableExprs, where *Where, groupBy GroupBy, having *Where) *Select {
 	var cache *bool
diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go
index cd83cf4221..4f41371777 100644
--- a/go/vt/vtctl/vtctl.go
+++ b/go/vt/vtctl/vtctl.go
@@ -328,7 +328,7 @@ var commands = []commandGroup{
 				`Externalize a backfilled vindex.`},
 			{"Materialize", commandMaterialize,
 				`<json_spec>, example : '{"workflow": "aaa", "source_keyspace": "source", "target_keyspace": "target", "table_settings": [{"target_table": "customer", "source_expression": "select * from customer", "create_ddl": "copy"}]}'`,
-				"Performs materialization based on the json spec. Is used directly to form VReplication rules, with an optional step to copy table structure/DDL."},
+				"Performs materialization based on the json spec."},
 			{"SplitClone", commandSplitClone,
 				"<keyspace> <from_shards> <to_shards>",
 				"Start the SplitClone process to perform horizontal resharding. Example: SplitClone ks '0' '-80,80-'"},
@@ -478,7 +478,7 @@ var commands = []commandGroup{
 		"Workflow", []command{
 			{"Workflow", commandWorkflow,
 				"<ks.workflow> <action> --dry-run",
-				"Start/Stop/Delete/Show/ListAll Workflow on all target tablets in workflow. Example: Workflow merchant.morders Start",
+				"Start/Stop/Delete/List/ListAll Workflow on all target tablets in workflow. Example: Workflow merchant.morders Start",
 			},
 		},
 	},
@@ -2950,10 +2950,6 @@ func commandWorkflow(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.
 	}
 	keyspace := subFlags.Arg(0)
 	action := strings.ToLower(subFlags.Arg(1))
-	// Note: List is deprecated and replaced by show.
-	if action == "list" {
-		action = "show"
-	}
 	var workflow string
 	var err error
 	if action != "listall" {
@@ -2971,7 +2967,7 @@ func commandWorkflow(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.
 	if err != nil {
 		return err
 	}
-	if action == "show" || action == "listall" {
+	if action == "list" || action == "listall" {
 		return nil
 	}
 	if len(results) == 0 {
diff --git a/go/vt/vtgate/engine/route.go b/go/vt/vtgate/engine/route.go
index 5c4c49227c..962665a6a2 100644
--- a/go/vt/vtgate/engine/route.go
+++ b/go/vt/vtgate/engine/route.go
@@ -90,6 +90,10 @@ type Route struct {
 	// ScatterErrorsAsWarnings is true if results should be returned even if some shards have an error
 	ScatterErrorsAsWarnings bool
 
+	// SysTableKeyspaceExpr contains the schema expressions
+	// It will be used to route the system table queries to a keyspace.
+	SysTableKeyspaceExpr []evalengine.Expr
+
 	// Route does not take inputs
 	noInputs
 
@@ -228,7 +232,9 @@ func (route *Route) execute(vcursor VCursor, bindVars map[string]*querypb.BindVa
 	var bvs []map[string]*querypb.BindVariable
 	var err error
 	switch route.Opcode {
-	case SelectUnsharded, SelectNext, SelectDBA, SelectReference:
+	case SelectDBA:
+		rss, bvs, err = route.paramsSystemQuery(vcursor, bindVars)
+	case SelectUnsharded, SelectNext, SelectReference:
 		rss, bvs, err = route.paramsAnyShard(vcursor, bindVars)
 	case SelectScatter:
 		rss, bvs, err = route.paramsAllShards(vcursor, bindVars)
@@ -289,7 +295,9 @@ func (route *Route) StreamExecute(vcursor VCursor, bindVars map[string]*querypb.
 		defer cancel()
 	}
 	switch route.Opcode {
-	case SelectUnsharded, SelectNext, SelectDBA, SelectReference:
+	case SelectDBA:
+		rss, bvs, err = route.paramsSystemQuery(vcursor, bindVars)
+	case SelectUnsharded, SelectNext, SelectReference:
 		rss, bvs, err = route.paramsAnyShard(vcursor, bindVars)
 	case SelectScatter:
 		rss, bvs, err = route.paramsAllShards(vcursor, bindVars)
@@ -369,6 +377,36 @@ func (route *Route) paramsAllShards(vcursor VCursor, bindVars map[string]*queryp
 	return rss, multiBindVars, nil
 }
 
+func (route *Route) paramsSystemQuery(vcursor VCursor, bindVars map[string]*querypb.BindVariable) ([]*srvtopo.ResolvedShard, []map[string]*querypb.BindVariable, error) {
+	env := evalengine.ExpressionEnv{
+		BindVars: bindVars,
+		Row:      []sqltypes.Value{},
+	}
+
+	var keyspace string
+	for _, expr := range route.SysTableKeyspaceExpr {
+		result, err := expr.Evaluate(env)
+		if err != nil {
+			return nil, nil, err
+		}
+		if keyspace == "" {
+			keyspace = result.Value().ToString()
+		} else if other := result.Value().ToString(); keyspace != other {
+			return nil, nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "can't use more than one keyspace per system table query - found both '%s' and '%s'", keyspace, other)
+		}
+	}
+
+	if keyspace == "" {
+		keyspace = route.Keyspace.Name
+	}
+
+	destinations, _, err := vcursor.ResolveDestinations(keyspace, nil, []key.Destination{key.DestinationAnyShard{}})
+	if err != nil {
+		return nil, nil, vterrors.Wrapf(err, "failed to find information about keyspace `%s`", keyspace)
+	}
+	return destinations, []map[string]*querypb.BindVariable{bindVars}, nil
+}
+
 func (route *Route) paramsAnyShard(vcursor VCursor, bindVars map[string]*querypb.BindVariable) ([]*srvtopo.ResolvedShard, []map[string]*querypb.BindVariable, error) {
 	rss, _, err := vcursor.ResolveDestinations(route.Keyspace.Name, nil, []key.Destination{key.DestinationAnyShard{}})
 	if err != nil {
@@ -577,6 +615,13 @@ func (route *Route) description() PrimitiveDescription {
 	if len(route.Values) > 0 {
 		other["Values"] = route.Values
 	}
+	if len(route.SysTableKeyspaceExpr) > 0 {
+		var exprs []string
+		for _, expr := range route.SysTableKeyspaceExpr {
+			exprs = append(exprs, expr.String())
+		}
+		other["SysTableKeyspaceExpr"] = exprs
+	}
 
 	return PrimitiveDescription{
 		OperatorType:      "Route",
diff --git a/go/vt/vtgate/planbuilder/from.go b/go/vt/vtgate/planbuilder/from.go
index 642e22de8e..467e83ac75 100644
--- a/go/vt/vtgate/planbuilder/from.go
+++ b/go/vt/vtgate/planbuilder/from.go
@@ -173,7 +173,7 @@ func (pb *primitiveBuilder) buildTablePrimitive(tableExpr *sqlparser.AliasedTabl
 	sel := &sqlparser.Select{From: sqlparser.TableExprs([]sqlparser.TableExpr{tableExpr})}
 
 	if systemTable(tableName.Qualifier.String()) {
-		ks, err := pb.vschema.DefaultKeyspace()
+		ks, err := pb.vschema.AnyKeyspace()
 		if err != nil {
 			return err
 		}
@@ -182,7 +182,7 @@ func (pb *primitiveBuilder) buildTablePrimitive(tableExpr *sqlparser.AliasedTabl
 		pb.bldr, pb.st = rb, st
 		// Add the table to symtab
 		return st.AddTable(&table{
-			alias:  tableName,
+			alias:  alias,
 			origin: rb,
 		})
 	}
diff --git a/go/vt/vtgate/planbuilder/select.go b/go/vt/vtgate/planbuilder/select.go
index d33596d025..d7764a2764 100644
--- a/go/vt/vtgate/planbuilder/select.go
+++ b/go/vt/vtgate/planbuilder/select.go
@@ -22,7 +22,7 @@ import (
 
 	"vitess.io/vitess/go/vt/key"
 
-	"vitess.io/vitess/go/vt/proto/vtrpc"
+	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
 	"vitess.io/vitess/go/vt/vterrors"
 
 	"vitess.io/vitess/go/vt/vtgate/evalengine"
@@ -92,11 +92,11 @@ func (pb *primitiveBuilder) processSelect(sel *sqlparser.Select, outer *symtab)
 	// Check and error if there is any locking function present in select expression.
 	for _, expr := range sel.SelectExprs {
 		if aExpr, ok := expr.(*sqlparser.AliasedExpr); ok && sqlparser.IsLockingFunc(aExpr.Expr) {
-			return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "%v allowed only with dual", sqlparser.String(aExpr))
+			return vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "%v allowed only with dual", sqlparser.String(aExpr))
 		}
 	}
 	if sel.SQLCalcFoundRows && sel.Limit != nil {
-		return vterrors.Errorf(vtrpc.Code_UNIMPLEMENTED, "sql_calc_found_rows not yet fully supported")
+		return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "sql_calc_found_rows not yet fully supported")
 	}
 
 	if err := pb.processTableExprs(sel.From); err != nil {
@@ -215,6 +215,18 @@ func (pb *primitiveBuilder) pushFilter(in sqlparser.Expr, whereType string) erro
 		if err != nil {
 			return err
 		}
+		rut, isRoute := origin.(*route)
+		if isRoute && rut.eroute.Opcode == engine.SelectDBA {
+			r := &rewriter{}
+			sqlparser.Rewrite(expr, r.rewriteTableSchema, nil)
+			if r.err == sqlparser.ErrExprNotSupported {
+				return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "comparison with `table_schema` column not supported")
+			}
+			if r.err != nil {
+				return r.err
+			}
+			rut.eroute.SysTableKeyspaceExpr = append(rut.eroute.SysTableKeyspaceExpr, r.tableNameExpressions...)
+		}
 		// The returned expression may be complex. Resplit before pushing.
 		for _, subexpr := range splitAndExpression(nil, expr) {
 			if err := pb.bldr.PushFilter(pb, subexpr, whereType, origin); err != nil {
@@ -226,6 +238,42 @@ func (pb *primitiveBuilder) pushFilter(in sqlparser.Expr, whereType string) erro
 	return nil
 }
 
+type rewriter struct {
+	tableNameExpressions []evalengine.Expr
+	err                  error
+}
+
+func (r *rewriter) rewriteTableSchema(cursor *sqlparser.Cursor) bool {
+	switch node := cursor.Node().(type) {
+	case *sqlparser.ColName:
+		if node.Name.EqualString("table_schema") {
+			switch parent := cursor.Parent().(type) {
+			case *sqlparser.ComparisonExpr:
+				if parent.Operator == sqlparser.EqualStr && shouldRewrite(parent.Right) {
+
+					evalExpr, err := sqlparser.Convert(parent.Right)
+					if err != nil {
+						r.err = err
+						return false
+					}
+					r.tableNameExpressions = append(r.tableNameExpressions, evalExpr)
+					parent.Right = sqlparser.NewValArg([]byte(":__vtschemaname"))
+				}
+			}
+		}
+	}
+	return true
+}
+
+func shouldRewrite(e sqlparser.Expr) bool {
+	switch node := e.(type) {
+	case *sqlparser.FuncExpr:
+		// we should not rewrite database() calls against information_schema
+		return !(node.Name.EqualString("database") || node.Name.EqualString("schema"))
+	}
+	return true
+}
+
 // reorderBySubquery reorders the filters by pushing subqueries
 // to the end. This allows the non-subquery filters to be
 // pushed first because they can potentially improve the routing
diff --git a/go/vt/vttablet/tabletmanager/replmanager.go b/go/vt/vttablet/tabletmanager/replmanager.go
index a7790e31a4..c80f3c3de8 100644
--- a/go/vt/vttablet/tabletmanager/replmanager.go
+++ b/go/vt/vttablet/tabletmanager/replmanager.go
@@ -91,8 +91,8 @@ func (rm *replManager) SetTabletType(tabletType topodatapb.TabletType) {
 
 func (rm *replManager) check() {
 	// We need to obtain the action lock if we're going to fix
-	// replication, but only if the lock is available to take.
-	if !rm.tm.tryLock() {
+	// replication
+	if err := rm.tm.lock(rm.ctx); err != nil {
 		return
 	}
 	defer rm.tm.unlock()
diff --git a/go/vt/vttablet/tabletmanager/restore.go b/go/vt/vttablet/tabletmanager/restore.go
index 0cbd401227..c35c5a529c 100644
--- a/go/vt/vttablet/tabletmanager/restore.go
+++ b/go/vt/vttablet/tabletmanager/restore.go
@@ -274,14 +274,14 @@ func (tm *TabletManager) getGTIDFromTimestamp(ctx context.Context, pos mysql.Pos
 						return err
 					}
 
-					if event.Timestamp >= restoreTime {
-						afterPos = event.Gtid
-						gtidsChan <- []string{event.Gtid, beforePos}
+					if eventPos.AtLeast(lastPos) {
+						gtidsChan <- []string{"", beforePos}
 						break
 					}
 
-					if eventPos.AtLeast(lastPos) {
-						gtidsChan <- []string{"", beforePos}
+					if event.Timestamp >= restoreTime {
+						afterPos = event.Gtid
+						gtidsChan <- []string{event.Gtid, beforePos}
 						break
 					}
 					beforePos = event.Gtid
diff --git a/go/vt/vttablet/tabletmanager/rpc_server.go b/go/vt/vttablet/tabletmanager/rpc_server.go
index 9420ca9824..d451fc778c 100644
--- a/go/vt/vttablet/tabletmanager/rpc_server.go
+++ b/go/vt/vttablet/tabletmanager/rpc_server.go
@@ -34,23 +34,28 @@ import (
 // Utility functions for RPC service
 //
 
-// lock is used at the beginning of an RPC call, to acquire the
-// action semaphore. It returns ctx.Err() if the context expires.
+// lock is used at the beginning of an RPC call, to lock the
+// action mutex. It returns ctx.Err() if <-ctx.Done() after the lock.
 func (tm *TabletManager) lock(ctx context.Context) error {
-	if tm.actionSema.AcquireContext(ctx) {
+	tm.actionMutex.Lock()
+	tm.actionMutexLocked = true
+
+	// After we take the lock (which could take a long time), we
+	// check the client is still here.
+	select {
+	case <-ctx.Done():
+		tm.actionMutexLocked = false
+		tm.actionMutex.Unlock()
+		return ctx.Err()
+	default:
 		return nil
 	}
-	return ctx.Err()
-}
-
-// tryLock will return immediately, true on success and false on failure.
-func (tm *TabletManager) tryLock() bool {
-	return tm.actionSema.TryAcquire()
 }
 
 // unlock is the symmetrical action to lock.
 func (tm *TabletManager) unlock() {
-	tm.actionSema.Release()
+	tm.actionMutexLocked = false
+	tm.actionMutex.Unlock()
 }
 
 // HandleRPCPanic is part of the RPCTM interface.
diff --git a/go/vt/vttablet/tabletmanager/tm_init.go b/go/vt/vttablet/tabletmanager/tm_init.go
index 6b247604ba..c06161f97b 100644
--- a/go/vt/vttablet/tabletmanager/tm_init.go
+++ b/go/vt/vttablet/tabletmanager/tm_init.go
@@ -25,10 +25,10 @@ topology server. Only 'vtctl DeleteTablet'
 should be run by other processes, everything else should ask
 the tablet server to make the change.
 
-Most RPC calls obtain the actionSema, except the easy read-only ones.
+Most RPC calls lock the actionMutex, except the easy read-only ones.
 RPC calls that change the tablet record will also call updateState.
 
-See rpc_server.go for all cases, and which actions take the actionSema,
+See rpc_server.go for all cases, and which actions take the actionMutex,
 and which run changeCallback.
 */
 package tabletmanager
@@ -42,7 +42,6 @@ import (
 	"time"
 
 	"vitess.io/vitess/go/flagutil"
-	"vitess.io/vitess/go/sync2"
 	"vitess.io/vitess/go/vt/vterrors"
 
 	"golang.org/x/net/context"
@@ -141,11 +140,17 @@ type TabletManager struct {
 	// when we transition back from something like MASTER.
 	baseTabletType topodatapb.TabletType
 
-	// actionSema is there to run only one action at a time.
-	// This semaphore can be held for long periods of time (hours),
-	// like in the case of a restore. This semaphore must be obtained
+	// actionMutex is there to run only one action at a time.
+	// This mutex can be held for long periods of time (hours),
+	// like in the case of a restore. This mutex must be obtained
 	// first before other mutexes.
-	actionSema *sync2.Semaphore
+	actionMutex sync.Mutex
+
+	// actionMutexLocked is set to true after we acquire actionMutex,
+	// and reset to false when we release it.
+	// It is meant as a sanity check to make sure the methods that need
+	// to have the actionMutex have it.
+	actionMutexLocked bool
 
 	// orc is an optional client for Orchestrator HTTP API calls.
 	// If this is nil, those calls will be skipped.
@@ -233,7 +238,6 @@ func (tm *TabletManager) Start(tablet *topodatapb.Tablet, healthCheckInterval ti
 	tm.replManager = newReplManager(tm.BatchCtx, tm, healthCheckInterval)
 	tm.tabletAlias = tablet.Alias
 	tm.tmState = newTMState(tm, tablet)
-	tm.actionSema = sync2.NewSemaphore(1, 0)
 
 	demoteType, err := topoproto.ParseTabletType(*demoteMasterType)
 	if err != nil {
@@ -455,7 +459,6 @@ func (tm *TabletManager) checkMastership(ctx context.Context, si *topo.ShardInfo
 		case topo.IsErrType(err, topo.NoNode):
 			// There's no existing tablet record, so we can assume
 			// no one has left us a message to step down.
-			log.Infof("Shard master alias matches, but there is no existing tablet record. Switching to master with 'Now' as time")
 			tm.tmState.UpdateTablet(func(tablet *topodatapb.Tablet) {
 				tablet.Type = topodatapb.TabletType_MASTER
 				// Update the master term start time (current value is 0) because we
@@ -465,19 +468,12 @@ func (tm *TabletManager) checkMastership(ctx context.Context, si *topo.ShardInfo
 			})
 		case err == nil:
 			if oldTablet.Type == topodatapb.TabletType_MASTER {
-				log.Infof("Shard master alias matches, and existing tablet agrees. Switching to master with tablet's master term start time: %v", oldTablet.MasterTermStartTime)
 				// We're marked as master in the shard record,
 				// and our existing tablet record agrees.
 				tm.tmState.UpdateTablet(func(tablet *topodatapb.Tablet) {
 					tablet.Type = topodatapb.TabletType_MASTER
 					tablet.MasterTermStartTime = oldTablet.MasterTermStartTime
 				})
-			} else {
-				log.Warningf("Shard master alias matches, but existing tablet is not master. Switching to master with the shard's master term start time: %v", oldTablet.MasterTermStartTime)
-				tm.tmState.UpdateTablet(func(tablet *topodatapb.Tablet) {
-					tablet.Type = topodatapb.TabletType_MASTER
-					tablet.MasterTermStartTime = si.MasterTermStartTime
-				})
 			}
 		default:
 			return vterrors.Wrap(err, "InitTablet failed to read existing tablet record")
@@ -494,13 +490,10 @@ func (tm *TabletManager) checkMastership(ctx context.Context, si *topo.ShardInfo
 				oldMasterTermStartTime := oldTablet.GetMasterTermStartTime()
 				currentShardTime := si.GetMasterTermStartTime()
 				if oldMasterTermStartTime.After(currentShardTime) {
-					log.Infof("Shard master alias does not match, but the tablet's master term start time is newer. Switching to master with tablet's master term start time: %v", oldTablet.MasterTermStartTime)
 					tm.tmState.UpdateTablet(func(tablet *topodatapb.Tablet) {
 						tablet.Type = topodatapb.TabletType_MASTER
 						tablet.MasterTermStartTime = oldTablet.MasterTermStartTime
 					})
-				} else {
-					log.Infof("Existing tablet type is master, but the shard record has a different master with a newer timestamp. Remaining a replica")
 				}
 			}
 		default:
diff --git a/go/vt/vttablet/tabletmanager/tm_state.go b/go/vt/vttablet/tabletmanager/tm_state.go
index 86ca17fced..a18fc11885 100644
--- a/go/vt/vttablet/tabletmanager/tm_state.go
+++ b/go/vt/vttablet/tabletmanager/tm_state.go
@@ -49,7 +49,7 @@ type tmState struct {
 	// while changing the state of the system to match these values.
 	// This can be held for many seconds while tmState connects to
 	// external components to change their state.
-	// Obtaining tm.actionSema before calling a tmState function is
+	// Obtaining tm.actionMutex before calling a tmState function is
 	// not required.
 	// Because mu can be held for long, we publish the current state
 	// of these variables into displayState, which can be accessed
diff --git a/go/vt/vttablet/tabletserver/planbuilder/builder.go b/go/vt/vttablet/tabletserver/planbuilder/builder.go
index 54eb4c1165..abd09d7d98 100644
--- a/go/vt/vttablet/tabletserver/planbuilder/builder.go
+++ b/go/vt/vttablet/tabletserver/planbuilder/builder.go
@@ -17,8 +17,6 @@ limitations under the License.
 package planbuilder
 
 import (
-	"strings"
-
 	"vitess.io/vitess/go/vt/sqlparser"
 	"vitess.io/vitess/go/vt/vterrors"
 	"vitess.io/vitess/go/vt/vttablet/tabletserver/schema"
@@ -127,25 +125,6 @@ func analyzeInsert(ins *sqlparser.Insert, tables map[string]*schema.Table) (plan
 	return plan, nil
 }
 
-func analyzeShowTables(show *sqlparser.Show, dbName string) {
-	// rewrite WHERE clause if it exists
-	// `where Tables_in_Keyspace` => `where Tables_in_DbName`
-	if show.ShowTablesOpt != nil && show.ShowTablesOpt.Filter != nil {
-		filter := show.ShowTablesOpt.Filter.Filter
-		if filter != nil {
-			sqlparser.Rewrite(filter, func(cursor *sqlparser.Cursor) bool {
-				switch n := cursor.Node().(type) {
-				case *sqlparser.ColName:
-					if n.Qualifier.IsEmpty() && strings.HasPrefix(n.Name.Lowered(), "tables_in_") {
-						cursor.Replace(sqlparser.NewColName("Tables_in_" + dbName))
-					}
-				}
-				return true
-			}, nil)
-		}
-	}
-}
-
 func analyzeSet(set *sqlparser.Set) (plan *Plan) {
 	return &Plan{
 		PlanID:    PlanSet,
diff --git a/go/vt/vttablet/tabletserver/planbuilder/plan.go b/go/vt/vttablet/tabletserver/planbuilder/plan.go
index 3c96679188..8f1285a97d 100644
--- a/go/vt/vttablet/tabletserver/planbuilder/plan.go
+++ b/go/vt/vttablet/tabletserver/planbuilder/plan.go
@@ -64,12 +64,11 @@ const (
 	PlanSavepoint
 	PlanRelease
 	PlanSRollback
-	PlanShowTables
 	NumPlans
 )
 
 // Must exactly match order of plan constants.
-var planName = []string{
+var planName = [NumPlans]string{
 	"Select",
 	"SelectLock",
 	"Nextval",
@@ -89,7 +88,6 @@ var planName = []string{
 	"Savepoint",
 	"Release",
 	"RollbackSavepoint",
-	"ShowTables",
 }
 
 func (pt PlanType) String() string {
@@ -153,7 +151,7 @@ func (plan *Plan) TableName() sqlparser.TableIdent {
 }
 
 // Build builds a plan based on the schema.
-func Build(statement sqlparser.Statement, tables map[string]*schema.Table, isReservedConn bool, dbName string) (plan *Plan, err error) {
+func Build(statement sqlparser.Statement, tables map[string]*schema.Table, isReservedConn bool) (plan *Plan, err error) {
 	if !isReservedConn {
 		err = checkForPoolingUnsafeConstructs(statement)
 		if err != nil {
@@ -182,17 +180,7 @@ func Build(statement sqlparser.Statement, tables map[string]*schema.Table, isRes
 		// DDLs and other statements below don't get fully parsed.
 		// We have to use the original query at the time of execution.
 		plan = &Plan{PlanID: PlanDDL}
-	case *sqlparser.Show:
-		if stmt.Type == sqlparser.KeywordString(sqlparser.TABLES) {
-			analyzeShowTables(stmt, dbName)
-			plan = &Plan{
-				PlanID:    PlanShowTables,
-				FullQuery: GenerateFullQuery(stmt),
-			}
-		} else {
-			plan, err = &Plan{PlanID: PlanOtherRead}, nil
-		}
-	case *sqlparser.OtherRead, *sqlparser.Explain:
+	case *sqlparser.Show, *sqlparser.OtherRead, *sqlparser.Explain:
 		plan, err = &Plan{PlanID: PlanOtherRead}, nil
 	case *sqlparser.OtherAdmin:
 		plan, err = &Plan{PlanID: PlanOtherAdmin}, nil
diff --git a/go/vt/vttablet/tabletserver/query_engine.go b/go/vt/vttablet/tabletserver/query_engine.go
index 14870a630d..cfe94e972e 100644
--- a/go/vt/vttablet/tabletserver/query_engine.go
+++ b/go/vt/vttablet/tabletserver/query_engine.go
@@ -309,7 +309,7 @@ func (qe *QueryEngine) GetPlan(ctx context.Context, logStats *tabletenv.LogStats
 	if err != nil {
 		return nil, err
 	}
-	splan, err := planbuilder.Build(statement, qe.tables, isReservedConn, qe.env.Config().DB.DBName)
+	splan, err := planbuilder.Build(statement, qe.tables, isReservedConn)
 	if err != nil {
 		return nil, err
 	}
diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go
index 2cd757df3a..bcdd68458f 100644
--- a/go/vt/vttablet/tabletserver/query_executor.go
+++ b/go/vt/vttablet/tabletserver/query_executor.go
@@ -121,9 +121,10 @@ func (qre *QueryExecutor) Execute() (reply *sqltypes.Result, err error) {
 	}
 
 	switch qre.plan.PlanID {
-	case planbuilder.PlanSelect, planbuilder.PlanSelectImpossible, planbuilder.PlanShowTables:
+	case planbuilder.PlanSelect, planbuilder.PlanSelectImpossible:
 		maxrows := qre.getSelectLimit()
 		qre.bindVars["#maxLimit"] = sqltypes.Int64BindVariable(maxrows + 1)
+		qre.bindVars["__vtschemaname"] = sqltypes.StringBindVariable(qre.tsv.config.DB.DBName)
 		qr, err := qre.execSelect()
 		if err != nil {
 			return nil, err
@@ -203,9 +204,10 @@ func (qre *QueryExecutor) txConnExec(conn *StatefulConnection) (*sqltypes.Result
 		return qre.execSQL(conn, qre.query, true)
 	case planbuilder.PlanSavepoint, planbuilder.PlanRelease, planbuilder.PlanSRollback:
 		return qre.execSQL(conn, qre.query, true)
-	case planbuilder.PlanSelect, planbuilder.PlanSelectLock, planbuilder.PlanSelectImpossible, planbuilder.PlanShowTables:
+	case planbuilder.PlanSelect, planbuilder.PlanSelectLock, planbuilder.PlanSelectImpossible:
 		maxrows := qre.getSelectLimit()
 		qre.bindVars["#maxLimit"] = sqltypes.Int64BindVariable(maxrows + 1)
+		qre.bindVars["__vtschemaname"] = sqltypes.StringBindVariable(qre.tsv.config.DB.DBName)
 		qr, err := qre.txFetch(conn, false)
 		if err != nil {
 			return nil, err
diff --git a/go/vt/wrangler/vexec.go b/go/vt/wrangler/vexec.go
index f7b64a2738..0df718ac23 100644
--- a/go/vt/wrangler/vexec.go
+++ b/go/vt/wrangler/vexec.go
@@ -27,7 +27,6 @@ import (
 	"k8s.io/apimachinery/pkg/util/sets"
 
 	"vitess.io/vitess/go/vt/log"
-	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
 
 	"github.com/golang/protobuf/proto"
 	"github.com/olekukonko/tablewriter"
@@ -104,7 +103,7 @@ func (vx *vexec) outputDryRunInfo(wr *Wrangler) error {
 	table.SetHeader([]string{"Tablet", "ID", "BinLogSource", "State", "DBName", "Current GTID", "MaxReplicationLag"})
 	for _, master := range vx.masters {
 		key := fmt.Sprintf("%s/%s", master.Shard, master.AliasString())
-		for _, stream := range rsr.ShardStatuses[key].MasterReplicationStatuses {
+		for _, stream := range rsr.Statuses[key] {
 			table.Append([]string{key, fmt.Sprintf("%d", stream.ID), stream.Bls.String(), stream.State, stream.DBName, stream.Pos, fmt.Sprintf("%d", stream.MaxReplicationLag)})
 		}
 	}
@@ -193,9 +192,8 @@ func (vx *vexec) getMasterForShard(shard string) (*topo.TabletInfo, error) {
 
 // WorkflowAction can start/stop/delete or list streams in _vt.vreplication on all masters in the target keyspace of the workflow.
 func (wr *Wrangler) WorkflowAction(ctx context.Context, workflow, keyspace, action string, dryRun bool) (map[*topo.TabletInfo]*sqltypes.Result, error) {
-	if action == "show" {
-		_, err := wr.ShowWorkflow(ctx, workflow, keyspace)
-		return nil, err
+	if action == "list" {
+		return nil, wr.listStreams(ctx, workflow, keyspace)
 	} else if action == "listall" {
 		_, err := wr.ListAllWorkflows(ctx, keyspace)
 		return nil, err
@@ -246,33 +244,12 @@ func (wr *Wrangler) execWorkflowAction(ctx context.Context, workflow, keyspace,
 	return results, err
 }
 
-// ReplicationStatusResult represents the result of trying to get the replication status for a given workflow.
-type ReplicationStatusResult struct {
-	// Workflow represents the name of the workflow relevant to the related replication statuses.
-	Workflow string
-	// SourceLocation represents the keyspace and shards that we are vreplicating from.
-	SourceLocation ReplicationLocation
-	// TargetLocation represents the keyspace and shards that we are vreplicating into.
-	TargetLocation ReplicationLocation
-
-	// Statuses is a map of <shard>/<master tablet alias> : ShardReplicationStatus (for the given shard).
-	ShardStatuses map[string]*ShardReplicationStatus
-}
+type replicationStatusResult struct {
+	Workflow       string
+	SourceKeyspace string
+	TargetKeyspace string
 
-// ReplicationLocation represents a location that data is either replicating from, or replicating into.
-type ReplicationLocation struct {
-	Keyspace string
-	Shards   []string
-}
-
-// ShardReplicationStatus holds relevant vreplication related info for the given shard.
-type ShardReplicationStatus struct {
-	// MasterReplicationStatuses represents all of the replication statuses for the master tablets in the given shard.
-	MasterReplicationStatuses []*ReplicationStatus
-	// TabletControls represents the tablet controls for the tablets in the shard.
-	TabletControls []*topodatapb.Shard_TabletControl
-	// MasterIsServing indicates whether the master tablet of the given shard is currently serving write traffic.
-	MasterIsServing bool
+	Statuses map[string][]*replicationStatus
 }
 
 type copyState struct {
@@ -280,36 +257,23 @@ type copyState struct {
 	LastPK string
 }
 
-// ReplicationStatus includes data from the _vt.vreplication table, along with other useful relevant data.
-type ReplicationStatus struct {
-	// Shard represents the relevant shard name.
-	Shard string
-	// Tablet is the tablet alias that the ReplicationStatus came from.
-	Tablet string
-	// ID represents the id column from the _vt.vreplication table.
-	ID int64
-	// Bls represents the BinlogSource.
-	Bls binlogdatapb.BinlogSource
-	// Pos represents the pos column from the _vt.vreplication table.
-	Pos string
-	// StopPos represents the stop_pos column from the _vt.vreplication table.
-	StopPos string
-	// State represents the state column from the _vt.vreplication table.
-	State string
-	// MaxReplicationLag represents the max_replication_lag column from the _vt.vreplication table.
+type replicationStatus struct {
+	Shard             string
+	Tablet            string
+	ID                int64
+	Bls               binlogdatapb.BinlogSource
+	Pos               string
+	StopPos           string
+	State             string
 	MaxReplicationLag int64
-	// DbName represents the db_name column from the _vt.vreplication table.
-	DBName string
-	// TimeUpdated represents the time_updated column from the _vt.vreplication table.
-	TimeUpdated int64
-	// Message represents the message column from the _vt.vreplication table.
-	Message string
-
-	// CopyState represents the rows from the _vt.copy_state table.
+	DBName            string
+	TimeUpdated       int64
+	Message           string
+
 	CopyState []copyState
 }
 
-func (wr *Wrangler) getReplicationStatusFromRow(ctx context.Context, row []sqltypes.Value, master *topo.TabletInfo) (*ReplicationStatus, string, error) {
+func (wr *Wrangler) getReplicationStatusFromRow(ctx context.Context, row []sqltypes.Value, master *topo.TabletInfo) (*replicationStatus, string, error) {
 	var err error
 	var id, maxReplicationLag, timeUpdated int64
 	var state, dbName, pos, stopPos, message string
@@ -334,7 +298,7 @@ func (wr *Wrangler) getReplicationStatusFromRow(ctx context.Context, row []sqlty
 		return nil, "", err
 	}
 	message = row[8].ToString()
-	status := &ReplicationStatus{
+	status := &replicationStatus{
 		Shard:             master.Shard,
 		Tablet:            master.AliasString(),
 		ID:                id,
@@ -356,57 +320,32 @@ func (wr *Wrangler) getReplicationStatusFromRow(ctx context.Context, row []sqlty
 	return status, bls.Keyspace, nil
 }
 
-func (wr *Wrangler) getStreams(ctx context.Context, workflow, keyspace string) (*ReplicationStatusResult, error) {
-	var rsr ReplicationStatusResult
-	rsr.ShardStatuses = make(map[string]*ShardReplicationStatus)
+func (wr *Wrangler) getStreams(ctx context.Context, workflow, keyspace string) (*replicationStatusResult, error) {
+	var rsr replicationStatusResult
+	rsr.Statuses = make(map[string][]*replicationStatus)
 	rsr.Workflow = workflow
+	rsr.TargetKeyspace = keyspace
 	var results map[*topo.TabletInfo]*querypb.QueryResult
 	query := "select id, source, pos, stop_pos, max_replication_lag, state, db_name, time_updated, message from _vt.vreplication"
 	results, err := wr.runVexec(ctx, workflow, keyspace, query, false)
 	if err != nil {
 		return nil, err
 	}
-
-	// We set a topo timeout since we contact topo for the shard record.
-	ctx, cancel := context.WithTimeout(ctx, *topo.RemoteOperationTimeout)
-	defer cancel()
-	var sourceKeyspace string
-	sourceShards := sets.NewString()
-	targetShards := sets.NewString()
 	for master, result := range results {
-		var rsrStatus []*ReplicationStatus
+		var rsrStatus []*replicationStatus
 		qr := sqltypes.Proto3ToResult(result)
 		for _, row := range qr.Rows {
-			status, sk, err := wr.getReplicationStatusFromRow(ctx, row, master)
+			status, sourceKeyspace, err := wr.getReplicationStatusFromRow(ctx, row, master)
 			fmt.Printf("getReplicationStatusFromRow status for master %s is %v\n", master.AliasString(), status)
 			if err != nil {
 				return nil, err
 			}
-			sourceKeyspace = sk
-			sourceShards.Insert(status.Bls.Shard)
+			rsr.SourceKeyspace = sourceKeyspace
 
 			rsrStatus = append(rsrStatus, status)
 		}
-		si, err := wr.ts.GetShard(ctx, keyspace, master.Shard)
-		if err != nil {
-			return nil, err
-		}
-		targetShards.Insert(si.ShardName())
-		rsr.ShardStatuses[fmt.Sprintf("%s/%s", master.Shard, master.AliasString())] = &ShardReplicationStatus{
-			MasterReplicationStatuses: rsrStatus,
-			TabletControls:            si.TabletControls,
-			MasterIsServing:           si.IsMasterServing,
-		}
+		rsr.Statuses[fmt.Sprintf("%s/%s", master.Shard, master.AliasString())] = rsrStatus
 	}
-	rsr.SourceLocation = ReplicationLocation{
-		Keyspace: sourceKeyspace,
-		Shards:   sourceShards.List(),
-	}
-	rsr.TargetLocation = ReplicationLocation{
-		Keyspace: keyspace,
-		Shards:   targetShards.List(),
-	}
-
 	return &rsr, nil
 }
 
@@ -435,21 +374,20 @@ func (wr *Wrangler) ListAllWorkflows(ctx context.Context, keyspace string) ([]st
 	return workflows, nil
 }
 
-// ShowWorkflow will return all of the relevant replication related information for the given workflow.
-func (wr *Wrangler) ShowWorkflow(ctx context.Context, workflow, keyspace string) (*ReplicationStatusResult, error) {
+func (wr *Wrangler) listStreams(ctx context.Context, workflow, keyspace string) error {
 	replStatus, err := wr.getStreams(ctx, workflow, keyspace)
 	if err != nil {
-		return nil, err
+		return err
 	}
-	if len(replStatus.ShardStatuses) == 0 {
-		return nil, fmt.Errorf("no streams found for workflow %s in keyspace %s", workflow, keyspace)
+	if len(replStatus.Statuses) == 0 {
+		return fmt.Errorf("no streams found for workflow %s in keyspace %s", workflow, keyspace)
 	}
 
 	if err := dumpStreamListAsJSON(replStatus, wr); err != nil {
-		return nil, err
+		return err
 	}
 
-	return replStatus, nil
+	return nil
 }
 
 func updateState(message, state string, cs []copyState, timeUpdated int64) string {
@@ -463,7 +401,7 @@ func updateState(message, state string, cs []copyState, timeUpdated int64) strin
 	return state
 }
 
-func dumpStreamListAsJSON(replStatus *ReplicationStatusResult, wr *Wrangler) error {
+func dumpStreamListAsJSON(replStatus *replicationStatusResult, wr *Wrangler) error {
 	text, err := json.MarshalIndent(replStatus, "", "\t")
 	if err != nil {
 		return err


Test patch:
diff --git a/go/sync2/semaphore_test.go b/go/sync2/semaphore_flaky_test.go
similarity index 53%
rename from go/sync2/semaphore_test.go
rename to go/sync2/semaphore_flaky_test.go
index aa4f6f5cee..60b287df21 100644
--- a/go/sync2/semaphore_test.go
+++ b/go/sync2/semaphore_flaky_test.go
@@ -17,11 +17,8 @@ limitations under the License.
 package sync2
 
 import (
-	"context"
 	"testing"
 	"time"
-
-	"github.com/stretchr/testify/assert"
 )
 
 func TestSemaNoTimeout(t *testing.T) {
@@ -29,51 +26,42 @@ func TestSemaNoTimeout(t *testing.T) {
 	s.Acquire()
 	released := false
 	go func() {
+		time.Sleep(10 * time.Millisecond)
 		released = true
 		s.Release()
 	}()
 	s.Acquire()
-	assert.True(t, released)
+	if !released {
+		t.Errorf("release: false, want true")
+	}
 }
 
 func TestSemaTimeout(t *testing.T) {
-	s := NewSemaphore(1, 1*time.Millisecond)
-	s.Acquire()
-	release := make(chan struct{})
-	released := make(chan struct{})
-	go func() {
-		<-release
-		s.Release()
-		released <- struct{}{}
-	}()
-	assert.False(t, s.Acquire())
-	release <- struct{}{}
-	<-released
-	assert.True(t, s.Acquire())
-}
-
-func TestSemaAcquireContext(t *testing.T) {
-	s := NewSemaphore(1, 0)
+	s := NewSemaphore(1, 5*time.Millisecond)
 	s.Acquire()
-	release := make(chan struct{})
-	released := make(chan struct{})
 	go func() {
-		<-release
+		time.Sleep(10 * time.Millisecond)
 		s.Release()
-		released <- struct{}{}
 	}()
-	ctx, cancel := context.WithCancel(context.Background())
-	cancel()
-	assert.False(t, s.AcquireContext(ctx))
-	release <- struct{}{}
-	<-released
-	assert.True(t, s.AcquireContext(context.Background()))
+	if s.Acquire() {
+		t.Errorf("Acquire: true, want false")
+	}
+	time.Sleep(10 * time.Millisecond)
+	if !s.Acquire() {
+		t.Errorf("Acquire: false, want true")
+	}
 }
 
 func TestSemaTryAcquire(t *testing.T) {
 	s := NewSemaphore(1, 0)
-	assert.True(t, s.TryAcquire())
-	assert.False(t, s.TryAcquire())
+	if !s.TryAcquire() {
+		t.Errorf("TryAcquire: false, want true")
+	}
+	if s.TryAcquire() {
+		t.Errorf("TryAcquire: true, want false")
+	}
 	s.Release()
-	assert.True(t, s.TryAcquire())
+	if !s.TryAcquire() {
+		t.Errorf("TryAcquire: false, want true")
+	}
 }
diff --git a/go/test/endtoend/recovery/pitr/binlog_server.go b/go/test/endtoend/recovery/pitr/binlog_server.go
index b753d0faf8..efe04255fc 100644
--- a/go/test/endtoend/recovery/pitr/binlog_server.go
+++ b/go/test/endtoend/recovery/pitr/binlog_server.go
@@ -1,19 +1,3 @@
-/*
-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 pitr
 
 import (
@@ -54,7 +38,7 @@ type mysqlMaster struct {
 
 // newBinlogServer returns an instance of binlog server
 func newBinlogServer(hostname string, port int) (*binLogServer, error) {
-	dataDir := path.Join(os.Getenv("VTDATAROOT"), fmt.Sprintf("%s_%d", binlogDataDir, port))
+	dataDir := path.Join(os.Getenv("VTDATAROOT"), binlogDataDir)
 	fmt.Println(dataDir)
 	if _, err := os.Stat(dataDir); os.IsNotExist(err) {
 		err := os.Mkdir(dataDir, 0700)
diff --git a/go/test/endtoend/recovery/pitr/main_test.go b/go/test/endtoend/recovery/pitr/main_test.go
new file mode 100644
index 0000000000..2421e35a57
--- /dev/null
+++ b/go/test/endtoend/recovery/pitr/main_test.go
@@ -0,0 +1,134 @@
+package pitr
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"os/exec"
+	"testing"
+
+	"vitess.io/vitess/go/test/endtoend/cluster"
+	"vitess.io/vitess/go/vt/log"
+)
+
+var (
+	clusterInstance *cluster.LocalProcessCluster
+	masterTablet    *cluster.Vttablet
+	replicaTablet   *cluster.Vttablet
+	initDBFile      string
+
+	cell                 = "zone1"
+	hostname             = "localhost"
+	binlogHost           = "127.0.0.1"
+	keyspaceName         = "ks"
+	partialRestoreKSName = "restoreks1"
+	fullRestoreKSName    = "restoreks2"
+	dbName               = "vt_ks"
+	shardName            = "0"
+	shardKsName          = "ks/0"
+	mysqlUserName        = "vt_dba"
+)
+
+func TestMain(m *testing.M) {
+	defer cluster.PanicHandler(nil)
+	flag.Parse()
+
+	exitCode, err := func() (int, error) {
+		clusterInstance = cluster.NewCluster(cell, hostname)
+		defer clusterInstance.Teardown()
+
+		// Start topo server
+		if err := clusterInstance.StartTopo(); err != nil {
+			log.Error(err)
+			return 1, err
+		}
+
+		if err := clusterInstance.VtctlProcess.CreateKeyspace(keyspaceName); err != nil {
+			log.Error(err)
+			return 1, err
+		}
+		clusterInstance.Keyspaces = append(clusterInstance.Keyspaces, cluster.Keyspace{Name: keyspaceName})
+
+		masterTablet = clusterInstance.NewVttabletInstance("replica", 0, cell)
+		replicaTablet = clusterInstance.NewVttabletInstance("replica", 0, cell)
+
+		err := startTablets([]*cluster.Vttablet{masterTablet, replicaTablet})
+		if err != nil {
+			return 1, err
+		}
+		err = clusterInstance.VtctlclientProcess.InitShardMaster(keyspaceName, shardName, cell, masterTablet.TabletUID)
+		if err != nil {
+			return 1, err
+		}
+		return m.Run(), nil
+	}()
+	if err != nil {
+		log.Error(err)
+		os.Exit(1)
+	}
+	os.Exit(exitCode)
+
+}
+
+func startTablets(tablets []*cluster.Vttablet) error {
+	var mysqlProcesses []*exec.Cmd
+	shard := &cluster.Shard{
+		Name: shardName,
+	}
+	for _, tablet := range tablets {
+		tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory)
+		tablet.MysqlctlProcess.InitDBFile = initDBFile
+		if proc, err := tablet.MysqlctlProcess.StartProcess(); err != nil {
+			return err
+		} else {
+			// ignore golint warning, we need the else block to use proc
+			mysqlProcesses = append(mysqlProcesses, proc) //nolint
+		}
+		tablet.VttabletProcess = cluster.VttabletProcessInstance(tablet.HTTPPort,
+			tablet.GrpcPort,
+			tablet.TabletUID,
+			clusterInstance.Cell,
+			shardName,
+			keyspaceName,
+			clusterInstance.VtctldProcess.Port,
+			tablet.Type,
+			clusterInstance.TopoProcess.Port,
+			clusterInstance.Hostname,
+			clusterInstance.TmpDirectory,
+			clusterInstance.VtTabletExtraArgs,
+			clusterInstance.EnableSemiSync)
+		tablet.Alias = tablet.VttabletProcess.TabletPath
+		tablet.VttabletProcess.SupportsBackup = true
+		shard.Vttablets = append(shard.Vttablets, tablet)
+		shard.Vttablets = append(shard.Vttablets, tablet)
+	}
+	for _, proc := range mysqlProcesses {
+		proc.Wait()
+	}
+	queryCmds := []string{
+		fmt.Sprintf("CREATE USER '%s'@'%%';", mysqlUserName),
+		fmt.Sprintf("GRANT ALL ON *.* TO '%s'@'%%';", mysqlUserName),
+		fmt.Sprintf("GRANT GRANT OPTION ON *.* TO '%s'@'%%';", mysqlUserName),
+		"FLUSH PRIVILEGES;",
+		fmt.Sprintf("create database %s;", dbName),
+	}
+	for _, tablet := range tablets {
+		for _, query := range queryCmds {
+			_, err := tablet.VttabletProcess.QueryTablet(query, keyspaceName, false)
+			if err != nil {
+				log.Error(err)
+				return err
+			}
+		}
+	}
+	for _, tablet := range tablets {
+		err := tablet.VttabletProcess.Setup()
+		if err != nil {
+			log.Error(err)
+			return err
+		}
+	}
+
+	clusterInstance.Keyspaces[0].Shards = []cluster.Shard{*shard}
+	return nil
+}
diff --git a/go/test/endtoend/recovery/pitr/pitr_test.go b/go/test/endtoend/recovery/pitr/pitr_test.go
new file mode 100644
index 0000000000..8c3bbec89e
--- /dev/null
+++ b/go/test/endtoend/recovery/pitr/pitr_test.go
@@ -0,0 +1,172 @@
+package pitr
+
+import (
+	"fmt"
+	"testing"
+	"time"
+
+	"github.com/magiconair/properties/assert"
+
+	"vitess.io/vitess/go/vt/log"
+
+	"vitess.io/vitess/go/test/endtoend/cluster"
+
+	"github.com/stretchr/testify/require"
+)
+
+var (
+	createTable = `create table product (id bigint(20) primary key, name char(10), created bigint(20));`
+	insertTable = `insert into product (id, name, created) values(%d, '%s', unix_timestamp());`
+	selectMaxID = `select max(id) from product`
+)
+
+func TestPointInTimeRecovery(t *testing.T) {
+	// create table and insert 2 rows
+	_, err := masterTablet.VttabletProcess.QueryTablet(createTable, keyspaceName, true)
+	require.NoError(t, err)
+	insertRow(t, 1, "p1", false)
+	insertRow(t, 2, "p2", false)
+
+	// wait till replica catchup
+	cluster.VerifyRowsInTabletForTable(t, replicaTablet, keyspaceName, 2, "product")
+
+	//start the binlog server and point it to master
+	bs, err := newBinlogServer(hostname, clusterInstance.GetAndReservePort())
+	defer bs.stop()
+	require.NoError(t, err)
+
+	err = bs.start(mysqlMaster{
+		hostname: binlogHost,
+		port:     masterTablet.MysqlctlProcess.MySQLPort,
+		username: mysqlUserName,
+	})
+	require.NoError(t, err)
+
+	// take the backup (to simulate the regular backup)
+	err = clusterInstance.VtctlclientProcess.ExecuteCommand("Backup", replicaTablet.Alias)
+	require.NoError(t, err)
+
+	backups, err := clusterInstance.ListBackups(shardKsName)
+	require.NoError(t, err)
+	require.Equal(t, len(backups), 1)
+
+	// now insert some more data to simulate the changes after regular backup
+	// every insert has some time lag/difference to simulate the time gap between rows
+	// and when we recover to certain time, this time gap will be able to identify the exact eligible row
+	var timeToRecover string
+	for counter := 3; counter <= 7; counter++ {
+		if counter == 5 { // we want to recovery till this, so noting the time
+			tm := time.Now().Add(1 * time.Second).UTC()
+			timeToRecover = tm.Format(time.RFC3339)
+		}
+		insertRow(t, counter, fmt.Sprintf("prd-%d", counter), true)
+	}
+	currentTime := time.Now().UTC()
+	timeForCompleteBinlogRecover := currentTime.Format(time.RFC3339)
+	// create restoreSnapshot
+	createRestoreSnapshot(t, timeToRecover, partialRestoreKSName)
+
+	// test the recovery with smaller binlog_lookup_timeout
+	recoveryTabletWithSmallTimeout := clusterInstance.NewVttabletInstance("replica", 0, cell)
+	launchRecoveryTablet(t, recoveryTabletWithSmallTimeout, bs, "1ms", partialRestoreKSName)
+
+	// since we have smaller timeout, it will just get whatever available in the backup
+	sqlRes, err := recoveryTabletWithSmallTimeout.VttabletProcess.QueryTablet(selectMaxID, keyspaceName, true)
+	require.NoError(t, err)
+	assert.Equal(t, sqlRes.Rows[0][0].String(), "INT64(2)")
+
+	// test the recovery with valid binlog_lookup_timeout and timeToRecover pointing to 5th row
+	recoveryTablet1 := clusterInstance.NewVttabletInstance("replica", 0, cell)
+	launchRecoveryTablet(t, recoveryTablet1, bs, "2m", partialRestoreKSName)
+
+	sqlRes, err = recoveryTablet1.VttabletProcess.QueryTablet(selectMaxID, keyspaceName, true)
+	require.NoError(t, err)
+	assert.Equal(t, sqlRes.Rows[0][0].String(), "INT64(5)")
+
+	// test the recovery with timetorecover > (timestmap of last binlog event in binlog server)
+	createRestoreSnapshot(t, timeForCompleteBinlogRecover, fullRestoreKSName)
+
+	recoveryTablet2 := clusterInstance.NewVttabletInstance("replica", 0, cell)
+	launchRecoveryTablet(t, recoveryTablet2, bs, "2m", fullRestoreKSName)
+
+	sqlRes, err = recoveryTablet2.VttabletProcess.QueryTablet(selectMaxID, keyspaceName, true)
+	require.NoError(t, err)
+	assert.Equal(t, sqlRes.Rows[0][0].String(), "INT64(7)")
+
+	defer recoveryTablet1.MysqlctlProcess.Stop()
+	defer recoveryTablet1.VttabletProcess.TearDown()
+
+	defer recoveryTablet2.MysqlctlProcess.Stop()
+	defer recoveryTablet2.VttabletProcess.TearDown()
+
+	defer recoveryTabletWithSmallTimeout.MysqlctlProcess.Stop()
+	defer recoveryTabletWithSmallTimeout.VttabletProcess.TearDown()
+}
+
+func insertRow(t *testing.T, id int, productName string, isSlow bool) {
+	_, err := masterTablet.VttabletProcess.QueryTablet(fmt.Sprintf(insertTable, id, productName), keyspaceName, true)
+	require.NoError(t, err)
+	if isSlow {
+		time.Sleep(1 * time.Second)
+	}
+}
+
+func createRestoreSnapshot(t *testing.T, timeToRecover, restoreKSName string) {
+	output, err := clusterInstance.VtctlclientProcess.ExecuteCommandWithOutput("CreateKeyspace",
+		"-keyspace_type=SNAPSHOT", "-base_keyspace="+keyspaceName,
+		"-snapshot_time", timeToRecover, restoreKSName)
+	log.Info(output)
+	require.Nil(t, err)
+}
+
+func launchRecoveryTablet(t *testing.T, tablet *cluster.Vttablet, binlogServer *binLogServer, lookupTimeout, restoreKSName string) {
+	tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory)
+	tablet.MysqlctlProcess.InitDBFile = initDBFile
+	err := tablet.MysqlctlProcess.Start()
+	require.NoError(t, err)
+
+	tablet.VttabletProcess = cluster.VttabletProcessInstance(tablet.HTTPPort,
+		tablet.GrpcPort,
+		tablet.TabletUID,
+		clusterInstance.Cell,
+		shardName,
+		keyspaceName,
+		clusterInstance.VtctldProcess.Port,
+		tablet.Type,
+		clusterInstance.TopoProcess.Port,
+		clusterInstance.Hostname,
+		clusterInstance.TmpDirectory,
+		clusterInstance.VtTabletExtraArgs,
+		clusterInstance.EnableSemiSync)
+	tablet.Alias = tablet.VttabletProcess.TabletPath
+	tablet.VttabletProcess.SupportsBackup = true
+	tablet.VttabletProcess.Keyspace = restoreKSName
+	tablet.VttabletProcess.EnableSemiSync = true
+	tablet.VttabletProcess.ExtraArgs = []string{
+		"-disable_active_reparents",
+		"-enable_replication_reporter=false",
+		"-init_db_name_override", dbName,
+		"-init_tablet_type", "replica",
+		"-init_keyspace", restoreKSName,
+		"-init_shard", shardName,
+		"-binlog_host", binlogServer.hostname,
+		"-binlog_port", fmt.Sprintf("%d", binlogServer.port),
+		"-binlog_user", binlogServer.username,
+		"-pitr_gtid_lookup_timeout", lookupTimeout,
+		"-vreplication_healthcheck_topology_refresh", "1s",
+		"-vreplication_healthcheck_retry_delay", "1s",
+		"-vreplication_tablet_type", "replica",
+		"-vreplication_retry_delay", "1s",
+		"-degraded_threshold", "5s",
+		"-lock_tables_timeout", "5s",
+		"-watch_replication_stream",
+		"-serving_state_grace_period", "1s",
+	}
+	tablet.VttabletProcess.ServingStatus = ""
+
+	err = tablet.VttabletProcess.Setup()
+	require.NoError(t, err)
+
+	tablet.VttabletProcess.WaitForTabletTypesForTimeout([]string{"SERVING"}, 20*time.Second)
+	require.Nil(t, err)
+}
diff --git a/go/test/endtoend/recovery/pitr/shardedpitr_test.go b/go/test/endtoend/recovery/pitr/shardedpitr_test.go
deleted file mode 100644
index 16a9be2fed..0000000000
--- a/go/test/endtoend/recovery/pitr/shardedpitr_test.go
+++ /dev/null
@@ -1,539 +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 pitr
-
-import (
-	"context"
-	"fmt"
-	"os/exec"
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-	"vitess.io/vitess/go/mysql"
-	"vitess.io/vitess/go/test/endtoend/cluster"
-	"vitess.io/vitess/go/vt/log"
-)
-
-var (
-	createTable = `create table product (id bigint(20) primary key, name char(10), created bigint(20));`
-	insertTable = `insert into product (id, name, created) values(%d, '%s', unix_timestamp());`
-	getCountID  = `select count(*) from product`
-)
-
-var (
-	clusterInstance *cluster.LocalProcessCluster
-
-	master        *cluster.Vttablet
-	replica       *cluster.Vttablet
-	shard0Master  *cluster.Vttablet
-	shard0Replica *cluster.Vttablet
-	shard1Master  *cluster.Vttablet
-	shard1Replica *cluster.Vttablet
-
-	cell           = "zone1"
-	hostname       = "localhost"
-	binlogHost     = "127.0.0.1"
-	keyspaceName   = "ks"
-	restoreKS1Name = "restoreks1"
-	restoreKS2Name = "restoreks2"
-	restoreKS3Name = "restoreks3"
-	shardName      = "0"
-	shard0Name     = "-80"
-	shard1Name     = "80-"
-	dbName         = "vt_ks"
-	mysqlUserName  = "vt_dba"
-	vSchema        = `{
-		"sharded": true,
-		"vindexes": {
-			"hash_index": {
-				"type": "hash"
-			}
-		},
-		"tables": {
-			"product": {
-				"column_vindexes": [
-					{
-						"column": "id",
-						"name": "hash_index"
-					}
-				]
-			}
-		}
-	}`
-	commonTabletArg = []string{
-		"-vreplication_healthcheck_topology_refresh", "1s",
-		"-vreplication_healthcheck_retry_delay", "1s",
-		"-vreplication_retry_delay", "1s",
-		"-degraded_threshold", "5s",
-		"-lock_tables_timeout", "5s",
-		"-watch_replication_stream",
-		"-serving_state_grace_period", "1s"}
-)
-
-// Test pitr (Point in time recovery).
-// -------------------------------------------
-// The following test will:
-// - create a shard with master and replica
-// - run InitShardMaster
-// - point binlog server to master
-// - insert some data using vtgate (e.g. here we have inserted rows 1,2)
-// - verify the replication
-// - take backup of replica
-// - insert some data using vtgate (e.g. we inserted rows 3 4 5 6), while inserting row-4, note down the time (restoreTime1)
-// - perform a resharding to create 2 shards (-80, 80-), and delete the old shard
-// - point binlog server to master of both shards
-// - insert some data using vtgate (e.g. we will insert 7 8 9 10) and verify we get required number of rows in -80, 80- shard
-// - take backup of both shards
-// - insert some more data using vtgate (e.g. we will insert 11 12 13 14 15), while inserting row-13, note down the time (restoreTime2)
-// - note down the current time (restoreTime3)
-
-// - Till now we did all the presetup for assertions
-
-// - asserting that restoring to restoreTime1 (going from 2 shards to 1 shard) is working, i.e. we should get 4 rows.
-// - asserting that while restoring if we give small timeout value, it will restore upto to the last available backup (asserting only -80 shard)
-// - asserting that restoring to restoreTime2 (going from 2 shards to 2 shards with past time) is working, it will assert for both shards
-// - asserting that restoring to restoreTime3 is working, we should get complete data after restoring,  as we have in existing shards.
-func TestPITRRecovery(t *testing.T) {
-	defer cluster.PanicHandler(nil)
-	initializeCluster(t)
-	defer clusterInstance.Teardown()
-
-	//start the binlog server and point it to master
-	bs := startBinlogServer(t, master)
-	defer bs.stop()
-
-	// Creating the table
-	_, err := master.VttabletProcess.QueryTablet(createTable, keyspaceName, true)
-	require.NoError(t, err)
-
-	insertRow(t, 1, "prd-1", false)
-	insertRow(t, 2, "prd-2", false)
-
-	cluster.VerifyRowsInTabletForTable(t, replica, keyspaceName, 2, "product")
-
-	// backup the replica
-	err = clusterInstance.VtctlclientProcess.ExecuteCommand("Backup", replica.Alias)
-	require.NoError(t, err)
-
-	// check that the backup shows up in the listing
-	output, err := clusterInstance.ListBackups("ks/0")
-	require.NoError(t, err)
-	assert.Equal(t, 1, len(output))
-
-	// now insert some more data to simulate the changes after regular backup
-	// every insert has some time lag/difference to simulate the time gap between rows
-	// and when we recover to certain time, this time gap will be able to identify the exact eligible row
-	var restoreTime1 string
-	for counter := 3; counter <= 6; counter++ {
-		if counter == 4 { // we want to recovery till this, so noting the time
-			tm := time.Now().Add(1 * time.Second).UTC()
-			restoreTime1 = tm.Format(time.RFC3339)
-		}
-		insertRow(t, counter, fmt.Sprintf("prd-%d", counter), true)
-	}
-
-	// starting resharding process
-	performResharding(t)
-
-	//start the binlog server and point it to shard0master
-	bs0 := startBinlogServer(t, shard0Master)
-	defer bs0.stop()
-
-	//start the binlog server and point it to shard1master
-	bs1 := startBinlogServer(t, shard1Master)
-	defer bs1.stop()
-
-	for counter := 7; counter <= 10; counter++ {
-		insertRow(t, counter, fmt.Sprintf("prd-%d", counter), false)
-	}
-
-	// wait till all the shards have required data
-	cluster.VerifyRowsInTabletForTable(t, shard0Replica, keyspaceName, 6, "product")
-	cluster.VerifyRowsInTabletForTable(t, shard1Replica, keyspaceName, 4, "product")
-
-	// take the backup (to simulate the regular backup)
-	err = clusterInstance.VtctlclientProcess.ExecuteCommand("Backup", shard0Replica.Alias)
-	require.NoError(t, err)
-	// take the backup (to simulate the regular backup)
-	err = clusterInstance.VtctlclientProcess.ExecuteCommand("Backup", shard1Replica.Alias)
-	require.NoError(t, err)
-
-	backups, err := clusterInstance.ListBackups(keyspaceName + "/-80")
-	require.NoError(t, err)
-	require.Equal(t, len(backups), 1)
-
-	backups, err = clusterInstance.ListBackups(keyspaceName + "/80-")
-	require.NoError(t, err)
-	require.Equal(t, len(backups), 1)
-
-	// now insert some more data to simulate the changes after regular backup
-	// every insert has some time lag/difference to simulate the time gap between rows
-	// and when we recover to certain time, this time gap will be able to identify the exact eligible row
-	var restoreTime2 string
-	for counter := 11; counter <= 15; counter++ {
-		if counter == 13 { // we want to recovery till this, so noting the time
-			tm := time.Now().Add(1 * time.Second).UTC()
-			restoreTime2 = tm.Format(time.RFC3339)
-		}
-		insertRow(t, counter, fmt.Sprintf("prd-%d", counter), true)
-	}
-	restoreTime3 := time.Now().UTC().Format(time.RFC3339)
-
-	// creating restore keyspace with snapshot time as restoreTime1
-	createRestoreKeyspace(t, restoreTime1, restoreKS1Name)
-
-	// Launching a recovery tablet which recovers data from the master till the restoreTime1
-	testTabletRecovery(t, bs, "2m", restoreKS1Name, "0", "INT64(4)")
-
-	// create restoreKeyspace with snapshot time as restoreTime2
-	createRestoreKeyspace(t, restoreTime2, restoreKS2Name)
-
-	// test the recovery with smaller binlog_lookup_timeout for shard0
-	// since we have small lookup timeout, it will just get whatever available in the backup
-	// mysql> select * from product;
-	// +----+--------+------------+
-	// | id | name   | created    |
-	// +----+--------+------------+
-	// |  1 | prd-1  | 1597219030 |
-	// |  2 | prd-2  | 1597219030 |
-	// |  3 | prd-3  | 1597219043 |
-	// |  5 | prd-5  | 1597219045 |
-	// |  9 | prd-9  | 1597219130 |
-	// | 10 | prd-10 | 1597219130 |
-	// +----+--------+------------+
-	testTabletRecovery(t, bs0, "1ms", restoreKS2Name, "-80", "INT64(6)")
-
-	// test the recovery with valid binlog_lookup_timeout for shard0 and getting the data till the restoreTime2
-	// 	mysql> select * from product;
-	// +----+--------+------------+
-	// | id | name   | created    |
-	// +----+--------+------------+
-	// |  1 | prd-1  | 1597219030 |
-	// |  2 | prd-2  | 1597219030 |
-	// |  3 | prd-3  | 1597219043 |
-	// |  5 | prd-5  | 1597219045 |
-	// |  9 | prd-9  | 1597219130 |
-	// | 10 | prd-10 | 1597219130 |
-	// | 13 | prd-13 | 1597219141 |
-	// +----+--------+------------+
-	testTabletRecovery(t, bs0, "2m", restoreKS2Name, "-80", "INT64(7)")
-
-	// test the recovery with valid binlog_lookup_timeout for shard1 and getting the data till the restoreTime2
-	// 	mysql> select * from product;
-	// +----+--------+------------+
-	// | id | name   | created    |
-	// +----+--------+------------+
-	// |  4 | prd-4  | 1597219044 |
-	// |  6 | prd-6  | 1597219046 |
-	// |  7 | prd-7  | 1597219130 |
-	// |  8 | prd-8  | 1597219130 |
-	// | 11 | prd-11 | 1597219139 |
-	// | 12 | prd-12 | 1597219140 |
-	// +----+--------+------------+
-	testTabletRecovery(t, bs1, "2m", restoreKS2Name, "80-", "INT64(6)")
-
-	// test the recovery with timetorecover > (timestmap of last binlog event in binlog server)
-	createRestoreKeyspace(t, restoreTime3, restoreKS3Name)
-
-	// 	mysql> select * from product;
-	// +----+--------+------------+
-	// | id | name   | created    |
-	// +----+--------+------------+
-	// |  1 | prd-1  | 1597219030 |
-	// |  2 | prd-2  | 1597219030 |
-	// |  3 | prd-3  | 1597219043 |
-	// |  5 | prd-5  | 1597219045 |
-	// |  9 | prd-9  | 1597219130 |
-	// | 10 | prd-10 | 1597219130 |
-	// | 13 | prd-13 | 1597219141 |
-	// | 15 | prd-15 | 1597219142 |
-	// +----+--------+------------+
-	testTabletRecovery(t, bs0, "2m", restoreKS3Name, "-80", "INT64(8)")
-
-	// 	mysql> select * from product;
-	// +----+--------+------------+
-	// | id | name   | created    |
-	// +----+--------+------------+
-	// |  4 | prd-4  | 1597219044 |
-	// |  6 | prd-6  | 1597219046 |
-	// |  7 | prd-7  | 1597219130 |
-	// |  8 | prd-8  | 1597219130 |
-	// | 11 | prd-11 | 1597219139 |
-	// | 12 | prd-12 | 1597219140 |
-	// | 14 | prd-14 | 1597219142 |
-	// +----+--------+------------+
-	testTabletRecovery(t, bs1, "2m", restoreKS3Name, "80-", "INT64(7)")
-
-}
-
-func performResharding(t *testing.T) {
-	err := clusterInstance.VtctlclientProcess.ApplyVSchema(keyspaceName, vSchema)
-	require.NoError(t, err)
-
-	err = clusterInstance.VtctlProcess.ExecuteCommand("InitShardMaster", "-force", "ks/-80", shard0Master.Alias)
-	require.NoError(t, err)
-
-	err = clusterInstance.VtctlProcess.ExecuteCommand("InitShardMaster", "-force", "ks/80-", shard1Master.Alias)
-	require.NoError(t, err)
-
-	// we need to create the schema, and the worker will do data copying
-	for _, keyspaceShard := range []string{"ks/-80", "ks/80-"} {
-		err = clusterInstance.VtctlclientProcess.ExecuteCommand("CopySchemaShard", "ks/0", keyspaceShard)
-		require.NoError(t, err)
-	}
-
-	err = clusterInstance.VtctlclientProcess.ExecuteCommand("Reshard", "ks.reshardWorkflow", "0", "-80,80-")
-	require.NoError(t, err)
-
-	err = clusterInstance.VtctlclientProcess.ExecuteCommand("SwitchReads", "-tablet_type=rdonly", "ks.reshardWorkflow")
-	require.NoError(t, err)
-
-	err = clusterInstance.VtctlclientProcess.ExecuteCommand("SwitchReads", "-tablet_type=replica", "ks.reshardWorkflow")
-	require.NoError(t, err)
-
-	// then serve master from the split shards
-	err = clusterInstance.VtctlclientProcess.ExecuteCommand("SwitchWrites", "ks.reshardWorkflow")
-	require.NoError(t, err)
-
-	// remove the original tablets in the original shard
-	removeTablets(t, []*cluster.Vttablet{master, replica})
-
-	for _, tablet := range []*cluster.Vttablet{replica} {
-		err = clusterInstance.VtctlclientProcess.ExecuteCommand("DeleteTablet", tablet.Alias)
-		require.NoError(t, err)
-	}
-	err = clusterInstance.VtctlclientProcess.ExecuteCommand("DeleteTablet", "-allow_master", master.Alias)
-	require.NoError(t, err)
-
-	// rebuild the serving graph, all mentions of the old shards should be gone
-	err = clusterInstance.VtctlclientProcess.ExecuteCommand("RebuildKeyspaceGraph", "ks")
-	require.NoError(t, err)
-
-	// delete the original shard
-	err = clusterInstance.VtctlclientProcess.ExecuteCommand("DeleteShard", "ks/0")
-	require.NoError(t, err)
-
-	// Restart vtgate process
-	err = clusterInstance.VtgateProcess.TearDown()
-	require.NoError(t, err)
-
-	err = clusterInstance.VtgateProcess.Setup()
-	require.NoError(t, err)
-
-	clusterInstance.WaitForTabletsToHealthyInVtgate()
-}
-
-func startBinlogServer(t *testing.T, masterTablet *cluster.Vttablet) *binLogServer {
-	bs, err := newBinlogServer(hostname, clusterInstance.GetAndReservePort())
-	require.NoError(t, err)
-
-	err = bs.start(mysqlMaster{
-		hostname: binlogHost,
-		port:     masterTablet.MysqlctlProcess.MySQLPort,
-		username: mysqlUserName,
-	})
-	require.NoError(t, err)
-	return bs
-}
-
-func removeTablets(t *testing.T, tablets []*cluster.Vttablet) {
-	var mysqlProcs []*exec.Cmd
-	for _, tablet := range tablets {
-		proc, _ := tablet.MysqlctlProcess.StopProcess()
-		mysqlProcs = append(mysqlProcs, proc)
-	}
-	for _, proc := range mysqlProcs {
-		err := proc.Wait()
-		require.NoError(t, err)
-	}
-	for _, tablet := range tablets {
-		tablet.VttabletProcess.TearDown()
-	}
-}
-
-func initializeCluster(t *testing.T) {
-	clusterInstance = cluster.NewCluster(cell, hostname)
-
-	// Start topo server
-	err := clusterInstance.StartTopo()
-	require.NoError(t, err)
-
-	// Start keyspace
-	keyspace := &cluster.Keyspace{
-		Name: keyspaceName,
-	}
-	clusterInstance.Keyspaces = append(clusterInstance.Keyspaces, *keyspace)
-
-	shard := &cluster.Shard{
-		Name: shardName,
-	}
-	shard0 := &cluster.Shard{
-		Name: shard0Name,
-	}
-	shard1 := &cluster.Shard{
-		Name: shard1Name,
-	}
-
-	// Defining all the tablets
-	master = clusterInstance.NewVttabletInstance("replica", 0, "")
-	replica = clusterInstance.NewVttabletInstance("replica", 0, "")
-	shard0Master = clusterInstance.NewVttabletInstance("replica", 0, "")
-	shard0Replica = clusterInstance.NewVttabletInstance("replica", 0, "")
-	shard1Master = clusterInstance.NewVttabletInstance("replica", 0, "")
-	shard1Replica = clusterInstance.NewVttabletInstance("replica", 0, "")
-
-	shard.Vttablets = []*cluster.Vttablet{master, replica}
-	shard0.Vttablets = []*cluster.Vttablet{shard0Master, shard0Replica}
-	shard1.Vttablets = []*cluster.Vttablet{shard1Master, shard1Replica}
-
-	clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs, commonTabletArg...)
-	clusterInstance.VtTabletExtraArgs = append(clusterInstance.VtTabletExtraArgs, "-restore_from_backup", "-enable_semi_sync")
-
-	err = clusterInstance.LaunchCluster(keyspace, []cluster.Shard{*shard, *shard0, *shard1})
-	require.NoError(t, err)
-	// Start MySql
-	var mysqlCtlProcessList []*exec.Cmd
-	for _, shard := range clusterInstance.Keyspaces[0].Shards {
-		for _, tablet := range shard.Vttablets {
-			proc, err := tablet.MysqlctlProcess.StartProcess()
-			require.NoError(t, err)
-			mysqlCtlProcessList = append(mysqlCtlProcessList, proc)
-		}
-	}
-
-	// Wait for mysql processes to start
-	for _, proc := range mysqlCtlProcessList {
-		err = proc.Wait()
-		require.NoError(t, err)
-	}
-
-	queryCmds := []string{
-		fmt.Sprintf("CREATE USER '%s'@'%%';", mysqlUserName),
-		fmt.Sprintf("GRANT ALL ON *.* TO '%s'@'%%';", mysqlUserName),
-		fmt.Sprintf("GRANT GRANT OPTION ON *.* TO '%s'@'%%';", mysqlUserName),
-		fmt.Sprintf("create database %s;", "vt_ks"),
-		"FLUSH PRIVILEGES;",
-	}
-
-	for _, tablet := range []*cluster.Vttablet{master, replica, shard0Master, shard0Replica, shard1Master, shard1Replica} {
-		for _, query := range queryCmds {
-			_, err = tablet.VttabletProcess.QueryTablet(query, keyspace.Name, false)
-			require.NoError(t, err)
-		}
-
-		err = tablet.VttabletProcess.Setup()
-		require.NoError(t, err)
-	}
-
-	err = clusterInstance.VtctlclientProcess.InitShardMaster(keyspaceName, shard.Name, cell, master.TabletUID)
-	require.NoError(t, err)
-
-	// Start vtgate
-	err = clusterInstance.StartVtgate()
-	require.NoError(t, err)
-}
-
-func insertRow(t *testing.T, id int, productName string, isSlow bool) {
-	ctx := context.Background()
-	vtParams := mysql.ConnParams{
-		Host: clusterInstance.Hostname,
-		Port: clusterInstance.VtgateMySQLPort,
-	}
-	conn, err := mysql.Connect(ctx, &vtParams)
-	require.NoError(t, err)
-	defer conn.Close()
-
-	insertSmt := fmt.Sprintf(insertTable, id, productName)
-	_, err = conn.ExecuteFetch(insertSmt, 1000, true)
-	require.NoError(t, err)
-
-	if isSlow {
-		time.Sleep(1 * time.Second)
-	}
-}
-
-func createRestoreKeyspace(t *testing.T, timeToRecover, restoreKeyspaceName string) {
-	output, err := clusterInstance.VtctlclientProcess.ExecuteCommandWithOutput("CreateKeyspace",
-		"-keyspace_type=SNAPSHOT", "-base_keyspace="+keyspaceName,
-		"-snapshot_time", timeToRecover, restoreKeyspaceName)
-	log.Info(output)
-	require.NoError(t, err)
-}
-
-func testTabletRecovery(t *testing.T, binlogServer *binLogServer, lookupTimeout, restoreKeyspaceName, shardName, expectedRows string) {
-	recoveryTablet := clusterInstance.NewVttabletInstance("replica", 0, cell)
-	launchRecoveryTablet(t, recoveryTablet, binlogServer, lookupTimeout, restoreKeyspaceName, shardName)
-
-	sqlRes, err := recoveryTablet.VttabletProcess.QueryTablet(getCountID, keyspaceName, true)
-	require.NoError(t, err)
-	assert.Equal(t, expectedRows, sqlRes.Rows[0][0].String())
-
-	defer recoveryTablet.MysqlctlProcess.Stop()
-	defer recoveryTablet.VttabletProcess.TearDown()
-}
-
-func launchRecoveryTablet(t *testing.T, tablet *cluster.Vttablet, binlogServer *binLogServer, lookupTimeout, restoreKeyspaceName, shardName string) {
-	tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory)
-	err := tablet.MysqlctlProcess.Start()
-	require.NoError(t, err)
-
-	tablet.VttabletProcess = cluster.VttabletProcessInstance(tablet.HTTPPort,
-		tablet.GrpcPort,
-		tablet.TabletUID,
-		clusterInstance.Cell,
-		shardName,
-		keyspaceName,
-		clusterInstance.VtctldProcess.Port,
-		tablet.Type,
-		clusterInstance.TopoProcess.Port,
-		clusterInstance.Hostname,
-		clusterInstance.TmpDirectory,
-		clusterInstance.VtTabletExtraArgs,
-		clusterInstance.EnableSemiSync)
-	tablet.Alias = tablet.VttabletProcess.TabletPath
-	tablet.VttabletProcess.SupportsBackup = true
-	tablet.VttabletProcess.Keyspace = restoreKeyspaceName
-	tablet.VttabletProcess.EnableSemiSync = true
-	tablet.VttabletProcess.ExtraArgs = []string{
-		"-disable_active_reparents",
-		"-enable_replication_reporter=false",
-		"-init_db_name_override", dbName,
-		"-init_tablet_type", "replica",
-		"-init_keyspace", restoreKeyspaceName,
-		"-init_shard", shardName,
-		"-binlog_host", binlogServer.hostname,
-		"-binlog_port", fmt.Sprintf("%d", binlogServer.port),
-		"-binlog_user", binlogServer.username,
-		"-pitr_gtid_lookup_timeout", lookupTimeout,
-		"-vreplication_healthcheck_topology_refresh", "1s",
-		"-vreplication_healthcheck_retry_delay", "1s",
-		"-vreplication_tablet_type", "replica",
-		"-vreplication_retry_delay", "1s",
-		"-degraded_threshold", "5s",
-		"-lock_tables_timeout", "5s",
-		"-watch_replication_stream",
-		"-serving_state_grace_period", "1s",
-	}
-	tablet.VttabletProcess.ServingStatus = ""
-
-	err = tablet.VttabletProcess.Setup()
-	require.NoError(t, err)
-
-	tablet.VttabletProcess.WaitForTabletTypesForTimeout([]string{"SERVING"}, 20*time.Second)
-}
diff --git a/go/test/endtoend/tabletmanager/dbnameoverride/tablet_master_test.go b/go/test/endtoend/vtgate/dbnameoverride/tablet_master_test.go
similarity index 85%
rename from go/test/endtoend/tabletmanager/dbnameoverride/tablet_master_test.go
rename to go/test/endtoend/vtgate/dbnameoverride/tablet_master_test.go
index 88fcbc7674..d4bae5200d 100644
--- a/go/test/endtoend/tabletmanager/dbnameoverride/tablet_master_test.go
+++ b/go/test/endtoend/vtgate/dbnameoverride/tablet_master_test.go
@@ -119,3 +119,16 @@ func TestDbNameOverride(t *testing.T) {
 	require.Equal(t, 1, len(qr.Rows), "did not get enough rows back")
 	require.Equal(t, dbName, qr.Rows[0][0].ToString())
 }
+
+func TestInformationSchemaQuery(t *testing.T) {
+	defer cluster.PanicHandler(t)
+	ctx := context.Background()
+	conn, err := mysql.Connect(ctx, &vtParams)
+	require.Nil(t, err)
+	defer conn.Close()
+	qr, err := conn.ExecuteFetch("SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema = 'ks'", 1000, true)
+
+	require.Nil(t, err)
+	require.Equal(t, 1, len(qr.Rows), "did not get enough rows back")
+	require.Equal(t, "t1", qr.Rows[0][0].ToString())
+}
diff --git a/go/test/endtoend/vtgate/misc_test.go b/go/test/endtoend/vtgate/misc_test.go
index d69e06008b..db8fc24e82 100644
--- a/go/test/endtoend/vtgate/misc_test.go
+++ b/go/test/endtoend/vtgate/misc_test.go
@@ -276,18 +276,6 @@ func TestXXHash(t *testing.T) {
 	assertMatches(t, conn, "select phone, keyspace_id from t7_xxhash_idx", `[]`)
 }
 
-func TestShowTablesWithWhereClause(t *testing.T) {
-	defer cluster.PanicHandler(t)
-	ctx := context.Background()
-	conn, err := mysql.Connect(ctx, &vtParams)
-	require.Nil(t, err)
-	defer conn.Close()
-
-	assertMatches(t, conn, "show tables from ks where Tables_in_ks='t6'", `[[VARCHAR("t6")]]`)
-	exec(t, conn, "begin")
-	assertMatches(t, conn, "show tables from ks where Tables_in_ks='t3'", `[[VARCHAR("t3")]]`)
-}
-
 func assertMatches(t *testing.T, conn *mysql.Conn, query, expected string) {
 	t.Helper()
 	qr := exec(t, conn, query)
diff --git a/go/vt/vtexplain/vtexplain_flaky_test.go b/go/vt/vtexplain/vtexplain_flaky_test.go
index fdec04732d..8162ff43f3 100644
--- a/go/vt/vtexplain/vtexplain_flaky_test.go
+++ b/go/vt/vtexplain/vtexplain_flaky_test.go
@@ -216,6 +216,7 @@ func TestJSONOutput(t *testing.T) {
             {
                 "BindVars": {
                     "#maxLimit": "10001",
+                    "__vtschemaname": "''",
                     "vtg1": "1"
                 },
                 "SQL": "select :vtg1 from user where id = :vtg1",
@@ -224,5 +225,8 @@ func TestJSONOutput(t *testing.T) {
         ]
     }
 }`
-	require.Equal(t, wantJSON, string(actionsJSON))
+	diff := cmp.Diff(wantJSON, string(actionsJSON))
+	if diff != "" {
+		t.Errorf(diff)
+	}
 }
diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go
index 0f3eb6046d..cbdb136275 100644
--- a/go/vt/vtgate/executor_select_test.go
+++ b/go/vt/vtgate/executor_select_test.go
@@ -2281,3 +2281,26 @@ func TestSelectLock(t *testing.T) {
 	utils.MustMatch(t, wantQueries, sbc1.Queries, "")
 	utils.MustMatch(t, wantSession, session.Session, "")
 }
+
+func TestSelectFromInformationSchema(t *testing.T) {
+	executor, sbc1, _, _ := createExecutorEnv()
+	session := NewSafeSession(nil)
+
+	// check failure when trying to query two keyspaces
+	_, err := exec(executor, session, "SELECT B.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES AS A, INFORMATION_SCHEMA.COLUMNS AS B WHERE A.TABLE_SCHEMA = 'TestExecutor' AND A.TABLE_SCHEMA = 'TestXBadSharding'")
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "can't use more than one keyspace per system table query - found both 'TestExecutor' and 'TestXBadSharding")
+
+	// we pick a keyspace and query for table_schema = database(). should be routed to the picked keyspace
+	session.TargetString = "TestExecutor"
+	_, err = exec(executor, session, "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = database()")
+	require.NoError(t, err)
+	assert.Equal(t, sbc1.StringQueries(), []string{"select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = database()"})
+
+	// `USE TestXBadSharding` and then query info_schema about TestExecutor - should target TestExecutor and not use the default keyspace
+	sbc1.Queries = nil
+	session.TargetString = "TestXBadSharding"
+	_, err = exec(executor, session, "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'TestExecutor'")
+	require.NoError(t, err)
+	assert.Equal(t, sbc1.StringQueries(), []string{"select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname"})
+}
diff --git a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
index c368362ad1..79d9ddbbd1 100644
--- a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
@@ -1387,3 +1387,42 @@
     "Table": "music"
   }
 }
+
+# query trying to query two different keyspaces at the same time
+"SELECT B.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES AS A, INFORMATION_SCHEMA.COLUMNS AS B WHERE A.TABLE_SCHEMA = 'user' AND A.TABLE_SCHEMA = 'main' AND B.TABLE_NAME = A.TABLE_NAME"
+{
+  "QueryType": "SELECT",
+  "Original": "SELECT B.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES AS A, INFORMATION_SCHEMA.COLUMNS AS B WHERE A.TABLE_SCHEMA = 'user' AND A.TABLE_SCHEMA = 'main' AND B.TABLE_NAME = A.TABLE_NAME",
+  "Instructions": {
+    "OperatorType": "Route",
+    "Variant": "SelectDBA",
+    "Keyspace": {
+      "Name": "main",
+      "Sharded": false
+    },
+    "FieldQuery": "select B.TABLE_NAME from INFORMATION_SCHEMA.`TABLES` as A, INFORMATION_SCHEMA.`COLUMNS` as B where 1 != 1",
+    "Query": "select B.TABLE_NAME from INFORMATION_SCHEMA.`TABLES` as A, INFORMATION_SCHEMA.`COLUMNS` as B where A.TABLE_SCHEMA = :__vtschemaname and A.TABLE_SCHEMA = :__vtschemaname and B.TABLE_NAME = A.TABLE_NAME",
+    "SysTableKeyspaceExpr": [
+      "VARBINARY(\"user\")",
+      "VARBINARY(\"main\")"
+    ]
+  }
+}
+
+# information_schema query using database() func
+"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = database()"
+{
+  "QueryType": "SELECT",
+  "Original": "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = database()",
+  "Instructions": {
+    "OperatorType": "Route",
+    "Variant": "SelectDBA",
+    "Keyspace": {
+      "Name": "main",
+      "Sharded": false
+    },
+    "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1",
+    "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = database()"
+  }
+}
+                
\ No newline at end of file
diff --git a/go/vt/vttablet/tabletmanager/tm_init_test.go b/go/vt/vttablet/tabletmanager/tm_init_test.go
index 81ef2d5cf7..821c4a9750 100644
--- a/go/vt/vttablet/tabletmanager/tm_init_test.go
+++ b/go/vt/vttablet/tabletmanager/tm_init_test.go
@@ -218,13 +218,9 @@ func TestCheckMastership(t *testing.T) {
 	// 2. Update shard's master to our alias, then try to init again.
 	// (This simulates the case where the MasterAlias in the shard record says
 	// that we are the master but the tablet record says otherwise. In that case,
-	// we become master by inheriting the shard record's timestamp.)
-	now := time.Now()
+	// we assume we are not the MASTER.)
 	_, err = ts.UpdateShardFields(ctx, "ks", "0", func(si *topo.ShardInfo) error {
 		si.MasterAlias = alias
-		si.MasterTermStartTime = logutil.TimeToProto(now)
-		// Reassign to now for easier comparison.
-		now = si.GetMasterTermStartTime()
 		return nil
 	})
 	require.NoError(t, err)
@@ -232,9 +228,9 @@ func TestCheckMastership(t *testing.T) {
 	require.NoError(t, err)
 	ti, err = ts.GetTablet(ctx, alias)
 	require.NoError(t, err)
-	assert.Equal(t, topodatapb.TabletType_MASTER, ti.Type)
+	assert.Equal(t, topodatapb.TabletType_REPLICA, ti.Type)
 	ter0 := ti.GetMasterTermStartTime()
-	assert.Equal(t, now, ter0)
+	assert.True(t, ter0.IsZero())
 	tm.Stop()
 
 	// 3. Delete the tablet record. The shard record still says that we are the
@@ -295,25 +291,6 @@ func TestCheckMastership(t *testing.T) {
 	ter4 := ti.GetMasterTermStartTime()
 	assert.Equal(t, ter1, ter4)
 	tm.Stop()
-
-	// 7. If the shard record shows a different master with a newer
-	// timestamp, we remain replica.
-	_, err = ts.UpdateShardFields(ctx, "ks", "0", func(si *topo.ShardInfo) error {
-		si.MasterAlias = otherAlias
-		si.MasterTermStartTime = logutil.TimeToProto(ter4.Add(10 * time.Second))
-		return nil
-	})
-	require.NoError(t, err)
-	tablet.Type = topodatapb.TabletType_REPLICA
-	tablet.MasterTermStartTime = nil
-	err = tm.Start(tablet, 0)
-	require.NoError(t, err)
-	ti, err = ts.GetTablet(ctx, alias)
-	require.NoError(t, err)
-	assert.Equal(t, topodatapb.TabletType_REPLICA, ti.Type)
-	ter5 := ti.GetMasterTermStartTime()
-	assert.True(t, ter5.IsZero())
-	tm.Stop()
 }
 
 func TestStartCheckMysql(t *testing.T) {
diff --git a/go/vt/vttablet/tabletmanager/vreplication/engine_test.go b/go/vt/vttablet/tabletmanager/vreplication/engine_test.go
index dbd095a7a8..3ebb563fa3 100644
--- a/go/vt/vttablet/tabletmanager/vreplication/engine_test.go
+++ b/go/vt/vttablet/tabletmanager/vreplication/engine_test.go
@@ -495,7 +495,6 @@ func TestCreateDBAndTable(t *testing.T) {
 		dbClient.ExpectRequest("DROP TABLE IF EXISTS _vt.blp_checkpoint", &sqltypes.Result{}, nil)
 		dbClient.ExpectRequestRE("CREATE TABLE IF NOT EXISTS _vt.vreplication.*", &sqltypes.Result{}, nil)
 		dbClient.ExpectRequestRE("ALTER TABLE _vt.vreplication ADD COLUMN db_name.*", &sqltypes.Result{}, nil)
-		dbClient.ExpectRequestRE("ALTER TABLE _vt.vreplication MODIFY source.*", &sqltypes.Result{}, nil)
 		dbClient.ExpectRequestRE("create table if not exists _vt.resharding_journal.*", &sqltypes.Result{}, nil)
 		dbClient.ExpectRequestRE("create table if not exists _vt.copy_state.*", &sqltypes.Result{}, nil)
 	}
diff --git a/go/vt/vttablet/tabletserver/planbuilder/plan_test.go b/go/vt/vttablet/tabletserver/planbuilder/plan_test.go
index 34c7e9c87f..f1314592c1 100644
--- a/go/vt/vttablet/tabletserver/planbuilder/plan_test.go
+++ b/go/vt/vttablet/tabletserver/planbuilder/plan_test.go
@@ -72,7 +72,7 @@ func TestPlan(t *testing.T) {
 			var err error
 			statement, err := sqlparser.Parse(tcase.input)
 			if err == nil {
-				plan, err = Build(statement, testSchema, false, "dbName")
+				plan, err = Build(statement, testSchema, false)
 			}
 			PassthroughDMLs = false
 
@@ -109,7 +109,7 @@ func TestPlanPoolUnsafe(t *testing.T) {
 			statement, err := sqlparser.Parse(tcase.input)
 			require.NoError(t, err)
 			// In Pooled Connection, plan building will fail.
-			plan, err = Build(statement, testSchema, false /* isReservedConn */, "dbName")
+			plan, err = Build(statement, testSchema, false /* isReservedConn */)
 			require.Error(t, err)
 			out := err.Error()
 			if out != tcase.output {
@@ -123,7 +123,7 @@ func TestPlanPoolUnsafe(t *testing.T) {
 				fmt.Printf("\"%s\"\n%s\n\n", tcase.input, out)
 			}
 			// In Reserved Connection, plan will be built.
-			plan, err = Build(statement, testSchema, true /* isReservedConn */, "dbName")
+			plan, err = Build(statement, testSchema, true /* isReservedConn */)
 			require.NoError(t, err)
 			require.NotEmpty(t, plan)
 		})
@@ -141,7 +141,7 @@ func TestPlanInReservedConn(t *testing.T) {
 			var err error
 			statement, err := sqlparser.Parse(tcase.input)
 			if err == nil {
-				plan, err = Build(statement, testSchema, true, "dbName")
+				plan, err = Build(statement, testSchema, true)
 			}
 			PassthroughDMLs = false
 
@@ -192,7 +192,7 @@ func TestCustom(t *testing.T) {
 				if err != nil {
 					t.Fatalf("Got error: %v, parsing sql: %v", err.Error(), tcase.input)
 				}
-				plan, err := Build(statement, schem, false, "dbName")
+				plan, err := Build(statement, schem, false)
 				var out string
 				if err != nil {
 					out = err.Error()
diff --git a/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt b/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt
index 79f9063187..185afbafd8 100644
--- a/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt
+++ b/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt
@@ -787,19 +787,3 @@ options:PassthroughDMLs
 # syntax error
 "syntax error"
 "syntax error at position 7 near 'syntax'"
-
-# show tables #1
-"show tables like 'key%'"
-{
-  "PlanID": "ShowTables",
-  "TableName":"",
-  "FullQuery": "show tables like 'key%'"
-}
-
-# show tables #2
-"show tables where Tables_in_keyspace='apa'"
-{
-  "PlanID": "ShowTables",
-  "TableName":"",
-  "FullQuery": "show tables where Tables_in_dbName = 'apa'"
-}
diff --git a/go/vt/wrangler/testlib/emergency_reparent_shard_test.go b/go/vt/wrangler/testlib/emergency_reparent_shard_test.go
index 217f29e1bc..58dde99388 100644
--- a/go/vt/wrangler/testlib/emergency_reparent_shard_test.go
+++ b/go/vt/wrangler/testlib/emergency_reparent_shard_test.go
@@ -171,13 +171,27 @@ func TestEmergencyReparentShard(t *testing.T) {
 	waitReplicaTimeout := time.Second * 2
 	err := vp.Run([]string{"EmergencyReparentShard", "-wait_replicas_timeout", waitReplicaTimeout.String(), newMaster.Tablet.Keyspace + "/" + newMaster.Tablet.Shard,
 		topoproto.TabletAliasString(newMaster.Tablet.Alias)})
+	buffer := 100 * time.Millisecond
+	time.Sleep(waitReplicaTimeout + buffer)
 	require.NoError(t, err)
 	// check what was run
 	err = newMaster.FakeMysqlDaemon.CheckSuperQueryList()
 	require.NoError(t, err)
+	err = oldMaster.FakeMysqlDaemon.CheckSuperQueryList()
+	require.NoError(t, err)
+	err = goodReplica1.FakeMysqlDaemon.CheckSuperQueryList()
+	require.NoError(t, err)
+	err = goodReplica2.FakeMysqlDaemon.CheckSuperQueryList()
+	require.NoError(t, err)
 
 	assert.False(t, newMaster.FakeMysqlDaemon.ReadOnly, "newMaster.FakeMysqlDaemon.ReadOnly set")
+	// old master read-only flag doesn't matter, it is scrapped
+	assert.True(t, goodReplica1.FakeMysqlDaemon.ReadOnly, "goodReplica1.FakeMysqlDaemon.ReadOnly not set")
+	assert.True(t, goodReplica2.FakeMysqlDaemon.ReadOnly, "goodReplica2.FakeMysqlDaemon.ReadOnly not set")
+	assert.True(t, goodReplica1.FakeMysqlDaemon.Replicating, "goodReplica1.FakeMysqlDaemon.Replicating not set")
+	assert.False(t, goodReplica2.FakeMysqlDaemon.Replicating, "goodReplica2.FakeMysqlDaemon.Replicating set")
 	checkSemiSyncEnabled(t, true, true, newMaster)
+	checkSemiSyncEnabled(t, false, true, goodReplica1, goodReplica2)
 }
 
 // TestEmergencyReparentShardMasterElectNotBest tries to emergency reparent
diff --git a/go/vt/wrangler/vexec_test.go b/go/vt/wrangler/vexec_test.go
index cb38d1570a..8a85b11dc2 100644
--- a/go/vt/wrangler/vexec_test.go
+++ b/go/vt/wrangler/vexec_test.go
@@ -188,94 +188,75 @@ func TestWorkflowListStreams(t *testing.T) {
 	logger := logutil.NewMemoryLogger()
 	wr := New(logger, env.topoServ, env.tmc)
 
-	_, err := wr.ShowWorkflow(ctx, workflow, keyspace)
+	err := wr.listStreams(ctx, workflow, keyspace)
 	require.Nil(t, err)
 	want := `{
 	"Workflow": "wrWorkflow",
-	"SourceLocation": {
-		"Keyspace": "source",
-		"Shards": [
-			"0"
-		]
-	},
-	"TargetLocation": {
-		"Keyspace": "target",
-		"Shards": [
-			"-80",
-			"80-"
+	"SourceKeyspace": "source",
+	"TargetKeyspace": "target",
+	"Statuses": {
+		"-80/zone1-0000000200": [
+			{
+				"Shard": "-80",
+				"Tablet": "zone1-0000000200",
+				"ID": 1,
+				"Bls": {
+					"keyspace": "source",
+					"shard": "0",
+					"filter": {
+						"rules": [
+							{
+								"match": "t1"
+							}
+						]
+					}
+				},
+				"Pos": "pos",
+				"StopPos": "",
+				"State": "Copying",
+				"MaxReplicationLag": 0,
+				"DBName": "vt_target",
+				"TimeUpdated": 1234,
+				"Message": "",
+				"CopyState": [
+					{
+						"Table": "t",
+						"LastPK": "1"
+					}
+				]
+			}
+		],
+		"80-/zone1-0000000210": [
+			{
+				"Shard": "80-",
+				"Tablet": "zone1-0000000210",
+				"ID": 1,
+				"Bls": {
+					"keyspace": "source",
+					"shard": "0",
+					"filter": {
+						"rules": [
+							{
+								"match": "t1"
+							}
+						]
+					}
+				},
+				"Pos": "pos",
+				"StopPos": "",
+				"State": "Copying",
+				"MaxReplicationLag": 0,
+				"DBName": "vt_target",
+				"TimeUpdated": 1234,
+				"Message": "",
+				"CopyState": [
+					{
+						"Table": "t",
+						"LastPK": "1"
+					}
+				]
+			}
 		]
-	},
-	"ShardStatuses": {
-		"-80/zone1-0000000200": {
-			"MasterReplicationStatuses": [
-				{
-					"Shard": "-80",
-					"Tablet": "zone1-0000000200",
-					"ID": 1,
-					"Bls": {
-						"keyspace": "source",
-						"shard": "0",
-						"filter": {
-							"rules": [
-								{
-									"match": "t1"
-								}
-							]
-						}
-					},
-					"Pos": "pos",
-					"StopPos": "",
-					"State": "Copying",
-					"MaxReplicationLag": 0,
-					"DBName": "vt_target",
-					"TimeUpdated": 1234,
-					"Message": "",
-					"CopyState": [
-						{
-							"Table": "t",
-							"LastPK": "1"
-						}
-					]
-				}
-			],
-			"TabletControls": null,
-			"MasterIsServing": true
-		},
-		"80-/zone1-0000000210": {
-			"MasterReplicationStatuses": [
-				{
-					"Shard": "80-",
-					"Tablet": "zone1-0000000210",
-					"ID": 1,
-					"Bls": {
-						"keyspace": "source",
-						"shard": "0",
-						"filter": {
-							"rules": [
-								{
-									"match": "t1"
-								}
-							]
-						}
-					},
-					"Pos": "pos",
-					"StopPos": "",
-					"State": "Copying",
-					"MaxReplicationLag": 0,
-					"DBName": "vt_target",
-					"TimeUpdated": 1234,
-					"Message": "",
-					"CopyState": [
-						{
-							"Table": "t",
-							"LastPK": "1"
-						}
-					]
-				}
-			],
-			"TabletControls": null,
-			"MasterIsServing": true
-		}
 	}
 }