private OdbcDataReader ExecuteReaderObject(CommandBehavior behavior, string method) // MDAC 68324 { if ((_cmdText == null) || (_cmdText == "")) { throw (ADP.CommandTextRequired(method)); } OdbcDataReader localReader = null; try { // try-finally inside try-catch-throw try { ValidateConnectionAndTransaction(method); _canceling = false; if (0 != (CommandBehavior.SingleRow & behavior)) { // CommandBehavior.SingleRow implies CommandBehavior.SingleResult behavior |= CommandBehavior.SingleResult; } IntPtr keyinfostmt = IntPtr.Zero; ODBC32.RETCODE retcode; HandleRef stmt = GetStatementHandle(); if ((behavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo) { GetKeyInfoStatementHandle(); } localReader = new OdbcDataReader(this, _cmdWrapper, behavior); //Set command properties //Not all drivers support timeout. So fail silently if error if (supportsCommandTimeout) { retcode = (ODBC32.RETCODE)UnsafeNativeMethods.Odbc32.SQLSetStmtAttrW( stmt, (Int32)ODBC32.SQL_ATTR.QUERY_TIMEOUT, (IntPtr)this.CommandTimeout, (Int32)ODBC32.SQL_IS.UINTEGER ); if (ODBC32.RETCODE.SUCCESS != retcode) { supportsCommandTimeout = false; } } // todo: correct name is SQL_NB.ON/OFF for NOBROWSETABLE option (same values so not bug but should change name) // // todo: If we remember the state we can omit a lot of SQLSetStmtAttrW calls ... // if (Connection.IsV3Driver) { // Need to get the metadata information //SQLServer actually requires browse info turned on ahead of time... //Note: We ignore any failures, since this is SQLServer specific //We won't specialcase for SQL Server but at least for non-V3 drivers if (localReader.IsBehavior(CommandBehavior.KeyInfo)) { retcode = (ODBC32.RETCODE)UnsafeNativeMethods.Odbc32.SQLSetStmtAttrW( stmt, (Int32)ODBC32.SQL_SOPT_SS.NOBROWSETABLE, (IntPtr)ODBC32.SQL_HC.ON, (Int32)ODBC32.SQL_IS.INTEGER ); retcode = (ODBC32.RETCODE)UnsafeNativeMethods.Odbc32.SQLSetStmtAttrW( stmt, (Int32)ODBC32.SQL_SOPT_SS.HIDDEN_COLUMNS, (IntPtr)ODBC32.SQL_HC.ON, (Int32)ODBC32.SQL_IS.INTEGER ); } else { retcode = (ODBC32.RETCODE)UnsafeNativeMethods.Odbc32.SQLSetStmtAttrW( stmt, (Int32)ODBC32.SQL_SOPT_SS.NOBROWSETABLE, (IntPtr)ODBC32.SQL_HC.OFF, (Int32)ODBC32.SQL_IS.INTEGER ); retcode = (ODBC32.RETCODE)UnsafeNativeMethods.Odbc32.SQLSetStmtAttrW( stmt, (Int32)ODBC32.SQL_SOPT_SS.HIDDEN_COLUMNS, (IntPtr)ODBC32.SQL_HC.OFF, (Int32)ODBC32.SQL_IS.INTEGER ); } } if (localReader.IsBehavior(CommandBehavior.KeyInfo) || localReader.IsBehavior(CommandBehavior.SchemaOnly)) { #if DEBUG if (AdapterSwitches.OleDbTrace.TraceInfo) { ADP.DebugWriteLine("SQLPrepareW: " + CommandText); } #endif retcode = (ODBC32.RETCODE)UnsafeNativeMethods.Odbc32.SQLPrepareW( stmt, CommandText, ODBC32.SQL_NTS ); if (ODBC32.RETCODE.SUCCESS != retcode) { _connection.HandleError(stmt, ODBC32.SQL_HANDLE.STMT, retcode); } } //Handle Parameters //Note: We use the internal variable as to not instante a new object collection, //for the the common case of using no parameters. if ((null != _parameterCollection) && (0 < _parameterCollection.Count)) { //Bind all the parameters to the statement int count = _parameterCollection.Count; _cmdWrapper.ReAllocParameterBuffers(count); localReader.SetParameterBuffers(_cmdWrapper._parameterBuffer, _cmdWrapper._parameterintBuffer); //Note: It's more efficent for this function to just tell the parameter which //binding it is that for it to try and figure it out (IndexOf, etc). for (int i = 0; i < count; ++i) { _parameterCollection[i].Bind(_cmdWrapper, this, (short)(i + 1), _cmdWrapper._parameterBuffer[i], _cmdWrapper._parameterintBuffer[i]); } _parameterCollection.CollectionIsBound = true; _parameterCollection.BindingIsValid = true; } if (!localReader.IsBehavior(CommandBehavior.SchemaOnly)) { if (localReader.IsBehavior(CommandBehavior.KeyInfo) || _isPrepared) { //Already prepared, so use SQLExecute retcode = (ODBC32.RETCODE)UnsafeNativeMethods.Odbc32.SQLExecute(stmt); // Build metadata here // localReader.GetSchemaTable(); } else { #if DEBUG if (AdapterSwitches.OleDbTrace.TraceInfo) { ADP.DebugWriteLine("SQLExecDirectW: " + CommandText); } #endif //SQLExecDirect retcode = (ODBC32.RETCODE)UnsafeNativeMethods.Odbc32.SQLExecDirectW( stmt, // SQLHSTMT StatementHandle CommandText, // SQLCHAR * StatementText ODBC32.SQL_NTS // SQLINTEGER TextLength ); } //Note: Execute will return NO_DATA for Update/Delete non-row returning queries if ((ODBC32.RETCODE.SUCCESS != retcode) && (ODBC32.RETCODE.NO_DATA != retcode)) { _connection.HandleError(stmt, ODBC32.SQL_HANDLE.STMT, retcode); } } this.weakDataReaderReference = new WeakReference(localReader); _connection.SetStateFetchingTrue(); // XXXCommand.Execute should position reader on first row returning result // any exceptions in the initial non-row returning results should be thrown // from from ExecuteXXX not the DataReader if (!localReader.IsBehavior(CommandBehavior.SchemaOnly)) { localReader.FirstResult(); } cmdState = ConnectionState.Fetching; } finally { if (ConnectionState.Fetching != cmdState) { if (null != localReader) { // clear bindings so we don't grab output parameters on a failed execute int count = ((null != _parameterCollection) ? _parameterCollection.Count : 0); for (int i = 0; i < count; ++i) { _parameterCollection[i].ClearBinding(); } ((IDisposable)localReader).Dispose(); } if (ConnectionState.Closed != cmdState) { cmdState = ConnectionState.Closed; _connection.SetStateExecutingFalse(); } } } } catch { // MDAC 81875 throw; } GC.KeepAlive(localReader); GC.KeepAlive(this); return(localReader); }