in core/src/main/java/org/apache/calcite/materialize/LatticeSuggester.java [149:279]
private void addFrame(Query q, Frame frame, List<Lattice> lattices) {
final AttributedDirectedGraph<TableRef, StepRef> g =
AttributedDirectedGraph.create(new StepRef.Factory());
final Multimap<Pair<TableRef, TableRef>, IntPair> map =
LinkedListMultimap.create();
for (TableRef tableRef : frame.tableRefs) {
g.addVertex(tableRef);
}
for (Hop hop : frame.hops) {
map.put(Pair.of(hop.source.tableRef(), hop.target.tableRef()),
IntPair.of(hop.source.col(space), hop.target.col(space)));
}
for (Map.Entry<Pair<TableRef, TableRef>, Collection<IntPair>> e
: map.asMap().entrySet()) {
final TableRef source = e.getKey().left;
final TableRef target = e.getKey().right;
final StepRef stepRef =
q.stepRef(source, target, ImmutableList.copyOf(e.getValue()));
g.addVertex(stepRef.source());
g.addVertex(stepRef.target());
g.addEdge(stepRef.source(), stepRef.target(), stepRef.step,
stepRef.ordinalInQuery);
}
// If the join graph is cyclic, we can't use it.
final Set<TableRef> cycles = new CycleDetector<>(g).findCycles();
if (!cycles.isEmpty()) {
return;
}
// Translate the query graph to mutable nodes
final IdentityHashMap<TableRef, @Nullable MutableNode> nodes = new IdentityHashMap<>();
final Map<List, MutableNode> nodesByParent = new HashMap<>();
final List<MutableNode> rootNodes = new ArrayList<>();
for (TableRef tableRef : TopologicalOrderIterator.of(g)) {
final List<StepRef> edges = g.getInwardEdges(tableRef);
final MutableNode node;
switch (edges.size()) {
case 0:
node = new MutableNode(tableRef.table);
rootNodes.add(node);
break;
case 1:
final StepRef edge = edges.get(0);
final MutableNode parent = nodes.get(edge.source());
final List key =
FlatLists.of(parent, tableRef.table, edge.step.keys);
final MutableNode existingNode = nodesByParent.get(key);
if (existingNode == null) {
node = new MutableNode(tableRef.table, parent, edge.step);
nodesByParent.put(key, node);
} else {
node = existingNode;
}
break;
default:
for (StepRef edge2 : edges) {
final MutableNode parent2 = nodes.get(edge2.source());
requireNonNull(
parent2,
() -> "parent for " + edge2.source());
final MutableNode node2 =
new MutableNode(tableRef.table, parent2, edge2.step);
parent2.children.add(node2);
}
node = null;
break;
}
nodes.put(tableRef, node);
}
// Transcribe the hierarchy of mutable nodes to immutable nodes
for (MutableNode rootNode : rootNodes) {
if (rootNode.isCyclic()) {
continue;
}
final CalciteSchema rootSchema = CalciteSchema.createRootSchema(false);
final Lattice.Builder latticeBuilder =
new Lattice.Builder(space, rootSchema, rootNode);
final List<MutableNode> flatNodes = new ArrayList<>();
rootNode.flatten(flatNodes);
for (MutableMeasure measure : frame.measures) {
for (ColRef arg : measure.arguments) {
if (arg == null) {
// Cannot handle expressions, e.g. "sum(x + 1)" yet
return;
}
}
latticeBuilder.addMeasure(
new Lattice.Measure(measure.aggregate, measure.distinct,
measure.name,
Util.transform(measure.arguments, colRef -> {
final Lattice.Column column;
if (colRef instanceof BaseColRef) {
final BaseColRef baseColRef = (BaseColRef) colRef;
final MutableNode node = nodes.get(baseColRef.t);
final int table = flatNodes.indexOf(node);
column = latticeBuilder.column(table, baseColRef.c);
} else if (colRef instanceof DerivedColRef) {
final DerivedColRef derivedColRef =
(DerivedColRef) colRef;
final String alias = deriveAlias(measure, derivedColRef);
column =
latticeBuilder.expression(derivedColRef.e, alias,
derivedColRef.tableAliases());
} else {
throw new AssertionError("expression in measure");
}
latticeBuilder.use(column, true);
return column;
})));
}
for (int i = 0; i < frame.columnCount; i++) {
final ColRef c = frame.column(i);
if (c instanceof DerivedColRef) {
final DerivedColRef derivedColRef = (DerivedColRef) c;
final Lattice.Column expression =
latticeBuilder.expression(derivedColRef.e,
derivedColRef.alias, derivedColRef.tableAliases());
latticeBuilder.use(expression, false);
}
}
final Lattice lattice0 = latticeBuilder.build();
final Lattice lattice1 = findMatch(lattice0, rootNode);
lattices.add(lattice1);
}
}