Search in sources :

Example 11 with JoinNode

use of org.voltdb.planner.parseinfo.JoinNode in project voltdb by VoltDB.

the class SelectSubPlanAssembler method queueSubJoinOrders.

private static void queueSubJoinOrders(List<List<JoinNode>> joinOrderList, int joinOrderListIdx, ArrayList<JoinNode> currentJoinOrder, ArrayDeque<JoinNode> joinOrders, boolean findAll) {
    if (!findAll && joinOrders.size() > 0) {
        // At least find one valid join order
        return;
    }
    if (joinOrderListIdx == joinOrderList.size()) {
        // End of recursion
        assert (!currentJoinOrder.isEmpty());
        JoinNode joinTree = JoinNode.reconstructJoinTreeFromSubTrees(currentJoinOrder);
        joinOrders.add(joinTree);
        return;
    }
    // Recursive step
    List<JoinNode> nextTrees = joinOrderList.get(joinOrderListIdx);
    for (JoinNode headTree : nextTrees) {
        ArrayList<JoinNode> updatedJoinOrder = new ArrayList<>();
        // Order is important: The top sub-trees must be first
        for (JoinNode node : currentJoinOrder) {
            updatedJoinOrder.add((JoinNode) node.clone());
        }
        updatedJoinOrder.add((JoinNode) headTree.clone());
        queueSubJoinOrders(joinOrderList, joinOrderListIdx + 1, updatedJoinOrder, joinOrders, findAll);
    }
}
Also used : JoinNode(org.voltdb.planner.parseinfo.JoinNode) ArrayList(java.util.ArrayList)

Example 12 with JoinNode

use of org.voltdb.planner.parseinfo.JoinNode in project voltdb by VoltDB.

the class SelectSubPlanAssembler method generateFullJoinOrdersForTree.

/**
     * Helper method to generate join orders for a join tree containing only FULL joins.
     * The only allowed permutation is a join order that has original left and right nodes
     * swapped.
     *
     * @param subTree  join tree
     * @return list of valid join orders
     */
private static List<JoinNode> generateFullJoinOrdersForTree(JoinNode subTree) {
    assert (subTree != null);
    List<JoinNode> joinOrders = new ArrayList<>();
    if (!(subTree instanceof BranchNode)) {
        // End of recursion
        joinOrders.add(subTree);
        return joinOrders;
    }
    BranchNode branchNode = (BranchNode) subTree;
    // Descend to the left branch
    assert (branchNode.getLeftNode() != null);
    List<JoinNode> leftJoinOrders = generateFullJoinOrdersForTree(branchNode.getLeftNode());
    assert (!leftJoinOrders.isEmpty());
    // Descend to the right branch
    assert (branchNode.getRightNode() != null);
    List<JoinNode> rightJoinOrders = generateFullJoinOrdersForTree(branchNode.getRightNode());
    assert (!rightJoinOrders.isEmpty());
    // Create permutation pairing left and right nodes and the revere variant
    for (JoinNode leftNode : leftJoinOrders) {
        for (JoinNode rightNode : rightJoinOrders) {
            JoinNode resultOne = new BranchNode(branchNode.getId(), branchNode.getJoinType(), (JoinNode) leftNode.clone(), (JoinNode) rightNode.clone());
            JoinNode resultTwo = new BranchNode(branchNode.getId(), branchNode.getJoinType(), (JoinNode) rightNode.clone(), (JoinNode) leftNode.clone());
            if (branchNode.getJoinExpression() != null) {
                resultOne.setJoinExpression(branchNode.getJoinExpression().clone());
                resultTwo.setJoinExpression(branchNode.getJoinExpression().clone());
            }
            if (branchNode.getWhereExpression() != null) {
                resultOne.setWhereExpression(branchNode.getWhereExpression().clone());
                resultTwo.setWhereExpression(branchNode.getWhereExpression().clone());
            }
            joinOrders.add(resultOne);
            joinOrders.add(resultTwo);
        }
    }
    return joinOrders;
}
Also used : BranchNode(org.voltdb.planner.parseinfo.BranchNode) JoinNode(org.voltdb.planner.parseinfo.JoinNode) ArrayList(java.util.ArrayList)

Example 13 with JoinNode

use of org.voltdb.planner.parseinfo.JoinNode in project voltdb by VoltDB.

