Repository: vitessio/vitess
Pull request #7313 (2021-01-17 15:25:54)

Gen4: Handling subquery in query graph
<!-- if this PR is Work in Progress please create it as a Draft Pull Request -->

## Description
<!-- A few sentences describing the overall goals of the pull request's commits. -->

## Related Issue(s)
<!-- List related issues and pull requests: -->

- 

## Checklist
- [ ] Should this PR be backported?
- [ ] Tests were added or are not required
- [ ] Documentation was added or is not required

## Deployment Notes
<!-- Notes regarding deployment of the contained body of work. These should note any db migrations, etc. -->

## Impacted Areas in Vitess
Components that this PR will affect:

- [ ]  Query Serving
- [ ]  VReplication
- [ ]  Cluster Management
- [ ]  Build 
- [ ]  VTAdmin



Patch:
diff --git a/go/vt/vtgate/planbuilder/querygraph.go b/go/vt/vtgate/planbuilder/querygraph.go
index 28641f495b..45b0e68ad3 100644
--- a/go/vt/vtgate/planbuilder/querygraph.go
+++ b/go/vt/vtgate/planbuilder/querygraph.go
@@ -41,6 +41,9 @@ type (
 
 		// noDeps contains the predicates that can be evaluated anywhere.
 		noDeps sqlparser.Expr
+
+		// subqueries contains the subqueries that depend on this query graph
+		subqueries map[*sqlparser.Subquery][]*queryGraph
 	}
 
 	// queryTable is a single FROM table, including all predicates particular to this table
@@ -79,9 +82,38 @@ func createQGFromSelect(sel *sqlparser.Select, semTable *semantics.SemTable) (*q
 	return qg, nil
 }
 
+func createQGFromSelectStatement(selStmt sqlparser.SelectStatement, semTable *semantics.SemTable) ([]*queryGraph, error) {
+	switch stmt := selStmt.(type) {
+	case *sqlparser.Select:
+		qg, err := createQGFromSelect(stmt, semTable)
+		if err != nil {
+			return nil, err
+		}
+		return []*queryGraph{qg}, err
+	case *sqlparser.Union:
+		qg, err := createQGFromSelectStatement(stmt.FirstStatement, semTable)
+		if err != nil {
+			return nil, err
+		}
+		for _, sel := range stmt.UnionSelects {
+			qgr, err := createQGFromSelectStatement(sel.Statement, semTable)
+			if err != nil {
+				return nil, err
+			}
+			qg = append(qg, qgr...)
+		}
+		return qg, nil
+	case *sqlparser.ParenSelect:
+		return createQGFromSelectStatement(stmt.Select, semTable)
+	}
+
+	return nil, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "BUG: not reachable %T", selStmt)
+}
+
 func newQueryGraph() *queryGraph {
 	return &queryGraph{
 		crossTable: map[semantics.TableSet][]sqlparser.Expr{},
+		subqueries: map[*sqlparser.Subquery][]*queryGraph{},
 	}
 }
 
@@ -156,7 +188,20 @@ func (qg *queryGraph) collectPredicate(predicate sqlparser.Expr, semTable *seman
 		}
 		qg.crossTable[deps] = allPredicates
 	}
-	return nil
+	err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
+		switch subQuery := node.(type) {
+		case *sqlparser.Subquery:
+
+			qgr, err := createQGFromSelectStatement(subQuery.Select, semTable)
+			if err != nil {
+				return false, err
+			}
+			qg.subqueries[subQuery] = qgr
+		}
+		return true, nil
+	}, predicate)
+
+	return err
 }
 
 func (qg *queryGraph) addToSingleTable(table semantics.TableSet, predicate sqlparser.Expr) bool {
diff --git a/go/vt/vtgate/planbuilder/route_planning.go b/go/vt/vtgate/planbuilder/route_planning.go
index 92277985a2..e655083d19 100644
--- a/go/vt/vtgate/planbuilder/route_planning.go
+++ b/go/vt/vtgate/planbuilder/route_planning.go
@@ -65,12 +65,40 @@ func newBuildSelectPlan(sel *sqlparser.Select, vschema ContextVSchema) (engine.P
 		return nil, err
 	}
 
+	plan, err = planLimit(sel.Limit, plan)
+	if err != nil {
+		return nil, err
+	}
+
 	if err := plan.WireupV4(semTable); err != nil {
 		return nil, err
 	}
 	return plan.Primitive(), nil
 }
 
+func planLimit(limit *sqlparser.Limit, plan logicalPlan) (logicalPlan, error) {
+	if limit == nil {
+		return plan, nil
+	}
+	rb, ok := plan.(*route)
+	if ok && rb.isSingleShard() {
+		rb.SetLimit(limit)
+		return plan, nil
+	}
+
+	lPlan, err := createLimit(plan, limit)
+	if err != nil {
+		return nil, err
+	}
+
+	// visit does not modify the plan.
+	_, err = visit(lPlan, setUpperLimit)
+	if err != nil {
+		return nil, err
+	}
+	return lPlan, nil
+}
+
 func planProjections(sel *sqlparser.Select, plan logicalPlan, semTable *semantics.SemTable) error {
 	rb, ok := plan.(*route)
 	if ok {
@@ -78,25 +106,22 @@ func planProjections(sel *sqlparser.Select, plan logicalPlan, semTable *semantic
 		ast.Distinct = sel.Distinct
 		ast.GroupBy = sel.GroupBy
 		ast.OrderBy = sel.OrderBy
-		ast.Limit = sel.Limit
 		ast.SelectExprs = sel.SelectExprs
 		ast.Comments = sel.Comments
 	} else {
-		var projections []*sqlparser.AliasedExpr
 
 		// TODO real horizon planning to be done
 		for _, expr := range sel.SelectExprs {
 			switch e := expr.(type) {
 			case *sqlparser.AliasedExpr:
-				projections = append(projections, e)
+				if _, err := pushProjection(e, plan, semTable); err != nil {
+					return err
+				}
 			default:
 				return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "not yet supported %T", e)
 			}
 		}
 
-		if _, err := pushProjection(projections, plan, semTable); err != nil {
-			return err
-		}
 	}
 	return nil
 }
