diff --git a/pkg/sql/colexec/colexecbase/cast.eg.go b/pkg/sql/colexec/colexecbase/cast.eg.go
index 7507dd6d39c3..9d41c398fb09 100644
--- a/pkg/sql/colexec/colexecbase/cast.eg.go
+++ b/pkg/sql/colexec/colexecbase/cast.eg.go
@@ -17,6 +17,7 @@ import (
 	"strconv"
 	"strings"
 	"time"
+	"unicode/utf8"
 
 	"github.com/cockroachdb/apd/v3"
 	"github.com/cockroachdb/cockroach/pkg/col/coldata"
@@ -205,6 +206,12 @@ func GetCastOperator(
 					default:
 						return &castBoolIntOp{castOpBase: base}, nil
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castBoolStringOp{castOpBase: base}, nil
+					}
 				}
 			}
 		case types.BytesFamily:
@@ -212,6 +219,12 @@ func GetCastOperator(
 			case -1:
 			default:
 				switch toType.Family() {
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castBytesStringOp{castOpBase: base}, nil
+					}
 				case types.UuidFamily:
 					switch toType.Width() {
 					case -1:
@@ -247,6 +260,12 @@ func GetCastOperator(
 					default:
 						return &castDateIntOp{castOpBase: base}, nil
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castDateStringOp{castOpBase: base}, nil
+					}
 				}
 			}
 		case types.DecimalFamily:
@@ -282,6 +301,12 @@ func GetCastOperator(
 					default:
 						return &castDecimalIntOp{castOpBase: base}, nil
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castDecimalStringOp{castOpBase: base}, nil
+					}
 				}
 			}
 		case types.FloatFamily:
@@ -311,6 +336,12 @@ func GetCastOperator(
 					default:
 						return &castFloatIntOp{castOpBase: base}, nil
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castFloatStringOp{castOpBase: base}, nil
+					}
 				}
 			}
 		case types.IntFamily:
@@ -343,6 +374,12 @@ func GetCastOperator(
 					default:
 						return &castInt2IntOp{castOpBase: base}, nil
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castInt2StringOp{castOpBase: base}, nil
+					}
 				}
 			case 32:
 				switch toType.Family() {
@@ -372,6 +409,12 @@ func GetCastOperator(
 					default:
 						return &castInt4IntOp{castOpBase: base}, nil
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castInt4StringOp{castOpBase: base}, nil
+					}
 				}
 			case -1:
 			default:
@@ -401,6 +444,25 @@ func GetCastOperator(
 					case 32:
 						return &castIntInt4Op{castOpBase: base}, nil
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castIntStringOp{castOpBase: base}, nil
+					}
+				}
+			}
+		case types.IntervalFamily:
+			switch fromType.Width() {
+			case -1:
+			default:
+				switch toType.Family() {
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castIntervalStringOp{castOpBase: base}, nil
+					}
 				}
 			}
 		case types.JsonFamily:
@@ -499,6 +561,45 @@ func GetCastOperator(
 					}
 				}
 			}
+		case types.TimestampFamily:
+			switch fromType.Width() {
+			case -1:
+			default:
+				switch toType.Family() {
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castTimestampStringOp{castOpBase: base}, nil
+					}
+				}
+			}
+		case types.TimestampTZFamily:
+			switch fromType.Width() {
+			case -1:
+			default:
+				switch toType.Family() {
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castTimestamptzStringOp{castOpBase: base}, nil
+					}
+				}
+			}
+		case types.UuidFamily:
+			switch fromType.Width() {
+			case -1:
+			default:
+				switch toType.Family() {
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return &castUuidStringOp{castOpBase: base}, nil
+					}
+				}
+			}
 		}
 	}
 	return nil, errors.Errorf("unhandled cast %s -> %s", fromType.SQLString(), toType.SQLString())
@@ -621,6 +722,12 @@ func IsCastSupported(fromType, toType *types.T) bool {
 					default:
 						return true
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
 				}
 			}
 		case types.BytesFamily:
@@ -628,6 +735,12 @@ func IsCastSupported(fromType, toType *types.T) bool {
 			case -1:
 			default:
 				switch toType.Family() {
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
 				case types.UuidFamily:
 					switch toType.Width() {
 					case -1:
@@ -663,6 +776,12 @@ func IsCastSupported(fromType, toType *types.T) bool {
 					default:
 						return true
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
 				}
 			}
 		case types.DecimalFamily:
@@ -698,6 +817,12 @@ func IsCastSupported(fromType, toType *types.T) bool {
 					default:
 						return true
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
 				}
 			}
 		case types.FloatFamily:
@@ -727,6 +852,12 @@ func IsCastSupported(fromType, toType *types.T) bool {
 					default:
 						return true
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
 				}
 			}
 		case types.IntFamily:
@@ -759,6 +890,12 @@ func IsCastSupported(fromType, toType *types.T) bool {
 					default:
 						return true
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
 				}
 			case 32:
 				switch toType.Family() {
@@ -788,6 +925,12 @@ func IsCastSupported(fromType, toType *types.T) bool {
 					default:
 						return true
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
 				}
 			case -1:
 			default:
@@ -817,6 +960,25 @@ func IsCastSupported(fromType, toType *types.T) bool {
 					case 32:
 						return true
 					}
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
+				}
+			}
+		case types.IntervalFamily:
+			switch fromType.Width() {
+			case -1:
+			default:
+				switch toType.Family() {
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
 				}
 			}
 		case types.JsonFamily:
@@ -915,6 +1077,45 @@ func IsCastSupported(fromType, toType *types.T) bool {
 					}
 				}
 			}
+		case types.TimestampFamily:
+			switch fromType.Width() {
+			case -1:
+			default:
+				switch toType.Family() {
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
+				}
+			}
+		case types.TimestampTZFamily:
+			switch fromType.Width() {
+			case -1:
+			default:
+				switch toType.Family() {
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
+				}
+			}
+		case types.UuidFamily:
+			switch fromType.Width() {
+			case -1:
+			default:
+				switch toType.Family() {
+				case types.StringFamily:
+					switch toType.Width() {
+					case -1:
+					default:
+						return true
+					}
+				}
+			}
 		}
 	}
 	return false
