public void readLobResults(
      SessionInterface session, DataInputStream inputStream, RowInputBinary in)
      throws IOException, HsqlException {

    Result currentResult = this;
    boolean hasLob = false;

    setSession(session);

    while (true) {
      int addedResultMode = inputStream.readByte();

      if (addedResultMode == ResultConstants.LARGE_OBJECT_OP) {
        ResultLob resultLob = ResultLob.newLob(inputStream, false);

        if (session instanceof Session) {
          ((Session) session).allocateResultLob(resultLob, inputStream);
        } else {
          currentResult.addLobResult(resultLob);
        }

        hasLob = true;

        continue;
      } else if (addedResultMode == ResultConstants.NONE) {
        break;
      } else {
        throw Error.runtimeError(ErrorCode.U_S0500, "Result");
      }
    }

    if (hasLob) {
      ((Session) session).registerResultLobs(currentResult);
    }
  }
  public static Result newResult(Session session, int mode, DataInput dataInput, RowInputBinary in)
      throws IOException, HsqlException {

    try {
      if (mode == ResultConstants.LARGE_OBJECT_OP) {
        return ResultLob.newLob(dataInput, false);
      }

      Result result = newResult(session, dataInput, in, mode);

      return result;
    } catch (IOException e) {
      throw Error.error(ErrorCode.X_08000);
    }
  }
  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();
  }