Search in sources :

Example 1 with WindowFunctionPlanNode

use of org.voltdb.plannodes.WindowFunctionPlanNode in project voltdb by VoltDB.

the class TestWindowedFunctions method validatePartitionedQuery.

private void validatePartitionedQuery(String query, boolean hasStatementOrderBy) {
    List<AbstractPlanNode> nodes = compileToFragments(query);
    assertEquals(2, nodes.size());
    AbstractPlanNode child = nodes.get(0);
    // Validate the coordinator fragment.
    assertTrue(child instanceof SendPlanNode);
    child = child.getChild(0);
    assertTrue(child instanceof ProjectionPlanNode);
    if (hasStatementOrderBy) {
        child = child.getChild(0);
        assertTrue(child instanceof OrderByPlanNode);
    }
    child = child.getChild(0);
    assertTrue(child instanceof WindowFunctionPlanNode);
    child = child.getChild(0);
    assertTrue(child instanceof OrderByPlanNode);
    child = child.getChild(0);
    assertTrue(child instanceof ReceivePlanNode);
    assertEquals(0, child.getChildCount());
    // Get the distributed fragment.
    child = nodes.get(1);
    assertTrue(child instanceof SendPlanNode);
    child = child.getChild(0);
    assertTrue(child instanceof SeqScanPlanNode);
    assertEquals(0, child.getChildCount());
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) SeqScanPlanNode(org.voltdb.plannodes.SeqScanPlanNode) OrderByPlanNode(org.voltdb.plannodes.OrderByPlanNode) SendPlanNode(org.voltdb.plannodes.SendPlanNode) WindowFunctionPlanNode(org.voltdb.plannodes.WindowFunctionPlanNode) ReceivePlanNode(org.voltdb.plannodes.ReceivePlanNode) ProjectionPlanNode(org.voltdb.plannodes.ProjectionPlanNode)

Example 2 with WindowFunctionPlanNode

use of org.voltdb.plannodes.WindowFunctionPlanNode 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)

Example 3 with WindowFunctionPlanNode

use of org.voltdb.plannodes.WindowFunctionPlanNode in project voltdb by VoltDB.

the class InlineOrderByIntoMergeReceive method recursivelyApply.

@Override
protected AbstractPlanNode recursivelyApply(AbstractPlanNode planNode) {
    assert (planNode != null);
    // side effects.
    if (m_parsedStmt.topmostParentStatementIsDML()) {
        // Do not apply the optimization.
        return planNode;
    }
    Queue<AbstractPlanNode> children = new LinkedList<>();
    children.add(planNode);
    while (!children.isEmpty()) {
        AbstractPlanNode plan = children.remove();
        PlanNodeType nodeType = plan.getPlanNodeType();
        if (PlanNodeType.RECEIVE == nodeType) {
            // continue. We are after the coordinator ORDER BY or WINDOWFUNCTION node.
            return planNode;
        }
        if (PlanNodeType.ORDERBY == nodeType) {
            assert (plan instanceof OrderByPlanNode);
            AbstractPlanNode newPlan = applyOptimization((OrderByPlanNode) plan);
            //     the new plan node.
            if (newPlan != plan) {
                // Only one coordinator ORDER BY node is possible
                if (plan == planNode) {
                    return newPlan;
                } else {
                    // Do not apply the optimization.
                    return planNode;
                }
            }
        } else if (PlanNodeType.WINDOWFUNCTION == nodeType) {
            assert (plan instanceof WindowFunctionPlanNode);
            AbstractPlanNode newPlan = applyOptimization((WindowFunctionPlanNode) plan);
            // See above for why this is the way it is.
            if (newPlan != plan) {
                return newPlan;
            } else {
                return planNode;
            }
        }
        for (int i = 0; i < plan.getChildCount(); i++) {
            children.add(plan.getChild(i));
        }
    }
    // Do not apply the optimization.
    return planNode;
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) PlanNodeType(org.voltdb.types.PlanNodeType) OrderByPlanNode(org.voltdb.plannodes.OrderByPlanNode) WindowFunctionPlanNode(org.voltdb.plannodes.WindowFunctionPlanNode) LinkedList(java.util.LinkedList)

