Repository: vitessio/vitess
Pull request #9646 (2022-02-07 16:36:45)

evalengine: use sqltypes
## Description

This is a cleanup PR: the new implementation of the `evalengine` was using an ugly mixture of SQL types from `querypb` and from `sqltypes`, even though all these constants are aliases between each other.

This PR cleans this mess by switching everything to the constants defined in `sqltypes`, which are more readable.

While I was here, I also added a randomization element to the integration tests: now every test run decides at random whether to simplify the tested expressions before evaluation. The expressions should (obviously) give identical results with and without simplification, so this randomization is a good way to ensure this property over time without doubling the duration of the integration tests, which are already quite long.

## Related Issue(s)
<!-- List related issues and pull requests. If this PR fixes an issue, please add it using Fixes #????  -->


## Checklist
- [ ] Should this PR be backported?
- [x] Tests were added or are not required
- [x] 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. -->


Patch:
diff --git a/go/sqltypes/type.go b/go/sqltypes/type.go
index f1d4888c6a..9bc45a756b 100644
--- a/go/sqltypes/type.go
+++ b/go/sqltypes/type.go
@@ -22,6 +22,8 @@ import (
 	querypb "vitess.io/vitess/go/vt/proto/query"
 )
 
+type Type = querypb.Type
+
 // This file provides wrappers and support
 // functions for querypb.Type.
 
@@ -152,6 +154,7 @@ const (
 	Expression = querypb.Type_EXPRESSION
 	HexNum     = querypb.Type_HEXNUM
 	HexVal     = querypb.Type_HEXVAL
+	Tuple      = querypb.Type_TUPLE
 )
 
 // bit-shift the mysql flags by two byte so we
diff --git a/go/vt/vtgate/engine/ordered_aggregate.go b/go/vt/vtgate/engine/ordered_aggregate.go
index 90aa1e6222..bd69a48ce3 100644
--- a/go/vt/vtgate/engine/ordered_aggregate.go
+++ b/go/vt/vtgate/engine/ordered_aggregate.go
@@ -58,10 +58,6 @@ type OrderedAggregate struct {
 	// from the result received. If 0, no truncation happens.
 	TruncateColumnCount int `json:",omitempty"`
 
-	// Collations stores the collation ID per column offset.
-	// It is used for grouping keys and distinct aggregate functions
-	Collations map[int]collations.ID
-
 	// Input is the primitive that will feed into this Primitive.
 	Input Primitive
 }
