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);
}
}
});
}