Example 4 with WindowFunctionPlanNode

use of org.voltdb.plannodes.WindowFunctionPlanNode in project voltdb by VoltDB.

the class TestWindowedFunctions method validateWindowedFunctionPlan.

/**
     * Validate that each similar windowed query in testRank produces a similar
     * plan, with the expected minor variation to its ORDER BY node.
     * @param windowedQuery a variant of a test query of a known basic format
     * @param nSorts the expected number of sort criteria that should have been
     *        extracted from the variant query's PARTITION BY and ORDER BY.
     * @param descSortIndex the position among the sort criteria of the original
     *        ORDER BY column, always distinguishable by its "DESC" direction.
     **/
private void validateWindowedFunctionPlan(String windowedQuery, int nSorts, int descSortIndex, int numPartitionExprs, ExpressionType winOpType) {
    // Sometimes we get multi-fragment nodes when we
    // expect single fragment nodes.  Keeping all the fragments
    // helps to diagnose the problem.
    List<AbstractPlanNode> nodes = compileToFragments(windowedQuery);
    assertEquals(1, nodes.size());
    AbstractPlanNode node = nodes.get(0);
    // The plan should look like:
    // SendNode -> ProjectionPlanNode -> PartitionByPlanNode -> OrderByPlanNode -> SeqScanNode
    // We also do some sanity checking on the PartitionPlan node.
    // First dissect the plan.
    assertTrue(node instanceof SendPlanNode);
    AbstractPlanNode projPlanNode = node.getChild(0);
    assertTrue(projPlanNode instanceof ProjectionPlanNode);
    AbstractPlanNode windowFuncPlanNode = projPlanNode.getChild(0);
    assertTrue(windowFuncPlanNode instanceof WindowFunctionPlanNode);
    AbstractPlanNode abstractOrderByNode = windowFuncPlanNode.getChild(0);
    assertTrue(abstractOrderByNode instanceof OrderByPlanNode);
    OrderByPlanNode orderByNode = (OrderByPlanNode) abstractOrderByNode;
    NodeSchema input_schema = orderByNode.getOutputSchema();
    assertNotNull(input_schema);
    AbstractPlanNode seqScanNode = orderByNode.getChild(0);
    assertTrue(seqScanNode instanceof SeqScanPlanNode || seqScanNode instanceof NestLoopPlanNode);
    WindowFunctionPlanNode wfPlanNode = (WindowFunctionPlanNode) windowFuncPlanNode;
    NodeSchema schema = wfPlanNode.getOutputSchema();
    //
    // Check that the window function plan node's output schema is correct.
    // Look at the first expression, to verify that it's the windowed expression.
    // Then check that the TVEs all make sense.
    //
    SchemaColumn column = schema.getColumns().get(0);
    assertEquals("ARANK", column.getColumnAlias());
    assertEquals(numPartitionExprs, wfPlanNode.getPartitionByExpressions().size());
    validateTVEs(input_schema, wfPlanNode, false);
    //
    // Check that the operation is what we expect.
    //
    assertTrue(wfPlanNode.getAggregateTypes().size() > 0);
    assertEquals(winOpType, wfPlanNode.getAggregateTypes().get(0));
    //
    for (List<AbstractExpression> exprs : wfPlanNode.getAggregateExpressions()) {
        if (exprs != null) {
            for (AbstractExpression expr : exprs) {
                assertNotNull(expr.getValueType());
            }
        }
    }
    //
    // Check that the order by node has the right number of expressions.
    // and that they have the correct order.
    //
    assertEquals(nSorts, orderByNode.getSortExpressions().size());
    int sortIndex = 0;
    for (SortDirectionType direction : orderByNode.getSortDirections()) {
        SortDirectionType expected = (sortIndex == descSortIndex) ? SortDirectionType.DESC : SortDirectionType.ASC;
        assertEquals(expected, direction);
        ++sortIndex;
    }
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) OrderByPlanNode(org.voltdb.plannodes.OrderByPlanNode) SendPlanNode(org.voltdb.plannodes.SendPlanNode) SchemaColumn(org.voltdb.plannodes.SchemaColumn) SortDirectionType(org.voltdb.types.SortDirectionType) NestLoopPlanNode(org.voltdb.plannodes.NestLoopPlanNode) SeqScanPlanNode(org.voltdb.plannodes.SeqScanPlanNode) AbstractExpression(org.voltdb.expressions.AbstractExpression) WindowFunctionPlanNode(org.voltdb.plannodes.WindowFunctionPlanNode) NodeSchema(org.voltdb.plannodes.NodeSchema) ProjectionPlanNode(org.voltdb.plannodes.ProjectionPlanNode)