the class SelectSubPlanAssembler 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
protected AbstractPlanNode nextPlan() {
    // or no more plans can be created
    while (m_plans.size() == 0) {
        // get the join order for us to make plans out of
        JoinNode joinTree = m_joinOrders.poll();
        // no more join orders => no more plans to generate
        if (joinTree == null) {
            return null;
        }
        // Analyze join and filter conditions
        joinTree.analyzeJoinExpressions(m_parsedStmt.m_noTableSelectionList);
        // a query that is a little too quirky or complicated.
        if (!m_parsedStmt.m_noTableSelectionList.isEmpty()) {
            throw new PlanningErrorException("Join with filters that do not depend on joined tables is not supported in VoltDB");
        }
        if (!m_partitioning.wasSpecifiedAsSingle()) {
            // Now that analyzeJoinExpressions has done its job of properly categorizing
            // and placing the various filters that the HSQL parser tends to leave in the strangest
            // configuration, this is the first opportunity to analyze WHERE and JOIN filters'
            // effects on statement partitioning.
            // But this causes the analysis to be run based on a particular join order.
            // Which join orders does this analysis actually need to be run on?
            // Can it be run on the first join order and be assumed to hold for all join orders?
            // If there is a join order that fails to generate a single viable plan, is its
            // determination of partitioning (or partitioning failure) always valid for other
            // join orders, or should the analysis be repeated on a viable join order
            // in that case?
            // For now, analyze each join order independently and when an invalid partitioning is
            // detected, skip the plan generation for that particular ordering.
            // If this causes all plans to be skipped, commonly the case, the PlanAssembler
            // should propagate an error message identifying partitioning as the problem.
            HashMap<AbstractExpression, Set<AbstractExpression>> valueEquivalence = joinTree.getAllEquivalenceFilters();
            Collection<StmtTableScan> scans = m_parsedStmt.allScans();
            m_partitioning.analyzeForMultiPartitionAccess(scans, valueEquivalence);
            if (!m_partitioning.isJoinValid()) {
                // The case of more than one independent partitioned table
                // would result in an illegal plan with more than two fragments.
                // Don't throw a planning error here, in case the problem is just with this
                // particular join order, but do leave a hint to the PlanAssembler in case
                // the failure is unanimous -- a common case.
                m_recentErrorMsg = m_partitioning.getJoinInvalidReason();
                // This join order, at least, is not worth trying to plan.
                continue;
            }
        }
        generateMorePlansForJoinTree(joinTree);
    }
    return m_plans.poll();
}
Also used : HashSet(java.util.HashSet) Set(java.util.Set) AbstractExpression(org.voltdb.expressions.AbstractExpression) JoinNode(org.voltdb.planner.parseinfo.JoinNode) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan)

Example 14 with JoinNode

use of org.voltdb.planner.parseinfo.JoinNode in project voltdb by VoltDB.

the class SelectSubPlanAssembler method generateOuterAccessPaths.

/**
     * Generate all possible access paths for an outer node in a join.
     * The outer table and/or join can have the naive access path and possible index path(s)
     * Optimizations - outer-table-only where expressions can be pushed down to the child node
     * to pre-qualify the outer tuples before they enter the join.
     * For inner joins outer-table-only join expressions can be pushed down as well
     *
     * @param parentNode A parent node to the node to generate paths to.
     */
private void generateOuterAccessPaths(BranchNode parentNode) {
    JoinNode outerChildNode = parentNode.getLeftNode();
    assert (outerChildNode != null);
    JoinType joinType = parentNode.getJoinType();
    // For LEFT and FULL join types, the outer join expressions are kept as a pre-join predicate
    // at the join node to pre-qualify the outer rows
    List<AbstractExpression> joinOuterList = (joinType == JoinType.INNER) ? parentNode.m_joinOuterList : null;
    if (outerChildNode instanceof BranchNode) {
        generateOuterAccessPaths((BranchNode) outerChildNode);
        generateInnerAccessPaths((BranchNode) outerChildNode);
        // The join node can have only sequential scan access
        outerChildNode.m_accessPaths.add(getRelevantNaivePath(joinOuterList, parentNode.m_whereOuterList));
        assert (outerChildNode.m_accessPaths.size() > 0);
        return;
    }
    // WHERE Outer expressions must stay at the join node for the FULL joins
    // They will be added later as part of the WHERE predicate of the join node
    List<AbstractExpression> parentWhereList = null;
    if (joinType != JoinType.FULL) {
        parentWhereList = parentNode.m_whereOuterList;
    }
    outerChildNode.m_accessPaths.addAll(getRelevantAccessPathsForTable(outerChildNode.getTableScan(), joinOuterList, parentWhereList, null));
}
Also used : BranchNode(org.voltdb.planner.parseinfo.BranchNode) AbstractExpression(org.voltdb.expressions.AbstractExpression) JoinNode(org.voltdb.planner.parseinfo.JoinNode) JoinType(org.voltdb.types.JoinType)

Aggregations

JoinNode (org.voltdb.planner.parseinfo.JoinNode)14 ArrayList (java.util.ArrayList)9 AbstractExpression (org.voltdb.expressions.AbstractExpression)9 BranchNode (org.voltdb.planner.parseinfo.BranchNode)7 StmtTableScan (org.voltdb.planner.parseinfo.StmtTableScan)3 List (java.util.List)2 AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)2 JoinType (org.voltdb.types.JoinType)2 ArrayDeque (java.util.ArrayDeque)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Set (java.util.Set)1 VoltXMLElement (org.hsqldb_voltpatches.VoltXMLElement)1 Constraint (org.voltdb.catalog.Constraint)1 Table (org.voltdb.catalog.Table)1 TupleValueExpression (org.voltdb.expressions.TupleValueExpression)1 StmtSubqueryScan (org.voltdb.planner.parseinfo.StmtSubqueryScan)1 StmtTargetTableScan (org.voltdb.planner.parseinfo.StmtTargetTableScan)1 SubqueryLeafNode (org.voltdb.planner.parseinfo.SubqueryLeafNode)1 TableLeafNode (org.voltdb.planner.parseinfo.TableLeafNode)1