@@ -433,27 +458,18 @@ func transformToLogicalPlan(tree joinTree, semTable *semantics.SemTable) (logica
 func transformJoinPlan(n *joinPlan, semTable *semantics.SemTable) (*joinV4, error) {
 	lhsColList := extractColumnsNeededFromLHS(n, semTable, n.lhs.tables())
 
-	var lhsColExpr []*sqlparser.AliasedExpr
-	for _, col := range lhsColList {
-		lhsColExpr = append(lhsColExpr, &sqlparser.AliasedExpr{
-			Expr: col,
-		})
-	}
-
 	lhs, err := transformToLogicalPlan(n.lhs, semTable)
 	if err != nil {
 		return nil, err
 	}
-	offset, err := pushProjection(lhsColExpr, lhs, semTable)
-	if err != nil {
-		return nil, err
-	}
 
 	vars := map[string]int{}
-
 	for _, col := range lhsColList {
+		offset, err := pushProjection(&sqlparser.AliasedExpr{Expr: col}, lhs, semTable)
+		if err != nil {
+			return nil, err
+		}
 		vars[col.CompliantName("")] = offset
-		offset++
 	}
 
 	rhs, err := transformToLogicalPlan(n.rhs, semTable)
diff --git a/go/vt/vtgate/planbuilder/select.go b/go/vt/vtgate/planbuilder/select.go
index 79900def0c..d348450c71 100644
--- a/go/vt/vtgate/planbuilder/select.go
+++ b/go/vt/vtgate/planbuilder/select.go
@@ -62,55 +62,34 @@ func buildSelectPlan(query string) func(sqlparser.Statement, ContextVSchema) (en
 	}
 }
 
-func pushProjection(expr []*sqlparser.AliasedExpr, plan logicalPlan, semTable *semantics.SemTable) (firstOffset int, err error) {
+func pushProjection(expr *sqlparser.AliasedExpr, plan logicalPlan, semTable *semantics.SemTable) (firstOffset int, err error) {
 	switch node := plan.(type) {
 	case *route:
 		sel := node.Select.(*sqlparser.Select)
 		offset := len(sel.SelectExprs)
-		for _, e := range expr {
-			sel.SelectExprs = append(sel.SelectExprs, e)
-		}
+		sel.SelectExprs = append(sel.SelectExprs, expr)
 		return offset, nil
 	case *joinV4:
-		cols := make([]int, len(expr))
-		var lhs, rhs []*sqlparser.AliasedExpr
 		lhsSolves := node.Left.ContainsTables()
 		rhsSolves := node.Right.ContainsTables()
-		for i, e := range expr {
-			deps := semTable.Dependencies(e.Expr)
-			switch {
-			case deps.IsSolvedBy(lhsSolves):
-				lhs = append(lhs, e)
-				cols[i] = -1
-			case deps.IsSolvedBy(rhsSolves):
-				rhs = append(rhs, e)
-				cols[i] = 1
-			default:
-				return 0, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "unknown dependencies for %s", sqlparser.String(e.Expr))
+		deps := semTable.Dependencies(expr.Expr)
+		switch {
+		case deps.IsSolvedBy(lhsSolves):
+			offset, err := pushProjection(expr, node.Left, semTable)
+			if err != nil {
+				return 0, err
 			}
-		}
-		lOffset, err := pushProjection(lhs, node.Left, semTable)
-		if err != nil {
-			return 0, err
-		}
-		rOffset, err := pushProjection(rhs, node.Right, semTable)
-		if err != nil {
-			return 0, err
-		}
-		rOffset++
-		lOffset = -(lOffset + 1)
-		for i, col := range cols {
-			if col == -1 {
-				cols[i] = lOffset
-				lOffset--
-			} else {
-				cols[i] = rOffset
-				rOffset++
+			node.Cols = append(node.Cols, -(offset + 1))
+		case deps.IsSolvedBy(rhsSolves):
+			offset, err := pushProjection(expr, node.Right, semTable)
+			if err != nil {
+				return 0, err
 			}
+			node.Cols = append(node.Cols, offset+1)
+		default:
+			return 0, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "unknown dependencies for %s", sqlparser.String(expr))
 		}
-		node.Cols = cols
-		return 0, nil
-
+		return len(node.Cols) - 1, nil
 	default:
 		return 0, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "not yet supported %T", node)
 	}
diff --git a/go/vt/vtgate/semantics/analyzer.go b/go/vt/vtgate/semantics/analyzer.go
index 097164380d..ebb23e181b 100644
--- a/go/vt/vtgate/semantics/analyzer.go
+++ b/go/vt/vtgate/semantics/analyzer.go
@@ -53,6 +53,8 @@ func (a *analyzer) analyzeDown(cursor *sqlparser.Cursor) bool {
 			a.err = err
 			return false
 		}
+	case *sqlparser.DerivedTable:
+		a.err = vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "%T not supported", node)
 	case *sqlparser.TableExprs:
 		// this has already been visited when we encountered the SELECT struct
 		return false
@@ -99,6 +101,9 @@ func (a *analyzer) analyzeTableExpr(tableExpr sqlparser.TableExpr) error {
 	case *sqlparser.AliasedTableExpr:
 		return a.bindTable(table, table.Expr)
 	case *sqlparser.JoinTableExpr:
+		if table.Join != sqlparser.NormalJoinType {
+			return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "Join type not supported: %s", table.Join.ToString())
+		}
 		if err := a.analyzeTableExpr(table.LeftExpr); err != nil {
 			return err
 		}
diff --git a/go/vt/vtgate/semantics/semantic_state.go b/go/vt/vtgate/semantics/semantic_state.go
index 555748d4f1..6e770a5c18 100644
--- a/go/vt/vtgate/semantics/semantic_state.go
+++ b/go/vt/vtgate/semantics/semantic_state.go
@@ -109,6 +109,18 @@ func (ts TableSet) NumberOfTables() int {
 	return count
 }
 
+// Constituents returns an slice with all the
+// individual tables in their own TableSet identifier
+func (ts TableSet) Constituents() (result []TableSet) {
+	for i := 0; i < 64; i++ {
+		i2 := TableSet(1 << i)
+		if ts&i2 == i2 {
+			result = append(result, i2)
+		}
+	}
+	return
+}
+
 // Merge creates a TableSet that contains both inputs
 func (ts TableSet) Merge(other TableSet) TableSet {
 	return ts | other


Test patch:
diff --git a/go/vt/vtgate/planbuilder/plan_test.go b/go/vt/vtgate/planbuilder/plan_test.go
index c38717e8ab..b280a215b1 100644
--- a/go/vt/vtgate/planbuilder/plan_test.go
+++ b/go/vt/vtgate/planbuilder/plan_test.go
@@ -149,6 +149,8 @@ func init() {
 	vindexes.Register("costly", newCostlyIndex)
 }
 
+const samePlanMarker = "Gen4 plan same as above\n"
+
 func TestPlan(t *testing.T) {
 	vschemaWrapper := &vschemaWrapper{
 		v:             loadSchema(t, "schema_test.json"),
@@ -418,9 +420,6 @@ func testFile(t *testing.T, filename, tempDir string, vschema *vschemaWrapper, c
 			if tcase.output2ndPlanner == "" {
 				empty = true
 			}
-			if tcase.output2ndPlanner == "{\n}\n" {
-				tcase.output2ndPlanner = tcase.output
-			}
 
 			vschema.version = V4
 			out, err := getPlanOutput(tcase, vschema)
@@ -444,7 +443,7 @@ func testFile(t *testing.T, filename, tempDir string, vschema *vschemaWrapper, c
 					}
 
 					if tcase.output == out {
-						expected.WriteString("{\n}\n")
+						expected.WriteString(samePlanMarker)
 					} else {
 						expected.WriteString(out)
 					}
@@ -555,7 +554,9 @@ func iterateExecFile(name string) (testCaseIterator chan testCase) {
 			if err != nil && err != io.EOF {
 				panic(fmt.Sprintf("error reading file %s line# %d: %s", name, lineno, err.Error()))
 			}
-			if len(binput) > 0 && (binput[0] == '"' || binput[0] == '{') {
+			if len(binput) > 0 && string(binput) == samePlanMarker {
+				output2Planner = output
+			} else if len(binput) > 0 && (binput[0] == '"' || binput[0] == '{') {
 				output2Planner = append(output2Planner, binput...)
 				for {
 					l, err := r.ReadBytes('\n')
@@ -573,9 +574,6 @@ func iterateExecFile(name string) (testCaseIterator chan testCase) {
 						break
 					}
 				}
-				if string(output2Planner) == "{\n}" {
-					output2Planner = output
-				}
 			}
 
 			testCaseIterator <- testCase{
diff --git a/go/vt/vtgate/planbuilder/querygraph_test.go b/go/vt/vtgate/planbuilder/querygraph_test.go
index df16ab022e..71c8c06989 100644
--- a/go/vt/vtgate/planbuilder/querygraph_test.go
+++ b/go/vt/vtgate/planbuilder/querygraph_test.go
@@ -18,130 +18,84 @@ package planbuilder
 
 import (
 	"fmt"
+	"sort"
+	"strings"
 	"testing"
 
+	"github.com/stretchr/testify/assert"
+
 	"vitess.io/vitess/go/test/utils"
 
 	"github.com/stretchr/testify/require"
 
 	"vitess.io/vitess/go/vt/sqlparser"
 	"vitess.io/vitess/go/vt/vtgate/semantics"
-	"vitess.io/vitess/go/vt/vtgate/vindexes"
 )
 
 type tcase struct {
-	input  string
-	output *queryGraph
+	input, output string
 }
 
-var threeWayJoin = &queryGraph{
-	tables: []*queryTable{{
-		tableID:    1,
-		alias:      tableAlias("t"),
-		table:      tableName("t"),
-		predicates: []sqlparser.Expr{equals(colName("t", "name"), literalString("foo"))},
-	}, {
-		tableID:    2,
-		alias:      tableAlias("y"),
-		table:      tableName("y"),
-		predicates: []sqlparser.Expr{equals(colName("y", "col"), literalInt(42))},
-	}, {
-		tableID:    4,
-		alias:      tableAlias("z"),
-		table:      tableName("z"),
-		predicates: []sqlparser.Expr{equals(colName("z", "baz"), literalInt(101))},
-	}},
-	crossTable: map[semantics.TableSet][]sqlparser.Expr{
-		1 | 2: {
-			equals(
-				colName("t", "id"),
-				colName("y", "t_id"))},
-		1 | 4: {
-			equals(
-				colName("t", "id"),
-				colName("z", "t_id"))}}}
-
 var tcases = []tcase{{
 	input: "select * from t",
-	output: &queryGraph{
-		tables: []*queryTable{{
-			tableID: 1,
-			alias:   tableAlias("t"),
-			table:   tableName("t"),
-		}},
-		crossTable: map[semantics.TableSet][]sqlparser.Expr{},
-	},
+	output: `{
+Tables:
+	1:t
+}`,
 }, {
 	input: "select t.c from t,y,z where t.c = y.c and (t.a = z.a or t.a = y.a) and 1 < 2",
-	output: &queryGraph{
-		tables: []*queryTable{{
-			tableID: 1,
-			alias:   tableAlias("t"),
-			table:   tableName("t"),
-		}, {
-			tableID: 2,
-			alias:   tableAlias("y"),
-			table:   tableName("y"),
-		}, {
-			tableID: 4,
-			alias:   tableAlias("z"),
-			table:   tableName("z"),
-		}},
-		crossTable: map[semantics.TableSet][]sqlparser.Expr{
-			1 | 2: {
-				equals(
-					colName("t", "c"),
-					colName("y", "c"))},
-			1 | 2 | 4: {
-				or(
-					equals(
-						colName("t", "a"),
-						colName("z", "a")),
-					equals(
-						colName("t", "a"),
-						colName("y", "a")))},
-		},
-		noDeps: &sqlparser.ComparisonExpr{
-			Operator: sqlparser.LessThanOp,
-			Left:     literalInt(1),
-			Right:    literalInt(2)},
-	},
+	output: `{
+Tables:
+	1:t
+	2:y
+	4:z
+JoinPredicates:
+	1:2 - t.c = y.c
+	1:2:4 - t.a = z.a or t.a = y.a
+ForAll: 1 < 2
+}`,
 }, {
-	input:  "select t.c from t join y on t.id = y.t_id join z on t.id = z.t_id where t.name = 'foo' and y.col = 42 and z.baz = 101",
-	output: threeWayJoin,
+	input: "select t.c from t join y on t.id = y.t_id join z on t.id = z.t_id where t.name = 'foo' and y.col = 42 and z.baz = 101",
+	output: `{
+Tables:
+	1:t where t.` + "`name`" + ` = 'foo'
+	2:y where y.col = 42
+	4:z where z.baz = 101
+JoinPredicates:
+	1:2 - t.id = y.t_id
+	1:4 - t.id = z.t_id
+}`,
 }, {
-	input:  "select t.c from t,y,z where t.name = 'foo' and y.col = 42 and z.baz = 101 and t.id = y.t_id and t.id = z.t_id",
-	output: threeWayJoin,
+	input: "select t.c from t,y,z where t.name = 'foo' and y.col = 42 and z.baz = 101 and t.id = y.t_id and t.id = z.t_id",
+	output: `{
+Tables:
+	1:t where t.` + "`name`" + ` = 'foo'
+	2:y where y.col = 42
+	4:z where z.baz = 101
+JoinPredicates:
+	1:2 - t.id = y.t_id
+	1:4 - t.id = z.t_id
+}`,
 }, {
 	input: "select 1 from t where '1' = 1 and 12 = '12'",
-	output: &queryGraph{
-		tables: []*queryTable{{
-			tableID: 1,
-			alias:   tableAlias("t"),
-			table:   tableName("t"),
-		}},
-		crossTable: map[semantics.TableSet][]sqlparser.Expr{},
-		noDeps: &sqlparser.AndExpr{
-			Left:  equals(literalString("1"), literalInt(1)),
-			Right: equals(literalInt(12), literalString("12")),
-		},
-	},
-}}
-
-func literalInt(i int) *sqlparser.Literal {
-	return &sqlparser.Literal{Type: sqlparser.IntVal, Val: []byte(fmt.Sprintf("%d", i))}
-}
-
-func literalString(s string) *sqlparser.Literal {
-	return &sqlparser.Literal{Type: sqlparser.StrVal, Val: []byte(s)}
-}
-
-func or(left, right sqlparser.Expr) sqlparser.Expr {
-	return &sqlparser.OrExpr{
-		Left:  left,
-		Right: right,
+	output: `{
+Tables:
+	1:t
+ForAll: '1' = 1 and 12 = '12'
+}`,
+}, {
+	input: "select 1 from t where exists (select 1)",
+	output: `{
+Tables:
+	1:t
+ForAll: exists (select 1 from dual)
+SubQueries:
+(select 1 from dual) - 	{
+	Tables:
+		2:dual
 	}
-}
+}`,
+}}
 
 func equals(left, right sqlparser.Expr) sqlparser.Expr {
 	return &sqlparser.ComparisonExpr{
@@ -155,40 +109,127 @@ func colName(table, column string) *sqlparser.ColName {
 	return &sqlparser.ColName{Name: sqlparser.NewColIdent(column), Qualifier: tableName(table)}
 }
 
-func tableAlias(name string) *sqlparser.AliasedTableExpr {
-	return &sqlparser.AliasedTableExpr{Expr: sqlparser.TableName{Name: sqlparser.NewTableIdent(name)}}
-}
-
 func tableName(name string) sqlparser.TableName {
 	return sqlparser.TableName{Name: sqlparser.NewTableIdent(name)}
 }
 
-type schemaInf struct{}
-
-func (node *schemaInf) FindTable(tablename sqlparser.TableName) (*vindexes.Table, error) {
-	return nil, nil
-}
-
 func TestQueryGraph(t *testing.T) {
-	for _, tc := range tcases {
+	for i, tc := range tcases {
 		sql := tc.input
-		t.Run(sql, func(t *testing.T) {
+		t.Run(fmt.Sprintf("%d %s", i, sql), func(t *testing.T) {
 			tree, err := sqlparser.Parse(sql)
 			require.NoError(t, err)
 			semTable, err := semantics.Analyse(tree)
 			require.NoError(t, err)
 			qgraph, err := createQGFromSelect(tree.(*sqlparser.Select), semTable)
 			require.NoError(t, err)
-			mustMatch(t, tc.output, qgraph, "incorrect query graph")
+			fmt.Println(qgraph.testString())
+			assert.Equal(t, tc.output, qgraph.testString())
+			utils.MustMatch(t, tc.output, qgraph.testString(), "incorrect query graph")
 		})
 	}
 }
 
-var mustMatch = utils.MustMatchFn(
-	[]interface{}{ // types with unexported fields
-		queryGraph{},
-		queryTable{},
-		sqlparser.TableIdent{},
-	},
-	[]string{}, // ignored fields
-)
+func TestString(t *testing.T) {
+	tree, err := sqlparser.Parse("select * from a,b join c on b.id = c.id where a.id = b.id and b.col IN (select 42) and func() = 'foo'")
+	require.NoError(t, err)
+	semTable, err := semantics.Analyse(tree)
+	require.NoError(t, err)
+	qgraph, err := createQGFromSelect(tree.(*sqlparser.Select), semTable)
+	require.NoError(t, err)
+	utils.MustMatch(t, `{
+Tables:
+	1:a
+	2:b where b.col in (select 42 from dual)
+	4:c
+JoinPredicates:
+	1:2 - a.id = b.id
+	2:4 - b.id = c.id
+ForAll: func() = 'foo'
+SubQueries:
+(select 42 from dual) - 	{
+	Tables:
+		8:dual
+	}
+}`, qgraph.testString())
+}
+
+func (qt *queryTable) testString() string {
+	var alias string
+	if !qt.alias.As.IsEmpty() {
+		alias = " AS " + sqlparser.String(qt.alias.As)
+	}
+	var preds []string
+	for _, predicate := range qt.predicates {
+		preds = append(preds, sqlparser.String(predicate))
+	}
+	var where string
+	if len(preds) > 0 {
+		where = " where " + strings.Join(preds, " and ")
+	}
+
+	return fmt.Sprintf("\t%d:%s%s%s", qt.tableID, sqlparser.String(qt.table), alias, where)
+}
+
+func (qg *queryGraph) testString() string {
+	return fmt.Sprintf(`{
+Tables:
+%s%s%s%s
+}`, strings.Join(qg.tableNames(), "\n"), qg.crossPredicateString(), qg.noDepsString(), qg.subqueriesString())
+}
+
+func (qg *queryGraph) crossPredicateString() string {
+	if len(qg.crossTable) == 0 {
+		return ""
+	}
+	var joinPreds []string
+	for deps, predicates := range qg.crossTable {
+		var tables []string
+		for _, id := range deps.Constituents() {
+			tables = append(tables, fmt.Sprintf("%d", id))
+		}
+		var expressions []string
+		for _, expr := range predicates {
+			expressions = append(expressions, sqlparser.String(expr))
+		}
+		tableConcat := strings.Join(tables, ":")
+		exprConcat := strings.Join(expressions, " and ")
+		joinPreds = append(joinPreds, fmt.Sprintf("\t%s - %s", tableConcat, exprConcat))
+	}
+	sort.Strings(joinPreds)
+	return fmt.Sprintf("\nJoinPredicates:\n%s", strings.Join(joinPreds, "\n"))
+}
+
+func (qg *queryGraph) tableNames() []string {
+	var tables []string
+	for _, t := range qg.tables {
+		tables = append(tables, t.testString())
+	}
+	return tables
+}
+
+func (qg *queryGraph) subqueriesString() string {
+	if len(qg.subqueries) == 0 {
+		return ""
+	}
+	var graphs []string
+	for sq, qgraphs := range qg.subqueries {
+		key := sqlparser.String(sq)
+		for _, inner := range qgraphs {
+			str := inner.testString()
+			splitInner := strings.Split(str, "\n")
+			for i, s := range splitInner {
+				splitInner[i] = "\t" + s
+			}
+			graphs = append(graphs, fmt.Sprintf("%s - %s", key, strings.Join(splitInner, "\n")))
+		}
+	}
+	return fmt.Sprintf("\nSubQueries:\n%s", strings.Join(graphs, "\n"))
+}
+
+func (qg *queryGraph) noDepsString() string {
+	if qg.noDeps == nil {
+		return ""
+	}
+	return fmt.Sprintf("\nForAll: %s", sqlparser.String(qg.noDeps))
+}
diff --git a/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt b/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt
index 0691dbaa8d..71980f7325 100644
--- a/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt
@@ -17,8 +17,7 @@
     "Table": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Aggregate on unique sharded
 "select count(*), col from user where id = 1"
@@ -41,8 +40,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Aggregate detection (non-aggregate function)
 "select fun(1), col from user"
@@ -61,8 +59,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # select distinct with unique vindex for scatter route.
 "select distinct col1, id from user"
@@ -81,8 +78,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # distinct and group by together for single route.
 "select distinct col1, id from user group by col1"
@@ -101,8 +97,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # scatter group by a text column
 "select count(*), a, textcol1, b from user group by a, textcol1, b"
@@ -352,8 +347,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # group by a unique vindex and other column should use a simple route
 "select id, col, count(*) from user group by id, col"
@@ -372,8 +366,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # group by a non-vindex column should use an OrderdAggregate primitive
 "select col, count(*) from user group by col"
@@ -452,8 +445,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # group by a unique vindex where alias from select list is used
 "select id as val, 1+count(*) from user group by val"
@@ -472,8 +464,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # group by a unique vindex where expression is qualified (alias should be ignored)
 "select val as id, 1+count(*) from user group by user.id"
@@ -492,8 +483,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # group by a unique vindex where it should skip non-aliased expressions.
 "select *, id, 1+count(*) from user group by id"
@@ -512,8 +502,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # group by a unique vindex should revert to simple route, and having clause should find the correct symbols.
 "select id, count(*) c from user group by id having id=1 and c=10"
@@ -668,8 +657,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # count with distinct unique vindex
 "select col, count(distinct id) from user group by col"
@@ -1221,8 +1209,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # routing rules for aggregates
 "select id, count(*) from route2 group by id"
@@ -1259,8 +1246,7 @@
     "Table": "ref"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # distinct and aggregate functions missing group by
 "select distinct a, count(*) from user"
diff --git a/go/vt/vtgate/planbuilder/testdata/bypass_cases.txt b/go/vt/vtgate/planbuilder/testdata/bypass_cases.txt
index fb49577466..c324053b9e 100644
--- a/go/vt/vtgate/planbuilder/testdata/bypass_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/bypass_cases.txt
@@ -15,8 +15,7 @@
     "SingleShardOnly": false
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update bypass
 "update user set val = 1 where id = 18446744073709551616 and id = 1"
@@ -35,8 +34,7 @@
     "SingleShardOnly": false
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete bypass
 "DELETE FROM USER WHERE ID = 42"
@@ -55,8 +53,7 @@
     "SingleShardOnly": false
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert bypass
 "INSERT INTO USER (ID, NAME) VALUES (42, 'ms X')"
@@ -75,8 +72,7 @@
     "SingleShardOnly": false
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert bypass with sequence: sequences ignored
 "insert into user(nonid) values (2)"
@@ -95,8 +91,7 @@
     "SingleShardOnly": false
   }
 }
-{
-}
+Gen4 plan same as above
 
 # bypass query for into outfile s3
 "select count(*), col from unsharded into outfile S3 'x.txt'"
@@ -115,8 +110,7 @@
     "SingleShardOnly": false
   }
 }
-{
-}
+Gen4 plan same as above
 
 "select * from user into outfile S3 'x.txt'"
 {
@@ -134,8 +128,7 @@
     "SingleShardOnly": false
   }
 }
-{
-}
+Gen4 plan same as above
 
 "load data from s3 'x.txt' into table x"
 {
@@ -153,8 +146,7 @@
     "SingleShardOnly": true
   }
 }
-{
-}
+Gen4 plan same as above
 
 "load data from s3 'x.txt'"
 {
@@ -172,5 +164,4 @@
     "SingleShardOnly": true
   }
 }
-{
-}
+Gen4 plan same as above
diff --git a/go/vt/vtgate/planbuilder/testdata/dml_cases.txt b/go/vt/vtgate/planbuilder/testdata/dml_cases.txt
index be4db7a0b4..e8bd270674 100644
--- a/go/vt/vtgate/planbuilder/testdata/dml_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/dml_cases.txt
@@ -1,14 +1,12 @@
 # update table not found
 "update nouser set val = 1"
 "table nouser not found"
-{
-}
+Gen4 plan same as above
 
 # delete table not found
 "delete from nouser"
 "table nouser not found"
-{
-}
+Gen4 plan same as above
 
 # explicit keyspace reference
 "update main.m1 set val = 1"
@@ -27,8 +25,7 @@
     "Query": "update m1 set val = 1"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update unsharded
 "update unsharded set val = 1"
@@ -47,8 +44,7 @@
     "Query": "update unsharded set val = 1"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # subqueries in unsharded update
 "update unsharded set col = (select col from unsharded limit 1)"
@@ -67,8 +63,7 @@
     "Query": "update unsharded set col = (select col from unsharded limit 1)"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # unsharded union in subquery of unsharded update
 "update unsharded set col = (select id from unsharded union select id from unsharded)"
@@ -87,8 +82,7 @@
     "Query": "update unsharded set col = (select id from unsharded union select id from unsharded)"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # unsharded join in subquery of unsharded update
 "update unsharded set col = (select id from unsharded a join unsharded b on a.id = b.id)"
@@ -107,8 +101,7 @@
     "Query": "update unsharded set col = (select id from unsharded as a join unsharded as b on a.id = b.id)"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with join subquery
 "update unsharded as foo left join (select id from unsharded where col is not null order by col desc limit 10) as keepers on foo.id = keepers.id set col1 = 'asdf' where keepers.id is null and foo.col is not null and foo.col < 1000"
@@ -127,8 +120,7 @@
     "Query": "update unsharded as foo left join (select id from unsharded where col is not null order by col desc limit 10) as keepers on foo.id = keepers.id set col1 = 'asdf' where keepers.id is null and foo.col is not null and foo.col \u003c 1000"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # routing rules: updated of a routed table
 "update route1 set a=1 where id=1"
@@ -152,8 +144,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update: routing rules for subquery.
 "update unsharded_a set a=(select a from route2)"
@@ -172,8 +163,7 @@
     "Query": "update unsharded_a set a = (select a from unsharded as route2)"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete unsharded
 "delete from unsharded"
@@ -192,8 +182,7 @@
     "Query": "delete from unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update by primary keyspace id
 "update user set val = 1 where id = 1"
@@ -217,8 +206,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update by primary keyspace id with alias
 "update user as user_alias set val = 1 where user_alias.id = 1"
@@ -242,8 +230,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update by primary keyspace id with parenthesized expression
 "update user set val = 1 where (id = 1)"
@@ -267,8 +254,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update by primary keyspace id with multi-part where clause with parens
 "update user set val = 1 where (name = 'foo' and id = 1)"
@@ -292,8 +278,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update by primary keyspace id, changing one vindex column
 "update user_metadata set email = 'juan@vitess.io' where user_id = 1"
@@ -322,14 +307,12 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update by primary keyspace id, changing same vindex twice
 "update user_metadata set email = 'a', email = 'b' where user_id = 1"
 "column has duplicate set values: 'email'"
-{
-}
+Gen4 plan same as above
 
 # update by primary keyspace id, changing multiple vindex columns
 "update user_metadata set email = 'juan@vitess.io', address = '155 5th street' where user_id = 1"
@@ -359,8 +342,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update by primary keyspace id, changing one vindex column, using order by and limit
 "update user_metadata set email = 'juan@vitess.io' where user_id = 1 order by user_id asc limit 10"
@@ -389,8 +371,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update by primary keyspace id, stray where clause
 "update user set val = 1 where id = id2 and id = 1"
@@ -414,8 +395,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update by primary keyspace id, stray where clause with conversion error
 "update user set val = 1 where id = 18446744073709551616 and id = 1"
@@ -439,8 +419,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete from by primary keyspace id
 "delete from user where id = 1"
@@ -466,8 +445,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # multi-table delete with comma join
 "delete a from unsharded_a a, unsharded_b b where a.id = b.id and b.val = 1"
@@ -486,8 +464,7 @@
     "Query": "delete a from unsharded_a as a, unsharded_b as b where a.id = b.id and b.val = 1"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # multi-table delete with ansi join
 "delete a from unsharded_a a join unsharded_b b on a.id = b.id where b.val = 1"
@@ -506,8 +483,7 @@
     "Query": "delete a from unsharded_a as a join unsharded_b as b on a.id = b.id where b.val = 1"
   }
 }
-{
-}
+Gen4 plan same as above
 
 #delete with join from subquery
 "delete foo from unsharded as foo left join (select id from unsharded where col is not null order by col desc limit 10) as keepers on foo.id = keepers.id where keepers.id is null and foo.col is not null and foo.col < 1000"
@@ -526,8 +502,7 @@
     "Query": "delete foo from unsharded as foo left join (select id from unsharded where col is not null order by col desc limit 10) as keepers on foo.id = keepers.id where keepers.id is null and foo.col is not null and foo.col \u003c 1000"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # routing rules: deleted from a routed table
 "delete from route1 where id = 1"
@@ -553,8 +528,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete: routing rules for subquery
 "delete from  unsharded_a where a=(select a from route2)"
@@ -573,8 +547,7 @@
     "Query": "delete from unsharded_a where a = (select a from unsharded as route2)"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update by lookup
 "update music set val = 1 where id = 1"
@@ -598,8 +571,7 @@
     "Vindex": "music_user_map"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update multi-table ansi join
 "update unsharded_a a join unsharded_b b on a.id = b.id set a.val = 'foo' where b.val = 1"
@@ -618,8 +590,7 @@
     "Query": "update unsharded_a as a join unsharded_b as b on a.id = b.id set a.val = 'foo' where b.val = 1"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update multi-table comma join
 "update unsharded_a a, unsharded_b b set a.val = 'foo' where a.id = b.id and b.val = 1"
@@ -638,8 +609,7 @@
     "Query": "update unsharded_a as a, unsharded_b as b set a.val = 'foo' where a.id = b.id and b.val = 1"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete from by lookup
 "delete from music where id = 1"
@@ -665,8 +635,7 @@
     "Vindex": "music_user_map"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete from, no owned vindexes
 "delete from music_extra where user_id = 1"
@@ -690,8 +659,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # simple insert, no values
 "insert into unsharded values()"
@@ -711,8 +679,7 @@
     "TableName": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # simple insert unsharded
 "insert into unsharded values(1, 2)"
@@ -732,8 +699,7 @@
     "TableName": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # simple upsert unsharded
 "insert into unsharded values(1, 2) on duplicate key update x = 3"
@@ -753,8 +719,7 @@
     "TableName": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # unsharded insert, no col list with auto-inc and authoritative column list
 "insert into unsharded_authoritative values(1,1)"
@@ -774,8 +739,7 @@
     "TableName": "unsharded_authoritative"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # sharded upsert with sharding key set to vindex column
 "insert into music(user_id, id) values(1, 2) on duplicate key update user_id = values(user_id)"
@@ -795,8 +759,7 @@
     "TableName": "music"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # sharded bulk upsert with sharding key set to vindex column
 "insert into music(user_id, id) values (1, 2), (3,4) on duplicate key update user_id = values(user_id)"
@@ -816,8 +779,7 @@
     "TableName": "music"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert unsharded with select
 "insert into unsharded select id from unsharded_auto"
@@ -837,8 +799,7 @@
     "TableName": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert unsharded with select with join
 "insert into unsharded select id from unsharded join unsharded_auto"
@@ -858,14 +819,12 @@
     "TableName": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert unsharded, invalid value for auto-inc
 "insert into unsharded_auto(id, val) values(18446744073709551616, 'aa')"
 "could not compute value for vindex or auto-inc column: strconv.ParseUint: parsing "18446744073709551616": value out of range"
-{
-}
+Gen4 plan same as above
 
 # insert unsharded, column present
 "insert into unsharded_auto(id, val) values(1, 'aa')"
@@ -885,8 +844,7 @@
     "TableName": "unsharded_auto"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert unsharded, column absent
 "insert into unsharded_auto(val) values('aa')"
@@ -906,8 +864,7 @@
     "TableName": "unsharded_auto"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert unsharded, column absent
 "insert into unsharded_auto(val) values(false)"
@@ -927,8 +884,7 @@
     "TableName": "unsharded_auto"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert unsharded, multi-val
 "insert into unsharded_auto(id, val) values(1, 'aa'), (null, 'bb')"
@@ -948,8 +904,7 @@
     "TableName": "unsharded_auto"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # unsharded insert subquery in insert value
 "insert into unsharded values((select 1 from dual), 1)"
@@ -969,8 +924,7 @@
     "TableName": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # sharded insert subquery in insert value
 "insert into user(id, val) values((select 1), 1)"
@@ -990,8 +944,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert into a routed table
 "insert into route1(id) values (1)"
@@ -1011,14 +964,12 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert with mimatched column list
 "insert into user(id) values (1, 2)"
 "column list doesn't match values"
-{
-}
+Gen4 plan same as above
 
 # insert no column list for sharded authoritative table
 "insert into authoritative values(1, 2, 3)"
@@ -1038,8 +989,7 @@
     "TableName": "authoritative"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert sharded, no values
 "insert into user values()"
@@ -1059,8 +1009,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert with one vindex
 "insert into user(id) values (1)"
@@ -1080,8 +1029,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert ignore sharded
 "insert ignore into user(id) values (1)"
@@ -1101,8 +1049,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert on duplicate key
 "insert into user(id) values(1) on duplicate key update col = 2"
@@ -1122,8 +1069,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert with one vindex and bind var
 "insert into user(id) values (:aa)"
@@ -1143,8 +1089,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert with non vindex
 "insert into user(nonid) values (2)"
@@ -1164,8 +1109,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert with default seq
 "insert into user(id, nonid) values (default, 2)"
@@ -1185,8 +1129,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert with non vindex bool value
 "insert into user(nonid) values (true)"
@@ -1206,8 +1149,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert with all vindexes supplied
 "insert into user(nonid, name, id) values (2, 'foo', 1)"
@@ -1227,8 +1169,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert for non-vindex autoinc
 "insert into user_extra(nonid) values (2)"
@@ -1248,8 +1189,7 @@
     "TableName": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert for non-compliant names
 "insert into `weird``name`(`a``b*c`, `b*c`) values(1, 2)"
@@ -1269,8 +1209,7 @@
     "TableName": "weird`name"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # unsharded insert from union
 "insert into unsharded select 1 from dual union select 1 from dual"
@@ -1290,32 +1229,27 @@
     "TableName": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert for non-vindex autoinc, invalid value
 "insert into user_extra(nonid, extra_id) values (2, 18446744073709551616)"
 "could not compute value for vindex or auto-inc column: strconv.ParseUint: parsing "18446744073709551616": value out of range"
-{
-}
+Gen4 plan same as above
 
 # insert invalid index value
 "insert into music_extra(music_id, user_id) values(1, 18446744073709551616)"
 "could not compute value for vindex or auto-inc column: strconv.ParseUint: parsing "18446744073709551616": value out of range"
-{
-}
+Gen4 plan same as above
 
 # insert invalid index value
 "insert into music_extra(music_id, user_id) values(1, id)"
 "could not compute value for vindex or auto-inc column: expression is too complex 'id'"
-{
-}
+Gen4 plan same as above
 
 # insert invalid table
 "insert into noexist(music_id, user_id) values(1, 18446744073709551616)"
 "table noexist not found"
-{
-}
+Gen4 plan same as above
 
 # insert with multiple rows
 "insert into user(id) values (1), (2)"
@@ -1335,8 +1269,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert with query timeout
 "insert /*vt+ QUERY_TIMEOUT_MS=1 */ into user(id) values (1), (2)"
@@ -1357,8 +1290,7 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert with multiple rows - multi-shard autocommit
 "insert /*vt+ MULTI_SHARD_AUTOCOMMIT=1 */ into user(id) values (1), (2)"
@@ -1378,14 +1310,12 @@
     "TableName": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert into a vindex not allowed
 "insert into user_index(id) values(1)"
 "unsupported: multi-shard or vindex write statement"
-{
-}
+Gen4 plan same as above
 
 # simple replace unsharded
 "replace into unsharded values(1, 2)"
@@ -1405,8 +1335,7 @@
     "TableName": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # replace unsharded with select
 "replace into unsharded select id from unsharded_auto"
@@ -1426,14 +1355,12 @@
     "TableName": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # replace unsharded, invalid value for auto-inc
 "replace into unsharded_auto(id, val) values(18446744073709551616, 'aa')"
 "could not compute value for vindex or auto-inc column: strconv.ParseUint: parsing "18446744073709551616": value out of range"
-{
-}
+Gen4 plan same as above
 
 # replace unsharded, column present
 "replace into unsharded_auto(id, val) values(1, 'aa')"
@@ -1453,8 +1380,7 @@
     "TableName": "unsharded_auto"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # replace unsharded, column absent
 "replace into unsharded_auto(val) values('aa')"
@@ -1474,8 +1400,7 @@
     "TableName": "unsharded_auto"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # replace unsharded, multi-val
 "replace into unsharded_auto(id, val) values(1, 'aa'), (null, 'bb')"
@@ -1495,14 +1420,12 @@
     "TableName": "unsharded_auto"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # replace invalid table
 "replace into noexist(music_id, user_id) values(1, 18446744073709551616)"
 "table noexist not found"
-{
-}
+Gen4 plan same as above
 
 # insert a row in a multi column vindex table
 "insert multicolvin (column_a, column_b, column_c, kid) VALUES (1,2,3,4)"
@@ -1522,8 +1445,7 @@
     "TableName": "multicolvin"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert for overlapped vindex columns
 "insert overlap_vindex (kid, column_a, column_b) VALUES (1,2,3)"
@@ -1543,8 +1465,7 @@
     "TableName": "overlap_vindex"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert multiple rows in a multi column vindex table
 "insert multicolvin (column_a, column_b, column_c, kid) VALUES (1,2,3,4), (5,6,7,8)"
@@ -1564,8 +1485,7 @@
     "TableName": "multicolvin"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete row in a multi column vindex table
 "delete from multicolvin where kid=1"
@@ -1591,8 +1511,7 @@
     "Vindex": "kid_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update columns of multi column vindex
 "update multicolvin set column_b = 1, column_c = 2 where kid = 1"
@@ -1621,8 +1540,7 @@
     "Vindex": "kid_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update multiple vindexes, with multi column vindex
 "update multicolvin set column_a = 0, column_b = 1, column_c = 2 where kid = 1"
@@ -1652,8 +1570,7 @@
     "Vindex": "kid_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with no primary vindex on where clause (scatter update)
 "update user_extra set val = 1"
@@ -1673,8 +1590,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with target destination
 "update `user[-]`.user_extra set val = 1"
@@ -1694,8 +1610,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with no primary vindex on where clause (scatter update)   - multi shard autocommit
 "update /*vt+ MULTI_SHARD_AUTOCOMMIT=1 */  user_extra set val = 1"
@@ -1715,8 +1630,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with no primary vindex on where clause (scatter update)   - query timeout
 "update /*vt+ QUERY_TIMEOUT_MS=1 */  user_extra set val = 1"
@@ -1737,8 +1651,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with non-comparison expr
 "update user_extra set val = 1 where id between 1 and 2"
@@ -1758,8 +1671,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with primary id through IN clause
 "update user_extra set val = 1 where user_id in (1, 2)"
@@ -1786,8 +1698,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with non-unique key
 "update user_extra set val = 1 where name = 'foo'"
@@ -1807,8 +1718,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update by lookup with IN clause
 "update user_extra set val = 1 where id in (1, 2)"
@@ -1828,8 +1738,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with where clause with parens
 "update user_extra set val = 1 where (name = 'foo' or id = 1)"
@@ -1849,8 +1758,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete from with no where clause
 "delete from user_extra"
@@ -1870,8 +1778,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete with target destination
 "delete from `user[-]`.user_extra"
@@ -1891,8 +1798,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete with non-comparison expr
 "delete from user_extra where user_id between 1 and 2"
@@ -1912,8 +1818,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete from with no index match
 "delete from user_extra where name = 'jose'"
@@ -1933,8 +1838,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete from with no index match - multi shard autocommit
 "delete /*vt+ MULTI_SHARD_AUTOCOMMIT=1 */ from user_extra where name = 'jose'"
@@ -1954,8 +1858,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete from with no index match - query timeout
 "delete /*vt+ QUERY_TIMEOUT_MS=1 */ from user_extra where name = 'jose'"
@@ -1976,8 +1879,7 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete from with primary id in through IN clause
 "delete from user_extra where user_id in (1, 2)"
@@ -2004,8 +1906,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # unsharded update where inner query references outer query
 "update unsharded set col = (select id from unsharded_a where id = unsharded.col) where col = (select id from unsharded_b)"
@@ -2024,8 +1925,7 @@
     "Query": "update unsharded set col = (select id from unsharded_a where id = unsharded.col) where col = (select id from unsharded_b)"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # unsharded delete where inner query references outer query
 "delete from unsharded where col = (select id from unsharded_a where id = unsharded.col)"
@@ -2044,8 +1944,7 @@
     "Query": "delete from unsharded where col = (select id from unsharded_a where id = unsharded.col)"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update vindex value to null
 "update user set name = null where id = 1"
@@ -2074,8 +1973,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # insert using last_insert_id
 "insert into unsharded values(last_insert_id(), 2)"
@@ -2095,8 +1993,7 @@
     "TableName": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update vindex value to null with multiple primary keyspace id
 "update user set name = null where id in (1, 2, 3)"
@@ -2129,8 +2026,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update vindex value to null without a where clause
 "update user set name = null"
@@ -2155,8 +2051,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update vindex value to null with complex where clause
 "update user set name = null where id + 1 = 2"
@@ -2181,8 +2076,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete from user by primary keyspace id with in clause
 "delete from user where id in (1, 2, 3)"
@@ -2212,8 +2106,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete from user by complex expression
 "delete from user where id + 1 = 2"
@@ -2235,8 +2128,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete from user without a where clause
 "delete from user"
@@ -2258,8 +2150,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete with single table targets
 "delete music from music where id = 1"
@@ -2285,8 +2176,7 @@
     "Vindex": "music_user_map"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # scatter update table with owned vindexes without changing lookup vindex
 "update user set val = 1"
@@ -2306,8 +2196,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # scatter delete with owned lookup vindex
 "delete from user"
@@ -2329,8 +2218,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update multi column vindex, without values for all the vindex columns
 "update multicolvin set column_c = 2 where kid = 1"
@@ -2359,8 +2247,7 @@
     "Vindex": "kid_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with binary value
 "update user set name = _binary 'abc' where id = 1"
@@ -2389,8 +2276,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete with binary value
 "delete from user where name = _binary 'abc'"
@@ -2412,8 +2298,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # delete with shard targeting
 "delete from `user[-]`.user"
@@ -2435,8 +2320,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with shard targeting
 "update `user[-]`.user set name = 'myname'"
@@ -2461,8 +2345,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # update with shard targeting without vindex
 "update `user[-]`.user_extra set val = 1"
@@ -2482,5 +2365,4 @@
     "Table": "user_extra"
   }
 }
-{
-}
+Gen4 plan same as above
diff --git a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
index 126602ac3d..d7ebbd53b1 100644
--- a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt
@@ -15,8 +15,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Query that always return empty
 "select id from user where someColumn = null"
@@ -35,8 +34,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single table unique vindex route
 "select id from user where user.id = 5"
@@ -59,8 +57,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single table unique vindex route, but complex expr
 "select id from user where user.id = 5+5"
@@ -101,8 +98,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single table multiple non-unique vindex match
 "select id from user where costly = 'aa' and name = 'bb'"
@@ -125,8 +121,7 @@
     "Vindex": "name_user_map"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single table multiple non-unique vindex match for IN clause
 "select id from user where costly in ('aa', 'bb') and name in ('aa', 'bb')"
@@ -298,8 +293,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Composite IN: multiple vindex matches
 "select id from user where (costly, name) in (('aa', 'bb'), ('cc', 'dd'))"
@@ -393,8 +387,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Composite IN: RHS not tuple
 "select id from user where (col1, name) in (select * from music where music.user_id=user.id)"
@@ -431,8 +424,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # IN clause: LHS is neither column nor composite tuple
 "select Id from user where 1 in ('aa', 'bb')"
@@ -469,8 +461,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single table equality route with val arg
 "select id from user where name = :a"
@@ -493,8 +484,7 @@
     "Vindex": "name_user_map"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single table equality route with unsigned value
 "select id from user where name = 18446744073709551615"
@@ -517,8 +507,7 @@
     "Vindex": "name_user_map"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single table in clause list arg
 "select id from user where name in ::list"
@@ -670,8 +659,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Multi-route unique vindex route on both routes
 "select user_extra.id from user join user_extra on user.col = user_extra.col where user.id = 5 and user_extra.user_id = 5"
@@ -867,8 +855,7 @@
     "Vindex": "name_user_map"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Route with multiple route constraints, SelectEqual is the best constraint.
 "select id from user where user.col = false and user.id in (1, 2) and user.name = 'aa'"
@@ -891,8 +878,7 @@
     "Vindex": "name_user_map"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Route with multiple route constraints, SelectEqualUnique is the best constraint.
 "select id from user where user.col = 5 and user.id in (1, 2) and user.name = 'aa' and user.id = 1"
@@ -915,8 +901,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Route with multiple route constraints, SelectEqualUnique is the best constraint, order reversed.
 "select id from user where user.id = 1 and user.name = 'aa' and user.id in (1, 2) and user.col = 5"
@@ -939,8 +924,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Route with OR and AND clause, must parenthesize correctly.
 "select id from user where user.id = 1 or user.name = 'aa' and user.id in (1, 2)"
@@ -959,8 +943,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Unsharded route
 "select unsharded.id from user join unsharded where unsharded.id = user.id"
@@ -998,8 +981,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # routing rules: choose the redirected table
 "select col from route1 where id = 1"
@@ -1600,8 +1582,7 @@
     "Table": "music"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # SELECT with IS NULL
 "select id from music where id is null"
@@ -1642,8 +1623,7 @@
     "Table": "music"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single table with unique vindex match and null match
 "select id from music where user_id = 4 and id = null"
@@ -1662,8 +1642,7 @@
     "Table": "music"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single table with unique vindex match and IN (null)
 "select id from music where user_id = 4 and id IN (null)"
@@ -1704,8 +1683,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single table with unique vindex match and NOT IN (null, 1, 2)
 "select id from music where user_id = 4 and id NOT IN (null, 1, 2)"
diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.txt b/go/vt/vtgate/planbuilder/testdata/from_cases.txt
index 9305de7fe2..b0d3f050b3 100644
--- a/go/vt/vtgate/planbuilder/testdata/from_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/from_cases.txt
@@ -15,8 +15,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single table unsharded
 "select col from unsharded"
@@ -35,8 +34,7 @@
     "Table": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Select from sequence
 "select next 2 values from seq"
@@ -55,8 +53,7 @@
     "Table": "seq"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Select from reference
 "select * from ref"
@@ -75,8 +72,7 @@
     "Table": "ref"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Single information_schema query
 "select col from information_schema.foo"
@@ -164,8 +160,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # routing rules where table name matches, and there's no alias.
 "select * from second_user.user"
@@ -184,8 +179,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # routing rules where table name matches, and there's an alias.
 "select * from second_user.user as a"
@@ -204,8 +198,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # routing rules where table name does not match, and there's no alias.
 "select * from route1"
@@ -264,14 +257,12 @@
 # routing rules bad table
 "select * from bad_table"
 "keyspace noks not found in vschema"
-{
-}
+Gen4 plan same as above
 
 # routing rules disabled table
 "select * from disabled"
 "table disabled has been disabled"
-{
-}
+Gen4 plan same as above
 
 # ',' join
 "select music.col from user, music"
@@ -309,8 +300,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # ',' join unsharded
 "select u1.a, u2.a from unsharded u1, unsharded u2"
@@ -329,8 +319,7 @@
     "Table": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # ',' join information_schema
 "select a.id,b.id from information_schema.a as a, information_schema.b as b"
@@ -1120,8 +1109,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # sharded join, non-col reference LHS
 "select user.col from user join user_extra on 5 = user.id"
@@ -2344,8 +2332,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # last_insert_id for unsharded route
 "select last_insert_id() from main.unsharded"
@@ -2364,8 +2351,7 @@
     "Table": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # join with USING construct
 "select user.id from user join user_extra using(id)"
@@ -2445,8 +2431,7 @@
 # first expression fails for ',' join (code coverage: ensure error is returned)
 "select user.foo.col from user.foo, user"
 "table foo not found"
-{
-}
+Gen4 plan same as above
 
 # table names should be case-sensitive
 "select unsharded.id from unsharded where Unsharded.val = 1"
@@ -2455,8 +2440,7 @@
 # implicit table reference for sharded keyspace
 "select user.foo.col from user.foo"
 "table foo not found"
-{
-}
+Gen4 plan same as above
 
 # duplicate symbols
 "select user.id from user join user"
@@ -2469,8 +2453,7 @@
 # non-existent table
 "select c from t"
 "table t not found"
-{
-}
+Gen4 plan same as above
 
 # non-existent table on left of join
 "select c from t join user"
diff --git a/go/vt/vtgate/planbuilder/testdata/lock_cases.txt b/go/vt/vtgate/planbuilder/testdata/lock_cases.txt
index d77f70a801..17737bc117 100644
--- a/go/vt/vtgate/planbuilder/testdata/lock_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/lock_cases.txt
@@ -39,8 +39,7 @@
     "OperatorType": "Rows"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # lock tables write
 "lock tables t low_priority write"
@@ -51,8 +50,7 @@
     "OperatorType": "Rows"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # unlock tables
 "unlock tables"
@@ -63,5 +61,4 @@
     "OperatorType": "Rows"
   }
 }
-{
-}
+Gen4 plan same as above
diff --git a/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt b/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt
index 6cace35e97..901b68b2b8 100644
--- a/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/postprocess_cases.txt
@@ -154,8 +154,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # ORDER BY uses column numbers
 "select col from user where id = 1 order by 1"
@@ -178,8 +177,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # ORDER BY on scatter
 "select col from user order by col"
@@ -316,8 +314,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # ORDER BY after pull-out subquery
 "select col from user where col in (select col2 from user) order by col"
@@ -542,8 +539,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # ORDER BY RAND() for join
 "select user.col1 as a, user.col2, music.col3 from user join music on user.id = music.id where user.id = 1 order by RAND()"
@@ -646,8 +642,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Order by, qualified '*' expression
 "select user.* from user where id = 5 order by user.col"
@@ -670,8 +665,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Order by, '*' expression with qualified reference
 "select * from user where id = 5 order by user.col"
@@ -694,8 +688,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Order by, '*' expression in a subquery
 "select u.id, e.id from user u join user_extra e where u.col = e.col and u.col in (select * from user where user.id = u.id order by col)"
@@ -771,8 +764,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 #Order by with math functions
 "select * from user where id = 5 order by -col1"
@@ -795,8 +787,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 #Order by with string operations
 "select * from user where id = 5 order by concat(col,col1) collate utf8_general_ci desc"
@@ -819,8 +810,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 #Order by with math operations
 "select * from user where id = 5 order by id+col collate utf8_general_ci desc"
@@ -843,8 +833,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 #Order by subquery column
 "select * from user u join (select user_id from user_extra where user_id = 5) eu on u.id = eu.user_id where u.id = 5 order by eu.user_id"
@@ -911,8 +900,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # limit for joins. Can't push down the limit because result
 # counts get multiplied by join operations.
@@ -981,6 +969,7 @@
     ]
   }
 }
