Package org.voltdb.planner.parseinfo

Examples of org.voltdb.planner.parseinfo.JoinNode


        // match the SQL order
        int tableNameIdx = 0;
        List<JoinNode> finalSubTrees = new ArrayList<JoinNode>();
        // we need to process the sub-trees last one first because the top sub-tree is the first one on the list
        for (int i = subTrees.size() - 1; i >= 0; --i) {
            JoinNode subTree = subTrees.get(i);
            // Get all tables for the subTree
            List<JoinNode> subTableNodes = subTree.generateLeafNodesJoinOrder();
            JoinNode joinOrderSubTree;
            if ((subTree instanceof BranchNode) && ((BranchNode)subTree).getJoinType() != JoinType.INNER) {
                // add the sub-tree as is
                joinOrderSubTree = subTree;
                for (JoinNode tableNode : subTableNodes) {
                    if (tableNode.getId() >= 0) {
                        String tableAlias = tableNode.getTableAlias();
                        if ( ! tableAliases.get(tableNameIdx++).equals(tableAlias)) {
                            return false;
                        }
                    }
                }
            } else {
                // Collect all the "real" tables from the sub-tree skipping the nodes representing
                // the sub-trees with the different join type (id < 0)
                Map<String, JoinNode> nodeNameMap = new HashMap<String, JoinNode>();
                for (JoinNode tableNode : subTableNodes) {
                    if (tableNode.getId() >= 0) {
                        nodeNameMap.put(tableNode.getTableAlias(), tableNode);
                    }
                }

                // rearrange the sub tree to match the order
                List<JoinNode> joinOrderSubNodes = new ArrayList<JoinNode>();
                for (int j = 0; j < subTableNodes.size(); ++j) {
                    if (subTableNodes.get(j).getId() >= 0) {
                        assert(tableNameIdx < tableAliases.size());
                        String tableAlias = tableAliases.get(tableNameIdx);
                        if (tableAlias == null || ! nodeNameMap.containsKey(tableAlias)) {
                            return false;
                        }
                        joinOrderSubNodes.add(nodeNameMap.get(tableAlias));
                        ++tableNameIdx;
                    } else {
                        // It's dummy node
                        joinOrderSubNodes.add(subTableNodes.get(j));
                    }
                }
                joinOrderSubTree = JoinNode.reconstructJoinTreeFromTableNodes(joinOrderSubNodes);
                //Collect all the join/where conditions to reassign them later
                AbstractExpression combinedWhereExpr = subTree.getAllInnerJoinFilters();
                if (combinedWhereExpr != null) {
                    joinOrderSubTree.setWhereExpression((AbstractExpression)combinedWhereExpr.clone());
                }
                // The new tree root node id must match the original one to be able to reconnect the
                // subtrees
                joinOrderSubTree.setId(subTree.getId());
            }
            finalSubTrees.add(0, joinOrderSubTree);
        }
        // if we got there the join order is OK. Rebuild the whole tree
        JoinNode newNode = JoinNode.reconstructJoinTreeFromSubTrees(finalSubTrees);
        m_joinOrderList.add(newNode);
        return true;
    }
View Full Code Here


        // The join type of the leaf node is always INNER
        // For a new tree its node's ids start with 0 and keep incrementing by 1
        int nodeId = (m_joinTree == null) ? 0 : m_joinTree.getId() + 1;

        JoinNode leafNode;
        if (tableScan instanceof StmtTargetTableScan) {
            Table table = ((StmtTargetTableScan)tableScan).getTargetTable();
            m_tableList.add(table);
            leafNode = new TableLeafNode(nodeId, joinExpr, whereExpr, (StmtTargetTableScan)tableScan);
        } else {
            leafNode = new SubqueryLeafNode(nodeId, joinExpr, whereExpr, (StmtSubqueryScan)tableScan);
        }

        if (m_joinTree == null) {
            // this is the first table
            m_joinTree = leafNode;
        } else {
            // Build the tree by attaching the next table always to the right
            // The node's join type is determined by the type of its right node

            JoinType joinType = JoinType.get(tableNode.attributes.get("jointype"));
            assert(joinType != JoinType.INVALID);
            if (joinType == JoinType.FULL) {
                throw new PlanningErrorException("VoltDB does not support full outer joins");
            }

            JoinNode joinNode = new BranchNode(nodeId + 1, joinType, m_joinTree, leafNode);
            m_joinTree = joinNode;
       }
    }
