org.apache.drill.exec.planner.common.DrillRelOptUtil 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 org.apache.drill.exec.planner.common;
import java.util.AbstractList;
import java.util.List;
import com.google.common.collect.Lists;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Project;
import org.apache.calcite.rel.logical.LogicalCalc;
import org.apache.calcite.rel.rules.ProjectRemoveRule;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rex.RexInputRef;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.sql.validate.SqlValidatorUtil;
import org.apache.calcite.util.Pair;
import org.apache.drill.common.types.TypeProtos;
import org.apache.drill.common.types.Types;
import org.apache.drill.exec.resolver.TypeCastRules;
/**
* Utility class that is a subset of the RelOptUtil class and is a placeholder for Drill specific
* static methods that are needed during either logical or physical planning.
*/
public abstract class DrillRelOptUtil {
// Similar to RelOptUtil.areRowTypesEqual() with the additional check for allowSubstring
public static boolean areRowTypesCompatible(
RelDataType rowType1,
RelDataType rowType2,
boolean compareNames,
boolean allowSubstring) {
if (rowType1 == rowType2) {
return true;
}
if (compareNames) {
// if types are not identity-equal, then either the names or
// the types must be different
return false;
}
if (rowType2.getFieldCount() != rowType1.getFieldCount()) {
return false;
}
final List f1 = rowType1.getFieldList();
final List f2 = rowType2.getFieldList();
for (Pair pair : Pair.zip(f1, f2)) {
final RelDataType type1 = pair.left.getType();
final RelDataType type2 = pair.right.getType();
// If one of the types is ANY comparison should succeed
if (type1.getSqlTypeName() == SqlTypeName.ANY
|| type2.getSqlTypeName() == SqlTypeName.ANY) {
continue;
}
if (type1.getSqlTypeName() != type2.getSqlTypeName()) {
if (allowSubstring
&& (type1.getSqlTypeName() == SqlTypeName.CHAR && type2.getSqlTypeName() == SqlTypeName.CHAR)
&& (type1.getPrecision() <= type2.getPrecision())) {
return true;
}
// Check if Drill implicit casting can resolve the incompatibility
List types = Lists.newArrayListWithCapacity(2);
types.add(Types.getMinorTypeFromName(type1.getSqlTypeName().getName()));
types.add(Types.getMinorTypeFromName(type2.getSqlTypeName().getName()));
if(TypeCastRules.getLeastRestrictiveType(types) != null) {
return true;
}
return false;
}
}
return true;
}
/**
* Returns a relational expression which has the same fields as the
* underlying expression, but the fields have different names.
*
*
* @param rel Relational expression
* @param fieldNames Field names
* @return Renamed relational expression
*/
public static RelNode createRename(
RelNode rel,
final List fieldNames) {
final List fields = rel.getRowType().getFieldList();
assert fieldNames.size() == fields.size();
final List refs =
new AbstractList() {
public int size() {
return fields.size();
}
public RexNode get(int index) {
return RexInputRef.of(index, fields);
}
};
return RelOptUtil.createProject(rel, refs, fieldNames, false);
}
public static boolean isTrivialProject(Project project, boolean useNamesInIdentityProjCalc) {
if (!useNamesInIdentityProjCalc) {
return ProjectRemoveRule.isTrivial(project);
} else {
return containIdentity(project.getProjects(), project.getRowType(), project.getInput().getRowType());
}
}
/** Returns a rowType having all unique field name.
*
* @param rowType : input rowType
* @param typeFactory : type factory used to create a new row type.
* @return
*/
public static RelDataType uniqifyFieldName(final RelDataType rowType, final RelDataTypeFactory typeFactory) {
return typeFactory.createStructType(RelOptUtil.getFieldTypeList(rowType),
SqlValidatorUtil.uniquify(rowType.getFieldNames()));
}
/**
* Returns whether the leading edge of a given array of expressions is
* wholly {@link RexInputRef} objects with types and names corresponding
* to the underlying row type. */
private static boolean containIdentity(List extends RexNode> exps,
RelDataType rowType, RelDataType childRowType) {
List fields = rowType.getFieldList();
List childFields = childRowType.getFieldList();
int fieldCount = childFields.size();
if (exps.size() != fieldCount) {
return false;
}
for (int i = 0; i < exps.size(); i++) {
RexNode exp = exps.get(i);
if (!(exp instanceof RexInputRef)) {
return false;
}
RexInputRef var = (RexInputRef) exp;
if (var.getIndex() != i) {
return false;
}
if (!fields.get(i).getName().equals(childFields.get(i).getName())) {
return false;
}
if (!fields.get(i).getType().equals(childFields.get(i).getType())) {
return false;
}
}
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy