/* * 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.relopt; import org.eigenbase.rel.*; import org.eigenbase.rel.convert.*; import com.google.common.cache.*; /** * RelTraitDef represents a class of {@link RelTrait}s. Implementations of * RelTraitDef may be singletons under the following conditions: * * <ol> * <li>if the set of all possible associated RelTraits is finite and fixed (e.g. * all RelTraits for this RelTraitDef are known at compile time). For example, * the CallingConvention trait meets this requirement, because CallingConvention * is effectively an enumeration.</li> * <li>Either * * <ul> * <li> {@link #canConvert(RelOptPlanner, RelTrait, RelTrait)} and {@link * #convert(RelOptPlanner, RelNode, RelTrait, boolean)} do not require * planner-instance-specific information, <b>or</b></li> * <li>the RelTraitDef manages separate sets of conversion data internally. See * {@link ConventionTraitDef} for an example of this.</li> * </ul> * </li> * </ol> * * <p>Otherwise, a new instance of RelTraitDef must be constructed and * registered with each new planner instantiated.</p> * * @param <T> Trait that this trait definition is based upon */ public abstract class RelTraitDef<T extends RelTrait> { //~ Instance fields -------------------------------------------------------- private final LoadingCache<T, T> canonicalMap = CacheBuilder.newBuilder() .softValues() .build( new CacheLoader<T, T>() { @Override public T load(T key) throws Exception { return key; } }); //~ Constructors ----------------------------------------------------------- protected RelTraitDef() { } //~ Methods ---------------------------------------------------------------- /** * Whether a relational expression may possess more than one instance of * this trait simultaneously. * * <p>A subset has only one instance of a trait.</p> */ public boolean multiple() { return false; } /** * @return the specific RelTrait type associated with this RelTraitDef. */ public abstract Class<T> getTraitClass(); /** * @return a simple name for this RelTraitDef (for use in * {@link org.eigenbase.rel.RelNode#explain(RelWriter)}). */ public abstract String getSimpleName(); /** * Takes an arbitrary RelTrait and returns the canonical representation of * that RelTrait. Canonized RelTrait objects may always be compared using * the equality operator (<code>==</code>). * * <p>If an equal RelTrait has already been canonized and is still in use, * it will be returned. Otherwise, the given RelTrait is made canonical and * returned. * * @param trait a possibly non-canonical RelTrait * @return a canonical RelTrait. */ public final T canonize(T trait) { assert getTraitClass().isInstance(trait) : getClass().getName() + " cannot canonize a " + trait.getClass().getName(); return canonicalMap.getUnchecked(trait); } /** * Converts the given RelNode to the given RelTrait. * * @param planner the planner requesting the conversion * @param rel RelNode to convert * @param toTrait RelTrait to convert to * @param allowInfiniteCostConverters flag indicating whether infinite cost * converters are allowed * @return a converted RelNode or null if conversion is not possible */ public abstract RelNode convert( RelOptPlanner planner, RelNode rel, T toTrait, boolean allowInfiniteCostConverters); /** * Tests whether the given RelTrait can be converted to another RelTrait. * * @param planner the planner requesting the conversion test * @param fromTrait the RelTrait to convert from * @param toTrait the RelTrait to convert to * @return true if fromTrait can be converted to toTrait */ public abstract boolean canConvert( RelOptPlanner planner, T fromTrait, T toTrait); /** * Provides notification of the registration of a particular {@link * ConverterRule} with a {@link RelOptPlanner}. The default implementation * does nothing. * * @param planner the planner registering the rule * @param converterRule the registered converter rule */ public void registerConverterRule( RelOptPlanner planner, ConverterRule converterRule) { } /** * Provides notification that a particular {@link ConverterRule} has been * de-registered from a {@link RelOptPlanner}. The default implementation * does nothing. * * @param planner the planner registering the rule * @param converterRule the registered converter rule */ public void deregisterConverterRule( RelOptPlanner planner, ConverterRule converterRule) { } /** * Returns the default member of this trait. */ public abstract T getDefault(); } // End RelTraitDef.java