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());
}
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;
}
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;
}
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;
}
}
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);
}
Aggregations