@@ -77,19 +73,10 @@ type GroupByParams struct {
 
 // String returns a string. Used for plan descriptions
 func (gbp GroupByParams) String() string {
-	var out string
 	if gbp.WeightStringCol == -1 || gbp.KeyCol == gbp.WeightStringCol {
-		out = strconv.Itoa(gbp.KeyCol)
-	} else {
-		out = fmt.Sprintf("(%d|%d)", gbp.KeyCol, gbp.WeightStringCol)
-	}
-
-	if gbp.CollationID != collations.Unknown {
-		collation := collations.Local().LookupByID(gbp.CollationID)
-		out += " COLLATE " + collation.Name()
+		return strconv.Itoa(gbp.KeyCol)
 	}
-
-	return out
+	return fmt.Sprintf("(%d|%d)", gbp.KeyCol, gbp.WeightStringCol)
 }
 
 // AggregateParams specify the parameters for each aggregation.
@@ -99,10 +86,9 @@ type AggregateParams struct {
 	Col    int
 
 	// These are used only for distinct opcodes.
-	KeyCol      int
-	WCol        int
-	WAssigned   bool
-	CollationID collations.ID
+	KeyCol    int
+	WCol      int
+	WAssigned bool
 
 	Alias string `json:",omitempty"`
 	Expr  sqlparser.Expr
@@ -121,10 +107,6 @@ func (ap *AggregateParams) String() string {
 	if ap.WAssigned {
 		keyCol = fmt.Sprintf("%s|%d", keyCol, ap.WCol)
 	}
-	if ap.CollationID != collations.Unknown {
-		collation := collations.Local().LookupByID(ap.CollationID)
-		keyCol += " COLLATE " + collation.Name()
-	}
 	if ap.Alias != "" {
 		return fmt.Sprintf("%s(%s) AS %s", ap.Opcode.String(), keyCol, ap.Alias)
 	}
@@ -204,6 +186,17 @@ func (oa *OrderedAggregate) GetTableName() string {
 	return oa.Input.GetTableName()
 }
 
+// getCollations specifies the collation ID value for columns.
+func (oa *OrderedAggregate) getCollations() map[int]collations.ID {
+	colls := make(map[int]collations.ID)
+	for _, key := range oa.GroupByKeys {
+		if key.CollationID != collations.Unknown {
+			colls[key.KeyCol] = key.CollationID
+		}
+	}
+	return colls
+}
+
 // SetTruncateColumnCount sets the truncate column count.
 func (oa *OrderedAggregate) SetTruncateColumnCount(count int) {
 	oa.TruncateColumnCount = count
@@ -227,6 +220,7 @@ func (oa *OrderedAggregate) execute(vcursor VCursor, bindVars map[string]*queryp
 		Fields: oa.convertFields(result.Fields),
 		Rows:   make([][]sqltypes.Value, 0, len(result.Rows)),
 	}
+	colls := oa.getCollations()
 	// This code is similar to the one in StreamExecute.
 	var current []sqltypes.Value
 	var curDistincts []sqltypes.Value
@@ -235,13 +229,13 @@ func (oa *OrderedAggregate) execute(vcursor VCursor, bindVars map[string]*queryp
 			current, curDistincts = oa.convertRow(row)
 			continue
 		}
-		equal, err := oa.keysEqual(current, row, oa.Collations)
+		equal, err := oa.keysEqual(current, row, colls)
 		if err != nil {
 			return nil, err
 		}
 
 		if equal {
-			current, curDistincts, err = oa.merge(result.Fields, current, row, curDistincts, oa.Collations)
+			current, curDistincts, err = oa.merge(result.Fields, current, row, curDistincts, colls)
 			if err != nil {
 				return nil, err
 			}
@@ -288,6 +282,7 @@ func (oa *OrderedAggregate) TryStreamExecute(vcursor VCursor, bindVars map[strin
 				return err
 			}
 		}
+		colls := oa.getCollations()
 		// This code is similar to the one in Execute.
 		for _, row := range qr.Rows {
 			if current == nil {
@@ -295,13 +290,13 @@ func (oa *OrderedAggregate) TryStreamExecute(vcursor VCursor, bindVars map[strin
 				continue
 			}
 
-			equal, err := oa.keysEqual(current, row, oa.Collations)
+			equal, err := oa.keysEqual(current, row, colls)
 			if err != nil {
 				return err
 			}
 
 			if equal {
-				current, curDistincts, err = oa.merge(fields, current, row, curDistincts, oa.Collations)
+				current, curDistincts, err = oa.merge(fields, current, row, curDistincts, colls)
 				if err != nil {
 					return err
 				}
diff --git a/go/vt/vtgate/evalengine/arithmetic.go b/go/vt/vtgate/evalengine/arithmetic.go
index d1cf4f9d06..5dbb9f48d3 100644
--- a/go/vt/vtgate/evalengine/arithmetic.go
+++ b/go/vt/vtgate/evalengine/arithmetic.go
@@ -26,7 +26,6 @@ import (
 	"vitess.io/vitess/go/hack"
 	"vitess.io/vitess/go/mysql/collations"
 	"vitess.io/vitess/go/sqltypes"
-	querypb "vitess.io/vitess/go/vt/proto/query"
 	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
 	"vitess.io/vitess/go/vt/vterrors"
 	"vitess.io/vitess/go/vt/vtgate/evalengine/decimal"
@@ -38,8 +37,8 @@ var zeroBytes = []byte("0")
 
 // UnsupportedComparisonError represents the error where the comparison between the two types is unsupported on vitess
 type UnsupportedComparisonError struct {
-	Type1 querypb.Type
-	Type2 querypb.Type
+	Type1 sqltypes.Type
+	Type2 sqltypes.Type
 }
 
 // Error function implements the error interface
@@ -160,7 +159,7 @@ func Divide(v1, v2 sqltypes.Value) (sqltypes.Value, error) {
 // addition, if one of the input types was Decimal, then
 // a Decimal is built. Otherwise, the final type of the
 // result is preserved.
-func NullSafeAdd(v1, v2 sqltypes.Value, resultType querypb.Type) (sqltypes.Value, error) {
+func NullSafeAdd(v1, v2 sqltypes.Value, resultType sqltypes.Type) (sqltypes.Value, error) {
 	if v1.IsNull() {
 		v1 = sqltypes.MakeTrusted(resultType, zeroBytes)
 	}
@@ -266,7 +265,7 @@ func NullsafeCompare(v1, v2 sqltypes.Value, collationID collations.ID) (int, err
 }
 
 // isByteComparable returns true if the type is binary or date/time.
-func isByteComparable(typ querypb.Type) bool {
+func isByteComparable(typ sqltypes.Type) bool {
 	if sqltypes.IsBinary(typ) {
 		return true
 	}
diff --git a/go/vt/vtgate/evalengine/arithmetic_expr.go b/go/vt/vtgate/evalengine/arithmetic_expr.go
index 805f88a2fb..4876447e89 100644
--- a/go/vt/vtgate/evalengine/arithmetic_expr.go
+++ b/go/vt/vtgate/evalengine/arithmetic_expr.go
@@ -18,7 +18,6 @@ package evalengine
 
 import (
 	"vitess.io/vitess/go/sqltypes"
-	querypb "vitess.io/vitess/go/vt/proto/query"
 )
 
 type (
@@ -30,7 +29,7 @@ type (
 	// ArithmeticOp allows arithmetic expressions to not have to evaluate child expressions - this is done by the BinaryExpr
 	ArithmeticOp interface {
 		eval(left, right, out *EvalResult) error
-		typeof(left querypb.Type) querypb.Type
+		typeof(left sqltypes.Type) sqltypes.Type
 		String() string
 	}
 
@@ -53,7 +52,7 @@ func (b *ArithmeticExpr) eval(env *ExpressionEnv, out *EvalResult) {
 		out.setNull()
 		return
 	}
-	if left.typeof() == querypb.Type_TUPLE || right.typeof() == querypb.Type_TUPLE {
+	if left.typeof() == sqltypes.Tuple || right.typeof() == sqltypes.Tuple {
 		panic("failed to typecheck tuples")
 	}
 	if err := b.Op.eval(&left, &right, out); err != nil {
@@ -62,7 +61,7 @@ func (b *ArithmeticExpr) eval(env *ExpressionEnv, out *EvalResult) {
 }
 
 // typeof implements the Expr interface
-func (b *ArithmeticExpr) typeof(env *ExpressionEnv) querypb.Type {
+func (b *ArithmeticExpr) typeof(env *ExpressionEnv) sqltypes.Type {
 	// TODO: this is returning an unknown type for this arithmetic expression;
 	// for some cases, it may be possible to calculate the resulting type
 	// of the expression ahead of time, making the evaluation lazier.
@@ -72,23 +71,23 @@ func (b *ArithmeticExpr) typeof(env *ExpressionEnv) querypb.Type {
 func (a *OpAddition) eval(left, right, out *EvalResult) error {
 	return addNumericWithError(left, right, out)
 }
-func (a *OpAddition) typeof(left querypb.Type) querypb.Type { return left }
-func (a *OpAddition) String() string                        { return "+" }
+func (a *OpAddition) typeof(left sqltypes.Type) sqltypes.Type { return left }
+func (a *OpAddition) String() string                          { return "+" }
 
 func (s *OpSubstraction) eval(left, right, out *EvalResult) error {
 	return subtractNumericWithError(left, right, out)
 }
-func (s *OpSubstraction) typeof(left querypb.Type) querypb.Type { return left }
-func (s *OpSubstraction) String() string                        { return "-" }
+func (s *OpSubstraction) typeof(left sqltypes.Type) sqltypes.Type { return left }
+func (s *OpSubstraction) String() string                          { return "-" }
 
 func (m *OpMultiplication) eval(left, right, out *EvalResult) error {
 	return multiplyNumericWithError(left, right, out)
 }
-func (m *OpMultiplication) typeof(left querypb.Type) querypb.Type { return left }
-func (m *OpMultiplication) String() string                        { return "*" }
+func (m *OpMultiplication) typeof(left sqltypes.Type) sqltypes.Type { return left }
+func (m *OpMultiplication) String() string                          { return "*" }
 
 func (d *OpDivision) eval(left, right, out *EvalResult) error {
 	return divideNumericWithError(left, right, true, out)
 }
-func (d *OpDivision) typeof(querypb.Type) querypb.Type { return sqltypes.Float64 }
-func (d *OpDivision) String() string                   { return "/" }
+func (d *OpDivision) typeof(sqltypes.Type) sqltypes.Type { return sqltypes.Float64 }
+func (d *OpDivision) String() string                     { return "/" }
diff --git a/go/vt/vtgate/evalengine/comparisons.go b/go/vt/vtgate/evalengine/comparisons.go
index 6947e0fe66..bfa9d39962 100644
--- a/go/vt/vtgate/evalengine/comparisons.go
+++ b/go/vt/vtgate/evalengine/comparisons.go
@@ -19,7 +19,6 @@ package evalengine
 import (
 	"vitess.io/vitess/go/mysql/collations"
 	"vitess.io/vitess/go/sqltypes"
-	querypb "vitess.io/vitess/go/vt/proto/query"
 	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
 	"vitess.io/vitess/go/vt/vterrors"
 )
@@ -142,8 +141,8 @@ func evalResultsAreDateAndNumeric(l, r *EvalResult) bool {
 }
 
 func compareAsTuples(lVal, rVal *EvalResult) bool {
-	left := lVal.typeof() == querypb.Type_TUPLE
-	right := rVal.typeof() == querypb.Type_TUPLE
+	left := lVal.typeof() == sqltypes.Tuple
+	right := rVal.typeof() == sqltypes.Tuple
 	if left && right {
 		return true
 	}
@@ -221,7 +220,7 @@ func evalCompare(lVal, rVal *EvalResult) (comp int, err error) {
 		// 			- select 1 where 104200 = cast("10:42:00" as time)
 		return 0, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "cannot compare a date with a numeric value")
 
-	case lVal.typeof() == querypb.Type_TUPLE || rVal.typeof() == querypb.Type_TUPLE:
+	case lVal.typeof() == sqltypes.Tuple || rVal.typeof() == sqltypes.Tuple:
 		panic("evalCompare: tuple comparison should be handled early")
 
 	default:
@@ -270,7 +269,7 @@ func (c *ComparisonExpr) eval(env *ExpressionEnv, result *EvalResult) {
 }
 
 // typeof implements the Expr interface
-func (c *ComparisonExpr) typeof(*ExpressionEnv) querypb.Type {
+func (c *ComparisonExpr) typeof(*ExpressionEnv) sqltypes.Type {
 	// TODO: make this less aggressive
 	return -1
 }
@@ -281,7 +280,7 @@ func (i *InExpr) eval(env *ExpressionEnv, result *EvalResult) {
 	left.init(env, i.Left)
 	right.init(env, i.Right)
 
-	if right.typeof() != querypb.Type_TUPLE {
+	if right.typeof() != sqltypes.Tuple {
 		throwEvalError(vterrors.Errorf(vtrpcpb.Code_INTERNAL, "rhs of an In operation should be a tuple"))
 	}
 	if left.null() {
@@ -332,9 +331,9 @@ func (i *InExpr) eval(env *ExpressionEnv, result *EvalResult) {
 	}
 }
 
-func (i *InExpr) typeof(env *ExpressionEnv) querypb.Type {
+func (i *InExpr) typeof(env *ExpressionEnv) sqltypes.Type {
 	// TODO: make this less aggressive
-	// return querypb.Type_INT64, nil
+	// return sqltypes.Int64, nil
 	return -1
 }
 
@@ -359,7 +358,7 @@ func (l *LikeExpr) eval(env *ExpressionEnv, result *EvalResult) {
 
 	var matched bool
 	switch {
-	case left.typeof() == querypb.Type_TUPLE || right.typeof() == querypb.Type_TUPLE:
+	case left.typeof() == sqltypes.Tuple || right.typeof() == sqltypes.Tuple:
 		panic("failed to typecheck tuples")
 	case left.null() || right.null():
 		result.setNull()
@@ -378,8 +377,8 @@ func (l *LikeExpr) eval(env *ExpressionEnv, result *EvalResult) {
 }
 
 // typeof implements the ComparisonOp interface
-func (l *LikeExpr) typeof(env *ExpressionEnv) querypb.Type {
+func (l *LikeExpr) typeof(env *ExpressionEnv) sqltypes.Type {
 	// TODO: make this less aggressive
-	// return querypb.Type_UINT64, nil
+	// return sqltypes.Uint64, nil
 	return -1
 }
diff --git a/go/vt/vtgate/evalengine/convert.go b/go/vt/vtgate/evalengine/convert.go
index 0bb4bea38a..cf744fd1fa 100644
--- a/go/vt/vtgate/evalengine/convert.go
+++ b/go/vt/vtgate/evalengine/convert.go
@@ -20,7 +20,7 @@ import (
 	"fmt"
 
 	"vitess.io/vitess/go/mysql/collations"
-	querypb "vitess.io/vitess/go/vt/proto/query"
+	"vitess.io/vitess/go/sqltypes"
 	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
 	"vitess.io/vitess/go/vt/sqlparser"
 	"vitess.io/vitess/go/vt/vterrors"
@@ -319,19 +319,19 @@ func convertExpr(e sqlparser.Expr, lookup ConverterLookup) (Expr, error) {
 		case *Literal:
 			switch collation {
 			case collations.CollationBinaryID:
-				lit.Val.type_ = int16(querypb.Type_VARBINARY)
+				lit.Val.type_ = int16(sqltypes.VarBinary)
 				lit.Val.collation_ = collationBinary
 			default:
-				lit.Val.type_ = int16(querypb.Type_VARCHAR)
+				lit.Val.type_ = int16(sqltypes.VarChar)
 				lit.Val.replaceCollationID(collation)
 			}
 		case *BindVariable:
 			switch collation {
 			case collations.CollationBinaryID:
-				lit.coerceType = querypb.Type_VARBINARY
+				lit.coerceType = sqltypes.VarBinary
 				lit.coll = collationBinary
 			default:
-				lit.coerceType = querypb.Type_VARCHAR
+				lit.coerceType = sqltypes.VarChar
 				lit.coll.Collation = collation
 			}
 		default:
@@ -381,13 +381,6 @@ func convertExpr(e sqlparser.Expr, lookup ConverterLookup) (Expr, error) {
 	return nil, convertNotSupported(e)
 }
 
-var builtinFunctions = map[string]func(*ExpressionEnv, []EvalResult, *EvalResult){
-	"coalesce":  builtinFuncCoalesce,
-	"greatest":  builtinFuncGreatest,
-	"least":     builtinFuncLeast,
-	"collation": builtinFuncCollation,
-}
-
 func convertNotSupported(e sqlparser.Expr) error {
 	return vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "%s: %s", ErrConvertExprNotSupported, sqlparser.String(e))
 }
diff --git a/go/vt/vtgate/evalengine/eval_result.go b/go/vt/vtgate/evalengine/eval_result.go
index ececfa9eeb..4d53ace619 100644
--- a/go/vt/vtgate/evalengine/eval_result.go
+++ b/go/vt/vtgate/evalengine/eval_result.go
@@ -27,7 +27,6 @@ import (
 	"vitess.io/vitess/go/hack"
 	"vitess.io/vitess/go/mysql/collations"
 	"vitess.io/vitess/go/sqltypes"
-	querypb "vitess.io/vitess/go/vt/proto/query"
 	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
 	"vitess.io/vitess/go/vt/vterrors"
 	"vitess.io/vitess/go/vt/vtgate/evalengine/decimal"
@@ -98,8 +97,8 @@ func (er *EvalResult) resolve() {
 			er.expr.eval(er.env, er)
 			if er.type_ != before {
 				panic(fmt.Sprintf("did not pre-compute the right type: %v before evaluation, %v after",
-					querypb.Type(before).String(),
-					querypb.Type(er.type_).String()))
+					sqltypes.Type(before).String(),
+					sqltypes.Type(er.type_).String()))
 			}
 		} else {
 			er.expr.eval(er.env, er)
@@ -108,11 +107,11 @@ func (er *EvalResult) resolve() {
 	}
 }
 
-func (er *EvalResult) typeof() querypb.Type {
+func (er *EvalResult) typeof() sqltypes.Type {
 	if er.type_ < 0 {
 		er.resolve()
 	}
-	return querypb.Type(er.type_)
+	return sqltypes.Type(er.type_)
 }
 
 func (er *EvalResult) hasFlag(f uint16) bool {
@@ -191,7 +190,7 @@ func (er *EvalResult) setBoolean(b boolean) {
 	}
 }
 
-func (er *EvalResult) setRaw(typ querypb.Type, raw []byte, coll collations.TypedCollation) {
+func (er *EvalResult) setRaw(typ sqltypes.Type, raw []byte, coll collations.TypedCollation) {
 	er.type_ = int16(typ)
 	er.bytes_ = raw
 	er.collation_ = coll
@@ -210,7 +209,7 @@ func (er *EvalResult) setString(str string, coll collations.TypedCollation) {
 	er.collation_ = coll
 }
 
-func (er *EvalResult) setRawNumeric(typ querypb.Type, u uint64) {
+func (er *EvalResult) setRawNumeric(typ sqltypes.Type, u uint64) {
 	er.type_ = int16(typ)
 	er.numeric_ = u
 	er.collation_ = collationNumeric
@@ -241,7 +240,7 @@ func (er *EvalResult) setDecimal(dec *decimalResult) {
 }
 
 func (er *EvalResult) setTuple(t []EvalResult) {
-	er.type_ = int16(querypb.Type_TUPLE)
+	er.type_ = int16(sqltypes.Tuple)
 	er.tuple_ = &t
 	er.collation_ = collations.TypedCollation{}
 }
@@ -351,7 +350,7 @@ func (er *EvalResult) TupleValues() []sqltypes.Value {
 
 // debugString prints the entire EvalResult in a debug format
 func (er *EvalResult) debugString() string {
-	return fmt.Sprintf("(%s) 0x%08x %s", querypb.Type_name[int32(er.type_)], er.numeric_, er.bytes_)
+	return fmt.Sprintf("(%s) 0x%08x %s", sqltypes.Type(er.type_).String(), er.numeric_, er.bytes_)
 }
 
 // ToBooleanStrict is used when the casting to a boolean has to be minimally forgiving,
@@ -408,7 +407,7 @@ func (er *EvalResult) truthy() boolean {
 		return makeboolean(!er.decimal().num.IsZero())
 	case sqltypes.VarBinary, sqltypes.VarChar:
 		return makeboolean(parseStringToFloat(er.string()) != 0.0)
-	case querypb.Type_TUPLE:
+	case sqltypes.Tuple:
 		panic("did not typecheck tuples")
 	default:
 		return boolTrue
@@ -416,7 +415,7 @@ func (er *EvalResult) truthy() boolean {
 }
 
 // FormatFloat formats a float64 as a byte string in a similar way to what MySQL does
-func FormatFloat(typ querypb.Type, f float64) []byte {
+func FormatFloat(typ sqltypes.Type, f float64) []byte {
 	format := byte('g')
 	if typ == sqltypes.Decimal {
 		format = 'f'
@@ -455,7 +454,7 @@ func (er *EvalResult) toRawBytes() []byte {
 	}
 }
 
-func (er *EvalResult) toSQLValue(resultType querypb.Type) sqltypes.Value {
+func (er *EvalResult) toSQLValue(resultType sqltypes.Type) sqltypes.Value {
 	switch {
 	case sqltypes.IsSigned(resultType):
 		switch er.typeof() {
@@ -523,7 +522,7 @@ func (er *EvalResult) nullSafeHashcode() (HashCode, error) {
 	}
 }
 
-func (er *EvalResult) setValueCast(v sqltypes.Value, typ querypb.Type) error {
+func (er *EvalResult) setValueCast(v sqltypes.Value, typ sqltypes.Type) error {
 	switch {
 	case typ == sqltypes.Null:
 		er.setNull()
@@ -611,7 +610,7 @@ func (er *EvalResult) setValueCast(v sqltypes.Value, typ querypb.Type) error {
 	return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "coercion should not try to coerce this value: %v", v)
 }
 
-func (er *EvalResult) setBindVar1(typ querypb.Type, value []byte, collation collations.TypedCollation) {
+func (er *EvalResult) setBindVar1(typ sqltypes.Type, value []byte, collation collations.TypedCollation) {
 	switch typ {
 	case sqltypes.Int64:
 		ival, err := strconv.ParseInt(string(value), 10, 64)
@@ -670,7 +669,7 @@ func (er *EvalResult) setBindVar1(typ querypb.Type, value []byte, collation coll
 }
 
 // CoerceTo takes two input types, and decides how they should be coerced before compared
-func CoerceTo(v1, v2 querypb.Type) (querypb.Type, error) {
+func CoerceTo(v1, v2 sqltypes.Type) (sqltypes.Type, error) {
 	if v1 == v2 {
 		return v1, nil
 	}
@@ -709,7 +708,7 @@ func CoerceTo(v1, v2 querypb.Type) (querypb.Type, error) {
 
 // NullsafeHashcode returns an int64 hashcode that is guaranteed to be the same
 // for two values that are considered equal by `NullsafeCompare`.
-func NullsafeHashcode(v sqltypes.Value, collation collations.ID, coerceType querypb.Type) (HashCode, error) {
+func NullsafeHashcode(v sqltypes.Value, collation collations.ID, coerceType sqltypes.Type) (HashCode, error) {
 	var cast EvalResult
 	if err := cast.setValueCast(v, coerceType); err != nil {
 		return 0, err
@@ -746,7 +745,7 @@ func (er *EvalResult) makeNumeric() {
 	if er.numeric() {
 		return
 	}
-	if er.typeof() == querypb.Type_VARBINARY && er.hasFlag(flagHex) {
+	if er.typeof() == sqltypes.VarBinary && er.hasFlag(flagHex) {
 		raw := er.bytes()
 		if len(raw) > 8 {
 			// overflow
@@ -776,7 +775,7 @@ func (er *EvalResult) makeNumeric() {
 func (er *EvalResult) negateNumeric() {
 	er.makeNumeric()
 	switch er.typeof() {
-	case querypb.Type_INT8, querypb.Type_INT16, querypb.Type_INT32, querypb.Type_INT64:
+	case sqltypes.Int8, sqltypes.Int16, sqltypes.Int32, sqltypes.Int64:
 		i := er.int64()
 		if i == math.MinInt64 {
 			dec := newDecimalInt64(i)
@@ -785,7 +784,7 @@ func (er *EvalResult) negateNumeric() {
 		} else {
 			er.setInt64(-i)
 		}
-	case querypb.Type_UINT8, querypb.Type_UINT16, querypb.Type_UINT32, querypb.Type_UINT64:
+	case sqltypes.Uint8, sqltypes.Uint16, sqltypes.Uint32, sqltypes.Uint64:
 		u := er.uint64()
 		if er.hasFlag(flagHex) {
 			er.setFloat(-float64(u))
@@ -796,9 +795,9 @@ func (er *EvalResult) negateNumeric() {
 		} else {
 			er.setInt64(-int64(u))
 		}
-	case querypb.Type_FLOAT32, querypb.Type_FLOAT64:
+	case sqltypes.Float32, sqltypes.Float64:
 		er.setFloat(-er.float64())
-	case querypb.Type_DECIMAL:
+	case sqltypes.Decimal:
 		dec := er.decimal()
 		if !dec.num.IsZero() {
 			dec.num.SetSignbit(!dec.num.Signbit())
@@ -880,7 +879,7 @@ func newEvalResultNumeric(v sqltypes.Value) (er EvalResult, err error) {
 	return
 }
 
-func newEvalRaw(typ querypb.Type, raw []byte) (er EvalResult) {
+func newEvalRaw(typ sqltypes.Type, raw []byte) (er EvalResult) {
 	er.setRaw(typ, raw, collations.TypedCollation{})
 	return
 }
diff --git a/go/vt/vtgate/evalengine/evalengine.go b/go/vt/vtgate/evalengine/evalengine.go
index 5e7bc70de1..b849fa149e 100644
--- a/go/vt/vtgate/evalengine/evalengine.go
+++ b/go/vt/vtgate/evalengine/evalengine.go
@@ -23,13 +23,12 @@ import (
 
 	"vitess.io/vitess/go/mysql/collations"
 	"vitess.io/vitess/go/sqltypes"
-	querypb "vitess.io/vitess/go/vt/proto/query"
 	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
 	"vitess.io/vitess/go/vt/vterrors"
 )
 
 // Cast converts a Value to the target type.
-func Cast(v sqltypes.Value, typ querypb.Type) (sqltypes.Value, error) {
+func Cast(v sqltypes.Value, typ sqltypes.Type) (sqltypes.Value, error) {
 	if v.Type() == typ || v.IsNull() {
 		return v, nil
 	}
diff --git a/go/vt/vtgate/evalengine/expressions.go b/go/vt/vtgate/evalengine/expressions.go
index 8a649e56a4..0a93602cd4 100644
--- a/go/vt/vtgate/evalengine/expressions.go
+++ b/go/vt/vtgate/evalengine/expressions.go
@@ -41,7 +41,7 @@ type (
 	// Expr is the interface that all evaluating expressions must implement
 	Expr interface {
 		eval(env *ExpressionEnv, result *EvalResult)
-		typeof(env *ExpressionEnv) querypb.Type
+		typeof(env *ExpressionEnv) sqltypes.Type
 		format(buf *formatter, depth int)
 		constant() bool
 		simplify(env *ExpressionEnv) error
@@ -54,7 +54,7 @@ type (
 	BindVariable struct {
 		Key        string
 		coll       collations.TypedCollation
-		coerceType querypb.Type
+		coerceType sqltypes.Type
 	}
 
 	Column struct {
@@ -104,7 +104,7 @@ func throwCardinalityError(expected int) {
 func (env *ExpressionEnv) cardinality(expr Expr) int {
 	switch expr := expr.(type) {
 	case *BindVariable:
-		if expr.typeof(env) == querypb.Type_TUPLE {
+		if expr.typeof(env) == sqltypes.Tuple {
 			return len(expr.bvar(env).Values)
 		}
 		return 1
@@ -126,7 +126,7 @@ func (env *ExpressionEnv) ensureCardinality(expr Expr, expected int) {
 func (env *ExpressionEnv) subexpr(expr Expr, nth int) (Expr, int) {
 	switch expr := expr.(type) {
 	case *BindVariable:
-		if expr.typeof(env) == querypb.Type_TUPLE {
+		if expr.typeof(env) == sqltypes.Tuple {
 			return nil, 1
 		}
 	case TupleExpr:
@@ -183,7 +183,7 @@ func (env *ExpressionEnv) typecheck(expr Expr) {
 		left := env.cardinality(expr.Left)
 		right := env.cardinality(expr.Right)
 
-		if expr.Right.typeof(env) != querypb.Type_TUPLE {
+		if expr.Right.typeof(env) != sqltypes.Tuple {
 			throwEvalError(vterrors.Errorf(vtrpcpb.Code_INTERNAL, "rhs of an In operation should be a tuple"))
 		}
 
@@ -230,7 +230,7 @@ func (env *ExpressionEnv) Evaluate(expr Expr) (er EvalResult, err error) {
 	return
 }
 
-func (env *ExpressionEnv) TypeOf(expr Expr) (ty querypb.Type, err error) {
+func (env *ExpressionEnv) TypeOf(expr Expr) (ty sqltypes.Type, err error) {
 	defer func() {
 		if r := recover(); r != nil {
 			if ee, ok := r.(evalError); ok {
@@ -442,7 +442,7 @@ func (bv *BindVariable) eval(env *ExpressionEnv, result *EvalResult) {
 	}
 
 	switch typ {
-	case querypb.Type_TUPLE:
+	case sqltypes.Tuple:
 		tuple := make([]EvalResult, len(bvar.Values))
 		for i, value := range bvar.Values {
 			tuple[i].setBindVar1(value.Type, value.Value, collations.TypedCollation{})
@@ -455,7 +455,7 @@ func (bv *BindVariable) eval(env *ExpressionEnv, result *EvalResult) {
 }
 
 // typeof implements the Expr interface
-func (bv *BindVariable) typeof(env *ExpressionEnv) querypb.Type {
+func (bv *BindVariable) typeof(env *ExpressionEnv) sqltypes.Type {
 	if bv.coerceType >= 0 {
 		return bv.coerceType
 	}
@@ -472,16 +472,16 @@ func (c *Column) eval(env *ExpressionEnv, result *EvalResult) {
 }
 
 // typeof implements the Expr interface
-func (l *Literal) typeof(*ExpressionEnv) querypb.Type {
+func (l *Literal) typeof(*ExpressionEnv) sqltypes.Type {
 	return l.Val.typeof()
 }
 
 // typeof implements the Expr interface
-func (t TupleExpr) typeof(*ExpressionEnv) querypb.Type {
-	return querypb.Type_TUPLE
+func (t TupleExpr) typeof(*ExpressionEnv) sqltypes.Type {
+	return sqltypes.Tuple
 }
 
-func (c *Column) typeof(env *ExpressionEnv) querypb.Type {
+func (c *Column) typeof(env *ExpressionEnv) sqltypes.Type {
 	value := env.Row[c.Offset]
 	return value.Type()
 }
diff --git a/go/vt/vtgate/evalengine/format.go b/go/vt/vtgate/evalengine/format.go
index f03ce42260..273f80f444 100644
--- a/go/vt/vtgate/evalengine/format.go
+++ b/go/vt/vtgate/evalengine/format.go
@@ -21,7 +21,7 @@ import (
 	"strings"
 
 	"vitess.io/vitess/go/mysql/collations"
-	querypb "vitess.io/vitess/go/vt/proto/query"
+	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/sqlparser"
 )
 
@@ -72,7 +72,7 @@ func (f *formatter) formatBinary(left Expr, op string, right Expr, depth int) {
 func (l *Literal) format(w *formatter, depth int) {
 	w.Indent(depth)
 	switch l.Val.typeof() {
-	case querypb.Type_TUPLE:
+	case sqltypes.Tuple:
 		w.WriteByte('(')
 		for i, val := range l.Val.TupleValues() {
 			if i > 0 {
diff --git a/go/vt/vtgate/evalengine/func.go b/go/vt/vtgate/evalengine/func.go
index 9b2df8d7e7..26b25adfec 100644
--- a/go/vt/vtgate/evalengine/func.go
+++ b/go/vt/vtgate/evalengine/func.go
@@ -22,10 +22,18 @@ import (
 	"math"
 
 	"vitess.io/vitess/go/mysql/collations"
-	querypb "vitess.io/vitess/go/vt/proto/query"
+	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/sqlparser"
 )
 
+var builtinFunctions = map[string]func(*ExpressionEnv, []EvalResult, *EvalResult){
+	"coalesce":  builtinFuncCoalesce,
+	"greatest":  builtinFuncGreatest,
+	"least":     builtinFuncLeast,
+	"collation": builtinFuncCollation,
+	"isnull":    builtinFuncIsNull,
+}
+
 type CallExpr struct {
 	Arguments TupleExpr
 	Aliases   []sqlparser.ColIdent
@@ -33,7 +41,7 @@ type CallExpr struct {
 	Call      func(*ExpressionEnv, []EvalResult, *EvalResult)
 }
 
-func (c *CallExpr) typeof(*ExpressionEnv) querypb.Type {
+func (c *CallExpr) typeof(*ExpressionEnv) sqltypes.Type {
 	return -1
 }
 
@@ -79,25 +87,25 @@ func getMultiComparisonFunc(args []EvalResult) multiComparisonFunc {
 	for i := range args {
 		arg := &args[i]
 		switch arg.typeof() {
-		case querypb.Type_NULL_TYPE:
+		case sqltypes.Null:
 			return func(args []EvalResult, result *EvalResult, cmp int) {
 				result.setNull()
 			}
-		case querypb.Type_INT8, querypb.Type_INT16, querypb.Type_INT32, querypb.Type_INT64:
+		case sqltypes.Int8, sqltypes.Int16, sqltypes.Int32, sqltypes.Int64:
 			integers++
-		case querypb.Type_UINT8, querypb.Type_UINT16, querypb.Type_UINT32, querypb.Type_UINT64:
+		case sqltypes.Uint8, sqltypes.Uint16, sqltypes.Uint32, sqltypes.Uint64:
 			if arg.uint64() > math.MaxInt64 {
 				decimals++
 			} else {
 				integers++
 			}
-		case querypb.Type_FLOAT32, querypb.Type_FLOAT64:
+		case sqltypes.Float32, sqltypes.Float64:
 			floats++
-		case querypb.Type_DECIMAL:
+		case sqltypes.Decimal:
 			decimals++
-		case querypb.Type_TEXT, querypb.Type_VARCHAR:
+		case sqltypes.Text, sqltypes.VarChar:
 			text++
-		case querypb.Type_BLOB, querypb.Type_BINARY, querypb.Type_VARBINARY:
+		case sqltypes.Blob, sqltypes.Binary, sqltypes.VarBinary:
 			binary++
 		}
 	}
@@ -197,7 +205,7 @@ func compareAllText(args []EvalResult, result *EvalResult, cmp int) {
 		}
 	}
 
-	result.setRaw(querypb.Type_VARCHAR, candidateB, collationB)
+	result.setRaw(sqltypes.VarChar, candidateB, collationB)
 }
 
 func compareAllBinary(args []EvalResult, result *EvalResult, cmp int) {
@@ -210,7 +218,7 @@ func compareAllBinary(args []EvalResult, result *EvalResult, cmp int) {
 		}
 	}
 
-	result.setRaw(querypb.Type_VARBINARY, candidateB, collationBinary)
+	result.setRaw(sqltypes.VarBinary, candidateB, collationBinary)
 }
 
 func throwArgError(fname string) {
@@ -243,3 +251,10 @@ func builtinFuncCollation(env *ExpressionEnv, args []EvalResult, result *EvalRes
 		Repertoire:   collations.RepertoireASCII,
 	})
 }
+
+func builtinFuncIsNull(_ *ExpressionEnv, args []EvalResult, result *EvalResult) {
+	if len(args) != 1 {
+		throwArgError("ISNULL")
+	}
+	result.setBool(args[0].null())
+}
diff --git a/go/vt/vtgate/evalengine/logical.go b/go/vt/vtgate/evalengine/logical.go
index 762136dfc1..6702753a23 100644
--- a/go/vt/vtgate/evalengine/logical.go
+++ b/go/vt/vtgate/evalengine/logical.go
@@ -17,7 +17,7 @@ limitations under the License.
 package evalengine
 
 import (
-	querypb "vitess.io/vitess/go/vt/proto/query"
+	"vitess.io/vitess/go/sqltypes"
 	"vitess.io/vitess/go/vt/sqlparser"
 )
 
@@ -130,22 +130,22 @@ func (n *NotExpr) eval(env *ExpressionEnv, out *EvalResult) {
 	out.setBoolean(inner.truthy().not())
 }
 
-func (n *NotExpr) typeof(*ExpressionEnv) querypb.Type {
-	return querypb.Type_UINT64
+func (n *NotExpr) typeof(*ExpressionEnv) sqltypes.Type {
+	return sqltypes.Uint64
 }
 
 func (l *LogicalExpr) eval(env *ExpressionEnv, out *EvalResult) {
 	var left, right EvalResult
 	left.init(env, l.Left)
 	right.init(env, l.Right)
-	if left.typeof() == querypb.Type_TUPLE || right.typeof() == querypb.Type_TUPLE {
+	if left.typeof() == sqltypes.Tuple || right.typeof() == sqltypes.Tuple {
 		panic("did not typecheck tuples")
 	}
 	out.setBoolean(l.op(left.truthy(), right.truthy()))
 }
 
-func (l *LogicalExpr) typeof(env *ExpressionEnv) querypb.Type {
-	return querypb.Type_UINT64
+func (l *LogicalExpr) typeof(env *ExpressionEnv) sqltypes.Type {
+	return sqltypes.Uint64
 }
 
 // IsExpr represents the IS expression in MySQL.
@@ -164,6 +164,6 @@ func (i *IsExpr) eval(env *ExpressionEnv, result *EvalResult) {
 	result.setBool(i.Check(&in))
 }
 
-func (i *IsExpr) typeof(env *ExpressionEnv) querypb.Type {
-	return querypb.Type_INT64
+func (i *IsExpr) typeof(env *ExpressionEnv) sqltypes.Type {
+	return sqltypes.Int64
 }
diff --git a/go/vt/vtgate/evalengine/simplify.go b/go/vt/vtgate/evalengine/simplify.go
index 1638b9eeb9..b6be921190 100644
--- a/go/vt/vtgate/evalengine/simplify.go
+++ b/go/vt/vtgate/evalengine/simplify.go
@@ -18,7 +18,7 @@ package evalengine
 
 import (
 	"vitess.io/vitess/go/mysql/collations"
-	querypb "vitess.io/vitess/go/vt/proto/query"
+	"vitess.io/vitess/go/sqltypes"
 )
 
 func (expr *Literal) constant() bool {
@@ -101,7 +101,7 @@ func (inexpr *InExpr) simplify(env *ExpressionEnv) error {
 
 	var (
 		collation collations.ID
-		typ       querypb.Type
+		typ       sqltypes.Type
 		optimize  = true
 	)
 
diff --git a/go/vt/vtgate/evalengine/unary.go b/go/vt/vtgate/evalengine/unary.go
index 5f063702a0..c7c9aadf49 100644
--- a/go/vt/vtgate/evalengine/unary.go
+++ b/go/vt/vtgate/evalengine/unary.go
@@ -16,7 +16,7 @@ limitations under the License.
 
 package evalengine
 
-import querypb "vitess.io/vitess/go/vt/proto/query"
+import "vitess.io/vitess/go/sqltypes"
 
 type (
 	UnaryExpr struct {
@@ -28,7 +28,7 @@ type (
 	}
 )
 
-func (c *UnaryExpr) typeof(env *ExpressionEnv) querypb.Type {
+func (c *UnaryExpr) typeof(env *ExpressionEnv) sqltypes.Type {
 	return c.Inner.typeof(env)
 }
 
@@ -37,7 +37,7 @@ func (n *NegateExpr) eval(env *ExpressionEnv, result *EvalResult) {
 	result.negateNumeric()
 }
 
-func (n *NegateExpr) typeof(env *ExpressionEnv) querypb.Type {
+func (n *NegateExpr) typeof(env *ExpressionEnv) sqltypes.Type {
 	// the type of a NegateExpr is not known beforehand because negating
 	// a large enough value can cause it to be upcasted into a larger type
 	return -1
diff --git a/go/vt/vtgate/planbuilder/horizon_planning.go b/go/vt/vtgate/planbuilder/horizon_planning.go
index 1ac8fb25a3..7bee6f7705 100644
--- a/go/vt/vtgate/planbuilder/horizon_planning.go
+++ b/go/vt/vtgate/planbuilder/horizon_planning.go
@@ -511,14 +511,17 @@ func (hp *horizonPlanning) planAggregations(ctx *plancontext.PlanningContext, pl
 			return nil, err
 		}
 
-		pushExpr, param := hp.createPushExprAndAlias(ctx, e, handleDistinct, innerAliased, opcode, oa)
+		pushExpr, alias, opcode := hp.createPushExprAndAlias(e, handleDistinct, innerAliased, opcode, oa)
 		offset, _, err := pushProjection(ctx, pushExpr, plan, true, false, true)
 		if err != nil {
 			return nil, err
 		}
-		param.Col = offset
-		param.Expr = fExpr
-		oa.eaggr.Aggregates = append(oa.eaggr.Aggregates, param)
+		oa.eaggr.Aggregates = append(oa.eaggr.Aggregates, &engine.AggregateParams{
+			Opcode: opcode,
+			Col:    offset,
+			Alias:  alias,
+			Expr:   fExpr,
+		})
 	}
 
 	for _, groupExpr := range hp.qp.GroupByExprs {
@@ -574,16 +577,15 @@ func (hp *horizonPlanning) planAggregations(ctx *plancontext.PlanningContext, pl
 // createPushExprAndAlias creates the expression that should be pushed down to the leaves,
 // and changes the opcode so it is a distinct one if needed
 func (hp *horizonPlanning) createPushExprAndAlias(
-	ctx *plancontext.PlanningContext,
 	expr abstract.SelectExpr,
 	handleDistinct bool,
 	innerAliased *sqlparser.AliasedExpr,
 	opcode engine.AggregateOpcode,
 	oa *orderedAggregate,
-) (*sqlparser.AliasedExpr, *engine.AggregateParams) {
+) (*sqlparser.AliasedExpr, string, engine.AggregateOpcode) {
 	aliasExpr, isAlias := expr.Col.(*sqlparser.AliasedExpr)
 	if !isAlias {
-		return nil, nil
+		return nil, "", 0
 	}
 	var alias string
 	if aliasExpr.As.IsEmpty() {
@@ -609,17 +611,7 @@ func (hp *horizonPlanning) createPushExprAndAlias(
 		}
 		hp.qp.GroupByExprs = append(hp.qp.GroupByExprs, by)
 	}
-	collID := collations.Unknown
-	if innerAliased != nil {
-		collID = ctx.SemTable.CollationForExpr(innerAliased.Expr)
-	}
-
-	param := &engine.AggregateParams{
-		Opcode:      opcode,
-		Alias:       alias,
-		CollationID: collID,
-	}
-	return aliasExpr, param
+	return aliasExpr, alias, opcode
 }
 
 func hasUniqueVindex(vschema plancontext.VSchema, semTable *semantics.SemTable, groupByExprs []abstract.GroupBy) bool {
@@ -1164,12 +1156,7 @@ func selectHasUniqueVindex(vschema plancontext.VSchema, semTable *semantics.SemT
 // needDistinctHandling returns true if oa needs to handle the distinct clause.
 // If true, it will also return the aliased expression that needs to be pushed
 // down into the underlying route.
-func (hp *horizonPlanning) needDistinctHandling(
-	ctx *plancontext.PlanningContext,
-	funcExpr *sqlparser.FuncExpr,
-	opcode engine.AggregateOpcode,
-	input logicalPlan,
-) (bool, *sqlparser.AliasedExpr, error) {
+func (hp *horizonPlanning) needDistinctHandling(ctx *plancontext.PlanningContext, funcExpr *sqlparser.FuncExpr, opcode engine.AggregateOpcode, input logicalPlan) (bool, *sqlparser.AliasedExpr, error) {
 	if !funcExpr.Distinct {
 		return false, nil, nil
 	}
diff --git a/go/vt/vtgate/planbuilder/ordered_aggregate.go b/go/vt/vtgate/planbuilder/ordered_aggregate.go
index 8cc037d6ac..bb7f058d8d 100644
--- a/go/vt/vtgate/planbuilder/ordered_aggregate.go
+++ b/go/vt/vtgate/planbuilder/ordered_aggregate.go
@@ -20,8 +20,6 @@ import (
 	"fmt"
 	"strconv"
 
-	"vitess.io/vitess/go/mysql/collations"
-
 	"vitess.io/vitess/go/sqltypes"
 
 	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
@@ -335,18 +333,6 @@ func (oa *orderedAggregate) Wireup(plan logicalPlan, jt *jointab) error {
 }
 
 func (oa *orderedAggregate) WireupGen4(semTable *semantics.SemTable) error {
-	colls := map[int]collations.ID{}
-	oa.eaggr.Collations = colls
-	for _, key := range oa.eaggr.Aggregates {
-		if key.CollationID != collations.Unknown {
-			colls[key.KeyCol] = key.CollationID
-		}
-	}
-	for _, key := range oa.eaggr.GroupByKeys {
-		if key.CollationID != collations.Unknown {
-			colls[key.KeyCol] = key.CollationID
-		}
-	}
 	return oa.input.WireupGen4(semTable)
 }
 


Test patch:
diff --git a/go/vt/vtgate/engine/ordered_aggregate_test.go b/go/vt/vtgate/engine/ordered_aggregate_test.go
index 3de0ca0f9e..baf686a250 100644
--- a/go/vt/vtgate/engine/ordered_aggregate_test.go
+++ b/go/vt/vtgate/engine/ordered_aggregate_test.go
@@ -1084,7 +1084,6 @@ func TestOrderedAggregateCollate(t *testing.T) {
 		}},
 		GroupByKeys: []*GroupByParams{{KeyCol: 0, CollationID: collationID}},
 		Input:       fp,
-		Collations:  map[int]collations.ID{0: collationID},
 	}
 
 	result, err := oa.TryExecute(&noopVCursor{}, nil, false)
@@ -1126,7 +1125,6 @@ func TestOrderedAggregateCollateAS(t *testing.T) {
 			Col:    1,
 		}},
 		GroupByKeys: []*GroupByParams{{KeyCol: 0, CollationID: collationID}},
-		Collations:  map[int]collations.ID{0: collationID},
 		Input:       fp,
 	}
 
@@ -1171,7 +1169,6 @@ func TestOrderedAggregateCollateKS(t *testing.T) {
 			Col:    1,
 		}},
 		GroupByKeys: []*GroupByParams{{KeyCol: 0, CollationID: collationID}},
-		Collations:  map[int]collations.ID{0: collationID},
 		Input:       fp,
 	}
 
diff --git a/go/vt/vtgate/evalengine/arithmetic_expr_test.go b/go/vt/vtgate/evalengine/arithmetic_expr_test.go
index 5a6fc21087..e57a4f5a88 100644
--- a/go/vt/vtgate/evalengine/arithmetic_expr_test.go
+++ b/go/vt/vtgate/evalengine/arithmetic_expr_test.go
@@ -24,15 +24,13 @@ import (
 	"github.com/stretchr/testify/assert"
 
 	"vitess.io/vitess/go/sqltypes"
-
-	querypb "vitess.io/vitess/go/vt/proto/query"
 )
 
 // more tests in go/sqlparser/expressions_test.go
 
 func TestBinaryOpTypes(t *testing.T) {
 	type testcase struct {
-		l, r, e querypb.Type
+		l, r, e sqltypes.Type
 	}
 	type ops struct {
 		op        ArithmeticOp
diff --git a/go/vt/vtgate/evalengine/arithmetic_test.go b/go/vt/vtgate/evalengine/arithmetic_test.go
index 86ac17b793..db72c314ed 100644
--- a/go/vt/vtgate/evalengine/arithmetic_test.go
+++ b/go/vt/vtgate/evalengine/arithmetic_test.go
@@ -32,7 +32,6 @@ import (
 
 	"vitess.io/vitess/go/sqltypes"
 
-	querypb "vitess.io/vitess/go/vt/proto/query"
 	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
 	"vitess.io/vitess/go/vt/vterrors"
 )
@@ -106,22 +105,22 @@ func TestArithmetics(t *testing.T) {
 			v2:  NewUint64(0),
 			err: dataOutOfRangeError(math.MinInt64, 0, "BIGINT UNSIGNED", "-").Error(),
 		}, {
-			v1:  TestValue(querypb.Type_VARCHAR, "c"),
+			v1:  TestValue(sqltypes.VarChar, "c"),
 			v2:  NewInt64(1),
 			out: NewFloat64(-1),
 		}, {
 			v1:  NewUint64(1),
-			v2:  TestValue(querypb.Type_VARCHAR, "c"),
+			v2:  TestValue(sqltypes.VarChar, "c"),
 			out: NewFloat64(1),
 		}, {
 			// testing for error for parsing float value to uint64
-			v1:  TestValue(querypb.Type_UINT64, "1.2"),
+			v1:  TestValue(sqltypes.Uint64, "1.2"),
 			v2:  NewInt64(2),
 			err: "strconv.ParseUint: parsing \"1.2\": invalid syntax",
 		}, {
 			// testing for error for parsing float value to uint64
 			v1:  NewUint64(2),
-			v2:  TestValue(querypb.Type_UINT64, "1.2"),
+			v2:  TestValue(sqltypes.Uint64, "1.2"),
 			err: "strconv.ParseUint: parsing \"1.2\": invalid syntax",
 		}, {
 			// uint64 - uint64
@@ -244,19 +243,19 @@ func TestArithmetics(t *testing.T) {
 			out: NewUint64(9223372036854775808),
 		}, {
 			v1:  NewUint64(1),
-			v2:  TestValue(querypb.Type_VARCHAR, "c"),
+			v2:  TestValue(sqltypes.VarChar, "c"),
 			out: NewFloat64(1),
 		}, {
 			v1:  NewUint64(1),
-			v2:  TestValue(querypb.Type_VARCHAR, "1.2"),
+			v2:  TestValue(sqltypes.VarChar, "1.2"),
 			out: NewFloat64(2.2),
 		}, {
-			v1:  TestValue(querypb.Type_INT64, "1.2"),
+			v1:  TestValue(sqltypes.Int64, "1.2"),
 			v2:  NewInt64(2),
 			err: "strconv.ParseInt: parsing \"1.2\": invalid syntax",
 		}, {
 			v1:  NewInt64(2),
-			v2:  TestValue(querypb.Type_INT64, "1.2"),
+			v2:  TestValue(sqltypes.Int64, "1.2"),
 			err: "strconv.ParseInt: parsing \"1.2\": invalid syntax",
 		}, {
 			// testing for uint64 overflow with max uint64 + int value
@@ -314,13 +313,13 @@ func TestArithmetics(t *testing.T) {
 			out: NewDecimal(strconv.FormatUint(math.MaxUint64, 10) + ".0000"),
 		}, {
 			// testing for error in types
-			v1:  TestValue(querypb.Type_INT64, "1.2"),
+			v1:  TestValue(sqltypes.Int64, "1.2"),
 			v2:  NewInt64(2),
 			err: "strconv.ParseInt: parsing \"1.2\": invalid syntax",
 		}, {
 			// testing for error in types
 			v1:  NewInt64(2),
-			v2:  TestValue(querypb.Type_INT64, "1.2"),
+			v2:  TestValue(sqltypes.Int64, "1.2"),
 			err: "strconv.ParseInt: parsing \"1.2\": invalid syntax",
 		}, {
 			// testing for uint/int
@@ -334,12 +333,12 @@ func TestArithmetics(t *testing.T) {
 			out: NewDecimal("0.5000"),
 		}, {
 			// testing for float64/int64
-			v1:  TestValue(querypb.Type_FLOAT64, "1.2"),
+			v1:  TestValue(sqltypes.Float64, "1.2"),
 			v2:  NewInt64(-2),
 			out: NewFloat64(-0.6),
 		}, {
 			// testing for float64/uint64
-			v1:  TestValue(querypb.Type_FLOAT64, "1.2"),
+			v1:  TestValue(sqltypes.Float64, "1.2"),
 			v2:  NewUint64(2),
 			out: NewFloat64(0.6),
 		}, {
@@ -378,13 +377,13 @@ func TestArithmetics(t *testing.T) {
 			out: NewInt64(math.MinInt64),
 		}, {
 			// testing for error in types
-			v1:  TestValue(querypb.Type_INT64, "1.2"),
+			v1:  TestValue(sqltypes.Int64, "1.2"),
 			v2:  NewInt64(2),
 			err: "strconv.ParseInt: parsing \"1.2\": invalid syntax",
 		}, {
 			// testing for error in types
 			v1:  NewInt64(2),
-			v2:  TestValue(querypb.Type_INT64, "1.2"),
+			v2:  TestValue(sqltypes.Int64, "1.2"),
 			err: "strconv.ParseInt: parsing \"1.2\": invalid syntax",
 		}, {
 			// testing for uint*int
@@ -398,12 +397,12 @@ func TestArithmetics(t *testing.T) {
 			out: NewUint64(2),
 		}, {
 			// testing for float64*int64
-			v1:  TestValue(querypb.Type_FLOAT64, "1.2"),
+			v1:  TestValue(sqltypes.Float64, "1.2"),
 			v2:  NewInt64(-2),
 			out: NewFloat64(-2.4),
 		}, {
 			// testing for float64*uint64
-			v1:  TestValue(querypb.Type_FLOAT64, "1.2"),
+			v1:  TestValue(sqltypes.Float64, "1.2"),
 			v2:  NewUint64(2),
 			out: NewFloat64(2.4),
 		}, {
@@ -473,13 +472,13 @@ func TestNullSafeAdd(t *testing.T) {
 		out: NewInt64(3),
 	}, {
 		// Make sure underlying error is returned for LHS.
-		v1:  TestValue(querypb.Type_INT64, "1.2"),
+		v1:  TestValue(sqltypes.Int64, "1.2"),
 		v2:  NewInt64(2),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseInt: parsing \"1.2\": invalid syntax"),
 	}, {
 		// Make sure underlying error is returned for RHS.
 		v1:  NewInt64(2),
-		v2:  TestValue(querypb.Type_INT64, "1.2"),
+		v2:  TestValue(sqltypes.Int64, "1.2"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseInt: parsing \"1.2\": invalid syntax"),
 	}, {
 		// Make sure underlying error is returned while adding.
@@ -497,7 +496,7 @@ func TestNullSafeAdd(t *testing.T) {
 		out: NewInt64(3),
 	}}
 	for _, tcase := range tcases {
-		got, err := NullSafeAdd(tcase.v1, tcase.v2, querypb.Type_INT64)
+		got, err := NullSafeAdd(tcase.v1, tcase.v2, sqltypes.Int64)
 
 		if tcase.err == nil {
 			require.NoError(t, err)
@@ -534,18 +533,18 @@ func TestNullsafeCompare(t *testing.T) {
 		out: 1,
 	}, {
 		// LHS Text
-		v1:  TestValue(querypb.Type_VARCHAR, "abcd"),
-		v2:  TestValue(querypb.Type_VARCHAR, "abcd"),
+		v1:  TestValue(sqltypes.VarChar, "abcd"),
+		v2:  TestValue(sqltypes.VarChar, "abcd"),
 		out: 0,
 	}, {
 		// Make sure underlying error is returned for LHS.
-		v1:  TestValue(querypb.Type_INT64, "1.2"),
+		v1:  TestValue(sqltypes.Int64, "1.2"),
 		v2:  NewInt64(2),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseInt: parsing \"1.2\": invalid syntax"),
 	}, {
 		// Make sure underlying error is returned for RHS.
 		v1:  NewInt64(2),
-		v2:  TestValue(querypb.Type_INT64, "1.2"),
+		v2:  TestValue(sqltypes.Int64, "1.2"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseInt: parsing \"1.2\": invalid syntax"),
 	}, {
 		// Numeric equal.
@@ -559,43 +558,43 @@ func TestNullsafeCompare(t *testing.T) {
 		out: -1,
 	}, {
 		// Non-numeric equal
-		v1:  TestValue(querypb.Type_VARBINARY, "abcd"),
-		v2:  TestValue(querypb.Type_BINARY, "abcd"),
+		v1:  TestValue(sqltypes.VarBinary, "abcd"),
+		v2:  TestValue(sqltypes.Binary, "abcd"),
 		out: 0,
 	}, {
 		// Non-numeric unequal
-		v1:  TestValue(querypb.Type_VARBINARY, "abcd"),
-		v2:  TestValue(querypb.Type_BINARY, "bcde"),
+		v1:  TestValue(sqltypes.VarBinary, "abcd"),
+		v2:  TestValue(sqltypes.Binary, "bcde"),
 		out: -1,
 	}, {
 		// Date/Time types
-		v1:  TestValue(querypb.Type_DATETIME, "1000-01-01 00:00:00"),
-		v2:  TestValue(querypb.Type_BINARY, "1000-01-01 00:00:00"),
+		v1:  TestValue(sqltypes.Datetime, "1000-01-01 00:00:00"),
+		v2:  TestValue(sqltypes.Binary, "1000-01-01 00:00:00"),
 		out: 0,
 	}, {
 		// Date/Time types
-		v1:  TestValue(querypb.Type_DATETIME, "2000-01-01 00:00:00"),
-		v2:  TestValue(querypb.Type_BINARY, "1000-01-01 00:00:00"),
+		v1:  TestValue(sqltypes.Datetime, "2000-01-01 00:00:00"),
+		v2:  TestValue(sqltypes.Binary, "1000-01-01 00:00:00"),
 		out: 1,
 	}, {
 		// Date/Time types
-		v1:  TestValue(querypb.Type_DATETIME, "1000-01-01 00:00:00"),
-		v2:  TestValue(querypb.Type_BINARY, "2000-01-01 00:00:00"),
+		v1:  TestValue(sqltypes.Datetime, "1000-01-01 00:00:00"),
+		v2:  TestValue(sqltypes.Binary, "2000-01-01 00:00:00"),
 		out: -1,
 	}, {
 		// Date/Time types
-		v1:  TestValue(querypb.Type_BIT, "101"),
-		v2:  TestValue(querypb.Type_BIT, "101"),
+		v1:  TestValue(sqltypes.Bit, "101"),
+		v2:  TestValue(sqltypes.Bit, "101"),
 		out: 0,
 	}, {
 		// Date/Time types
-		v1:  TestValue(querypb.Type_BIT, "1"),
-		v2:  TestValue(querypb.Type_BIT, "0"),
+		v1:  TestValue(sqltypes.Bit, "1"),
+		v2:  TestValue(sqltypes.Bit, "0"),
 		out: 1,
 	}, {
 		// Date/Time types
-		v1:  TestValue(querypb.Type_BIT, "0"),
-		v2:  TestValue(querypb.Type_BIT, "1"),
+		v1:  TestValue(sqltypes.Bit, "0"),
+		v2:  TestValue(sqltypes.Bit, "1"),
 		out: -1,
 	}}
 	for _, tcase := range tcases {
@@ -688,7 +687,7 @@ func TestNullsafeCompareCollate(t *testing.T) {
 		},
 	}
 	for _, tcase := range tcases {
-		got, err := NullsafeCompare(TestValue(querypb.Type_VARCHAR, tcase.v1), TestValue(querypb.Type_VARCHAR, tcase.v2), tcase.collation)
+		got, err := NullsafeCompare(TestValue(sqltypes.VarChar, tcase.v1), TestValue(sqltypes.VarChar, tcase.v2), tcase.collation)
 		if !vterrors.Equals(err, tcase.err) {
 			t.Errorf("NullsafeCompare(%v, %v) error: %v, want %v", tcase.v1, tcase.v2, vterrors.Print(err), vterrors.Print(tcase.err))
 		}
@@ -704,84 +703,84 @@ func TestNullsafeCompareCollate(t *testing.T) {
 
 func TestCast(t *testing.T) {
 	tcases := []struct {
-		typ querypb.Type
+		typ sqltypes.Type
 		v   sqltypes.Value
 		out sqltypes.Value
 		err error
 	}{{
-		typ: querypb.Type_VARCHAR,
+		typ: sqltypes.VarChar,
 		v:   NULL,
 		out: NULL,
 	}, {
-		typ: querypb.Type_VARCHAR,
-		v:   TestValue(querypb.Type_VARCHAR, "exact types"),
-		out: TestValue(querypb.Type_VARCHAR, "exact types"),
+		typ: sqltypes.VarChar,
+		v:   TestValue(sqltypes.VarChar, "exact types"),
+		out: TestValue(sqltypes.VarChar, "exact types"),
 	}, {
-		typ: querypb.Type_INT64,
-		v:   TestValue(querypb.Type_INT32, "32"),
-		out: TestValue(querypb.Type_INT64, "32"),
+		typ: sqltypes.Int64,
+		v:   TestValue(sqltypes.Int32, "32"),
+		out: TestValue(sqltypes.Int64, "32"),
 	}, {
-		typ: querypb.Type_INT24,
-		v:   TestValue(querypb.Type_UINT64, "64"),
-		out: TestValue(querypb.Type_INT24, "64"),
+		typ: sqltypes.Int24,
+		v:   TestValue(sqltypes.Uint64, "64"),
+		out: TestValue(sqltypes.Int24, "64"),
 	}, {
-		typ: querypb.Type_INT24,
-		v:   TestValue(querypb.Type_VARCHAR, "bad int"),
+		typ: sqltypes.Int24,
+		v:   TestValue(sqltypes.VarChar, "bad int"),
 		err: vterrors.New(vtrpcpb.Code_UNKNOWN, `strconv.ParseInt: parsing "bad int": invalid syntax`),
 	}, {
-		typ: querypb.Type_UINT64,
-		v:   TestValue(querypb.Type_UINT32, "32"),
-		out: TestValue(querypb.Type_UINT64, "32"),
+		typ: sqltypes.Uint64,
+		v:   TestValue(sqltypes.Uint32, "32"),
+		out: TestValue(sqltypes.Uint64, "32"),
 	}, {
-		typ: querypb.Type_UINT24,
-		v:   TestValue(querypb.Type_INT64, "64"),
-		out: TestValue(querypb.Type_UINT24, "64"),
+		typ: sqltypes.Uint24,
+		v:   TestValue(sqltypes.Int64, "64"),
+		out: TestValue(sqltypes.Uint24, "64"),
 	}, {
-		typ: querypb.Type_UINT24,
-		v:   TestValue(querypb.Type_INT64, "-1"),
+		typ: sqltypes.Uint24,
+		v:   TestValue(sqltypes.Int64, "-1"),
 		err: vterrors.New(vtrpcpb.Code_UNKNOWN, `strconv.ParseUint: parsing "-1": invalid syntax`),
 	}, {
-		typ: querypb.Type_FLOAT64,
-		v:   TestValue(querypb.Type_INT64, "64"),
-		out: TestValue(querypb.Type_FLOAT64, "64"),
+		typ: sqltypes.Float64,
+		v:   TestValue(sqltypes.Int64, "64"),
+		out: TestValue(sqltypes.Float64, "64"),
 	}, {
-		typ: querypb.Type_FLOAT32,
-		v:   TestValue(querypb.Type_FLOAT64, "64"),
-		out: TestValue(querypb.Type_FLOAT32, "64"),
+		typ: sqltypes.Float32,
+		v:   TestValue(sqltypes.Float64, "64"),
+		out: TestValue(sqltypes.Float32, "64"),
 	}, {
-		typ: querypb.Type_FLOAT32,
-		v:   TestValue(querypb.Type_DECIMAL, "1.24"),
-		out: TestValue(querypb.Type_FLOAT32, "1.24"),
+		typ: sqltypes.Float32,
+		v:   TestValue(sqltypes.Decimal, "1.24"),
+		out: TestValue(sqltypes.Float32, "1.24"),
 	}, {
-		typ: querypb.Type_FLOAT64,
-		v:   TestValue(querypb.Type_VARCHAR, "1.25"),
-		out: TestValue(querypb.Type_FLOAT64, "1.25"),
+		typ: sqltypes.Float64,
+		v:   TestValue(sqltypes.VarChar, "1.25"),
+		out: TestValue(sqltypes.Float64, "1.25"),
 	}, {
-		typ: querypb.Type_FLOAT64,
-		v:   TestValue(querypb.Type_VARCHAR, "bad float"),
+		typ: sqltypes.Float64,
+		v:   TestValue(sqltypes.VarChar, "bad float"),
 		err: vterrors.New(vtrpcpb.Code_UNKNOWN, `strconv.ParseFloat: parsing "bad float": invalid syntax`),
 	}, {
-		typ: querypb.Type_VARCHAR,
-		v:   TestValue(querypb.Type_INT64, "64"),
-		out: TestValue(querypb.Type_VARCHAR, "64"),
+		typ: sqltypes.VarChar,
+		v:   TestValue(sqltypes.Int64, "64"),
+		out: TestValue(sqltypes.VarChar, "64"),
 	}, {
-		typ: querypb.Type_VARBINARY,
-		v:   TestValue(querypb.Type_FLOAT64, "64"),
-		out: TestValue(querypb.Type_VARBINARY, "64"),
+		typ: sqltypes.VarBinary,
+		v:   TestValue(sqltypes.Float64, "64"),
+		out: TestValue(sqltypes.VarBinary, "64"),
 	}, {
-		typ: querypb.Type_VARBINARY,
-		v:   TestValue(querypb.Type_DECIMAL, "1.24"),
-		out: TestValue(querypb.Type_VARBINARY, "1.24"),
+		typ: sqltypes.VarBinary,
+		v:   TestValue(sqltypes.Decimal, "1.24"),
+		out: TestValue(sqltypes.VarBinary, "1.24"),
 	}, {
-		typ: querypb.Type_VARBINARY,
-		v:   TestValue(querypb.Type_VARCHAR, "1.25"),
-		out: TestValue(querypb.Type_VARBINARY, "1.25"),
+		typ: sqltypes.VarBinary,
+		v:   TestValue(sqltypes.VarChar, "1.25"),
+		out: TestValue(sqltypes.VarBinary, "1.25"),
 	}, {
-		typ: querypb.Type_VARCHAR,
-		v:   TestValue(querypb.Type_VARBINARY, "valid string"),
-		out: TestValue(querypb.Type_VARCHAR, "valid string"),
+		typ: sqltypes.VarChar,
+		v:   TestValue(sqltypes.VarBinary, "valid string"),
+		out: TestValue(sqltypes.VarChar, "valid string"),
 	}, {
-		typ: querypb.Type_VARCHAR,
+		typ: sqltypes.VarChar,
 		v:   TestValue(sqltypes.Expression, "bad string"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "expression cannot be converted to bytes"),
 	}}
@@ -806,7 +805,7 @@ func TestToUint64(t *testing.T) {
 		out uint64
 		err error
 	}{{
-		v:   TestValue(querypb.Type_VARCHAR, "abcd"),
+		v:   TestValue(sqltypes.VarChar, "abcd"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "could not parse value: 'abcd'"),
 	}, {
 		v:   NewInt64(-1),
@@ -839,7 +838,7 @@ func TestToInt64(t *testing.T) {
 		out int64
 		err error
 	}{{
-		v:   TestValue(querypb.Type_VARCHAR, "abcd"),
+		v:   TestValue(sqltypes.VarChar, "abcd"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "could not parse value: 'abcd'"),
 	}, {
 		v:   NewUint64(18446744073709551615),
@@ -872,10 +871,10 @@ func TestToFloat64(t *testing.T) {
 		out float64
 		err error
 	}{{
-		v:   TestValue(querypb.Type_VARCHAR, "abcd"),
+		v:   TestValue(sqltypes.VarChar, "abcd"),
 		out: 0,
 	}, {
-		v:   TestValue(querypb.Type_VARCHAR, "1.2"),
+		v:   TestValue(sqltypes.VarChar, "1.2"),
 		out: 1.2,
 	}, {
 		v:   NewInt64(1),
@@ -887,7 +886,7 @@ func TestToFloat64(t *testing.T) {
 		v:   NewFloat64(1.2),
 		out: 1.2,
 	}, {
-		v:   TestValue(querypb.Type_INT64, "1.2"),
+		v:   TestValue(sqltypes.Int64, "1.2"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseInt: parsing \"1.2\": invalid syntax"),
 	}}
 	for _, tcase := range tcases {
@@ -910,85 +909,85 @@ func TestToNative(t *testing.T) {
 		in:  NULL,
 		out: nil,
 	}, {
-		in:  TestValue(querypb.Type_INT8, "1"),
+		in:  TestValue(sqltypes.Int8, "1"),
 		out: int64(1),
 	}, {
-		in:  TestValue(querypb.Type_INT16, "1"),
+		in:  TestValue(sqltypes.Int16, "1"),
 		out: int64(1),
 	}, {
-		in:  TestValue(querypb.Type_INT24, "1"),
+		in:  TestValue(sqltypes.Int24, "1"),
 		out: int64(1),
 	}, {
-		in:  TestValue(querypb.Type_INT32, "1"),
+		in:  TestValue(sqltypes.Int32, "1"),
 		out: int64(1),
 	}, {
-		in:  TestValue(querypb.Type_INT64, "1"),
+		in:  TestValue(sqltypes.Int64, "1"),
 		out: int64(1),
 	}, {
-		in:  TestValue(querypb.Type_UINT8, "1"),
+		in:  TestValue(sqltypes.Uint8, "1"),
 		out: uint64(1),
 	}, {
-		in:  TestValue(querypb.Type_UINT16, "1"),
+		in:  TestValue(sqltypes.Uint16, "1"),
 		out: uint64(1),
 	}, {
-		in:  TestValue(querypb.Type_UINT24, "1"),
+		in:  TestValue(sqltypes.Uint24, "1"),
 		out: uint64(1),
 	}, {
-		in:  TestValue(querypb.Type_UINT32, "1"),
+		in:  TestValue(sqltypes.Uint32, "1"),
 		out: uint64(1),
 	}, {
-		in:  TestValue(querypb.Type_UINT64, "1"),
+		in:  TestValue(sqltypes.Uint64, "1"),
 		out: uint64(1),
 	}, {
-		in:  TestValue(querypb.Type_FLOAT32, "1"),
+		in:  TestValue(sqltypes.Float32, "1"),
 		out: float64(1),
 	}, {
-		in:  TestValue(querypb.Type_FLOAT64, "1"),
+		in:  TestValue(sqltypes.Float64, "1"),
 		out: float64(1),
 	}, {
-		in:  TestValue(querypb.Type_TIMESTAMP, "2012-02-24 23:19:43"),
+		in:  TestValue(sqltypes.Timestamp, "2012-02-24 23:19:43"),
 		out: []byte("2012-02-24 23:19:43"),
 	}, {
-		in:  TestValue(querypb.Type_DATE, "2012-02-24"),
+		in:  TestValue(sqltypes.Date, "2012-02-24"),
 		out: []byte("2012-02-24"),
 	}, {
-		in:  TestValue(querypb.Type_TIME, "23:19:43"),
+		in:  TestValue(sqltypes.Time, "23:19:43"),
 		out: []byte("23:19:43"),
 	}, {
-		in:  TestValue(querypb.Type_DATETIME, "2012-02-24 23:19:43"),
+		in:  TestValue(sqltypes.Datetime, "2012-02-24 23:19:43"),
 		out: []byte("2012-02-24 23:19:43"),
 	}, {
-		in:  TestValue(querypb.Type_YEAR, "1"),
+		in:  TestValue(sqltypes.Year, "1"),
 		out: uint64(1),
 	}, {
-		in:  TestValue(querypb.Type_DECIMAL, "1"),
+		in:  TestValue(sqltypes.Decimal, "1"),
 		out: []byte("1"),
 	}, {
-		in:  TestValue(querypb.Type_TEXT, "a"),
+		in:  TestValue(sqltypes.Text, "a"),
 		out: []byte("a"),
 	}, {
-		in:  TestValue(querypb.Type_BLOB, "a"),
+		in:  TestValue(sqltypes.Blob, "a"),
 		out: []byte("a"),
 	}, {
-		in:  TestValue(querypb.Type_VARCHAR, "a"),
+		in:  TestValue(sqltypes.VarChar, "a"),
 		out: []byte("a"),
 	}, {
-		in:  TestValue(querypb.Type_VARBINARY, "a"),
+		in:  TestValue(sqltypes.VarBinary, "a"),
 		out: []byte("a"),
 	}, {
-		in:  TestValue(querypb.Type_CHAR, "a"),
+		in:  TestValue(sqltypes.Char, "a"),
 		out: []byte("a"),
 	}, {
-		in:  TestValue(querypb.Type_BINARY, "a"),
+		in:  TestValue(sqltypes.Binary, "a"),
 		out: []byte("a"),
 	}, {
-		in:  TestValue(querypb.Type_BIT, "1"),
+		in:  TestValue(sqltypes.Bit, "1"),
 		out: []byte("1"),
 	}, {
-		in:  TestValue(querypb.Type_ENUM, "a"),
+		in:  TestValue(sqltypes.Enum, "a"),
 		out: []byte("a"),
 	}, {
-		in:  TestValue(querypb.Type_SET, "a"),
+		in:  TestValue(sqltypes.Set, "a"),
 		out: []byte("a"),
 	}}
 	for _, tcase := range testcases {
@@ -1002,7 +1001,7 @@ func TestToNative(t *testing.T) {
 	}
 
 	// Test Expression failure.
-	_, err := ToNative(TestValue(querypb.Type_EXPRESSION, "aa"))
+	_, err := ToNative(TestValue(sqltypes.Expression, "aa"))
 	want := vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "EXPRESSION(aa) cannot be converted to a go type")
 	if !vterrors.Equals(err, want) {
 		t.Errorf("ToNative(EXPRESSION): %v, want %v", vterrors.Print(err), vterrors.Print(want))
@@ -1025,26 +1024,26 @@ func TestNewNumeric(t *testing.T) {
 		out: newEvalFloat(1.0),
 	}, {
 		// For non-number type, Int64 is the default.
-		v:   TestValue(querypb.Type_VARCHAR, "1"),
+		v:   TestValue(sqltypes.VarChar, "1"),
 		out: newEvalInt64(1),
 	}, {
 		// If Int64 can't work, we use Float64.
-		v:   TestValue(querypb.Type_VARCHAR, "1.2"),
+		v:   TestValue(sqltypes.VarChar, "1.2"),
 		out: newEvalFloat(1.2),
 	}, {
 		// Only valid Int64 allowed if type is Int64.
-		v:   TestValue(querypb.Type_INT64, "1.2"),
+		v:   TestValue(sqltypes.Int64, "1.2"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseInt: parsing \"1.2\": invalid syntax"),
 	}, {
 		// Only valid Uint64 allowed if type is Uint64.
-		v:   TestValue(querypb.Type_UINT64, "1.2"),
+		v:   TestValue(sqltypes.Uint64, "1.2"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseUint: parsing \"1.2\": invalid syntax"),
 	}, {
 		// Only valid Float64 allowed if type is Float64.
-		v:   TestValue(querypb.Type_FLOAT64, "abcd"),
+		v:   TestValue(sqltypes.Float64, "abcd"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseFloat: parsing \"abcd\": invalid syntax"),
 	}, {
-		v:   TestValue(querypb.Type_VARCHAR, "abcd"),
+		v:   TestValue(sqltypes.VarChar, "abcd"),
 		out: newEvalFloat(0),
 	}}
 	for _, tcase := range tcases {
@@ -1076,22 +1075,22 @@ func TestNewIntegralNumeric(t *testing.T) {
 		out: newEvalInt64(1),
 	}, {
 		// For non-number type, Int64 is the default.
-		v:   TestValue(querypb.Type_VARCHAR, "1"),
+		v:   TestValue(sqltypes.VarChar, "1"),
 		out: newEvalInt64(1),
 	}, {
 		// If Int64 can't work, we use Uint64.
-		v:   TestValue(querypb.Type_VARCHAR, "18446744073709551615"),
+		v:   TestValue(sqltypes.VarChar, "18446744073709551615"),
 		out: newEvalUint64(18446744073709551615),
 	}, {
 		// Only valid Int64 allowed if type is Int64.
-		v:   TestValue(querypb.Type_INT64, "1.2"),
+		v:   TestValue(sqltypes.Int64, "1.2"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseInt: parsing \"1.2\": invalid syntax"),
 	}, {
 		// Only valid Uint64 allowed if type is Uint64.
-		v:   TestValue(querypb.Type_UINT64, "1.2"),
+		v:   TestValue(sqltypes.Uint64, "1.2"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "strconv.ParseUint: parsing \"1.2\": invalid syntax"),
 	}, {
-		v:   TestValue(querypb.Type_VARCHAR, "abcd"),
+		v:   TestValue(sqltypes.VarChar, "abcd"),
 		err: vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "could not parse value: 'abcd'"),
 	}}
 	for _, tcase := range tcases {
@@ -1176,8 +1175,8 @@ func TestPrioritize(t *testing.T) {
 	ival := newEvalInt64(-1)
 	uval := newEvalUint64(1)
 	fval := newEvalFloat(1.2)
-	textIntval := newEvalRaw(querypb.Type_VARBINARY, []byte("-1"))
-	textFloatval := newEvalRaw(querypb.Type_VARBINARY, []byte("1.2"))
+	textIntval := newEvalRaw(sqltypes.VarBinary, []byte("-1"))
+	textFloatval := newEvalRaw(sqltypes.VarBinary, []byte("1.2"))
 
 	tcases := []struct {
 		v1, v2     EvalResult
@@ -1234,59 +1233,59 @@ func TestPrioritize(t *testing.T) {
 
 func TestToSqlValue(t *testing.T) {
 	tcases := []struct {
-		typ querypb.Type
+		typ sqltypes.Type
 		v   EvalResult
 		out sqltypes.Value
 		err error
 	}{{
-		typ: querypb.Type_INT64,
+		typ: sqltypes.Int64,
 		v:   newEvalInt64(1),
 		out: NewInt64(1),
 	}, {
-		typ: querypb.Type_INT64,
+		typ: sqltypes.Int64,
 		v:   newEvalUint64(1),
 		out: NewInt64(1),
 	}, {
-		typ: querypb.Type_INT64,
+		typ: sqltypes.Int64,
 		v:   newEvalFloat(1.2e-16),
 		out: NewInt64(0),
 	}, {
-		typ: querypb.Type_UINT64,
+		typ: sqltypes.Uint64,
 		v:   newEvalInt64(1),
 		out: NewUint64(1),
 	}, {
-		typ: querypb.Type_UINT64,
+		typ: sqltypes.Uint64,
 		v:   newEvalUint64(1),
 		out: NewUint64(1),
 	}, {
-		typ: querypb.Type_UINT64,
+		typ: sqltypes.Uint64,
 		v:   newEvalFloat(1.2e-16),
 		out: NewUint64(0),
 	}, {
-		typ: querypb.Type_FLOAT64,
+		typ: sqltypes.Float64,
 		v:   newEvalInt64(1),
-		out: TestValue(querypb.Type_FLOAT64, "1"),
+		out: TestValue(sqltypes.Float64, "1"),
 	}, {
-		typ: querypb.Type_FLOAT64,
+		typ: sqltypes.Float64,
 		v:   newEvalUint64(1),
-		out: TestValue(querypb.Type_FLOAT64, "1"),
+		out: TestValue(sqltypes.Float64, "1"),
 	}, {
-		typ: querypb.Type_FLOAT64,
+		typ: sqltypes.Float64,
 		v:   newEvalFloat(1.2e-16),
-		out: TestValue(querypb.Type_FLOAT64, "1.2e-16"),
+		out: TestValue(sqltypes.Float64, "1.2e-16"),
 	}, {
-		typ: querypb.Type_DECIMAL,
+		typ: sqltypes.Decimal,
 		v:   newEvalInt64(1),
-		out: TestValue(querypb.Type_DECIMAL, "1"),
+		out: TestValue(sqltypes.Decimal, "1"),
 	}, {
-		typ: querypb.Type_DECIMAL,
+		typ: sqltypes.Decimal,
 		v:   newEvalUint64(1),
-		out: TestValue(querypb.Type_DECIMAL, "1"),
+		out: TestValue(sqltypes.Decimal, "1"),
 	}, {
 		// For float, we should not use scientific notation.
-		typ: querypb.Type_DECIMAL,
+		typ: sqltypes.Decimal,
 		v:   newEvalFloat(1.2e-16),
-		out: TestValue(querypb.Type_DECIMAL, "0.00000000000000012"),
+		out: TestValue(sqltypes.Decimal, "0.00000000000000012"),
 	}}
 	for _, tcase := range tcases {
 		got := tcase.v.toSQLValue(tcase.typ)
@@ -1379,8 +1378,8 @@ func TestMin(t *testing.T) {
 		v2:  NewInt64(1),
 		min: NewInt64(1),
 	}, {
-		v1:  TestValue(querypb.Type_VARCHAR, "aa"),
-		v2:  TestValue(querypb.Type_VARCHAR, "aa"),
+		v1:  TestValue(sqltypes.VarChar, "aa"),
+		v2:  TestValue(sqltypes.VarChar, "aa"),
 		err: vterrors.New(vtrpcpb.Code_UNKNOWN, "cannot compare strings, collation is unknown or unsupported (collation ID: 0)"),
 	}}
 	for _, tcase := range tcases {
@@ -1442,7 +1441,7 @@ func TestMinCollate(t *testing.T) {
 		},
 	}
 	for _, tcase := range tcases {
-		got, err := Min(TestValue(querypb.Type_VARCHAR, tcase.v1), TestValue(querypb.Type_VARCHAR, tcase.v2), tcase.collation)
+		got, err := Min(TestValue(sqltypes.VarChar, tcase.v1), TestValue(sqltypes.VarChar, tcase.v2), tcase.collation)
 		if !vterrors.Equals(err, tcase.err) {
 			t.Errorf("NullsafeCompare(%v, %v) error: %v, want %v", tcase.v1, tcase.v2, vterrors.Print(err), vterrors.Print(tcase.err))
 		}
@@ -1486,8 +1485,8 @@ func TestMax(t *testing.T) {
 		v2:  NewInt64(1),
 		max: NewInt64(1),
 	}, {
-		v1:  TestValue(querypb.Type_VARCHAR, "aa"),
-		v2:  TestValue(querypb.Type_VARCHAR, "aa"),
+		v1:  TestValue(sqltypes.VarChar, "aa"),
+		v2:  TestValue(sqltypes.VarChar, "aa"),
 		err: vterrors.New(vtrpcpb.Code_UNKNOWN, "cannot compare strings, collation is unknown or unsupported (collation ID: 0)"),
 	}}
 	for _, tcase := range tcases {
@@ -1549,7 +1548,7 @@ func TestMaxCollate(t *testing.T) {
 		},
 	}
 	for _, tcase := range tcases {
-		got, err := Max(TestValue(querypb.Type_VARCHAR, tcase.v1), TestValue(querypb.Type_VARCHAR, tcase.v2), tcase.collation)
+		got, err := Max(TestValue(sqltypes.VarChar, tcase.v1), TestValue(sqltypes.VarChar, tcase.v2), tcase.collation)
 		if !vterrors.Equals(err, tcase.err) {
 			t.Errorf("NullsafeCompare(%v, %v) error: %v, want %v", tcase.v1, tcase.v2, vterrors.Print(err), vterrors.Print(tcase.err))
 		}
@@ -1586,20 +1585,20 @@ func printValue(v sqltypes.Value) string {
 // BenchmarkAddGoNonInterface-8    2000000000               1.00 ns/op
 // BenchmarkAddGo-8                2000000000               1.00 ns/op
 func BenchmarkAddActual(b *testing.B) {
-	v1 := sqltypes.MakeTrusted(querypb.Type_INT64, []byte("1"))
-	v2 := sqltypes.MakeTrusted(querypb.Type_INT64, []byte("12"))
+	v1 := sqltypes.MakeTrusted(sqltypes.Int64, []byte("1"))
+	v2 := sqltypes.MakeTrusted(sqltypes.Int64, []byte("12"))
 	for i := 0; i < b.N; i++ {
-		v1, _ = NullSafeAdd(v1, v2, querypb.Type_INT64)
+		v1, _ = NullSafeAdd(v1, v2, sqltypes.Int64)
 	}
 }
 
 func BenchmarkAddNoNative(b *testing.B) {
-	v1 := sqltypes.MakeTrusted(querypb.Type_INT64, []byte("1"))
-	v2 := sqltypes.MakeTrusted(querypb.Type_INT64, []byte("12"))
+	v1 := sqltypes.MakeTrusted(sqltypes.Int64, []byte("1"))
+	v2 := sqltypes.MakeTrusted(sqltypes.Int64, []byte("12"))
 	for i := 0; i < b.N; i++ {
 		iv1, _ := ToInt64(v1)
 		iv2, _ := ToInt64(v2)
-		v1 = sqltypes.MakeTrusted(querypb.Type_INT64, strconv.AppendInt(nil, iv1+iv2, 10))
+		v1 = sqltypes.MakeTrusted(sqltypes.Int64, strconv.AppendInt(nil, iv1+iv2, 10))
 	}
 }
 
@@ -1616,7 +1615,7 @@ func BenchmarkAddNative(b *testing.B) {
 func makeNativeInt64(v int64) sqltypes.Value {
 	buf := make([]byte, 8)
 	binary.BigEndian.PutUint64(buf, uint64(v))
-	return sqltypes.MakeTrusted(querypb.Type_INT64, buf)
+	return sqltypes.MakeTrusted(sqltypes.Int64, buf)
 }
 
 func BenchmarkAddGoInterface(b *testing.B) {
@@ -1632,10 +1631,10 @@ func BenchmarkAddGoNonInterface(b *testing.B) {
 	v1 := newEvalInt64(1)
 	v2 := newEvalInt64(12)
 	for i := 0; i < b.N; i++ {
-		if v1.typeof() != querypb.Type_INT64 {
+		if v1.typeof() != sqltypes.Int64 {
 			b.Error("type assertion failed")
 		}
-		if v2.typeof() != querypb.Type_INT64 {
+		if v2.typeof() != sqltypes.Int64 {
 			b.Error("type assertion failed")
 		}
 		v1 = newEvalInt64(v1.int64() + v2.int64())
diff --git a/go/vt/vtgate/evalengine/integration/comparison_test.go b/go/vt/vtgate/evalengine/integration/comparison_test.go
index 73b5a15d9d..83810ae991 100644
--- a/go/vt/vtgate/evalengine/integration/comparison_test.go
+++ b/go/vt/vtgate/evalengine/integration/comparison_test.go
@@ -23,6 +23,7 @@ import (
 	"strconv"
 	"strings"
 	"testing"
+	"time"
 
 	"vitess.io/vitess/go/mysql"
 	"vitess.io/vitess/go/sqltypes"
@@ -70,6 +71,7 @@ func normalize(v sqltypes.Value) string {
 
 var debugPrintAll = flag.Bool("print-all", false, "print all matching tests")
 var debugNormalize = flag.Bool("normalize", true, "normalize comparisons against MySQL values")
+var debugSimplify = flag.Bool("simplify", time.Now().UnixNano()&1 != 0, "simplify expressions before evaluating them")
 
 func compareRemoteQuery(t *testing.T, conn *mysql.Conn, query string) {
 	t.Helper()
@@ -89,7 +91,7 @@ func compareRemoteQuery(t *testing.T, conn *mysql.Conn, query string) {
 		}
 	}
 	if diff := compareResult(localErr, remoteErr, localVal, remoteVal, evaluated); diff != "" {
-		t.Errorf("%s\nquery: %s", diff, query)
+		t.Errorf("%s\nquery: %s (SIMPLIFY=%v)", diff, query, *debugSimplify)
 	} else if *debugPrintAll {
 		t.Logf("local=%s mysql=%s\nquery: %s", localVal, remoteVal, query)
 	}
@@ -200,6 +202,7 @@ func TestMultiComparisons(t *testing.T) {
 		`"0"`, `"-1"`, `"1"`,
 		`_utf8mb4 'foobar'`, `_utf8mb4 'FOOBAR'`,
 		`_binary '0'`, `_binary '-1'`, `_binary '1'`,
+		`0x0`, `0x1`, `-0x0`, `-0x1`,
 	}
 
 	var conn = mysqlconn(t)
@@ -262,7 +265,6 @@ func TestCollationOperations(t *testing.T) {
 }
 
 func TestNegateArithmetic(t *testing.T) {
-	*debugPrintAll = true
 	var cases = []string{
 		`0`, `1`, `1.0`, `0.0`, `1.0e0`, `0.0e0`,
 		`X'00'`, `X'1234'`, `X'ff'`,
diff --git a/go/vt/vtgate/evalengine/integration/fuzz_test.go b/go/vt/vtgate/evalengine/integration/fuzz_test.go
index d1c55ff88d..a438420300 100644
--- a/go/vt/vtgate/evalengine/integration/fuzz_test.go
+++ b/go/vt/vtgate/evalengine/integration/fuzz_test.go
@@ -119,7 +119,7 @@ func safeEvaluate(query string) (evalengine.EvalResult, bool, error) {
 				err = fmt.Errorf("PANIC: %v", r)
 			}
 		}()
-		expr, err = evalengine.ConvertEx(astExpr, evalengine.LookupDefaultCollation(255), true)
+		expr, err = evalengine.ConvertEx(astExpr, evalengine.LookupDefaultCollation(255), *debugSimplify)
 		return
 	}()
 
diff --git a/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt b/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt
index 2677992171..5f95f9bf5d 100644
--- a/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/aggr_cases.txt
@@ -134,7 +134,7 @@ Gen4 plan same as above
     "OperatorType": "Aggregate",
     "Variant": "Ordered",
     "Aggregates": "count(0) AS count(*)",
-    "GroupBy": "(1|4), (2|5) COLLATE latin1_swedish_ci, (3|6)",
+    "GroupBy": "(1|4), (2|5), (3|6)",
     "ResultColumns": 4,
     "Inputs": [
       {
@@ -253,7 +253,7 @@ Gen4 plan same as above
         "OperatorType": "Aggregate",
         "Variant": "Ordered",
         "Aggregates": "count(0) AS k",
-        "GroupBy": "(1|4), (2|5) COLLATE latin1_swedish_ci, (3|6)",
+        "GroupBy": "(1|4), (2|5), (3|6)",
         "Inputs": [
           {
             "OperatorType": "Route",
@@ -3063,56 +3063,3 @@ Gen4 plan same as above
     ]
   }
 }
-
-# distinct on text column with collation
-"select col, count(distinct textcol1) from user group by col"
-{
-  "QueryType": "SELECT",
-  "Original": "select col, count(distinct textcol1) from user group by col",
-  "Instructions": {
-    "OperatorType": "Aggregate",
-    "Variant": "Ordered",
-    "Aggregates": "count_distinct(1) AS count(distinct textcol1)",
-    "GroupBy": "0",
-    "Inputs": [
-      {
-        "OperatorType": "Route",
-        "Variant": "Scatter",
-        "Keyspace": {
-          "Name": "user",
-          "Sharded": true
-        },
-        "FieldQuery": "select col, textcol1, weight_string(textcol1) from `user` where 1 != 1 group by col, textcol1, weight_string(textcol1)",
-        "OrderBy": "0 ASC, (1|2) ASC",
-        "Query": "select col, textcol1, weight_string(textcol1) from `user` group by col, textcol1, weight_string(textcol1) order by col asc, textcol1 asc",
-        "ResultColumns": 2,
-        "Table": "`user`"
-      }
-    ]
-  }
-}
-{
-  "QueryType": "SELECT",
-  "Original": "select col, count(distinct textcol1) from user group by col",
-  "Instructions": {
-    "OperatorType": "Aggregate",
-    "Variant": "Ordered",
-    "Aggregates": "count_distinct(1|2 COLLATE latin1_swedish_ci) AS count(distinct textcol1)",
-    "GroupBy": "0",
-    "ResultColumns": 2,
-    "Inputs": [
-      {
-        "OperatorType": "Route",
-        "Variant": "Scatter",
-        "Keyspace": {
-          "Name": "user",
-          "Sharded": true
-        },
-        "FieldQuery": "select col, textcol1, weight_string(textcol1) from `user` where 1 != 1 group by col, textcol1, weight_string(textcol1)",
-        "OrderBy": "0 ASC, (1|2) ASC COLLATE latin1_swedish_ci",
-        "Query": "select col, textcol1, weight_string(textcol1) from `user` group by col, textcol1, weight_string(textcol1) order by col asc, textcol1 asc",
-        "Table": "`user`"
-      }
-    ]
-  }
-}
diff --git a/go/vt/vtgate/planbuilder/testdata/memory_sort_cases.txt b/go/vt/vtgate/planbuilder/testdata/memory_sort_cases.txt
index 1ec97dc829..4d91069b05 100644
--- a/go/vt/vtgate/planbuilder/testdata/memory_sort_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/memory_sort_cases.txt
@@ -241,7 +241,7 @@ Gen4 error: Expression of SELECT list is not in GROUP BY clause and contains non
         "OperatorType": "Aggregate",
         "Variant": "Ordered",
         "Aggregates": "count(1) AS k",
-        "GroupBy": "(2|3) COLLATE latin1_swedish_ci",
+        "GroupBy": "(2|3)",
         "Inputs": [
           {
             "OperatorType": "Route",
diff --git a/go/vt/vtgate/planbuilder/testdata/oltp_cases.txt b/go/vt/vtgate/planbuilder/testdata/oltp_cases.txt
index 7a5662054e..56d8276f23 100644
--- a/go/vt/vtgate/planbuilder/testdata/oltp_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/oltp_cases.txt
@@ -157,7 +157,7 @@ Gen4 plan same as above
   "Instructions": {
     "OperatorType": "Aggregate",
     "Variant": "Ordered",
-    "GroupBy": "(0|1) COLLATE latin1_swedish_ci",
+    "GroupBy": "(0|1)",
     "ResultColumns": 1,
     "Inputs": [
       {