Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 package com.facebook.presto.sql.planner;
 
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import static com.facebook.presto.spi.type.BooleanType.BOOLEAN;
 import static com.facebook.presto.util.ImmutableCollectors.toImmutableSet;
 import static com.google.common.base.MoreObjects.firstNonNull;
 import static com.google.common.base.Preconditions.checkState;
 
         extends DefaultTraversalVisitor<PlanBuilderVoid>
 {
     private final Analysis analysis;
     private final SymbolAllocator symbolAllocator;
     private final PlanNodeIdAllocator idAllocator;
     private final Metadata metadata;
     private final Session session;
 
     QueryPlanner(Analysis analysisSymbolAllocator symbolAllocatorPlanNodeIdAllocator idAllocatorMetadata metadataSession session)
     {
         Preconditions.checkNotNull(analysis"analysis is null");
         Preconditions.checkNotNull(symbolAllocator"symbolAllocator is null");
         Preconditions.checkNotNull(idAllocator"idAllocator is null");
         Preconditions.checkNotNull(metadata"metadata is null");
         Preconditions.checkNotNull(session"session is null");
 
         this. = analysis;
         this. = symbolAllocator;
         this. = idAllocator;
         this. = metadata;
         this. = session;
     }
 
     @Override
     protected PlanBuilder visitQuery(Query queryVoid context)
     {
         PlanBuilder builder = planQueryBody(query);
         Set<InPredicateinPredicates = .getInPredicates(query);
         builder = appendSemiJoins(builderinPredicates);
        List<FieldOrExpressionorderBy = .getOrderByExpressions(query);
        List<FieldOrExpressionoutputs = .getOutputExpressions(query);
        builder = project(builder, Iterables.concat(orderByoutputs));
        builder = sort(builderquery);
        builder = project(builder.getOutputExpressions(query));
        builder = limit(builderquery);
        return builder;
    }
    @Override
    protected PlanBuilder visitQuerySpecification(QuerySpecification nodeVoid context)
    {
        PlanBuilder builder = planFrom(node);
        Set<InPredicateinPredicates = .getInPredicates(node);
        builder = appendSemiJoins(builderinPredicates);
        builder = filter(builder.getWhere(node));
        builder = aggregate(buildernode);
        builder = filter(builder.getHaving(node));
        builder = window(buildernode);
        List<FieldOrExpressionorderBy = .getOrderByExpressions(node);
        List<FieldOrExpressionoutputs = .getOutputExpressions(node);
        builder = project(builder, Iterables.concat(orderByoutputs));
        builder = distinct(buildernodeoutputsorderBy);
        builder = sort(buildernode);
        builder = project(builder.getOutputExpressions(node));
        builder = limit(buildernode);
        return builder;
    }
    private PlanBuilder planQueryBody(Query query)
    {
        RelationPlan relationPlan = new RelationPlanner()
                .process(query.getQueryBody(), null);
        TranslationMap translations = new TranslationMap(relationPlan);
        // Make field->symbol mapping from underlying relation plan available for translations
        // This makes it possible to rewrite FieldOrExpressions that reference fields from the QuerySpecification directly
        translations.setFieldMappings(relationPlan.getOutputSymbols());
        return new PlanBuilder(translationsrelationPlan.getRoot(), relationPlan.getSampleWeight());
    }
    private PlanBuilder planFrom(QuerySpecification node)
    {
        RelationPlan relationPlan;
        if (node.getFrom().isPresent()) {
            relationPlan = new RelationPlanner()
                    .process(node.getFrom().get(), null);
        }
        else {
            relationPlan = planImplicitTable();
        }
        TranslationMap translations = new TranslationMap(relationPlan);
        // Make field->symbol mapping from underlying relation plan available for translations
        // This makes it possible to rewrite FieldOrExpressions that reference fields from the FROM clause directly
        translations.setFieldMappings(relationPlan.getOutputSymbols());
        return new PlanBuilder(translationsrelationPlan.getRoot(), relationPlan.getSampleWeight());
    }
    {
        List<ExpressionemptyRow = ImmutableList.of();
        return new RelationPlan(
                new ValuesNode(.getNextId(), ImmutableList.<Symbol>of(), ImmutableList.of(emptyRow)),
                new TupleDescriptor(),
                ImmutableList.<Symbol>of(),
                Optional.empty());
    }
    private PlanBuilder filter(PlanBuilder subPlanExpression predicate)
    {
        if (predicate == null) {
            return subPlan;
        }
        Expression rewritten = subPlan.rewrite(predicate);
        return new PlanBuilder(subPlan.getTranslations(), new FilterNode(.getNextId(), subPlan.getRoot(), rewritten), subPlan.getSampleWeight());
    }
    private PlanBuilder project(PlanBuilder subPlanIterable<FieldOrExpressionexpressions)
    {
        TranslationMap outputTranslations = new TranslationMap(subPlan.getRelationPlan(), );
        ImmutableMap.Builder<SymbolExpressionprojections = ImmutableMap.builder();
        for (FieldOrExpression fieldOrExpression : ImmutableSet.copyOf(expressions)) {
            Symbol symbol;
            if (fieldOrExpression.isFieldReference()) {
                Field field = subPlan.getRelationPlan().getDescriptor().getFieldByIndex(fieldOrExpression.getFieldIndex());
                symbol = .newSymbol(field);
            }
            else {
                Expression expression = fieldOrExpression.getExpression();
                symbol = .newSymbol(expression.getType(expression));
            }
            projections.put(symbolsubPlan.rewrite(fieldOrExpression));
            outputTranslations.put(fieldOrExpressionsymbol);
        }
        if (subPlan.getSampleWeight().isPresent()) {
            Symbol symbol = subPlan.getSampleWeight().get();
            projections.put(symbolnew QualifiedNameReference(symbol.toQualifiedName()));
        }
        return new PlanBuilder(outputTranslationsnew ProjectNode(.getNextId(), subPlan.getRoot(), projections.build()), subPlan.getSampleWeight());
    }
    private Map<SymbolExpressioncoerce(Iterable<? extends ExpressionexpressionsPlanBuilder subPlanTranslationMap translations)
    {
        ImmutableMap.Builder<SymbolExpressionprojections = ImmutableMap.builder();
        for (Expression expression : expressions) {
            Type coercion = .getCoercion(expression);
            Symbol symbol = .newSymbol(expressionfirstNonNull(coercion.getType(expression)));
            Expression rewritten = subPlan.rewrite(expression);
            if (coercion != null) {
                rewritten = new Cast(rewrittencoercion.getTypeSignature().toString());
            }
            projections.put(symbolrewritten);
            translations.put(expressionsymbol);
        }
        return projections.build();
    }
    private PlanBuilder explicitCoercionFields(PlanBuilder subPlanIterable<FieldOrExpressionalreadyCoercedIterable<? extends Expressionuncoerced)
    {
        TranslationMap translations = new TranslationMap(subPlan.getRelationPlan(), );
        ImmutableMap.Builder<SymbolExpressionprojections = ImmutableMap.builder();
        projections.putAll(coerce(uncoercedsubPlantranslations));
        for (FieldOrExpression fieldOrExpression : alreadyCoerced) {
            Symbol symbol;
            if (fieldOrExpression.isFieldReference()) {
                Field field = subPlan.getRelationPlan().getDescriptor().getFieldByIndex(fieldOrExpression.getFieldIndex());
                symbol = .newSymbol(field);
            }
            else {
                symbol = .newSymbol(fieldOrExpression.getExpression(), .getType(fieldOrExpression.getExpression()));
            }
            Expression rewritten = subPlan.rewrite(fieldOrExpression);
            projections.put(symbolrewritten);
            translations.put(fieldOrExpressionsymbol);
        }
        return new PlanBuilder(translationsnew ProjectNode(.getNextId(), subPlan.getRoot(), projections.build()), subPlan.getSampleWeight());
    }
    private PlanBuilder explicitCoercionSymbols(PlanBuilder subPlanIterable<SymbolalreadyCoercedIterable<? extends Expressionuncoerced)
    {
        TranslationMap translations = new TranslationMap(subPlan.getRelationPlan(), );
        translations.copyMappingsFrom(subPlan.getTranslations());
        ImmutableMap.Builder<SymbolExpressionprojections = ImmutableMap.builder();
        projections.putAll(coerce(uncoercedsubPlantranslations));
        for (Symbol symbol : alreadyCoerced) {
            projections.put(symbolnew QualifiedNameReference(symbol.toQualifiedName()));
        }
        return new PlanBuilder(translationsnew ProjectNode(.getNextId(), subPlan.getRoot(), projections.build()), subPlan.getSampleWeight());
    }
    private PlanBuilder aggregate(PlanBuilder subPlanQuerySpecification node)
    {
        if (.getAggregates(node).isEmpty() && .getGroupByExpressions(node).isEmpty()) {
            return subPlan;
        }
        Set<FieldOrExpressionarguments = .getAggregates(node).stream()
                .map(FunctionCall::getArguments)
                .flatMap(List::stream)
                .map(FieldOrExpression::new)
                .collect(toImmutableSet());
        // 1. Pre-project all scalar inputs (arguments and non-trivial group by expressions)
        Iterable<FieldOrExpressioninputs = Iterables.concat(.getGroupByExpressions(node), arguments);
        if (!Iterables.isEmpty(inputs)) { // avoid an empty projection if the only aggregation is COUNT (which has no arguments)
            subPlan = project(subPlaninputs);
        }
        // 2. Aggregate
        ImmutableMap.Builder<SymbolFunctionCallaggregationAssignments = ImmutableMap.builder();
        ImmutableMap.Builder<SymbolSignaturefunctions = ImmutableMap.builder();
        // 2.a. Rewrite aggregates in terms of pre-projected inputs
        TranslationMap translations = new TranslationMap(subPlan.getRelationPlan(), );
        boolean needPostProjectionCoercion = false;
        for (FunctionCall aggregate : .getAggregates(node)) {
            Expression rewritten = subPlan.rewrite(aggregate);
            Symbol newSymbol = .newSymbol(rewritten.getType(aggregate));
            // TODO: this is a hack, because we apply coercions to the output of expressions, rather than the arguments to expressions.
            // Therefore we can end up with this implicit cast, and have to move it into a post-projection
            if (rewritten instanceof Cast) {
                rewritten = ((Castrewritten).getExpression();
                needPostProjectionCoercion = true;
            }
            aggregationAssignments.put(newSymbol, (FunctionCallrewritten);
            translations.put(aggregatenewSymbol);
            functions.put(newSymbol.getFunctionInfo(aggregate).getSignature());
        }
        // 2.b. Rewrite group by expressions in terms of pre-projected inputs
        Set<SymbolgroupBySymbols = new LinkedHashSet<>();
        for (FieldOrExpression fieldOrExpression : .getGroupByExpressions(node)) {
            Symbol symbol = subPlan.translate(fieldOrExpression);
            groupBySymbols.add(symbol);
            translations.put(fieldOrExpressionsymbol);
        }
        // 2.c. Mark distinct rows for each aggregate that has DISTINCT
        // Map from aggregate function arguments to marker symbols, so that we can reuse the markers, if two aggregates have the same argument
        Map<Set<Expression>, SymbolargumentMarkers = new HashMap<>();
        // Map from aggregate functions to marker symbols
        Map<SymbolSymbolmasks = new HashMap<>();
        for (FunctionCall aggregate : Iterables.filter(.getAggregates(node), FunctionCall::isDistinct)) {
            Set<Expressionargs = ImmutableSet.copyOf(aggregate.getArguments());
            Symbol marker = argumentMarkers.get(args);
            Symbol aggregateSymbol = translations.get(aggregate);
            if (marker == null) {
                if (args.size() == 1) {
                    marker = .newSymbol(Iterables.getOnlyElement(args), "distinct");
                }
                else {
                    marker = .newSymbol(aggregateSymbol.getName(), "distinct");
                }
                argumentMarkers.put(argsmarker);
            }
            masks.put(aggregateSymbolmarker);
        }
        for (Map.Entry<Set<Expression>, Symbolentry : argumentMarkers.entrySet()) {
            ImmutableList.Builder<Symbolbuilder = ImmutableList.builder();
            builder.addAll(groupBySymbols);
            for (Expression expression : entry.getKey()) {
                builder.add(subPlan.translate(expression));
            }
            MarkDistinctNode markDistinct = new MarkDistinctNode(.getNextId(),
                    subPlan.getRoot(),
                    entry.getValue(),
                    builder.build(),
                    Optional.empty());
            subPlan = new PlanBuilder(subPlan.getTranslations(), markDistinctsubPlan.getSampleWeight());
        }
        double confidence = 1.0;
        if (.getQuery().getApproximate().isPresent()) {
            confidence = Double.valueOf(.getQuery().getApproximate().get().getConfidence()) / 100.0;
        }
        AggregationNode aggregationNode = new AggregationNode(
                .getNextId(),
                subPlan.getRoot(),
                ImmutableList.copyOf(groupBySymbols),
                aggregationAssignments.build(),
                functions.build(),
                masks,
                ..,
                subPlan.getSampleWeight(),
                confidence,
                Optional.empty());
        subPlan = new PlanBuilder(translationsaggregationNode, Optional.empty());
        // 3. Post-projection
        // Add back the implicit casts that we removed in 2.a
        // TODO: this is a hack, we should change type coercions to coerce the inputs to functions/operators instead of coercing the output
        if (needPostProjectionCoercion) {
            return explicitCoercionFields(subPlan.getGroupByExpressions(node), .getAggregates(node));
        }
        return subPlan;
    }
    private PlanBuilder window(PlanBuilder subPlanQuerySpecification node)
    {
        Set<FunctionCallwindowFunctions = ImmutableSet.copyOf(.getWindowFunctions(node));
        if (windowFunctions.isEmpty()) {
            return subPlan;
        }
        for (FunctionCall windowFunction : windowFunctions) {
            Window window = windowFunction.getWindow().get();
            // Extract frame
            WindowFrame.Type frameType = ..;
            FrameBound.Type frameStartType = ..;
            FrameBound.Type frameEndType = ..;
            Expression frameStart = null;
            Expression frameEnd = null;
            if (window.getFrame().isPresent()) {
                WindowFrame frame = window.getFrame().get();
                frameType = frame.getType();
                frameStartType = frame.getStart().getType();
                frameStart = frame.getStart().getValue().orElse(null);
                if (frame.getEnd().isPresent()) {
                    frameEndType = frame.getEnd().get().getType();
                    frameEnd = frame.getEnd().get().getValue().orElse(null);
                }
            }
            // Pre-project inputs
            ImmutableList.Builder<Expressioninputs = ImmutableList.<Expression>builder()
                    .addAll(windowFunction.getArguments())
                    .addAll(window.getPartitionBy())
                    .addAll(Iterables.transform(window.getOrderBy(), SortItem::getSortKey));
            if (frameStart != null) {
                inputs.add(frameStart);
            }
            if (frameEnd != null) {
                inputs.add(frameEnd);
            }
            subPlan = appendProjections(subPlaninputs.build());
            // Rewrite PARTITION BY in terms of pre-projected inputs
            ImmutableList.Builder<SymbolpartitionBySymbols = ImmutableList.builder();
            for (Expression expression : window.getPartitionBy()) {
                partitionBySymbols.add(subPlan.translate(expression));
            }
            // Rewrite ORDER BY in terms of pre-projected inputs
            ImmutableList.Builder<SymbolorderBySymbols = ImmutableList.builder();
            Map<SymbolSortOrderorderings = new HashMap<>();
            for (SortItem item : window.getOrderBy()) {
                Symbol symbol = subPlan.translate(item.getSortKey());
                orderBySymbols.add(symbol);
                orderings.put(symboltoSortOrder(item));
            }
            // Rewrite frame bounds in terms of pre-projected inputs
            Optional<SymbolframeStartSymbol = Optional.empty();
            Optional<SymbolframeEndSymbol = Optional.empty();
            if (frameStart != null) {
                frameStartSymbol = Optional.of(subPlan.translate(frameStart));
            }
            if (frameEnd != null) {
                frameEndSymbol = Optional.of(subPlan.translate(frameEnd));
            }
            WindowNode.Frame frame = new WindowNode.Frame(frameType,
                    frameStartTypeframeStartSymbol,
                    frameEndTypeframeEndSymbol);
            TranslationMap outputTranslations = new TranslationMap(subPlan.getRelationPlan(), );
            outputTranslations.copyMappingsFrom(subPlan.getTranslations());
            ImmutableMap.Builder<SymbolFunctionCallassignments = ImmutableMap.builder();
            Map<SymbolSignaturesignatures = new HashMap<>();
            // Rewrite function call in terms of pre-projected inputs
            Expression rewritten = subPlan.rewrite(windowFunction);
            Symbol newSymbol = .newSymbol(rewritten.getType(windowFunction));
            boolean needCoercion = rewritten instanceof Cast;
            // Strip out the cast and add it back as a post-projection
            if (rewritten instanceof Cast) {
                rewritten = ((Castrewritten).getExpression();
            }
            assignments.put(newSymbol, (FunctionCallrewritten);
            outputTranslations.put(windowFunctionnewSymbol);
            signatures.put(newSymbol.getFunctionInfo(windowFunction).getSignature());
            List<SymbolsourceSymbols = subPlan.getRoot().getOutputSymbols();
            // create window node
            subPlan = new PlanBuilder(outputTranslations,
                    new WindowNode(
                            .getNextId(),
                            subPlan.getRoot(),
                            partitionBySymbols.build(),
                            orderBySymbols.build(),
                            orderings,
                            frame,
                            assignments.build(),
                            signatures,
                            Optional.empty(),
                            ImmutableSet.of(),
                            0),
                    subPlan.getSampleWeight());
            if (needCoercion) {
                subPlan = explicitCoercionSymbols(subPlansourceSymbols, ImmutableList.of(windowFunction));
            }
        }
        return subPlan;
    }
    private PlanBuilder appendProjections(PlanBuilder subPlanIterable<Expressionexpressions)
    {
        TranslationMap translations = new TranslationMap(subPlan.getRelationPlan(), );
        // Carry over the translations from the source because we are appending projections
        translations.copyMappingsFrom(subPlan.getTranslations());
        ImmutableMap.Builder<SymbolExpressionprojections = ImmutableMap.builder();
        // add an identity projection for underlying plan
        for (Symbol symbol : subPlan.getRoot().getOutputSymbols()) {
            Expression expression = new QualifiedNameReference(symbol.toQualifiedName());
            projections.put(symbolexpression);
        }
        ImmutableMap.Builder<SymbolExpressionnewTranslations = ImmutableMap.builder();
        for (Expression expression : expressions) {
            Symbol symbol = .newSymbol(expression.getType(expression));
            projections.put(symboltranslations.rewrite(expression));
            newTranslations.put(symbolexpression);
        }
        // Now append the new translations into the TranslationMap
        for (Map.Entry<SymbolExpressionentry : newTranslations.build().entrySet()) {
            translations.put(entry.getValue(), entry.getKey());
        }
        return new PlanBuilder(translationsnew ProjectNode(.getNextId(), subPlan.getRoot(), projections.build()), subPlan.getSampleWeight());
    }
    private PlanBuilder appendSemiJoins(PlanBuilder subPlanSet<InPredicateinPredicates)
    {
        for (InPredicate inPredicate : inPredicates) {
            subPlan = appendSemiJoin(subPlaninPredicate);
        }
        return subPlan;
    }

    
Semijoins are planned as follows: 1) SQL constructs that need to be semijoined are extracted during Analysis phase (currently only InPredicates so far) 2) Create a new SemiJoinNode that connects the semijoin lookup field with the planned subquery and have it output a new boolean symbol for the result of the semijoin. 3) Add an entry to the TranslationMap that notes to map the InPredicate into semijoin output symbol

Currently, we only support semijoins deriving from InPredicates, but we will probably need to add support for more SQL constructs in the future.

    private PlanBuilder appendSemiJoin(PlanBuilder subPlanInPredicate inPredicate)
    {
        TranslationMap translations = new TranslationMap(subPlan.getRelationPlan(), );
        translations.copyMappingsFrom(subPlan.getTranslations());
        subPlan = appendProjections(subPlan, ImmutableList.of(inPredicate.getValue()));
        Symbol sourceJoinSymbol = subPlan.translate(inPredicate.getValue());
        Preconditions.checkState(inPredicate.getValueList() instanceof SubqueryExpression);
        SubqueryExpression subqueryExpression = (SubqueryExpressioninPredicate.getValueList();
        RelationPlanner relationPlanner = new RelationPlanner();
        RelationPlan valueListRelation = relationPlanner.process(subqueryExpression.getQuery(), null);
        Symbol filteringSourceJoinSymbol = Iterables.getOnlyElement(valueListRelation.getRoot().getOutputSymbols());
        Symbol semiJoinOutputSymbol = .newSymbol("semijoinresult");
        translations.put(inPredicatesemiJoinOutputSymbol);
        return new PlanBuilder(translations,
                new SemiJoinNode(.getNextId(),
                        subPlan.getRoot(),
                        valueListRelation.getRoot(),
                        sourceJoinSymbol,
                        filteringSourceJoinSymbol,
                        semiJoinOutputSymbol,
                        Optional.empty(),
                        Optional.empty()),
                subPlan.getSampleWeight());
    }
    private PlanBuilder distinct(PlanBuilder subPlanQuerySpecification nodeList<FieldOrExpressionoutputsList<FieldOrExpressionorderBy)
    {
        if (node.getSelect().isDistinct()) {
            checkState(outputs.containsAll(orderBy), "Expected ORDER BY terms to be in SELECT. Broken analysis");
            AggregationNode aggregation = new AggregationNode(.getNextId(),
                    subPlan.getRoot(),
                    subPlan.getRoot().getOutputSymbols(),
                    ImmutableMap.<SymbolFunctionCall>of(),
                    ImmutableMap.<SymbolSignature>of(),
                    ImmutableMap.<SymbolSymbol>of(),
                    ..,
                    Optional.empty(),
                    1.0,
                    Optional.empty());
            return new PlanBuilder(subPlan.getTranslations(), aggregationsubPlan.getSampleWeight());
        }
        return subPlan;
    }
    private PlanBuilder sort(PlanBuilder subPlanQuery node)
    {
        return sort(subPlannode.getOrderBy(), node.getLimit(), .getOrderByExpressions(node));
    }
    private PlanBuilder sort(PlanBuilder subPlanQuerySpecification node)
    {
        return sort(subPlannode.getOrderBy(), node.getLimit(), .getOrderByExpressions(node));
    }
    private PlanBuilder sort(PlanBuilder subPlanList<SortItemorderByOptional<StringlimitList<FieldOrExpressionorderByExpressions)
    {
        if (orderBy.isEmpty()) {
            return subPlan;
        }
        Iterator<SortItemsortItems = orderBy.iterator();
        ImmutableList.Builder<SymbolorderBySymbols = ImmutableList.builder();
        ImmutableMap.Builder<SymbolSortOrderorderings = ImmutableMap.builder();
        for (FieldOrExpression fieldOrExpression : orderByExpressions) {
            Symbol symbol = subPlan.translate(fieldOrExpression);
            orderBySymbols.add(symbol);
            orderings.put(symboltoSortOrder(sortItems.next()));
        }
        PlanNode planNode;
        if (limit.isPresent()) {
            planNode = new TopNNode(.getNextId(), subPlan.getRoot(), Long.parseLong(limit.get()), orderBySymbols.build(), orderings.build(), false);
        }
        else {
            planNode = new SortNode(.getNextId(), subPlan.getRoot(), orderBySymbols.build(), orderings.build());
        }
        return new PlanBuilder(subPlan.getTranslations(), planNodesubPlan.getSampleWeight());
    }
    private PlanBuilder limit(PlanBuilder subPlanQuery node)
    {
        return limit(subPlannode.getOrderBy(), node.getLimit());
    }
    private PlanBuilder limit(PlanBuilder subPlanQuerySpecification node)
    {
        return limit(subPlannode.getOrderBy(), node.getLimit());
    }
    private PlanBuilder limit(PlanBuilder subPlanList<SortItemorderByOptional<Stringlimit)
    {
        if (orderBy.isEmpty() && limit.isPresent()) {
            long limitValue = Long.parseLong(limit.get());
            return new PlanBuilder(subPlan.getTranslations(), new LimitNode(.getNextId(), subPlan.getRoot(), limitValue), subPlan.getSampleWeight());
        }
        return subPlan;
    }
    private SortOrder toSortOrder(SortItem sortItem)
    {
        if (sortItem.getOrdering() == .) {
            if (sortItem.getNullOrdering() == .) {
                return .;
            }
            else {
                return .;
            }
        }
        else {
            if (sortItem.getNullOrdering() == .) {
                return .;
            }
            else {
                return .;
            }
        }
    }
New to GrepCode? Check out our FAQ X