Repository: vitessio/vitess
Pull request #6964 (2020-10-28 15:29:34)

Set udv allow more expressions
Fixes: https://github.com/vitessio/vitess/issues/6915

Set UDV allowed only specific function calls. With this change. UDV can be set using any function all and can also be done through subquery.


Patch:
diff --git a/docker/k8s/vttablet/Dockerfile b/docker/k8s/vttablet/Dockerfile
index fefd0dfa50..97d40a0b6e 100644
--- a/docker/k8s/vttablet/Dockerfile
+++ b/docker/k8s/vttablet/Dockerfile
@@ -21,7 +21,7 @@ FROM debian:buster-slim
 # TODO: remove when https://github.com/vitessio/vitess/issues/3553 is fixed
 RUN apt-get update && \
    apt-get upgrade -qq && \
-   apt-get install wget default-mysql-client jq curl -qq --no-install-recommends && \
+   apt-get install wget default-mysql-client jq -qq --no-install-recommends && \
    apt-get autoremove && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
diff --git a/docker/lite/install_dependencies.sh b/docker/lite/install_dependencies.sh
index 8ed522d77c..1afff6e3f4 100755
--- a/docker/lite/install_dependencies.sh
+++ b/docker/lite/install_dependencies.sh
@@ -44,7 +44,6 @@ BASE_PACKAGES=(
     strace
     sysstat
     wget
-    curl
 )
 
 apt-get update
@@ -114,18 +113,13 @@ percona57)
 percona80)
     PACKAGES=(
         libperconaserverclient21
-        percona-server-rocksdb
+	    percona-server-rocksdb
         percona-server-server
         percona-server-tokudb
         percona-xtrabackup-80
     )
     ;;
-mariadb)
-    PACKAGES=(
-        mariadb-server-10.2
-    )
-    ;;
-mariadb103)
+mariadb|mariadb103)
     PACKAGES=(
         mariadb-server
     )
diff --git a/go/mysql/binlog_event_rbr.go b/go/mysql/binlog_event_rbr.go
index fb496ac5d2..89e87c1909 100644
--- a/go/mysql/binlog_event_rbr.go
+++ b/go/mysql/binlog_event_rbr.go
@@ -700,7 +700,7 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ
 		// now the full digits, 32 bits each, 9 digits
 		for i := 0; i < intg0; i++ {
 			val = binary.BigEndian.Uint32(d[pos : pos+4])
-			fmt.Fprintf(txt, "%09d", val)
+			fmt.Fprintf(txt, "%9d", val)
 			pos += 4
 		}
 
@@ -872,7 +872,12 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ
 		l := int(data[pos])
 		mdata := data[pos+1 : pos+1+l]
 		if sqltypes.IsBinary(styp) {
-			return sqltypes.MakeTrusted(querypb.Type_BINARY, mdata), l + 1, nil
+			// Fixed length binaries have to be padded with zeroes
+			// up to the length of the field. Otherwise, equality checks
+			// fail against saved data. See https://github.com/vitessio/vitess/issues/3984.
+			ret := make([]byte, max)
+			copy(ret, mdata)
+			return sqltypes.MakeTrusted(querypb.Type_BINARY, ret), l + 1, nil
 		}
 		return sqltypes.MakeTrusted(querypb.Type_VARCHAR, mdata), l + 1, nil
 
diff --git a/go/sqltypes/value.go b/go/sqltypes/value.go
index 20e10f8e1d..550e8b86ea 100644
--- a/go/sqltypes/value.go
+++ b/go/sqltypes/value.go
@@ -335,6 +335,12 @@ func (v Value) IsBinary() bool {
 	return IsBinary(v.typ)
 }
 
+// IsDateTime returns true if Value is datetime.
+func (v Value) IsDateTime() bool {
+	dt := int(querypb.Type_DATETIME)
+	return int(v.typ)&dt == dt
+}
+
 // MarshalJSON should only be used for testing.
 // It's not a complete implementation.
 func (v Value) MarshalJSON() ([]byte, error) {
diff --git a/go/vt/vtgate/evalengine/arithmetic.go b/go/vt/vtgate/evalengine/arithmetic.go
index bf34797276..aa338f4808 100644
--- a/go/vt/vtgate/evalengine/arithmetic.go
+++ b/go/vt/vtgate/evalengine/arithmetic.go
@@ -55,7 +55,7 @@ func Add(v1, v2 sqltypes.Value) (sqltypes.Value, error) {
 		return sqltypes.NULL, err
 	}
 
-	return castFromNumeric(lresult, lresult.typ), nil
+	return lresult.toSQLValue(lresult.typ), nil
 }
 
 // Subtract takes two values and subtracts them
@@ -79,7 +79,7 @@ func Subtract(v1, v2 sqltypes.Value) (sqltypes.Value, error) {
 		return sqltypes.NULL, err
 	}
 
-	return castFromNumeric(lresult, lresult.typ), nil
+	return lresult.toSQLValue(lresult.typ), nil
 }
 
 // Multiply takes two values and multiplies it together
@@ -101,7 +101,7 @@ func Multiply(v1, v2 sqltypes.Value) (sqltypes.Value, error) {
 		return sqltypes.NULL, err
 	}
 
-	return castFromNumeric(lresult, lresult.typ), nil
+	return lresult.toSQLValue(lresult.typ), nil
 }
 
 // Divide (Float) for MySQL. Replicates behavior of "/" operator
@@ -132,7 +132,7 @@ func Divide(v1, v2 sqltypes.Value) (sqltypes.Value, error) {
 		return sqltypes.NULL, err
 	}
 
-	return castFromNumeric(lresult, lresult.typ), nil
+	return lresult.toSQLValue(lresult.typ), nil
 }
 
 // NullsafeAdd adds two Values in a null-safe manner. A null value
@@ -164,7 +164,7 @@ func NullsafeAdd(v1, v2 sqltypes.Value, resultType querypb.Type) sqltypes.Value
 	}
 	lresult := addNumeric(lv1, lv2)
 
