internal override ProviderType MostPreciseTypeInFamily(ProviderType type) { SqlType sqlType = (SqlType)type; switch (sqlType.SqlDbType) { case SqlDbType.TinyInt: case SqlDbType.SmallInt: case SqlDbType.Int: return(From(typeof(int))); case SqlDbType.SmallMoney: case SqlDbType.Money: return(SqlTypeSystem.Create(SqlDbType.Money)); case SqlDbType.Real: case SqlDbType.Float: return(From(typeof(double))); case SqlDbType.Date: case SqlDbType.Time: case SqlDbType.SmallDateTime: case SqlDbType.DateTime: case SqlDbType.DateTime2: return(From(typeof(DateTime))); case SqlDbType.DateTimeOffset: return(From(typeof(DateTimeOffset))); default: return(type); } }
internal override Type GetClosestRuntimeType() { if (this.RuntimeOnlyType != null) { return(this.RuntimeOnlyType); } return(SqlTypeSystem.GetClosestRuntimeType(this.sqlDbType)); }
internal override ProviderType From(Type type, int?size) { if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable <>)) { type = type.GetGenericArguments()[0]; } // Retain mappings for DateTime and TimeSpan; add one for the new DateTimeOffset type. // if (System.Type.GetTypeCode(type) == TypeCode.Object && type == typeof(DateTimeOffset)) { return(SqlTypeSystem.Create(SqlDbType.DateTimeOffset)); } return(base.From(type, size)); }
internal override ProviderType GetBestLargeType(ProviderType type) { SqlType sqlType = (SqlType)type; switch (sqlType.SqlDbType) { case SqlDbType.NChar: case SqlDbType.NVarChar: return(SqlTypeSystem.Create(SqlDbType.NText)); case SqlDbType.Char: case SqlDbType.VarChar: return(SqlTypeSystem.Create(SqlDbType.Text)); case SqlDbType.Binary: case SqlDbType.VarBinary: return(SqlTypeSystem.Create(SqlDbType.Image)); } return(type); }
internal override ProviderType GetBestLargeType(ProviderType type) { SqlType sqlType = (SqlType)type; switch (sqlType.SqlDbType) { case SqlDbType.NText: case SqlDbType.NChar: case SqlDbType.NVarChar: return(SqlTypeSystem.Create(SqlDbType.NVarChar, ProviderConstants.LargeTypeSizeIndicator)); case SqlDbType.Text: case SqlDbType.Char: case SqlDbType.VarChar: return(SqlTypeSystem.Create(SqlDbType.VarChar, ProviderConstants.LargeTypeSizeIndicator)); case SqlDbType.Image: case SqlDbType.Binary: case SqlDbType.VarBinary: return(SqlTypeSystem.Create(SqlDbType.VarBinary, ProviderConstants.LargeTypeSizeIndicator)); } return(type); }
/// <summary> /// For types with size, determine the closest matching type for the information /// specified, promoting to the appropriate large type as needed. If no size is /// specified, we use the max. /// </summary> protected ProviderType GetBestType(SqlDbType targetType, int?size) { // determine max size for the specified db type int maxSize = 0; switch (targetType) { case SqlDbType.NChar: case SqlDbType.NVarChar: maxSize = 4000; break; case SqlDbType.Char: case SqlDbType.VarChar: case SqlDbType.Binary: case SqlDbType.VarBinary: maxSize = 8000; break; } ; if (size.HasValue) { if (size.Value <= maxSize) { return(SqlTypeSystem.Create(targetType, size.Value)); } else { return(GetBestLargeType(SqlTypeSystem.Create(targetType))); } } // if the type provider supports MAX types, return one, otherwise use // the maximum size determined above return(SqlTypeSystem.Create(targetType, SupportsMaxSize ? ProviderConstants.LargeTypeSizeIndicator : maxSize)); }
internal override ProviderType ChangeTypeFamilyTo(ProviderType type, ProviderType toType) { // if this is already the same family, do nothing if (type.IsSameTypeFamily(toType)) { return(type); } // otherwise as a default return toType // but look for special cases we have to convert carefully if (type.IsApplicationType || toType.IsApplicationType) { return(toType); } SqlType sqlToType = (SqlType)toType; SqlType sqlThisType = (SqlType)type; if (sqlToType.Category == TypeCategory.Numeric && sqlThisType.Category == TypeCategory.Char) { switch (sqlThisType.SqlDbType) { case SqlDbType.NChar: return(SqlTypeSystem.Create(SqlDbType.Int)); case SqlDbType.Char: return(SqlTypeSystem.Create(SqlDbType.SmallInt)); default: return(toType); } } else { return(toType); } }
internal override ProviderType From(Type type, int?size) { if (type.IsGenericType) { if (type.GetGenericTypeDefinition() == typeof(Nullable <>)) { type = type.GetGenericArguments()[0]; } if (type.GetGenericTypeDefinition() == typeof(DbId <,>)) { type = type.GenericTypeArguments[1];// return From(typeof(int), size); } } TypeCode tc = System.Type.GetTypeCode(type); switch (tc) { case TypeCode.Boolean: return(SqlTypeSystem.Create(SqlDbType.Bit)); case TypeCode.Byte: return(SqlTypeSystem.Create(SqlDbType.TinyInt)); case TypeCode.SByte: case TypeCode.Int16: return(SqlTypeSystem.Create(SqlDbType.SmallInt)); case TypeCode.Int32: case TypeCode.UInt16: return(SqlTypeSystem.Create(SqlDbType.Int)); case TypeCode.Int64: case TypeCode.UInt32: return(SqlTypeSystem.Create(SqlDbType.BigInt)); case TypeCode.UInt64: return(SqlTypeSystem.Create(SqlDbType.Decimal, 20, 0)); case TypeCode.Decimal: return(SqlTypeSystem.Create(SqlDbType.Decimal, 29, size ?? 4)); case TypeCode.Double: return(SqlTypeSystem.Create(SqlDbType.Float)); case TypeCode.Single: return(SqlTypeSystem.Create(SqlDbType.Real)); case TypeCode.Char: return(SqlTypeSystem.Create(SqlDbType.NChar, 1)); case TypeCode.String: return(GetBestType(SqlDbType.NVarChar, size)); case TypeCode.DateTime: return(SqlTypeSystem.Create(SqlDbType.DateTime)); case TypeCode.Object: { if (type == typeof(Guid)) { return(SqlTypeSystem.Create(SqlDbType.UniqueIdentifier)); } if (type == typeof(byte[]) || type == typeof(Binary)) { return(GetBestType(SqlDbType.VarBinary, size)); } if (type == typeof(char[])) { return(GetBestType(SqlDbType.NVarChar, size)); } if (type == typeof(TimeSpan)) { return(SqlTypeSystem.Create(SqlDbType.BigInt)); } if (type == typeof(System.Xml.Linq.XDocument) || type == typeof(System.Xml.Linq.XElement)) { return(ProviderConstants.XmlType); } // else UDT? return(new SqlType(type)); } default: throw Error.UnexpectedTypeCode(tc); } }
internal override ProviderType GetBestType(ProviderType typeA, ProviderType typeB) { // first determine the type precedence SqlType bestType = (SqlType)(typeA.ComparePrecedenceTo(typeB) > 0 ? typeA : typeB); // if one of the types is a not a server type, return // that type if (typeA.IsApplicationType || typeA.IsRuntimeOnlyType) { return(typeA); } if (typeB.IsApplicationType || typeB.IsRuntimeOnlyType) { return(typeB); } SqlType sqlTypeA = (SqlType)typeA; SqlType sqlTypeB = (SqlType)typeB; if (sqlTypeA.HasPrecisionAndScale && sqlTypeB.HasPrecisionAndScale && bestType.SqlDbType == SqlDbType.Decimal) { int p0 = sqlTypeA.Precision; int s0 = sqlTypeA.Scale; int p1 = sqlTypeB.Precision; int s1 = sqlTypeB.Scale; // precision and scale may be zero if this is an unsized type. if (p0 == 0 && s0 == 0 && p1 == 0 && s1 == 0) { return(SqlTypeSystem.Create(bestType.SqlDbType)); } else if (p0 == 0 && s0 == 0) { return(SqlTypeSystem.Create(bestType.SqlDbType, p1, s1)); } else if (p1 == 0 && s1 == 0) { return(SqlTypeSystem.Create(bestType.SqlDbType, p0, s0)); } // determine best scale/precision int bestLeft = Math.Max(p0 - s0, p1 - s1); int bestRight = Math.Max(s0, s1); int precision = Math.Min(bestLeft + bestRight, 38); return(SqlTypeSystem.Create(bestType.SqlDbType, precision, /*scale*/ bestRight)); } else { // determine the best size int?bestSize = null; if (sqlTypeA.Size.HasValue && sqlTypeB.Size.HasValue) { bestSize = (sqlTypeB.Size > sqlTypeA.Size) ? sqlTypeB.Size : sqlTypeA.Size; } if (sqlTypeB.Size.HasValue && sqlTypeB.Size.Value == ProviderConstants.LargeTypeSizeIndicator || sqlTypeA.Size.HasValue && sqlTypeA.Size.Value == ProviderConstants.LargeTypeSizeIndicator) { // the large type size trumps all bestSize = ProviderConstants.LargeTypeSizeIndicator; } bestType = new SqlType(bestType.SqlDbType, bestSize); } return(bestType); }
internal override ProviderType ReturnTypeOfFunction(SqlFunctionCall functionCall) { var argumentTypes = this.GetArgumentTypes(functionCall); SqlType arg0 = (SqlType)argumentTypes[0]; SqlType arg1 = argumentTypes.Length > 1 ? (SqlType)argumentTypes[1] : (SqlType)null; switch (functionCall.Name) { case "LEN": case "DATALENGTH": switch (arg0.SqlDbType) { case SqlDbType.NVarChar: case SqlDbType.VarChar: case SqlDbType.VarBinary: if (arg0.IsLargeType) { return(SqlTypeSystem.Create(SqlDbType.BigInt)); } else { return(SqlTypeSystem.Create(SqlDbType.Int)); } default: return(SqlTypeSystem.Create(SqlDbType.Int)); } case "ABS": case "SIGN": case "ROUND": case "CEILING": case "FLOOR": case "POWER": switch (arg0.SqlDbType) { case SqlDbType.TinyInt: case SqlDbType.Int: case SqlDbType.SmallInt: return(SqlTypeSystem.Create(SqlDbType.Int)); case SqlDbType.Float: case SqlDbType.Real: return(SqlTypeSystem.Create(SqlDbType.Float)); default: return(arg0); } case "PATINDEX": case "CHARINDEX": if (arg1.IsLargeType) { return(SqlTypeSystem.Create(SqlDbType.BigInt)); } return(SqlTypeSystem.Create(SqlDbType.Int)); case "SUBSTRING": if (functionCall.Arguments[2].NodeType == SqlNodeType.Value) { SqlValue val = (SqlValue)functionCall.Arguments[2]; if (val.Value is int) { switch (arg0.SqlDbType) { case SqlDbType.NVarChar: case SqlDbType.NChar: case SqlDbType.VarChar: case SqlDbType.Char: return(SqlTypeSystem.Create(arg0.SqlDbType, (int)val.Value)); default: return(null); } } } switch (arg0.SqlDbType) { case SqlDbType.NVarChar: case SqlDbType.NChar: return(SqlTypeSystem.Create(SqlDbType.NVarChar)); case SqlDbType.VarChar: case SqlDbType.Char: return(SqlTypeSystem.Create(SqlDbType.VarChar)); default: return(null); } case "STUFF": // if the stuff call is an insertion and is strictly additive // (no deletion of characters) the return type is the same as // a concatenation if (functionCall.Arguments.Count == 4) { SqlValue delLength = functionCall.Arguments[2] as SqlValue; if (delLength != null && (int)delLength.Value == 0) { return(PredictTypeForBinary(SqlNodeType.Concat, functionCall.Arguments[0].SqlType, functionCall.Arguments[3].SqlType)); } } return(null); case "LOWER": case "UPPER": case "RTRIM": case "LTRIM": case "INSERT": case "REPLACE": case "LEFT": case "RIGHT": case "REVERSE": return(arg0); default: return(null); } }
internal override ProviderType Parse(string stype) { // parse type... string typeName = null; string param1 = null; string param2 = null; int paren = stype.IndexOf('('); int space = stype.IndexOf(' '); int end = (paren != -1 && space != -1) ? Math.Min(space, paren) : (paren != -1) ? paren : (space != -1) ? space : -1; if (end == -1) { typeName = stype; end = stype.Length; } else { typeName = stype.Substring(0, end); } int start = end; if (start < stype.Length && stype[start] == '(') { start++; end = stype.IndexOf(',', start); if (end > 0) { param1 = stype.Substring(start, end - start); start = end + 1; end = stype.IndexOf(')', start); param2 = stype.Substring(start, end - start); } else { end = stype.IndexOf(')', start); param1 = stype.Substring(start, end - start); } start = end++; } #region Special case type mappings if (String.Compare(typeName, "rowversion", StringComparison.OrdinalIgnoreCase) == 0) { typeName = "Timestamp"; } if (String.Compare(typeName, "numeric", StringComparison.OrdinalIgnoreCase) == 0) { typeName = "Decimal"; } if (String.Compare(typeName, "sql_variant", StringComparison.OrdinalIgnoreCase) == 0) { typeName = "Variant"; } if (String.Compare(typeName, "filestream", StringComparison.OrdinalIgnoreCase) == 0) { typeName = "Binary"; } #endregion // since we're going to parse the enum value below, we verify // here that it is defined. For example, types like table, cursor // are not valid. if (!Enum.GetNames(typeof(SqlDbType)).Select(n => n.ToUpperInvariant()).Contains(typeName.ToUpperInvariant())) { throw Error.InvalidProviderType(typeName); } int p1 = 0; int p2 = 0; SqlDbType dbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), typeName, true); if (param1 != null) { if (String.Compare(param1.Trim(), "max", StringComparison.OrdinalIgnoreCase) == 0) { p1 = ProviderConstants.LargeTypeSizeIndicator; } else { p1 = Int32.Parse(param1, Globalization.CultureInfo.InvariantCulture); if (p1 == Int32.MaxValue) { p1 = ProviderConstants.LargeTypeSizeIndicator; } } } if (param2 != null) { if (String.Compare(param2.Trim(), "max", StringComparison.OrdinalIgnoreCase) == 0) { p2 = ProviderConstants.LargeTypeSizeIndicator; } else { p2 = Int32.Parse(param2, Globalization.CultureInfo.InvariantCulture); if (p2 == Int32.MaxValue) { p2 = ProviderConstants.LargeTypeSizeIndicator; } } } switch (dbType) { case SqlDbType.Binary: case SqlDbType.Char: case SqlDbType.NChar: case SqlDbType.NVarChar: case SqlDbType.VarBinary: case SqlDbType.VarChar: return(SqlTypeSystem.Create(dbType, p1)); case SqlDbType.Decimal: case SqlDbType.Real: case SqlDbType.Float: return(SqlTypeSystem.Create(dbType, p1, p2)); case SqlDbType.Timestamp: default: return(SqlTypeSystem.Create(dbType)); } }