Repository: vitessio/vitess
Pull request #8451 (2021-07-12 06:09:16)

Gen4: fail more unsupported queries
## Description

This pull request is the continuity of https://github.com/vitessio/vitess/pull/8382. The goal is to support and/or fail more queries in gen4. This pull request ensures we error out queries that are not supposed to be supported, and return a `Gen4NotSupported` error for those that are not yet handled by the gen4 planner.

## Checklist
- [x] Tests were added or are not required
- [x] Documentation was added or is not required



Patch:
diff --git a/go/vt/discovery/tablet_picker.go b/go/vt/discovery/tablet_picker.go
index bb5bf3005d..af813ae13e 100644
--- a/go/vt/discovery/tablet_picker.go
+++ b/go/vt/discovery/tablet_picker.go
@@ -19,13 +19,10 @@ package discovery
 import (
 	"fmt"
 	"math/rand"
-	"sort"
 	"strings"
 	"sync"
 	"time"
 
-	"vitess.io/vitess/go/stats"
-
 	"vitess.io/vitess/go/vt/topo/topoproto"
 
 	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
@@ -44,8 +41,6 @@ import (
 var (
 	tabletPickerRetryDelay   = 30 * time.Second
 	muTabletPickerRetryDelay sync.Mutex
-	globalTPStats            *tabletPickerStats
-	inOrderHint              = "in_order:"
 )
 
 // GetTabletPickerRetryDelay synchronizes changes to tabletPickerRetryDelay. Used in tests only at the moment
@@ -69,16 +64,10 @@ type TabletPicker struct {
 	keyspace    string
 	shard       string
 	tabletTypes []topodatapb.TabletType
-	inOrder     bool
 }
 
 // NewTabletPicker returns a TabletPicker.
 func NewTabletPicker(ts *topo.Server, cells []string, keyspace, shard, tabletTypesStr string) (*TabletPicker, error) {
-	inOrder := false
-	if strings.HasPrefix(tabletTypesStr, inOrderHint) {
-		inOrder = true
-		tabletTypesStr = tabletTypesStr[len(inOrderHint):]
-	}
 	tabletTypes, err := topoproto.ParseTabletTypes(tabletTypesStr)
 	if err != nil {
 		return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "failed to parse list of tablet types: %v", tabletTypesStr)
@@ -103,7 +92,6 @@ func NewTabletPicker(ts *topo.Server, cells []string, keyspace, shard, tabletTyp
 		keyspace:    keyspace,
 		shard:       shard,
 		tabletTypes: tabletTypes,
-		inOrder:     inOrder,
 	}, nil
 }
 
@@ -111,7 +99,6 @@ func NewTabletPicker(ts *topo.Server, cells []string, keyspace, shard, tabletTyp
 // All tablets that belong to tp.cells are evaluated and one is
 // chosen at random
 func (tp *TabletPicker) PickForStreaming(ctx context.Context) (*topodatapb.Tablet, error) {
-	rand.Seed(time.Now().UnixNano())
 	// keep trying at intervals (tabletPickerRetryDelay) until a tablet is found
 	// or the context is canceled
 	for {
@@ -121,28 +108,9 @@ func (tp *TabletPicker) PickForStreaming(ctx context.Context) (*topodatapb.Table
 		default:
 		}
 		candidates := tp.GetMatchingTablets(ctx)
-		if tp.inOrder {
-			// Sort candidates slice such that tablets appear in same tablet type order as in tp.tabletTypes
-			orderMap := map[topodatapb.TabletType]int{}
-			for i, t := range tp.tabletTypes {
-				orderMap[t] = i
-			}
-			sort.Slice(candidates, func(i, j int) bool {
-				if orderMap[candidates[i].Type] == orderMap[candidates[j].Type] {
-					// identical tablet types: randomize order of tablets for this type
-					return rand.Intn(2) == 0 // 50% chance
-				}
-				return orderMap[candidates[i].Type] < orderMap[candidates[j].Type]
-			})
-		} else {
-			// Randomize candidates
-			rand.Shuffle(len(candidates), func(i, j int) {
-				candidates[i], candidates[j] = candidates[j], candidates[i]
-			})
-		}
+
 		if len(candidates) == 0 {
 			// if no candidates were found, sleep and try again
-			tp.incNoTabletFoundStat()
 			log.Infof("No tablet found for streaming, shard %s.%s, cells %v, tabletTypes %v, sleeping for %d seconds",
 				tp.keyspace, tp.shard, tp.cells, tp.tabletTypes, int(GetTabletPickerRetryDelay()/1e9))
 			timer := time.NewTimer(GetTabletPickerRetryDelay())
@@ -154,19 +122,26 @@ func (tp *TabletPicker) PickForStreaming(ctx context.Context) (*topodatapb.Table
 			}
 			continue
 		}
-		for _, ti := range candidates {
+		// try at most len(candidate) times to find a healthy tablet
+		for i := 0; i < len(candidates); i++ {
+			idx := rand.Intn(len(candidates))
+			ti := candidates[idx]
+			// get tablet
 			// try to connect to tablet
-			if conn, err := tabletconn.GetDialer()(ti.Tablet, true); err == nil {
-				// OK to use ctx here because it is not actually used by the underlying Close implementation
-				_ = conn.Close(ctx)
-				log.Infof("tablet picker found tablet %s", ti.Tablet.String())
-				return ti.Tablet, nil
+			conn, err := tabletconn.GetDialer()(ti.Tablet, true)
+			if err != nil {
+				log.Warningf("unable to connect to tablet for alias %v", ti.Alias)
+				candidates = append(candidates[:idx], candidates[idx+1:]...)
+				if len(candidates) == 0 {
+					break
+				}
+				continue
 			}
-			// err found
-			log.Warningf("unable to connect to tablet for alias %v", ti.Alias)
+			// OK to use ctx here because it is not actually used by the underlying Close implementation
+			_ = conn.Close(ctx)
+			log.Infof("tablet picker found tablet %s", ti.Tablet.String())
+			return ti.Tablet, nil
 		}
-		// Got here? Means we iterated all tablets and did not find a healthy one
-		tp.incNoTabletFoundStat()
 	}
 }
 
@@ -251,25 +226,4 @@ func (tp *TabletPicker) GetMatchingTablets(ctx context.Context) []*topo.TabletIn
 func init() {
 	// TODO(sougou): consolidate this call to be once per process.
 	rand.Seed(time.Now().UnixNano())
-	globalTPStats = newTabletPickerStats()
-}
-
-type tabletPickerStats struct {
-	mu                 sync.Mutex
-	noTabletFoundError *stats.CountersWithMultiLabels
-}
-
-func newTabletPickerStats() *tabletPickerStats {
-	tpStats := &tabletPickerStats{}
-	tpStats.noTabletFoundError = stats.NewCountersWithMultiLabels("TabletPickerNoTabletFoundErrorCount", "", []string{"cells", "keyspace", "shard", "types"})
-	return tpStats
-}
-
-func (tp *TabletPicker) incNoTabletFoundStat() {
-	globalTPStats.mu.Lock()
-	defer globalTPStats.mu.Unlock()
-	cells := strings.Join(tp.cells, "_")
-	tabletTypes := strings.Join(topoproto.MakeStringTypeList(tp.tabletTypes), "_")
-	labels := []string{cells, tp.keyspace, tp.shard, tabletTypes}
-	globalTPStats.noTabletFoundError.Add(labels, 1)
 }
diff --git a/go/vt/schema/ddl_strategy.go b/go/vt/schema/ddl_strategy.go
index ad2b98e563..dbc1f2d32b 100644
--- a/go/vt/schema/ddl_strategy.go
+++ b/go/vt/schema/ddl_strategy.go
@@ -155,10 +155,13 @@ func (setting *DDLStrategySetting) RuntimeOptions() []string {
 
 // IsSkipTopo suggests that DDL should apply to tables bypassing global topo request
 func (setting *DDLStrategySetting) IsSkipTopo() bool {
-	// Vitess 11 introduced the flag -skip-topo. starting Vitess 12 the flag is _always_ considered 'true'.
-	// Ideally the flag should be gone, but for backwards compatibility we allow users to still specify it
-	// (and we stil ignore the value, it's always set to true)
-	return true
+	switch {
+	case setting.IsSingleton(), setting.IsSingletonContext():
+		return true
+	case setting.hasFlag(skipTopoFlag):
+		return true
+	}
+	return false
 }
 
 // ToString returns a simple string representation of this instance
diff --git a/go/vt/schema/online_ddl.go b/go/vt/schema/online_ddl.go
index a67fe0cc26..81f0d506f2 100644
--- a/go/vt/schema/online_ddl.go
+++ b/go/vt/schema/online_ddl.go
@@ -372,32 +372,6 @@ func (onlineDDL *OnlineDDL) ToJSON() ([]byte, error) {
 	return json.Marshal(onlineDDL)
 }
 
-// sqlWithoutComments returns the SQL statement without comment directives. Useful for tests
-func (onlineDDL *OnlineDDL) sqlWithoutComments() (sql string, err error) {
-	sql = onlineDDL.SQL
-	stmt, err := sqlparser.Parse(sql)
-	if err != nil {
-		// query validation and rebuilding
-		if _, err := legacyParseRevertUUID(sql); err == nil {
-			// This is a revert statement of the form "revert <uuid>". We allow this for now. Future work will
-			// make sure the statement is a valid, parseable "revert vitess_migration '<uuid>'", but we must
-			// be backwards compatible for now.
-			return sql, nil
-		}
-		// otherwise the statement should have been parseable!
-		return "", err
-	}
-
-	switch stmt := stmt.(type) {
-	case sqlparser.DDLStatement:
-		stmt.SetComments(nil)
-	case *sqlparser.RevertMigration:
-		stmt.SetComments(nil)
-	}
-	sql = sqlparser.String(stmt)
-	return sql, nil
-}
-
 // GetAction extracts the DDL action type from the online DDL statement
 func (onlineDDL *OnlineDDL) GetAction() (action sqlparser.DDLAction, err error) {
 	if _, err := onlineDDL.GetRevertUUID(); err == nil {
diff --git a/go/vt/topo/tablet.go b/go/vt/topo/tablet.go
index eb9ef29074..42cb1544f9 100644
--- a/go/vt/topo/tablet.go
+++ b/go/vt/topo/tablet.go
@@ -80,7 +80,7 @@ func IsRunningQueryService(tt topodatapb.TabletType) bool {
 // lameduck.  Lameduck is a transition period where we are still
 // allowed to serve, but we tell the clients we are going away
 // soon. Typically, a vttablet will still serve, but broadcast a
-// non-serving state through its health check. then vtgate will catch
+// non-serving state through its health check. then vtgate will ctahc
 // that non-serving state, and stop sending queries.
 //
 // Masters are not subject to lameduck, as we usually want to transition
diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go
index 5061678807..7702e76523 100644
--- a/go/vt/vtexplain/vtexplain_vttablet.go
+++ b/go/vt/vtexplain/vtexplain_vttablet.go
@@ -103,7 +103,6 @@ func newTablet(opts *Options, t *topodatapb.Tablet) *explainTablet {
 		config.TwoPCAbandonAge = 1.0
 		config.TwoPCEnable = true
 	}
-	config.EnableOnlineDDL = false
 
 	// XXX much of this is cloned from the tabletserver tests
 	tsv := tabletserver.NewTabletServer(topoproto.TabletAliasString(t.Alias), config, memorytopo.NewServer(""), t.Alias)
diff --git a/go/vt/vtgate/planbuilder/abstract/operator.go b/go/vt/vtgate/planbuilder/abstract/operator.go
index 137a19394d..c1e9395db4 100644
--- a/go/vt/vtgate/planbuilder/abstract/operator.go
+++ b/go/vt/vtgate/planbuilder/abstract/operator.go
@@ -42,7 +42,13 @@ func getOperatorFromTableExpr(tableExpr sqlparser.TableExpr, semTable *semantics
 	case *sqlparser.AliasedTableExpr:
 		qg := newQueryGraph()
 		tableName := tableExpr.Expr.(sqlparser.TableName)
-		qt := &QueryTable{Alias: tableExpr, Table: tableName, TableID: semTable.TableSetFor(tableExpr)}
+		tableID := semTable.TableSetFor(tableExpr)
+		tableInfo, err := semTable.TableInfoFor(tableID)
+		if err != nil {
+			return nil, err
+		}
+		isInfSchema := tableInfo.IsInfSchema()
+		qt := &QueryTable{Alias: tableExpr, Table: tableName, TableID: tableID, IsInfSchema: isInfSchema}
 		qg.Tables = append(qg.Tables, qt)
 		return qg, nil
 	case *sqlparser.JoinTableExpr:
diff --git a/go/vt/vtgate/planbuilder/abstract/querygraph.go b/go/vt/vtgate/planbuilder/abstract/querygraph.go
index 5d75d1f472..98129eb608 100644
--- a/go/vt/vtgate/planbuilder/abstract/querygraph.go
+++ b/go/vt/vtgate/planbuilder/abstract/querygraph.go
@@ -44,10 +44,11 @@ type (
 
 	// QueryTable is a single FROM table, including all predicates particular to this table
 	QueryTable struct {
-		TableID    semantics.TableSet
-		Alias      *sqlparser.AliasedTableExpr
-		Table      sqlparser.TableName
-		Predicates []sqlparser.Expr
+		TableID     semantics.TableSet
+		Alias       *sqlparser.AliasedTableExpr
+		Table       sqlparser.TableName
+		Predicates  []sqlparser.Expr
+		IsInfSchema bool
 	}
 )
 
@@ -90,46 +91,6 @@ func newQueryGraph() *QueryGraph {
 	}
 }
 
-func (qg *QueryGraph) collectTable(t sqlparser.TableExpr, semTable *semantics.SemTable) error {
-	switch table := t.(type) {
-	case *sqlparser.AliasedTableExpr:
-		tableName := table.Expr.(sqlparser.TableName)
-		qt := &QueryTable{Alias: table, Table: tableName, TableID: semTable.TableSetFor(table)}
-		qg.Tables = append(qg.Tables, qt)
-	case *sqlparser.JoinTableExpr:
-		if err := qg.collectTable(table.LeftExpr, semTable); err != nil {
-			return err
-		}
-		if err := qg.collectTable(table.RightExpr, semTable); err != nil {
-			return err
-		}
-		if table.Condition.On != nil {
-			for _, predicate := range sqlparser.SplitAndExpression(nil, table.Condition.On) {
-				err := qg.collectPredicateTable(t, predicate, semTable)
-				if err != nil {
-					return err
-				}
-			}
-		}
-	case *sqlparser.ParenTableExpr:
-		for _, expr := range table.Exprs {
-			if err := qg.collectTable(expr, semTable); err != nil {
-				return err
-			}
-		}
-	}
-	return nil
-}
-
-func (qg *QueryGraph) collectTables(t sqlparser.TableExprs, semTable *semantics.SemTable) error {
-	for _, expr := range t {
-		if err := qg.collectTable(expr, semTable); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
 func (qg *QueryGraph) collectPredicates(sel *sqlparser.Select, semTable *semantics.SemTable) error {
 	predicates := sqlparser.SplitAndExpression(nil, sel.Where.Expr)
 
diff --git a/go/vt/vtgate/planbuilder/from.go b/go/vt/vtgate/planbuilder/from.go
index 026010585a..f783419158 100644
--- a/go/vt/vtgate/planbuilder/from.go
+++ b/go/vt/vtgate/planbuilder/from.go
@@ -19,6 +19,7 @@ package planbuilder
 import (
 	"errors"
 	"fmt"
+	"strings"
 
 	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
 	"vitess.io/vitess/go/vt/vterrors"
@@ -186,6 +187,7 @@ func (pb *primitiveBuilder) buildTablePrimitive(tableExpr *sqlparser.AliasedTabl
 		}
 		rb, st := newRoute(sel)
 		rb.eroute = engine.NewSimpleRoute(engine.SelectDBA, ks)
+		rb.eroute.TableName = sqlparser.String(tableName)
 		pb.plan, pb.st = rb, st
 		// Add the table to symtab
 		return st.AddTable(&table{
@@ -343,6 +345,10 @@ func (pb *primitiveBuilder) join(rpb *primitiveBuilder, ajoin *sqlparser.JoinTab
 	} else {
 		sel.From = sqlparser.TableExprs{ajoin}
 	}
+	// join table name
+	if lRoute.eroute.TableName != rRoute.eroute.TableName {
+		lRoute.eroute.TableName = strings.Join([]string{lRoute.eroute.TableName, rRoute.eroute.TableName}, ", ")
+	}
 
 	// Since the routes have merged, set st.singleRoute to point at
 	// the merged route.
diff --git a/go/vt/vtgate/planbuilder/jointree.go b/go/vt/vtgate/planbuilder/jointree.go
index dee3a07b6d..91ff3c6675 100644
--- a/go/vt/vtgate/planbuilder/jointree.go
+++ b/go/vt/vtgate/planbuilder/jointree.go
@@ -140,7 +140,13 @@ func (rp *leJoin) tableNames() []string {
 }
 
 func (rp *routeTable) tableNames() []string {
-	return []string{sqlparser.String(rp.qtable.Table.Name)}
+	var name string
+	if rp.qtable.IsInfSchema {
+		name = sqlparser.String(rp.qtable.Table)
+	} else {
+		name = sqlparser.String(rp.qtable.Table.Name)
+	}
+	return []string{name}
 }
 
 func (p parenTables) tableNames() []string {
diff --git a/go/vt/vtgate/planbuilder/jointree_transformers.go b/go/vt/vtgate/planbuilder/jointree_transformers.go
index d828cc0971..a99c0fb16b 100644
--- a/go/vt/vtgate/planbuilder/jointree_transformers.go
+++ b/go/vt/vtgate/planbuilder/jointree_transformers.go
@@ -112,8 +112,9 @@ func transformRoutePlan(n *routePlan) (*route, error) {
 			LeftExpr:  lft,
 		}
 		tablesForSelect = sqlparser.TableExprs{joinExpr}
-		// todo: add table
-		// tableNameMap[sqlparser.String()] = nil
+		for _, tblNames := range leftJoin.right.tableNames() {
+			tableNameMap[tblNames] = nil
+		}
 	}
 
 	predicates := n.Predicates()
@@ -161,13 +162,19 @@ func transformRoutePlan(n *routePlan) (*route, error) {
 func relToTableExpr(t relation) (sqlparser.TableExpr, error) {
 	switch t := t.(type) {
 	case *routeTable:
-		return &sqlparser.AliasedTableExpr{
-			Expr: sqlparser.TableName{
+		var expr sqlparser.SimpleTableExpr
+		if t.qtable.IsInfSchema {
+			expr = t.qtable.Table
+		} else {
+			expr = sqlparser.TableName{
 				Name: t.vtable.Name,
-			},
+			}
+		}
+		return &sqlparser.AliasedTableExpr{
+			Expr:       expr,
 			Partitions: nil,
 			As:         t.qtable.Alias.As,
-			Hints:      nil,
+			Hints:      t.qtable.Alias.Hints,
 		}, nil
 	case parenTables:
 		tables := sqlparser.TableExprs{}
diff --git a/go/vt/vtgate/planbuilder/route_planning.go b/go/vt/vtgate/planbuilder/route_planning.go
index 3af16a96e1..84fdec1574 100644
--- a/go/vt/vtgate/planbuilder/route_planning.go
+++ b/go/vt/vtgate/planbuilder/route_planning.go
@@ -464,6 +464,26 @@ func removeAt(plans []joinTree, idx int) []joinTree {
 }
 
 func createRoutePlan(table *abstract.QueryTable, solves semantics.TableSet, vschema ContextVSchema) (*routePlan, error) {
+	if table.IsInfSchema {
+		defaultKeyspace, err := vschema.DefaultKeyspace()
+		if err != nil {
+			return nil, err
+		}
+		return &routePlan{
+			routeOpCode: engine.SelectDBA,
+			solved:      solves,
+			// TODO: find keyspace to route using the predicates as in v3
+			keyspace: defaultKeyspace,
+			tables: []relation{&routeTable{
+				qtable: table,
+				vtable: &vindexes.Table{
+					Name:     table.Table.Name,
+					Keyspace: defaultKeyspace,
+				},
+			}},
+			predicates: table.Predicates,
+		}, nil
+	}
 	vschemaTable, _, _, _, _, err := vschema.FindTableOrVindex(table.Table)
 	if err != nil {
 		return nil, err
@@ -603,6 +623,9 @@ func tryMerge(a, b joinTree, joinPredicates []sqlparser.Expr, semTable *semantic
 			return nil
 		}
 	case engine.SelectScatter, engine.SelectEqualUnique:
+		if bRoute.routeOpCode == engine.SelectReference {
+			return r
+		}
 		if len(joinPredicates) == 0 {
 			// If we are doing two Scatters, we have to make sure that the
 			// joins are on the correct vindex to allow them to be merged
@@ -615,6 +638,10 @@ func tryMerge(a, b joinTree, joinPredicates []sqlparser.Expr, semTable *semantic
 			return nil
 		}
 		r.pickBestAvailableVindex()
+	case engine.SelectReference:
+		if bRoute.routeOpCode != engine.SelectReference {
+			return nil
+		}
 	}
 	return r
 }
diff --git a/go/vt/vtgate/semantics/analyzer.go b/go/vt/vtgate/semantics/analyzer.go
index 7eb9e4321f..1ee90fd7d0 100644
--- a/go/vt/vtgate/semantics/analyzer.go
+++ b/go/vt/vtgate/semantics/analyzer.go
@@ -300,23 +300,25 @@ func (a *analyzer) tableSetFor(t *sqlparser.AliasedTableExpr) TableSet {
 	panic("unknown table")
 }
 
-func (a *analyzer) createTable(t sqlparser.TableName, alias *sqlparser.AliasedTableExpr, tbl *vindexes.Table) TableInfo {
+func (a *analyzer) createTable(t sqlparser.TableName, alias *sqlparser.AliasedTableExpr, tbl *vindexes.Table, isInfSchema bool) TableInfo {
 	dbName := t.Qualifier.String()
 	if dbName == "" {
 		dbName = a.currentDb
 	}
 	if alias.As.IsEmpty() {
 		return &RealTable{
-			dbName:    dbName,
-			tableName: t.Name.String(),
-			ASTNode:   alias,
-			Table:     tbl,
+			dbName:      dbName,
+			tableName:   t.Name.String(),
+			ASTNode:     alias,
+			Table:       tbl,
+			isInfSchema: isInfSchema,
 		}
 	}
 	return &AliasedTable{
-		tableName: alias.As.String(),
-		ASTNode:   alias,
-		Table:     tbl,
+		tableName:   alias.As.String(),
+		ASTNode:     alias,
+		Table:       tbl,
+		isInfSchema: isInfSchema,
 	}
 }
 
@@ -325,18 +327,22 @@ func (a *analyzer) bindTable(alias *sqlparser.AliasedTableExpr, expr sqlparser.S
 	case *sqlparser.DerivedTable:
 		return Gen4NotSupportedF("derived table")
 	case sqlparser.TableName:
+		var tbl *vindexes.Table
+		var isInfSchema bool
 		if sqlparser.SystemSchema(t.Qualifier.String()) {
-			return Gen4NotSupportedF("system tables")
-		}
-		tbl, vdx, _, _, _, err := a.si.FindTableOrVindex(t)
-		if err != nil {
-			return err
-		}
-		if tbl == nil && vdx != nil {
-			return Gen4NotSupportedF("vindex in FROM")
+			isInfSchema = true
+		} else {
+			table, vdx, _, _, _, err := a.si.FindTableOrVindex(t)
+			if err != nil {
+				return err
+			}
+			tbl = table
+			if tbl == nil && vdx != nil {
+				return Gen4NotSupportedF("vindex in FROM")
+			}
 		}
 		scope := a.currentScope()
-		tableInfo := a.createTable(t, alias, tbl)
+		tableInfo := a.createTable(t, alias, tbl, isInfSchema)
 
 		a.Tables = append(a.Tables, tableInfo)
 		return scope.addTable(tableInfo)
diff --git a/go/vt/vtgate/semantics/semantic_state.go b/go/vt/vtgate/semantics/semantic_state.go
index c2287c7784..1db9028029 100644
--- a/go/vt/vtgate/semantics/semantic_state.go
+++ b/go/vt/vtgate/semantics/semantic_state.go
@@ -37,6 +37,7 @@ type (
 		GetColumns() []ColumnInfo
 		IsVirtual() bool
 		DepsFor(col *sqlparser.ColName, org originable, single bool) *TableSet
+		IsInfSchema() bool
 	}
 
 	// ColumnInfo contains information about columns
@@ -50,13 +51,15 @@ type (
 		dbName, tableName string
 		ASTNode           *sqlparser.AliasedTableExpr
 		Table             *vindexes.Table
+		isInfSchema       bool
 	}
 
 	// AliasedTable contains the alias table expr and vindex table
 	AliasedTable struct {
-		tableName string
-		ASTNode   *sqlparser.AliasedTableExpr
-		Table     *vindexes.Table
+		tableName   string
+		ASTNode     *sqlparser.AliasedTableExpr
+		Table       *vindexes.Table
+		isInfSchema bool
 	}
 
 	vTableInfo struct {
@@ -93,6 +96,7 @@ type (
 	}
 )
 
+// DepsFor implements the TableInfo interface
 func (v *vTableInfo) DepsFor(col *sqlparser.ColName, org originable, single bool) *TableSet {
 	if !col.Qualifier.IsEmpty() {
 		return nil
@@ -106,6 +110,7 @@ func (v *vTableInfo) DepsFor(col *sqlparser.ColName, org originable, single bool
 	return nil
 }
 
+// DepsFor implements the TableInfo interface
 func (a *AliasedTable) DepsFor(col *sqlparser.ColName, org originable, single bool) *TableSet {
 	if single {
 		ts := org.tableSetFor(a.ASTNode)
@@ -120,6 +125,7 @@ func (a *AliasedTable) DepsFor(col *sqlparser.ColName, org originable, single bo
 	return nil
 }
 
+// DepsFor implements the TableInfo interface
 func (r *RealTable) DepsFor(col *sqlparser.ColName, org originable, single bool) *TableSet {
 	if single {
 		ts := org.tableSetFor(r.ASTNode)
@@ -134,14 +140,32 @@ func (r *RealTable) DepsFor(col *sqlparser.ColName, org originable, single bool)
 	return nil
 }
 
+// IsInfSchema implements the TableInfo interface
+func (v *vTableInfo) IsInfSchema() bool {
+	return false
+}
+
+// IsInfSchema implements the TableInfo interface
+func (a *AliasedTable) IsInfSchema() bool {
+	return a.isInfSchema
+}
+
+// IsInfSchema implements the TableInfo interface
+func (r *RealTable) IsInfSchema() bool {
+	return r.isInfSchema
+}
+
+// IsVirtual implements the TableInfo interface
 func (v *vTableInfo) IsVirtual() bool {
 	return true
 }
 
+// IsVirtual implements the TableInfo interface
 func (a *AliasedTable) IsVirtual() bool {
 	return false
 }
 
+// IsVirtual implements the TableInfo interface
 func (r *RealTable) IsVirtual() bool {
 	return false
 }
diff --git a/go/vt/vttablet/onlineddl/executor.go b/go/vt/vttablet/onlineddl/executor.go
index b50e4cd2eb..9ec3ac42c0 100644
--- a/go/vt/vttablet/onlineddl/executor.go
+++ b/go/vt/vttablet/onlineddl/executor.go
@@ -257,7 +257,7 @@ func (e *Executor) InitDBConfig(keyspace, shard, dbName string) {
 func (e *Executor) Open() error {
 	e.initMutex.Lock()
 	defer e.initMutex.Unlock()
-	if e.isOpen || !e.env.Config().EnableOnlineDDL {
+	if e.isOpen {
 		return nil
 	}
 	e.pool.Open(e.env.Config().DB.AppWithDB(), e.env.Config().DB.DbaWithDB(), e.env.Config().DB.AppDebugWithDB())
@@ -1380,10 +1380,6 @@ func (e *Executor) terminateMigration(ctx context.Context, onlineDDL *schema.Onl
 
 // CancelMigration attempts to abort a scheduled or a running migration
 func (e *Executor) CancelMigration(ctx context.Context, uuid string, terminateRunningMigration bool, message string) (result *sqltypes.Result, err error) {
-	if !e.isOpen {
-		return nil, vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "online ddl is disabled")
-	}
-
 	e.migrationMutex.Lock()
 	defer e.migrationMutex.Unlock()
 
@@ -1437,10 +1433,6 @@ func (e *Executor) cancelMigrations(ctx context.Context, uuids []string, message
 // CancelPendingMigrations cancels all pending migrations (that are expected to run or are running)
 // for this keyspace
 func (e *Executor) CancelPendingMigrations(ctx context.Context, message string) (result *sqltypes.Result, err error) {
-	if !e.isOpen {
-		return nil, vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "online ddl is disabled")
-	}
-
 	uuids, err := e.readPendingMigrationsUUIDs(ctx)
 	if err != nil {
 		return result, err
@@ -2713,9 +2705,6 @@ func (e *Executor) retryMigrationWhere(ctx context.Context, whereExpr string) (r
 
 // RetryMigration marks given migration for retry
 func (e *Executor) RetryMigration(ctx context.Context, uuid string) (result *sqltypes.Result, err error) {
-	if !e.isOpen {
-		return nil, vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "online ddl is disabled")
-	}
 	if !schema.IsOnlineDDLUUID(uuid) {
 		return nil, vterrors.Errorf(vtrpcpb.Code_UNKNOWN, "Not a valid migration ID in RETRY: %s", uuid)
 	}
@@ -2737,9 +2726,7 @@ func (e *Executor) SubmitMigration(
 	ctx context.Context,
 	stmt sqlparser.Statement,
 ) (result *sqltypes.Result, err error) {
-	if !e.isOpen {
-		return nil, vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "online ddl is disabled")
-	}
+
 	onlineDDL, err := schema.OnlineDDLFromCommentedStatement(stmt)
 	if err != nil {
 		return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Error submitting migration %s: %v", sqlparser.String(stmt), err)
diff --git a/go/vt/vttablet/onlineddl/vrepl.go b/go/vt/vttablet/onlineddl/vrepl.go
index a082717522..851fbdd3ff 100644
--- a/go/vt/vttablet/onlineddl/vrepl.go
+++ b/go/vt/vttablet/onlineddl/vrepl.go
@@ -525,7 +525,7 @@ func (v *VRepl) analyze(ctx context.Context, conn *dbconnpool.DBConnection) erro
 // generateInsertStatement generates the INSERT INTO _vt.replication stataement that creates the vreplication workflow
 func (v *VRepl) generateInsertStatement(ctx context.Context) (string, error) {
 	ig := vreplication.NewInsertGenerator(binlogplayer.BlpStopped, v.dbName)
-	ig.AddRow(v.workflow, v.bls, v.pos, "", "in_order:REPLICA,MASTER")
+	ig.AddRow(v.workflow, v.bls, v.pos, "", "MASTER")
 
 	return ig.String(), nil
 }
diff --git a/go/vt/vttablet/tabletserver/tabletenv/config.go b/go/vt/vttablet/tabletserver/tabletenv/config.go
index 1bf959c4d9..652a21eb0e 100644
--- a/go/vt/vttablet/tabletserver/tabletenv/config.go
+++ b/go/vt/vttablet/tabletserver/tabletenv/config.go
@@ -161,7 +161,6 @@ func init() {
 	flag.DurationVar(&transitionGracePeriod, "serving_state_grace_period", 0, "how long to pause after broadcasting health to vtgate, before enforcing a new serving state")
 
 	flag.BoolVar(&enableReplicationReporter, "enable_replication_reporter", false, "Use polling to track replication lag.")
-	flag.BoolVar(&currentConfig.EnableOnlineDDL, "queryserver_enable_online_ddl", true, "Enable online DDL.")
 }
 
 // Init must be called after flag.Parse, and before doing any other operations.
@@ -280,7 +279,6 @@ type TabletConfig struct {
 	TransactionLimitConfig `json:"-"`
 
 	EnforceStrictTransTables bool `json:"-"`
-	EnableOnlineDDL          bool `json:"-"`
 }
 
 // ConnPoolConfig contains the config for a conn pool.
@@ -480,7 +478,6 @@ var defaultConfig = TabletConfig{
 	TransactionLimitConfig: defaultTransactionLimitConfig(),
 
 	EnforceStrictTransTables: true,
-	EnableOnlineDDL:          true,
 }
 
 // defaultTxThrottlerConfig formats the default throttlerdata.Configuration


Test patch:
diff --git a/.github/workflows/unit_test_mariadb101.yml b/.github/workflows/unit_test_mariadb101.yml
new file mode 100644
index 0000000000..ee0fcd8297
--- /dev/null
+++ b/.github/workflows/unit_test_mariadb101.yml
@@ -0,0 +1,71 @@
+# DO NOT MODIFY: THIS FILE IS GENERATED USING "make generate_ci_workflows"
+
+name: Unit Test (mariadb101)
+on: [push, pull_request]
+jobs:
+
+  test:
+    runs-on: ubuntu-18.04
+
+    steps:
+    - name: Set up Go
+      uses: actions/setup-go@v1
+      with:
+        go-version: 1.16
+
+    - name: Tune the OS
+      run: |
+        echo '1024 65535' | sudo tee -a /proc/sys/net/ipv4/ip_local_port_range
+
+    # TEMPORARY WHILE GITHUB FIXES THIS https://github.com/actions/virtual-environments/issues/3185
+    - name: Add the current IP address, long hostname and short hostname record to /etc/hosts file
+      run: |
+        echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts
+    # DON'T FORGET TO REMOVE CODE ABOVE WHEN ISSUE IS ADRESSED!
+
+    - name: Check out code
+      uses: actions/checkout@v2
+
+    - name: Get dependencies
+      run: |
+        export DEBIAN_FRONTEND="noninteractive"
+        sudo apt-get update
+
+        # !mysql57
+
+        # Uninstall any previously installed MySQL first
+        sudo systemctl stop apparmor
+        sudo DEBIAN_FRONTEND="noninteractive" apt-get remove -y --purge mysql-server mysql-client mysql-common
+        sudo apt-get -y autoremove
+        sudo apt-get -y autoclean
+        sudo deluser mysql
+        sudo rm -rf /var/lib/mysql
+        sudo rm -rf /etc/mysql
+
+        # mariadb101
+        sudo apt-get install -y software-properties-common
+        sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
+        sudo add-apt-repository 'deb [arch=amd64,arm64,ppc64el] http://nyc2.mirrors.digitalocean.com/mariadb/repo/10.1/ubuntu bionic main'
+        sudo apt update
+        sudo DEBIAN_FRONTEND="noninteractive" apt install -y mariadb-server
+
+        sudo apt-get install -y make unzip g++ curl git wget ant openjdk-8-jdk eatmydata
+        sudo service mysql stop
+        sudo bash -c "echo '/usr/sbin/mysqld { }' > /etc/apparmor.d/usr.sbin.mysqld" # https://bugs.launchpad.net/ubuntu/+source/mariadb-10.1/+bug/1806263
+        sudo ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/
+        sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld || echo "could not remove mysqld profile"
+
+        mkdir -p dist bin
+        curl -L https://github.com/coreos/etcd/releases/download/v3.3.10/etcd-v3.3.10-linux-amd64.tar.gz | tar -zxC dist
+        mv dist/etcd-v3.3.10-linux-amd64/{etcd,etcdctl} bin/
+
+        go mod download
+
+    - name: Run make tools
+      run: |
+        make tools
+
+    - name: Run test
+      timeout-minutes: 30
+      run: |
+        eatmydata -- make unit_test
diff --git a/go/vt/discovery/tablet_picker_test.go b/go/vt/discovery/tablet_picker_test.go
index 0f2f3e2431..94bfe4d56e 100644
--- a/go/vt/discovery/tablet_picker_test.go
+++ b/go/vt/discovery/tablet_picker_test.go
@@ -17,10 +17,13 @@ limitations under the License.
 package discovery
 
 import (
-	"context"
 	"testing"
 	"time"
 
+	"vitess.io/vitess/go/vt/log"
+
+	"context"
+
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"google.golang.org/protobuf/proto"
@@ -34,7 +37,7 @@ import (
 func TestPickSimple(t *testing.T) {
 	te := newPickerTestEnv(t, []string{"cell"})
 	want := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want)
+	defer deleteTablet(te, want)
 
 	tp, err := NewTabletPicker(te.topoServ, te.cells, te.keyspace, te.shard, "replica")
 	require.NoError(t, err)
@@ -47,9 +50,9 @@ func TestPickSimple(t *testing.T) {
 func TestPickFromTwoHealthy(t *testing.T) {
 	te := newPickerTestEnv(t, []string{"cell"})
 	want1 := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want1)
+	defer deleteTablet(te, want1)
 	want2 := addTablet(te, 101, topodatapb.TabletType_RDONLY, "cell", true, true)
-	defer deleteTablet(t, te, want2)
+	defer deleteTablet(te, want2)
 
 	tp, err := NewTabletPicker(te.topoServ, te.cells, te.keyspace, te.shard, "replica,rdonly")
 	require.NoError(t, err)
@@ -70,102 +73,12 @@ func TestPickFromTwoHealthy(t *testing.T) {
 	assert.True(t, picked2)
 }
 
-func TestPickInOrder1(t *testing.T) {
-	te := newPickerTestEnv(t, []string{"cell"})
-	want1 := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want1)
-	want2 := addTablet(te, 101, topodatapb.TabletType_RDONLY, "cell", true, true)
-	defer deleteTablet(t, te, want2)
-
-	tp, err := NewTabletPicker(te.topoServ, te.cells, te.keyspace, te.shard, "in_order:replica,rdonly")
-	require.NoError(t, err)
-
-	// In 20 attempts, we always pick the first healthy tablet in order
-	var picked1, picked2 bool
-	for i := 0; i < 20; i++ {
-		tablet, err := tp.PickForStreaming(context.Background())
-		require.NoError(t, err)
-		if proto.Equal(tablet, want1) {
-			picked1 = true
-		}
-		if proto.Equal(tablet, want2) {
-			picked2 = true
-		}
-	}
-	assert.True(t, picked1)
-	assert.False(t, picked2)
-}
-
-func TestPickInOrder2(t *testing.T) {
-	te := newPickerTestEnv(t, []string{"cell"})
-	want1 := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want1)
-	want2 := addTablet(te, 101, topodatapb.TabletType_RDONLY, "cell", true, true)
-	defer deleteTablet(t, te, want2)
-
-	tp, err := NewTabletPicker(te.topoServ, te.cells, te.keyspace, te.shard, "in_order:rdonly,replica")
-	require.NoError(t, err)
-
-	// In 20 attempts, we always pick the first healthy tablet in order
-	var picked1, picked2 bool
-	for i := 0; i < 20; i++ {
-		tablet, err := tp.PickForStreaming(context.Background())
-		require.NoError(t, err)
-		if proto.Equal(tablet, want1) {
-			picked1 = true
-		}
-		if proto.Equal(tablet, want2) {
-			picked2 = true
-		}
-	}
-	assert.False(t, picked1)
-	assert.True(t, picked2)
-}
-
-func TestPickInOrderMultipleInGroup(t *testing.T) {
-	te := newPickerTestEnv(t, []string{"cell"})
-	want1 := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want1)
-	want2 := addTablet(te, 101, topodatapb.TabletType_RDONLY, "cell", true, true)
-	defer deleteTablet(t, te, want2)
-	want3 := addTablet(te, 102, topodatapb.TabletType_RDONLY, "cell", true, true)
-	defer deleteTablet(t, te, want3)
-	want4 := addTablet(te, 103, topodatapb.TabletType_RDONLY, "cell", true, true)
-	defer deleteTablet(t, te, want4)
-
-	tp, err := NewTabletPicker(te.topoServ, te.cells, te.keyspace, te.shard, "in_order:rdonly,replica")
-	require.NoError(t, err)
-
-	// In 40 attempts, we pick each of the three RDONLY, but never the REPLICA
-	var picked1, picked2, picked3, picked4 bool
-	for i := 0; i < 40; i++ {
-		tablet, err := tp.PickForStreaming(context.Background())
-		require.NoError(t, err)
-		if proto.Equal(tablet, want1) {
-			picked1 = true
-		}
-		if proto.Equal(tablet, want2) {
-			picked2 = true
-		}
-		if proto.Equal(tablet, want3) {
-			picked3 = true
-		}
-		if proto.Equal(tablet, want4) {
-			picked4 = true
-		}
-	}
-	assert.False(t, picked1)
-	assert.True(t, picked2)
-	assert.True(t, picked3)
-	assert.True(t, picked4)
-}
-
 func TestPickRespectsTabletType(t *testing.T) {
 	te := newPickerTestEnv(t, []string{"cell"})
 	want := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want)
+	defer deleteTablet(te, want)
 	dont := addTablet(te, 101, topodatapb.TabletType_MASTER, "cell", true, true)
-	defer deleteTablet(t, te, dont)
+	defer deleteTablet(te, dont)
 
 	tp, err := NewTabletPicker(te.topoServ, te.cells, te.keyspace, te.shard, "replica,rdonly")
 	require.NoError(t, err)
@@ -182,7 +95,7 @@ func TestPickRespectsTabletType(t *testing.T) {
 func TestPickMultiCell(t *testing.T) {
 	te := newPickerTestEnv(t, []string{"cell", "otherCell"})
 	want := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want)
+	defer deleteTablet(te, want)
 
 	tp, err := NewTabletPicker(te.topoServ, te.cells, te.keyspace, te.shard, "replica")
 	require.NoError(t, err)
@@ -197,7 +110,7 @@ func TestPickMultiCell(t *testing.T) {
 func TestPickMaster(t *testing.T) {
 	te := newPickerTestEnv(t, []string{"cell", "otherCell"})
 	want := addTablet(te, 100, topodatapb.TabletType_MASTER, "cell", true, true)
-	defer deleteTablet(t, te, want)
+	defer deleteTablet(te, want)
 	ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
 	defer cancel()
 	_, err := te.topoServ.UpdateShardFields(ctx, te.keyspace, te.shard, func(si *topo.ShardInfo) error {
@@ -219,7 +132,7 @@ func TestPickMaster(t *testing.T) {
 func TestPickFromOtherCell(t *testing.T) {
 	te := newPickerTestEnv(t, []string{"cell", "otherCell"})
 	want := addTablet(te, 100, topodatapb.TabletType_REPLICA, "otherCell", true, true)
-	defer deleteTablet(t, te, want)
+	defer deleteTablet(te, want)
 
 	tp, err := NewTabletPicker(te.topoServ, te.cells, te.keyspace, te.shard, "replica")
 	require.NoError(t, err)
@@ -234,9 +147,9 @@ func TestPickFromOtherCell(t *testing.T) {
 func TestDontPickFromOtherCell(t *testing.T) {
 	te := newPickerTestEnv(t, []string{"cell", "otherCell"})
 	want1 := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want1)
+	defer deleteTablet(te, want1)
 	want2 := addTablet(te, 101, topodatapb.TabletType_REPLICA, "otherCell", true, true)
-	defer deleteTablet(t, te, want2)
+	defer deleteTablet(te, want2)
 
 	tp, err := NewTabletPicker(te.topoServ, []string{"cell"}, te.keyspace, te.shard, "replica")
 	require.NoError(t, err)
@@ -263,9 +176,9 @@ func TestDontPickFromOtherCell(t *testing.T) {
 func TestPickMultiCellTwoTablets(t *testing.T) {
 	te := newPickerTestEnv(t, []string{"cell", "otherCell"})
 	want1 := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want1)
+	defer deleteTablet(te, want1)
 	want2 := addTablet(te, 101, topodatapb.TabletType_REPLICA, "otherCell", true, true)
-	defer deleteTablet(t, te, want2)
+	defer deleteTablet(te, want2)
 
 	tp, err := NewTabletPicker(te.topoServ, te.cells, te.keyspace, te.shard, "replica")
 	require.NoError(t, err)
@@ -292,9 +205,9 @@ func TestPickMultiCellTwoTablets(t *testing.T) {
 func TestPickMultiCellTwoTabletTypes(t *testing.T) {
 	te := newPickerTestEnv(t, []string{"cell", "otherCell"})
 	want1 := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want1)
+	defer deleteTablet(te, want1)
 	want2 := addTablet(te, 101, topodatapb.TabletType_RDONLY, "otherCell", true, true)
-	defer deleteTablet(t, te, want2)
+	defer deleteTablet(te, want2)
 
 	tp, err := NewTabletPicker(te.topoServ, te.cells, te.keyspace, te.shard, "replica,rdonly")
 	require.NoError(t, err)
@@ -322,7 +235,7 @@ func TestPickUsingCellAlias(t *testing.T) {
 	// test env puts all cells into an alias called "cella"
 	te := newPickerTestEnv(t, []string{"cell", "otherCell"})
 	want1 := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want1)
+	defer deleteTablet(te, want1)
 
 	tp, err := NewTabletPicker(te.topoServ, []string{"cella"}, te.keyspace, te.shard, "replica")
 	require.NoError(t, err)
@@ -334,9 +247,9 @@ func TestPickUsingCellAlias(t *testing.T) {
 	assert.True(t, proto.Equal(want1, tablet), "Pick: %v, want %v", tablet, want1)
 
 	// create a tablet in the other cell, it should be picked
-	deleteTablet(t, te, want1)
+	deleteTablet(te, want1)
 	want2 := addTablet(te, 101, topodatapb.TabletType_REPLICA, "otherCell", true, true)
-	defer deleteTablet(t, te, want2)
+	defer deleteTablet(te, want2)
 	ctx2, cancel2 := context.WithTimeout(context.Background(), 200*time.Millisecond)
 	defer cancel2()
 	tablet, err = tp.PickForStreaming(ctx2)
@@ -386,7 +299,7 @@ func TestTabletAppearsDuringSleep(t *testing.T) {
 	}()
 
 	want := addTablet(te, 100, topodatapb.TabletType_REPLICA, "cell", true, true)
-	defer deleteTablet(t, te, want)
+	defer deleteTablet(te, want)
 	got := <-result
 	require.NotNil(t, got, "Tablet should not be nil")
 	assert.True(t, proto.Equal(want, got), "Pick: %v, want %v", got, want)
@@ -411,12 +324,11 @@ func TestPickError(t *testing.T) {
 	_, err = tp.PickForStreaming(ctx)
 	require.EqualError(t, err, "context has expired")
 	// no tablets of the correct type
-	defer deleteTablet(t, te, addTablet(te, 200, topodatapb.TabletType_RDONLY, "cell", true, true))
+	defer deleteTablet(te, addTablet(te, 200, topodatapb.TabletType_RDONLY, "cell", true, true))
 	ctx, cancel = context.WithTimeout(context.Background(), 20*time.Millisecond)
 	defer cancel()
 	_, err = tp.PickForStreaming(ctx)
 	require.EqualError(t, err, "context has expired")
-	require.Greater(t, globalTPStats.noTabletFoundError.Counts()["cell.ks.0.replica"], int64(0))
 }
 
 type pickerTestEnv struct {
@@ -482,16 +394,18 @@ func addTablet(te *pickerTestEnv, id int, tabletType topodatapb.TabletType, cell
 	return tablet
 }
 
-func deleteTablet(t *testing.T, te *pickerTestEnv, tablet *topodatapb.Tablet) {
+func deleteTablet(te *pickerTestEnv, tablet *topodatapb.Tablet) {
+
 	if tablet == nil {
 		return
 	}
-	{ //log error
-		err := te.topoServ.DeleteTablet(context.Background(), tablet.Alias)
-		require.NoError(t, err, "failed to DeleteTablet with alias: %v", err)
+	//log error
+	if err := te.topoServ.DeleteTablet(context.Background(), tablet.Alias); err != nil {
+		log.Errorf("failed to DeleteTablet with alias : %v", err)
 	}
-	{ //This is not automatically removed from shard replication, which results in log spam and log error
-		err := topo.DeleteTabletReplicationData(context.Background(), te.topoServ, tablet)
-		require.NoError(t, err, "failed to automatically remove from shard replication: %v", err)
+
+	//This is not automatically removed from shard replication, which results in log spam and log error
+	if err := topo.DeleteTabletReplicationData(context.Background(), te.topoServ, tablet); err != nil {
+		log.Errorf("failed to automatically remove from shard replication: %v", err)
 	}
 }
diff --git a/go/vt/schema/online_ddl_test.go b/go/vt/schema/online_ddl_test.go
index fcf4634ac4..b361ac1ae3 100644
--- a/go/vt/schema/online_ddl_test.go
+++ b/go/vt/schema/online_ddl_test.go
@@ -210,8 +210,8 @@ func TestNewOnlineDDL(t *testing.T) {
 		NewDDLStrategySetting(DDLStrategyOnline, ""),
 		NewDDLStrategySetting(DDLStrategyOnline, "-singleton"),
 	}
-	require.True(t, strategies[0].IsSkipTopo())
-	require.True(t, strategies[1].IsSkipTopo())
+	require.False(t, strategies[0].IsSkipTopo())
+	require.False(t, strategies[1].IsSkipTopo())
 	require.True(t, strategies[2].IsSkipTopo())
 
 	for _, ts := range tt {
@@ -224,11 +224,16 @@ func TestNewOnlineDDL(t *testing.T) {
 						return
 					}
 					assert.NoError(t, err)
-					require.True(t, stgy.IsSkipTopo(), "IsSkipTopo() should always be true")
-					// onlineDDL.SQL enriched with /*vt+ ... */ comment
-					assert.Contains(t, onlineDDL.SQL, hex.EncodeToString([]byte(onlineDDL.UUID)))
-					assert.Contains(t, onlineDDL.SQL, hex.EncodeToString([]byte(migrationContext)))
-					assert.Contains(t, onlineDDL.SQL, hex.EncodeToString([]byte(string(stgy.Strategy))))
+					if stgy.IsSkipTopo() {
+						// onlineDDL.SQL enriched with /*vt+ ... */ comment
+						assert.Contains(t, onlineDDL.SQL, hex.EncodeToString([]byte(onlineDDL.UUID)))
+						assert.Contains(t, onlineDDL.SQL, hex.EncodeToString([]byte(migrationContext)))
+						assert.Contains(t, onlineDDL.SQL, hex.EncodeToString([]byte(string(stgy.Strategy))))
+					} else {
+						assert.NotContains(t, onlineDDL.SQL, hex.EncodeToString([]byte(onlineDDL.UUID)))
+						assert.NotContains(t, onlineDDL.SQL, hex.EncodeToString([]byte(migrationContext)))
+						assert.NotContains(t, onlineDDL.SQL, hex.EncodeToString([]byte(string(stgy.Strategy))))
+					}
 				})
 			}
 		})
@@ -292,8 +297,7 @@ func TestNewOnlineDDLs(t *testing.T) {
 
 			sqls := []string{}
 			for _, onlineDDL := range onlineDDLs {
-				sql, err := onlineDDL.sqlWithoutComments()
-				assert.NoError(t, err)
+				sql := onlineDDL.SQL
 				sql = strings.ReplaceAll(sql, "\n", "")
 				sql = strings.ReplaceAll(sql, "\t", "")
 				sqls = append(sqls, sql)
diff --git a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
index 4ae8b355b6..08422d1fc7 100644
--- a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
@@ -557,7 +557,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select user_extra.id from `user` join user_extra on `user`.id = user_extra.user_id where 1 != 1",
     "Query": "select user_extra.id from `user` join user_extra on `user`.id = user_extra.user_id where `user`.id = 5",
-    "Table": "`user`",
+    "Table": "`user`, user_extra",
     "Values": [
       5
     ],
@@ -598,7 +598,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select user_extra.id from `user` join user_extra on `user`.id = user_extra.user_id where 1 != 1",
     "Query": "select user_extra.id from `user` join user_extra on `user`.id = user_extra.user_id where user_extra.user_id = 5",
-    "Table": "`user`",
+    "Table": "`user`, user_extra",
     "Values": [
       5
     ],
@@ -639,7 +639,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select user_extra.id from `user` left join user_extra on `user`.id = user_extra.user_id where 1 != 1",
     "Query": "select user_extra.id from `user` left join user_extra on `user`.id = user_extra.user_id where `user`.id = 5",
-    "Table": "`user`",
+    "Table": "`user`, user_extra",
     "Values": [
       5
     ],
@@ -662,7 +662,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select user_extra.id from `user` left join user_extra on `user`.id = user_extra.user_id where 1 != 1",
     "Query": "select user_extra.id from `user` left join user_extra on `user`.id = user_extra.user_id where user_extra.user_id = 5",
-    "Table": "`user`",
+    "Table": "`user`, user_extra",
     "Values": [
       5
     ],
@@ -1185,7 +1185,8 @@ Gen4 plan same as above
       "Sharded": false
     },
     "FieldQuery": "select * from information_schema.a where 1 != 1",
-    "Query": "select * from information_schema.a where id in (select * from information_schema.b)"
+    "Query": "select * from information_schema.a where id in (select * from information_schema.b)",
+    "Table": "information_schema.a"
   }
 }
 
@@ -1700,7 +1701,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select user_extra.Id from `user` join user_extra on `user`.iD = user_extra.User_Id where 1 != 1",
     "Query": "select user_extra.Id from `user` join user_extra on `user`.iD = user_extra.User_Id where `user`.Id = 5",
-    "Table": "`user`",
+    "Table": "`user`, user_extra",
     "Values": [
       5
     ],
@@ -1912,7 +1913,6 @@ Gen4 plan same as above
 }
 Gen4 plan same as above
 
-
 # query trying to query two different keyspaces at the same time
 "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'user' AND TABLE_SCHEMA = 'main'"
 {
@@ -1927,7 +1927,8 @@ Gen4 plan same as above
     },
     "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1",
     "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and TABLE_SCHEMA = :__vtschemaname",
-    "SysTableTableSchema": "[VARBINARY(\"user\"), VARBINARY(\"main\")]"
+    "SysTableTableSchema": "[VARBINARY(\"user\"), VARBINARY(\"main\")]",
+    "Table": "INFORMATION_SCHEMA.`TABLES`"
   }
 }
 
@@ -1944,9 +1945,11 @@ Gen4 plan same as above
       "Sharded": false
     },
     "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1",
-    "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = database()"
+    "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = database()",
+    "Table": "INFORMATION_SCHEMA.`TABLES`"
   }
 }
+Gen4 plan same as above
 
 # table_schema predicate the wrong way around
 "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE 'ks' = TABLE_SCHEMA"
@@ -1962,24 +1965,8 @@ Gen4 plan same as above
     },
     "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1",
     "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname",
-    "SysTableTableSchema": "[VARBINARY(\"ks\")]"
-  }
-}
-
-# table_schema OR predicate
-"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'ks' OR TABLE_SCHEMA = 'main'"
-{
-  "QueryType": "SELECT",
-  "Original": "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'ks' OR TABLE_SCHEMA = 'main'",
-  "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 = 'ks' or TABLE_SCHEMA = 'main'"
+    "SysTableTableSchema": "[VARBINARY(\"ks\")]",
+    "Table": "INFORMATION_SCHEMA.`TABLES`"
   }
 }
 
@@ -1998,7 +1985,8 @@ Gen4 plan same as above
     "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1",
     "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and TABLE_NAME = :__vttablename",
     "SysTableTableName": "[VARBINARY(\"route1\")]",
-    "SysTableTableSchema": "[VARBINARY(\"ks\")]"
+    "SysTableTableSchema": "[VARBINARY(\"ks\")]",
+    "Table": "INFORMATION_SCHEMA.`TABLES`"
   }
 }
 
@@ -2016,7 +2004,8 @@ Gen4 plan same as above
     },
     "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1",
     "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and other_column = 42",
-    "SysTableTableSchema": "[VARBINARY(\"ks\")]"
+    "SysTableTableSchema": "[VARBINARY(\"ks\")]",
+    "Table": "INFORMATION_SCHEMA.`TABLES`"
   }
 }
 
@@ -2098,7 +2087,8 @@ Gen4 plan same as above
     },
     "FieldQuery": "select * from INFORMATION_SCHEMA.`TABLES` where 1 != 1",
     "Query": "select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname and (other_column = 42 or TABLE_SCHEMA = 'ks') and (other_column = 42 or foobar = 'value')",
-    "SysTableTableSchema": "[VARBINARY(\"ks\")]"
+    "SysTableTableSchema": "[VARBINARY(\"ks\")]",
+    "Table": "INFORMATION_SCHEMA.`TABLES`"
   }
 }
 
@@ -2125,7 +2115,6 @@ Gen4 plan same as above
 }
 Gen4 plan same as above
 
-
 "select * from samecolvin where col = :col"
 {
   "QueryType": "SELECT",
diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.txt b/go/vt/vtgate/planbuilder/testdata/from_cases.txt
index d80acba258..83539e3704 100644
--- a/go/vt/vtgate/planbuilder/testdata/from_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/from_cases.txt
@@ -87,9 +87,11 @@ Gen4 plan same as above
       "Sharded": false
     },
     "FieldQuery": "select col from information_schema.foo where 1 != 1",
-    "Query": "select col from information_schema.foo"
+    "Query": "select col from information_schema.foo",
+    "Table": "information_schema.foo"
   }
 }
+Gen4 plan same as above
 
 # Multi-table unsharded
 "select m1.col from unsharded as m1 join unsharded as m2"
@@ -332,9 +334,11 @@ Gen4 plan same as above
       "Sharded": false
     },
     "FieldQuery": "select a.id, b.id from information_schema.a as a, information_schema.b as b where 1 != 1",
-    "Query": "select a.id, b.id from information_schema.a as a, information_schema.b as b"
+    "Query": "select a.id, b.id from information_schema.a as a, information_schema.b as b",
+    "Table": "information_schema.a, information_schema.b"
   }
 }
+Gen4 plan same as above
 
 # ',' 3-way join unsharded
 "select u1.a, u2.a from unsharded u1, unsharded u2, unsharded u3"
@@ -821,7 +825,6 @@ Gen4 plan same as above
   }
 }
 
-
 # Parenthesized, single chunk
 "select user.col from user join (unsharded as m1 join unsharded as m2)"
 {
@@ -1018,6 +1021,7 @@ Gen4 plan same as above
     "Table": "`user`"
   }
 }
+Gen4 plan same as above
 
 # mergeable sharded join on unique vindex
 "select user.col from user join user_extra on user.id = user_extra.user_id"
@@ -1033,7 +1037,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select `user`.col from `user` join user_extra on `user`.id = user_extra.user_id where 1 != 1",
     "Query": "select `user`.col from `user` join user_extra on `user`.id = user_extra.user_id",
-    "Table": "`user`"
+    "Table": "`user`, user_extra"
   }
 }
 {
@@ -1066,7 +1070,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select `user`.col from `user` join user_extra on `user`.id = user_extra.user_id where 1 != 1",
     "Query": "select `user`.col from `user` join user_extra on `user`.id = user_extra.user_id",
-    "Table": "`user`"
+    "Table": "`user`, user_extra"
   }
 }
 {
@@ -1099,7 +1103,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select `user`.col from `user` join user_extra on `user`.col between 1 and 2 and `user`.id = user_extra.user_id where 1 != 1",
     "Query": "select `user`.col from `user` join user_extra on `user`.col between 1 and 2 and `user`.id = user_extra.user_id",
-    "Table": "`user`"
+    "Table": "`user`, user_extra"
   }
 }
 {
@@ -1132,7 +1136,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select `user`.col from `user` join user_extra on user_extra.user_id = `user`.id where 1 != 1",
     "Query": "select `user`.col from `user` join user_extra on user_extra.user_id = `user`.id",
-    "Table": "`user`"
+    "Table": "`user`, user_extra"
   }
 }
 {
@@ -1165,7 +1169,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select `user`.col from `user` join user_extra on `user`.id = 5 and `user`.id = user_extra.user_id where 1 != 1",
     "Query": "select `user`.col from `user` join user_extra on `user`.id = 5 and `user`.id = user_extra.user_id",
-    "Table": "`user`",
+    "Table": "`user`, user_extra",
     "Values": [
       5
     ],
@@ -1481,7 +1485,22 @@ Gen4 plan same as above
     },
     "FieldQuery": "select `user`.col from `user` join ref where 1 != 1",
     "Query": "select `user`.col from `user` join ref",
-    "Table": "`user`"
+    "Table": "`user`, ref"
+  }
+}
+{
+  "QueryType": "SELECT",
+  "Original": "select user.col from user join ref",
+  "Instructions": {
+    "OperatorType": "Route",
+    "Variant": "SelectScatter",
+    "Keyspace": {
+      "Name": "user",
+      "Sharded": true
+    },
+    "FieldQuery": "select `user`.col from `user`, ref where 1 != 1",
+    "Query": "select `user`.col from `user`, ref",
+    "Table": "`user`, ref"
   }
 }
 
@@ -1502,6 +1521,21 @@ Gen4 plan same as above
     "Table": "ref"
   }
 }
+{
+  "QueryType": "SELECT",
+  "Original": "select r1.col from ref r1 join ref",
+  "Instructions": {
+    "OperatorType": "Route",
+    "Variant": "SelectReference",
+    "Keyspace": {
+      "Name": "user",
+      "Sharded": true
+    },
+    "FieldQuery": "select r1.col from ref as r1, ref where 1 != 1",
+    "Query": "select r1.col from ref as r1, ref",
+    "Table": "ref"
+  }
+}
 
 # reference table can merge with other opcodes left to right.
 "select ref.col from ref join user"
@@ -1517,7 +1551,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select ref.col from ref join `user` where 1 != 1",
     "Query": "select ref.col from ref join `user`",
-    "Table": "`user`"
+    "Table": "`user`, ref"
   }
 }
 
@@ -1536,7 +1570,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select ref.col from ref join (select aa from `user` where 1 != 1) as `user` where 1 != 1",
     "Query": "select ref.col from ref join (select aa from `user` where `user`.id = 1) as `user`",
-    "Table": "`user`",
+    "Table": "`user`, ref",
     "Values": [
       1
     ],
@@ -1618,7 +1652,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select t.id from (select id from `user` where 1 != 1) as t join user_extra on t.id = user_extra.user_id where 1 != 1",
     "Query": "select t.id from (select id from `user` where id = 5) as t join user_extra on t.id = user_extra.user_id",
-    "Table": "`user`",
+    "Table": "`user`, user_extra",
     "Values": [
       5
     ],
@@ -1640,7 +1674,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select t.id from (select `user`.id from `user` where 1 != 1) as t join user_extra on t.id = user_extra.user_id where 1 != 1",
     "Query": "select t.id from (select `user`.id from `user` where `user`.id = 5) as t join user_extra on t.id = user_extra.user_id",
-    "Table": "`user`",
+    "Table": "`user`, user_extra",
     "Values": [
       5
     ],
@@ -1666,7 +1700,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select t.id from user_extra join (select id from `user` where 1 != 1) as t on t.id = user_extra.user_id where 1 != 1",
     "Query": "select t.id from user_extra join (select id from `user` where id = 5) as t on t.id = user_extra.user_id",
-    "Table": "user_extra"
+    "Table": "user_extra, `user`"
   }
 }
 
@@ -1777,7 +1811,6 @@ Gen4 plan same as above
   }
 }
 
-
 # merge subqueries with single-shard routes
 "select u.col, e.col from (select col from user where id = 5) as u join (select col from user_extra where user_id = 5) as e"
 {
@@ -1792,7 +1825,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select u.col, e.col from (select col from `user` where 1 != 1) as u join (select col from user_extra where 1 != 1) as e where 1 != 1",
     "Query": "select u.col, e.col from (select col from `user` where id = 5) as u join (select col from user_extra where user_id = 5) as e",
-    "Table": "`user`",
+    "Table": "`user`, user_extra",
     "Values": [
       5
     ],
@@ -1813,9 +1846,11 @@ Gen4 plan same as above
       "Sharded": false
     },
     "FieldQuery": "select * from information_schema.a where 1 != 1",
-    "Query": "select * from information_schema.a where b = 10"
+    "Query": "select * from information_schema.a where b = 10",
+    "Table": "information_schema.a"
   }
 }
+Gen4 plan same as above
 
 # access to qualified column names in information_schema
 "select * from information_schema.a where information_schema.a.b=10"
@@ -1830,9 +1865,11 @@ Gen4 plan same as above
       "Sharded": false
     },
     "FieldQuery": "select * from information_schema.a where 1 != 1",