+Gen4 plan same as above
 
 # limit for scatter with bind var
 "select col from user limit :a"
@@ -1005,6 +994,7 @@
     ]
   }
 }
+Gen4 plan same as above
 
 # cross-shard expression in parenthesis with limit
 "select * from user where (id1 = 4 AND name1 ='abc') limit 5"
@@ -1029,6 +1019,7 @@
     ]
   }
 }
+Gen4 plan same as above
 
 # scatter limit after pullout subquery
 "select col from user where col in (select col1 from user) limit 1"
@@ -1088,9 +1079,9 @@
     "Table": "ref"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # invalid limit expression
 "select id from user limit 1+1"
 "unexpected expression in LIMIT: expression is too complex '1 + 1'"
+Gen4 plan same as above
diff --git a/go/vt/vtgate/planbuilder/testdata/select_cases.txt b/go/vt/vtgate/planbuilder/testdata/select_cases.txt
index ead579b8b0..5d07ee2cc9 100644
--- a/go/vt/vtgate/planbuilder/testdata/select_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/select_cases.txt
@@ -15,8 +15,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # '*' expression for simple route
 "select user.* from user"
@@ -35,8 +34,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # unqualified '*' expression for simple route
 "select * from user"
@@ -55,8 +53,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # select with timeout directive sets QueryTimeout in the route
 "select /*vt+ QUERY_TIMEOUT_MS=1000 */ * from user"
