static SelectResults getConditionedRelationshipIndexResultsExpandedToTopOrCGJLevel(List data,
      IndexInfo[] indxInfo, ExecutionContext context, boolean completeExpansionNeeded,
      CompiledValue iterOperands, RuntimeIterator[] indpdntItrs) throws FunctionDomainException,
      TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
    ObjectType resultType1 = indxInfo[0]._index.getResultSetType();
    int indexFieldsSize1 = resultType1 instanceof StructType
        ? ((StructTypeImpl) resultType1).getFieldNames().length : 1;
    ObjectType resultType2 = indxInfo[1]._index.getResultSetType();
    int indexFieldsSize2 = resultType2 instanceof StructType
        ? ((StructTypeImpl) resultType2).getFieldNames().length : 1;
    /*
     * even if th complete expansion is needed pass the flag of complete expansion as false. Thus
     * for LHS & RHS we will get the expansionList for that individual group. Thus the total
     * expansion List wil contain sum of the individual expansion lists plus all the iterators of
     * the current scope which are dependent on any other groups or are composite iterators ( i.e
     * dependent on both the independent groups currently under consideration
     */

    // pass completeExpansion as false, irrespective of actual value
    IndexConditioningHelper ich1 = new IndexConditioningHelper(indxInfo[0], context,
        indexFieldsSize1, false, iterOperands, null);

    // pass completeExpansion as false, irrespective of actual value
    IndexConditioningHelper ich2 = new IndexConditioningHelper(indxInfo[1], context,
        indexFieldsSize2, false, iterOperands, null);

    List totalExpList = new ArrayList();
    totalExpList.addAll(ich1.expansionList);
    totalExpList.addAll(ich2.expansionList);

    List totalFinalList = null;
    if (completeExpansionNeeded) {
      totalFinalList = context.getCurrentIterators();
      Set expnItrsAlreadyAccounted = new HashSet();
      expnItrsAlreadyAccounted.addAll(ich1.finalList);
      expnItrsAlreadyAccounted.addAll(ich2.finalList);
      int size = totalFinalList.size();
      for (Object o : totalFinalList) {
        RuntimeIterator currItr = (RuntimeIterator) o;
        // If the runtimeIterators of scope not present in CheckSet add it to the expansion list
        if (!expnItrsAlreadyAccounted.contains(currItr)) {
          totalExpList.add(currItr);
        }
      }
    } else {
      totalFinalList = new ArrayList();
      for (RuntimeIterator indpndntItr : indpdntItrs) {
        if (indpndntItr == ich1.finalList.get(0)) {
          totalFinalList.addAll(ich1.finalList);
        } else if (indpndntItr == ich2.finalList.get(0)) {
          totalFinalList.addAll(ich2.finalList);
        } else {
          List temp = context.getCurrScopeDpndntItrsBasedOnSingleIndpndntItr(indpndntItr);
          totalFinalList.addAll(temp);
          totalExpList.addAll(temp);
        }
      }
    }
    SelectResults returnSet;
    StructType stype = createStructTypeForRuntimeIterators(totalFinalList);
    if (totalFinalList.size() == 1) {
      returnSet = QueryUtils.createResultCollection(context, new ObjectTypeImpl(stype.getClass()));
    } else {
      returnSet = QueryUtils.createStructCollection(context, stype);
    }


    RuntimeIterator[][] mappings = new RuntimeIterator[2][];
    mappings[0] = ich1.indexFieldToItrsMapping;
    mappings[1] = ich2.indexFieldToItrsMapping;
    Iterator dataItr = data.iterator();
    IndexCutDownExpansionHelper[] icdeh =
        new IndexCutDownExpansionHelper[] {new IndexCutDownExpansionHelper(ich1.checkList, context),
            new IndexCutDownExpansionHelper(ich2.checkList, context)};
    ListIterator expansionListIterator = totalExpList.listIterator();
    if (dataItr.hasNext()) {
      QueryObserver observer = QueryObserverHolder.getInstance();
      try {
        observer.beforeMergeJoinOfDoubleIndexResults(ich1.indxInfo._index, ich2.indxInfo._index,
            data);
        while (dataItr.hasNext()) {
          // TODO: Change the code in range Index so that while collecting data instead of creating
          // two dimensional object array , we create one dimensional Object array of size 2, & each
          // elemnt stores an Object array
          Object[][] values = (Object[][]) dataItr.next();
          // Before doing the cartesian of the Results , we need to clear the CheckSet of
          // IndexCutDownExpansionHelper. This is needed because for a new key , the row of sets
          // needs to be considered fresh as presence of old row in checkset may cause us to wrongly
          // skip the similar row of a set , even when the row in its entirety is unique ( made by
          // different data in the other set)
          mergeAndExpandCutDownRelationshipIndexResults(values, returnSet, mappings,
              expansionListIterator, totalFinalList, context, iterOperands, icdeh,
              0 /* Level */);
          if (icdeh[0].cutDownNeeded) {
            icdeh[0].checkSet.clear();
          }
        }
      } finally {
        observer.afterMergeJoinOfDoubleIndexResults(returnSet);
      }
    }
    return returnSet;
  }
This function is used to evaluate a filter evaluatable composite condition. It gets invoked
either from a CompositeGroupJunction of "OR" type or a where clause containing single composite
condition. In the later case the boolean completeExpansion flag is always true. While in the
former case it may be true or false. If it is false, the array of independent iterators passed
is not null.

@param data A List object whose elements are two dimensional object array. Each element of the
       List represent a value which satisfies the equi-join condition. Since there may be more
       than one tuples on either side of the equality condition which meet the criteria for a
       given value, we require a 2 dimensional Object array. The cartesian of the two rows will
       give us the set of tuples satisfying the join criteria. Each element of the row of
       Object Array may be either an Object or a Struct object.
@param indxInfo An array of IndexInfo objects of size 2 , representing the range indexes of the
       two operands. The other Index maps to the 0th Object array row of the List object ( data
       ) & so on.
@param context ExecutionContext object
@param completeExpansionNeeded boolean if true indicates that the CGJ needs to be expanded to
       the query from clause ( top level )
@param iterOperands This will be null as for OR junction we cannot have iter operand
@param indpdntItrs Array of independent iterators representing the various Groups forming the
       composite group junction. It will be null, if complete expansion flag is true
@return SelectResults objet representing the result obtained by evaluating a filter evaluatable
        composite condition in an OR junction. The returned Result is expanded either to the
        CompositeGroupJunction level or to the top level as the case may be
geode-core/src/main/java/org/apache/geode/cache/query/internal/QueryUtils.java