mirror of https://github.com/apache/druid.git
Corrected Strict NON NULL return type checks (#16279)
This commit is contained in:
parent
4285a5e2c6
commit
960a674442
|
@ -3606,7 +3606,7 @@ public interface Function extends NamedFunction
|
||||||
final Object[] array = arrayExpr.asArray();
|
final Object[] array = arrayExpr.asArray();
|
||||||
final int position = scalarExpr.asInt();
|
final int position = scalarExpr.asInt();
|
||||||
|
|
||||||
if (array.length > position) {
|
if (array.length > position && position >= 0) {
|
||||||
return ExprEval.ofType(arrayExpr.elementType(), array[position]);
|
return ExprEval.ofType(arrayExpr.elementType(), array[position]);
|
||||||
}
|
}
|
||||||
return ExprEval.of(null);
|
return ExprEval.of(null);
|
||||||
|
@ -3634,7 +3634,7 @@ public interface Function extends NamedFunction
|
||||||
final Object[] array = arrayExpr.asArray();
|
final Object[] array = arrayExpr.asArray();
|
||||||
final int position = scalarExpr.asInt() - 1;
|
final int position = scalarExpr.asInt() - 1;
|
||||||
|
|
||||||
if (array.length > position) {
|
if (array.length > position && position >= 0) {
|
||||||
return ExprEval.ofType(arrayExpr.elementType(), array[position]);
|
return ExprEval.ofType(arrayExpr.elementType(), array[position]);
|
||||||
}
|
}
|
||||||
return ExprEval.of(null);
|
return ExprEval.of(null);
|
||||||
|
|
|
@ -336,6 +336,7 @@ public class FunctionTest extends InitializedNullHandlingTest
|
||||||
{
|
{
|
||||||
assertExpr("array_offset([1, 2, 3], 2)", 3L);
|
assertExpr("array_offset([1, 2, 3], 2)", 3L);
|
||||||
assertArrayExpr("array_offset([1, 2, 3], 3)", null);
|
assertArrayExpr("array_offset([1, 2, 3], 3)", null);
|
||||||
|
assertArrayExpr("array_offset([1, 2, 3], -1)", null);
|
||||||
assertExpr("array_offset(a, 2)", "baz");
|
assertExpr("array_offset(a, 2)", "baz");
|
||||||
// nested types only work with typed bindings right now, and pretty limited support for stuff
|
// nested types only work with typed bindings right now, and pretty limited support for stuff
|
||||||
assertExpr("array_offset(nestedArray, 1)", ImmutableMap.of("x", 4L, "y", 6.6), typedBindings);
|
assertExpr("array_offset(nestedArray, 1)", ImmutableMap.of("x", 4L, "y", 6.6), typedBindings);
|
||||||
|
@ -346,6 +347,7 @@ public class FunctionTest extends InitializedNullHandlingTest
|
||||||
{
|
{
|
||||||
assertExpr("array_ordinal([1, 2, 3], 3)", 3L);
|
assertExpr("array_ordinal([1, 2, 3], 3)", 3L);
|
||||||
assertArrayExpr("array_ordinal([1, 2, 3], 4)", null);
|
assertArrayExpr("array_ordinal([1, 2, 3], 4)", null);
|
||||||
|
assertArrayExpr("array_ordinal([1, 2, 3], 0)", null);
|
||||||
assertExpr("array_ordinal(a, 3)", "baz");
|
assertExpr("array_ordinal(a, 3)", "baz");
|
||||||
// nested types only work with typed bindings right now, and pretty limited support for stuff
|
// nested types only work with typed bindings right now, and pretty limited support for stuff
|
||||||
assertExpr("array_ordinal(nestedArray, 2)", ImmutableMap.of("x", 4L, "y", 6.6), typedBindings);
|
assertExpr("array_ordinal(nestedArray, 2)", ImmutableMap.of("x", 4L, "y", 6.6), typedBindings);
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class ContainsOperatorConversion extends DirectOperatorConversion
|
||||||
.operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER)
|
.operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER)
|
||||||
.requiredOperandCount(2)
|
.requiredOperandCount(2)
|
||||||
.literalOperands(1)
|
.literalOperands(1)
|
||||||
.returnTypeNonNull(SqlTypeName.BOOLEAN)
|
.returnTypeNullable(SqlTypeName.BOOLEAN)
|
||||||
.functionCategory(SqlFunctionCategory.STRING)
|
.functionCategory(SqlFunctionCategory.STRING)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class RegexpLikeOperatorConversion implements SqlOperatorConversion
|
||||||
.operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER)
|
.operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER)
|
||||||
.requiredOperandCount(2)
|
.requiredOperandCount(2)
|
||||||
.literalOperands(1)
|
.literalOperands(1)
|
||||||
.returnTypeNonNull(SqlTypeName.BOOLEAN)
|
.returnTypeCascadeNullable(SqlTypeName.BOOLEAN)
|
||||||
.functionCategory(SqlFunctionCategory.STRING)
|
.functionCategory(SqlFunctionCategory.STRING)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.apache.calcite.sql.SqlFunctionCategory;
|
||||||
import org.apache.calcite.sql.SqlOperator;
|
import org.apache.calcite.sql.SqlOperator;
|
||||||
import org.apache.calcite.sql.type.ReturnTypes;
|
import org.apache.calcite.sql.type.ReturnTypes;
|
||||||
import org.apache.calcite.sql.type.SqlTypeFamily;
|
import org.apache.calcite.sql.type.SqlTypeFamily;
|
||||||
|
import org.apache.calcite.sql.type.SqlTypeTransforms;
|
||||||
import org.apache.druid.java.util.common.StringUtils;
|
import org.apache.druid.java.util.common.StringUtils;
|
||||||
import org.apache.druid.query.extraction.SubstringDimExtractionFn;
|
import org.apache.druid.query.extraction.SubstringDimExtractionFn;
|
||||||
import org.apache.druid.segment.column.RowSignature;
|
import org.apache.druid.segment.column.RowSignature;
|
||||||
|
@ -45,7 +46,7 @@ public class SubstringOperatorConversion implements SqlOperatorConversion
|
||||||
.operatorBuilder("SUBSTRING")
|
.operatorBuilder("SUBSTRING")
|
||||||
.operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTEGER, SqlTypeFamily.INTEGER)
|
.operandTypes(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTEGER, SqlTypeFamily.INTEGER)
|
||||||
.functionCategory(SqlFunctionCategory.STRING)
|
.functionCategory(SqlFunctionCategory.STRING)
|
||||||
.returnTypeInference(ReturnTypes.ARG0)
|
.returnTypeInference(ReturnTypes.ARG0.andThen(SqlTypeTransforms.FORCE_NULLABLE))
|
||||||
.requiredOperandCount(2)
|
.requiredOperandCount(2)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,8 @@ import org.apache.calcite.sql.SqlFunctionCategory;
|
||||||
import org.apache.calcite.sql.SqlOperator;
|
import org.apache.calcite.sql.SqlOperator;
|
||||||
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
|
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
|
||||||
import org.apache.calcite.sql.parser.SqlParserPos;
|
import org.apache.calcite.sql.parser.SqlParserPos;
|
||||||
|
import org.apache.calcite.sql.type.ReturnTypes;
|
||||||
import org.apache.calcite.sql.type.SqlTypeFamily;
|
import org.apache.calcite.sql.type.SqlTypeFamily;
|
||||||
import org.apache.calcite.sql.type.SqlTypeName;
|
|
||||||
import org.apache.calcite.sql2rel.SqlRexContext;
|
import org.apache.calcite.sql2rel.SqlRexContext;
|
||||||
import org.apache.calcite.sql2rel.SqlRexConvertlet;
|
import org.apache.calcite.sql2rel.SqlRexConvertlet;
|
||||||
import org.apache.calcite.util.Static;
|
import org.apache.calcite.util.Static;
|
||||||
|
@ -56,7 +56,7 @@ public class TimeInIntervalConvertletFactory implements DruidConvertletFactory
|
||||||
.operandTypes(SqlTypeFamily.TIMESTAMP, SqlTypeFamily.CHARACTER)
|
.operandTypes(SqlTypeFamily.TIMESTAMP, SqlTypeFamily.CHARACTER)
|
||||||
.requiredOperandCount(2)
|
.requiredOperandCount(2)
|
||||||
.literalOperands(1)
|
.literalOperands(1)
|
||||||
.returnTypeNonNull(SqlTypeName.BOOLEAN)
|
.returnTypeInference(ReturnTypes.BOOLEAN_NULLABLE)
|
||||||
.functionCategory(SqlFunctionCategory.TIMEDATE)
|
.functionCategory(SqlFunctionCategory.TIMEDATE)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.apache.druid.java.util.common.StringUtils;
|
||||||
import org.apache.druid.java.util.common.UOE;
|
import org.apache.druid.java.util.common.UOE;
|
||||||
import org.apache.druid.java.util.common.granularity.Granularities;
|
import org.apache.druid.java.util.common.granularity.Granularities;
|
||||||
import org.apache.druid.java.util.common.granularity.PeriodGranularity;
|
import org.apache.druid.java.util.common.granularity.PeriodGranularity;
|
||||||
|
import org.apache.druid.math.expr.ExprEval;
|
||||||
import org.apache.druid.math.expr.ExprMacroTable;
|
import org.apache.druid.math.expr.ExprMacroTable;
|
||||||
import org.apache.druid.query.Druids;
|
import org.apache.druid.query.Druids;
|
||||||
import org.apache.druid.query.InlineDataSource;
|
import org.apache.druid.query.InlineDataSource;
|
||||||
|
@ -110,6 +111,7 @@ import org.apache.druid.segment.VirtualColumns;
|
||||||
import org.apache.druid.segment.column.ColumnType;
|
import org.apache.druid.segment.column.ColumnType;
|
||||||
import org.apache.druid.segment.column.RowSignature;
|
import org.apache.druid.segment.column.RowSignature;
|
||||||
import org.apache.druid.segment.join.JoinType;
|
import org.apache.druid.segment.join.JoinType;
|
||||||
|
import org.apache.druid.segment.virtual.ExpressionVirtualColumn;
|
||||||
import org.apache.druid.sql.calcite.DecoupledTestConfig.NativeQueryIgnore;
|
import org.apache.druid.sql.calcite.DecoupledTestConfig.NativeQueryIgnore;
|
||||||
import org.apache.druid.sql.calcite.NotYetSupported.Modes;
|
import org.apache.druid.sql.calcite.NotYetSupported.Modes;
|
||||||
import org.apache.druid.sql.calcite.expression.DruidExpression;
|
import org.apache.druid.sql.calcite.expression.DruidExpression;
|
||||||
|
@ -6120,6 +6122,34 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTimeInIntervalBooleanNullable()
|
||||||
|
{
|
||||||
|
testQuery(
|
||||||
|
"SELECT TIME_IN_INTERVAL(TIME_PARSE('2000-01-10'), '2000-01-01/P1Y')",
|
||||||
|
QUERY_CONTEXT_LOS_ANGELES,
|
||||||
|
ImmutableList.of(
|
||||||
|
Druids.newScanQueryBuilder()
|
||||||
|
.dataSource(InlineDataSource.fromIterable(
|
||||||
|
ImmutableList.of(new Object[]{0L}),
|
||||||
|
RowSignature.builder()
|
||||||
|
.add("ZERO", ColumnType.LONG)
|
||||||
|
.build()
|
||||||
|
))
|
||||||
|
.intervals(querySegmentSpec(Filtration.eternity()))
|
||||||
|
.virtualColumns(new ExpressionVirtualColumn("v0", ExprEval.of(1L).toExpr(), ColumnType.LONG))
|
||||||
|
.columns("v0")
|
||||||
|
.resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
|
||||||
|
.legacy(false)
|
||||||
|
.context(QUERY_CONTEXT_LOS_ANGELES)
|
||||||
|
.build()
|
||||||
|
),
|
||||||
|
ImmutableList.of(
|
||||||
|
new Object[]{true}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCountStarWithTimeInIntervalFilterNonLiteral()
|
public void testCountStarWithTimeInIntervalFilterNonLiteral()
|
||||||
{
|
{
|
||||||
|
@ -15612,4 +15642,48 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStringOperationsNullableInference()
|
||||||
|
{
|
||||||
|
testBuilder()
|
||||||
|
.sql(
|
||||||
|
"SELECT ICONTAINS_STRING(dim3, 'a'), REGEXP_LIKE(dim3,'x'), SUBSTRING(dim3, 1, 1) " +
|
||||||
|
"from druid.numfoo where dim3 is NULL LIMIT 1"
|
||||||
|
)
|
||||||
|
.queryContext(QUERY_CONTEXT_LOS_ANGELES)
|
||||||
|
.expectedQueries(
|
||||||
|
ImmutableList.of(
|
||||||
|
Druids.newScanQueryBuilder()
|
||||||
|
.dataSource(CalciteTests.DATASOURCE3)
|
||||||
|
.intervals(querySegmentSpec(Filtration.eternity()))
|
||||||
|
.virtualColumns(
|
||||||
|
new ExpressionVirtualColumn(
|
||||||
|
"v0",
|
||||||
|
NullHandling.replaceWithDefault() ? "0" : "null",
|
||||||
|
ColumnType.LONG,
|
||||||
|
ExprMacroTable.nil()
|
||||||
|
),
|
||||||
|
new ExpressionVirtualColumn(
|
||||||
|
"v1",
|
||||||
|
"null",
|
||||||
|
ColumnType.STRING,
|
||||||
|
ExprMacroTable.nil()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.columns("v0", "v1")
|
||||||
|
.filters(isNull("dim3"))
|
||||||
|
.limit(1)
|
||||||
|
.resultFormat(ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
|
||||||
|
.legacy(false)
|
||||||
|
.context(QUERY_CONTEXT_LOS_ANGELES)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
).expectedResults(
|
||||||
|
ResultMatchMode.RELAX_NULLS,
|
||||||
|
ImmutableList.of(
|
||||||
|
new Object[]{null, null, null}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue