docs: CopyOperationImpl processCopyResults(CopyOperationImpl op, boolean block)
        throws SQLException, IOException {
  
      boolean endReceiving = false;
      SQLException error = null;
      SQLException errors = null;
      int len;
  
      while (!endReceiving && (block || pgStream.hasMessagePending())) {
  
        // There is a bug in the server's implementation of the copy
        // protocol. It returns command complete immediately upon
        // receiving the EOF marker in the binary protocol,
        // potentially before we've issued CopyDone. When we are not
        // blocking, we don't think we are done, so we hold off on
        // processing command complete and any subsequent messages
        // until we actually are done with the copy.
        //
        if (!block) {
          int c = pgStream.peekChar();
          if (c == 'C') {
            // CommandComplete
            LOGGER.log(Level.FINEST, " <=BE CommandStatus, Ignored until CopyDone");
            break;
          }
        }
  
        int c = pgStream.receiveChar();
        switch (c) {
  
          case 'A': // Asynchronous Notify
  
            LOGGER.log(Level.FINEST, " <=BE Asynchronous Notification while copying");
  
            receiveAsyncNotify();
            break;
  
          case 'N': // Notice Response
  
            LOGGER.log(Level.FINEST, " <=BE Notification while copying");
  
            addWarning(receiveNoticeResponse());
            break;
  
          case 'C': // Command Complete
  
            String status = receiveCommandStatus();
  
            try {
              if (op == null) {
                throw new PSQLException(GT
                    .tr("Received CommandComplete ''{0}'' without an active copy operation", status),
                    PSQLState.OBJECT_NOT_IN_STATE);
              }
              op.handleCommandStatus(status);
            } catch (SQLException se) {
              error = se;
            }
  
            block = true;
            break;
  
          case 'E': // ErrorMessage (expected response to CopyFail)
  
            error = receiveErrorResponse();
            // We've received the error and we now expect to receive
            // Ready for query, but we must block because it might still be
            // on the wire and not here yet.
            block = true;
            break;
  
          case 'G': // CopyInResponse
  
            LOGGER.log(Level.FINEST, " <=BE CopyInResponse");
  
            if (op != null) {
              error = new PSQLException(GT.tr("Got CopyInResponse from server during an active {0}",
                  op.getClass().getName()), PSQLState.OBJECT_NOT_IN_STATE);
            }
  
            op = new CopyInImpl();
            initCopy(op);
            endReceiving = true;
            break;
  
          case 'H': // CopyOutResponse
  
            LOGGER.log(Level.FINEST, " <=BE CopyOutResponse");
  
            if (op != null) {
              error = new PSQLException(GT.tr("Got CopyOutResponse from server during an active {0}",
                  op.getClass().getName()), PSQLState.OBJECT_NOT_IN_STATE);
            }
  
            op = new CopyOutImpl();
            initCopy(op);
            endReceiving = true;
            break;
  
          case 'W': // CopyBothResponse
  
            LOGGER.log(Level.FINEST, " <=BE CopyBothResponse");
  
            if (op != null) {
              error = new PSQLException(GT.tr("Got CopyBothResponse from server during an active {0}",
                      op.getClass().getName()), PSQLState.OBJECT_NOT_IN_STATE);
            }
  
            op = new CopyDualImpl();
            initCopy(op);
            endReceiving = true;
            break;
  
          case 'd': // CopyData
  
            LOGGER.log(Level.FINEST, " <=BE CopyData");
  
            len = pgStream.receiveInteger4() - 4;
            byte[] buf = pgStream.receive(len);
            if (op == null) {
              error = new PSQLException(GT.tr("Got CopyData without an active copy operation"),
                  PSQLState.OBJECT_NOT_IN_STATE);
            } else if (!(op instanceof CopyOut)) {
              error = new PSQLException(
                  GT.tr("Unexpected copydata from server for {0}", op.getClass().getName()),
                  PSQLState.COMMUNICATION_ERROR);
            } else {
              op.handleCopydata(buf);
            }
            endReceiving = true;
            break;
  
          case 'c': // CopyDone (expected after all copydata received)
  
            LOGGER.log(Level.FINEST, " <=BE CopyDone");
  
            len = pgStream.receiveInteger4() - 4;
            if (len > 0) {
              pgStream.receive(len); // not in specification; should never appear
            }
  
            if (!(op instanceof CopyOut)) {
              error = new PSQLException("Got CopyDone while not copying from server",
                  PSQLState.OBJECT_NOT_IN_STATE);
            }
  
            // keep receiving since we expect a CommandComplete
            block = true;
            break;
          case 'S': // Parameter Status
            try {
              receiveParameterStatus();
            } catch (SQLException e) {
              error = e;
              endReceiving = true;
            }
            break;
  
          case 'Z': // ReadyForQuery: After FE:CopyDone => BE:CommandComplete
  
            receiveRFQ();
            if (hasLock(op)) {
              unlock(op);
            }
            op = null;
            endReceiving = true;
            break;
  
          // If the user sends a non-copy query, we've got to handle some additional things.
          //
          case 'T': // Row Description (response to Describe)
            LOGGER.log(Level.FINEST, " <=BE RowDescription (during copy ignored)");
  
            skipMessage();
            break;
  
          case 'D': // DataRow
            LOGGER.log(Level.FINEST, " <=BE DataRow (during copy ignored)");
  
            skipMessage();
            break;
  
          default:
            throw new IOException(
                GT.tr("Unexpected packet type during copy: {0}", Integer.toString(c)));
        }
  
        // Collect errors into a neat chain for completeness
        if (error != null) {
          if (errors != null) {
            error.setNextException(errors);
          }
          errors = error;
          error = null;
        }
      }
  
      if (errors != null) {
        throw errors;
      }
  
      return op;
    }