Package org.modeshape.jcr.query.engine.process

Examples of org.modeshape.jcr.query.engine.process.DistinctSequence


                    // 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();
View Full Code Here

TOP

Related Classes of org.modeshape.jcr.query.engine.process.DistinctSequence

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.