/*
* 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 org.eigenbase.rel;
import java.util.*;
import org.eigenbase.relopt.RelOptPlanner;
import org.eigenbase.relopt.RelTrait;
import org.eigenbase.relopt.RelTraitDef;
import org.eigenbase.reltype.*;
import org.eigenbase.util.Util;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
/**
* Simple implementation of {@link RelCollation}.
*/
public class RelCollationImpl implements RelCollation {
//~ Static fields/initializers ---------------------------------------------
/**
* A collation indicating that a relation is not sorted. Ordering by no
* columns.
*/
public static final RelCollation EMPTY =
RelCollationTraitDef.INSTANCE.canonize(
new RelCollationImpl(ImmutableList.<RelFieldCollation>of()));
/**
* A collation that cannot be replicated by applying a sort. The only
* implementation choice is to apply operations that preserve order.
*/
public static final RelCollation PRESERVE =
RelCollationTraitDef.INSTANCE.canonize(
new RelCollationImpl(
ImmutableList.of(new RelFieldCollation(-1))) {
public String toString() {
return "PRESERVE";
}
});
//~ Instance fields --------------------------------------------------------
private final ImmutableList<RelFieldCollation> fieldCollations;
//~ Constructors -----------------------------------------------------------
protected RelCollationImpl(ImmutableList<RelFieldCollation> fieldCollations) {
this.fieldCollations = fieldCollations;
}
public static RelCollation of(RelFieldCollation... fieldCollations) {
return new RelCollationImpl(ImmutableList.copyOf(fieldCollations));
}
public static RelCollation of(List<RelFieldCollation> fieldCollations) {
return new RelCollationImpl(ImmutableList.copyOf(fieldCollations));
}
//~ Methods ----------------------------------------------------------------
public RelTraitDef getTraitDef() {
return RelCollationTraitDef.INSTANCE;
}
public List<RelFieldCollation> getFieldCollations() {
return fieldCollations;
}
public int hashCode() {
return fieldCollations.hashCode();
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof RelCollationImpl) {
RelCollationImpl that = (RelCollationImpl) obj;
return this.fieldCollations.equals(that.fieldCollations);
}
return false;
}
public void register(RelOptPlanner planner) {}
public boolean subsumes(RelTrait trait) {
return this == trait
|| trait instanceof RelCollationImpl
&& Util.startsWith(fieldCollations,
((RelCollationImpl) trait).fieldCollations);
}
/** Returns a string representation of this collation, suitably terse given
* that it will appear in plan traces. Examples:
* "[]", "[2]", "[0 DESC, 1]", "[0 DESC, 1 ASC NULLS LAST]". */
public String toString() {
Iterator<RelFieldCollation> it = fieldCollations.iterator();
if (! it.hasNext()) {
return "[]";
}
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
RelFieldCollation e = it.next();
sb.append(e.getFieldIndex());
if (e.direction != RelFieldCollation.Direction.ASCENDING
|| e.nullDirection != RelFieldCollation.NullDirection.UNSPECIFIED) {
sb.append(' ').append(e.shortString());
}
if (!it.hasNext()) {
return sb.append(']').toString();
}
sb.append(',').append(' ');
}
}
/**
* Creates a list containing one collation containing one field.
*/
public static List<RelCollation> createSingleton(int fieldIndex) {
return ImmutableList.of(
of(
new RelFieldCollation(fieldIndex,
RelFieldCollation.Direction.ASCENDING,
RelFieldCollation.NullDirection.UNSPECIFIED)));
}
/**
* Checks that a collection of collations is valid.
*
* @param rowType Row type of the relational expression
* @param collationList List of collations
* @param fail Whether to fail if invalid
* @return Whether valid
*/
public static boolean isValid(
RelDataType rowType,
List<RelCollation> collationList,
boolean fail) {
final int fieldCount = rowType.getFieldCount();
for (RelCollation collation : collationList) {
for (RelFieldCollation fieldCollation : collation.getFieldCollations()) {
final int index = fieldCollation.getFieldIndex();
if (index < 0 || index >= fieldCount) {
assert !fail;
return false;
}
}
}
return true;
}
public static boolean equal(
List<RelCollation> collationList1,
List<RelCollation> collationList2) {
return collationList1.equals(collationList2);
}
/** Returns the indexes of the field collations in a given collation. */
public static List<Integer> ordinals(RelCollation collation) {
return Lists.transform(collation.getFieldCollations(),
new Function<RelFieldCollation, Integer>() {
public Integer apply(RelFieldCollation input) {
return input.getFieldIndex();
}
});
}
}
// End RelCollationImpl.java