-    "Query": "select * from information_schema.a where information_schema.a.b = 10"
+    "Query": "select * from information_schema.a where information_schema.a.b = 10",
+    "Table": "information_schema.a"
   }
 }
+Gen4 plan same as above
 
 # join of information_schema with normal table
 "select unsharded.foo from information_schema.a join unsharded"
@@ -1843,7 +1880,7 @@ Gen4 plan same as above
     "OperatorType": "Join",
     "Variant": "Join",
     "JoinColumnIndexes": "1",
-    "TableName": "_unsharded",
+    "TableName": "information_schema.a_unsharded",
     "Inputs": [
       {
         "OperatorType": "Route",
@@ -1853,7 +1890,8 @@ Gen4 plan same as above
           "Sharded": false
         },
         "FieldQuery": "select 1 from information_schema.a where 1 != 1",
-        "Query": "select 1 from information_schema.a"
+        "Query": "select 1 from information_schema.a",
+        "Table": "information_schema.a"
       },
       {
         "OperatorType": "Route",
@@ -1869,6 +1907,7 @@ Gen4 plan same as above
     ]
   }
 }
+Gen4 plan same as above
 
 # join of normal table with information_schema
 "select unsharded.foo from unsharded join information_schema.a"
@@ -1879,7 +1918,7 @@ Gen4 plan same as above
     "OperatorType": "Join",
     "Variant": "Join",
     "JoinColumnIndexes": "-1",