@@ -75,8 +72,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # select aggregation with timeout directive sets QueryTimeout in the route
 "select /*vt+ QUERY_TIMEOUT_MS=1000 */ count(*) from user"
@@ -127,6 +123,7 @@
     ]
   }
 }
+Gen4 plan same as above
 
 # select with partial scatter directive
 "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ * from user"
@@ -145,8 +142,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # select aggregation with partial scatter directive
 "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ count(*) from user"
@@ -223,6 +219,7 @@
     ]
   }
 }
+Gen4 plan same as above
 
 # qualified '*' expression for simple route
 "select user.* from user"
@@ -241,8 +238,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # fully qualified '*' expression for simple route
 "select user.user.* from user.user"
@@ -457,8 +453,7 @@
     "Table": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # select from dual on unqualified keyspace
 "select @@session.auto_increment_increment from dual"
@@ -477,8 +472,7 @@
     "Table": "dual"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # select from pinned table
 "select * from pin_test"
@@ -519,8 +513,7 @@
     "Table": "dual"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # RHS route referenced
 "select user_extra.id from user join user_extra"
@@ -558,8 +551,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Both routes referenced
 "select user.col, user_extra.id from user join user_extra"
@@ -597,8 +589,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Expression with single-route reference
 "select user.col, user_extra.id + user_extra.col from user join user_extra"
