Search in sources :

Example 1 with WindowFunctionExpression

use of org.voltdb.expressions.WindowFunctionExpression in project voltdb by VoltDB.

the class AbstractParsedStmt method parseWindowedAggregationExpression.

/**
     * Parse a windowed expression.  This actually just returns a TVE.  The
     * WindowFunctionExpression is squirreled away in the m_windowFunctionExpressions
     * object, though, because we will need it later.
     *
     * @param exprNode
     * @return
     */
private AbstractExpression parseWindowedAggregationExpression(VoltXMLElement exprNode) {
    int id = Integer.parseInt(exprNode.attributes.get("id"));
    String optypeName = exprNode.attributes.get("optype");
    ExpressionType optype = ExpressionType.get(optypeName);
    if (optype == ExpressionType.INVALID) {
        throw new PlanningErrorException("Undefined windowed function call " + optypeName);
    }
    // the windowed expression, then this is an error.
    if (!m_parsingInDisplayColumns) {
        if (m_windowFunctionExpressions.size() > 0) {
            WindowFunctionExpression we = m_windowFunctionExpressions.get(0);
            if (we.getXMLID() == id) {
                // away in the windowed expression.
                return we.getDisplayListExpression();
            }
        }
        throw new PlanningErrorException("Windowed function call expressions can only appear in the selection list of a query or subquery.");
    }
    // Parse individual aggregate expressions
    List<AbstractExpression> partitionbyExprs = new ArrayList<>();
    List<AbstractExpression> orderbyExprs = new ArrayList<>();
    List<SortDirectionType> orderbyDirs = new ArrayList<>();
    List<AbstractExpression> aggParams = new ArrayList<>();
    for (VoltXMLElement childEle : exprNode.children) {
        if (childEle.name.equals("winspec")) {
            for (VoltXMLElement ele : childEle.children) {
                if (ele.name.equals("partitionbyList")) {
                    for (VoltXMLElement childNode : ele.children) {
                        AbstractExpression expr = parseExpressionNode(childNode);
                        ExpressionUtil.finalizeValueTypes(expr);
                        partitionbyExprs.add(expr);
                    }
                } else if (ele.name.equals("orderbyList")) {
                    for (VoltXMLElement childNode : ele.children) {
                        SortDirectionType sortDir = Boolean.valueOf(childNode.attributes.get("descending")) ? SortDirectionType.DESC : SortDirectionType.ASC;
                        AbstractExpression expr = parseExpressionNode(childNode.children.get(0));
                        ExpressionUtil.finalizeValueTypes(expr);
                        orderbyExprs.add(expr);
                        orderbyDirs.add(sortDir);
                    }
                }
            }
        } else {
            AbstractExpression aggParam = parseExpressionNode(childEle);
            if (aggParam != null) {
                aggParam.finalizeValueTypes();
                aggParams.add(aggParam);
            }
        }
    }
    String alias = WINDOWED_AGGREGATE_COLUMN_NAME;
    if (exprNode.attributes.containsKey("alias")) {
        alias = exprNode.attributes.get("alias");
    }
    WindowFunctionExpression rankExpr = new WindowFunctionExpression(optype, partitionbyExprs, orderbyExprs, orderbyDirs, aggParams, id);
    ExpressionUtil.finalizeValueTypes(rankExpr);
    // Only offset 0 is useful.  But we keep the index anyway.
    int offset = m_windowFunctionExpressions.size();
    m_windowFunctionExpressions.add(rankExpr);
    TupleValueExpression tve = new TupleValueExpression(TEMP_TABLE_NAME, TEMP_TABLE_NAME, alias, alias, rankExpr, offset);
    // This tve does not ever need a differentiator.
    tve.setNeedsNoDifferentiation();
    rankExpr.setDisplayListExpression(tve);
    return tve;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) WindowFunctionExpression(org.voltdb.expressions.WindowFunctionExpression) ArrayList(java.util.ArrayList) SortDirectionType(org.voltdb.types.SortDirectionType) VoltXMLElement(org.hsqldb_voltpatches.VoltXMLElement) ExpressionType(org.voltdb.types.ExpressionType) Constraint(org.voltdb.catalog.Constraint)

