Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data / System / Data / OleDb / OleDbCommand.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="OleDbCommand.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">[....]</owner>
6 // <owner current="true" primary="false">[....]</owner>
7 //------------------------------------------------------------------------------
8
9 namespace System.Data.OleDb {
10
11     using System;
12     using System.ComponentModel;
13     using System.Data;
14     using System.Data.Common;
15     using System.Data.ProviderBase;
16     using System.Diagnostics;
17     using System.IO;
18     using System.Runtime.CompilerServices;
19     using System.Runtime.InteropServices;
20     using System.Security;
21     using System.Security.Permissions;
22     using System.Threading;
23     using System.Text;
24
25     [
26     DefaultEvent("RecordsAffected"),
27     ToolboxItem(true),
28     Designer("Microsoft.VSDesigner.Data.VS.OleDbCommandDesigner, " + AssemblyRef.MicrosoftVSDesigner)
29     ]
30     public sealed class OleDbCommand : DbCommand, ICloneable, IDbCommand {
31
32         // command data
33         private string _commandText;
34         private CommandType _commandType;
35         private int _commandTimeout = ADP.DefaultCommandTimeout;
36         private UpdateRowSource _updatedRowSource = UpdateRowSource.Both;
37         private bool _designTimeInvisible;
38         private OleDbConnection _connection;
39         private OleDbTransaction _transaction;
40
41         private static int _objectTypeCount; // Bid counter
42         internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
43
44         private OleDbParameterCollection _parameters;
45
46         // native information
47         private UnsafeNativeMethods.ICommandText _icommandText;
48
49         // if executing with a different CommandBehavior.KeyInfo behavior
50         // original ICommandText must be released and a new ICommandText generated
51         private CommandBehavior commandBehavior;
52
53         private Bindings _dbBindings;
54
55         internal bool canceling; // MDAC 68964
56         private bool _isPrepared;
57         private bool _executeQuery;
58         private bool _trackingForClose;
59         private bool _hasDataReader;
60
61         private IntPtr _recordsAffected;
62         private int _changeID;
63         private int _lastChangeID;
64
65         public OleDbCommand() : base() {
66             GC.SuppressFinalize(this);
67         }
68
69         public OleDbCommand(string cmdText) : this() {
70             CommandText = cmdText;
71         }
72
73         public OleDbCommand(string cmdText, OleDbConnection connection) : this() {
74             CommandText = cmdText;
75             Connection = connection;
76         }
77
78         public OleDbCommand(string cmdText, OleDbConnection connection, OleDbTransaction transaction) : this() {
79             CommandText = cmdText;
80             Connection = connection;
81             Transaction = transaction;
82         }
83
84         private OleDbCommand(OleDbCommand from) : this() { // Clone
85             CommandText = from.CommandText;
86             CommandTimeout = from.CommandTimeout;
87             CommandType = from.CommandType;
88             Connection = from.Connection;
89             DesignTimeVisible = from.DesignTimeVisible;
90             UpdatedRowSource = from.UpdatedRowSource;
91             Transaction = from.Transaction;
92
93             OleDbParameterCollection parameters = Parameters;
94             foreach(object parameter in from.Parameters) {
95                 parameters.Add((parameter is ICloneable) ? (parameter as ICloneable).Clone() : parameter);
96             }
97         }
98
99         private Bindings ParameterBindings {
100             get {
101                 return _dbBindings;
102             }
103             set {
104                 Bindings bindings = _dbBindings;
105                 _dbBindings = value;
106                 if ((null != bindings) && (value != bindings)) {
107                     bindings.Dispose();
108                 }
109             }
110         }
111
112         [
113         DefaultValue(""),
114         Editor("Microsoft.VSDesigner.Data.ADO.Design.OleDbCommandTextEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
115         RefreshProperties(RefreshProperties.All), // MDAC 67707
116         ResCategoryAttribute(Res.DataCategory_Data),
117         ResDescriptionAttribute(Res.DbCommand_CommandText),
118         ]
119         override public string CommandText {
120             get {
121                 string value = _commandText;
122                 return ((null != value) ? value : ADP.StrEmpty);
123             }
124             set {
125                 if (Bid.TraceOn) {
126                     Bid.Trace("<oledb.OleDbCommand.set_CommandText|API> %d#, '", ObjectID);
127                     Bid.PutStr(value); // Use PutStr to write out entire string
128                     Bid.Trace("'\n");
129                 }
130                 if (0 != ADP.SrcCompare(_commandText, value)) {
131                     PropertyChanging();
132                     _commandText = value;
133                 }
134             }
135         }
136
137         [
138         ResCategoryAttribute(Res.DataCategory_Data),
139         ResDescriptionAttribute(Res.DbCommand_CommandTimeout),
140         ]
141         override public int CommandTimeout { // V1.2.3300, XXXCommand V1.0.5000
142             get {
143                 return _commandTimeout;
144             }
145             set {
146                 Bid.Trace("<oledb.OleDbCommand.set_CommandTimeout|API> %d#, %d\n", ObjectID, value);
147                 if (value < 0) {
148                     throw ADP.InvalidCommandTimeout(value);
149                 }
150                 if (value != _commandTimeout) {
151                     PropertyChanging();
152                     _commandTimeout = value;
153                 }
154             }
155         }
156
157         public void ResetCommandTimeout() { // V1.2.3300
158             if (ADP.DefaultCommandTimeout != _commandTimeout) {
159                 PropertyChanging();
160                 _commandTimeout = ADP.DefaultCommandTimeout;
161             }
162         }
163
164         private bool ShouldSerializeCommandTimeout() { // V1.2.3300
165             return (ADP.DefaultCommandTimeout != _commandTimeout);
166         }
167
168         [
169         DefaultValue(System.Data.CommandType.Text),
170         RefreshProperties(RefreshProperties.All),
171         ResCategoryAttribute(Res.DataCategory_Data),
172         ResDescriptionAttribute(Res.DbCommand_CommandType),
173         ]
174         override public CommandType CommandType {
175             get {
176                 CommandType cmdType = _commandType;
177                 return ((0 != cmdType) ? cmdType : CommandType.Text);
178             }
179             set  {
180                 switch(value) { // @perfnote: Enum.IsDefined
181                 case CommandType.Text:
182                 case CommandType.StoredProcedure:
183                 case CommandType.TableDirect:
184                     PropertyChanging();
185                     _commandType = value;
186                     break;
187                 default:
188                     throw ADP.InvalidCommandType(value);
189                 }
190             }
191         }
192
193         [
194         DefaultValue(null),
195         Editor("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
196         ResCategoryAttribute(Res.DataCategory_Data),
197         ResDescriptionAttribute(Res.DbCommand_Connection),
198         ]
199         new public OleDbConnection Connection {
200             get {
201                 return _connection;
202             }
203             set {
204                 OleDbConnection connection = _connection;
205                 if (value != connection) {
206                     PropertyChanging();
207                     ResetConnection();
208
209                     _connection = value;
210                     Bid.Trace("<oledb.OleDbCommand.set_Connection|API> %d#\n", ObjectID);
211
212                     if (null != value) {
213                         _transaction = OleDbTransaction.TransactionUpdate(_transaction); // MDAC 63226
214                     }
215                 }
216             }
217         }
218
219         private void ResetConnection() {
220             OleDbConnection connection = _connection;
221             if (null != connection) {
222                 PropertyChanging();
223                 CloseInternal();
224                 if (_trackingForClose) {
225                     connection.RemoveWeakReference(this);
226                     _trackingForClose = false;
227                 }
228             }
229             _connection = null;
230         }
231
232         override protected DbConnection DbConnection { // V1.2.3300
233             get {
234                 return Connection;
235             }
236             set {
237                 Connection = (OleDbConnection)value;
238             }
239         }
240
241         override protected DbParameterCollection DbParameterCollection { // V1.2.3300
242             get {
243                 return Parameters;
244             }
245         }
246
247         override protected DbTransaction DbTransaction { // V1.2.3300
248             get {
249                 return Transaction;
250             }
251             set {
252                 Transaction = (OleDbTransaction)value;
253             }
254         }
255
256         // @devnote: By default, the cmd object is visible on the design surface (i.e. VS7 Server Tray)
257         // to limit the number of components that clutter the design surface,
258         // when the DataAdapter design wizard generates the insert/update/delete commands it will
259         // set the DesignTimeVisible property to false so that cmds won't appear as individual objects
260         [
261         DefaultValue(true),
262         DesignOnly(true),
263         Browsable(false),
264         EditorBrowsableAttribute(EditorBrowsableState.Never),
265         ]
266         public override bool DesignTimeVisible { // V1.2.3300, XXXCommand V1.0.5000
267             get {
268                 return !_designTimeInvisible;
269             }
270             set {
271                 _designTimeInvisible = !value;
272                 TypeDescriptor.Refresh(this); // VS7 208845
273             }
274         }
275
276         [
277         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
278         ResCategoryAttribute(Res.DataCategory_Data),
279         ResDescriptionAttribute(Res.DbCommand_Parameters),
280         ]
281         new public OleDbParameterCollection Parameters {
282             get {
283                 OleDbParameterCollection value = _parameters;
284                 if (null == value) {
285                     // delay the creation of the OleDbParameterCollection
286                     // until user actually uses the Parameters property
287                     value = new OleDbParameterCollection();
288                     _parameters = value;
289                 }
290                 return value;
291             }
292         }
293
294         private bool HasParameters() { // MDAC 65548
295             OleDbParameterCollection value = _parameters;
296             return (null != value) && (0 < value.Count); // VS 300569
297         }
298
299         [
300         Browsable(false),
301         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
302         ResDescriptionAttribute(Res.DbCommand_Transaction),
303         ]
304         new public OleDbTransaction Transaction {
305             get {
306                 // find the last non-zombied local transaction object, but not transactions
307                 // that may have been started after the current local transaction
308                 OleDbTransaction transaction = _transaction;
309                 while ((null != transaction) && (null == transaction.Connection)) {
310                     transaction = transaction.Parent;
311                     _transaction = transaction;
312                 }
313                 return transaction;
314             }
315             set {
316                 _transaction = value;
317                 Bid.Trace("<oledb.OleDbCommand.set_Transaction|API> %d#\n", ObjectID);
318             }
319         }
320
321         [
322         DefaultValue(System.Data.UpdateRowSource.Both),
323         ResCategoryAttribute(Res.DataCategory_Update),
324         ResDescriptionAttribute(Res.DbCommand_UpdatedRowSource),
325         ]
326         override public UpdateRowSource UpdatedRowSource { // V1.2.3300, XXXCommand V1.0.5000
327             get {
328                 return _updatedRowSource;
329             }
330             set {
331                 switch(value) { // @perfnote: Enum.IsDefined
332                 case UpdateRowSource.None:
333                 case UpdateRowSource.OutputParameters:
334                 case UpdateRowSource.FirstReturnedRecord:
335                 case UpdateRowSource.Both:
336                     _updatedRowSource = value;
337                     break;
338                 default:
339                     throw ADP.InvalidUpdateRowSource(value);
340                 }
341             }
342         }
343
344         // required interface, safe cast
345         private UnsafeNativeMethods.IAccessor IAccessor() {
346             Bid.Trace("<oledb.IUnknown.QueryInterface|API|OLEDB|command> %d#, IAccessor\n", ObjectID);
347             Debug.Assert(null != _icommandText, "IAccessor: null ICommandText");
348             return (UnsafeNativeMethods.IAccessor) _icommandText;
349         }
350
351         // required interface, safe cast
352         internal UnsafeNativeMethods.ICommandProperties ICommandProperties() {
353             Bid.Trace("<oledb.IUnknown.QueryInterface|API|OLEDB|command> %d#, ICommandProperties\n", ObjectID);
354             Debug.Assert(null != _icommandText, "ICommandProperties: null ICommandText");
355             return (UnsafeNativeMethods.ICommandProperties) _icommandText;
356         }
357
358         // optional interface, unsafe cast
359         private UnsafeNativeMethods.ICommandPrepare ICommandPrepare() {
360             Bid.Trace("<oledb.IUnknown.QueryInterface|API|OLEDB|command> %d#, ICommandPrepare\n", ObjectID);
361             Debug.Assert(null != _icommandText, "ICommandPrepare: null ICommandText");
362             return (_icommandText as UnsafeNativeMethods.ICommandPrepare);
363         }
364
365         // optional interface, unsafe cast
366         private UnsafeNativeMethods.ICommandWithParameters ICommandWithParameters() {
367             Bid.Trace("<oledb.IUnknown.QueryInterface|API|OLEDB|command> %d#, ICommandWithParameters\n", ObjectID);
368             Debug.Assert(null != _icommandText, "ICommandWithParameters: null ICommandText");
369             UnsafeNativeMethods.ICommandWithParameters value = (_icommandText as UnsafeNativeMethods.ICommandWithParameters);
370             if (null == value) {
371                 throw ODB.NoProviderSupportForParameters(_connection.Provider, (Exception)null);
372             }
373             return value;
374         }
375
376         private void CreateAccessor() {
377             Debug.Assert(System.Data.CommandType.Text == CommandType || System.Data.CommandType.StoredProcedure == CommandType, "CreateAccessor: incorrect CommandType");
378             Debug.Assert(null == _dbBindings, "CreateAccessor: already has dbBindings");
379             Debug.Assert(HasParameters(), "CreateAccessor: unexpected, no parameter collection");
380
381             // do this first in-case the command doesn't support parameters
382             UnsafeNativeMethods.ICommandWithParameters commandWithParameters = ICommandWithParameters();
383
384             OleDbParameterCollection collection = _parameters;
385             OleDbParameter[] parameters = new OleDbParameter[collection.Count];
386             collection.CopyTo(parameters, 0);
387
388             // _dbBindings is used as a switch during ExecuteCommand, so don't set it until everything okay
389             Bindings bindings = new Bindings(parameters, collection.ChangeID);
390
391             for (int i = 0; i < parameters.Length; ++i) {
392                 bindings.ForceRebind |= parameters[i].BindParameter(i, bindings);
393             }
394
395             bindings.AllocateForAccessor(null, 0, 0);
396
397             ApplyParameterBindings(commandWithParameters, bindings.BindInfo);
398
399             UnsafeNativeMethods.IAccessor iaccessor = IAccessor();
400             OleDbHResult hr = bindings.CreateAccessor(iaccessor, ODB.DBACCESSOR_PARAMETERDATA);
401             if (hr < 0) {
402                 ProcessResults(hr);
403             }
404             _dbBindings = bindings;
405         }
406
407         private void ApplyParameterBindings(UnsafeNativeMethods.ICommandWithParameters commandWithParameters, tagDBPARAMBINDINFO[] bindInfo) {
408             IntPtr[] ordinals = new IntPtr[bindInfo.Length];
409             for (int i = 0; i < ordinals.Length; ++i) {
410                 ordinals[i] = (IntPtr)(i+1);
411             }
412
413             Bid.Trace("<oledb.ICommandWithParameters.SetParameterInfo|API|OLEDB> %d#\n", ObjectID);
414             OleDbHResult hr = commandWithParameters.SetParameterInfo((IntPtr)bindInfo.Length, ordinals, bindInfo);
415             Bid.Trace("<oledb.ICommandWithParameters.SetParameterInfo|API|OLEDB|RET> %08X{HRESULT}\n", hr);
416
417             if (hr < 0) {
418                 ProcessResults(hr);
419             }
420         }
421
422         override public void Cancel() {
423             IntPtr hscp;
424             Bid.ScopeEnter(out hscp, "<oledb.OleDbCommand.Cancel|API> %d#\n", ObjectID);
425             try {
426                 unchecked { _changeID++; }
427
428                 UnsafeNativeMethods.ICommandText icmdtxt = _icommandText;
429                 if (null != icmdtxt) {
430                     OleDbHResult hr = OleDbHResult.S_OK;
431
432                     lock(icmdtxt) {
433                         // lock the object to avoid race conditions between using the object and releasing the object
434                         // after we acquire the lock, if the class has moved on don't actually call Cancel
435                         if (icmdtxt == _icommandText) {
436                             Bid.Trace("<oledb.ICommandText.Cancel|API|OLEDB> %d#\n", ObjectID);
437                             hr = icmdtxt.Cancel();
438                             Bid.Trace("<oledb.ICommandText.Cancel|API|OLEDB|RET> %08X{HRESULT}\n", hr);
439                         }
440                     }
441                     if (OleDbHResult.DB_E_CANTCANCEL != hr) {
442                         // if the provider can't cancel the command - don't cancel the DataReader
443                         this.canceling = true;
444                     }
445
446                     // since cancel is allowed to occur at anytime we can't check the connection status
447                     // since if it returns as closed then the connection will close causing the reader to close
448                     // and that would introduce the possilbility of one thread reading and one thread closing at the same time
449                     ProcessResultsNoReset(hr); // MDAC 72667
450                 }
451                 else {
452                     this.canceling = true;
453                 }
454             }
455             finally {
456                 Bid.ScopeLeave(ref hscp);
457             }
458         }
459
460         public OleDbCommand Clone() {
461             OleDbCommand clone = new OleDbCommand(this);
462             Bid.Trace("<oledb.OleDbCommand.Clone|API> %d#, clone=%d#\n", ObjectID, clone.ObjectID);
463             return clone;
464         }
465
466         object ICloneable.Clone() {
467             return Clone();
468         }
469
470         // Connection.Close & Connection.Dispose(true) notification
471         internal void CloseCommandFromConnection(bool canceling) {
472             this.canceling = canceling; // MDAC 71435
473             CloseInternal();
474             _trackingForClose = false;
475             _transaction = null;
476             //GC.SuppressFinalize(this);
477         }
478
479         internal void CloseInternal() {
480             Debug.Assert(null != _connection, "no connection, CloseInternal");
481             CloseInternalParameters();
482             CloseInternalCommand();
483         }
484
485         // may be called from either
486         //      OleDbDataReader.Close/Dispose
487         //      via OleDbCommand.Dispose or OleDbConnection.Close
488         internal void CloseFromDataReader(Bindings bindings) {
489             if (null != bindings) {
490                 if (canceling) {
491                     bindings.Dispose();
492                     Debug.Assert(_dbBindings == bindings, "bindings with two owners");
493                 }
494                 else {
495                     bindings.ApplyOutputParameters();
496                     ParameterBindings = bindings;
497                 }
498             }
499             _hasDataReader = false;
500         }
501
502         private void CloseInternalCommand() {
503             unchecked { _changeID++; }
504             this.commandBehavior = CommandBehavior.Default;
505             _isPrepared = false;
506
507             
508
509             UnsafeNativeMethods.ICommandText ict = Interlocked.Exchange<UnsafeNativeMethods.ICommandText>(ref _icommandText, null);
510             if (null != ict) {
511                 lock(ict) {
512                     // lock the object to avoid race conditions between using the object and releasing the object
513                     Marshal.ReleaseComObject(ict);
514                 }
515             }
516         }
517         private void CloseInternalParameters() {
518             Debug.Assert(null != _connection, "no connection, CloseInternalParameters");
519             Bindings bindings = _dbBindings;
520             _dbBindings = null;
521             if (null != bindings) {
522                 bindings.Dispose();
523             }
524         }
525
526         new public OleDbParameter CreateParameter() {
527             return new OleDbParameter();
528         }
529
530         override protected DbParameter CreateDbParameter() {
531             return CreateParameter();
532         }
533
534         override protected void Dispose(bool disposing) { // MDAC 65459
535             if (disposing) { // release mananged objects
536                 // the DataReader takes ownership of the parameter Bindings
537                 // this way they don't get destroyed when user calls OleDbCommand.Dispose
538                 // when there is an open DataReader
539
540                 unchecked { _changeID++; }
541
542                 // in V1.0, V1.1 the Connection,Parameters,CommandText,Transaction where reset
543                 ResetConnection();
544                 _transaction = null;
545                 _parameters = null;
546                 CommandText = null;
547             }
548             // release unmanaged objects
549             base.Dispose(disposing); // notify base classes
550         }
551
552
553         new public OleDbDataReader ExecuteReader() {
554             return ExecuteReader(CommandBehavior.Default);
555         }
556
557         IDataReader IDbCommand.ExecuteReader() {
558             return ExecuteReader(CommandBehavior.Default);
559         }
560
561         new public OleDbDataReader ExecuteReader(CommandBehavior behavior) {
562             OleDbConnection.ExecutePermission.Demand();
563
564             IntPtr hscp;
565             Bid.ScopeEnter(out hscp, "<oledb.OleDbCommand.ExecuteReader|API> %d#, behavior=%d{ds.CommandBehavior}\n", ObjectID, (int)behavior);
566             try {
567                 _executeQuery = true;
568                 return ExecuteReaderInternal(behavior, ADP.ExecuteReader);
569             }
570             finally {
571                 Bid.ScopeLeave(ref hscp);
572             }
573         }
574
575         IDataReader IDbCommand.ExecuteReader(CommandBehavior behavior) {
576             return ExecuteReader(behavior);
577         }
578
579         override protected DbDataReader ExecuteDbDataReader(CommandBehavior behavior) {
580             return ExecuteReader(behavior);
581         }
582
583         private OleDbDataReader ExecuteReaderInternal(CommandBehavior behavior, string method) {
584             OleDbDataReader dataReader = null;
585             OleDbException nextResultsFailure = null;
586             int state = ODB.InternalStateClosed;
587             try {
588                 ValidateConnectionAndTransaction(method);
589
590                 if (0 != (CommandBehavior.SingleRow & behavior)) {
591                     // CommandBehavior.SingleRow implies CommandBehavior.SingleResult
592                     behavior |= CommandBehavior.SingleResult;
593                 }
594
595                 object executeResult;
596                 int resultType;
597
598                 switch(CommandType) {
599                 case 0: // uninitialized CommandType.Text
600                 case CommandType.Text:
601                 case CommandType.StoredProcedure:
602                     resultType = ExecuteCommand(behavior, out executeResult);
603                     break;
604
605                 case CommandType.TableDirect:
606                     resultType = ExecuteTableDirect(behavior, out executeResult);
607                     break;
608
609                 default:
610                     throw ADP.InvalidCommandType(CommandType);
611                 }
612
613                 if (_executeQuery) {
614                     try {
615                         dataReader = new OleDbDataReader(_connection, this, 0, this.commandBehavior);
616
617                         switch(resultType) {
618                         case ODB.ExecutedIMultipleResults:
619                             dataReader.InitializeIMultipleResults(executeResult);
620                             dataReader.NextResult();
621                             break;
622                         case ODB.ExecutedIRowset:
623                             dataReader.InitializeIRowset(executeResult, ChapterHandle.DB_NULL_HCHAPTER, _recordsAffected);
624                             dataReader.BuildMetaInfo();
625                             dataReader.HasRowsRead();
626                             break;
627                         case ODB.ExecutedIRow:
628                             dataReader.InitializeIRow(executeResult, _recordsAffected);
629                             dataReader.BuildMetaInfo();
630                             break;
631                         case ODB.PrepareICommandText:
632                             if (!_isPrepared) {
633                                 PrepareCommandText(2);
634                             }
635                             OleDbDataReader.GenerateSchemaTable(dataReader, _icommandText, behavior);
636                             break;
637                         default:
638                             Debug.Assert(false, "ExecuteReaderInternal: unknown result type");
639                             break;
640                         }
641                         executeResult = null;
642                         _hasDataReader = true;
643                         _connection.AddWeakReference(dataReader, OleDbReferenceCollection.DataReaderTag);
644
645                         // command stays in the executing state until the connection
646                         // has a datareader to track for it being closed
647                         state = ODB.InternalStateOpen; // MDAC 72655
648                     }
649                     finally {
650                         if (ODB.InternalStateOpen != state) {
651                             this.canceling = true;
652                             if (null != dataReader) {
653                                 ((IDisposable) dataReader).Dispose();
654                                 dataReader = null;
655                             }
656                         }
657                     }
658                     Debug.Assert(null != dataReader, "ExecuteReader should never return a null DataReader");
659                 }
660                 else { // optimized code path for ExecuteNonQuery to not create a OleDbDataReader object
661                     try {
662                         if (ODB.ExecutedIMultipleResults == resultType) {
663                             UnsafeNativeMethods.IMultipleResults multipleResults = (UnsafeNativeMethods.IMultipleResults) executeResult;
664
665                             // may cause a Connection.ResetState which closes connection
666                             nextResultsFailure = OleDbDataReader.NextResults(multipleResults, _connection, this, out _recordsAffected);
667                         }
668                     }
669                     finally {
670                         try {
671                             if (null != executeResult) {
672                                 Marshal.ReleaseComObject(executeResult);
673                                 executeResult = null;
674                             }
675                             CloseFromDataReader(ParameterBindings);
676                         }
677                         catch(Exception e) {
678                             // 
679                             if (!ADP.IsCatchableExceptionType(e)) {
680                                 throw;
681                             }
682                             if (null != nextResultsFailure) {
683                                 nextResultsFailure = new OleDbException(nextResultsFailure, e);
684                             }
685                             else {
686                                 throw;
687                             }
688                         }
689                     }
690                 }
691             }
692             finally { // finally clear executing state
693                 try {
694                     if ((null == dataReader) && (ODB.InternalStateOpen != state)) { // MDAC 67218
695                         ParameterCleanup();
696                     }
697                 }
698                 catch(Exception e) {
699                     // 
700                     if (!ADP.IsCatchableExceptionType(e)) {
701                         throw;
702                     }
703                     if (null != nextResultsFailure) {
704                         nextResultsFailure = new OleDbException(nextResultsFailure, e);
705                     }
706                     else {
707                         throw;
708                     }
709                 }
710                 if (null != nextResultsFailure) {
711                     throw nextResultsFailure;
712                 }
713             }
714             return dataReader;
715         }
716
717         private int ExecuteCommand(CommandBehavior behavior, out object executeResult) {
718             if (InitializeCommand(behavior, false)) {
719                 if (0 != (CommandBehavior.SchemaOnly & this.commandBehavior)) {
720                     executeResult = null;
721                     return ODB.PrepareICommandText;
722                 }
723                 return ExecuteCommandText(out executeResult);
724             }
725             return ExecuteTableDirect(behavior, out executeResult); // MDAC 57856
726         }
727
728         // dbindings handle can't be freed until the output parameters
729         // have been filled in which occurs after the last rowset is released
730         // dbbindings.FreeDataHandle occurs in Cloe
731         private int ExecuteCommandText(out object executeResult) {
732             int retcode;
733             tagDBPARAMS dbParams = null;
734             RowBinding rowbinding = null;
735             Bindings bindings = ParameterBindings;
736             bool mustRelease = false;
737
738             RuntimeHelpers.PrepareConstrainedRegions();
739             try {
740                 if (null != bindings) { // parameters may be suppressed
741                     rowbinding = bindings.RowBinding();
742
743                     rowbinding.DangerousAddRef(ref mustRelease);
744
745                     // bindings can't be released until after last rowset is released
746                     // that is when output parameters are populated
747                     // initialize the input parameters to the input databuffer
748                     bindings.ApplyInputParameters();
749
750                     dbParams = new tagDBPARAMS();
751                     dbParams.pData = rowbinding.DangerousGetDataPtr();
752                     dbParams.cParamSets = 1;
753                     dbParams.hAccessor = rowbinding.DangerousGetAccessorHandle();
754                 }
755                 if ((0 == (CommandBehavior.SingleResult & this.commandBehavior)) && _connection.SupportMultipleResults()) {
756                     retcode = ExecuteCommandTextForMultpleResults(dbParams, out executeResult);
757                 }
758                 else if (0 == (CommandBehavior.SingleRow & this.commandBehavior) || !_executeQuery) {
759                     retcode = ExecuteCommandTextForSingleResult(dbParams, out executeResult);
760                 }
761                 else {
762                     retcode = ExecuteCommandTextForSingleRow(dbParams, out executeResult);
763                 }
764             }
765             finally {
766                 if (mustRelease) {
767                     rowbinding.DangerousRelease();
768                 }
769             }
770             return retcode;
771         }
772
773         private int ExecuteCommandTextForMultpleResults(tagDBPARAMS dbParams, out object executeResult) {
774             Debug.Assert(0 == (CommandBehavior.SingleRow & this.commandBehavior), "SingleRow implies SingleResult");
775             OleDbHResult hr;
776
777             Bid.Trace("<oledb.ICommandText.Execute|API|OLEDB> %d#, IID_IMultipleResults\n", ObjectID);
778             hr = _icommandText.Execute(ADP.PtrZero, ref ODB.IID_IMultipleResults, dbParams, out _recordsAffected, out executeResult);
779             Bid.Trace("<oledb.ICommandText.Execute|API|OLEDB|RET> %08X{HRESULT}, RecordsAffected=%Id\n", hr, _recordsAffected);
780
781             if (OleDbHResult.E_NOINTERFACE != hr) {
782                 ExecuteCommandTextErrorHandling(hr);
783                 return ODB.ExecutedIMultipleResults;
784             }
785             SafeNativeMethods.Wrapper.ClearErrorInfo();
786             return ExecuteCommandTextForSingleResult(dbParams, out executeResult);
787         }
788
789         private int ExecuteCommandTextForSingleResult(tagDBPARAMS dbParams, out object executeResult) {
790             OleDbHResult hr;
791
792             // MDAC 64465 (Microsoft.Jet.OLEDB.4.0 returns 0 for recordsAffected instead of -1)
793             if (_executeQuery) {
794                 Bid.Trace("<oledb.ICommandText.Execute|API|OLEDB> %d#, IID_IRowset\n", ObjectID);
795                 hr = _icommandText.Execute(ADP.PtrZero, ref ODB.IID_IRowset, dbParams, out _recordsAffected, out executeResult);
796                 Bid.Trace("<oledb.ICommandText.Execute|API|OLEDB|RET> %08X{HRESULT}, RecordsAffected=%Id\n", hr, _recordsAffected);
797             }
798             else {
799                 Bid.Trace("<oledb.ICommandText.Execute|API|OLEDB> %d#, IID_NULL\n", ObjectID);
800                 hr = _icommandText.Execute(ADP.PtrZero, ref ODB.IID_NULL, dbParams, out _recordsAffected, out executeResult);
801                 Bid.Trace("<oledb.ICommandText.Execute|API|OLEDB|RET> %08X{HRESULT}, RecordsAffected=%Id\n", hr, _recordsAffected);
802             }
803             ExecuteCommandTextErrorHandling(hr);
804             return ODB.ExecutedIRowset;
805         }
806
807         private int ExecuteCommandTextForSingleRow(tagDBPARAMS dbParams, out object executeResult) {
808             Debug.Assert(_executeQuery, "ExecuteNonQuery should always use ExecuteCommandTextForSingleResult");
809
810             if (_connection.SupportIRow(this)) {
811                 OleDbHResult hr;
812
813                 Bid.Trace("<oledb.ICommandText.Execute|API|OLEDB> %d#, IID_IRow\n", ObjectID);
814                 hr = _icommandText.Execute(ADP.PtrZero, ref ODB.IID_IRow, dbParams, out _recordsAffected, out executeResult);
815                 Bid.Trace("<oledb.ICommandText.Execute|API|OLEDB|RET> %08X{HRESULT}, RecordsAffected=%Id\n", hr, _recordsAffected);
816
817                 if (OleDbHResult.DB_E_NOTFOUND == hr) { // MDAC 76110
818                     SafeNativeMethods.Wrapper.ClearErrorInfo();
819                     return ODB.ExecutedIRow;
820                 }
821                 else if (OleDbHResult.E_NOINTERFACE != hr) {
822                     ExecuteCommandTextErrorHandling(hr);
823                     return ODB.ExecutedIRow;
824                 }
825             }
826             SafeNativeMethods.Wrapper.ClearErrorInfo();
827             return ExecuteCommandTextForSingleResult(dbParams, out executeResult);
828         }
829
830         private void ExecuteCommandTextErrorHandling(OleDbHResult hr) {
831             Exception e = OleDbConnection.ProcessResults(hr, _connection, this);
832             if (null != e) {
833                 e = ExecuteCommandTextSpecialErrorHandling(hr, e);
834                 throw e;
835             }
836         }
837
838         private Exception ExecuteCommandTextSpecialErrorHandling(OleDbHResult hr, Exception e) {
839             if (((OleDbHResult.DB_E_ERRORSOCCURRED == hr) || (OleDbHResult.DB_E_BADBINDINFO == hr)) && (null != _dbBindings)) { // MDAC 66026, 67039
840                 //
841                 // this code exist to try for a better user error message by post-morten detection
842                 // of invalid parameter types being passed to a provider that doesn't understand
843                 // the user specified parameter OleDbType
844
845                 Debug.Assert(null != e, "missing inner exception");
846
847                 StringBuilder builder = new StringBuilder();
848                 ParameterBindings.ParameterStatus(builder);
849                 e = ODB.CommandParameterStatus(builder.ToString(), e);
850             }
851             return e;
852         }
853
854         override public int ExecuteNonQuery() {
855             OleDbConnection.ExecutePermission.Demand();
856
857             IntPtr hscp;
858             Bid.ScopeEnter(out hscp, "<oledb.OleDbCommand.ExecuteNonQuery|API> %d#\n", ObjectID);
859             try {
860                 _executeQuery = false;
861                 ExecuteReaderInternal(CommandBehavior.Default, ADP.ExecuteNonQuery);
862                 return ADP.IntPtrToInt32(_recordsAffected);
863             }
864             finally {
865                 Bid.ScopeLeave(ref hscp);
866             }
867         }
868
869         override public object ExecuteScalar() {
870             OleDbConnection.ExecutePermission.Demand();
871
872             IntPtr hscp;
873             Bid.ScopeEnter(out hscp, "<oledb.OleDbCommand.ExecuteScalar|API> %d#\n", ObjectID);
874             try {
875                 object value = null;
876                 _executeQuery = true;
877                 using(OleDbDataReader reader = ExecuteReaderInternal(CommandBehavior.Default, ADP.ExecuteScalar)) {
878                     if (reader.Read() && (0 < reader.FieldCount)) {
879                         value = reader.GetValue(0);
880                     }
881                 }
882                 return value;
883             }
884             finally {
885                 Bid.ScopeLeave(ref hscp);
886             }
887         }
888
889         private int ExecuteTableDirect(CommandBehavior behavior, out object executeResult) {
890             this.commandBehavior = behavior;
891             executeResult = null;
892
893             OleDbHResult hr = OleDbHResult.S_OK;
894             
895             StringMemHandle sptr = null;
896             bool            mustReleaseStringHandle = false;
897
898             RuntimeHelpers.PrepareConstrainedRegions();
899             try {
900                 sptr = new StringMemHandle(ExpandCommandText());
901
902                 sptr.DangerousAddRef(ref mustReleaseStringHandle);
903
904                 if (mustReleaseStringHandle) {
905                     tagDBID tableID = new tagDBID();
906                     tableID.uGuid = Guid.Empty;
907                     tableID.eKind = ODB.DBKIND_NAME;
908                     tableID.ulPropid = sptr.DangerousGetHandle();
909
910                     using(IOpenRowsetWrapper iopenRowset = _connection.IOpenRowset()) {
911                         using(DBPropSet propSet = CommandPropertySets()) {
912                             if (null != propSet) {
913
914                                 // MDAC 65279
915                                 Bid.Trace("<oledb.IOpenRowset.OpenRowset|API|OLEDB> %d#, IID_IRowset\n", ObjectID);
916                                 bool mustRelease = false;
917                                 RuntimeHelpers.PrepareConstrainedRegions();
918                                 try {
919                                     propSet.DangerousAddRef(ref mustRelease);
920                                     hr = iopenRowset.Value.OpenRowset(ADP.PtrZero, tableID, ADP.PtrZero, ref ODB.IID_IRowset, propSet.PropertySetCount, propSet.DangerousGetHandle(), out executeResult);
921                                 }
922                                 finally {
923                                     if (mustRelease) {
924                                         propSet.DangerousRelease();
925                                     }
926                                 }
927                                     
928                                 Bid.Trace("<oledb.IOpenRowset.OpenRowset|API|OLEDB|RET> %08X{HRESULT}", hr);
929
930                                 if (OleDbHResult.DB_E_ERRORSOCCURRED == hr) {
931                                     Bid.Trace("<oledb.IOpenRowset.OpenRowset|API|OLEDB> %d#, IID_IRowset\n", ObjectID);
932                                     hr = iopenRowset.Value.OpenRowset(ADP.PtrZero, tableID, ADP.PtrZero, ref ODB.IID_IRowset, 0, IntPtr.Zero, out executeResult);
933                                     Bid.Trace("<oledb.IOpenRowset.OpenRowset|API|OLEDB|RET> %08X{HRESULT}", hr);
934                                 }
935                             }
936                             else {
937                                 Bid.Trace("<oledb.IOpenRowset.OpenRowset|API|OLEDB> %d#, IID_IRowset\n", ObjectID);
938                                 hr = iopenRowset.Value.OpenRowset(ADP.PtrZero, tableID, ADP.PtrZero, ref ODB.IID_IRowset, 0, IntPtr.Zero, out executeResult);
939                                 Bid.Trace("<oledb.IOpenRowset.OpenRowset|API|OLEDB|RET> %08X{HRESULT}", hr);
940                             }
941                         }
942                     }
943                 }
944             }
945             finally {
946                 if (mustReleaseStringHandle) {
947                     sptr.DangerousRelease();
948                 }
949             }
950             ProcessResults(hr);
951             _recordsAffected = ADP.RecordsUnaffected;
952             return ODB.ExecutedIRowset;
953         }
954
955         private string ExpandCommandText() {
956             string cmdtxt = CommandText;
957             if (ADP.IsEmpty(cmdtxt)) {
958                 return ADP.StrEmpty;
959             }
960             CommandType cmdtype = CommandType;
961             switch(cmdtype) {
962             case System.Data.CommandType.Text:
963                 // do nothing, already expanded by user
964                 return cmdtxt;
965
966             case System.Data.CommandType.StoredProcedure:
967                 // { ? = CALL SPROC (? ?) }, { ? = CALL SPROC }, { CALL SPRC (? ?) }, { CALL SPROC }
968                 return ExpandStoredProcedureToText(cmdtxt);
969
970             case System.Data.CommandType.TableDirect:
971                 // @devnote: Provider=Jolt4.0 doesn't like quoted table names, SQOLEDB requires them
972                 // Providers should not require table names to be quoted and should guarantee that
973                 // unquoted table names correctly open the specified table, even if the table name
974                 // contains special characters, as long as the table can be unambiguously identified
975                 // without quoting.
976                 return cmdtxt;
977
978             default:
979                 throw ADP.InvalidCommandType(cmdtype);
980             }
981         }
982
983         private string ExpandOdbcMaximumToText(string sproctext, int parameterCount) {
984             StringBuilder builder = new StringBuilder();
985             if ((0 < parameterCount) && (ParameterDirection.ReturnValue == Parameters[0].Direction)) {
986                 parameterCount--;
987                 builder.Append("{ ? = CALL ");
988             }
989             else {
990                 builder.Append("{ CALL ");
991             }
992             builder.Append(sproctext); // WebData 95634
993
994             switch(parameterCount) {
995             case 0:
996                 builder.Append(" }");
997                 break;
998             case 1:
999                 builder.Append("( ? ) }");
1000                 break;
1001             default:
1002                 builder.Append("( ?, ?");
1003                 for (int i = 2; i < parameterCount; ++i) {
1004                     builder.Append(", ?");
1005                 }
1006                 builder.Append(" ) }");
1007                 break;
1008             }
1009             return builder.ToString();
1010         }
1011
1012         private string ExpandOdbcMinimumToText(string sproctext, int parameterCount) {
1013             //if ((0 < parameterCount) && (ParameterDirection.ReturnValue == Parameters[0].Direction)) {
1014             //    Debug.Assert("doesn't support ReturnValue parameters");
1015             //}
1016             StringBuilder builder = new StringBuilder();
1017             builder.Append("exec ");
1018             builder.Append(sproctext);
1019             if (0 < parameterCount) {
1020                 builder.Append(" ?");
1021                 for(int i = 1; i < parameterCount; ++i) {
1022                     builder.Append(", ?");
1023                 }
1024             }
1025             return builder.ToString();
1026         }
1027
1028         private string ExpandStoredProcedureToText(string sproctext) {
1029             Debug.Assert(null != _connection, "ExpandStoredProcedureToText: null Connection");
1030
1031             int parameterCount = (null != _parameters) ? _parameters.Count : 0;
1032             if (0 == (ODB.DBPROPVAL_SQL_ODBC_MINIMUM & _connection.SqlSupport())) {
1033                 return ExpandOdbcMinimumToText(sproctext, parameterCount);
1034             }
1035             return ExpandOdbcMaximumToText(sproctext, parameterCount);
1036         }
1037
1038         private void ParameterCleanup() {
1039             Bindings bindings = ParameterBindings;
1040             if (null != bindings) {
1041                 bindings.CleanupBindings();
1042             }
1043         }
1044
1045         private bool InitializeCommand(CommandBehavior behavior, bool throwifnotsupported) {
1046             Debug.Assert(null != _connection, "InitializeCommand: null OleDbConnection");
1047
1048             int changeid = _changeID;
1049             if ((0 != (CommandBehavior.KeyInfo & (this.commandBehavior ^ behavior))) || (_lastChangeID != changeid)) {
1050                 CloseInternalParameters(); // could optimize out
1051                 CloseInternalCommand();
1052             }
1053             this.commandBehavior = behavior;
1054             changeid = _changeID;
1055
1056             if (!PropertiesOnCommand(false)) {
1057                 return false; // MDAC 57856
1058             }
1059
1060             if ((null != _dbBindings) && _dbBindings.AreParameterBindingsInvalid(_parameters)) {
1061                 CloseInternalParameters();
1062             }
1063
1064             // if we already having bindings - don't create the accessor
1065             // if _parameters is null - no parameters exist - don't create the collection
1066             // do we actually have parameters since the collection exists
1067             if ((null == _dbBindings) && HasParameters()) {
1068                 // if we setup the parameters before setting cmdtxt then named parameters can happen
1069                 CreateAccessor();
1070             }
1071
1072             if (_lastChangeID != changeid) {
1073                 OleDbHResult hr;
1074
1075                 String commandText = ExpandCommandText();
1076
1077                 if (Bid.TraceOn) {
1078                     Bid.Trace("<oledb.ICommandText.SetCommandText|API|OLEDB> %d#, DBGUID_DEFAULT, CommandText='", ObjectID);
1079                     Bid.PutStr(commandText); // Use PutStr to write out entire string
1080                     Bid.Trace("'\n");
1081                 }
1082                 hr = _icommandText.SetCommandText(ref ODB.DBGUID_DEFAULT, commandText);
1083                 Bid.Trace("<oledb.ICommandText.SetCommandText|API|OLEDB|RET> %08X{HRESULT}\n", hr);
1084
1085                 if (hr < 0) {
1086                     ProcessResults(hr);
1087                 }
1088             }
1089
1090             _lastChangeID = changeid;
1091
1092             return true;
1093         }
1094
1095         private void PropertyChanging() {
1096             unchecked { _changeID++; }
1097         }
1098
1099         override public void Prepare() {
1100             OleDbConnection.ExecutePermission.Demand();
1101
1102             IntPtr hscp;
1103             Bid.ScopeEnter(out hscp, "<oledb.OleDbCommand.Prepare|API> %d#\n", ObjectID);
1104             try {
1105                 if (CommandType.TableDirect != CommandType) { // MDAC 70946, 71194
1106                     ValidateConnectionAndTransaction(ADP.Prepare);
1107
1108                     _isPrepared = false;
1109                     if (CommandType.TableDirect != CommandType) {
1110                         InitializeCommand(0, true);
1111                         PrepareCommandText(1);
1112                     }
1113                 }
1114             }
1115             finally {
1116                 Bid.ScopeLeave(ref hscp);
1117             }
1118         }
1119
1120         private void PrepareCommandText(int expectedExecutionCount) {
1121             OleDbParameterCollection parameters = _parameters;
1122             if (null != parameters) {
1123                 foreach(OleDbParameter parameter in parameters) {
1124                     if (parameter.IsParameterComputed()) {
1125                         // @devnote: use IsParameterComputed which is called in the normal case
1126                         // only to call Prepare to throw the specialized error message
1127                         // reducing the overall number of methods to actually jit
1128                         parameter.Prepare(this); // MDAC 70232
1129                     }
1130                 }
1131             }
1132             UnsafeNativeMethods.ICommandPrepare icommandPrepare = ICommandPrepare();
1133             if (null != icommandPrepare) {
1134                 OleDbHResult hr;
1135
1136                 Bid.Trace("<oledb.ICommandPrepare.Prepare|API|OLEDB> %d#, expectedExecutionCount=%d\n", ObjectID, expectedExecutionCount);
1137                 hr = icommandPrepare.Prepare(expectedExecutionCount);
1138                 Bid.Trace("<oledb.ICommandPrepare.Prepare|API|OLEDB|RET> %08X{HRESULT}\n", hr);
1139
1140                 ProcessResults(hr);
1141
1142             }
1143             // don't recompute bindings on prepared statements
1144             _isPrepared = true;
1145         }
1146
1147         private void ProcessResults(OleDbHResult hr) {
1148             Exception e = OleDbConnection.ProcessResults(hr, _connection, this);
1149             if (null != e) { throw e; }
1150         }
1151
1152         private void ProcessResultsNoReset(OleDbHResult hr) {
1153             Exception e = OleDbConnection.ProcessResults(hr, null, this);
1154             if (null != e) { throw e; }
1155         }
1156
1157         internal object GetPropertyValue(Guid propertySet, int propertyID) {
1158             if (null != _icommandText) {
1159                 OleDbHResult hr;
1160                 tagDBPROP[] dbprops;
1161                 UnsafeNativeMethods.ICommandProperties icommandProperties = ICommandProperties();
1162
1163                 using(PropertyIDSet propidset = new PropertyIDSet(propertySet, propertyID)) {
1164
1165                     using(DBPropSet propset = new DBPropSet(icommandProperties, propidset, out hr)) {
1166                         if (hr < 0) {
1167                             // VSDD 621427: OLEDB Data Reader masks provider specific errors by raising "Internal .Net Framework Data Provider error 30."
1168                             // DBPropSet c-tor will register the exception and it will be raised at GetPropertySet call in case of failure
1169                             SafeNativeMethods.Wrapper.ClearErrorInfo();
1170                         }
1171                         dbprops = propset.GetPropertySet(0, out propertySet);
1172                     }
1173                 }
1174                 if (OleDbPropertyStatus.Ok == dbprops[0].dwStatus) {
1175                     return dbprops[0].vValue;
1176                 }
1177                 return dbprops[0].dwStatus;
1178             }
1179             return OleDbPropertyStatus.NotSupported;
1180         }
1181
1182         private bool PropertiesOnCommand(bool throwNotSupported) {
1183             if (null != _icommandText) {
1184                 return true;
1185             }
1186             Debug.Assert(!_isPrepared, "null command isPrepared");
1187
1188             OleDbConnection connection = _connection;
1189             if (null == connection) {
1190                 connection.CheckStateOpen(ODB.Properties);
1191             }
1192             if (!_trackingForClose) {
1193                 _trackingForClose = true;
1194                 connection.AddWeakReference(this, OleDbReferenceCollection.CommandTag);
1195             }
1196             _icommandText = connection.ICommandText();
1197
1198             if (null == _icommandText) {
1199                 if (throwNotSupported || HasParameters()) {
1200                     throw ODB.CommandTextNotSupported(connection.Provider, null);
1201                 }
1202                 return false; // MDAC 57856
1203             }
1204
1205             using(DBPropSet propSet = CommandPropertySets()) {
1206                 if (null != propSet) {
1207                     UnsafeNativeMethods.ICommandProperties icommandProperties = ICommandProperties();
1208
1209                     Bid.Trace("<oledb.ICommandProperties.SetProperties|API|OLEDB> %d#\n", ObjectID);
1210                     OleDbHResult hr = icommandProperties.SetProperties(propSet.PropertySetCount, propSet);
1211                     Bid.Trace("<oledb.ICommandProperties.SetProperties|API|OLEDB|RET> %08X{HRESULT}\n", hr);
1212
1213                     if (hr < 0) {
1214                         SafeNativeMethods.Wrapper.ClearErrorInfo();
1215                     }
1216                 }
1217             }
1218             return true;
1219         }
1220
1221         private DBPropSet CommandPropertySets() {
1222             DBPropSet propSet = null;
1223
1224             bool keyInfo = (0 != (CommandBehavior.KeyInfo & this.commandBehavior));
1225
1226             // always set the CommandTimeout value?
1227             int count = (_executeQuery ? (keyInfo ? 4 : 2) : 1);
1228
1229             if (0 < count) {
1230                 propSet = new DBPropSet(1);
1231
1232                 tagDBPROP[] dbprops = new tagDBPROP[count];
1233
1234                 dbprops[0] = new tagDBPROP(ODB.DBPROP_COMMANDTIMEOUT, false, CommandTimeout);
1235
1236                 if (_executeQuery) {
1237                     // 'Microsoft.Jet.OLEDB.4.0' default is DBPROPVAL_AO_SEQUENTIAL
1238                     dbprops[1] = new tagDBPROP(ODB.DBPROP_ACCESSORDER, false, ODB.DBPROPVAL_AO_RANDOM); // MDAC 73030
1239
1240                     if (keyInfo) {
1241                         // 'Unique Rows' property required for SQLOLEDB to retrieve things like 'BaseTableName'
1242                         dbprops[2] = new tagDBPROP(ODB.DBPROP_UNIQUEROWS, false, keyInfo);
1243
1244                         // otherwise 'Microsoft.Jet.OLEDB.4.0' doesn't support IColumnsRowset
1245                         dbprops[3] = new tagDBPROP(ODB.DBPROP_IColumnsRowset, false, true);
1246                     }
1247                 }
1248                 propSet.SetPropertySet(0, OleDbPropertySetGuid.Rowset, dbprops);
1249             }
1250             return propSet;
1251         }
1252
1253         internal Bindings TakeBindingOwnerShip() {
1254             Bindings bindings = _dbBindings;
1255             _dbBindings = null;
1256             return bindings;
1257         }
1258
1259         private void ValidateConnection(string method) {
1260             if (null == _connection) {
1261                 throw ADP.ConnectionRequired(method);
1262             }
1263             _connection.CheckStateOpen(method);
1264
1265             // user attempting to execute the command while the first dataReader hasn't returned
1266             // use the connection reference collection to see if the dataReader referencing this
1267             // command has been garbage collected or not.
1268             if (_hasDataReader) {
1269                 if (_connection.HasLiveReader(this)) {
1270                     throw ADP.OpenReaderExists();
1271                 }
1272                 _hasDataReader = false;
1273             }
1274         }
1275
1276         private void ValidateConnectionAndTransaction(string method) {
1277             ValidateConnection(method);
1278             _transaction = _connection.ValidateTransaction(Transaction, method);
1279             this.canceling = false;
1280         }
1281     }
1282 }