Skip to content

Commit

Permalink
[CALCITE-528] When making field names unique, follow type system's ca…
Browse files Browse the repository at this point in the history
…se-sensitivity policy (Jacques Nadeau, Jinfeng Ni, Minji Kim)

Ensure that uniquify keeps the ordinal position of input names (Jinfeng Ni).

Add tests (Minji Kim).

Fix up (Julian Hyde).

Close apache#245
  • Loading branch information
jacques-n authored and julianhyde committed Jun 15, 2016
1 parent 0599cdd commit acd27fd
Show file tree
Hide file tree
Showing 25 changed files with 621 additions and 199 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ public RelNode createProject(RelNode child,
final RelOptCluster cluster = child.getCluster();
final RelDataType rowType =
RexUtil.createStructType(cluster.getTypeFactory(), projects,
fieldNames == null ? null
: SqlValidatorUtil.uniquify(fieldNames,
SqlValidatorUtil.F_SUGGESTER));
fieldNames, SqlValidatorUtil.F_SUGGESTER);
return EnumerableProject.create(child, projects, rowType);
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ private Lattice(CalciteSchema rootSchema, ImmutableList<Node> nodes,
}
uniqueColumnNames =
ImmutableList.copyOf(
SqlValidatorUtil.uniquify(Lists.transform(columns, GET_ALIAS)));
SqlValidatorUtil.uniquify(Lists.transform(columns, GET_ALIAS), true));
if (rowCountEstimate == null) {
// We could improve this when we fix
// [CALCITE-429] Add statistics SPI for lattice optimization algorithm
Expand Down
27 changes: 13 additions & 14 deletions core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.apache.calcite.rel.type.RelDataTypeFactory;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rel.type.RelDataTypeFieldImpl;
import org.apache.calcite.rel.type.RelDataTypeSystem;
import org.apache.calcite.rex.RexBuilder;
import org.apache.calcite.rex.RexCall;
import org.apache.calcite.rex.RexCorrelVariable;
Expand Down Expand Up @@ -1541,7 +1542,10 @@ public static void projectJoinInputs(
List<Integer> outputProj) {
RelNode leftRel = inputRels[0];
RelNode rightRel = inputRels[1];
RexBuilder rexBuilder = leftRel.getCluster().getRexBuilder();
final RelOptCluster cluster = leftRel.getCluster();
final RexBuilder rexBuilder = cluster.getRexBuilder();
final RelDataTypeSystem typeSystem =
cluster.getTypeFactory().getTypeSystem();

int origLeftInputSize = leftRel.getRowType().getFieldCount();
int origRightInputSize = rightRel.getRowType().getFieldCount();
Expand Down Expand Up @@ -1612,12 +1616,14 @@ public static void projectJoinInputs(
// fields
if (newLeftKeyCount > 0) {
leftRel = createProject(leftRel, newLeftFields,
SqlValidatorUtil.uniquify(newLeftFieldNames));
SqlValidatorUtil.uniquify(newLeftFieldNames,
typeSystem.isSchemaCaseSensitive()));
}

if (newRightKeyCount > 0) {
rightRel = createProject(rightRel, newRightFields,
SqlValidatorUtil.uniquify(newRightFieldNames));
SqlValidatorUtil.uniquify(newRightFieldNames,
typeSystem.isSchemaCaseSensitive()));
}

inputRels[0] = leftRel;
Expand Down Expand Up @@ -2834,27 +2840,20 @@ public static RelNode createProject(
boolean optimize,
RelFactories.ProjectFactory projectFactory) {
final RelOptCluster cluster = child.getCluster();
final List<String> fieldNames2 =
fieldNames == null
? null
: SqlValidatorUtil.uniquify(fieldNames,
SqlValidatorUtil.F_SUGGESTER);
final RelDataType rowType =
RexUtil.createStructType(cluster.getTypeFactory(), exprs,
fieldNames, SqlValidatorUtil.F_SUGGESTER);
if (optimize
&& RexUtil.isIdentity(exprs, child.getRowType())) {
if (child instanceof Project && fieldNames != null) {
final RelDataType rowType =
RexUtil.createStructType(
cluster.getTypeFactory(),
exprs,
fieldNames2);
// Rename columns of child projection if desired field names are given.
Project childProject = (Project) child;
child = childProject.copy(childProject.getTraitSet(),
childProject.getInput(), childProject.getProjects(), rowType);
}
return child;
}
return projectFactory.createProject(child, exprs, fieldNames2);
return projectFactory.createProject(child, exprs, rowType.getFieldNames());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1678,10 +1678,7 @@ public static MutableRel of(MutableRel child, List<RexNode> exprList,
List<String> fieldNameList) {
final RelDataType rowType =
RexUtil.createStructType(child.cluster.getTypeFactory(), exprList,
fieldNameList == null
? null
: SqlValidatorUtil.uniquify(fieldNameList,
SqlValidatorUtil.F_SUGGESTER));
fieldNameList, SqlValidatorUtil.F_SUGGESTER);
return of(rowType, child, exprList);
}

Expand Down Expand Up @@ -2017,8 +2014,9 @@ static MutableJoin of(RelOptCluster cluster, MutableRel left,
Set<CorrelationId> variablesStopped) {
List<RelDataTypeField> fieldList = Collections.emptyList();
RelDataType rowType =
Join.deriveJoinRowType(left.getRowType(), right.getRowType(),
joinType, cluster.getTypeFactory(), null, fieldList);
SqlValidatorUtil.deriveJoinRowType(left.getRowType(),
right.getRowType(), joinType, cluster.getTypeFactory(), null,
fieldList);
return new MutableJoin(rowType, left, right, condition, joinType,
variablesStopped);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,12 @@ public RelDataTypeFactory getTypeFactory() {

public void registerRules(RelOptPlanner planner) throws Exception {
}

@Override public boolean isCaseSensitive() {
return caseSensitive;
}


}

// End CalciteCatalogReader.java
115 changes: 9 additions & 106 deletions core/src/main/java/org/apache/calcite/rel/core/Join.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,15 @@
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexShuttle;
import org.apache.calcite.sql.type.SqlTypeName;
import org.apache.calcite.sql.validate.SqlValidatorUtil;
import org.apache.calcite.util.Litmus;
import org.apache.calcite.util.Util;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -214,12 +213,8 @@ public static double estimateJoinedRows(
}

@Override protected RelDataType deriveRowType() {
return deriveJoinRowType(
left.getRowType(),
right.getRowType(),
joinType,
getCluster().getTypeFactory(),
null,
return SqlValidatorUtil.deriveJoinRowType(left.getRowType(),
right.getRowType(), joinType, getCluster().getTypeFactory(), null,
getSystemFieldList());
}

Expand All @@ -246,119 +241,27 @@ public List<RelDataTypeField> getSystemFieldList() {
return Collections.emptyList();
}

/**
* Derives the type of a join relational expression.
*
* @param leftType Row type of left input to join
* @param rightType Row type of right input to join
* @param joinType Type of join
* @param typeFactory Type factory
* @param fieldNameList List of names of fields; if null, field names are
* inherited and made unique
* @param systemFieldList List of system fields that will be prefixed to
* output row type; typically empty but must not be
* null
* @return join type
*/
@Deprecated // to be removed before 2.0
public static RelDataType deriveJoinRowType(
RelDataType leftType,
RelDataType rightType,
JoinRelType joinType,
RelDataTypeFactory typeFactory,
List<String> fieldNameList,
List<RelDataTypeField> systemFieldList) {
assert systemFieldList != null;
switch (joinType) {
case LEFT:
rightType = typeFactory.createTypeWithNullability(rightType, true);
break;
case RIGHT:
leftType = typeFactory.createTypeWithNullability(leftType, true);
break;
case FULL:
leftType = typeFactory.createTypeWithNullability(leftType, true);
rightType = typeFactory.createTypeWithNullability(rightType, true);
break;
default:
break;
}
return createJoinType(
typeFactory, leftType, rightType, fieldNameList, systemFieldList);
return SqlValidatorUtil.deriveJoinRowType(leftType, rightType, joinType,
typeFactory, fieldNameList, systemFieldList);
}

/**
* Returns the type the row which results when two relations are joined.
*
* <p>The resulting row type consists of
* the system fields (if any), followed by
* the fields of the left type, followed by
* the fields of the right type. The field name list, if present, overrides
* the original names of the fields.
*
* @param typeFactory Type factory
* @param leftType Type of left input to join
* @param rightType Type of right input to join
* @param fieldNameList If not null, overrides the original names of the
* fields
* @param systemFieldList List of system fields that will be prefixed to
* output row type; typically empty but must not be
* null
* @return type of row which results when two relations are joined
*/
@Deprecated // to be removed before 2.0
public static RelDataType createJoinType(
RelDataTypeFactory typeFactory,
RelDataType leftType,
RelDataType rightType,
List<String> fieldNameList,
List<RelDataTypeField> systemFieldList) {
assert (fieldNameList == null)
|| (fieldNameList.size()
== (systemFieldList.size()
+ leftType.getFieldCount()
+ rightType.getFieldCount()));
List<String> nameList = new ArrayList<>();
final List<RelDataType> typeList = new ArrayList<>();

// use a hashset to keep track of the field names; this is needed
// to ensure that the contains() call to check for name uniqueness
// runs in constant time; otherwise, if the number of fields is large,
// doing a contains() on a list can be expensive
final HashSet<String> uniqueNameList = new HashSet<>();
addFields(systemFieldList, typeList, nameList, uniqueNameList);
addFields(leftType.getFieldList(), typeList, nameList, uniqueNameList);
if (rightType != null) {
addFields(
rightType.getFieldList(), typeList, nameList, uniqueNameList);
}
if (fieldNameList != null) {
assert fieldNameList.size() == nameList.size();
nameList = fieldNameList;
}
return typeFactory.createStructType(typeList, nameList);
}

private static void addFields(
List<RelDataTypeField> fieldList,
List<RelDataType> typeList,
List<String> nameList,
HashSet<String> uniqueNameList) {
for (RelDataTypeField field : fieldList) {
String name = field.getName();

// Ensure that name is unique from all previous field names
if (uniqueNameList.contains(name)) {
String nameBase = name;
for (int j = 0;; j++) {
name = nameBase + j;
if (!uniqueNameList.contains(name)) {
break;
}
}
}
nameList.add(name);
uniqueNameList.add(name);
typeList.add(field.getType());
}
return SqlValidatorUtil.createJoinType(typeFactory, leftType, rightType,
fieldNameList, systemFieldList);
}

@Override public final Join copy(RelTraitSet traitSet, List<RelNode> inputs) {
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/org/apache/calcite/rel/core/SemiJoin.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.sql.validate.SqlValidatorUtil;
import org.apache.calcite.util.ImmutableIntList;
import org.apache.calcite.util.Util;

Expand Down Expand Up @@ -114,7 +115,7 @@ public static SemiJoin create(RelNode left, RelNode right, RexNode condition,
* input only.
*/
@Override public RelDataType deriveRowType() {
return deriveJoinRowType(
return SqlValidatorUtil.deriveJoinRowType(
left.getRowType(),
null,
JoinRelType.INNER,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public LogicalProject(RelOptCluster cluster, RelNode input,
this(cluster, cluster.traitSetOf(RelCollations.EMPTY),
input, projects,
RexUtil.createStructType(cluster.getTypeFactory(), projects,
fieldNames));
fieldNames, null));
Util.discard(flags);
}

Expand All @@ -97,14 +97,9 @@ public LogicalProject(RelInput input) {
public static LogicalProject create(final RelNode input,
final List<? extends RexNode> projects, List<String> fieldNames) {
final RelOptCluster cluster = input.getCluster();
final List<String> fieldNames2 =
fieldNames == null
? null
: SqlValidatorUtil.uniquify(fieldNames,
SqlValidatorUtil.F_SUGGESTER);
final RelDataType rowType =
RexUtil.createStructType(cluster.getTypeFactory(), projects,
fieldNames2);
fieldNames, SqlValidatorUtil.F_SUGGESTER);
return create(input, projects, rowType);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -595,10 +595,7 @@ private RexProgram createProgramForLevel(
}
if (outputRowType == null) {
outputRowType =
RexUtil.createStructType(
typeFactory,
projectRefs,
fieldNames);
RexUtil.createStructType(typeFactory, projectRefs, fieldNames, null);
}
final RexProgram program =
new RexProgram(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexProgram;
import org.apache.calcite.rex.RexProgramBuilder;
import org.apache.calcite.sql.validate.SqlValidatorUtil;
import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.tools.RelBuilderFactory;
import org.apache.calcite.util.Pair;
Expand Down Expand Up @@ -180,7 +181,7 @@ public void onMatch(RelOptRuleCall call) {
// into the bottom RexProgram. Note that the join type is an inner
// join because the inputs haven't actually been joined yet.
RelDataType joinChildrenRowType =
Join.deriveJoinRowType(
SqlValidatorUtil.deriveJoinRowType(
leftJoinChild.getRowType(),
rightJoinChild.getRowType(),
JoinRelType.INNER,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import org.apache.calcite.plan.RelOptRule;
import org.apache.calcite.plan.RelOptRuleCall;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.rel.core.Join;
import org.apache.calcite.rel.core.JoinRelType;
import org.apache.calcite.rel.core.RelFactories;
import org.apache.calcite.rel.core.SemiJoin;
Expand All @@ -32,6 +31,7 @@
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexProgram;
import org.apache.calcite.rex.RexProgramBuilder;
import org.apache.calcite.sql.validate.SqlValidatorUtil;
import org.apache.calcite.tools.RelBuilder;
import org.apache.calcite.tools.RelBuilderFactory;
import org.apache.calcite.util.ImmutableIntList;
Expand Down Expand Up @@ -125,7 +125,7 @@ private RexNode adjustCondition(LogicalProject project, SemiJoin semiJoin) {
// for the bottom RexProgram, the input is a concatenation of the
// child of the project and the RHS of the semijoin
RelDataType bottomInputRowType =
Join.deriveJoinRowType(
SqlValidatorUtil.deriveJoinRowType(
project.getInput().getRowType(),
rightChild.getRowType(),
JoinRelType.INNER,
Expand Down Expand Up @@ -156,7 +156,7 @@ private RexNode adjustCondition(LogicalProject project, SemiJoin semiJoin) {
// input rowtype into the top program is the concatenation of the
// project and the RHS of the semijoin
RelDataType topInputRowType =
Join.deriveJoinRowType(
SqlValidatorUtil.deriveJoinRowType(
project.getRowType(),
rightChild.getRowType(),
JoinRelType.INNER,
Expand Down
Loading

0 comments on commit acd27fd

Please sign in to comment.