@@ -636,8 +627,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Jumbled references
 "select user.col, user_extra.id, user.col2 from user join user_extra"
@@ -675,8 +665,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Comments
 "select /* comment */ user.col from user join user_extra"
@@ -825,14 +814,12 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # syntax error
 "the quick brown fox"
 "syntax error at position 4 near 'the'"
-{
-}
+Gen4 plan same as above
 
 # Hex number is not treated as a simple value
 "select * from user where id = 0x04"
@@ -899,8 +886,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Multiple parenthesized expressions
 "select * from user where (id = 4) AND (name ='abc') limit 5"
@@ -923,8 +909,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Multiple parenthesized expressions
 "select * from user where (id = 4 and name ='abc') limit 5"
@@ -947,8 +932,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Column Aliasing with Table.Column
 "select user0_.col as col0_ from user user0_ where id = 1 order by user0_.col desc limit 2"
@@ -971,8 +955,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Column Aliasing with Column
 "select user0_.col as col0_ from user user0_ where id = 1 order by col0_ desc limit 3"
@@ -995,8 +978,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Booleans and parenthesis
 "select * from user where (id = 1) AND name = true limit 5"
@@ -1019,8 +1001,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Column as boolean-ish
 "select * from user where (id = 1) AND name limit 5"
@@ -1043,8 +1024,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # PK as fake boolean, and column as boolean-ish
 "select * from user where (id = 5) AND name = true limit 5"
