/// <summary> /// Get one of the known data types. Data types /// are created automatically during model deserialization. /// </summary> /// <param name="portableType">PortableDataType value</param> /// <returns>Known type, or throws if out of range</returns> public DataType GetPortableDataType(PortableDataType portableType) { return myPortableTypes[(int)portableType]; }
/// <summary> /// Get one of the known data types. Data types /// are created automatically during model deserialization. /// </summary> /// <param name="portableType">PortableDataType value</param> /// <returns>Known type, or throws if out of range</returns> public DataType GetPortableDataType(PortableDataType portableType) { return(myPortableTypes[(int)portableType]); }
/// <summary> /// Check if two data types can be compared. This is a weaker check /// than <see cref="IsAssignableValueType"/> in that it does not /// do any facet checking to see if one value can store the only, /// but only checks if the two can be compared. /// </summary> /// <param name="valueType1">The first value type to compare.</param> /// <param name="valueType2">The second value type to compare.</param> /// <param name="equalityOnly">Set to true if the equality or inequality /// of the two values is required, but an ordered check is not.</param> /// <returns><see langword="true"/> if the two types can be compared.</returns> public static bool IsComparableValueType(ObjectType valueType1, ObjectType valueType2, bool equalityOnly) { DataType dataType1 = valueType1.DataType; DataType dataType2 = valueType2.DataType; if (dataType1 == dataType2) { switch (dataType1.PortableDataType) { case PortableDataType.Unspecified: // Give the user the benefit of the doubt that fixing the // unspecified data type will result in comparable values. return(true); case PortableDataType.NumericAutoCounter: // Only support this if the value types are the same. Otherwise, we're mapping different // counters to each other, which is meaningless. return(valueType1 == valueType2); default: return(dataType1.CanCompare && (equalityOnly || (dataType1.RangeSupport != DataTypeRangeSupport.None))); } } else if (dataType1.CanCompare && dataType2.CanCompare && (equalityOnly || (dataType1.RangeSupport != DataTypeRangeSupport.None && dataType2.RangeSupport != DataTypeRangeSupport.None))) { // Look at specific types. PortableDataType targetType = dataType1.PortableDataType; PortableDataType sourceType = dataType2.PortableDataType; if (sourceType == PortableDataType.Unspecified) { // Give user the benefit of the doubt that the types will be made comparable // if this choice is made. return(true); } switch (targetType) { case PortableDataType.Unspecified: // Let user fix return(true); case PortableDataType.TextFixedLength: case PortableDataType.TextVariableLength: case PortableDataType.TextLargeLength: switch (sourceType) { case PortableDataType.TextFixedLength: case PortableDataType.TextVariableLength: case PortableDataType.TextLargeLength: return(true); } break; case PortableDataType.NumericSignedInteger: case PortableDataType.NumericSignedSmallInteger: case PortableDataType.NumericSignedLargeInteger: case PortableDataType.NumericUnsignedInteger: case PortableDataType.NumericUnsignedTinyInteger: case PortableDataType.NumericUnsignedSmallInteger: case PortableDataType.NumericUnsignedLargeInteger: case PortableDataType.NumericFloatingPoint: case PortableDataType.NumericSinglePrecisionFloatingPoint: case PortableDataType.NumericDoublePrecisionFloatingPoint: case PortableDataType.NumericDecimal: case PortableDataType.NumericMoney: switch (sourceType) { case PortableDataType.NumericSignedInteger: case PortableDataType.NumericSignedSmallInteger: case PortableDataType.NumericSignedLargeInteger: case PortableDataType.NumericUnsignedInteger: case PortableDataType.NumericUnsignedTinyInteger: case PortableDataType.NumericUnsignedSmallInteger: case PortableDataType.NumericUnsignedLargeInteger: case PortableDataType.NumericFloatingPoint: case PortableDataType.NumericSinglePrecisionFloatingPoint: case PortableDataType.NumericDoublePrecisionFloatingPoint: case PortableDataType.NumericDecimal: case PortableDataType.NumericMoney: return(true); } break; //case PortableDataType.RawDataFixedLength: //case PortableDataType.RawDataVariableLength: //case PortableDataType.RawDataLargeLength: //case PortableDataType.RawDataPicture: //case PortableDataType.RawDataOleObject: // Raw data types are not comparable, these cases would form a dead code path. //case PortableDataType.NumericAutoCounter: //case PortableDataType.TemporalTime: //case PortableDataType.TemporalDate: //case PortableDataType.OtherRowId: //case PortableDataType.OtherObjectId: // These compare only to themselves, will be caught in first if block case PortableDataType.TemporalAutoTimestamp: case PortableDataType.TemporalDateAndTime: switch (sourceType) { case PortableDataType.TemporalAutoTimestamp: case PortableDataType.TemporalDateAndTime: return(true); } break; case PortableDataType.LogicalTrueOrFalse: case PortableDataType.LogicalYesOrNo: switch (sourceType) { case PortableDataType.LogicalTrueOrFalse: case PortableDataType.LogicalYesOrNo: return(true); } break; } } return(false); }
/// <summary> /// Test if an instance of one value type can be always be assigned to /// an instance of another value type. /// </summary> /// <param name="targetValueType">The type of the value being assigned to.</param> /// <param name="sourceValueType">The type of the value being assigned from.</param> /// <returns><see langword="true"/> if the source value can be assigned to the target value.</returns> /// <remarks>If either data type is unspecified, then the assumption is made that there is an error /// for this condition elsewhere and that the user will fix it, so this method returns true in these /// cases. Autogenerated values are assumed to be incompatible if they come from different value types /// because assigning autogenerated values to each other is also meaningingless.</remarks> public static bool IsAssignableValueType(ObjectType targetValueType, ObjectType sourceValueType) { if (targetValueType == sourceValueType) { return(true); } ValueTypeHasDataType targetUse; ValueTypeHasDataType sourceUse; if (null == (targetUse = ValueTypeHasDataType.GetLinkToDataType(targetValueType)) || null == (sourceUse = ValueTypeHasDataType.GetLinkToDataType(sourceValueType))) { return(false); } PortableDataType targetType = targetUse.DataType.PortableDataType; PortableDataType sourceType = sourceUse.DataType.PortableDataType; if (sourceType == PortableDataType.Unspecified) { // Give user the benefit of the doubt that the types will be made compatible // if this choice is made. return(true); } int targetLength; int sourceLength; int targetScale; int sourceScale; switch (targetType) { case PortableDataType.Unspecified: // Let user fix return(true); case PortableDataType.TextFixedLength: case PortableDataType.TextVariableLength: case PortableDataType.TextLargeLength: switch (sourceType) { case PortableDataType.TextFixedLength: case PortableDataType.TextVariableLength: case PortableDataType.TextLargeLength: targetLength = targetUse.Length; sourceLength = sourceUse.Length; return((targetLength == 0 ? int.MaxValue : targetLength) >= (sourceLength == 0 ? int.MaxValue : sourceLength)); } break; case PortableDataType.NumericSignedInteger: switch (sourceType) { case PortableDataType.NumericSignedInteger: case PortableDataType.NumericSignedSmallInteger: return(true); case PortableDataType.NumericDecimal: if (sourceUse.Scale == 0) { sourceLength = sourceUse.Length; if (sourceLength != 0 && sourceLength <= 9) // 10 might be too big { return(true); } } break; } break; case PortableDataType.NumericSignedSmallInteger: switch (sourceType) { case PortableDataType.NumericSignedSmallInteger: return(true); case PortableDataType.NumericDecimal: if (sourceUse.Scale == 0) { sourceLength = sourceUse.Length; if (sourceLength != 0 && sourceLength <= 4) // 5 might be too big { return(true); } } break; } break; case PortableDataType.NumericSignedLargeInteger: switch (sourceType) { case PortableDataType.NumericSignedInteger: case PortableDataType.NumericSignedSmallInteger: case PortableDataType.NumericSignedLargeInteger: return(true); case PortableDataType.NumericDecimal: if (sourceUse.Scale == 0) { sourceLength = sourceUse.Length; if (sourceLength != 0 && sourceLength <= 18) // 19 might be too big { return(true); } } break; } break; case PortableDataType.NumericUnsignedInteger: switch (sourceType) { case PortableDataType.NumericUnsignedInteger: case PortableDataType.NumericUnsignedTinyInteger: case PortableDataType.NumericUnsignedSmallInteger: return(true); } break; case PortableDataType.NumericUnsignedTinyInteger: switch (sourceType) { case PortableDataType.NumericUnsignedTinyInteger: return(true); } break; case PortableDataType.NumericUnsignedSmallInteger: switch (sourceType) { case PortableDataType.NumericUnsignedTinyInteger: case PortableDataType.NumericUnsignedSmallInteger: return(true); } break; case PortableDataType.NumericUnsignedLargeInteger: switch (sourceType) { case PortableDataType.NumericUnsignedInteger: case PortableDataType.NumericUnsignedTinyInteger: case PortableDataType.NumericUnsignedSmallInteger: case PortableDataType.NumericUnsignedLargeInteger: return(true); } break; //case PortableDataType.NumericAutoCounter: // Only support this if the value types are the same. Otherwise, we're mapping different // counters to each other, which is meaningless. case PortableDataType.NumericFloatingPoint: case PortableDataType.NumericSinglePrecisionFloatingPoint: case PortableDataType.NumericDoublePrecisionFloatingPoint: switch (sourceType) { case PortableDataType.NumericFloatingPoint: sourceLength = sourceUse.Length; if (sourceLength == 0) { sourceLength = 53; } break; case PortableDataType.NumericSinglePrecisionFloatingPoint: sourceLength = 24; break; case PortableDataType.NumericDoublePrecisionFloatingPoint: sourceLength = 53; break; default: sourceLength = -1; break; } if (sourceLength != -1) { switch (targetType) { case PortableDataType.NumericSinglePrecisionFloatingPoint: targetLength = 24; break; case PortableDataType.NumericDoublePrecisionFloatingPoint: targetLength = 53; break; //case PortableDataType.NumericFloatingPoint: default: targetLength = targetUse.Length; if (targetLength == 0) { targetLength = 53; } break; } if (targetLength >= sourceLength) { return(true); } } break; case PortableDataType.NumericDecimal: case PortableDataType.NumericMoney: sourceScale = 0; switch (sourceType) { case PortableDataType.NumericDecimal: sourceLength = sourceUse.Length; if (sourceLength == 0) { sourceLength = 18; } else { sourceScale = sourceUse.Scale; } break; case PortableDataType.NumericMoney: sourceLength = 19; sourceScale = 4; break; case PortableDataType.NumericSignedInteger: case PortableDataType.NumericUnsignedInteger: sourceLength = 10; break; case PortableDataType.NumericSignedSmallInteger: case PortableDataType.NumericUnsignedSmallInteger: sourceLength = 5; break; case PortableDataType.NumericSignedLargeInteger: sourceLength = 19; break; case PortableDataType.NumericUnsignedLargeInteger: sourceLength = 20; break; case PortableDataType.NumericUnsignedTinyInteger: sourceLength = 3; break; default: sourceLength = -1; break; } if (sourceLength != -1) { if (targetType == PortableDataType.NumericMoney) { targetLength = 19; targetScale = 4; } else { targetLength = targetUse.Length; // Length maps to precision, verify precision first, then scale if (targetLength == 0) { targetLength = 18; targetScale = 0; } else { targetScale = targetUse.Scale; } } if (targetLength >= sourceLength && targetScale >= sourceScale) { return(true); } } break; case PortableDataType.RawDataFixedLength: case PortableDataType.RawDataVariableLength: case PortableDataType.RawDataLargeLength: switch (sourceType) { case PortableDataType.RawDataFixedLength: case PortableDataType.RawDataVariableLength: case PortableDataType.RawDataLargeLength: targetLength = targetUse.Length; sourceLength = sourceUse.Length; return((targetLength == 0 ? int.MaxValue : targetLength) >= (sourceLength == 0 ? int.MaxValue : sourceLength)); } break; case PortableDataType.RawDataPicture: case PortableDataType.RawDataOleObject: case PortableDataType.TemporalTime: case PortableDataType.TemporalDate: case PortableDataType.OtherRowId: case PortableDataType.OtherObjectId: if (sourceType == targetType) { return(true); } break; case PortableDataType.TemporalAutoTimestamp: case PortableDataType.TemporalDateAndTime: switch (sourceType) { case PortableDataType.TemporalAutoTimestamp: case PortableDataType.TemporalTime: case PortableDataType.TemporalDate: case PortableDataType.TemporalDateAndTime: return(true); } break; case PortableDataType.LogicalTrueOrFalse: case PortableDataType.LogicalYesOrNo: switch (sourceType) { case PortableDataType.LogicalTrueOrFalse: case PortableDataType.LogicalYesOrNo: return(true); } break; } return(false); }