Package org.modeshape.jcr.query.plan

Examples of org.modeshape.jcr.query.plan.PlanNode


    public PlanNode execute( QueryContext context,
                             PlanNode plan,
                             LinkedList<OptimizerRule> ruleStack ) {
        for (PlanNode depQuery : plan.findAllAtOrBelow(Traversal.PRE_ORDER, Type.DEPENDENT_QUERY)) {
            // Check the left ...
            PlanNode left = depQuery.getFirstChild();
            raiseVariableName(left);

            // Check the right ...
            PlanNode right = depQuery.getLastChild();
            raiseVariableName(right);
        }
        return plan;
    }
View Full Code Here


        int numJoins = 0;
        for (PlanNode joinNode : plan.findAllAtOrBelow(Type.JOIN)) {
            ++numJoins;
            JoinCondition condition = joinNode.getProperty(Property.JOIN_CONDITION, JoinCondition.class);
            if (condition instanceof EquiJoinCondition) {
                PlanNode leftNode = joinNode.getFirstChild().findAtOrBelow(Type.SOURCE);
                PlanNode rightNode = joinNode.getLastChild().findAtOrBelow(Type.SOURCE);
                assert leftNode != null;
                assert rightNode != null;
                EquiJoinCondition equiJoin = (EquiJoinCondition)condition;
                // Find the names (or aliases) of the tables ...
                Schemata schemata = context.getSchemata();
                assert schemata != null;
                SelectorName leftTableName = leftNode.getProperty(Property.SOURCE_NAME, SelectorName.class);
                SelectorName rightTableName = rightNode.getProperty(Property.SOURCE_NAME, SelectorName.class);
                assert leftTableName != null;
                assert rightTableName != null;
                // Presumably the join condition is using at least one alias, but we only care about the actual name ...
                if (!leftTableName.equals(rightTableName)) {
                    // The join is not joining the same table, so this doesn't meet the condition ...
View Full Code Here

                         context.getWorkspaceNames(), repositoryName, query, context.id());
        }

        // Create the canonical plan ...
        long start = System.nanoTime();
        PlanNode plan = planner.createPlan(context, query);
        long duration = Math.abs(System.nanoTime() - start);
        Statistics stats = new Statistics(duration);
        final String workspaceName = context.getWorkspaceNames().iterator().next();

        if (trace) {
            LOGGER.trace("Computed canonical query plan for query {0}: {1}", context.id(), plan);
        }

        checkCancelled(context);
        Columns resultColumns = null;
        if (!context.getProblems().hasErrors()) {
            // Optimize the plan ...
            start = System.nanoTime();
            PlanNode optimizedPlan = optimizer.optimize(context, plan);
            duration = Math.abs(System.nanoTime() - start);
            stats = stats.withOptimizationTime(duration);

            if (trace) {
                LOGGER.trace("Computed optimized query plan for query {0}:\n{1}", context.id(), optimizedPlan);
            }

            // Find the query result columns ...
            start = System.nanoTime();

            // Determine the Columns object for specific nodes in the plan, and store them in the context ...
            optimizedPlan.apply(Traversal.POST_ORDER, new PlanNode.Operation() {

                @Override
                public void apply( PlanNode node ) {
                    Columns columns = null;
                    switch (node.getType()) {
View Full Code Here

    protected void rewriteJoinNode( QueryContext context,
                                    PlanNode joinNode,
                                    Map<SelectorName, SelectorName> rewrittenSelectors ) {
        // Remove the right source node from the join node ...
        PlanNode rightChild = joinNode.getLastChild();
        rightChild.removeFromParent();
        PlanNode rightSource = rightChild.findAtOrBelow(Type.SOURCE);

        // Replace the join node with the left source node ...
        PlanNode leftChild = joinNode.getFirstChild();
        joinNode.extractFromParent();
        PlanNode leftSource = leftChild.findAtOrBelow(Type.SOURCE);

        // Combine the right PROJECT node with that on the left ...
        PlanNode rightProject = rightChild.findAtOrBelow(Type.PROJECT);
        if (rightProject != null) {
            PlanNode leftProject = leftChild.findAtOrBelow(Type.PROJECT);
            if (leftProject != null) {
                List<Column> leftColumns = leftProject.getPropertyAsList(Property.PROJECT_COLUMNS, Column.class);
                for (Column rightColumn : rightProject.getPropertyAsList(Property.PROJECT_COLUMNS, Column.class)) {
                    for (SelectorName leftSelector : leftProject.getSelectors()) {
                        rightColumn = rightColumn.with(leftSelector);
                        break;
                    }
                    if (!leftColumns.contains(rightColumn)) leftColumns.add(rightColumn);
                }
            } else {
                // Just create a project on the left side ...
                leftProject = new PlanNode(Type.PROJECT);
                leftProject.setProperty(Property.PROJECT_COLUMNS, rightProject.getProperty(Property.PROJECT_COLUMNS));
                leftChild.getFirstChild().insertAsParent(leftProject);
            }
        }

        // Now record that references to the right selector name should be removed ...
        SelectorName rightTableName = rightSource.getProperty(Property.SOURCE_NAME, SelectorName.class);
        SelectorName rightTableAlias = rightSource.getProperty(Property.SOURCE_ALIAS, SelectorName.class);
        SelectorName leftTableAlias = leftSource.getProperty(Property.SOURCE_ALIAS, SelectorName.class);
        if (leftTableAlias != null) {
            if (rightTableName != null) rewrittenSelectors.put(rightTableName, leftTableAlias);
            if (rightTableAlias != null) rewrittenSelectors.put(rightTableAlias, leftTableAlias);
        } else {
            SelectorName leftTableName = leftSource.getProperty(Property.SOURCE_NAME, SelectorName.class);
            assert leftTableName != null;
            if (rightTableName != null) rewrittenSelectors.put(rightTableName, leftTableName);
            if (rightTableAlias != null) rewrittenSelectors.put(rightTableAlias, leftTableName);
        }

        // Accumulate any SELECT nodes from the right side and add to the left ...
        PlanNode topRightSelect = rightChild.findAtOrBelow(Type.SELECT);
        if (topRightSelect != null) {
            PlanNode bottomRightSelect = topRightSelect;
            replaceInSelectNodeReferencesToRemovedSource(context, topRightSelect, rewrittenSelectors);
            while (true) {
                if (bottomRightSelect.getFirstChild().isNot(Type.SELECT)) break;
                bottomRightSelect = bottomRightSelect.getFirstChild();
                replaceInSelectNodeReferencesToRemovedSource(context, bottomRightSelect, rewrittenSelectors);
            }
            topRightSelect.setParent(null);
            bottomRightSelect.removeAllChildren();

            // Place just above the left source ...
            leftSource.getParent().addLastChild(topRightSelect);
            leftSource.setParent(bottomRightSelect);
        }
View Full Code Here

    protected Columns determineProjectedColumns( PlanNode optimizedPlan,
                                                 final ScanQueryContext context ) {
        final PlanHints hints = context.getHints();

        // Look for which columns to include in the results; this will be defined by the highest PROJECT node ...
        PlanNode project = optimizedPlan;
        if (project.getType() != Type.PROJECT) {
            project = optimizedPlan.findAtOrBelow(Traversal.LEVEL_ORDER, Type.PROJECT);
        }
        if (project != null) {
            List<Column> columns = project.getPropertyAsList(Property.PROJECT_COLUMNS, Column.class);
            List<String> columnTypes = project.getPropertyAsList(Property.PROJECT_COLUMN_TYPES, String.class);
            // Determine whether to include the full-text search scores in the results ...
            boolean includeFullTextSearchScores = hints.hasFullTextSearch;
            if (!includeFullTextSearchScores) {
                for (PlanNode select : optimizedPlan.findAllAtOrBelow(Type.SELECT)) {
                    Constraint constraint = select.getProperty(Property.SELECT_CRITERIA, Constraint.class);
                    if (QueryUtil.includeFullTextScores(constraint)) {
                        includeFullTextSearchScores = true;
                        break;
                    }
                }
            }
            // The projected columns may not include all of the selectors from the child of the PROJECT node.
            // So, we need to figure out the selector indexes based upon the ResultColumn for the child ...
            Columns childColumns = context.columnsFor(project.getFirstChild());
            return new ResultColumns(columns, columnTypes, includeFullTextSearchScores, childColumns);
        }
        // Look for a SOURCE ...
        if (optimizedPlan.getType() == Type.SOURCE) {
            PlanNode source = optimizedPlan;
            List<Schemata.Column> schemataColumns = source.getPropertyAsList(Property.SOURCE_COLUMNS, Schemata.Column.class);
            List<Column> columns = new ArrayList<>(schemataColumns.size());
            List<String> columnTypes = new ArrayList<>(schemataColumns.size());
            SelectorName selector = source.getSelectors().iterator().next();
            for (Schemata.Column schemataColumn : schemataColumns) {
                Column column = new Column(selector, schemataColumn.getName(), schemataColumn.getName());
                columns.add(column);
                columnTypes.add(schemataColumn.getPropertyTypeName());
            }
View Full Code Here

        NodeSequence rows = null;
        final String workspaceName = context.getWorkspaceNames().iterator().next();
        try {

            // Find the topmost PROJECT node and build the Columns ...
            PlanNode project = plan.findAtOrBelow(Type.PROJECT);
            assert project != null;
            columns = context.columnsFor(plan);
            assert columns != null;

            boolean trace = LOGGER.isTraceEnabled();
View Full Code Here

                }
                break;
            case DEPENDENT_QUERY:
                assert plan.getChildCount() == 2;
                // Create the independent query from the left ...
                PlanNode indepPlan = plan.getFirstChild();
                Columns indepColumns = context.columnsFor(indepPlan);
                String variableName = indepPlan.getProperty(Property.VARIABLE_NAME, String.class);
                NodeSequence independent = createNodeSequence(originalQuery, context, indepPlan, indepColumns, sources);

                // Create an extractor to get the value specified in the columns ...
                Column column = indepColumns.getColumns().get(0);
                boolean allowMultiValued = false;
                String typeName = indepColumns.getColumnTypeForProperty(column.getSelectorName(), column.getPropertyName());
                TypeFactory<?> type = context.getTypeSystem().getTypeFactory(typeName);
                ExtractFromRow indepExtractor = createExtractFromRow(column.getSelectorName(), column.getPropertyName(), context,
                                                                     indepColumns, sources, type, allowMultiValued);
                // Create the sequence for the dependent query ...
                PlanNode depPlan = plan.getLastChild();
                Columns depColumns = context.columnsFor(depPlan);
                NodeSequence dependent = createNodeSequence(originalQuery, context, depPlan, depColumns, sources);

                // now create the dependent query ...
                rows = new DependentQuery(independent, indepExtractor, type, dependent, variableName, context.getVariables());
                break;
            case DUP_REMOVE:
                assert plan.getChildCount() == 1;
                if (plan.getFirstChild().getType() == Type.SORT) {
                    // There is a SORT below this DUP_REMOVE, and we can do that in one fell swoop with the sort ...
                    rows = createNodeSequence(originalQuery, context, plan.getFirstChild(), columns, sources);
                } else {
                    // Create the sequence for the plan node under the DUP_REMOVE ...
                    rows = createNodeSequence(originalQuery, context, plan.getFirstChild(), columns, sources);
                    if (!rows.isEmpty() && !(rows instanceof DistinctSequence)) {
                        // Wrap that with a sequence that removes duplicates ...
                        boolean useHeap = false;
                        rows = new DistinctSequence(rows, context.getTypeSystem(), context.getBufferManager(), useHeap);
                    }
                }
                break;
            case GROUP:
                throw new UnsupportedOperationException();
            case JOIN:
                // Create the components under the JOIN ...
                assert plan.getChildCount() == 2;
                PlanNode leftPlan = plan.getFirstChild();
                PlanNode rightPlan = plan.getLastChild();

                // Define the columns for each side, taken from the supplied columns ...
                Columns leftColumns = context.columnsFor(leftPlan);
                Columns rightColumns = context.columnsFor(rightPlan);

                // Query context for the join (must remove isExists condition).
                ScanQueryContext joinQueryContext = context;
                if (context.getHints().isExistsQuery) {
                    // must not push down a LIMIT 1 condition to joins.
                    PlanHints joinPlanHints = context.getHints().clone();
                    joinPlanHints.isExistsQuery = false;
                    joinQueryContext = context.with(joinPlanHints);
                }

                NodeSequence left = createNodeSequence(originalQuery, joinQueryContext, leftPlan, leftColumns, sources);
                NodeSequence right = createNodeSequence(originalQuery, joinQueryContext, rightPlan, rightColumns, sources);

                // Figure out the join algorithm ...
                JoinAlgorithm algorithm = plan.getProperty(Property.JOIN_ALGORITHM, JoinAlgorithm.class);
                JoinType joinType = plan.getProperty(Property.JOIN_TYPE, JoinType.class);
                JoinCondition joinCondition = plan.getProperty(Property.JOIN_CONDITION, JoinCondition.class);
                boolean pack = false;
                boolean useHeap = false;
                if (0 >= right.getRowCount() && right.getRowCount() < 100) useHeap = true;
                ExtractFromRow leftExtractor = null;
                ExtractFromRow rightExtractor = null;
                RangeProducer<?> rangeProducer = null;
                switch (algorithm) {
                    case NESTED_LOOP:
                        // rows = new NestedLoopJoinComponent(context, left, right, joinCondition, joinType);
                        // break;
                    case MERGE:
                        if (joinCondition instanceof SameNodeJoinCondition) {
                            SameNodeJoinCondition condition = (SameNodeJoinCondition)joinCondition;
                            // check if the JOIN was not reversed by an optimization
                            boolean joinReversed = !leftColumns.getSelectorNames().contains(condition.getSelector1Name());
                            int leftIndex;
                            int rightIndex;
                            if (joinReversed) {
                                // figure out the row indexes for the different selectors ...
                                leftIndex = leftColumns.getSelectorIndex(condition.getSelector2Name());
                                rightIndex = rightColumns.getSelectorIndex(condition.getSelector1Name());
                            } else {
                                leftIndex = leftColumns.getSelectorIndex(condition.getSelector1Name());
                                rightIndex = rightColumns.getSelectorIndex(condition.getSelector2Name());
                            }
                            String relativePath = condition.getSelector2Path();
                            if (relativePath != null) {
                                // Get extractors that will get the path of the nodes ...
                                PathFactory pathFactory = context.getExecutionContext().getValueFactories().getPathFactory();
                                Path relPath = pathFactory.create(relativePath);
                                if (joinReversed) {
                                    leftExtractor = RowExtractors.extractRelativePath(leftIndex, relPath, cache, types);
                                    rightExtractor = RowExtractors.extractPath(rightIndex, cache, types);
                                } else {
                                    leftExtractor = RowExtractors.extractPath(leftIndex, cache, types);
                                    rightExtractor = RowExtractors.extractRelativePath(rightIndex, relPath, cache, types);
                                }
                            } else {
                                // The nodes must be the same node ...
                                leftExtractor = RowExtractors.extractNodeKey(leftIndex, cache, types);
                                rightExtractor = RowExtractors.extractNodeKey(rightIndex, cache, types);
                            }
                        } else if (joinCondition instanceof ChildNodeJoinCondition) {
                            ChildNodeJoinCondition condition = (ChildNodeJoinCondition)joinCondition;
                            assert leftColumns.getSelectorNames().contains(condition.getParentSelectorName());
                            int leftIndex = leftColumns.getSelectorIndex(condition.getParentSelectorName());
                            int rightIndex = rightColumns.getSelectorIndex(condition.getChildSelectorName());
                            leftExtractor = RowExtractors.extractNodeKey(leftIndex, cache, types);
                            rightExtractor = RowExtractors.extractParentNodeKey(rightIndex, cache, types);
                        } else if (joinCondition instanceof EquiJoinCondition) {
                            EquiJoinCondition condition = (EquiJoinCondition)joinCondition;
                            // check if the JOIN was not reversed by an optimization
                            boolean joinReversed = !leftColumns.getSelectorNames().contains(condition.getSelector1Name());

                            String sel1 = condition.getSelector1Name();
                            String sel2 = condition.getSelector2Name();
                            String prop1 = condition.getProperty1Name();
                            String prop2 = condition.getProperty2Name();
                            if (joinReversed) {
                                leftExtractor = createExtractFromRow(sel2, prop2, joinQueryContext, leftColumns, sources, null,
                                                                     true);
                                rightExtractor = createExtractFromRow(sel1, prop1, joinQueryContext, rightColumns, sources, null,
                                                                      true);
                            } else {
                                leftExtractor = createExtractFromRow(sel1, prop1, joinQueryContext, leftColumns, sources, null,
                                                                     true);
                                rightExtractor = createExtractFromRow(sel2, prop2, joinQueryContext, rightColumns, sources, null,
                                                                      true);
                            }

                        } else if (joinCondition instanceof DescendantNodeJoinCondition) {
                            DescendantNodeJoinCondition condition = (DescendantNodeJoinCondition)joinCondition;
                            // For this to work, we want the ancestors to be on the left, so that the descendants can quickly
                            // be found given a path of each ancestor ...
                            assert leftColumns.getSelectorNames().contains(condition.getAncestorSelectorName());
                            String ancestorSelector = condition.getAncestorSelectorName();
                            String descendantSelector = condition.getDescendantSelectorName();
                            int ancestorSelectorIndex = leftColumns.getSelectorIndex(ancestorSelector);
                            int descendantSelectorIndex = rightColumns.getSelectorIndex(descendantSelector);
                            leftExtractor = RowExtractors.extractPath(ancestorSelectorIndex, cache, types);
                            rightExtractor = RowExtractors.extractPath(descendantSelectorIndex, cache, types);
                            // This is the only time we need a RangeProducer ...
                            final PathFactory paths = context.getExecutionContext().getValueFactories().getPathFactory();
                            rangeProducer = new RangeProducer<Path>() {
                                @Override
                                public Range<Path> getRange( Path leftPath ) {
                                    if (leftPath.isRoot()) {
                                        // All paths are descendants of the root
                                        return new Range<>(leftPath, false, null, true);
                                    }
                                    // Given the path of the node on the left side of the join, find the range of all paths
                                    // that might be considered descendants of the left path....
                                    boolean includeLower = false; // we don't want to include the left node; only descendants
                                    // The upper bound path is the same as the left path, just with an incremented SNS ...
                                    Path.Segment lastSegment = leftPath.getLastSegment();
                                    Path.Segment upperSegment = paths.createSegment(lastSegment.getName(),
                                                                                    lastSegment.getIndex() + 1);
                                    Path upperBoundPath = paths.create(leftPath.getParent(), upperSegment);
                                    return new Range<>(leftPath, includeLower, upperBoundPath, false);
                                }
                            };
                        } else {
                            assert false : "Unable to use merge algorithm with join conditions: " + joinCondition;
                            throw new UnsupportedOperationException();
                        }
                        break;
                }

                // Perform conversion if required ...
                assert leftExtractor != null;
                assert rightExtractor != null;
                TypeFactory<?> leftType = leftExtractor.getType();
                TypeFactory<?> rightType = rightExtractor.getType();
                if (!leftType.equals(rightType)) {
                    // wrap the right extractor with a converting extractor ...
                    final TypeFactory<?> commonType = context.getTypeSystem().getCompatibleType(leftType, rightType);
                    if (!leftType.equals(commonType)) leftExtractor = RowExtractors.convert(leftExtractor, commonType);
                    if (!rightType.equals(commonType)) rightExtractor = RowExtractors.convert(rightExtractor, commonType);
                }

                rows = new HashJoinSequence(workspaceName, left, right, leftExtractor, rightExtractor, joinType,
                                            context.getBufferManager(), cache, rangeProducer, pack, useHeap);
                // For each Constraint object applied to the JOIN, simply create a SelectComponent on top ...
                RowFilter filter = null;
                List<Constraint> constraints = plan.getPropertyAsList(Property.JOIN_CONSTRAINTS, Constraint.class);
                if (constraints != null) {
                    for (Constraint constraint : constraints) {
                        RowFilter constraintFilter = createRowFilter(constraint, context, columns, sources);
                        filter = NodeSequence.requireBoth(filter, constraintFilter);
                    }
                }
                rows = NodeSequence.filter(rows, filter); // even if filter is null
                break;
            case LIMIT:
                // Create the sequence for the plan node under the LIMIT ...
                assert plan.getChildCount() == 1;
                rows = createNodeSequence(originalQuery, context, plan.getFirstChild(), columns, sources);
                // Calculate the limit ...
                Integer rowLimit = plan.getProperty(Property.LIMIT_COUNT, Integer.class);
                Integer offset = plan.getProperty(Property.LIMIT_OFFSET, Integer.class);
                Limit limit = Limit.NONE;
                if (rowLimit != null) limit = limit.withRowLimit(rowLimit.intValue());
                if (offset != null) limit = limit.withOffset(offset.intValue());
                // Then create the limited sequence ...
                if (!limit.isUnlimited()) {
                    rows = NodeSequence.limit(rows, limit);
                }
                break;
            case NULL:
                // No results ...
                rows = NodeSequence.emptySequence(columns.getColumns().size());
                break;
            case PROJECT:
                // Nothing to do, since the projected columns will be accessed as needed when the results are processed. Instead,
                // just process the PROJECT node's only child ...
                PlanNode child = plan.getFirstChild();
                columns = context.columnsFor(child);
                rows = createNodeSequence(originalQuery, context, child, columns, sources);
                break;
            case SELECT:
                // Create the sequence for the plan node under the SELECT ...
                assert plan.getChildCount() == 1;
                rows = createNodeSequence(originalQuery, context, plan.getFirstChild(), columns, sources);
                Constraint constraint = plan.getProperty(Property.SELECT_CRITERIA, Constraint.class);
                filter = createRowFilter(constraint, context, columns, sources);
                rows = NodeSequence.filter(rows, filter);
                break;
            case SET_OPERATION:
                Operation operation = plan.getProperty(Property.SET_OPERATION, Operation.class);
                boolean all = plan.getProperty(Property.SET_USE_ALL, Boolean.class);
                PlanNode firstPlan = plan.getFirstChild();
                PlanNode secondPlan = plan.getLastChild();
                Columns firstColumns = context.columnsFor(firstPlan);
                Columns secondColumns = context.columnsFor(secondPlan);
                NodeSequence first = createNodeSequence(originalQuery, context, firstPlan, firstColumns, sources);
                NodeSequence second = createNodeSequence(originalQuery, context, secondPlan, secondColumns, sources);
                useHeap = 0 >= second.getRowCount() && second.getRowCount() < 100;
                if (first.width() != second.width()) {
                    // A set operation requires that the 'first' and 'second' sequences have the same width, but this is
                    // not necessarily the case (e.g., when one side involves a JOIN but the other does not). The columns
                    // will dictate which subset of selector indexes in the sequences should be used.
                    first = NodeSequence.slice(first, firstColumns);
                    second = NodeSequence.slice(second, secondColumns);
                    assert first.width() == second.width();
                }
                pack = false;
                switch (operation) {
                    case UNION: {
                        // If one of them is empty, return the other ...
                        if (first.isEmpty()) return second;
                        if (second.isEmpty()) return first;
                        // This is really just a sequence with the two parts ...
                        rows = NodeSequence.append(first, second);
                        break;
                    }
                    case INTERSECT: {
                        // If one of them is empty, there are no results ...
                        if (first.isEmpty()) return first;
                        if (second.isEmpty()) return second;
                        rows = new IntersectSequence(workspaceName, first, second, types, bufferManager, cache, pack, useHeap);
                        break;
                    }
                    case EXCEPT: {
                        // If the second is empty, there's nothing to exclude ...
                        if (second.isEmpty()) return first;
                        rows = new ExceptSequence(workspaceName, first, second, types, bufferManager, cache, pack, useHeap);
                        break;
                    }
                }
                if (!all) {
                    useHeap = false;
                    rows = new DistinctSequence(rows, context.getTypeSystem(), context.getBufferManager(), useHeap);
                }
                break;
            case SORT:
                assert plan.getChildCount() == 1;
                PlanNode delegate = plan.getFirstChild();
                boolean allowDuplicates = true;
                if (delegate.getType() == Type.DUP_REMOVE) {
                    // This SORT already removes duplicates, so we can skip the first child ...
                    delegate = delegate.getFirstChild();
                    allowDuplicates = false;
                }
                PlanNode parent = plan.getParent();
                if (parent != null && parent.getType() == Type.DUP_REMOVE) {
                    // The parent is a DUP_REMOVE (shouldn't really happen in an optimized plan), we should disallow duplicates
                    // ...
                    allowDuplicates = false;
                }
                // Create the sequence for the delegate plan node ...
View Full Code Here

                             LinkedList<OptimizerRule> ruleStack ) {
        for (PlanNode distinct : plan.findAllAtOrBelow(Traversal.PRE_ORDER, Type.DUP_REMOVE)) {
            // If there is a SORT below the DUP_REMOVE, then swap them...
            if (distinct.getFirstChild().getType() == Type.SORT) {
                // Swap them so that duplicate removal happens first (it's lower in the plan) ...
                PlanNode parent = distinct.getParent();
                PlanNode sort = distinct.getFirstChild();
                assert sort.getParent() == distinct;
                // First, remove SORT from DUP_REMOVE (which will be empty) ...
                sort.removeFromParent();
                assert sort.getParent() == null;
                // Move all children of SORT into the currently-empty DUP_REMOVE ...
                distinct.addChildren(sort.getChildren());
                assert sort.getChildCount() == 0;
                assert sort.getParent() == null;
                // Swap DUP_REMOVE in parent with SORT
                parent.replaceChild(distinct, sort);
                assert sort.getParent() == parent;
                assert sort.getChildCount() == 0;
                assert distinct.getParent() == null;
                // Now move DUP_REMOVE under SORT ...
                distinct.setParent(sort);
                assert distinct.getParent() == sort;
                assert sort.getParent() == parent;
            }
        }
        return plan;
    }
View Full Code Here

                SelectorName tableName = sourceNode.getProperty(Property.SOURCE_NAME, SelectorName.class);
                SelectorName tableAlias = sourceNode.getProperty(Property.SOURCE_ALIAS, SelectorName.class);
                Table table = schemata.getTable(tableName);
                if (table instanceof View) {
                    View view = (View)table;
                    PlanNode viewPlan = planner.createPlan(context, view.getDefinition());
                    if (viewPlan == null) continue; // there were likely errors when creating the plan

                    // If the view doesn't have an alias, or if the view's alias doesn't match the table's name/alias ...
                    PlanNode viewProjectNode = viewPlan.findAtOrBelow(Type.PROJECT);
                    if (viewProjectNode.getSelectors().size() == 1) {
                        SelectorName tableAliasOrName = tableAlias != null ? tableAlias : tableName;
                        SelectorName viewAlias = viewProjectNode.getSelectors().iterator().next();
                        // Replace the view's alias ...
                        Map<SelectorName, SelectorName> replacements = Collections.singletonMap(viewAlias, tableAliasOrName);
                        PlanUtil.replaceReferencesToRemovedSource(context, viewPlan, replacements);

                        if (!context.getHints().validateColumnExistance) {
                            // Find the next highest PROJECT node above the source ...
                            PlanNode project = sourceNode.findAncestor(Type.PROJECT);
                            if (project != null) {
                                List<Column> projectedColumns = project.getPropertyAsList(Property.PROJECT_COLUMNS, Column.class);
                                // There may be columns that don't appear in the source, so make sure they are there ...
                                viewPlan = PlanUtil.addMissingProjectColumns(context, viewProjectNode, projectedColumns);
                                assert viewPlan != null;
                            }
                        }
                    }

                    // Insert the view plan under the parent SOURCE node ...
                    sourceNode.addLastChild(viewPlan);

                    // Remove the source node ...
                    sourceNode.extractFromParent();

                    // // Replace the original view's name with the name/alias ...
                    PlanNode parent = viewPlan.getParent();
                    if (parent != null) {
                        PlanUtil.ColumnMapping aliasMappings = null;
                        if (tableAlias != null) {
                            aliasMappings = PlanUtil.createMappingForAliased(tableAlias, view, viewPlan);
                            PlanUtil.replaceViewReferences(context, parent, aliasMappings);
                        }
                        PlanUtil.ColumnMapping viewMappings = PlanUtil.createMappingFor(view, viewPlan);
                        PlanUtil.replaceViewReferences(context, parent, viewMappings);
                    }

                    if (viewPlan.is(Type.PROJECT)) {
                        // The PROJECT from the plan may actually not be needed if there is another PROJECT above it ...
                        PlanNode node = viewPlan.getParent();
                        while (node != null) {
                            if (node.isOneOf(Type.JOIN)) break;
                            if (node.is(Type.PROJECT) && viewPlan.getSelectors().containsAll(node.getSelectors())) {
                                viewPlan.extractFromParent();
                                break;
                            }
                            node = node.getParent();
                        }
                    }
                    foundViews = true;
                }
            }
View Full Code Here

                    // Sort the index plans, so the best one is first ...
                    Collections.sort(indexPlans);
                    // Add an index node for each index ...
                    for (IndexPlan indexPlan : indexPlans) {
                        // Add a plan node for this index ...
                        PlanNode indexNode = new PlanNode(Type.INDEX, source.getSelectors());
                        indexNode.setProperty(Property.INDEX_SPECIFICATION, indexPlan);
                        // and add it under the SOURCE node ...
                        source.addLastChild(indexNode);
                    }
                }
            }
View Full Code Here

TOP

Related Classes of org.modeshape.jcr.query.plan.PlanNode

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.