/**
   * Implements a partial transaction ROLLBACK.
   *
   * @param name Name of savepoint that was marked before by savepoint() call
   * @throws HsqlException
   */
  void rollbackToSavepoint(String name) throws HsqlException {

    int index = savepoints.getIndex(name);

    Trace.check(index >= 0, Trace.SAVEPOINT_NOT_FOUND, name);

    Integer oi = (Integer) savepoints.get(index);

    index = oi.intValue();

    int i = tTransaction.size() - 1;

    for (; i >= index; i--) {
      Transaction t = (Transaction) tTransaction.get(i);

      t.rollback(this);
      tTransaction.remove(i);
    }

    releaseSavepoint(name);

    try {
      dDatabase.logger.writeToLog(
          this, Token.T_ROLLBACK + " " + Token.T_TO + " " + Token.T_SAVEPOINT + " " + name);
    } catch (HsqlException e) {
    }
  }
  Result getResult(Session session) {

    boolean startTransaction = false;

    if (this.isExplain) {
      return Result.newSingleColumnStringResult("OPERATION", describe(session));
    }

    switch (type) {

        // cursor
      case StatementTypes.ALLOCATE_CURSOR:
      case StatementTypes.ALLOCATE_DESCRIPTOR:
        return Result.updateZeroResult;

        //
      case StatementTypes.COMMIT_WORK:
        {
          try {
            boolean chain = parameters != null;

            session.commit(chain);

            return Result.updateZeroResult;
          } catch (HsqlException e) {
            return Result.newErrorResult(e, sql);
          }
        }
      case StatementTypes.DEALLOCATE_DESCRIPTOR:
      case StatementTypes.DEALLOCATE_PREPARE:
        return Result.updateZeroResult;

      case StatementTypes.DISCONNECT:
        session.close();

        return Result.updateZeroResult;

        //
      case StatementTypes.DYNAMIC_CLOSE:
      case StatementTypes.DYNAMIC_DELETE_CURSOR:
      case StatementTypes.DYNAMIC_FETCH:
      case StatementTypes.DYNAMIC_OPEN:

        //
      case StatementTypes.FETCH:
      case StatementTypes.FREE_LOCATOR:
      case StatementTypes.GET_DESCRIPTOR:
      case StatementTypes.HOLD_LOCATOR:

        //
      case StatementTypes.OPEN:
      case StatementTypes.PREPARABLE_DYNAMIC_DELETE_CURSOR:
      case StatementTypes.PREPARABLE_DYNAMIC_UPDATE_CURSOR:
      case StatementTypes.PREPARE:
        return Result.updateZeroResult;

      case StatementTypes.TRANSACTION_LOCK_TABLE:
        {
          return Result.updateZeroResult;
        }
      case StatementTypes.RELEASE_SAVEPOINT:
        {
          String savepoint = (String) parameters[0];

          try {
            session.releaseSavepoint(savepoint);

            return Result.updateZeroResult;
          } catch (HsqlException e) {
            return Result.newErrorResult(e, sql);
          }
        }
      case StatementTypes.ROLLBACK_WORK:
        {
          boolean chain = ((Boolean) parameters[0]).booleanValue();

          session.rollback(chain);

          return Result.updateZeroResult;
        }
      case StatementTypes.ROLLBACK_SAVEPOINT:
        {
          String savepoint = (String) parameters[0];

          try {
            session.rollbackToSavepoint(savepoint);

            return Result.updateZeroResult;
          } catch (HsqlException e) {
            return Result.newErrorResult(e, sql);
          }
        }
      case StatementTypes.SAVEPOINT:
        {
          String savepoint = (String) parameters[0];

          session.savepoint(savepoint);

          return Result.updateZeroResult;
        }
      case StatementTypes.SET_CATALOG:
        {
          String name;

          try {
            name = (String) expressions[0].getValue(session);
            name = (String) Type.SQL_VARCHAR.trim(session, name, ' ', true, true);

            if (session.database.getCatalogName().name.equals(name)) {
              return Result.updateZeroResult;
            }

            return Result.newErrorResult(Error.error(ErrorCode.X_3D000), sql);
          } catch (HsqlException e) {
            return Result.newErrorResult(e, sql);
          }
        }
      case StatementTypes.SET_CONNECTION:
      case StatementTypes.SET_CONSTRAINT:
      case StatementTypes.SET_DESCRIPTOR:
        return Result.updateZeroResult;

      case StatementTypes.SET_TIME_ZONE:
        {
          Object value = null;

          if (expressions[0].getType() == OpTypes.VALUE
              && expressions[0].getConstantValueNoCheck(session) == null) {
            session.timeZoneSeconds = session.sessionTimeZoneSeconds;

            return Result.updateZeroResult;
          }

          try {
            value = expressions[0].getValue(session);
          } catch (HsqlException e) {
          }

          if (value instanceof Result) {
            Result result = (Result) value;

            if (result.isData()) {
              Object[] data = (Object[]) result.getNavigator().getNext();
              boolean single = !result.getNavigator().next();

              if (single && data != null && data[0] != null) {
                value = data[0];

                result.getNavigator().close();
              } else {
                result.getNavigator().close();

                return Result.newErrorResult(Error.error(ErrorCode.X_22009), sql);
              }
            } else {
              return Result.newErrorResult(Error.error(ErrorCode.X_22009), sql);
            }
          } else {
            if (value == null) {
              return Result.newErrorResult(Error.error(ErrorCode.X_22009), sql);
            }
          }

          long seconds = ((IntervalSecondData) value).getSeconds();

          if (-DTIType.timezoneSecondsLimit <= seconds && seconds <= DTIType.timezoneSecondsLimit) {
            session.timeZoneSeconds = (int) seconds;

            return Result.updateZeroResult;
          }

          return Result.newErrorResult(Error.error(ErrorCode.X_22009), sql);
        }
      case StatementTypes.SET_NAMES:
        return Result.updateZeroResult;

      case StatementTypes.SET_PATH:
        return Result.updateZeroResult;

      case StatementTypes.SET_ROLE:
        {
          String name;
          Grantee role = null;

          try {
            name = (String) expressions[0].getValue(session);

            if (name != null) {
              name = (String) Type.SQL_VARCHAR.trim(session, name, ' ', true, true);
              role = session.database.granteeManager.getRole(name);
            }
          } catch (HsqlException e) {
            return Result.newErrorResult(Error.error(ErrorCode.X_0P000), sql);
          }

          if (session.isInMidTransaction()) {
            return Result.newErrorResult(Error.error(ErrorCode.X_25001), sql);
          }

          if (role == null) {
            session.setRole(null);
          }

          if (session.getGrantee().hasRole(role)) {
            session.setRole(role);

            return Result.updateZeroResult;
          } else {
            return Result.newErrorResult(Error.error(ErrorCode.X_0P000), sql);
          }
        }
      case StatementTypes.SET_SCHEMA:
        {
          String name;
          HsqlName schema;

          try {
            if (expressions == null) {
              name = ((HsqlName) parameters[0]).name;
            } else {
              name = (String) expressions[0].getValue(session);
            }

            name = (String) Type.SQL_VARCHAR.trim(session, name, ' ', true, true);
            schema = session.database.schemaManager.getSchemaHsqlName(name);

            session.setSchema(schema.name);

            return Result.updateZeroResult;
          } catch (HsqlException e) {
            return Result.newErrorResult(e, sql);
          }
        }
      case StatementTypes.SET_SESSION_AUTHORIZATION:
        {
          if (session.isInMidTransaction()) {
            return Result.newErrorResult(Error.error(ErrorCode.X_25001), sql);
          }

          try {
            String user;
            String password = null;

            user = (String) expressions[0].getValue(session);
            user = (String) Type.SQL_VARCHAR.trim(session, user, ' ', true, true);

            if (expressions[1] != null) {
              password = (String) expressions[1].getValue(session);
            }

            User userObject;

            if (password == null) {
              userObject = session.database.userManager.get(user);
            } else {
              userObject = session.database.getUserManager().getUser(user, password);
            }

            if (userObject == null) {
              throw Error.error(ErrorCode.X_28501);
            }

            sql = userObject.getConnectUserSQL();

            if (userObject == session.getGrantee()) {
              return Result.updateZeroResult;
            }

            if (session.getGrantee().canChangeAuthorisation()) {
              session.setUser((User) userObject);
              session.setRole(null);
              session.resetSchema();

              return Result.updateZeroResult;
            }

            /** @todo may need different error code */
            throw Error.error(ErrorCode.X_28000);
          } catch (HsqlException e) {
            return Result.newErrorResult(e, sql);
          }
        }
      case StatementTypes.SET_SESSION_CHARACTERISTICS:
        {
          try {
            if (parameters[0] != null) {
              boolean readonly = ((Boolean) parameters[0]).booleanValue();

              session.setReadOnlyDefault(readonly);
            }

            if (parameters[1] != null) {
              int level = ((Integer) parameters[1]).intValue();

              session.setIsolationDefault(level);
            }

            return Result.updateZeroResult;
          } catch (HsqlException e) {
            return Result.newErrorResult(e, sql);
          }
        }
      case StatementTypes.SET_COLLATION:
        return Result.updateZeroResult;

      case StatementTypes.SET_TRANSFORM_GROUP:
        return Result.updateZeroResult;

      case StatementTypes.START_TRANSACTION:
        startTransaction = true;

        // fall through
      case StatementTypes.SET_TRANSACTION:
        {
          try {
            if (parameters[0] != null) {
              boolean readonly = ((Boolean) parameters[0]).booleanValue();

              session.setReadOnly(readonly);
            }

            if (parameters[1] != null) {
              int level = ((Integer) parameters[1]).intValue();

              session.setIsolation(level);
            }

            if (startTransaction) {
              session.startTransaction();
            }

            return Result.updateZeroResult;
          } catch (HsqlException e) {
            return Result.newErrorResult(e, sql);
          }
        }

        //
      case StatementTypes.SET_SESSION_AUTOCOMMIT:
        {
          boolean mode = ((Boolean) parameters[0]).booleanValue();

          try {
            session.setAutoCommit(mode);

            return Result.updateZeroResult;
          } catch (HsqlException e) {
            return Result.newErrorResult(e, sql);
          }
        }
      case StatementTypes.DECLARE_VARIABLE:
        {
          ColumnSchema variable = (ColumnSchema) parameters[0];

          try {
            session.sessionContext.addSessionVariable(variable);

            return Result.updateZeroResult;
          } catch (HsqlException e) {
            return Result.newErrorResult(e, sql);
          }
        }
      case StatementTypes.SET_SESSION_RESULT_MAX_ROWS:
        {
          int size = ((Integer) parameters[0]).intValue();

          session.setSQLMaxRows(size);

          return Result.updateZeroResult;
        }
      case StatementTypes.SET_SESSION_RESULT_MEMORY_ROWS:
        {
          int size = ((Integer) parameters[0]).intValue();

          session.setResultMemoryRowCount(size);

          return Result.updateZeroResult;
        }
      default:
        throw Error.runtimeError(ErrorCode.U_S0500, "CompiledStateemntCommand");
    }
  }
  /**
   * Executes the command encapsulated by the cmd argument.
   *
   * @param cmd the command to execute
   * @return the result of executing the command
   */
  public Result execute(Result cmd) {

    try {
      if (Trace.DOASSERT) {
        Trace.doAssert(!isNestedTransaction);
      }

      Trace.check(!isClosed, Trace.ACCESS_IS_DENIED, "Session is closed");
    } catch (Throwable t) {
      return new Result(t, null);
    }

    int type = cmd.iMode;

    synchronized (dDatabase) {
      if (sessionMaxRows == 0) {
        currentMaxRows = cmd.iUpdateCount;
      }

      DatabaseManager.gc();

      switch (type) {
        case ResultConstants.SQLEXECUTE:
          {
            return cmd.getSize() > 1 ? sqlExecuteBatch(cmd) : sqlExecute(cmd);
          }
        case ResultConstants.SQLEXECDIRECT:
          {
            return cmd.getSize() > 0
                ? sqlExecuteBatchDirect(cmd)
                : sqlExecuteDirectNoPreChecks(cmd.getMainString());
          }
        case ResultConstants.SQLPREPARE:
          {
            return sqlPrepare(cmd.getMainString(), cmd.getStatementType());
          }
        case ResultConstants.SQLFREESTMT:
          {
            return sqlFreeStatement(cmd.getStatementID());
          }
        case ResultConstants.GETSESSIONATTR:
          {
            return getAttributes();
          }
        case ResultConstants.SETSESSIONATTR:
          {
            return setAttributes(cmd);
          }
        case ResultConstants.SQLENDTRAN:
          {
            switch (cmd.getEndTranType()) {
              case ResultConstants.COMMIT:
                commit();
                break;

              case ResultConstants.ROLLBACK:
                rollback();
                break;

              case ResultConstants.SAVEPOINT_NAME_RELEASE:
                try {
                  String name = cmd.getMainString();

                  releaseSavepoint(name);
                } catch (Throwable t) {
                  return new Result(t, null);
                }
                break;

              case ResultConstants.SAVEPOINT_NAME_ROLLBACK:
                try {
                  rollbackToSavepoint(cmd.getMainString());
                } catch (Throwable t) {
                  return new Result(t, null);
                }
                break;

                // not yet
                //                        case ResultConstants.COMMIT_AND_CHAIN :
                //                        case ResultConstants.ROLLBACK_AND_CHAIN :
            }

            return emptyUpdateCount;
          }
        case ResultConstants.SQLSETCONNECTATTR:
          {
            switch (cmd.getConnectionAttrType()) {
              case ResultConstants.SQL_ATTR_SAVEPOINT_NAME:
                try {
                  savepoint(cmd.getMainString());
                } catch (Throwable t) {
                  return new Result(t, null);
                }

                // case ResultConstants.SQL_ATTR_AUTO_IPD
                //   - always true
                // default: throw - case never happens
            }

            return emptyUpdateCount;
          }
        default:
          {
            String msg = "operation type:" + type;

            return new Result(msg, "s1000", Trace.OPERATION_NOT_SUPPORTED);
          }
      }
    }
  }