public void apply()

in asterix-graphix/src/main/java/org/apache/asterix/graphix/lang/rewrite/lower/action/MatchSemanticAction.java [135:331]


    public void apply(LoweringEnvironment loweringEnvironment) throws CompilationException {
        Map<ElementLabel, List<VariableExpr>> vertexVariableMap = new HashMap<>();
        Map<ElementLabel, List<VariableExpr>> edgeVariableMap = new HashMap<>();

        // Populate the collections above.
        fromGraphClause.accept(new AbstractGraphixQueryVisitor() {
            private void populateVariableMap(ElementLabel label, VariableExpr variableExpr,
                    Map<ElementLabel, List<VariableExpr>> labelVariableMap) {
                Function<VariableExpr, Boolean> mapMatchFinder = v -> {
                    final String variableName = SqlppVariableUtil.toUserDefinedName(variableExpr.getVar().getValue());
                    return variableName.equals(SqlppVariableUtil.toUserDefinedName(v.getVar().getValue()));
                };
                if (labelVariableMap.containsKey(label)) {
                    if (labelVariableMap.get(label).stream().noneMatch(mapMatchFinder::apply)) {
                        labelVariableMap.get(label).add(variableExpr);
                    }

                } else {
                    List<VariableExpr> variableList = new ArrayList<>();
                    variableList.add(variableExpr);
                    labelVariableMap.put(label, variableList);
                }
            }

            @Override
            public Expression visit(FromGraphClause fromGraphClause, ILangExpression arg) throws CompilationException {
                // We only want to explore the top level of our FROM-GRAPH-CLAUSEs.
                for (MatchClause matchClause : fromGraphClause.getMatchClauses()) {
                    matchClause.accept(this, arg);
                }
                return null;
            }

            @Override
            public Expression visit(VertexPatternExpr vertexPatternExpr, ILangExpression arg)
                    throws CompilationException {
                VariableExpr vertexVariable = vertexPatternExpr.getVariableExpr();
                VariableExpr iterationVariable = aliasLookupTable.getIterationAlias(vertexVariable);
                ElementLabel elementLabel = vertexPatternExpr.getLabels().iterator().next();
                iterationVariable.setSourceLocation(vertexVariable.getSourceLocation());
                populateVariableMap(elementLabel, iterationVariable, vertexVariableMap);
                return null;
            }

            @Override
            public Expression visit(EdgePatternExpr edgePatternExpr, ILangExpression arg) throws CompilationException {
                EdgeDescriptor edgeDescriptor = edgePatternExpr.getEdgeDescriptor();
                VariableExpr edgeVariable = edgeDescriptor.getVariableExpr();
                VariableExpr iterationVariable = aliasLookupTable.getIterationAlias(edgeVariable);
                ElementLabel elementLabel = edgeDescriptor.getEdgeLabels().iterator().next();
                iterationVariable.setSourceLocation(edgeVariable.getSourceLocation());
                populateVariableMap(elementLabel, iterationVariable, edgeVariableMap);
                return null;
            }
        }, null);

        // Construct our isomorphism conjuncts.
        List<OperatorExpr> isomorphismConjuncts = new ArrayList<>();
        if (patternSemantics == SemanticsPatternOption.ISOMORPHISM
                || patternSemantics == SemanticsPatternOption.VERTEX_ISOMORPHISM) {
            vertexVariableMap.values().stream().map(MatchSemanticAction::generateIsomorphismConjuncts)
                    .forEach(isomorphismConjuncts::addAll);
        }
        if (patternSemantics == SemanticsPatternOption.ISOMORPHISM
                || patternSemantics == SemanticsPatternOption.EDGE_ISOMORPHISM) {
            edgeVariableMap.values().stream().map(MatchSemanticAction::generateIsomorphismConjuncts)
                    .forEach(isomorphismConjuncts::addAll);
        }

        // Iterate through our clause sequence.
        remapCloneVisitor.resetSubstitutions();
        loweringEnvironment.acceptTransformer(new ILowerListTransformer() {
            private final Set<VariableExpr> visitedVariables = new HashSet<>();

            @Override
            public void accept(ClauseCollection lowerList) throws CompilationException {
                List<AbstractClause> nonRepresentativeClauses = lowerList.getNonRepresentativeClauses();
                ListIterator<AbstractClause> clauseIterator = nonRepresentativeClauses.listIterator();
                while (clauseIterator.hasNext()) {
                    AbstractClause workingClause = clauseIterator.next();
                    if (workingClause.getClauseType() == Clause.ClauseType.LET_CLAUSE) {
                        LetClause letClause = (LetClause) workingClause;
                        visitedVariables.add(letClause.getVarExpr());

                    } else if (workingClause.getClauseType() == Clause.ClauseType.EXTENSION) {
                        // Navigation semantics will be introduced at the plan translator.
                        LowerSwitchClause lowerSwitchClause = (LowerSwitchClause) workingClause;
                        lowerSwitchClause.setNavigationSemantics(navigationSemantics);

                    } else if (workingClause.getClauseType() == Clause.ClauseType.WHERE_CLAUSE) {
                        continue;

                    } else {
                        AbstractBinaryCorrelateClause correlateClause = (AbstractBinaryCorrelateClause) workingClause;
                        visitedVariables.add(correlateClause.getRightVariable());

                        // If we encounter a LEFT-JOIN, then we have created a LEFT-MATCH branch.
                        if (workingClause.getClauseType() == Clause.ClauseType.JOIN_CLAUSE) {
                            JoinClause joinClause = (JoinClause) workingClause;
                            if (joinClause.getJoinType() == JoinType.LEFTOUTER) {
                                acceptLeftMatchJoin(clauseIterator, joinClause);
                            }
                        }
                    }

                    // Only introduce our conjunct if we have visited both variables (eagerly).
                    Set<OperatorExpr> appliedIsomorphismConjuncts = new HashSet<>();
                    for (OperatorExpr isomorphismConjunct : isomorphismConjuncts) {
                        List<Expression> operandList = isomorphismConjunct.getExprList();
                        VariableExpr termVariable1 = ((VariableExpr) operandList.get(0));
                        VariableExpr termVariable2 = ((VariableExpr) operandList.get(1));
                        if (visitedVariables.contains(termVariable1) && visitedVariables.contains(termVariable2)) {
                            clauseIterator.add(new WhereClause(isomorphismConjunct));
                            appliedIsomorphismConjuncts.add(isomorphismConjunct);
                        }
                    }
                    isomorphismConjuncts.removeAll(appliedIsomorphismConjuncts);
                }
            }

            private void acceptLeftMatchJoin(ListIterator<AbstractClause> clauseIterator, JoinClause joinClause)
                    throws CompilationException {
                // We can make the following assumptions about our JOIN here (i.e. the casts here are valid).
                Expression rightExpression = joinClause.getRightExpression();
                SelectExpression selectExpression = (SelectExpression) rightExpression;
                SelectSetOperation selectSetOperation = selectExpression.getSelectSetOperation();
                SelectBlock selectBlock = selectSetOperation.getLeftInput().getSelectBlock();
                FromGraphClause fromGraphClause = (FromGraphClause) selectBlock.getFromClause();
                LowerListClause lowerClause = (LowerListClause) fromGraphClause.getLowerClause();
                Set<VariableExpr> localLiveVariables = new HashSet<>();
                ListIterator<AbstractClause> leftClauseIterator =
                        lowerClause.getClauseCollection().getNonRepresentativeClauses().listIterator();
                while (leftClauseIterator.hasNext()) {
                    AbstractClause workingClause = leftClauseIterator.next();
                    VariableExpr rightVariable;
                    if (workingClause.getClauseType() == Clause.ClauseType.WHERE_CLAUSE) {
                        continue;

                    } else if (workingClause.getClauseType() == Clause.ClauseType.LET_CLAUSE) {
                        rightVariable = ((LetClause) workingClause).getVarExpr();

                    } else {
                        rightVariable = ((AbstractBinaryCorrelateClause) workingClause).getRightVariable();
                    }

                    // Add our isomorphism conjunct to our main iterator.
                    localLiveVariables.add(rightVariable);
                    Set<OperatorExpr> appliedIsomorphismConjuncts = new HashSet<>();
                    for (OperatorExpr isomorphismConjunct : isomorphismConjuncts) {
                        List<Expression> operandList = isomorphismConjunct.getExprList();
                        VariableExpr termVariable1 = ((VariableExpr) operandList.get(0));
                        VariableExpr termVariable2 = ((VariableExpr) operandList.get(1));
                        VariableExpr leftVariable;
                        if (termVariable1.equals(rightVariable)) {
                            leftVariable = termVariable2;

                        } else if (termVariable2.equals(rightVariable)) {
                            leftVariable = termVariable1;

                        } else {
                            continue;
                        }

                        // Is our left variable introduced in our LEFT-CLAUSE-COLLECTION? Add the conjunct here.
                        if (localLiveVariables.contains(leftVariable)) {
                            leftClauseIterator.add(new WhereClause(isomorphismConjunct));
                            appliedIsomorphismConjuncts.add(isomorphismConjunct);
                            visitedVariables.add(rightVariable);
                            continue;
                        }

                        // Have we seen our left variable somewhere else? Add our conjunct in our main collection.
                        if (visitedVariables.contains(leftVariable)) {
                            VariableExpr joinVariable1 = deepCopyVisitor.visit(joinClause.getRightVariable(), null);
                            VariableExpr joinVariable2 = deepCopyVisitor.visit(joinClause.getRightVariable(), null);
                            FieldAccessor fieldAccessor1 = new FieldAccessor(joinVariable1, rightVariable.getVar());
                            FieldAccessor fieldAccessor2 = new FieldAccessor(joinVariable2, rightVariable.getVar());
                            remapCloneVisitor.addSubstitution(rightVariable, fieldAccessor1);
                            ILangExpression qualifiedConjunct = remapCloneVisitor.substitute(isomorphismConjunct);

                            // Our right variable can also be optional.
                            FunctionSignature functionSignature = new FunctionSignature(BuiltinFunctions.IS_MISSING);
                            CallExpr isMissingCallExpr = new CallExpr(functionSignature, List.of(fieldAccessor2));
                            OperatorExpr disjunctionExpr = new OperatorExpr();
                            disjunctionExpr.addOperator(OperatorType.OR);
                            disjunctionExpr.addOperand(isMissingCallExpr);
                            disjunctionExpr.addOperand((Expression) qualifiedConjunct);
                            clauseIterator.add(new WhereClause(disjunctionExpr));
                            appliedIsomorphismConjuncts.add(isomorphismConjunct);
                            visitedVariables.add(rightVariable);
                        }
                    }
                    isomorphismConjuncts.removeAll(appliedIsomorphismConjuncts);
                }
            }
        });
    }