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.

363 lines
13 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. #if MYSQL_6_9
  2. // Copyright 2004, 2013, 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 Externals.MySql.Data.Types;
  25. using System.ComponentModel;
  26. using System.Globalization;
  27. using System.Reflection;
  28. using System.Text;
  29. using System.Collections;
  30. using System.Data;
  31. using System.Data.Common;
  32. namespace Externals.MySql.Data.MySqlClient
  33. {
  34. /// <summary>
  35. /// Represents a parameter to a <see cref="MySqlCommand"/>, and optionally, its mapping to <see cref="DataSet"/> columns. This class cannot be inherited.
  36. /// </summary>
  37. internal sealed partial class MySqlParameter : ICloneable
  38. {
  39. private const int UNSIGNED_MASK = 0x8000;
  40. private object paramValue;
  41. private string paramName;
  42. private MySqlDbType mySqlDbType;
  43. private bool inferType = true;
  44. private const int GEOMETRY_LENGTH = 25;
  45. #region Constructors
  46. public MySqlParameter()
  47. {
  48. Init();
  49. }
  50. /// <summary>
  51. /// Initializes a new instance of the <see cref="MySqlParameter"/> class with the parameter name and a value of the new MySqlParameter.
  52. /// </summary>
  53. /// <param name="parameterName">The name of the parameter to map. </param>
  54. /// <param name="value">An <see cref="Object"/> that is the value of the <see cref="MySqlParameter"/>. </param>
  55. public MySqlParameter(string parameterName, object value) : this()
  56. {
  57. ParameterName = parameterName;
  58. Value = value;
  59. }
  60. /// <summary>
  61. /// Initializes a new instance of the <see cref="MySqlParameter"/> class with the parameter name and the data type.
  62. /// </summary>
  63. /// <param name="parameterName">The name of the parameter to map. </param>
  64. /// <param name="dbType">One of the <see cref="MySqlDbType"/> values. </param>
  65. public MySqlParameter(string parameterName, MySqlDbType dbType) : this(parameterName, null)
  66. {
  67. MySqlDbType = dbType;
  68. }
  69. /// <summary>
  70. /// Initializes a new instance of the <see cref="MySqlParameter"/> class with the parameter name, the <see cref="MySqlDbType"/>, and the size.
  71. /// </summary>
  72. /// <param name="parameterName">The name of the parameter to map. </param>
  73. /// <param name="dbType">One of the <see cref="MySqlDbType"/> values. </param>
  74. /// <param name="size">The length of the parameter. </param>
  75. public MySqlParameter(string parameterName, MySqlDbType dbType, int size) : this(parameterName, dbType)
  76. {
  77. Size = size;
  78. }
  79. partial void Init();
  80. #endregion
  81. #region Properties
  82. [Category("Misc")]
  83. public override String ParameterName
  84. {
  85. get { return paramName; }
  86. set { SetParameterName(value); }
  87. }
  88. internal MySqlParameterCollection Collection { get; set; }
  89. internal Encoding Encoding { get; set; }
  90. internal bool TypeHasBeenSet
  91. {
  92. get { return inferType == false; }
  93. }
  94. internal string BaseName
  95. {
  96. get
  97. {
  98. if (ParameterName.StartsWith("@", StringComparison.Ordinal) || ParameterName.StartsWith("?", StringComparison.Ordinal))
  99. return ParameterName.Substring(1);
  100. return ParameterName;
  101. }
  102. }
  103. /// <summary>
  104. /// Gets or sets a value indicating whether the parameter is input-only, output-only, bidirectional, or a stored procedure return value parameter.
  105. /// As of MySql version 4.1 and earlier, input-only is the only valid choice.
  106. /// </summary>
  107. [Category("Data")]
  108. public override ParameterDirection Direction { get; set; }
  109. /// <summary>
  110. /// Gets or sets a value indicating whether the parameter accepts null values.
  111. /// </summary>
  112. [Browsable(false)]
  113. public override Boolean IsNullable { get; set; }
  114. /// <summary>
  115. /// Gets or sets the MySqlDbType of the parameter.
  116. /// </summary>
  117. [Category("Data")]
  118. [DbProviderSpecificTypeProperty(true)]
  119. public MySqlDbType MySqlDbType
  120. {
  121. get { return mySqlDbType; }
  122. set
  123. {
  124. SetMySqlDbType(value);
  125. inferType = false;
  126. }
  127. }
  128. /// <summary>
  129. /// Gets or sets the maximum number of digits used to represent the <see cref="Value"/> property.
  130. /// </summary>
  131. [Category("Data")]
  132. #if NET40
  133. public byte Precision { get; set; }
  134. #else
  135. public override byte Precision { get; set; }
  136. #endif
  137. /// <summary>
  138. /// Gets or sets the number of decimal places to which <see cref="Value"/> is resolved.
  139. /// </summary>
  140. [Category("Data")]
  141. #if NET40
  142. public byte Scale { get; set; }
  143. #else
  144. public override byte Scale { get; set; }
  145. #endif
  146. /// <summary>
  147. /// Gets or sets the maximum size, in bytes, of the data within the column.
  148. /// </summary>
  149. [Category("Data")]
  150. public override int Size { get; set; }
  151. /// <summary>
  152. /// Gets or sets the value of the parameter.
  153. /// </summary>
  154. [TypeConverter(typeof(StringConverter))]
  155. [Category("Data")]
  156. public override object Value
  157. {
  158. get { return paramValue; }
  159. set
  160. {
  161. paramValue = value;
  162. byte[] valueAsByte = value as byte[];
  163. string valueAsString = value as string;
  164. if (valueAsByte != null)
  165. Size = valueAsByte.Length;
  166. else if (valueAsString != null)
  167. Size = valueAsString.Length;
  168. if (inferType)
  169. SetTypeFromValue();
  170. }
  171. }
  172. private IMySqlValue _valueObject;
  173. internal IMySqlValue ValueObject
  174. {
  175. get { return _valueObject; }
  176. private set
  177. {
  178. _valueObject = value;
  179. }
  180. }
  181. /// <summary>
  182. /// Returns the possible values for this parameter if this parameter is of type
  183. /// SET or ENUM. Returns null otherwise.
  184. /// </summary>
  185. public IList PossibleValues { get; internal set; }
  186. #endregion
  187. private void SetParameterName(string name)
  188. {
  189. if (Collection != null)
  190. Collection.ParameterNameChanged(this, paramName, name);
  191. paramName = name;
  192. }
  193. /// <summary>
  194. /// Overridden. Gets a string containing the <see cref="ParameterName"/>.
  195. /// </summary>
  196. /// <returns></returns>
  197. public override string ToString()
  198. {
  199. return paramName;
  200. }
  201. internal int GetPSType()
  202. {
  203. switch (mySqlDbType)
  204. {
  205. case MySqlDbType.Bit:
  206. return (int)MySqlDbType.Int64 | UNSIGNED_MASK;
  207. case MySqlDbType.UByte:
  208. return (int)MySqlDbType.Byte | UNSIGNED_MASK;
  209. case MySqlDbType.UInt64:
  210. return (int)MySqlDbType.Int64 | UNSIGNED_MASK;
  211. case MySqlDbType.UInt32:
  212. return (int)MySqlDbType.Int32 | UNSIGNED_MASK;
  213. case MySqlDbType.UInt24:
  214. return (int)MySqlDbType.Int32 | UNSIGNED_MASK;
  215. case MySqlDbType.UInt16:
  216. return (int)MySqlDbType.Int16 | UNSIGNED_MASK;
  217. default:
  218. return (int)mySqlDbType;
  219. }
  220. }
  221. internal void Serialize(MySqlPacket packet, bool binary, MySqlConnectionStringBuilder settings)
  222. {
  223. if (!binary && (paramValue == null || paramValue == DBNull.Value))
  224. packet.WriteStringNoNull("NULL");
  225. else
  226. {
  227. if (ValueObject.MySqlDbType == MySqlDbType.Guid)
  228. {
  229. MySqlGuid g = (MySqlGuid)ValueObject;
  230. g.OldGuids = settings.OldGuids;
  231. ValueObject = g;
  232. }
  233. if (ValueObject.MySqlDbType == MySqlDbType.Geometry)
  234. {
  235. MySqlGeometry v = (MySqlGeometry)ValueObject;
  236. if (v.IsNull && Value != null)
  237. {
  238. MySqlGeometry.TryParse(Value.ToString(), out v);
  239. }
  240. ValueObject = v;
  241. }
  242. ValueObject.WriteValue(packet, binary, paramValue, Size);
  243. }
  244. }
  245. partial void SetDbTypeFromMySqlDbType();
  246. private void SetMySqlDbType(MySqlDbType mysql_dbtype)
  247. {
  248. mySqlDbType = mysql_dbtype;
  249. ValueObject = MySqlField.GetIMySqlValue(mySqlDbType);
  250. SetDbTypeFromMySqlDbType();
  251. }
  252. private void SetTypeFromValue()
  253. {
  254. if (paramValue == null || paramValue == DBNull.Value) return;
  255. if (paramValue is Guid)
  256. MySqlDbType = MySqlDbType.Guid;
  257. else if (paramValue is TimeSpan)
  258. MySqlDbType = MySqlDbType.Time;
  259. else if (paramValue is bool)
  260. MySqlDbType = MySqlDbType.Byte;
  261. else
  262. {
  263. Type t = paramValue.GetType();
  264. switch (t.Name)
  265. {
  266. case "SByte": MySqlDbType = MySqlDbType.Byte; break;
  267. case "Byte": MySqlDbType = MySqlDbType.UByte; break;
  268. case "Int16": MySqlDbType = MySqlDbType.Int16; break;
  269. case "UInt16": MySqlDbType = MySqlDbType.UInt16; break;
  270. case "Int32": MySqlDbType = MySqlDbType.Int32; break;
  271. case "UInt32": MySqlDbType = MySqlDbType.UInt32; break;
  272. case "Int64": MySqlDbType = MySqlDbType.Int64; break;
  273. case "UInt64": MySqlDbType = MySqlDbType.UInt64; break;
  274. case "DateTime": MySqlDbType = MySqlDbType.DateTime; break;
  275. case "String": MySqlDbType = MySqlDbType.VarChar; break;
  276. case "Single": MySqlDbType = MySqlDbType.Float; break;
  277. case "Double": MySqlDbType = MySqlDbType.Double; break;
  278. case "Decimal": MySqlDbType = MySqlDbType.Decimal; break;
  279. case "Object":
  280. default:
  281. if (t.BaseType == typeof(Enum))
  282. MySqlDbType = MySqlDbType.Int32;
  283. else
  284. MySqlDbType = MySqlDbType.Blob;
  285. break;
  286. }
  287. }
  288. }
  289. #region ICloneable
  290. public MySqlParameter Clone()
  291. {
  292. MySqlParameter clone = new MySqlParameter(paramName, mySqlDbType, Direction, SourceColumn, SourceVersion, paramValue);
  293. // if we have not had our type set yet then our clone should not either
  294. clone.inferType = inferType;
  295. return clone;
  296. }
  297. object ICloneable.Clone()
  298. {
  299. return this.Clone();
  300. }
  301. #endregion
  302. // this method is pretty dumb but we want it to be fast. it doesn't return size based
  303. // on value and type but just on the value.
  304. internal long EstimatedSize()
  305. {
  306. if (Value == null || Value == DBNull.Value)
  307. return 4; // size of NULL
  308. if (Value is byte[])
  309. return (Value as byte[]).Length;
  310. if (Value is string)
  311. return (Value as string).Length * 4; // account for UTF-8 (yeah I know)
  312. if (Value is decimal || Value is float)
  313. return 64;
  314. return 32;
  315. }
  316. }
  317. }
  318. #endif