diff --git a/docs/obsoletions.md b/docs/obsoletions.md index 8893f3a2..78b9bc31 100644 --- a/docs/obsoletions.md +++ b/docs/obsoletions.md @@ -7,7 +7,7 @@ Following [the deprecation policy of TileDB Embedded][core-deprecation], obsolet |Diagnostic codes|Deprecated in version|Removed in version| |----------------|---------------------|------------------| |[`TILEDB0001`](#TILEDB0001) …[`TILEDB0011`](#TILEDB0011)|5.3.0|5.5.0| -|[`TILEDB0012`](#TILEDB0012) …[`TILEDB0012`](#TILEDB0012)|5.7.0|5.9.0| +|[`TILEDB0012`](#TILEDB0012) …[`TILEDB0013`](#TILEDB0013)|5.7.0|5.9.0| ## `TILEDB0001` - Enum value names that start with `TILEDB_` were replaced with C#-friendly names. @@ -320,3 +320,17 @@ The obsoleted APIs fall into the following categories: - Types with the name `tiledb_***_t` were made public again only to support the APIs of the safe handles above. They have little other use on their own. You should use APIs in the `TileDB.CSharp` namespace instead. [core-deprecation]: https://github.com/TileDB-Inc/TileDB/blob/dev/doc/policy/api_changes.md + +## `TILEDB0013` - The `EnumUtils.TypeToDataType` and `EnumUtils.DataTypeToType` methods are obsolete and will be removed in a future version. + + + +The `EnumUtils.TypeToDataType` and `EnumUtils.DataTypeToType` methods convert between TileDB data types and .NET types. Given that there is no one-to-one correspondence between these two and for legacy reasons, these methods sometimes return wrong results and were obsoleted. + +### Version introduced + +5.7.0 + +### Recommended action + +If you are performing queries on arrays of unknown schema, you can use the `Query.UnsafeSetDataBuffer` and `Query.UnsafeSetWriteDataBuffer` methods to set a data buffer to a query without type validation. diff --git a/sources/TileDB.CSharp/Array.cs b/sources/TileDB.CSharp/Array.cs index 7c04c1a4..9d8315c4 100644 --- a/sources/TileDB.CSharp/Array.cs +++ b/sources/TileDB.CSharp/Array.cs @@ -501,15 +501,11 @@ static void GetDomain(Array array, string dimName, uint i, NonEmptyDomain non /// is not the dimension's type. public (T Start, T End, bool IsEmpty) NonEmptyDomain(uint index) where T : struct { - var datatype = EnumUtil.TypeToDataType(typeof(T)); using (var schema = Schema()) using (var domain = schema.Domain()) using (var dimension = domain.Dimension(index)) { - if (datatype != dimension.Type()) - { - throw new ArgumentException("Array.NonEmptyDomain, not valid datatype!"); - } + ErrorHandling.CheckDataType(dimension.Type()); } SequentialPair data; @@ -531,15 +527,11 @@ static void GetDomain(Array array, string dimName, uint i, NonEmptyDomain non /// is not the dimension's type. public (T Start, T End, bool IsEmpty) NonEmptyDomain(string name) where T : struct { - var datatype = EnumUtil.TypeToDataType(typeof(T)); using (var schema = Schema()) using (var domain = schema.Domain()) using (var dimension = domain.Dimension(name)) { - if (datatype != dimension.Type()) - { - throw new ArgumentException("Array.NonEmptyDomain, not valid datatype!"); - } + ErrorHandling.CheckDataType(dimension.Type()); } using var ms_name = new MarshaledString(name); diff --git a/sources/TileDB.CSharp/ArrayMetadata.cs b/sources/TileDB.CSharp/ArrayMetadata.cs index 0e7b1ef3..92583854 100644 --- a/sources/TileDB.CSharp/ArrayMetadata.cs +++ b/sources/TileDB.CSharp/ArrayMetadata.cs @@ -300,7 +300,7 @@ IEnumerator IEnumerable.GetEnumerator() private void put_metadata(string key, T[] value, tiledb_datatype_t tiledb_datatype) where T : struct { - ErrorHandling.ThrowIfManagedType(); + ErrorHandling.CheckDataType((DataType)tiledb_datatype); if (string.IsNullOrEmpty(key) || value.Length == 0) { throw new ArgumentException("ArrayMetadata.put_metadata, null or empty key-value!"); diff --git a/sources/TileDB.CSharp/Attribute.cs b/sources/TileDB.CSharp/Attribute.cs index 98f478f6..a1bd479c 100644 --- a/sources/TileDB.CSharp/Attribute.cs +++ b/sources/TileDB.CSharp/Attribute.cs @@ -195,7 +195,7 @@ public ulong CellSize() /// An array of values that will be used as the fill value. private void SetFillValue(T[] data) where T : struct { - ErrorHandling.ThrowIfManagedType(); + ErrorHandling.CheckDataType(Type()); if (data.Length == 0) { throw new ArgumentException("Attribute.SetFillValue, data is empty!"); diff --git a/sources/TileDB.CSharp/Dimension.cs b/sources/TileDB.CSharp/Dimension.cs index 009ffa6d..4ff733c4 100644 --- a/sources/TileDB.CSharp/Dimension.cs +++ b/sources/TileDB.CSharp/Dimension.cs @@ -146,7 +146,7 @@ public DataType Type() /// public (T Start, T End) GetDomain() where T : struct { - ErrorHandling.ThrowIfManagedType(); + ErrorHandling.CheckDataType(Type()); void* value_p; using var ctxHandle = _ctx.Handle.Acquire(); @@ -163,7 +163,7 @@ public DataType Type() /// public T TileExtent() where T : struct { - ErrorHandling.ThrowIfManagedType(); + ErrorHandling.CheckDataType(Type()); using var ctxHandle = _ctx.Handle.Acquire(); using var handle = _handle.Acquire(); void* value_p; diff --git a/sources/TileDB.CSharp/Enums.cs b/sources/TileDB.CSharp/Enums.cs index 1d365eb2..98747f74 100644 --- a/sources/TileDB.CSharp/Enums.cs +++ b/sources/TileDB.CSharp/Enums.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using System.Text; using TileDB.Interop; namespace TileDB.CSharp @@ -185,115 +186,217 @@ public enum DataType : uint /// /// A signed 32-bit integer. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// Int32 = tiledb_datatype_t.TILEDB_INT32, /// /// A signed 64-bit integer. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// Int64 = tiledb_datatype_t.TILEDB_INT64, /// /// A 32-bit floating-point number. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// Float32 = tiledb_datatype_t.TILEDB_FLOAT32, /// /// A 64-bit floating-point number. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// Float64 = tiledb_datatype_t.TILEDB_FLOAT64, /// /// A signed 8-bit integer. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// Int8 = tiledb_datatype_t.TILEDB_INT8, /// /// An unsigned 8-bit integer. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// UInt8 = tiledb_datatype_t.TILEDB_UINT8, /// /// A signed 16-bit integer. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// Int16 = tiledb_datatype_t.TILEDB_INT16, /// /// An unsigned 16-bit integer. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// UInt16 = tiledb_datatype_t.TILEDB_UINT16, /// /// An unsigned 32-bit integer. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// UInt32 = tiledb_datatype_t.TILEDB_UINT32, /// /// An unsigned 64-bit integer. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// UInt64 = tiledb_datatype_t.TILEDB_UINT64, /// /// An ASCII string. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// StringAscii = tiledb_datatype_t.TILEDB_STRING_ASCII, /// /// A UTF-8 string. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// StringUtf8 = tiledb_datatype_t.TILEDB_STRING_UTF8, /// /// A UTF-16 string. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with or . + /// StringUtf16 = tiledb_datatype_t.TILEDB_STRING_UTF16, /// /// A UTF-32 string. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// StringUtf32 = tiledb_datatype_t.TILEDB_STRING_UTF32, /// /// A date and time, counted as the signed 64-bit number of /// years since the Unix epoch (January 1 1970 at midnight). /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// DateTimeYear = tiledb_datatype_t.TILEDB_DATETIME_YEAR, /// /// A date and time, counted as the signed 64-bit number of /// months since the Unix epoch (January 1 1970 at midnight). /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// DateTimeMonth = tiledb_datatype_t.TILEDB_DATETIME_MONTH, /// /// A date and time, counted as the signed 64-bit number of /// weeks since the Unix epoch (January 1 1970 at midnight). /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// DateTimeWeek = tiledb_datatype_t.TILEDB_DATETIME_WEEK, /// /// A date and time, counted as the signed 64-bit number of /// days since the Unix epoch (January 1 1970 at midnight). /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// DateTimeDay = tiledb_datatype_t.TILEDB_DATETIME_DAY, /// /// A date and time, counted as the signed 64-bit number of /// hours since the Unix epoch (January 1 1970 at midnight). /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// DateTimeHour = tiledb_datatype_t.TILEDB_DATETIME_HR, /// /// A date and time, counted as the signed 64-bit number of /// minutes since the Unix epoch (January 1 1970 at midnight). /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// DateTimeMinute = tiledb_datatype_t.TILEDB_DATETIME_MIN, /// /// A date and time, counted as the signed 64-bit number of /// seconds since the Unix epoch (January 1 1970 at midnight). /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// DateTimeSecond = tiledb_datatype_t.TILEDB_DATETIME_SEC, /// /// A date and time, counted as the signed 64-bit number of /// milliseconds since the Unix epoch (January 1 1970 at midnight). /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// DateTimeMillisecond = tiledb_datatype_t.TILEDB_DATETIME_MS, /// /// A date and time, counted as the signed 64-bit number of /// microseconds since the Unix epoch (January 1 1970 at midnight). /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// DateTimeMicrosecond = tiledb_datatype_t.TILEDB_DATETIME_US, /// /// A date and time, counted as the signed 64-bit number of /// nanoseconds since the Unix epoch (January 1 1970 at midnight). /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// DateTimeNanosecond = tiledb_datatype_t.TILEDB_DATETIME_NS, /// /// A date and time, counted as the signed 64-bit number of /// picoseconds since the Unix epoch (January 1 1970 at midnight). /// /// + /// /// One second consists of one trillion picoseconds. + /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// /// DateTimePicosecond = tiledb_datatype_t.TILEDB_DATETIME_PS, /// @@ -301,7 +404,13 @@ public enum DataType : uint /// femtoseconds since the Unix epoch (January 1 1970 at midnight). /// /// + /// /// One second consists of one quadrillion femtoseconds. + /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// /// DateTimeFemtosecond = tiledb_datatype_t.TILEDB_DATETIME_FS, /// @@ -309,32 +418,62 @@ public enum DataType : uint /// attoseconds since the Unix epoch (January 1 1970 at midnight). /// /// + /// /// One second consists of one quintillion attoseconds. + /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// /// DateTimeAttosecond = tiledb_datatype_t.TILEDB_DATETIME_AS, /// /// A time of day counted in hours. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// TimeHour = tiledb_datatype_t.TILEDB_TIME_HR, /// /// A time of day counted in minutes. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// TimeMinute = tiledb_datatype_t.TILEDB_TIME_MIN, /// /// A time of day counted in seconds. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// TimeSecond = tiledb_datatype_t.TILEDB_TIME_SEC, /// /// A time of day counted in milliseconds. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// TimeMillisecond = tiledb_datatype_t.TILEDB_TIME_MS, /// /// A time of day counted in microseconds. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// TimeMicrosecond = tiledb_datatype_t.TILEDB_TIME_US, /// /// A time of day counted in nanoseconds. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// TimeNanosecond = tiledb_datatype_t.TILEDB_TIME_NS, /// /// A time of day counted in picoseconds. @@ -349,12 +488,20 @@ public enum DataType : uint /// TimeAttosecond = tiledb_datatype_t.TILEDB_TIME_AS, /// - /// A binary blob. + /// Binary data. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with . + /// Blob = tiledb_datatype_t.TILEDB_BLOB, /// /// A boolean value. /// + /// + /// On generic methods operating to objects of this datatype, + /// this datatype can be used with or . + /// Boolean = tiledb_datatype_t.TILEDB_BOOL } @@ -968,6 +1115,7 @@ public static VfsMode VfsModeFromStr(string str) /// /// The type to convert. /// is unsupported. + [Obsolete(Obsoletions.DataTypeTypeConversionsMessage, DiagnosticId = Obsoletions.DataTypeTypeConversionsDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] public static DataType TypeToDataType(Type t) { if (t == typeof(int)) @@ -1025,6 +1173,7 @@ public static DataType TypeToDataType(Type t) } } + [Obsolete(Obsoletions.DataTypeTypeConversionsMessage, DiagnosticId = Obsoletions.DataTypeTypeConversionsDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] public static Type DataTypeToType(DataType datatype) { switch (datatype) @@ -1087,6 +1236,71 @@ public static Type DataTypeToType(DataType datatype) } } + // Same with DataTypeToType, but returns the correct corresponding numeric type for strings. + internal static Type DataTypeToNumericType(DataType datatype) + { + switch (datatype) + { + case DataType.DateTimeAttosecond: + case DataType.DateTimeDay: + case DataType.DateTimeFemtosecond: + case DataType.DateTimeHour: + case DataType.DateTimeMinute: + case DataType.DateTimeMonth: + case DataType.DateTimeMillisecond: + case DataType.DateTimeNanosecond: + case DataType.DateTimePicosecond: + case DataType.DateTimeSecond: + case DataType.DateTimeMicrosecond: + case DataType.DateTimeWeek: + case DataType.DateTimeYear: + return typeof(long); + case DataType.Float32: + return typeof(float); + case DataType.Float64: + return typeof(double); + case DataType.Int16: + return typeof(short); + case DataType.Int32: + return typeof(int); + case DataType.Int64: + return typeof(long); + case DataType.Int8: + return typeof(sbyte); + case DataType.StringAscii: + case DataType.StringUtf8: + return typeof(byte); + case DataType.StringUtf16: + return typeof(ushort); + case DataType.StringUtf32: + return typeof(uint); + case DataType.TimeAttosecond: + case DataType.TimeFemtosecond: + case DataType.TimeHour: + case DataType.TimeMinute: + case DataType.TimeMillisecond: + case DataType.TimeNanosecond: + case DataType.TimePicosecond: + case DataType.TimeSecond: + case DataType.TimeMicrosecond: + return typeof(long); + case DataType.UInt16: + return typeof(ushort); + case DataType.UInt32: + return typeof(uint); + case DataType.UInt64: + return typeof(ulong); + case DataType.UInt8: + return typeof(byte); + case DataType.Blob: + return typeof(byte); + case DataType.Boolean: + return typeof(byte); + default: + return typeof(byte); + } + } + public static bool IsStringType(DataType datatype) { return datatype == DataType.StringAscii diff --git a/sources/TileDB.CSharp/ErrorHandling.cs b/sources/TileDB.CSharp/ErrorHandling.cs index 3d2c3bd8..c7e0f87e 100644 --- a/sources/TileDB.CSharp/ErrorHandling.cs +++ b/sources/TileDB.CSharp/ErrorHandling.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +using System.Text; using TileDB.Interop; namespace TileDB.CSharp @@ -55,5 +56,39 @@ public static void ThrowIfManagedType() ThrowHelpers.ThrowManagedType(); } } + + /// + /// Returns whether values of type can be stored or + /// retrieved from a TileDB buffer of type . + /// + private static unsafe bool AreTypesCompatible(DataType dataType) + { + if (EnumUtil.DataTypeToNumericType(dataType) == typeof(T)) + { + return true; + } + if (typeof(T) == typeof(bool) && dataType == DataType.Boolean) + { + return true; + } + if (typeof(T) == typeof(char) && dataType == DataType.StringUtf16) + { + return true; + } + return false; + } + + /// + /// Throws if values of type cannot be stored or + /// retrieved from a TileDB buffer of type . + /// + public static void CheckDataType(DataType dataType) + { + ThrowIfManagedType(); + if (!AreTypesCompatible(dataType)) + { + ThrowHelpers.ThrowTypeMismatch(dataType); + } + } } } diff --git a/sources/TileDB.CSharp/FragmentInfo.cs b/sources/TileDB.CSharp/FragmentInfo.cs index 5db26a0d..aba0faf0 100644 --- a/sources/TileDB.CSharp/FragmentInfo.cs +++ b/sources/TileDB.CSharp/FragmentInfo.cs @@ -409,18 +409,18 @@ public ulong GetMinimumBoundedRectangleCount(uint fragmentIndex) public (T Start, T End) GetMinimumBoundedRectangle(uint fragmentIndex, uint minimumBoundedRectangleIndex, uint dimensionIndex) { DataType dataType = GetDimensionType(fragmentIndex, dimensionIndex); - ValidateDomainType(dataType); if (RuntimeHelpers.IsReferenceOrContainsReferences()) { - if (typeof(T) == typeof(string)) + if (typeof(T) == typeof(string) && EnumUtil.IsStringType(dataType)) { (string startStr, string endStr) = GetStringMinimumBoundedRectangle(fragmentIndex, minimumBoundedRectangleIndex, dimensionIndex, dataType); return ((T)(object)startStr, (T)(object)endStr); } - ThrowHelpers.ThrowTypeNotSupported(); + ThrowHelpers.ThrowTypeMismatch(dataType); return default; } + ValidateDomainType(dataType); using var ctxHandle = _ctx.Handle.Acquire(); using var handle = _handle.Acquire(); @@ -448,18 +448,18 @@ public ulong GetMinimumBoundedRectangleCount(uint fragmentIndex) public (T Start, T End) GetMinimumBoundedRectangle(uint fragmentIndex, uint minimumBoundedRectangleIndex, string dimensionName) { DataType dataType = GetDimensionType(fragmentIndex, dimensionName); - ValidateDomainType(dataType); if (RuntimeHelpers.IsReferenceOrContainsReferences()) { - if (typeof(T) == typeof(string)) + if (typeof(T) == typeof(string) && EnumUtil.IsStringType(dataType)) { (string startStr, string endStr) = GetStringMinimumBoundedRectangle(fragmentIndex, minimumBoundedRectangleIndex, dimensionName, dataType); return ((T)(object)startStr, (T)(object)endStr); } - ThrowHelpers.ThrowTypeNotSupported(); + ThrowHelpers.ThrowTypeMismatch(dataType); return default; } + ValidateDomainType(dataType); using var ctxHandle = _ctx.Handle.Acquire(); using var handle = _handle.Acquire(); @@ -534,17 +534,17 @@ public ulong GetMinimumBoundedRectangleCount(uint fragmentIndex) public (T Start, T End) GetNonEmptyDomain(uint fragmentIndex, uint dimensionIndex) { DataType dataType = GetDimensionType(fragmentIndex, dimensionIndex); - ValidateDomainType(dataType); if (RuntimeHelpers.IsReferenceOrContainsReferences()) { - if (typeof(T) == typeof(string)) + if (typeof(T) == typeof(string) && EnumUtil.IsStringType(dataType)) { (string startStr, string endStr) = GetStringNonEmptyDomain(fragmentIndex, dimensionIndex, dataType); return ((T)(object)startStr, (T)(object)endStr); } - ThrowHelpers.ThrowTypeNotSupported(); + ThrowHelpers.ThrowTypeMismatch(dataType); return default; } + ValidateDomainType(dataType); using var ctxHandle = _ctx.Handle.Acquire(); using var handle = _handle.Acquire(); @@ -572,17 +572,17 @@ public ulong GetMinimumBoundedRectangleCount(uint fragmentIndex) public (T Start, T End) GetNonEmptyDomain(uint fragmentIndex, string dimensionName) { DataType dataType = GetDimensionType(fragmentIndex, dimensionName); - ValidateDomainType(dataType); if (RuntimeHelpers.IsReferenceOrContainsReferences()) { - if (typeof(T) == typeof(string)) + if (typeof(T) == typeof(string) && EnumUtil.IsStringType(dataType)) { (string startStr, string endStr) = GetStringNonEmptyDomain(fragmentIndex, dimensionName, dataType); return ((T)(object)startStr, (T)(object)endStr); } - ThrowHelpers.ThrowTypeNotSupported(); + ThrowHelpers.ThrowTypeMismatch(dataType); return default; } + ValidateDomainType(dataType); using var ctxHandle = _ctx.Handle.Acquire(); using var handle = _handle.Acquire(); @@ -653,10 +653,7 @@ private static void ValidateDomainType(DataType dataType) { ThrowHelpers.ThrowStringTypeMismatch(dataType); } - if (dataType != EnumUtil.TypeToDataType(typeof(T))) - { - ThrowHelpers.ThrowTypeMismatch(dataType); - } + ErrorHandling.CheckDataType(dataType); } private DataType GetDimensionType(uint fragmentIndex, uint dimensionIndex) diff --git a/sources/TileDB.CSharp/GroupMetadata.cs b/sources/TileDB.CSharp/GroupMetadata.cs index 3c7a5253..c7af584a 100644 --- a/sources/TileDB.CSharp/GroupMetadata.cs +++ b/sources/TileDB.CSharp/GroupMetadata.cs @@ -330,7 +330,7 @@ IEnumerator IEnumerable.GetEnumerator() #region Private methods private void put_metadata(string key, T[] value, tiledb_datatype_t tiledb_datatype) where T : struct { - ErrorHandling.ThrowIfManagedType(); + ErrorHandling.CheckDataType((DataType)tiledb_datatype); if (string.IsNullOrEmpty(key) || value.Length == 0) { throw new ArgumentException("ArrayMetadata.put_metadata, null or empty key-value!"); diff --git a/sources/TileDB.CSharp/Interop/SpanExtensions.cs b/sources/TileDB.CSharp/Interop/SpanExtensions.cs index 99a4ae4b..07041740 100644 --- a/sources/TileDB.CSharp/Interop/SpanExtensions.cs +++ b/sources/TileDB.CSharp/Interop/SpanExtensions.cs @@ -8,7 +8,7 @@ namespace TileDB.Interop { - [Obsolete(Obsoletions.TileDBInteropMessage, DiagnosticId = Obsoletions.TileDBInteropDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] + [Obsolete(Obsoletions.TileDBInterop2Message, DiagnosticId = Obsoletions.TileDBInterop2DiagId, UrlFormat = Obsoletions.SharedUrlFormat)] [EditorBrowsable(EditorBrowsableState.Never)] public static unsafe class SpanExtensions { diff --git a/sources/TileDB.CSharp/Marshalling/MarshaledStringOut.cs b/sources/TileDB.CSharp/Marshalling/MarshaledStringOut.cs index 4850c2b7..22bdff72 100644 --- a/sources/TileDB.CSharp/Marshalling/MarshaledStringOut.cs +++ b/sources/TileDB.CSharp/Marshalling/MarshaledStringOut.cs @@ -5,7 +5,7 @@ namespace TileDB.Interop { - [Obsolete(Obsoletions.TileDBInteropMessage, DiagnosticId = Obsoletions.TileDBInteropDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] + [Obsolete(Obsoletions.TileDBInterop2Message, DiagnosticId = Obsoletions.TileDBInterop2DiagId, UrlFormat = Obsoletions.SharedUrlFormat)] [EditorBrowsable(EditorBrowsableState.Never)] public unsafe class LibC { diff --git a/sources/TileDB.CSharp/Obsoletions.cs b/sources/TileDB.CSharp/Obsoletions.cs index 33850a81..8b4f69ec 100644 --- a/sources/TileDB.CSharp/Obsoletions.cs +++ b/sources/TileDB.CSharp/Obsoletions.cs @@ -41,5 +41,8 @@ internal static class Obsoletions public const string TileDBInterop2Message = "Members of the TileDB.Interop namespace should not be used by user code and will become internal in a future version."; public const string TileDBInterop2DiagId = "TILEDB0012"; + + public const string DataTypeTypeConversionsMessage = "The EnumUtils.TypeToDataType and EnumUtils.DataTypeToType methods are obsolete and will be removed in a future version."; + public const string DataTypeTypeConversionsDiagId = "TILEDB0013"; } } diff --git a/sources/TileDB.CSharp/Query.cs b/sources/TileDB.CSharp/Query.cs index 800d3ce0..bb7e9928 100644 --- a/sources/TileDB.CSharp/Query.cs +++ b/sources/TileDB.CSharp/Query.cs @@ -285,7 +285,7 @@ public void SetDataBuffer(string name, Memory data) where T : struct using (var schema = _array.Schema()) using (var domain = schema.Domain()) { - CheckDataType(GetDataType(name, schema, domain)); + ErrorHandling.CheckDataType(GetDataType(name, schema, domain)); } if (data.IsEmpty) @@ -321,7 +321,7 @@ public void SetDataBuffer(string name, T* data, ulong size) where T : struct using (var schema = _array.Schema()) using (var domain = schema.Domain()) { - CheckDataType(GetDataType(name, schema, domain)); + ErrorHandling.CheckDataType(GetDataType(name, schema, domain)); } UnsafeSetDataBuffer(name, new MemoryHandle(data), size * (ulong)sizeof(T), sizeof(T)); @@ -931,18 +931,6 @@ public Tuple FragmentTimestampRange(ulong idx) return new Tuple(t1, t2); } - private void CheckDataType(DataType dataType) - { - if (EnumUtil.TypeToDataType(typeof(T)) != dataType) - { - if (!(dataType== DataType.StringAscii && (typeof(T)==typeof(byte) || typeof(T) == typeof(sbyte) || typeof(T) == typeof(string))) - && !(dataType == DataType.Boolean && typeof(T) == typeof(byte))) - { - throw new ArgumentException("T " + typeof(T).Name + " doesnot match " + dataType.ToString()); - } - } - } - private static DataType GetDataType(string name, ArraySchema schema, Domain domain) { if (schema.HasAttribute(name)) diff --git a/sources/TileDB.CSharp/Subarray.cs b/sources/TileDB.CSharp/Subarray.cs index 958fbc56..b0f439e4 100644 --- a/sources/TileDB.CSharp/Subarray.cs +++ b/sources/TileDB.CSharp/Subarray.cs @@ -118,13 +118,9 @@ public void SetSubarray(params T[] data) where T : struct public void SetSubarray(ReadOnlySpan data) where T : struct { ErrorHandling.ThrowIfManagedType(); - var dataType = EnumUtil.TypeToDataType(typeof(T)); (var domainType, var nDim) = GetDomainInfo(); - if (dataType != domainType) - { - ThrowHelpers.ThrowTypeMismatch(dataType); - } + ErrorHandling.CheckDataType(domainType); if (data.Length != nDim * 2) { ThrowHelpers.ThrowSubarrayLengthMismatch(nameof(data)); @@ -141,27 +137,19 @@ public void SetSubarray(ReadOnlySpan data) where T : struct private void ValidateType(string name) where T : struct { ErrorHandling.ThrowIfManagedType(); - var dataType = EnumUtil.TypeToDataType(typeof(T)); using var schema = _array.Schema(); using var domain = schema.Domain(); using var dimension = domain.Dimension(name); - if (dimension.Type() != dataType) - { - ThrowHelpers.ThrowTypeMismatch(dataType); - } + ErrorHandling.CheckDataType(dimension.Type()); } private void ValidateType(uint index) where T : struct { ErrorHandling.ThrowIfManagedType(); - var dataType = EnumUtil.TypeToDataType(typeof(T)); using var schema = _array.Schema(); using var domain = schema.Domain(); using var dimension = domain.Dimension(index); - if (dimension.Type() != dataType) - { - ThrowHelpers.ThrowTypeMismatch(dataType); - } + ErrorHandling.CheckDataType(dimension.Type()); } /// diff --git a/sources/TileDB.CSharp/ThrowHelpers.cs b/sources/TileDB.CSharp/ThrowHelpers.cs index bdfe9e96..13a14ad4 100644 --- a/sources/TileDB.CSharp/ThrowHelpers.cs +++ b/sources/TileDB.CSharp/ThrowHelpers.cs @@ -17,11 +17,11 @@ public static void ThrowTypeNotSupported() => // We don't have to specify the type in the type argument, it can be seen from the stacktrace. [DoesNotReturn] public static void ThrowTypeMismatch(DataType type) => - throw new InvalidOperationException($"Type is not compatible with data type {type}."); + throw new ArgumentException($"Type is not compatible with data type {type}."); [DoesNotReturn] public static void ThrowStringTypeMismatch(DataType type) => - throw new InvalidOperationException($"Cannot encode data type {type} into strings."); + throw new ArgumentException($"Cannot encode data type {type} into strings."); [DoesNotReturn] public static void ThrowTooBigSize(ulong size, [CallerArgumentExpression(nameof(size))] string? paramName = null) => diff --git a/sources/TileDB.CSharp/TileDB.CSharp.csproj b/sources/TileDB.CSharp/TileDB.CSharp.csproj index 01330c29..ddc8d445 100644 --- a/sources/TileDB.CSharp/TileDB.CSharp.csproj +++ b/sources/TileDB.CSharp/TileDB.CSharp.csproj @@ -12,7 +12,7 @@ true true 5.6.0 - $(NoWarn);TILEDB0012 + $(NoWarn);TILEDB0012;TILEDB0013 diff --git a/tests/TileDB.CSharp.Test/FragmentInfoTest.cs b/tests/TileDB.CSharp.Test/FragmentInfoTest.cs index 5c1ac9b3..a3787bfb 100644 --- a/tests/TileDB.CSharp.Test/FragmentInfoTest.cs +++ b/tests/TileDB.CSharp.Test/FragmentInfoTest.cs @@ -172,11 +172,11 @@ public void TestMinimumBoundedRectanglesString() Assert.AreEqual(("a", "bb"), info.GetMinimumBoundedRectangle(0, 0, 0)); Assert.AreEqual(("c", "ddd"), info.GetMinimumBoundedRectangle(0, 1, "d")); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 1, "d")); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 1, "d")); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 1, "d")); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 1, "d")); Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 1, "d")); } @@ -199,11 +199,11 @@ public void TestMinimumBoundedRectangles() Assert.AreEqual((1, 2), info.GetMinimumBoundedRectangle(0, 0, 0)); Assert.AreEqual((7, 8), info.GetMinimumBoundedRectangle(1, 1, "d1")); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(1, 1, "d1")); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(1, 1, "d1")); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(1, 1, "d1")); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(1, 1, "d1")); Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(1, 1, "d1")); } @@ -226,11 +226,11 @@ public void TestMinimumBoundedRectanglesInt32() Assert.AreEqual((1, 2), info.GetMinimumBoundedRectangle(0, 0, 0)); Assert.AreEqual((7, 8), info.GetMinimumBoundedRectangle(1, 1, "d1")); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(0, 0, 0)); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(1, 1, "d1")); - Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(1, 1, "d1")); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(1, 1, "d1")); + Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(1, 1, "d1")); Assert.ThrowsException(() => info.GetMinimumBoundedRectangle(1, 1, "d1")); } @@ -268,8 +268,8 @@ public void TestNonEmptyDomain() (int Start, int End, _) => (Start, End) }; Assert.AreEqual(expectedNonEmptyDomain, actualNonEmptyDomain); - Assert.ThrowsException(() => info.GetNonEmptyDomain(i, dim)); - Assert.ThrowsException(() => info.GetNonEmptyDomain(i, dim)); + Assert.ThrowsException(() => info.GetNonEmptyDomain(i, dim)); + Assert.ThrowsException(() => info.GetNonEmptyDomain(i, dim)); Assert.ThrowsException(() => info.GetNonEmptyDomain(i, dim)); string name = d.Name(); @@ -279,8 +279,8 @@ public void TestNonEmptyDomain() (int Start, int End, _) => (Start, End) }; Assert.AreEqual(expectedNonEmptyDomain, actualNonEmptyDomain); - Assert.ThrowsException(() => info.GetNonEmptyDomain(i, name)); - Assert.ThrowsException(() => info.GetNonEmptyDomain(i, name)); + Assert.ThrowsException(() => info.GetNonEmptyDomain(i, name)); + Assert.ThrowsException(() => info.GetNonEmptyDomain(i, name)); Assert.ThrowsException(() => info.GetNonEmptyDomain(i, name)); } } diff --git a/tests/TileDB.CSharp.Test/QueryTest.cs b/tests/TileDB.CSharp.Test/QueryTest.cs index 92b2a6cf..288676aa 100644 --- a/tests/TileDB.CSharp.Test/QueryTest.cs +++ b/tests/TileDB.CSharp.Test/QueryTest.cs @@ -50,13 +50,13 @@ public void TestGlobalQuery(LayoutType layoutType, ArrayType arrayType) { using var subarray = new Subarray(array); subarray.AddRange("rows", 1, 4); - Assert.ThrowsException(() => subarray.AddRange("rows", 1, 4)); + Assert.ThrowsException(() => subarray.AddRange("rows", 1, 4)); Assert.AreEqual((1, 4), subarray.GetRange("rows", 0)); - Assert.ThrowsException(() => subarray.GetRange("rows", 0)); + Assert.ThrowsException(() => subarray.GetRange("rows", 0)); subarray.AddRange(1, 1, 2); // cols - Assert.ThrowsException(() => subarray.AddRange(1, 1, 2)); + Assert.ThrowsException(() => subarray.AddRange(1, 1, 2)); Assert.AreEqual((1, 2), subarray.GetRange(1, 0)); - Assert.ThrowsException(() => subarray.GetRange(1, 0)); + Assert.ThrowsException(() => subarray.GetRange(1, 0)); queryWrite.SetSubarray(subarray); queryWrite.SetDataReadOnlyBuffer("a1", new[] { 1, 2, 3, 4, 5, 6, 7, 8 }.AsMemory()); } @@ -181,8 +181,8 @@ public void TestDenseQuery() using (var subarray = new Subarray(array)) { subarray.SetSubarray(0, 1); - Assert.ThrowsException(() => subarray.SetSubarray(0, 1)); - Assert.ThrowsException(() => subarray.SetSubarray(0)); + Assert.ThrowsException(() => subarray.SetSubarray(0, 1)); + Assert.ThrowsException(() => subarray.SetSubarray(0)); query.SetSubarray(subarray); }