Package com.espertech.esper.epl.agg.rollup

Source Code of com.espertech.esper.epl.agg.rollup.GroupByExpressionHelper$GroupByExpressionInfo

/*
* *************************************************************************************
*  Copyright (C) 2008 EsperTech, Inc. All rights reserved.                            *
*  http://esper.codehaus.org                                                          *
*  http://www.espertech.com                                                           *
*  ---------------------------------------------------------------------------------- *
*  The software in this package is published under the terms of the GPL license       *
*  a copy of which has been included with this distribution in the license.txt file.  *
* *************************************************************************************
*/

package com.espertech.esper.epl.agg.rollup;

import com.espertech.esper.collection.CombinationEnumeration;
import com.espertech.esper.collection.MultiKeyInt;
import com.espertech.esper.epl.expression.ExprNode;
import com.espertech.esper.epl.expression.ExprNodeSubselectDeclaredDotVisitor;
import com.espertech.esper.epl.expression.ExprNodeUtility;
import com.espertech.esper.epl.expression.ExprValidationException;
import com.espertech.esper.epl.spec.*;
import com.espertech.esper.util.CollectionUtil;
import com.espertech.esper.util.SerializableObjectCopier;

import java.io.StringWriter;
import java.util.*;

public class GroupByExpressionHelper {
    public static GroupByClauseExpressions getGroupByRollupExpressions(List<GroupByClauseElement> groupByElements,
                                           SelectClauseSpecRaw selectClauseSpec, ExprNode optionalHavingNode, List<OrderByItem> orderByList,
                                           ExprNodeSubselectDeclaredDotVisitor visitor)
            throws ExprValidationException {
        if (groupByElements == null || groupByElements.size() == 0) {
            return null;
        }

        // walk group-by-elements, determine group-by expressions and rollup nodes
        GroupByExpressionInfo groupByExpressionInfo = groupByToRollupNodes(groupByElements);

        // obtain expression nodes, collect unique nodes and assign index
        List<ExprNode> distinctGroupByExpressions = new ArrayList<ExprNode>();
        Map<ExprNode, Integer> expressionToIndex = new HashMap<ExprNode, Integer>();
        for (ExprNode exprNode : groupByExpressionInfo.getExpressions()) {
            boolean found = false;
            for (int i = 0; i < distinctGroupByExpressions.size(); i++) {
                ExprNode other = distinctGroupByExpressions.get(i);
                // find same expression
                if (ExprNodeUtility.deepEquals(exprNode, other)) {
                    expressionToIndex.put(exprNode, i);
                    found = true;
                    break;
                }
            }

            // not seen before
            if (!found) {
                expressionToIndex.put(exprNode, distinctGroupByExpressions.size());
                distinctGroupByExpressions.add(exprNode);
            }
        }

        // determine rollup, validate it is either (not both)
        boolean hasGroupingSet = false;
        boolean hasRollup = false;
        for (GroupByClauseElement element : groupByElements) {
            if (element instanceof GroupByClauseElementGroupingSet) {
                hasGroupingSet = true;
            }
            if (element instanceof GroupByClauseElementRollupOrCube) {
                hasRollup = true;
            }
        }

        // no-rollup or grouping-sets means simply validate
        ExprNode[] groupByExpressions = distinctGroupByExpressions.toArray(new ExprNode[distinctGroupByExpressions.size()]);
        if (!hasRollup && !hasGroupingSet) {
            return new GroupByClauseExpressions(groupByExpressions);
        }

        // evaluate rollup node roots
        List<GroupByRollupNodeBase> nodes = groupByExpressionInfo.getNodes();
        Object[][] perNodeCombinations = new Object[nodes.size()][];
        GroupByRollupEvalContext context = new GroupByRollupEvalContext(expressionToIndex);
        try {
            for (int i = 0; i < nodes.size(); i++) {
                GroupByRollupNodeBase node = nodes.get(i);
                List<int[]> combinations = node.evaluate(context);
                perNodeCombinations[i] = new Object[combinations.size()];
                for (int j = 0; j < combinations.size(); j++) {
                    perNodeCombinations[i][j] = combinations.get(j);
                }
            }
        }
        catch (GroupByRollupDuplicateException ex) {
            if (ex.getIndexes().length == 0) {
                throw new ExprValidationException("Failed to validate the group-by clause, found duplicate specification of the overall grouping '()'");
            }
            else {
                StringWriter writer = new StringWriter();
                String delimiter = "";
                for (int i = 0; i < ex.getIndexes().length; i++) {
                    writer.append(delimiter);
                    writer.append(ExprNodeUtility.toExpressionStringMinPrecedence(groupByExpressions[ex.getIndexes()[i]]));
                    delimiter = ", ";
                }
                throw new ExprValidationException("Failed to validate the group-by clause, found duplicate specification of expressions (" + writer.toString() + ")");
            }
        }

        // enumerate combinations building an index list
        CombinationEnumeration combinationEnumeration = new CombinationEnumeration(perNodeCombinations);
        Set<Integer> combination = new TreeSet<Integer>();
        Set<MultiKeyInt> indexList = new LinkedHashSet<MultiKeyInt>();
        for (;combinationEnumeration.hasMoreElements();) {
            combination.clear();
            Object[] combinationOA = combinationEnumeration.nextElement();
            for (Object indexes : combinationOA) {
                int[] indexarr = (int[]) indexes;
                for (int anIndex : indexarr) {
                    combination.add(anIndex);
                }
            }
            int[] indexArr = CollectionUtil.intArray(combination);
            indexList.add(new MultiKeyInt(indexArr));
        }

        // obtain rollup levels
        int[][] rollupLevels = new int[indexList.size()][];
        int count = 0;
        for (MultiKeyInt mk : indexList) {
            rollupLevels[count++] = mk.getKeys();
        }
        int numberOfLevels = rollupLevels.length;
        if (numberOfLevels == 1 && rollupLevels[0].length == 0) {
            throw new ExprValidationException("Failed to validate the group-by clause, the overall grouping '()' cannot be the only grouping");
        }

        // obtain select-expression copies for rewrite
        List<SelectClauseElementRaw> expressions = selectClauseSpec.getSelectExprList();
        ExprNode[][] selects = new ExprNode[numberOfLevels][];
        for (int i = 0; i < numberOfLevels; i++) {
            selects[i] = new ExprNode[expressions.size()];
            for (int j = 0; j < expressions.size(); j++) {
                SelectClauseElementRaw selectRaw = expressions.get(j);
                if (!(selectRaw instanceof SelectClauseExprRawSpec)) {
                    throw new ExprValidationException("Group-by with rollup requires that the select-clause does not use wildcard");
                }
                SelectClauseExprRawSpec compiled = (SelectClauseExprRawSpec) selectRaw;
                selects[i][j] = copyVisitExpression(compiled.getSelectExpression(), visitor);
            }
        }

        // obtain having-expression copies for rewrite
        ExprNode[] optHavingNodeCopy = null;
        if (optionalHavingNode != null) {
            optHavingNodeCopy = new ExprNode[numberOfLevels];
            for (int i = 0; i < numberOfLevels; i++) {
                optHavingNodeCopy[i] = copyVisitExpression(optionalHavingNode, visitor);
            }
        }

        // obtain orderby-expression copies for rewrite
        ExprNode[][] optOrderByCopy = null;
        if (orderByList != null && orderByList.size() > 0) {
            optOrderByCopy = new ExprNode[numberOfLevels][];
            for (int i = 0; i < numberOfLevels; i++) {
                optOrderByCopy[i] = new ExprNode[orderByList.size()];
                for (int j = 0; j < orderByList.size(); j++) {
                    OrderByItem element = orderByList.get(j);
                    optOrderByCopy[i][j] = copyVisitExpression(element.getExprNode(), visitor);
                }
            }
        }

        return new GroupByClauseExpressions(groupByExpressions, rollupLevels, selects, optHavingNodeCopy, optOrderByCopy);
    }

