SqlCommand.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. //
  2. // System.Data.SqlClient.SqlCommand.cs
  3. //
  4. // Author:
  5. // Rodrigo Moya ([email protected])
  6. // Daniel Morgan ([email protected])
  7. // Tim Coleman ([email protected])
  8. // Diego Caravana ([email protected])
  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. bool disposed = false;
  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 = null;
  73. #if NET_2_0
  74. SqlNotificationRequest notification;
  75. #endif
  76. bool notificationAutoEnlist;
  77. #endregion // Fields
  78. #region Constructors
  79. public SqlCommand()
  80. : this (String.Empty, null, null)
  81. {
  82. }
  83. public SqlCommand (string commandText)
  84. : this (commandText, null, null)
  85. {
  86. }
  87. public SqlCommand (string commandText, SqlConnection connection)
  88. : this (commandText, connection, null)
  89. {
  90. }
  91. public SqlCommand (string commandText, SqlConnection connection, SqlTransaction transaction)
  92. {
  93. this.commandText = commandText;
  94. this.connection = connection;
  95. this.transaction = transaction;
  96. this.commandType = CommandType.Text;
  97. this.updatedRowSource = UpdateRowSource.Both;
  98. this.designTimeVisible = false;
  99. this.commandTimeout = 30;
  100. notificationAutoEnlist = true;
  101. parameters = new SqlParameterCollection (this);
  102. }
  103. private SqlCommand(string commandText, SqlConnection connection, SqlTransaction transaction, CommandType commandType, UpdateRowSource updatedRowSource, bool designTimeVisible, int commandTimeout, SqlParameterCollection parameters)
  104. {
  105. this.commandText = commandText;
  106. this.connection = connection;
  107. this.transaction = transaction;
  108. this.commandType = commandType;
  109. this.updatedRowSource = updatedRowSource;
  110. this.designTimeVisible = designTimeVisible;
  111. this.commandTimeout = commandTimeout;
  112. this.parameters = new SqlParameterCollection(this);
  113. for (int i = 0;i < parameters.Count;i++)
  114. this.parameters.Add(((ICloneable)parameters[i]).Clone());
  115. }
  116. #endregion // Constructors
  117. #region Properties
  118. internal CommandBehavior CommandBehavior {
  119. get { return behavior; }
  120. }
  121. #if !NET_2_0
  122. [DataSysDescription ("Command text to execute.")]
  123. #endif
  124. [DefaultValue ("")]
  125. [EditorAttribute ("Microsoft.VSDesigner.Data.SQL.Design.SqlCommandTextEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
  126. [RefreshProperties (RefreshProperties.All)]
  127. public
  128. #if NET_2_0
  129. override
  130. #endif //NET_2_0
  131. string CommandText {
  132. get { return commandText; }
  133. set {
  134. if (value != commandText && preparedStatement != null)
  135. Unprepare ();
  136. commandText = value;
  137. }
  138. }
  139. #if !NET_2_0
  140. [DataSysDescription ("Time to wait for command to execute.")]
  141. [DefaultValue (30)]
  142. #endif
  143. public
  144. #if NET_2_0
  145. override
  146. #endif //NET_2_0
  147. int CommandTimeout {
  148. get { return commandTimeout; }
  149. set {
  150. if (value < 0)
  151. throw new ArgumentException ("The property value assigned is less than 0.");
  152. commandTimeout = value;
  153. }
  154. }
  155. #if !NET_2_0
  156. [DataSysDescription ("How to interpret the CommandText.")]
  157. #endif
  158. [DefaultValue (CommandType.Text)]
  159. [RefreshProperties (RefreshProperties.All)]
  160. public
  161. #if NET_2_0
  162. override
  163. #endif //NET_2_0
  164. CommandType CommandType {
  165. get { return commandType; }
  166. set {
  167. if (value == CommandType.TableDirect)
  168. #if NET_2_0
  169. throw new ArgumentOutOfRangeException ("CommandType.TableDirect is not supported " +
  170. "by the Mono SqlClient Data Provider.");
  171. #else
  172. throw new ArgumentException ("CommandType.TableDirect is not supported by the Mono SqlClient Data Provider.");
  173. #endif
  174. if (!Enum.IsDefined (typeof (CommandType), value))
  175. #if NET_2_0
  176. throw new ArgumentOutOfRangeException (String.Format ("The CommandType enumeration value, {0}, is invalid",
  177. value));
  178. #else
  179. throw ExceptionHelper.InvalidEnumValueException ("CommandType", value);
  180. #endif
  181. commandType = value;
  182. }
  183. }
  184. [DefaultValue (null)]
  185. #if !NET_2_0
  186. [DataSysDescription ("Connection used by the command.")]
  187. #endif
  188. [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
  189. public
  190. #if NET_2_0
  191. new
  192. #endif //NET_2_0
  193. SqlConnection Connection {
  194. get { return connection; }
  195. set {
  196. if (transaction != null && connection.Transaction != null && connection.Transaction.IsOpen)
  197. throw new InvalidOperationException ("The Connection property was changed while a transaction was in progress.");
  198. transaction = null;
  199. connection = value;
  200. }
  201. }
  202. [Browsable (false)]
  203. [DefaultValue (true)]
  204. [DesignOnly (true)]
  205. #if NET_2_0
  206. [EditorBrowsable (EditorBrowsableState.Never)]
  207. #endif
  208. public
  209. #if NET_2_0
  210. override
  211. #endif //NET_2_0
  212. bool DesignTimeVisible {
  213. get { return designTimeVisible; }
  214. set { designTimeVisible = value; }
  215. }
  216. #if !NET_2_0
  217. [DataSysDescription ("The parameters collection.")]
  218. #endif
  219. [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
  220. public
  221. #if NET_2_0
  222. new
  223. #endif //NET_2_0
  224. SqlParameterCollection Parameters {
  225. get { return parameters; }
  226. }
  227. internal ITds Tds {
  228. get { return Connection.Tds; }
  229. }
  230. IDbConnection IDbCommand.Connection {
  231. get { return Connection; }
  232. set {
  233. if (!(value == null || value is SqlConnection))
  234. throw new InvalidCastException ("The value was not a valid SqlConnection.");
  235. Connection = (SqlConnection) value;
  236. }
  237. }
  238. IDataParameterCollection IDbCommand.Parameters {
  239. get { return Parameters; }
  240. }
  241. IDbTransaction IDbCommand.Transaction {
  242. get { return Transaction; }
  243. set {
  244. if (!(value == null || value is SqlTransaction))
  245. throw new ArgumentException ();
  246. Transaction = (SqlTransaction) value;
  247. }
  248. }
  249. [Browsable (false)]
  250. #if !NET_2_0
  251. [DataSysDescription ("The transaction used by the command.")]
  252. #endif
  253. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  254. public new SqlTransaction Transaction {
  255. get { return transaction; }
  256. set { transaction = value; }
  257. }
  258. #if !NET_2_0
  259. [DataSysDescription ("When used by a DataAdapter.Update, how command results are applied to the current DataRow.")]
  260. #endif
  261. [DefaultValue (UpdateRowSource.Both)]
  262. public
  263. #if NET_2_0
  264. override
  265. #endif // NET_2_0
  266. UpdateRowSource UpdatedRowSource {
  267. get { return updatedRowSource; }
  268. set {
  269. if (!Enum.IsDefined (typeof (UpdateRowSource), value))
  270. #if NET_2_0
  271. throw new ArgumentOutOfRangeException (String.Format ("The UpdateRowSource enumeration value, {0}, is invalid",
  272. value));
  273. #else
  274. throw ExceptionHelper.InvalidEnumValueException ("UpdateRowSource", value);
  275. #endif
  276. updatedRowSource = value;
  277. }
  278. }
  279. #if NET_2_0
  280. [Browsable (false)]
  281. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  282. public SqlNotificationRequest Notification {
  283. get { return notification; }
  284. set { notification = value; }
  285. }
  286. [DefaultValue (true)]
  287. public bool NotificationAutoEnlist {
  288. get { return notificationAutoEnlist; }
  289. set { notificationAutoEnlist = value; }
  290. }
  291. #endif
  292. #endregion // Fields
  293. #region Methods
  294. public
  295. #if NET_2_0
  296. override
  297. #endif // NET_2_0
  298. void Cancel ()
  299. {
  300. if (Connection == null || Connection.Tds == null)
  301. return;
  302. Connection.Tds.Cancel ();
  303. }
  304. #if NET_2_0
  305. public SqlCommand Clone ()
  306. {
  307. return new SqlCommand (commandText, connection, transaction, commandType, updatedRowSource, designTimeVisible, commandTimeout, parameters);
  308. }
  309. #endif // NET_2_0
  310. internal void CloseDataReader (bool moreResults)
  311. {
  312. Connection.DataReader = null;
  313. if ((behavior & CommandBehavior.CloseConnection) != 0)
  314. Connection.Close ();
  315. // Reset the behavior
  316. behavior = CommandBehavior.Default;
  317. if (Tds != null)
  318. Tds.SequentialAccess = false;
  319. }
  320. public new SqlParameter CreateParameter ()
  321. {
  322. return new SqlParameter ();
  323. }
  324. internal void DeriveParameters ()
  325. {
  326. if (commandType != CommandType.StoredProcedure)
  327. throw new InvalidOperationException (String.Format ("SqlCommand DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType));
  328. ValidateCommand ("DeriveParameters");
  329. SqlParameterCollection localParameters = new SqlParameterCollection (this);
  330. localParameters.Add ("@procedure_name", SqlDbType.NVarChar, commandText.Length).Value = commandText;
  331. string sql = "sp_procedure_params_rowset";
  332. try {
  333. Connection.Tds.ExecProc (sql, localParameters.MetaParameters, 0, true);
  334. } catch (TdsInternalException ex) {
  335. Connection.Close ();
  336. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  337. }
  338. SqlDataReader reader = new SqlDataReader (this);
  339. parameters.Clear ();
  340. object[] dbValues = new object[reader.FieldCount];
  341. while (reader.Read ()) {
  342. reader.GetValues (dbValues);
  343. parameters.Add (new SqlParameter (dbValues));
  344. }
  345. reader.Close ();
  346. }
  347. private void Execute (CommandBehavior behavior, bool wantResults)
  348. {
  349. int index = 0;
  350. Connection.Tds.RecordsAffected = -1;
  351. TdsMetaParameterCollection parms = Parameters.MetaParameters;
  352. foreach (TdsMetaParameter param in parms) {
  353. param.Validate (index++);
  354. }
  355. if (preparedStatement == null) {
  356. bool schemaOnly = ((behavior & CommandBehavior.SchemaOnly) > 0);
  357. bool keyInfo = ((behavior & CommandBehavior.KeyInfo) > 0);
  358. StringBuilder sql1 = new StringBuilder ();
  359. StringBuilder sql2 = new StringBuilder ();
  360. if (schemaOnly || keyInfo)
  361. sql1.Append ("SET FMTONLY OFF;");
  362. if (keyInfo) {
  363. sql1.Append ("SET NO_BROWSETABLE ON;");
  364. sql2.Append ("SET NO_BROWSETABLE OFF;");
  365. }
  366. if (schemaOnly) {
  367. sql1.Append ("SET FMTONLY ON;");
  368. sql2.Append ("SET FMTONLY OFF;");
  369. }
  370. switch (CommandType) {
  371. case CommandType.StoredProcedure:
  372. try {
  373. if (keyInfo || schemaOnly)
  374. Connection.Tds.Execute (sql1.ToString ());
  375. Connection.Tds.ExecProc (CommandText, parms, CommandTimeout, wantResults);
  376. if (keyInfo || schemaOnly)
  377. Connection.Tds.Execute (sql2.ToString ());
  378. } catch (TdsInternalException ex) {
  379. Connection.Close ();
  380. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  381. }
  382. break;
  383. case CommandType.Text:
  384. string sql;
  385. if (sql2.Length > 0) {
  386. sql = String.Format ("{0}{1};{2}", sql1.ToString (), CommandText, sql2.ToString ());
  387. } else {
  388. sql = String.Format ("{0}{1}", sql1.ToString (), CommandText);
  389. }
  390. try {
  391. Connection.Tds.Execute (sql, parms, CommandTimeout, wantResults);
  392. } catch (TdsInternalException ex) {
  393. Connection.Close ();
  394. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  395. }
  396. break;
  397. }
  398. }
  399. else {
  400. try {
  401. Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults);
  402. } catch (TdsInternalException ex) {
  403. Connection.Close ();
  404. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  405. }
  406. }
  407. }
  408. public
  409. #if NET_2_0
  410. override
  411. #endif // NET_2_0
  412. int ExecuteNonQuery ()
  413. {
  414. ValidateCommand ("ExecuteNonQuery");
  415. int result = 0;
  416. behavior = CommandBehavior.Default;
  417. try {
  418. Execute (CommandBehavior.Default, false);
  419. result = Connection.Tds.RecordsAffected;
  420. }
  421. catch (TdsTimeoutException e) {
  422. throw SqlException.FromTdsInternalException ((TdsInternalException) e);
  423. }
  424. GetOutputParameters ();
  425. return result;
  426. }
  427. public new SqlDataReader ExecuteReader ()
  428. {
  429. return ExecuteReader (CommandBehavior.Default);
  430. }
  431. public new SqlDataReader ExecuteReader (CommandBehavior behavior)
  432. {
  433. ValidateCommand ("ExecuteReader");
  434. try {
  435. this.behavior = behavior;
  436. if ((behavior & CommandBehavior.SequentialAccess) != 0)
  437. Tds.SequentialAccess = true;
  438. Execute (behavior, true);
  439. Connection.DataReader = new SqlDataReader (this);
  440. } catch (TdsTimeoutException e) {
  441. // if behavior is closeconnection, even if it throws exception
  442. // the connection has to be closed.
  443. if ((behavior & CommandBehavior.CloseConnection) != 0)
  444. Connection.Close ();
  445. throw SqlException.FromTdsInternalException ((TdsInternalException) e);
  446. } catch (SqlException) {
  447. // if behavior is closeconnection, even if it throws exception
  448. // the connection has to be closed.
  449. if ((behavior & CommandBehavior.CloseConnection) != 0)
  450. Connection.Close ();
  451. throw;
  452. }
  453. return Connection.DataReader;
  454. }
  455. public
  456. #if NET_2_0
  457. override
  458. #endif // NET_2_0
  459. object ExecuteScalar ()
  460. {
  461. try {
  462. object result = null;
  463. ValidateCommand ("ExecuteScalar");
  464. behavior = CommandBehavior.Default;
  465. try {
  466. Execute (CommandBehavior.Default, true);
  467. }
  468. catch (TdsTimeoutException e) {
  469. throw SqlException.FromTdsInternalException ((TdsInternalException) e);
  470. }
  471. try {
  472. if (Connection.Tds.NextResult () && Connection.Tds.NextRow ())
  473. result = Connection.Tds.ColumnValues[0];
  474. if (commandType == CommandType.StoredProcedure) {
  475. Connection.Tds.SkipToEnd ();
  476. GetOutputParameters ();
  477. }
  478. } catch (TdsInternalException ex) {
  479. Connection.Close ();
  480. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  481. }
  482. return result;
  483. }
  484. finally {
  485. CloseDataReader (true);
  486. }
  487. }
  488. public XmlReader ExecuteXmlReader ()
  489. {
  490. ValidateCommand ("ExecuteXmlReader");
  491. behavior = CommandBehavior.Default;
  492. try {
  493. Execute (CommandBehavior.Default, true);
  494. } catch (TdsTimeoutException e) {
  495. throw SqlException.FromTdsInternalException ((TdsInternalException) e);
  496. }
  497. SqlDataReader dataReader = new SqlDataReader (this);
  498. SqlXmlTextReader textReader = new SqlXmlTextReader (dataReader);
  499. XmlReader xmlReader = new XmlTextReader (textReader);
  500. return xmlReader;
  501. }
  502. internal void GetOutputParameters ()
  503. {
  504. IList list = Connection.Tds.OutputParameters;
  505. if (list != null && list.Count > 0) {
  506. int index = 0;
  507. foreach (SqlParameter parameter in parameters) {
  508. if (parameter.Direction != ParameterDirection.Input) {
  509. parameter.Value = list [index];
  510. index += 1;
  511. }
  512. if (index >= list.Count)
  513. break;
  514. }
  515. }
  516. }
  517. object ICloneable.Clone ()
  518. {
  519. return new SqlCommand (commandText, connection, transaction, commandType, updatedRowSource, designTimeVisible, commandTimeout, parameters);
  520. }
  521. #if !NET_2_0
  522. IDbDataParameter IDbCommand.CreateParameter ()
  523. {
  524. return CreateParameter ();
  525. }
  526. IDataReader IDbCommand.ExecuteReader ()
  527. {
  528. return ExecuteReader ();
  529. }
  530. IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
  531. {
  532. return ExecuteReader (behavior);
  533. }
  534. #endif
  535. #if NET_2_0
  536. protected override void Dispose (bool disposing)
  537. {
  538. if (disposed) return;
  539. if (disposing) {
  540. parameters.Clear();
  541. }
  542. base.Dispose (disposing);
  543. disposed = true;
  544. }
  545. #endif
  546. public
  547. #if NET_2_0
  548. override
  549. #endif // NET_2_0
  550. void Prepare ()
  551. {
  552. ValidateCommand ("Prepare");
  553. if (CommandType == CommandType.StoredProcedure)
  554. return;
  555. try {
  556. foreach (SqlParameter param in Parameters)
  557. param.CheckIfInitialized ();
  558. } catch (Exception e) {
  559. throw new InvalidOperationException ("SqlCommand.Prepare requires " + e.Message);
  560. }
  561. preparedStatement = Connection.Tds.Prepare (CommandText, Parameters.MetaParameters);
  562. }
  563. public void ResetCommandTimeout ()
  564. {
  565. commandTimeout = 30;
  566. }
  567. private void Unprepare ()
  568. {
  569. Connection.Tds.Unprepare (preparedStatement);
  570. preparedStatement = null;
  571. }
  572. private void ValidateCommand (string method)
  573. {
  574. if (Connection == null)
  575. #if NET_2_0
  576. throw new NullReferenceException (String.Format ("{0} requires a Connection object to continue.", method));
  577. #else
  578. throw new InvalidOperationException (String.Format ("{0} requires a Connection object to continue.", method));
  579. #endif
  580. if (Connection.Transaction != null && transaction != Connection.Transaction)
  581. throw new InvalidOperationException ("The Connection object does not have the same transaction as the command object.");
  582. if (Connection.State != ConnectionState.Open)
  583. #if NET_2_0
  584. throw new NullReferenceException (String.Format ("ExecuteNonQuery requires an open Connection object to continue. This connection is closed.", method));
  585. #else
  586. throw new InvalidOperationException (String.Format ("ExecuteNonQuery requires an open Connection object to continue. This connection is closed.", method));
  587. #endif
  588. if (commandText == String.Empty || commandText == null)
  589. throw new InvalidOperationException ("The command text for this Command has not been set.");
  590. if (Connection.DataReader != null)
  591. throw new InvalidOperationException ("There is already an open DataReader associated with this Connection which must be closed first.");
  592. if (Connection.XmlReader != null)
  593. throw new InvalidOperationException ("There is already an open XmlReader associated with this Connection which must be closed first.");
  594. #if NET_2_0
  595. if (method.StartsWith ("Begin") && !Connection.AsyncProcessing)
  596. throw new InvalidOperationException ("This Connection object is not " +
  597. "in Asynchronous mode. Use 'Asynchronous" +
  598. " Processing = true' to set it.");
  599. #endif // NET_2_0
  600. }
  601. #if NET_2_0
  602. protected override DbParameter CreateDbParameter ()
  603. {
  604. return CreateParameter ();
  605. }
  606. protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior)
  607. {
  608. return ExecuteReader (behavior);
  609. }
  610. protected override DbConnection DbConnection {
  611. get { return Connection; }
  612. set { Connection = (SqlConnection) value; }
  613. }
  614. protected override DbParameterCollection DbParameterCollection {
  615. get { return Parameters; }
  616. }
  617. protected override DbTransaction DbTransaction {
  618. get { return Transaction; }
  619. set { Transaction = (SqlTransaction) value; }
  620. }
  621. #endif // NET_2_0
  622. #endregion // Methods
  623. #if NET_2_0
  624. #region Asynchronous Methods
  625. internal IAsyncResult BeginExecuteInternal (CommandBehavior behavior,
  626. bool wantResults,
  627. AsyncCallback callback,
  628. object state)
  629. {
  630. IAsyncResult ar = null;
  631. Connection.Tds.RecordsAffected = -1;
  632. TdsMetaParameterCollection parms = Parameters.MetaParameters;
  633. if (preparedStatement == null) {
  634. bool schemaOnly = ((behavior & CommandBehavior.SchemaOnly) > 0);
  635. bool keyInfo = ((behavior & CommandBehavior.KeyInfo) > 0);
  636. StringBuilder sql1 = new StringBuilder ();
  637. StringBuilder sql2 = new StringBuilder ();
  638. if (schemaOnly || keyInfo)
  639. sql1.Append ("SET FMTONLY OFF;");
  640. if (keyInfo) {
  641. sql1.Append ("SET NO_BROWSETABLE ON;");
  642. sql2.Append ("SET NO_BROWSETABLE OFF;");
  643. }
  644. if (schemaOnly) {
  645. sql1.Append ("SET FMTONLY ON;");
  646. sql2.Append ("SET FMTONLY OFF;");
  647. }
  648. switch (CommandType) {
  649. case CommandType.StoredProcedure:
  650. string prolog = "";
  651. string epilog = "";
  652. if (keyInfo || schemaOnly)
  653. prolog = sql1.ToString ();
  654. if (keyInfo || schemaOnly)
  655. epilog = sql2.ToString ();
  656. try {
  657. Connection.Tds.BeginExecuteProcedure (prolog,
  658. epilog,
  659. CommandText,
  660. !wantResults,
  661. parms,
  662. callback,
  663. state);
  664. } catch (TdsInternalException ex) {
  665. Connection.Close ();
  666. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  667. }
  668. break;
  669. case CommandType.Text:
  670. string sql = String.Format ("{0}{1};{2}", sql1.ToString (), CommandText, sql2.ToString ());
  671. try {
  672. if (wantResults)
  673. ar = Connection.Tds.BeginExecuteQuery (sql, parms, callback, state);
  674. else
  675. ar = Connection.Tds.BeginExecuteNonQuery (sql, parms, callback, state);
  676. } catch (TdsInternalException ex) {
  677. Connection.Close ();
  678. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  679. }
  680. break;
  681. }
  682. }
  683. else {
  684. try {
  685. Connection.Tds.ExecPrepared (preparedStatement, parms, CommandTimeout, wantResults);
  686. } catch (TdsInternalException ex) {
  687. Connection.Close ();
  688. throw SqlException.FromTdsInternalException ((TdsInternalException) ex);
  689. }
  690. }
  691. return ar;
  692. }
  693. internal void EndExecuteInternal (IAsyncResult ar)
  694. {
  695. SqlAsyncResult sqlResult = ( (SqlAsyncResult) ar);
  696. Connection.Tds.WaitFor (sqlResult.InternalResult);
  697. Connection.Tds.CheckAndThrowException (sqlResult.InternalResult);
  698. }
  699. public IAsyncResult BeginExecuteNonQuery ()
  700. {
  701. return BeginExecuteNonQuery (null, null);
  702. }
  703. public IAsyncResult BeginExecuteNonQuery (AsyncCallback callback, object state)
  704. {
  705. ValidateCommand ("BeginExecuteNonQuery");
  706. SqlAsyncResult ar = new SqlAsyncResult (callback, state);
  707. ar.EndMethod = "EndExecuteNonQuery";
  708. ar.InternalResult = BeginExecuteInternal (CommandBehavior.Default, false, ar.BubbleCallback, ar);
  709. return ar;
  710. }
  711. public int EndExecuteNonQuery (IAsyncResult ar)
  712. {
  713. ValidateAsyncResult (ar, "EndExecuteNonQuery");
  714. EndExecuteInternal (ar);
  715. int ret = Connection.Tds.RecordsAffected;
  716. GetOutputParameters ();
  717. ((SqlAsyncResult) ar).Ended = true;
  718. return ret;
  719. }
  720. public IAsyncResult BeginExecuteReader ()
  721. {
  722. return BeginExecuteReader (null, null, CommandBehavior.Default);
  723. }
  724. public IAsyncResult BeginExecuteReader (CommandBehavior behavior)
  725. {
  726. return BeginExecuteReader (null, null, behavior);
  727. }
  728. public IAsyncResult BeginExecuteReader (AsyncCallback callback, object state)
  729. {
  730. return BeginExecuteReader (callback, state, CommandBehavior.Default);
  731. }
  732. public IAsyncResult BeginExecuteReader (AsyncCallback callback, object state, CommandBehavior behavior)
  733. {
  734. ValidateCommand ("BeginExecuteReader");
  735. this.behavior = behavior;
  736. SqlAsyncResult ar = new SqlAsyncResult (callback, state);
  737. ar.EndMethod = "EndExecuteReader";
  738. IAsyncResult tdsResult = BeginExecuteInternal (behavior, true,
  739. ar.BubbleCallback, state);
  740. ar.InternalResult = tdsResult;
  741. return ar;
  742. }
  743. public SqlDataReader EndExecuteReader (IAsyncResult ar)
  744. {
  745. ValidateAsyncResult (ar, "EndExecuteReader");
  746. EndExecuteInternal (ar);
  747. SqlDataReader reader = null;
  748. try {
  749. reader = new SqlDataReader (this);
  750. } catch (TdsTimeoutException e) {
  751. // if behavior is closeconnection, even if it throws exception
  752. // the connection has to be closed.
  753. if ((behavior & CommandBehavior.CloseConnection) != 0)
  754. Connection.Close ();
  755. throw SqlException.FromTdsInternalException ((TdsInternalException) e);
  756. } catch (SqlException) {
  757. // if behavior is closeconnection, even if it throws exception
  758. // the connection has to be closed.
  759. if ((behavior & CommandBehavior.CloseConnection) != 0)
  760. Connection.Close ();
  761. throw;
  762. }
  763. ((SqlAsyncResult) ar).Ended = true;
  764. return reader;
  765. }
  766. public IAsyncResult BeginExecuteXmlReader (AsyncCallback callback, object state)
  767. {
  768. ValidateCommand ("BeginExecuteXmlReader");
  769. SqlAsyncResult ar = new SqlAsyncResult (callback, state);
  770. ar.EndMethod = "EndExecuteXmlReader";
  771. ar.InternalResult = BeginExecuteInternal (behavior, true,
  772. ar.BubbleCallback, state);
  773. return ar;
  774. }
  775. public IAsyncResult BeginExecuteXmlReader ()
  776. {
  777. return BeginExecuteXmlReader (null, null);
  778. }
  779. public XmlReader EndExecuteXmlReader (IAsyncResult ar)
  780. {
  781. ValidateAsyncResult (ar, "EndExecuteXmlReader");
  782. EndExecuteInternal (ar);
  783. SqlDataReader reader = new SqlDataReader (this);
  784. SqlXmlTextReader textReader = new SqlXmlTextReader (reader);
  785. XmlReader xmlReader = new XmlTextReader (textReader);
  786. ((SqlAsyncResult) ar).Ended = true;
  787. return xmlReader;
  788. }
  789. internal void ValidateAsyncResult (IAsyncResult ar, string endMethod)
  790. {
  791. if (ar == null)
  792. throw new ArgumentException ("result passed is null!");
  793. if (! (ar is SqlAsyncResult))
  794. throw new ArgumentException (String.Format ("cannot test validity of types {0}",
  795. ar.GetType ()));
  796. SqlAsyncResult result = (SqlAsyncResult) ar;
  797. if (result.EndMethod != endMethod)
  798. throw new InvalidOperationException (String.Format ("Mismatched {0} called for AsyncResult. " +
  799. "Expected call to {1} but {0} is called instead.",
  800. endMethod, result.EndMethod));
  801. if (result.Ended)
  802. throw new InvalidOperationException (String.Format ("The method {0} cannot be called " +
  803. "more than once for the same AsyncResult.", endMethod));
  804. }
  805. #endregion // Asynchronous Methods
  806. public event StatementCompletedEventHandler StatementCompleted;
  807. #endif // NET_2_0
  808. }
  809. }