nextPrecompOrderBy = new Field(((SelectValue) valueMap .get(precompOrderByIter.next())).getAlias(), precomputedSqlTable);
    protected static Set merge(PrecomputedTable precomputedTable, Query query,            Query originalQuery) {        Query precompQuery = precomputedTable.getQuery();        if (!precompQuery.getGroupBy().isEmpty()) {            return mergeGroupBy(precomputedTable, query);        }        Set retval = new HashSet();                // Find the possible mappings from tables in the        // PrecomputedTable query to tables in the Query        Set mappings = new ConsistentSet();        mappings.addAll(MappingUtil.findCombinations(precompQuery.getFrom(),                                                    query.getFrom(),                                                    new AbstractTableComparator()));        // Create a map from AbstractValue to SelectValue for the PrecomputedTable        Map valueMap = precomputedTable.getValueMap();        // These are Maps where we can store away those structures we have built while checking the        // precomputed table mapping.        //Map lookupWhereConstraintEqualsSet = new HashMap();        // Iterate through the mappings and compare combinations. Note that each mapping is a case        // where the precomputed table has the same set of tables as the Query.        Iterator mappingsIter = mappings.iterator();        while (mappingsIter.hasNext()) {            Map mapping = (Map) mappingsIter.next();            // Remap the aliases            // TODO: query.getFrom() is really the wrong thing to use. To be extra-specially            // paranoid about realiasing things so they clash, this should be the getFrom() of the            // original Query, before any precomputed tables have been inserted.            remapAliases(mapping, query.getFrom());            // Compare the WHERE constraints.            Set whereConstraintEqualsSet = new HashSet();            // NOTE: this if line has a side-effect... Careful.            if (!compareConstraints(precompQuery.getWhere(), query.getWhere(),                        whereConstraintEqualsSet)) {                mappingsIter.remove();                continue;            }            // So now whereConstraintEqualsSet contains all the constraints that can be left out of            // the WHERE clause            // If the PrecomputedTable is distinct, then the Query can't be.            if (precompQuery.isDistinct() && (!query.isDistinct())) {                mappingsIter.remove();                continue;            }        }        // Now, we can pass the trimmed mappings Set into MappingUtil.findMultipleCombinations. For        // each multiple combination, produce a new Query.        Set multipleMappings = MappingUtil.findMultipleCombinations(mappings);                Iterator multipleMappingsIter = multipleMappings.iterator();        while (multipleMappingsIter.hasNext()) {            Set multipleMapping = (Set) multipleMappingsIter.next();            Query currentQuery = query;            try {                mappingsIter = multipleMapping.iterator();                while (mappingsIter.hasNext()) {                    Map mapping = (Map) mappingsIter.next();                    // Remap the aliases                    // TODO: currentQuery.getFrom() is really the wrong thing to use. To be                    // extra-specially paranoid about realiasing things so they clash, this should                    // be the getFrom() of the original Query, before any precomputed tables have                    // been inserted.                    //                    // Okay, trying the original query table list instead. Watch this space...                    remapAliases(mapping, originalQuery.getFrom());                             // Compare the WHERE constraints.                    Set whereConstraintEqualsSet = new HashSet();                    // NOTE: this if line has a side-effect... Careful.                    compareConstraints(precompQuery.getWhere(), currentQuery.getWhere(),                                whereConstraintEqualsSet);                    // So now whereConstraintEqualsSet contains all the constraints that can be                    // left out of the WHERE clause                                  Table precomputedSqlTable = new Table(precomputedTable.getName(),                            ALIAS_PREFIX + StringUtil.uniqueString());                    Query newQuery = new Query();                                    // Populate the SELECT list of the new Query. This method will throw an                    // exception if any of the AbstractValues required are not present in the                    // precomputed table.                    reconstructSelectValues(currentQuery.getSelect(), precomputedSqlTable, valueMap,                            precompQuery.getFrom(), false, newQuery);                                        // Populate the FROM list - first the precomputed table                    newQuery.addFrom(precomputedSqlTable);                    // And also the non-covered tables.                    addNonCoveredFrom(currentQuery.getFrom(), precompQuery.getFrom(),                            newQuery.getFrom());                    // Populate the WHERE clause of newQuery with the contents of the WHERE clause                    // of currentQuery, leaving out those constraints in whereConstraintEqualsSet.                    List precompOrderBy = precompQuery.getOrderBy();                    if (precompOrderBy.isEmpty() || (precomputedTable.getOrderByField() == null)) {                        reconstructAbstractConstraints(currentQuery.getWhere(), precomputedSqlTable,                                valueMap, precompQuery.getFrom(), false, newQuery.getWhere(),                                whereConstraintEqualsSet, null, 0, null);                    } else {                        Field firstPrecompOrderBy = new Field(((SelectValue) valueMap.get(                                        precompOrderBy.get(0))).getAlias(), precomputedSqlTable);                        reconstructAbstractConstraints(currentQuery.getWhere(), precomputedSqlTable,                                valueMap, precompQuery.getFrom(), false, newQuery.getWhere(),                                whereConstraintEqualsSet, firstPrecompOrderBy,                                precompOrderBy.size(), new Field(precomputedTable.getOrderByField(),                                    precomputedSqlTable));                    }                    // Populate the HAVING clause of newQuery with the contents of the HAVING clause                    // of currentQuery.                    reconstructAbstractConstraints(currentQuery.getHaving(), precomputedSqlTable,                            valueMap, precompQuery.getFrom(), false, newQuery.getHaving(),                            Collections.EMPTY_SET, null, 0, null);                    // Now populate the ORDER BY clause of newQuery from the contents of the ORDER                    // BY clause of currentQuery.                    if (precompOrderBy.isEmpty() || (precomputedTable.getOrderByField() == null)) {                        reconstructAbstractValues(currentQuery.getOrderBy(), precomputedSqlTable,                                valueMap, precompQuery.getFrom(), false, newQuery.getOrderBy());                    } else {                        List tempOrderBy = new ArrayList();                        reconstructAbstractValues(currentQuery.getOrderBy(), precomputedSqlTable,                                valueMap, precompQuery.getFrom(), false, tempOrderBy);                        // Now, we have a chance to improve the performance of the query by                        // substituting the orderby_field instead of certain elements of the order                        // by list.                        List newOrderBy = newQuery.getOrderBy();                        Iterator precompOrderByIter = precompOrderBy.iterator();                        Field nextPrecompOrderBy = new Field(((SelectValue) valueMap                                    .get(precompOrderByIter.next())).getAlias(),                                precomputedSqlTable);                        Field firstPrecompOrderBy = nextPrecompOrderBy;                        int inARow = 0;                        Iterator orderByIter = tempOrderBy.iterator();                        while (orderByIter.hasNext()) {                            AbstractValue origValue = (AbstractValue) orderByIter.next();                            //System.out .println("Comparing " + origValue.getSQLString() + " to "                            //        + nextPrecompOrderBy.getSQLString());                            if (origValue.equals(nextPrecompOrderBy)) {                                inARow++;                                //System.out .println("inARow now " + inARow);                                if (!precompOrderByIter.hasNext()) {                                    precompOrderByIter = precompOrderBy.iterator();                                }                                nextPrecompOrderBy = new Field(((SelectValue) valueMap                                            .get(precompOrderByIter.next())).getAlias(),                                        precomputedSqlTable);                            } else {                                if (inARow == 1) {                                    newOrderBy.add(new Field(((Field) firstPrecompOrderBy)                                                .getName(), precomputedSqlTable));                                } else if (inARow > 1) {                                    newOrderBy.add(new Field(precomputedTable.getOrderByField(),                                                precomputedSqlTable));                                }                                inARow = 0;                                //System.out .println("inARow now " + inARow);                                newOrderBy.add(origValue);                            }                        }                        if (inARow == 1) {                            newOrderBy.add(new Field(((Field) firstPrecompOrderBy).getName(),                                        precomputedSqlTable));                        } else if (inARow > 1) {                            newOrderBy.add(new Field(precomputedTable.getOrderByField(),                                        precomputedSqlTable));                        }                    }                    // Now populate the GROUP BY clause of newQuery from the contents of the GROUP                    // BY clause of currentQuery.                    reconstructAbstractValues(currentQuery.getGroupBy(), precomputedSqlTable,                            valueMap, precompQuery.getFrom(), false, newQuery.getGroupBy());                    // Now copy the EXPLAIN, DISTINCT, LIMIT, and OFFSET status to newQuery:                    newQuery.setDistinct(currentQuery.isDistinct());                    newQuery.setExplain(currentQuery.isExplain());                    newQuery.setLimitOffset(currentQuery.getLimit(), currentQuery.getOffset());                    // Finally, set currentQuery to newQuery.                    currentQuery = newQuery;                }                retval.add(currentQuery);            } catch (QueryOptimiserException e) {                continue;            }        }        return retval;    }