-    "TableName": "unsharded_",
+    "TableName": "unsharded_information_schema.a",
     "Inputs": [
       {
         "OperatorType": "Route",
@@ -1900,11 +1939,13 @@ Gen4 plan same as above
           "Sharded": false
         },
         "FieldQuery": "select 1 from information_schema.a where 1 != 1",
-        "Query": "select 1 from information_schema.a"
+        "Query": "select 1 from information_schema.a",
+        "Table": "information_schema.a"
       }
     ]
   }
 }
+Gen4 plan same as above
 
 # wire-up on join with cross-shard subquery
 "select t.col1 from (select user.id, user.col1 from user join user_extra) as t join unsharded on unsharded.col1 = t.col1 and unsharded.id = t.id"
@@ -2109,7 +2150,7 @@ Gen4 plan same as above
         },
         "FieldQuery": "select unsharded_a.col from unsharded_a join unsharded_b on :__sq1 where 1 != 1",
         "Query": "select unsharded_a.col from unsharded_a join unsharded_b on :__sq1",
-        "Table": "unsharded_a"
+        "Table": "unsharded_a, unsharded_b"
       }
     ]
   }
@@ -2144,7 +2185,7 @@ Gen4 plan same as above
         },
         "FieldQuery": "select unsharded_a.col from unsharded_a join unsharded_b on unsharded_a.col + :__sq1 where 1 != 1",
         "Query": "select unsharded_a.col from unsharded_a join unsharded_b on unsharded_a.col + :__sq1",
