diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java index 31707997ea5..8745d060646 100644 --- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java +++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java @@ -46,7 +46,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import org.checkerframework.checker.nullness.qual.Nullable; @@ -54,7 +54,6 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -63,8 +62,6 @@ import static org.apache.calcite.rel.metadata.RelMdColumnUniqueness.PASSTHROUGH_AGGREGATIONS; import static org.apache.calcite.rel.metadata.RelMdColumnUniqueness.getConstantColumnSet; -import static java.util.Objects.requireNonNull; - /** * RelMdUniqueKeys supplies a default implementation of * {@link RelMetadataQuery#getUniqueKeys} for the standard logical algebra. @@ -172,8 +169,7 @@ private static Set getProjectUniqueKeys(SingleRel rel, RelMetad return ImmutableSet.of(); } - Map mapInToOutPos = - Maps.transformValues(inToOutPosBuilder.build().asMap(), ImmutableBitSet::of); + Multimap mapInToOutPos = inToOutPosBuilder.build(); ImmutableSet.Builder resultBuilder = ImmutableSet.builder(); // Now add to the projUniqueKeySet the child keys that are fully @@ -184,19 +180,12 @@ private static Set getProjectUniqueKeys(SingleRel rel, RelMetad continue; } // colMask is mapped to output project, however, the column can be mapped more than once: - // select id, id, id, unique2, unique2 - // the resulting unique keys would be {{0},{3}}, {{0},{4}}, {{0},{1},{4}}, ... - - Iterable> product = - Linq4j.product( - Util.transform(colMask, in -> - Util.filter( - requireNonNull(mapInToOutPos.get(in), - () -> "no entry for column " + in - + " in mapInToOutPos: " + mapInToOutPos).powerSet(), - bs -> !bs.isEmpty()))); - - resultBuilder.addAll(Util.transform(product, ImmutableBitSet::union)); + // select key1, key1, val1, val2, key2 from ... + // the resulting unique keys would be {{0},{4}}, {{1},{4}} + + Iterable> product = Linq4j.product(Util.transform(colMask, mapInToOutPos::get)); + + resultBuilder.addAll(Util.transform(product, ImmutableBitSet::of)); } return resultBuilder.build(); } diff --git a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java index d654612851b..61937ac10f0 100644 --- a/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java +++ b/core/src/test/java/org/apache/calcite/test/RelMetadataTest.java @@ -1448,6 +1448,17 @@ private void checkColumnUniquenessForFilterWithConstantColumns(String sql) { .withCatalogReaderFactory(factory) .assertThatUniqueKeysAre(); + sql("select key1, key1, key2, value1 from s.composite_keys_table") + .withCatalogReaderFactory(factory) + .assertThatUniqueKeysAre(bitSetOf(0, 2), bitSetOf(1, 2)); + sql("select key1, key2, key2, value1 from s.composite_keys_table") + .withCatalogReaderFactory(factory) + .assertThatUniqueKeysAre(bitSetOf(0, 1), bitSetOf(0, 2)); + + sql("select key1, key1, key2, key2, value1 from s.composite_keys_table") + .withCatalogReaderFactory(factory) + .assertThatUniqueKeysAre(bitSetOf(0, 2), bitSetOf(0, 3), bitSetOf(1, 2), bitSetOf(1, 3)); + // no column of composite keys sql("select value1 from s.composite_keys_table") .withCatalogReaderFactory(factory) @@ -1640,7 +1651,7 @@ private static ImmutableBitSet bitSetOf(int... bits) { @Test void calcMultipleColumnsAreUniqueCalc() { sql("select empno, empno from emp") .convertingProjectAsCalc() - .assertThatUniqueKeysAre(bitSetOf(0), bitSetOf(1), bitSetOf(0, 1)); + .assertThatUniqueKeysAre(bitSetOf(0), bitSetOf(1)); } @Test void calcMultipleColumnsAreUniqueCalc2() { @@ -1655,7 +1666,7 @@ private static ImmutableBitSet bitSetOf(int... bits) { + " from emp a1 join emp a2\n" + " on (a1.empno=a2.empno)") .convertingProjectAsCalc() - .assertThatUniqueKeysAre(bitSetOf(0), bitSetOf(1), bitSetOf(1, 2), bitSetOf(2)); + .assertThatUniqueKeysAre(bitSetOf(0), bitSetOf(1), bitSetOf(2)); } @Test void calcColumnsAreNonUniqueCalc() {