public Expression visit()

in asterix-graphix/src/main/java/org/apache/asterix/graphix/lang/rewrite/visitor/QueryCanonicalizationVisitor.java [87:208]


    public Expression visit(SelectExpression selectExpression, ILangExpression arg) throws CompilationException {
        // Visit our SELECT-EXPR-level LET-CLAUSEs.
        for (LetClause letClause : selectExpression.getLetList()) {
            letClause.accept(this, selectExpression);
        }

        // First pass: collect all ambiguous graph elements.
        AmbiguousElementVisitor ambiguousElementVisitor = new AmbiguousElementVisitor(graphixRewritingContext);
        SelectSetOperation selectSetOperation = selectExpression.getSelectSetOperation();
        selectSetOperation.accept(ambiguousElementVisitor, selectExpression);
        if (ambiguousElementVisitor.getAmbiguousElements().isEmpty()) {
            // We have no ambiguous elements. Our [sub]query is in canonical form, and we can exit here.
            return selectExpression;
        }

        // Second pass: enumerate all canonical forms of each ambiguous element.
        Map<AbstractExpression, List<? extends AbstractExpression>> canonicalElementMap = new HashMap<>();
        for (AbstractExpression element : ambiguousElementVisitor.getAmbiguousElements()) {
            CanonicalElementGeneratorFactory factory = ambiguousElementVisitor.getGeneratorFactory(element);
            if (element instanceof VertexPatternExpr) {
                VertexPatternExpr vertexPatternExpr = (VertexPatternExpr) element;
                List<VertexPatternExpr> canonicalVertices = factory.generateCanonicalVertices(vertexPatternExpr);
                canonicalElementMap.put(element, canonicalVertices);

            } else { // ambiguousElement instanceof EdgePatternExpr
                EdgePatternExpr edgePatternExpr = (EdgePatternExpr) element;
                EdgeDescriptor edgeDescriptor = edgePatternExpr.getEdgeDescriptor();
                if (edgeDescriptor.getPatternType() == EdgeDescriptor.PatternType.EDGE) {
                    List<EdgePatternExpr> canonicalEdges = factory.generateCanonicalEdges(edgePatternExpr);
                    canonicalElementMap.put(element, canonicalEdges);

                } else { // edgeDescriptor.getPatternType() == EdgeDescriptor.PatternType.PATH
                    ElementEvaluationOption option = ambiguousElementVisitor.getElementEvaluationOption(element);
                    List<PathPatternExpr> canonicalPaths = factory.generateCanonicalPaths(edgePatternExpr,
                            option == ElementEvaluationOption.SWITCH_AND_CYCLE);
                    canonicalElementMap.put(element, canonicalPaths);
                }
            }
        }

        // Third pass: invoke the appropriate consumer for each canonical element.
        SelectExpression selectExpressionCopy = graphixDeepCopyVisitor.visit(selectExpression, null);
        CanonicalElementExpansionConsumer expansionConsumer =
                new CanonicalElementExpansionConsumer(selectExpressionCopy, graphixRewritingContext);
        CanonicalElementBranchConsumer branchConsumer = new CanonicalElementBranchConsumer(branchLookupTable);
        Map<SelectBlock, List<AbstractExpression>> groupedElements = new HashMap<>();
        ambiguousElementVisitor.getAmbiguousElements().forEach(e -> {
            SelectBlock sourceSelectBlock = ambiguousElementVisitor.getSourceSelectBlock(e);
            groupedElements.putIfAbsent(sourceSelectBlock, new ArrayList<>());
            groupedElements.get(sourceSelectBlock).add(e);
        });
        for (Map.Entry<SelectBlock, List<AbstractExpression>> entry : groupedElements.entrySet()) {
            expansionConsumer.resetSelectBlock(entry.getKey());
            for (AbstractExpression ambiguousElement : entry.getValue()) {
                ElementEvaluationOption option = ambiguousElementVisitor.getElementEvaluationOption(ambiguousElement);
                if (option == ElementEvaluationOption.EXPAND_AND_UNION) {
                    expansionConsumer.accept(ambiguousElement, canonicalElementMap.get(ambiguousElement));

                } else { // option == ElementEvaluationOption.SWITCH_AND_CYCLE
                    branchConsumer.accept(ambiguousElement, canonicalElementMap.get(ambiguousElement));
                }
            }
        }

        // Check if we have any output-modifiers / grouping, that we have no SET-OPs, and if expansion has occurred.
        boolean hasRightInputs = selectSetOperation.hasRightInputs();
        boolean hasOutputModifiers = selectExpression.hasLimit() || selectExpression.hasOrderby();
        boolean hasGroupBy = false, hasAggregation = false;
        SelectBlock originalLeftSelectBlock = selectSetOperation.getLeftInput().getSelectBlock();
        if (selectSetOperation.getLeftInput().selectBlock()) {
            hasGroupBy = originalLeftSelectBlock.hasGroupbyClause();
            hasAggregation = checkSql92AggregateVisitor.visit(originalLeftSelectBlock, null);
            hasAggregation |= originalLeftSelectBlock.getSelectClause().distinct();
        }

        // Finalize our expansion consumer.
        Set<SelectBlock> generatedSelectBlocks = new HashSet<>();
        expansionConsumer.finalize(selectExpression, generatedSelectBlocks::add);

        // Perform a post-canonical expansion pass if necessary.
        boolean hasExpansionOccurred = !generatedSelectBlocks.isEmpty();
        if (hasExpansionOccurred && !hasRightInputs && (hasOutputModifiers | hasGroupBy | hasAggregation)) {
            Set<VariableExpr> liveVariables = new HashSet<>();
            FromGraphClause fromGraphClause = (FromGraphClause) originalLeftSelectBlock.getFromClause();
            for (MatchClause matchClause : fromGraphClause.getMatchClauses()) {
                for (PathPatternExpr pathExpression : matchClause.getPathExpressions()) {
                    if (pathExpression.getVariableExpr() != null) {
                        liveVariables.add(pathExpression.getVariableExpr());
                    }
                    for (VertexPatternExpr vertexExpression : pathExpression.getVertexExpressions()) {
                        VariableExpr vertexVariable = vertexExpression.getVariableExpr();
                        liveVariables.add(vertexVariable);
                    }
                    for (EdgePatternExpr edgeExpression : pathExpression.getEdgeExpressions()) {
                        VariableExpr edgeVariable = edgeExpression.getEdgeDescriptor().getVariableExpr();
                        liveVariables.add(edgeVariable);
                    }
                }
            }
            if (!fromGraphClause.getCorrelateClauses().isEmpty()) {
                List<AbstractBinaryCorrelateClause> correlateClauses = fromGraphClause.getCorrelateClauses();
                for (AbstractBinaryCorrelateClause correlateClause : correlateClauses) {
                    VariableExpr bindingVariable = correlateClause.getRightVariable();
                    liveVariables.add(bindingVariable);
                }
            }
            if (originalLeftSelectBlock.hasLetWhereClauses()) {
                for (AbstractClause abstractClause : originalLeftSelectBlock.getLetWhereList()) {
                    if (abstractClause.getClauseType() == Clause.ClauseType.LET_CLAUSE) {
                        LetClause letClause = (LetClause) abstractClause;
                        VariableExpr bindingVariable = letClause.getVarExpr();
                        liveVariables.add(bindingVariable);
                    }
                }
            }
            return new PostCanonicalExpansionVisitor(graphixRewritingContext, originalLeftSelectBlock,
                    generatedSelectBlocks, liveVariables).visit(selectExpression, arg);
        }

        // Return our current SELECT-EXPR.
        return selectExpression;
    }