-        "Table": "unsharded_a"
+        "Table": "unsharded_a, unsharded_b"
       }
     ]
   }
@@ -2179,7 +2220,7 @@ Gen4 plan same as above
         },
         "FieldQuery": "select unsharded_a.col from unsharded_a join unsharded_b on :__sq_has_values1 = 1 and unsharded_a.col in ::__sq1 where 1 != 1",
         "Query": "select unsharded_a.col from unsharded_a join unsharded_b on :__sq_has_values1 = 1 and unsharded_a.col in ::__sq1",
-        "Table": "unsharded_a"
+        "Table": "unsharded_a, unsharded_b"
       }
     ]
   }
@@ -2472,7 +2513,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select `user`.col from `user` join user_extra on `user`.ID = user_extra.User_Id where 1 != 1",
     "Query": "select `user`.col from `user` join user_extra on `user`.ID = user_extra.User_Id",
-    "Table": "`user`"
+    "Table": "`user`, user_extra"
   }
 }
 {
@@ -2763,9 +2804,11 @@ Gen4 plan same as above
       "Sharded": false
     },
     "FieldQuery": "select column_name from information_schema.`columns` where 1 != 1",
-    "Query": "select column_name from information_schema.`columns` where table_schema = schema()"
+    "Query": "select column_name from information_schema.`columns` where table_schema = schema()",
+    "Table": "information_schema.`columns`"
   }
 }
