mirror of https://github.com/apache/druid.git
GREATEST/LEAST function is incorrectly specifying that it cannot return null (#12804)
This commit is contained in:
parent
809bf161ce
commit
3bf1e699ff
|
@ -23,6 +23,7 @@ import org.apache.calcite.rel.type.RelDataType;
|
|||
import org.apache.calcite.rel.type.RelDataTypeFactory;
|
||||
import org.apache.calcite.sql.type.SqlReturnTypeInference;
|
||||
import org.apache.calcite.sql.type.SqlTypeName;
|
||||
import org.apache.druid.common.config.NullHandling;
|
||||
import org.apache.druid.java.util.common.IAE;
|
||||
import org.apache.druid.math.expr.ExpressionTypeConversion;
|
||||
import org.apache.druid.segment.column.ColumnType;
|
||||
|
@ -53,7 +54,7 @@ class ReductionOperatorConversionHelper
|
|||
|
||||
SqlTypeName returnSqlTypeName = SqlTypeName.NULL;
|
||||
boolean hasDouble = false;
|
||||
|
||||
boolean isString = false;
|
||||
for (int i = 0; i < n; i++) {
|
||||
RelDataType type = opBinding.getOperandType(i);
|
||||
SqlTypeName sqlTypeName = type.getSqlTypeName();
|
||||
|
@ -63,6 +64,7 @@ class ReductionOperatorConversionHelper
|
|||
if (valueType != null) {
|
||||
if (valueType.is(ValueType.STRING)) {
|
||||
returnSqlTypeName = sqlTypeName;
|
||||
isString = true;
|
||||
break;
|
||||
} else if (valueType.anyOf(ValueType.DOUBLE, ValueType.FLOAT)) {
|
||||
returnSqlTypeName = SqlTypeName.DOUBLE;
|
||||
|
@ -75,6 +77,12 @@ class ReductionOperatorConversionHelper
|
|||
}
|
||||
}
|
||||
|
||||
return typeFactory.createSqlType(returnSqlTypeName);
|
||||
if (isString || NullHandling.sqlCompatible()) {
|
||||
// String can be null in both modes
|
||||
return typeFactory.createTypeWithNullability(typeFactory.createSqlType(returnSqlTypeName), true);
|
||||
} else {
|
||||
return typeFactory.createSqlType(returnSqlTypeName);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.apache.druid.query.Druids;
|
|||
import org.apache.druid.query.InlineDataSource;
|
||||
import org.apache.druid.query.JoinDataSource;
|
||||
import org.apache.druid.query.LookupDataSource;
|
||||
import org.apache.druid.query.Query;
|
||||
import org.apache.druid.query.QueryContext;
|
||||
import org.apache.druid.query.QueryContexts;
|
||||
import org.apache.druid.query.QueryDataSource;
|
||||
|
@ -13902,4 +13903,113 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
|||
null
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGreatestFunctionForNumberWithIsNull() throws Exception
|
||||
{
|
||||
String query = "SELECT dim1, MAX(GREATEST(l1, l2)) IS NULL FROM druid.numfoo GROUP BY dim1";
|
||||
|
||||
List<Object[]> expectedResult;
|
||||
List<Query> expectedQueries;
|
||||
|
||||
if (NullHandling.replaceWithDefault()) {
|
||||
expectedResult = ImmutableList.of(
|
||||
new Object[]{"", false},
|
||||
new Object[]{"1", false},
|
||||
new Object[]{"10.1", false},
|
||||
new Object[]{"2", false},
|
||||
new Object[]{"abc", false},
|
||||
new Object[]{"def", false}
|
||||
);
|
||||
expectedQueries = ImmutableList.of(
|
||||
GroupByQuery.builder()
|
||||
.setDataSource(CalciteTests.DATASOURCE3)
|
||||
.setInterval(querySegmentSpec(Intervals.ETERNITY))
|
||||
.setGranularity(Granularities.ALL)
|
||||
.addDimension(new DefaultDimensionSpec("dim1", "_d0"))
|
||||
.setPostAggregatorSpecs(ImmutableList.of(
|
||||
expressionPostAgg("p0", "0")
|
||||
))
|
||||
.build()
|
||||
);
|
||||
} else {
|
||||
cannotVectorize();
|
||||
expectedResult = ImmutableList.of(
|
||||
new Object[]{"", false},
|
||||
new Object[]{"1", true},
|
||||
new Object[]{"10.1", false},
|
||||
new Object[]{"2", false},
|
||||
new Object[]{"abc", true},
|
||||
new Object[]{"def", true}
|
||||
);
|
||||
expectedQueries = ImmutableList.of(
|
||||
GroupByQuery.builder()
|
||||
.setDataSource(CalciteTests.DATASOURCE3)
|
||||
.setInterval(querySegmentSpec(Intervals.ETERNITY))
|
||||
.setVirtualColumns(
|
||||
expressionVirtualColumn(
|
||||
"v0",
|
||||
"greatest(\"l1\",\"l2\")",
|
||||
ColumnType.LONG
|
||||
)
|
||||
)
|
||||
.setGranularity(Granularities.ALL)
|
||||
.addDimension(new DefaultDimensionSpec("dim1", "_d0"))
|
||||
.addAggregator(new LongMaxAggregatorFactory("a0", "v0"))
|
||||
.setPostAggregatorSpecs(ImmutableList.of(
|
||||
expressionPostAgg("p0", "isnull(\"a0\")")
|
||||
))
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
testQuery(
|
||||
query,
|
||||
expectedQueries,
|
||||
expectedResult
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGreatestFunctionForStringWithIsNull() throws Exception
|
||||
{
|
||||
cannotVectorize();
|
||||
|
||||
String query = "SELECT l1, LATEST(GREATEST(dim1, dim2)) IS NULL FROM druid.numfoo GROUP BY l1";
|
||||
|
||||
testQuery(
|
||||
query,
|
||||
ImmutableList.of(
|
||||
GroupByQuery.builder()
|
||||
.setDataSource(CalciteTests.DATASOURCE3)
|
||||
.setInterval(querySegmentSpec(Intervals.ETERNITY))
|
||||
.setVirtualColumns(
|
||||
expressionVirtualColumn(
|
||||
"v0",
|
||||
"CAST(greatest(\"dim1\",\"dim2\"), 'DOUBLE')",
|
||||
ColumnType.DOUBLE
|
||||
)
|
||||
)
|
||||
.setGranularity(Granularities.ALL)
|
||||
.addDimension(new DefaultDimensionSpec("l1", "_d0", ColumnType.LONG))
|
||||
.addAggregator(new DoubleLastAggregatorFactory("a0", "v0", null))
|
||||
.setPostAggregatorSpecs(ImmutableList.of(
|
||||
expressionPostAgg("p0", "isnull(\"a0\")")
|
||||
))
|
||||
.build()
|
||||
),
|
||||
NullHandling.replaceWithDefault() ?
|
||||
ImmutableList.of(
|
||||
new Object[]{0L, false},
|
||||
new Object[]{7L, false},
|
||||
new Object[]{325323L, false}
|
||||
) :
|
||||
ImmutableList.of(
|
||||
new Object[]{null, true},
|
||||
new Object[]{0L, false},
|
||||
new Object[]{7L, true},
|
||||
new Object[]{325323L, false}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue