|
//---------------------------------------------------------------------
// <copyright file="SqlProviderManifest.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//
// @owner Microsoft
// @backupOwner Microsoft
//---------------------------------------------------------------------
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Metadata.Edm;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml;
namespace System.Data.SqlClient
{
/// <summary>
/// The Provider Manifest for SQL Server
/// </summary>
internal class SqlProviderManifest : DbXmlEnabledProviderManifest
{
internal const string TokenSql8 = "2000";
internal const string TokenSql9 = "2005";
internal const string TokenSql10 = "2008";
// '~' is the same escape character that L2S uses
internal const char LikeEscapeChar = '~';
internal const string LikeEscapeCharToString = "~";
#region Private Fields
// Default to SQL Server 2005 (9.0)
private SqlVersion _version = SqlVersion.Sql9;
/// <summary>
/// maximum size of sql server unicode
/// </summary>
private const int varcharMaxSize = 8000;
private const int nvarcharMaxSize = 4000;
private const int binaryMaxSize = 8000;
private System.Collections.ObjectModel.ReadOnlyCollection<PrimitiveType> _primitiveTypes = null;
private System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> _functions = null;
#endregion
#region Constructors
/// <summary>
/// Constructor
/// </summary>
/// <param name="manifestToken">A token used to infer the capabilities of the store</param>
public SqlProviderManifest(string manifestToken)
: base(SqlProviderManifest.GetProviderManifest())
{
// GetSqlVersion will throw ArgumentException if manifestToken is null, empty, or not recognized.
_version = SqlVersionUtils.GetSqlVersion(manifestToken);
}
#endregion
#region Properties
internal SqlVersion SqlVersion
{
get { return this._version; }
}
#endregion
#region Private Methods
private static XmlReader GetProviderManifest()
{
return DbProviderServices.GetXmlResource("System.Data.Resources.SqlClient.SqlProviderServices.ProviderManifest.xml");
}
private XmlReader GetStoreSchemaMapping(string mslName)
{
return DbProviderServices.GetXmlResource("System.Data.Resources.SqlClient.SqlProviderServices." + mslName + ".msl");
}
private XmlReader GetStoreSchemaDescription(string ssdlName)
{
if (this._version == SqlVersion.Sql8)
{
return DbProviderServices.GetXmlResource("System.Data.Resources.SqlClient.SqlProviderServices." + ssdlName + "_Sql8.ssdl");
}
return DbProviderServices.GetXmlResource("System.Data.Resources.SqlClient.SqlProviderServices." + ssdlName + ".ssdl");
}
#endregion
#region Internal Methods
/// <summary>
/// Function to detect wildcard characters %, _, [ and ^ and escape them with a preceding ~
/// This escaping is used when StartsWith, EndsWith and Contains canonical and CLR functions
/// are translated to their equivalent LIKE expression
/// NOTE: This code has been copied from LinqToSql
/// </summary>
/// <param name="text">Original input as specified by the user</param>
/// <param name="alwaysEscapeEscapeChar">escape the escape character ~ regardless whether wildcard
/// characters were encountered </param>
/// <param name="usedEscapeChar">true if the escaping was performed, false if no escaping was required</param>
/// <returns>The escaped string that can be used as pattern in a LIKE expression</returns>
internal static string EscapeLikeText(string text, bool alwaysEscapeEscapeChar, out bool usedEscapeChar)
{
usedEscapeChar = false;
if (!(text.Contains("%") || text.Contains("_") || text.Contains("[")
|| text.Contains("^") || alwaysEscapeEscapeChar && text.Contains(LikeEscapeCharToString)))
{
return text;
}
StringBuilder sb = new StringBuilder(text.Length);
foreach (char c in text)
{
if (c == '%' || c == '_' || c == '[' || c == '^' || c == LikeEscapeChar)
{
sb.Append(LikeEscapeChar);
usedEscapeChar = true;
}
sb.Append(c);
}
return sb.ToString();
}
#endregion
#region Overrides
/// <summary>
/// Providers should override this to return information specific to their provider.
///
/// This method should never return null.
/// </summary>
/// <param name="informationType">The name of the information to be retrieved.</param>
/// <returns>An XmlReader at the begining of the information requested.</returns>
protected override XmlReader GetDbInformation(string informationType)
{
if (informationType == DbProviderManifest.StoreSchemaDefinitionVersion3 ||
informationType == DbProviderManifest.StoreSchemaDefinition)
{
return GetStoreSchemaDescription(informationType);
}
if (informationType == DbProviderManifest.StoreSchemaMappingVersion3 ||
informationType == DbProviderManifest.StoreSchemaMapping)
{
return GetStoreSchemaMapping(informationType);
}
// Use default Conceptual Schema Definition
if (informationType == DbProviderManifest.ConceptualSchemaDefinitionVersion3 ||
informationType == DbProviderManifest.ConceptualSchemaDefinition)
{
return null;
}
throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.ProviderReturnedNullForGetDbInformation(informationType));
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
public override System.Collections.ObjectModel.ReadOnlyCollection<PrimitiveType> GetStoreTypes()
{
if (this._primitiveTypes == null)
{
if (this._version == SqlVersion.Sql10)
{
this._primitiveTypes = base.GetStoreTypes();
}
else
{
List<PrimitiveType> primitiveTypes = new List<PrimitiveType>(base.GetStoreTypes());
Debug.Assert((this._version == SqlVersion.Sql8) || (this._version == SqlVersion.Sql9), "Found verion other than Sql 8, 9 or 10");
//Remove the Katmai types for both Sql8 and Sql9
primitiveTypes.RemoveAll(new Predicate<PrimitiveType>(
delegate(PrimitiveType primitiveType)
{
string name = primitiveType.Name.ToLowerInvariant();
return name.Equals("time", StringComparison.Ordinal) ||
name.Equals("date", StringComparison.Ordinal) ||
name.Equals("datetime2", StringComparison.Ordinal) ||
name.Equals("datetimeoffset", StringComparison.Ordinal) ||
name.Equals("geography", StringComparison.Ordinal) ||
name.Equals("geometry", StringComparison.Ordinal);
}
)
);
//Remove the types that won't work in Sql8
if (this._version == SqlVersion.Sql8) {
// SQLBUDT 550667 and 551271: Remove xml and 'max' types for SQL Server 2000
primitiveTypes.RemoveAll(new Predicate<PrimitiveType>(
delegate(PrimitiveType primitiveType)
{
string name = primitiveType.Name.ToLowerInvariant();
return name.Equals("xml", StringComparison.Ordinal) || name.EndsWith("(max)", StringComparison.Ordinal);
}
)
);
}
this._primitiveTypes = primitiveTypes.AsReadOnly();
}
}
return this._primitiveTypes;
}
public override System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> GetStoreFunctions()
{
if (this._functions == null)
{
if (this._version == SqlVersion.Sql10)
{
this._functions = base.GetStoreFunctions();
}
else
{
//Remove the functions over katmai types from both Sql 9 and Sql 8.
IEnumerable<EdmFunction> functions = base.GetStoreFunctions().Where(f => !IsKatmaiOrNewer(f));
if(this._version == SqlVersion.Sql8)
{
// SQLBUDT 550998: Remove unsupported overloads from Provider Manifest on SQL 8.0
functions = functions.Where(f => !IsYukonOrNewer(f));
}
this._functions = functions.ToList().AsReadOnly();
}
}
return this._functions;
}
private static bool IsKatmaiOrNewer(EdmFunction edmFunction)
{
// Spatial types are only supported from Katmai onward; any functions using them must therefore also be Katmai or newer.
if ((edmFunction.ReturnParameter != null && Helper.IsSpatialType(edmFunction.ReturnParameter.TypeUsage)) ||
edmFunction.Parameters.Any(p => Helper.IsSpatialType(p.TypeUsage)))
{
return true;
}
ReadOnlyMetadataCollection<FunctionParameter> funParams = edmFunction.Parameters;
switch (edmFunction.Name.ToUpperInvariant())
{
case "COUNT":
case "COUNT_BIG":
case "MAX":
case "MIN":
{
string name = ((CollectionType)funParams[0].TypeUsage.EdmType).TypeUsage.EdmType.Name;
return ((name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase)) ||
(name.Equals("Time", StringComparison.OrdinalIgnoreCase)));
}
case "DAY":
case "MONTH":
case "YEAR":
case "DATALENGTH":
case "CHECKSUM":
{
string name = funParams[0].TypeUsage.EdmType.Name;
return ((name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase)) ||
(name.Equals("Time", StringComparison.OrdinalIgnoreCase)));
}
case "DATEADD":
case "DATEDIFF":
{
string param1Name = funParams[1].TypeUsage.EdmType.Name;
string param2Name = funParams[2].TypeUsage.EdmType.Name;
return ((param1Name.Equals("Time", StringComparison.OrdinalIgnoreCase)) ||
(param2Name.Equals("Time", StringComparison.OrdinalIgnoreCase)) ||
(param1Name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase)) ||
(param2Name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase)));
}
case "DATENAME":
case "DATEPART":
{
string name = funParams[1].TypeUsage.EdmType.Name;
return ((name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase)) ||
(name.Equals("Time", StringComparison.OrdinalIgnoreCase)));
}
case "SYSUTCDATETIME":
case "SYSDATETIME":
case "SYSDATETIMEOFFSET":
return true;
default:
break;
}
return false;
}
private static bool IsYukonOrNewer(EdmFunction edmFunction)
{
ReadOnlyMetadataCollection<FunctionParameter> funParams = edmFunction.Parameters;
if (funParams == null || funParams.Count == 0)
{
return false;
}
switch (edmFunction.Name.ToUpperInvariant())
{
case "COUNT":
case "COUNT_BIG":
{
string name = ((CollectionType)funParams[0].TypeUsage.EdmType).TypeUsage.EdmType.Name;
return name.Equals("Guid", StringComparison.OrdinalIgnoreCase);
}
case "CHARINDEX":
{
foreach (FunctionParameter funParam in funParams)
{
if (funParam.TypeUsage.EdmType.Name.Equals("Int64", StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
}
break;
default:
break;
}
return false;
}
/// <summary>
/// This method takes a type and a set of facets and returns the best mapped equivalent type
/// in EDM.
/// </summary>
/// <param name="storeType">A TypeUsage encapsulating a store type and a set of facets</param>
/// <returns>A TypeUsage encapsulating an EDM type and a set of facets</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
public override TypeUsage GetEdmType(TypeUsage storeType)
{
EntityUtil.CheckArgumentNull<TypeUsage>(storeType, "storeType");
string storeTypeName = storeType.EdmType.Name.ToLowerInvariant();
if (!base.StoreTypeNameToEdmPrimitiveType.ContainsKey(storeTypeName))
{
throw EntityUtil.Argument(Strings.ProviderDoesNotSupportType(storeTypeName));
}
PrimitiveType edmPrimitiveType = base.StoreTypeNameToEdmPrimitiveType[storeTypeName];
int maxLength = 0;
bool isUnicode = true;
bool isFixedLen = false;
bool isUnbounded = true;
PrimitiveTypeKind newPrimitiveTypeKind;
switch (storeTypeName)
{
// for some types we just go with simple type usage with no facets
case "tinyint":
case "smallint":
case "bigint":
case "bit":
case "uniqueidentifier":
case "int":
case "geography":
case "geometry":
return TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType);
case "varchar":
newPrimitiveTypeKind = PrimitiveTypeKind.String;
isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
isUnicode = false;
isFixedLen = false;
break;
case "char":
newPrimitiveTypeKind = PrimitiveTypeKind.String;
isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
isUnicode = false;
isFixedLen = true;
break;
case "nvarchar":
newPrimitiveTypeKind = PrimitiveTypeKind.String;
isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
isUnicode = true;
isFixedLen = false;
break;
case "nchar":
newPrimitiveTypeKind = PrimitiveTypeKind.String;
isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
isUnicode = true;
isFixedLen = true;
break;
case "varchar(max)":
case "text":
newPrimitiveTypeKind = PrimitiveTypeKind.String;
isUnbounded = true;
isUnicode = false;
isFixedLen = false;
break;
case "nvarchar(max)":
case "ntext":
case "xml":
newPrimitiveTypeKind = PrimitiveTypeKind.String;
isUnbounded = true;
isUnicode = true;
isFixedLen = false;
break;
case "binary":
newPrimitiveTypeKind = PrimitiveTypeKind.Binary;
isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
isFixedLen = true;
break;
case "varbinary":
newPrimitiveTypeKind = PrimitiveTypeKind.Binary;
isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
isFixedLen = false;
break;
case "varbinary(max)":
case "image":
newPrimitiveTypeKind = PrimitiveTypeKind.Binary;
isUnbounded = true;
isFixedLen = false;
break;
case "timestamp":
case "rowversion":
return TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, true, 8);
case "float":
case "real":
return TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType);
case "decimal":
case "numeric":
{
byte precision;
byte scale;
if (TypeHelpers.TryGetPrecision(storeType, out precision) && TypeHelpers.TryGetScale(storeType, out scale))
{
return TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType, precision, scale);
}
else
{
return TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType);
}
}
case "money":
return TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType, 19, 4);
case "smallmoney":
return TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType, 10, 4);
case "datetime":
case "datetime2":
case "smalldatetime":
return TypeUsage.CreateDateTimeTypeUsage(edmPrimitiveType, null);
case "date":
return TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType);
case "time":
return TypeUsage.CreateTimeTypeUsage(edmPrimitiveType, null);
case "datetimeoffset":
return TypeUsage.CreateDateTimeOffsetTypeUsage(edmPrimitiveType, null);
default:
throw EntityUtil.NotSupported(Strings.ProviderDoesNotSupportType(storeTypeName));
}
Debug.Assert(newPrimitiveTypeKind == PrimitiveTypeKind.String || newPrimitiveTypeKind == PrimitiveTypeKind.Binary, "at this point only string and binary types should be present");
switch(newPrimitiveTypeKind)
{
case PrimitiveTypeKind.String:
if (!isUnbounded)
{
return TypeUsage.CreateStringTypeUsage(edmPrimitiveType, isUnicode, isFixedLen, maxLength);
}
else
{
return TypeUsage.CreateStringTypeUsage(edmPrimitiveType, isUnicode, isFixedLen);
}
case PrimitiveTypeKind.Binary:
if (!isUnbounded)
{
return TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, isFixedLen, maxLength);
}
else
{
return TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, isFixedLen);
}
default:
throw EntityUtil.NotSupported(Strings.ProviderDoesNotSupportType(storeTypeName));
}
}
/// <summary>
/// This method takes a type and a set of facets and returns the best mapped equivalent type
/// in SQL Server, taking the store version into consideration.
/// </summary>
/// <param name="storeType">A TypeUsage encapsulating an EDM type and a set of facets</param>
/// <returns>A TypeUsage encapsulating a store type and a set of facets</returns>
public override TypeUsage GetStoreType(TypeUsage edmType)
{
EntityUtil.CheckArgumentNull<TypeUsage>(edmType, "edmType");
System.Diagnostics.Debug.Assert(edmType.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType);
PrimitiveType primitiveType = edmType.EdmType as PrimitiveType;
if (primitiveType == null)
{
throw EntityUtil.Argument(Strings.ProviderDoesNotSupportType(edmType.Identity));
}
ReadOnlyMetadataCollection<Facet> facets = edmType.Facets;
switch (primitiveType.PrimitiveTypeKind)
{
case PrimitiveTypeKind.Boolean:
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["bit"]);
case PrimitiveTypeKind.Byte:
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["tinyint"]);
case PrimitiveTypeKind.Int16:
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["smallint"]);
case PrimitiveTypeKind.Int32:
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["int"]);
case PrimitiveTypeKind.Int64:
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["bigint"]);
case PrimitiveTypeKind.Geography:
case PrimitiveTypeKind.GeographyPoint:
case PrimitiveTypeKind.GeographyLineString:
case PrimitiveTypeKind.GeographyPolygon:
case PrimitiveTypeKind.GeographyMultiPoint:
case PrimitiveTypeKind.GeographyMultiLineString:
case PrimitiveTypeKind.GeographyMultiPolygon:
case PrimitiveTypeKind.GeographyCollection:
return GetStorePrimitiveTypeIfPostSql9("geography", edmType.Identity, primitiveType.PrimitiveTypeKind);
case PrimitiveTypeKind.Geometry:
case PrimitiveTypeKind.GeometryPoint:
case PrimitiveTypeKind.GeometryLineString:
case PrimitiveTypeKind.GeometryPolygon:
case PrimitiveTypeKind.GeometryMultiPoint:
case PrimitiveTypeKind.GeometryMultiLineString:
case PrimitiveTypeKind.GeometryMultiPolygon:
case PrimitiveTypeKind.GeometryCollection:
return GetStorePrimitiveTypeIfPostSql9("geometry", edmType.Identity, primitiveType.PrimitiveTypeKind);
case PrimitiveTypeKind.Guid:
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["uniqueidentifier"]);
case PrimitiveTypeKind.Double:
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["float"]);
case PrimitiveTypeKind.Single:
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["real"]);
case PrimitiveTypeKind.Decimal: // decimal, numeric, smallmoney, money
{
byte precision;
if (!TypeHelpers.TryGetPrecision(edmType, out precision))
{
precision = 18;
}
byte scale;
if (!TypeHelpers.TryGetScale(edmType, out scale))
{
scale = 0;
}
TypeUsage tu = TypeUsage.CreateDecimalTypeUsage(StoreTypeNameToStorePrimitiveType["decimal"], precision, scale);
return tu;
}
case PrimitiveTypeKind.Binary: // binary, varbinary, varbinary(max), image, timestamp, rowversion
{
bool isFixedLength = null != facets[DbProviderManifest.FixedLengthFacetName].Value && (bool)facets[DbProviderManifest.FixedLengthFacetName].Value;
Facet f = facets[DbProviderManifest.MaxLengthFacetName];
bool isMaxLength = Helper.IsUnboundedFacetValue(f) || null == f.Value || (int)f.Value > binaryMaxSize;
int maxLength = !isMaxLength ? (int)f.Value : Int32.MinValue;
TypeUsage tu;
if (isFixedLength)
{
tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["binary"], true, (isMaxLength ? binaryMaxSize : maxLength));
}
else
{
if (isMaxLength)
{
if (_version != SqlVersion.Sql8)
{
tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["varbinary(max)"], false);
Debug.Assert(tu.Facets[DbProviderManifest.MaxLengthFacetName].Description.IsConstant, "varbinary(max) is not constant!");
}
else
{
tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["varbinary"], false, binaryMaxSize);
}
}
else
{
tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["varbinary"], false, maxLength);
}
}
return tu;
}
case PrimitiveTypeKind.String:
// char, nchar, varchar, nvarchar, varchar(max), nvarchar(max), ntext, text, xml
{
bool isUnicode = null == facets[DbProviderManifest.UnicodeFacetName].Value || (bool)facets[DbProviderManifest.UnicodeFacetName].Value;
bool isFixedLength = null != facets[DbProviderManifest.FixedLengthFacetName].Value && (bool)facets[DbProviderManifest.FixedLengthFacetName].Value;
Facet f = facets[DbProviderManifest.MaxLengthFacetName];
// maxlen is true if facet value is unbounded, the value is bigger than the limited string sizes *or* the facet
// value is null. this is needed since functions still have maxlength facet value as null
bool isMaxLength = Helper.IsUnboundedFacetValue(f) || null == f.Value || (int)f.Value > (isUnicode ? nvarcharMaxSize : varcharMaxSize);
int maxLength = !isMaxLength ? (int)f.Value : Int32.MinValue;
TypeUsage tu;
if (isUnicode)
{
if (isFixedLength)
{
tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["nchar"], true, true, (isMaxLength ? nvarcharMaxSize : maxLength));
}
else
{
if (isMaxLength)
{
// nvarchar(max) (SQL 9) or ntext (SQL 8)
if (_version != SqlVersion.Sql8)
{
tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["nvarchar(max)"], true, false);
Debug.Assert(tu.Facets[DbProviderManifest.MaxLengthFacetName].Description.IsConstant, "NVarchar(max) is not constant!");
}
else
{
// if it is unknown, fallback to nvarchar[4000] instead of ntext since it has limited store semantics
tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["nvarchar"], true, false, nvarcharMaxSize);
}
}
else
{
tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["nvarchar"], true, false, maxLength);
}
}
}
else // !isUnicode
{
if (isFixedLength)
{
tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["char"], false, true,
(isMaxLength ? varcharMaxSize : maxLength));
}
else
{
if (isMaxLength)
{
// nvarchar(max) (SQL 9) or ntext (SQL 8)
if (_version != SqlVersion.Sql8)
{
tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["varchar(max)"], false, false);
Debug.Assert(tu.Facets[DbProviderManifest.MaxLengthFacetName].Description.IsConstant, "varchar(max) is not constant!");
}
else
{
// if it is unknown, fallback to varchar[8000] instead of text since it has limited store semantics
tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["varchar"], false, false, varcharMaxSize);
}
}
else
{
tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["varchar"], false, false, maxLength);
}
}
}
return tu;
}
case PrimitiveTypeKind.DateTime:
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["datetime"]);
case PrimitiveTypeKind.DateTimeOffset:
return GetStorePrimitiveTypeIfPostSql9("datetimeoffset", edmType.Identity, primitiveType.PrimitiveTypeKind);
case PrimitiveTypeKind.Time:
return GetStorePrimitiveTypeIfPostSql9("time", edmType.Identity, primitiveType.PrimitiveTypeKind);
default:
throw EntityUtil.NotSupported(Strings.NoStoreTypeForEdmType(edmType.Identity, primitiveType.PrimitiveTypeKind));
}
}
private TypeUsage GetStorePrimitiveTypeIfPostSql9(string storeTypeName, string edmTypeIdentity, PrimitiveTypeKind primitiveTypeKind)
{
if ((this.SqlVersion != SqlVersion.Sql8) && (this.SqlVersion != SqlVersion.Sql9))
{
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType[storeTypeName]);
}
else
{
throw EntityUtil.NotSupported(Strings.NoStoreTypeForEdmType(edmTypeIdentity, primitiveTypeKind));
}
}
/// <summary>
/// Returns true, SqlClient supports escaping strings to be used as arguments to like
/// The escape character is '~'
/// </summary>
/// <param name="escapeCharacter">The character '~'</param>
/// <returns>True</returns>
public override bool SupportsEscapingLikeArgument(out char escapeCharacter)
{
escapeCharacter = SqlProviderManifest.LikeEscapeChar;
return true;
}
/// <summary>
/// Escapes the wildcard characters and the escape character in the given argument.
/// </summary>
/// <param name="argument"></param>
/// <returns>Equivalent to the argument, with the wildcard characters and the escape character escaped</returns>
public override string EscapeLikeArgument(string argument)
{
EntityUtil.CheckArgumentNull(argument, "argument");
bool usedEscapeCharacter;
return SqlProviderManifest.EscapeLikeText(argument, true, out usedEscapeCharacter);
}
#endregion
}
}
|