/*
   * INTERNAL:
   * If this query key represents a foreign reference answer the
   * base expression -> foreign reference join criteria.
   */
  public Expression mappingCriteria() {
    Expression selectionCriteria;

    // First look for a query key, then a mapping
    if (getQueryKeyOrNull() == null) {
      if ((getMapping() == null) || (!getMapping().isForeignReferenceMapping())) {
        return null;
      } else {
        // The join criteria is now twisted by the mappings.
        selectionCriteria = ((ForeignReferenceMapping) getMapping()).getJoinCriteria(this);
      }
    } else {
      if (!getQueryKeyOrNull().isForeignReferenceQueryKey()) {
        return null;
      } else {
        selectionCriteria = ((ForeignReferenceQueryKey) getQueryKeyOrNull()).getJoinCriteria();
        selectionCriteria = getBaseExpression().twist(selectionCriteria, this);
      }
    }

    if (shouldUseOuterJoin() && getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
      selectionCriteria = selectionCriteria.convertToUseOuterJoin();
    }

    return selectionCriteria;
  }
 /**
  * INTERNAL: Rebuild myself against the base, with the values of parameters supplied by the
  * context expression. This is used for transforming a standalone expression (e.g. the join
  * criteria of a mapping) into part of some larger expression. You normally would not call this
  * directly, instead calling twist See the comment there for more details"
  */
 public Expression twistedForBaseAndContext(Expression newBase, Expression context) {
   Expression twistedBase = getBaseExpression().twistedForBaseAndContext(newBase, context);
   QueryKeyExpression result = (QueryKeyExpression) twistedBase.get(getName());
   if (shouldUseOuterJoin) {
     result.doUseOuterJoin();
   }
   if (shouldQueryToManyRelationship) {
     result.doQueryToManyRelationship();
   }
   return result;
 }
 public void test() {
   ExpressionBuilder eb = new ExpressionBuilder();
   ReportQuery rq = new ReportQuery(Employee.class, eb);
   rq.addAttribute("firstName");
   rq.addAttribute("lastName");
   Expression exp = eb.getFunction("dbms_random.value");
   exp.setSelectIfOrderedBy(false);
   rq.addOrdering(exp.ascending());
   rq.setSelectionCriteria(eb.anyOf("projects").get("teamLeader").isNull());
   results = (Vector) getSession().executeQuery(rq);
 }
  /**
   * INTERNAL: This expression is built on a different base than the one we want. Rebuild it and
   * return the root of the new tree
   */
  public Expression rebuildOn(Expression newBase) {
    Expression newLocalBase = getBaseExpression().rebuildOn(newBase);
    QueryKeyExpression result = null;

    // For bug 3096634 rebuild outer joins correctly from the start.
    if (shouldUseOuterJoin) {
      result = (QueryKeyExpression) newLocalBase.getAllowingNull(getName());
    } else {
      result = (QueryKeyExpression) newLocalBase.get(getName());
    }
    if (shouldQueryToManyRelationship) {
      result.doQueryToManyRelationship();
    }
    result.setSelectIfOrderedBy(selectIfOrderedBy());
    return result;
  }
  /**
   * INTERNAL: Selection criteria is created with source foreign keys and target keys. This criteria
   * is then used to read target records from the table.
   */
  public void initializeSelectionCriteria(AbstractSession session) {
    Expression selectionCriteria = null;
    Expression expression;

    ExpressionBuilder expBuilder = new ExpressionBuilder();

    Iterator sourceKeysEnum = getSourceToTargetQueryKeyNames().keySet().iterator();

    while (sourceKeysEnum.hasNext()) {
      DatabaseField sourceKey = (DatabaseField) sourceKeysEnum.next();
      String target = (String) this.getSourceToTargetQueryKeyNames().get(sourceKey);
      expression = expBuilder.getParameter(sourceKey).equal(expBuilder.get(target));

      if (selectionCriteria == null) {
        selectionCriteria = expression;
      } else {
        selectionCriteria = expression.and(selectionCriteria);
      }
    }

    setSelectionCriteria(selectionCriteria);
  }
  public void setup() {
    Employee emp = (Employee) getSomeEmployees().firstElement();

    PhoneNumber phone = (PhoneNumber) emp.getPhoneNumbers().firstElement();
    String areaCode = phone.getAreaCode();
    String firstName = emp.getFirstName();

    setReferenceClass(Employee.class);

    ExpressionBuilder employeeBuilder = new ExpressionBuilder();
    Expression phones = employeeBuilder.anyOf("phoneNumbers");
    Expression whereClause =
        phones
            .get("owner")
            .get("firstName")
            .equal(firstName)
            .and(phones.get("areaCode").equal(areaCode));

    ReportQuery rq = new ReportQuery();
    rq.setSelectionCriteria(whereClause);
    rq.addAttribute("number", phones.get("number"));
    rq.setReferenceClass(Employee.class);

    setOriginalOject(getAttributeFromAll("number", (Vector) getSession().executeQuery(rq)));
    getSession().getIdentityMapAccessor().initializeAllIdentityMaps();

    String ejbqlString;
    ejbqlString =
        "SELECT phone.number FROM Employee employee, IN(employee.phoneNumbers) phone "
            + "WHERE phone.owner.firstName = \""
            + firstName
            + "\" AND phone.areaCode = \""
            + areaCode
            + "\"";

    useReportQuery();
    setEjbqlString(ejbqlString);
    super.setup();
  }
  /**
   * INTERNAL: Return the expression to join the main table of this node to any auxiliary tables.
   */
  public Expression additionalExpressionCriteria() {
    if (getDescriptor() == null) {
      return null;
    }

    Expression criteria = getDescriptor().getQueryManager().getAdditionalJoinExpression();
    if (criteria != null) {
      criteria = getBaseExpression().twist(criteria, this);
      if (shouldUseOuterJoin() && getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
        criteria.convertToUseOuterJoin();
      }
    }
    if (getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
      if (isUsingOuterJoinForMultitableInheritance()) {
        Expression childrenCriteria =
            getDescriptor().getInheritancePolicy().getChildrenJoinExpression();
        childrenCriteria = getBaseExpression().twist(childrenCriteria, this);
        childrenCriteria.convertToUseOuterJoin();
        if (criteria == null) {
          criteria = childrenCriteria;
        } else {
          criteria = criteria.and(childrenCriteria);
        }
      }
    }
    if ((getDescriptor() != null) && (getDescriptor().getHistoryPolicy() != null)) {
      Expression historyCriteria =
          getDescriptor().getHistoryPolicy().additionalHistoryExpression(this);
      if (criteria != null) {
        criteria = criteria.and(historyCriteria);
      } else {
        criteria = historyCriteria;
      }
    }
    return criteria;
  }
  /**
   * INTERNAL: For CR#2456 if this is part of an objExp.equal(objExp), do not need to add additional
   * expressions to normalizer both times, and the foreign key join replaces the equal expression.
   */
  public Expression normalize(ExpressionNormalizer normalizer, Vector foreignKeyJoinPointer) {
    if (hasBeenNormalized()) {
      return this;
    }
    super.normalize(normalizer);

    setHasBeenNormalized(true);
    if ((getMapping() != null) && getMapping().isDirectToXMLTypeMapping()) {
      normalizer.getStatement().setRequiresAliases(true);
    }

    // Check if any joins need to be added.
    if (isAttribute()) {
      return this;
    }

    // If the mapping is 'ref' or 'structure', no join needed.
    if ((getMapping() != null)
        && (getMapping().isReferenceMapping() || getMapping().isStructureMapping())) {
      normalizer.getStatement().setRequiresAliases(true);
      return this;
    }

    // Compute if a distinct is required during normalization.
    if (shouldQueryToManyRelationship()
        && (!normalizer.getStatement().isDistinctComputed())
        && (!normalizer.getStatement().isAggregateSelect())) {
      normalizer.getStatement().useDistinct();
    }

    // Turn off DISTINCT if nestedTableMapping is used (not supported by Oracle 8.1.5).
    if ((getMapping() != null) && getMapping().isNestedTableMapping()) {
      // There are two types of nested tables, one used by clients, one used by mappings, do nothing
      // in the mapping case.
      if (!shouldQueryToManyRelationship()) {
        return this;
      }
      normalizer.getStatement().dontUseDistinct();
    }

    Expression mappingExpression = mappingCriteria();
    if (mappingExpression != null) {
      mappingExpression = mappingExpression.normalize(normalizer);
    }
    if (mappingExpression != null) {
      // If the join was an outer join we must not add the join criteria to the where clause,
      // if the platform prints the join in the from clause.
      if (shouldUseOuterJoin() && (getSession().getPlatform().isInformixOuterJoin())) {
        normalizer.getStatement().getOuterJoinExpressions().addElement(this);
        normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(mappingExpression);
        normalizer.addAdditionalExpression(mappingExpression.and(additionalExpressionCriteria()));
        return this;
      } else if ((shouldUseOuterJoin() || isUsingOuterJoinForMultitableInheritance())
          && (!getSession().getPlatform().shouldPrintOuterJoinInWhereClause())) {
        if (shouldUseOuterJoin()) {
          normalizer.getStatement().getOuterJoinExpressions().addElement(this);
          normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(mappingExpression);
          normalizer
              .getStatement()
              .getOuterJoinedAdditionalJoinCriteria()
              .addElement(additionalExpressionCriteriaMap());
          normalizer.getStatement().getDescriptorsForMultitableInheritanceOnly().add(null);
          return this;
        } else {
          if (isUsingOuterJoinForMultitableInheritance()) {
            normalizer.getStatement().getOuterJoinExpressions().addElement(null);
            normalizer.getStatement().getOuterJoinedMappingCriteria().addElement(null);
            normalizer
                .getStatement()
                .getOuterJoinedAdditionalJoinCriteria()
                .addElement(additionalExpressionCriteriaMap());
            normalizer
                .getStatement()
                .getDescriptorsForMultitableInheritanceOnly()
                .add(getMapping().getReferenceDescriptor());
            // fall through to the main case
          }
        }
      }

      // This must be added even if outer. Actually it should be converted to use a right outer
      // join, but that gets complex
      // so we do not support this current which is a limitation in some cases.
      if (foreignKeyJoinPointer != null) {
        // If this expression is right side of an objExp.equal(objExp), one
        // need not add additionalExpressionCriteria twice.
        // Also the join will replace the original objExp.equal(objExp).
        // For CR#2456.
        foreignKeyJoinPointer.add(mappingExpression);
      } else {
        normalizer.addAdditionalExpression(mappingExpression.and(additionalExpressionCriteria()));
      }
    }

    // For bug 2900974 special code for DirectCollectionMappings moved to printSQL.
    return this;
  }