@@ -1067,8 +1047,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # top level subquery in select
 "select a, (select col from user) from unsharded"
@@ -1210,8 +1189,7 @@
     "Query": "select * from information_schema.a union select * from information_schema.b"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union with the same target shard
 "select * from music where user_id = 1 union select * from user where id = 1"
@@ -1234,8 +1212,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union with the same target shard last_insert_id
 "select *, last_insert_id() from music where user_id = 1 union select * from user where id = 1"
@@ -1258,8 +1235,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 "select * from (select col1, col2 from unsharded where id = 1 union select col1, col2 from unsharded where id = 3) a"
 {
@@ -1311,8 +1287,7 @@
     "Table": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 "select id from unsharded union select id from unsharded_auto union select id from unsharded_auto where id in (132)"
 {
@@ -1330,8 +1305,7 @@
     "Table": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 "(select id from unsharded union select id from unsharded_auto) union (select id from unsharded_auto union select name from unsharded)"
 {
@@ -1349,8 +1323,7 @@
     "Table": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 "(select id from unsharded order by id asc limit 1) union (select id from unsharded order by id desc limit 1) order by id asc limit 1"
 {
@@ -1368,8 +1341,7 @@
     "Table": "unsharded"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # routing rules: ensure directives are not lost
 "select /*vt+ QUERY_TIMEOUT_MS=1000 */ * from route2"
@@ -1470,8 +1442,7 @@
     "Vindex": "user_index"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # sql_calc_found_rows with limit
 "select sql_calc_found_rows * from music limit 100"
@@ -1677,8 +1648,7 @@
 # Union after into outfile is incorrect
 "select id from user into outfile 'out_file_name' union all select id from music"
 "Incorrect usage/placement of 'INTO' (errno 1234) (sqlstate 42000)"
-{
-}
+Gen4 plan same as above
 
 # Into outfile s3 in sub-query is incorrect
 "select id from (select id from user into outfile s3 'inner_outfile') as t2"
diff --git a/go/vt/vtgate/planbuilder/testdata/set_cases.txt b/go/vt/vtgate/planbuilder/testdata/set_cases.txt
index 8fbb811636..1a00e12031 100644
--- a/go/vt/vtgate/planbuilder/testdata/set_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/set_cases.txt
@@ -19,8 +19,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set multi user defined variable
 "set @foo = 42, @bar = @foo"
@@ -48,8 +47,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set multi user defined variable with complex expression
 "set @foo = 42, @bar = @foo + 1"
@@ -77,8 +75,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set UDV to expression that can't be evaluated at vtgate
 "set @foo = CONCAT('Any','Expression','Is','Valid')"
@@ -109,8 +106,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # single sysvar cases
 "SET sql_mode = 'STRICT_ALL_TABLES,NO_AUTO_VALUE_ON_ZERO'"
@@ -137,8 +133,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # multiple sysvar cases
 "SET @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_safe_updates = 0"
@@ -174,8 +169,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # autocommit case
 "SET autocommit = 1, autocommit = on, autocommit = 'on', autocommit = @myudv, autocommit = `on`, autocommit = `off`"
@@ -223,8 +217,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set ignore plan
 "set @@default_storage_engine = 'DONOTCHANGEME'"
@@ -247,8 +240,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set check and ignore plan
 "set @@sql_mode = concat(@@sql_mode, ',NO_AUTO_CREATE_USER')"
@@ -275,8 +267,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set system settings
 "set @@sql_safe_updates = 1"
@@ -303,8 +294,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set plan building with ON/OFF enum
 "set @@innodb_strict_mode = OFF"
@@ -327,8 +317,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set plan building with string literal
 "set @@innodb_strict_mode = 'OFF'"
@@ -351,8 +340,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set plan building with string literal
 "set @@innodb_tmpdir = 'OFF'"
@@ -375,14 +363,12 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set system settings
 "set @@ndbinfo_max_bytes = 192"
 "ndbinfo_max_bytes: system setting is not supported"
-{
-}
+Gen4 plan same as above
 
 # set autocommit
 "set autocommit = 1"
@@ -405,8 +391,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set autocommit false
 "set autocommit = 0"
@@ -429,8 +414,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set autocommit with backticks
 "set @@session.`autocommit` = 0"
@@ -453,8 +437,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # more vitess aware settings
 "set client_found_rows = off, skip_query_plan_cache = ON, sql_select_limit=20"
@@ -487,8 +470,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set autocommit to default
 "set @@autocommit = default"
@@ -511,8 +493,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # set global autocommit to default
 "set global autocommit = off"
@@ -540,5 +521,4 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
diff --git a/go/vt/vtgate/planbuilder/testdata/transaction_cases.txt b/go/vt/vtgate/planbuilder/testdata/transaction_cases.txt
index c3e6278ef2..68be3ff6d8 100644
--- a/go/vt/vtgate/planbuilder/testdata/transaction_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/transaction_cases.txt
@@ -4,8 +4,7 @@
   "QueryType": "BEGIN",
   "Original": "begin"
 }
-{
-}
+Gen4 plan same as above
 
 # Start Transaction
 "start transaction"
@@ -13,8 +12,7 @@
   "QueryType": "BEGIN",
   "Original": "start transaction"
 }
-{
-}
+Gen4 plan same as above
 
 # Commit
 "commit"
@@ -22,8 +20,7 @@
   "QueryType": "COMMIT",
   "Original": "commit"
 }
-{
-}
+Gen4 plan same as above
 
 # Rollback
 "rollback"
@@ -31,8 +28,7 @@
   "QueryType": "ROLLBACK",
   "Original": "rollback"
 }
