1 //---------------------------------------------------------------------
2 // <copyright file="SqlProviderManifest.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
8 //---------------------------------------------------------------------
10 using System.Collections.Generic;
11 using System.Data.Common;
12 using System.Data.Entity;
13 using System.Data.Metadata.Edm;
14 using System.Diagnostics;
19 namespace System.Data.SqlClient
22 /// The Provider Manifest for SQL Server
24 internal class SqlProviderManifest : DbXmlEnabledProviderManifest
26 internal const string TokenSql8 = "2000";
27 internal const string TokenSql9 = "2005";
28 internal const string TokenSql10 = "2008";
30 // '~' is the same escape character that L2S uses
31 internal const char LikeEscapeChar = '~';
32 internal const string LikeEscapeCharToString = "~";
34 #region Private Fields
36 // Default to SQL Server 2005 (9.0)
37 private SqlVersion _version = SqlVersion.Sql9;
40 /// maximum size of sql server unicode
42 private const int varcharMaxSize = 8000;
43 private const int nvarcharMaxSize = 4000;
44 private const int binaryMaxSize = 8000;
46 private System.Collections.ObjectModel.ReadOnlyCollection<PrimitiveType> _primitiveTypes = null;
47 private System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> _functions = null;
56 /// <param name="manifestToken">A token used to infer the capabilities of the store</param>
57 public SqlProviderManifest(string manifestToken)
58 : base(SqlProviderManifest.GetProviderManifest())
60 // GetSqlVersion will throw ArgumentException if manifestToken is null, empty, or not recognized.
61 _version = SqlVersionUtils.GetSqlVersion(manifestToken);
69 internal SqlVersion SqlVersion
71 get { return this._version; }
76 #region Private Methods
77 private static XmlReader GetProviderManifest()
79 return DbProviderServices.GetXmlResource("System.Data.Resources.SqlClient.SqlProviderServices.ProviderManifest.xml");
82 private XmlReader GetStoreSchemaMapping(string mslName)
84 return DbProviderServices.GetXmlResource("System.Data.Resources.SqlClient.SqlProviderServices." + mslName + ".msl");
87 private XmlReader GetStoreSchemaDescription(string ssdlName)
89 if (this._version == SqlVersion.Sql8)
91 return DbProviderServices.GetXmlResource("System.Data.Resources.SqlClient.SqlProviderServices." + ssdlName + "_Sql8.ssdl");
94 return DbProviderServices.GetXmlResource("System.Data.Resources.SqlClient.SqlProviderServices." + ssdlName + ".ssdl");
98 #region Internal Methods
101 /// Function to detect wildcard characters %, _, [ and ^ and escape them with a preceding ~
102 /// This escaping is used when StartsWith, EndsWith and Contains canonical and CLR functions
103 /// are translated to their equivalent LIKE expression
104 /// NOTE: This code has been copied from LinqToSql
106 /// <param name="text">Original input as specified by the user</param>
107 /// <param name="alwaysEscapeEscapeChar">escape the escape character ~ regardless whether wildcard
108 /// characters were encountered </param>
109 /// <param name="usedEscapeChar">true if the escaping was performed, false if no escaping was required</param>
110 /// <returns>The escaped string that can be used as pattern in a LIKE expression</returns>
111 internal static string EscapeLikeText(string text, bool alwaysEscapeEscapeChar, out bool usedEscapeChar)
113 usedEscapeChar = false;
114 if (!(text.Contains("%") || text.Contains("_") || text.Contains("[")
115 || text.Contains("^") || alwaysEscapeEscapeChar && text.Contains(LikeEscapeCharToString)))
119 StringBuilder sb = new StringBuilder(text.Length);
120 foreach (char c in text)
122 if (c == '%' || c == '_' || c == '[' || c == '^' || c == LikeEscapeChar)
124 sb.Append(LikeEscapeChar);
125 usedEscapeChar = true;
129 return sb.ToString();
135 /// Providers should override this to return information specific to their provider.
137 /// This method should never return null.
139 /// <param name="informationType">The name of the information to be retrieved.</param>
140 /// <returns>An XmlReader at the begining of the information requested.</returns>
141 protected override XmlReader GetDbInformation(string informationType)
143 if (informationType == DbProviderManifest.StoreSchemaDefinitionVersion3 ||
144 informationType == DbProviderManifest.StoreSchemaDefinition)
146 return GetStoreSchemaDescription(informationType);
149 if (informationType == DbProviderManifest.StoreSchemaMappingVersion3 ||
150 informationType == DbProviderManifest.StoreSchemaMapping)
152 return GetStoreSchemaMapping(informationType);
155 // Use default Conceptual Schema Definition
156 if (informationType == DbProviderManifest.ConceptualSchemaDefinitionVersion3 ||
157 informationType == DbProviderManifest.ConceptualSchemaDefinition)
162 throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.ProviderReturnedNullForGetDbInformation(informationType));
165 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
166 public override System.Collections.ObjectModel.ReadOnlyCollection<PrimitiveType> GetStoreTypes()
168 if (this._primitiveTypes == null)
170 if (this._version == SqlVersion.Sql10)
172 this._primitiveTypes = base.GetStoreTypes();
176 List<PrimitiveType> primitiveTypes = new List<PrimitiveType>(base.GetStoreTypes());
177 Debug.Assert((this._version == SqlVersion.Sql8) || (this._version == SqlVersion.Sql9), "Found verion other than Sql 8, 9 or 10");
178 //Remove the Katmai types for both Sql8 and Sql9
179 primitiveTypes.RemoveAll(new Predicate<PrimitiveType>(
180 delegate(PrimitiveType primitiveType)
182 string name = primitiveType.Name.ToLowerInvariant();
183 return name.Equals("time", StringComparison.Ordinal) ||
184 name.Equals("date", StringComparison.Ordinal) ||
185 name.Equals("datetime2", StringComparison.Ordinal) ||
186 name.Equals("datetimeoffset", StringComparison.Ordinal) ||
187 name.Equals("geography", StringComparison.Ordinal) ||
188 name.Equals("geometry", StringComparison.Ordinal);
192 //Remove the types that won't work in Sql8
193 if (this._version == SqlVersion.Sql8) {
195 // SQLBUDT 550667 and 551271: Remove xml and 'max' types for SQL Server 2000
196 primitiveTypes.RemoveAll(new Predicate<PrimitiveType>(
197 delegate(PrimitiveType primitiveType)
199 string name = primitiveType.Name.ToLowerInvariant();
200 return name.Equals("xml", StringComparison.Ordinal) || name.EndsWith("(max)", StringComparison.Ordinal);
205 this._primitiveTypes = primitiveTypes.AsReadOnly();
209 return this._primitiveTypes;
212 public override System.Collections.ObjectModel.ReadOnlyCollection<EdmFunction> GetStoreFunctions()
214 if (this._functions == null)
216 if (this._version == SqlVersion.Sql10)
218 this._functions = base.GetStoreFunctions();
222 //Remove the functions over katmai types from both Sql 9 and Sql 8.
223 IEnumerable<EdmFunction> functions = base.GetStoreFunctions().Where(f => !IsKatmaiOrNewer(f));
224 if(this._version == SqlVersion.Sql8)
226 // SQLBUDT 550998: Remove unsupported overloads from Provider Manifest on SQL 8.0
227 functions = functions.Where(f => !IsYukonOrNewer(f));
229 this._functions = functions.ToList().AsReadOnly();
233 return this._functions;
236 private static bool IsKatmaiOrNewer(EdmFunction edmFunction)
238 // Spatial types are only supported from Katmai onward; any functions using them must therefore also be Katmai or newer.
239 if ((edmFunction.ReturnParameter != null && Helper.IsSpatialType(edmFunction.ReturnParameter.TypeUsage)) ||
240 edmFunction.Parameters.Any(p => Helper.IsSpatialType(p.TypeUsage)))
245 ReadOnlyMetadataCollection<FunctionParameter> funParams = edmFunction.Parameters;
246 switch (edmFunction.Name.ToUpperInvariant())
253 string name = ((CollectionType)funParams[0].TypeUsage.EdmType).TypeUsage.EdmType.Name;
254 return ((name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase)) ||
255 (name.Equals("Time", StringComparison.OrdinalIgnoreCase)));
264 string name = funParams[0].TypeUsage.EdmType.Name;
265 return ((name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase)) ||
266 (name.Equals("Time", StringComparison.OrdinalIgnoreCase)));
272 string param1Name = funParams[1].TypeUsage.EdmType.Name;
273 string param2Name = funParams[2].TypeUsage.EdmType.Name;
274 return ((param1Name.Equals("Time", StringComparison.OrdinalIgnoreCase)) ||
275 (param2Name.Equals("Time", StringComparison.OrdinalIgnoreCase)) ||
276 (param1Name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase)) ||
277 (param2Name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase)));
282 string name = funParams[1].TypeUsage.EdmType.Name;
283 return ((name.Equals("DateTimeOffset", StringComparison.OrdinalIgnoreCase)) ||
284 (name.Equals("Time", StringComparison.OrdinalIgnoreCase)));
286 case "SYSUTCDATETIME":
288 case "SYSDATETIMEOFFSET":
297 private static bool IsYukonOrNewer(EdmFunction edmFunction)
299 ReadOnlyMetadataCollection<FunctionParameter> funParams = edmFunction.Parameters;
300 if (funParams == null || funParams.Count == 0)
305 switch (edmFunction.Name.ToUpperInvariant())
310 string name = ((CollectionType)funParams[0].TypeUsage.EdmType).TypeUsage.EdmType.Name;
311 return name.Equals("Guid", StringComparison.OrdinalIgnoreCase);
316 foreach (FunctionParameter funParam in funParams)
318 if (funParam.TypeUsage.EdmType.Name.Equals("Int64", StringComparison.OrdinalIgnoreCase))
334 /// This method takes a type and a set of facets and returns the best mapped equivalent type
337 /// <param name="storeType">A TypeUsage encapsulating a store type and a set of facets</param>
338 /// <returns>A TypeUsage encapsulating an EDM type and a set of facets</returns>
339 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")]
340 public override TypeUsage GetEdmType(TypeUsage storeType)
342 EntityUtil.CheckArgumentNull<TypeUsage>(storeType, "storeType");
344 string storeTypeName = storeType.EdmType.Name.ToLowerInvariant();
345 if (!base.StoreTypeNameToEdmPrimitiveType.ContainsKey(storeTypeName))
347 throw EntityUtil.Argument(Strings.ProviderDoesNotSupportType(storeTypeName));
350 PrimitiveType edmPrimitiveType = base.StoreTypeNameToEdmPrimitiveType[storeTypeName];
353 bool isUnicode = true;
354 bool isFixedLen = false;
355 bool isUnbounded = true;
357 PrimitiveTypeKind newPrimitiveTypeKind;
359 switch (storeTypeName)
361 // for some types we just go with simple type usage with no facets
366 case "uniqueidentifier":
370 return TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType);
373 newPrimitiveTypeKind = PrimitiveTypeKind.String;
374 isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
380 newPrimitiveTypeKind = PrimitiveTypeKind.String;
381 isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
387 newPrimitiveTypeKind = PrimitiveTypeKind.String;
388 isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
394 newPrimitiveTypeKind = PrimitiveTypeKind.String;
395 isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
402 newPrimitiveTypeKind = PrimitiveTypeKind.String;
408 case "nvarchar(max)":
411 newPrimitiveTypeKind = PrimitiveTypeKind.String;
418 newPrimitiveTypeKind = PrimitiveTypeKind.Binary;
419 isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
424 newPrimitiveTypeKind = PrimitiveTypeKind.Binary;
425 isUnbounded = !TypeHelpers.TryGetMaxLength(storeType, out maxLength);
429 case "varbinary(max)":
431 newPrimitiveTypeKind = PrimitiveTypeKind.Binary;
438 return TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, true, 8);
442 return TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType);
449 if (TypeHelpers.TryGetPrecision(storeType, out precision) && TypeHelpers.TryGetScale(storeType, out scale))
451 return TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType, precision, scale);
455 return TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType);
460 return TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType, 19, 4);
463 return TypeUsage.CreateDecimalTypeUsage(edmPrimitiveType, 10, 4);
467 case "smalldatetime":
468 return TypeUsage.CreateDateTimeTypeUsage(edmPrimitiveType, null);
470 return TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType);
472 return TypeUsage.CreateTimeTypeUsage(edmPrimitiveType, null);
473 case "datetimeoffset":
474 return TypeUsage.CreateDateTimeOffsetTypeUsage(edmPrimitiveType, null);
477 throw EntityUtil.NotSupported(Strings.ProviderDoesNotSupportType(storeTypeName));
480 Debug.Assert(newPrimitiveTypeKind == PrimitiveTypeKind.String || newPrimitiveTypeKind == PrimitiveTypeKind.Binary, "at this point only string and binary types should be present");
482 switch(newPrimitiveTypeKind)
484 case PrimitiveTypeKind.String:
487 return TypeUsage.CreateStringTypeUsage(edmPrimitiveType, isUnicode, isFixedLen, maxLength);
491 return TypeUsage.CreateStringTypeUsage(edmPrimitiveType, isUnicode, isFixedLen);
493 case PrimitiveTypeKind.Binary:
496 return TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, isFixedLen, maxLength);
500 return TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, isFixedLen);
503 throw EntityUtil.NotSupported(Strings.ProviderDoesNotSupportType(storeTypeName));
508 /// This method takes a type and a set of facets and returns the best mapped equivalent type
509 /// in SQL Server, taking the store version into consideration.
511 /// <param name="storeType">A TypeUsage encapsulating an EDM type and a set of facets</param>
512 /// <returns>A TypeUsage encapsulating a store type and a set of facets</returns>
513 public override TypeUsage GetStoreType(TypeUsage edmType)
515 EntityUtil.CheckArgumentNull<TypeUsage>(edmType, "edmType");
516 System.Diagnostics.Debug.Assert(edmType.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType);
518 PrimitiveType primitiveType = edmType.EdmType as PrimitiveType;
519 if (primitiveType == null)
521 throw EntityUtil.Argument(Strings.ProviderDoesNotSupportType(edmType.Identity));
524 ReadOnlyMetadataCollection<Facet> facets = edmType.Facets;
526 switch (primitiveType.PrimitiveTypeKind)
528 case PrimitiveTypeKind.Boolean:
529 return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["bit"]);
531 case PrimitiveTypeKind.Byte:
532 return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["tinyint"]);
534 case PrimitiveTypeKind.Int16:
535 return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["smallint"]);
537 case PrimitiveTypeKind.Int32:
538 return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["int"]);
540 case PrimitiveTypeKind.Int64:
541 return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["bigint"]);
543 case PrimitiveTypeKind.Geography:
544 case PrimitiveTypeKind.GeographyPoint:
545 case PrimitiveTypeKind.GeographyLineString:
546 case PrimitiveTypeKind.GeographyPolygon:
547 case PrimitiveTypeKind.GeographyMultiPoint:
548 case PrimitiveTypeKind.GeographyMultiLineString:
549 case PrimitiveTypeKind.GeographyMultiPolygon:
550 case PrimitiveTypeKind.GeographyCollection:
551 return GetStorePrimitiveTypeIfPostSql9("geography", edmType.Identity, primitiveType.PrimitiveTypeKind);
553 case PrimitiveTypeKind.Geometry:
554 case PrimitiveTypeKind.GeometryPoint:
555 case PrimitiveTypeKind.GeometryLineString:
556 case PrimitiveTypeKind.GeometryPolygon:
557 case PrimitiveTypeKind.GeometryMultiPoint:
558 case PrimitiveTypeKind.GeometryMultiLineString:
559 case PrimitiveTypeKind.GeometryMultiPolygon:
560 case PrimitiveTypeKind.GeometryCollection:
561 return GetStorePrimitiveTypeIfPostSql9("geometry", edmType.Identity, primitiveType.PrimitiveTypeKind);
563 case PrimitiveTypeKind.Guid:
564 return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["uniqueidentifier"]);
566 case PrimitiveTypeKind.Double:
567 return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["float"]);
569 case PrimitiveTypeKind.Single:
570 return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["real"]);
572 case PrimitiveTypeKind.Decimal: // decimal, numeric, smallmoney, money
575 if (!TypeHelpers.TryGetPrecision(edmType, out precision))
581 if (!TypeHelpers.TryGetScale(edmType, out scale))
585 TypeUsage tu = TypeUsage.CreateDecimalTypeUsage(StoreTypeNameToStorePrimitiveType["decimal"], precision, scale);
589 case PrimitiveTypeKind.Binary: // binary, varbinary, varbinary(max), image, timestamp, rowversion
591 bool isFixedLength = null != facets[DbProviderManifest.FixedLengthFacetName].Value && (bool)facets[DbProviderManifest.FixedLengthFacetName].Value;
592 Facet f = facets[DbProviderManifest.MaxLengthFacetName];
593 bool isMaxLength = Helper.IsUnboundedFacetValue(f) || null == f.Value || (int)f.Value > binaryMaxSize;
594 int maxLength = !isMaxLength ? (int)f.Value : Int32.MinValue;
599 tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["binary"], true, (isMaxLength ? binaryMaxSize : maxLength));
605 if (_version != SqlVersion.Sql8)
608 tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["varbinary(max)"], false);
609 Debug.Assert(tu.Facets[DbProviderManifest.MaxLengthFacetName].Description.IsConstant, "varbinary(max) is not constant!");
613 tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["varbinary"], false, binaryMaxSize);
618 tu = TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType["varbinary"], false, maxLength);
624 case PrimitiveTypeKind.String:
625 // char, nchar, varchar, nvarchar, varchar(max), nvarchar(max), ntext, text, xml
627 bool isUnicode = null == facets[DbProviderManifest.UnicodeFacetName].Value || (bool)facets[DbProviderManifest.UnicodeFacetName].Value;
628 bool isFixedLength = null != facets[DbProviderManifest.FixedLengthFacetName].Value && (bool)facets[DbProviderManifest.FixedLengthFacetName].Value;
629 Facet f = facets[DbProviderManifest.MaxLengthFacetName];
630 // maxlen is true if facet value is unbounded, the value is bigger than the limited string sizes *or* the facet
631 // value is null. this is needed since functions still have maxlength facet value as null
632 bool isMaxLength = Helper.IsUnboundedFacetValue(f) || null == f.Value || (int)f.Value > (isUnicode ? nvarcharMaxSize : varcharMaxSize);
633 int maxLength = !isMaxLength ? (int)f.Value : Int32.MinValue;
641 tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["nchar"], true, true, (isMaxLength ? nvarcharMaxSize : maxLength));
647 // nvarchar(max) (SQL 9) or ntext (SQL 8)
648 if (_version != SqlVersion.Sql8)
650 tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["nvarchar(max)"], true, false);
651 Debug.Assert(tu.Facets[DbProviderManifest.MaxLengthFacetName].Description.IsConstant, "NVarchar(max) is not constant!");
655 // if it is unknown, fallback to nvarchar[4000] instead of ntext since it has limited store semantics
656 tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["nvarchar"], true, false, nvarcharMaxSize);
661 tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["nvarchar"], true, false, maxLength);
669 tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["char"], false, true,
670 (isMaxLength ? varcharMaxSize : maxLength));
676 // nvarchar(max) (SQL 9) or ntext (SQL 8)
677 if (_version != SqlVersion.Sql8)
679 tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["varchar(max)"], false, false);
680 Debug.Assert(tu.Facets[DbProviderManifest.MaxLengthFacetName].Description.IsConstant, "varchar(max) is not constant!");
684 // if it is unknown, fallback to varchar[8000] instead of text since it has limited store semantics
685 tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["varchar"], false, false, varcharMaxSize);
690 tu = TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["varchar"], false, false, maxLength);
698 case PrimitiveTypeKind.DateTime:
699 return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["datetime"]);
700 case PrimitiveTypeKind.DateTimeOffset:
701 return GetStorePrimitiveTypeIfPostSql9("datetimeoffset", edmType.Identity, primitiveType.PrimitiveTypeKind);
702 case PrimitiveTypeKind.Time:
703 return GetStorePrimitiveTypeIfPostSql9("time", edmType.Identity, primitiveType.PrimitiveTypeKind);
706 throw EntityUtil.NotSupported(Strings.NoStoreTypeForEdmType(edmType.Identity, primitiveType.PrimitiveTypeKind));
710 private TypeUsage GetStorePrimitiveTypeIfPostSql9(string storeTypeName, string edmTypeIdentity, PrimitiveTypeKind primitiveTypeKind)
712 if ((this.SqlVersion != SqlVersion.Sql8) && (this.SqlVersion != SqlVersion.Sql9))
714 return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType[storeTypeName]);
718 throw EntityUtil.NotSupported(Strings.NoStoreTypeForEdmType(edmTypeIdentity, primitiveTypeKind));
723 /// Returns true, SqlClient supports escaping strings to be used as arguments to like
724 /// The escape character is '~'
726 /// <param name="escapeCharacter">The character '~'</param>
727 /// <returns>True</returns>
728 public override bool SupportsEscapingLikeArgument(out char escapeCharacter)
730 escapeCharacter = SqlProviderManifest.LikeEscapeChar;
735 /// Escapes the wildcard characters and the escape character in the given argument.
737 /// <param name="argument"></param>
738 /// <returns>Equivalent to the argument, with the wildcard characters and the escape character escaped</returns>
739 public override string EscapeLikeArgument(string argument)
741 EntityUtil.CheckArgumentNull(argument, "argument");
743 bool usedEscapeCharacter;
744 return SqlProviderManifest.EscapeLikeText(argument, true, out usedEscapeCharacter);