diff --git a/core/casts/collection.go b/core/casts/collection.go index bf1a74ffe6..1093792f33 100644 --- a/core/casts/collection.go +++ b/core/casts/collection.go @@ -89,7 +89,7 @@ func (pgc *Collection) GetExplicitCast(ctx *sql.Context, sourceType *pgtypes.Dol return c, nil } // We check for the identity and sizing casts after checking the maps, as the identity may be overridden by a user. - if cast := pgc.getSizingOrIdentityCast(sourceType, targetType, CastType_Explicit); cast.ID.IsValid() { + if cast := pgc.getSizingOrIdentityCast(castID, sourceType, targetType, CastType_Explicit); cast.ID.IsValid() { return cast, nil } // We then check for a record to composite cast @@ -134,8 +134,8 @@ func (pgc *Collection) GetExplicitCast(ctx *sql.Context, sourceType *pgtypes.Dol // GetAssignmentCast returns the assignment type cast function that will cast the source type to the target type. // Returns a Cast with an invalid ID if such a cast is not valid. func (pgc *Collection) GetAssignmentCast(ctx *sql.Context, sourceType *pgtypes.DoltgresType, targetType *pgtypes.DoltgresType) (Cast, error) { - castID := id.NewCast(sourceType.ID, targetType.ID) - c, err := pgc.getCast(ctx, castID, sourceType, targetType, CastType_Assignment) + castID := id.NewCast(sourceType.ID, targetType.ID) // TODO: expensive + c, err := pgc.getCast(ctx, castID, sourceType, targetType, CastType_Assignment) // TODO: expensive if err != nil { return Cast{}, err } @@ -146,7 +146,7 @@ func (pgc *Collection) GetAssignmentCast(ctx *sql.Context, sourceType *pgtypes.D return c, nil } // We check for the identity and sizing casts after checking the maps, as the identity may be overridden by a user. - if cast := pgc.getSizingOrIdentityCast(sourceType, targetType, CastType_Assignment); cast.ID.IsValid() { + if cast := pgc.getSizingOrIdentityCast(castID, sourceType, targetType, CastType_Assignment); cast.ID.IsValid() { return cast, nil } // We then check for a record to composite cast @@ -193,7 +193,7 @@ func (pgc *Collection) GetImplicitCast(ctx *sql.Context, sourceType *pgtypes.Dol return Cast{}, nil } // We check for the identity and sizing casts after checking the maps, as the identity may be overridden by a user. - if cast := pgc.getSizingOrIdentityCast(sourceType, targetType, CastType_Implicit); cast.ID.IsValid() { + if cast := pgc.getSizingOrIdentityCast(castID, sourceType, targetType, CastType_Implicit); cast.ID.IsValid() { return cast, nil } // We then check for a record to composite cast @@ -301,38 +301,29 @@ func (pgc *Collection) getCast(ctx context.Context, castID id.Cast, sourceType * // only differ in their atttypmod values. Returns a Cast with an invalid ID if no cast is matched. This mirrors the // behavior as described in: // https://www.postgresql.org/docs/15/typeconv-query.html -func (pgc *Collection) getSizingOrIdentityCast(sourceType *pgtypes.DoltgresType, targetType *pgtypes.DoltgresType, castType CastType) Cast { +func (pgc *Collection) getSizingOrIdentityCast(castID id.Cast, sourceType *pgtypes.DoltgresType, targetType *pgtypes.DoltgresType, castType CastType) Cast { // If we receive different types, then we can return immediately if sourceType.ID != targetType.ID { return Cast{} } + // TODO: We don't have any sizing cast functions implemented, so for now we'll approximate using output to input. + // We can use the query below to find all implemented sizing cast functions. It's also detailed in the link above. + // Lastly, not all sizing functions accept a boolean, but for those that do, we need to see whether true is + // used for explicit casts, or whether true is used for implicit casts. + // SELECT + // format_type(c.castsource, NULL) AS source, + // format_type(c.casttarget, NULL) AS target, + // p.oid::regprocedure AS func + // FROM pg_cast c JOIN pg_proc p ON p.oid = c.castfunc WHERE c.castsource = c.casttarget ORDER BY 1,2; // If we have different atttypmod values, then we need to do a sizing cast only if one exists - if sourceType.GetAttTypMod() != targetType.GetAttTypMod() { - // TODO: We don't have any sizing cast functions implemented, so for now we'll approximate using output to input. - // We can use the query below to find all implemented sizing cast functions. It's also detailed in the link above. - // Lastly, not all sizing functions accept a boolean, but for those that do, we need to see whether true is - // used for explicit casts, or whether true is used for implicit casts. - // SELECT - // format_type(c.castsource, NULL) AS source, - // format_type(c.casttarget, NULL) AS target, - // p.oid::regprocedure AS func - // FROM pg_cast c JOIN pg_proc p ON p.oid = c.castfunc WHERE c.castsource = c.casttarget ORDER BY 1,2; - return Cast{ - ID: id.NewCast(sourceType.ID, targetType.ID), - CastType: castType, - Function: id.NullFunction, - BuiltIn: nil, - UseInOut: true, - request: castType, - } - } - // If there is no sizing cast, then we simply use the identity cast + // Otherwise, then we simply use the identity cast + useInOut := sourceType.GetAttTypMod() != targetType.GetAttTypMod() return Cast{ - ID: id.NewCast(sourceType.ID, targetType.ID), + ID: castID, CastType: castType, Function: id.NullFunction, BuiltIn: nil, - UseInOut: false, + UseInOut: useInOut, request: castType, } } diff --git a/core/id/id_wrappers.go b/core/id/id_wrappers.go index 090f049e6f..c37dff119c 100644 --- a/core/id/id_wrappers.go +++ b/core/id/id_wrappers.go @@ -90,7 +90,18 @@ func NewCast(sourceType Type, targetType Type) Cast { if len(sourceType) == 0 && len(targetType) == 0 { return NullCast } - return Cast(NewId(Section_Cast, string(sourceType), string(targetType))) + + return Cast( + string( + []byte{ + uint8(Section_Cast), + 2, + uint8(len(sourceType)), + uint8(len(targetType)), + }) + + string(sourceType) + + string(targetType), + ) } // NewCheck returns a new Check. This wrapper must not be returned to the client.