Example 2 with WindowFunctionExpression

use of org.voltdb.expressions.WindowFunctionExpression in project voltdb by VoltDB.

the class ParsedSelectStmt method isPartitionColumnInWindowedAggregatePartitionByList.

/**
     * Return true iff all the windowed partition expressions
     * have a table partition column in their partition by list,
     * and if there is one such windowed partition expression.
     * If there are no windowed expressions, we return false.
     * Note that there can only be one windowed
     * expression currently, so this is more general than it needs to be.
     *
     * @return
     */
public boolean isPartitionColumnInWindowedAggregatePartitionByList() {
    if (getWindowFunctionExpressions().size() == 0) {
        return false;
    }
    // If we ever do, this should fail gracelessly.
    assert (getWindowFunctionExpressions().size() == 1);
    WindowFunctionExpression we = getWindowFunctionExpressions().get(0);
    List<AbstractExpression> partitionByExprs = we.getPartitionByExpressions();
    boolean foundPartExpr = false;
    for (AbstractExpression ae : partitionByExprs) {
        if (!(ae instanceof TupleValueExpression)) {
            continue;
        }
        TupleValueExpression tve = (TupleValueExpression) ae;
        String tableAlias = tve.getTableAlias();
        String columnName = tve.getColumnName();
        StmtTableScan scanTable = getStmtTableScanByAlias(tableAlias);
        if (scanTable == null || scanTable.getPartitioningColumns() == null) {
            continue;
        }
        boolean foundPartCol = false;
        for (SchemaColumn pcol : scanTable.getPartitioningColumns()) {
            if (pcol != null && pcol.getColumnName().equals(columnName)) {
                foundPartCol = true;
                break;
            }
        }
        // in this windowed expression.
        if (foundPartCol) {
            foundPartExpr = true;
            break;
        }
    }
    return foundPartExpr;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) WindowFunctionExpression(org.voltdb.expressions.WindowFunctionExpression) SchemaColumn(org.voltdb.plannodes.SchemaColumn) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan)

Example 3 with WindowFunctionExpression

use of org.voltdb.expressions.WindowFunctionExpression in project voltdb by VoltDB.

the class ParsedSelectStmt method verifyWindowFunctionExpressions.

/**
     * Verify the validity of the windowed expressions.
     *
     * @return
     */
