add round test (#11088)

* add round test

* code style

* handle null val for round function

* handle null val for round function

* support null for round

* fix compatiblity

* fix test

* fix test

* code style

* optimize format
diff --git a/core/src/main/java/org/apache/druid/math/expr/Function.java b/core/src/main/java/org/apache/druid/math/expr/Function.java
index 874d1ed..baa5768 100644
--- a/core/src/main/java/org/apache/druid/math/expr/Function.java
+++ b/core/src/main/java/org/apache/druid/math/expr/Function.java
@@ -1311,6 +1311,9 @@
     public ExprEval apply(List<Expr> args, Expr.ObjectBinding bindings)
     {
       ExprEval value1 = args.get(0).eval(bindings);
+      if (NullHandling.sqlCompatible() && value1.isNumericNull()) {
+        return ExprEval.of(null);
+      }
       if (value1.type() != ExprType.LONG && value1.type() != ExprType.DOUBLE) {
         throw new IAE(
             "The first argument to the function[%s] should be integer or double type but got the type: %s",
diff --git a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java
index 0d4fb4d..bd729fe 100644
--- a/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java
+++ b/core/src/test/java/org/apache/druid/math/expr/FunctionTest.java
@@ -23,6 +23,7 @@
 import com.google.common.collect.ImmutableSet;
 import org.apache.druid.common.config.NullHandling;
 import org.apache.druid.java.util.common.Pair;
+import org.apache.druid.java.util.common.StringUtils;
 import org.apache.druid.testing.InitializedNullHandlingTest;
 import org.junit.Assert;
 import org.junit.Before;
@@ -408,11 +409,39 @@
   }
 
   @Test
+  public void testRoundWithNullValue()
+  {
+    Set<Pair<String, String>> invalidArguments = ImmutableSet.of(
+        Pair.of("null", "STRING"),
+        Pair.of("x", "STRING")
+    );
+    for (Pair<String, String> argAndType : invalidArguments) {
+      if (NullHandling.sqlCompatible()) {
+        assertExpr(StringUtils.format("round(%s)", argAndType.lhs), null);
+      } else {
+        try {
+          assertExpr(StringUtils.format("round(%s)", argAndType.lhs), null);
+          Assert.fail("Did not throw IllegalArgumentException");
+        }
+        catch (IllegalArgumentException e) {
+          Assert.assertEquals(
+              String.format(
+                  Locale.ENGLISH,
+                  "The first argument to the function[round] should be integer or double type but got the type: %s",
+                  argAndType.rhs
+              ),
+              e.getMessage()
+          );
+        }
+      }
+    }
+  }
+
+  @Test
   public void testRoundWithInvalidFirstArgument()
   {
     Set<Pair<String, String>> invalidArguments = ImmutableSet.of(
         Pair.of("b", "LONG_ARRAY"),
-        Pair.of("x", "STRING"),
         Pair.of("c", "DOUBLE_ARRAY"),
         Pair.of("a", "STRING_ARRAY")
 
diff --git a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java
index 86ef6dc..cbd875a 100644
--- a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java
@@ -17552,4 +17552,43 @@
         )
     );
   }
+
+  @Test
+  public void testRoundFuc() throws Exception
+  {
+
+    testQuery(
+        "SELECT f1, round(f1) FROM druid.numfoo",
+        ImmutableList.of(
+            new Druids.ScanQueryBuilder()
+                .dataSource(CalciteTests.DATASOURCE3)
+                .intervals(querySegmentSpec(Filtration.eternity()))
+                .virtualColumns(
+                    expressionVirtualColumn("v0", "round(\"f1\")", ValueType.FLOAT)
+                )
+                .columns("f1", "v0")
+                .legacy(false)
+                .resultFormat(ScanQuery.ResultFormat.RESULT_FORMAT_COMPACTED_LIST)
+                .context(QUERY_CONTEXT_DEFAULT)
+                .build()
+        ),
+        NullHandling.sqlCompatible()
+        ? ImmutableList.of(
+            new Object[]{1.0f, 1.0f},
+            new Object[]{0.1f, 0.0f},
+            new Object[]{0.0f, 0.0f},
+            new Object[]{null, null},
+            new Object[]{null, null},
+            new Object[]{null, null}
+        )
+        : ImmutableList.of(
+            new Object[]{1.0f, 1.0f},
+            new Object[]{0.1f, 0.0f},
+            new Object[]{0.0f, 0.0f},
+            new Object[]{0.0f, 0.0f},
+            new Object[]{0.0f, 0.0f},
+            new Object[]{0.0f, 0.0f}
+        )
+    );
+  }
 }
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 898a64c..9525b75 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
@@ -904,15 +904,17 @@
   {
     final SqlFunction roundFunction = new RoundOperatorConversion().calciteOperator();
 
-    expectException(
-        IAE.class,
-        "The first argument to the function[round] should be integer or double type but got the type: STRING"
-    );
+    if (!NullHandling.sqlCompatible()) {
+      expectException(
+          IAE.class,
+          "The first argument to the function[round] should be integer or double type but got the type: STRING"
+      );
+    }
     testHelper.testExpression(
         roundFunction,
         testHelper.makeInputRef("s"),
         DruidExpression.fromExpression("round(\"s\")"),
-        "IAE Exception"
+        NullHandling.sqlCompatible() ? null : "IAE Exception"
     );
   }