/**
   * Chooses certain query conditions and assigns a copy of them to this filter. The original
   * condition is set to Expression.TRUE once assigned.
   *
   * @param condition
   * @throws HsqlException
   */
  void setConditions(Expression condition) throws HsqlException {

    setCondition(condition);

    if (filterIndex == null) {
      filterIndex = filterTable.getPrimaryIndex();
    }

    if (filterIndex.getVisibleColumns() == 1
        || eStart == null
        || eAnd == null
        || eStart.exprType != Expression.EQUAL) {
      return;
    }

    boolean[] check = filterTable.getNewColumnCheckList();
    Expression[] expr = new Expression[check.length];
    int colindex = eStart.getArg().getColumnNr();

    check[colindex] = true;
    expr[colindex] = eStart.getArg2();

    eAnd.getEquiJoinColumns(this, check, expr);

    if (ArrayUtil.containsAllTrueElements(check, filterIndex.colCheck)) {
      isMultiFindFirst = true;
      findFirstExpressions = expr;
    }
  }
  /**
   * Finds the first row in the table (using an index if there is one) and checks it against the
   * eEnd (range) and eAnd (other conditions) Expression objects. (fredt)
   *
   * @return true if first row was found, else false
   */
  boolean findFirst() throws HsqlException {

    nonJoinIsNull = false;
    isCurrentOuter = false;

    if (filterIndex == null) {
      filterIndex = filterTable.getPrimaryIndex();
    }

    if (this.isMultiFindFirst) {
      Object[] data = filterTable.getNewRow();
      int[] types = filterTable.getColumnTypes();

      for (int i = 0; i < findFirstExpressions.length; i++) {
        Expression e = findFirstExpressions[i];

        if (e != null) {
          data[i] = e.getValue(null, types[i]);
        }
      }

      currentNode = filterIndex.findFirst(data);
    } else if (eStart == null) {
      currentNode = eEnd == null ? filterIndex.first() : filterIndex.findFirstNotNull();
    } else {
      int type = eStart.getArg().getDataType();
      Object o = eStart.getArg2().getValue(null, type);

      currentNode = filterIndex.findFirst(o, eStart.getType());
    }

    while (currentNode != null) {
      currentData = currentNode.getData();
      currentRow = currentNode.getRow();

      if (!(eEnd == null || eEnd.test(null))) {
        break;
      }

      if (eAnd == null || eAnd.test(null)) {
        return true;
      }

      currentNode = filterIndex.next(currentNode);
    }

    currentData = emptyData;
    currentRow = null;

    return false;
  }
  private void setCondition(Expression e) throws HsqlException {

    int type = e.getType();
    Expression e1 = e.getArg();
    Expression e2 = e.getArg2();

    this.isAssigned = true;

    if (type == Expression.AND) {
      setCondition(e1);
      setCondition(e2);

      return;
    }

    int conditionType = toConditionType(type);

    if (conditionType == CONDITION_NONE) {

      // not a condition expression
      return;
    }

    // fredt@users 20030813 - patch 1.7.2 - fix for column comparison within same table bugs #572075
    // and 722443
    if (e1.getFilter() == this && e2.getFilter() == this) {
      conditionType = CONDITION_UNORDERED;
    } else if (e1.getFilter() == this) {

      // ok include this
    } else if ((e2.getFilter() == this) && (conditionType != CONDITION_UNORDERED)) {

      // swap and try again to allow index usage
      e.swapCondition();
      setCondition(e);

      return;
    } else if (e1.outerFilter == this) {

      // fredt - this test is last to allow swapping the terms above
      conditionType = CONDITION_OUTER;
    } else {

      // unrelated: don't include
      return;
    }

    //        Trace.doAssert(e1.getFilter() == this, "setCondition");
    if (!e2.isResolved()) {
      return;
    }

    // fredt - condition defined in outer but not this one
    if (e1.outerFilter != null && e1.outerFilter != this) {
      return;
    }

    if (conditionType == CONDITION_UNORDERED) {
      if (!isOuterJoin) {
        addAndCondition(e);
      }

      return;
    }

    if (conditionType == CONDITION_OUTER) {
      addAndCondition(e);
      e.setTrue();

      return;
    }

    int i = e1.getColumnNr();
    Index index = filterTable.getIndexForColumn(i);

    if (index == null || (filterIndex != index && filterIndex != null)) {
      addAndCondition(e);

      return;
    }

    filterIndex = index;

    switch (conditionType) {
      case CONDITION_START_END:
        {

          // candidate for both start and end
          if ((eStart != null) || (eEnd != null)) {
            addAndCondition(e);

            return;
          }

          eStart = new Expression(e);
          eEnd = eStart;

          break;
        }
      case CONDITION_START:
        {

          // candidate for start
          if (eStart != null) {
            addAndCondition(e);

            return;
          }

          eStart = new Expression(e);

          break;
        }
      case CONDITION_END:
        {

          // candidate for end
          if (eEnd != null) {
            addAndCondition(e);

            return;
          }

          eEnd = new Expression(e);

          break;
        }
    }

    e.setTrue();
  }