+Gen4 plan same as above
 
 # information schema join
 "select * from information_schema.a join information_schema.b"
@@ -2780,7 +2823,23 @@ Gen4 plan same as above
       "Sharded": false
     },
     "FieldQuery": "select * from information_schema.a join information_schema.b where 1 != 1",
-    "Query": "select * from information_schema.a join information_schema.b"
+    "Query": "select * from information_schema.a join information_schema.b",
+    "Table": "information_schema.a, information_schema.b"
+  }
+}
+{
+  "QueryType": "SELECT",
+  "Original": "select * from information_schema.a join information_schema.b",
+  "Instructions": {
+    "OperatorType": "Route",
+    "Variant": "SelectDBA",
+    "Keyspace": {
+      "Name": "main",
+      "Sharded": false
+    },
+    "FieldQuery": "select * from information_schema.a, information_schema.b where 1 != 1",
+    "Query": "select * from information_schema.a, information_schema.b",
+    "Table": "information_schema.a, information_schema.b"
   }
 }
 
@@ -2798,7 +2857,8 @@ Gen4 plan same as above
     },
     "FieldQuery": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where 1 != 1",
     "Query": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where fk.referenced_column_name is not null and fk.table_schema = database() and fk.table_name = :__vttablename and rc.constraint_schema = database() and rc.table_name = :__vttablename",