Example 5 with WindowFunctionPlanNode

use of org.voltdb.plannodes.WindowFunctionPlanNode in project voltdb by VoltDB.

the class TestWindowedFunctions method validateQueryWithSubquery.

/**
     * Validate that each similar windowed query in testRankWithSubqueries
     * produces a similar plan
     * @param windowedQuery a variant of a test query of a known basic format
     **/
private void validateQueryWithSubquery(String windowedQuery, boolean waiveAliasMatch) {
    AbstractPlanNode node = compile(windowedQuery);
    // Dissect the plan.
    assertTrue(node instanceof SendPlanNode);
    AbstractPlanNode projectionPlanNode = node.getChild(0);
    assertTrue(projectionPlanNode instanceof ProjectionPlanNode);
    AbstractPlanNode partitionByPlanNode = projectionPlanNode.getChild(0);
    assertTrue(partitionByPlanNode instanceof WindowFunctionPlanNode);
    AbstractPlanNode orderByPlanNode = partitionByPlanNode.getChild(0);
    assertTrue(orderByPlanNode instanceof OrderByPlanNode);
    NodeSchema input_schema = orderByPlanNode.getOutputSchema();
    AbstractPlanNode scanNode = orderByPlanNode.getChild(0);
    assertTrue(scanNode instanceof NestLoopPlanNode);
    NodeSchema schema = partitionByPlanNode.getOutputSchema();
    SchemaColumn column = schema.getColumns().get(0);
    assertEquals("ARANK", column.getColumnAlias());
    validateTVEs(input_schema, (WindowFunctionPlanNode) partitionByPlanNode, waiveAliasMatch);
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) OrderByPlanNode(org.voltdb.plannodes.OrderByPlanNode) SendPlanNode(org.voltdb.plannodes.SendPlanNode) WindowFunctionPlanNode(org.voltdb.plannodes.WindowFunctionPlanNode) SchemaColumn(org.voltdb.plannodes.SchemaColumn) NestLoopPlanNode(org.voltdb.plannodes.NestLoopPlanNode) NodeSchema(org.voltdb.plannodes.NodeSchema) ProjectionPlanNode(org.voltdb.plannodes.ProjectionPlanNode)

Aggregations

AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)5 OrderByPlanNode (org.voltdb.plannodes.OrderByPlanNode)5 WindowFunctionPlanNode (org.voltdb.plannodes.WindowFunctionPlanNode)5 ProjectionPlanNode (org.voltdb.plannodes.ProjectionPlanNode)3 SendPlanNode (org.voltdb.plannodes.SendPlanNode)3 AbstractExpression (org.voltdb.expressions.AbstractExpression)2 NestLoopPlanNode (org.voltdb.plannodes.NestLoopPlanNode)2 NodeSchema (org.voltdb.plannodes.NodeSchema)2 SchemaColumn (org.voltdb.plannodes.SchemaColumn)2 SeqScanPlanNode (org.voltdb.plannodes.SeqScanPlanNode)2 SortDirectionType (org.voltdb.types.SortDirectionType)2 LinkedList (java.util.LinkedList)1 Constraint (org.voltdb.catalog.Constraint)1 WindowFunctionExpression (org.voltdb.expressions.WindowFunctionExpression)1 IndexUseForOrderBy (org.voltdb.plannodes.IndexUseForOrderBy)1 ReceivePlanNode (org.voltdb.plannodes.ReceivePlanNode)1 PlanNodeType (org.voltdb.types.PlanNodeType)1