private void verifyWindowFunctionExpressions() {
    // Check for windowed expressions.
    if (m_windowFunctionExpressions.size() > 0) {
        if (m_windowFunctionExpressions.size() > 1) {
            throw new PlanningErrorException("Only one windowed function call may appear in a selection list.");
        }
        if (m_hasAggregateExpression) {
            throw new PlanningErrorException("Use of window functions (in an OVER clause) isn't supported with other aggregate functions on the SELECT list.");
        }
        if (m_windowFunctionExpressions.get(0).hasSubqueryArgs()) {
            throw new PlanningErrorException("Window function calls with subquery expression arguments are not allowed.");
        }
        //
        // This could be an if statement, but I think it's better to
        // leave this as a pattern in case we decide to implement more
        // legality conditions for other windowed operators.
        //
        WindowFunctionExpression windowFunctionExpression = m_windowFunctionExpressions.get(0);
        List<AbstractExpression> orderByExpressions = windowFunctionExpression.getOrderByExpressions();
        ExpressionType exprType = windowFunctionExpression.getExpressionType();
        String aggName = exprType.symbol().toUpperCase();
        switch(exprType) {
            case AGGREGATE_WINDOWED_RANK:
            case AGGREGATE_WINDOWED_DENSE_RANK:
                if (orderByExpressions.size() == 0) {
                    throw new PlanningErrorException("Windowed " + aggName + " function call expressions require an ORDER BY specification.");
                }
                VoltType valType = orderByExpressions.get(0).getValueType();
                assert (valType != null);
                if (!valType.isAnyIntegerType() && (valType != VoltType.TIMESTAMP)) {
                    throw new PlanningErrorException("Windowed function call expressions can have only integer or TIMESTAMP value types in the ORDER BY expression of their window.");
                }
                break;
            case AGGREGATE_WINDOWED_COUNT:
                if (windowFunctionExpression.getAggregateArguments().size() > 1) {
                    throw new PlanningErrorException(String.format("Windowed COUNT must have either exactly one argument or else a star for an argument"));
                }
                // Any type is ok, so we won't inspect the type.
                break;
            case AGGREGATE_WINDOWED_MAX:
            case AGGREGATE_WINDOWED_MIN:
                if (windowFunctionExpression.getAggregateArguments().size() != 1) {
                    throw new PlanningErrorException(String.format("Windowed %s must have exactly one argument", aggName));
                }
                // Any type is ok, so we won't inspect the type.
                break;
            case AGGREGATE_WINDOWED_SUM:
                if (windowFunctionExpression.getAggregateArguments().size() != 1) {
                    throw new PlanningErrorException(String.format("Windowed SUM must have exactly one numeric argument"));
                }
                AbstractExpression arg = windowFunctionExpression.getAggregateArguments().get(0);
                VoltType vt = arg.getValueType();
                assert (vt != null);
                if (!vt.isNumber()) {
                    throw new PlanningErrorException("Windowed SUM must have exactly one numeric argument");
                }
                break;
            default:
                {
                    String opName = (exprType == null) ? "NULL" : exprType.symbol();
                    throw new PlanningErrorException("Unknown windowed aggregate function type: " + opName);
                }
        }
    }
}
Also used : AbstractExpression(org.voltdb.expressions.AbstractExpression) VoltType(org.voltdb.VoltType) WindowFunctionExpression(org.voltdb.expressions.WindowFunctionExpression) ExpressionType(org.voltdb.types.ExpressionType)

Example 4 with WindowFunctionExpression

use of org.voltdb.expressions.WindowFunctionExpression in project voltdb by VoltDB.

the class PlanAssembler method handleWindowedOperators.

/**
     * Create nodes for windowed operations.
     *
     * @param root
     * @return
     */