-	return castFromNumeric(lresult, resultType)
+	return lresult.toSQLValue(resultType)
 }
 
 // NullsafeCompare returns 0 if v1==v2, -1 if v1<v2, and 1 if v1>v2.
@@ -387,8 +387,9 @@ func newEvalResult(v sqltypes.Value) (EvalResult, error) {
 			return EvalResult{}, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v", err)
 		}
 		return EvalResult{fval: fval, typ: sqltypes.Float64}, nil
+	default:
+		return EvalResult{typ: v.Type(), bytes: raw}, nil
 	}
-	return EvalResult{}, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "this should not be reached. got %s", v.String())
 }
 
 // newIntegralNumeric parses a value and produces an Int64 or Uint64.
@@ -719,7 +720,7 @@ func anyMinusFloat(v1 EvalResult, v2 float64) EvalResult {
 	return EvalResult{typ: sqltypes.Float64, fval: v1.fval - v2}
 }
 
-func castFromNumeric(v EvalResult, resultType querypb.Type) sqltypes.Value {
+func (v EvalResult) toSQLValue(resultType querypb.Type) sqltypes.Value {
 	switch {
 	case sqltypes.IsSigned(resultType):
 		switch v.typ {
@@ -752,7 +753,7 @@ func castFromNumeric(v EvalResult, resultType querypb.Type) sqltypes.Value {
 			}
 			return sqltypes.MakeTrusted(resultType, strconv.AppendFloat(nil, v.fval, format, -1, 64))
 		}
-	case resultType == sqltypes.VarChar || resultType == sqltypes.VarBinary || resultType == sqltypes.Binary || resultType == sqltypes.Text:
+	default:
 		return sqltypes.MakeTrusted(resultType, v.bytes)
 	}
 	return sqltypes.NULL
diff --git a/go/vt/vtgate/evalengine/expressions.go b/go/vt/vtgate/evalengine/expressions.go
index 153ecd09ba..a32badee48 100644
--- a/go/vt/vtgate/evalengine/expressions.go
+++ b/go/vt/vtgate/evalengine/expressions.go
@@ -74,7 +74,7 @@ type (
 
 //Value allows for retrieval of the value we expose for public consumption
 func (e EvalResult) Value() sqltypes.Value {
-	return castFromNumeric(e, e.typ)
+	return e.toSQLValue(e.typ)
 }
 
 //NewLiteralIntFromBytes returns a literal expression
diff --git a/go/vt/vtgate/planbuilder/expression_converter.go b/go/vt/vtgate/planbuilder/expression_converter.go
index 751228e9fa..d90da46be7 100644
--- a/go/vt/vtgate/planbuilder/expression_converter.go
+++ b/go/vt/vtgate/planbuilder/expression_converter.go
@@ -20,9 +20,7 @@ import (
 	"fmt"
 	"strings"
 
-	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
 	"vitess.io/vitess/go/vt/sqlparser"
-	"vitess.io/vitess/go/vt/vterrors"
 	"vitess.io/vitess/go/vt/vtgate/engine"
 	"vitess.io/vitess/go/vt/vtgate/evalengine"
 )
@@ -87,11 +85,6 @@ func (ec *expressionConverter) convert(astExpr sqlparser.Expr, boolean, identifi
 		if err != sqlparser.ErrExprNotSupported {
 			return nil, err
 		}
-		// We have an expression that we can't handle at the vtgate level
-		if !expressionOkToDelegateToTablet(astExpr) {
-			// Uh-oh - this expression is not even safe to delegate to the tablet. Give up.
-			return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "expression not supported for SET: %s", sqlparser.String(astExpr))
-		}
 		evalExpr = &evalengine.Column{Offset: len(ec.tabletExpressions)}
 		ec.tabletExpressions = append(ec.tabletExpressions, astExpr)
 	}
diff --git a/go/vt/vtgate/planbuilder/set.go b/go/vt/vtgate/planbuilder/set.go
index 7a7558fe61..9bd2d921a4 100644
--- a/go/vt/vtgate/planbuilder/set.go
+++ b/go/vt/vtgate/planbuilder/set.go
@@ -145,26 +145,6 @@ func planSysVarCheckIgnore(expr *sqlparser.SetExpr, schema ContextVSchema, boole
 	}, nil
 }
 
-func expressionOkToDelegateToTablet(e sqlparser.Expr) bool {
-	valid := true
-	sqlparser.Rewrite(e, nil, func(cursor *sqlparser.Cursor) bool {
-		switch n := cursor.Node().(type) {
-		case *sqlparser.Subquery, *sqlparser.TimestampFuncExpr, *sqlparser.CurTimeFuncExpr:
-			valid = false
-			return false
-		case *sqlparser.FuncExpr:
-			_, ok := validFuncs[n.Name.Lowered()]
-			valid = ok
-			return ok
-		case *sqlparser.ColName:
-			valid = n.Name.AtCount() == 2
-			return false
-		}
-		return true
-	})
-	return valid
-}
-
 func buildSetOpReservedConn(s setting) planFunc {
 	return func(expr *sqlparser.SetExpr, vschema ContextVSchema, _ *expressionConverter) (engine.SetOp, error) {
 		if !vschema.SysVarSetEnabled() {
@@ -257,137 +237,3 @@ func extractValue(expr *sqlparser.SetExpr, boolean bool) (string, error) {
 
 	return sqlparser.String(expr.Expr), nil
 }
-
-// whitelist of functions knows to be safe to pass through to mysql for evaluation
-// this list tries to not include functions that might return different results on different tablets
-var validFuncs = map[string]interface{}{
-	"if":               nil,
-	"ifnull":           nil,
-	"nullif":           nil,
-	"abs":              nil,
-	"acos":             nil,
-	"asin":             nil,
-	"atan2":            nil,
-	"atan":             nil,
-	"ceil":             nil,
-	"ceiling":          nil,
-	"conv":             nil,
-	"cos":              nil,
-	"cot":              nil,
-	"crc32":            nil,
-	"degrees":          nil,
-	"div":              nil,
-	"exp":              nil,
-	"floor":            nil,
-	"ln":               nil,
-	"log":              nil,
-	"log10":            nil,
-	"log2":             nil,
-	"mod":              nil,
-	"pi":               nil,
-	"pow":              nil,
-	"power":            nil,
-	"radians":          nil,
-	"rand":             nil,
-	"round":            nil,
-	"sign":             nil,
-	"sin":              nil,
-	"sqrt":             nil,
-	"tan":              nil,
-	"truncate":         nil,
-	"adddate":          nil,
-	"addtime":          nil,
-	"convert_tz":       nil,
-	"date":             nil,
-	"date_add":         nil,
-	"date_format":      nil,
-	"date_sub":         nil,
-	"datediff":         nil,
-	"day":              nil,
-	"dayname":          nil,
-	"dayofmonth":       nil,
-	"dayofweek":        nil,
-	"dayofyear":        nil,
-	"extract":          nil,
-	"from_days":        nil,
-	"from_unixtime":    nil,
-	"get_format":       nil,
-	"hour":             nil,
-	"last_day":         nil,
-	"makedate":         nil,
-	"maketime":         nil,
-	"microsecond":      nil,
-	"minute":           nil,
-	"month":            nil,
-	"monthname":        nil,
-	"period_add":       nil,
-	"period_diff":      nil,
-	"quarter":          nil,
-	"sec_to_time":      nil,
-	"second":           nil,
-	"str_to_date":      nil,
-	"subdate":          nil,
-	"subtime":          nil,
-	"time_format":      nil,
-	"time_to_sec":      nil,
-	"timediff":         nil,
-	"timestampadd":     nil,
-	"timestampdiff":    nil,
-	"to_days":          nil,
-	"to_seconds":       nil,
-	"week":             nil,
-	"weekday":          nil,
-	"weekofyear":       nil,
-	"year":             nil,
-	"yearweek":         nil,
-	"ascii":            nil,
-	"bin":              nil,
-	"bit_length":       nil,
-	"char":             nil,
-	"char_length":      nil,
-	"character_length": nil,
-	"concat":           nil,
-	"concat_ws":        nil,
-	"elt":              nil,
-	"export_set":       nil,
-	"field":            nil,
-	"find_in_set":      nil,
-	"format":           nil,
-	"from_base64":      nil,
-	"hex":              nil,
-	"insert":           nil,
-	"instr":            nil,
-	"lcase":            nil,
-	"left":             nil,
-	"length":           nil,
-	"load_file":        nil,
-	"locate":           nil,
-	"lower":            nil,
-	"lpad":             nil,
-	"ltrim":            nil,
-	"make_set":         nil,
-	"mid":              nil,
-	"oct":              nil,
-	"octet_length":     nil,
-	"ord":              nil,
-	"position":         nil,
-	"quote":            nil,
-	"repeat":           nil,
-	"replace":          nil,
-	"reverse":          nil,
-	"right":            nil,
-	"rpad":             nil,
-	"rtrim":            nil,
-	"soundex":          nil,
-	"space":            nil,
-	"strcmp":           nil,
-	"substr":           nil,
-	"substring":        nil,
-	"substring_index":  nil,
-	"to_base64":        nil,
-	"trim":             nil,
-	"ucase":            nil,
-	"unhex":            nil,
-	"upper":            nil,
-	"weight_string":    nil,
-}
diff --git a/go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go b/go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go
index ee1930abcf..9a7c5bad7d 100644
--- a/go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go
+++ b/go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go
@@ -65,10 +65,8 @@ type colExpr struct {
 	// references contains all the column names referenced in the expression.
 	references map[string]bool
 
-	isGrouped  bool
-	isPK       bool
-	dataType   string
-	columnType string
+	isGrouped bool
+	isPK      bool
 }
 
 // operation is the opcode for the colExpr.
@@ -472,14 +470,12 @@ func (tpb *tablePlanBuilder) analyzePK(pkInfoMap map[string][]*PrimaryKeyInfo) e
 	for _, pkcol := range pkcols {
 		cexpr := tpb.findCol(sqlparser.NewColIdent(pkcol.Name))
 		if cexpr == nil {
-			return fmt.Errorf("primary key column %v not found in select list", pkcol)
+			return fmt.Errorf("primary key column %s not found in select list", pkcol)
 		}
 		if cexpr.operation != opExpr {
-			return fmt.Errorf("primary key column %v is not allowed to reference an aggregate expression", pkcol)
+			return fmt.Errorf("primary key column %s is not allowed to reference an aggregate expression", pkcol)
 		}
 		cexpr.isPK = true
-		cexpr.dataType = pkcol.DataType
-		cexpr.columnType = pkcol.ColumnType
 		tpb.pkCols = append(tpb.pkCols, cexpr)
 	}
 	return nil
@@ -666,29 +662,16 @@ func (tpb *tablePlanBuilder) generateDeleteStatement() *sqlparser.ParsedQuery {
 	return buf.ParsedQuery()
 }
 
-// For binary(n) column types, the value in the where clause needs to be padded with nulls upto the length of the column
-// for MySQL comparison to work properly. This is achieved by casting it to the column type
-func castIfNecessary(buf *sqlparser.TrackedBuffer, cexpr *colExpr) {
-	if cexpr.dataType == "binary" {
-		buf.Myprintf("cast(%v as %s)", cexpr.expr, cexpr.columnType)
-		return
-	}
-	buf.Myprintf("%v", cexpr.expr)
-}
-
 func (tpb *tablePlanBuilder) generateWhere(buf *sqlparser.TrackedBuffer, bvf *bindvarFormatter) {
 	buf.WriteString(" where ")
 	bvf.mode = bvBefore
 	separator := ""
 	for _, cexpr := range tpb.pkCols {
 		if _, ok := cexpr.expr.(*sqlparser.ColName); ok {
-			buf.Myprintf("%s%v=", separator, cexpr.colName)
-			castIfNecessary(buf, cexpr)
+			buf.Myprintf("%s%v=%v", separator, cexpr.colName, cexpr.expr)
 		} else {
 			// Parenthesize non-trivial expressions.
-			buf.Myprintf("%s%v=(", separator, cexpr.colName)
-			castIfNecessary(buf, cexpr)
-			buf.Myprintf(")")
+			buf.Myprintf("%s%v=(%v)", separator, cexpr.colName, cexpr.expr)
 		}
 		separator = " and "
 	}
diff --git a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go
index 510a27e286..48135c9910 100644
--- a/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go
+++ b/go/vt/vttablet/tabletmanager/vreplication/vreplicator.go
@@ -193,11 +193,9 @@ func (vr *vreplicator) replicate(ctx context.Context) error {
 
 // PrimaryKeyInfo is used to store charset and collation for primary keys where applicable
 type PrimaryKeyInfo struct {
-	Name       string
-	CharSet    string
-	Collation  string
-	DataType   string
-	ColumnType string
+	Name      string
+	CharSet   string
+	Collation string
 }
 
 func (vr *vreplicator) buildPkInfoMap(ctx context.Context) (map[string][]*PrimaryKeyInfo, error) {
@@ -205,7 +203,7 @@ func (vr *vreplicator) buildPkInfoMap(ctx context.Context) (map[string][]*Primar
 	if err != nil {
 		return nil, err
 	}
-	queryTemplate := "select character_set_name, collation_name, column_name, data_type, column_type from information_schema.columns where table_schema=%s and table_name=%s;"
+	queryTemplate := "select character_set_name, collation_name,column_name,data_type from information_schema.columns where table_schema=%s and table_name=%s;"
 	pkInfoMap := make(map[string][]*PrimaryKeyInfo)
 	for _, td := range schema.TableDefinitions {
 
@@ -214,8 +212,8 @@ func (vr *vreplicator) buildPkInfoMap(ctx context.Context) (map[string][]*Primar
 		if err != nil {
 			return nil, err
 		}
-		if len(qr.Rows) == 0 {
-			return nil, fmt.Errorf("no data returned from information_schema.columns")
+		if len(qr.Rows) > 0 && len(qr.Fields) != 4 {
+			return nil, fmt.Errorf("incorrect result returned for collation query")
 		}
 
 		var pks []string
@@ -228,7 +226,6 @@ func (vr *vreplicator) buildPkInfoMap(ctx context.Context) (map[string][]*Primar
 		for _, pk := range pks {
 			charSet := ""
 			collation := ""
-			var dataType, columnType string
 			for _, row := range qr.Rows {
 				columnName := row[2].ToString()
 				if strings.EqualFold(columnName, pk) {
@@ -239,27 +236,17 @@ func (vr *vreplicator) buildPkInfoMap(ctx context.Context) (map[string][]*Primar
 							break
 						}
 					}
-					if currentField == nil {
-						continue
-					}
-					dataType = row[3].ToString()
-					columnType = row[4].ToString()
-					if sqltypes.IsText(currentField.Type) {
+					if currentField != nil && sqltypes.IsText(currentField.Type) {
 						charSet = row[0].ToString()
 						collation = row[1].ToString()
 					}
 					break
 				}
 			}
-			if dataType == "" || columnType == "" {
-				return nil, fmt.Errorf("no dataType/columnType found in information_schema.columns for table %s, column %s", td.Name, pk)
-			}
 			pkInfos = append(pkInfos, &PrimaryKeyInfo{
-				Name:       pk,
-				CharSet:    charSet,
-				Collation:  collation,
-				DataType:   dataType,
-				ColumnType: columnType,
+				Name:      pk,
+				CharSet:   charSet,
+				Collation: collation,
 			})
 		}
 		pkInfoMap[td.Name] = pkInfos
diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go
index 411bad9225..6d387beee8 100644
--- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go
+++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go
@@ -172,6 +172,7 @@ func (vs *vstreamer) replicate(ctx context.Context) error {
 		return wrapError(err, vs.pos, vs.vse)
 	}
 	defer conn.Close()
+
 	events, err := conn.StartBinlogDumpFromPosition(vs.ctx, vs.pos)
 	if err != nil {
 		return wrapError(err, vs.pos, vs.vse)


Test patch:
diff --git a/go/mysql/binlog_event_rbr_test.go b/go/mysql/binlog_event_rbr_test.go
index 7c0ba4afe9..7d651f38d3 100644
--- a/go/mysql/binlog_event_rbr_test.go
+++ b/go/mysql/binlog_event_rbr_test.go
@@ -468,12 +468,6 @@ func TestCellLengthAndData(t *testing.T) {
 		data:     []byte{0x81, 0x0D, 0xFB, 0x38, 0xD2, 0x00, 0x01},
 		out: sqltypes.MakeTrusted(querypb.Type_DECIMAL,
 			[]byte("1234567890.0001")),
-	}, {
-		typ:      TypeNewDecimal,
-		metadata: 20<<8 | 2, // DECIMAL(20,2)
-		data:     []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0x01, 0x0a},
-		out: sqltypes.MakeTrusted(querypb.Type_DECIMAL,
-			[]byte("000000000000000001.10")),
 	}, {
 		typ:      TypeBlob,
 		metadata: 1,
diff --git a/go/test/endtoend/vtgate/reservedconn/udv_test.go b/go/test/endtoend/vtgate/reservedconn/udv_test.go
index 387c252dfa..d8ab49f267 100644
--- a/go/test/endtoend/vtgate/reservedconn/udv_test.go
+++ b/go/test/endtoend/vtgate/reservedconn/udv_test.go
@@ -96,6 +96,12 @@ func TestSetUDV(t *testing.T) {
 	}, {
 		query:        "select id, val1 from test where val1 = @tablet",
 		expectedRows: `[[INT64(42) VARCHAR("foobar")]]`, rowsAffected: 1,
+	}, {
+		query:        "set @foo = now(), @bar = now(), @dd = date('2020-10-20'), @tt = time('10:15')",
+		expectedRows: `[]`, rowsAffected: 0,
+	}, {
+		query:        "select @foo = @bar, @dd, @tt",
+		expectedRows: `[[INT64(1) VARCHAR("2020-10-20") VARCHAR("10:15:00")]]`, rowsAffected: 1,
 	}}
 
 	conn, err := mysql.Connect(ctx, &vtParams)
diff --git a/go/vt/vtgate/engine/set_test.go b/go/vt/vtgate/engine/set_test.go
index afd0b0bc6f..2d142e5e9f 100644
--- a/go/vt/vtgate/engine/set_test.go
+++ b/go/vt/vtgate/engine/set_test.go
@@ -72,6 +72,7 @@ func TestSetTable(t *testing.T) {
 		expectedQueryLog []string
 		expectedWarning  []*querypb.QueryWarning
 		expectedError    string
+		input            Primitive
 	}
 
 	tests := []testCase{
@@ -91,6 +92,36 @@ func TestSetTable(t *testing.T) {
 				`UDV set with (x,INT64(42))`,
 			},
 		},
+		{
+			testName: "udv with input",
+			setOps: []SetOp{
+				&UserDefinedVariable{
+					Name: "x",
+					Expr: evalengine.NewColumn(0),
+				},
+			},
+			qr: []*sqltypes.Result{sqltypes.MakeTestResult(
+				sqltypes.MakeTestFields(
+					"col0",
+					"datetime",
+				),
+				"2020-10-28",
+			)},
+			expectedQueryLog: []string{
+				`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
+				`ExecuteMultiShard ks.-20: select now() from dual {} false false`,
+				`UDV set with (x,DATETIME("2020-10-28"))`,
+			},
+			input: &Send{
+				Keyspace: &vindexes.Keyspace{
+					Name:    "ks",
+					Sharded: true,
+				},
+				TargetDestination: key.DestinationAnyShard{},
+				Query:             "select now() from dual",
+				SingleShardOnly:   true,
+			},
+		},
 		{
 			testName: "sysvar ignore",
 			setOps: []SetOp{
@@ -259,9 +290,12 @@ func TestSetTable(t *testing.T) {
 
 	for _, tc := range tests {
 		t.Run(tc.testName, func(t *testing.T) {
+			if tc.input == nil {
+				tc.input = &SingleRow{}
+			}
 			set := &Set{
 				Ops:   tc.setOps,
-				Input: &SingleRow{},
+				Input: tc.input,
 			}
 			vc := &loggingVCursor{
 				shards:  []string{"-20", "20-"},
diff --git a/go/vt/vtgate/evalengine/arithmetic_test.go b/go/vt/vtgate/evalengine/arithmetic_test.go
index cf5f5a099b..2d7578e275 100644
--- a/go/vt/vtgate/evalengine/arithmetic_test.go
+++ b/go/vt/vtgate/evalengine/arithmetic_test.go
@@ -1101,7 +1101,7 @@ func TestPrioritize(t *testing.T) {
 	}
 }
 
-func TestCastFromNumeric(t *testing.T) {
+func TestToSqlValue(t *testing.T) {
 	tcases := []struct {
 		typ querypb.Type
 		v   EvalResult
@@ -1158,10 +1158,10 @@ func TestCastFromNumeric(t *testing.T) {
 		out: sqltypes.TestValue(querypb.Type_DECIMAL, "0.00000000000000012"),
 	}}
 	for _, tcase := range tcases {
-		got := castFromNumeric(tcase.v, tcase.typ)
+		got := tcase.v.toSQLValue(tcase.typ)
 
 		if !reflect.DeepEqual(got, tcase.out) {
-			t.Errorf("castFromNumeric(%v, %v): %v, want %v", tcase.v, tcase.typ, printValue(got), printValue(tcase.out))
+			t.Errorf("toSQLValue(%v, %v): %v, want %v", tcase.v, tcase.typ, printValue(got), printValue(tcase.out))
 		}
 	}
 }
diff --git a/go/vt/vtgate/planbuilder/set_test.go b/go/vt/vtgate/planbuilder/set_test.go
deleted file mode 100644
index 16e3e7079e..0000000000
--- a/go/vt/vtgate/planbuilder/set_test.go
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-Copyright 2020 The Vitess Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package planbuilder
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/require"
-	"vitess.io/vitess/go/vt/sqlparser"
-)
-
-func TestExpressionOkToDelegateToTablet(t *testing.T) {
-	tests := []struct {
-		expr   string
-		expect bool
-	}{{
-		expr:   "42",
-		expect: true,
-	}, {
-		expr:   "(select count(*) from someTable)",
-		expect: false,
-	}, {
-		expr:   "TIMESTAMP()",
-		expect: false,
-	}, {
-		expr:   "concat('a','b')",
-		expect: true,
-	}}
-	for _, tt := range tests {
-		t.Run(tt.expr, func(t *testing.T) {
-			stmt, err := sqlparser.Parse("select " + tt.expr)
-			require.NoError(t, err)
-			e := stmt.(*sqlparser.Select).SelectExprs[0].(*sqlparser.AliasedExpr).Expr
-			got := expressionOkToDelegateToTablet(e)
-			require.Equal(t, tt.expect, got)
-		})
-	}
-}
diff --git a/go/vt/vtgate/planbuilder/testdata/set_cases.txt b/go/vt/vtgate/planbuilder/testdata/set_cases.txt
index 02ea986cc1..0d2289bf20 100644
--- a/go/vt/vtgate/planbuilder/testdata/set_cases.txt
+++ b/go/vt/vtgate/planbuilder/testdata/set_cases.txt
@@ -104,10 +104,6 @@
   }
 }
 
-# only allow whitelisted functions
-"set @foo = BAD_FUNC()"
-"expression not supported for SET: BAD_FUNC()"
-
 # single sysvar cases
 "SET sql_mode = 'STRICT_ALL_TABLES,NO_AUTO_VALUE_ON_ZERO'"
 {
diff --git a/go/vt/vttablet/tabletmanager/vreplication/framework_test.go b/go/vt/vttablet/tabletmanager/vreplication/framework_test.go
index 60449db43f..145e9b8559 100644
--- a/go/vt/vttablet/tabletmanager/vreplication/framework_test.go
+++ b/go/vt/vttablet/tabletmanager/vreplication/framework_test.go
@@ -27,8 +27,9 @@ import (
 	"testing"
 	"time"
 
-	"github.com/golang/protobuf/proto"
 	"github.com/stretchr/testify/require"
+
+	"github.com/golang/protobuf/proto"
 	"golang.org/x/net/context"
 
 	"vitess.io/vitess/go/mysql"
@@ -514,6 +515,7 @@ func expectNontxQueries(t *testing.T, queries []string) {
 	retry:
 		select {
 		case got = <-globalDBQueries:
+
 			if got == "begin" || got == "commit" || got == "rollback" || strings.Contains(got, "update _vt.vreplication set pos") || heartbeatRe.MatchString(got) {
 				goto retry
 			}
@@ -528,9 +530,11 @@ func expectNontxQueries(t *testing.T, queries []string) {
 			} else {
 				match = (got == query)
 			}
-			require.True(t, match, "query %d:: got:%s, want:%s", i, got, query)
+			if !match {
+				t.Errorf("query:\n%q, does not match query %d:\n%q", got, i, query)
+			}
 		case <-time.After(5 * time.Second):
-			t.Fatalf("no query received, expecting %s", query)
+			t.Errorf("no query received, expecting %s", query)
 			failed = true
 		}
 	}
diff --git a/go/vt/vttablet/tabletmanager/vreplication/vcopier_test.go b/go/vt/vttablet/tabletmanager/vreplication/vcopier_test.go
index dc3959b62b..d5f2028a7c 100644
--- a/go/vt/vttablet/tabletmanager/vreplication/vcopier_test.go
+++ b/go/vt/vttablet/tabletmanager/vreplication/vcopier_test.go
@@ -30,106 +30,6 @@ import (
 	"vitess.io/vitess/go/vt/vttablet/tabletserver/vstreamer"
 )
 
-func TestPlayerCopyCharPK(t *testing.T) {
-	defer deleteTablet(addTablet(100))
-
-	savedPacketSize := *vstreamer.PacketSize
-	// PacketSize of 1 byte will send at most one row at a time.
-	*vstreamer.PacketSize = 1
-	defer func() { *vstreamer.PacketSize = savedPacketSize }()
-
-	savedCopyTimeout := copyTimeout
-	// copyTimeout should be low enough to have time to send one row.
-	copyTimeout = 500 * time.Millisecond
-	defer func() { copyTimeout = savedCopyTimeout }()
-
-	savedWaitRetryTime := waitRetryTime
-	// waitRetry time should be very low to cause the wait loop to execute multipel times.
-	waitRetryTime = 10 * time.Millisecond
-	defer func() { waitRetryTime = savedWaitRetryTime }()
-
-	execStatements(t, []string{
-		"create table src(idc binary(2) , val int, primary key(idc))",
-		"insert into src values('a', 1), ('c', 2)",
-		fmt.Sprintf("create table %s.dst(idc binary(2), val int, primary key(idc))", vrepldb),
-	})
-	defer execStatements(t, []string{
-		"drop table src",
-		fmt.Sprintf("drop table %s.dst", vrepldb),
-	})
-	env.SchemaEngine.Reload(context.Background())
-
-	count := 0
-	vstreamRowsSendHook = func(ctx context.Context) {
-		defer func() { count++ }()
-		// Allow the first two calls to go through: field info and one row.
-		if count <= 1 {
-			return
-		}
-		// Insert a row with PK which is < the lastPK till now because of the utf8mb4 collation
-		execStatements(t, []string{
-			"update src set val = 3 where idc = 'a\000'",
-		})
-		// Wait for context to expire and then send the row.
-		// This will cause the copier to abort and go back to catchup mode.
-		<-ctx.Done()
-		// Do this no more than once.
-		vstreamRowsSendHook = nil
-	}
-
-	vstreamHook = func(context.Context) {
-		// Sleeping 50ms guarantees that the catchup wait loop executes multiple times.
-		// This is because waitRetryTime is set to 10ms.
-		time.Sleep(50 * time.Millisecond)
-		// Do this no more than once.
-		vstreamHook = nil
-	}
-
-	filter := &binlogdatapb.Filter{
-		Rules: []*binlogdatapb.Rule{{
-			Match:  "dst",
-			Filter: "select * from src",
-		}},
-	}
-
-	bls := &binlogdatapb.BinlogSource{
-		Keyspace: env.KeyspaceName,
-		Shard:    env.ShardName,
-		Filter:   filter,
-		OnDdl:    binlogdatapb.OnDDLAction_IGNORE,
-	}
-
-	query := binlogplayer.CreateVReplicationState("test", bls, "", binlogplayer.VReplicationInit, playerEngine.dbName)
-	qr, err := playerEngine.Exec(query)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer func() {
-		query := fmt.Sprintf("delete from _vt.vreplication where id = %d", qr.InsertID)
-		if _, err := playerEngine.Exec(query); err != nil {
-			t.Fatal(err)
-		}
-		expectDeleteQueries(t)
-	}()
-
-	expectNontxQueries(t, []string{
-		"/insert into _vt.vreplication",
-		"/insert into _vt.copy_state",
-		"/update _vt.vreplication set state='Copying'",
-		"insert into dst(idc,val) values ('a\\0',1)",
-		`/update _vt.copy_state set lastpk='fields:<name:\\"idc\\" type:BINARY > rows:<lengths:2 values:\\"a\\\\000\\" > ' where vrepl_id=.*`,
-		`update dst set val=3 where idc=cast('a' as binary(2)) and ('a') <= ('a\0')`,
-		"insert into dst(idc,val) values ('c\\0',2)",
-		`/update _vt.copy_state set lastpk='fields:<name:\\"idc\\" type:BINARY > rows:<lengths:2 values:\\"c\\\\000\\" > ' where vrepl_id=.*`,
-		"/delete from _vt.copy_state.*dst",
-		"/update _vt.vreplication set state='Running'",
-	})
-	expectData(t, "dst", [][]string{
-		{"a\000", "3"},
-		{"c\000", "2"},
-	})
-}
-
 // TestPlayerCopyVarcharPKCaseInsensitive tests the copy/catchup phase for a table with a varchar primary key
 // which is case insensitive.
 func TestPlayerCopyVarcharPKCaseInsensitive(t *testing.T) {
diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go
index a5bdb345b9..c3850807a3 100644
--- a/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go
+++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer_flaky_test.go
@@ -34,133 +34,6 @@ import (
 	binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata"
 )
 
-func TestCharPK(t *testing.T) {
-	defer deleteTablet(addTablet(100))
-
-	execStatements(t, []string{
-		"create table t1(id int, val binary(2), primary key(val))",
-		fmt.Sprintf("create table %s.t1(id int, val binary(2), primary key(val))", vrepldb),
-		"create table t2(id int, val char(2), primary key(val))",
-		fmt.Sprintf("create table %s.t2(id int, val char(2), primary key(val))", vrepldb),
-		"create table t3(id int, val varbinary(2), primary key(val))",
-		fmt.Sprintf("create table %s.t3(id int, val varbinary(2), primary key(val))", vrepldb),
-		"create table t4(id int, val varchar(2), primary key(val))",
-		fmt.Sprintf("create table %s.t4(id int, val varchar(2), primary key(val))", vrepldb),
-	})
-	defer execStatements(t, []string{
-		"drop table t1",
-		fmt.Sprintf("drop table %s.t1", vrepldb),
-		"drop table t2",
-		fmt.Sprintf("drop table %s.t2", vrepldb),
-		"drop table t3",
-		fmt.Sprintf("drop table %s.t3", vrepldb),
-		"drop table t4",
-		fmt.Sprintf("drop table %s.t4", vrepldb),
-	})
-	env.SchemaEngine.Reload(context.Background())
-
-	filter := &binlogdatapb.Filter{
-		Rules: []*binlogdatapb.Rule{{
-			Match:  "t1",
-			Filter: "select * from t1",
-		}, {
-			Match:  "t2",
-			Filter: "select * from t2",
-		}, {
-			Match:  "t3",
-			Filter: "select * from t3",
-		}, {
-			Match:  "t4",
-			Filter: "select * from t4",
-		}},
-	}
-	bls := &binlogdatapb.BinlogSource{
-		Keyspace: env.KeyspaceName,
-		Shard:    env.ShardName,
-		Filter:   filter,
-		OnDdl:    binlogdatapb.OnDDLAction_IGNORE,
-	}
-	cancel, _ := startVReplication(t, bls, "")
-	defer cancel()
-
-	testcases := []struct {
-		input  string
-		output string
-		table  string
-		data   [][]string
-	}{{ //binary(2)
-		input:  "insert into t1 values(1, 'a')",
-		output: "insert into t1(id,val) values (1,'a')",
-		table:  "t1",
-		data: [][]string{
-			{"1", "a\000"},
-		},
-	}, {
-		input:  "update t1 set id = 2 where val = 'a\000'",
-		output: "update t1 set id=2 where val=cast('a' as binary(2))",
-		table:  "t1",
-		data: [][]string{
-			{"2", "a\000"},
-		},
-	}, { //char(2)
-		input:  "insert into t2 values(1, 'a')",
-		output: "insert into t2(id,val) values (1,'a')",
-		table:  "t2",
-		data: [][]string{
-			{"1", "a"},
-		},
-	}, {
-		input:  "update t2 set id = 2 where val = 'a'",
-		output: "update t2 set id=2 where val='a'",
-		table:  "t2",
-		data: [][]string{
-			{"2", "a"},
-		},
-	}, { //varbinary(2)
-		input:  "insert into t3 values(1, 'a')",
-		output: "insert into t3(id,val) values (1,'a')",
-		table:  "t3",
-		data: [][]string{
-			{"1", "a"},
-		},
-	}, {
-		input:  "update t3 set id = 2 where val = 'a'",
-		output: "update t3 set id=2 where val='a'",
-		table:  "t3",
-		data: [][]string{
-			{"2", "a"},
-		},
-	}, { //varchar(2)
-		input:  "insert into t4 values(1, 'a')",
-		output: "insert into t4(id,val) values (1,'a')",
-		table:  "t4",
-		data: [][]string{
-			{"1", "a"},
-		},
-	}, {
-		input:  "update t4 set id = 2 where val = 'a'",
-		output: "update t4 set id=2 where val='a'",
-		table:  "t4",
-		data: [][]string{
-			{"2", "a"},
-		},
-	}}
-
-	for _, tcases := range testcases {
-		execStatements(t, []string{tcases.input})
-		output := []string{
-			"begin",
-			tcases.output,
-			"/update _vt.vreplication set pos",
-			"commit",
-		}
-		expectDBClientQueries(t, output)
-		if tcases.table != "" {
-			expectData(t, tcases.table, tcases.data)
-		}
-	}
-}
-
 func TestRollup(t *testing.T) {
 	defer deleteTablet(addTablet(100))
 
@@ -1280,10 +1153,10 @@ func TestPlayerTypes(t *testing.T) {
 		},
 	}, {
 		input:  "insert into vitess_strings values('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a', 'a,b')",
-		output: "insert into vitess_strings(vb,c,vc,b,tb,bl,ttx,tx,en,s) values ('a','b','c','d','e','f','g','h','1','3')",
+		output: "insert into vitess_strings(vb,c,vc,b,tb,bl,ttx,tx,en,s) values ('a','b','c','d\\0\\0\\0','e','f','g','h','1','3')",
 		table:  "vitess_strings",
 		data: [][]string{
-			{"a", "b", "c", "d\000\000\000", "e", "f", "g", "h", "a", "a,b"},
+			{"a", "b", "c", "d\x00\x00\x00", "e", "f", "g", "h", "a", "a,b"},
 		},
 	}, {
 		input:  "insert into vitess_misc values(1, '\x01', '2012-01-01', '2012-01-01 15:45:45', '15:45:45', point(1, 2))",
@@ -1301,15 +1174,15 @@ func TestPlayerTypes(t *testing.T) {
 		},
 	}, {
 		input:  "insert into binary_pk values('a', 'aaa')",
-		output: "insert into binary_pk(b,val) values ('a','aaa')",
+		output: "insert into binary_pk(b,val) values ('a\\0\\0\\0','aaa')",
 		table:  "binary_pk",
 		data: [][]string{
-			{"a\000\000\000", "aaa"},
+			{"a\x00\x00\x00", "aaa"},
 		},
 	}, {
 		// Binary pk is a special case: https://github.com/vitessio/vitess/issues/3984
 		input:  "update binary_pk set val='bbb' where b='a\\0\\0\\0'",
-		output: "update binary_pk set val='bbb' where b=cast('a' as binary(4))",
+		output: "update binary_pk set val='bbb' where b='a\\0\\0\\0'",
 		table:  "binary_pk",
 		data: [][]string{
 			{"a\x00\x00\x00", "bbb"},
diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go
index 4ea6b4dc1d..baceab92f8 100644
--- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go
+++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go
@@ -53,47 +53,6 @@ func checkIfOptionIsSupported(t *testing.T, variable string) bool {
 	return false
 }
 
-func TestCellValuePadding(t *testing.T) {
-
-	execStatements(t, []string{
-		"create table t1(id int, val binary(4), primary key(val))",
-		"create table t2(id int, val char(4), primary key(val))",
-	})
-	defer execStatements(t, []string{
-		"drop table t1",
-		"drop table t2",
-	})
-	engine.se.Reload(context.Background())
-	queries := []string{
-		"begin",
-		"insert into t1 values (1, 'aaa')",
-		"insert into t1 values (2, 'bbb')",
-		"update t1 set id = 11 where val = 'aaa\000'",
-		"insert into t2 values (1, 'aaa')",
-		"insert into t2 values (2, 'bbb')",
-		"update t2 set id = 11 where val = 'aaa'",
-		"commit",
-	}
-
-	testcases := []testcase{{
-		input: queries,
-		output: [][]string{{
-			`begin`,
-			`type:FIELD field_event:<table_name:"t1" fields:<name:"id" type:INT32 table:"t1" org_table:"t1" database:"vttest" org_name:"id" column_length:11 charset:63 > fields:<name:"val" type:BINARY table:"t1" org_table:"t1" database:"vttest" org_name:"val" column_length:4 charset:63 > > `,
-			`type:ROW row_event:<table_name:"t1" row_changes:<after:<lengths:1 lengths:3 values:"1aaa" > > > `,
-			`type:ROW row_event:<table_name:"t1" row_changes:<after:<lengths:1 lengths:3 values:"2bbb" > > > `,
-			`type:ROW row_event:<table_name:"t1" row_changes:<before:<lengths:1 lengths:3 values:"1aaa" > after:<lengths:2 lengths:3 values:"11aaa" > > > `,
-			`type:FIELD field_event:<table_name:"t2" fields:<name:"id" type:INT32 table:"t2" org_table:"t2" database:"vttest" org_name:"id" column_length:11 charset:63 > fields:<name:"val" type:CHAR table:"t2" org_table:"t2" database:"vttest" org_name:"val" column_length:12 charset:33 > > `,
-			`type:ROW row_event:<table_name:"t2" row_changes:<after:<lengths:1 lengths:3 values:"1aaa" > > > `,
-			`type:ROW row_event:<table_name:"t2" row_changes:<after:<lengths:1 lengths:3 values:"2bbb" > > > `,
-			`type:ROW row_event:<table_name:"t2" row_changes:<before:<lengths:1 lengths:3 values:"1aaa" > after:<lengths:2 lengths:3 values:"11aaa" > > > `,
-			`gtid`,
-			`commit`,
-		}},
-	}}
-	runCases(t, nil, testcases, "current", nil)
-}
-
 func TestSetStatement(t *testing.T) {
 
 	if testing.Short() {
@@ -599,7 +558,6 @@ func TestSavepoint(t *testing.T) {
 	}}
 	runCases(t, nil, testcases, "current", nil)
 }
-
 func TestStatements(t *testing.T) {
 	if testing.Short() {
 		t.Skip()
@@ -1406,8 +1364,8 @@ func TestTypes(t *testing.T) {
 		output: [][]string{{
 			`begin`,
 			`type:FIELD field_event:<table_name:"vitess_strings" fields:<name:"vb" type:VARBINARY table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"vb" column_length:16 charset:63 > fields:<name:"c" type:CHAR table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"c" column_length:48 charset:33 > fields:<name:"vc" type:VARCHAR table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"vc" column_length:48 charset:33 > fields:<name:"b" type:BINARY table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"b" column_length:4 charset:63 > fields:<name:"tb" type:BLOB table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"tb" column_length:255 charset:63 > fields:<name:"bl" type:BLOB table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"bl" column_length:65535 charset:63 > fields:<name:"ttx" type:TEXT table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"ttx" column_length:765 charset:33 > fields:<name:"tx" type:TEXT table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"tx" column_length:196605 charset:33 > fields:<name:"en" type:ENUM table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"en" column_length:3 charset:33 > fields:<name:"s" type:SET table:"vitess_strings" org_table:"vitess_strings" database:"vttest" org_name:"s" column_length:9 charset:33 > > `,
-			`type:ROW row_event:<table_name:"vitess_strings" row_changes:<after:<lengths:1 lengths:1 lengths:1 lengths:1 lengths:1 lengths:1 lengths:1 lengths:1 lengths:1 lengths:1 ` +
-				`values:"abcdefgh13" > > > `,
+			`type:ROW row_event:<table_name:"vitess_strings" row_changes:<after:<lengths:1 lengths:1 lengths:1 lengths:4 lengths:1 lengths:1 lengths:1 lengths:1 lengths:1 lengths:1 ` +
+				`values:"abcd\000\000\000efgh13" > > > `,
 			`gtid`,
 			`commit`,
 		}},