Skip to content

Commit

Permalink
Correct the decision of whether the return type is nullable
Browse files Browse the repository at this point in the history
  • Loading branch information
normanj-bitquill committed Sep 10, 2024
1 parent ab839e3 commit ed0d0f2
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 50 deletions.
38 changes: 21 additions & 17 deletions core/src/main/java/org/apache/calcite/sql/type/ReturnTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -614,33 +614,37 @@ public static SqlCall stripSeparator(SqlCall call) {
ARG0_EXCEPT_INTEGER.andThen(SqlTypeTransforms.TO_NULLABLE);

/**
* Returns the type of the first non NULL argument or INTEGER if all arguments
* are NULL.
* Chooses a type to return.
* If all arguments are null, return nullable integer type.
* If all arguments are integer types, choose the largest integer type. Nullable
* if any argument is nullable.
* As a fallback, choose the type of the first argument that is not of the NULL type.
* Nullable if at least one argument is nullable.
*/
public static final SqlReturnTypeInference LARGEST_INT_OR_FIRST_NON_NULL_DEFAULT_INTEGER =
opBinding -> {
final RelDataTypeFactory typeFactory = opBinding.getTypeFactory();
RelDataType integerReturnType = null;
RelDataType largestIntegerType = null;
RelDataType firstNonNullType = null;
boolean allArgsInteger = true;
boolean nullable = false;
for (RelDataType opType : opBinding.collectOperandTypes()) {
if (SqlTypeName.INT_TYPES.contains(opType.getSqlTypeName())) {
if (integerReturnType == null) {
integerReturnType = opType;
} else if (integerReturnType.getPrecision() < opType.getPrecision()) {
integerReturnType = opType;
}
if (firstNonNullType == null && SqlTypeName.NULL != opType.getSqlTypeName()) {
firstNonNullType = opType;
}
if (SqlTypeName.INT_TYPES.contains(opType.getSqlTypeName())
&& (largestIntegerType == null
|| largestIntegerType.getPrecision() < opType.getPrecision())) {
largestIntegerType = opType;
} else {
allArgsInteger = false;
break;
}
nullable |= opType.isNullable();
}
if (integerReturnType != null && allArgsInteger) {
return typeFactory.createTypeWithNullability(integerReturnType, true);
}
for (RelDataType opType : opBinding.collectOperandTypes()) {
if (!opType.isNullable()) {
return typeFactory.createTypeWithNullability(opType, true);
}
if (allArgsInteger && largestIntegerType != null) {
return typeFactory.createTypeWithNullability(largestIntegerType, nullable);
} else if (firstNonNullType != null) {
return typeFactory.createTypeWithNullability(firstNonNullType, nullable);
}
return typeFactory.createTypeWithNullability(
typeFactory.createSqlType(SqlTypeName.INTEGER), true);
Expand Down
66 changes: 33 additions & 33 deletions testkit/src/main/java/org/apache/calcite/test/SqlOperatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15482,19 +15482,19 @@ private static void checkLogicalOrFunc(SqlOperatorFixture f) {
final SqlOperatorFixture f = fixture();
f.setFor(SqlStdOperatorTable.BITAND, VmName.EXPAND);
f.checkFails("bitand(^*^)", "Unknown identifier '\\*'", false);
f.checkScalar("bitand(2, 3)", "2", "INTEGER");
f.checkScalar("bitand(CAST(2 AS INTEGER), CAST(3 AS BIGINT))", "2", "BIGINT");
f.checkScalar("bitand(-5, 7)", "3", "INTEGER");
f.checkScalar("bitand(-5, -31)", "-31", "INTEGER");
f.checkScalar("bitand(CAST(-5 AS TINYINT), CAST(7 AS TINYINT))", "3", "TINYINT");
f.checkScalar("bitand(CAST(-5 AS TINYINT), CAST(-31 AS TINYINT))", "-31", "TINYINT");
f.checkType("bitand(CAST(2 AS TINYINT), CAST(6 AS TINYINT))", "TINYINT");
f.checkType("bitand(CAST(2 AS SMALLINT), CAST(6 AS SMALLINT))", "SMALLINT");
f.checkType("bitand(CAST(2 AS BIGINT), CAST(6 AS BIGINT))", "BIGINT");
f.checkScalar("bitand(2, 3)", "2", "INTEGER NOT NULL");
f.checkScalar("bitand(CAST(2 AS INTEGER), CAST(3 AS BIGINT))", "2", "BIGINT NOT NULL");
f.checkScalar("bitand(-5, 7)", "3", "INTEGER NOT NULL");
f.checkScalar("bitand(-5, -31)", "-31", "INTEGER NOT NULL");
f.checkScalar("bitand(CAST(-5 AS TINYINT), CAST(7 AS TINYINT))", "3", "TINYINT NOT NULL");
f.checkScalar("bitand(CAST(-5 AS TINYINT), CAST(-31 AS TINYINT))", "-31", "TINYINT NOT NULL");
f.checkType("bitand(CAST(2 AS TINYINT), CAST(6 AS TINYINT))", "TINYINT NOT NULL");
f.checkType("bitand(CAST(2 AS SMALLINT), CAST(6 AS SMALLINT))", "SMALLINT NOT NULL");
f.checkType("bitand(CAST(2 AS BIGINT), CAST(6 AS BIGINT))", "BIGINT NOT NULL");
f.checkScalar("bitand(CAST(x'0201' AS BINARY(2)), CAST(x'07f9' AS BINARY(2)))", "0201",
"BINARY(2)");
"BINARY(2) NOT NULL");
f.checkScalar("bitand(CAST(x'0201' AS VARBINARY(2)), CAST(x'07f9' AS VARBINARY(2)))", "0201",
"VARBINARY(2)");
"VARBINARY(2) NOT NULL");
f.checkFails("^bitand(1.2, 1.3)^",
"Cannot apply 'BITAND' to arguments of type '"
+ "BITAND\\(<DECIMAL\\(2, 1\\)>, <DECIMAL\\(2, 1\\)>\\)'\\. Supported form\\(s\\): '"
Expand Down Expand Up @@ -15522,19 +15522,19 @@ private static void checkLogicalOrFunc(SqlOperatorFixture f) {
final SqlOperatorFixture f = fixture();
f.setFor(SqlStdOperatorTable.BITOR, VmName.EXPAND);
f.checkFails("bitor(^*^)", "Unknown identifier '\\*'", false);
f.checkScalar("bitor(2, 4)", "6", "INTEGER");
f.checkScalar("bitor(CAST(2 AS INTEGER), CAST(4 AS BIGINT))", "6", "BIGINT");
f.checkScalar("bitor(-5, 7)", "-1", "INTEGER");
f.checkScalar("bitor(-5, -31)", "-5", "INTEGER");
f.checkScalar("bitor(CAST(-5 AS TINYINT), CAST(7 AS TINYINT))", "-1", "TINYINT");
f.checkScalar("bitor(CAST(-5 AS TINYINT), CAST(-31 AS TINYINT))", "-5", "TINYINT");
f.checkType("bitor(CAST(2 AS TINYINT), CAST(6 AS TINYINT))", "TINYINT");
f.checkType("bitor(CAST(2 AS SMALLINT), CAST(6 AS SMALLINT))", "SMALLINT");
f.checkType("bitor(CAST(2 AS BIGINT), CAST(6 AS BIGINT))", "BIGINT");
f.checkScalar("bitor(2, 4)", "6", "INTEGER NOT NULL");
f.checkScalar("bitor(CAST(2 AS INTEGER), CAST(4 AS BIGINT))", "6", "BIGINT NOT NULL");
f.checkScalar("bitor(-5, 7)", "-1", "INTEGER NOT NULL");
f.checkScalar("bitor(-5, -31)", "-5", "INTEGER NOT NULL");
f.checkScalar("bitor(CAST(-5 AS TINYINT), CAST(7 AS TINYINT))", "-1", "TINYINT NOT NULL");
f.checkScalar("bitor(CAST(-5 AS TINYINT), CAST(-31 AS TINYINT))", "-5", "TINYINT NOT NULL");
f.checkType("bitor(CAST(2 AS TINYINT), CAST(6 AS TINYINT))", "TINYINT NOT NULL");
f.checkType("bitor(CAST(2 AS SMALLINT), CAST(6 AS SMALLINT))", "SMALLINT NOT NULL");
f.checkType("bitor(CAST(2 AS BIGINT), CAST(6 AS BIGINT))", "BIGINT NOT NULL");
f.checkScalar("bitor(CAST(x'0201' AS BINARY(2)), CAST(x'07f9' AS BINARY(2)))", "07f9",
"BINARY(2)");
"BINARY(2) NOT NULL");
f.checkScalar("bitor(CAST(x'0201' AS VARBINARY(2)), CAST(x'07f9' AS VARBINARY(2)))", "07f9",
"VARBINARY(2)");
"VARBINARY(2) NOT NULL");
f.checkFails("^bitor(1.2, 1.3)^",
"Cannot apply 'BITOR' to arguments of type '"
+ "BITOR\\(<DECIMAL\\(2, 1\\)>, <DECIMAL\\(2, 1\\)>\\)'\\. Supported form\\(s\\): '"
Expand Down Expand Up @@ -15562,19 +15562,19 @@ private static void checkLogicalOrFunc(SqlOperatorFixture f) {
final SqlOperatorFixture f = fixture();
f.setFor(SqlStdOperatorTable.BITXOR, VmName.EXPAND);
f.checkFails("bitxor(^*^)", "Unknown identifier '\\*'", false);
f.checkScalar("bitxor(2, 3)", "1", "INTEGER");
f.checkScalar("bitxor(CAST(2 AS INTEGER), CAST(3 AS BIGINT))", "1", "BIGINT");
f.checkScalar("bitxor(-5, 7)", "-4", "INTEGER");
f.checkScalar("bitxor(-5, -31)", "26", "INTEGER");
f.checkScalar("bitxor(CAST(-5 AS TINYINT), CAST(7 AS TINYINT))", "-4", "TINYINT");
f.checkScalar("bitxor(CAST(-5 AS TINYINT), CAST(-31 AS TINYINT))", "26", "TINYINT");
f.checkType("bitxor(CAST(2 AS TINYINT), CAST(6 AS TINYINT))", "TINYINT");
f.checkType("bitxor(CAST(2 AS SMALLINT), CAST(6 AS SMALLINT))", "SMALLINT");
f.checkType("bitxor(CAST(2 AS BIGINT), CAST(6 AS BIGINT))", "BIGINT");
f.checkScalar("bitxor(2, 3)", "1", "INTEGER NOT NULL");
f.checkScalar("bitxor(CAST(2 AS INTEGER), CAST(3 AS BIGINT))", "1", "BIGINT NOT NULL");
f.checkScalar("bitxor(-5, 7)", "-4", "INTEGER NOT NULL");
f.checkScalar("bitxor(-5, -31)", "26", "INTEGER NOT NULL");
f.checkScalar("bitxor(CAST(-5 AS TINYINT), CAST(7 AS TINYINT))", "-4", "TINYINT NOT NULL");
f.checkScalar("bitxor(CAST(-5 AS TINYINT), CAST(-31 AS TINYINT))", "26", "TINYINT NOT NULL");
f.checkType("bitxor(CAST(2 AS TINYINT), CAST(6 AS TINYINT))", "TINYINT NOT NULL");
f.checkType("bitxor(CAST(2 AS SMALLINT), CAST(6 AS SMALLINT))", "SMALLINT NOT NULL");
f.checkType("bitxor(CAST(2 AS BIGINT), CAST(6 AS BIGINT))", "BIGINT NOT NULL");
f.checkScalar("bitxor(CAST(x'0201' AS BINARY(2)), CAST(x'07f9' AS BINARY(2)))", "05f8",
"BINARY(2)");
"BINARY(2) NOT NULL");
f.checkScalar("bitxor(CAST(x'0201' AS VARBINARY(2)), CAST(x'07f9' AS VARBINARY(2)))", "05f8",
"VARBINARY(2)");
"VARBINARY(2) NOT NULL");
f.checkFails("^bitxor(1.2, 1.3)^",
"Cannot apply 'BITXOR' to arguments of type '"
+ "BITXOR\\(<DECIMAL\\(2, 1\\)>, <DECIMAL\\(2, 1\\)>\\)'\\. Supported form\\(s\\): '"
Expand Down

0 comments on commit ed0d0f2

Please sign in to comment.