diff --git a/go/libraries/doltcore/schema/typecompatibility/type_compatibility.go b/go/libraries/doltcore/schema/typecompatibility/type_compatibility.go index f5a64fb81e5..ce8dee0417a 100644 --- a/go/libraries/doltcore/schema/typecompatibility/type_compatibility.go +++ b/go/libraries/doltcore/schema/typecompatibility/type_compatibility.go @@ -119,6 +119,14 @@ func (d doltTypeCompatibilityChecker) IsTypeChangeCompatible(from, to typeinfo.T return res } + // The TypeCompatibility checkers don't support ExtendedTypes added by integrators, so if we see + // one, return early and report the types are not compatible. + _, fromExtendedType := fromSqlType.(types.ExtendedType) + _, toExtendedType := toSqlType.(types.ExtendedType) + if fromExtendedType || toExtendedType { + return res + } + for _, checker := range d.checkers { if checker.canHandle(fromSqlType, toSqlType) { subcheckerResult := checker.isCompatible(fromSqlType, toSqlType) diff --git a/go/libraries/doltcore/schema/typecompatibility/type_compatibility_test.go b/go/libraries/doltcore/schema/typecompatibility/type_compatibility_test.go index 24e3013e64d..ade6f02f7ca 100644 --- a/go/libraries/doltcore/schema/typecompatibility/type_compatibility_test.go +++ b/go/libraries/doltcore/schema/typecompatibility/type_compatibility_test.go @@ -15,11 +15,14 @@ package typecompatibility import ( + "context" + "reflect" "testing" "github.com/dolthub/go-mysql-server/sql" gmstypes "github.com/dolthub/go-mysql-server/sql/types" "github.com/dolthub/vitess/go/sqltypes" + "github.com/dolthub/vitess/go/vt/proto/query" "github.com/stretchr/testify/assert" "github.com/dolthub/dolt/go/libraries/doltcore/schema/typeinfo" @@ -70,6 +73,9 @@ var varbinary10 = mustCreateType(gmstypes.MustCreateString(sqltypes.VarBinary, 1 var blob = mustCreateType(gmstypes.MustCreateString(sqltypes.Blob, 65_535, sql.Collation_binary)) var mediumBlob = mustCreateType(gmstypes.MustCreateBinary(sqltypes.Blob, 16_777_215)) +// ExtendedType test data +var extendedTypeInfo = typeinfo.CreateExtendedTypeFromSqlType(extendedType{}) + // TestLd1IsTypeChangeCompatible tests that the LD1 TypeCompatibilityChecker implementation // correctly computes compatibility between types. func TestLd1IsTypeChangeCompatible(t *testing.T) { @@ -313,6 +319,26 @@ func TestDoltIsTypeChangeCompatible(t *testing.T) { to: text, compatible: false, }, + + // Extended types + { + name: "incompatible: VARBINARY(10) to ExtendedType", + from: varbinary10, + to: extendedTypeInfo, + compatible: false, + }, + { + name: "incompatible: ExtendedType to TEXT", + from: extendedTypeInfo, + to: text, + compatible: false, + }, + { + name: "incompatible: ExtendedType to ExtendedType", + from: extendedTypeInfo, + to: extendedTypeInfo, + compatible: false, + }, }) } @@ -337,3 +363,76 @@ func mustCreateType(sqlType sql.Type) typeinfo.TypeInfo { } return mediumBlob } + +// extendedType is a no-op implementation of gmstypes.ExtendedType, used for testing type compatibility with extended types. +type extendedType struct{} + +var _ gmstypes.ExtendedType = extendedType{} + +func (e extendedType) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { + panic("unimplemented") +} + +func (e extendedType) Compare(i interface{}, i2 interface{}) (int, error) { + panic("unimplemented") +} + +func (e extendedType) Convert(i interface{}) (interface{}, sql.ConvertInRange, error) { + panic("unimplemented") +} + +func (e extendedType) ConvertToType(ctx *sql.Context, typ gmstypes.ExtendedType, val any) (any, error) { + panic("unimplemented") +} + +func (e extendedType) Equals(otherType sql.Type) bool { + return false +} + +func (e extendedType) MaxTextResponseByteLength(ctx *sql.Context) uint32 { + panic("unimplemented") +} + +func (e extendedType) Promote() sql.Type { + panic("unimplemented") +} + +func (e extendedType) SQL(ctx *sql.Context, dest []byte, v interface{}) (sqltypes.Value, error) { + panic("unimplemented") +} + +func (e extendedType) Type() query.Type { + panic("unimplemented") +} + +func (e extendedType) ValueType() reflect.Type { + panic("unimplemented") +} + +func (e extendedType) Zero() interface{} { + panic("unimplemented") +} + +func (e extendedType) String() string { + panic("unimplemented") +} + +func (e extendedType) SerializedCompare(ctx context.Context, v1 []byte, v2 []byte) (int, error) { + panic("unimplemented") +} + +func (e extendedType) SerializeValue(ctx context.Context, val any) ([]byte, error) { + panic("unimplemented") +} + +func (e extendedType) DeserializeValue(ctx context.Context, val []byte) (any, error) { + panic("unimplemented") +} + +func (e extendedType) FormatValue(val any) (string, error) { + panic("unimplemented") +} + +func (e extendedType) MaxSerializedWidth() gmstypes.ExtendedTypeSerializedWidth { + panic("unimplemented") +}