/**
   * Analye EQUALS (=) node.
   *
   * @param equalsNode - node to analyze
   * @param queryGraph - store relationships between stream properties
   */
  protected static void analyzeEqualsNode(
      ExprEqualsNode equalsNode, QueryGraph queryGraph, boolean isOuterJoin) {
    if ((equalsNode.getChildNodes()[0] instanceof ExprIdentNode)
        && (equalsNode.getChildNodes()[1] instanceof ExprIdentNode)) {
      ExprIdentNode identNodeLeft = (ExprIdentNode) equalsNode.getChildNodes()[0];
      ExprIdentNode identNodeRight = (ExprIdentNode) equalsNode.getChildNodes()[1];

      if (identNodeLeft.getStreamId() != identNodeRight.getStreamId()) {
        queryGraph.addStrictEquals(
            identNodeLeft.getStreamId(),
            identNodeLeft.getResolvedPropertyName(),
            identNodeLeft,
            identNodeRight.getStreamId(),
            identNodeRight.getResolvedPropertyName(),
            identNodeRight);
      }

      return;
    }
    if (isOuterJoin) { // outerjoins don't use constants or one-way expression-derived information
                       // to evaluate join
      return;
    }

    // handle constant-compare or transformation case
    int indexedStream = -1;
    String indexedProp = null;
    ExprNode exprNodeNoIdent = null;

    if (equalsNode.getChildNodes()[0] instanceof ExprIdentNode) {
      ExprIdentNode identNode = (ExprIdentNode) equalsNode.getChildNodes()[0];
      indexedStream = identNode.getStreamId();
      indexedProp = identNode.getResolvedPropertyName();
      exprNodeNoIdent = equalsNode.getChildNodes()[1];
    } else if (equalsNode.getChildNodes()[1] instanceof ExprIdentNode) {
      ExprIdentNode identNode = (ExprIdentNode) equalsNode.getChildNodes()[1];
      indexedStream = identNode.getStreamId();
      indexedProp = identNode.getResolvedPropertyName();
      exprNodeNoIdent = equalsNode.getChildNodes()[0];
    }
    if (indexedStream == -1) {
      return; // require property of right/left side of equals
    }

    EligibilityDesc eligibility = EligibilityUtil.verifyInputStream(exprNodeNoIdent, indexedStream);
    if (!eligibility.getEligibility().isEligible()) {
      return;
    }

    if (eligibility.getEligibility() == Eligibility.REQUIRE_NONE) {
      queryGraph.addUnkeyedExpression(indexedStream, indexedProp, exprNodeNoIdent);
    } else {
      queryGraph.addKeyedExpression(
          indexedStream, indexedProp, eligibility.getStreamNum(), exprNodeNoIdent);
    }
  }
 /**
  * Analyzes filter expression to build query graph model.
  *
  * @param topNode - filter top node
  * @param queryGraph - model containing relationships between streams, to be written to
  */
 public static void analyze(ExprNode topNode, QueryGraph queryGraph, boolean isOuterJoin) {
   // Analyze relationships between streams. Relationships are properties in AND and EQUALS nodes
   // of joins.
   if (topNode instanceof ExprEqualsNode) {
     ExprEqualsNode equalsNode = (ExprEqualsNode) topNode;
     if (!equalsNode.isNotEquals()) {
       analyzeEqualsNode(equalsNode, queryGraph, isOuterJoin);
     }
   } else if (topNode instanceof ExprAndNode) {
     ExprAndNode andNode = (ExprAndNode) topNode;
     analyzeAndNode(andNode, queryGraph, isOuterJoin);
   } else if (topNode instanceof ExprBetweenNode) {
     ExprBetweenNode betweenNode = (ExprBetweenNode) topNode;
     analyzeBetweenNode(betweenNode, queryGraph);
   } else if (topNode instanceof ExprRelationalOpNode) {
     ExprRelationalOpNode relNode = (ExprRelationalOpNode) topNode;
     analyzeRelationalOpNode(relNode, queryGraph);
   } else if (topNode instanceof ExprDotNode && !isOuterJoin) {
     ExprDotNode dotNode = (ExprDotNode) topNode;
     analyzeDotNode(dotNode, queryGraph);
   }
 }