Skip to content

Commit

Permalink
sql: allow cast from a type T to T in all contexts
Browse files Browse the repository at this point in the history
This commit updates `tree.ValidCast` so that it returns true when the
given types are identical for any cast context. Casts from a type
without modifiers (like width modifiers) to the same type have been
removed from the cast map because they are no longer necessary.

Release note: None
  • Loading branch information
mgartner committed Nov 29, 2021
1 parent 206f956 commit 6be0153
Showing 1 changed file with 44 additions and 49 deletions.
93 changes: 44 additions & 49 deletions pkg/sql/sem/tree/cast.go
Expand Up @@ -79,11 +79,6 @@ const (
// contextOriginPgCast specifies that a cast's maximum context is based on
// information in Postgres's pg_cast table.
contextOriginPgCast
// contextOriginSameType specifies that a cast's maximum context is not
// included in Postgres's pg_cast table. This is only used for casts where
// the source and target are the same. Such casts have a maximum context of
// implicit.
contextOriginSameType
// contextOriginAutomaticIOConversion specifies that a cast's maximum
// context is not included in Postgres's pg_cast table. In Postgres's
// internals, these casts are evaluated by each data type's input and output
Expand Down Expand Up @@ -148,7 +143,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_varchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
},
oid.T_bool: {
oid.T_bool: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int4: {maxContext: CastContextExplicit, origin: contextOriginPgCast},
oid.T_text: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
Expand All @@ -158,7 +152,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_name: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
},
oidext.T_box2d: {
oidext.T_box2d: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oidext.T_geometry: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
Expand Down Expand Up @@ -205,7 +198,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_varbit: {maxContext: CastContextExplicit, origin: contextOriginAutomaticIOConversion},
},
oid.T_bytea: {
oid.T_bytea: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oidext.T_geography: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oidext.T_geometry: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
Expand All @@ -217,7 +209,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
},
oid.T_char: {
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_char: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_int4: {maxContext: CastContextExplicit, origin: contextOriginPgCast},
oid.T_text: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_varchar: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
Expand Down Expand Up @@ -254,7 +245,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_varbit: {maxContext: CastContextExplicit, origin: contextOriginAutomaticIOConversion},
},
oid.T_date: {
oid.T_date: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_timestamp: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_timestamptz: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
Expand All @@ -265,7 +255,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_varchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
},
oid.T_float4: {
oid.T_float4: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_float8: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_int2: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
Expand All @@ -280,7 +269,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
},
oid.T_float8: {
oid.T_float4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_float8: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_int2: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
Expand Down Expand Up @@ -318,7 +306,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
},
oid.T_inet: {
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_inet: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_text: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_varchar: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
Expand All @@ -328,7 +315,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_int2: {
oid.T_float4: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_float8: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_int2: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_int4: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_numeric: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
Expand All @@ -353,7 +339,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_float4: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_float8: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_int2: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int4: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_int8: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_numeric: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
Expand All @@ -375,7 +360,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_float8: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_int2: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_numeric: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regclass: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
Expand Down Expand Up @@ -408,7 +392,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_int2: {maxContext: CastContextExplicit, origin: contextOriginPgCast},
oid.T_int4: {maxContext: CastContextExplicit, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextExplicit, origin: contextOriginPgCast},
oid.T_jsonb: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_numeric: {maxContext: CastContextExplicit, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
Expand All @@ -419,7 +402,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
},
oid.T_name: {
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_name: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_text: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_varchar: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
Expand Down Expand Up @@ -472,7 +454,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_oid: {
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_regclass: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regnamespace: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regproc: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
Expand All @@ -487,10 +468,9 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_varchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
},
oid.T_regclass: {
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regclass: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
oid.T_char: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
Expand All @@ -499,10 +479,9 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_varchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
},
oid.T_regnamespace: {
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regnamespace: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
oid.T_char: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
Expand All @@ -514,7 +493,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regproc: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_regprocedure: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
Expand All @@ -524,11 +502,10 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_varchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
},
oid.T_regprocedure: {
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regproc: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regprocedure: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regproc: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
oid.T_char: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
Expand All @@ -537,10 +514,9 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_varchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
},
oid.T_regrole: {
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regrole: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
oid.T_char: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
Expand All @@ -549,10 +525,9 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_varchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
},
oid.T_regtype: {
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regtype: {maxContext: CastContextImplicit, origin: contextOriginSameType},
oid.T_int4: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_int8: {maxContext: CastContextAssignment, origin: contextOriginPgCast},
oid.T_oid: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
// Automatic I/O conversions to string types.
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
oid.T_char: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
Expand All @@ -566,8 +541,19 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oidext.T_geometry: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_name: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_regclass: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_varchar: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_text: {maxContext: CastContextImplicit, origin: contextOriginSameType},
// We include a TEXT->TEXT entry to mimic the VARCHAR->VARCHAR entry
// that is included in the pg_cast table. Postgres doesn't include a
// TEXT->TEXT entry because it does not allow width-limited TEXT types,
// so a cast from TEXT->TEXT is always a trivial no-op because the types
// are always identical (see ValidCast). Because we support
// width-limited TEXT types with STRING(n), it is possible to have
// non-identical TEXT types. So, we must include a TEXT->TEXT entry so
// that casts from STRING(n)->STRING(m) are valid.
//
// TODO(#72980): If we use the VARCHAR OID for STRING(n) types rather
// then the TEXT OID, and we can remove this entry.
oid.T_text: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
oid.T_varchar: {maxContext: CastContextImplicit, origin: contextOriginPgCast},
// Automatic I/O conversions from TEXT to other types.
oid.T_bit: {maxContext: CastContextExplicit, origin: contextOriginAutomaticIOConversion},
oid.T_bool: {maxContext: CastContextExplicit, origin: contextOriginAutomaticIOConversion},
Expand Down Expand Up @@ -681,7 +667,6 @@ var castMap = map[oid.Oid]map[oid.Oid]cast{
oid.T_varchar: {maxContext: CastContextImplicit, origin: contextOriginNullConversion},
},
oid.T_uuid: {
oid.T_uuid: {maxContext: CastContextImplicit, origin: contextOriginSameType},
// Automatic I/O conversions to string types.
oid.T_bpchar: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
oid.T_char: {maxContext: CastContextAssignment, origin: contextOriginAutomaticIOConversion},
Expand Down Expand Up @@ -759,6 +744,9 @@ func init() {
// Assert that there is a cast to and from every string type.
for _, strType := range stringTypes {
for otherType := range castMap {
if strType == otherType {
continue
}
strTypeName := oid.TypeName[strType]
otherTypeName := oid.TypeName[otherType]
if _, from := castMap[strType][otherType]; !from && otherType != oid.T_unknown {
Expand Down Expand Up @@ -850,6 +838,11 @@ func ForEachCast(fn func(src, tgt oid.Oid)) {
// ValidCast returns true if a valid cast exists from src to tgt in the given
// context.
func ValidCast(src, tgt *types.T, ctx CastContext) bool {
// If src and tgt are identical, a cast is valid in any context.
if src.Identical(tgt) {
return true
}

srcFamily := src.Family()
tgtFamily := tgt.Family()

Expand Down Expand Up @@ -1359,7 +1352,8 @@ func LookupCastVolatility(from, to *types.T, sd *sessiondata.SessionData) (_ Vol
}

// PerformCast performs a cast from the provided Datum to the specified
// types.T.
// types.T. The original datum is returned if its type is identical
// to the specified type.
func PerformCast(ctx *EvalContext, d Datum, t *types.T) (Datum, error) {
ret, err := performCastWithoutPrecisionTruncation(ctx, d, t, true /* truncateWidth */)
if err != nil {
Expand All @@ -1369,10 +1363,11 @@ func PerformCast(ctx *EvalContext, d Datum, t *types.T) (Datum, error) {
}

// PerformAssignmentCast performs an assignment cast from the provided Datum to
// the specified type. It is similar to PerformCast, but differs because it
// errors if the datum's width is too wide for the given type rather than
// silently truncating. The one exception is casts to the special "char" type
// which are truncated.
// the specified type. The original datum is returned if its type is identical
// to the specified type. It is similar to PerformCast, but differs because it
// errors in more cases than PerformCast if the datum's width is too wide for
// the given type rather than silently truncating. The one exception is casts to
// the special "char" type which are truncated.
func PerformAssignmentCast(ctx *EvalContext, d Datum, t *types.T) (Datum, error) {
if !ValidCast(d.ResolvedType(), t, CastContextAssignment) {
return nil, pgerror.Newf(
Expand Down

0 comments on commit 6be0153

Please sign in to comment.