    private static GroupByExpressionInfo groupByToRollupNodes(List<GroupByClauseElement> groupByExpressions) {
        List<GroupByRollupNodeBase> parents = new ArrayList<GroupByRollupNodeBase>(groupByExpressions.size());
        List<ExprNode> exprNodes = new ArrayList<ExprNode>();

        for (GroupByClauseElement element : groupByExpressions) {

            GroupByRollupNodeBase parent;
            if (element instanceof GroupByClauseElementExpr) {
                GroupByClauseElementExpr expr = (GroupByClauseElementExpr) element;
                exprNodes.add(expr.getExpr());
                parent = new GroupByRollupNodeSingleExpr(expr.getExpr());
            }
            else if (element instanceof GroupByClauseElementRollupOrCube) {
                GroupByClauseElementRollupOrCube spec = (GroupByClauseElementRollupOrCube) element;
                parent = new GroupByRollupNodeRollupOrCube(spec.isCube());
                groupByAddRollup(spec, parent, exprNodes);
            }
            else if (element instanceof GroupByClauseElementGroupingSet) {
                GroupByClauseElementGroupingSet spec = (GroupByClauseElementGroupingSet) element;
                parent = new GroupByRollupNodeGroupingSet();
                for (GroupByClauseElement groupElement : spec.getElements()) {
                    if (groupElement instanceof GroupByClauseElementExpr) {
                        GroupByClauseElementExpr single = (GroupByClauseElementExpr) groupElement;
                        exprNodes.add(single.getExpr());
                        parent.add(new GroupByRollupNodeSingleExpr(single.getExpr()));
                    }
                    if (groupElement instanceof GroupByClauseElementCombinedExpr) {
                        GroupByClauseElementCombinedExpr combined = (GroupByClauseElementCombinedExpr) groupElement;
                        exprNodes.addAll(combined.getExpressions());
                        parent.add(new GroupByRollupNodeCombinedExpr(combined.getExpressions()));
                    }
                    if (groupElement instanceof GroupByClauseElementRollupOrCube) {
                        GroupByClauseElementRollupOrCube rollup = (GroupByClauseElementRollupOrCube) groupElement;
                        GroupByRollupNodeRollupOrCube node = new GroupByRollupNodeRollupOrCube(rollup.isCube());
                        groupByAddRollup(rollup, node, exprNodes);
                        parent.add(node);
                    }
                }
            }
            else {
                throw new IllegalStateException("Unexpected group-by clause element " + element);
            }
            parents.add(parent);
        }

        return new GroupByExpressionInfo(exprNodes, parents);
    }

