From 62a9ff622eb50ab61d7708288f895b2f190feb89 Mon Sep 17 00:00:00 2001 From: James Cor Date: Tue, 30 Jun 2026 16:26:03 -0700 Subject: [PATCH 1/5] cache this --- core/casts/collection.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/casts/collection.go b/core/casts/collection.go index bf1a74ffe6..15940144c4 100644 --- a/core/casts/collection.go +++ b/core/casts/collection.go @@ -39,6 +39,7 @@ type Collection struct { mapHash hash.Hash // This is cached so that we don't have to calculate the hash every time underlyingMap prolly.AddressMap ns tree.NodeStore + castCache map[string]id.Cast } // CastType is the type of the cast, indicating which contexts it may be called in. @@ -134,7 +135,14 @@ 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) + cID := string(sourceType.ID) + string(targetType.ID) + var castID id.Cast + var ok bool + if castID, ok = pgc.castCache[cID]; !ok { + pgc.castCache[cID] = id.NewCast(sourceType.ID, targetType.ID) + } + + // TODO: possible to cache this too? c, err := pgc.getCast(ctx, castID, sourceType, targetType, CastType_Assignment) if err != nil { return Cast{}, err From b2a1f4a546ff391e1b475a1e258e1b01ba2b811c Mon Sep 17 00:00:00 2001 From: James Cor Date: Tue, 30 Jun 2026 16:32:59 -0700 Subject: [PATCH 2/5] nil map --- core/casts/collection.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/casts/collection.go b/core/casts/collection.go index 15940144c4..44078dad63 100644 --- a/core/casts/collection.go +++ b/core/casts/collection.go @@ -74,6 +74,7 @@ func NewCollection(ctx context.Context, underlyingMap prolly.AddressMap, ns tree mapHash: underlyingMap.HashOf(), underlyingMap: underlyingMap, ns: ns, + castCache: make(map[string]id.Cast), } return collection, nil } @@ -575,6 +576,7 @@ func (pgc *Collection) Clone(ctx context.Context) *Collection { mapHash: pgc.mapHash, underlyingMap: pgc.underlyingMap, ns: pgc.ns, + castCache: pgc.castCache, } } From b038cb51ef068f2c82ddb32e779297537997b36a Mon Sep 17 00:00:00 2001 From: James Cor Date: Tue, 30 Jun 2026 16:52:29 -0700 Subject: [PATCH 3/5] try this --- core/casts/collection.go | 14 ++------------ core/id/id_wrappers.go | 11 ++++++++++- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/core/casts/collection.go b/core/casts/collection.go index 44078dad63..ba5512d91a 100644 --- a/core/casts/collection.go +++ b/core/casts/collection.go @@ -39,7 +39,6 @@ type Collection struct { mapHash hash.Hash // This is cached so that we don't have to calculate the hash every time underlyingMap prolly.AddressMap ns tree.NodeStore - castCache map[string]id.Cast } // CastType is the type of the cast, indicating which contexts it may be called in. @@ -74,7 +73,6 @@ func NewCollection(ctx context.Context, underlyingMap prolly.AddressMap, ns tree mapHash: underlyingMap.HashOf(), underlyingMap: underlyingMap, ns: ns, - castCache: make(map[string]id.Cast), } return collection, nil } @@ -136,15 +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) { - cID := string(sourceType.ID) + string(targetType.ID) - var castID id.Cast - var ok bool - if castID, ok = pgc.castCache[cID]; !ok { - pgc.castCache[cID] = id.NewCast(sourceType.ID, targetType.ID) - } - - // TODO: possible to cache this too? - 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 } @@ -576,7 +567,6 @@ func (pgc *Collection) Clone(ctx context.Context) *Collection { mapHash: pgc.mapHash, underlyingMap: pgc.underlyingMap, ns: pgc.ns, - castCache: pgc.castCache, } } diff --git a/core/id/id_wrappers.go b/core/id/id_wrappers.go index 090f049e6f..c54136d3bf 100644 --- a/core/id/id_wrappers.go +++ b/core/id/id_wrappers.go @@ -90,7 +90,16 @@ 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))) + + // segment + len(data) + len(source) + len(target) + source + target + buf := make([]byte, 1+1+1+1+len(sourceType)+len(targetType)) + buf[0] = uint8(Section_Cast) + buf[1] = 2 + buf[2] = uint8(len(sourceType)) + buf[3] = uint8(len(targetType)) + copy(buf[4:], sourceType) + copy(buf[4+len(sourceType):], targetType) + return Cast(buf) } // NewCheck returns a new Check. This wrapper must not be returned to the client. From ed5cb9bc04faa4e06b0feb5c1eb61656233b5b0b Mon Sep 17 00:00:00 2001 From: James Cor Date: Tue, 30 Jun 2026 17:12:26 -0700 Subject: [PATCH 4/5] asdfasdf --- core/id/id_wrappers.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/core/id/id_wrappers.go b/core/id/id_wrappers.go index c54136d3bf..c37dff119c 100644 --- a/core/id/id_wrappers.go +++ b/core/id/id_wrappers.go @@ -91,15 +91,17 @@ func NewCast(sourceType Type, targetType Type) Cast { return NullCast } - // segment + len(data) + len(source) + len(target) + source + target - buf := make([]byte, 1+1+1+1+len(sourceType)+len(targetType)) - buf[0] = uint8(Section_Cast) - buf[1] = 2 - buf[2] = uint8(len(sourceType)) - buf[3] = uint8(len(targetType)) - copy(buf[4:], sourceType) - copy(buf[4+len(sourceType):], targetType) - return Cast(buf) + 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. From 6269d47f5a5dc03cfa6ecf781e8a8081086d070c Mon Sep 17 00:00:00 2001 From: James Cor Date: Tue, 7 Jul 2026 16:21:40 -0700 Subject: [PATCH 5/5] not sure what the difference even is here --- core/casts/collection.go | 43 ++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/core/casts/collection.go b/core/casts/collection.go index ba5512d91a..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 @@ -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, } }