PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/Core/System.Data.EffiProz/EfzCommand.cs

https://bitbucket.org/efz/effiproz
C# | 715 lines | 471 code | 80 blank | 164 comment | 79 complexity | 2d7fdea057d3c61a7def9d90f1855295 MD5 | raw file
  1. //
  2. // (C) Copyright 2009,2010 EffiProz Systems
  3. // All rights reserved.
  4. // NOTICE: This code has not been licensed under any public license.
  5. // Author: Irantha Suwandarathna (irantha@gmail.com)
  6. //
  7. /********************************************************
  8. * ADO.NET 2.0 Data Provider for SQLLite Version 3.X
  9. * Written by Robert Simpson (robert@blackcastlesoft.com)
  10. ********************************************************/
  11. #if !SILVERLIGHT
  12. using System.ComponentModel;
  13. using System.Data.Common;
  14. #endif
  15. using System.Collections.Generic;
  16. namespace System.Data.EffiProz
  17. {
  18. #if !PLATFORM_COMPACTFRAMEWORK && !SILVERLIGHT
  19. [Designer(
  20. "EffiProz.Designer.EfzCommandDesigner, EffiProz.Designer, Version=1.5.0.0, Culture=neutral, PublicKeyToken=9c147f7358eea142"
  21. ), ToolboxItem(true)]
  22. #endif
  23. public sealed class EfzCommand
  24. #if !SILVERLIGHT
  25. : DbCommand, ICloneable
  26. #else
  27. : IDisposable
  28. #endif
  29. {
  30. private CommandType _commandType;
  31. /// <summary>
  32. /// The command text this command is based on
  33. /// </summary>
  34. private string _commandText;
  35. /// <summary>
  36. /// The connection the command is associated with
  37. /// </summary>
  38. private EfzConnection _cnn;
  39. /// <summary>
  40. /// The version of the connection the command is associated with
  41. /// </summary>
  42. private long _version;
  43. /// <summary>
  44. /// Indicates whether or not a DataReader is active on the command.
  45. /// </summary>
  46. private WeakReference _activeReader;
  47. /// <summary>
  48. /// The timeout for the command, kludged because EffiProz doesn't support per-command timeout values
  49. /// </summary>
  50. private int _commandTimeout;
  51. /// <summary>
  52. /// Designer support
  53. /// </summary>
  54. private bool _designTimeVisible;
  55. /// <summary>
  56. /// Used by DbDataAdapter to determine updating behavior
  57. /// </summary>
  58. #if !SILVERLIGHT
  59. private UpdateRowSource _updateRowSource;
  60. #endif
  61. /// <summary>
  62. /// The collection of parameters for the command
  63. /// </summary>
  64. private readonly EfzParameterCollection _parameterCollection;
  65. internal EfzStatement Statement;
  66. /// <summary>
  67. /// Transaction associated with this command
  68. /// </summary>
  69. private EfzTransaction _transaction;
  70. private List<EfzException> _warnings;
  71. /** The maximum number of rows to generate when executing this statement. */
  72. public int MaxRows;
  73. public int FetchSize;
  74. public bool FetchGeneratedResults;
  75. public void SetWarnings(List<EfzException> warnings)
  76. {
  77. _warnings = warnings;
  78. }
  79. public List<EfzException> Warnings
  80. {
  81. get { return _warnings; }
  82. }
  83. ///<overloads>
  84. /// Constructs a new EffiProzCommand
  85. /// </overloads>
  86. /// <summary>
  87. /// Default constructor
  88. /// </summary>
  89. public EfzCommand()
  90. : this(null, null, null)
  91. {
  92. }
  93. /// <summary>
  94. /// Initializes the command with the given command text
  95. /// </summary>
  96. /// <param name="commandText">The SQL command text</param>
  97. public EfzCommand(string commandText)
  98. : this(commandText, null, null)
  99. {
  100. }
  101. /// <summary>
  102. /// Initializes the command with the given SQL command text and attach the command to the specified
  103. /// connection.
  104. /// </summary>
  105. /// <param name="commandText">The SQL command text</param>
  106. /// <param name="connection">The connection to associate with the command</param>
  107. public EfzCommand(string commandText, EfzConnection connection)
  108. : this(commandText, connection, null)
  109. {
  110. }
  111. /// <summary>
  112. /// Initializes the command and associates it with the specified connection.
  113. /// </summary>
  114. /// <param name="connection">The connection to associate with the command</param>
  115. public EfzCommand(EfzConnection connection)
  116. : this(null, connection, null)
  117. {
  118. }
  119. private EfzCommand(EfzCommand source)
  120. : this(source.CommandText, source.Connection, source.Transaction)
  121. {
  122. CommandTimeout = source.CommandTimeout;
  123. _commandType = source.CommandType;
  124. DesignTimeVisible = source.DesignTimeVisible;
  125. #if !SILVERLIGHT
  126. UpdatedRowSource = source.UpdatedRowSource;
  127. #endif
  128. FetchGeneratedResults = source.FetchGeneratedResults;
  129. foreach (EfzParameter param in source._parameterCollection)
  130. {
  131. Parameters.Add((EfzParameter) param.Clone());
  132. }
  133. }
  134. /// <summary>
  135. /// Initializes a command with the given SQL, connection and transaction
  136. /// </summary>
  137. /// <param name="commandText">The SQL command text</param>
  138. /// <param name="connection">The connection to associate with the command</param>
  139. /// <param name="transaction">The transaction the command should be associated with</param>
  140. public EfzCommand(string commandText, EfzConnection connection, EfzTransaction transaction)
  141. {
  142. _commandTimeout = 30;
  143. _commandType = CommandType.Text;
  144. _parameterCollection = new EfzParameterCollection(this);
  145. _designTimeVisible = true;
  146. #if !SILVERLIGHT
  147. _updateRowSource = UpdateRowSource.None;
  148. #endif
  149. if (commandText != null)
  150. CommandText = commandText;
  151. if (connection != null)
  152. {
  153. #if !SILVERLIGHT
  154. DbConnection = connection;
  155. #else
  156. _cnn = connection;
  157. #endif
  158. // _commandTimeout = connection.connectio;
  159. }
  160. if (transaction != null)
  161. Transaction = transaction;
  162. FetchGeneratedResults = false;
  163. }
  164. /// <summary>
  165. /// Disposes of the command and clears all member variables
  166. /// </summary>
  167. /// <param name="disposing">Whether or not the class is being explicitly or implicitly disposed</param>
  168. #if SILVERLIGHT
  169. public void Dispose()
  170. {
  171. Dispose(true);
  172. }
  173. #endif
  174. #if !SILVERLIGHT
  175. protected override
  176. #else
  177. internal
  178. #endif
  179. void Dispose(bool disposing)
  180. {
  181. #if !SILVERLIGHT
  182. base.Dispose(disposing);
  183. #endif
  184. if (disposing)
  185. {
  186. // If a reader is active on this command, don't destroy the command, instead let the reader do it
  187. EfzDataReader reader = null;
  188. if (_activeReader != null)
  189. {
  190. try
  191. {
  192. reader = _activeReader.Target as EfzDataReader;
  193. }
  194. catch (InvalidOperationException)
  195. {
  196. }
  197. }
  198. if (reader != null)
  199. {
  200. reader.DisposeCommand = true;
  201. _activeReader = null;
  202. return;
  203. }
  204. Connection = null;
  205. //_parameterCollection.Clear();
  206. //_commandText = null;
  207. }
  208. }
  209. /// <summary>
  210. /// Clears and destroys all statements currently prepared
  211. /// </summary>
  212. internal void ClearCommands()
  213. {
  214. if (_activeReader != null)
  215. {
  216. EfzDataReader reader = null;
  217. try
  218. {
  219. reader = _activeReader.Target as EfzDataReader;
  220. }
  221. catch (InvalidOperationException)
  222. {
  223. }
  224. if (reader != null)
  225. reader.Close();
  226. _activeReader = null;
  227. }
  228. if (Statement != null)
  229. Statement.Dispose();
  230. Statement = null;
  231. //_parameterCollection.Unbind();
  232. }
  233. #if !SILVERLIGHT
  234. /// <summary>
  235. /// Not implemented
  236. /// </summary>
  237. public override void Cancel()
  238. {
  239. throw new NotImplementedException();
  240. //if (_activeReader != null)
  241. //{
  242. // EfzDataReader reader = _activeReader.Target as EfzDataReader;
  243. // if (reader != null)
  244. // reader.Cancel();
  245. //}
  246. }
  247. #endif
  248. /// <summary>
  249. /// The SQL command text associated with the command
  250. /// </summary>
  251. #if !PLATFORM_COMPACTFRAMEWORK && !SILVERLIGHT
  252. [DefaultValue(""), RefreshProperties(RefreshProperties.All),
  253. Editor(
  254. "Microsoft.VSDesigner.Data.SQL.Design.SqlCommandTextEditor, Microsoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  255. ,
  256. "System.Drawing.Design.UITypeEditor, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  257. )]
  258. #endif
  259. public
  260. #if !SILVERLIGHT
  261. override
  262. #endif
  263. string CommandText
  264. {
  265. get { return _commandText; }
  266. set
  267. {
  268. if (value == null)
  269. throw new ArgumentNullException();
  270. if (_commandText == value) return;
  271. if (_activeReader != null && _activeReader.IsAlive)
  272. {
  273. throw new InvalidOperationException("Cannot set CommandText while a DataReader is active");
  274. }
  275. ClearCommands();
  276. _commandText = value;
  277. Statement = null;
  278. }
  279. }
  280. /// <summary>
  281. /// The amount of time to wait for the connection to become available before erroring out
  282. /// </summary>
  283. #if !PLATFORM_COMPACTFRAMEWORK && !SILVERLIGHT
  284. [DefaultValue(30)]
  285. #endif
  286. public
  287. #if !SILVERLIGHT
  288. override
  289. #endif
  290. int CommandTimeout
  291. {
  292. get { return _commandTimeout; }
  293. set { _commandTimeout = value; }
  294. }
  295. /// <summary>
  296. /// The type of the command. EffiProz only supports CommandType.Text
  297. /// </summary>
  298. #if !PLATFORM_COMPACTFRAMEWORK && !SILVERLIGHT
  299. [RefreshProperties(RefreshProperties.All), DefaultValue(CommandType.Text)]
  300. #endif
  301. public
  302. #if !SILVERLIGHT
  303. override
  304. #endif
  305. CommandType CommandType
  306. {
  307. get { return _commandType; }
  308. set
  309. {
  310. if (value != CommandType.Text && value != CommandType.StoredProcedure)
  311. throw new NotSupportedException();
  312. _commandType = value;
  313. }
  314. }
  315. #if !SILVERLIGHT
  316. /// <summary>
  317. /// Forwards to the local CreateParameter() function
  318. /// </summary>
  319. /// <returns></returns>
  320. protected override DbParameter CreateDbParameter()
  321. {
  322. return CreateParameter();
  323. }
  324. #endif
  325. /// <summary>
  326. /// Create a new parameter
  327. /// </summary>
  328. /// <returns></returns>
  329. public new EfzParameter CreateParameter()
  330. {
  331. return new EfzParameter();
  332. }
  333. /// <summary>
  334. /// The connection associated with this command
  335. /// </summary>
  336. #if !PLATFORM_COMPACTFRAMEWORK && !SILVERLIGHT
  337. [DefaultValue((string) null),
  338. Editor(
  339. "Microsoft.VSDesigner.Data.Design.DbConnectionEditor, Microsoft.VSDesigner, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  340. ,
  341. "System.Drawing.Design.UITypeEditor, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
  342. )]
  343. #endif
  344. public new EfzConnection Connection
  345. {
  346. get { return _cnn; }
  347. set
  348. {
  349. if (_activeReader != null && _activeReader.IsAlive)
  350. throw new InvalidOperationException("Cannot set Connection while a DataReader is active");
  351. if (_cnn != null)
  352. {
  353. ClearCommands();
  354. }
  355. _cnn = value;
  356. if (_cnn != null)
  357. _version = _cnn.Version;
  358. }
  359. }
  360. #if !SILVERLIGHT
  361. /// <summary>
  362. /// Forwards to the local Connection property
  363. /// </summary>
  364. protected override DbConnection DbConnection
  365. {
  366. get { return Connection; }
  367. set { Connection = (EfzConnection) value; }
  368. }
  369. #endif
  370. /// <summary>
  371. /// Returns the EffiProzDBParameterCollection for the given command
  372. /// </summary>
  373. #if !PLATFORM_COMPACTFRAMEWORK && !SILVERLIGHT
  374. [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
  375. #endif
  376. public new EfzParameterCollection Parameters
  377. {
  378. get { return _parameterCollection; }
  379. }
  380. /// <summary>
  381. /// Forwards to the local Parameters property
  382. /// </summary>
  383. #if !SILVERLIGHT
  384. protected override DbParameterCollection DbParameterCollection
  385. {
  386. get { return Parameters; }
  387. }
  388. #endif
  389. /// <summary>
  390. /// The transaction associated with this command. EffiProz only supports one transaction per connection, so this property forwards to the
  391. /// command's underlying connection.
  392. /// </summary>
  393. #if !PLATFORM_COMPACTFRAMEWORK && !SILVERLIGHT
  394. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  395. #endif
  396. #if !SILVERLIGHT
  397. new
  398. #endif
  399. public EfzTransaction Transaction
  400. {
  401. get { return _transaction; }
  402. set
  403. {
  404. if (_cnn != null)
  405. {
  406. if (_activeReader != null && _activeReader.IsAlive)
  407. throw new InvalidOperationException("Cannot set Transaction while a DataReader is active");
  408. if (value != null)
  409. {
  410. if (value.Conn != _cnn)
  411. throw new ArgumentException("Transaction is not associated with the command's connection");
  412. }
  413. _transaction = value;
  414. }
  415. else
  416. {
  417. if (value != null) Connection = value.Connection;
  418. _transaction = value;
  419. }
  420. }
  421. }
  422. #if !SILVERLIGHT
  423. /// <summary>
  424. /// Forwards to the local Transaction property
  425. /// </summary>
  426. protected override DbTransaction DbTransaction
  427. {
  428. get { return Transaction; }
  429. set { Transaction = (EfzTransaction) value; }
  430. }
  431. #else
  432. internal EfzTransaction DbTransaction
  433. {
  434. get
  435. {
  436. return Transaction;
  437. }
  438. set
  439. {
  440. Transaction = (EfzTransaction)value;
  441. }
  442. }
  443. #endif
  444. /// <summary>
  445. /// This function ensures there are no active readers, that we have a valid connection,
  446. /// that the connection is open, that all statements are prepared and all parameters are assigned
  447. /// in preparation for allocating a data reader.
  448. /// </summary>
  449. private void InitializeForReader()
  450. {
  451. if (_activeReader != null && _activeReader.IsAlive)
  452. {
  453. //throw new InvalidOperationException("DataReader already active on this command");
  454. ClearDataReader();
  455. }
  456. if (_cnn == null)
  457. throw new InvalidOperationException("No connection associated with this command");
  458. if (_cnn.State != ConnectionState.Open)
  459. throw new InvalidOperationException("Database is not open");
  460. // If the version of the connection has changed, clear out any previous commands before starting
  461. if (_cnn.Version != _version)
  462. {
  463. _version = _cnn.Version;
  464. ClearCommands();
  465. }
  466. }
  467. /// <summary>
  468. /// Creates a new EffiProzDBDataReader to execute/iterate the array of EffiProz prepared statements
  469. /// </summary>
  470. /// <param name="behavior">The behavior the data reader should adopt</param>
  471. /// <returns>Returns a EffiProzDBDataReader object</returns>
  472. #if !SILVERLIGHT
  473. protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
  474. {
  475. return ExecuteReader(behavior);
  476. }
  477. #endif
  478. /// <summary>
  479. /// Overrides the default behavior to return a EffiProzDBDataReader specialization class
  480. /// </summary>
  481. /// <param name="behavior">The flags to be associated with the reader</param>
  482. /// <returns>A EffiProzDBDataReader</returns>
  483. public new EfzDataReader ExecuteReader(CommandBehavior behavior)
  484. {
  485. #if TRACE2
  486. long start = DateTime.Now.Ticks;
  487. #endif
  488. InitializeForReader();
  489. var rd = new EfzDataReader(this, behavior);
  490. _activeReader = new WeakReference(rd, false);
  491. #if TRACE2
  492. long duration = (DateTime.Now.Ticks - start) / TimeSpan.TicksPerMillisecond;
  493. if (duration > 0)
  494. {
  495. System.Diagnostics.Trace.WriteLine("Query : " + CommandText);
  496. if (_parameterCollection != null)
  497. for (int i = 0; i < _parameterCollection.Count; i++)
  498. System.Diagnostics.Trace.WriteLine("ParamName : " + _parameterCollection[i].ParameterName + " Value: " + _parameterCollection[i].Value);
  499. System.Diagnostics.Trace.WriteLine("Duration : " + duration);
  500. System.Diagnostics.Trace.WriteLine("");
  501. System.Diagnostics.Trace.Flush();
  502. }
  503. #endif
  504. return rd;
  505. }
  506. /// <summary>
  507. /// Overrides the default behavior of DbDataReader to return a specialized EffiProzDBDataReader class
  508. /// </summary>
  509. /// <returns>A EffiProzDBDataReader</returns>
  510. public new EfzDataReader ExecuteReader()
  511. {
  512. return ExecuteReader(CommandBehavior.Default);
  513. }
  514. /// <summary>
  515. /// Called by the EffiProzDBDataReader when the data reader is closed.
  516. /// </summary>
  517. internal void ClearDataReader()
  518. {
  519. _activeReader = null;
  520. }
  521. /// <summary>
  522. /// Execute the command and return the number of rows inserted/updated affected by it.
  523. /// </summary>
  524. /// <returns></returns>
  525. public
  526. #if !SILVERLIGHT
  527. override
  528. #endif
  529. int ExecuteNonQuery()
  530. {
  531. #if TRACE2
  532. long start = DateTime.Now.Ticks;
  533. #endif
  534. using (EfzDataReader reader = ExecuteReader(CommandBehavior.SingleRow | CommandBehavior.SingleResult))
  535. {
  536. while (reader.NextResult())
  537. {
  538. }
  539. #if TRACE2
  540. long duration = (DateTime.Now.Ticks - start) / TimeSpan.TicksPerMillisecond;
  541. if (duration > 0)
  542. {
  543. System.Diagnostics.Trace.WriteLine("Query : " + CommandText);
  544. if (_parameterCollection != null)
  545. for (int i = 0; i < _parameterCollection.Count; i++ )
  546. System.Diagnostics.Trace.WriteLine("ParamName : " + _parameterCollection[i].ParameterName+" Value: "+_parameterCollection[i].Value);
  547. System.Diagnostics.Trace.WriteLine("Duration : " + duration);
  548. System.Diagnostics.Trace.WriteLine("");
  549. System.Diagnostics.Trace.Flush();
  550. }
  551. #endif
  552. return reader.RecordsAffected;
  553. }
  554. }
  555. /// <summary>
  556. /// Execute the command and return the first column of the first row of the resultset
  557. /// (if present), or null if no resultset was returned.
  558. /// </summary>
  559. /// <returns>The first column of the first row of the first resultset from the query</returns>
  560. public
  561. #if !SILVERLIGHT
  562. override
  563. #endif
  564. object ExecuteScalar()
  565. {
  566. #if TRACE2
  567. long start = DateTime.Now.Ticks;
  568. #endif
  569. InitializeForReader();
  570. using (EfzDataReader reader = ExecuteReader(CommandBehavior.SingleRow | CommandBehavior.SingleResult))
  571. {
  572. #if TRACE2
  573. long duration = (DateTime.Now.Ticks - start) / TimeSpan.TicksPerMillisecond;
  574. if (duration > 0)
  575. {
  576. System.Diagnostics.Trace.WriteLine("Query : " + CommandText);
  577. if (_parameterCollection != null)
  578. for (int i = 0; i < _parameterCollection.Count; i++)
  579. System.Diagnostics.Trace.WriteLine("ParamName : " + _parameterCollection[i].ParameterName + " Value: " + _parameterCollection[i].Value);
  580. System.Diagnostics.Trace.WriteLine("Duration : " + duration);
  581. System.Diagnostics.Trace.WriteLine("");
  582. System.Diagnostics.Trace.Flush();
  583. }
  584. #endif
  585. if (reader.Read())
  586. return reader[0];
  587. }
  588. return null;
  589. }
  590. public
  591. #if !SILVERLIGHT
  592. override
  593. #endif
  594. void Prepare()
  595. {
  596. if (Statement != null)
  597. Statement.Dispose();
  598. Statement = new EfzStatement(this, _commandText, true);
  599. }
  600. /// <summary>
  601. /// Sets the method the EffiProzCommandBuilder uses to determine how to update inserted or updated rows in a DataTable.
  602. /// </summary>
  603. #if !SILVERLIGHT
  604. [DefaultValue(UpdateRowSource.None)]
  605. public override UpdateRowSource UpdatedRowSource
  606. {
  607. get { return _updateRowSource; }
  608. set { _updateRowSource = value; }
  609. }
  610. #endif
  611. /// <summary>
  612. /// Determines if the command is visible at design time. Defaults to True.
  613. /// </summary>
  614. #if !PLATFORM_COMPACTFRAMEWORK && !SILVERLIGHT
  615. [DesignOnly(true), Browsable(false), DefaultValue(true), EditorBrowsable(EditorBrowsableState.Never)]
  616. #endif
  617. public
  618. #if !SILVERLIGHT
  619. override
  620. #endif
  621. bool DesignTimeVisible
  622. {
  623. get { return _designTimeVisible; }
  624. set { _designTimeVisible = value; }
  625. }
  626. /// <summary>
  627. /// Clones a command, including all its parameters
  628. /// </summary>
  629. /// <returns>A new EffiProzCommand with the same commandtext, connection and parameters</returns>
  630. public object Clone()
  631. {
  632. return new EfzCommand(this);
  633. }
  634. }
  635. }