PageRenderTime 46ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs

https://bitbucket.org/danipen/mono
C# | 1025 lines | 863 code | 116 blank | 46 comment | 150 complexity | 67522ea116dc3850010e801e9d0faf14 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // System.Data.SqlClient.SqlCommand.cs
  3. //
  4. // Author:
  5. // Rodrigo Moya (rodrigo@ximian.com)
  6. // Daniel Morgan (danmorg@sc.rr.com)
  7. // Tim Coleman (tim@timcoleman.com)
  8. // Diego Caravana (diego@toth.it)
  9. //
  10. // (C) Ximian, Inc 2002 http://www.ximian.com/
  11. // (C) Daniel Morgan, 2002
  12. // Copyright (C) Tim Coleman, 2002
  13. //
  14. //
  15. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  16. //
  17. // Permission is hereby granted, free of charge, to any person obtaining
  18. // a copy of this software and associated documentation files (the
  19. // "Software"), to deal in the Software without restriction, including
  20. // without limitation the rights to use, copy, modify, merge, publish,
  21. // distribute, sublicense, and/or sell copies of the Software, and to
  22. // permit persons to whom the Software is furnished to do so, subject to
  23. // the following conditions:
  24. //
  25. // The above copyright notice and this permission notice shall be
  26. // included in all copies or substantial portions of the Software.
  27. //
  28. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  29. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  30. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  31. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  32. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  33. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  34. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  35. //
  36. using Mono.Data.Tds;
  37. using Mono.Data.Tds.Protocol;
  38. using System;
  39. using System.IO;
  40. using System.Collections;
  41. using System.Collections.Specialized;
  42. using System.ComponentModel;
  43. using System.Data;
  44. using System.Data.Common;
  45. #if NET_2_0
  46. using System.Data.Sql;
  47. #endif
  48. using System.Runtime.InteropServices;
  49. using System.Text;
  50. using System.Xml;
  51. namespace System.Data.SqlClient {
  52. [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.SqlCommandDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
  53. [ToolboxItemAttribute ("System.Drawing.Design.ToolboxItem, "+ Consts.AssemblySystem_Drawing)]
  54. #if NET_2_0
  55. [DefaultEventAttribute ("RecordsAffected")]
  56. public sealed class SqlCommand : DbCommand, IDbCommand, ICloneable
  57. #else
  58. public sealed class SqlCommand : Component, IDbCommand, ICloneable
  59. #endif // NET_2_0
  60. {
  61. #region Fields
  62. const int DEFAULT_COMMAND_TIMEOUT = 30;
  63. int commandTimeout;
  64. bool designTimeVisible;
  65. string commandText;
  66. CommandType commandType;
  67. SqlConnection connection;
  68. SqlTransaction transaction;
  69. UpdateRowSource updatedRowSource;
  70. CommandBehavior behavior = CommandBehavior.Default;
  71. SqlParameterCollection parameters;
  72. string preparedStatement;
  73. #if NET_2_0
  74. bool disposed;
  75. SqlNotificationRequest notification;
  76. bool notificationAutoEnlist;
  77. #endif
  78. #endregion // Fields
  79. #region Constructors
  80. public SqlCommand()
  81. : this (String.Empty, null, null)
  82. {
  83. }
  84. public SqlCommand (string cmdText)
  85. : this (cmdText, null, null)
  86. {
  87. }
  88. public SqlCommand (string cmdText, SqlConnection connection)
  89. : this (cmdText, connection, null)
  90. {
  91. }
  92. public SqlCommand (string cmdText, SqlConnection connection, SqlTransaction transaction)
  93. {
  94. this.commandText = cmdText;
  95. this.connection = connection;
  96. this.transaction = transaction;
  97. this.commandType = CommandType.Text;
  98. this.updatedRowSource = UpdateRowSource.Both;
  99. this.commandTimeout = DEFAULT_COMMAND_TIMEOUT;
  100. #if NET_2_0
  101. notificationAutoEnlist = true;
  102. #endif
  103. designTimeVisible = true;
  104. parameters = new SqlParameterCollection (this);
  105. }
  106. private SqlCommand(string commandText, SqlConnection connection, SqlTransaction transaction, CommandType commandType, UpdateRowSource updatedRowSource, bool designTimeVisible, int commandTimeout, SqlParameterCollection parameters)
  107. {
  108. this.commandText = commandText;
  109. this.connection = connection;
  110. this.transaction = transaction;
  111. this.commandType = commandType;
  112. this.updatedRowSource = updatedRowSource;
  113. this.designTimeVisible = designTimeVisible;
  114. this.commandTimeout = commandTimeout;
  115. this.parameters = new SqlParameterCollection(this);
  116. for (int i = 0;i < parameters.Count;i++)
  117. this.parameters.Add(((ICloneable)parameters[i]).Clone());
  118. }
  119. #endregion // Constructors
  120. #region Properties
  121. internal CommandBehavior CommandBehavior {
  122. get { return behavior; }
  123. }
  124. #if !NET_2_0
  125. [DataSysDescription ("Command text to execute.")]
  126. #endif
  127. [DefaultValue ("")]
  128. [EditorAttribute ("Microsoft.VSDesigner.Data.SQL.Design.SqlCommandTextEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
  129. [RefreshProperties (RefreshProperties.All)]
  130. public
  131. #if NET_2_0
  132. override
  133. #endif //NET_2_0
  134. string CommandText {
  135. get {
  136. if (commandText == null)
  137. return string.Empty;
  138. return commandText;
  139. }
  140. set {
  141. if (value != commandText && preparedStatement != null)
  142. Unprepare ();
  143. commandText = value;
  144. }
  145. }
  146. #if !NET_2_0
  147. [DataSysDescription ("Time to wait for command to execute.")]
  148. [DefaultValue (DEFAULT_COMMAND_TIMEOUT)]
  149. #endif
  150. public
  151. #if NET_2_0
  152. override
  153. #endif //NET_2_0
  154. int CommandTimeout {
  155. get { return commandTimeout; }
  156. set {
  157. if (value < 0)
  158. #if NET_2_0
  159. throw new ArgumentException ("The property value assigned is less than 0.",
  160. "CommandTimeout");
  161. #else
  162. throw new ArgumentException ("The property value assigned is less than 0.");
  163. #endif
  164. commandTimeout = value;
  165. }
  166. }
  167. #if !NET_2_0
  168. [DataSysDescription ("How to interpret the CommandText.")]
  169. #endif
  170. [DefaultValue (CommandType.Text)]
  171. [RefreshProperties (RefreshProperties.All)]
  172. public
  173. #if NET_2_0
  174. override
  175. #endif //NET_2_0
  176. CommandType CommandType {
  177. get { return commandType; }
  178. set {
  179. if (value == CommandType.TableDirect)
  180. #if NET_2_0
  181. throw new ArgumentOutOfRangeException ("CommandType.TableDirect is not supported " +
  182. "by the Mono SqlClient Data Provider.");
  183. #else
  184. throw new ArgumentException ("CommandType.TableDirect is not supported by the Mono SqlClient Data Provider.");
  185. #endif
  186. ExceptionHelper.CheckEnumValue (typeof (CommandType), value);
  187. commandType = value;
  188. }
  189. }
  190. [DefaultValue (null)]
  191. #if !NET_2_0
  192. [DataSysDescription ("Connection used by the command.")]
  193. #endif
  194. [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
  195. public
  196. #if NET_2_0
  197. new
  198. #endif //NET_2_0
  199. SqlConnection Connection {
  200. get { return connection; }
  201. set
  202. {
  203. #if ONLY_1_1
  204. if (connection != null && connection.DataReader != null)
  205. throw new InvalidOperationException ("The connection is busy fetching data.");
  206. #endif
  207. connection = value;
  208. }
  209. }
  210. [Browsable (false)]
  211. [DefaultValue (true)]
  212. [DesignOnly (true)]
  213. #if NET_2_0
  214. [EditorBrowsable (EditorBrowsableState.Never)]
  215. #endif
  216. public
  217. #if NET_2_0
  218. override
  219. #endif //NET_2_0
  220. bool DesignTimeVisible {
  221. get { return designTimeVisible; }
  222. set { designTimeVisible = value; }
  223. }
  224. #if !NET_2_0
  225. [DataSysDescription ("The parameters collection.")]
  226. #endif
  227. [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
  228. public
  229. #if NET_2_0
  230. new
  231. #endif //NET_2_0
  232. SqlParameterCollection Parameters {
  233. get { return parameters; }
  234. }
  235. internal Tds Tds {
  236. get { return Connection.Tds; }
  237. }
  238. #if !NET_2_0
  239. IDbConnection IDbCommand.Connection {
  240. get { return Connection; }
  241. set {
  242. if (!(value == null || value is SqlConnection))
  243. throw new InvalidCastException ("The value was not a valid SqlConnection.");
  244. Connection = (SqlConnection) value;
  245. }
  246. }
  247. IDataParameterCollection IDbCommand.Parameters {
  248. get { return Parameters; }
  249. }
  250. IDbTransaction IDbCommand.Transaction {
  251. get { return Transaction; }
  252. set {
  253. if (!(value == null || value is SqlTransaction))
  254. throw new ArgumentException ();
  255. Transaction = (SqlTransaction) value;
  256. }
  257. }
  258. #endif
  259. [Browsable (false)]
  260. #if !NET_2_0
  261. [DataSysDescription ("The transaction used by the command.")]
  262. #endif
  263. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  264. public new SqlTransaction Transaction {
  265. get {
  266. if (transaction != null && !transaction.IsOpen)
  267. transaction = null;
  268. return transaction;
  269. }
  270. set
  271. {
  272. #if ONLY_1_1
  273. if (connection != null && connection.DataReader != null)
  274. throw new InvalidOperationException ("The connection is busy fetching data.");
  275. #endif
  276. transaction = value;
  277. }
  278. }
  279. #if !NET_2_0
  280. [DataSysDescription ("When used by a DataAdapter.Update, how command results are applied to the current DataRow.")]
  281. #endif
  282. [DefaultValue (UpdateRowSource.Both)]
  283. public
  284. #if NET_2_0
  285. override
  286. #endif // NET_2_0
  287. UpdateRowSource UpdatedRowSource {
  288. get { return updatedRowSource; }
  289. set {
  290. ExceptionHelper.CheckEnumValue (typeof (UpdateRowSource), value);
  291. updatedRowSource = value;
  292. }
  293. }
  294. #if NET_2_0
  295. [Browsable (false)]
  296. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  297. public SqlNotificationRequest Notification {
  298. get { return notification; }
  299. set { notification = value; }
  300. }
  301. [DefaultValue (true)]
  302. public bool NotificationAutoEnlist {
  303. get { return notificationAutoEnlist; }
  304. set { notificationAutoEnlist = value; }
  305. }
  306. #endif
  307. #endregion // Fields
  308. #region Methods
  309. public
  310. #if NET_2_0
  311. override
  312. #endif // NET_2_0
  313. void Cancel ()
  314. {
  315. if (Connection == null || Connection.Tds == null)
  316. return;
  317. Connection.Tds.Cancel ();
  318. }
  319. #if NET_2_0
  320. public SqlCommand Clone ()
  321. {
  322. return new SqlCommand (commandText, connection, transaction, commandType, updatedRowSource, designTimeVisible, commandTimeout, parameters);
  323. }
  324. #endif // NET_2_0
  325. internal void CloseDataReader ()
  326. {
  327. if (Connection != null) {
  328. Connection.DataReader = null;
  329. if ((behavior & CommandBehavior.CloseConnection) != 0)
  330. Connection.Close ();
  331. if (Tds != null)
  332. Tds.SequentialAccess = false;
  333. }
  334. // Reset the behavior
  335. behavior = CommandBehavior.Default;
  336. }
  337. public new SqlParameter CreateParameter ()
  338. {
  339. return new SqlParameter ();
  340. }
  341. private string EscapeProcName (string name, bool schema)
  342. {
  343. string procName;
  344. string tmpProcName = name.Trim ();
  345. int procNameLen = tmpProcName.Length;
  346. char[] brkts = new char [] {'[', ']'};
  347. bool foundMatching = false;
  348. int start = 0, count = procNameLen;
  349. int sindex = -1, eindex = -1;
  350. // We try to match most of the "brackets" combination here, however
  351. // there could be other combinations that may generate a different type
  352. // of exception in MS.NET
  353. if (procNameLen > 1) {
  354. if ((sindex = tmpProcName.IndexOf ('[')) <= 0)
  355. foundMatching = true;
  356. else
  357. foundMatching = false;
  358. if (foundMatching == true && sindex > -1) {
  359. eindex = tmpProcName.IndexOf (']');
  360. if (sindex > eindex && eindex != -1) {
  361. foundMatching = false;
  362. } else if (eindex == procNameLen-1) {
  363. if (tmpProcName.IndexOfAny (brkts, 1, procNameLen-2) != -1) {
  364. foundMatching = false;
  365. } else {
  366. start = 1;
  367. count = procNameLen - 2;
  368. }
  369. } else if (eindex == -1 && schema) {
  370. foundMatching = true;
  371. } else {
  372. foundMatching = false;
  373. }
  374. }
  375. if (foundMatching)
  376. procName = tmpProcName.Substring (start, count);
  377. else
  378. throw new ArgumentException (String.Format ("SqlCommand.CommandText property value is an invalid multipart name {0}, incorrect usage of quotes", CommandText));
  379. } else {
  380. procName = tmpProcName;
  381. }
  382. return procName;
  383. }
  384. internal void DeriveParameters ()
  385. {
  386. if (commandType != CommandType.StoredProcedure)
  387. throw new InvalidOperationException (String.Format ("SqlCommand DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType));
  388. ValidateCommand ("DeriveParameters", false);
  389. string procName = CommandText;
  390. string schemaName = String.Empty;
  391. int dotPosition = procName.LastIndexOf ('.');
  392. // Procedure name can be: [database].[user].[procname]
  393. if (dotPosition >= 0) {
  394. schemaName = procName.Substring (0, dotPosition);
  395. procName = procName.Substring (dotPosition + 1);
  396. if ((dotPosition = schemaName.LastIndexOf ('.')) >= 0)
  397. schemaName = schemaName.Substring (dotPosition + 1);
  398. }
  399. procName = EscapeProcName (procName, false);
  400. schemaName = EscapeProcName (schemaName, true);
  401. SqlParameterCollection localParameters = new SqlParameterCollection (this);
  402. localParameters.Add ("@procedure_name", SqlDbType.NVarChar, procName.Length).Value = procName;
  403. if (schemaName.Length > 0)
  404. localParameters.Add ("@procedure_schema", SqlDbType.NVarChar, schemaName.Length).Value = schemaName;
  405. string sql = "sp_procedure_params_rowset";
  406. try {
  407. Connection.Tds.ExecProc (sql, localParameters.MetaParameters, 0, true);
  408. } catch (TdsTimeoutException ex) {
  409. Connection.Tds.Reset ();
  410. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  411. } catch (TdsInternalException ex) {
  412. Connection.Close ();
  413. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  414. }
  415. SqlDataReader reader = new SqlDataReader (this);
  416. parameters.Clear ();
  417. object[] dbValues = new object[reader.FieldCount];
  418. while (reader.Read ()) {
  419. reader.GetValues (dbValues);
  420. parameters.Add (new SqlParameter (dbValues));
  421. }
  422. reader.Close ();
  423. if (parameters.Count == 0)
  424. throw new InvalidOperationException ("Stored procedure '" + procName + "' does not exist.");
  425. }
  426. private void Execute (bool wantResults)
  427. {
  428. int index = 0;
  429. Connection.Tds.RecordsAffected = -1;
  430. TdsMetaParameterCollection parms = Parameters.MetaParameters;
  431. foreach (TdsMetaParameter param in parms) {
  432. param.Validate (index++);
  433. }
  434. if (preparedStatement == null) {
  435. bool schemaOnly = ((behavior & CommandBehavior.SchemaOnly) > 0);
  436. bool keyInfo = ((behavior & CommandBehavior.KeyInfo) > 0);
  437. StringBuilder sql1 = new StringBuilder ();
  438. StringBuilder sql2 = new StringBuilder ();
  439. if (schemaOnly || keyInfo)
  440. sql1.Append ("SET FMTONLY OFF;");
  441. if (keyInfo) {
  442. sql1.Append ("SET NO_BROWSETABLE ON;");
  443. sql2.Append ("SET NO_BROWSETABLE OFF;");
  444. }
  445. if (schemaOnly) {
  446. sql1.Append ("SET FMTONLY ON;");
  447. sql2.Append ("SET FMTONLY OFF;");
  448. }
  449. switch (CommandType) {
  450. case CommandType.StoredProcedure:
  451. try {
  452. if (keyInfo || schemaOnly)
  453. Connection.Tds.Execute (sql1.ToString ());
  454. Connection.Tds.ExecProc (CommandText, parms, CommandTimeout, wantResults);
  455. if (keyInfo || schemaOnly)
  456. Connection.Tds.Execute (sql2.ToString ());
  457. } catch (TdsTimeoutException ex) {
  458. // If it is a timeout exception there can be many reasons:
  459. // 1) Network is down/server is down/not reachable
  460. // 2) Somebody has an exclusive lock on Table/DB
  461. // In any of these cases, don't close the connection. Let the user do it
  462. Connection.Tds.Reset ();
  463. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  464. } catch (TdsInternalException ex) {
  465. Connection.Close ();
  466. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  467. }
  468. break;
  469. case CommandType.Text:
  470. string sql;
  471. if (sql2.Length > 0) {
  472. sql = String.Format ("{0}{1};{2}", sql1.ToString (), CommandText, sql2.ToString ());
  473. } else {
  474. sql = String.Format ("{0}{1}", sql1.ToString (), CommandText);
  475. }
  476. try {
  477. Connection.Tds.Execute (sql, parms, CommandTimeout, wantResults);
  478. } catch (TdsTimeoutException ex) {
  479. Connection.Tds.Reset ();
  480. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  481. } catch (TdsInternalException ex) {
  482. Connection.Close ();
  483. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  484. }
  485. break;
  486. }
  487. }
  488. else {
  489. try {
  490. Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults);
  491. } catch (TdsTimeoutException ex) {
  492. Connection.Tds.Reset ();
  493. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  494. } catch (TdsInternalException ex) {
  495. Connection.Close ();
  496. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  497. }
  498. }
  499. }
  500. public
  501. #if NET_2_0
  502. override
  503. #endif // NET_2_0
  504. int ExecuteNonQuery ()
  505. {
  506. ValidateCommand ("ExecuteNonQuery", false);
  507. int result = 0;
  508. behavior = CommandBehavior.Default;
  509. try {
  510. Execute (false);
  511. result = Connection.Tds.RecordsAffected;
  512. } catch (TdsTimeoutException e) {
  513. Connection.Tds.Reset ();
  514. throw SqlException.FromTdsInternalException ((TdsInternalException) e);
  515. }
  516. GetOutputParameters ();
  517. return result;
  518. }
  519. public new SqlDataReader ExecuteReader ()
  520. {
  521. return ExecuteReader (CommandBehavior.Default);
  522. }
  523. public new SqlDataReader ExecuteReader (CommandBehavior behavior)
  524. {
  525. ValidateCommand ("ExecuteReader", false);
  526. if ((behavior & CommandBehavior.SingleRow) != 0)
  527. behavior |= CommandBehavior.SingleResult;
  528. this.behavior = behavior;
  529. if ((behavior & CommandBehavior.SequentialAccess) != 0)
  530. Tds.SequentialAccess = true;
  531. try {
  532. Execute (true);
  533. Connection.DataReader = new SqlDataReader (this);
  534. return Connection.DataReader;
  535. } catch {
  536. if ((behavior & CommandBehavior.CloseConnection) != 0)
  537. Connection.Close ();
  538. throw;
  539. }
  540. }
  541. public
  542. #if NET_2_0
  543. override
  544. #endif // NET_2_0
  545. object ExecuteScalar ()
  546. {
  547. try {
  548. object result = null;
  549. #if NET_2_0
  550. ValidateCommand ("ExecuteScalar", false);
  551. #else
  552. ValidateCommand ("ExecuteReader", false);
  553. #endif
  554. behavior = CommandBehavior.Default;
  555. Execute (true);
  556. try {
  557. if (Connection.Tds.NextResult () && Connection.Tds.NextRow ())
  558. result = Connection.Tds.ColumnValues[0];
  559. if (commandType == CommandType.StoredProcedure) {
  560. Connection.Tds.SkipToEnd ();
  561. GetOutputParameters ();
  562. }
  563. } catch (TdsTimeoutException ex) {
  564. Connection.Tds.Reset ();
  565. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  566. } catch (TdsInternalException ex) {
  567. Connection.Close ();
  568. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  569. }
  570. return result;
  571. } finally {
  572. CloseDataReader ();
  573. }
  574. }
  575. public XmlReader ExecuteXmlReader ()
  576. {
  577. ValidateCommand ("ExecuteXmlReader", false);
  578. behavior = CommandBehavior.Default;
  579. try {
  580. Execute (true);
  581. } catch (TdsTimeoutException e) {
  582. Connection.Tds.Reset ();
  583. throw SqlException.FromTdsInternalException ((TdsInternalException) e);
  584. }
  585. SqlDataReader dataReader = new SqlDataReader (this);
  586. SqlXmlTextReader textReader = new SqlXmlTextReader (dataReader);
  587. XmlReader xmlReader = new XmlTextReader (textReader);
  588. return xmlReader;
  589. }
  590. internal void GetOutputParameters ()
  591. {
  592. IList list = Connection.Tds.OutputParameters;
  593. if (list != null && list.Count > 0) {
  594. int index = 0;
  595. foreach (SqlParameter parameter in parameters) {
  596. if (parameter.Direction != ParameterDirection.Input &&
  597. parameter.Direction != ParameterDirection.ReturnValue) {
  598. parameter.Value = list [index];
  599. index += 1;
  600. }
  601. if (index >= list.Count)
  602. break;
  603. }
  604. }
  605. }
  606. object ICloneable.Clone ()
  607. {
  608. return new SqlCommand (commandText, connection, transaction, commandType, updatedRowSource, designTimeVisible, commandTimeout, parameters);
  609. }
  610. #if !NET_2_0
  611. IDbDataParameter IDbCommand.CreateParameter ()
  612. {
  613. return CreateParameter ();
  614. }
  615. IDataReader IDbCommand.ExecuteReader ()
  616. {
  617. return ExecuteReader ();
  618. }
  619. IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
  620. {
  621. return ExecuteReader (behavior);
  622. }
  623. #endif
  624. #if NET_2_0
  625. protected override void Dispose (bool disposing)
  626. {
  627. if (disposed) return;
  628. if (disposing) {
  629. parameters.Clear();
  630. if (Connection != null)
  631. Connection.DataReader = null;
  632. }
  633. base.Dispose (disposing);
  634. disposed = true;
  635. }
  636. #endif
  637. public
  638. #if NET_2_0
  639. override
  640. #endif // NET_2_0
  641. void Prepare ()
  642. {
  643. #if NET_2_0
  644. if (Connection == null)
  645. throw new NullReferenceException ();
  646. #endif
  647. if (CommandType == CommandType.StoredProcedure || CommandType == CommandType.Text && Parameters.Count == 0)
  648. return;
  649. ValidateCommand ("Prepare", false);
  650. try {
  651. foreach (SqlParameter param in Parameters)
  652. param.CheckIfInitialized ();
  653. } catch (Exception e) {
  654. throw new InvalidOperationException ("SqlCommand.Prepare requires " + e.Message);
  655. }
  656. preparedStatement = Connection.Tds.Prepare (CommandText, Parameters.MetaParameters);
  657. }
  658. public void ResetCommandTimeout ()
  659. {
  660. commandTimeout = DEFAULT_COMMAND_TIMEOUT;
  661. }
  662. private void Unprepare ()
  663. {
  664. Connection.Tds.Unprepare (preparedStatement);
  665. preparedStatement = null;
  666. }
  667. private void ValidateCommand (string method, bool async)
  668. {
  669. if (Connection == null)
  670. throw new InvalidOperationException (String.Format ("{0}: A Connection object is required to continue.", method));
  671. if (Transaction == null && Connection.Transaction != null)
  672. throw new InvalidOperationException (String.Format (
  673. "{0} requires a transaction if the command's connection is in a pending transaction.",
  674. #if NET_2_0
  675. method));
  676. #else
  677. "Execute"));
  678. #endif
  679. if (Transaction != null && Transaction.Connection != Connection)
  680. throw new InvalidOperationException ("The connection does not have the same transaction as the command.");
  681. if (Connection.State != ConnectionState.Open)
  682. throw new InvalidOperationException (String.Format ("{0} requires an open connection to continue. This connection is closed.", method));
  683. if (CommandText.Length == 0)
  684. throw new InvalidOperationException (String.Format ("{0}: CommandText has not been set for this Command.", method));
  685. if (Connection.DataReader != null)
  686. throw new InvalidOperationException ("There is already an open DataReader associated with this Connection which must be closed first.");
  687. if (Connection.XmlReader != null)
  688. throw new InvalidOperationException ("There is already an open XmlReader associated with this Connection which must be closed first.");
  689. #if NET_2_0
  690. if (async && !Connection.AsyncProcessing)
  691. throw new InvalidOperationException ("This Connection object is not " +
  692. "in Asynchronous mode. Use 'Asynchronous" +
  693. " Processing = true' to set it.");
  694. #endif // NET_2_0
  695. }
  696. #if NET_2_0
  697. protected override DbParameter CreateDbParameter ()
  698. {
  699. return CreateParameter ();
  700. }
  701. protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior)
  702. {
  703. return ExecuteReader (behavior);
  704. }
  705. protected override DbConnection DbConnection {
  706. get { return Connection; }
  707. set { Connection = (SqlConnection) value; }
  708. }
  709. protected override DbParameterCollection DbParameterCollection {
  710. get { return Parameters; }
  711. }
  712. protected override DbTransaction DbTransaction {
  713. get { return Transaction; }
  714. set { Transaction = (SqlTransaction) value; }
  715. }
  716. #endif // NET_2_0
  717. #endregion // Methods
  718. #if NET_2_0
  719. #region Asynchronous Methods
  720. internal IAsyncResult BeginExecuteInternal (CommandBehavior behavior,
  721. bool wantResults,
  722. AsyncCallback callback,
  723. object state)
  724. {
  725. IAsyncResult ar = null;
  726. Connection.Tds.RecordsAffected = -1;
  727. TdsMetaParameterCollection parms = Parameters.MetaParameters;
  728. if (preparedStatement == null) {
  729. bool schemaOnly = ((behavior & CommandBehavior.SchemaOnly) > 0);
  730. bool keyInfo = ((behavior & CommandBehavior.KeyInfo) > 0);
  731. StringBuilder sql1 = new StringBuilder ();
  732. StringBuilder sql2 = new StringBuilder ();
  733. if (schemaOnly || keyInfo)
  734. sql1.Append ("SET FMTONLY OFF;");
  735. if (keyInfo) {
  736. sql1.Append ("SET NO_BROWSETABLE ON;");
  737. sql2.Append ("SET NO_BROWSETABLE OFF;");
  738. }
  739. if (schemaOnly) {
  740. sql1.Append ("SET FMTONLY ON;");
  741. sql2.Append ("SET FMTONLY OFF;");
  742. }
  743. switch (CommandType) {
  744. case CommandType.StoredProcedure:
  745. string prolog = "";
  746. string epilog = "";
  747. if (keyInfo || schemaOnly)
  748. prolog = sql1.ToString ();
  749. if (keyInfo || schemaOnly)
  750. epilog = sql2.ToString ();
  751. try {
  752. Connection.Tds.BeginExecuteProcedure (prolog,
  753. epilog,
  754. CommandText,
  755. !wantResults,
  756. parms,
  757. callback,
  758. state);
  759. } catch (TdsTimeoutException ex) {
  760. Connection.Tds.Reset ();
  761. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  762. } catch (TdsInternalException ex) {
  763. Connection.Close ();
  764. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  765. }
  766. break;
  767. case CommandType.Text:
  768. string sql = String.Format ("{0}{1};{2}", sql1.ToString (), CommandText, sql2.ToString ());
  769. try {
  770. if (wantResults)
  771. ar = Connection.Tds.BeginExecuteQuery (sql, parms, callback, state);
  772. else
  773. ar = Connection.Tds.BeginExecuteNonQuery (sql, parms, callback, state);
  774. } catch (TdsTimeoutException ex) {
  775. Connection.Tds.Reset ();
  776. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  777. } catch (TdsInternalException ex) {
  778. Connection.Close ();
  779. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  780. }
  781. break;
  782. }
  783. }
  784. else {
  785. try {
  786. Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults);
  787. } catch (TdsTimeoutException ex) {
  788. Connection.Tds.Reset ();
  789. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  790. } catch (TdsInternalException ex) {
  791. Connection.Close ();
  792. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  793. }
  794. }
  795. return ar;
  796. }
  797. internal void EndExecuteInternal (IAsyncResult ar)
  798. {
  799. SqlAsyncResult sqlResult = ( (SqlAsyncResult) ar);
  800. Connection.Tds.WaitFor (sqlResult.InternalResult);
  801. Connection.Tds.CheckAndThrowException (sqlResult.InternalResult);
  802. }
  803. public IAsyncResult BeginExecuteNonQuery ()
  804. {
  805. return BeginExecuteNonQuery (null, null);
  806. }
  807. public IAsyncResult BeginExecuteNonQuery (AsyncCallback callback, object stateObject)
  808. {
  809. ValidateCommand ("BeginExecuteNonQuery", true);
  810. SqlAsyncResult ar = new SqlAsyncResult (callback, stateObject);
  811. ar.EndMethod = "EndExecuteNonQuery";
  812. ar.InternalResult = BeginExecuteInternal (CommandBehavior.Default, false, ar.BubbleCallback, ar);
  813. return ar;
  814. }
  815. public int EndExecuteNonQuery (IAsyncResult asyncResult)
  816. {
  817. ValidateAsyncResult (asyncResult, "EndExecuteNonQuery");
  818. EndExecuteInternal (asyncResult);
  819. int ret = Connection.Tds.RecordsAffected;
  820. GetOutputParameters ();
  821. ((SqlAsyncResult) asyncResult).Ended = true;
  822. return ret;
  823. }
  824. public IAsyncResult BeginExecuteReader ()
  825. {
  826. return BeginExecuteReader (null, null, CommandBehavior.Default);
  827. }
  828. public IAsyncResult BeginExecuteReader (CommandBehavior behavior)
  829. {
  830. return BeginExecuteReader (null, null, behavior);
  831. }
  832. public IAsyncResult BeginExecuteReader (AsyncCallback callback, object stateObject)
  833. {
  834. return BeginExecuteReader (callback, stateObject, CommandBehavior.Default);
  835. }
  836. public IAsyncResult BeginExecuteReader (AsyncCallback callback, object stateObject, CommandBehavior behavior)
  837. {
  838. ValidateCommand ("BeginExecuteReader", true);
  839. this.behavior = behavior;
  840. SqlAsyncResult ar = new SqlAsyncResult (callback, stateObject);
  841. ar.EndMethod = "EndExecuteReader";
  842. IAsyncResult tdsResult = BeginExecuteInternal (behavior, true,
  843. ar.BubbleCallback, stateObject);
  844. ar.InternalResult = tdsResult;
  845. return ar;
  846. }
  847. public SqlDataReader EndExecuteReader (IAsyncResult asyncResult)
  848. {
  849. ValidateAsyncResult (asyncResult, "EndExecuteReader");
  850. EndExecuteInternal (asyncResult);
  851. SqlDataReader reader = null;
  852. try {
  853. reader = new SqlDataReader (this);
  854. } catch (TdsTimeoutException e) {
  855. throw SqlException.FromTdsInternalException ((TdsInternalException) e);
  856. } catch (TdsInternalException e) {
  857. // if behavior is closeconnection, even if it throws exception
  858. // the connection has to be closed.
  859. if ((behavior & CommandBehavior.CloseConnection) != 0)
  860. Connection.Close ();
  861. throw SqlException.FromTdsInternalException ((TdsInternalException) e);
  862. }
  863. ((SqlAsyncResult) asyncResult).Ended = true;
  864. return reader;
  865. }
  866. public IAsyncResult BeginExecuteXmlReader (AsyncCallback callback, object stateObject)
  867. {
  868. ValidateCommand ("BeginExecuteXmlReader", true);
  869. SqlAsyncResult ar = new SqlAsyncResult (callback, stateObject);
  870. ar.EndMethod = "EndExecuteXmlReader";
  871. ar.InternalResult = BeginExecuteInternal (behavior, true,
  872. ar.BubbleCallback, stateObject);
  873. return ar;
  874. }
  875. public IAsyncResult BeginExecuteXmlReader ()
  876. {
  877. return BeginExecuteXmlReader (null, null);
  878. }
  879. public XmlReader EndExecuteXmlReader (IAsyncResult asyncResult)
  880. {
  881. ValidateAsyncResult (asyncResult, "EndExecuteXmlReader");
  882. EndExecuteInternal (asyncResult);
  883. SqlDataReader reader = new SqlDataReader (this);
  884. SqlXmlTextReader textReader = new SqlXmlTextReader (reader);
  885. XmlReader xmlReader = new XmlTextReader (textReader);
  886. ((SqlAsyncResult) asyncResult).Ended = true;
  887. return xmlReader;
  888. }
  889. internal void ValidateAsyncResult (IAsyncResult ar, string endMethod)
  890. {
  891. if (ar == null)
  892. throw new ArgumentException ("result passed is null!");
  893. if (! (ar is SqlAsyncResult))
  894. throw new ArgumentException (String.Format ("cannot test validity of types {0}",
  895. ar.GetType ()));
  896. SqlAsyncResult result = (SqlAsyncResult) ar;
  897. if (result.EndMethod != endMethod)
  898. throw new InvalidOperationException (String.Format ("Mismatched {0} called for AsyncResult. " +
  899. "Expected call to {1} but {0} is called instead.",
  900. endMethod, result.EndMethod));
  901. if (result.Ended)
  902. throw new InvalidOperationException (String.Format ("The method {0} cannot be called " +
  903. "more than once for the same AsyncResult.", endMethod));
  904. }
  905. #endregion // Asynchronous Methods
  906. public event StatementCompletedEventHandler StatementCompleted;
  907. #endif // NET_2_0
  908. }
  909. }