Skip to content

Commit 42862af

Browse files
committed
[CALCITE-7499] COALESCE with args of different types might be simplified wrong
1 parent 97fd524 commit 42862af

2 files changed

Lines changed: 65 additions & 1 deletion

File tree

core/src/main/java/org/apache/calcite/rex/RexSimplify.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1324,7 +1324,7 @@ private RexNode simplifyCoalesce(RexCall call) {
13241324
case 0:
13251325
return rexBuilder.makeNullLiteral(call.type);
13261326
case 1:
1327-
return operands.get(0);
1327+
return rexBuilder.ensureType(call.type, operands.get(0), true);
13281328
default:
13291329
if (operands.equals(call.operands)) {
13301330
return call;

core/src/test/java/org/apache/calcite/rex/RexProgramTest.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3724,6 +3724,70 @@ private void assertTypeAndToString(
37243724
"COALESCE(?0.decimal0, ?0.decimal1)");
37253725
}
37263726

3727+
/** Unit test for
3728+
* <a href="https://issues.apache.org/jira/browse/CALCITE-7499">[CALCITE-7499]
3729+
* COALESCE doesn't take into account leastRestrictiveType for input args</a>. */
3730+
@Test void testSimplifyCoalescePreservesLeastRestrictiveReturnType() {
3731+
final RelDataType tinyint = typeFactory.createSqlType(SqlTypeName.TINYINT);
3732+
final RelDataType tinyintNullable = nullable(tinyint);
3733+
3734+
checkSimplify(
3735+
coalesce(nullInt,
3736+
literal(BigDecimal.ONE, tInt()),
3737+
literal(BigDecimal.valueOf(2L), tBigInt())),
3738+
"1:BIGINT");
3739+
3740+
checkSimplify(
3741+
coalesce(nullSmallInt,
3742+
literal(BigDecimal.ONE, tSmallInt()),
3743+
literal(BigDecimal.valueOf(2L), tBigInt())),
3744+
"1:BIGINT");
3745+
3746+
checkSimplify(
3747+
coalesce(nullSmallInt,
3748+
literal(BigDecimal.ONE, tSmallInt()),
3749+
literal(BigDecimal.valueOf(42L), tInt())),
3750+
"1");
3751+
3752+
checkSimplify(
3753+
coalesce(null_(tinyintNullable),
3754+
literal(BigDecimal.valueOf(7L), tinyint),
3755+
literal(BigDecimal.valueOf(42L), tInt())),
3756+
"7");
3757+
3758+
checkSimplify(
3759+
coalesce(null_(tinyintNullable),
3760+
literal(BigDecimal.valueOf(7L), tinyint),
3761+
literal(BigDecimal.valueOf(42L), tBigInt())),
3762+
"7:BIGINT");
3763+
3764+
// Two narrow operands then a wide one.
3765+
checkSimplify(
3766+
coalesce(nullSmallInt,
3767+
literal(BigDecimal.valueOf(11L), tSmallInt()),
3768+
literal(BigDecimal.valueOf(22L), tInt()),
3769+
literal(BigDecimal.valueOf(33L), tBigInt())),
3770+
"11:BIGINT");
3771+
3772+
// ---- DECIMAL: precision widening (same scale, so the underlying BigDecimal value is
3773+
final RelDataType dec5_2 = typeFactory.createSqlType(SqlTypeName.DECIMAL, 5, 2);
3774+
final RelDataType dec10_2 = typeFactory.createSqlType(SqlTypeName.DECIMAL, 10, 2);
3775+
checkSimplify(
3776+
coalesce(null_(nullable(dec5_2)),
3777+
literal(new BigDecimal("1.23"), dec5_2),
3778+
literal(new BigDecimal("9876543.21"), dec10_2)),
3779+
"1.23:DECIMAL(10, 2)");
3780+
3781+
// ---- TIMESTAMP: precision widening ----
3782+
final RelDataType ts0 = typeFactory.createSqlType(SqlTypeName.TIMESTAMP, 0);
3783+
checkSimplify(
3784+
coalesce(rexBuilder.makeNullLiteral(nullable(ts0)),
3785+
rexBuilder.makeTimestampLiteral(new TimestampString("2026-01-01 00:00:00"), 0),
3786+
rexBuilder.makeTimestampLiteral(
3787+
new TimestampString("2026-01-01 00:00:00.123"), 3)),
3788+
"2026-01-01 00:00:00:TIMESTAMP(3)");
3789+
}
3790+
37273791
@Test void simplifyNull() {
37283792
checkSimplify3(nullBool, "null:BOOLEAN", "false", "true");
37293793
// null int must not be simplified to false

0 commit comments

Comments
 (0)