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