/**
   * Executes a generic CompiledStatement. Execution includes first building any subquery result
   * dependencies and clearing them after the main result is built.
   *
   * @return the result of executing the statement
   * @param cs any valid CompiledStatement
   */
  Result execute(CompiledStatement cs) {

    Result result = null;

    DatabaseManager.gc();

    try {
      cs.materializeSubQueries(session);

      result = executeImpl(cs);
    } catch (Throwable t) {

      // t.printStackTrace();
      result = new Result(t, cs.sql);
    }

    // clear redundant data
    cs.dematerializeSubQueries();

    if (result == null) {
      result = emptyResult;
    }

    return result;
  }
  /**
   * 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);
          }
      }
    }
  }