public void testTypeMix() throws IOException {
    byte[] buffer = new byte[1024];
    String resPath = "/org/hsqldb/resources/odbcPacket.data";
    InputStream is = OdbcPacketOutputStreamTest.class.getResourceAsStream(resPath);
    if (is == null) {
      throw new RuntimeException(
          "CLASSPATH not set properly.  " + "Res file '" + resPath + "' not accessible");
    }
    ByteArrayOutputStream baosA = new ByteArrayOutputStream();
    ByteArrayOutputStream baosE = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(baosA);

    int i;
    while ((i = is.read(buffer)) > -1) {
      baosE.write(buffer, 0, i);
    }
    byte[] expectedBa = baosE.toByteArray();
    baosE.close();

    targetPacket.writeShort((short) distinguishableLong);
    targetPacket.writeInt((int) distinguishableLong);
    targetPacket.writeLong(distinguishableLong);
    targetPacket.writeByte((byte) distinguishableLong);
    targetPacket.writeByteChar('k');
    // the writeByteChar() method is explicitly not for ext. characters.

    int preLength = targetPacket.getSize();
    targetPacket.write("Ein gro\u00df Baum\nwith blossom", false);
    if (targetPacket.getSize() - preLength != 27) {
      throw new RuntimeException("Assertion failed.  Fix test because encoding size changed");
    }
    targetPacket.write("Another string", true);
    targetPacket.writeSized("Ein gro\u00df Baum\nmit blossom");
    targetPacket.xmit('a', dos);
    dos.flush();
    dos.close();
    byte[] actualBa = baosA.toByteArray();

    /* Use this to regenerate the test data (which is also used to test
     * the reader).
    java.io.FileOutputStream fos =
        new java.io.FileOutputStream("/tmp/fix.bin");
    fos.write(actualBa);
    fos.flush();
    fos.close();
    */

    // JUnit 4.x has a built-in byte-array comparator.  Until then...
    assertEquals("Byte stream size is wrong", expectedBa.length, actualBa.length);
    for (i = 0; i < expectedBa.length; i++) {
      assertEquals("Bye stream corruption at offset " + i, expectedBa[i], actualBa[i]);
    }
  }
  public void write(SessionInterface session, DataOutputStream dataOut, RowOutputInterface rowOut)
      throws IOException, HsqlException {

    rowOut.reset();
    rowOut.writeByte(mode);

    int startPos = rowOut.size();

    rowOut.writeSize(0);

    switch (mode) {
      case ResultConstants.GETSESSIONATTR:
        rowOut.writeByte(statementReturnType);
        break;

      case ResultConstants.DISCONNECT:
      case ResultConstants.RESETSESSION:
      case ResultConstants.STARTTRAN:
        break;

      case ResultConstants.PREPARE:
        rowOut.writeByte(statementReturnType);
        rowOut.writeString(mainString);
        rowOut.writeByte(rsProperties);
        rowOut.writeByte(generateKeys);

        if (generateKeys == ResultConstants.RETURN_GENERATED_KEYS_COL_NAMES
            || generateKeys == ResultConstants.RETURN_GENERATED_KEYS_COL_INDEXES) {
          generatedMetaData.write(rowOut);
        }
        break;

      case ResultConstants.FREESTMT:
        rowOut.writeLong(statementID);
        break;

      case ResultConstants.CLOSE_RESULT:
        rowOut.writeLong(id);
        break;

      case ResultConstants.EXECDIRECT:
        rowOut.writeInt(updateCount);
        rowOut.writeInt(fetchSize);
        rowOut.writeByte(statementReturnType);
        rowOut.writeString(mainString);
        rowOut.writeByte(rsProperties);
        rowOut.writeShort(queryTimeout);
        rowOut.writeByte(generateKeys);

        if (generateKeys == ResultConstants.RETURN_GENERATED_KEYS_COL_NAMES
            || generateKeys == ResultConstants.RETURN_GENERATED_KEYS_COL_INDEXES) {
          generatedMetaData.write(rowOut);
        }
        break;

      case ResultConstants.CONNECT:
        rowOut.writeString(databaseName);
        rowOut.writeString(mainString);
        rowOut.writeString(subString);
        rowOut.writeString(zoneString);
        rowOut.writeInt(updateCount);
        break;

      case ResultConstants.ERROR:
      case ResultConstants.WARNING:
        rowOut.writeString(mainString);
        rowOut.writeString(subString);
        rowOut.writeInt(errorCode);
        break;

      case ResultConstants.CONNECTACKNOWLEDGE:
        rowOut.writeInt(databaseID);
        rowOut.writeLong(sessionID);
        rowOut.writeString(databaseName);
        rowOut.writeString(mainString);
        break;

      case ResultConstants.UPDATECOUNT:
        rowOut.writeInt(updateCount);
        break;

      case ResultConstants.ENDTRAN:
        {
          int type = getActionType();

          rowOut.writeInt(type); // endtran type

          switch (type) {
            case ResultConstants.TX_SAVEPOINT_NAME_RELEASE:
            case ResultConstants.TX_SAVEPOINT_NAME_ROLLBACK:
              rowOut.writeString(mainString); // savepoint name
              break;

            case ResultConstants.TX_COMMIT:
            case ResultConstants.TX_ROLLBACK:
            case ResultConstants.TX_COMMIT_AND_CHAIN:
            case ResultConstants.TX_ROLLBACK_AND_CHAIN:
            case ResultConstants.PREPARECOMMIT:
              break;

            default:
              throw Error.runtimeError(ErrorCode.U_S0500, "Result");
          }

          break;
        }
      case ResultConstants.PREPARE_ACK:
        rowOut.writeByte(statementReturnType);
        rowOut.writeLong(statementID);
        rowOut.writeByte(rsProperties);
        metaData.write(rowOut);
        parameterMetaData.write(rowOut);
        break;

      case ResultConstants.CALL_RESPONSE:
        rowOut.writeInt(updateCount);
        rowOut.writeInt(fetchSize);
        rowOut.writeLong(statementID);
        rowOut.writeByte(statementReturnType);
        rowOut.writeByte(rsProperties);
        metaData.write(rowOut);
        writeSimple(rowOut, metaData, (Object[]) valueData);
        break;

      case ResultConstants.EXECUTE:
        rowOut.writeInt(updateCount);
        rowOut.writeInt(fetchSize);
        rowOut.writeLong(statementID);
        rowOut.writeByte(rsProperties);
        rowOut.writeShort(queryTimeout);
        writeSimple(rowOut, metaData, (Object[]) valueData);
        break;

      case ResultConstants.UPDATE_RESULT:
        rowOut.writeLong(id);
        rowOut.writeInt(getActionType());
        metaData.write(rowOut);
        writeSimple(rowOut, metaData, (Object[]) valueData);
        break;

      case ResultConstants.BATCHEXECRESPONSE:
      case ResultConstants.BATCHEXECUTE:
      case ResultConstants.BATCHEXECDIRECT:
      case ResultConstants.SETSESSIONATTR:
        {
          rowOut.writeInt(updateCount);
          rowOut.writeInt(fetchSize);
          rowOut.writeLong(statementID);
          rowOut.writeShort(queryTimeout);
          metaData.write(rowOut);
          navigator.writeSimple(rowOut, metaData);

          break;
        }
      case ResultConstants.PARAM_METADATA:
        {
          metaData.write(rowOut);
          navigator.write(rowOut, metaData);

          break;
        }
      case ResultConstants.SETCONNECTATTR:
        {
          int type = getConnectionAttrType();

          rowOut.writeInt(type); // attr type / updateCount

          switch (type) {
            case ResultConstants.SQL_ATTR_SAVEPOINT_NAME:
              rowOut.writeString(mainString); // savepoint name
              break;

              // case ResultConstants.SQL_ATTR_AUTO_IPD // always true
              // default: // throw, but case never happens
            default:
              throw Error.runtimeError(ErrorCode.U_S0500, "Result");
          }

          break;
        }
      case ResultConstants.REQUESTDATA:
        {
          rowOut.writeLong(id);
          rowOut.writeInt(updateCount);
          rowOut.writeInt(fetchSize);

          break;
        }
      case ResultConstants.DATAROWS:
        metaData.write(rowOut);
        navigator.write(rowOut, metaData);
        break;

      case ResultConstants.DATAHEAD:
      case ResultConstants.DATA:
      case ResultConstants.GENERATED:
        rowOut.writeLong(id);
        rowOut.writeInt(updateCount);
        rowOut.writeInt(fetchSize);
        rowOut.writeByte(rsProperties);
        metaData.write(rowOut);
        navigator.write(rowOut, metaData);
        break;

      default:
        throw Error.runtimeError(ErrorCode.U_S0500, "Result");
    }

    rowOut.writeIntData(rowOut.size() - startPos, startPos);
    dataOut.write(rowOut.getOutputStream().getBuffer(), 0, rowOut.size());

    int count = getLobCount();
    Result current = this;

    for (int i = 0; i < count; i++) {
      ResultLob lob = current.lobResults;

      lob.writeBody(session, dataOut);

      current = current.lobResults;
    }

    if (chainedResult == null) {
      dataOut.writeByte(ResultConstants.NONE);
    } else {
      chainedResult.write(session, dataOut, rowOut);
    }

    dataOut.flush();
  }