-    "SysTableTableName": "[VARBINARY(\":vtg1\"), VARBINARY(\":vtg1\")]"
+    "SysTableTableName": "[VARBINARY(\":vtg1\"), VARBINARY(\":vtg1\")]",
+    "Table": "information_schema.referential_constraints, information_schema.key_column_usage"
   }
 }
 
@@ -2816,7 +2876,8 @@ Gen4 plan same as above
     },
     "FieldQuery": "select * from information_schema.schemata where 1 != 1",
     "Query": "select * from information_schema.schemata where schema_name = :__vtschemaname",
-    "SysTableTableSchema": "[VARBINARY(\"user\")]"
+    "SysTableTableSchema": "[VARBINARY(\"user\")]",
+    "Table": "information_schema.schemata"
   }
 }
 
@@ -2835,7 +2896,8 @@ Gen4 plan same as above
     "FieldQuery": "select table_comment from information_schema.`tables` where 1 != 1",
     "Query": "select table_comment from information_schema.`tables` where table_schema = :__vtschemaname and table_name = :__vttablename",
     "SysTableTableName": "[VARBINARY(\"table_name\")]",
-    "SysTableTableSchema": "[VARBINARY(\"schema_name\")]"
+    "SysTableTableSchema": "[VARBINARY(\"schema_name\")]",
+    "Table": "information_schema.`tables`"
   }
 }
 
@@ -2854,7 +2916,8 @@ Gen4 plan same as above
     "FieldQuery": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where 1 != 1",
     "Query": "select fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as `name`, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on rc.constraint_schema = fk.constraint_schema and rc.constraint_name = fk.constraint_name where fk.referenced_column_name is not null and fk.table_schema = :__vtschemaname and fk.table_name = :__vttablename and rc.constraint_schema = :__vtschemaname and rc.table_name = :__vttablename",
     "SysTableTableName": "[VARBINARY(\"table_name\"), VARBINARY(\"table_name\")]",
-    "SysTableTableSchema": "[VARBINARY(\"table_schema\"), VARBINARY(\"table_schema\")]"
+    "SysTableTableSchema": "[VARBINARY(\"table_schema\"), VARBINARY(\"table_schema\")]",
+    "Table": "information_schema.referential_constraints, information_schema.key_column_usage"
   }
 }
 
