use of org.voltdb.planner.parseinfo.StmtSubqueryScan in project voltdb by VoltDB.
the class PlanAssembler method getBestCostPlanForFromSubQueries.
/**
* Generate best cost plans for a list of FROM sub-queries.
* @param subqueryNodes - list of FROM sub-queries.
* @return ParsedResultAccumulator
*/
private ParsedResultAccumulator getBestCostPlanForFromSubQueries(List<StmtSubqueryScan> subqueryNodes) {
int nextPlanId = m_planSelector.m_planId;
boolean orderIsDeterministic = true;
boolean hasSignificantOffsetOrLimit = false;
String isContentDeterministic = null;
for (StmtSubqueryScan subqueryScan : subqueryNodes) {
nextPlanId = planForParsedSubquery(subqueryScan, nextPlanId);
CompiledPlan subqueryBestPlan = subqueryScan.getBestCostPlan();
if (subqueryBestPlan == null) {
throw new PlanningErrorException(m_recentErrorMsg);
}
orderIsDeterministic &= subqueryBestPlan.isOrderDeterministic();
if (isContentDeterministic != null && !subqueryBestPlan.isContentDeterministic()) {
isContentDeterministic = subqueryBestPlan.nondeterminismDetail();
}
// Offsets or limits in subqueries are only significant (only effect content determinism)
// when they apply to un-ordered subquery contents.
hasSignificantOffsetOrLimit |= ((!subqueryBestPlan.isOrderDeterministic()) && subqueryBestPlan.hasLimitOrOffset());
}
// need to reset plan id for the entire SQL
m_planSelector.m_planId = nextPlanId;
return new ParsedResultAccumulator(orderIsDeterministic, hasSignificantOffsetOrLimit, isContentDeterministic);
}
use of org.voltdb.planner.parseinfo.StmtSubqueryScan in project voltdb by VoltDB.
the class PlanAssembler method connectChildrenBestPlans.
/**
* For each Subquery node in the plan tree attach the subquery plan to the parent node.
* @param initial plan
* @return A complete plan tree for the entire SQl.
*/
private AbstractPlanNode connectChildrenBestPlans(AbstractPlanNode parentPlan) {
if (parentPlan instanceof AbstractScanPlanNode) {
AbstractScanPlanNode scanNode = (AbstractScanPlanNode) parentPlan;
StmtTableScan tableScan = scanNode.getTableScan();
if (tableScan instanceof StmtSubqueryScan) {
CompiledPlan bestCostPlan = ((StmtSubqueryScan) tableScan).getBestCostPlan();
assert (bestCostPlan != null);
AbstractPlanNode subQueryRoot = bestCostPlan.rootPlanGraph;
subQueryRoot.disconnectParents();
scanNode.clearChildren();
scanNode.addAndLinkChild(subQueryRoot);
}
} else {
for (int i = 0; i < parentPlan.getChildCount(); ++i) {
connectChildrenBestPlans(parentPlan.getChild(i));
}
}
return parentPlan;
}
use of org.voltdb.planner.parseinfo.StmtSubqueryScan in project voltdb by VoltDB.
the class PlanAssembler method getBestCostPlan.
CompiledPlan getBestCostPlan(AbstractParsedStmt parsedStmt) {
// parse any subqueries that the statement contains
List<StmtSubqueryScan> subqueryNodes = parsedStmt.getSubqueryScans();
ParsedResultAccumulator fromSubqueryResult = null;
if (!subqueryNodes.isEmpty()) {
fromSubqueryResult = getBestCostPlanForFromSubQueries(subqueryNodes);
if (fromSubqueryResult == null) {
// There was at least one sub-query and we should have a compiled plan for it
return null;
}
}
// Get the best plans for the expression subqueries ( IN/EXISTS (SELECT...) )
Set<AbstractExpression> subqueryExprs = parsedStmt.findSubquerySubexpressions();
if (!subqueryExprs.isEmpty()) {
// guards against IN/EXISTS/Scalar subqueries
if (!m_partitioning.wasSpecifiedAsSingle()) {
// levels of correlated subqueries.
for (AbstractExpression e : subqueryExprs) {
assert (e instanceof SelectSubqueryExpression);
SelectSubqueryExpression subExpr = (SelectSubqueryExpression) e;
if (!subExpr.getSubqueryScan().getIsReplicated()) {
m_recentErrorMsg = IN_EXISTS_SCALAR_ERROR_MESSAGE;
return null;
}
}
}
if (!getBestCostPlanForExpressionSubQueries(subqueryExprs)) {
// There was at least one sub-query and we should have a compiled plan for it
return null;
}
}
// set up the plan assembler for this statement
setupForNewPlans(parsedStmt);
// get ready to find the plan with minimal cost
CompiledPlan rawplan = null;
// loop over all possible plans
while (true) {
rawplan = getNextPlan();
// stop this while loop when no more plans are generated
if (rawplan == null) {
break;
}
// Update the best cost plan so far
m_planSelector.considerCandidatePlan(rawplan, parsedStmt);
}
CompiledPlan retval = m_planSelector.m_bestPlan;
if (retval == null) {
return null;
}
if (fromSubqueryResult != null) {
// Calculate the combined state of determinism for the parent and child statements
boolean orderIsDeterministic = retval.isOrderDeterministic();
String contentDeterminismDetail = fromSubqueryResult.m_isContentDeterministic;
if (orderIsDeterministic && !fromSubqueryResult.m_orderIsDeterministic) {
//TODO: this reliance on the vague isOrderDeterministicInSpiteOfUnorderedSubqueries test
// is subject to false negatives for determinism. It misses the subtlety of parent
// queries that surgically add orderings for specific "key" columns of a subquery result
// or a subquery-based join for an effectively deterministic result.
// The first step towards repairing this would involve detecting deterministic and
// non-deterministic subquery results IN CONTEXT where they are scanned in the parent
// query, so that the parent query can ensure that ALL the columns from a
// non-deterministic subquery are later sorted.
// The next step would be to extend the model for "subquery scans"
// to identify dependencies / uniqueness constraints in subquery results
// that can be exploited to impose determinism with fewer parent order by columns
// -- like just the keys.
orderIsDeterministic = parsedStmt.isOrderDeterministicInSpiteOfUnorderedSubqueries();
}
boolean hasLimitOrOffset = fromSubqueryResult.m_hasLimitOrOffset || retval.hasLimitOrOffset();
retval.statementGuaranteesDeterminism(hasLimitOrOffset, orderIsDeterministic, contentDeterminismDetail);
// Need to re-attach the sub-queries plans to the best parent plan. The same best plan for each
// sub-query is reused with all parent candidate plans and needs to be reconnected with
// the final best parent plan
retval.rootPlanGraph = connectChildrenBestPlans(retval.rootPlanGraph);
}
/*
* Find out if the query is inherently content deterministic and
* remember it.
*/
String contentDeterminismMessage = parsedStmt.getContentDeterminismMessage();
if (contentDeterminismMessage != null) {
retval.setNondeterminismDetail(contentDeterminismMessage);
}
failIfNonDeterministicDml(parsedStmt, retval);
if (m_partitioning != null) {
retval.setStatementPartitioning(m_partitioning);
}
return retval;
}
use of org.voltdb.planner.parseinfo.StmtSubqueryScan in project voltdb by VoltDB.
the class PlanAssembler method getBestCostPlanForExpressionSubQueries.
/**
* Generate best cost plans for each Subquery expression from the list
* @param subqueryExprs - list of subquery expressions
* @return true if a best plan was generated for each subquery, false otherwise
*/
private boolean getBestCostPlanForExpressionSubQueries(Set<AbstractExpression> subqueryExprs) {
int nextPlanId = m_planSelector.m_planId;
for (AbstractExpression expr : subqueryExprs) {
assert (expr instanceof SelectSubqueryExpression);
if (!(expr instanceof SelectSubqueryExpression)) {
// DEAD CODE?
continue;
}
SelectSubqueryExpression subqueryExpr = (SelectSubqueryExpression) expr;
StmtSubqueryScan subqueryScan = subqueryExpr.getSubqueryScan();
nextPlanId = planForParsedSubquery(subqueryScan, nextPlanId);
CompiledPlan bestPlan = subqueryScan.getBestCostPlan();
if (bestPlan == null) {
return false;
}
subqueryExpr.setSubqueryNode(bestPlan.rootPlanGraph);
// multiple times during the parent statement execution.
if (bestPlan.rootPlanGraph.hasAnyNodeOfType(PlanNodeType.SEND)) {
// fail the whole plan
m_recentErrorMsg = IN_EXISTS_SCALAR_ERROR_MESSAGE;
return false;
}
}
// need to reset plan id for the entire SQL
m_planSelector.m_planId = nextPlanId;
return true;
}
use of org.voltdb.planner.parseinfo.StmtSubqueryScan in project voltdb by VoltDB.
the class TestPlansSubQueries method checkSubqueryNoSimplification.
private void checkSubqueryNoSimplification(String sql) {
AbstractPlanNode pn = compile(sql);
pn = pn.getChild(0);
assertEquals(PlanNodeType.SEQSCAN, pn.getPlanNodeType());
StmtTableScan tableScan = ((SeqScanPlanNode) pn).getTableScan();
assertTrue(tableScan instanceof StmtSubqueryScan);
}
Aggregations