Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CALCITE-6751] Reduction of CAST from string to interval is incorrect #4116

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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 @@ -304,8 +304,8 @@ Expression translateCast(
ConstantExpression format) {
Expression convert = getConvertExpression(sourceType, targetType, operand, format);
Expression convert2 = checkExpressionPadTruncate(convert, sourceType, targetType);
Expression convert3 = expressionHandlingSafe(convert2, safe, targetType);
return scaleValue(sourceType, targetType, convert3);
Expression convert3 = scaleValue(sourceType, targetType, convert2);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the right order to do the conversion: first scaling, then checking for safety.
Otherwise the safe cast implementation returns null, which cannot be an input for the scaling computation.

return expressionHandlingSafe(convert3, safe, targetType);
}

private Expression getConvertExpression(
Expand Down Expand Up @@ -1195,7 +1195,7 @@ private static Expression scaleValue(
final SqlTypeFamily sourceFamily = sourceType.getSqlTypeName().getFamily();
if (targetFamily == SqlTypeFamily.NUMERIC
// multiplyDivide cannot handle DECIMALs, but for DECIMAL
// destination types the result is already scaled.
// target types the result is already scaled.
&& targetType.getSqlTypeName() != SqlTypeName.DECIMAL
&& (sourceFamily == SqlTypeFamily.INTERVAL_YEAR_MONTH
|| sourceFamily == SqlTypeFamily.INTERVAL_DAY_TIME)) {
Expand All @@ -1205,6 +1205,11 @@ private static Expression scaleValue(
sourceType.getSqlTypeName().getEndUnit().multiplier;
return RexImpTable.multiplyDivide(operand, multiplier, divider);
}
if (SqlTypeName.INTERVAL_TYPES.contains(targetType.getSqlTypeName())) {
final BigDecimal multiplier = targetType.getSqlTypeName().getEndUnit().multiplier;
final BigDecimal divider = BigDecimal.ONE;
return RexImpTable.multiplyDivide(operand, multiplier, divider);
}
return operand;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4271,6 +4271,10 @@ public static int toInt(java.sql.Time v) {
return v == null ? castNonNull(null) : toInt(v);
}

// Method tagged as non-deterministic because it can throw.
// The DeterministicCodeOptimizer may otherwise try to lift it out of try-catch blocks.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the indent.

// See https://issues.apache.org/jira/browse/CALCITE-6753
ILuffZhe marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CALCITE-6753 can be resolved in an independent PR.

@NonDeterministic
public static int toInt(String s) {
return parseInt(s.trim());
}
Expand Down
34 changes: 34 additions & 0 deletions core/src/test/resources/sql/misc.iq
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,40 @@
!use post
!set outputformat mysql

# [CALCITE-6751] Reduction of CAST from string to interval is incorrect
SELECT TIME '10:00:00' + CAST('1' AS INTERVAL SECOND);
+----------+
| EXPR$0 |
+----------+
| 10:00:01 |
+----------+
(1 row)

!ok

# Unfortunately, due to CALCITE-6752 the following test crashes
# SELECT TIME '10:00:00' + CAST('1.1' AS INTERVAL SECOND);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the annotations here add the correct results?Even if it can't run here.

#
SELECT TIME '10:00:00' + CAST('1' AS INTERVAL HOUR);
+----------+
| EXPR$0 |
+----------+
| 11:00:00 |
+----------+
(1 row)

!ok

SELECT TIME '10:00:00' + CAST('1' AS INTERVAL MINUTE);
+----------+
| EXPR$0 |
+----------+
| 10:01:00 |
+----------+
(1 row)

!ok

# Compared by casting varchar to number
SELECT '1' > 0 AS C;
+------+
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,13 @@ static void assertQuery(
try {
if (updateChecker == null) {
resultSet = statement.executeQuery(sql);
if (resultChecker == null && exceptionChecker != null) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a separate bug, which was uncovered by the @NonDeterministic annotation on toInt. The exception was happening at compilation time, instead of runtime. This change is necessary to uncover exceptions that happen at runtime.

// Pull data from result set, otherwise exceptions that happen during evaluation
// won't be triggered
while (resultSet.next()) {
// no need to do anything with the data
}
}
} else {
updateCount = statement.executeUpdate(sql);
}
Expand Down
Loading