use of org.voltdb.plannodes.AbstractPlanNode in project voltdb by VoltDB.
the class InlineOrderByIntoMergeReceive method applyOptimization.
/**
* Convert ReceivePlanNodes into MergeReceivePlanNodes when the
* RECEIVE node's nearest parent is a window function. We won't
* have any inline limits or aggregates here, so this is somewhat
* simpler than the order by case.
*
* @param plan
* @return
*/
private AbstractPlanNode applyOptimization(WindowFunctionPlanNode plan) {
assert (plan.getChildCount() == 1);
assert (plan.getChild(0) != null);
AbstractPlanNode child = plan.getChild(0);
assert (child != null);
// an order by node.
if (!(child instanceof OrderByPlanNode)) {
return plan;
}
OrderByPlanNode onode = (OrderByPlanNode) child;
child = onode.getChild(0);
// for this optimization to work.
if (!(child instanceof ReceivePlanNode)) {
return plan;
}
ReceivePlanNode receiveNode = (ReceivePlanNode) child;
assert (receiveNode.getChildCount() == 1);
child = receiveNode.getChild(0);
// The Receive node needs a send node child.
assert (child instanceof SendPlanNode);
SendPlanNode sendNode = (SendPlanNode) child;
child = sendNode.getChild(0);
// returns the number in the plan node.
if (!(child instanceof IndexSortablePlanNode)) {
return plan;
}
IndexSortablePlanNode indexed = (IndexSortablePlanNode) child;
if (indexed.indexUse().getWindowFunctionUsesIndex() != 0) {
return plan;
}
// Remove the Receive node and the Order by node
// and replace them with a MergeReceive node. Leave
// the order by node inline in the MergeReceive node,
// since we need it to calculate the merge.
plan.clearChildren();
receiveNode.removeFromGraph();
MergeReceivePlanNode mrnode = new MergeReceivePlanNode();
mrnode.addInlinePlanNode(onode);
mrnode.addAndLinkChild(sendNode);
plan.addAndLinkChild(mrnode);
return plan;
}
use of org.voltdb.plannodes.AbstractPlanNode in project voltdb by VoltDB.
the class WriterSubPlanAssembler method nextPlan.
/**
* Pull a join order out of the join orders deque, compute all possible plans
* for that join order, then append them to the computed plans deque.
*/
@Override
AbstractPlanNode nextPlan() {
if (!m_generatedPlans) {
assert (m_parsedStmt.m_joinTree != null);
// Clone the node to make make sure that analyze expression is called
// only once on the node.
JoinNode tableNode = (JoinNode) m_parsedStmt.m_joinTree.clone();
// Analyze join conditions
tableNode.analyzeJoinExpressions(m_parsedStmt.m_noTableSelectionList);
// these just shouldn't happen right?
assert (m_parsedStmt.m_noTableSelectionList.size() == 0);
m_generatedPlans = true;
// This is either UPDATE or DELETE statement. Consolidate all expressions
// into the WHERE list.
tableNode.m_whereInnerList.addAll(tableNode.m_joinInnerList);
tableNode.m_joinInnerList.clear();
tableNode.m_accessPaths.addAll(getRelevantAccessPathsForTable(tableNode.getTableScan(), null, tableNode.m_whereInnerList, null));
for (AccessPath path : tableNode.m_accessPaths) {
tableNode.m_currentAccessPath = path;
AbstractPlanNode plan = getAccessPlanForTable(tableNode);
m_plans.add(plan);
}
}
return m_plans.poll();
}
use of org.voltdb.plannodes.AbstractPlanNode in project voltdb by VoltDB.
the class PushdownLimits method recursivelyApply.
@Override
protected AbstractPlanNode recursivelyApply(AbstractPlanNode plan) {
assert (plan != null);
// depth first:
// find LimitPlanNodes with exactly one child
// where that child is an AbstractScanPlanNode
// disconnect the LimitPlanNode
// and inline the LimitPlanNode in to the AbstractScanPlanNode
ArrayList<AbstractPlanNode> children = new ArrayList<AbstractPlanNode>();
for (int i = 0; i < plan.getChildCount(); i++) children.add(plan.getChild(i));
plan.clearChildren();
for (AbstractPlanNode child : children) {
// TODO this will break when children feed multiple parents
child = recursivelyApply(child);
child.clearParents();
plan.addAndLinkChild(child);
}
if (!(plan instanceof LimitPlanNode)) {
return plan;
}
if (plan.getChildCount() != 1) {
assert (plan.getChildCount() == 1);
return plan;
}
AbstractPlanNode child = plan.getChild(0);
// push into Scans
if (child instanceof AbstractScanPlanNode) {
// in future, this limit can be aggregate inline node.
if (AggregatePlanNode.getInlineAggregationNode(child) != null) {
return plan;
}
plan.clearChildren();
child.clearParents();
child.addInlinePlanNode(plan);
return child;
}
// == child/projection . recursivelyApply(plan/limit . leaf/whatever)
if (child instanceof ProjectionPlanNode) {
assert (child.getChildCount() == 1);
AbstractPlanNode leaf = child.getChild(0);
leaf.clearParents();
plan.clearChildren();
plan.addAndLinkChild(leaf);
child.clearChildren();
child.clearParents();
child.addAndLinkChild(plan);
return recursivelyApply(child);
}
// push into JOINs
if (child instanceof AbstractJoinPlanNode) {
plan.clearChildren();
child.clearParents();
child.addInlinePlanNode(plan);
// }
return child;
}
return plan;
}
use of org.voltdb.plannodes.AbstractPlanNode in project voltdb by VoltDB.
the class TestPlansDistinct method checkDistinctWithGroupbyPlans.
/**
*
* @param distinctSQL Group by query with distinct
* @param groupbySQL Group by query without distinct
*/
protected void checkDistinctWithGroupbyPlans(String distinctSQL, String groupbySQL, boolean limitPushdown) {
List<AbstractPlanNode> pns1 = compileToFragments(distinctSQL);
List<AbstractPlanNode> pns2 = compileToFragments(groupbySQL);
//printExplainPlan(pns1);
//printExplainPlan(pns2);
assertTrue(pns1.get(0) instanceof SendPlanNode);
assertTrue(pns2.get(0) instanceof SendPlanNode);
AbstractPlanNode apn1, apn2;
apn1 = pns1.get(0).getChild(0);
apn2 = pns2.get(0).getChild(0);
boolean hasTopProjection1 = false;
if (apn1 instanceof ProjectionPlanNode) {
apn1 = apn1.getChild(0);
hasTopProjection1 = true;
}
boolean hasTopProjection2 = false;
if (apn2 instanceof ProjectionPlanNode) {
apn2 = apn2.getChild(0);
hasTopProjection2 = true;
}
// DISTINCT plan node is rewrote with GROUP BY and adds above the original GROUP BY node
// there may be another projection node in between for complex aggregation case
boolean hasOrderby = false, hasLimit = false;
boolean groupByMergeReceive = false;
// infer the ORDERBY/LIMIT information from the base line query
if (apn2 instanceof OrderByPlanNode) {
hasOrderby = true;
if (apn2.getInlinePlanNode(PlanNodeType.LIMIT) != null) {
hasLimit = true;
}
apn2 = apn2.getChild(0);
} else if (apn2 instanceof LimitPlanNode) {
hasLimit = true;
apn2 = apn2.getChild(0);
} else if (apn2 instanceof MergeReceivePlanNode) {
assertTrue(apn2.getInlinePlanNode(PlanNodeType.ORDERBY) != null);
hasOrderby = true;
hasLimit = apn2.getInlinePlanNode(PlanNodeType.LIMIT) != null;
groupByMergeReceive = true;
}
// check the DISTINCT query plan
boolean distinctMergeReceive = false;
if (hasOrderby) {
if (apn1 instanceof OrderByPlanNode) {
assertTrue(apn1 instanceof OrderByPlanNode);
if (hasLimit) {
// check inline limit
assertNotNull(apn1.getInlinePlanNode(PlanNodeType.LIMIT));
}
apn1 = apn1.getChild(0);
} else if (apn1 instanceof MergeReceivePlanNode) {
distinctMergeReceive = true;
assertNotNull(apn1.getInlinePlanNode(PlanNodeType.ORDERBY));
assertEquals(0, apn1.getChildCount());
} else {
fail("The distinctSQL top node is not OrderBy or MergeReceive.");
}
} else if (hasLimit) {
assertTrue(apn1 instanceof LimitPlanNode);
apn1 = apn1.getChild(0);
}
// Check DISTINCT group by plan node
if (distinctMergeReceive) {
AbstractPlanNode aggr = AggregatePlanNode.getInlineAggregationNode(apn1);
assertTrue(aggr instanceof AggregatePlanNode);
assertEquals(0, ((AggregatePlanNode) aggr).getAggregateTypesSize());
assertEquals(pns1.get(0).getOutputSchema().getColumns().size(), ((AggregatePlanNode) aggr).getGroupByExpressionsSize());
if (hasLimit) {
// check inline limit
assertNotNull(aggr.getInlinePlanNode(PlanNodeType.LIMIT));
}
} else {
assertTrue(apn1 instanceof HashAggregatePlanNode);
assertEquals(0, ((HashAggregatePlanNode) apn1).getAggregateTypesSize());
assertEquals(pns1.get(0).getOutputSchema().getColumns().size(), ((HashAggregatePlanNode) apn1).getGroupByExpressionsSize());
apn1 = apn1.getChild(0);
}
// check projection node for complex aggregation case
if (apn1 instanceof ProjectionPlanNode) {
apn1 = apn1.getChild(0);
assertFalse(hasTopProjection1);
}
if (apn2 instanceof ProjectionPlanNode) {
apn2 = apn2.getChild(0);
assertFalse(hasTopProjection2);
}
// check the rest plan nodes.
if (distinctMergeReceive == false && groupByMergeReceive == false) {
assertEquals(apn1.toExplainPlanString(), apn2.toExplainPlanString());
} else if (distinctMergeReceive == true && groupByMergeReceive == true) {
// In case of applied MergeReceive optimization the apn1 and apn2 nodes
// should not have any children
assertEquals(0, apn1.getChildCount());
assertEquals(0, apn2.getChildCount());
}
// Distributed DISTINCT GROUP BY
if (pns1.size() > 1) {
if (!limitPushdown) {
assertEquals(pns1.get(1).toExplainPlanString(), pns2.get(1).toExplainPlanString());
return;
}
assertTrue(pns1.get(1) instanceof SendPlanNode);
assertTrue(pns2.get(1) instanceof SendPlanNode);
apn1 = pns1.get(1).getChild(0);
apn2 = pns2.get(1).getChild(0);
// ignore the ORDER BY/LIMIT pushdown plan node
// because DISTINCT case can not be pushed down
assertTrue(apn2 instanceof OrderByPlanNode);
assertNotNull(apn2.getInlinePlanNode(PlanNodeType.LIMIT));
apn2 = apn2.getChild(0);
// winners may produce completely different paths.
if (distinctMergeReceive == false && groupByMergeReceive == false) {
assertEquals(apn1.toExplainPlanString(), apn2.toExplainPlanString());
}
}
}
use of org.voltdb.plannodes.AbstractPlanNode in project voltdb by VoltDB.
the class TestPlansGroupBy method testDistinctA1_Subquery.
public void testDistinctA1_Subquery() {
AbstractPlanNode p;
List<AbstractPlanNode> pns;
// Distinct rewrote with group by
pns = compileToFragments("select * from (SELECT DISTINCT A1 FROM T1) temp");
p = pns.get(0).getChild(0);
assertTrue(p instanceof SeqScanPlanNode);
assertTrue(p.getChild(0) instanceof HashAggregatePlanNode);
assertTrue(p.getChild(0).getChild(0) instanceof ReceivePlanNode);
p = pns.get(1).getChild(0);
assertTrue(p instanceof AbstractScanPlanNode);
assertNotNull(p.getInlinePlanNode(PlanNodeType.HASHAGGREGATE));
}
Aggregations