-{
-}
+Gen4 plan same as above
 
 # Savepoint
 "savepoint a"
@@ -40,8 +36,7 @@
   "QueryType": "SAVEPOINT",
   "Original": "savepoint a"
 }
-{
-}
+Gen4 plan same as above
 
 # Savepoint rollback
 "rollback work to savepoint a"
@@ -49,8 +44,7 @@
   "QueryType": "SAVEPOINT_ROLLBACK",
   "Original": "rollback work to savepoint a"
 }
-{
-}
+Gen4 plan same as above
 
 # Savepoint release
 "release savepoint a"
@@ -58,5 +52,4 @@
   "QueryType": "RELEASE",
   "Original": "release savepoint a"
 }
-{
-}
+Gen4 plan same as above
diff --git a/go/vt/vtgate/planbuilder/testdata/union_cases.txt b/go/vt/vtgate/planbuilder/testdata/union_cases.txt
index 4a48e616ce..49fe6182ac 100644
--- a/go/vt/vtgate/planbuilder/testdata/union_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/union_cases.txt
@@ -15,8 +15,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union distinct between two scatter selects
 "select id from user union select id from music"
@@ -56,8 +55,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union all between two SelectEqualUnique
 "select id from user where id = 1 union all select id from user where id = 5"
@@ -100,8 +98,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 #almost dereks query - two queries with order by and limit being scattered to two different sets of tablets
 "(SELECT id FROM user ORDER BY id DESC LIMIT 1) UNION ALL (SELECT id FROM music ORDER BY id DESC LIMIT 1)"
@@ -150,8 +147,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # Union all
 "select col1, col2 from user union all select col1, col2 from user_extra"
@@ -170,8 +166,7 @@
     "Table": "user"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union operations in subqueries (FROM)
 "select * from (select * from user union all select * from user_extra) as t"
@@ -238,8 +233,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union all on scatter and single route
 "select id from user where id = 1 union select id from user where id = 1  union all select id from user"
@@ -278,8 +272,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union of information_schema with normal table
 "select * from information_schema.a union select * from unsharded"
@@ -318,8 +311,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union of information_schema with normal table
 "select * from unsharded union select * from information_schema.a"
@@ -358,8 +350,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # multi-shard union
 "(select id from user union select id from music) union select 1 from dual"
@@ -420,8 +411,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # multi-shard union
 "select 1 from music union (select id from user union all select name from unsharded)"
@@ -477,8 +467,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # multi-shard union
 "select 1 from music union (select id from user union select name from unsharded)"
@@ -539,8 +528,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union with the same target shard because of vindex
 "select * from music where id = 1 union select * from user where id = 1"
@@ -588,8 +576,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union with different target shards
 "select 1 from music where id = 1 union select 1 from music where id = 2"
@@ -637,8 +624,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # multiple select statement have inner order by with union - TODO (systay) no need to send down ORDER BY if we are going to loose it with UNION DISTINCT
 "(select 1 from user order by 1 desc) union (select 1 from user order by 1 asc)"
@@ -680,8 +666,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # multiple unions
 "select 1 union select null union select 1.0 union select '1' union select 2 union select 2.0 from user"
@@ -721,8 +706,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union distinct between a scatter query and a join (other side)
 "(select user.id, user.name from user join user_extra where user_extra.extra = 'asdf') union select 'b','c' from user"
@@ -781,8 +765,7 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # union distinct between a scatter query and a join (other side)
 "select 'b','c' from user union (select user.id, user.name from user join user_extra where user_extra.extra = 'asdf')"
@@ -841,17 +824,14 @@
     ]
   }
 }
-{
-}
+Gen4 plan same as above
 
 # ambiguous LIMIT
 "select id from user limit 1 union all select id from music limit 1"
 "Incorrect usage of UNION and LIMIT - add parens to disambiguate your query (errno 1221) (sqlstate 21000)"
-{
-}
+Gen4 plan same as above
 
 # different number of columns
 "select id, 42 from user where id = 1 union all select id from user where id = 5"
 "The used SELECT statements have a different number of columns (errno 1222) (sqlstate 21000) during query: select id, 42 from user where id = 1 union all select id from user where id = 5"
-{
-}
+Gen4 plan same as above
diff --git a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt
index d534ab856a..d328c022c4 100644
--- a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt
@@ -1,8 +1,7 @@
 # SHOW
 "show create database"
 "plan building not supported"
-{
-}
+Gen4 plan same as above
 
 # union operations in subqueries (expressions)
 "select * from user where id in (select * from user union select * from user_extra)"
@@ -15,20 +14,17 @@
 # Unsupported INSERT statement with a target destination
 "insert into `user[-]`.user_metadata (a, b) values (1,2)"
 "unsupported: INSERT with a target destination"
-{
-}
+Gen4 plan same as above
 
 # Unsupported delete statement with a replica target destination
 "DELETE FROM `user[-]@replica`.user_metadata limit 1"
 "unsupported: delete statement with a replica target"
-{
-}
+Gen4 plan same as above
 
 # Unsupported update statement with a replica target destination
 "update `user[-]@replica`.user_metadata set id=2"
 "unsupported: update statement with a replica target"
-{
-}
+Gen4 plan same as above
 
 # scatter order by with * expression
 "select * from user order by id"
@@ -177,218 +173,182 @@
 # subqueries in update
 "update user set col = (select id from unsharded)"
 "unsupported: subqueries in sharded DML"
-{
-}
+Gen4 plan same as above
 
 # sharded subqueries in unsharded update
 "update unsharded set col = (select id from user)"
 "unsupported: sharded subqueries in DML"
-{
-}
+Gen4 plan same as above
 
 # sharded join unsharded subqueries in unsharded update
 "update unsharded set col = (select id from unsharded join user on unsharded.id = user.id)"
 "unsupported: sharded subqueries in DML"
-{
-}
+Gen4 plan same as above
 
 # subqueries in delete
 "delete from user where col = (select id from unsharded)"
 "unsupported: subqueries in sharded DML"
-{
-}
+Gen4 plan same as above
 
 # sharded subqueries in unsharded delete
 "delete from unsharded where col = (select id from user)"
 "unsupported: sharded subqueries in DML"
-{
-}
+Gen4 plan same as above
 
 # sharded delete with limit clasue
 "delete from user_extra limit 10"
 "unsupported: multi shard delete with limit"
-{
-}
+Gen4 plan same as above
 
 # sharded subquery in unsharded subquery in unsharded delete
 "delete from unsharded where col = (select id from unsharded where id = (select id from user))"
 "unsupported: sharded subqueries in DML"
-{
-}
+Gen4 plan same as above
 
 # sharded join unsharded subqueries in unsharded delete
 "delete from unsharded where col = (select id from unsharded join user on unsharded.id = user.id)"
 "unsupported: sharded subqueries in DML"
-{
-}
+Gen4 plan same as above
 
 # scatter update with limit clause
 "update user_extra set val = 1 where (name = 'foo' or id = 1) limit 1"
 "unsupported: multi shard update with limit"
