mirror of
https://bitbucket.org/anguist/ntpa
synced 2026-10-01 06:51:19 +00:00
343 lines
13 KiB
C#
343 lines
13 KiB
C#
// Copyright © 2008, 2014, Oracle and/or its affiliates. All rights reserved.
|
|
//
|
|
// MySQL Connector/NET is licensed under the terms of the GPLv2
|
|
// <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
|
|
// MySQL Connectors. There are special exceptions to the terms and
|
|
// conditions of the GPLv2 as it is applied to this software, see the
|
|
// FLOSS License Exception
|
|
// <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published
|
|
// by the Free Software Foundation; version 2 of the License.
|
|
//
|
|
// This program is distributed in the hope that it will be useful, but
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
// for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along
|
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
|
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Data;
|
|
using System.Xml;
|
|
using System.Data.Common;
|
|
using System.Diagnostics;
|
|
using MySql.Data.Entity.Properties;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
#if EF6
|
|
using System.Data.Entity.Core;
|
|
using System.Data.Entity.Core.Common;
|
|
using System.Data.Entity.Core.Metadata.Edm;
|
|
#else
|
|
using System.Data.Metadata.Edm;
|
|
#endif
|
|
|
|
|
|
namespace MySql.Data.MySqlClient
|
|
{
|
|
internal class MySqlProviderManifest : DbXmlEnabledProviderManifest
|
|
{
|
|
string manifestToken;
|
|
|
|
internal const char LikeEscapeChar = '\u005c';
|
|
internal const string LikeEscapeCharToString = "\u005c";
|
|
|
|
public MySqlProviderManifest(string version)
|
|
: base(GetManifest())
|
|
{
|
|
manifestToken = version;
|
|
}
|
|
|
|
private static XmlReader GetManifest()
|
|
{
|
|
return GetXmlResource("MySql.Data.Entity.Properties.ProviderManifest.xml");
|
|
}
|
|
|
|
protected override XmlReader GetDbInformation(string informationType)
|
|
{
|
|
if (informationType == DbProviderManifest.StoreSchemaDefinition)
|
|
{
|
|
return GetStoreSchemaDescription();
|
|
}
|
|
|
|
if (informationType == DbProviderManifest.StoreSchemaMapping)
|
|
{
|
|
return GetStoreSchemaMapping();
|
|
}
|
|
|
|
throw new ProviderIncompatibleException(String.Format("The provider returned null for the informationType '{0}'.", informationType));
|
|
}
|
|
|
|
private XmlReader GetStoreSchemaMapping()
|
|
{
|
|
return GetMappingResource("SchemaMapping.msl");
|
|
}
|
|
|
|
private XmlReader GetStoreSchemaDescription()
|
|
{
|
|
double version = double.Parse(manifestToken, CultureInfo.InvariantCulture);
|
|
|
|
if (version < 5.0) throw new NotSupportedException("Your version of MySQL is not currently supported");
|
|
if (version < 5.1) return GetMappingResource("SchemaDefinition-5.0.ssdl");
|
|
if (version < 5.5) return GetMappingResource("SchemaDefinition-5.1.ssdl");
|
|
if (version < 5.6) return GetMappingResource("SchemaDefinition-5.5.ssdl");
|
|
if (version < 5.7) return GetMappingResource("SchemaDefinition-5.6.ssdl");
|
|
return GetMappingResource("SchemaDefinition-5.7.ssdl");
|
|
}
|
|
|
|
public override TypeUsage GetEdmType(TypeUsage storeType)
|
|
{
|
|
if (storeType == null)
|
|
{
|
|
throw new ArgumentNullException("storeType");
|
|
}
|
|
|
|
string storeTypeName = storeType.EdmType.Name.ToLowerInvariant();
|
|
|
|
if (!base.StoreTypeNameToEdmPrimitiveType.ContainsKey(storeTypeName))
|
|
{
|
|
throw new ArgumentException(String.Format("The underlying provider does not support the type '{0}'.", storeTypeName));
|
|
}
|
|
|
|
PrimitiveType edmPrimitiveType = base.StoreTypeNameToEdmPrimitiveType[storeTypeName];
|
|
|
|
if (edmPrimitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Binary)
|
|
{
|
|
return TypeUsage.CreateBinaryTypeUsage(edmPrimitiveType, false);
|
|
}
|
|
|
|
if (edmPrimitiveType.PrimitiveTypeKind == PrimitiveTypeKind.String)
|
|
{
|
|
Facet facet;
|
|
if (storeType.Facets.TryGetValue("MaxLength", false, out facet) && !facet.IsUnbounded && facet.Value != null)
|
|
return TypeUsage.CreateStringTypeUsage(edmPrimitiveType, false, false, (int)facet.Value);
|
|
else
|
|
return TypeUsage.CreateStringTypeUsage(edmPrimitiveType, false, false);
|
|
}
|
|
|
|
return TypeUsage.CreateDefaultTypeUsage(edmPrimitiveType);
|
|
}
|
|
|
|
private const int CHAR_MAXLEN = 255;
|
|
private const int VARCHAR_MAXLEN = 65535;
|
|
private const int MEDIUMTEXT_MAXLEN = 16777215;
|
|
private const int LONGTEXT_MAXLEN = 1073741823;
|
|
|
|
private const int BINARY_MAXLEN = 255;
|
|
private const int VARBINARY_MAXLEN = 65535;
|
|
private const int MEDIUMBLOB_MAXLEN = 16777215;
|
|
private const int LONGBLOB_MAXLEN = 2147483647;
|
|
|
|
internal const int DEFAULT_DECIMAL_PRECISION = 10;
|
|
internal const int DEFAULT_DECIMAL_SCALE = 2;
|
|
|
|
public override TypeUsage GetStoreType(TypeUsage edmType)
|
|
{
|
|
if (edmType == null)
|
|
throw new ArgumentNullException("edmType");
|
|
|
|
Debug.Assert(edmType.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType);
|
|
|
|
PrimitiveType primitiveType = edmType.EdmType as PrimitiveType;
|
|
if (primitiveType == null)
|
|
throw new ArgumentException(String.Format(Resources.TypeNotSupported, edmType));
|
|
|
|
ReadOnlyMetadataCollection<Facet> facets = edmType.Facets;
|
|
|
|
switch (primitiveType.PrimitiveTypeKind)
|
|
{
|
|
case PrimitiveTypeKind.Boolean:
|
|
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["bool"]);
|
|
|
|
case PrimitiveTypeKind.Byte:
|
|
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["utinyint"]);
|
|
|
|
case PrimitiveTypeKind.SByte:
|
|
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.Guid:
|
|
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["guid"]);
|
|
|
|
case PrimitiveTypeKind.Double:
|
|
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["double"]);
|
|
|
|
case PrimitiveTypeKind.Single:
|
|
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["float"]);
|
|
|
|
case PrimitiveTypeKind.Decimal:
|
|
{
|
|
byte precision = DEFAULT_DECIMAL_PRECISION;
|
|
byte scale = DEFAULT_DECIMAL_SCALE;
|
|
Facet facet;
|
|
|
|
if (edmType.Facets.TryGetValue("Precision", false, out facet))
|
|
{
|
|
if (!facet.IsUnbounded && facet.Value != null)
|
|
precision = (byte)facet.Value;
|
|
}
|
|
|
|
if (edmType.Facets.TryGetValue("Scale", false, out facet))
|
|
{
|
|
if (!facet.IsUnbounded && facet.Value != null )
|
|
scale = (byte)facet.Value;
|
|
}
|
|
|
|
return TypeUsage.CreateDecimalTypeUsage(StoreTypeNameToStorePrimitiveType["decimal"], precision, scale);
|
|
}
|
|
|
|
case PrimitiveTypeKind.Binary:
|
|
{
|
|
bool isFixedLength = null != facets["FixedLength"].Value && (bool)facets["FixedLength"].Value;
|
|
Facet f = facets["MaxLength"];
|
|
bool isMaxLength = f.IsUnbounded || null == f.Value || (int)f.Value > MEDIUMBLOB_MAXLEN;
|
|
int maxLength = !isMaxLength ? (int)f.Value : LONGBLOB_MAXLEN;
|
|
|
|
string typeName = String.Empty;
|
|
|
|
// now this applies for both isFixedLength and !isFixedLength
|
|
if (maxLength < CHAR_MAXLEN) typeName = "tinyblob";
|
|
else if (maxLength < MEDIUMBLOB_MAXLEN) typeName = "blob";
|
|
else if (maxLength < LONGTEXT_MAXLEN) typeName = "mediumblob";
|
|
else typeName = "longblob";
|
|
|
|
return TypeUsage.CreateBinaryTypeUsage(StoreTypeNameToStorePrimitiveType[typeName], isFixedLength, maxLength);
|
|
}
|
|
|
|
case PrimitiveTypeKind.String:
|
|
{
|
|
string typeName = String.Empty;
|
|
bool isUnicode = null != facets["Unicode"].Value && (bool)facets["Unicode"].Value;
|
|
bool isFixedLength = null != facets["FixedLength"].Value && (bool)facets["FixedLength"].Value;
|
|
int maxLenghtValue;
|
|
|
|
Facet maxLengthFacet = facets["MaxLength"];
|
|
if (isFixedLength)
|
|
{
|
|
typeName = isUnicode ? "nchar" : "char";
|
|
if (maxLengthFacet.Value != null && Int32.TryParse(maxLengthFacet.Value.ToString(), out maxLenghtValue) && maxLenghtValue <= CHAR_MAXLEN)
|
|
return TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType[typeName], isUnicode, isFixedLength, (int)maxLengthFacet.Value);
|
|
else if (maxLengthFacet.Value != null && maxLengthFacet.Value.ToString() == "Max")
|
|
return TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType[typeName], isUnicode, isFixedLength, CHAR_MAXLEN);
|
|
else
|
|
return TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType[typeName], isUnicode, isFixedLength);
|
|
}
|
|
else
|
|
{
|
|
typeName = isUnicode ? "nvarchar" : "varchar";
|
|
if (maxLengthFacet.Value != null && Int32.TryParse(maxLengthFacet.Value.ToString(), out maxLenghtValue))
|
|
{
|
|
if (maxLenghtValue > VARCHAR_MAXLEN && maxLenghtValue <= MEDIUMTEXT_MAXLEN) typeName = "mediumtext";
|
|
else if ((int)maxLengthFacet.Value > MEDIUMTEXT_MAXLEN) typeName = "longtext";
|
|
return TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType[typeName], isUnicode, isFixedLength, (int)maxLengthFacet.Value);
|
|
}
|
|
else
|
|
return TypeUsage.CreateStringTypeUsage(StoreTypeNameToStorePrimitiveType["longtext"], isUnicode, isFixedLength, LONGBLOB_MAXLEN);
|
|
}
|
|
}
|
|
|
|
case PrimitiveTypeKind.DateTimeOffset:
|
|
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["timestamp"]);
|
|
case PrimitiveTypeKind.DateTime:
|
|
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["datetime"]);
|
|
case PrimitiveTypeKind.Time:
|
|
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["time"]);
|
|
#if NET_45_OR_GREATER
|
|
case PrimitiveTypeKind.Geometry:
|
|
return TypeUsage.CreateDefaultTypeUsage(StoreTypeNameToStorePrimitiveType["geometry"]);
|
|
#endif
|
|
default:
|
|
throw new NotSupportedException(String.Format(Resources.NoStoreTypeForEdmType, edmType, primitiveType.PrimitiveTypeKind));
|
|
}
|
|
}
|
|
|
|
private static XmlReader GetXmlResource(string resourceName)
|
|
{
|
|
Assembly executingAssembly = Assembly.GetExecutingAssembly();
|
|
Stream stream = executingAssembly.GetManifestResourceStream(resourceName);
|
|
return XmlReader.Create(stream);
|
|
}
|
|
|
|
private static XmlReader GetMappingResource(string resourceBaseName)
|
|
{
|
|
string rez = GetResourceAsString(
|
|
String.Format("MySql.Data.Entity.Properties.{0}", resourceBaseName));
|
|
|
|
StringReader sr = new StringReader(rez);
|
|
return XmlReader.Create(sr);
|
|
|
|
}
|
|
|
|
private static string GetResourceAsString(string resourceName)
|
|
{
|
|
Assembly executingAssembly = Assembly.GetExecutingAssembly();
|
|
Stream s = executingAssembly.GetManifestResourceStream(resourceName);
|
|
StreamReader sr = new StreamReader(s);
|
|
string resourceAsString = sr.ReadToEnd();
|
|
sr.Close();
|
|
s.Close();
|
|
return resourceAsString;
|
|
}
|
|
|
|
#if NET_40_OR_GREATER
|
|
public override bool SupportsEscapingLikeArgument(out char escapeCharacter)
|
|
{
|
|
escapeCharacter = LikeEscapeChar;
|
|
return true;
|
|
}
|
|
|
|
public override string EscapeLikeArgument(string argument)
|
|
{
|
|
|
|
bool usedEscapeCharacter;
|
|
return EscapeLikeArgument(argument, out usedEscapeCharacter);
|
|
}
|
|
#endif
|
|
|
|
internal static string EscapeLikeArgument(string argument, out bool usedEscapeChar)
|
|
{
|
|
usedEscapeChar = false;
|
|
if (argument == null)
|
|
return string.Empty;
|
|
|
|
if (!(argument.Contains("%") || argument.Contains("_") || argument.Contains(LikeEscapeCharToString)))
|
|
{
|
|
return argument;
|
|
}
|
|
var sb = new StringBuilder(argument.Length);
|
|
foreach (var c in argument)
|
|
{
|
|
if (c == '%' || c == '_' || c == LikeEscapeChar)
|
|
{
|
|
sb.Append(LikeEscapeChar);
|
|
usedEscapeChar = true;
|
|
}
|
|
sb.Append(c);
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
|
|
#if EF6
|
|
public override bool SupportsInExpression()
|
|
{
|
|
return true;
|
|
}
|
|
#endif
|
|
}
|
|
}
|