View Full Code Here

     */
    public static ArrayDeque<JoinNode> queueJoinOrders(JoinNode joinNode, boolean findAll) {
        assert(joinNode != null);

        // Clone the original
        JoinNode clonedTree = (JoinNode) joinNode.clone();
        // Split join tree into a set of subtrees. The join type for all nodes in a subtree is the same
        List<JoinNode> subTrees = clonedTree.extractSubTrees();
        assert(!subTrees.isEmpty());
        // Generate possible join orders for each sub-tree separately
        ArrayList<ArrayList<JoinNode>> joinOrderList = generateJoinOrders(subTrees);
        // Reassemble the all possible combinations of the sub-tree and queue them
        ArrayDeque<JoinNode> joinOrders = new ArrayDeque<JoinNode>();
View Full Code Here

        }

        if (joinOrderListIdx == joinOrderList.size()) {
            // End of recursion
            assert(!currentJoinOrder.isEmpty());
            JoinNode joinTree = JoinNode.reconstructJoinTreeFromSubTrees(currentJoinOrder);
            joinOrders.add(joinTree);
            return;
        }
        // Recursive step
        ArrayList<JoinNode> nextTrees = joinOrderList.get(joinOrderListIdx);
View Full Code Here

        // repeat (usually run once) until plans are created
        // 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.
            assert(m_parsedStmt.m_noTableSelectionList.size() == 0);

            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();
                m_partitioning.analyzeForMultiPartitionAccess(m_parsedStmt.m_tableAliasMap.values(),
                                                                      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.
View Full Code Here

     * 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);
        List<AbstractExpression> joinOuterList =  (parentNode.getJoinType() == 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;
        }
        outerChildNode.m_accessPaths.addAll(
                getRelevantAccessPathsForTable(outerChildNode.getTableScan(),
                        joinOuterList, parentNode.m_whereOuterList, null));
    }
