Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
import org.apache.calcite.linq4j.tree.Expressions;
import org.apache.calcite.linq4j.tree.ParameterExpression;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelTrait;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.RelCollation;
import org.apache.calcite.rel.RelCollationTraitDef;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.util.BuiltInMethod;
import org.apache.calcite.util.Pair;
Expand All @@ -42,17 +44,20 @@ public class EnumerableMergeUnion extends EnumerableUnion {
protected EnumerableMergeUnion(RelOptCluster cluster, RelTraitSet traitSet,
List<RelNode> inputs, boolean all) {
super(cluster, traitSet, inputs, all);
final RelCollation collation = traitSet.getCollation();
if (collation == null || collation.getFieldCollations().isEmpty()) {
final List<RelCollation> collations = traitSet.getCollations();
if (collations.isEmpty() || collations.get(0).getFieldCollations().isEmpty()) {
throw new IllegalArgumentException("EnumerableMergeUnion with no collation");
}
for (RelNode input : inputs) {
final RelCollation inputCollation = input.getTraitSet().getCollation();
if (inputCollation == null || !inputCollation.satisfies(collation)) {
throw new IllegalArgumentException("EnumerableMergeUnion input does "
+ "not satisfy collation. EnumerableMergeUnion collation: "
+ collation + ". Input collation: " + inputCollation + ". Input: "
+ input);
final RelTrait inputCollationTrait =
input.getTraitSet().getTrait(RelCollationTraitDef.INSTANCE);
for (RelCollation collation : collations) {
if (inputCollationTrait == null || !inputCollationTrait.satisfies(collation)) {
throw new IllegalArgumentException("EnumerableMergeUnion input does "
+ "not satisfy collation. EnumerableMergeUnion collation: "
+ collation + ". Input collation: " + inputCollationTrait + ". Input: "
+ input);
}
}
}
}
Expand Down
16 changes: 16 additions & 0 deletions core/src/main/java/org/apache/calcite/plan/RelTraitSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,22 @@ public RelTraitSet getDefaultSansConvention() {
return (@Nullable T) getTrait(RelCollationTraitDef.INSTANCE);
}

/**
* Returns {@link RelCollation} traits defined by
* {@link RelCollationTraitDef#INSTANCE}.
*/
@SuppressWarnings("unchecked")
public List<RelCollation> getCollations() {
RelCollation trait = getTrait(RelCollationTraitDef.INSTANCE);
if (trait == null) {
return ImmutableList.of();
}
if (trait instanceof RelCompositeTrait) {
return ((RelCompositeTrait<RelCollation>) trait).traitList();
}
return ImmutableList.of(trait);
}

/**
* Returns the size of the RelTraitSet.
*
Expand Down
43 changes: 43 additions & 0 deletions core/src/test/resources/sql/sort.iq
Original file line number Diff line number Diff line change
Expand Up @@ -465,4 +465,47 @@ order by arr desc nulls first;

!ok

# [CALCITE-7374] NULLS LAST throws ClassCastException when sorting arrays
select * from
(values
(2, array[null, 3]),
(3, array[3, 4]),
(1, array[1, 2]),
(4, array[4, 5]),
(5, cast(null as integer array))) as t(id, arr)
order by arr nulls last;
+----+-----------+
| ID | ARR |
+----+-----------+
| 1 | [1, 2] |
| 3 | [3, 4] |
| 4 | [4, 5] |
| 2 | [null, 3] |
| 5 | |
+----+-----------+
(5 rows)

!ok

select * from
(values
(2, array[null, 3]),
(3, array[3, 4]),
(1, array[1, 2]),
(4, array[4, 5]),
(5, cast(null as integer array))) as t(id, arr)
order by arr desc nulls last;
+----+-----------+
| ID | ARR |
+----+-----------+
| 2 | [null, 3] |
| 4 | [4, 5] |
| 3 | [3, 4] |
| 1 | [1, 2] |
| 5 | |
+----+-----------+
(5 rows)

!ok

# End sort.iq
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,8 @@ private static class NullsFirstComparator
} else if (o1 instanceof Object[] && o2 instanceof Object[]) {
return compareObjectArrays((Object[]) o1, (Object[]) o2);
} else {
throw new IllegalArgumentException();
throw new IllegalArgumentException("Item types do not match: "
+ o1.getClass() + " vs " + o2.getClass());
}
}
}
Expand All @@ -582,15 +583,16 @@ private static class NullsLastComparator
} else if (o1 instanceof Object[] && o2 instanceof Object[]) {
return compareObjectArrays((Object[]) o1, (Object[]) o2);
} else {
throw new IllegalArgumentException();
throw new IllegalArgumentException("Item types do not match: "
+ o1.getClass() + " vs " + o2.getClass());
}
}
}

/** Nulls first reverse comparator. */
private static class NullsFirstReverseComparator
implements Comparator<Object>, Serializable {
@Override public int compare(Object o1, Object o2) {
@Override public int compare(@Nullable Object o1, @Nullable Object o2) {
if (o1 == o2) {
return 0;
}
Expand All @@ -608,7 +610,8 @@ private static class NullsFirstReverseComparator
} else if (o1 instanceof Object[] && o2 instanceof Object[]) {
return -compareObjectArrays((Object[]) o1, (Object[]) o2);
} else {
throw new IllegalArgumentException();
throw new IllegalArgumentException("Item types do not match: "
+ o1.getClass() + " vs " + o2.getClass());
}
}
}
Expand Down Expand Up @@ -707,8 +710,8 @@ public static int compareObjectArrays(@Nullable Object @Nullable [] b0,

/** Nulls last reverse comparator. */
private static class NullsLastReverseComparator
implements Comparator<Comparable>, Serializable {
@Override public int compare(Comparable o1, Comparable o2) {
implements Comparator<Object>, Serializable {
@Override public int compare(@Nullable Object o1, @Nullable Object o2) {
if (o1 == o2) {
return 0;
}
Expand All @@ -718,8 +721,17 @@ private static class NullsLastReverseComparator
if (o2 == null) {
return -1;
}
//noinspection unchecked
return -o1.compareTo(o2);
if (o1 instanceof Comparable && o2 instanceof Comparable) {
//noinspection unchecked
return -((Comparable) o1).compareTo(o2);
} else if (o1 instanceof List && o2 instanceof List) {
return -compareLists((List<?>) o1, (List<?>) o2);
} else if (o1 instanceof Object[] && o2 instanceof Object[]) {
return -compareObjectArrays((Object[]) o1, (Object[]) o2);
} else {
throw new IllegalArgumentException("Item types do not match: "
+ o1.getClass() + " vs " + o2.getClass());
}
}
}

Expand Down
Loading