-{
-}
+Gen4 plan same as above
 
 # multi delete multi table
 "delete user from user join user_extra on user.id = user_extra.id where user.name = 'foo'"
 "unsupported: multi-shard or vindex write statement"
-{
-}
+Gen4 plan same as above
 
 # update changes primary vindex column
 "update user set id = 1 where id = 1"
 "unsupported: You can't update primary vindex columns. Invalid update on vindex: user_index"
-{
-}
+Gen4 plan same as above
 
 # update changes non owned vindex column
 "update music_extra set music_id = 1 where user_id = 1"
 "unsupported: You can only update owned vindexes. Invalid update on vindex: music_user_map"
-{
-}
+Gen4 plan same as above
 
 # update changes non lookup vindex column
 "update user_metadata set md5 = 1 where user_id = 1"
 "unsupported: You can only update lookup vindexes. Invalid update on vindex: user_md5_index"
-{
-}
+Gen4 plan same as above
 
 # update with complex set clause
 "update music set id = id + 1 where id = 1"
 "unsupported: Only values are supported. Invalid update on column: id"
-{
-}
+Gen4 plan same as above
 
 # update by primary keyspace id, changing one vindex column, limit without order clause
 "update user_metadata set email = 'juan@vitess.io' where user_id = 1 limit 10"
 "unsupported: Need to provide order by clause when using limit. Invalid update on vindex: email_user_map"
-{
-}
+Gen4 plan same as above
 
 # cross-shard update tables
 "update (select id from user) as u set id = 4"
 "unsupported: subqueries in sharded DML"
-{
-}
+Gen4 plan same as above
 
 # join in update tables
 "update user join user_extra on user.id = user_extra.id set user.name = 'foo'"
 "unsupported: multi-shard or vindex write statement"
-{
-}
+Gen4 plan same as above
 
 # multiple tables in update
 "update user as u, user_extra as ue set u.name = 'foo' where u.id = ue.id"
 "unsupported: multi-shard or vindex write statement"
-{
-}
+Gen4 plan same as above
 
 # unsharded insert with cross-shard join"
 "insert into unsharded select u.col from user u join user u1"
 "unsupported: sharded subquery in insert values"
-{
-}
+Gen4 plan same as above
 
 # unsharded insert with mismatched keyspaces"
 "insert into unsharded select col from user where id=1"
 "unsupported: sharded subquery in insert values"
-{
-}
+Gen4 plan same as above
 
 # unsharded insert, unqualified names and auto-inc combined
 "insert into unsharded_auto select col from unsharded"
 "unsupported: auto-inc and select in insert"
-{
-}
+Gen4 plan same as above
 
 # unsharded insert, with sharded subquery in insert value
 "insert into unsharded values((select 1 from user), 1)"
 "unsupported: sharded subquery in insert values"
-{
-}
+Gen4 plan same as above
 
 # unsharded insert, no col list with auto-inc
 "insert into unsharded_auto values(1,1)"
 "column list required for tables with auto-inc columns"
-{
-}
+Gen4 plan same as above
 
 # unsharded insert, col list does not match values
 "insert into unsharded_auto(id, val) values(1)"
 "column list doesn't match values"
-{
-}
+Gen4 plan same as above
 
 # sharded upsert can't change vindex
 "insert into user(id) values(1) on duplicate key update id = 3"
 "unsupported: DML cannot change vindex column"
-{
-}
+Gen4 plan same as above
 
 # sharded upsert can't change vindex using values function
 "insert into music(user_id, id) values(1, 2) on duplicate key update user_id = values(id)"
 "unsupported: DML cannot change vindex column"
-{
-}
+Gen4 plan same as above
 
 # sharded insert from select
 "insert into user(id) select 1 from dual"
 "unsupported: insert into select"
-{
-}
+Gen4 plan same as above
 
 # sharded replace no vindex
 "replace into user(val) values(1, 'foo')"
 "unsupported: REPLACE INTO with sharded schema"
-{
-}
+Gen4 plan same as above
 
 # sharded replace with vindex
 "replace into user(id, name) values(1, 'foo')"
 "unsupported: REPLACE INTO with sharded schema"
-{
-}
+Gen4 plan same as above
 
 # replace no column list
 "replace into user values(1, 2, 3)"
 "unsupported: REPLACE INTO with sharded schema"
-{
-}
+Gen4 plan same as above
 
 # replace with mimatched column list
 "replace into user(id) values (1, 2)"
 "unsupported: REPLACE INTO with sharded schema"
-{
-}
+Gen4 plan same as above
 
 # replace with one vindex
 "replace into user(id) values (1)"
 "unsupported: REPLACE INTO with sharded schema"
-{
-}
+Gen4 plan same as above
 
 # replace with non vindex on vindex-enabled table
 "replace into user(nonid) values (2)"
 "unsupported: REPLACE INTO with sharded schema"
-{
-}
+Gen4 plan same as above
 
 # replace with all vindexes supplied
 "replace into user(nonid, name, id) values (2, 'foo', 1)"
 "unsupported: REPLACE INTO with sharded schema"
-{
-}
+Gen4 plan same as above
 
 # replace for non-vindex autoinc
 "replace into user_extra(nonid) values (2)"
 "unsupported: REPLACE INTO with sharded schema"
-{
-}
+Gen4 plan same as above
 
 # replace with multiple rows
 "replace into user(id) values (1), (2)"
 "unsupported: REPLACE INTO with sharded schema"
-{
-}
+Gen4 plan same as above
 
 "select keyspace_id from user_index where id = 1 and id = 2"
 "unsupported: where clause for vindex function must be of the form id = <val> (multiple filters)"
@@ -417,26 +377,22 @@
 # delete with unknown reference
 "delete music from user where id = 1"
 "Unknown table 'music' in MULTI DELETE"
-{
-}
+Gen4 plan same as above
 
 # delete with multi-table targets
 "delete music,user from music inner join user where music.id = user.id"
 "unsupported: multi-shard or vindex write statement"
-{
-}
+Gen4 plan same as above
 
 # order by inside and outside parenthesis select
 "(select 1 from user order by 1 desc) order by 1 asc limit 2"
 "can't do ORDER BY on top of ORDER BY"
-{
-}
+Gen4 plan same as above
 
 # ambiguous ORDER BY
 "select id from user order by id union all select id from music order by id desc"
 "Incorrect usage of UNION and ORDER BY - add parens to disambiguate your query (errno 1221) (sqlstate 21000)"
-{
-}
+Gen4 plan same as above
 
 # select get_lock with non-dual table
 "select get_lock('xyz', 10) from user"
@@ -449,26 +405,22 @@
 # insert using select get_lock from table
 "insert into user(pattern) SELECT GET_LOCK('xyz1', 10)"
 "unsupported: insert into select"
-{
-}
+Gen4 plan same as above
 
 # union with SQL_CALC_FOUND_ROWS 
 "(select sql_calc_found_rows id from user where id = 1 limit 1) union select id from user where id = 1"
 "SQL_CALC_FOUND_ROWS not supported with union"
-{
-}
+Gen4 plan same as above
 
 # set with DEFAULT - vitess aware
 "set workload = default"
 "DEFAULT not supported for @@workload"
-{
-}
+Gen4 plan same as above
 
 # set with DEFAULT - reserved connection
 "set sql_mode = default"
 "DEFAULT not supported for @@sql_mode"
-{
-}
+Gen4 plan same as above
 
 # Multi shard query using into outfile s3
 "select * from user into outfile s3 'out_file_name'"
@@ -485,12 +437,12 @@
 # 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"
 "Complex select queries are not supported in create or alter view statements"
-{
-}
+Gen4 plan same as above
 
 # create view with sharded limit
 "create view user.view_a as select id from user order by id limit 10"
 "Complex select queries are not supported in create or alter view statements"
+Gen4 plan same as above
 
 # create view with top level subquery in select
 "create view user.view_a as select a, (select col from user) from unsharded"
@@ -499,13 +451,14 @@
 # create view with sql_calc_found_rows with limit
 "create view user.view_a as select sql_calc_found_rows * from music limit 100"
 "Complex select queries are not supported in create or alter view statements"
+Gen4 plan same as above
 
 # create view with sql_calc_found_rows with group by and having
 "create view user.view_a as select sql_calc_found_rows user_id, count(id) from music group by user_id having count(user_id) = 1 order by user_id limit 2"
 "Complex select queries are not supported in create or alter view statements"
+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"
-{
-}
+Gen4 plan same as above
diff --git a/go/vt/vtgate/planbuilder/testdata/use_cases.txt b/go/vt/vtgate/planbuilder/testdata/use_cases.txt
index 47a1f09075..bc7ce1e968 100644
--- a/go/vt/vtgate/planbuilder/testdata/use_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/use_cases.txt
@@ -8,8 +8,7 @@
     "target": "ks"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # use db tablet
 "use ks@replica"
@@ -21,8 +20,7 @@
     "target": "ks@replica"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # use db target with :
 "use `ks:-80@replica`"
@@ -34,8 +32,7 @@
     "target": "ks:-80@replica"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # use db target with /
 "use `ks/80-@replica`"
@@ -47,8 +44,7 @@
     "target": "ks/80-@replica"
   }
 }
-{
-}
+Gen4 plan same as above
 
 # reset db
 "use"
@@ -59,5 +55,4 @@
     "OperatorType": "UpdateTarget"
   }
 }
-{
-}
+Gen4 plan same as above
diff --git a/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt b/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt
index 8865eff33b..d2ae819cd3 100644
--- a/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/vindex_func_cases.txt
@@ -81,8 +81,7 @@
 # ambiguous vindex reference
 "select id, keyspace_id, id from hash_dup where id = :id"
 "ambiguous vindex reference: hash_dup"
-{
-}
+Gen4 plan same as above
 
 # disambiguated vindex reference
 "select id, keyspace_id, id from second_user.hash_dup where id = :id"
diff --git a/go/vt/vtgate/planbuilder/testdata/wireup_cases.txt b/go/vt/vtgate/planbuilder/testdata/wireup_cases.txt
index b0502d888f..7bba805ed0 100644
--- a/go/vt/vtgate/planbuilder/testdata/wireup_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/wireup_cases.txt
@@ -633,11 +633,9 @@
 # Invalid value in IN clause from LHS of join
 "select u1.id from user u1 join user u2 where u1.id = 18446744073709551616"
 "strconv.ParseUint: parsing "18446744073709551616": value out of range"
-{
-}
+Gen4 plan same as above
 
 # Invalid value in IN clause from RHS of join
 "select u1.id from user u1 join user u2 where u2.id = 18446744073709551616"
 "strconv.ParseUint: parsing "18446744073709551616": value out of range"
-{
-}
+Gen4 plan same as above