/// <include file='docs/mysqlcommand.xml' path='docs/ExecuteReader1/*'/> public new MySqlDataReader ExecuteReader(CommandBehavior behavior) { // give our interceptors a shot at it first MySqlDataReader interceptedReader = null; if (connection?.commandInterceptor != null && connection.commandInterceptor.ExecuteReader(CommandText, behavior, ref interceptedReader)) { return(interceptedReader); } // interceptors didn't handle this so we fall through bool success = false; CheckState(); Driver driver = connection.driver; cmdText = cmdText.Trim(); if (String.IsNullOrEmpty(cmdText)) { Throw(new InvalidOperationException(Resources.CommandTextNotInitialized)); } string sql = cmdText.Trim(';'); #if !NETSTANDARD1_3 // Load balancing getting a new connection if (connection.hasBeenOpen && !driver.HasStatus(ServerStatusFlags.InTransaction)) { ReplicationManager.GetNewConnection(connection.Settings.Server, !IsReadOnlyCommand(sql), connection); } #endif lock (driver) { // We have to recheck that there is no reader, after we got the lock if (connection.Reader != null) { Throw(new MySqlException(Resources.DataReaderOpen)); } #if !NETSTANDARD1_3 System.Transactions.Transaction curTrans = System.Transactions.Transaction.Current; if (curTrans != null) { bool inRollback = false; //TODO: ADD support for 452 and 46X if (driver.currentTransaction != null) { inRollback = driver.currentTransaction.InRollback; } if (!inRollback) { System.Transactions.TransactionStatus status = System.Transactions.TransactionStatus.InDoubt; try { // in some cases (during state transitions) this throws // an exception. Ignore exceptions, we're only interested // whether transaction was aborted or not. status = curTrans.TransactionInformation.Status; } catch (System.Transactions.TransactionException) { } if (status == System.Transactions.TransactionStatus.Aborted) { Throw(new System.Transactions.TransactionAbortedException()); } } } #endif commandTimer = new CommandTimer(connection, CommandTimeout); LastInsertedId = -1; if (CommandType == CommandType.TableDirect) { sql = "SELECT * FROM " + sql; } else if (CommandType == CommandType.Text) { // validates single word statetment (maybe is a stored procedure call) if (sql.IndexOf(" ") == -1) { if (AddCallStatement(sql)) { sql = "call " + sql; } } } // if we are on a replicated connection, we are only allow readonly statements if (connection.Settings.Replication && !InternallyCreated) { EnsureCommandIsReadOnly(sql); } if (statement == null || !statement.IsPrepared) { if (CommandType == CommandType.StoredProcedure) { statement = new StoredProcedure(this, sql); } else { statement = new PreparableStatement(this, sql); } } // stored procs are the only statement type that need do anything during resolve statement.Resolve(false); // Now that we have completed our resolve step, we can handle our // command behaviors HandleCommandBehaviors(behavior); try { MySqlDataReader reader = new MySqlDataReader(this, statement, behavior); connection.Reader = reader; Canceled = false; // execute the statement statement.Execute(); // wait for data to return reader.NextResult(); success = true; return(reader); } catch (TimeoutException tex) { connection.HandleTimeoutOrThreadAbort(tex); throw; //unreached } #if !NETSTANDARD1_3 catch (ThreadAbortException taex) { connection.HandleTimeoutOrThreadAbort(taex); throw; } #endif catch (IOException ioex) { connection.Abort(); // Closes connection without returning it to the pool throw new MySqlException(Resources.FatalErrorDuringExecute, ioex); } catch (MySqlException ex) { if (ex.InnerException is TimeoutException) { throw; // already handled } try { ResetReader(); ResetSqlSelectLimit(); } catch (Exception) { // Reset SqlLimit did not work, connection is hosed. Connection.Abort(); throw new MySqlException(ex.Message, true, ex); } // if we caught an exception because of a cancel, then just return null if (ex.IsQueryAborted) { return(null); } if (ex.IsFatal) { Connection.Close(); } if (ex.Number == 0) { throw new MySqlException(Resources.FatalErrorDuringExecute, ex); } throw; } finally { if (connection != null) { if (connection.Reader == null) { // Something went seriously wrong, and reader would not // be able to clear timeout on closing. // So we clear timeout here. ClearCommandTimer(); } if (!success) { // ExecuteReader failed.Close Reader and set to null to // prevent subsequent errors with DataReaderOpen ResetReader(); } } } } }
/// <summary> /// Advances the data reader to the next result, when reading the results of batch SQL statements. /// </summary> /// <returns></returns> public override bool NextResult() { if (!isOpen) { throw new MySqlException(Resources.NextResultIsClosed); } bool isCaching = command.CommandType == CommandType.TableDirect && command.EnableCaching && (commandBehavior & CommandBehavior.SequentialAccess) == 0; // this will clear out any unread data if (resultSet != null) { resultSet.Close(); if (isCaching) { TableCache.AddToCache(command.CommandText, resultSet); } } // single result means we only return a single resultset. If we have already // returned one, then we return false // TableDirect is basically a select * from a single table so it will generate // a single result also if (resultSet != null && ((commandBehavior & CommandBehavior.SingleResult) != 0 || isCaching)) { return(false); } // next load up the next resultset if any try { do { resultSet = null; // if we are table caching, then try to retrieve the resultSet from the cache if (isCaching) { resultSet = TableCache.RetrieveFromCache(command.CommandText, command.CacheAge); } if (resultSet == null) { resultSet = driver.NextResult(Statement.StatementId, false); if (resultSet == null) { return(false); } if (resultSet.IsOutputParameters && command.CommandType == CommandType.StoredProcedure) { StoredProcedure sp = statement as StoredProcedure; sp.ProcessOutputParameters(this); resultSet.Close(); if (!sp.ServerProvidingOutputParameters) { return(false); } // if we are using server side output parameters then we will get our ok packet // *after* the output parameters resultset resultSet = driver.NextResult(Statement.StatementId, true); } resultSet.Cached = isCaching; } if (resultSet.Size == 0) { Command.lastInsertedId = resultSet.InsertedId; if (affectedRows == -1) { affectedRows = resultSet.AffectedRows; } else { affectedRows += resultSet.AffectedRows; } } } while (resultSet.Size == 0); return(true); } catch (MySqlException ex) { if (ex.IsFatal) { connection.Abort(); } if (ex.Number == 0) { throw new MySqlException(Resources.FatalErrorReadingResult, ex); } if ((commandBehavior & CommandBehavior.CloseConnection) != 0) { Close(); } throw; } }
/// <include file='docs/mysqlcommand.xml' path='docs/ExecuteReader1/*'/> public new MySqlDataReader ExecuteReader(CommandBehavior behavior) { bool success = false; CheckState(); Driver driver = connection.driver; lock (driver) { // We have to recheck that there is no reader, after we got the lock if (connection.Reader != null) { throw new MySqlException(Resources.DataReaderOpen); } #if !CF System.Transactions.Transaction curTrans = System.Transactions.Transaction.Current; if (curTrans != null) { bool inRollback = false; if (driver.CurrentTransaction != null) { inRollback = driver.CurrentTransaction.InRollback; } if (!inRollback) { TransactionStatus status = TransactionStatus.InDoubt; try { // in some cases (during state transitions) this throws // an exception. Ignore exceptions, we're only interested // whether transaction was aborted or not. status = curTrans.TransactionInformation.Status; } catch (TransactionException) { } if (status == TransactionStatus.Aborted) { throw new TransactionAbortedException(); } } } #endif commandTimer = new CommandTimer(connection, CommandTimeout); lastInsertedId = -1; if (cmdText == null || cmdText.Trim().Length == 0) { throw new InvalidOperationException(Resources.CommandTextNotInitialized); } string sql = TrimSemicolons(cmdText); if (CommandType == CommandType.TableDirect) { sql = "SELECT * FROM " + sql; } if (statement == null || !statement.IsPrepared) { if (CommandType == CommandType.StoredProcedure) { statement = new StoredProcedure(this, sql); } else { statement = new PreparableStatement(this, sql); } } // stored procs are the only statement type that need do anything during resolve statement.Resolve(false); // Now that we have completed our resolve step, we can handle our // command behaviors HandleCommandBehaviors(behavior); updatedRowCount = -1; try { MySqlDataReader reader = new MySqlDataReader(this, statement, behavior); connection.Reader = reader; // execute the statement statement.Execute(); // wait for data to return reader.NextResult(); success = true; return(reader); } catch (TimeoutException tex) { connection.HandleTimeoutOrThreadAbort(tex); throw; //unreached } catch (ThreadAbortException taex) { connection.HandleTimeoutOrThreadAbort(taex); throw; } catch (IOException ioex) { connection.Abort(); // Closes connection without returning it to the pool throw new MySqlException(Resources.FatalErrorDuringExecute, ioex); } catch (MySqlException ex) { if (ex.InnerException is TimeoutException) { throw; // already handled } try { ResetReader(); ResetSqlSelectLimit(); } catch (Exception) { // Reset SqlLimit did not work, connection is hosed. Connection.Abort(); throw new MySqlException(ex.Message, true, ex); } if (ex.IsFatal) { Connection.Close(); } if (ex.Number == 0) { throw new MySqlException(Resources.FatalErrorDuringExecute, ex); } throw; } finally { if (connection != null) { if (connection.Reader == null) { // Something went seriously wrong, and reader would not // be able to clear timeout on closing. // So we clear timeout here. ClearCommandTimer(); } if (!success) { // ExecuteReader failed.Close Reader and set to null to // prevent subsequent errors with DataReaderOpen ResetReader(); } } } } }
/// <summary> /// Advances the data reader to the next result, when reading the results of batch SQL statements. /// </summary> /// <returns></returns> public override bool NextResult() { if (!isOpen) { throw new MySqlException(Resources.NextResultIsClosed); } // this will clear out any unread data if (resultSet != null) { resultSet.Close(); } // single result means we only return a single resultset. If we have already // returned one, then we return false; if (resultSet != null && (commandBehavior & CommandBehavior.SingleResult) != 0) { return(false); } // next load up the next resultset if any try { do { resultSet = null; resultSet = driver.NextResult(Statement.StatementId); if (resultSet == null) { return(false); } if (resultSet.IsOutputParameters) { return(false); } if (resultSet.Size == 0) { Command.lastInsertedId = resultSet.InsertedId; if (affectedRows == -1) { affectedRows = resultSet.AffectedRows; } else { affectedRows += resultSet.AffectedRows; } } } while (resultSet.Size == 0); return(true); } catch (MySqlException ex) { if (ex.IsFatal) { connection.Abort(); } if (ex.Number == 0) { throw new MySqlException(Resources.FatalErrorReadingResult, ex); } throw; } }
public void CanOpenConnectionAfterAborting() { MySqlConnection connection = new MySqlConnection(GetConnectionString(true)); connection.Open(); Assert.AreEqual(ConnectionState.Open, connection.State); connection.Abort(); Assert.AreEqual(ConnectionState.Closed, connection.State); connection.Open(); Assert.AreEqual(ConnectionState.Open, connection.State); connection.Close(); }
/// <summary> /// Advances the data reader to the next result, when reading the results of batch SQL statements. /// </summary> /// <returns></returns> public override bool NextResult() { if (!isOpen) { throw new MySqlException(Resources.NextResultIsClosed); } bool firstResult = fields == null; if (fields != null) { ClearCurrentResultset(); fields = null; } // single result means we only return a single resultset. If we have already // returned one, then we return false; if (!firstResult && (commandBehavior & CommandBehavior.SingleResult) != 0) { return(false); } // tell our command to continue execution of the SQL batch until it its // another resultset try { long fieldCount = GetResultSet(); if (fieldCount == -1) { nextResultDone = true; hasRows = canRead = false; return(false); } // issue any requested UA warnings if (connection.Settings.UseUsageAdvisor) { if ((connection.driver.ServerStatus & ServerStatusFlags.NoIndex) != 0) { connection.UsageAdvisor.UsingNoIndex(command.CommandText); } if ((connection.driver.ServerStatus & ServerStatusFlags.BadIndex) != 0) { connection.UsageAdvisor.UsingBadIndex(command.CommandText); } } fields = driver.ReadColumnMetadata((int)fieldCount); fieldHashCS.Clear(); fieldHashCI.Clear(); values = new IMySqlValue[fields.Length]; for (int i = 0; i < fields.Length; i++) { string columnName = fields[i].ColumnName; if (!fieldHashCS.ContainsKey(columnName)) { fieldHashCS.Add(columnName, i); } if (!fieldHashCI.ContainsKey(columnName)) { fieldHashCI.Add(columnName, i); } values[i] = fields[i].GetValueObject(); } hasRead = false; uaFieldsUsed = new bool[fields.Length]; hasRows = canRead = driver.FetchDataRow(statement.StatementId, 0, fields.Length); return(true); } catch (MySqlException ex) { if (ex.IsFatal) { connection.Abort(); } nextResultDone = true; hasRows = canRead = false; if (command.TimedOut) { throw new MySqlException(Resources.Timeout); } if (ex.Number == 0) { throw new MySqlException(Resources.FatalErrorReadingResult, ex); } throw; } }
/// <include file='docs/mysqlcommand.xml' path='docs/ExecuteReader1/*'/> public new MySqlDataReader ExecuteReader(CommandBehavior behavior) { // interceptors didn't handle this so we fall through bool success = false; CheckState(); Driver driver = connection.driver; cmdText = cmdText.Trim(); string sql = cmdText.Trim(';'); lock (driver) { // We have to recheck that there is no reader, after we got the lock if (connection.Reader != null) { throw (new MySqlException("Resources.DataReaderOpen")); } commandTimer = new CommandTimer(connection, CommandTimeout); lastInsertedId = -1; if (CommandType == CommandType.TableDirect) { sql = "SELECT * FROM " + sql; } else if (CommandType == CommandType.Text) { // validates single word statetment (maybe is a stored procedure call) if (sql.IndexOf(" ") == -1) { if (AddCallStatement(sql)) { sql = "call " + sql; } } } // if we are on a replicated connection, we are only allow readonly statements if (connection.Settings.Replication && !InternallyCreated) { EnsureCommandIsReadOnly(sql); } if (statement == null || !statement.IsPrepared) { if (CommandType == CommandType.StoredProcedure) { statement = new StoredProcedure(this, sql); } else { statement = new PreparableStatement(this, sql); } } // stored procs are the only statement type that need do anything during resolve statement.Resolve(false); // Now that we have completed our resolve step, we can handle our // command behaviors HandleCommandBehaviors(behavior); updatedRowCount = -1; try { MySqlDataReader reader = new MySqlDataReader(this, statement, behavior); connection.Reader = reader; canceled = false; // execute the statement statement.Execute(); // wait for data to return reader.NextResult(); success = true; return(reader); } catch (TimeoutException tex) { connection.HandleTimeoutOrThreadAbort(tex); throw; //unreached } catch (ThreadAbortException taex) { connection.HandleTimeoutOrThreadAbort(taex); throw; } catch (IOException ioex) { connection.Abort(); // Closes connection without returning it to the pool throw new MySqlException("Resources.FatalErrorDuringExecute", ioex); } catch (MySqlException ex) { if (ex.InnerException is TimeoutException) { throw; // already handled } try { ResetReader(); ResetSqlSelectLimit(); } catch (Exception) { // Reset SqlLimit did not work, connection is hosed. Connection.Abort(); throw new MySqlException(ex.Message, true, ex); } // if we caught an exception because of a cancel, then just return null if (ex.IsQueryAborted) { return(null); } if (ex.IsFatal) { Connection.Close(); } if (ex.Number == 0) { throw new MySqlException("Resources.FatalErrorDuringExecute", ex); } throw; } finally { if (connection != null) { if (connection.Reader == null) { // Something went seriously wrong, and reader would not // be able to clear timeout on closing. // So we clear timeout here. ClearCommandTimer(); } if (!success) { // ExecuteReader failed.Close Reader and set to null to // prevent subsequent errors with DataReaderOpen ResetReader(); } } } } }