From e40634c7d1723541fd625b8ef879f190526c2bd1 Mon Sep 17 00:00:00 2001 From: Clint Wylie Date: Mon, 11 Dec 2023 23:28:49 -0800 Subject: [PATCH] fix expression post aggregator array handling when grouping wrapper types leak --- .../druid/math/expr/BinaryEvalOpExprBase.java | 2 +- .../org/apache/druid/math/expr/ExprEval.java | 20 +- .../druid/math/expr/FunctionalExpr.java | 8 +- .../druid/math/expr/UnaryOperatorExpr.java | 2 +- .../apache/druid/segment/column/Types.java | 16 + .../org/apache/druid/math/expr/EvalTest.java | 14 + .../apache/druid/math/expr/FunctionTest.java | 212 ++++++------- .../sql/calcite/CalciteArraysQueryTest.java | 93 ++++++ .../expression/ExpressionTestBase.java | 36 --- .../calcite/expression/ExpressionsTest.java | 290 +++++++++--------- .../expression/GreatestExpressionTest.java | 3 +- .../IPv4AddressMatchExpressionTest.java | 80 ++--- .../IPv4AddressParseExpressionTest.java | 38 ++- .../IPv4AddressStringifyExpressionTest.java | 38 ++- .../expression/LeastExpressionTest.java | 3 +- .../TimeFormatOperatorConversionTest.java | 3 +- 16 files changed, 483 insertions(+), 375 deletions(-) delete mode 100644 sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestBase.java diff --git a/processing/src/main/java/org/apache/druid/math/expr/BinaryEvalOpExprBase.java b/processing/src/main/java/org/apache/druid/math/expr/BinaryEvalOpExprBase.java index 8dd4b9602518..2104dcc45db7 100644 --- a/processing/src/main/java/org/apache/druid/math/expr/BinaryEvalOpExprBase.java +++ b/processing/src/main/java/org/apache/druid/math/expr/BinaryEvalOpExprBase.java @@ -207,7 +207,7 @@ public ExprEval eval(ObjectBinding bindings) break; } if (!ExpressionProcessing.useStrictBooleans() && !type.is(ExprType.STRING) && !type.isArray()) { - return ExprEval.ofBoolean(result, type.getType()); + return ExprEval.ofBoolean(result, type); } return ExprEval.ofLongBoolean(result); } diff --git a/processing/src/main/java/org/apache/druid/math/expr/ExprEval.java b/processing/src/main/java/org/apache/druid/math/expr/ExprEval.java index 35f59e5ebe75..8b8cee07824f 100644 --- a/processing/src/main/java/org/apache/druid/math/expr/ExprEval.java +++ b/processing/src/main/java/org/apache/druid/math/expr/ExprEval.java @@ -30,6 +30,9 @@ import org.apache.druid.segment.column.NullableTypeStrategy; import org.apache.druid.segment.column.TypeStrategies; import org.apache.druid.segment.column.TypeStrategy; +import org.apache.druid.segment.column.Types; +import org.apache.druid.segment.data.ComparableList; +import org.apache.druid.segment.data.ComparableStringArray; import org.apache.druid.segment.nested.StructuredData; import javax.annotation.Nullable; @@ -357,9 +360,9 @@ public static ExprEval ofArray(ExpressionType outputType, @Nullable Object[] val * instead. */ @Deprecated - public static ExprEval ofBoolean(boolean value, ExprType type) + public static ExprEval ofBoolean(boolean value, ExpressionType type) { - switch (type) { + switch (type.getType()) { case DOUBLE: return ExprEval.of(Evals.asDouble(value)); case LONG: @@ -367,7 +370,7 @@ public static ExprEval ofBoolean(boolean value, ExprType type) case STRING: return ExprEval.of(String.valueOf(value)); default: - throw new IllegalArgumentException("Invalid type, cannot coerce [" + type + "] to boolean"); + throw new Types.InvalidCastBooleanException(type); } } @@ -502,6 +505,13 @@ public static ExprEval bestEffortOf(@Nullable Object val) final List theList = val instanceof List ? ((List) val) : Arrays.asList((Object[]) val); return bestEffortArray(theList); } + // handle leaky group by array types + if (val instanceof ComparableStringArray) { + return new ArrayExprEval(ExpressionType.STRING_ARRAY, ((ComparableStringArray) val).getDelegate()); + } + if (val instanceof ComparableList) { + return bestEffortArray(((ComparableList) val).getDelegate()); + } // in 'best effort' mode, we couldn't possibly use byte[] as a complex or anything else useful without type // knowledge, so lets turn it into a base64 encoded string so at least something downstream can use it by decoding @@ -1567,8 +1577,8 @@ public Expr toExpr() } } - public static IAE invalidCast(ExpressionType fromType, ExpressionType toType) + public static Types.InvalidCastException invalidCast(ExpressionType fromType, ExpressionType toType) { - return new IAE("Invalid type, cannot cast [" + fromType + "] to [" + toType + "]"); + return new Types.InvalidCastException(fromType, toType); } } diff --git a/processing/src/main/java/org/apache/druid/math/expr/FunctionalExpr.java b/processing/src/main/java/org/apache/druid/math/expr/FunctionalExpr.java index 3d5a7f511f9e..7db3e9bfd7a5 100644 --- a/processing/src/main/java/org/apache/druid/math/expr/FunctionalExpr.java +++ b/processing/src/main/java/org/apache/druid/math/expr/FunctionalExpr.java @@ -24,6 +24,7 @@ import org.apache.druid.error.DruidException; import org.apache.druid.java.util.common.StringUtils; import org.apache.druid.math.expr.vector.ExprVectorProcessor; +import org.apache.druid.segment.column.Types; import javax.annotation.Nullable; import java.util.List; @@ -190,7 +191,12 @@ public ExprEval eval(ObjectBinding bindings) try { return function.apply(args, bindings); } - catch (DruidException | ExpressionValidationException e) { + catch (ExpressionValidationException | Types.InvalidCastException | Types.InvalidCastBooleanException e) { + throw DruidException.forPersona(DruidException.Persona.USER) + .ofCategory(DruidException.Category.INVALID_INPUT) + .build(e.getMessage()); + } + catch (DruidException e) { throw e; } catch (Exception e) { diff --git a/processing/src/main/java/org/apache/druid/math/expr/UnaryOperatorExpr.java b/processing/src/main/java/org/apache/druid/math/expr/UnaryOperatorExpr.java index 684f3ac2520d..f9f2c5bbcc28 100644 --- a/processing/src/main/java/org/apache/druid/math/expr/UnaryOperatorExpr.java +++ b/processing/src/main/java/org/apache/druid/math/expr/UnaryOperatorExpr.java @@ -184,7 +184,7 @@ public ExprEval eval(ObjectBinding bindings) if (!ExpressionProcessing.useStrictBooleans()) { // conforming to other boolean-returning binary operators ExpressionType retType = ret.type().is(ExprType.DOUBLE) ? ExpressionType.DOUBLE : ExpressionType.LONG; - return ExprEval.ofBoolean(!ret.asBoolean(), retType.getType()); + return ExprEval.ofBoolean(!ret.asBoolean(), retType); } return ExprEval.ofLongBoolean(!ret.asBoolean()); } diff --git a/processing/src/main/java/org/apache/druid/segment/column/Types.java b/processing/src/main/java/org/apache/druid/segment/column/Types.java index 2a0256f76673..831f5c76ce94 100644 --- a/processing/src/main/java/org/apache/druid/segment/column/Types.java +++ b/processing/src/main/java/org/apache/druid/segment/column/Types.java @@ -141,4 +141,20 @@ public IncompatibleTypeException(TypeSignature type, TypeSignature other) super("Cannot implicitly cast [%s] to [%s]", type, other); } } + + public static class InvalidCastException extends IAE + { + public InvalidCastException(TypeSignature type, TypeSignature other) + { + super("Invalid type, cannot cast [" + type + "] to [" + other + "]"); + } + } + + public static class InvalidCastBooleanException extends IAE + { + public InvalidCastBooleanException(TypeSignature type) + { + super("Invalid type, cannot coerce [" + type + "] to boolean"); + } + } } diff --git a/processing/src/test/java/org/apache/druid/math/expr/EvalTest.java b/processing/src/test/java/org/apache/druid/math/expr/EvalTest.java index 2f68840955fa..f969ede92b9a 100644 --- a/processing/src/test/java/org/apache/druid/math/expr/EvalTest.java +++ b/processing/src/test/java/org/apache/druid/math/expr/EvalTest.java @@ -28,6 +28,8 @@ import org.apache.druid.java.util.common.StringUtils; import org.apache.druid.segment.column.TypeStrategies; import org.apache.druid.segment.column.TypeStrategiesTest; +import org.apache.druid.segment.data.ComparableList; +import org.apache.druid.segment.data.ComparableStringArray; import org.apache.druid.segment.nested.StructuredData; import org.apache.druid.testing.InitializedNullHandlingTest; import org.junit.Assert; @@ -1683,6 +1685,18 @@ public void testBestEffortOf() ExpressionType.UNKNOWN_COMPLEX, someOtherComplex ); + + assertBestEffortOf( + ComparableStringArray.of("a", "b", "c"), + ExpressionType.STRING_ARRAY, + new Object[]{"a", "b", "c"} + ); + + assertBestEffortOf( + new ComparableList<>(Arrays.asList(1L, 2L)), + ExpressionType.LONG_ARRAY, + new Object[]{1L, 2L} + ); } private void assertBestEffortOf(@Nullable Object val, ExpressionType expectedType, @Nullable Object expectedValue) diff --git a/processing/src/test/java/org/apache/druid/math/expr/FunctionTest.java b/processing/src/test/java/org/apache/druid/math/expr/FunctionTest.java index e38b2ea51452..06813e51dc05 100644 --- a/processing/src/test/java/org/apache/druid/math/expr/FunctionTest.java +++ b/processing/src/test/java/org/apache/druid/math/expr/FunctionTest.java @@ -609,19 +609,17 @@ public void testRoundWithInvalidSecondArgument() ); for (Pair argAndType : invalidArguments) { - try { - assertExpr(StringUtils.format("round(d, %s)", argAndType.lhs), null); - Assert.fail("Did not throw IllegalArgumentException"); - } - catch (ExpressionValidationException e) { - Assert.assertEquals( - StringUtils.format( - "Function[round] second argument should be a LONG but got %s instead", - argAndType.rhs - ), - e.getMessage() - ); - } + Throwable t = Assert.assertThrows( + DruidException.class, + () -> assertExpr(StringUtils.format("round(d, %s)", argAndType.lhs), null) + ); + Assert.assertEquals( + StringUtils.format( + "Function[round] second argument should be a LONG but got %s instead", + argAndType.rhs + ), + t.getMessage() + ); } } @@ -639,13 +637,11 @@ public void testGreatest() assertExpr("greatest(1, 'A')", "A"); // Invalid types - try { - assertExpr("greatest(1, ['A'])", null); - Assert.fail("Did not throw IllegalArgumentException"); - } - catch (ExpressionValidationException e) { - Assert.assertEquals("Function[greatest] does not accept ARRAY types", e.getMessage()); - } + Throwable t = Assert.assertThrows( + DruidException.class, + () -> assertExpr("greatest(1, ['A'])", null) + ); + Assert.assertEquals("Function[greatest] does not accept ARRAY types", t.getMessage()); // Null handling assertExpr("greatest()", null); @@ -667,13 +663,11 @@ public void testLeast() assertExpr("least(1, 'A')", "1"); // Invalid types - try { - assertExpr("least(1, [2, 3])", null); - Assert.fail("Did not throw IllegalArgumentException"); - } - catch (ExpressionValidationException e) { - Assert.assertEquals("Function[least] does not accept ARRAY types", e.getMessage()); - } + Throwable t = Assert.assertThrows( + DruidException.class, + () -> assertExpr("least(1, [2, 3])", null) + ); + Assert.assertEquals("Function[least] does not accept ARRAY types", t.getMessage()); // Null handling assertExpr("least()", null); @@ -770,102 +764,76 @@ public void testSizeForatInvalidArgumentType() ); } - try { - //x = "foo" - Parser.parse("human_readable_binary_byte_format(1024, x)", ExprMacroTable.nil()) - .eval(bestEffortBindings); - - //must not go to here - Assert.assertTrue(false); - } - catch (ExpressionValidationException e) { - Assert.assertEquals( - "Function[human_readable_binary_byte_format] needs a LONG as its second argument but got STRING instead", - e.getMessage() - ); - } - - try { - //of = 0F - Parser.parse("human_readable_binary_byte_format(1024, of)", ExprMacroTable.nil()) - .eval(bestEffortBindings); - - //must not go to here - Assert.assertTrue(false); - } - catch (ExpressionValidationException e) { - Assert.assertEquals( - "Function[human_readable_binary_byte_format] needs a LONG as its second argument but got DOUBLE instead", - e.getMessage() - ); - } + // x = "foo" + Throwable t = Assert.assertThrows( + DruidException.class, + () -> Parser.parse("human_readable_binary_byte_format(1024, x)", ExprMacroTable.nil()).eval(bestEffortBindings) + ); + Assert.assertEquals( + "Function[human_readable_binary_byte_format] needs a LONG as its second argument but got STRING instead", + t.getMessage() + ); + //of = 0F + t = Assert.assertThrows( + DruidException.class, + () -> Parser.parse("human_readable_binary_byte_format(1024, of)", ExprMacroTable.nil()).eval(bestEffortBindings) + ); + Assert.assertEquals( + "Function[human_readable_binary_byte_format] needs a LONG as its second argument but got DOUBLE instead", + t.getMessage() + ); - try { //of = 0F - Parser.parse("human_readable_binary_byte_format(1024, nonexist)", ExprMacroTable.nil()) - .eval(bestEffortBindings); - - //must not go to here - Assert.assertTrue(false); - } - catch (ExpressionValidationException e) { - Assert.assertEquals( - "Function[human_readable_binary_byte_format] needs a LONG as its second argument but got STRING instead", - e.getMessage() - ); - } + t = Assert.assertThrows( + DruidException.class, + () -> Parser.parse("human_readable_binary_byte_format(1024, nonexist)", ExprMacroTable.nil()).eval(bestEffortBindings) + ); + Assert.assertEquals( + "Function[human_readable_binary_byte_format] needs a LONG as its second argument but got STRING instead", + t.getMessage() + ); } @Test public void testSizeFormatInvalidPrecision() { - try { - Parser.parse("human_readable_binary_byte_format(1024, maxLong)", ExprMacroTable.nil()) - .eval(bestEffortBindings); - Assert.assertTrue(false); - } - catch (ExpressionValidationException e) { - Assert.assertEquals( - "Function[human_readable_binary_byte_format] given precision[9223372036854775807] must be in the range of [0,3]", - e.getMessage() - ); - } + Throwable t = Assert.assertThrows( + DruidException.class, + () -> Parser.parse("human_readable_binary_byte_format(1024, maxLong)", ExprMacroTable.nil()) + .eval(bestEffortBindings) + ); - try { - Parser.parse("human_readable_binary_byte_format(1024, minLong)", ExprMacroTable.nil()) - .eval(bestEffortBindings); - Assert.assertTrue(false); - } - catch (ExpressionValidationException e) { - Assert.assertEquals( - "Function[human_readable_binary_byte_format] given precision[-9223372036854775808] must be in the range of [0,3]", - e.getMessage() - ); - } + Assert.assertEquals( + "Function[human_readable_binary_byte_format] given precision[9223372036854775807] must be in the range of [0,3]", + t.getMessage() + ); - try { - Parser.parse("human_readable_binary_byte_format(1024, -1)", ExprMacroTable.nil()) - .eval(bestEffortBindings); - Assert.assertTrue(false); - } - catch (ExpressionValidationException e) { - Assert.assertEquals( - "Function[human_readable_binary_byte_format] given precision[-1] must be in the range of [0,3]", - e.getMessage() - ); - } + t = Assert.assertThrows( + DruidException.class, + () -> Parser.parse("human_readable_binary_byte_format(1024, minLong)", ExprMacroTable.nil()).eval(bestEffortBindings) + ); + Assert.assertEquals( + "Function[human_readable_binary_byte_format] given precision[-9223372036854775808] must be in the range of [0,3]", + t.getMessage() + ); - try { - Parser.parse("human_readable_binary_byte_format(1024, 4)", ExprMacroTable.nil()) - .eval(bestEffortBindings); - Assert.assertTrue(false); - } - catch (ExpressionValidationException e) { - Assert.assertEquals( - "Function[human_readable_binary_byte_format] given precision[4] must be in the range of [0,3]", - e.getMessage() - ); - } + t = Assert.assertThrows( + DruidException.class, + () -> Parser.parse("human_readable_binary_byte_format(1024, -1)", ExprMacroTable.nil()).eval(bestEffortBindings) + ); + Assert.assertEquals( + "Function[human_readable_binary_byte_format] given precision[-1] must be in the range of [0,3]", + t.getMessage() + ); + + t = Assert.assertThrows( + DruidException.class, + () -> Parser.parse("human_readable_binary_byte_format(1024, 4)", ExprMacroTable.nil()).eval(bestEffortBindings) + ); + Assert.assertEquals( + "Function[human_readable_binary_byte_format] given precision[4] must be in the range of [0,3]", + t.getMessage() + ); } @Test @@ -923,16 +891,14 @@ public void testBitwise() assertExpr("bitwiseComplement(null)", null); // data truncation - try { - assertExpr("bitwiseComplement(461168601842738800000000000000.000000)", null); - Assert.fail("Did not throw IllegalArgumentException"); - } - catch (ExpressionValidationException e) { - Assert.assertEquals( - "Function[bitwiseComplement] Possible data truncation, param [461168601842738800000000000000.000000] is out of LONG value range", - e.getMessage() - ); - } + Throwable t = Assert.assertThrows( + DruidException.class, + () -> assertExpr("bitwiseComplement(461168601842738800000000000000.000000)", null) + ); + Assert.assertEquals( + "Function[bitwiseComplement] Possible data truncation, param [461168601842738800000000000000.000000] is out of LONG value range", + t.getMessage() + ); // doubles are cast assertExpr("bitwiseOr(2.345, 1)", 3L); diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteArraysQueryTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteArraysQueryTest.java index 372374f1e25e..e1d2d128b8bd 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteArraysQueryTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteArraysQueryTest.java @@ -50,6 +50,7 @@ import org.apache.druid.query.aggregation.ExpressionLambdaAggregatorFactory; import org.apache.druid.query.aggregation.FilteredAggregatorFactory; import org.apache.druid.query.aggregation.LongSumAggregatorFactory; +import org.apache.druid.query.aggregation.post.ExpressionPostAggregator; import org.apache.druid.query.dimension.DefaultDimensionSpec; import org.apache.druid.query.expression.TestExprMacroTable; import org.apache.druid.query.extraction.SubstringDimExtractionFn; @@ -80,6 +81,7 @@ import org.apache.druid.segment.incremental.IncrementalIndexSchema; import org.apache.druid.segment.join.JoinType; import org.apache.druid.segment.join.JoinableFactoryWrapper; +import org.apache.druid.segment.virtual.ExpressionVirtualColumn; import org.apache.druid.segment.writeout.OffHeapMemorySegmentWriteOutMediumFactory; import org.apache.druid.server.QueryStackTests; import org.apache.druid.server.SpecificSegmentsQuerySegmentWalker; @@ -7193,4 +7195,95 @@ public void testUnnestWithGroupByOnExpression() ) ); } + + @Test + public void testArrayToMvPostaggInline() + { + cannotVectorize(); + testQuery( + "WITH \"ext\" AS (\n" + + " SELECT\n" + + " CAST(\"c0\" AS TIMESTAMP) AS \"__time\",\n" + + " STRING_TO_ARRAY(\"c1\", '<#>') AS \"strings\",\n" + + " CAST(STRING_TO_ARRAY(\"c2\", '<#>') AS BIGINT ARRAY) AS \"longs\"\n" + + " FROM (\n" + + " VALUES\n" + + " (0, 'A<#>B', '1<#>2'),\n" + + " (0, 'C<#>D', '3<#>4')\n" + + " ) AS \"t\" (\"c0\", \"c1\", \"c2\")\n" + + ")\n" + + "SELECT\n" + + " ARRAY_TO_MV(\"strings\") AS \"strings\",\n" + + " ARRAY_TO_MV(\"longs\") AS \"longs\",\n" + + " COUNT(*) AS \"count\"\n" + + "FROM \"ext\"\n" + + "GROUP BY \"strings\", \"longs\"", + ImmutableList.of( + GroupByQuery.builder() + .setDataSource( + InlineDataSource.fromIterable( + Arrays.asList( + new Object[]{0L, "A<#>B", "1<#>2"}, + new Object[]{0L, "C<#>D", "3<#>4"} + ), + RowSignature.builder() + .add("c0", ColumnType.LONG) + .add("c1", ColumnType.STRING) + .add("c2", ColumnType.STRING) + .build() + ) + ) + .setQuerySegmentSpec(new MultipleIntervalSegmentSpec(ImmutableList.of(Intervals.ETERNITY))) + .setDimensions( + new DefaultDimensionSpec("v0", "d0", ColumnType.STRING_ARRAY), + new DefaultDimensionSpec("v1", "d1", ColumnType.LONG_ARRAY) + ) + .setVirtualColumns( + new ExpressionVirtualColumn( + "v0", + "string_to_array(\"c1\",'<#>')", + ColumnType.STRING_ARRAY, + TestExprMacroTable.INSTANCE + ), + new ExpressionVirtualColumn( + "v1", + "CAST(string_to_array(\"c2\",'<#>'), 'ARRAY')", + ColumnType.LONG_ARRAY, + TestExprMacroTable.INSTANCE + ) + ) + .setAggregatorSpecs( + new CountAggregatorFactory("a0") + ) + .setPostAggregatorSpecs( + new ExpressionPostAggregator( + "p0", + "array_to_mv(\"d0\")", + null, + ColumnType.STRING, + TestExprMacroTable.INSTANCE + ), + new ExpressionPostAggregator( + "p1", + "array_to_mv(\"d1\")", + null, + ColumnType.STRING, + TestExprMacroTable.INSTANCE + ) + ) + .setGranularity(Granularities.ALL) + .setContext(QUERY_CONTEXT_DEFAULT) + .build() + ), + ImmutableList.of( + new Object[]{"[\"A\",\"B\"]", "[\"1\",\"2\"]", 1L}, + new Object[]{"[\"C\",\"D\"]", "[\"3\",\"4\"]", 1L} + ), + RowSignature.builder() + .add("strings", ColumnType.STRING) + .add("longs", ColumnType.STRING) + .add("count", ColumnType.LONG) + .build() + ); + } } diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestBase.java b/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestBase.java deleted file mode 100644 index 0a03bcc8aa71..000000000000 --- a/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionTestBase.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.druid.sql.calcite.expression; - -import org.apache.druid.sql.calcite.util.CalciteTestBase; -import org.junit.Rule; -import org.junit.rules.ExpectedException; - -public abstract class ExpressionTestBase extends CalciteTestBase -{ - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - void expectException(Class type, String message) - { - expectedException.expect(type); - expectedException.expectMessage(message); - } -} diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionsTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionsTest.java index 6610951f07dd..2ca9323b9024 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionsTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/expression/ExpressionsTest.java @@ -30,8 +30,8 @@ import org.apache.calcite.sql.parser.SqlParserPos; import org.apache.calcite.sql.type.SqlTypeName; import org.apache.druid.common.config.NullHandling; +import org.apache.druid.error.DruidException; import org.apache.druid.java.util.common.DateTimes; -import org.apache.druid.math.expr.ExpressionValidationException; import org.apache.druid.query.expression.TestExprMacroTable; import org.apache.druid.query.extraction.RegexDimExtractionFn; import org.apache.druid.query.extraction.SubstringDimExtractionFn; @@ -65,7 +65,9 @@ import org.apache.druid.sql.calcite.expression.builtin.TimeParseOperatorConversion; import org.apache.druid.sql.calcite.expression.builtin.TimeShiftOperatorConversion; import org.apache.druid.sql.calcite.expression.builtin.TruncateOperatorConversion; +import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.joda.time.Period; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -73,7 +75,7 @@ import java.util.Collections; import java.util.Map; -public class ExpressionsTest extends ExpressionTestBase +public class ExpressionsTest extends CalciteTestBase { private static final RowSignature ROW_SIGNATURE = RowSignature .builder() @@ -100,28 +102,31 @@ public class ExpressionsTest extends ExpressionTestBase .build(); private static final Map BINDINGS = ImmutableMap.builder() - .put("t", DateTimes.of("2000-02-03T04:05:06").getMillis()) - .put("a", 10) - .put("b", 25) - .put("p", 3) - .put("x", 2.25) - .put("y", 3.0) - .put("z", -2.25) - .put("o", 0) - .put("nan", Double.NaN) - .put("inf", Double.POSITIVE_INFINITY) - .put("-inf", Double.NEGATIVE_INFINITY) - .put("fnan", Float.NaN) - .put("finf", Float.POSITIVE_INFINITY) - .put("-finf", Float.NEGATIVE_INFINITY) - .put("s", "foo") - .put("hexstr", "EF") - .put("intstr", "-100") - .put("spacey", " hey there ") - .put("newliney", "beep\nboop") - .put("tstr", "2000-02-03 04:05:06") - .put("dstr", "2000-02-03") - .build(); + .put( + "t", + DateTimes.of("2000-02-03T04:05:06").getMillis() + ) + .put("a", 10) + .put("b", 25) + .put("p", 3) + .put("x", 2.25) + .put("y", 3.0) + .put("z", -2.25) + .put("o", 0) + .put("nan", Double.NaN) + .put("inf", Double.POSITIVE_INFINITY) + .put("-inf", Double.NEGATIVE_INFINITY) + .put("fnan", Float.NaN) + .put("finf", Float.POSITIVE_INFINITY) + .put("-finf", Float.NEGATIVE_INFINITY) + .put("s", "foo") + .put("hexstr", "EF") + .put("intstr", "-100") + .put("spacey", " hey there ") + .put("newliney", "beep\nboop") + .put("tstr", "2000-02-03 04:05:06") + .put("dstr", "2000-02-03") + .build(); private ExpressionTestHelper testHelper; @@ -1255,23 +1260,26 @@ public void testRoundWithInvalidArgument() final SqlFunction roundFunction = new RoundOperatorConversion().calciteOperator(); if (!NullHandling.sqlCompatible()) { - expectException( - ExpressionValidationException.class, - "Function[round] first argument should be a LONG or DOUBLE but got STRING instead" + Throwable t = Assert.assertThrows( + DruidException.class, + () -> testHelper.testExpression( + roundFunction, + testHelper.makeInputRef("s"), + DruidExpression.ofExpression( + ColumnType.STRING, + DruidExpression.functionCall("round"), + ImmutableList.of( + DruidExpression.ofColumn(ColumnType.STRING, "s") + ) + ), + NullHandling.sqlCompatible() ? null : "IAE Exception" + ) + ); + Assert.assertEquals( + "Function[round] first argument should be a LONG or DOUBLE but got STRING instead", + t.getMessage() ); } - testHelper.testExpression( - roundFunction, - testHelper.makeInputRef("s"), - DruidExpression.ofExpression( - ColumnType.STRING, - DruidExpression.functionCall("round"), - ImmutableList.of( - DruidExpression.ofColumn(ColumnType.STRING, "s") - ) - ), - NullHandling.sqlCompatible() ? null : "IAE Exception" - ); } @Test @@ -1279,26 +1287,26 @@ public void testRoundWithInvalidSecondArgument() { final SqlFunction roundFunction = new RoundOperatorConversion().calciteOperator(); - expectException( - ExpressionValidationException.class, - "Function[round] second argument should be a LONG but got STRING instead" - ); - testHelper.testExpressionString( - roundFunction, - ImmutableList.of( - testHelper.makeInputRef("x"), - testHelper.makeLiteral("foo") - ), - DruidExpression.ofExpression( - ColumnType.FLOAT, - DruidExpression.functionCall("round"), + Throwable t = Assert.assertThrows( + DruidException.class, + () -> testHelper.testExpressionString( + roundFunction, ImmutableList.of( - DruidExpression.ofColumn(ColumnType.FLOAT, "x"), - DruidExpression.ofStringLiteral("foo") - ) - ), - "IAE Exception" + testHelper.makeInputRef("x"), + testHelper.makeLiteral("foo") + ), + DruidExpression.ofExpression( + ColumnType.FLOAT, + DruidExpression.functionCall("round"), + ImmutableList.of( + DruidExpression.ofColumn(ColumnType.FLOAT, "x"), + DruidExpression.ofStringLiteral("foo") + ) + ), + "IAE Exception" + ) ); + Assert.assertEquals("Function[round] second argument should be a LONG but got STRING instead", t.getMessage()); } @Test @@ -2237,23 +2245,22 @@ public void testReverse() @Test public void testAbnormalReverseWithWrongType() { - expectException( - ExpressionValidationException.class, - "Function[reverse] needs a STRING argument but got LONG instead" - ); - - testHelper.testExpression( - new ReverseOperatorConversion().calciteOperator(), - testHelper.makeInputRef("a"), - DruidExpression.ofExpression( - ColumnType.STRING, - DruidExpression.functionCall("reverse"), - ImmutableList.of( - DruidExpression.ofColumn(ColumnType.LONG, "a") - ) - ), - null + Throwable t = Assert.assertThrows( + DruidException.class, + () -> testHelper.testExpression( + new ReverseOperatorConversion().calciteOperator(), + testHelper.makeInputRef("a"), + DruidExpression.ofExpression( + ColumnType.STRING, + DruidExpression.functionCall("reverse"), + ImmutableList.of( + DruidExpression.ofColumn(ColumnType.LONG, "a") + ) + ), + null + ) ); + Assert.assertEquals("Function[reverse] needs a STRING argument but got LONG instead", t.getMessage()); } @Test @@ -2313,38 +2320,39 @@ public void testRight() @Test public void testAbnormalRightWithNegativeNumber() { - expectException( - ExpressionValidationException.class, - "Function[right] needs a positive integer as the second argument" - ); - - testHelper.testExpressionString( - new RightOperatorConversion().calciteOperator(), - ImmutableList.of( - testHelper.makeInputRef("s"), - testHelper.makeLiteral(-1) - ), - makeExpression("right(\"s\",-1)"), - null + Throwable t = Assert.assertThrows( + DruidException.class, + () -> testHelper.testExpressionString( + new RightOperatorConversion().calciteOperator(), + ImmutableList.of( + testHelper.makeInputRef("s"), + testHelper.makeLiteral(-1) + ), + makeExpression("right(\"s\",-1)"), + null + ) ); + Assert.assertEquals("Function[right] needs a positive integer as the second argument", t.getMessage()); } @Test public void testAbnormalRightWithWrongType() { - expectException( - ExpressionValidationException.class, - "Function[right] needs a STRING as first argument and a LONG as second argument" + Throwable t = Assert.assertThrows( + DruidException.class, + () -> testHelper.testExpressionString( + new RightOperatorConversion().calciteOperator(), + ImmutableList.of( + testHelper.makeInputRef("s"), + testHelper.makeInputRef("s") + ), + makeExpression("right(\"s\",\"s\")"), + null + ) ); - - testHelper.testExpressionString( - new RightOperatorConversion().calciteOperator(), - ImmutableList.of( - testHelper.makeInputRef("s"), - testHelper.makeInputRef("s") - ), - makeExpression("right(\"s\",\"s\")"), - null + Assert.assertEquals( + "Function[right] needs a STRING as first argument and a LONG as second argument", + t.getMessage() ); } @@ -2405,38 +2413,39 @@ public void testLeft() @Test public void testAbnormalLeftWithNegativeNumber() { - expectException( - ExpressionValidationException.class, - "Function[left] needs a postive integer as second argument" - ); - - testHelper.testExpressionString( - new LeftOperatorConversion().calciteOperator(), - ImmutableList.of( - testHelper.makeInputRef("s"), - testHelper.makeLiteral(-1) - ), - makeExpression("left(\"s\",-1)"), - null + Throwable t = Assert.assertThrows( + DruidException.class, + () -> testHelper.testExpressionString( + new LeftOperatorConversion().calciteOperator(), + ImmutableList.of( + testHelper.makeInputRef("s"), + testHelper.makeLiteral(-1) + ), + makeExpression("left(\"s\",-1)"), + null + ) ); + Assert.assertEquals("Function[left] needs a postive integer as second argument", t.getMessage()); } @Test public void testAbnormalLeftWithWrongType() { - expectException( - ExpressionValidationException.class, - "Function[left] needs a STRING as first argument and a LONG as second argument" + Throwable t = Assert.assertThrows( + DruidException.class, + () -> testHelper.testExpressionString( + new LeftOperatorConversion().calciteOperator(), + ImmutableList.of( + testHelper.makeInputRef("s"), + testHelper.makeInputRef("s") + ), + makeExpression("left(\"s\",\"s\")"), + null + ) ); - - testHelper.testExpressionString( - new LeftOperatorConversion().calciteOperator(), - ImmutableList.of( - testHelper.makeInputRef("s"), - testHelper.makeInputRef("s") - ), - makeExpression("left(\"s\",\"s\")"), - null + Assert.assertEquals( + "Function[left] needs a STRING as first argument and a LONG as second argument", + t.getMessage() ); } @@ -2477,19 +2486,21 @@ public void testRepeat() @Test public void testAbnormalRepeatWithWrongType() { - expectException( - ExpressionValidationException.class, - "Function[repeat] needs a STRING as first argument and a LONG as second argument" + Throwable t = Assert.assertThrows( + DruidException.class, + () -> testHelper.testExpressionString( + new RepeatOperatorConversion().calciteOperator(), + ImmutableList.of( + testHelper.makeInputRef("s"), + testHelper.makeInputRef("s") + ), + makeExpression("repeat(\"s\",\"s\")"), + null + ) ); - - testHelper.testExpressionString( - new RepeatOperatorConversion().calciteOperator(), - ImmutableList.of( - testHelper.makeInputRef("s"), - testHelper.makeInputRef("s") - ), - makeExpression("repeat(\"s\",\"s\")"), - null + Assert.assertEquals( + "Function[repeat] needs a STRING as first argument and a LONG as second argument", + t.getMessage() ); } @@ -2528,7 +2539,8 @@ public void testOperatorConversionsDruidUnaryLongFn() public void testOperatorConversionsDruidUnaryDoubleFn() { testHelper.testExpressionString( - OperatorConversions.druidUnaryDoubleFn("BITWISE_CONVERT_LONG_BITS_TO_DOUBLE", "bitwiseConvertLongBitsToDouble").calciteOperator(), + OperatorConversions.druidUnaryDoubleFn("BITWISE_CONVERT_LONG_BITS_TO_DOUBLE", "bitwiseConvertLongBitsToDouble") + .calciteOperator(), ImmutableList.of( testHelper.makeInputRef("a") ), @@ -2537,7 +2549,8 @@ public void testOperatorConversionsDruidUnaryDoubleFn() ); testHelper.testExpressionString( - OperatorConversions.druidUnaryDoubleFn("BITWISE_CONVERT_LONG_BITS_TO_DOUBLE", "bitwiseConvertLongBitsToDouble").calciteOperator(), + OperatorConversions.druidUnaryDoubleFn("BITWISE_CONVERT_LONG_BITS_TO_DOUBLE", "bitwiseConvertLongBitsToDouble") + .calciteOperator(), ImmutableList.of( testHelper.makeInputRef("x") ), @@ -2546,7 +2559,8 @@ public void testOperatorConversionsDruidUnaryDoubleFn() ); testHelper.testExpressionString( - OperatorConversions.druidUnaryDoubleFn("BITWISE_CONVERT_LONG_BITS_TO_DOUBLE", "bitwiseConvertLongBitsToDouble").calciteOperator(), + OperatorConversions.druidUnaryDoubleFn("BITWISE_CONVERT_LONG_BITS_TO_DOUBLE", "bitwiseConvertLongBitsToDouble") + .calciteOperator(), ImmutableList.of( testHelper.makeInputRef("s") ), diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/expression/GreatestExpressionTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/expression/GreatestExpressionTest.java index 8418edf994e8..816befbdc0d7 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/expression/GreatestExpressionTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/expression/GreatestExpressionTest.java @@ -28,6 +28,7 @@ import org.apache.druid.segment.column.ColumnType; import org.apache.druid.segment.column.RowSignature; import org.apache.druid.sql.calcite.expression.builtin.GreatestOperatorConversion; +import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.junit.Before; import org.junit.Test; @@ -37,7 +38,7 @@ import java.util.List; import java.util.Map; -public class GreatestExpressionTest extends ExpressionTestBase +public class GreatestExpressionTest extends CalciteTestBase { private static final String DOUBLE_KEY = "d"; private static final double DOUBLE_VALUE = 3.1; diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressMatchExpressionTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressMatchExpressionTest.java index 9db4868c47ea..cf1a221d7ac8 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressMatchExpressionTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressMatchExpressionTest.java @@ -25,6 +25,8 @@ import org.apache.druid.segment.column.ColumnType; import org.apache.druid.segment.column.RowSignature; import org.apache.druid.sql.calcite.expression.builtin.IPv4AddressMatchOperatorConversion; +import org.apache.druid.sql.calcite.util.CalciteTestBase; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -33,7 +35,7 @@ import java.util.List; import java.util.Map; -public class IPv4AddressMatchExpressionTest extends ExpressionTestBase +public class IPv4AddressMatchExpressionTest extends CalciteTestBase { private static final String IPV4 = "192.168.0.1"; private static final long IPV4_LONG = 3232235521L; @@ -65,65 +67,73 @@ public void setUp() @Test public void testTooFewArgs() { - expectException(IllegalArgumentException.class, "requires 2 arguments"); - - testExpression( - Collections.emptyList(), - buildExpectedExpression(), - IGNORE_EXPECTED_RESULT + Throwable t = Assert.assertThrows( + ExpressionValidationException.class, + () -> testExpression( + Collections.emptyList(), + buildExpectedExpression(), + IGNORE_EXPECTED_RESULT + ) ); + Assert.assertEquals("Function[ipv4_match] requires 2 arguments", t.getMessage()); } @Test public void testTooManyArgs() { - expectException(IllegalArgumentException.class, "requires 2 arguments"); - String address = IPV4; String subnet = SUBNET_192_168; - testExpression( - Arrays.asList( - testHelper.makeLiteral(address), - testHelper.makeLiteral(subnet), - testHelper.makeLiteral(address) - ), - buildExpectedExpression(address, subnet, address), - IGNORE_EXPECTED_RESULT + Throwable t = Assert.assertThrows( + ExpressionValidationException.class, + () -> testExpression( + Arrays.asList( + testHelper.makeLiteral(address), + testHelper.makeLiteral(subnet), + testHelper.makeLiteral(address) + ), + buildExpectedExpression(address, subnet, address), + IGNORE_EXPECTED_RESULT + ) ); + Assert.assertEquals("Function[ipv4_match] requires 2 arguments", t.getMessage()); } @Test public void testSubnetArgNotLiteral() { - expectException(ExpressionValidationException.class, "subnet argument must be a literal"); - String address = IPV4; String variableName = VAR; - testExpression( - Arrays.asList( - testHelper.makeLiteral(address), - testHelper.makeInputRef(variableName) - ), - buildExpectedExpression(address, testHelper.makeVariable(variableName)), - IGNORE_EXPECTED_RESULT + Throwable t = Assert.assertThrows( + ExpressionValidationException.class, + () -> testExpression( + Arrays.asList( + testHelper.makeLiteral(address), + testHelper.makeInputRef(variableName) + ), + buildExpectedExpression(address, testHelper.makeVariable(variableName)), + IGNORE_EXPECTED_RESULT + ) ); + Assert.assertEquals("Function[ipv4_match] subnet argument must be a literal", t.getMessage()); } @Test public void testSubnetArgInvalid() { - expectException(IllegalArgumentException.class, "subnet arg has an invalid format"); - String address = IPV4; String invalidSubnet = "192.168.0.1/invalid"; - testExpression( - Arrays.asList( - testHelper.makeLiteral(address), - testHelper.makeLiteral(invalidSubnet) - ), - buildExpectedExpression(address, invalidSubnet), - IGNORE_EXPECTED_RESULT + Throwable t = Assert.assertThrows( + ExpressionValidationException.class, + () -> testExpression( + Arrays.asList( + testHelper.makeLiteral(address), + testHelper.makeLiteral(invalidSubnet) + ), + buildExpectedExpression(address, invalidSubnet), + IGNORE_EXPECTED_RESULT + ) ); + Assert.assertEquals("Function[ipv4_match] subnet arg has an invalid format: 192.168.0.1/invalid", t.getMessage()); } @Test diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressParseExpressionTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressParseExpressionTest.java index 6e4273f35528..f495b6e95006 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressParseExpressionTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressParseExpressionTest.java @@ -25,6 +25,8 @@ import org.apache.druid.segment.column.ColumnType; import org.apache.druid.segment.column.RowSignature; import org.apache.druid.sql.calcite.expression.builtin.IPv4AddressParseOperatorConversion; +import org.apache.druid.sql.calcite.util.CalciteTestBase; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -33,7 +35,7 @@ import java.util.List; import java.util.Map; -public class IPv4AddressParseExpressionTest extends ExpressionTestBase +public class IPv4AddressParseExpressionTest extends CalciteTestBase { private static final String VALID = "192.168.0.1"; private static final long EXPECTED = 3232235521L; @@ -56,28 +58,32 @@ public void setUp() @Test public void testTooFewArgs() { - expectException(ExpressionValidationException.class, "requires 1 argument"); - - testExpression( - Collections.emptyList(), - buildExpectedExpression(), - IGNORE_EXPECTED_RESULT + Throwable t = Assert.assertThrows( + ExpressionValidationException.class, + () -> testExpression( + Collections.emptyList(), + buildExpectedExpression(), + IGNORE_EXPECTED_RESULT + ) ); + Assert.assertEquals("Function[ipv4_parse] requires 1 argument", t.getMessage()); } @Test public void testTooManyArgs() { - expectException(ExpressionValidationException.class, "requires 1 argument"); - - testExpression( - Arrays.asList( - testHelper.getConstantNull(), - testHelper.getConstantNull() - ), - buildExpectedExpression(null, null), - IGNORE_EXPECTED_RESULT + Throwable t = Assert.assertThrows( + ExpressionValidationException.class, + () -> testExpression( + Arrays.asList( + testHelper.getConstantNull(), + testHelper.getConstantNull() + ), + buildExpectedExpression(null, null), + IGNORE_EXPECTED_RESULT + ) ); + Assert.assertEquals("Function[ipv4_parse] requires 1 argument", t.getMessage()); } @Test diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressStringifyExpressionTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressStringifyExpressionTest.java index f434b7dca105..fb1b358cb081 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressStringifyExpressionTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/expression/IPv4AddressStringifyExpressionTest.java @@ -25,6 +25,8 @@ import org.apache.druid.segment.column.ColumnType; import org.apache.druid.segment.column.RowSignature; import org.apache.druid.sql.calcite.expression.builtin.IPv4AddressStringifyOperatorConversion; +import org.apache.druid.sql.calcite.util.CalciteTestBase; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -33,7 +35,7 @@ import java.util.List; import java.util.Map; -public class IPv4AddressStringifyExpressionTest extends ExpressionTestBase +public class IPv4AddressStringifyExpressionTest extends CalciteTestBase { private static final long VALID = 3232235521L; private static final String EXPECTED = "192.168.0.1"; @@ -57,28 +59,32 @@ public void setUp() @Test public void testTooFewArgs() { - expectException(ExpressionValidationException.class, "requires 1 argument"); - - testExpression( - Collections.emptyList(), - buildExpectedExpression(), - IGNORE_EXPECTED_RESULT + Throwable t = Assert.assertThrows( + ExpressionValidationException.class, + () -> testExpression( + Collections.emptyList(), + buildExpectedExpression(), + IGNORE_EXPECTED_RESULT + ) ); + Assert.assertEquals("Function[ipv4_stringify] requires 1 argument", t.getMessage()); } @Test public void testTooManyArgs() { - expectException(ExpressionValidationException.class, "requires 1 argument"); - - testExpression( - Arrays.asList( - testHelper.makeLiteral(VALID), - testHelper.makeLiteral(VALID) - ), - buildExpectedExpression(VALID, VALID), - IGNORE_EXPECTED_RESULT + Throwable t = Assert.assertThrows( + ExpressionValidationException.class, + () -> testExpression( + Arrays.asList( + testHelper.makeLiteral(VALID), + testHelper.makeLiteral(VALID) + ), + buildExpectedExpression(VALID, VALID), + IGNORE_EXPECTED_RESULT + ) ); + Assert.assertEquals("Function[ipv4_stringify] requires 1 argument", t.getMessage()); } @Test diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/expression/LeastExpressionTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/expression/LeastExpressionTest.java index 6702769e927a..496543a5dd78 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/expression/LeastExpressionTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/expression/LeastExpressionTest.java @@ -28,6 +28,7 @@ import org.apache.druid.segment.column.ColumnType; import org.apache.druid.segment.column.RowSignature; import org.apache.druid.sql.calcite.expression.builtin.LeastOperatorConversion; +import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.junit.Before; import org.junit.Test; @@ -37,7 +38,7 @@ import java.util.List; import java.util.Map; -public class LeastExpressionTest extends ExpressionTestBase +public class LeastExpressionTest extends CalciteTestBase { private static final String DOUBLE_KEY = "d"; private static final double DOUBLE_VALUE = 3.1; diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/expression/TimeFormatOperatorConversionTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/expression/TimeFormatOperatorConversionTest.java index 204b7784281f..021e35795152 100644 --- a/sql/src/test/java/org/apache/druid/sql/calcite/expression/TimeFormatOperatorConversionTest.java +++ b/sql/src/test/java/org/apache/druid/sql/calcite/expression/TimeFormatOperatorConversionTest.java @@ -27,6 +27,7 @@ import org.apache.druid.segment.column.ColumnType; import org.apache.druid.segment.column.RowSignature; import org.apache.druid.sql.calcite.expression.builtin.TimeFormatOperatorConversion; +import org.apache.druid.sql.calcite.util.CalciteTestBase; import org.junit.Before; import org.junit.Test; @@ -36,7 +37,7 @@ /** * Tests for TIME_FORMAT */ -public class TimeFormatOperatorConversionTest extends ExpressionTestBase +public class TimeFormatOperatorConversionTest extends CalciteTestBase { private static final RowSignature ROW_SIGNATURE = RowSignature .builder()