@@ -927,6 +1128,7 @@ type castOpBase struct {
 	colIdx    int
 	outputIdx int
 	evalCtx   *eval.Context
+	buf       bytes.Buffer
 }
 
 func (c *castOpBase) Reset(ctx context.Context) {
@@ -1164,9 +1366,13 @@ func (c *castBoolFloatOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1186,9 +1392,13 @@ func (c *castBoolFloatOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -1214,9 +1424,13 @@ func (c *castBoolFloatOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1236,9 +1450,13 @@ func (c *castBoolFloatOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -1296,9 +1514,13 @@ func (c *castBoolInt2Op) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1318,9 +1540,13 @@ func (c *castBoolInt2Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -1346,9 +1572,13 @@ func (c *castBoolInt2Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1368,9 +1598,13 @@ func (c *castBoolInt2Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -1428,9 +1662,13 @@ func (c *castBoolInt4Op) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1450,9 +1688,13 @@ func (c *castBoolInt4Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -1478,9 +1720,13 @@ func (c *castBoolInt4Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1500,9 +1746,13 @@ func (c *castBoolInt4Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -1560,9 +1810,13 @@ func (c *castBoolIntOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1582,9 +1836,13 @@ func (c *castBoolIntOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -1610,9 +1868,13 @@ func (c *castBoolIntOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1632,9 +1894,13 @@ func (c *castBoolIntOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -1663,14 +1929,14 @@ func (c *castBoolIntOp) Next() coldata.Batch {
 	return batch
 }
 
-type castBytesUuidOp struct {
+type castBoolStringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castBytesUuidOp{}
-var _ colexecop.ClosableOperator = &castBytesUuidOp{}
+var _ colexecop.ResettableOperator = &castBoolStringOp{}
+var _ colexecop.ClosableOperator = &castBoolStringOp{}
 
-func (c *castBytesUuidOp) Next() coldata.Batch {
+func (c *castBoolStringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -1684,7 +1950,7 @@ func (c *castBytesUuidOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Bytes()
+			inputCol := inputVec.Bool()
 			inputNulls := inputVec.Nulls()
 			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
@@ -1692,9 +1958,13 @@ func (c *castBytesUuidOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1704,34 +1974,74 @@ func (c *castBytesUuidOp) Next() coldata.Batch {
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							_uuid, err := uuid.FromBytes(v)
-							if err != nil {
-								colexecerror.ExpectedError(err)
-							}
-							r = _uuid.GetBytes()
-
-							outputCol.Set(tupleIdx, r)
-						}
-					}
-				} else {
-					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+							r = []byte(strconv.FormatBool(v))
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							_uuid, err := uuid.FromBytes(v)
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							r = []byte(strconv.FormatBool(v))
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
-							r = _uuid.GetBytes()
 
 							outputCol.Set(tupleIdx, r)
 						}
@@ -1740,9 +2050,13 @@ func (c *castBytesUuidOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1752,34 +2066,74 @@ func (c *castBytesUuidOp) Next() coldata.Batch {
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							_uuid, err := uuid.FromBytes(v)
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							r = []byte(strconv.FormatBool(v))
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
-							r = _uuid.GetBytes()
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							_uuid, err := uuid.FromBytes(v)
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							r = []byte(strconv.FormatBool(v))
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
-							r = _uuid.GetBytes()
 
 							outputCol.Set(tupleIdx, r)
 						}
@@ -1791,14 +2145,14 @@ func (c *castBytesUuidOp) Next() coldata.Batch {
 	return batch
 }
 
-type castDateDecimalOp struct {
+type castBytesStringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castDateDecimalOp{}
-var _ colexecop.ClosableOperator = &castDateDecimalOp{}
+var _ colexecop.ResettableOperator = &castBytesStringOp{}
+var _ colexecop.ClosableOperator = &castBytesStringOp{}
 
-func (c *castDateDecimalOp) Next() coldata.Batch {
+func (c *castBytesStringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -1812,17 +2166,21 @@ func (c *castDateDecimalOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int64()
+			inputCol := inputVec.Bytes()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Decimal()
+			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1830,12 +2188,31 @@ func (c *castDateDecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
+							var r []byte
 
-							r.SetInt64(int64(v))
+							_format := evalCtx.SessionData().DataConversionConfig.BytesEncodeFormat
+							r = []byte(lex.EncodeByteArrayToRawBytes(string(v), _format, false /* skipHexPrefix */))
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -1843,28 +2220,47 @@ func (c *castDateDecimalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
-							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
+							var r []byte
 
-							r.SetInt64(int64(v))
+							_format := evalCtx.SessionData().DataConversionConfig.BytesEncodeFormat
+							r = []byte(lex.EncodeByteArrayToRawBytes(string(v), _format, false /* skipHexPrefix */))
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -1872,9 +2268,13 @@ func (c *castDateDecimalOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1882,12 +2282,31 @@ func (c *castDateDecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
+							var r []byte
 
-							r.SetInt64(int64(v))
+							_format := evalCtx.SessionData().DataConversionConfig.BytesEncodeFormat
+							r = []byte(lex.EncodeByteArrayToRawBytes(string(v), _format, false /* skipHexPrefix */))
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -1895,28 +2314,47 @@ func (c *castDateDecimalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
-							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
+							var r []byte
 
-							r.SetInt64(int64(v))
+							_format := evalCtx.SessionData().DataConversionConfig.BytesEncodeFormat
+							r = []byte(lex.EncodeByteArrayToRawBytes(string(v), _format, false /* skipHexPrefix */))
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -1927,14 +2365,14 @@ func (c *castDateDecimalOp) Next() coldata.Batch {
 	return batch
 }
 
-type castDateFloatOp struct {
+type castBytesUuidOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castDateFloatOp{}
-var _ colexecop.ClosableOperator = &castDateFloatOp{}
+var _ colexecop.ResettableOperator = &castBytesUuidOp{}
+var _ colexecop.ClosableOperator = &castBytesUuidOp{}
 
-func (c *castDateFloatOp) Next() coldata.Batch {
+func (c *castBytesUuidOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -1948,17 +2386,21 @@ func (c *castDateFloatOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int64()
+			inputCol := inputVec.Bytes()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Float64()
+			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -1966,33 +2408,41 @@ func (c *castDateFloatOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r []byte
 
-							r = float64(v)
+							_uuid, err := uuid.FromBytes(v)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							r = _uuid.GetBytes()
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
-							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r []byte
 
-							r = float64(v)
+							_uuid, err := uuid.FromBytes(v)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							r = _uuid.GetBytes()
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -2000,9 +2450,13 @@ func (c *castDateFloatOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2010,33 +2464,41 @@ func (c *castDateFloatOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r []byte
 
-							r = float64(v)
+							_uuid, err := uuid.FromBytes(v)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							r = _uuid.GetBytes()
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
-							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r []byte
 
-							r = float64(v)
+							_uuid, err := uuid.FromBytes(v)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							r = _uuid.GetBytes()
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -2047,14 +2509,14 @@ func (c *castDateFloatOp) Next() coldata.Batch {
 	return batch
 }
 
-type castDateInt2Op struct {
+type castDateDecimalOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castDateInt2Op{}
-var _ colexecop.ClosableOperator = &castDateInt2Op{}
+var _ colexecop.ResettableOperator = &castDateDecimalOp{}
+var _ colexecop.ClosableOperator = &castDateDecimalOp{}
 
-func (c *castDateInt2Op) Next() coldata.Batch {
+func (c *castDateDecimalOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -2070,15 +2532,19 @@ func (c *castDateInt2Op) Next() coldata.Batch {
 		[]coldata.Vec{outputVec}, func() {
 			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int16()
+			outputCol := outputVec.Decimal()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2086,22 +2552,26 @@ func (c *castDateInt2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r apd.Decimal
 
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
 							}
-							r = int16(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2112,13 +2582,13 @@ func (c *castDateInt2Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r apd.Decimal
 
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
 							}
-							r = int16(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -2128,9 +2598,13 @@ func (c *castDateInt2Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2138,22 +2612,26 @@ func (c *castDateInt2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r apd.Decimal
 
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
 							}
-							r = int16(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2164,13 +2642,13 @@ func (c *castDateInt2Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r apd.Decimal
 
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
 							}
-							r = int16(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -2183,14 +2661,14 @@ func (c *castDateInt2Op) Next() coldata.Batch {
 	return batch
 }
 
-type castDateInt4Op struct {
+type castDateFloatOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castDateInt4Op{}
-var _ colexecop.ClosableOperator = &castDateInt4Op{}
+var _ colexecop.ResettableOperator = &castDateFloatOp{}
+var _ colexecop.ClosableOperator = &castDateFloatOp{}
 
-func (c *castDateInt4Op) Next() coldata.Batch {
+func (c *castDateFloatOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -2206,15 +2684,19 @@ func (c *castDateInt4Op) Next() coldata.Batch {
 		[]coldata.Vec{outputVec}, func() {
 			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int32()
+			outputCol := outputVec.Float64()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2222,22 +2704,22 @@ func (c *castDateInt4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r float64
 
-							shifted := v >> uint(31)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-							}
-							r = int32(v)
+							r = float64(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2248,13 +2730,9 @@ func (c *castDateInt4Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r float64
 
-							shifted := v >> uint(31)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-							}
-							r = int32(v)
+							r = float64(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -2264,9 +2742,13 @@ func (c *castDateInt4Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2274,22 +2756,22 @@ func (c *castDateInt4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r float64
 
-							shifted := v >> uint(31)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-							}
-							r = int32(v)
+							r = float64(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2300,13 +2782,9 @@ func (c *castDateInt4Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r float64
 
-							shifted := v >> uint(31)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-							}
-							r = int32(v)
+							r = float64(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -2319,14 +2797,14 @@ func (c *castDateInt4Op) Next() coldata.Batch {
 	return batch
 }
 
-type castDateIntOp struct {
+type castDateInt2Op struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castDateIntOp{}
-var _ colexecop.ClosableOperator = &castDateIntOp{}
+var _ colexecop.ResettableOperator = &castDateInt2Op{}
+var _ colexecop.ClosableOperator = &castDateInt2Op{}
 
-func (c *castDateIntOp) Next() coldata.Batch {
+func (c *castDateInt2Op) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -2342,15 +2820,19 @@ func (c *castDateIntOp) Next() coldata.Batch {
 		[]coldata.Vec{outputVec}, func() {
 			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int64()
+			outputCol := outputVec.Int16()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2358,16 +2840,26 @@ func (c *castDateIntOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
-							r = int64(v)
+							var r int16
+
+							shifted := v >> uint(15)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+							}
+							r = int16(v)
+
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2378,8 +2870,14 @@ func (c *castDateIntOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
-							r = int64(v)
+							var r int16
+
+							shifted := v >> uint(15)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+							}
+							r = int16(v)
+
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -2388,9 +2886,13 @@ func (c *castDateIntOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2398,16 +2900,26 @@ func (c *castDateIntOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
-							r = int64(v)
+							var r int16
+
+							shifted := v >> uint(15)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+							}
+							r = int16(v)
+
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2418,8 +2930,14 @@ func (c *castDateIntOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
-							r = int64(v)
+							var r int16
+
+							shifted := v >> uint(15)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+							}
+							r = int16(v)
+
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -2431,14 +2949,14 @@ func (c *castDateIntOp) Next() coldata.Batch {
 	return batch
 }
 
-type castDecimalBoolOp struct {
+type castDateInt4Op struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castDecimalBoolOp{}
-var _ colexecop.ClosableOperator = &castDecimalBoolOp{}
+var _ colexecop.ResettableOperator = &castDateInt4Op{}
+var _ colexecop.ClosableOperator = &castDateInt4Op{}
 
-func (c *castDecimalBoolOp) Next() coldata.Batch {
+func (c *castDateInt4Op) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -2452,17 +2970,21 @@ func (c *castDecimalBoolOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Decimal()
+			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Bool()
+			outputCol := outputVec.Int32()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2470,16 +2992,26 @@ func (c *castDecimalBoolOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r bool
-							r = v.Sign() != 0
+							var r int32
+
+							shifted := v >> uint(31)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+							}
+							r = int32(v)
+
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2490,8 +3022,14 @@ func (c *castDecimalBoolOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r bool
-							r = v.Sign() != 0
+							var r int32
+
+							shifted := v >> uint(31)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+							}
+							r = int32(v)
+
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -2500,9 +3038,13 @@ func (c *castDecimalBoolOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2510,16 +3052,26 @@ func (c *castDecimalBoolOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r bool
-							r = v.Sign() != 0
+							var r int32
+
+							shifted := v >> uint(31)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+							}
+							r = int32(v)
+
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2530,8 +3082,14 @@ func (c *castDecimalBoolOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r bool
-							r = v.Sign() != 0
+							var r int32
+
+							shifted := v >> uint(31)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+							}
+							r = int32(v)
+
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -2543,14 +3101,14 @@ func (c *castDecimalBoolOp) Next() coldata.Batch {
 	return batch
 }
 
-type castDecimalDecimalOp struct {
+type castDateIntOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castDecimalDecimalOp{}
-var _ colexecop.ClosableOperator = &castDecimalDecimalOp{}
+var _ colexecop.ResettableOperator = &castDateIntOp{}
+var _ colexecop.ClosableOperator = &castDateIntOp{}
 
-func (c *castDecimalDecimalOp) Next() coldata.Batch {
+func (c *castDateIntOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -2564,17 +3122,21 @@ func (c *castDecimalDecimalOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Decimal()
+			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Decimal()
+			outputCol := outputVec.Int64()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2582,21 +3144,20 @@ func (c *castDecimalDecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							r.Set(&v)
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
-
+							var r int64
+							r = int64(v)
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2607,13 +3168,8 @@ func (c *castDecimalDecimalOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							r.Set(&v)
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
-
+							var r int64
+							r = int64(v)
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -2622,9 +3178,13 @@ func (c *castDecimalDecimalOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2632,21 +3192,20 @@ func (c *castDecimalDecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							r.Set(&v)
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
-
+							var r int64
+							r = int64(v)
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2657,13 +3216,8 @@ func (c *castDecimalDecimalOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							r.Set(&v)
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
-
+							var r int64
+							r = int64(v)
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -2675,14 +3229,14 @@ func (c *castDecimalDecimalOp) Next() coldata.Batch {
 	return batch
 }
 
-type castDecimalFloatOp struct {
+type castDateStringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castDecimalFloatOp{}
-var _ colexecop.ClosableOperator = &castDecimalFloatOp{}
+var _ colexecop.ResettableOperator = &castDateStringOp{}
+var _ colexecop.ClosableOperator = &castDateStringOp{}
 
-func (c *castDecimalFloatOp) Next() coldata.Batch {
+func (c *castDateStringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -2696,17 +3250,21 @@ func (c *castDecimalFloatOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Decimal()
+			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Float64()
+			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2714,14 +3272,33 @@ func (c *castDecimalFloatOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r []byte
 
-							{
-								f, err := v.Float64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrFloatOutOfRange)
+							_date := pgdate.MakeCompatibleDateFromDisk(v)
+							buf.Reset()
+							_date.Format(buf)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
 								}
-								r = f
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -2729,11 +3306,14 @@ func (c *castDecimalFloatOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -2742,17 +3322,35 @@ func (c *castDecimalFloatOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r []byte
 
-							{
-								f, err := v.Float64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrFloatOutOfRange)
+							_date := pgdate.MakeCompatibleDateFromDisk(v)
+							buf.Reset()
+							_date.Format(buf)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
 								}
-								r = f
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -2760,9 +3358,13 @@ func (c *castDecimalFloatOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2770,14 +3372,33 @@ func (c *castDecimalFloatOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r []byte
 
-							{
-								f, err := v.Float64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrFloatOutOfRange)
+							_date := pgdate.MakeCompatibleDateFromDisk(v)
+							buf.Reset()
+							_date.Format(buf)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
 								}
-								r = f
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -2785,11 +3406,14 @@ func (c *castDecimalFloatOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -2798,17 +3422,35 @@ func (c *castDecimalFloatOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r []byte
 
-							{
-								f, err := v.Float64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrFloatOutOfRange)
+							_date := pgdate.MakeCompatibleDateFromDisk(v)
+							buf.Reset()
+							_date.Format(buf)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
 								}
-								r = f
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -2819,14 +3461,14 @@ func (c *castDecimalFloatOp) Next() coldata.Batch {
 	return batch
 }
 
-type castDecimalInt2Op struct {
+type castDecimalBoolOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castDecimalInt2Op{}
-var _ colexecop.ClosableOperator = &castDecimalInt2Op{}
+var _ colexecop.ResettableOperator = &castDecimalBoolOp{}
+var _ colexecop.ClosableOperator = &castDecimalBoolOp{}
 
-func (c *castDecimalInt2Op) Next() coldata.Batch {
+func (c *castDecimalBoolOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -2842,15 +3484,19 @@ func (c *castDecimalInt2Op) Next() coldata.Batch {
 		[]coldata.Vec{outputVec}, func() {
 			inputCol := inputVec.Decimal()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int16()
+			outputCol := outputVec.Bool()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2858,35 +3504,20 @@ func (c *castDecimalInt2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-
-								shifted := _i >> uint(15)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-								r = int16(_i)
-
-							}
-
+							var r bool
+							r = v.Sign() != 0
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2897,27 +3528,8 @@ func (c *castDecimalInt2Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-
-								shifted := _i >> uint(15)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-								r = int16(_i)
-
-							}
-
+							var r bool
+							r = v.Sign() != 0
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -2926,9 +3538,13 @@ func (c *castDecimalInt2Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -2936,35 +3552,20 @@ func (c *castDecimalInt2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-
-								shifted := _i >> uint(15)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-								r = int16(_i)
-
-							}
-
+							var r bool
+							r = v.Sign() != 0
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -2975,27 +3576,8 @@ func (c *castDecimalInt2Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-
-								shifted := _i >> uint(15)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-								r = int16(_i)
-
-							}
-
+							var r bool
+							r = v.Sign() != 0
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -3007,14 +3589,14 @@ func (c *castDecimalInt2Op) Next() coldata.Batch {
 	return batch
 }
 
-type castDecimalInt4Op struct {
+type castDecimalDecimalOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castDecimalInt4Op{}
-var _ colexecop.ClosableOperator = &castDecimalInt4Op{}
+var _ colexecop.ResettableOperator = &castDecimalDecimalOp{}
+var _ colexecop.ClosableOperator = &castDecimalDecimalOp{}
 
-func (c *castDecimalInt4Op) Next() coldata.Batch {
+func (c *castDecimalDecimalOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -3030,15 +3612,19 @@ func (c *castDecimalInt4Op) Next() coldata.Batch {
 		[]coldata.Vec{outputVec}, func() {
 			inputCol := inputVec.Decimal()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int32()
+			outputCol := outputVec.Decimal()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
-						_ = evalCtx
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3046,25 +3632,11 @@ func (c *castDecimalInt4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
-
-							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-								}
-
-								shifted := _i >> uint(31)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-								}
-								r = int32(_i)
+							var r apd.Decimal
 
+							r.Set(&v)
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -3072,9 +3644,13 @@ func (c *castDecimalInt4Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -3085,25 +3661,11 @@ func (c *castDecimalInt4Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
-
-							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-								}
-
-								shifted := _i >> uint(31)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-								}
-								r = int32(_i)
+							var r apd.Decimal
 
+							r.Set(&v)
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
 							}
 
 							//gcassert:bce
@@ -3114,9 +3676,13 @@ func (c *castDecimalInt4Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3124,25 +3690,11 @@ func (c *castDecimalInt4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
-
-							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-								}
-
-								shifted := _i >> uint(31)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-								}
-								r = int32(_i)
+							var r apd.Decimal
 
+							r.Set(&v)
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -3150,9 +3702,13 @@ func (c *castDecimalInt4Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -3163,25 +3719,11 @@ func (c *castDecimalInt4Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
-
-							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
-								if err != nil {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-								}
-
-								shifted := _i >> uint(31)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
-								}
-								r = int32(_i)
+							var r apd.Decimal
 
+							r.Set(&v)
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
 							}
 
 							//gcassert:bce
@@ -3195,14 +3737,14 @@ func (c *castDecimalInt4Op) Next() coldata.Batch {
 	return batch
 }
 
-type castDecimalIntOp struct {
+type castDecimalFloatOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castDecimalIntOp{}
-var _ colexecop.ClosableOperator = &castDecimalIntOp{}
+var _ colexecop.ResettableOperator = &castDecimalFloatOp{}
+var _ colexecop.ClosableOperator = &castDecimalFloatOp{}
 
-func (c *castDecimalIntOp) Next() coldata.Batch {
+func (c *castDecimalFloatOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -3218,15 +3760,19 @@ func (c *castDecimalIntOp) Next() coldata.Batch {
 		[]coldata.Vec{outputVec}, func() {
 			inputCol := inputVec.Decimal()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int64()
+			outputCol := outputVec.Float64()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3234,19 +3780,14 @@ func (c *castDecimalIntOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r float64
 
 							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
+								f, err := v.Float64()
 								if err != nil {
-									colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+									colexecerror.ExpectedError(tree.ErrFloatOutOfRange)
 								}
-								r = int64(_i)
+								r = f
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -3254,9 +3795,13 @@ func (c *castDecimalIntOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -3267,19 +3812,14 @@ func (c *castDecimalIntOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r float64
 
 							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
+								f, err := v.Float64()
 								if err != nil {
-									colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+									colexecerror.ExpectedError(tree.ErrFloatOutOfRange)
 								}
-								r = int64(_i)
+								r = f
 							}
 
 							//gcassert:bce
@@ -3290,9 +3830,13 @@ func (c *castDecimalIntOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3300,19 +3844,14 @@ func (c *castDecimalIntOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r float64
 
 							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
+								f, err := v.Float64()
 								if err != nil {
-									colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+									colexecerror.ExpectedError(tree.ErrFloatOutOfRange)
 								}
-								r = int64(_i)
+								r = f
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -3320,9 +3859,13 @@ func (c *castDecimalIntOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -3333,19 +3876,14 @@ func (c *castDecimalIntOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r float64
 
 							{
-								var tmpDec apd.Decimal //gcassert:noescape
-								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
-								if err != nil {
-									colexecerror.ExpectedError(err)
-								}
-								_i, err := tmpDec.Int64()
+								f, err := v.Float64()
 								if err != nil {
-									colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+									colexecerror.ExpectedError(tree.ErrFloatOutOfRange)
 								}
-								r = int64(_i)
+								r = f
 							}
 
 							//gcassert:bce
@@ -3359,14 +3897,14 @@ func (c *castDecimalIntOp) Next() coldata.Batch {
 	return batch
 }
 
-type castFloatBoolOp struct {
+type castDecimalInt2Op struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castFloatBoolOp{}
-var _ colexecop.ClosableOperator = &castFloatBoolOp{}
+var _ colexecop.ResettableOperator = &castDecimalInt2Op{}
+var _ colexecop.ClosableOperator = &castDecimalInt2Op{}
 
-func (c *castFloatBoolOp) Next() coldata.Batch {
+func (c *castDecimalInt2Op) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -3380,17 +3918,21 @@ func (c *castFloatBoolOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Float64()
+			inputCol := inputVec.Decimal()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Bool()
+			outputCol := outputVec.Int16()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3398,18 +3940,39 @@ func (c *castFloatBoolOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r int16
 
-							r = v != 0
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
+
+								shifted := _i >> uint(15)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
+								r = int16(_i)
+
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -3420,9 +3983,26 @@ func (c *castFloatBoolOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r int16
 
-							r = v != 0
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
+
+								shifted := _i >> uint(15)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
+								r = int16(_i)
+
+							}
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -3432,9 +4012,13 @@ func (c *castFloatBoolOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3442,18 +4026,39 @@ func (c *castFloatBoolOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r int16
 
-							r = v != 0
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
 
-							outputCol.Set(tupleIdx, r)
-						}
-					}
-				} else {
-					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+								shifted := _i >> uint(15)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
+								r = int16(_i)
+
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -3464,9 +4069,26 @@ func (c *castFloatBoolOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r int16
 
-							r = v != 0
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
+
+								shifted := _i >> uint(15)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
+								r = int16(_i)
+
+							}
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -3479,14 +4101,14 @@ func (c *castFloatBoolOp) Next() coldata.Batch {
 	return batch
 }
 
-type castFloatDecimalOp struct {
+type castDecimalInt4Op struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castFloatDecimalOp{}
-var _ colexecop.ClosableOperator = &castFloatDecimalOp{}
+var _ colexecop.ResettableOperator = &castDecimalInt4Op{}
+var _ colexecop.ClosableOperator = &castDecimalInt4Op{}
 
-func (c *castFloatDecimalOp) Next() coldata.Batch {
+func (c *castDecimalInt4Op) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -3500,17 +4122,21 @@ func (c *castFloatDecimalOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Float64()
+			inputCol := inputVec.Decimal()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Decimal()
+			outputCol := outputVec.Int32()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3518,14 +4144,25 @@ func (c *castFloatDecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
+							var r int32
 
-							if _, err := r.SetFloat64(float64(v)); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+
+								shifted := _i >> uint(31)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+								r = int32(_i)
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -3533,9 +4170,13 @@ func (c *castFloatDecimalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -3546,14 +4187,25 @@ func (c *castFloatDecimalOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
+							var r int32
 
-							if _, err := r.SetFloat64(float64(v)); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+
+								shifted := _i >> uint(31)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+								r = int32(_i)
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
 							}
 
 							//gcassert:bce
@@ -3564,9 +4216,13 @@ func (c *castFloatDecimalOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3574,14 +4230,25 @@ func (c *castFloatDecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
+							var r int32
 
-							if _, err := r.SetFloat64(float64(v)); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+
+								shifted := _i >> uint(31)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+								r = int32(_i)
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -3589,9 +4256,13 @@ func (c *castFloatDecimalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -3602,14 +4273,25 @@ func (c *castFloatDecimalOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
+							var r int32
 
-							if _, err := r.SetFloat64(float64(v)); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+
+								shifted := _i >> uint(31)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+								r = int32(_i)
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
 							}
 
 							//gcassert:bce
@@ -3623,14 +4305,14 @@ func (c *castFloatDecimalOp) Next() coldata.Batch {
 	return batch
 }
 
-type castFloatInt2Op struct {
+type castDecimalIntOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castFloatInt2Op{}
-var _ colexecop.ClosableOperator = &castFloatInt2Op{}
+var _ colexecop.ResettableOperator = &castDecimalIntOp{}
+var _ colexecop.ClosableOperator = &castDecimalIntOp{}
 
-func (c *castFloatInt2Op) Next() coldata.Batch {
+func (c *castDecimalIntOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -3644,17 +4326,21 @@ func (c *castFloatInt2Op) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Float64()
+			inputCol := inputVec.Decimal()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int16()
+			outputCol := outputVec.Int64()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3662,21 +4348,33 @@ func (c *castFloatInt2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r int64
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt16) || v >= float64(math.MaxInt16) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+								}
+								r = int64(_i)
 							}
-							r = int16(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -3687,12 +4385,20 @@ func (c *castFloatInt2Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r int64
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt16) || v >= float64(math.MaxInt16) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+								}
+								r = int64(_i)
 							}
-							r = int16(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -3702,9 +4408,13 @@ func (c *castFloatInt2Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3712,21 +4422,33 @@ func (c *castFloatInt2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r int64
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt16) || v >= float64(math.MaxInt16) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+								}
+								r = int64(_i)
 							}
-							r = int16(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -3737,12 +4459,20 @@ func (c *castFloatInt2Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r int64
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt16) || v >= float64(math.MaxInt16) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							{
+								var tmpDec apd.Decimal //gcassert:noescape
+								_, err := tree.DecimalCtx.RoundToIntegralValue(&tmpDec, &v)
+								if err != nil {
+									colexecerror.ExpectedError(err)
+								}
+								_i, err := tmpDec.Int64()
+								if err != nil {
+									colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+								}
+								r = int64(_i)
 							}
-							r = int16(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -3755,14 +4485,14 @@ func (c *castFloatInt2Op) Next() coldata.Batch {
 	return batch
 }
 
-type castFloatInt4Op struct {
+type castDecimalStringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castFloatInt4Op{}
-var _ colexecop.ClosableOperator = &castFloatInt4Op{}
+var _ colexecop.ResettableOperator = &castDecimalStringOp{}
+var _ colexecop.ClosableOperator = &castDecimalStringOp{}
 
-func (c *castFloatInt4Op) Next() coldata.Batch {
+func (c *castDecimalStringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -3776,17 +4506,21 @@ func (c *castFloatInt4Op) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Float64()
+			inputCol := inputVec.Decimal()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int32()
+			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3794,23 +4528,44 @@ func (c *castFloatInt4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r []byte
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt32) || v >= float64(math.MaxInt32) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
-							}
-							r = int32(v)
+							r = []byte(v.String())
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -3819,14 +4574,31 @@ func (c *castFloatInt4Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r []byte
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt32) || v >= float64(math.MaxInt32) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							r = []byte(v.String())
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
-							r = int32(v)
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -3834,9 +4606,13 @@ func (c *castFloatInt4Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3844,23 +4620,44 @@ func (c *castFloatInt4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r []byte
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt32) || v >= float64(math.MaxInt32) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							r = []byte(v.String())
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
-							r = int32(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -3869,14 +4666,31 @@ func (c *castFloatInt4Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r []byte
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt32) || v >= float64(math.MaxInt32) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							r = []byte(v.String())
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
-							r = int32(v)
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -3887,14 +4701,14 @@ func (c *castFloatInt4Op) Next() coldata.Batch {
 	return batch
 }
 
-type castFloatIntOp struct {
+type castFloatBoolOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castFloatIntOp{}
-var _ colexecop.ClosableOperator = &castFloatIntOp{}
+var _ colexecop.ResettableOperator = &castFloatBoolOp{}
+var _ colexecop.ClosableOperator = &castFloatBoolOp{}
 
-func (c *castFloatIntOp) Next() coldata.Batch {
+func (c *castFloatBoolOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -3910,15 +4724,19 @@ func (c *castFloatIntOp) Next() coldata.Batch {
 		[]coldata.Vec{outputVec}, func() {
 			inputCol := inputVec.Float64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int64()
+			outputCol := outputVec.Bool()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3926,21 +4744,22 @@ func (c *castFloatIntOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r bool
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
-							}
-							r = int64(v)
+							r = v != 0
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -3951,12 +4770,9 @@ func (c *castFloatIntOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r bool
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
-							}
-							r = int64(v)
+							r = v != 0
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -3966,9 +4782,13 @@ func (c *castFloatIntOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -3976,21 +4796,22 @@ func (c *castFloatIntOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r bool
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
-							}
-							r = int64(v)
+							r = v != 0
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4001,12 +4822,9 @@ func (c *castFloatIntOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r bool
 
-							if math.IsNaN(float64(v)) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) {
-								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
-							}
-							r = int64(v)
+							r = v != 0
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -4019,14 +4837,14 @@ func (c *castFloatIntOp) Next() coldata.Batch {
 	return batch
 }
 
-type castInt2BoolOp struct {
+type castFloatDecimalOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castInt2BoolOp{}
-var _ colexecop.ClosableOperator = &castInt2BoolOp{}
+var _ colexecop.ResettableOperator = &castFloatDecimalOp{}
+var _ colexecop.ClosableOperator = &castFloatDecimalOp{}
 
-func (c *castInt2BoolOp) Next() coldata.Batch {
+func (c *castFloatDecimalOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -4040,17 +4858,21 @@ func (c *castInt2BoolOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int16()
+			inputCol := inputVec.Float64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Bool()
+			outputCol := outputVec.Decimal()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4058,18 +4880,28 @@ func (c *castInt2BoolOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r apd.Decimal
 
-							r = v != 0
+							if _, err := r.SetFloat64(float64(v)); err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4080,9 +4912,15 @@ func (c *castInt2BoolOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r apd.Decimal
 
-							r = v != 0
+							if _, err := r.SetFloat64(float64(v)); err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -4092,9 +4930,13 @@ func (c *castInt2BoolOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4102,18 +4944,28 @@ func (c *castInt2BoolOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r apd.Decimal
 
-							r = v != 0
+							if _, err := r.SetFloat64(float64(v)); err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4124,9 +4976,15 @@ func (c *castInt2BoolOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r apd.Decimal
 
-							r = v != 0
+							if _, err := r.SetFloat64(float64(v)); err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -4139,14 +4997,14 @@ func (c *castInt2BoolOp) Next() coldata.Batch {
 	return batch
 }
 
-type castInt2DecimalOp struct {
+type castFloatInt2Op struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castInt2DecimalOp{}
-var _ colexecop.ClosableOperator = &castInt2DecimalOp{}
+var _ colexecop.ResettableOperator = &castFloatInt2Op{}
+var _ colexecop.ClosableOperator = &castFloatInt2Op{}
 
-func (c *castInt2DecimalOp) Next() coldata.Batch {
+func (c *castFloatInt2Op) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -4160,17 +5018,21 @@ func (c *castInt2DecimalOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int16()
+			inputCol := inputVec.Float64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Decimal()
+			outputCol := outputVec.Int16()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4178,22 +5040,25 @@ func (c *castInt2DecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							r.SetInt64(int64(v))
+							var r int16
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt16) || v >= float64(math.MaxInt16) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
 							}
+							r = int16(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4204,13 +5069,12 @@ func (c *castInt2DecimalOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							r.SetInt64(int64(v))
+							var r int16
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt16) || v >= float64(math.MaxInt16) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
 							}
+							r = int16(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -4220,9 +5084,13 @@ func (c *castInt2DecimalOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4230,22 +5098,25 @@ func (c *castInt2DecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							r.SetInt64(int64(v))
+							var r int16
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt16) || v >= float64(math.MaxInt16) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
 							}
+							r = int16(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4256,13 +5127,12 @@ func (c *castInt2DecimalOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							r.SetInt64(int64(v))
+							var r int16
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt16) || v >= float64(math.MaxInt16) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
 							}
+							r = int16(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -4275,14 +5145,14 @@ func (c *castInt2DecimalOp) Next() coldata.Batch {
 	return batch
 }
 
-type castInt2FloatOp struct {
+type castFloatInt4Op struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castInt2FloatOp{}
-var _ colexecop.ClosableOperator = &castInt2FloatOp{}
+var _ colexecop.ResettableOperator = &castFloatInt4Op{}
+var _ colexecop.ClosableOperator = &castFloatInt4Op{}
 
-func (c *castInt2FloatOp) Next() coldata.Batch {
+func (c *castFloatInt4Op) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -4296,17 +5166,21 @@ func (c *castInt2FloatOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int16()
+			inputCol := inputVec.Float64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Float64()
+			outputCol := outputVec.Int32()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4314,18 +5188,25 @@ func (c *castInt2FloatOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r int32
 
-							r = float64(v)
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt32) || v >= float64(math.MaxInt32) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							}
+							r = int32(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4336,9 +5217,12 @@ func (c *castInt2FloatOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r int32
 
-							r = float64(v)
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt32) || v >= float64(math.MaxInt32) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							}
+							r = int32(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -4348,9 +5232,13 @@ func (c *castInt2FloatOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4358,18 +5246,25 @@ func (c *castInt2FloatOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r int32
 
-							r = float64(v)
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt32) || v >= float64(math.MaxInt32) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							}
+							r = int32(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4380,9 +5275,12 @@ func (c *castInt2FloatOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r int32
 
-							r = float64(v)
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt32) || v >= float64(math.MaxInt32) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							}
+							r = int32(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -4395,14 +5293,14 @@ func (c *castInt2FloatOp) Next() coldata.Batch {
 	return batch
 }
 
-type castInt2Int4Op struct {
+type castFloatIntOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castInt2Int4Op{}
-var _ colexecop.ClosableOperator = &castInt2Int4Op{}
+var _ colexecop.ResettableOperator = &castFloatIntOp{}
+var _ colexecop.ClosableOperator = &castFloatIntOp{}
 
-func (c *castInt2Int4Op) Next() coldata.Batch {
+func (c *castFloatIntOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -4416,17 +5314,21 @@ func (c *castInt2Int4Op) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int16()
+			inputCol := inputVec.Float64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int32()
+			outputCol := outputVec.Int64()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4434,16 +5336,25 @@ func (c *castInt2Int4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
-							r = int32(v)
+							var r int64
+
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							}
+							r = int64(v)
+
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4454,8 +5365,13 @@ func (c *castInt2Int4Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
-							r = int32(v)
+							var r int64
+
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							}
+							r = int64(v)
+
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -4464,9 +5380,13 @@ func (c *castInt2Int4Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4474,16 +5394,25 @@ func (c *castInt2Int4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
-							r = int32(v)
+							var r int64
+
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							}
+							r = int64(v)
+
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4494,8 +5423,13 @@ func (c *castInt2Int4Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
-							r = int32(v)
+							var r int64
+
+							if math.IsNaN(float64(v)) || v <= float64(math.MinInt64) || v >= float64(math.MaxInt64) {
+								colexecerror.ExpectedError(tree.ErrIntOutOfRange)
+							}
+							r = int64(v)
+
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -4507,14 +5441,14 @@ func (c *castInt2Int4Op) Next() coldata.Batch {
 	return batch
 }
 
-type castInt2IntOp struct {
+type castFloatStringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castInt2IntOp{}
-var _ colexecop.ClosableOperator = &castInt2IntOp{}
+var _ colexecop.ResettableOperator = &castFloatStringOp{}
+var _ colexecop.ClosableOperator = &castFloatStringOp{}
 
-func (c *castInt2IntOp) Next() coldata.Batch {
+func (c *castFloatStringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -4528,17 +5462,21 @@ func (c *castInt2IntOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int16()
+			inputCol := inputVec.Float64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int64()
+			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4546,18 +5484,46 @@ func (c *castInt2IntOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
-							r = int64(v)
+							var r []byte
+
+							dcc := evalCtx.SessionData().DataConversionConfig
+							r = tree.PgwireFormatFloat(nil /* buf */, v, dcc, types.Float)
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -4566,9 +5532,33 @@ func (c *castInt2IntOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
-							r = int64(v)
-							//gcassert:bce
+							var r []byte
+
+							dcc := evalCtx.SessionData().DataConversionConfig
+							r = tree.PgwireFormatFloat(nil /* buf */, v, dcc, types.Float)
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -4576,9 +5566,13 @@ func (c *castInt2IntOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4586,18 +5580,46 @@ func (c *castInt2IntOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
-							r = int64(v)
+							var r []byte
+
+							dcc := evalCtx.SessionData().DataConversionConfig
+							r = tree.PgwireFormatFloat(nil /* buf */, v, dcc, types.Float)
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -4606,9 +5628,33 @@ func (c *castInt2IntOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
-							r = int64(v)
-							//gcassert:bce
+							var r []byte
+
+							dcc := evalCtx.SessionData().DataConversionConfig
+							r = tree.PgwireFormatFloat(nil /* buf */, v, dcc, types.Float)
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -4619,14 +5665,14 @@ func (c *castInt2IntOp) Next() coldata.Batch {
 	return batch
 }
 
-type castInt4BoolOp struct {
+type castInt2BoolOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castInt4BoolOp{}
-var _ colexecop.ClosableOperator = &castInt4BoolOp{}
+var _ colexecop.ResettableOperator = &castInt2BoolOp{}
+var _ colexecop.ClosableOperator = &castInt2BoolOp{}
 
-func (c *castInt4BoolOp) Next() coldata.Batch {
+func (c *castInt2BoolOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -4640,7 +5686,7 @@ func (c *castInt4BoolOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int32()
+			inputCol := inputVec.Int16()
 			inputNulls := inputVec.Nulls()
 			outputCol := outputVec.Bool()
 			outputNulls := outputVec.Nulls()
@@ -4648,9 +5694,13 @@ func (c *castInt4BoolOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4667,9 +5717,13 @@ func (c *castInt4BoolOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4692,9 +5746,13 @@ func (c *castInt4BoolOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4711,9 +5769,13 @@ func (c *castInt4BoolOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4739,14 +5801,14 @@ func (c *castInt4BoolOp) Next() coldata.Batch {
 	return batch
 }
 
-type castInt4DecimalOp struct {
+type castInt2DecimalOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castInt4DecimalOp{}
-var _ colexecop.ClosableOperator = &castInt4DecimalOp{}
+var _ colexecop.ResettableOperator = &castInt2DecimalOp{}
+var _ colexecop.ClosableOperator = &castInt2DecimalOp{}
 
-func (c *castInt4DecimalOp) Next() coldata.Batch {
+func (c *castInt2DecimalOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -4760,7 +5822,7 @@ func (c *castInt4DecimalOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int32()
+			inputCol := inputVec.Int16()
 			inputNulls := inputVec.Nulls()
 			outputCol := outputVec.Decimal()
 			outputNulls := outputVec.Nulls()
@@ -4768,9 +5830,13 @@ func (c *castInt4DecimalOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4791,9 +5857,13 @@ func (c *castInt4DecimalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4820,9 +5890,13 @@ func (c *castInt4DecimalOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4843,9 +5917,13 @@ func (c *castInt4DecimalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4875,14 +5953,14 @@ func (c *castInt4DecimalOp) Next() coldata.Batch {
 	return batch
 }
 
-type castInt4FloatOp struct {
+type castInt2FloatOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castInt4FloatOp{}
-var _ colexecop.ClosableOperator = &castInt4FloatOp{}
+var _ colexecop.ResettableOperator = &castInt2FloatOp{}
+var _ colexecop.ClosableOperator = &castInt2FloatOp{}
 
-func (c *castInt4FloatOp) Next() coldata.Batch {
+func (c *castInt2FloatOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -4896,7 +5974,7 @@ func (c *castInt4FloatOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int32()
+			inputCol := inputVec.Int16()
 			inputNulls := inputVec.Nulls()
 			outputCol := outputVec.Float64()
 			outputNulls := outputVec.Nulls()
@@ -4904,9 +5982,13 @@ func (c *castInt4FloatOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4923,9 +6005,13 @@ func (c *castInt4FloatOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4948,9 +6034,13 @@ func (c *castInt4FloatOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -4967,9 +6057,13 @@ func (c *castInt4FloatOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -4995,14 +6089,14 @@ func (c *castInt4FloatOp) Next() coldata.Batch {
 	return batch
 }
 
-type castInt4Int2Op struct {
+type castInt2Int4Op struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castInt4Int2Op{}
-var _ colexecop.ClosableOperator = &castInt4Int2Op{}
+var _ colexecop.ResettableOperator = &castInt2Int4Op{}
+var _ colexecop.ClosableOperator = &castInt2Int4Op{}
 
-func (c *castInt4Int2Op) Next() coldata.Batch {
+func (c *castInt2Int4Op) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -5016,17 +6110,21 @@ func (c *castInt4Int2Op) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int32()
+			inputCol := inputVec.Int16()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int16()
+			outputCol := outputVec.Int32()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5034,22 +6132,20 @@ func (c *castInt4Int2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-							}
-							r = int16(v)
-
+							var r int32
+							r = int32(v)
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5060,14 +6156,8 @@ func (c *castInt4Int2Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-							}
-							r = int16(v)
-
+							var r int32
+							r = int32(v)
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -5076,9 +6166,13 @@ func (c *castInt4Int2Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5086,22 +6180,20 @@ func (c *castInt4Int2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-							}
-							r = int16(v)
-
+							var r int32
+							r = int32(v)
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5112,14 +6204,8 @@ func (c *castInt4Int2Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-							}
-							r = int16(v)
-
+							var r int32
+							r = int32(v)
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
@@ -5131,14 +6217,14 @@ func (c *castInt4Int2Op) Next() coldata.Batch {
 	return batch
 }
 
-type castInt4IntOp struct {
+type castInt2IntOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castInt4IntOp{}
-var _ colexecop.ClosableOperator = &castInt4IntOp{}
+var _ colexecop.ResettableOperator = &castInt2IntOp{}
+var _ colexecop.ClosableOperator = &castInt2IntOp{}
 
-func (c *castInt4IntOp) Next() coldata.Batch {
+func (c *castInt2IntOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -5152,7 +6238,7 @@ func (c *castInt4IntOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int32()
+			inputCol := inputVec.Int16()
 			inputNulls := inputVec.Nulls()
 			outputCol := outputVec.Int64()
 			outputNulls := outputVec.Nulls()
@@ -5160,9 +6246,13 @@ func (c *castInt4IntOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5177,9 +6267,13 @@ func (c *castInt4IntOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5200,9 +6294,13 @@ func (c *castInt4IntOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5217,9 +6315,13 @@ func (c *castInt4IntOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5243,14 +6345,14 @@ func (c *castInt4IntOp) Next() coldata.Batch {
 	return batch
 }
 
-type castIntBoolOp struct {
+type castInt2StringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castIntBoolOp{}
-var _ colexecop.ClosableOperator = &castIntBoolOp{}
+var _ colexecop.ResettableOperator = &castInt2StringOp{}
+var _ colexecop.ClosableOperator = &castInt2StringOp{}
 
-func (c *castIntBoolOp) Next() coldata.Batch {
+func (c *castInt2StringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -5264,17 +6366,21 @@ func (c *castIntBoolOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int64()
+			inputCol := inputVec.Int16()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Bool()
+			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5282,20 +6388,57 @@ func (c *castIntBoolOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r []byte
 
-							r = v != 0
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
+								}
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
+								}
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -5304,11 +6447,44 @@ func (c *castIntBoolOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r []byte
 
-							r = v != 0
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
+								}
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
+								}
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -5316,9 +6492,13 @@ func (c *castIntBoolOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5326,20 +6506,57 @@ func (c *castIntBoolOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r []byte
 
-							r = v != 0
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
+								}
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
+								}
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
-						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -5348,11 +6565,44 @@ func (c *castIntBoolOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r []byte
 
-							r = v != 0
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
+								}
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
+								}
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -5363,14 +6613,14 @@ func (c *castIntBoolOp) Next() coldata.Batch {
 	return batch
 }
 
-type castIntDecimalOp struct {
+type castInt4BoolOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castIntDecimalOp{}
-var _ colexecop.ClosableOperator = &castIntDecimalOp{}
+var _ colexecop.ResettableOperator = &castInt4BoolOp{}
+var _ colexecop.ClosableOperator = &castInt4BoolOp{}
 
-func (c *castIntDecimalOp) Next() coldata.Batch {
+func (c *castInt4BoolOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -5384,17 +6634,21 @@ func (c *castIntDecimalOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int64()
+			inputCol := inputVec.Int32()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Decimal()
+			outputCol := outputVec.Bool()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5402,22 +6656,22 @@ func (c *castIntDecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							r.SetInt64(int64(v))
+							var r bool
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = v != 0
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5428,13 +6682,9 @@ func (c *castIntDecimalOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							r.SetInt64(int64(v))
+							var r bool
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = v != 0
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -5444,9 +6694,13 @@ func (c *castIntDecimalOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5454,22 +6708,22 @@ func (c *castIntDecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
+							var r bool
 
-							r.SetInt64(int64(v))
-
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = v != 0
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5480,13 +6734,9 @@ func (c *castIntDecimalOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							r.SetInt64(int64(v))
+							var r bool
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = v != 0
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -5499,14 +6749,14 @@ func (c *castIntDecimalOp) Next() coldata.Batch {
 	return batch
 }
 
-type castIntFloatOp struct {
+type castInt4DecimalOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castIntFloatOp{}
-var _ colexecop.ClosableOperator = &castIntFloatOp{}
+var _ colexecop.ResettableOperator = &castInt4DecimalOp{}
+var _ colexecop.ClosableOperator = &castInt4DecimalOp{}
 
-func (c *castIntFloatOp) Next() coldata.Batch {
+func (c *castInt4DecimalOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -5520,17 +6770,21 @@ func (c *castIntFloatOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int64()
+			inputCol := inputVec.Int32()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Float64()
+			outputCol := outputVec.Decimal()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5538,18 +6792,26 @@ func (c *castIntFloatOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r apd.Decimal
 
-							r = float64(v)
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5560,9 +6822,13 @@ func (c *castIntFloatOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r apd.Decimal
 
-							r = float64(v)
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -5572,9 +6838,13 @@ func (c *castIntFloatOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5582,18 +6852,26 @@ func (c *castIntFloatOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r apd.Decimal
 
-							r = float64(v)
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5604,9 +6882,13 @@ func (c *castIntFloatOp) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r apd.Decimal
 
-							r = float64(v)
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -5619,14 +6901,14 @@ func (c *castIntFloatOp) Next() coldata.Batch {
 	return batch
 }
 
-type castIntInt2Op struct {
+type castInt4FloatOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castIntInt2Op{}
-var _ colexecop.ClosableOperator = &castIntInt2Op{}
+var _ colexecop.ResettableOperator = &castInt4FloatOp{}
+var _ colexecop.ClosableOperator = &castInt4FloatOp{}
 
-func (c *castIntInt2Op) Next() coldata.Batch {
+func (c *castInt4FloatOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -5640,17 +6922,21 @@ func (c *castIntInt2Op) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int64()
+			inputCol := inputVec.Int32()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int16()
+			outputCol := outputVec.Float64()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5658,22 +6944,22 @@ func (c *castIntInt2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r float64
 
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-							}
-							r = int16(v)
+							r = float64(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5684,13 +6970,9 @@ func (c *castIntInt2Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r float64
 
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-							}
-							r = int16(v)
+							r = float64(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -5700,9 +6982,13 @@ func (c *castIntInt2Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5710,22 +6996,22 @@ func (c *castIntInt2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r float64
 
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-							}
-							r = int16(v)
+							r = float64(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5736,13 +7022,9 @@ func (c *castIntInt2Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
+							var r float64
 
-							shifted := v >> uint(15)
-							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-							}
-							r = int16(v)
+							r = float64(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -5755,14 +7037,14 @@ func (c *castIntInt2Op) Next() coldata.Batch {
 	return batch
 }
 
-type castIntInt4Op struct {
+type castInt4Int2Op struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castIntInt4Op{}
-var _ colexecop.ClosableOperator = &castIntInt4Op{}
+var _ colexecop.ResettableOperator = &castInt4Int2Op{}
+var _ colexecop.ClosableOperator = &castInt4Int2Op{}
 
-func (c *castIntInt4Op) Next() coldata.Batch {
+func (c *castInt4Int2Op) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -5776,17 +7058,21 @@ func (c *castIntInt4Op) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Int64()
+			inputCol := inputVec.Int32()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int32()
+			outputCol := outputVec.Int16()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5794,22 +7080,26 @@ func (c *castIntInt4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r int16
 
-							shifted := v >> uint(31)
+							shifted := v >> uint(15)
 							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
 							}
-							r = int32(v)
+							r = int16(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5820,13 +7110,13 @@ func (c *castIntInt4Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r int16
 
-							shifted := v >> uint(31)
+							shifted := v >> uint(15)
 							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
 							}
-							r = int32(v)
+							r = int16(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -5836,9 +7126,13 @@ func (c *castIntInt4Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5846,22 +7140,26 @@ func (c *castIntInt4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r int16
 
-							shifted := v >> uint(31)
+							shifted := v >> uint(15)
 							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
 							}
-							r = int32(v)
+							r = int16(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
@@ -5872,13 +7170,13 @@ func (c *castIntInt4Op) Next() coldata.Batch {
 							}
 							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r int16
 
-							shifted := v >> uint(31)
+							shifted := v >> uint(15)
 							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
-								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
 							}
-							r = int32(v)
+							r = int16(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -5891,14 +7189,14 @@ func (c *castIntInt4Op) Next() coldata.Batch {
 	return batch
 }
 
-type castJsonbStringOp struct {
+type castInt4IntOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castJsonbStringOp{}
-var _ colexecop.ClosableOperator = &castJsonbStringOp{}
+var _ colexecop.ResettableOperator = &castInt4IntOp{}
+var _ colexecop.ClosableOperator = &castInt4IntOp{}
 
-func (c *castJsonbStringOp) Next() coldata.Batch {
+func (c *castInt4IntOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -5912,17 +7210,21 @@ func (c *castJsonbStringOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.JSON()
+			inputCol := inputVec.Int32()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Bytes()
+			outputCol := outputVec.Int64()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5930,47 +7232,33 @@ func (c *castJsonbStringOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r []byte
-
-							_string := v.String()
-							switch toType.Oid() {
-							case oid.T_char:
-								// "char" is supposed to truncate long values.
-								_string = util.TruncateString(_string, 1)
-							case oid.T_bpchar:
-								// bpchar types truncate trailing whitespace.
-								_string = strings.TrimRight(_string, " ")
-							}
-							r = []byte(_string)
-
+							var r int64
+							r = int64(v)
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
+						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r []byte
-
-							_string := v.String()
-							switch toType.Oid() {
-							case oid.T_char:
-								// "char" is supposed to truncate long values.
-								_string = util.TruncateString(_string, 1)
-							case oid.T_bpchar:
-								// bpchar types truncate trailing whitespace.
-								_string = strings.TrimRight(_string, " ")
-							}
-							r = []byte(_string)
-
+							var r int64
+							r = int64(v)
+							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -5978,9 +7266,13 @@ func (c *castJsonbStringOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -5988,47 +7280,33 @@ func (c *castJsonbStringOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r []byte
-
-							_string := v.String()
-							switch toType.Oid() {
-							case oid.T_char:
-								// "char" is supposed to truncate long values.
-								_string = util.TruncateString(_string, 1)
-							case oid.T_bpchar:
-								// bpchar types truncate trailing whitespace.
-								_string = strings.TrimRight(_string, " ")
-							}
-							r = []byte(_string)
-
+							var r int64
+							r = int64(v)
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
+						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r []byte
-
-							_string := v.String()
-							switch toType.Oid() {
-							case oid.T_char:
-								// "char" is supposed to truncate long values.
-								_string = util.TruncateString(_string, 1)
-							case oid.T_bpchar:
-								// bpchar types truncate trailing whitespace.
-								_string = strings.TrimRight(_string, " ")
-							}
-							r = []byte(_string)
-
+							var r int64
+							r = int64(v)
+							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -6039,14 +7317,14 @@ func (c *castJsonbStringOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringBoolOp struct {
+type castInt4StringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringBoolOp{}
-var _ colexecop.ClosableOperator = &castStringBoolOp{}
+var _ colexecop.ResettableOperator = &castInt4StringOp{}
+var _ colexecop.ClosableOperator = &castInt4StringOp{}
 
-func (c *castStringBoolOp) Next() coldata.Batch {
+func (c *castInt4StringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -6060,17 +7338,21 @@ func (c *castStringBoolOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Bytes()
+			inputCol := inputVec.Int32()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Bool()
+			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6078,12 +7360,42 @@ func (c *castStringBoolOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r []byte
 
-							var err error
-							r, err = tree.ParseBool(string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
+								}
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
+								}
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -6091,26 +7403,60 @@ func (c *castStringBoolOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = outputCol.Get(n - 1)
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r []byte
 
-							var err error
-							r, err = tree.ParseBool(string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
+								}
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
+								}
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -6118,9 +7464,13 @@ func (c *castStringBoolOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6128,12 +7478,42 @@ func (c *castStringBoolOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r []byte
 
-							var err error
-							r, err = tree.ParseBool(string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
+								}
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
+								}
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -6141,26 +7521,60 @@ func (c *castStringBoolOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = outputCol.Get(n - 1)
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r bool
+							var r []byte
 
-							var err error
-							r, err = tree.ParseBool(string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
+								}
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
+								}
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -6171,14 +7585,14 @@ func (c *castStringBoolOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringBytesOp struct {
+type castIntBoolOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringBytesOp{}
-var _ colexecop.ClosableOperator = &castStringBytesOp{}
+var _ colexecop.ResettableOperator = &castIntBoolOp{}
+var _ colexecop.ClosableOperator = &castIntBoolOp{}
 
-func (c *castStringBytesOp) Next() coldata.Batch {
+func (c *castIntBoolOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -6192,17 +7606,21 @@ func (c *castStringBytesOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Bytes()
+			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Bytes()
+			outputCol := outputVec.Bool()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6210,37 +7628,37 @@ func (c *castStringBytesOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r []byte
+							var r bool
 
-							var err error
-							r, err = lex.DecodeRawBytesToByteArrayAuto(v)
-							if err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = v != 0
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
+						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r []byte
+							var r bool
 
-							var err error
-							r, err = lex.DecodeRawBytesToByteArrayAuto(v)
-							if err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = v != 0
 
+							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -6248,9 +7666,13 @@ func (c *castStringBytesOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6258,37 +7680,37 @@ func (c *castStringBytesOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r []byte
+							var r bool
 
-							var err error
-							r, err = lex.DecodeRawBytesToByteArrayAuto(v)
-							if err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = v != 0
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
+						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r []byte
+							var r bool
 
-							var err error
-							r, err = lex.DecodeRawBytesToByteArrayAuto(v)
-							if err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = v != 0
 
+							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -6299,14 +7721,14 @@ func (c *castStringBytesOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringDateOp struct {
+type castIntDecimalOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringDateOp{}
-var _ colexecop.ClosableOperator = &castStringDateOp{}
+var _ colexecop.ResettableOperator = &castIntDecimalOp{}
+var _ colexecop.ClosableOperator = &castIntDecimalOp{}
 
-func (c *castStringDateOp) Next() coldata.Batch {
+func (c *castIntDecimalOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -6320,17 +7742,21 @@ func (c *castStringDateOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Bytes()
+			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int64()
+			outputCol := outputVec.Decimal()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6338,24 +7764,27 @@ func (c *castStringDateOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r apd.Decimal
 
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_d, _, err := pgdate.ParseDate(_now, _dateStyle, string(v))
-							if err != nil {
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							r = _d.UnixEpochDays()
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -6363,16 +7792,15 @@ func (c *castStringDateOp) Next() coldata.Batch {
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r apd.Decimal
 
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_d, _, err := pgdate.ParseDate(_now, _dateStyle, string(v))
-							if err != nil {
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							r = _d.UnixEpochDays()
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -6382,9 +7810,13 @@ func (c *castStringDateOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6392,24 +7824,27 @@ func (c *castStringDateOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r apd.Decimal
 
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_d, _, err := pgdate.ParseDate(_now, _dateStyle, string(v))
-							if err != nil {
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							r = _d.UnixEpochDays()
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -6417,16 +7852,15 @@ func (c *castStringDateOp) Next() coldata.Batch {
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r apd.Decimal
 
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_d, _, err := pgdate.ParseDate(_now, _dateStyle, string(v))
-							if err != nil {
+							r.SetInt64(int64(v))
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							r = _d.UnixEpochDays()
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -6439,14 +7873,14 @@ func (c *castStringDateOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringDecimalOp struct {
+type castIntFloatOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringDecimalOp{}
-var _ colexecop.ClosableOperator = &castStringDecimalOp{}
+var _ colexecop.ResettableOperator = &castIntFloatOp{}
+var _ colexecop.ClosableOperator = &castIntFloatOp{}
 
-func (c *castStringDecimalOp) Next() coldata.Batch {
+func (c *castIntFloatOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -6460,17 +7894,21 @@ func (c *castStringDecimalOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Bytes()
+			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Decimal()
+			outputCol := outputVec.Float64()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6478,37 +7916,23 @@ func (c *castStringDecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
+							var r float64
 
-							_s := strings.TrimSpace(string(v))
-							_, res, err := tree.ExactCtx.SetString(&r, _s)
-							if res != 0 || err != nil {
-								colexecerror.ExpectedError(tree.MakeParseError(_s, types.Decimal, err))
-							}
-							switch r.Form {
-							case apd.NaNSignaling:
-								r.Form = apd.NaN
-								r.Negative = false
-							case apd.NaN:
-								r.Negative = false
-							case apd.Finite:
-								if r.IsZero() && r.Negative {
-									r.Negative = false
-								}
-							}
-
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = float64(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -6516,29 +7940,11 @@ func (c *castStringDecimalOp) Next() coldata.Batch {
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							_s := strings.TrimSpace(string(v))
-							_, res, err := tree.ExactCtx.SetString(&r, _s)
-							if res != 0 || err != nil {
-								colexecerror.ExpectedError(tree.MakeParseError(_s, types.Decimal, err))
-							}
-							switch r.Form {
-							case apd.NaNSignaling:
-								r.Form = apd.NaN
-								r.Negative = false
-							case apd.NaN:
-								r.Negative = false
-							case apd.Finite:
-								if r.IsZero() && r.Negative {
-									r.Negative = false
-								}
-							}
+							var r float64
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = float64(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -6548,9 +7954,13 @@ func (c *castStringDecimalOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6558,37 +7968,23 @@ func (c *castStringDecimalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							_s := strings.TrimSpace(string(v))
-							_, res, err := tree.ExactCtx.SetString(&r, _s)
-							if res != 0 || err != nil {
-								colexecerror.ExpectedError(tree.MakeParseError(_s, types.Decimal, err))
-							}
-							switch r.Form {
-							case apd.NaNSignaling:
-								r.Form = apd.NaN
-								r.Negative = false
-							case apd.NaN:
-								r.Negative = false
-							case apd.Finite:
-								if r.IsZero() && r.Negative {
-									r.Negative = false
-								}
-							}
+							var r float64
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = float64(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -6596,29 +7992,11 @@ func (c *castStringDecimalOp) Next() coldata.Batch {
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r apd.Decimal
-
-							_s := strings.TrimSpace(string(v))
-							_, res, err := tree.ExactCtx.SetString(&r, _s)
-							if res != 0 || err != nil {
-								colexecerror.ExpectedError(tree.MakeParseError(_s, types.Decimal, err))
-							}
-							switch r.Form {
-							case apd.NaNSignaling:
-								r.Form = apd.NaN
-								r.Negative = false
-							case apd.NaN:
-								r.Negative = false
-							case apd.Finite:
-								if r.IsZero() && r.Negative {
-									r.Negative = false
-								}
-							}
+							var r float64
 
-							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
-								colexecerror.ExpectedError(err)
-							}
+							r = float64(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -6631,14 +8009,14 @@ func (c *castStringDecimalOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringFloatOp struct {
+type castIntInt2Op struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringFloatOp{}
-var _ colexecop.ClosableOperator = &castStringFloatOp{}
+var _ colexecop.ResettableOperator = &castIntInt2Op{}
+var _ colexecop.ClosableOperator = &castIntInt2Op{}
 
-func (c *castStringFloatOp) Next() coldata.Batch {
+func (c *castIntInt2Op) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -6652,17 +8030,21 @@ func (c *castStringFloatOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Bytes()
+			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Float64()
+			outputCol := outputVec.Int16()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6670,23 +8052,27 @@ func (c *castStringFloatOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r int16
 
-							_s := string(v)
-							var _err error
-							r, _err = strconv.ParseFloat(strings.TrimSpace(_s), 64)
-							if _err != nil {
-								colexecerror.ExpectedError(tree.MakeParseError(_s, toType, _err))
+							shifted := v >> uint(15)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
 							}
+							r = int16(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -6694,15 +8080,15 @@ func (c *castStringFloatOp) Next() coldata.Batch {
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r int16
 
-							_s := string(v)
-							var _err error
-							r, _err = strconv.ParseFloat(strings.TrimSpace(_s), 64)
-							if _err != nil {
-								colexecerror.ExpectedError(tree.MakeParseError(_s, toType, _err))
+							shifted := v >> uint(15)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
 							}
+							r = int16(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -6712,9 +8098,13 @@ func (c *castStringFloatOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6722,23 +8112,27 @@ func (c *castStringFloatOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r int16
 
-							_s := string(v)
-							var _err error
-							r, _err = strconv.ParseFloat(strings.TrimSpace(_s), 64)
-							if _err != nil {
-								colexecerror.ExpectedError(tree.MakeParseError(_s, toType, _err))
+							shifted := v >> uint(15)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
 							}
+							r = int16(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -6746,15 +8140,15 @@ func (c *castStringFloatOp) Next() coldata.Batch {
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r float64
+							var r int16
 
-							_s := string(v)
-							var _err error
-							r, _err = strconv.ParseFloat(strings.TrimSpace(_s), 64)
-							if _err != nil {
-								colexecerror.ExpectedError(tree.MakeParseError(_s, toType, _err))
+							shifted := v >> uint(15)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
 							}
+							r = int16(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -6767,14 +8161,14 @@ func (c *castStringFloatOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringInt2Op struct {
+type castIntInt4Op struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringInt2Op{}
-var _ colexecop.ClosableOperator = &castStringInt2Op{}
+var _ colexecop.ResettableOperator = &castIntInt4Op{}
+var _ colexecop.ClosableOperator = &castIntInt4Op{}
 
-func (c *castStringInt2Op) Next() coldata.Batch {
+func (c *castIntInt4Op) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -6788,17 +8182,21 @@ func (c *castStringInt2Op) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Bytes()
+			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int16()
+			outputCol := outputVec.Int32()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6806,31 +8204,27 @@ func (c *castStringInt2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
-								}
-
-								shifted := _i >> uint(15)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-								r = int16(_i)
+							var r int32
 
+							shifted := v >> uint(31)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
 							}
+							r = int32(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -6838,23 +8232,15 @@ func (c *castStringInt2Op) Next() coldata.Batch {
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
-								}
-
-								shifted := _i >> uint(15)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-								r = int16(_i)
+							var r int32
 
+							shifted := v >> uint(31)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
 							}
+							r = int32(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -6864,9 +8250,13 @@ func (c *castStringInt2Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6874,31 +8264,27 @@ func (c *castStringInt2Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
-								}
-
-								shifted := _i >> uint(15)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-								r = int16(_i)
+							var r int32
 
+							shifted := v >> uint(31)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
 							}
+							r = int32(v)
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -6906,23 +8292,15 @@ func (c *castStringInt2Op) Next() coldata.Batch {
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int16
-
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
-								}
-
-								shifted := _i >> uint(15)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
-								}
-								r = int16(_i)
+							var r int32
 
+							shifted := v >> uint(31)
+							if (v >= 0 && shifted > 0) || (v < 0 && shifted < -1) {
+								colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
 							}
+							r = int32(v)
 
 							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
@@ -6935,14 +8313,14 @@ func (c *castStringInt2Op) Next() coldata.Batch {
 	return batch
 }
 
-type castStringInt4Op struct {
+type castIntStringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringInt4Op{}
-var _ colexecop.ClosableOperator = &castStringInt4Op{}
+var _ colexecop.ResettableOperator = &castIntStringOp{}
+var _ colexecop.ClosableOperator = &castIntStringOp{}
 
-func (c *castStringInt4Op) Next() coldata.Batch {
+func (c *castIntStringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -6956,17 +8334,21 @@ func (c *castStringInt4Op) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Bytes()
+			inputCol := inputVec.Int64()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int32()
+			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -6974,21 +8356,42 @@ func (c *castStringInt4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r []byte
 
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
 								}
-
-								shifted := _i >> uint(31)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
 								}
-								r = int32(_i)
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
 
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -6996,35 +8399,60 @@ func (c *castStringInt4Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = outputCol.Get(n - 1)
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r []byte
 
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
 								}
-
-								shifted := _i >> uint(31)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
 								}
-								r = int32(_i)
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
 
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -7032,9 +8460,13 @@ func (c *castStringInt4Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7042,21 +8474,42 @@ func (c *castStringInt4Op) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r []byte
 
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
 								}
-
-								shifted := _i >> uint(31)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
 								}
-								r = int32(_i)
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
 
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -7064,35 +8517,60 @@ func (c *castStringInt4Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = outputCol.Get(n - 1)
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int32
+							var r []byte
 
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+							if toType.Oid() == oid.T_char {
+								// int to "char" casts just return the corresponding ASCII byte.
+								if v > math.MaxInt8 || v < math.MinInt8 {
+									colexecerror.ExpectedError(tree.ErrCharOutOfRange)
 								}
-
-								shifted := _i >> uint(31)
-								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
-									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								if v == 0 {
+									r = []byte{}
+								} else {
+									r = []byte{byte(v)}
 								}
-								r = int32(_i)
+							} else {
+								r = []byte(strconv.FormatInt(int64(v), 10))
+							}
 
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -7103,14 +8581,14 @@ func (c *castStringInt4Op) Next() coldata.Batch {
 	return batch
 }
 
-type castStringIntOp struct {
+type castIntervalStringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringIntOp{}
-var _ colexecop.ClosableOperator = &castStringIntOp{}
+var _ colexecop.ResettableOperator = &castIntervalStringOp{}
+var _ colexecop.ClosableOperator = &castIntervalStringOp{}
 
-func (c *castStringIntOp) Next() coldata.Batch {
+func (c *castIntervalStringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -7124,17 +8602,21 @@ func (c *castStringIntOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Bytes()
+			inputCol := inputVec.Interval()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Int64()
+			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7142,15 +8624,33 @@ func (c *castStringIntOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r []byte
 
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+							dcc := evalCtx.SessionData().DataConversionConfig
+							buf.Reset()
+							v.FormatWithStyle(buf, dcc.IntervalStyle)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
 								}
-								r = int64(_i)
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -7158,29 +8658,51 @@ func (c *castStringIntOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = outputCol.Get(n - 1)
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r []byte
 
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+							dcc := evalCtx.SessionData().DataConversionConfig
+							buf.Reset()
+							v.FormatWithStyle(buf, dcc.IntervalStyle)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
 								}
-								r = int64(_i)
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -7188,9 +8710,13 @@ func (c *castStringIntOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7198,15 +8724,33 @@ func (c *castStringIntOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r []byte
 
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+							dcc := evalCtx.SessionData().DataConversionConfig
+							buf.Reset()
+							v.FormatWithStyle(buf, dcc.IntervalStyle)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
 								}
-								r = int64(_i)
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -7214,29 +8758,2119 @@ func (c *castStringIntOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = outputCol.Get(n - 1)
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r int64
+							var r []byte
 
-							{
-								_s := string(v)
-								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
-								if err != nil {
-									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+							dcc := evalCtx.SessionData().DataConversionConfig
+							buf.Reset()
+							v.FormatWithStyle(buf, dcc.IntervalStyle)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castJsonbStringOp struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castJsonbStringOp{}
+var _ colexecop.ClosableOperator = &castJsonbStringOp{}
+
+func (c *castJsonbStringOp) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.JSON()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.Bytes()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							r = []byte(v.String())
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							r = []byte(v.String())
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							r = []byte(v.String())
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							r = []byte(v.String())
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castStringBoolOp struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castStringBoolOp{}
+var _ colexecop.ClosableOperator = &castStringBoolOp{}
+
+func (c *castStringBoolOp) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.Bytes()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.Bool()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r bool
+
+							var err error
+							r, err = tree.ParseBool(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r bool
+
+							var err error
+							r, err = tree.ParseBool(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r bool
+
+							var err error
+							r, err = tree.ParseBool(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r bool
+
+							var err error
+							r, err = tree.ParseBool(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castStringBytesOp struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castStringBytesOp{}
+var _ colexecop.ClosableOperator = &castStringBytesOp{}
+
+func (c *castStringBytesOp) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.Bytes()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.Bytes()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							var err error
+							r, err = lex.DecodeRawBytesToByteArrayAuto(v)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							var err error
+							r, err = lex.DecodeRawBytesToByteArrayAuto(v)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							var err error
+							r, err = lex.DecodeRawBytesToByteArrayAuto(v)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							var err error
+							r, err = lex.DecodeRawBytesToByteArrayAuto(v)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castStringDateOp struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castStringDateOp{}
+var _ colexecop.ClosableOperator = &castStringDateOp{}
+
+func (c *castStringDateOp) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.Bytes()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.Int64()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int64
+
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_d, _, err := pgdate.ParseDate(_now, _dateStyle, string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							r = _d.UnixEpochDays()
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int64
+
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_d, _, err := pgdate.ParseDate(_now, _dateStyle, string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							r = _d.UnixEpochDays()
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int64
+
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_d, _, err := pgdate.ParseDate(_now, _dateStyle, string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							r = _d.UnixEpochDays()
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int64
+
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_d, _, err := pgdate.ParseDate(_now, _dateStyle, string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							r = _d.UnixEpochDays()
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castStringDecimalOp struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castStringDecimalOp{}
+var _ colexecop.ClosableOperator = &castStringDecimalOp{}
+
+func (c *castStringDecimalOp) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.Bytes()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.Decimal()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r apd.Decimal
+
+							_s := strings.TrimSpace(string(v))
+							_, res, err := tree.ExactCtx.SetString(&r, _s)
+							if res != 0 || err != nil {
+								colexecerror.ExpectedError(tree.MakeParseError(_s, types.Decimal, err))
+							}
+							switch r.Form {
+							case apd.NaNSignaling:
+								r.Form = apd.NaN
+								r.Negative = false
+							case apd.NaN:
+								r.Negative = false
+							case apd.Finite:
+								if r.IsZero() && r.Negative {
+									r.Negative = false
+								}
+							}
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r apd.Decimal
+
+							_s := strings.TrimSpace(string(v))
+							_, res, err := tree.ExactCtx.SetString(&r, _s)
+							if res != 0 || err != nil {
+								colexecerror.ExpectedError(tree.MakeParseError(_s, types.Decimal, err))
+							}
+							switch r.Form {
+							case apd.NaNSignaling:
+								r.Form = apd.NaN
+								r.Negative = false
+							case apd.NaN:
+								r.Negative = false
+							case apd.Finite:
+								if r.IsZero() && r.Negative {
+									r.Negative = false
+								}
+							}
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r apd.Decimal
+
+							_s := strings.TrimSpace(string(v))
+							_, res, err := tree.ExactCtx.SetString(&r, _s)
+							if res != 0 || err != nil {
+								colexecerror.ExpectedError(tree.MakeParseError(_s, types.Decimal, err))
+							}
+							switch r.Form {
+							case apd.NaNSignaling:
+								r.Form = apd.NaN
+								r.Negative = false
+							case apd.NaN:
+								r.Negative = false
+							case apd.Finite:
+								if r.IsZero() && r.Negative {
+									r.Negative = false
+								}
+							}
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r apd.Decimal
+
+							_s := strings.TrimSpace(string(v))
+							_, res, err := tree.ExactCtx.SetString(&r, _s)
+							if res != 0 || err != nil {
+								colexecerror.ExpectedError(tree.MakeParseError(_s, types.Decimal, err))
+							}
+							switch r.Form {
+							case apd.NaNSignaling:
+								r.Form = apd.NaN
+								r.Negative = false
+							case apd.NaN:
+								r.Negative = false
+							case apd.Finite:
+								if r.IsZero() && r.Negative {
+									r.Negative = false
+								}
+							}
+
+							if err := tree.LimitDecimalWidth(&r, int(toType.Precision()), int(toType.Scale())); err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castStringFloatOp struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castStringFloatOp{}
+var _ colexecop.ClosableOperator = &castStringFloatOp{}
+
+func (c *castStringFloatOp) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.Bytes()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.Float64()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r float64
+
+							_s := string(v)
+							var _err error
+							r, _err = strconv.ParseFloat(strings.TrimSpace(_s), 64)
+							if _err != nil {
+								colexecerror.ExpectedError(tree.MakeParseError(_s, toType, _err))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r float64
+
+							_s := string(v)
+							var _err error
+							r, _err = strconv.ParseFloat(strings.TrimSpace(_s), 64)
+							if _err != nil {
+								colexecerror.ExpectedError(tree.MakeParseError(_s, toType, _err))
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r float64
+
+							_s := string(v)
+							var _err error
+							r, _err = strconv.ParseFloat(strings.TrimSpace(_s), 64)
+							if _err != nil {
+								colexecerror.ExpectedError(tree.MakeParseError(_s, toType, _err))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r float64
+
+							_s := string(v)
+							var _err error
+							r, _err = strconv.ParseFloat(strings.TrimSpace(_s), 64)
+							if _err != nil {
+								colexecerror.ExpectedError(tree.MakeParseError(_s, toType, _err))
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castStringInt2Op struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castStringInt2Op{}
+var _ colexecop.ClosableOperator = &castStringInt2Op{}
+
+func (c *castStringInt2Op) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.Bytes()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.Int16()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int16
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+
+								shifted := _i >> uint(15)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
+								r = int16(_i)
+
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int16
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+
+								shifted := _i >> uint(15)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
+								r = int16(_i)
+
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int16
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+
+								shifted := _i >> uint(15)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
+								r = int16(_i)
+
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int16
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+
+								shifted := _i >> uint(15)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt2OutOfRange)
+								}
+								r = int16(_i)
+
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castStringInt4Op struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castStringInt4Op{}
+var _ colexecop.ClosableOperator = &castStringInt4Op{}
+
+func (c *castStringInt4Op) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.Bytes()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.Int32()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int32
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+
+								shifted := _i >> uint(31)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+								r = int32(_i)
+
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int32
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+
+								shifted := _i >> uint(31)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+								r = int32(_i)
+
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int32
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+
+								shifted := _i >> uint(31)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+								r = int32(_i)
+
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int32
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+
+								shifted := _i >> uint(31)
+								if (_i >= 0 && shifted > 0) || (_i < 0 && shifted < -1) {
+									colexecerror.ExpectedError(tree.ErrInt4OutOfRange)
+								}
+								r = int32(_i)
+
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castStringIntOp struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castStringIntOp{}
+var _ colexecop.ClosableOperator = &castStringIntOp{}
+
+func (c *castStringIntOp) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.Bytes()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.Int64()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int64
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+								r = int64(_i)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int64
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+								r = int64(_i)
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int64
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+								r = int64(_i)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r int64
+
+							{
+								_s := string(v)
+								_i, err := strconv.ParseInt(strings.TrimSpace(_s), 0, 64)
+								if err != nil {
+									colexecerror.ExpectedError(tree.MakeParseError(_s, toType, err))
+								}
+								r = int64(_i)
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castStringIntervalOp struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castStringIntervalOp{}
+var _ colexecop.ClosableOperator = &castStringIntervalOp{}
+
+func (c *castStringIntervalOp) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.Bytes()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.Interval()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r duration.Duration
+
+							_itm, err := toType.IntervalTypeMetadata()
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							_intervalStyle := evalCtx.GetIntervalStyle()
+							r, err = tree.ParseIntervalWithTypeMetadata(_intervalStyle, string(v), _itm)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r duration.Duration
+
+							_itm, err := toType.IntervalTypeMetadata()
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							_intervalStyle := evalCtx.GetIntervalStyle()
+							r, err = tree.ParseIntervalWithTypeMetadata(_intervalStyle, string(v), _itm)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r duration.Duration
+
+							_itm, err := toType.IntervalTypeMetadata()
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							_intervalStyle := evalCtx.GetIntervalStyle()
+							r, err = tree.ParseIntervalWithTypeMetadata(_intervalStyle, string(v), _itm)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r duration.Duration
+
+							_itm, err := toType.IntervalTypeMetadata()
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+							_intervalStyle := evalCtx.GetIntervalStyle()
+							r, err = tree.ParseIntervalWithTypeMetadata(_intervalStyle, string(v), _itm)
+							if err != nil {
+								colexecerror.ExpectedError(err)
+							}
+
+							//gcassert:bce
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castStringJsonbOp struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castStringJsonbOp{}
+var _ colexecop.ClosableOperator = &castStringJsonbOp{}
+
+func (c *castStringJsonbOp) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.Bytes()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.JSON()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r json.JSON
+
+							var err error
+							r, err = json.ParseJSON(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(pgerror.Wrapf(err, pgcode.Syntax, "could not parse JSON"))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r json.JSON
+
+							var err error
+							r, err = json.ParseJSON(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(pgerror.Wrapf(err, pgcode.Syntax, "could not parse JSON"))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r json.JSON
+
+							var err error
+							r, err = json.ParseJSON(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(pgerror.Wrapf(err, pgcode.Syntax, "could not parse JSON"))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r json.JSON
+
+							var err error
+							r, err = json.ParseJSON(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(pgerror.Wrapf(err, pgcode.Syntax, "could not parse JSON"))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			}
+		},
+	)
+	return batch
+}
+
+type castStringStringOp struct {
+	castOpBase
+}
+
+var _ colexecop.ResettableOperator = &castStringStringOp{}
+var _ colexecop.ClosableOperator = &castStringStringOp{}
+
+func (c *castStringStringOp) Next() coldata.Batch {
+	batch := c.Input.Next()
+	n := batch.Length()
+	if n == 0 {
+		return coldata.ZeroBatch
+	}
+	sel := batch.Selection()
+	inputVec := batch.ColVec(c.colIdx)
+	outputVec := batch.ColVec(c.outputIdx)
+	toType := outputVec.Type()
+	// Remove unused warnings.
+	_ = toType
+	c.allocator.PerformOperation(
+		[]coldata.Vec{outputVec}, func() {
+			inputCol := inputVec.Bytes()
+			inputNulls := inputVec.Nulls()
+			outputCol := outputVec.Bytes()
+			outputNulls := outputVec.Nulls()
+			if inputVec.MaybeHasNulls() {
+				outputNulls.Copy(inputNulls)
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							r = v
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if true && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							r = v
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				}
+			} else {
+				if sel != nil {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = sel[i]
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							r = v
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
+
+							outputCol.Set(tupleIdx, r)
+						}
+					}
+				} else {
+					{
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
+						_ = evalCtx
+						_ = buf
+						var tupleIdx int
+						for i := 0; i < n; i++ {
+							tupleIdx = i
+							if false && inputNulls.NullAt(tupleIdx) {
+								continue
+							}
+							v := inputCol.Get(tupleIdx)
+							var r []byte
+
+							r = v
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
 								}
-								r = int64(_i)
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -7247,14 +10881,14 @@ func (c *castStringIntOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringIntervalOp struct {
+type castStringTimestampOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringIntervalOp{}
-var _ colexecop.ClosableOperator = &castStringIntervalOp{}
+var _ colexecop.ResettableOperator = &castStringTimestampOp{}
+var _ colexecop.ClosableOperator = &castStringTimestampOp{}
 
-func (c *castStringIntervalOp) Next() coldata.Batch {
+func (c *castStringTimestampOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -7270,15 +10904,19 @@ func (c *castStringIntervalOp) Next() coldata.Batch {
 		[]coldata.Vec{outputVec}, func() {
 			inputCol := inputVec.Bytes()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Interval()
+			outputCol := outputVec.Timestamp()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7286,16 +10924,19 @@ func (c *castStringIntervalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r duration.Duration
+							var r time.Time
 
-							_itm, err := toType.IntervalTypeMetadata()
+							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_t, _, err := pgdate.ParseTimestampWithoutTimezone(_now, _dateStyle, string(v))
 							if err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							_intervalStyle := evalCtx.GetIntervalStyle()
-							r, err = tree.ParseIntervalWithTypeMetadata(_intervalStyle, string(v), _itm)
-							if err != nil {
-								colexecerror.ExpectedError(err)
+
+							r = _t.Round(_roundTo)
+							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -7303,9 +10944,13 @@ func (c *castStringIntervalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -7314,16 +10959,19 @@ func (c *castStringIntervalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r duration.Duration
+							var r time.Time
 
-							_itm, err := toType.IntervalTypeMetadata()
+							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_t, _, err := pgdate.ParseTimestampWithoutTimezone(_now, _dateStyle, string(v))
 							if err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							_intervalStyle := evalCtx.GetIntervalStyle()
-							r, err = tree.ParseIntervalWithTypeMetadata(_intervalStyle, string(v), _itm)
-							if err != nil {
-								colexecerror.ExpectedError(err)
+
+							r = _t.Round(_roundTo)
+							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
 							}
 
 							//gcassert:bce
@@ -7334,9 +10982,13 @@ func (c *castStringIntervalOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7344,16 +10996,19 @@ func (c *castStringIntervalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r duration.Duration
+							var r time.Time
 
-							_itm, err := toType.IntervalTypeMetadata()
+							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_t, _, err := pgdate.ParseTimestampWithoutTimezone(_now, _dateStyle, string(v))
 							if err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							_intervalStyle := evalCtx.GetIntervalStyle()
-							r, err = tree.ParseIntervalWithTypeMetadata(_intervalStyle, string(v), _itm)
-							if err != nil {
-								colexecerror.ExpectedError(err)
+
+							r = _t.Round(_roundTo)
+							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -7361,9 +11016,13 @@ func (c *castStringIntervalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -7372,16 +11031,19 @@ func (c *castStringIntervalOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r duration.Duration
+							var r time.Time
 
-							_itm, err := toType.IntervalTypeMetadata()
+							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_t, _, err := pgdate.ParseTimestampWithoutTimezone(_now, _dateStyle, string(v))
 							if err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							_intervalStyle := evalCtx.GetIntervalStyle()
-							r, err = tree.ParseIntervalWithTypeMetadata(_intervalStyle, string(v), _itm)
-							if err != nil {
-								colexecerror.ExpectedError(err)
+
+							r = _t.Round(_roundTo)
+							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
 							}
 
 							//gcassert:bce
@@ -7395,14 +11057,14 @@ func (c *castStringIntervalOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringJsonbOp struct {
+type castStringTimestamptzOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringJsonbOp{}
-var _ colexecop.ClosableOperator = &castStringJsonbOp{}
+var _ colexecop.ResettableOperator = &castStringTimestamptzOp{}
+var _ colexecop.ClosableOperator = &castStringTimestamptzOp{}
 
-func (c *castStringJsonbOp) Next() coldata.Batch {
+func (c *castStringTimestamptzOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -7418,15 +11080,19 @@ func (c *castStringJsonbOp) Next() coldata.Batch {
 		[]coldata.Vec{outputVec}, func() {
 			inputCol := inputVec.Bytes()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.JSON()
+			outputCol := outputVec.Timestamp()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7434,12 +11100,19 @@ func (c *castStringJsonbOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r json.JSON
+							var r time.Time
 
-							var err error
-							r, err = json.ParseJSON(string(v))
+							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_t, _, err := pgdate.ParseTimestamp(_now, _dateStyle, string(v))
 							if err != nil {
-								colexecerror.ExpectedError(pgerror.Wrapf(err, pgcode.Syntax, "could not parse JSON"))
+								colexecerror.ExpectedError(err)
+							}
+
+							r = _t.Round(_roundTo)
+							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -7447,9 +11120,14 @@ func (c *castStringJsonbOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -7457,14 +11135,22 @@ func (c *castStringJsonbOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r json.JSON
+							var r time.Time
 
-							var err error
-							r, err = json.ParseJSON(string(v))
+							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_t, _, err := pgdate.ParseTimestamp(_now, _dateStyle, string(v))
 							if err != nil {
-								colexecerror.ExpectedError(pgerror.Wrapf(err, pgcode.Syntax, "could not parse JSON"))
+								colexecerror.ExpectedError(err)
+							}
+
+							r = _t.Round(_roundTo)
+							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
 							}
 
+							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -7472,9 +11158,13 @@ func (c *castStringJsonbOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7482,12 +11172,19 @@ func (c *castStringJsonbOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r json.JSON
+							var r time.Time
 
-							var err error
-							r, err = json.ParseJSON(string(v))
+							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_t, _, err := pgdate.ParseTimestamp(_now, _dateStyle, string(v))
 							if err != nil {
-								colexecerror.ExpectedError(pgerror.Wrapf(err, pgcode.Syntax, "could not parse JSON"))
+								colexecerror.ExpectedError(err)
+							}
+
+							r = _t.Round(_roundTo)
+							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -7495,9 +11192,14 @@ func (c *castStringJsonbOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
+						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -7505,14 +11207,22 @@ func (c *castStringJsonbOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r json.JSON
+							var r time.Time
 
-							var err error
-							r, err = json.ParseJSON(string(v))
+							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
+							_now := evalCtx.GetRelativeParseTime()
+							_dateStyle := evalCtx.GetDateStyle()
+							_t, _, err := pgdate.ParseTimestamp(_now, _dateStyle, string(v))
 							if err != nil {
-								colexecerror.ExpectedError(pgerror.Wrapf(err, pgcode.Syntax, "could not parse JSON"))
+								colexecerror.ExpectedError(err)
 							}
 
+							r = _t.Round(_roundTo)
+							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
+							}
+
+							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -7523,14 +11233,14 @@ func (c *castStringJsonbOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringStringOp struct {
+type castStringUuidOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringStringOp{}
-var _ colexecop.ClosableOperator = &castStringStringOp{}
+var _ colexecop.ResettableOperator = &castStringUuidOp{}
+var _ colexecop.ClosableOperator = &castStringUuidOp{}
 
-func (c *castStringStringOp) Next() coldata.Batch {
+func (c *castStringUuidOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -7552,9 +11262,13 @@ func (c *castStringStringOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7564,40 +11278,24 @@ func (c *castStringStringOp) Next() coldata.Batch {
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							if toType.Oid() == oid.T_name {
-								// For Names we don't perform the truncation, and there is no need
-								// to do anything about the Oids since those are stored in the type.
-								r = v
-							} else {
-								// bpchar types truncate trailing whitespace.
-								if toType.Oid() == oid.T_bpchar {
-									v = bytes.TrimRight(v, " ")
-								}
-								// If the string type specifies a limit we truncate to that limit:
-								//   'hello'::CHAR(2) -> 'he'
-								// This is true of all the string type variants.
-								if toType.Width() > 0 {
-									// TODO(yuzefovich): figure out whether we can avoid converting
-									// to a string.
-									v = []byte(util.TruncateString(string(v), int(toType.Width())))
-								}
-								if toType.Oid() == oid.T_char {
-									// "char" is supposed to truncate long values.
-									// TODO(yuzefovich): figure out whether we can avoid converting
-									// to a string.
-									v = []byte(util.TruncateString(string(v), 1))
-								}
-								r = v
+							_uuid, err := uuid.FromString(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
 							}
+							r = _uuid.GetBytes()
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -7607,31 +11305,11 @@ func (c *castStringStringOp) Next() coldata.Batch {
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							if toType.Oid() == oid.T_name {
-								// For Names we don't perform the truncation, and there is no need
-								// to do anything about the Oids since those are stored in the type.
-								r = v
-							} else {
-								// bpchar types truncate trailing whitespace.
-								if toType.Oid() == oid.T_bpchar {
-									v = bytes.TrimRight(v, " ")
-								}
-								// If the string type specifies a limit we truncate to that limit:
-								//   'hello'::CHAR(2) -> 'he'
-								// This is true of all the string type variants.
-								if toType.Width() > 0 {
-									// TODO(yuzefovich): figure out whether we can avoid converting
-									// to a string.
-									v = []byte(util.TruncateString(string(v), int(toType.Width())))
-								}
-								if toType.Oid() == oid.T_char {
-									// "char" is supposed to truncate long values.
-									// TODO(yuzefovich): figure out whether we can avoid converting
-									// to a string.
-									v = []byte(util.TruncateString(string(v), 1))
-								}
-								r = v
+							_uuid, err := uuid.FromString(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
 							}
+							r = _uuid.GetBytes()
 
 							outputCol.Set(tupleIdx, r)
 						}
@@ -7640,9 +11318,13 @@ func (c *castStringStringOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7652,40 +11334,24 @@ func (c *castStringStringOp) Next() coldata.Batch {
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							if toType.Oid() == oid.T_name {
-								// For Names we don't perform the truncation, and there is no need
-								// to do anything about the Oids since those are stored in the type.
-								r = v
-							} else {
-								// bpchar types truncate trailing whitespace.
-								if toType.Oid() == oid.T_bpchar {
-									v = bytes.TrimRight(v, " ")
-								}
-								// If the string type specifies a limit we truncate to that limit:
-								//   'hello'::CHAR(2) -> 'he'
-								// This is true of all the string type variants.
-								if toType.Width() > 0 {
-									// TODO(yuzefovich): figure out whether we can avoid converting
-									// to a string.
-									v = []byte(util.TruncateString(string(v), int(toType.Width())))
-								}
-								if toType.Oid() == oid.T_char {
-									// "char" is supposed to truncate long values.
-									// TODO(yuzefovich): figure out whether we can avoid converting
-									// to a string.
-									v = []byte(util.TruncateString(string(v), 1))
-								}
-								r = v
+							_uuid, err := uuid.FromString(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
 							}
+							r = _uuid.GetBytes()
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -7695,31 +11361,11 @@ func (c *castStringStringOp) Next() coldata.Batch {
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							if toType.Oid() == oid.T_name {
-								// For Names we don't perform the truncation, and there is no need
-								// to do anything about the Oids since those are stored in the type.
-								r = v
-							} else {
-								// bpchar types truncate trailing whitespace.
-								if toType.Oid() == oid.T_bpchar {
-									v = bytes.TrimRight(v, " ")
-								}
-								// If the string type specifies a limit we truncate to that limit:
-								//   'hello'::CHAR(2) -> 'he'
-								// This is true of all the string type variants.
-								if toType.Width() > 0 {
-									// TODO(yuzefovich): figure out whether we can avoid converting
-									// to a string.
-									v = []byte(util.TruncateString(string(v), int(toType.Width())))
-								}
-								if toType.Oid() == oid.T_char {
-									// "char" is supposed to truncate long values.
-									// TODO(yuzefovich): figure out whether we can avoid converting
-									// to a string.
-									v = []byte(util.TruncateString(string(v), 1))
-								}
-								r = v
+							_uuid, err := uuid.FromString(string(v))
+							if err != nil {
+								colexecerror.ExpectedError(err)
 							}
+							r = _uuid.GetBytes()
 
 							outputCol.Set(tupleIdx, r)
 						}
@@ -7731,14 +11377,14 @@ func (c *castStringStringOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringTimestampOp struct {
+type castTimestampStringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringTimestampOp{}
-var _ colexecop.ClosableOperator = &castStringTimestampOp{}
+var _ colexecop.ResettableOperator = &castTimestampStringOp{}
+var _ colexecop.ClosableOperator = &castTimestampStringOp{}
 
-func (c *castStringTimestampOp) Next() coldata.Batch {
+func (c *castTimestampStringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -7752,17 +11398,21 @@ func (c *castStringTimestampOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Bytes()
+			inputCol := inputVec.Timestamp()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Timestamp()
+			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7770,18 +11420,29 @@ func (c *castStringTimestampOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r time.Time
+							var r []byte
 
-							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_t, _, err := pgdate.ParseTimestampWithoutTimezone(_now, _dateStyle, string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							r = []byte(tree.FormatTimestamp(v))
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
 							}
-							r = _t.Round(_roundTo)
-							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
-								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -7789,32 +11450,47 @@ func (c *castStringTimestampOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = outputCol.Get(n - 1)
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r time.Time
+							var r []byte
 
-							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_t, _, err := pgdate.ParseTimestampWithoutTimezone(_now, _dateStyle, string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							r = []byte(tree.FormatTimestamp(v))
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
 							}
-							r = _t.Round(_roundTo)
-							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
-								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -7822,9 +11498,13 @@ func (c *castStringTimestampOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7832,18 +11512,29 @@ func (c *castStringTimestampOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r time.Time
+							var r []byte
 
-							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_t, _, err := pgdate.ParseTimestampWithoutTimezone(_now, _dateStyle, string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							r = []byte(tree.FormatTimestamp(v))
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
 							}
-							r = _t.Round(_roundTo)
-							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
-								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -7851,32 +11542,47 @@ func (c *castStringTimestampOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = outputCol.Get(n - 1)
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r time.Time
+							var r []byte
 
-							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_t, _, err := pgdate.ParseTimestampWithoutTimezone(_now, _dateStyle, string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							r = []byte(tree.FormatTimestamp(v))
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
 							}
-							r = _t.Round(_roundTo)
-							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
-								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -7887,14 +11593,14 @@ func (c *castStringTimestampOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringTimestamptzOp struct {
+type castTimestamptzStringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringTimestamptzOp{}
-var _ colexecop.ClosableOperator = &castStringTimestamptzOp{}
+var _ colexecop.ResettableOperator = &castTimestamptzStringOp{}
+var _ colexecop.ClosableOperator = &castTimestamptzStringOp{}
 
-func (c *castStringTimestamptzOp) Next() coldata.Batch {
+func (c *castTimestamptzStringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -7908,17 +11614,21 @@ func (c *castStringTimestamptzOp) Next() coldata.Batch {
 	_ = toType
 	c.allocator.PerformOperation(
 		[]coldata.Vec{outputVec}, func() {
-			inputCol := inputVec.Bytes()
+			inputCol := inputVec.Timestamp()
 			inputNulls := inputVec.Nulls()
-			outputCol := outputVec.Timestamp()
+			outputCol := outputVec.Bytes()
 			outputNulls := outputVec.Nulls()
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7926,18 +11636,40 @@ func (c *castStringTimestamptzOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r time.Time
+							var r []byte
 
-							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_t, _, err := pgdate.ParseTimestamp(_now, _dateStyle, string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							// Convert to context timezone for correct display.
+							_t := v.In(evalCtx.GetLocation())
+
+							_t = _t.Round(time.Microsecond)
+							if _t.After(tree.MaxSupportedTime) || _t.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(_t))
 							}
-							r = _t.Round(_roundTo)
-							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
-								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
+
+							buf.Reset()
+							tree.FormatTimestampTZ(_t, buf)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -7945,32 +11677,58 @@ func (c *castStringTimestamptzOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = outputCol.Get(n - 1)
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if true && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r time.Time
+							var r []byte
 
-							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_t, _, err := pgdate.ParseTimestamp(_now, _dateStyle, string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							// Convert to context timezone for correct display.
+							_t := v.In(evalCtx.GetLocation())
+
+							_t = _t.Round(time.Microsecond)
+							if _t.After(tree.MaxSupportedTime) || _t.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(_t))
 							}
-							r = _t.Round(_roundTo)
-							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
-								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
+
+							buf.Reset()
+							tree.FormatTimestampTZ(_t, buf)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -7978,9 +11736,13 @@ func (c *castStringTimestamptzOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -7988,18 +11750,40 @@ func (c *castStringTimestamptzOp) Next() coldata.Batch {
 								continue
 							}
 							v := inputCol.Get(tupleIdx)
-							var r time.Time
+							var r []byte
 
-							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_t, _, err := pgdate.ParseTimestamp(_now, _dateStyle, string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							// Convert to context timezone for correct display.
+							_t := v.In(evalCtx.GetLocation())
+
+							_t = _t.Round(time.Microsecond)
+							if _t.After(tree.MaxSupportedTime) || _t.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(_t))
 							}
-							r = _t.Round(_roundTo)
-							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
-								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
+
+							buf.Reset()
+							tree.FormatTimestampTZ(_t, buf)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
 							outputCol.Set(tupleIdx, r)
@@ -8007,32 +11791,58 @@ func (c *castStringTimestamptzOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
-						_ = outputCol.Get(n - 1)
+						_ = buf
+						_ = inputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
 							if false && inputNulls.NullAt(tupleIdx) {
 								continue
 							}
+							//gcassert:bce
 							v := inputCol.Get(tupleIdx)
-							var r time.Time
+							var r []byte
 
-							_roundTo := tree.TimeFamilyPrecisionToRoundDuration(toType.Precision())
-							_now := evalCtx.GetRelativeParseTime()
-							_dateStyle := evalCtx.GetDateStyle()
-							_t, _, err := pgdate.ParseTimestamp(_now, _dateStyle, string(v))
-							if err != nil {
-								colexecerror.ExpectedError(err)
+							// Convert to context timezone for correct display.
+							_t := v.In(evalCtx.GetLocation())
+
+							_t = _t.Round(time.Microsecond)
+							if _t.After(tree.MaxSupportedTime) || _t.Before(tree.MinSupportedTime) {
+								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(_t))
 							}
-							r = _t.Round(_roundTo)
-							if r.After(tree.MaxSupportedTime) || r.Before(tree.MinSupportedTime) {
-								colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(r))
+
+							buf.Reset()
+							tree.FormatTimestampTZ(_t, buf)
+							r = []byte(buf.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
 							}
 
-							//gcassert:bce
 							outputCol.Set(tupleIdx, r)
 						}
 					}
@@ -8043,14 +11853,14 @@ func (c *castStringTimestamptzOp) Next() coldata.Batch {
 	return batch
 }
 
-type castStringUuidOp struct {
+type castUuidStringOp struct {
 	castOpBase
 }
 
-var _ colexecop.ResettableOperator = &castStringUuidOp{}
-var _ colexecop.ClosableOperator = &castStringUuidOp{}
+var _ colexecop.ResettableOperator = &castUuidStringOp{}
+var _ colexecop.ClosableOperator = &castUuidStringOp{}
 
-func (c *castStringUuidOp) Next() coldata.Batch {
+func (c *castUuidStringOp) Next() coldata.Batch {
 	batch := c.Input.Next()
 	n := batch.Length()
 	if n == 0 {
@@ -8072,9 +11882,13 @@ func (c *castStringUuidOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8084,20 +11898,46 @@ func (c *castStringUuidOp) Next() coldata.Batch {
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							_uuid, err := uuid.FromString(string(v))
+							_uuid, err := uuid.FromBytes(v)
 							if err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							r = _uuid.GetBytes()
+							r = []byte(_uuid.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -8107,11 +11947,33 @@ func (c *castStringUuidOp) Next() coldata.Batch {
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							_uuid, err := uuid.FromString(string(v))
+							_uuid, err := uuid.FromBytes(v)
 							if err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							r = _uuid.GetBytes()
+							r = []byte(_uuid.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
@@ -8120,9 +11982,13 @@ func (c *castStringUuidOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8132,20 +11998,46 @@ func (c *castStringUuidOp) Next() coldata.Batch {
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							_uuid, err := uuid.FromString(string(v))
+							_uuid, err := uuid.FromBytes(v)
 							if err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							r = _uuid.GetBytes()
+							r = []byte(_uuid.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -8155,11 +12047,33 @@ func (c *castStringUuidOp) Next() coldata.Batch {
 							v := inputCol.Get(tupleIdx)
 							var r []byte
 
-							_uuid, err := uuid.FromString(string(v))
+							_uuid, err := uuid.FromBytes(v)
 							if err != nil {
 								colexecerror.ExpectedError(err)
 							}
-							r = _uuid.GetBytes()
+							r = []byte(_uuid.String())
+
+							if toType.Oid() != oid.T_name {
+								// bpchar types truncate trailing whitespace.
+								if toType.Oid() == oid.T_bpchar {
+									r = bytes.TrimRight(r, " ")
+								}
+								// If the string type specifies a limit we truncate to that limit:
+								//   'hello'::CHAR(2) -> 'he'
+								// This is true of all the string type variants.
+								if toType.Width() > 0 {
+									r = []byte(util.TruncateString(string(r), int(toType.Width())))
+								}
+								if toType.Oid() == oid.T_char {
+									// "char" is supposed to truncate long values.
+									r = []byte(util.TruncateString(string(r), 1))
+								}
+							}
+							if toType.Width() > 0 && utf8.RuneCountInString(string(r)) > int(toType.Width()) {
+								_typeString := toType.SQLString()
+								colexecerror.ExpectedError(
+									pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type "+_typeString))
+							}
 
 							outputCol.Set(tupleIdx, r)
 						}
@@ -8201,9 +12115,13 @@ func (c *castDatumBoolOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8226,9 +12144,13 @@ func (c *castDatumBoolOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -8255,9 +12177,13 @@ func (c *castDatumBoolOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8280,9 +12206,13 @@ func (c *castDatumBoolOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -8342,9 +12272,13 @@ func (c *castDatumInt2Op) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8367,9 +12301,13 @@ func (c *castDatumInt2Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -8396,9 +12334,13 @@ func (c *castDatumInt2Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8421,9 +12363,13 @@ func (c *castDatumInt2Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -8483,9 +12429,13 @@ func (c *castDatumInt4Op) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8508,9 +12458,13 @@ func (c *castDatumInt4Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -8537,9 +12491,13 @@ func (c *castDatumInt4Op) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8562,9 +12520,13 @@ func (c *castDatumInt4Op) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -8624,9 +12586,13 @@ func (c *castDatumIntOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8649,9 +12615,13 @@ func (c *castDatumIntOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -8678,9 +12648,13 @@ func (c *castDatumIntOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8703,9 +12677,13 @@ func (c *castDatumIntOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -8765,9 +12743,13 @@ func (c *castDatumFloatOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8790,9 +12772,13 @@ func (c *castDatumFloatOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -8819,9 +12805,13 @@ func (c *castDatumFloatOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8844,9 +12834,13 @@ func (c *castDatumFloatOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -8906,9 +12900,13 @@ func (c *castDatumDecimalOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8931,9 +12929,13 @@ func (c *castDatumDecimalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -8960,9 +12962,13 @@ func (c *castDatumDecimalOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -8985,9 +12991,13 @@ func (c *castDatumDecimalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -9047,9 +13057,13 @@ func (c *castDatumDateOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9072,9 +13086,13 @@ func (c *castDatumDateOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -9101,9 +13119,13 @@ func (c *castDatumDateOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9126,9 +13148,13 @@ func (c *castDatumDateOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -9188,9 +13214,13 @@ func (c *castDatumTimestampOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9213,9 +13243,13 @@ func (c *castDatumTimestampOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -9242,9 +13276,13 @@ func (c *castDatumTimestampOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9267,9 +13305,13 @@ func (c *castDatumTimestampOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -9329,9 +13371,13 @@ func (c *castDatumIntervalOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9354,9 +13400,13 @@ func (c *castDatumIntervalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -9383,9 +13433,13 @@ func (c *castDatumIntervalOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9408,9 +13462,13 @@ func (c *castDatumIntervalOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -9470,9 +13528,13 @@ func (c *castDatumStringOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9495,9 +13557,13 @@ func (c *castDatumStringOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -9522,9 +13588,13 @@ func (c *castDatumStringOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9547,9 +13617,13 @@ func (c *castDatumStringOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -9607,9 +13681,13 @@ func (c *castDatumBytesOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9632,9 +13710,13 @@ func (c *castDatumBytesOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -9659,9 +13741,13 @@ func (c *castDatumBytesOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9684,9 +13770,13 @@ func (c *castDatumBytesOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -9744,9 +13834,13 @@ func (c *castDatumTimestamptzOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9769,9 +13863,13 @@ func (c *castDatumTimestamptzOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -9798,9 +13896,13 @@ func (c *castDatumTimestamptzOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9823,9 +13925,13 @@ func (c *castDatumTimestamptzOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						_ = outputCol.Get(n - 1)
 						var tupleIdx int
 						for i := 0; i < n; i++ {
@@ -9885,9 +13991,13 @@ func (c *castDatumUuidOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9910,9 +14020,13 @@ func (c *castDatumUuidOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -9937,9 +14051,13 @@ func (c *castDatumUuidOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -9962,9 +14080,13 @@ func (c *castDatumUuidOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -10022,9 +14144,13 @@ func (c *castDatumJsonbOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -10047,9 +14173,13 @@ func (c *castDatumJsonbOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -10074,9 +14204,13 @@ func (c *castDatumJsonbOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -10099,9 +14233,13 @@ func (c *castDatumJsonbOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -10158,9 +14296,13 @@ func (c *castDatumDatumOp) Next() coldata.Batch {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -10189,9 +14331,13 @@ func (c *castDatumDatumOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
@@ -10222,9 +14368,13 @@ func (c *castDatumDatumOp) Next() coldata.Batch {
 			} else {
 				if sel != nil {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = sel[i]
@@ -10253,9 +14403,13 @@ func (c *castDatumDatumOp) Next() coldata.Batch {
 					}
 				} else {
 					{
-						var evalCtx *eval.Context = c.evalCtx
-						// Silence unused warning.
+						var (
+							evalCtx *eval.Context = c.evalCtx
+							buf     *bytes.Buffer = &c.buf
+						)
+						// Silence unused warnings.
 						_ = evalCtx
+						_ = buf
 						var tupleIdx int
 						for i := 0; i < n; i++ {
 							tupleIdx = i
diff --git a/pkg/sql/colexec/colexecbase/cast_test.go b/pkg/sql/colexec/colexecbase/cast_test.go
index 1c13cc734393..412f9dbbe655 100644
--- a/pkg/sql/colexec/colexecbase/cast_test.go
+++ b/pkg/sql/colexec/colexecbase/cast_test.go
@@ -61,7 +61,7 @@ func TestRandomizedCast(t *testing.T) {
 			}
 		}
 	}
-	const numTypePairs = 5
+	var numTypePairs = rng.Intn(10) + 1
 	numRows := 1 + rng.Intn(coldata.BatchSize()) + rng.Intn(3)*coldata.BatchSize()
 	log.Infof(ctx, "num rows = %d", numRows)
 	for run := 0; run < numTypePairs; run++ {
diff --git a/pkg/sql/colexec/colexecbase/cast_tmpl.go b/pkg/sql/colexec/colexecbase/cast_tmpl.go
index aac8c39b058e..861ab85a8ce9 100644
--- a/pkg/sql/colexec/colexecbase/cast_tmpl.go
+++ b/pkg/sql/colexec/colexecbase/cast_tmpl.go
@@ -22,6 +22,7 @@
 package colexecbase
 
 import (
+	"bytes"
 	"context"
 	"fmt"
 	"math"
@@ -81,7 +82,7 @@ const _TYPE_WIDTH = 0
 // "castOp" template in the scope of this value's "callsite".
 const _GENERATE_CAST_OP = 0
 
-func _CAST(to, from, evalCtx, toType interface{}) {
+func _CAST(to, from, evalCtx, toType, buf interface{}) {
 	colexecerror.InternalError(errors.AssertionFailedf(""))
 }
 
@@ -235,6 +236,7 @@ type castOpBase struct {
 	colIdx    int
 	outputIdx int
 	evalCtx   *eval.Context
+	buf       bytes.Buffer
 }
 
 func (c *castOpBase) Reset(ctx context.Context) {
@@ -448,15 +450,15 @@ func (c *cast_NAMEOp) Next() coldata.Batch {
 			if inputVec.MaybeHasNulls() {
 				outputNulls.Copy(inputNulls)
 				if sel != nil {
-					castTuples(inputCol, inputNulls, outputCol, outputNulls, toType, n, sel, c.evalCtx, true, true)
+					castTuples(inputCol, inputNulls, outputCol, outputNulls, toType, n, sel, c.evalCtx, &c.buf, true, true)
 				} else {
-					castTuples(inputCol, inputNulls, outputCol, outputNulls, toType, n, sel, c.evalCtx, true, false)
+					castTuples(inputCol, inputNulls, outputCol, outputNulls, toType, n, sel, c.evalCtx, &c.buf, true, false)
 				}
 			} else {
 				if sel != nil {
-					castTuples(inputCol, inputNulls, outputCol, outputNulls, toType, n, sel, c.evalCtx, false, true)
+					castTuples(inputCol, inputNulls, outputCol, outputNulls, toType, n, sel, c.evalCtx, &c.buf, false, true)
 				} else {
-					castTuples(inputCol, inputNulls, outputCol, outputNulls, toType, n, sel, c.evalCtx, false, false)
+					castTuples(inputCol, inputNulls, outputCol, outputNulls, toType, n, sel, c.evalCtx, &c.buf, false, false)
 				}
 			}
 		},
@@ -516,11 +518,13 @@ func castTuples(
 	n int,
 	sel []int,
 	evalCtx *eval.Context,
+	buf *bytes.Buffer,
 	hasNulls bool,
 	hasSel bool,
 ) {
-	// Silence unused warning.
+	// Silence unused warnings.
 	_ = evalCtx
+	_ = buf
 	if !hasSel {
 		// {{if $fromInfo.Sliceable}}
 		_ = inputCol.Get(n - 1)
@@ -546,7 +550,7 @@ func castTuples(
 		}
 		v := inputCol.Get(tupleIdx)
 		var r _TO_GO_TYPE
-		_CAST(r, v, evalCtx, toType)
+		_CAST(r, v, evalCtx, toType, buf)
 		if !hasSel {
 			// {{if .Sliceable}}
 			//gcassert:bce
diff --git a/pkg/sql/colexec/execgen/cmd/execgen/avg_agg_gen.go b/pkg/sql/colexec/execgen/cmd/execgen/avg_agg_gen.go
index 8b6d1fe5a25a..a5ccf35d4179 100644
--- a/pkg/sql/colexec/execgen/cmd/execgen/avg_agg_gen.go
+++ b/pkg/sql/colexec/execgen/cmd/execgen/avg_agg_gen.go
@@ -145,7 +145,7 @@ func genAvgAgg(inputFileContents string, wr io.Writer) error {
 	// canonical representatives, so we can operate with their type family
 	// directly.
 	for _, inputTypeFamily := range []types.Family{types.IntFamily, types.DecimalFamily, types.FloatFamily, types.IntervalFamily} {
-		tmplInfo := avgAggTypeTmplInfo{TypeFamily: toString(inputTypeFamily)}
+		tmplInfo := avgAggTypeTmplInfo{TypeFamily: familyToString(inputTypeFamily)}
 		for _, inputTypeWidth := range supportedWidthsByCanonicalTypeFamily[inputTypeFamily] {
 			// Note that we don't use execinfrapb.GetAggregateInfo because we don't
 			// want to bring in a dependency on that package to reduce the burden
diff --git a/pkg/sql/colexec/execgen/cmd/execgen/cast_gen.go b/pkg/sql/colexec/execgen/cmd/execgen/cast_gen.go
index 7e5532e639c9..8384089e5f64 100644
--- a/pkg/sql/colexec/execgen/cmd/execgen/cast_gen.go
+++ b/pkg/sql/colexec/execgen/cmd/execgen/cast_gen.go
@@ -32,8 +32,8 @@ func genCastOperators(inputFileContents string, wr io.Writer) error {
 	)
 	s := r.Replace(inputFileContents)
 
-	castRe := makeFunctionRegex("_CAST", 4)
-	s = castRe.ReplaceAllString(s, makeTemplateFunctionCall("Cast", 4))
+	castRe := makeFunctionRegex("_CAST", 5)
+	s = castRe.ReplaceAllString(s, makeTemplateFunctionCall("Cast", 5))
 
 	tmpl, err := template.New("cast").Funcs(template.FuncMap{"buildDict": buildDict}).Parse(s)
 	if err != nil {
diff --git a/pkg/sql/colexec/execgen/cmd/execgen/cast_gen_util.go b/pkg/sql/colexec/execgen/cmd/execgen/cast_gen_util.go
index 5a4a587ad69c..e247eef28e03 100644
--- a/pkg/sql/colexec/execgen/cmd/execgen/cast_gen_util.go
+++ b/pkg/sql/colexec/execgen/cmd/execgen/cast_gen_util.go
@@ -41,7 +41,9 @@ var nativeCastInfos = []supportedNativeCastInfo{
 	{types.Bool, types.Int2, boolToIntOrFloat},
 	{types.Bool, types.Int4, boolToIntOrFloat},
 	{types.Bool, types.Int, boolToIntOrFloat},
+	{types.Bool, types.String, boolToString},
 
+	{types.Bytes, types.String, bytesToString},
 	{types.Bytes, types.Uuid, bytesToUUID},
 
 	{types.Date, types.Decimal, intToDecimal},
@@ -53,6 +55,7 @@ var nativeCastInfos = []supportedNativeCastInfo{
 	{types.Date, types.Int2, getIntToIntCastFunc(64 /* fromWidth */, 16 /* toWidth */)},
 	{types.Date, types.Int4, getIntToIntCastFunc(64 /* fromWidth */, 32 /* toWidth */)},
 	{types.Date, types.Int, getIntToIntCastFunc(64 /* fromWidth */, anyWidth)},
+	{types.Date, types.String, dateToString},
 
 	{types.Decimal, types.Bool, decimalToBool},
 	{types.Decimal, types.Decimal, decimalToDecimal},
@@ -60,28 +63,35 @@ var nativeCastInfos = []supportedNativeCastInfo{
 	{types.Decimal, types.Int2, getDecimalToIntCastFunc(16)},
 	{types.Decimal, types.Int4, getDecimalToIntCastFunc(32)},
 	{types.Decimal, types.Int, getDecimalToIntCastFunc(anyWidth)},
+	{types.Decimal, types.String, decimalToString},
 
 	{types.Float, types.Bool, numToBool},
 	{types.Float, types.Decimal, floatToDecimal},
 	{types.Float, types.Int2, floatToInt(16, 64 /* floatWidth */)},
 	{types.Float, types.Int4, floatToInt(32, 64 /* floatWidth */)},
 	{types.Float, types.Int, floatToInt(anyWidth, 64 /* floatWidth */)},
+	{types.Float, types.String, floatToString},
 
 	{types.Int2, types.Bool, numToBool},
 	{types.Int2, types.Decimal, intToDecimal},
 	{types.Int2, types.Float, intToFloat},
 	{types.Int2, types.Int4, getIntToIntCastFunc(16, 32)},
 	{types.Int2, types.Int, getIntToIntCastFunc(16, anyWidth)},
+	{types.Int2, types.String, intToString},
 	{types.Int4, types.Bool, numToBool},
 	{types.Int4, types.Decimal, intToDecimal},
 	{types.Int4, types.Float, intToFloat},
 	{types.Int4, types.Int2, getIntToIntCastFunc(32, 16)},
 	{types.Int4, types.Int, getIntToIntCastFunc(32, anyWidth)},
+	{types.Int4, types.String, intToString},
 	{types.Int, types.Bool, numToBool},
 	{types.Int, types.Decimal, intToDecimal},
 	{types.Int, types.Float, intToFloat},
 	{types.Int, types.Int2, getIntToIntCastFunc(anyWidth, 16)},
 	{types.Int, types.Int4, getIntToIntCastFunc(anyWidth, 32)},
+	{types.Int, types.String, intToString},
+
+	{types.Interval, types.String, intervalToString},
 
 	{types.Jsonb, types.String, jsonToString},
 
@@ -99,6 +109,12 @@ var nativeCastInfos = []supportedNativeCastInfo{
 	{types.String, types.Timestamp, getStringToTimestampCastFunc(true /* withoutTimezone */)},
 	{types.String, types.TimestampTZ, getStringToTimestampCastFunc(false /* withoutTimezone */)},
 	{types.String, types.Uuid, stringToUUID},
+
+	{types.Timestamp, types.String, timestampToString},
+
+	{types.TimestampTZ, types.String, timestampTZToString},
+
+	{types.Uuid, types.String, uuidToString},
 }
 
 type supportedNativeCastInfo struct {
@@ -107,7 +123,7 @@ type supportedNativeCastInfo struct {
 	cast castFunc
 }
 
-func boolToIntOrFloat(to, from, _, _ string) string {
+func boolToIntOrFloat(to, from, _, _, _ string) string {
 	convStr := `
 			%[1]s = 0
 			if %[2]s {
@@ -117,7 +133,19 @@ func boolToIntOrFloat(to, from, _, _ string) string {
 	return fmt.Sprintf(convStr, to, from)
 }
 
-func bytesToUUID(to, from, _, _ string) string {
+func boolToString(to, from, _, toType, _ string) string {
+	return toString(fmt.Sprintf("%s = []byte(strconv.FormatBool(%s))", to, from), to, toType)
+}
+
+func bytesToString(to, from, evalCtx, toType, _ string) string {
+	convStr := `
+		_format := %[3]s.SessionData().DataConversionConfig.BytesEncodeFormat
+		%[1]s = []byte(lex.EncodeByteArrayToRawBytes(string(%[2]s), _format, false /* skipHexPrefix */))
+`
+	return toString(fmt.Sprintf(convStr, to, from, evalCtx), to, toType)
+}
+
+func bytesToUUID(to, from, _, _, _ string) string {
 	convStr := `
 		_uuid, err := uuid.FromBytes(%[2]s)
 		if err != nil {
@@ -128,15 +156,25 @@ func bytesToUUID(to, from, _, _ string) string {
 	return fmt.Sprintf(convStr, to, from)
 }
 
-func decimalToBool(to, from, _, _ string) string {
+func dateToString(to, from, _, toType, buf string) string {
+	convStr := `
+		_date := pgdate.MakeCompatibleDateFromDisk(%[2]s)
+		%[3]s.Reset()
+		_date.Format(%[3]s)
+		%[1]s = []byte(%[3]s.String())
+	`
+	return toString(fmt.Sprintf(convStr, to, from, buf), to, toType)
+}
+
+func decimalToBool(to, from, _, _, _ string) string {
 	return fmt.Sprintf("%[1]s = %[2]s.Sign() != 0", to, from)
 }
 
-func decimalToDecimal(to, from, _, toType string) string {
+func decimalToDecimal(to, from, _, toType, _ string) string {
 	return toDecimal(fmt.Sprintf(`%[1]s.Set(&%[2]s)`, to, from), to, toType)
 }
 
-func decimalToFloat(to, from, _, _ string) string {
+func decimalToFloat(to, from, _, _, _ string) string {
 	convStr := `
 		{
 			f, err := %[2]s.Float64()
@@ -153,7 +191,7 @@ func getDecimalToIntCastFunc(toIntWidth int32) castFunc {
 	if toIntWidth == anyWidth {
 		toIntWidth = 64
 	}
-	return func(to, from, evalCtx, toType string) string {
+	return func(to, from, evalCtx, toType, buf string) string {
 		// convStr is a format string expecting three arguments:
 		// 1. the code snippet that performs an assigment of int64 local
 		//    variable named '_i' to the result, possibly performing the bounds
@@ -184,13 +222,17 @@ func getDecimalToIntCastFunc(toIntWidth int32) castFunc {
 		}
 		return fmt.Sprintf(
 			convStr,
-			getIntToIntCastFunc(64 /* fromWidth */, toIntWidth)(to, "_i" /* from */, evalCtx, toType),
+			getIntToIntCastFunc(64 /* fromWidth */, toIntWidth)(to, "_i" /* from */, evalCtx, toType, buf),
 			from,
 			errOutOfRange,
 		)
 	}
 }
 
+func decimalToString(to, from, _, toType, _ string) string {
+	return toString(fmt.Sprintf("%s = []byte(%s.String())", to, from), to, toType)
+}
+
 // toDecimal returns the templated code that performs the cast to a decimal. It
 // first will execute whatever is passed in 'conv' (the main conversion) and
 // then will perform the rounding of 'to' variable according to 'toType'.
@@ -204,14 +246,14 @@ func toDecimal(conv, to, toType string) string {
 	return fmt.Sprintf(convStr, conv, to, toType)
 }
 
-func numToBool(to, from, _, _ string) string {
+func numToBool(to, from, _, _, _ string) string {
 	convStr := `
 		%[1]s = %[2]s != 0
 	`
 	return fmt.Sprintf(convStr, to, from)
 }
 
-func floatToDecimal(to, from, _, toType string) string {
+func floatToDecimal(to, from, _, toType, _ string) string {
 	convStr := `
 		if _, err := %[1]s.SetFloat64(float64(%[2]s)); err != nil {
 			colexecerror.ExpectedError(err)
@@ -220,8 +262,8 @@ func floatToDecimal(to, from, _, toType string) string {
 	return toDecimal(fmt.Sprintf(convStr, to, from), to, toType)
 }
 
-func floatToInt(intWidth, floatWidth int32) func(string, string, string, string) string {
-	return func(to, from, _, _ string) string {
+func floatToInt(intWidth, floatWidth int32) castFunc {
+	return func(to, from, _, _, _ string) string {
 		convStr := `
 			if math.IsNaN(float64(%[2]s)) || %[2]s <= float%[4]d(math.MinInt%[3]d) || %[2]s >= float%[4]d(math.MaxInt%[3]d) {
 				colexecerror.ExpectedError(tree.ErrIntOutOfRange)
@@ -235,14 +277,22 @@ func floatToInt(intWidth, floatWidth int32) func(string, string, string, string)
 	}
 }
 
-func intToDecimal(to, from, _, toType string) string {
+func floatToString(to, from, evalCtx, toType, _ string) string {
+	convStr := `
+		dcc := %[3]s.SessionData().DataConversionConfig
+		%[1]s = tree.PgwireFormatFloat(nil /* buf */, %[2]s, dcc, types.Float)
+`
+	return toString(fmt.Sprintf(convStr, to, from, evalCtx), to, toType)
+}
+
+func intToDecimal(to, from, _, toType, _ string) string {
 	conv := `
 		%[1]s.SetInt64(int64(%[2]s))
 	`
 	return toDecimal(fmt.Sprintf(conv, to, from), to, toType)
 }
 
-func intToFloat(to, from, _, _ string) string {
+func intToFloat(to, from, _, _, _ string) string {
 	convStr := `
 		%[1]s = float64(%[2]s)
 	`
@@ -257,7 +307,7 @@ func getIntToIntCastFunc(fromWidth, toWidth int32) castFunc {
 	if toWidth == anyWidth {
 		toWidth = 64
 	}
-	return func(to, from, _, _ string) string {
+	return func(to, from, _, _, _ string) string {
 		if fromWidth <= toWidth {
 			// If we're not reducing the width, there is no need to perform the
 			// integer range check.
@@ -286,23 +336,40 @@ func getIntToIntCastFunc(fromWidth, toWidth int32) castFunc {
 	}
 }
 
-func jsonToString(to, from, _, toType string) string {
+func intToString(to, from, _, toType, _ string) string {
 	convStr := `
-		_string := %[2]s.String()
-		switch %[3]s.Oid() {
-		case oid.T_char:
-			// "char" is supposed to truncate long values.
-			_string = util.TruncateString(_string, 1)
-		case oid.T_bpchar:
-			// bpchar types truncate trailing whitespace.
-			_string = strings.TrimRight(_string, " ")
+		if %[3]s.Oid() == oid.T_char {
+			// int to "char" casts just return the corresponding ASCII byte.
+			if %[2]s > math.MaxInt8 || %[2]s < math.MinInt8 {
+				colexecerror.ExpectedError(tree.ErrCharOutOfRange)
+			}
+			if %[2]s == 0 {
+				%[1]s = []byte{}
+			} else {
+				%[1]s = []byte{byte(%[2]s)}
+			}
+		} else {
+			%[1]s = []byte(strconv.FormatInt(int64(%[2]s), 10))
 		}
-		%[1]s = []byte(_string)
-	`
-	return fmt.Sprintf(convStr, to, from, toType)
+`
+	return toString(fmt.Sprintf(convStr, to, from, toType), to, toType)
+}
+
+func intervalToString(to, from, evalCtx, toType, buf string) string {
+	convStr := `
+		dcc := %[3]s.SessionData().DataConversionConfig
+		%[4]s.Reset()
+		%[2]s.FormatWithStyle(%[4]s, dcc.IntervalStyle)
+		%[1]s = []byte(%[4]s.String())
+`
+	return toString(fmt.Sprintf(convStr, to, from, evalCtx, buf), to, toType)
+}
+
+func jsonToString(to, from, _, toType, _ string) string {
+	return toString(fmt.Sprintf("%s = []byte(%s.String())", to, from), to, toType)
 }
 
-func stringToBool(to, from, _, _ string) string {
+func stringToBool(to, from, _, _, _ string) string {
 	convStr := `
 		var err error
 		%[1]s, err = tree.ParseBool(string(%[2]s))
@@ -313,7 +380,7 @@ func stringToBool(to, from, _, _ string) string {
 	return fmt.Sprintf(convStr, to, from)
 }
 
-func stringToBytes(to, from, _, _ string) string {
+func stringToBytes(to, from, _, _, _ string) string {
 	convStr := `
 		var err error
 		%[1]s, err = lex.DecodeRawBytesToByteArrayAuto(%[2]s)
@@ -324,7 +391,7 @@ func stringToBytes(to, from, _, _ string) string {
 	return fmt.Sprintf(convStr, to, from)
 }
 
-func stringToDate(to, from, evalCtx, _ string) string {
+func stringToDate(to, from, evalCtx, _, _ string) string {
 	convStr := `
 		_now := %[3]s.GetRelativeParseTime()
 		_dateStyle := %[3]s.GetDateStyle()
@@ -337,7 +404,7 @@ func stringToDate(to, from, evalCtx, _ string) string {
 	return fmt.Sprintf(convStr, to, from, evalCtx)
 }
 
-func stringToDecimal(to, from, _, toType string) string {
+func stringToDecimal(to, from, _, toType, _ string) string {
 	convStr := `
 		_s := strings.TrimSpace(string(%[2]s))
 		_, res, err := tree.ExactCtx.SetString(&%[1]s, _s)
@@ -359,7 +426,7 @@ func stringToDecimal(to, from, _, toType string) string {
 	return toDecimal(fmt.Sprintf(convStr, to, from), to, toType)
 }
 
-func stringToFloat(to, from, _, toType string) string {
+func stringToFloat(to, from, _, toType, _ string) string {
 	convStr := `
 		_s := string(%[2]s)
 		var _err error
@@ -375,7 +442,7 @@ func getStringToIntCastFunc(toIntWidth int32) castFunc {
 	if toIntWidth == anyWidth {
 		toIntWidth = 64
 	}
-	return func(to, from, evalCtx, toType string) string {
+	return func(to, from, evalCtx, toType, buf string) string {
 		// convStr is a format string expecting three arguments:
 		// 1. the code snippet that performs an assigment of int64 local
 		//    variable named '_i' to the result, possibly performing the bounds
@@ -394,14 +461,14 @@ func getStringToIntCastFunc(toIntWidth int32) castFunc {
 	`
 		return fmt.Sprintf(
 			convStr,
-			getIntToIntCastFunc(64 /* fromWidth */, toIntWidth)(to, "_i" /* from */, evalCtx, toType),
+			getIntToIntCastFunc(64 /* fromWidth */, toIntWidth)(to, "_i" /* from */, evalCtx, toType, buf),
 			from,
 			toType,
 		)
 	}
 }
 
-func stringToInterval(to, from, evalCtx, toType string) string {
+func stringToInterval(to, from, evalCtx, toType, _ string) string {
 	convStr := `
 		_itm, err := %[4]s.IntervalTypeMetadata()
 		if err != nil {
@@ -416,7 +483,7 @@ func stringToInterval(to, from, evalCtx, toType string) string {
 	return fmt.Sprintf(convStr, to, from, evalCtx, toType)
 }
 
-func stringToJSON(to, from, _, _ string) string {
+func stringToJSON(to, from, _, _, _ string) string {
 	convStr := `
 		var err error
 		%[1]s, err = json.ParseJSON(string(%[2]s))
@@ -427,13 +494,19 @@ func stringToJSON(to, from, _, _ string) string {
 	return fmt.Sprintf(convStr, to, from)
 }
 
-func stringToString(to, from, _, toType string) string {
+// TODO(yuzefovich): figure out whether we can avoid converting to a string in
+// the template below.
+
+// toString returns the templated code that performs the cast to a string. It
+// first will execute whatever is passed in 'conv' (the main conversion) and
+// then will perform the truncation of 'to' variable according to 'toType'.
+func toString(conv, to, toType string) string {
+	// The logic here is a combination of the relevant pieces from
+	// eval.performCastWithoutPrecisionTruncation as well as from
+	// tree.AdjustValueToType.
 	convStr := `
-		if %[3]s.Oid() == oid.T_name {
-			// For Names we don't perform the truncation, and there is no need
-			// to do anything about the Oids since those are stored in the type.
-			%[1]s = %[2]s
-		} else {
+		%[1]s
+		if %[3]s.Oid() != oid.T_name {
 			// bpchar types truncate trailing whitespace.
 			if %[3]s.Oid() == oid.T_bpchar {
 				%[2]s = bytes.TrimRight(%[2]s, " ")
@@ -442,24 +515,41 @@ func stringToString(to, from, _, toType string) string {
 			//   'hello'::CHAR(2) -> 'he'
 			// This is true of all the string type variants.
 			if %[3]s.Width() > 0 {
-				// TODO(yuzefovich): figure out whether we can avoid converting
-				// to a string.
 				%[2]s = []byte(util.TruncateString(string(%[2]s), int(%[3]s.Width())))
 			}
 			if %[3]s.Oid() == oid.T_char {
 				// "char" is supposed to truncate long values.
-				// TODO(yuzefovich): figure out whether we can avoid converting
-				// to a string.
 				%[2]s = []byte(util.TruncateString(string(%[2]s), 1))
 			}
-			%[1]s = %[2]s
+		}
+		if %[3]s.Width() > 0 && utf8.RuneCountInString(string(%[2]s)) > int(%[3]s.Width()) {
+			_typeString := %[3]s.SQLString()
+			colexecerror.ExpectedError(
+				pgerror.Newf(pgcode.StringDataRightTruncation, "value too long for type " + _typeString,
+			))
 		}
 	`
-	return fmt.Sprintf(convStr, to, from, toType)
+	return fmt.Sprintf(convStr, conv, to, toType)
+}
+
+func stringToString(to, from, _, toType, _ string) string {
+	return toString(fmt.Sprintf("%s = %s", to, from), to, toType)
 }
 
-func getStringToTimestampCastFunc(withoutTimezone bool) func(_, _, _, _ string) string {
-	return func(to, from, evalCtx, toType string) string {
+// roundTimestamp is a template that takes a timestamp specified by 'from',
+// rounds it according to 'precision', and assigns the result to 'to' timestamp.
+func roundTimestamp(to, from, precision string) string {
+	roundStr := `
+		%[1]s = %[2]s.Round(%[3]s)
+		if %[1]s.After(tree.MaxSupportedTime) || %[1]s.Before(tree.MinSupportedTime) {
+			colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(%[1]s))
+		}
+`
+	return fmt.Sprintf(roundStr, to, from, precision)
+}
+
+func getStringToTimestampCastFunc(withoutTimezone bool) castFunc {
+	return func(to, from, evalCtx, toType, _ string) string {
 		var parseTimestampKind string
 		if withoutTimezone {
 			parseTimestampKind = "WithoutTimezone"
@@ -475,16 +565,14 @@ func getStringToTimestampCastFunc(withoutTimezone bool) func(_, _, _, _ string)
 		if err != nil {
 			colexecerror.ExpectedError(err)
 		}
-		%[1]s = _t.Round(_roundTo)
-		if %[1]s.After(tree.MaxSupportedTime) || %[1]s.Before(tree.MinSupportedTime) {
-			colexecerror.ExpectedError(tree.NewTimestampExceedsBoundsError(%[1]s))
-		}
+		%[1]s
 `
-		return fmt.Sprintf(convStr, to, from, evalCtx, toType, parseTimestampKind)
+		roundAndAssign := roundTimestamp(to, "_t", "_roundTo")
+		return fmt.Sprintf(convStr, roundAndAssign, from, evalCtx, toType, parseTimestampKind)
 	}
 }
 
-func stringToUUID(to, from, _, _ string) string {
+func stringToUUID(to, from, _, _, _ string) string {
 	convStr := `
 		_uuid, err := uuid.FromString(string(%[2]s))
 		if err != nil {
@@ -495,14 +583,40 @@ func stringToUUID(to, from, _, _ string) string {
 	return fmt.Sprintf(convStr, to, from)
 }
 
+func timestampToString(to, from, _, toType, _ string) string {
+	return toString(fmt.Sprintf("%s = []byte(tree.FormatTimestamp(%s))", to, from), to, toType)
+}
+
+func timestampTZToString(to, from, evalCtx, toType, buf string) string {
+	convStr := `
+		// Convert to context timezone for correct display.
+		_t := %[2]s.In(%[3]s.GetLocation())
+		%[5]s
+		%[4]s.Reset()
+		tree.FormatTimestampTZ(_t, %[4]s)
+		%[1]s = []byte(%[4]s.String())
+`
+	roundT := roundTimestamp("_t", "_t", "time.Microsecond")
+	return toString(fmt.Sprintf(convStr, to, from, evalCtx, buf, roundT), to, toType)
+}
+
+func uuidToString(to, from, _, toType, _ string) string {
+	convStr := `
+		_uuid, err := uuid.FromBytes(%[2]s)
+		if err != nil {
+			colexecerror.ExpectedError(err)
+		}
+		%[1]s = []byte(_uuid.String())
+	`
+	return toString(fmt.Sprintf(convStr, to, from), to, toType)
+}
+
 // getDatumToNativeCastFunc returns a castFunc for casting datum-backed value
 // to a value of the specified physical representation (i.e. to natively
 // supported type). The returned castFunc assumes that there is a converter
 // function named "converter" in scope.
-func getDatumToNativeCastFunc(
-	nonDatumPhysicalRepresentation string,
-) func(string, string, string, string) string {
-	return func(to, from, evalCtx, toType string) string {
+func getDatumToNativeCastFunc(nonDatumPhysicalRepresentation string) castFunc {
+	return func(to, from, evalCtx, toType, _ string) string {
 		convStr := `
 		{
 			_castedDatum, err := eval.PerformCast(%[3]s, %[2]s.(tree.Datum), %[4]s)
@@ -516,7 +630,7 @@ func getDatumToNativeCastFunc(
 	}
 }
 
-func datumToDatum(to, from, evalCtx, toType string) string {
+func datumToDatum(to, from, evalCtx, toType, _ string) string {
 	convStr := `
 		{
 			_castedDatum, err := eval.PerformCast(%[3]s, %[2]s.(tree.Datum), %[4]s)
@@ -638,8 +752,8 @@ func (i castToWidthTmplInfo) TypeName() string {
 	return getTypeName(i.toType)
 }
 
-func (i castToWidthTmplInfo) Cast(to, from, evalCtx, toType string) string {
-	return i.CastFn(to, from, evalCtx, toType)
+func (i castToWidthTmplInfo) Cast(to, from, evalCtx, toType, buf string) string {
+	return i.CastFn(to, from, evalCtx, toType, buf)
 }
 
 func (i castToWidthTmplInfo) Sliceable() bool {
@@ -662,8 +776,8 @@ func (i castDatumToWidthTmplInfo) TypeName() string {
 	return getTypeName(i.toType)
 }
 
-func (i castDatumToWidthTmplInfo) Cast(to, from, evalCtx, toType string) string {
-	return i.CastFn(to, from, evalCtx, toType)
+func (i castDatumToWidthTmplInfo) Cast(to, from, evalCtx, toType, buf string) string {
+	return i.CastFn(to, from, evalCtx, toType, buf)
 }
 
 func (i castDatumToWidthTmplInfo) Sliceable() bool {
@@ -674,8 +788,8 @@ func (i castBetweenDatumsTmplInfo) TypeName() string {
 	return datumVecTypeName
 }
 
-func (i castBetweenDatumsTmplInfo) Cast(to, from, evalCtx, toType string) string {
-	return datumToDatum(to, from, evalCtx, toType)
+func (i castBetweenDatumsTmplInfo) Cast(to, from, evalCtx, toType, buf string) string {
+	return datumToDatum(to, from, evalCtx, toType, buf)
 }
 
 func (i castBetweenDatumsTmplInfo) Sliceable() bool {
diff --git a/pkg/sql/colexec/execgen/cmd/execgen/overloads_base.go b/pkg/sql/colexec/execgen/cmd/execgen/overloads_base.go
index 21f067226667..74438060106b 100644
--- a/pkg/sql/colexec/execgen/cmd/execgen/overloads_base.go
+++ b/pkg/sql/colexec/execgen/cmd/execgen/overloads_base.go
@@ -123,7 +123,7 @@ func (b *overloadBase) String() string {
 	return fmt.Sprintf("%s: %s", b.Name, b.OpStr)
 }
 
-func toString(family types.Family) string {
+func familyToString(family types.Family) string {
 	switch family {
 	case typeconv.DatumVecCanonicalTypeFamily:
 		return "typeconv.DatumVecCanonicalTypeFamily"
@@ -140,7 +140,7 @@ type argTypeOverloadBase struct {
 func newArgTypeOverloadBase(canonicalTypeFamily types.Family) *argTypeOverloadBase {
 	return &argTypeOverloadBase{
 		CanonicalTypeFamily:    canonicalTypeFamily,
-		CanonicalTypeFamilyStr: toString(canonicalTypeFamily),
+		CanonicalTypeFamilyStr: familyToString(canonicalTypeFamily),
 	}
 }
 
@@ -359,7 +359,7 @@ type twoArgsResolvedOverloadRightWidthInfo struct {
 
 type assignFunc func(op *lastArgWidthOverload, targetElem, leftElem, rightElem, targetCol, leftCol, rightCol string) string
 type compareFunc func(targetElem, leftElem, rightElem, leftCol, rightCol string) string
-type castFunc func(to, from, evalCtx, toType string) string
+type castFunc func(to, from, evalCtx, toType, buf string) string
 type hashFunc func(targetElem, vElem, vVec, vIdx string) string
 
 // Assign produces a Go source string that assigns the "targetElem" variable to
diff --git a/pkg/sql/colexec/execgen/cmd/execgen/overloads_gen_util.go b/pkg/sql/colexec/execgen/cmd/execgen/overloads_gen_util.go
index bfe96534ab77..8ba86057b752 100644
--- a/pkg/sql/colexec/execgen/cmd/execgen/overloads_gen_util.go
+++ b/pkg/sql/colexec/execgen/cmd/execgen/overloads_gen_util.go
@@ -49,13 +49,13 @@ func populateTwoArgsOverloads(
 		if !found {
 			colexecerror.InternalError(errors.AssertionFailedf("didn't find supported widths for %s", leftFamily))
 		}
-		leftFamilyStr := toString(leftFamily)
+		leftFamilyStr := familyToString(leftFamily)
 		for _, rightFamily := range combinableCanonicalTypeFamilies[leftFamily] {
 			rightWidths, found := supportedWidthsByCanonicalTypeFamily[rightFamily]
 			if !found {
 				colexecerror.InternalError(errors.AssertionFailedf("didn't find supported widths for %s", rightFamily))
 			}
-			rightFamilyStr := toString(rightFamily)
+			rightFamilyStr := familyToString(rightFamily)
 			for _, leftWidth := range leftWidths {
 				for _, rightWidth := range rightWidths {
 					customizer, ok := customizers[typePair{leftFamily, leftWidth, rightFamily, rightWidth}]
diff --git a/pkg/sql/colexec/execgen/cmd/execgen/range_offset_handler_gen.go b/pkg/sql/colexec/execgen/cmd/execgen/range_offset_handler_gen.go
index 4c3bb9932452..feaad76bebf4 100644
--- a/pkg/sql/colexec/execgen/cmd/execgen/range_offset_handler_gen.go
+++ b/pkg/sql/colexec/execgen/cmd/execgen/range_offset_handler_gen.go
@@ -76,7 +76,7 @@ func rangeOffsetHandlerGenerator(inputFileContents string, wr io.Writer) error {
 				ordColDirInfo := windowFrameOrdDirInfo{IsOrdColAsc: isOrdColAsc}
 				for _, typeFamily := range rangeOrderColTypeFamilies {
 					canonicalTypeFamily := typeconv.TypeFamilyToCanonicalTypeFamily(typeFamily)
-					typeFamilyStr := toString(typeFamily)
+					typeFamilyStr := familyToString(typeFamily)
 					typeFamilyInfo := windowFrameOrderTypeFamilyInfo{
 						TypeFamily: typeFamilyStr,
 					}
diff --git a/pkg/sql/colexec/execgen/cmd/execgen/span_encoder_gen.go b/pkg/sql/colexec/execgen/cmd/execgen/span_encoder_gen.go
index b0f7e238b384..bd390c673dd3 100644
--- a/pkg/sql/colexec/execgen/cmd/execgen/span_encoder_gen.go
+++ b/pkg/sql/colexec/execgen/cmd/execgen/span_encoder_gen.go
@@ -48,7 +48,7 @@ func genSpanEncoder(inputFileContents string, wr io.Writer) error {
 				// We are currently unable to encode JSON as a table key.
 				continue
 			}
-			familyInfo := spanEncoderTypeFamilyInfo{TypeFamily: toString(family)}
+			familyInfo := spanEncoderTypeFamilyInfo{TypeFamily: familyToString(family)}
 			for _, width := range supportedWidthsByCanonicalTypeFamily[family] {
 				overload := spanEncoderTmplInfo{
 					Asc:        asc,
diff --git a/pkg/sql/colexec/execgen/cmd/execgen/sum_agg_gen.go b/pkg/sql/colexec/execgen/cmd/execgen/sum_agg_gen.go
index 3b7583e56f60..64cede0e6950 100644
--- a/pkg/sql/colexec/execgen/cmd/execgen/sum_agg_gen.go
+++ b/pkg/sql/colexec/execgen/cmd/execgen/sum_agg_gen.go
@@ -161,7 +161,7 @@ func genSumAgg(inputFileContents string, wr io.Writer, isSumInt bool) error {
 	var tmplInfos []sumAggTypeTmplInfo
 	for _, inputTypeFamily := range supportedTypeFamilies {
 		tmplInfo := sumAggTypeTmplInfo{
-			TypeFamily: toString(inputTypeFamily),
+			TypeFamily: familyToString(inputTypeFamily),
 		}
 		for _, inputTypeWidth := range supportedWidthsByCanonicalTypeFamily[inputTypeFamily] {
 			// Note that we don't use execinfrapb.GetAggregateInfo because we don't
diff --git a/pkg/sql/sem/eval/cast.go b/pkg/sql/sem/eval/cast.go
index 7fedc6246598..094e15780cc3 100644
--- a/pkg/sql/sem/eval/cast.go
+++ b/pkg/sql/sem/eval/cast.go
@@ -399,7 +399,7 @@ func performCastWithoutPrecisionTruncation(
 			s = string(b)
 		case *tree.DInt:
 			if typ.Oid() == oid.T_char {
-				// int to "char" casts just return the correspondong ASCII byte.
+				// int to "char" casts just return the corresponding ASCII byte.
 				if *t > math.MaxInt8 || *t < math.MinInt8 {
 					return nil, tree.ErrCharOutOfRange
 				} else if *t == 0 {
diff --git a/pkg/sql/sem/tree/datum.go b/pkg/sql/sem/tree/datum.go
index 60cd0a61800c..2fa33c4d758e 100644
--- a/pkg/sql/sem/tree/datum.go
+++ b/pkg/sql/sem/tree/datum.go
@@ -2807,6 +2807,11 @@ func (d *DTimestamp) Max(ctx CompareContext) (Datum, bool) {
 // AmbiguousFormat implements the Datum interface.
 func (*DTimestamp) AmbiguousFormat() bool { return true }
 
+// FormatTimestamp outputs a timestamp in the UTC timezone.
+func FormatTimestamp(t time.Time) string {
+	return t.UTC().Format(timestampOutputFormat)
+}
+
 // Format implements the NodeFormatter interface.
 func (d *DTimestamp) Format(ctx *FmtCtx) {
 	f := ctx.flags
@@ -2814,7 +2819,7 @@ func (d *DTimestamp) Format(ctx *FmtCtx) {
 	if !bareStrings {
 		ctx.WriteByte('\'')
 	}
-	ctx.WriteString(d.UTC().Format(timestampOutputFormat))
+	ctx.WriteString(FormatTimestamp(d.Time))
 	if !bareStrings {
 		ctx.WriteByte('\'')
 	}
@@ -2974,15 +2979,11 @@ func (d *DTimestampTZ) Max(ctx CompareContext) (Datum, bool) {
 // AmbiguousFormat implements the Datum interface.
 func (*DTimestampTZ) AmbiguousFormat() bool { return true }
 
-// Format implements the NodeFormatter interface.
-func (d *DTimestampTZ) Format(ctx *FmtCtx) {
-	f := ctx.flags
-	bareStrings := f.HasFlags(FmtFlags(lexbase.EncBareStrings))
-	if !bareStrings {
-		ctx.WriteByte('\'')
-	}
-	ctx.WriteString(d.Time.Format(timestampTZOutputFormat))
-	_, offsetSecs := d.Time.Zone()
+// FormatTimestampTZ formats the given timestamp with timezone into the provided
+// buffer.
+func FormatTimestampTZ(t time.Time, buf *bytes.Buffer) {
+	buf.WriteString(t.Format(timestampTZOutputFormat))
+	_, offsetSecs := t.Zone()
 	// Only output remaining seconds offsets if it is available.
 	// This is to maintain backward compatibility with older CRDB versions,
 	// where we only output HH:MM.
@@ -2990,9 +2991,19 @@ func (d *DTimestampTZ) Format(ctx *FmtCtx) {
 		if secondOffset < 0 {
 			secondOffset = 60 + secondOffset
 		}
-		ctx.WriteByte(':')
-		ctx.WriteString(fmt.Sprintf("%02d", secondOffset))
+		buf.WriteByte(':')
+		buf.WriteString(fmt.Sprintf("%02d", secondOffset))
+	}
+}
+
+// Format implements the NodeFormatter interface.
+func (d *DTimestampTZ) Format(ctx *FmtCtx) {
+	f := ctx.flags
+	bareStrings := f.HasFlags(FmtFlags(lexbase.EncBareStrings))
+	if !bareStrings {
+		ctx.WriteByte('\'')
 	}
+	FormatTimestampTZ(d.Time, &ctx.Buffer)
 	if !bareStrings {
 		ctx.WriteByte('\'')
 	}
@@ -5640,7 +5651,14 @@ func AdjustValueToType(typ *types.T, inVal Datum) (outVal Datum, err error) {
 		} else if v, ok := inVal.(*DCollatedString); ok {
 			sv = v.Contents
 		}
-		sv = adjustStringValueToType(typ, sv)
+		switch typ.Oid() {
+		case oid.T_char:
+			// "char" is supposed to truncate long values.
+			sv = util.TruncateString(sv, 1)
+		case oid.T_bpchar:
+			// bpchar types truncate trailing whitespace.
+			sv = strings.TrimRight(sv, " ")
+		}
 		if typ.Width() > 0 && utf8.RuneCountInString(sv) > int(typ.Width()) {
 			return nil, pgerror.Newf(pgcode.StringDataRightTruncation,
 				"value too long for type %s",
@@ -5783,17 +5801,3 @@ func AdjustValueToType(typ *types.T, inVal Datum) (outVal Datum, err error) {
 	}
 	return inVal, nil
 }
-
-// adjustStringToType checks that the width for strings fits the
-// specified column type.
-func adjustStringValueToType(typ *types.T, sv string) string {
-	switch typ.Oid() {
-	case oid.T_char:
-		// "char" is supposed to truncate long values
-		return util.TruncateString(sv, 1)
-	case oid.T_bpchar:
-		// bpchar types truncate trailing whitespace.
-		return strings.TrimRight(sv, " ")
-	}
-	return sv
-}