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.
        List<AbstractExpression> filterExprs = null;
        List<AbstractExpression> postExprs = null;
        // For the FULL join type, the inner join expressions must stay at the join node and
        // not go down to the inner node as filters (as predicates for SeqScan nodes and/or
        // index expressions for Index Scan). The latter case (IndexScan) won't work for NLJ because
        // the inner join expression will effectively filter out inner tuple prior to the NLJ.
        if (parentNode.getJoinType() != JoinType.FULL) {
            filterExprs = parentNode.m_joinInnerList;
        }
        else {
            postExprs = parentNode.m_joinInnerList;
        }
        StmtTableScan innerTable = innerChildNode.getTableScan();
        assert(innerTable != null);
        innerChildNode.m_accessPaths.addAll(
                getRelevantAccessPathsForTable(innerTable,
                        parentNode.m_joinInnerOuterList, filterExprs, postExprs));

        // 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.
        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<>();
            for (AccessPath innerAccessPath : innerChildNode.m_accessPaths) {
                if ((innerAccessPath.index != null) &&
                    hasInnerOuterIndexExpression(innerChildNode.getTableAlias(),
                                                 innerAccessPath.indexExprs,
                                                 innerAccessPath.initialExpr,
                                                 innerAccessPath.endExprs)) {
                    innerOuterAccessPaths.add(innerAccessPath);
                }
            }
            if (parentNode.getJoinType() != JoinType.FULL) {
                filterExprs = parentNode.m_joinInnerList;
                postExprs = parentNode.m_joinInnerOuterList;
            }
            else {
                // For FULL join type the inner join expressions must be part of the post predicate
                // in order to stay at the join node and not be pushed down to the inner node
                filterExprs = null;
                postExprs = new ArrayList<>(parentNode.m_joinInnerList);
                postExprs.addAll(parentNode.m_joinInnerOuterList);
            }
            Collection<AccessPath>
            nljAccessPaths = getRelevantAccessPathsForTable(
                    innerTable, null, filterExprs, postExprs);

            innerChildNode.m_accessPaths.clear();
            innerChildNode.m_accessPaths.addAll(nljAccessPaths);
            innerChildNode.m_accessPaths.addAll(innerOuterAccessPaths);
        }

        assert(innerChildNode.m_accessPaths.size() > 0);
    }
private void generateInnerAccessPaths ( BranchNode parentNode ) { JoinNode innerChildNode = parentNode . getRightNode ( ) ; assert ( innerChildNode != null ) ; 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 ) ; innerChildNode . m_accessPaths . add ( getRelevantNaivePath ( parentNode . m_joinInnerOuterList , parentNode . m_joinInnerList ) ) ; return ; } List < AbstractExpression > filterExprs = null ; List < AbstractExpression > postExprs = null ; if ( parentNode . getJoinType ( ) != JoinType . FULL ) { filterExprs = parentNode . m_joinInnerList ; } else { postExprs = parentNode . m_joinInnerList ; } StmtTableScan innerTable = innerChildNode . getTableScan ( ) ; assert ( innerTable != null ) ; innerChildNode . m_accessPaths . addAll ( getRelevantAccessPathsForTable ( innerTable , parentNode . m_joinInnerOuterList , filterExprs , postExprs ) ) ; boolean mayNeedInnerSendReceive = ( ! m_partitioning . wasSpecifiedAsSingle ( ) ) && ( m_partitioning . getCountOfPartitionedTables ( ) > 0 ) && ( parentNode . getJoinType ( ) != JoinType . INNER ) && ! innerTable . getIsReplicated ( ) ; if ( mayNeedInnerSendReceive && ! parentNode . m_joinInnerOuterList . isEmpty ( ) ) { List < AccessPath > innerOuterAccessPaths = new ArrayList < > ( ) ; for ( AccessPath innerAccessPath : innerChildNode . m_accessPaths ) { if ( ( innerAccessPath . index != null ) && hasInnerOuterIndexExpression ( innerChildNode . getTableAlias ( ) , innerAccessPath . indexExprs , innerAccessPath . initialExpr , innerAccessPath . endExprs ) ) { innerOuterAccessPaths . add ( innerAccessPath ) ; } } if ( parentNode . getJoinType ( ) != JoinType . FULL ) { filterExprs = parentNode . m_joinInnerList ; postExprs = parentNode . m_joinInnerOuterList ; } else { filterExprs = null ; postExprs = new ArrayList < > ( parentNode . m_joinInnerList ) ; postExprs . addAll ( parentNode . m_joinInnerOuterList ) ; } Collection < AccessPath > nljAccessPaths = getRelevantAccessPathsForTable ( innerTable , null , filterExprs , postExprs ) ; innerChildNode . m_accessPaths . clear ( ) ; innerChildNode . m_accessPaths . addAll ( nljAccessPaths ) ; innerChildNode . m_accessPaths . addAll ( innerOuterAccessPaths ) ; } assert ( innerChildNode . m_accessPaths . size ( ) > 0 ) ; }
Generate all possible access paths for an inner node in a join.
The set of potential index expressions depends whether the inner node can be inlined
with the NLIJ or not. In the former case, inner and inner-outer join expressions can
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.