public override int Read(byte[] buffer, int offset, int count)
        {
            CheckDisposed();
            if (!CanRead)
            {
                throw new InvalidOperationException("Stream not open for reading");
            }

            if (_isConsumed)
            {
                return(0);
            }

            if (_leftToReadInDataMsg == 0)
            {
                // We've consumed the current DataMessage (or haven't yet received the first),
                // read the next message
                var msg = _connector.ReadMessage();
                switch (msg.Code)
                {
                case BackendMessageCode.CopyData:
                    _leftToReadInDataMsg = ((CopyDataMessage)msg).Length;
                    break;

                case BackendMessageCode.CopyDone:
                    _connector.ReadExpecting <CommandCompleteMessage>();
                    _connector.ReadExpecting <ReadyForQueryMessage>();
                    _isConsumed = true;
                    return(0);

                default:
                    throw _connector.UnexpectedMessageReceived(msg.Code);
                }
            }

            Debug.Assert(_leftToReadInDataMsg > 0);

            // If our buffer is empty, read in more. Otherwise return whatever is there, even if the
            // user asked for more (normal socket behavior)
            if (_readBuf.ReadBytesLeft == 0)
            {
                _readBuf.ReadMore(false).GetAwaiter().GetResult();
            }

            Debug.Assert(_readBuf.ReadBytesLeft > 0);

            var maxCount = Math.Min(_readBuf.ReadBytesLeft, _leftToReadInDataMsg);

            if (count > maxCount)
            {
                count = maxCount;
            }

            _leftToReadInDataMsg -= count;
            _readBuf.ReadBytes(buffer, offset, count);
            return(count);
        }
        internal NpgsqlRawCopyStream(NpgsqlConnector connector, string copyCommand)
        {
            _connector = connector;
            _readBuf   = connector.ReadBuffer;
            _writeBuf  = connector.WriteBuffer;
            _connector.SendQuery(copyCommand);
            var msg = _connector.ReadMessage();

            switch (msg.Code)
            {
            case BackendMessageCode.CopyInResponse:
                var copyInResponse = (CopyInResponseMessage)msg;
                IsBinary  = copyInResponse.IsBinary;
                _canWrite = true;
                _writeBuf.StartCopyMode();
                break;

            case BackendMessageCode.CopyOutResponse:
                var copyOutResponse = (CopyOutResponseMessage)msg;
                IsBinary = copyOutResponse.IsBinary;
                _canRead = true;
                break;

            case BackendMessageCode.CompletedResponse:
                throw new InvalidOperationException(
                          "This API only supports import/export from the client, i.e. COPY commands containing TO/FROM STDIN. " +
                          "To import/export with files on your PostgreSQL machine, simply execute the command with ExecuteNonQuery. " +
                          "Note that your data has been successfully imported/exported.");

            default:
                throw _connector.UnexpectedMessageReceived(msg.Code);
            }
        }
Exemple #3
0
        internal NpgsqlBinaryExporter(NpgsqlConnector connector, string copyToCommand)
        {
            _connector  = connector;
            _buf        = connector.ReadBuffer;
            _typeMapper = connector.TypeMapper;
            _columnLen  = int.MinValue;  // Mark that the (first) column length hasn't been read yet
            _column     = -1;

            try
            {
                _connector.SendQuery(copyToCommand);

                CopyOutResponseMessage copyOutResponse;
                var msg = _connector.ReadMessage();
                switch (msg.Code)
                {
                case BackendMessageCode.CopyOutResponse:
                    copyOutResponse = (CopyOutResponseMessage)msg;
                    if (!copyOutResponse.IsBinary)
                    {
                        throw new ArgumentException("copyToCommand triggered a text transfer, only binary is allowed", nameof(copyToCommand));
                    }
                    break;

                case BackendMessageCode.CompletedResponse:
                    throw new InvalidOperationException(
                              "This API only supports import/export from the client, i.e. COPY commands containing TO/FROM STDIN. " +
                              "To import/export with files on your PostgreSQL machine, simply execute the command with ExecuteNonQuery. " +
                              "Note that your data has been successfully imported/exported.");

                default:
                    throw _connector.UnexpectedMessageReceived(msg.Code);
                }

                NumColumns        = copyOutResponse.NumColumns;
                _typeHandlerCache = new NpgsqlTypeHandler[NumColumns];
                ReadHeader();
            }
            catch
            {
                _connector.Break();
                throw;
            }
        }
        internal NpgsqlBinaryImporter(NpgsqlConnector connector, string copyFromCommand)
        {
            _connector = connector;
            _buf       = connector.WriteBuffer;
            _column    = -1;

            try
            {
                _connector.SendQuery(copyFromCommand);

                CopyInResponseMessage copyInResponse;
                var msg = _connector.ReadMessage();
                switch (msg.Code)
                {
                case BackendMessageCode.CopyInResponse:
                    copyInResponse = (CopyInResponseMessage)msg;
                    if (!copyInResponse.IsBinary)
                    {
                        throw new ArgumentException("copyFromCommand triggered a text transfer, only binary is allowed", nameof(copyFromCommand));
                    }
                    break;

                case BackendMessageCode.CompletedResponse:
                    throw new InvalidOperationException(
                              "This API only supports import/export from the client, i.e. COPY commands containing TO/FROM STDIN. " +
                              "To import/export with files on your PostgreSQL machine, simply execute the command with ExecuteNonQuery. " +
                              "Note that your data has been successfully imported/exported.");

                default:
                    throw _connector.UnexpectedMessageReceived(msg.Code);
                }

                NumColumns = copyInResponse.NumColumns;
                _params    = new NpgsqlParameter[NumColumns];
                _buf.StartCopyMode();
                WriteHeader();
            }
            catch
            {
                _connector.Break();
                throw;
            }
        }
 void Cancel()
 {
     _state = ImporterState.Cancelled;
     _buf.Clear();
     _buf.EndCopyMode();
     _connector.SendMessage(new CopyFailMessage());
     try
     {
         var msg = _connector.ReadMessage();
         // The CopyFail should immediately trigger an exception from the read above.
         _connector.Break();
         throw new NpgsqlException("Expected ErrorResponse when cancelling COPY but got: " + msg.Code);
     }
     catch (PostgresException e)
     {
         if (e.SqlState != "57014")
         {
             throw;
         }
     }
 }