diff --git a/coral-common/src/main/java/com/linkedin/coral/common/HiveTypeSystem.java b/coral-common/src/main/java/com/linkedin/coral/common/HiveTypeSystem.java index 5f91ba462..430936b9b 100644 --- a/coral-common/src/main/java/com/linkedin/coral/common/HiveTypeSystem.java +++ b/coral-common/src/main/java/com/linkedin/coral/common/HiveTypeSystem.java @@ -1,5 +1,5 @@ /** - * Copyright 2017-2022 LinkedIn Corporation. All rights reserved. + * Copyright 2017-2023 LinkedIn Corporation. All rights reserved. * Licensed under the BSD-2 Clause license. * See LICENSE in the project root for license information. */ @@ -9,6 +9,7 @@ import org.apache.calcite.rel.type.RelDataTypeFactory; import org.apache.calcite.rel.type.RelDataTypeSystemImpl; import org.apache.calcite.sql.type.SqlTypeName; +import org.apache.calcite.sql.type.SqlTypeUtil; // Copied from Hive source code @@ -161,6 +162,19 @@ public boolean isSchemaCaseSensitive() { return false; } + /** + * This method needs to be overridden to make sure that the "/" operator returns {@link org.apache.calcite.sql.type.ReturnTypes#DOUBLE} + * if neither of the operands is decimal type, which is compatible with the expected data type in Hive/Spark. + */ + @Override + public RelDataType deriveDecimalDivideType(RelDataTypeFactory typeFactory, RelDataType type1, RelDataType type2) { + if (SqlTypeUtil.isDecimal(type1) || SqlTypeUtil.isDecimal(type2)) { + return super.deriveDecimalDivideType(typeFactory, type1, type2); + } else { + return nullableType(typeFactory, SqlTypeName.DOUBLE); + } + } + private RelDataType nullableType(RelDataTypeFactory typeFactory, SqlTypeName typeName) { return typeFactory.createTypeWithNullability(typeFactory.createSqlType(typeName), true); } diff --git a/coral-schema/src/test/java/com/linkedin/coral/schema/avro/ViewToAvroSchemaConverterTests.java b/coral-schema/src/test/java/com/linkedin/coral/schema/avro/ViewToAvroSchemaConverterTests.java index cb85eb524..fd8c73129 100644 --- a/coral-schema/src/test/java/com/linkedin/coral/schema/avro/ViewToAvroSchemaConverterTests.java +++ b/coral-schema/src/test/java/com/linkedin/coral/schema/avro/ViewToAvroSchemaConverterTests.java @@ -1078,5 +1078,16 @@ public void testUnionFloatAndDoublePromoteToDouble() { TestUtils.loadSchema("testUnionFloatAndDoublePromoteToDouble-expected.avsc")); } + @Test + public void testDivideReturnType() { + String viewSql = "CREATE VIEW v AS SELECT 1/2 AS a FROM baseprimitive"; + TestUtils.executeCreateViewQuery("default", "v", viewSql); + + ViewToAvroSchemaConverter viewToAvroSchemaConverter = ViewToAvroSchemaConverter.create(hiveMetastoreClient); + Schema actualSchema = viewToAvroSchemaConverter.toAvroSchema("default", "v"); + + Assert.assertEquals(actualSchema.toString(true), TestUtils.loadSchema("testDivideReturnType-expected.avsc")); + } + // TODO: add more unit tests } diff --git a/coral-schema/src/test/resources/testDivideReturnType-expected.avsc b/coral-schema/src/test/resources/testDivideReturnType-expected.avsc new file mode 100644 index 000000000..b12859520 --- /dev/null +++ b/coral-schema/src/test/resources/testDivideReturnType-expected.avsc @@ -0,0 +1,10 @@ +{ + "type" : "record", + "name" : "v", + "namespace" : "default.v", + "fields" : [ { + "name" : "a", + "type" : [ "null", "double" ], + "doc" : "Field created in view by applying operator '/' with argument(s): 1, 2" + } ] +} \ No newline at end of file