Skip to content

Commit

Permalink
[CALCITE-6480] OracleDialect does not support CASE WHEN returning boo…
Browse files Browse the repository at this point in the history
…lean
  • Loading branch information
suibianwanwan committed Aug 1, 2024
1 parent 9fa1e16 commit 638df57
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,31 @@ public SqlNode toSql(@Nullable RexProgram program, RexNode rex) {
}
}
elseNode = caseNodeList.get(caseNodeList.size() - 1);

if (caseCall.getType().getSqlTypeName() == SqlTypeName.BOOLEAN
&& !dialect.supportBooleanCaseWhen()) {
// Transformed when expressions of boolean type in SqlCase
// For example, given
// CASE WHEN x > 1 THEN y > 1 ELSE y < 10 END
// Transformed:
// CASE WHEN x > 1 THEN CASE WHEN y > 1 THEN 1 ELSE 0 END
// ELSE CASE WHEN y < 10 THEN 1 ELSE 0 END END = 1
final List<SqlNode> thenList2 = thenList.stream()
.map(
thenNode -> new SqlCase(POS, null, SqlNodeList.of(thenNode),
SqlNodeList.of(ONE), SqlNodeList.of(ZERO)))
.collect(SqlNode.toList());
final SqlNode elseNode2 =
new SqlCase(POS, null, SqlNodeList.of(elseNode),
SqlNodeList.of(ONE), SqlNodeList.of(ZERO));

final SqlCase sqlCase =
new SqlCase(POS, valueNode,
new SqlNodeList(whenList, POS),
new SqlNodeList(thenList2, POS), elseNode2);
return SqlStdOperatorTable.EQUALS.createCall(POS, sqlCase, ONE);
}

return new SqlCase(POS, valueNode, new SqlNodeList(whenList, POS),
new SqlNodeList(thenList, POS), elseNode);

Expand Down
5 changes: 5 additions & 0 deletions core/src/main/java/org/apache/calcite/sql/SqlDialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,11 @@ public boolean supportsWindowFunctions() {
return true;
}

/** Returns whether this dialect supports case when return boolean type. */
public boolean supportBooleanCaseWhen() {
return true;
}

/** Returns whether this dialect supports a given function or operator.
* It only applies to built-in scalar functions and operators, since
* user-defined functions and procedures should be read by JdbcSchema. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ public OracleSqlDialect(Context context) {
return false;
}

@Override public boolean supportBooleanCaseWhen() {
return majorVersion >= 23;
}

@Override public boolean supportsDataType(RelDataType type) {
switch (type.getSqlTypeName()) {
case BOOLEAN:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7774,6 +7774,62 @@ private void checkLiteral2(String expression, String expected) {
.withOracle(11).ok(expectedVersionLow);
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-6480">[CALCITE-6482]
* OracleDialect does not support CASE WHEN returning boolean < 23</a>. */
@Test void testBooleanCaseWhenOracle() {
String query0 = "SELECT \"e1\".\"department_id\" "
+ "FROM \"employee\" \"e1\""
+ "LEFT JOIN \"employee\" \"e2\""
+ "ON CASE WHEN \"e2\".\"employee_id\" = 'a' "
+ "THEN \"e1\".\"department_id\" > 10 "
+ "WHEN \"e2\".\"employee_id\" = 'b' "
+ "THEN \"e1\".\"department_id\" > 20 "
+ "ELSE \"e2\".\"employee_id\" = 'c' END";
String expectedVersionLow0 = "SELECT \"employee\".\"department_id\"\n"
+ "FROM \"foodmart\".\"employee\"\n"
+ "LEFT JOIN \"foodmart\".\"employee\" \"employee0\" "
+ "ON CASE WHEN \"employee0\".\"employee_id\" = 'a' "
+ "THEN CASE WHEN \"employee\".\"department_id\" > 10 "
+ "THEN 1 ELSE 0 END WHEN \"employee0\".\"employee_id\" = 'b' "
+ "THEN CASE WHEN \"employee\".\"department_id\" > 20 "
+ "THEN 1 ELSE 0 END ELSE CASE WHEN \"employee0\".\"employee_id\" = 'c' "
+ "THEN 1 ELSE 0 END END = 1";
String expectedVersionHigh0 = "SELECT \"employee\".\"department_id\"\n"
+ "FROM \"foodmart\".\"employee\"\n"
+ "LEFT JOIN \"foodmart\".\"employee\" \"employee0\" "
+ "ON CASE WHEN \"employee0\".\"employee_id\" = 'a' "
+ "THEN \"employee\".\"department_id\" > 10 "
+ "WHEN \"employee0\".\"employee_id\" = 'b' "
+ "THEN \"employee\".\"department_id\" > 20"
+ " ELSE \"employee0\".\"employee_id\" = 'c' END";

String query1 = "SELECT \"department_id\" "
+ "FROM \"employee\""
+ "WHERE CASE \"employee_id\" "
+ "WHEN 'a' THEN \"department_id\" > 10 "
+ "WHEN 'b' THEN \"department_id\" > 20 "
+ "ELSE TRUE END";
String expectedVersionLow1 = "SELECT \"department_id\"\n"
+ "FROM \"foodmart\".\"employee\"\n"
+ "WHERE CASE WHEN \"employee_id\" = 'a' THEN CASE WHEN \"department_id\" > 10 THEN 1 ELSE 0 END "
+ "WHEN \"employee_id\" = 'b' THEN CASE WHEN \"department_id\" > 20 THEN 1 ELSE 0 END ELSE "
+ "CASE WHEN (1 = 1) THEN 1 ELSE 0 END END = 1";
String expectedVersionHigh1 = "SELECT \"department_id\"\n"
+ "FROM \"foodmart\".\"employee\"\n"
+ "WHERE CASE WHEN \"employee_id\" = 'a' THEN \"department_id\" > 10 "
+ "WHEN \"employee_id\" = 'b' THEN \"department_id\" > 20 "
+ "ELSE TRUE END";

sql(query0)
.withOracle(23).ok(expectedVersionHigh0)
.withOracle(11).ok(expectedVersionLow0);

sql(query1)
.withOracle(23).ok(expectedVersionHigh1)
.withOracle(11).ok(expectedVersionLow1);
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-5265">[CALCITE-5265]
* JDBC adapter sometimes adds unnecessary parentheses around SELECT in INSERT</a>. */
Expand Down

0 comments on commit 638df57

Please sign in to comment.