@@ -2873,7 +2936,8 @@ Gen4 plan same as above
     "FieldQuery": "select cc.constraint_name as `name`, cc.check_clause as expression from information_schema.check_constraints as cc join information_schema.table_constraints as tc on cc.constraint_schema = tc.constraint_schema and cc.constraint_name = tc.constraint_name where 1 != 1",
     "Query": "select cc.constraint_name as `name`, cc.check_clause as expression from information_schema.check_constraints as cc join information_schema.table_constraints as tc on cc.constraint_schema = tc.constraint_schema and cc.constraint_name = tc.constraint_name where tc.table_schema = :__vtschemaname and tc.table_name = :__vttablename and cc.constraint_schema = :__vtschemaname",
     "SysTableTableName": "[VARBINARY(\"table_name\")]",
-    "SysTableTableSchema": "[VARBINARY(\"table_schema\"), VARBINARY(\"constraint_schema\")]"
+    "SysTableTableSchema": "[VARBINARY(\"table_schema\"), VARBINARY(\"constraint_schema\")]",
+    "Table": "information_schema.check_constraints, information_schema.table_constraints"
   }
 }
 
@@ -2892,7 +2956,8 @@ Gen4 plan same as above
     "FieldQuery": "select column_name from information_schema.statistics where 1 != 1",
     "Query": "select column_name from information_schema.statistics where index_name = 'PRIMARY' and table_schema = :__vtschemaname and table_name = :__vttablename order by seq_in_index asc",
     "SysTableTableName": "[VARBINARY(\"table_name\")]",
-    "SysTableTableSchema": "[VARBINARY(\"table_schema\")]"
+    "SysTableTableSchema": "[VARBINARY(\"table_schema\")]",
+    "Table": "information_schema.statistics"
   }
 }
 
@@ -2911,7 +2976,8 @@ Gen4 plan same as above
     "FieldQuery": "select generation_expression from information_schema.`columns` where 1 != 1",
     "Query": "select generation_expression from information_schema.`columns` where table_schema = :__vtschemaname and table_name = :__vttablename and column_name = 'column_name'",
     "SysTableTableName": "[VARBINARY(\"table_name\")]",
-    "SysTableTableSchema": "[VARBINARY(\"table_schema\")]"
+    "SysTableTableSchema": "[VARBINARY(\"table_schema\")]",
+    "Table": "information_schema.`columns`"
   }
 }
 
@@ -2928,9 +2994,11 @@ Gen4 plan same as above
       "Sharded": false
     },
     "FieldQuery": "select id from information_schema.`processlist` where 1 != 1",
-    "Query": "select id from information_schema.`processlist` where info like '% FOR UPDATE'"
+    "Query": "select id from information_schema.`processlist` where info like '% FOR UPDATE'",
+    "Table": "information_schema.`processlist`"
   }
 }
+Gen4 plan same as above
 
 #rails_query 9
 "SELECT table_name FROM (SELECT * FROM information_schema.tables WHERE table_schema = 'table_schema') _subquery"
@@ -2946,7 +3014,8 @@ Gen4 plan same as above
     },
     "FieldQuery": "select table_name from (select * from information_schema.`tables` where 1 != 1) as _subquery where 1 != 1",
     "Query": "select table_name from (select * from information_schema.`tables` where table_schema = :__vtschemaname) as _subquery",
-    "SysTableTableSchema": "[VARBINARY(\"table_schema\")]"
+    "SysTableTableSchema": "[VARBINARY(\"table_schema\")]",
+    "Table": "information_schema.`tables`"
   }
 }
 
@@ -2965,7 +3034,8 @@ Gen4 plan same as above
     "FieldQuery": "select table_name from (select * from information_schema.`tables` where 1 != 1) as _subquery where 1 != 1",
     "Query": "select table_name from (select * from information_schema.`tables` where table_schema = :__vtschemaname) as _subquery where _subquery.table_type = 'table_type' and _subquery.table_name = :__vttablename",
     "SysTableTableName": "[VARBINARY(\"table_name\")]",
-    "SysTableTableSchema": "[VARBINARY(\"table_schema\")]"
+    "SysTableTableSchema": "[VARBINARY(\"table_schema\")]",
+    "Table": "information_schema.`tables`"
   }
 }
 
@@ -2983,7 +3053,8 @@ Gen4 plan same as above
     },
     "FieldQuery": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where 1 != 1",
     "Query": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where cc.constraint_schema = :__vtschemaname and cc.table_schema = :__vtschemaname",
-    "SysTableTableSchema": "[VARBINARY(\"a\"), VARBINARY(\"a\")]"
+    "SysTableTableSchema": "[VARBINARY(\"a\"), VARBINARY(\"a\")]",
+    "Table": "information_schema.check_constraints"
   }
 }
 
@@ -3002,7 +3073,8 @@ Gen4 plan same as above
     "FieldQuery": "select COUNT(*) from INFORMATION_SCHEMA.`TABLES` where 1 != 1",
     "Query": "select COUNT(*) from INFORMATION_SCHEMA.`TABLES` where table_schema = :__vtschemaname and table_name = :__vttablename",
     "SysTableTableName": "[VARBINARY(\"foo\")]",
-    "SysTableTableSchema": "[VARBINARY(\"performance_schema\")]"
+    "SysTableTableSchema": "[VARBINARY(\"performance_schema\")]",
+    "Table": "INFORMATION_SCHEMA.`TABLES`"
   }
 }
 
diff --git a/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt b/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt
index 9072021236..5e6418c4f0 100644
--- a/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt
@@ -1072,7 +1072,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select * from `user` as u join (select user_id from user_extra where 1 != 1) as eu on u.id = eu.user_id where 1 != 1",
     "Query": "select * from `user` as u join (select user_id from user_extra where user_id = 5) as eu on u.id = eu.user_id where u.id = 5 order by eu.user_id asc",
-    "Table": "`user`",
+    "Table": "`user`, user_extra",
     "Values": [
       5
     ],
@@ -1416,7 +1416,6 @@ Gen4 plan same as above
     ]
   }
 }
-"gen4 does not yet support: aggregation and non-aggregation expressions, together are not supported in cross-shard query"
 
 # aggregation and non-aggregations column with order by
 "select count(id), num from user order by 2"
@@ -1449,7 +1448,6 @@ Gen4 plan same as above
     ]
   }
 }
-"gen4 does not yet support: aggregation and non-aggregation expressions, together are not supported in cross-shard query"
 
 # aggregation and non-aggregations column with group by
 "select count(id), num from user group by 2"
@@ -1478,7 +1476,6 @@ Gen4 plan same as above
     ]
   }
 }
-"gen4 does not yet support: aggregation and non-aggregation expressions, together are not supported in cross-shard query"
 
 # aggregation and non-aggregations column with group by and order by
 "select count(id), num from user group by 2 order by 1"
@@ -1514,5 +1511,3 @@ Gen4 plan same as above
     ]
   }
 }
-"gen4 does not yet support: aggregation and non-aggregation expressions, together are not supported in cross-shard query"
-
diff --git a/go/vt/vtgate/planbuilder/testdata/select_cases.txt b/go/vt/vtgate/planbuilder/testdata/select_cases.txt
index 46650433ae..68e697dbc2 100644
--- a/go/vt/vtgate/planbuilder/testdata/select_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/select_cases.txt
@@ -269,6 +269,21 @@ Gen4 plan same as above
     "Table": "authoritative"
   }
 }
+{
+  "QueryType": "SELECT",
+  "Original": "select * from authoritative",
+  "Instructions": {
+    "OperatorType": "Route",
+    "Variant": "SelectScatter",
+    "Keyspace": {
+      "Name": "user",
+      "Sharded": true
+    },
+    "FieldQuery": "select authoritative.user_id as user_id, authoritative.col1 as col1, authoritative.col2 as col2 from authoritative where 1 != 1",
+    "Query": "select authoritative.user_id as user_id, authoritative.col1 as col1, authoritative.col2 as col2 from authoritative",
+    "Table": "authoritative"
+  }
+}
 
 # select * from join of authoritative tables
 "select * from authoritative a join authoritative b on a.user_id=b.user_id"
@@ -291,6 +306,7 @@ Gen4 plan same as above
 # test table lookup failure for authoritative code path
 "select a.* from authoritative"
 "table a not found"
+"Unknown table 'a'"
 
 # select * from qualified authoritative table
 "select a.* from authoritative a"
@@ -309,6 +325,21 @@ Gen4 plan same as above
     "Table": "authoritative"
   }
 }
+{
+  "QueryType": "SELECT",
+  "Original": "select a.* from authoritative a",
+  "Instructions": {
+    "OperatorType": "Route",
+    "Variant": "SelectScatter",
+    "Keyspace": {
+      "Name": "user",
+      "Sharded": true
+    },
+    "FieldQuery": "select a.user_id as user_id, a.col1 as col1, a.col2 as col2 from authoritative as a where 1 != 1",
+    "Query": "select a.user_id as user_id, a.col1 as col1, a.col2 as col2 from authoritative as a",
+    "Table": "authoritative"
+  }
+}
 
 # select * from intermixing of authoritative table with non-authoritative results in no expansion
 "select * from authoritative join user on authoritative.user_id=user.id"
@@ -324,7 +355,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select * from authoritative join `user` on authoritative.user_id = `user`.id where 1 != 1",
     "Query": "select * from authoritative join `user` on authoritative.user_id = `user`.id",
-    "Table": "authoritative"
+    "Table": "authoritative, `user`"
   }
 }
 
@@ -342,7 +373,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select `user`.id, a.user_id, a.col1, a.col2, `user`.col1 from authoritative as a join `user` on a.user_id = `user`.id where 1 != 1",
     "Query": "select `user`.id, a.user_id, a.col1, a.col2, `user`.col1 from authoritative as a join `user` on a.user_id = `user`.id",
-    "Table": "authoritative"
+    "Table": "authoritative, `user`"
   }
 }
 
@@ -360,13 +391,62 @@ Gen4 plan same as above
     },
     "FieldQuery": "select col from `user` join user_extra on `user`.id = user_extra.user_id where 1 != 1",
     "Query": "select col from `user` join user_extra on `user`.id = user_extra.user_id",
-    "Table": "`user`"
+    "Table": "`user`, user_extra"
+  }
+}
+{
+  "QueryType": "SELECT",
+  "Original": "select col from user join user_extra on user.id = user_extra.user_id",
+  "Instructions": {
+    "OperatorType": "Route",
+    "Variant": "SelectScatter",
+    "Keyspace": {
+      "Name": "user",
+      "Sharded": true
+    },
+    "FieldQuery": "select col from `user`, user_extra where 1 != 1",
+    "Query": "select col from `user`, user_extra where `user`.id = user_extra.user_id",
+    "Table": "`user`, user_extra"
   }
 }
 
 # Cannot auto-resolve for cross-shard joins
 "select col from user join user_extra"
 "symbol col not found"
+{
+  "QueryType": "SELECT",
+  "Original": "select col from user join user_extra",
+  "Instructions": {
+    "OperatorType": "Join",
+    "Variant": "Join",
+    "JoinColumnIndexes": "-1",
+    "TableName": "`user`_user_extra",
+    "Inputs": [
+      {
+        "OperatorType": "Route",
+        "Variant": "SelectScatter",
+        "Keyspace": {
+          "Name": "user",
+          "Sharded": true
+        },
+        "FieldQuery": "select col from `user` where 1 != 1",
+        "Query": "select col from `user`",
+        "Table": "`user`"
+      },
+      {
+        "OperatorType": "Route",
+        "Variant": "SelectScatter",
+        "Keyspace": {
+          "Name": "user",
+          "Sharded": true
+        },
+        "FieldQuery": "select 1 from user_extra where 1 != 1",
+        "Query": "select 1 from user_extra",
+        "Table": "user_extra"
+      }
+    ]
+  }
+}
 
 # Auto-resolve should work if unique vindex columns are referenced
 "select id, user_id from user join user_extra"
@@ -1182,7 +1262,8 @@ Gen4 plan same as above
       "Sharded": false
     },
     "FieldQuery": "select * from information_schema.a where 1 != 1 union select * from information_schema.b where 1 != 1",
-    "Query": "select * from information_schema.a union select * from information_schema.b"
+    "Query": "select * from information_schema.a union select * from information_schema.b",
+    "Table": "information_schema.a"
   }
 }
 Gen4 plan same as above
