OracleCommand.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. //
  2. // OracleCommand.cs
  3. //
  4. // Part of the Mono class libraries at
  5. // mcs/class/System.Data.OracleClient/System.Data.OracleClient
  6. //
  7. // Assembly: System.Data.OracleClient.dll
  8. // Namespace: System.Data.OracleClient
  9. //
  10. // Authors:
  11. // Daniel Morgan <[email protected]>
  12. // Tim Coleman <[email protected]>
  13. //
  14. // Copyright (C) Daniel Morgan, 2002, 2004-2005
  15. // Copyright (C) Tim Coleman , 2003
  16. //
  17. // Licensed under the MIT/X11 License.
  18. //
  19. using System;
  20. using System.ComponentModel;
  21. using System.Data;
  22. using System.Data.OracleClient.Oci;
  23. using System.Drawing.Design;
  24. using System.Text;
  25. namespace System.Data.OracleClient {
  26. [Designer ("Microsoft.VSDesigner.Data.VS.OracleCommandDesigner, " + Consts.AssemblyMicrosoft_VSDesigner)]
  27. [ToolboxItem (true)]
  28. public sealed class OracleCommand : Component, ICloneable, IDbCommand
  29. {
  30. #region Fields
  31. CommandBehavior behavior;
  32. string commandText;
  33. CommandType commandType;
  34. OracleConnection connection;
  35. bool designTimeVisible;
  36. OracleParameterCollection parameters;
  37. OracleTransaction transaction;
  38. UpdateRowSource updatedRowSource;
  39. private OciStatementHandle preparedStatement;
  40. OciStatementType statementType;
  41. #endregion // Fields
  42. #region Constructors
  43. public OracleCommand ()
  44. : this (String.Empty, null, null)
  45. {
  46. }
  47. public OracleCommand (string commandText)
  48. : this (commandText, null, null)
  49. {
  50. }
  51. public OracleCommand (string commandText, OracleConnection connection)
  52. : this (commandText, connection, null)
  53. {
  54. }
  55. public OracleCommand (string commandText, OracleConnection connection, OracleTransaction tx)
  56. {
  57. preparedStatement = null;
  58. CommandText = commandText;
  59. Connection = connection;
  60. Transaction = tx;
  61. CommandType = CommandType.Text;
  62. UpdatedRowSource = UpdateRowSource.Both;
  63. DesignTimeVisible = false;
  64. parameters = new OracleParameterCollection (this);
  65. }
  66. #endregion // Constructors
  67. #region Properties
  68. [DefaultValue ("")]
  69. [RefreshProperties (RefreshProperties.All)]
  70. [Editor ("Microsoft.VSDesigner.Data.Oracle.Design.OracleCommandTextEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
  71. public string CommandText {
  72. get { return commandText; }
  73. set { commandText = value; }
  74. }
  75. [RefreshProperties (RefreshProperties.All)]
  76. [DefaultValue (CommandType.Text)]
  77. public CommandType CommandType {
  78. get { return commandType; }
  79. set {
  80. if (value == CommandType.TableDirect)
  81. throw new ArgumentException ("OracleClient provider does not support TableDirect CommandType.");
  82. commandType = value;
  83. }
  84. }
  85. [DefaultValue (null)]
  86. [Editor ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
  87. public OracleConnection Connection {
  88. get { return connection; }
  89. set { connection = value; }
  90. }
  91. [DefaultValue (true)]
  92. [Browsable (false)]
  93. [DesignOnly (true)]
  94. public bool DesignTimeVisible {
  95. get { return designTimeVisible; }
  96. set { designTimeVisible = value; }
  97. }
  98. internal OciEnvironmentHandle Environment {
  99. get { return Connection.Environment; }
  100. }
  101. internal OciErrorHandle ErrorHandle {
  102. get { return Connection.ErrorHandle; }
  103. }
  104. int IDbCommand.CommandTimeout {
  105. get { return 0; }
  106. set { }
  107. }
  108. [Editor ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
  109. [DefaultValue (null)]
  110. IDbConnection IDbCommand.Connection {
  111. get { return Connection; }
  112. set {
  113. if (!(value is OracleConnection))
  114. throw new InvalidCastException ("The value was not a valid OracleConnection.");
  115. Connection = (OracleConnection) value;
  116. }
  117. }
  118. IDataParameterCollection IDbCommand.Parameters {
  119. get { return Parameters; }
  120. }
  121. IDbTransaction IDbCommand.Transaction {
  122. get { return Transaction; }
  123. set {
  124. if (!(value is OracleTransaction))
  125. throw new ArgumentException ();
  126. Transaction = (OracleTransaction) value;
  127. }
  128. }
  129. [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
  130. public OracleParameterCollection Parameters {
  131. get { return parameters; }
  132. }
  133. [Browsable (false)]
  134. [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
  135. public OracleTransaction Transaction {
  136. get { return transaction; }
  137. set { transaction = value; }
  138. }
  139. [DefaultValue (UpdateRowSource.Both)]
  140. public UpdateRowSource UpdatedRowSource {
  141. get { return updatedRowSource; }
  142. set { updatedRowSource = value; }
  143. }
  144. #endregion
  145. #region Methods
  146. private void AssertCommandTextIsSet ()
  147. {
  148. if (CommandText == String.Empty || CommandText == null)
  149. throw new InvalidOperationException ("The command text for this Command has not been set.");
  150. }
  151. private void AssertConnectionIsOpen ()
  152. {
  153. if (Connection == null || Connection.State == ConnectionState.Closed)
  154. throw new InvalidOperationException ("An open Connection object is required to continue.");
  155. }
  156. private void AssertNoDataReader ()
  157. {
  158. if (Connection.DataReader != null)
  159. throw new InvalidOperationException ("There is already an open DataReader associated with this Connection which must be closed first.");
  160. }
  161. private void AssertTransactionMatch ()
  162. {
  163. if (Connection.Transaction != null && Transaction != Connection.Transaction)
  164. throw new InvalidOperationException ("Execute requires the Command object to have a Transaction object when the Connection object assigned to the command is in a pending local transaction. The Transaction property of the Command has not been initialized.");
  165. }
  166. private void BindParameters (OciStatementHandle statement)
  167. {
  168. foreach (OracleParameter p in Parameters)
  169. p.Bind (statement, Connection);
  170. }
  171. [MonoTODO]
  172. public void Cancel ()
  173. {
  174. throw new NotImplementedException ();
  175. }
  176. [MonoTODO]
  177. public object Clone ()
  178. {
  179. // create a new OracleCommand object with the same properties
  180. OracleCommand cmd = new OracleCommand ();
  181. cmd.CommandText = this.CommandText;
  182. cmd.CommandType = this.CommandType;
  183. // FIXME: not sure if I should set the same object here
  184. // or get a clone of these too
  185. cmd.Connection = this.Connection;
  186. cmd.Transaction = this.Transaction;
  187. foreach (OracleParameter parm in this.Parameters) {
  188. OracleParameter newParm = cmd.CreateParameter ();
  189. newParm.DbType = parm.DbType;
  190. newParm.Direction = parm.Direction;
  191. newParm.IsNullable = parm.IsNullable;
  192. newParm.Offset = parm.Offset;
  193. newParm.OracleType = parm.OracleType;
  194. newParm.ParameterName = parm.ParameterName;
  195. newParm.Precision = parm.Precision;
  196. newParm.Scale = parm.Scale;
  197. newParm.SourceColumn = parm.SourceColumn;
  198. newParm.SourceVersion = parm.SourceVersion;
  199. newParm.Value = parm.Value;
  200. cmd.Parameters.Add (newParm);
  201. }
  202. //cmd.Container = this.Container;
  203. cmd.DesignTimeVisible = this.DesignTimeVisible;
  204. //cmd.DesignMode = this.DesignMode;
  205. cmd.Site = this.Site;
  206. //cmd.UpdateRowSource = this.UpdateRowSource;
  207. return cmd;
  208. }
  209. internal void CloseDataReader ()
  210. {
  211. Connection.DataReader = null;
  212. if ((behavior & CommandBehavior.CloseConnection) != 0)
  213. Connection.Close ();
  214. }
  215. public OracleParameter CreateParameter ()
  216. {
  217. return new OracleParameter ();
  218. }
  219. private int ExecuteNonQueryInternal (OciStatementHandle statement, bool useAutoCommit)
  220. {
  221. if (preparedStatement == null)
  222. PrepareStatement (statement);
  223. bool isNonQuery = IsNonQuery (statement);
  224. BindParameters (statement);
  225. if (isNonQuery == true)
  226. statement.ExecuteNonQuery (useAutoCommit);
  227. else
  228. statement.ExecuteQuery ();
  229. int rowsAffected = statement.GetAttributeInt32 (OciAttributeType.RowCount, ErrorHandle);
  230. return rowsAffected;
  231. }
  232. public int ExecuteNonQuery ()
  233. {
  234. AssertConnectionIsOpen ();
  235. AssertTransactionMatch ();
  236. AssertCommandTextIsSet ();
  237. bool useAutoCommit = false;
  238. if (Transaction != null)
  239. Transaction.AttachToServiceContext ();
  240. else
  241. useAutoCommit = true;
  242. OciStatementHandle statement = GetStatementHandle ();
  243. try {
  244. return ExecuteNonQueryInternal (statement, useAutoCommit);
  245. }
  246. finally {
  247. SafeDisposeHandle (statement);
  248. }
  249. }
  250. public int ExecuteOracleNonQuery (out OracleString rowid)
  251. {
  252. AssertConnectionIsOpen ();
  253. AssertTransactionMatch ();
  254. AssertCommandTextIsSet ();
  255. bool useAutoCommit = false;
  256. if (Transaction != null)
  257. Transaction.AttachToServiceContext ();
  258. else
  259. useAutoCommit = true;
  260. OciStatementHandle statement = GetStatementHandle ();
  261. try {
  262. int retval = ExecuteNonQueryInternal (statement, useAutoCommit);
  263. OciRowIdDescriptor descriptor = (OciRowIdDescriptor) Environment.Allocate (OciHandleType.RowId);
  264. descriptor.SetHandle (statement.GetAttributeIntPtr (OciAttributeType.RowId, ErrorHandle));
  265. rowid = new OracleString (descriptor.GetRowId (ErrorHandle));
  266. return retval;
  267. }
  268. finally {
  269. SafeDisposeHandle (statement);
  270. }
  271. }
  272. [MonoTODO]
  273. public object ExecuteOracleScalar ()
  274. {
  275. object output = DBNull.Value;
  276. AssertConnectionIsOpen ();
  277. AssertTransactionMatch ();
  278. AssertCommandTextIsSet ();
  279. if (Transaction != null)
  280. Transaction.AttachToServiceContext ();
  281. OciStatementHandle statement = GetStatementHandle ();
  282. try {
  283. if (preparedStatement == null)
  284. PrepareStatement (statement);
  285. bool isNonQuery = IsNonQuery (statement);
  286. BindParameters (statement);
  287. if (isNonQuery == true)
  288. ExecuteNonQueryInternal (statement, false);
  289. else {
  290. statement.ExecuteQuery ();
  291. if (statement.Fetch ()) {
  292. OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
  293. if (!defineHandle.IsNull)
  294. output = defineHandle.GetOracleValue ();
  295. switch (defineHandle.DataType) {
  296. case OciDataType.Blob:
  297. case OciDataType.Clob:
  298. ((OracleLob) output).connection = Connection;
  299. break;
  300. }
  301. }
  302. }
  303. return output;
  304. }
  305. finally {
  306. SafeDisposeHandle (statement);
  307. }
  308. }
  309. private bool IsNonQuery (OciStatementHandle statementHandle)
  310. {
  311. // assumes Prepare() has been called prior to calling this function
  312. OciStatementType statementType = statementHandle.GetStatementType ();
  313. if (statementType.Equals (OciStatementType.Select))
  314. return false;
  315. return true;
  316. }
  317. public OracleDataReader ExecuteReader ()
  318. {
  319. return ExecuteReader (CommandBehavior.Default);
  320. }
  321. public OracleDataReader ExecuteReader (CommandBehavior behavior)
  322. {
  323. AssertConnectionIsOpen ();
  324. AssertTransactionMatch ();
  325. AssertCommandTextIsSet ();
  326. AssertNoDataReader ();
  327. bool hasRows = false;
  328. this.behavior = behavior;
  329. if (Transaction != null)
  330. Transaction.AttachToServiceContext ();
  331. OciStatementHandle statement = GetStatementHandle ();
  332. OracleDataReader rd = null;
  333. try {
  334. if (preparedStatement == null)
  335. PrepareStatement (statement);
  336. else
  337. preparedStatement = null; // OracleDataReader releases the statement handle
  338. bool isNonQuery = IsNonQuery (statement);
  339. BindParameters (statement);
  340. if (isNonQuery)
  341. ExecuteNonQueryInternal (statement, false);
  342. else
  343. hasRows = statement.ExecuteQuery ();
  344. rd = new OracleDataReader (this, statement, hasRows);
  345. }
  346. finally {
  347. if (statement != null && rd == null)
  348. statement.Dispose();
  349. }
  350. return rd;
  351. }
  352. public object ExecuteScalar ()
  353. {
  354. object output = DBNull.Value;
  355. AssertConnectionIsOpen ();
  356. AssertTransactionMatch ();
  357. AssertCommandTextIsSet ();
  358. if (Transaction != null)
  359. Transaction.AttachToServiceContext ();
  360. OciStatementHandle statement = GetStatementHandle ();
  361. try {
  362. if (preparedStatement == null)
  363. PrepareStatement (statement);
  364. bool isNonQuery = IsNonQuery (statement);
  365. BindParameters (statement);
  366. if (isNonQuery == true)
  367. ExecuteNonQueryInternal (statement, false);
  368. else {
  369. statement.ExecuteQuery ();
  370. if (statement.Fetch ()) {
  371. OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
  372. if (defineHandle.IsNull)
  373. output = DBNull.Value;
  374. else {
  375. switch (defineHandle.DataType) {
  376. case OciDataType.Blob:
  377. case OciDataType.Clob:
  378. OracleLob lob = (OracleLob) defineHandle.GetValue ();
  379. lob.connection = Connection;
  380. output = lob.Value;
  381. lob.Close ();
  382. break;
  383. default:
  384. output = defineHandle.GetValue ();
  385. break;
  386. }
  387. }
  388. }
  389. else
  390. output = DBNull.Value;
  391. }
  392. }
  393. finally {
  394. SafeDisposeHandle (statement);
  395. }
  396. return output;
  397. }
  398. private OciStatementHandle GetStatementHandle ()
  399. {
  400. AssertConnectionIsOpen ();
  401. if (preparedStatement != null)
  402. return preparedStatement;
  403. OciStatementHandle h = (OciStatementHandle) Connection.Environment.Allocate (OciHandleType.Statement);
  404. h.ErrorHandle = Connection.ErrorHandle;
  405. h.Service = Connection.ServiceContext;
  406. h.Command = this;
  407. return h;
  408. }
  409. private void SafeDisposeHandle (OciStatementHandle h)
  410. {
  411. if (h != null && h != preparedStatement)
  412. h.Dispose();
  413. }
  414. IDbDataParameter IDbCommand.CreateParameter ()
  415. {
  416. return CreateParameter ();
  417. }
  418. IDataReader IDbCommand.ExecuteReader ()
  419. {
  420. return ExecuteReader ();
  421. }
  422. IDataReader IDbCommand.ExecuteReader (CommandBehavior behavior)
  423. {
  424. return ExecuteReader (behavior);
  425. }
  426. void PrepareStatement (OciStatementHandle statement)
  427. {
  428. if (commandType == CommandType.StoredProcedure) {
  429. StringBuilder sb = new StringBuilder ();
  430. if (Parameters.Count > 0)
  431. foreach (OracleParameter parm in Parameters) {
  432. if (sb.Length > 0)
  433. sb.Append (",");
  434. sb.Append (":" + parm.ParameterName);
  435. }
  436. string sql = "call " + commandText + "(" + sb.ToString() + ")";
  437. statement.Prepare (sql);
  438. }
  439. else // Text
  440. statement.Prepare (commandText);
  441. }
  442. public void Prepare ()
  443. {
  444. AssertConnectionIsOpen ();
  445. OciStatementHandle statement = GetStatementHandle ();
  446. PrepareStatement (statement);
  447. preparedStatement = statement;
  448. }
  449. #endregion // Methods
  450. }
  451. }