Skip to content
Open
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 @@ -1445,69 +1445,38 @@ public RexNode visitInputRef(RexInputRef inputRef) {
/**
* Check if given {@link RexNode} is a 'loss-less' cast, that is, a cast from which the original value of the field can be certainly
* recovered.
*
* @see RexUtil#isLosslessCast(RexNode)
*/
public static boolean isLosslessCast(RexNode node) {
if (!node.isA(SqlKind.CAST)) {
return false;
}
return node.isA(SqlKind.CAST) && isLosslessCast(((RexCall) node).getOperands().get(0).getType(), node.getType());

RelDataType source = ((RexCall) node).getOperands().get(0).getType();
RelDataType target = node.getType();
}

/**
* Returns whether the conversion from source to target type is a 'loss-less' cast.
*
* @see RexUtil#isLosslessCast(RelDataType, RelDataType)
*/
private static boolean isLosslessCast(RelDataType source, RelDataType target) {
// Discard casts of different type families.
if (source.getFamily() != target.getFamily()) {
return false;
}

if (SqlTypeUtil.isExactNumeric(source) && target.getSqlTypeName() == SqlTypeName.DECIMAL) {
int tp = target.getPrecision();
int ts = target.getScale();
int sp = source.getPrecision();
int ss = source.getScale();

return ts >= ss && (tp - ts) >= (sp - ss);
}

// Extend support for CHARACTER with PRECISION_NOT_SPECIFIED.
if (SqlTypeFamily.CHARACTER.getTypeNames().contains(source.getSqlTypeName())
&& SqlTypeFamily.CHARACTER.getTypeNames().contains(target.getSqlTypeName())) {
return target.getSqlTypeName().compareTo(source.getSqlTypeName()) >= 0
&& (source.getPrecision() <= target.getPrecision() || target.getPrecision() == RelDataType.PRECISION_NOT_SPECIFIED);
}

if (source.getSqlTypeName() == target.getSqlTypeName() && SqlTypeUtil.isDatetime(source)) {
return source.getPrecision() <= target.getPrecision();
// Add support for temporal types.
if (source.getSqlTypeName() == target.getSqlTypeName() && SqlTypeName.DATETIME_TYPES.contains(source.getSqlTypeName())) {
return (source.getPrecision() <= target.getPrecision() || target.getPrecision() == RelDataType.PRECISION_NOT_SPECIFIED);
}

return isLosslessCast(source, target);
}

// TODO: https://issues.apache.org/jira/browse/IGNITE-27390
// This is copy of RexUtil.isLosslessCast from Calcite 1.40. We should replace RexUtils.isLosslessCast
// with calcite's implementation.
private static boolean isLosslessCast(RelDataType source, RelDataType target) {
final SqlTypeName sourceSqlTypeName = source.getSqlTypeName();
final SqlTypeName targetSqlTypeName = target.getSqlTypeName();
// 1) Both INT numeric types
if (SqlTypeFamily.INTEGER.getTypeNames().contains(sourceSqlTypeName)
&& SqlTypeFamily.INTEGER.getTypeNames().contains(targetSqlTypeName)) {
return targetSqlTypeName.compareTo(sourceSqlTypeName) >= 0;
}
// 2) Both CHARACTER types: it depends on the precision (length)
if (SqlTypeFamily.CHARACTER.getTypeNames().contains(sourceSqlTypeName)
&& SqlTypeFamily.CHARACTER.getTypeNames().contains(targetSqlTypeName)) {
return targetSqlTypeName.compareTo(sourceSqlTypeName) >= 0
&& source.getPrecision() <= target.getPrecision();
}
// 3) From NUMERIC family to CHARACTER family: it depends on the precision/scale
if (sourceSqlTypeName.getFamily() == SqlTypeFamily.NUMERIC
&& targetSqlTypeName.getFamily() == SqlTypeFamily.CHARACTER) {
int sourceLength = source.getPrecision() + 1; // include sign
if (source.getScale() != -1 && source.getScale() != 0) {
sourceLength += source.getScale() + 1; // include decimal mark
}
final int targetPrecision = target.getPrecision();
return targetPrecision == RelDataType.PRECISION_NOT_SPECIFIED || targetPrecision >= sourceLength;
}
// Return FALSE by default
return false;
// Finally, fallback to original method.
return RexUtil.isLosslessCast(source, target);
}
}