    private static void groupByAddRollup(GroupByClauseElementRollupOrCube spec, GroupByRollupNodeBase parent, List<ExprNode> exprNodes) {
        for (GroupByClauseElement rolledUp : spec.getRollupExpressions()) {
            if (rolledUp instanceof GroupByClauseElementExpr) {
                GroupByClauseElementExpr expr = (GroupByClauseElementExpr) rolledUp;
                exprNodes.add(expr.getExpr());
                parent.add(new GroupByRollupNodeSingleExpr(expr.getExpr()));
            }
            else {
                GroupByClauseElementCombinedExpr combined = (GroupByClauseElementCombinedExpr) rolledUp;
                exprNodes.addAll(combined.getExpressions());
                parent.add(new GroupByRollupNodeCombinedExpr(combined.getExpressions()));
            }
        }
    }

    private static ExprNode copyVisitExpression(ExprNode expression, ExprNodeSubselectDeclaredDotVisitor visitor) {
        try {
            ExprNode node = (ExprNode) SerializableObjectCopier.copy(expression);
            node.accept(visitor);
            return node;
        } catch (Exception e) {
            throw new RuntimeException("Internal error providing expression tree: " + e.getMessage(), e);
        }
    }

    private static class GroupByExpressionInfo {
        private final List<ExprNode> expressions;
        private final List<GroupByRollupNodeBase> nodes;

        private GroupByExpressionInfo(List<ExprNode> expressions, List<GroupByRollupNodeBase> nodes) {
            this.expressions = expressions;
            this.nodes = nodes;
        }

        public List<ExprNode> getExpressions() {
            return expressions;
        }

        public List<GroupByRollupNodeBase> getNodes() {
            return nodes;
        }
    }
}
TOP

Related Classes of com.espertech.esper.epl.agg.rollup.GroupByExpressionHelper$GroupByExpressionInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.