This is an automated email from the ASF dual-hosted git repository.

gian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 3ae5e978012 Add IS [NOT] TRUE, IS [NOT] FALSE native functions. 
(#14977)
3ae5e978012 is described below

commit 3ae5e978012e7a553e6ad3007eb210ab8da5b6fc
Author: Gian Merlino <[email protected]>
AuthorDate: Thu Sep 14 09:19:09 2023 -0700

    Add IS [NOT] TRUE, IS [NOT] FALSE native functions. (#14977)
    
    They are not quite the same as "x == true", "x != true", etc. These
    functions never return null, even when "x" itself is null.
---
 .../java/org/apache/druid/math/expr/Function.java  | 155 +++++++++++++++++++++
 .../java/org/apache/druid/math/expr/EvalTest.java  | 120 ++++++++++++++++
 .../expression/UnarySuffixOperatorConversion.java  |  64 ---------
 .../sql/calcite/planner/DruidOperatorTable.java    |  21 +--
 .../apache/druid/sql/calcite/CalciteQueryTest.java |   2 +-
 5 files changed, 280 insertions(+), 82 deletions(-)

diff --git a/processing/src/main/java/org/apache/druid/math/expr/Function.java 
b/processing/src/main/java/org/apache/druid/math/expr/Function.java
index 632425d1c75..406ffac1ea7 100644
--- a/processing/src/main/java/org/apache/druid/math/expr/Function.java
+++ b/processing/src/main/java/org/apache/druid/math/expr/Function.java
@@ -27,6 +27,7 @@ import org.apache.druid.java.util.common.StringUtils;
 import org.apache.druid.java.util.common.UOE;
 import org.apache.druid.math.expr.vector.CastToTypeVectorProcessor;
 import org.apache.druid.math.expr.vector.ExprVectorProcessor;
+import org.apache.druid.math.expr.vector.VectorComparisonProcessors;
 import org.apache.druid.math.expr.vector.VectorMathProcessors;
 import org.apache.druid.math.expr.vector.VectorProcessors;
 import org.apache.druid.math.expr.vector.VectorStringProcessors;
@@ -2224,6 +2225,160 @@ public interface Function extends NamedFunction
     }
   }
 