@@ -1707,7 +1788,8 @@ Gen4 plan same as above
     "FieldQuery": "select DELETE_RULE, UPDATE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where 1 != 1",
     "Query": "select DELETE_RULE, UPDATE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where KCU.TABLE_SCHEMA = :__vtschemaname and KCU.TABLE_NAME = :__vttablename and KCU.COLUMN_NAME = 'id' and KCU.REFERENCED_TABLE_SCHEMA = 'test' and KCU.CONSTRAINT_NAME = 'data_type_table_id_fkey' order by KCU.CONSTRAINT_NAME asc, KCU.COLUMN_NAME asc",
     "SysTableTableName": "[VARBINARY(\"data_type_table\")]",
-    "SysTableTableSchema": "[VARBINARY(\"test\")]"
+    "SysTableTableSchema": "[VARBINARY(\"test\")]",
+    "Table": "INFORMATION_SCHEMA.KEY_COLUMN_USAGE, INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS"
   }
 }
 
@@ -1720,7 +1802,7 @@ Gen4 plan same as above
     "OperatorType": "Join",
     "Variant": "Join",
     "JoinColumnIndexes": "-1,1",
-    "TableName": "_",
+    "TableName": "INFORMATION_SCHEMA.KEY_COLUMN_USAGE, INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS_INFORMATION_SCHEMA.K",
     "Inputs": [
       {
         "OperatorType": "Route",
@@ -1732,7 +1814,8 @@ Gen4 plan same as above
         "FieldQuery": "select KCU.DELETE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where 1 != 1",
         "Query": "select KCU.DELETE_RULE from INFORMATION_SCHEMA.KEY_COLUMN_USAGE as KCU join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as RC on KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME where KCU.TABLE_SCHEMA = :__vtschemaname and KCU.TABLE_NAME = :__vttablename and KCU.TABLE_NAME = :__vttablename order by KCU.CONSTRAINT_NAME asc, KCU.COLUMN_NAME asc",
         "SysTableTableName": "[VARBINARY(\"data_type_table\"), VARBINARY(\"data_type_table\")]",
-        "SysTableTableSchema": "[VARBINARY(\"test\")]"
+        "SysTableTableSchema": "[VARBINARY(\"test\")]",
+        "Table": "INFORMATION_SCHEMA.KEY_COLUMN_USAGE, INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS"
       },
       {
         "OperatorType": "Route",
@@ -1744,7 +1827,8 @@ Gen4 plan same as above
         "FieldQuery": "select S.UPDATE_RULE from INFORMATION_SCHEMA.K as S where 1 != 1",
         "Query": "select S.UPDATE_RULE from INFORMATION_SCHEMA.K as S where S.TABLE_SCHEMA = :__vtschemaname and S.TABLE_NAME = :__vttablename",
         "SysTableTableName": "[VARBINARY(\"sc\")]",
-        "SysTableTableSchema": "[VARBINARY(\"test\")]"
+        "SysTableTableSchema": "[VARBINARY(\"test\")]",
+        "Table": "INFORMATION_SCHEMA.K"
       }
     ]
   }
@@ -1764,7 +1848,8 @@ Gen4 plan same as above
     },
     "FieldQuery": "select routine_name as `name`, routine_definition as definition from information_schema.routines where 1 != 1",
     "Query": "select routine_name as `name`, routine_definition as definition from information_schema.routines where ROUTINE_SCHEMA = :__vtschemaname and ROUTINE_TYPE = 'PROCEDURE'",
-    "SysTableTableSchema": "[:v1]"
+    "SysTableTableSchema": "[:v1]",
+    "Table": "information_schema.routines"
   }
 }
 
@@ -1782,7 +1867,8 @@ Gen4 plan same as above
     },
     "FieldQuery": "select SUM(data_length + index_length) as size from information_schema.`TABLES` where 1 != 1",
     "Query": "select SUM(data_length + index_length) as size from information_schema.`TABLES` where table_schema = :__vtschemaname",
-    "SysTableTableSchema": "[:v1]"
+    "SysTableTableSchema": "[:v1]",
+    "Table": "information_schema.`TABLES`"
   }
 }
 
@@ -1800,6 +1886,7 @@ Gen4 plan same as above
     },
     "FieldQuery": "select kcu.constraint_name as constraint_name, kcu.column_name as column_name, kcu.referenced_table_name as referenced_table_name, kcu.referenced_column_name as referenced_column_name, kcu.ordinal_position as ordinal_position, kcu.table_name as table_name, rc.delete_rule as delete_rule, rc.update_rule as update_rule from information_schema.key_column_usage as kcu join information_schema.referential_constraints as rc on kcu.constraint_name = rc.constraint_name where 1 != 1",
     "Query": "select kcu.constraint_name as constraint_name, kcu.column_name as column_name, kcu.referenced_table_name as referenced_table_name, kcu.referenced_column_name as referenced_column_name, kcu.ordinal_position as ordinal_position, kcu.table_name as table_name, rc.delete_rule as delete_rule, rc.update_rule as update_rule from information_schema.key_column_usage as kcu join information_schema.referential_constraints as rc on kcu.constraint_name = rc.constraint_name where kcu.table_schema = :__vtschemaname and rc.constraint_schema = :__vtschemaname and kcu.referenced_column_name is not null order by ordinal_position asc",
-    "SysTableTableSchema": "[:v1, :v2]"
+    "SysTableTableSchema": "[:v1, :v2]",
+    "Table": "information_schema.key_column_usage, information_schema.referential_constraints"
   }
 }
diff --git a/go/vt/vtgate/planbuilder/testdata/union_cases.txt b/go/vt/vtgate/planbuilder/testdata/union_cases.txt
index 18c159fd04..82e018ceeb 100644
--- a/go/vt/vtgate/planbuilder/testdata/union_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/union_cases.txt
@@ -297,7 +297,8 @@ Gen4 plan same as above
               "Sharded": false
             },
             "FieldQuery": "select * from information_schema.a where 1 != 1",
-            "Query": "select * from information_schema.a"
+            "Query": "select * from information_schema.a",
+            "Table": "information_schema.a"
           },
           {
             "OperatorType": "Route",
@@ -347,7 +348,8 @@ Gen4 plan same as above
               "Sharded": false
             },
             "FieldQuery": "select * from information_schema.a where 1 != 1",
-            "Query": "select * from information_schema.a"
+            "Query": "select * from information_schema.a",
+            "Table": "information_schema.a"
           }
         ]
       }
diff --git a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt
index 26349d4c25..c2355ad7ea 100644
--- a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt
@@ -104,7 +104,7 @@ Gen4 plan same as above
 # Multi-value aggregates not supported
 "select count(a,b) from user"
 "unsupported: only one expression allowed inside aggregates: count(a, b)"
-"aggregate functions take a single argument 'count(a, b)'"
+Gen4 error: aggregate functions take a single argument 'count(a, b)'
 
 # Cannot have more than one aggr(distinct...
 "select count(distinct a), count(distinct b) from user"
@@ -457,14 +457,15 @@ Gen4 plan same as above
     },
     "FieldQuery": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where 1 != 1",
     "Query": "select cc.constraint_name as `name` from information_schema.check_constraints as cc where cc.constraint_schema = :__vtschemaname and cc.table_schema = :__vtschemaname",
-    "SysTableTableSchema": "[VARBINARY(\"constraint_schema\"), VARBINARY(\"a\")]"
+    "SysTableTableSchema": "[VARBINARY(\"constraint_schema\"), VARBINARY(\"a\")]",
+    "Table": "information_schema.check_constraints"
   }
 }
 
 # create view with Cannot auto-resolve for cross-shard joins
 "create view user.view_a as select col from user join user_extra"
 "symbol col not found"
-"Complex select queries are not supported in create or alter view statements"
+Gen4 error: Complex select queries are not supported in create or alter view statements
 
 # create view with join that cannot be served in each shard separately
 "create view user.view_a as select user_extra.id from user join user_extra"
@@ -491,3 +492,23 @@ Gen4 plan same as above
 # create view with incompatible keyspaces
 "create view main.view_a as select * from user.user_extra"
 "Select query does not belong to the same keyspace as the view statement"
+
+# table_schema OR predicate
+# It is unsupported because we do not route queries to multiple keyspaces right now
+"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'ks' OR TABLE_SCHEMA = 'main'"
+{
+  "QueryType": "SELECT",
+  "Original": "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'ks' OR TABLE_SCHEMA = 'main'",
+  "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 = 'ks' or TABLE_SCHEMA = 'main'",
+    "Table": "INFORMATION_SCHEMA.`TABLES`"
+  }
+}
+Gen4 plan same as above
diff --git a/go/vt/vttablet/tabletserver/query_executor_test.go b/go/vt/vttablet/tabletserver/query_executor_test.go
index bf064b9b25..8683d63b27 100644
--- a/go/vt/vttablet/tabletserver/query_executor_test.go
+++ b/go/vt/vttablet/tabletserver/query_executor_test.go
@@ -389,30 +389,6 @@ func TestQueryExecutorSelectImpossible(t *testing.T) {
 	}
 }
 
-// TestDisableOnlineDDL checks whether disabling online DDLs throws the correct error or not
-func TestDisableOnlineDDL(t *testing.T) {
-	db := setUpQueryExecutorTest(t)
-	defer db.Close()
-	query := "ALTER VITESS_MIGRATION CANCEL ALL"
-
-	db.AddQueryPattern(".*", &sqltypes.Result{})
-
-	ctx := context.Background()
-	tsv := newTestTabletServer(ctx, noFlags, db)
-
-	qre := newTestQueryExecutor(ctx, tsv, query, 0)
-	_, err := qre.Execute()
-	require.NoError(t, err)
-	tsv.StopService()
-
-	tsv = newTestTabletServer(ctx, disableOnlineDDL, db)
-	defer tsv.StopService()
-
-	qre = newTestQueryExecutor(ctx, tsv, query, 0)
-	_, err = qre.Execute()
-	require.EqualError(t, err, "online ddl is disabled")
-}
-
 func TestQueryExecutorLimitFailure(t *testing.T) {
 	type dbResponse struct {
 		query  string
@@ -1141,7 +1117,6 @@ const (
 	noTwopc
 	shortTwopcAge
 	smallResultSize
-	disableOnlineDDL
 )
 
 // newTestQueryExecutor uses a package level variable testTabletServer defined in tabletserver_test.go
@@ -1163,11 +1138,6 @@ func newTestTabletServer(ctx context.Context, flags executorFlags, db *fakesqldb
 	} else {
 		config.TwoPCEnable = true
 	}
-	if flags&disableOnlineDDL > 0 {
-		config.EnableOnlineDDL = false
-	} else {
-		config.EnableOnlineDDL = true
-	}
 	config.TwoPCCoordinatorAddress = "fake"
 	if flags&shortTwopcAge > 0 {
 		config.TwoPCAbandonAge = 0.5
diff --git a/go/vt/vttablet/tabletserver/tabletenv/config_test.go b/go/vt/vttablet/tabletserver/tabletenv/config_test.go
index 0a6d1da293..71e4ad7f07 100644
--- a/go/vt/vttablet/tabletserver/tabletenv/config_test.go
+++ b/go/vt/vttablet/tabletserver/tabletenv/config_test.go
@@ -214,7 +214,6 @@ func TestFlags(t *testing.T) {
 			TransactionLimitByPrincipal: true,
 		},
 		EnforceStrictTransTables: true,
-		EnableOnlineDDL:          true,
 		DB:                       &dbconfigs.DBConfigs{},
 	}
 	assert.Equal(t, want.DB, currentConfig.DB)
diff --git a/test/ci_workflow_gen.go b/test/ci_workflow_gen.go
index 0531d1ada8..dc79e4b043 100644
--- a/test/ci_workflow_gen.go
+++ b/test/ci_workflow_gen.go
@@ -29,7 +29,7 @@ const (
 	workflowConfigDir = "../.github/workflows"
 
 	unitTestTemplate  = "templates/unit_test.tpl"
-	unitTestDatabases = "percona56, mysql57, mysql80, mariadb102, mariadb103"
+	unitTestDatabases = "percona56, mysql57, mysql80, mariadb101, mariadb102, mariadb103"
 
 	clusterTestTemplate = "templates/cluster_endtoend_test.tpl"
 )