You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

359 lines
12 KiB

4 years ago
  1. #if MYSQL_6_10
  2. // Copyright ?2004, 2018, Oracle and/or its affiliates. All rights reserved.
  3. //
  4. // MySQL Connector/NET is licensed under the terms of the GPLv2
  5. // <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
  6. // MySQL Connectors. There are special exceptions to the terms and
  7. // conditions of the GPLv2 as it is applied to this software, see the
  8. // FLOSS License Exception
  9. // <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
  10. //
  11. // This program is free software; you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published
  13. // by the Free Software Foundation; version 2 of the License.
  14. //
  15. // This program is distributed in the hope that it will be useful, but
  16. // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  18. // for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License along
  21. // with this program; if not, write to the Free Software Foundation, Inc.,
  22. // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  23. using System;
  24. using System.Collections.Generic;
  25. using System.Text;
  26. using System.Text.RegularExpressions;
  27. using Externals.MySql.Data.Common;
  28. using Externals.MySql.Data.Types;
  29. using System.Security;
  30. namespace Externals.MySql.Data.MySqlClient
  31. {
  32. [Flags]
  33. internal enum ColumnFlags : int
  34. {
  35. NOT_NULL = 1,
  36. PRIMARY_KEY = 2,
  37. UNIQUE_KEY = 4,
  38. MULTIPLE_KEY = 8,
  39. BLOB = 16,
  40. UNSIGNED = 32,
  41. ZERO_FILL = 64,
  42. BINARY = 128,
  43. ENUM = 256,
  44. AUTO_INCREMENT = 512,
  45. TIMESTAMP = 1024,
  46. SET = 2048,
  47. NUMBER = 32768
  48. };
  49. /// <summary>
  50. /// Summary description for Field.
  51. /// </summary>
  52. internal class MySqlField
  53. {
  54. #region Fields
  55. // public fields
  56. public string CatalogName;
  57. public int ColumnLength;
  58. public string ColumnName;
  59. public string OriginalColumnName;
  60. public string TableName;
  61. public string RealTableName;
  62. public string DatabaseName;
  63. public Encoding Encoding;
  64. // protected fields
  65. protected int charSetIndex;
  66. protected DBVersion connVersion;
  67. protected bool binaryOk;
  68. // internal fields
  69. internal Driver driver;
  70. #endregion
  71. [SecuritySafeCritical]
  72. public MySqlField(Driver driver)
  73. {
  74. this.driver = driver;
  75. connVersion = driver.Version;
  76. MaxLength = 1;
  77. binaryOk = true;
  78. #if !NETFX
  79. Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
  80. #endif
  81. }
  82. #region Properties
  83. public int CharacterSetIndex
  84. {
  85. get { return charSetIndex; }
  86. set { charSetIndex = value; SetFieldEncoding(); }
  87. }
  88. public MySqlDbType Type { get; protected set; }
  89. public byte Precision { get; set; }
  90. public byte Scale { get; set; }
  91. public int MaxLength { get; set; }
  92. public ColumnFlags Flags { get; protected set; }
  93. public bool IsAutoIncrement => (Flags & ColumnFlags.AUTO_INCREMENT) > 0;
  94. public bool IsNumeric => (Flags & ColumnFlags.NUMBER) > 0;
  95. public bool AllowsNull => (Flags & ColumnFlags.NOT_NULL) == 0;
  96. public bool IsUnique => (Flags & ColumnFlags.UNIQUE_KEY) > 0;
  97. public bool IsPrimaryKey => (Flags & ColumnFlags.PRIMARY_KEY) > 0;
  98. public bool IsBlob => (Type >= MySqlDbType.TinyBlob &&
  99. Type <= MySqlDbType.Blob) ||
  100. (Type >= MySqlDbType.TinyText &&
  101. Type <= MySqlDbType.Text) ||
  102. (Flags & ColumnFlags.BLOB) > 0;
  103. public bool IsBinary => binaryOk && (CharacterSetIndex == 63);
  104. public bool IsUnsigned => (Flags & ColumnFlags.UNSIGNED) > 0;
  105. public bool IsTextField
  106. {
  107. get
  108. {
  109. return Type == MySqlDbType.VarString || Type == MySqlDbType.VarChar ||
  110. Type == MySqlDbType.String || (Type == MySqlDbType.Guid && !driver.Settings.OldGuids);
  111. }
  112. }
  113. private int CharacterLength => ColumnLength / MaxLength;
  114. public List<Type> TypeConversions { get; } = new List<Type>();
  115. #endregion
  116. public void SetTypeAndFlags(MySqlDbType type, ColumnFlags flags)
  117. {
  118. Flags = flags;
  119. Type = type;
  120. if (String.IsNullOrEmpty(TableName) && String.IsNullOrEmpty(RealTableName) &&
  121. IsBinary && driver.Settings.FunctionsReturnString)
  122. {
  123. CharacterSetIndex = driver.ConnectionCharSetIndex;
  124. }
  125. // if our type is an unsigned number, then we need
  126. // to bump it up into our unsigned types
  127. // we're trusting that the server is not going to set the UNSIGNED
  128. // flag unless we are a number
  129. if (IsUnsigned)
  130. {
  131. switch (type)
  132. {
  133. case MySqlDbType.Byte:
  134. Type = MySqlDbType.UByte;
  135. return;
  136. case MySqlDbType.Int16:
  137. Type = MySqlDbType.UInt16;
  138. return;
  139. case MySqlDbType.Int24:
  140. Type = MySqlDbType.UInt24;
  141. return;
  142. case MySqlDbType.Int32:
  143. Type = MySqlDbType.UInt32;
  144. return;
  145. case MySqlDbType.Int64:
  146. Type = MySqlDbType.UInt64;
  147. return;
  148. }
  149. }
  150. if (IsBlob)
  151. {
  152. // handle blob to UTF8 conversion if requested. This is only activated
  153. // on binary blobs
  154. if (IsBinary && driver.Settings.TreatBlobsAsUTF8)
  155. {
  156. bool convertBlob = false;
  157. Regex includeRegex = driver.Settings.GetBlobAsUTF8IncludeRegex();
  158. Regex excludeRegex = driver.Settings.GetBlobAsUTF8ExcludeRegex();
  159. if (includeRegex != null && includeRegex.IsMatch(ColumnName))
  160. convertBlob = true;
  161. else if (includeRegex == null && excludeRegex != null &&
  162. !excludeRegex.IsMatch(ColumnName))
  163. convertBlob = true;
  164. if (convertBlob)
  165. {
  166. binaryOk = false;
  167. Encoding = System.Text.Encoding.GetEncoding("UTF-8");
  168. charSetIndex = -1; // lets driver know we are in charge of encoding
  169. MaxLength = 4;
  170. }
  171. }
  172. if (!IsBinary)
  173. {
  174. if (type == MySqlDbType.TinyBlob)
  175. Type = MySqlDbType.TinyText;
  176. else if (type == MySqlDbType.MediumBlob)
  177. Type = MySqlDbType.MediumText;
  178. else if (type == MySqlDbType.Blob)
  179. Type = MySqlDbType.Text;
  180. else if (type == MySqlDbType.LongBlob)
  181. Type = MySqlDbType.LongText;
  182. }
  183. }
  184. // now determine if we really should be binary
  185. if (driver.Settings.RespectBinaryFlags)
  186. CheckForExceptions();
  187. if (Type == MySqlDbType.String && CharacterLength == 36 && !driver.Settings.OldGuids)
  188. Type = MySqlDbType.Guid;
  189. if (!IsBinary) return;
  190. if (driver.Settings.RespectBinaryFlags)
  191. {
  192. if (type == MySqlDbType.String)
  193. Type = MySqlDbType.Binary;
  194. else if (type == MySqlDbType.VarChar ||
  195. type == MySqlDbType.VarString)
  196. Type = MySqlDbType.VarBinary;
  197. }
  198. if (CharacterSetIndex == 63)
  199. CharacterSetIndex = driver.ConnectionCharSetIndex;
  200. if (Type == MySqlDbType.Binary && ColumnLength == 16 && driver.Settings.OldGuids)
  201. Type = MySqlDbType.Guid;
  202. }
  203. public void AddTypeConversion(Type t)
  204. {
  205. if (TypeConversions.Contains(t)) return;
  206. TypeConversions.Add(t);
  207. }
  208. private void CheckForExceptions()
  209. {
  210. string colName = String.Empty;
  211. if (OriginalColumnName != null)
  212. colName = StringUtility.ToUpperInvariant(OriginalColumnName);
  213. if (colName.StartsWith("CHAR(", StringComparison.Ordinal))
  214. binaryOk = false;
  215. }
  216. public IMySqlValue GetValueObject()
  217. {
  218. IMySqlValue v = GetIMySqlValue(Type);
  219. if (v is MySqlByte && ColumnLength == 1 && driver.Settings.TreatTinyAsBoolean)
  220. {
  221. MySqlByte b = (MySqlByte)v;
  222. b.TreatAsBoolean = true;
  223. v = b;
  224. }
  225. else if (v is MySqlGuid)
  226. {
  227. MySqlGuid g = (MySqlGuid)v;
  228. g.OldGuids = driver.Settings.OldGuids;
  229. v = g;
  230. }
  231. return v;
  232. }
  233. public static IMySqlValue GetIMySqlValue(MySqlDbType type)
  234. {
  235. switch (type)
  236. {
  237. case MySqlDbType.Byte:
  238. return new MySqlByte();
  239. case MySqlDbType.UByte:
  240. return new MySqlUByte();
  241. case MySqlDbType.Int16:
  242. return new MySqlInt16();
  243. case MySqlDbType.UInt16:
  244. return new MySqlUInt16();
  245. case MySqlDbType.Int24:
  246. case MySqlDbType.Int32:
  247. case MySqlDbType.Year:
  248. return new MySqlInt32(type, true);
  249. case MySqlDbType.UInt24:
  250. case MySqlDbType.UInt32:
  251. return new MySqlUInt32(type, true);
  252. case MySqlDbType.Bit:
  253. return new MySqlBit();
  254. case MySqlDbType.Int64:
  255. return new MySqlInt64();
  256. case MySqlDbType.UInt64:
  257. return new MySqlUInt64();
  258. case MySqlDbType.Time:
  259. return new MySqlTimeSpan();
  260. case MySqlDbType.Date:
  261. case MySqlDbType.DateTime:
  262. case MySqlDbType.Newdate:
  263. case MySqlDbType.Timestamp:
  264. return new MySqlDateTime(type, true);
  265. case MySqlDbType.Decimal:
  266. case MySqlDbType.NewDecimal:
  267. return new MySqlDecimal();
  268. case MySqlDbType.Float:
  269. return new MySqlSingle();
  270. case MySqlDbType.Double:
  271. return new MySqlDouble();
  272. case MySqlDbType.Set:
  273. case MySqlDbType.Enum:
  274. case MySqlDbType.String:
  275. case MySqlDbType.VarString:
  276. case MySqlDbType.VarChar:
  277. case MySqlDbType.Text:
  278. case MySqlDbType.TinyText:
  279. case MySqlDbType.MediumText:
  280. case MySqlDbType.LongText:
  281. case MySqlDbType.JSON:
  282. case (MySqlDbType)Field_Type.NULL:
  283. return new MySqlString(type, true);
  284. case MySqlDbType.Geometry:
  285. return new MySqlGeometry(type, true);
  286. case MySqlDbType.Blob:
  287. case MySqlDbType.MediumBlob:
  288. case MySqlDbType.LongBlob:
  289. case MySqlDbType.TinyBlob:
  290. case MySqlDbType.Binary:
  291. case MySqlDbType.VarBinary:
  292. return new MySqlBinary(type, true);
  293. case MySqlDbType.Guid:
  294. return new MySqlGuid();
  295. default:
  296. throw new MySqlException("Unknown data type");
  297. }
  298. }
  299. private void SetFieldEncoding()
  300. {
  301. Dictionary<int, string> charSets = driver.CharacterSets;
  302. DBVersion version = driver.Version;
  303. if (charSets == null || charSets.Count == 0 || CharacterSetIndex == -1) return;
  304. if (charSets[CharacterSetIndex] == null) return;
  305. CharacterSet cs = CharSetMap.GetCharacterSet(version, (string)charSets[CharacterSetIndex]);
  306. MaxLength = cs.byteCount;
  307. Encoding = CharSetMap.GetEncoding(version, (string)charSets[CharacterSetIndex]);
  308. }
  309. }
  310. }
  311. #endif