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.rel.type.RelDataTypeFactory;
|
||||||
import org.apache.calcite.sql.type.SqlReturnTypeInference;
|
import org.apache.calcite.sql.type.SqlReturnTypeInference;
|
||||||
import org.apache.calcite.sql.type.SqlTypeName;
|
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.java.util.common.IAE;
|
||||||
import org.apache.druid.math.expr.ExpressionTypeConversion;
|
import org.apache.druid.math.expr.ExpressionTypeConversion;
|
||||||
import org.apache.druid.segment.column.ColumnType;
|
import org.apache.druid.segment.column.ColumnType;
|
||||||
|
@ -53,7 +54,7 @@ class ReductionOperatorConversionHelper
|
||||||
|
|
||||||
SqlTypeName returnSqlTypeName = SqlTypeName.NULL;
|
SqlTypeName returnSqlTypeName = SqlTypeName.NULL;
|
||||||
boolean hasDouble = false;
|
boolean hasDouble = false;
|
||||||
|
boolean isString = false;
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
RelDataType type = opBinding.getOperandType(i);
|
RelDataType type = opBinding.getOperandType(i);
|
||||||
SqlTypeName sqlTypeName = type.getSqlTypeName();
|
SqlTypeName sqlTypeName = type.getSqlTypeName();
|
||||||
|
@ -63,6 +64,7 @@ class ReductionOperatorConversionHelper
|
||||||
if (valueType != null) {
|
if (valueType != null) {
|
||||||
if (valueType.is(ValueType.STRING)) {
|
if (valueType.is(ValueType.STRING)) {
|
||||||
returnSqlTypeName = sqlTypeName;
|
returnSqlTypeName = sqlTypeName;
|
||||||
|
isString = true;
|
||||||
break;
|
break;
|
||||||
} else if (valueType.anyOf(ValueType.DOUBLE, ValueType.FLOAT)) {
|
} else if (valueType.anyOf(ValueType.DOUBLE, ValueType.FLOAT)) {
|
||||||
returnSqlTypeName = SqlTypeName.DOUBLE;
|
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.InlineDataSource;
|
||||||
import org.apache.druid.query.JoinDataSource;
|
import org.apache.druid.query.JoinDataSource;
|
||||||
import org.apache.druid.query.LookupDataSource;
|
import org.apache.druid.query.LookupDataSource;
|
||||||
|
import org.apache.druid.query.Query;
|
||||||
import org.apache.druid.query.QueryContext;
|
import org.apache.druid.query.QueryContext;
|
||||||
import org.apache.druid.query.QueryContexts;
|
import org.apache.druid.query.QueryContexts;
|
||||||
import org.apache.druid.query.QueryDataSource;
|
import org.apache.druid.query.QueryDataSource;
|
||||||
|
@ -13902,4 +13903,113 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
null
|
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