Repository: vitessio/vitess
Pull request #7072 (2020-11-24 02:53:35)

Support statsd for vitess
This tries to address https://github.com/vitessio/vitess/issues/7064 and add very basic initial supports for statsd (we might need to tweak it a bit more later)

This PR mainly does 2 things:
1. Make statsd available as a plugin for VTTablet and VTGate
2. Export `stats.Timings` as histogram for now until we have better solution to store and export metrics directly as statsd.timing




Patch:
diff --git a/go.mod b/go.mod
index 19d3687ecd..2428cc21e9 100644
--- a/go.mod
+++ b/go.mod
@@ -9,6 +9,7 @@ require (
 	github.com/Azure/azure-storage-blob-go v0.10.0
 	github.com/Azure/go-autorest/autorest v0.10.0
 	github.com/Azure/go-autorest/autorest/validation v0.3.0 // indirect
+	github.com/DataDog/datadog-go v2.2.0+incompatible
 	github.com/GeertJohan/go.rice v1.0.0
 	github.com/PuerkitoBio/goquery v1.5.1
 	github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6
diff --git a/go/cmd/vtgate/plugin_statsd.go b/go/cmd/vtgate/plugin_statsd.go
new file mode 100644
index 0000000000..ae2ecb5b2e
--- /dev/null
+++ b/go/cmd/vtgate/plugin_statsd.go
@@ -0,0 +1,7 @@
+package main
+
+import "vitess.io/vitess/go/stats/statsd"
+
+func init() {
+	statsd.Init("vtgate")
+}
diff --git a/go/cmd/vttablet/plugin_statsd.go b/go/cmd/vttablet/plugin_statsd.go
new file mode 100644
index 0000000000..51761e6c40
--- /dev/null
+++ b/go/cmd/vttablet/plugin_statsd.go
@@ -0,0 +1,7 @@
+package main
+
+import "vitess.io/vitess/go/stats/statsd"
+
+func init() {
+	statsd.Init("vttablet")
+}
diff --git a/go/stats/statsd/statsd.go b/go/stats/statsd/statsd.go
new file mode 100644
index 0000000000..61f33f9acc
--- /dev/null
+++ b/go/stats/statsd/statsd.go
@@ -0,0 +1,227 @@
+package statsd
+
+import (
+	"encoding/json"
+	"expvar"
+	"flag"
+	"fmt"
+	"strings"
+
+	"github.com/DataDog/datadog-go/statsd"
+	"vitess.io/vitess/go/stats"
+	"vitess.io/vitess/go/vt/log"
+	"vitess.io/vitess/go/vt/servenv"
+)
+
+var (
+	statsdAddress    = flag.String("statsd_address", "", "Address for statsd client")
+	statsdSampleRate = flag.Float64("statsd_sample_rate", 1.0, "")
+)
+
+// StatsBackend implements PullBackend using statsd
+type StatsBackend struct {
+	namespace    string
+	statsdClient *statsd.Client
+	sampleRate   float64
+}
+
+var (
+	sb StatsBackend
+)
+
+// makeLabel builds a tag list with a single label + value.
+func makeLabel(labelName string, labelVal string) []string {
+	return []string{fmt.Sprintf("%s:%s", labelName, labelVal)}
+}
+
+// makeLabels takes the vitess stat representation of label values ("."-separated list) and breaks it
+// apart into a map of label name -> label value.
+func makeLabels(labelNames []string, labelValsCombined string) []string {
+	tags := make([]string, len(labelNames))
+	labelVals := strings.Split(labelValsCombined, ".")
+	for i, v := range labelVals {
+		tags[i] = fmt.Sprintf("%s:%s", labelNames[i], v)
+	}
+	return tags
+}
+
+func (sb StatsBackend) addHistogram(name string, h *stats.Histogram, tags []string) {
+	labels := h.Labels()
+	buckets := h.Buckets()
+	for i := range labels {
+		name := fmt.Sprintf("%s.%s", name, labels[i])
+		sb.statsdClient.Gauge(name, float64(buckets[i]), tags, sb.sampleRate)
+	}
+	sb.statsdClient.Gauge(fmt.Sprintf("%s.%s", name, h.CountLabel()),
+		(float64)(h.Count()),
+		tags,
+		sb.sampleRate,
+	)
+	sb.statsdClient.Gauge(fmt.Sprintf("%s.%s", name, h.TotalLabel()),
+		(float64)(h.Total()),
+		tags,
+		sb.sampleRate,
+	)
+}
+
+// Init initializes the statsd with the given namespace.
+func Init(namespace string) {
+	servenv.OnRun(func() {
+		if *statsdAddress == "" {
+			return
+		}
+		statsdC, err := statsd.NewBuffered(*statsdAddress, 100)
+		if err != nil {
+			log.Errorf("Failed to create statsd client %v", err)
+			return
+		}
+		statsdC.Namespace = namespace + "."
+		sb.namespace = namespace
+		sb.statsdClient = statsdC
+		sb.sampleRate = *statsdSampleRate
+		stats.RegisterPushBackend("statsd", sb)
+	})
+}
+
+func (sb StatsBackend) addExpVar(kv expvar.KeyValue) {
+	k := kv.Key
+	switch v := kv.Value.(type) {
+	case *stats.String:
+		if err := sb.statsdClient.Set(k, v.Get(), nil, sb.sampleRate); err != nil {
+			log.Errorf("Failed to add String %v for key %v", v, k)
+		}
+	case *stats.Counter:
+		if err := sb.statsdClient.Count(k, v.Get(), nil, sb.sampleRate); err != nil {
+			log.Errorf("Failed to add Counter %v for key %v", v, k)
+		}
+	case *stats.Gauge:
+		if err := sb.statsdClient.Gauge(k, float64(v.Get()), nil, sb.sampleRate); err != nil {
+			log.Errorf("Failed to add Gauge %v for key %v", v, k)
+		}
+	case *stats.GaugeFunc:
+		if err := sb.statsdClient.Gauge(k, float64(v.F()), nil, sb.sampleRate); err != nil {
+			log.Errorf("Failed to add GaugeFunc %v for key %v", v, k)
+		}
+	case *stats.CounterFunc:
+		if err := sb.statsdClient.Gauge(k, float64(v.F()), nil, sb.sampleRate); err != nil {
+			log.Errorf("Failed to add CounterFunc %v for key %v", v, k)
+		}
+	case *stats.CounterDuration:
+		if err := sb.statsdClient.TimeInMilliseconds(k, float64(v.Get().Milliseconds()), nil, sb.sampleRate); err != nil {
+			log.Errorf("Failed to add CounterDuration %v for key %v", v, k)
+		}
+	case *stats.CounterDurationFunc:
+		if err := sb.statsdClient.TimeInMilliseconds(k, float64(v.F().Milliseconds()), nil, sb.sampleRate); err != nil {
+			log.Errorf("Failed to add CounterDuration %v for key %v", v, k)
+		}
+	case *stats.GaugeDuration:
+		if err := sb.statsdClient.TimeInMilliseconds(k, float64(v.Get().Milliseconds()), nil, sb.sampleRate); err != nil {
+			log.Errorf("Failed to add GaugeDuration %v for key %v", v, k)
+		}
+	case *stats.GaugeDurationFunc:
+		if err := sb.statsdClient.TimeInMilliseconds(k, float64(v.F().Milliseconds()), nil, sb.sampleRate); err != nil {
+			log.Errorf("Failed to add GaugeDuration %v for key %v", v, k)
+		}
+	case *stats.CountersWithSingleLabel:
+		for labelVal, val := range v.Counts() {
+			if err := sb.statsdClient.Count(k, val, makeLabel(v.Label(), labelVal), sb.sampleRate); err != nil {
+				log.Errorf("Failed to add CountersWithSingleLabel %v for key %v", v, k)
+			}
+		}
+	case *stats.CountersWithMultiLabels:
+		for labelVals, val := range v.Counts() {
+			if err := sb.statsdClient.Count(k, val, makeLabels(v.Labels(), labelVals), sb.sampleRate); err != nil {
+				log.Errorf("Failed to add CountersFuncWithMultiLabels %v for key %v", v, k)
+			}
+		}
+	case *stats.CountersFuncWithMultiLabels:
+		for labelVals, val := range v.Counts() {
+			if err := sb.statsdClient.Count(k, val, makeLabels(v.Labels(), labelVals), sb.sampleRate); err != nil {
+				log.Errorf("Failed to add CountersFuncWithMultiLabels %v for key %v", v, k)
+			}
+		}
+	case *stats.GaugesWithMultiLabels:
+		for labelVals, val := range v.Counts() {
+			if err := sb.statsdClient.Gauge(k, float64(val), makeLabels(v.Labels(), labelVals), sb.sampleRate); err != nil {
+				log.Errorf("Failed to add GaugesWithMultiLabels %v for key %v", v, k)
+			}
+		}
+	case *stats.GaugesFuncWithMultiLabels:
+		for labelVals, val := range v.Counts() {
+			if err := sb.statsdClient.Gauge(k, float64(val), makeLabels(v.Labels(), labelVals), sb.sampleRate); err != nil {
+				log.Errorf("Failed to add GaugesFuncWithMultiLabels %v for key %v", v, k)
+			}
+		}
+	case *stats.GaugesWithSingleLabel:
+		for labelVal, val := range v.Counts() {
+			if err := sb.statsdClient.Gauge(k, float64(val), makeLabel(v.Label(), labelVal), sb.sampleRate); err != nil {
+				log.Errorf("Failed to add GaugesWithSingleLabel %v for key %v", v, k)
+			}
+		}
+	case *stats.MultiTimings:
+		labels := v.Labels()
+		hists := v.Histograms()
+		for labelValsCombined, histogram := range hists {
+			sb.addHistogram(k, histogram, makeLabels(labels, labelValsCombined))
+		}
+	case *stats.Timings:
+		// TODO: for statsd.timing metrics, there is no good way to transfer the histogram to it
+		// If we store a in memory buffer for stats.Timings and flush it here it's hard to make the stats
+		// thread safe.
+		// Instead, we export the timings stats as histogram here. We won't have the percentile breakdown
+		// for the metrics, but we can still get the average from total and count
+		labels := []string{v.Label()}
+		hists := v.Histograms()
+		for labelValsCombined, histogram := range hists {
+			sb.addHistogram(k, histogram, makeLabels(labels, labelValsCombined))
+		}
+	case *stats.Histogram:
+		sb.addHistogram(k, v, []string{})
+	case expvar.Func:
+		// Export memstats as gauge so that we don't need to call extra ReadMemStats
+		if k == "memstats" {
+			var obj map[string]interface{}
+			if err := json.Unmarshal([]byte(v.String()), &obj); err != nil {
+				return
+			}
+			for k, v := range obj {
+				if k == "NumGC" {
+					if err := sb.statsdClient.Gauge("NumGC", v.(float64), []string{}, sb.sampleRate); err != nil {
+						log.Errorf("Failed to export NumGC %v", v)
+					}
+				} else if k == "Frees" {
+					if err := sb.statsdClient.Gauge("Frees", v.(float64), []string{}, sb.sampleRate); err != nil {
+						log.Errorf("Failed to export Frees %v", v)
+					}
+				} else if k == "GCCPUFraction" {
+					if err := sb.statsdClient.Gauge("GCCPUFraction", v.(float64), []string{}, sb.sampleRate); err != nil {
+						log.Errorf("Failed to export GCCPUFraction %v", v)
+					}
+				} else if k == "PauseTotalNs" {
+					if err := sb.statsdClient.Gauge("PauseTotalNs", v.(float64), []string{}, sb.sampleRate); err != nil {
+						log.Errorf("Failed to export PauseTotalNs %v", v)
+					}
+				} else if k == "HeapAlloc" {
+					if err := sb.statsdClient.Gauge("HeapAlloc", v.(float64), []string{}, sb.sampleRate); err != nil {
+						log.Errorf("Failed to export HeapAlloc %v", v)
+					}
+				}
+			}
+		}
+	case *stats.StringMapFunc, *stats.Rates, *stats.RatesFunc:
+		// Silently ignore metrics that does not make sense to be exported to statsd
+	default:
+		log.Warningf("Silently ignore metrics with key %v [%T]", k, kv.Value)
+	}
+}
+
+// PushAll flush out the pending metrics
+func (sb StatsBackend) PushAll() error {
+	expvar.Do(func(kv expvar.KeyValue) {
+		sb.addExpVar(kv)
+	})
+	if err := sb.statsdClient.Flush(); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/go/vt/key/key.go b/go/vt/key/key.go
index 90f076403a..98143a1ff1 100644
--- a/go/vt/key/key.go
+++ b/go/vt/key/key.go
@@ -289,16 +289,10 @@ func KeyRangeIncludes(big, small *topodatapb.KeyRange) bool {
 // specification. a-b-c-d will be parsed as a-b, b-c, c-d. The empty
 // string may serve both as the start and end of the keyspace: -a-b-
 // will be parsed as start-a, a-b, b-end.
-// "0" is treated as "-", to allow us to not have to special-case
-// client code.
 func ParseShardingSpec(spec string) ([]*topodatapb.KeyRange, error) {
 	parts := strings.Split(spec, "-")
 	if len(parts) == 1 {
-		if spec == "0" {
-			parts = []string{"", ""}
-		} else {
-			return nil, fmt.Errorf("malformed spec: doesn't define a range: %q", spec)
-		}
+		return nil, fmt.Errorf("malformed spec: doesn't define a range: %q", spec)
 	}
 	old := parts[0]
 	ranges := make([]*topodatapb.KeyRange, len(parts)-1)
diff --git a/go/vt/sqlparser/parse_table.go b/go/vt/sqlparser/parse_table.go
deleted file mode 100644
index a8431aacc0..0000000000
--- a/go/vt/sqlparser/parse_table.go
+++ /dev/null
@@ -1,66 +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 sqlparser
-
-import (
-	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
-	"vitess.io/vitess/go/vt/vterrors"
-)
-
-// ParseTable parses the input as a qualified table name.
-// It handles all valid literal escaping.
-func ParseTable(input string) (keyspace, table string, err error) {
-	tokenizer := NewStringTokenizer(input)
-
-	// Start, want ID
-	token, value := tokenizer.Scan()
-	switch token {
-	case ID:
-		table = string(value)
-	default:
-		return "", "", vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid table name: %s", input)
-	}
-
-	// Seen first ID, want '.' or 0
-	token, _ = tokenizer.Scan()
-	switch token {
-	case '.':
-		keyspace = table
-	case 0:
-		return keyspace, table, nil
-	default:
-		return "", "", vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid table name: %s", input)
-	}
-
-	// Seen '.', want ID
-	token, value = tokenizer.Scan()
-	switch token {
-	case ID:
-		table = string(value)
-	default:
-		return "", "", vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid table name: %s", input)
-	}
-
-	// Seen second ID, want 0
-	token, _ = tokenizer.Scan()
-	switch token {
-	case 0:
-		return keyspace, table, nil
-	default:
-		return "", "", vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "invalid table name: %s", input)
-	}
-}
diff --git a/go/vt/vtgate/engine/primitive.go b/go/vt/vtgate/engine/primitive.go
index 93875593c1..966a1cd0f7 100644
--- a/go/vt/vtgate/engine/primitive.go
+++ b/go/vt/vtgate/engine/primitive.go
@@ -53,7 +53,6 @@ type (
 		// Context returns the context of the current request.
 		Context() context.Context
 
-		GetKeyspace() string
 		// MaxMemoryRows returns the maxMemoryRows flag value.
 		MaxMemoryRows() int
 
diff --git a/go/vt/vtgate/engine/vindex_func.go b/go/vt/vtgate/engine/vindex_func.go
index eb1c3b50b8..d301b238bb 100644
--- a/go/vt/vtgate/engine/vindex_func.go
+++ b/go/vt/vtgate/engine/vindex_func.go
@@ -18,7 +18,6 @@ package engine
 
 import (
 	"encoding/json"
-	"fmt"
 
 	"vitess.io/vitess/go/vt/vtgate/evalengine"
 
@@ -132,25 +131,10 @@ func (vf *VindexFunc) mapVindex(vcursor VCursor, bindVars map[string]*querypb.Bi
 		}
 	case key.DestinationKeyspaceID:
 		if len(d) > 0 {
-			if vcursor != nil {
-				resolvedShards, _, err := vcursor.ResolveDestinations(vcursor.GetKeyspace(), nil, []key.Destination{d})
-				if err != nil {
-					return nil, err
-				}
-				kr, err := key.ParseShardingSpec(resolvedShards[0].Target.Shard)
-				if err != nil {
-					return nil, err
-				}
-				result.Rows = [][]sqltypes.Value{
-					vf.buildRow(vkey, d, kr[0]),
-				}
-				result.RowsAffected = 1
-			} else {
-				result.Rows = [][]sqltypes.Value{
-					vf.buildRow(vkey, d, nil),
-				}
-				result.RowsAffected = 1
+			result.Rows = [][]sqltypes.Value{
+				vf.buildRow(vkey, d, nil),
 			}
+			result.RowsAffected = 1
 		}
 	case key.DestinationKeyspaceIDs:
 		for _, ksid := range d {
@@ -189,18 +173,6 @@ func (vf *VindexFunc) buildRow(id sqltypes.Value, ksid []byte, kr *topodatapb.Ke
 			} else {
 				row = append(row, sqltypes.NULL)
 			}
-		case 4:
-			if ksid != nil {
-				row = append(row, sqltypes.NewVarBinary(fmt.Sprintf("%x", ksid)))
-			} else {
-				row = append(row, sqltypes.NULL)
-			}
-		case 5:
-			if ksid != nil {
-				row = append(row, sqltypes.NewVarBinary(key.KeyRangeString(kr)))
-			} else {
-				row = append(row, sqltypes.NULL)
-			}
 		default:
 			panic("BUG: unexpected column number")
 		}
diff --git a/go/vt/vtgate/planbuilder/vindex_func.go b/go/vt/vtgate/planbuilder/vindex_func.go
index e29eb7a230..8891e42a0a 100644
--- a/go/vt/vtgate/planbuilder/vindex_func.go
+++ b/go/vt/vtgate/planbuilder/vindex_func.go
@@ -61,8 +61,6 @@ func newVindexFunc(alias sqlparser.TableName, vindex vindexes.SingleColumn) (*vi
 	t.addColumn(sqlparser.NewColIdent("keyspace_id"), &column{origin: vf})
 	t.addColumn(sqlparser.NewColIdent("range_start"), &column{origin: vf})
 	t.addColumn(sqlparser.NewColIdent("range_end"), &column{origin: vf})
-	t.addColumn(sqlparser.NewColIdent("hex_keyspace_id"), &column{origin: vf})
-	t.addColumn(sqlparser.NewColIdent("shard"), &column{origin: vf})
 	t.isAuthoritative = true
 
 	st := newSymtab()
diff --git a/go/vt/vtgate/vcursor_impl.go b/go/vt/vtgate/vcursor_impl.go
index 091d9ca5a2..41e86ef624 100644
--- a/go/vt/vtgate/vcursor_impl.go
+++ b/go/vt/vtgate/vcursor_impl.go
@@ -99,10 +99,6 @@ type vcursorImpl struct {
 	vm                    VSchemaOperator
 }
 
-func (vc *vcursorImpl) GetKeyspace() string {
-	return vc.keyspace
-}
-
 func (vc *vcursorImpl) ExecuteVSchema(keyspace string, vschemaDDL *sqlparser.DDL) error {
 	srvVschema := vc.vm.GetCurrentSrvVschema()
 	if srvVschema == nil {
diff --git a/go/vt/vtgate/vindexes/vschema.go b/go/vt/vtgate/vindexes/vschema.go
index 8046572a9b..ff7a041e24 100644
--- a/go/vt/vtgate/vindexes/vschema.go
+++ b/go/vt/vtgate/vindexes/vschema.go
@@ -22,6 +22,7 @@ import (
 	"fmt"
 	"io/ioutil"
 	"sort"
+	"strings"
 
 	"vitess.io/vitess/go/json2"
 	"vitess.io/vitess/go/sqltypes"
@@ -351,11 +352,7 @@ func resolveAutoIncrement(source *vschemapb.SrvVSchema, vschema *VSchema) {
 			if t == nil || table.AutoIncrement == nil {
 				continue
 			}
-			seqks, seqtab, err := sqlparser.ParseTable(table.AutoIncrement.Sequence)
-			var seq *Table
-			if err == nil {
-				seq, err = vschema.FindTable(seqks, seqtab)
-			}
+			seq, err := vschema.findQualified(table.AutoIncrement.Sequence)
 			if err != nil {
 				// Better to remove the table than to leave it partially initialized.
 				delete(ksvschema.Tables, tname)
@@ -413,20 +410,14 @@ outer:
 				}
 				continue outer
 			}
-			toks, totabname, err := sqlparser.ParseTable(toTable)
-			if err != nil {
-				vschema.RoutingRules[rule.FromTable] = &RoutingRule{
-					Error: err,
-				}
-				continue outer
-			}
-			if toks == "" {
+			parts := strings.Split(toTable, ".")
+			if len(parts) != 2 {
 				vschema.RoutingRules[rule.FromTable] = &RoutingRule{
 					Error: fmt.Errorf("table %s must be qualified", toTable),
 				}
 				continue outer
 			}
-			t, err := vschema.FindTable(toks, totabname)
+			t, err := vschema.FindTable(parts[0], parts[1])
 			if err != nil {
 				vschema.RoutingRules[rule.FromTable] = &RoutingRule{
 					Error: err,
@@ -439,6 +430,18 @@ outer:
 	}
 }
 
+// findQualified finds a table t or k.t.
+func (vschema *VSchema) findQualified(name string) (*Table, error) {
+	splits := strings.Split(name, ".")
+	switch len(splits) {
+	case 1:
+		return vschema.FindTable("", splits[0])
+	case 2:
+		return vschema.FindTable(splits[0], splits[1])
+	}
+	return nil, fmt.Errorf("table %s not found", name)
+}
+
 // FindTable returns a pointer to the Table. If a keyspace is specified, only tables
 // from that keyspace are searched. If the specified keyspace is unsharded
 // and no tables matched, it's considered valid: FindTable will construct a table
diff --git a/go/vt/vtgate/vtgate.go b/go/vt/vtgate/vtgate.go
index 84870af533..2df81025c3 100644
--- a/go/vt/vtgate/vtgate.go
+++ b/go/vt/vtgate/vtgate.go
@@ -61,7 +61,7 @@ var (
 	_                  = flag.Bool("disable_local_gateway", false, "deprecated: if specified, this process will not route any queries to local tablets in the local cell")
 	maxMemoryRows      = flag.Int("max_memory_rows", 300000, "Maximum number of rows that will be held in memory for intermediate results as well as the final result.")
 	warnMemoryRows     = flag.Int("warn_memory_rows", 30000, "Warning threshold for in-memory results. A row count higher than this amount will cause the VtGateWarnings.ResultsExceeded counter to be incremented.")
-	defaultDDLStrategy = flag.String("ddl_strategy", "", "Set default strategy for DDL statements. Override with @@ddl_strategy session variable")
+	defaultDDLStrategy = flag.String("ddl-strategy", "", "Set default strategy for DDL statements. Override with @@ddl_strategy session variable")
 
 	// TODO(deepthi): change these two vars to unexported and move to healthcheck.go when LegacyHealthcheck is removed
 
@@ -168,7 +168,7 @@ func Init(ctx context.Context, serv srvtopo.Server, cell string, tabletTypesToWa
 	}
 
 	if _, _, err := schema.ParseDDLStrategy(*defaultDDLStrategy); err != nil {
-		log.Fatalf("Invalid value for -ddl_strategy: %v", err.Error())
+		log.Fatalf("Invalid value for --ddl-strategy: %v", err.Error())
 	}
 	tc := NewTxConn(gw, getTxMode())
 	// ScatterConn depends on TxConn to perform forced rollbacks.


Test patch:
diff --git a/go/stats/statsd/statsd_test.go b/go/stats/statsd/statsd_test.go
new file mode 100644
index 0000000000..9d115bd44a
--- /dev/null
+++ b/go/stats/statsd/statsd_test.go
@@ -0,0 +1,495 @@
+package statsd
+
+import (
+	"expvar"
+	"net"
+	"sort"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/DataDog/datadog-go/statsd"
+	"gotest.tools/assert"
+	"vitess.io/vitess/go/stats"
+)
+
+func getBackend(t *testing.T) (StatsBackend, *net.UDPConn) {
+	addr := "localhost:1201"
+	udpAddr, _ := net.ResolveUDPAddr("udp", addr)
+	server, _ := net.ListenUDP("udp", udpAddr)
+	bufferLength := 9
+	client, _ := statsd.NewBuffered(addr, bufferLength)
+	client.Namespace = "test."
+	var sb StatsBackend
+	sb.namespace = "foo"
+	sb.sampleRate = 1
+	sb.statsdClient = client
+	return sb, server
+}
+
+func TestStatsdString(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "string_name"
+	stats.NewString(name).Set("foo")
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := string(bytes[:n])
+			expected := "test.string_name:foo|s"
+			assert.Equal(t, result, expected)
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdCounter(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "counter_name"
+	c := stats.NewCounter(name, "counter description")
+	c.Add(1)
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		found = true
+		if kv.Key == name {
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := string(bytes[:n])
+			expected := "test.counter_name:1|c"
+			assert.Equal(t, result, expected)
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdGauge(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "gauge_name"
+	s := stats.NewGauge(name, "help")
+	s.Set(10)
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := string(bytes[:n])
+			expected := "test.gauge_name:10.000000|g"
+			assert.Equal(t, result, expected)
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdGaugeFunc(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "gauge_func_name"
+	stats.NewGaugeFunc(name, "help", func() int64 {
+		return 2
+	})
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := string(bytes[:n])
+			expected := "test.gauge_func_name:2.000000|g"
+			assert.Equal(t, result, expected)
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdCounterDuration(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "counter_duration_name"
+	s := stats.NewCounterDuration(name, "help")
+	s.Add(1 * time.Millisecond)
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := string(bytes[:n])
+			expected := "test.counter_duration_name:1.000000|ms"
+			assert.Equal(t, result, expected)
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdCountersWithSingleLabel(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "counter_with_single_label_name"
+	s := stats.NewCountersWithSingleLabel(name, "help", "label", "tag1", "tag2")
+	s.Add("tag1", 2)
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := strings.Split(string(bytes[:n]), "\n")
+			sort.Strings(result)
+			expected := []string{
+				"test.counter_with_single_label_name:0|c|#label:tag2",
+				"test.counter_with_single_label_name:2|c|#label:tag1",
+			}
+			for i, res := range result {
+				assert.Equal(t, res, expected[i])
+			}
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdCountersWithMultiLabels(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "counter_with_multiple_label_name"
+	s := stats.NewCountersWithMultiLabels(name, "help", []string{"label1", "label2"})
+	s.Add([]string{"foo", "bar"}, 1)
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := string(bytes[:n])
+			expected := "test.counter_with_multiple_label_name:1|c|#label1:foo,label2:bar"
+			assert.Equal(t, result, expected)
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdCountersFuncWithMultiLabels(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "counter_func_with_multiple_labels_name"
+	stats.NewCountersFuncWithMultiLabels(name, "help", []string{"label1", "label2"}, func() map[string]int64 {
+		m := make(map[string]int64)
+		m["foo.bar"] = 1
+		m["bar.baz"] = 2
+		return m
+	})
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := strings.Split(string(bytes[:n]), "\n")
+			sort.Strings(result)
+			expected := []string{
+				"test.counter_func_with_multiple_labels_name:1|c|#label1:foo,label2:bar",
+				"test.counter_func_with_multiple_labels_name:2|c|#label1:bar,label2:baz",
+			}
+			for i, res := range result {
+				assert.Equal(t, res, expected[i])
+			}
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdGaugesWithMultiLabels(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "gauges_with_multiple_label_name"
+	s := stats.NewGaugesWithMultiLabels(name, "help", []string{"label1", "label2"})
+	s.Add([]string{"foo", "bar"}, 3)
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := string(bytes[:n])
+			expected := "test.gauges_with_multiple_label_name:3.000000|g|#label1:foo,label2:bar"
+			assert.Equal(t, result, expected)
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdGaugesFuncWithMultiLabels(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "gauges_func_with_multiple_labels_name"
+	stats.NewGaugesFuncWithMultiLabels(name, "help", []string{"label1", "label2"}, func() map[string]int64 {
+		m := make(map[string]int64)
+		m["foo.bar"] = 1
+		m["bar.baz"] = 2
+		return m
+	})
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := strings.Split(string(bytes[:n]), "\n")
+			sort.Strings(result)
+			expected := []string{
+				"test.gauges_func_with_multiple_labels_name:1.000000|g|#label1:foo,label2:bar",
+				"test.gauges_func_with_multiple_labels_name:2.000000|g|#label1:bar,label2:baz",
+			}
+			for i, res := range result {
+				assert.Equal(t, res, expected[i])
+			}
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdGaugesWithSingleLabel(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "gauges_with_single_label_name"
+	s := stats.NewGaugesWithSingleLabel(name, "help", "label1")
+	s.Add("bar", 1)
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := string(bytes[:n])
+			expected := "test.gauges_with_single_label_name:1.000000|g|#label1:bar"
+			assert.Equal(t, result, expected)
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdMultiTimings(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "multi_timings_name"
+	s := stats.NewMultiTimings(name, "help", []string{"label1", "label2"})
+	s.Add([]string{"foo", "bar"}, 10*time.Millisecond)
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 49152)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := string(bytes[:n])
+			expected := []string{
+				"test.multi_timings_name.500000:0.000000|g|#label1:foo,label2:bar",
+				"test.multi_timings_name.1000000:0.000000|g|#label1:foo,label2:bar",
+				"test.multi_timings_name.5000000:0.000000|g|#label1:foo,label2:bar",
+				"test.multi_timings_name.10000000:1.000000|g|#label1:foo,label2:bar",
+				"test.multi_timings_name.50000000:0.000000|g|#label1:foo,label2:bar",
+				"test.multi_timings_name.100000000:0.000000|g|#label1:foo,label2:bar",
+				"test.multi_timings_name.500000000:0.000000|g|#label1:foo,label2:bar",
+				"test.multi_timings_name.1000000000:0.000000|g|#label1:foo,label2:bar",
+				"test.multi_timings_name.5000000000:0.000000|g|#label1:foo,label2:bar",
+			}
+			for i, res := range strings.Split(result, "\n") {
+				assert.Equal(t, res, expected[i])
+			}
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdTimings(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "timings_name"
+	s := stats.NewTimings(name, "help", "label1")
+	s.Add("foo", 2*time.Millisecond)
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 49152)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := string(bytes[:n])
+			expected := []string{
+				"test.timings_name.500000:0.000000|g|#label1:foo",
+				"test.timings_name.1000000:0.000000|g|#label1:foo",
+				"test.timings_name.5000000:1.000000|g|#label1:foo",
+				"test.timings_name.10000000:0.000000|g|#label1:foo",
+				"test.timings_name.50000000:0.000000|g|#label1:foo",
+				"test.timings_name.100000000:0.000000|g|#label1:foo",
+				"test.timings_name.500000000:0.000000|g|#label1:foo",
+				"test.timings_name.1000000000:0.000000|g|#label1:foo",
+				"test.timings_name.5000000000:0.000000|g|#label1:foo",
+			}
+			for i, res := range strings.Split(result, "\n") {
+				assert.Equal(t, res, expected[i])
+			}
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
+
+func TestStatsdHistogram(t *testing.T) {
+	sb, server := getBackend(t)
+	defer server.Close()
+	name := "histogram_name"
+	s := stats.NewHistogram(name, "help", []int64{1, 5, 10})
+	s.Add(2)
+	s.Add(3)
+	s.Add(6)
+	found := false
+	expvar.Do(func(kv expvar.KeyValue) {
+		if kv.Key == name {
+			found = true
+			sb.addExpVar(kv)
+			if err := sb.statsdClient.Flush(); err != nil {
+				t.Errorf("Error flushing: %s", err)
+			}
+			bytes := make([]byte, 4096)
+			n, err := server.Read(bytes)
+			if err != nil {
+				t.Fatal(err)
+			}
+			result := string(bytes[:n])
+			expected := []string{
+				"test.histogram_name.1:0.000000|g",
+				"test.histogram_name.5:2.000000|g",
+				"test.histogram_name.10:1.000000|g",
+				"test.histogram_name.inf:0.000000|g",
+				"test.histogram_name.Count:3.000000|g",
+				"test.histogram_name.Total:11.000000|g",
+			}
+			for i, res := range strings.Split(result, "\n") {
+				assert.Equal(t, res, expected[i])
+			}
+		}
+	})
+	if !found {
+		t.Errorf("Stat %s not found...", name)
+	}
+}
diff --git a/go/test/endtoend/onlineddl/onlineddl_test.go b/go/test/endtoend/onlineddl/onlineddl_test.go
index ff835097c2..8395333b27 100644
--- a/go/test/endtoend/onlineddl/onlineddl_test.go
+++ b/go/test/endtoend/onlineddl/onlineddl_test.go
@@ -106,7 +106,7 @@ func TestMain(m *testing.M) {
 			"-migration_check_interval", "5s",
 		}
 		clusterInstance.VtGateExtraArgs = []string{
-			"-ddl_strategy", "gh-ost",
+			"-ddl-strategy", "gh-ost",
 		}
 
 		if err := clusterInstance.StartTopo(); err != nil {
diff --git a/go/vt/key/key_test.go b/go/vt/key/key_test.go
index 8643d0bcc7..89bac6311f 100644
--- a/go/vt/key/key_test.go
+++ b/go/vt/key/key_test.go
@@ -272,7 +272,6 @@ func TestParseShardingSpec(t *testing.T) {
 	x80 := []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
 	goodTable := map[string][]*topodatapb.KeyRange{
 		"-": {{}},
-		"0": {{}},
 		"-4000000000000000-8000000000000000-": {
 			{End: x40},
 			{Start: x40, End: x80},
diff --git a/go/vt/sqlparser/parse_table_test.go b/go/vt/sqlparser/parse_table_test.go
deleted file mode 100644
index 09e7ea4417..0000000000
--- a/go/vt/sqlparser/parse_table_test.go
+++ /dev/null
@@ -1,69 +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 sqlparser
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestParseTable(t *testing.T) {
-	testcases := []struct {
-		input    string
-		keyspace string
-		table    string
-		err      bool
-	}{{
-		input:    "t",
-		keyspace: "",
-		table:    "t",
-	}, {
-		input:    "k.t",
-		keyspace: "k",
-		table:    "t",
-	}, {
-		input:    "`k.k`.`t``.t`",
-		keyspace: "k.k",
-		table:    "t`.t",
-	}, {
-		input: ".",
-		err:   true,
-	}, {
-		input: "t,",
-		err:   true,
-	}, {
-		input: "t,",
-		err:   true,
-	}, {
-		input: "t..",
-		err:   true,
-	}, {
-		input: "k.t.",
-		err:   true,
-	}}
-	for _, tcase := range testcases {
-		keyspace, table, err := ParseTable(tcase.input)
-		assert.Equal(t, tcase.keyspace, keyspace)
-		assert.Equal(t, tcase.table, table)
-		if tcase.err {
-			assert.Error(t, err)
-		} else {
-			assert.NoError(t, err)
-		}
-	}
-}
diff --git a/go/vt/vtgate/engine/fake_vcursor_test.go b/go/vt/vtgate/engine/fake_vcursor_test.go
index 91a53f8ef7..43cd0b775c 100644
--- a/go/vt/vtgate/engine/fake_vcursor_test.go
+++ b/go/vt/vtgate/engine/fake_vcursor_test.go
@@ -166,10 +166,6 @@ func (t noopVCursor) ExceedsMaxMemoryRows(numRows int) bool {
 	return !testIgnoreMaxMemoryRows && numRows > testMaxMemoryRows
 }
 
-func (t noopVCursor) GetKeyspace() string {
-	return ""
-}
-
 func (t noopVCursor) SetContextTimeout(timeout time.Duration) context.CancelFunc {
 	return func() {}
 }
@@ -306,10 +302,6 @@ func (f *loggingVCursor) ErrorGroupCancellableContext() (*errgroup.Group, func()
 	panic("implement me")
 }
 
-func (f *loggingVCursor) GetKeyspace() string {
-	return ""
-}
-
 func (f *loggingVCursor) RecordWarning(warning *querypb.QueryWarning) {
 	f.warnings = append(f.warnings, warning)
 }
diff --git a/go/vt/vtgate/engine/vindex_func_test.go b/go/vt/vtgate/engine/vindex_func_test.go
index eb8e3265ae..ff22fe4e60 100644
--- a/go/vt/vtgate/engine/vindex_func_test.go
+++ b/go/vt/vtgate/engine/vindex_func_test.go
@@ -98,7 +98,7 @@ func TestVindexFuncMap(t *testing.T) {
 		t.Fatal(err)
 	}
 	want := &sqltypes.Result{
-		Fields: sqltypes.MakeTestFields("id|keyspace_id|hex(keyspace_id)|range_start|range_end", "varbinary|varbinary|varbinary|varbinary|varbinary"),
+		Fields: sqltypes.MakeTestFields("id|keyspace_id|range_start|range_end", "varbinary|varbinary|varbinary|varbinary"),
 	}
 	if !reflect.DeepEqual(got, want) {
 		t.Errorf("Execute(Map, uvindex(none)):\n%v, want\n%v", got, want)
@@ -111,13 +111,9 @@ func TestVindexFuncMap(t *testing.T) {
 		t.Fatal(err)
 	}
 	want = sqltypes.MakeTestResult(
-		sqltypes.MakeTestFields("id|keyspace_id|hex(keyspace_id)|range_start|range_end", "varbinary|varbinary|varbinary|varbinary|varbinary"),
-		"1|foo|||666f6f",
+		sqltypes.MakeTestFields("id|keyspace_id|range_start|range_end", "varbinary|varbinary|varbinary|varbinary"),
+		"1|foo",
 	)
-	for _, row := range want.Rows {
-		row[2] = sqltypes.NULL
-		row[3] = sqltypes.NULL
-	}
 	if !reflect.DeepEqual(got, want) {
 		t.Errorf("Execute(Map, uvindex(none)):\n%v, want\n%v", got, want)
 	}
@@ -129,13 +125,12 @@ func TestVindexFuncMap(t *testing.T) {
 		t.Fatal(err)
 	}
 	want = &sqltypes.Result{
-		Fields: sqltypes.MakeTestFields("id|keyspace_id|hex(keyspace_id)|range_start|range_end", "varbinary|varbinary|varbinary|varbinary|varbinary"),
+		Fields: sqltypes.MakeTestFields("id|keyspace_id|range_start|range_end", "varbinary|varbinary|varbinary|varbinary"),
 		Rows: [][]sqltypes.Value{{
 			sqltypes.NewVarBinary("1"),
 			sqltypes.NULL,
 			sqltypes.MakeTrusted(sqltypes.VarBinary, []byte{0x40}),
 			sqltypes.MakeTrusted(sqltypes.VarBinary, []byte{0x60}),
-			sqltypes.NULL,
 		}},
 		RowsAffected: 1,
 	}
@@ -150,7 +145,7 @@ func TestVindexFuncMap(t *testing.T) {
 		t.Fatal(err)
 	}
 	want = &sqltypes.Result{
-		Fields: sqltypes.MakeTestFields("id|keyspace_id|hex(keyspace_id)|range_start|range_end", "varbinary|varbinary|varbinary|varbinary|varbinary"),
+		Fields: sqltypes.MakeTestFields("id|keyspace_id|range_start|range_end", "varbinary|varbinary|varbinary|varbinary"),
 	}
 	if !reflect.DeepEqual(got, want) {
 		t.Errorf("Execute(Map, uvindex(none)):\n%v, want\n%v", got, want)
@@ -163,9 +158,9 @@ func TestVindexFuncMap(t *testing.T) {
 		t.Fatal(err)
 	}
 	want = sqltypes.MakeTestResult(
-		sqltypes.MakeTestFields("id|keyspace_id|hex(keyspace_id)|range_start|range_end", "varbinary|varbinary|varbinary|varbinary|varbinary"),
-		"1|foo|||666f6f",
-		"1|bar|||626172",
+		sqltypes.MakeTestFields("id|keyspace_id|range_start|range_end", "varbinary|varbinary|varbinary|varbinary"),
+		"1|foo||",
+		"1|bar||",
 	)
 	// Massage the rows because MakeTestResult doesn't do NULL values.
 	for _, row := range want.Rows {
@@ -183,13 +178,12 @@ func TestVindexFuncMap(t *testing.T) {
 		t.Fatal(err)
 	}
 	want = &sqltypes.Result{
-		Fields: sqltypes.MakeTestFields("id|keyspace_id|hex(keyspace_id)|range_start|range_end", "varbinary|varbinary|varbinary|varbinary|varbinary"),
+		Fields: sqltypes.MakeTestFields("id|keyspace_id|range_start|range_end", "varbinary|varbinary|varbinary|varbinary"),
 		Rows: [][]sqltypes.Value{{
 			sqltypes.NewVarBinary("1"),
 			sqltypes.NULL,
 			sqltypes.MakeTrusted(sqltypes.VarBinary, []byte{0x40}),
 			sqltypes.MakeTrusted(sqltypes.VarBinary, []byte{0x60}),
-			sqltypes.NULL,
 		}},
 		RowsAffected: 1,
 	}
@@ -201,12 +195,12 @@ func TestVindexFuncMap(t *testing.T) {
 func TestVindexFuncStreamExecute(t *testing.T) {
 	vf := testVindexFunc(&nvindex{matchid: true})
 	want := []*sqltypes.Result{{
-		Fields: sqltypes.MakeTestFields("id|keyspace_id|hex(keyspace_id)|range_start|range_end", "varbinary|varbinary|varbinary|varbinary|varbinary"),
+		Fields: sqltypes.MakeTestFields("id|keyspace_id|range_start|range_end", "varbinary|varbinary|varbinary|varbinary"),
 	}, {
 		Rows: [][]sqltypes.Value{{
-			sqltypes.NewVarBinary("1"), sqltypes.NewVarBinary("foo"), sqltypes.NULL, sqltypes.NULL, sqltypes.NewVarBinary("666f6f"),
+			sqltypes.NewVarBinary("1"), sqltypes.NewVarBinary("foo"), sqltypes.NULL, sqltypes.NULL,
 		}, {
-			sqltypes.NewVarBinary("1"), sqltypes.NewVarBinary("bar"), sqltypes.NULL, sqltypes.NULL, sqltypes.NewVarBinary("626172"),
+			sqltypes.NewVarBinary("1"), sqltypes.NewVarBinary("bar"), sqltypes.NULL, sqltypes.NULL,
 		}},
 	}}
 	i := 0
@@ -229,7 +223,7 @@ func TestVindexFuncGetFields(t *testing.T) {
 		t.Fatal(err)
 	}
 	want := &sqltypes.Result{
-		Fields: sqltypes.MakeTestFields("id|keyspace_id|hex(keyspace_id)|range_start|range_end", "varbinary|varbinary|varbinary|varbinary|varbinary"),
+		Fields: sqltypes.MakeTestFields("id|keyspace_id|range_start|range_end", "varbinary|varbinary|varbinary|varbinary"),
 	}
 	if !reflect.DeepEqual(got, want) {
 		t.Errorf("Execute(Map, uvindex(none)):\n%v, want\n%v", got, want)
@@ -256,8 +250,8 @@ func TestFieldOrder(t *testing.T) {
 
 func testVindexFunc(v vindexes.SingleColumn) *VindexFunc {
 	return &VindexFunc{
-		Fields: sqltypes.MakeTestFields("id|keyspace_id|hex(keyspace_id)|range_start|range_end", "varbinary|varbinary|varbinary|varbinary|varbinary"),
-		Cols:   []int{0, 1, 2, 3, 4},
+		Fields: sqltypes.MakeTestFields("id|keyspace_id|range_start|range_end", "varbinary|varbinary|varbinary|varbinary"),
+		Cols:   []int{0, 1, 2, 3},
 		Opcode: VindexMap,
 		Vindex: v,
 		Value:  int64PlanValue(1),
diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.txt b/go/vt/vtgate/planbuilder/testdata/from_cases.txt
index 4c4b966930..67195e515f 100644
--- a/go/vt/vtgate/planbuilder/testdata/from_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/from_cases.txt
@@ -234,7 +234,7 @@
 
 # routing rules bad table
 "select * from bad_table"
-"keyspace noks not found in vschema"
+"keyspace none not found in vschema"
 
 # routing rules disabled table
 "select * from disabled"
diff --git a/go/vt/vtgate/planbuilder/testdata/schema_test.json b/go/vt/vtgate/planbuilder/testdata/schema_test.json
index bc55db8568..c078fe5287 100644
--- a/go/vt/vtgate/planbuilder/testdata/schema_test.json
+++ b/go/vt/vtgate/planbuilder/testdata/schema_test.json
@@ -14,7 +14,7 @@
       "to_tables": ["user.user"]
     }, {
       "from_table": "bad_table",
-      "to_tables": ["noks.noks"]
+      "to_tables": ["none.none"]
     }, {
       "from_table": "disabled",
       "to_tables": []
diff --git a/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt b/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt
index c492ad196a..91529c462e 100644
--- a/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt
@@ -1,8 +1,8 @@
 # vindex func read all cols
-"select id, keyspace_id, range_start, range_end, hex_keyspace_id, shard from user_index where id = :id"
+"select id, keyspace_id, range_start, range_end from user_index where id = :id"
 {
   "QueryType": "SELECT",
-  "Original": "select id, keyspace_id, range_start, range_end, hex_keyspace_id, shard from user_index where id = :id",
+  "Original": "select id, keyspace_id, range_start, range_end from user_index where id = :id",
   "Instructions": {
     "OperatorType": "VindexFunc",
     "Variant": "VindexMap",
@@ -10,17 +10,13 @@
       0,
       1,
       2,
-      3,
-      4,
-      5
+      3
     ],
     "Fields": {
-      "hex_keyspace_id": "VARBINARY",
       "id": "VARBINARY",
       "keyspace_id": "VARBINARY",
       "range_end": "VARBINARY",
-      "range_start": "VARBINARY",
-      "shard": "VARBINARY"
+      "range_start": "VARBINARY"
     },
     "Value": ":id",
     "Vindex": "user_index"
@@ -39,17 +35,13 @@
       0,
       1,
       2,
-      3,
-      4,
-      5
+      3
     ],
     "Fields": {
-      "hex_keyspace_id": "VARBINARY",
       "id": "VARBINARY",
       "keyspace_id": "VARBINARY",
       "range_end": "VARBINARY",
-      "range_start": "VARBINARY",
-      "shard": "VARBINARY"
+      "range_start": "VARBINARY"
     },
     "Value": ":id",
     "Vindex": "user_index"
diff --git a/go/vt/vtgate/vindexes/vschema_test.go b/go/vt/vtgate/vindexes/vschema_test.go
index 823b46f4e8..7455a8e1be 100644
--- a/go/vt/vtgate/vindexes/vschema_test.go
+++ b/go/vt/vtgate/vindexes/vschema_test.go
@@ -664,18 +664,12 @@ func TestVSchemaRoutingRules(t *testing.T) {
 			}, {
 				FromTable: "rt2",
 				ToTables:  []string{"ks2.t2"},
-			}, {
-				FromTable: "escaped",
-				ToTables:  []string{"`ks2`.`t2`"},
 			}, {
 				FromTable: "dup",
 				ToTables:  []string{"ks1.t1"},
 			}, {
 				FromTable: "dup",
 				ToTables:  []string{"ks1.t1"},
-			}, {
-				FromTable: "badname",
-				ToTables:  []string{"t1.t2.t3"},
 			}, {
 				FromTable: "unqualified",
 				ToTables:  []string{"t1"},
@@ -759,15 +753,9 @@ func TestVSchemaRoutingRules(t *testing.T) {
 			"rt2": {
 				Tables: []*Table{t2},
 			},
-			"escaped": {
-				Tables: []*Table{t2},
-			},
 			"dup": {
 				Error: errors.New("duplicate rule for entry dup"),
 			},
-			"badname": {
-				Error: errors.New("invalid table name: t1.t2.t3"),
-			},
 			"unqualified": {
 				Error: errors.New("table t1 must be qualified"),
 			},
@@ -1868,7 +1856,7 @@ func TestSequence(t *testing.T) {
 						},
 						AutoIncrement: &vschemapb.AutoIncrement{
 							Column:   "c2",
-							Sequence: "`unsharded`.`seq`",
+							Sequence: "unsharded.seq",
 						},
 					},
 				},
@@ -2084,9 +2072,9 @@ func TestBadSequenceName(t *testing.T) {
 	}
 	got, _ := BuildVSchema(&bad)
 	err := got.Keyspaces["sharded"].Error
-	want := "invalid table name: a.b.seq"
-	if err == nil || !strings.Contains(err.Error(), want) {
-		t.Errorf("BuildVSchema: %v, must contain %v", err, want)
+	want := "cannot resolve sequence a.b.seq: table a.b.seq not found"
+	if err == nil || err.Error() != want {
+		t.Errorf("BuildVSchema: %v, want %v", err, want)
 	}
 	if t1 := got.Keyspaces["sharded"].Tables["t1"]; t1 != nil {
 		t.Errorf("BuildVSchema: table t1 must not be present in the keyspace: %v", t1)