+  /**
+   * SQL function "IS NOT FALSE". Different from "IS TRUE" in that it returns 
true for NULL as well.
+   */
+  class IsNotFalseFunc implements Function
+  {
+    @Override
+    public String name()
+    {
+      return "notfalse";
+    }
+
+    @Override
+    public ExprEval apply(List<Expr> args, Expr.ObjectBinding bindings)
+    {
+      final ExprEval arg = args.get(0).eval(bindings);
+      return ExprEval.ofLongBoolean(arg.value() == null || arg.asBoolean());
+    }
+
+    @Override
+    public void validateArguments(List<Expr> args)
+    {
+      validationHelperCheckArgumentCount(args, 1);
+    }
+
+    @Nullable
+    @Override
+    public ExpressionType getOutputType(Expr.InputBindingInspector inspector, 
List<Expr> args)
+    {
+      return ExpressionType.LONG;
+    }
+  }
+
+  /**
+   * SQL function "IS NOT TRUE". Different from "IS FALSE" in that it returns 
true for NULL as well.
+   */
+  class IsNotTrueFunc implements Function
+  {
+    @Override
+    public String name()
+    {
+      return "nottrue";
+    }
+
+    @Override
+    public ExprEval apply(List<Expr> args, Expr.ObjectBinding bindings)
+    {
+      final ExprEval arg = args.get(0).eval(bindings);
+      return ExprEval.ofLongBoolean(arg.value() == null || !arg.asBoolean());
+    }
+
+    @Override
+    public void validateArguments(List<Expr> args)
+    {
+      validationHelperCheckArgumentCount(args, 1);
+    }
+
+    @Nullable
+    @Override
+    public ExpressionType getOutputType(Expr.InputBindingInspector inspector, 
List<Expr> args)
+    {
+      return ExpressionType.LONG;
+    }
+  }
+
+  /**
+   * SQL function "IS FALSE".
+   */
+  class IsFalseFunc implements Function
+  {
+    @Override
+    public String name()
+    {
+      return "isfalse";
+    }
+
+    @Override
+    public ExprEval apply(List<Expr> args, Expr.ObjectBinding bindings)
+    {
+      final ExprEval arg = args.get(0).eval(bindings);
+      return ExprEval.ofLongBoolean(arg.value() != null && !arg.asBoolean());
+    }
+
+    @Override
+    public void validateArguments(List<Expr> args)
+    {
+      validationHelperCheckArgumentCount(args, 1);
+    }
+
+    @Nullable
+    @Override
+    public ExpressionType getOutputType(Expr.InputBindingInspector inspector, 
List<Expr> args)
+    {
+      return ExpressionType.LONG;
+    }
+
+    @Override
+    public boolean canVectorize(Expr.InputBindingInspector inspector, 
List<Expr> args)
+    {
+      final Expr expr = args.get(0);
+      return inspector.areNumeric(expr) && expr.canVectorize(inspector);
+    }
+
+    @Override
+    public <T> ExprVectorProcessor<T> 
asVectorProcessor(Expr.VectorInputBindingInspector inspector, List<Expr> args)
+    {
+      return VectorComparisonProcessors.lessThanOrEqual(inspector, 
args.get(0), ExprEval.of(0L).toExpr());
+    }
+  }
+
+  /**
+   * SQL function "IS TRUE".
+   */
+  class IsTrueFunc implements Function
+  {
+    @Override
+    public String name()
+    {
+      return "istrue";
+    }
+
+    @Override
+    public ExprEval apply(List<Expr> args, Expr.ObjectBinding bindings)
+    {
+      final ExprEval arg = args.get(0).eval(bindings);
+      return ExprEval.ofLongBoolean(arg.asBoolean());
+    }
+
+    @Override
+    public void validateArguments(List<Expr> args)
+    {
+      validationHelperCheckArgumentCount(args, 1);
+    }
+
+    @Nullable
+    @Override
+    public ExpressionType getOutputType(Expr.InputBindingInspector inspector, 
List<Expr> args)
+    {
+      return ExpressionType.LONG;
+    }
+
+    @Override
+    public boolean canVectorize(Expr.InputBindingInspector inspector, 
List<Expr> args)
+    {
+      final Expr expr = args.get(0);
+      return inspector.areNumeric(expr) && expr.canVectorize(inspector);
+    }
+
+    @Override
+    public <T> ExprVectorProcessor<T> 
asVectorProcessor(Expr.VectorInputBindingInspector inspector, List<Expr> args)
+    {
+      return VectorComparisonProcessors.greaterThan(inspector, args.get(0), 
ExprEval.of(0L).toExpr());
+    }
+  }
+
   class IsNullFunc implements Function
   {
     @Override
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 97a91cb3969..c49959aa1ae 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
@@ -99,6 +99,16 @@ public class EvalTest extends InitializedNullHandlingTest
       Assert.assertTrue(evalDouble("2.0 == 2.0", bindings) > 0.0);
       Assert.assertTrue(evalDouble("2.0 != 1.0", bindings) > 0.0);
 
+      Assert.assertEquals(0L, evalLong("istrue(0.0)", bindings));
+      Assert.assertEquals(1L, evalLong("isfalse(0.0)", bindings));
+      Assert.assertEquals(1L, evalLong("nottrue(0.0)", bindings));
+      Assert.assertEquals(0L, evalLong("notfalse(0.0)", bindings));
+
+      Assert.assertEquals(1L, evalLong("istrue(1.0)", bindings));
+      Assert.assertEquals(0L, evalLong("isfalse(1.0)", bindings));
+      Assert.assertEquals(0L, evalLong("nottrue(1.0)", bindings));
+      Assert.assertEquals(1L, evalLong("notfalse(1.0)", bindings));
+
       Assert.assertTrue(evalDouble("!-1.0", bindings) > 0.0);
       Assert.assertTrue(evalDouble("!0.0", bindings) > 0.0);
       Assert.assertFalse(evalDouble("!2.0", bindings) > 0.0);
@@ -121,6 +131,16 @@ public class EvalTest extends InitializedNullHandlingTest
       Assert.assertEquals(1L, evalLong("2.0 == 2.0", bindings));
       Assert.assertEquals(1L, evalLong("2.0 != 1.0", bindings));
 
+      Assert.assertEquals(0L, evalLong("istrue(0.0)", bindings));
+      Assert.assertEquals(1L, evalLong("isfalse(0.0)", bindings));
+      Assert.assertEquals(1L, evalLong("nottrue(0.0)", bindings));
+      Assert.assertEquals(0L, evalLong("notfalse(0.0)", bindings));
+
+      Assert.assertEquals(1L, evalLong("istrue(1.0)", bindings));
+      Assert.assertEquals(0L, evalLong("isfalse(1.0)", bindings));
+      Assert.assertEquals(0L, evalLong("nottrue(1.0)", bindings));
+      Assert.assertEquals(1L, evalLong("notfalse(1.0)", bindings));
+
       Assert.assertEquals(1L, evalLong("!-1.0", bindings));
       Assert.assertEquals(1L, evalLong("!0.0", bindings));
       Assert.assertEquals(0L, evalLong("!2.0", bindings));
@@ -201,6 +221,106 @@ public class EvalTest extends InitializedNullHandlingTest
     assertEquals("x", eval("nvl(if(x == 9223372036854775806, '', 'x'), 
'NULL')", bindings).asString());
   }
 
+  @Test
+  public void testIsFalse()
+  {
+    assertEquals(
+        0L,
+        new Function.IsFalseFunc()
+            .apply(ImmutableList.of(new NullLongExpr()), 
InputBindings.nilBindings())
+            .value()
+    );
+
+    assertEquals(
+        1L,
+        new Function.IsFalseFunc()
+            .apply(ImmutableList.of(new LongExpr(0L)), 
InputBindings.nilBindings())
+            .value()
+    );
+
+    assertEquals(
+        0L,
+        new Function.IsFalseFunc()
+            .apply(ImmutableList.of(new LongExpr(1L)), 
InputBindings.nilBindings())
+            .value()
+    );
+  }
+
+  @Test
+  public void testIsTrue()
+  {
+    assertEquals(
+        0L,
+        new Function.IsTrueFunc()
+            .apply(ImmutableList.of(new NullLongExpr()), 
InputBindings.nilBindings())
+            .value()
+    );
+
+    assertEquals(
+        0L,
+        new Function.IsTrueFunc()
+            .apply(ImmutableList.of(new LongExpr(0L)), 
InputBindings.nilBindings())
+            .value()
+    );
+
+    assertEquals(
+        1L,
+        new Function.IsTrueFunc()
+            .apply(ImmutableList.of(new LongExpr(1L)), 
InputBindings.nilBindings())
+            .value()
+    );
+  }
+
+  @Test
+  public void testIsNotFalse()
+  {
+    assertEquals(
+        1L,
+        new Function.IsNotFalseFunc()
+            .apply(ImmutableList.of(new NullLongExpr()), 
InputBindings.nilBindings())
+            .value()
+    );
+
+    assertEquals(
+        0L,
+        new Function.IsNotFalseFunc()
+            .apply(ImmutableList.of(new LongExpr(0L)), 
InputBindings.nilBindings())
+            .value()
+    );
+
+    assertEquals(
+        1L,
+        new Function.IsNotFalseFunc()
+            .apply(ImmutableList.of(new LongExpr(1L)), 
InputBindings.nilBindings())
+            .value()
+    );
+  }
+
+  @Test
+  public void testIsNotTrue()
+  {
+    assertEquals(
+        1L,
+        new Function.IsNotTrueFunc()
+            .apply(ImmutableList.of(new NullLongExpr()), 
InputBindings.nilBindings())
+            .value()
+    );
+
+    assertEquals(
+        1L,
+        new Function.IsNotTrueFunc()
+            .apply(ImmutableList.of(new LongExpr(0L)), 
InputBindings.nilBindings())
+            .value()
+    );
+
+    assertEquals(
+        0L,
+        new Function.IsNotTrueFunc()
+            .apply(ImmutableList.of(new LongExpr(1L)), 
InputBindings.nilBindings())
+            .value()
+    );
+  }
+
   @Test
   public void testArrayToScalar()
   {
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/UnarySuffixOperatorConversion.java
 
b/sql/src/main/java/org/apache/druid/sql/calcite/expression/UnarySuffixOperatorConversion.java
deleted file mode 100644
index 8a38fbe9c93..00000000000
--- 
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/UnarySuffixOperatorConversion.java
+++ /dev/null
@@ -1,64 +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 com.google.common.collect.Iterables;
-import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.sql.SqlOperator;
-import org.apache.druid.java.util.common.StringUtils;
-import org.apache.druid.segment.column.RowSignature;
-import org.apache.druid.sql.calcite.planner.PlannerContext;
-
-public class UnarySuffixOperatorConversion implements SqlOperatorConversion
-{
-  private final SqlOperator operator;
-  private final String druidOperator;
-
-  public UnarySuffixOperatorConversion(final SqlOperator operator, final 
String druidOperator)
-  {
-    this.operator = operator;
-    this.druidOperator = druidOperator;
-  }
-
-  @Override
-  public SqlOperator calciteOperator()
-  {
-    return operator;
-  }
-
-  @Override
-  public DruidExpression toDruidExpression(
-      final PlannerContext plannerContext,
-      final RowSignature rowSignature,
-      final RexNode rexNode
-  )
-  {
-    return OperatorConversions.convertCallBuilder(
-        plannerContext,
-        rowSignature,
-        rexNode,
-        operands -> StringUtils.format(
-            "(%s %s)",
-            Iterables.getOnlyElement(operands).getExpression(),
-            druidOperator
-        )
-    );
-  }
-}
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidOperatorTable.java
 
b/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidOperatorTable.java
index e8ab0cc71d8..16748b0b6ab 100644
--- 
a/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidOperatorTable.java
+++ 
b/sql/src/main/java/org/apache/druid/sql/calcite/planner/DruidOperatorTable.java
@@ -54,7 +54,6 @@ import 
org.apache.druid.sql.calcite.expression.OperatorConversions;
 import org.apache.druid.sql.calcite.expression.SqlOperatorConversion;
 import org.apache.druid.sql.calcite.expression.UnaryFunctionOperatorConversion;
 import org.apache.druid.sql.calcite.expression.UnaryPrefixOperatorConversion;
-import org.apache.druid.sql.calcite.expression.UnarySuffixOperatorConversion;
 import org.apache.druid.sql.calcite.expression.WindowSqlAggregate;
 import 
org.apache.druid.sql.calcite.expression.builtin.ArrayAppendOperatorConversion;
 import 
org.apache.druid.sql.calcite.expression.builtin.ArrayConcatOperatorConversion;
@@ -372,22 +371,10 @@ public class DruidOperatorTable implements 
SqlOperatorTable
                    .add(new 
UnaryPrefixOperatorConversion(SqlStdOperatorTable.UNARY_MINUS, "-"))
                    .add(new 
UnaryFunctionOperatorConversion(SqlStdOperatorTable.IS_NULL, "isnull"))
                    .add(new 
UnaryFunctionOperatorConversion(SqlStdOperatorTable.IS_NOT_NULL, "notnull"))
-                   .add(new UnarySuffixOperatorConversion(
-                       SqlStdOperatorTable.IS_FALSE,
-                       "<= 0"
-                   )) // Matches Evals.asBoolean
-                   .add(new UnarySuffixOperatorConversion(
-                       SqlStdOperatorTable.IS_NOT_TRUE,
-                       "<= 0"
-                   )) // Matches Evals.asBoolean
-                   .add(new UnarySuffixOperatorConversion(
-                       SqlStdOperatorTable.IS_TRUE,
-                       "> 0"
-                   )) // Matches Evals.asBoolean
-                   .add(new UnarySuffixOperatorConversion(
-                       SqlStdOperatorTable.IS_NOT_FALSE,
-                       "> 0"
-                   )) // Matches Evals.asBoolean
+                   .add(new 
DirectOperatorConversion(SqlStdOperatorTable.IS_FALSE, "isfalse"))
+                   .add(new 
DirectOperatorConversion(SqlStdOperatorTable.IS_TRUE, "istrue"))
+                   .add(new 
DirectOperatorConversion(SqlStdOperatorTable.IS_NOT_FALSE, "notfalse"))
+                   .add(new 
DirectOperatorConversion(SqlStdOperatorTable.IS_NOT_TRUE, "nottrue"))
                    .add(new 
BinaryOperatorConversion(SqlStdOperatorTable.MULTIPLY, "*"))
                    .add(new BinaryOperatorConversion(SqlStdOperatorTable.MOD, 
"%"))
                    .add(new 
BinaryOperatorConversion(SqlStdOperatorTable.DIVIDE, "/"))
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 58240800371..499dd8faeb8 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
@@ -2461,7 +2461,7 @@ public class CalciteQueryTest extends BaseCalciteQueryTest
                                                 "v0",
                                                 
NullHandling.replaceWithDefault()
                                                 ? "(\"cnt\" == 1)"
-                                                : "((\"cnt\" == 1) > 0)",
+                                                : "istrue((\"cnt\" == 1))",
                                                 ColumnType.LONG
                                             ))
                                             .setDimensions(dimensions(


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to