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;
  }
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 ( ) ) ) { if ( ! block ) { int c = pgStream . peekChar ( ) ; if ( c == 'C' ) { LOGGER . log ( Level . FINEST , " <=BE CommandStatus, Ignored until CopyDone" ) ; break ; } } int c = pgStream . receiveChar ( ) ; switch ( c ) { case 'A' : LOGGER . log ( Level . FINEST , " <=BE Asynchronous Notification while copying" ) ; receiveAsyncNotify ( ) ; break ; case 'N' : LOGGER . log ( Level . FINEST , " <=BE Notification while copying" ) ; addWarning ( receiveNoticeResponse ( ) ) ; break ; case 'C' : 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' : error = receiveErrorResponse ( ) ; block = true ; break ; case 'G' : 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' : 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' : 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' : 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' : LOGGER . log ( Level . FINEST , " <=BE CopyDone" ) ; len = pgStream . receiveInteger4 ( ) - 4 ; if ( len > 0 ) { pgStream . receive ( len ) ; } if ( ! ( op instanceof CopyOut ) ) { error = new PSQLException ( "Got CopyDone while not copying from server" , PSQLState . OBJECT_NOT_IN_STATE ) ; } block = true ; break ; case 'S' : try { receiveParameterStatus ( ) ; } catch ( SQLException e ) { error = e ; endReceiving = true ; } break ; case 'Z' : receiveRFQ ( ) ; if ( hasLock ( op ) ) { unlock ( op ) ; } op = null ; endReceiving = true ; break ; case 'T' : LOGGER . log ( Level . FINEST , " <=BE RowDescription (during copy ignored)" ) ; skipMessage ( ) ; break ; case 'D' : 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 ) ) ) ; } if ( error != null ) { if ( errors != null ) { error . setNextException ( errors ) ; } errors = error ; error = null ; } } if ( errors != null ) { throw errors ; } return op ; }
Handles copy sub protocol responses from server. Unlocks at end of sub protocol, so operations
on pgStream or QueryExecutor are not allowed in a method after calling this!

@param block whether to block waiting for input
@return CopyIn when COPY FROM STDIN starts; CopyOut when COPY TO STDOUT starts; null when copy
ends; otherwise, the operation given as parameter.
@throws SQLException in case of misuse
@throws IOException from the underlying connection