View Full Code Here

     * be considered for the index access. In the latter, only inner join expressions qualifies.
     *
     * @param parentNode A parent node to the node to generate paths to.
     */
    private void generateInnerAccessPaths(BranchNode parentNode) {
        JoinNode innerChildNode = parentNode.getRightNode();
        assert(innerChildNode != null);
        // In case of inner join WHERE and JOIN expressions can be merged
        if (parentNode.getJoinType() == JoinType.INNER) {
            parentNode.m_joinInnerOuterList.addAll(parentNode.m_whereInnerOuterList);
            parentNode.m_whereInnerOuterList.clear();
            parentNode.m_joinInnerList.addAll(parentNode.m_whereInnerList);
            parentNode.m_whereInnerList.clear();
        }
        if (innerChildNode instanceof BranchNode) {
            generateOuterAccessPaths((BranchNode)innerChildNode);
            generateInnerAccessPaths((BranchNode)innerChildNode);
            // The inner node is a join node itself. Only naive access path is possible
            innerChildNode.m_accessPaths.add(
                    getRelevantNaivePath(parentNode.m_joinInnerOuterList, parentNode.m_joinInnerList));
            return;
        }

        // The inner table can have multiple index access paths based on
        // inner and inner-outer join expressions plus the naive one.
        innerChildNode.m_accessPaths.addAll(
                getRelevantAccessPathsForTable(innerChildNode.getTableScan(),
                        parentNode.m_joinInnerOuterList, parentNode.m_joinInnerList, null));

        // If there are inner expressions AND inner-outer expressions, it could be that there
        // are indexed access paths that use elements of both in the indexing expressions,
        // especially in the case of a compound index.
        // These access paths can not be considered for use with an NLJ because they rely on
        // inner-outer expressions.
        // If there is a possibility that NLIJ will not be an option due to the
        // "special case" processing that puts a send/receive plan between the join node
        // and its inner child node, other access paths need to be considered that use the
        // same indexes as those identified so far but in a simpler, less effective way
        // that does not rely on inner-outer expressions.
        // The following simplistic method of finding these access paths is to force
        // inner-outer expressions to be handled as NLJ-compatible post-filters and repeat
        // the search for access paths.
        // This will typically generate some duplicate access paths, including the naive
        // sequential scan path and any indexed paths that happened to use only the inner
        // expressions.
        // For now, we deal with this redundancy by dropping (and re-generating) all
        // access paths EXCPT those that reference the inner-outer expressions.
        // TODO: implementing access path hash and equality and possibly using a "Set"
        // would allow deduping as new access paths are added OR
        // the simplified access path search process could be based on
        // the existing indexed access paths -- for each access path that "hasInnerOuterIndexExpression"
        // try to generate and add a simpler access path using the same index,
        // this time with the inner-outer expressions used only as non-indexable post-filters.

        // Don't bother generating these redundant or inferior access paths unless there is
        // an inner-outer expression and a chance that NLIJ will be taken out of the running.
        StmtTableScan innerTable = innerChildNode.getTableScan();
        assert(innerTable != null);
        boolean mayNeedInnerSendReceive = ( ! m_partitioning.wasSpecifiedAsSingle()) &&
                (m_partitioning.getCountOfPartitionedTables() > 0) &&
                (parentNode.getJoinType() != JoinType.INNER) &&
                ! innerTable.getIsReplicated();
// too expensive/complicated to test here? (parentNode.m_leftNode has a replicated result?) &&

        if (mayNeedInnerSendReceive && ! parentNode.m_joinInnerOuterList.isEmpty()) {
            List<AccessPath> innerOuterAccessPaths = new ArrayList<AccessPath>();
            for (AccessPath innerAccessPath : innerChildNode.m_accessPaths) {
                if ((innerAccessPath.index != null) &&
                    hasInnerOuterIndexExpression(innerChildNode.getTableAlias(),
                                                 innerAccessPath.indexExprs,
                                                 innerAccessPath.initialExpr,
                                                 innerAccessPath.endExprs)) {
                    innerOuterAccessPaths.add(innerAccessPath);
                }
            }
            Collection<AccessPath> nljAccessPaths =
                    getRelevantAccessPathsForTable(innerChildNode.getTableScan(),
                                                   null,
                                                   parentNode.m_joinInnerList,
                                                   parentNode.m_joinInnerOuterList);
            innerChildNode.m_accessPaths.clear();
            innerChildNode.m_accessPaths.addAll(nljAccessPaths);
View Full Code Here

     */
    private void generateSubPlanForJoinNodeRecursively(JoinNode rootNode,
                                                       int nextNode, List<JoinNode> nodes)
    {
        assert(nodes.size() > nextNode);
        JoinNode joinNode = nodes.get(nextNode);
        if (nodes.size() == nextNode + 1) {
            for (AccessPath path : joinNode.m_accessPaths) {
                joinNode.m_currentAccessPath = path;
                AbstractPlanNode plan = getSelectSubPlanForJoinNode(rootNode);
                if (plan == null) {
View Full Code Here

        //     SELECT * FROM replicated R LEFT JOIN partitioned P1 ON ...
        //                                LEFT JOIN also_partitioned P2 ON ...
        //

        assert(joinNode.getRightNode() != null);
        JoinNode innerJoinNode = joinNode.getRightNode();
        AccessPath innerAccessPath = innerJoinNode.m_currentAccessPath;
        // We may need to add a send/receive pair to the inner plan for the special case.
        // This trick only works once per plan, BUT once the partitioned data has been
        // received on the coordinator, it can be treated as replicated data in later
        // joins, which MAY help with later outer joins with replicated data.
View Full Code Here

            // these just shouldn't happen right?
            assert(m_parsedStmt.m_noTableSelectionList.size() == 0);

            m_generatedPlans = true;
            assert (m_parsedStmt.m_joinTree != null);
            JoinNode tableNode = m_parsedStmt.m_joinTree;
            // 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) {
View Full Code Here

TOP

Related Classes of org.voltdb.planner.parseinfo.JoinNode

Copyright © 2018 www.massapicom. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.