com.hazelcast.org.apache.calcite.materialize.LatticeSpace Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.org.apache.calcite.materialize;
import com.hazelcast.org.apache.calcite.plan.RelOptTable;
import com.hazelcast.org.apache.calcite.rel.type.RelDataTypeField;
import com.hazelcast.org.apache.calcite.rex.RexNode;
import com.hazelcast.org.apache.calcite.util.Util;
import com.hazelcast.org.apache.calcite.util.graph.AttributedDirectedGraph;
import com.hazelcast.org.apache.calcite.util.mapping.IntPair;
import com.hazelcast.com.google.common.collect.ImmutableList;
import com.hazelcast.org.checkerframework.checker.initialization.qual.NotOnlyInitialized;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
/** Space within which lattices exist. */
class LatticeSpace {
final SqlStatisticProvider statisticProvider;
private final Map, LatticeTable> tableMap = new HashMap<>();
@SuppressWarnings("assignment.type.incompatible")
final @NotOnlyInitialized AttributedDirectedGraph g =
new AttributedDirectedGraph<>(new Step.Factory(this));
private final Map, String> simpleTableNames = new HashMap<>();
private final Set simpleNames = new HashSet<>();
/** Root nodes, indexed by digest. */
final Map nodeMap = new HashMap<>();
final Map, Path> pathMap = new HashMap<>();
final Map> tableExpressions = new HashMap<>();
LatticeSpace(SqlStatisticProvider statisticProvider) {
this.statisticProvider = Objects.requireNonNull(statisticProvider, "statisticProvider");
}
/** Derives a unique name for a table, qualifying with schema name only if
* necessary. */
String simpleName(LatticeTable table) {
return simpleName(table.t.getQualifiedName());
}
String simpleName(RelOptTable table) {
return simpleName(table.getQualifiedName());
}
String simpleName(List table) {
final String name = simpleTableNames.get(table);
if (name != null) {
return name;
}
final String name2 = Util.last(table);
if (simpleNames.add(name2)) {
simpleTableNames.put(ImmutableList.copyOf(table), name2);
return name2;
}
final String name3 = table.toString();
simpleTableNames.put(ImmutableList.copyOf(table), name3);
return name3;
}
LatticeTable register(RelOptTable t) {
final LatticeTable table = tableMap.get(t.getQualifiedName());
if (table != null) {
return table;
}
final LatticeTable table2 = new LatticeTable(t);
tableMap.put(t.getQualifiedName(), table2);
g.addVertex(table2);
return table2;
}
Step addEdge(LatticeTable source, LatticeTable target, List keys) {
keys = sortUnique(keys);
final Step step = g.addEdge(source, target, keys);
if (step != null) {
return step;
}
for (Step step2 : g.getEdges(source, target)) {
if (step2.keys.equals(keys)) {
return step2;
}
}
throw new AssertionError("addEdge failed, yet no edge present");
}
/** Returns a list of {@link IntPair} that is sorted and unique. */
static List sortUnique(List keys) {
if (keys.size() > 1) {
// list may not be sorted; sort it
keys = IntPair.ORDERING.immutableSortedCopy(keys);
if (!IntPair.ORDERING.isStrictlyOrdered(keys)) {
// list may contain duplicates; sort and eliminate duplicates
final Set set = new TreeSet<>(IntPair.ORDERING);
set.addAll(keys);
keys = ImmutableList.copyOf(set);
}
}
return keys;
}
/** Returns a list of {@link IntPair}, transposing source and target fields,
* and ensuring the result is sorted and unique. */
static List swap(List keys) {
return sortUnique(Util.transform(keys, x -> IntPair.of(x.target, x.source)));
}
Path addPath(List steps) {
final ImmutableList key = ImmutableList.copyOf(steps);
final Path path = pathMap.get(key);
if (path != null) {
return path;
}
final Path path2 = new Path(key, pathMap.size());
pathMap.put(key, path2);
return path2;
}
/** Registers an expression as a derived column of a given table.
*
* Its ordinal is the number of fields in the row type plus the ordinal
* of the extended expression. For example, if a table has 10 fields then its
* derived columns will have ordinals 10, 11, 12 etc. */
int registerExpression(LatticeTable table, RexNode e) {
final List expressions =
tableExpressions.computeIfAbsent(table, t -> new ArrayList<>());
final int fieldCount = table.t.getRowType().getFieldCount();
for (int i = 0; i < expressions.size(); i++) {
if (expressions.get(i).toString().equals(e.toString())) {
return fieldCount + i;
}
}
final int result = fieldCount + expressions.size();
expressions.add(e);
return result;
}
/** Returns the name of field {@code field} of {@code table}.
*
* If the field is derived (see
* {@link #registerExpression(LatticeTable, RexNode)}) its name is its
* {@link RexNode#toString()}. */
public String fieldName(LatticeTable table, int field) {
final List fieldList =
table.t.getRowType().getFieldList();
final int fieldCount = fieldList.size();
if (field < fieldCount) {
return fieldList.get(field).getName();
} else {
List rexNodes = tableExpressions.get(table);
assert rexNodes != null : "no expressions found for table " + table;
return rexNodes.get(field - fieldCount).toString();
}
}
}