private void prepareFromClause(IndexManager imgr) throws IndexInvalidException {
    if (imports != null) {
      compiler.compileImports(imports);
    }
    List list = compiler.compileFromClause(fromClause);

    if (list == null) {
      throw new IndexInvalidException(
          String.format("Invalid FROM Clause : ' %s '",
              fromClause));
    }

    int size = list.size();
    canonicalizedIteratorNames = new String[size];
    canonicalizedIteratorDefinitions = new String[size];
    StringBuilder tempBuff = new StringBuilder();
    boolean isFromClauseNull = true;

    try {
      PartitionedRegion pr = context.getPartitionedRegion();
      for (int i = 0; i < size; i++) {
        CompiledIteratorDef iterDef = (CompiledIteratorDef) list.get(i);
        iterDef.computeDependencies(context);
        RuntimeIterator rIter = iterDef.getRuntimeIterator(context);
        context.addToIndependentRuntimeItrMapForIndexCreation(iterDef);
        context.bindIterator(rIter);
        if (i != 0 && !iterDef.isDependentOnCurrentScope(context)) {
          throw new IndexInvalidException(
              String.format(
                  "Invalid FROM Clause : ' %s '; subsequent iterator expressions in from clause must be dependent on previous iterators",
                  fromClause));
        }

        String definition = rIter.getDefinition();
        canonicalizedIteratorDefinitions[i] = definition;

        // Bind the Index_Internal_ID to the RuntimeIterator
        canonicalizedIteratorNames[i] = imgr.putCanonicalizedIteratorNameIfAbsent(definition);

        if (pr != null) {
          canonicalizedIteratorNames[i] =
              pr.getIndexManager().putCanonicalizedIteratorNameIfAbsent(definition);
        } else {
          canonicalizedIteratorNames[i] =
              imgr.putCanonicalizedIteratorNameIfAbsent(definition);
        }

        rIter.setIndexInternalID(canonicalizedIteratorNames[i]);
        tempBuff.append(definition).append(' ').append(canonicalizedIteratorNames[i])
            .append(", ");
        isFromClauseNull = false;
        CompiledIteratorDef newItr;

        if (i == 0) {
          CompiledValue cv = iterDef.getCollectionExpr();
          addnlProjType = rIter.getElementType();
          String name = iterDef.getName();
          if (isEmpty(name)) {
            // In case the name of iterator is null or blank set it to index_internal_id
            name = canonicalizedIteratorNames[i];
          }
          CompiledValue newCollExpr = new CompiledPath(new CompiledBindArgument(1), "entries");

          // TODO: What if cv is not an instance of CompiledRegion
          if (cv instanceof CompiledRegion) {
            missingLink = new CompiledPath(new CompiledID(name), "value");
            additionalProj = missingLink;

          } else if (cv instanceof CompiledOperation || cv instanceof CompiledPath
              || cv instanceof CompiledIndexOperation) {
            CompiledValue prevCV;
            List reconstruct = new ArrayList();
            while (!(cv instanceof CompiledRegion)) {
              prevCV = cv;
              if (cv instanceof CompiledOperation) {
                reconstruct.add(0, ((CompiledOperation) cv).getArguments());
                reconstruct.add(0, ((CompiledOperation) cv).getMethodName());
                cv = ((CompiledOperation) cv).getReceiver(context);
              } else if (cv instanceof CompiledPath) {
                reconstruct.add(0, ((CompiledPath) cv).getTailID());
                cv = cv.getReceiver();
              } else if (cv instanceof CompiledIndexOperation) {
                reconstruct.add(0, ((CompiledIndexOperation) cv).getExpression());
                cv = cv.getReceiver();
              } else {
                throw new IndexInvalidException(
                    "FunctionalIndexCreationHelper::prepareFromClause:From clause is neither a CompiledPath nor CompiledOperation");
              }
              reconstruct.add(0, prevCV.getType());
            }

            int firstTokenType = (Integer) reconstruct.get(0);
            if (firstTokenType == CompiledValue.PATH) {
              String tailID = (String) reconstruct.get(1);

              if (tailID.equals("asList") || tailID.equals("asSet") || tailID.equals("values")
                  || tailID.equals("toArray") || tailID.equals("getValues")) {
                missingLink = new CompiledPath(new CompiledID(name), "value");
              } else if (tailID.equals("keys") || tailID.equals("getKeys")
                  || tailID.equals("keySet")) {
                missingLink = new CompiledPath(new CompiledID(name), "key");
                isFirstIteratorRegionKey = true;
              } else if (tailID.equals("entries") || tailID.equals("getEntries")
                  || tailID.equals("entrySet")) {
                isFirstIteratorRegionEntry = true;
              } else {
                throw new IndexInvalidException(
                    "FunctionalIndexCreationHelper::prepareFromClause:From clause does not evaluate to valid collection");
              }

              remove(reconstruct, 2, 0);
              int secondTokenType = reconstruct.size() > 1 ? (Integer) reconstruct.get(0) : -1;
              if (!isFirstIteratorRegionEntry
                  && secondTokenType == OQLLexerTokenTypes.TOK_LBRACK) {

                // If the field just next to region , is values or getValues & next to it is
                // CompiledIndexOpn, it indirectly means Map operation & we are able to take care of
                // it by adding a flag in CompiledIndexOp which indicates to it whether to return
                // entry or value. But if the field is asList or toArray , we have a problem as we
                // don't have a corresponding list of entries. If the field is keys , an exception
                // should be thrown as IndexOpn on set is not defined.
                if (tailID.equals("values") || tailID.equals("getValues")) {
                  boolean returnEntryForRegionCollection = true;
                  additionalProj = new CompiledIndexOperation(new CompiledBindArgument(1),
                      (CompiledValue) reconstruct.get(1), returnEntryForRegionCollection);
                  isFirstIteratorRegionEntry = true;

                } else if (tailID.equals("toList") || tailID.equals("toArray")) {
                  // TODO: add support for toList and toArray
                  throw new IndexInvalidException(
                      "FunctionalIndexCreationHelper::prepareFromClause:toList and toArray not supported");

                } else {
                  throw new IndexInvalidException(
                      "FunctionalIndexCreationHelper::prepareFromClause:toList and toArray not supported");
                }
                remove(reconstruct, 2, 0);

              } else if (!isFirstIteratorRegionEntry
                  && (secondTokenType == OQLLexerTokenTypes.METHOD_INV
                      || secondTokenType == CompiledValue.PATH)
                  && (tailID.equals("values") || tailID.equals("getValues")
                      || tailID.equals("keySet") || tailID.equals("keys")
                      || tailID.equals("getKeys"))) {

                // Check if the second token name is toList or toArray or asSet.We need to remove
                // those
                String secTokName = (String) reconstruct.get(1);
                if (secTokName.equals("asList") || secTokName.equals("asSet")
                    || secTokName.equals("toArray")) {
                  remove(reconstruct, secondTokenType == OQLLexerTokenTypes.METHOD_INV ? 3 : 2, 0);
                }
              }

            } else if (firstTokenType == OQLLexerTokenTypes.TOK_LBRACK) {
              boolean returnEntryForRegionCollection = true;
              additionalProj = new CompiledIndexOperation(new CompiledBindArgument(1),
                  (CompiledValue) reconstruct.get(1), returnEntryForRegionCollection);
              isFirstIteratorRegionEntry = true;

            } else if (firstTokenType == OQLLexerTokenTypes.METHOD_INV) {
              String methodName = (String) reconstruct.get(1);
              if (methodName.equals("asList") || methodName.equals("asSet")
                  || methodName.equals("values") || methodName.equals("toArray")
                  || methodName.equals("getValues")) {
                missingLink = new CompiledPath(new CompiledID(name), "value");
              } else if (methodName.equals("keys") || methodName.equals("getKeys")
                  || methodName.equals("keySet")) {
                missingLink = new CompiledPath(new CompiledID(name), "key");
                isFirstIteratorRegionKey = true;
              } else if (methodName.equals("entries") || methodName.equals("getEntries")
                  || methodName.equals("entrySet")) {
                isFirstIteratorRegionEntry = true;
                List args = (List) reconstruct.get(2);
                if (args != null && args.size() == 1) {
                  Object obj = args.get(0);
                  if (obj instanceof CompiledBindArgument) {
                    throw new IndexInvalidException(
                        "FunctionalIndexCreationHelper::prepareFromClause:entries method called with CompiledBindArgument");
                  }
                }
              }

              remove(reconstruct, 3, 0);
              int secondTokenType = reconstruct.size() > 1 ? (Integer) reconstruct.get(0) : -1;
              if (!isFirstIteratorRegionEntry
                  && secondTokenType == OQLLexerTokenTypes.TOK_LBRACK) {

                if (methodName.equals("values") || methodName.equals("getValues")) {
                  boolean returnEntryForRegionCollection = true;
                  newCollExpr = new CompiledIndexOperation(new CompiledBindArgument(1),
                      (CompiledValue) reconstruct.get(1), returnEntryForRegionCollection);
                } else if (methodName.equals("toList") || methodName.equals("toArray")) {
                  // TODO: add support for toList and toArray
                  throw new IndexInvalidException(
                      "FunctionalIndexCreationHelper::prepareFromClause:toList and toArray not supported yet");
                } else {
                  throw new IndexInvalidException(
                      "FunctionalIndexCreationHelper::prepareFromClause:toList and toArray not supported yet");
                }

                remove(reconstruct, 2, 0);
              } else if (!isFirstIteratorRegionEntry
                  && (secondTokenType == OQLLexerTokenTypes.METHOD_INV
                      || secondTokenType == CompiledValue.PATH)
                  && (methodName.equals("values") || methodName.equals("getValues")
                      || methodName.equals("keys") || methodName.equals("getKeys")
                      || methodName.equals("keySet"))) {

                // Check if the second token name is toList or toArray or asSet.We need to remove
                // those
                String secTokName = (String) reconstruct.get(1);
                if (secTokName.equals("asList") || secTokName.equals("asSet")
                    || secTokName.equals("toArray")) {
                  remove(reconstruct, secondTokenType == OQLLexerTokenTypes.METHOD_INV ? 3 : 2, 0);
                }
              }
            }

            if (!isFirstIteratorRegionEntry) {
              additionalProj = missingLink;
              int len = reconstruct.size();
              for (int j = 0; j < len; ++j) {
                Object obj = reconstruct.get(j);
                if (obj instanceof Integer) {
                  int tokenType = (Integer) obj;
                  if (tokenType == CompiledValue.PATH) {
                    additionalProj =
                        new CompiledPath(additionalProj, (String) reconstruct.get(++j));
                  } else if (tokenType == OQLLexerTokenTypes.TOK_LBRACK) {
                    additionalProj = new CompiledIndexOperation(additionalProj,
                        (CompiledValue) reconstruct.get(++j));
                  } else if (tokenType == OQLLexerTokenTypes.METHOD_INV) {
                    additionalProj = new CompiledOperation(additionalProj,
                        (String) reconstruct.get(++j), (List) reconstruct.get(++j));
                  }
                }
              }
            }
          } else {
            throw new IndexInvalidException(
                "FunctionalIndexCreationHelper::prepareFromClause:From clause is neither a CompiledPath nor CompiledOperation");
          }

          if (!isFirstIteratorRegionEntry) {
            newItr = new CompiledIteratorDef(name, null, newCollExpr);
            indexInitIterators = new ArrayList();
            indexInitIterators.add(newItr);
          }

        } else if (!isFirstIteratorRegionEntry) {
          newItr = iterDef;
          if (rIter.getDefinition().contains(canonicalizedIteratorNames[0])) {
            newItr = (CompiledIteratorDef) getModifiedDependentCompiledValue(context, i,
                iterDef, true);
          }
          indexInitIterators.add(newItr);
        }
      }
    } catch (IndexInvalidException e) {
      throw e;
    } catch (Exception e) {
      throw new IndexInvalidException(e);
    }
    if (isFromClauseNull) {
      throw new IndexInvalidException(
          String.format("Invalid FROM Clause : ' %s '",
              fromClause));
    }
    fromClause = tempBuff.substring(0, tempBuff.length() - 2);
    fromClauseIterators = list;
  }
The function is modified to optimize the index creation code. If the 0th iterator of from
clause is not on Entries, then the 0th iterator is replaced with that of entries & the value
corresponding to original iterator is derived from the 0th iterator as additional projection
attribute. All the other iterators & index expression if were dependent on 0th iterator are
also appropriately modified such that they are correctly derived on the modified 0th iterator.
<p>
TODO: method is too complex for IDE to analyze -- refactor prepareFromClause
geode-core/src/main/java/org/apache/geode/cache/query/internal/index/FunctionalIndexCreationHelper.java