private AbstractPlanNode handleWindowedOperators(AbstractPlanNode root) {
    // Get the windowed expression.  We need to set its output
    // schema from the display list.
    WindowFunctionExpression winExpr = m_parsedSelect.getWindowFunctionExpressions().get(0);
    assert (winExpr != null);
    // This will set the output schema to contain the
    // windowed schema column only.  In generateOutputSchema
    // we will add the input columns.
    WindowFunctionPlanNode pnode = new WindowFunctionPlanNode();
    pnode.setWindowFunctionExpression(winExpr);
    // We always need an order by plan node, even if the sort
    // is optimized away by an index.  This may be turned
    // into an inline order by in a MergeReceivePlanNode.
    IndexUseForOrderBy scanNode = findScanNodeForWindowFunction(root);
    AbstractPlanNode cnode = null;
    int winfunc = (scanNode == null) ? SubPlanAssembler.NO_INDEX_USE : scanNode.getWindowFunctionUsesIndex();
    // statement level order by ordering.
    if ((SubPlanAssembler.STATEMENT_LEVEL_ORDER_BY_INDEX == winfunc) || (SubPlanAssembler.NO_INDEX_USE == winfunc)) {
        // No index.  Calculate the expression order here and stuff it into
        // the order by node.  Note that if we support more than one window
        // function this would be the case when scanNode.getWindowFunctionUsesIndex()
        // returns a window function number which is different from the number
        // of winExpr.
        List<AbstractExpression> partitionByExpressions = winExpr.getPartitionByExpressions();
        // If the order by expression list contains a partition by expression then
        // we won't have to sort by it twice.  We sort by the partition by expressions
        // first, and we don't care what order we sort by them.  So, find the
        // sort direction in the order by list and use that in the partition by
        // list, and then mark that it was deleted in the order by
        // list.
        //
        // We choose to make this dontsort rather than dosort because the
        // Java default value for boolean is false, and we want to sort by
        // default.
        boolean[] dontsort = new boolean[winExpr.getOrderbySize()];
        List<AbstractExpression> orderByExpressions = winExpr.getOrderByExpressions();
        List<SortDirectionType> orderByDirections = winExpr.getOrderByDirections();
        OrderByPlanNode onode = new OrderByPlanNode();
        for (int idx = 0; idx < winExpr.getPartitionbySize(); ++idx) {
            SortDirectionType pdir = SortDirectionType.ASC;
            AbstractExpression partitionByExpression = partitionByExpressions.get(idx);
            int sidx = winExpr.getSortIndexOfOrderByExpression(partitionByExpression);
            if (0 <= sidx) {
                pdir = orderByDirections.get(sidx);
                dontsort[sidx] = true;
            }
            onode.addSort(partitionByExpression, pdir);
        }
        for (int idx = 0; idx < winExpr.getOrderbySize(); ++idx) {
            if (!dontsort[idx]) {
                AbstractExpression orderByExpr = orderByExpressions.get(idx);
                SortDirectionType orderByDir = orderByDirections.get(idx);
                onode.addSort(orderByExpr, orderByDir);
            }
        }
        onode.addAndLinkChild(root);
        cnode = onode;
    } else {
        assert (scanNode != null);
        // inline order by node of a MergeReceive node.
        assert (0 == scanNode.getWindowFunctionUsesIndex());
        if (m_partitioning.requiresTwoFragments()) {
            OrderByPlanNode onode = new OrderByPlanNode();
            SortDirectionType dir = scanNode.getSortOrderFromIndexScan();
            assert (dir != SortDirectionType.INVALID);
            // This was created when the index was determined.
            // We cached it in the scan node.
            List<AbstractExpression> orderExprs = scanNode.getFinalExpressionOrderFromIndexScan();
            assert (orderExprs != null);
            for (AbstractExpression ae : orderExprs) {
                onode.addSort(ae, dir);
            }
            // Link in the OrderByNode.
            onode.addAndLinkChild(root);
            cnode = onode;
        } else {
            // Don't create and link in the order by node.
            cnode = root;
        }
    }
    pnode.addAndLinkChild(cnode);
    return pnode;
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) AbstractExpression(org.voltdb.expressions.AbstractExpression) OrderByPlanNode(org.voltdb.plannodes.OrderByPlanNode) WindowFunctionPlanNode(org.voltdb.plannodes.WindowFunctionPlanNode) WindowFunctionExpression(org.voltdb.expressions.WindowFunctionExpression) SortDirectionType(org.voltdb.types.SortDirectionType) Constraint(org.voltdb.catalog.Constraint) IndexUseForOrderBy(org.voltdb.plannodes.IndexUseForOrderBy)

Aggregations

AbstractExpression (org.voltdb.expressions.AbstractExpression)4 WindowFunctionExpression (org.voltdb.expressions.WindowFunctionExpression)4 Constraint (org.voltdb.catalog.Constraint)2 TupleValueExpression (org.voltdb.expressions.TupleValueExpression)2 ExpressionType (org.voltdb.types.ExpressionType)2 SortDirectionType (org.voltdb.types.SortDirectionType)2 ArrayList (java.util.ArrayList)1 VoltXMLElement (org.hsqldb_voltpatches.VoltXMLElement)1 VoltType (org.voltdb.VoltType)1 StmtTableScan (org.voltdb.planner.parseinfo.StmtTableScan)1 AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)1 IndexUseForOrderBy (org.voltdb.plannodes.IndexUseForOrderBy)1 OrderByPlanNode (org.voltdb.plannodes.OrderByPlanNode)1 SchemaColumn (org.voltdb.plannodes.SchemaColumn)1 WindowFunctionPlanNode (org.voltdb.plannodes.WindowFunctionPlanNode)1