Search in sources :

Example 11 with StmtSubqueryScan

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);
}
Also used : StmtSubqueryScan(org.voltdb.planner.parseinfo.StmtSubqueryScan) Constraint(org.voltdb.catalog.Constraint)

Example 12 with StmtSubqueryScan

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;
}
Also used : StmtSubqueryScan(org.voltdb.planner.parseinfo.StmtSubqueryScan) AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) AbstractScanPlanNode(org.voltdb.plannodes.AbstractScanPlanNode) Constraint(org.voltdb.catalog.Constraint) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan)

Example 13 with StmtSubqueryScan

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;
}
Also used : StmtSubqueryScan(org.voltdb.planner.parseinfo.StmtSubqueryScan) AbstractExpression(org.voltdb.expressions.AbstractExpression) SelectSubqueryExpression(org.voltdb.expressions.SelectSubqueryExpression)

Example 14 with StmtSubqueryScan

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;
}
Also used : StmtSubqueryScan(org.voltdb.planner.parseinfo.StmtSubqueryScan) AbstractExpression(org.voltdb.expressions.AbstractExpression) SelectSubqueryExpression(org.voltdb.expressions.SelectSubqueryExpression) Constraint(org.voltdb.catalog.Constraint)

Example 15 with StmtSubqueryScan

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);
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) SeqScanPlanNode(org.voltdb.plannodes.SeqScanPlanNode) StmtSubqueryScan(org.voltdb.planner.parseinfo.StmtSubqueryScan) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan)

Aggregations

StmtSubqueryScan (org.voltdb.planner.parseinfo.StmtSubqueryScan)15 AbstractExpression (org.voltdb.expressions.AbstractExpression)8 StmtTableScan (org.voltdb.planner.parseinfo.StmtTableScan)6 Constraint (org.voltdb.catalog.Constraint)5 Table (org.voltdb.catalog.Table)5 SelectSubqueryExpression (org.voltdb.expressions.SelectSubqueryExpression)4 TupleValueExpression (org.voltdb.expressions.TupleValueExpression)4 AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)4 SchemaColumn (org.voltdb.plannodes.SchemaColumn)4 HashMap (java.util.HashMap)3 HashSet (java.util.HashSet)3 VoltXMLElement (org.hsqldb_voltpatches.VoltXMLElement)3 Column (org.voltdb.catalog.Column)3 StmtTargetTableScan (org.voltdb.planner.parseinfo.StmtTargetTableScan)3 ArrayList (java.util.ArrayList)2 List (java.util.List)2 Set (java.util.Set)2 ColumnRef (org.voltdb.catalog.ColumnRef)2 BranchNode (org.voltdb.planner.parseinfo.BranchNode)2 SubqueryLeafNode (org.voltdb.planner.parseinfo.SubqueryLeafNode)2