public override int Read(char[] buffer, int index, int count) { ValidateReadParameters(buffer, index, count); if (IsClosed) { throw ADP.ObjectDisposed(this); } if (_currentTask != null) { throw ADP.AsyncOperationPending(); } int charsRead = 0; int charsNeeded = count; // Load in peeked char if ((charsNeeded > 0) && (HasPeekedChar)) { Debug.Assert((_peekedChar >= char.MinValue) && (_peekedChar <= char.MaxValue), $"Bad peeked character: {_peekedChar}"); buffer[index + charsRead] = (char)_peekedChar; charsRead++; charsNeeded--; _peekedChar = -1; } // If we need more data and there is data avaiable, read charsRead += InternalRead(buffer, index + charsRead, charsNeeded); return(charsRead); }
public override int Read() { if (_currentTask != null) { throw ADP.AsyncOperationPending(); } if (IsClosed) { throw ADP.ObjectDisposed(this); } int readChar = -1; // If there is already a peeked char, then return it if (HasPeekedChar) { readChar = _peekedChar; _peekedChar = -1; } // If there is data available try to read a char else { char[] tempBuffer = new char[1]; int charsRead = InternalRead(tempBuffer, 0, 1); if (charsRead == 1) { readChar = tempBuffer[0]; } } Debug.Assert(readChar == -1 || ((readChar >= char.MinValue) && (readChar <= char.MaxValue)), $"Bad read character: {readChar}"); return(readChar); }
public override int Peek() { if (_currentTask != null) { throw ADP.AsyncOperationPending(); } if (IsClosed) { throw ADP.ObjectDisposed(this); } if (!HasPeekedChar) { _peekedChar = Read(); } Debug.Assert(_peekedChar == -1 || ((_peekedChar >= char.MinValue) && (_peekedChar <= char.MaxValue)), $"Bad peeked character: {_peekedChar}"); return(_peekedChar); }
public override int Read(byte[] buffer, int offset, int count) { ValidateReadParameters(buffer, offset, count); if (!CanRead) { throw ADP.ObjectDisposed(this); } if (_currentTask != null) { throw ADP.AsyncOperationPending(); } try { return(_reader.GetBytesInternalSequential(_columnIndex, buffer, offset, count, _readTimeout)); } catch (SqlException ex) { // Stream.Read() can't throw a SqlException - so wrap it in an IOException throw ADP.ErrorReadingFromStream(ex); } }
public override Task <int> ReadAsync(char[] buffer, int index, int count) { ValidateReadParameters(buffer, index, count); TaskCompletionSource <int> completion = new TaskCompletionSource <int>(); if (IsClosed) { completion.SetException(ADP.ExceptionWithStackTrace(ADP.ObjectDisposed(this))); } else { try { Task original = Interlocked.CompareExchange <Task>(ref _currentTask, completion.Task, null); if (original != null) { completion.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending())); } else { bool completedSynchronously = true; int charsRead = 0; int adjustedIndex = index; int charsNeeded = count; // Load in peeked char if ((HasPeekedChar) && (charsNeeded > 0)) { // Take a copy of _peekedChar in case it is cleared during close int peekedChar = _peekedChar; if (peekedChar >= char.MinValue) { Debug.Assert((_peekedChar >= char.MinValue) && (_peekedChar <= char.MaxValue), $"Bad peeked character: {_peekedChar}"); buffer[adjustedIndex] = (char)peekedChar; adjustedIndex++; charsRead++; charsNeeded--; _peekedChar = -1; } } int byteBufferUsed; byte[] byteBuffer = PrepareByteBuffer(charsNeeded, out byteBufferUsed); // Permit a 0 byte read in order to advance the reader to the correct column if ((byteBufferUsed < byteBuffer.Length) || (byteBuffer.Length == 0)) { int bytesRead; var reader = _reader; if (reader != null) { Task <int> getBytesTask = reader.GetBytesAsync(_columnIndex, byteBuffer, byteBufferUsed, byteBuffer.Length - byteBufferUsed, Timeout.Infinite, _disposalTokenSource.Token, out bytesRead); if (getBytesTask == null) { byteBufferUsed += bytesRead; } else { // We need more data - setup the callback, and mark this as not completed sync completedSynchronously = false; getBytesTask.ContinueWith((t) => { _currentTask = null; // If we completed but the textreader is closed, then report cancellation if ((t.Status == TaskStatus.RanToCompletion) && (!IsClosed)) { try { int bytesReadFromStream = t.Result; byteBufferUsed += bytesReadFromStream; if (byteBufferUsed > 0) { charsRead += DecodeBytesToChars(byteBuffer, byteBufferUsed, buffer, adjustedIndex, charsNeeded); } completion.SetResult(charsRead); } catch (Exception ex) { completion.SetException(ex); } } else if (IsClosed) { completion.SetException(ADP.ExceptionWithStackTrace(ADP.ObjectDisposed(this))); } else if (t.Status == TaskStatus.Faulted) { if (t.Exception.InnerException is SqlException) { // ReadAsync can't throw a SqlException, so wrap it in an IOException completion.SetException(ADP.ExceptionWithStackTrace(ADP.ErrorReadingFromStream(t.Exception.InnerException))); } else { completion.SetException(t.Exception.InnerException); } } else { completion.SetCanceled(); } }, TaskScheduler.Default); } if ((completedSynchronously) && (byteBufferUsed > 0)) { // No more data needed, decode what we have charsRead += DecodeBytesToChars(byteBuffer, byteBufferUsed, buffer, adjustedIndex, charsNeeded); } } else { // Reader is null, close must of happened in the middle of this read completion.SetException(ADP.ExceptionWithStackTrace(ADP.ObjectDisposed(this))); } } if (completedSynchronously) { _currentTask = null; if (IsClosed) { completion.SetCanceled(); } else { completion.SetResult(charsRead); } } } } catch (Exception ex) { // In case of any errors, ensure that the completion is completed and the task is set back to null if we switched it completion.TrySetException(ex); Interlocked.CompareExchange(ref _currentTask, null, completion.Task); throw; } } return(completion.Task); }
public override Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { ValidateReadParameters(buffer, offset, count); TaskCompletionSource <int> completion = new TaskCompletionSource <int>(); if (!CanRead) { completion.SetException(ADP.ExceptionWithStackTrace(ADP.ObjectDisposed(this))); } else { try { Task original = Interlocked.CompareExchange <Task>(ref _currentTask, completion.Task, null); if (original != null) { completion.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending())); } else { // Set up a combined cancellation token for both the user's and our disposal tokens CancellationTokenSource combinedTokenSource; if (!cancellationToken.CanBeCanceled) { // Users token is not cancellable - just use ours combinedTokenSource = _disposalTokenSource; } else { // Setup registrations from user and disposal token to cancel the combined token combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _disposalTokenSource.Token); } int bytesRead = 0; Task <int> getBytesTask = null; var reader = _reader; if ((reader != null) && (!cancellationToken.IsCancellationRequested) && (!_disposalTokenSource.Token.IsCancellationRequested)) { getBytesTask = reader.GetBytesAsync(_columnIndex, buffer, offset, count, _readTimeout, combinedTokenSource.Token, out bytesRead); } if (getBytesTask == null) { _currentTask = null; if (cancellationToken.IsCancellationRequested) { completion.SetCanceled(); } else if (!CanRead) { completion.SetException(ADP.ExceptionWithStackTrace(ADP.ObjectDisposed(this))); } else { completion.SetResult(bytesRead); } if (combinedTokenSource != _disposalTokenSource) { combinedTokenSource.Dispose(); } } else { getBytesTask.ContinueWith((t) => { _currentTask = null; // If we completed, but _reader is null (i.e. the stream is closed), then report cancellation if ((t.Status == TaskStatus.RanToCompletion) && (CanRead)) { completion.SetResult((int)t.Result); } else if (t.Status == TaskStatus.Faulted) { if (t.Exception.InnerException is SqlException) { // Stream.ReadAsync() can't throw a SqlException - so wrap it in an IOException completion.SetException(ADP.ExceptionWithStackTrace(ADP.ErrorReadingFromStream(t.Exception.InnerException))); } else { completion.SetException(t.Exception.InnerException); } } else if (!CanRead) { completion.SetException(ADP.ExceptionWithStackTrace(ADP.ObjectDisposed(this))); } else { completion.SetCanceled(); } if (combinedTokenSource != _disposalTokenSource) { combinedTokenSource.Dispose(); } }, TaskScheduler.Default); } } } catch (Exception ex) { // In case of any errors, ensure that the completion is completed and the task is set back to null if we switched it completion.TrySetException(ex); Interlocked.CompareExchange(ref _currentTask, null, completion.Task); throw; } } return(completion.Task); }