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

mbudiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new af286b5493 [CALCITE-7425] Correct the logical inverse of 
SqlBetweenOperator
af286b5493 is described below

commit af286b54931fa2cb7604faee2f66b2ac0a31b3ae
Author: wforget <[email protected]>
AuthorDate: Mon Mar 2 10:52:36 2026 +0800

    [CALCITE-7425] Correct the logical inverse of SqlBetweenOperator
    
    Signed-off-by: wforget <[email protected]>
---
 .../apache/calcite/sql/fun/SqlBetweenOperator.java | 11 ++--
 .../rel/rel2sql/RelToSqlConverterStructsTest.java  |  3 +-
 .../calcite/rel/rel2sql/RelToSqlConverterTest.java | 65 ++++++++++++++++++----
 3 files changed, 62 insertions(+), 17 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
index 6f6234c3ed..2d77fd9df7 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
@@ -112,7 +112,10 @@ public SqlBetweenOperator(Flag flag, boolean negated) {
   //~ Methods ----------------------------------------------------------------
 
   @Override public boolean validRexOperands(int count, Litmus litmus) {
-    return litmus.fail("not a rex operator");
+    if (count != 3) {
+      return litmus.fail("wrong operand count {} for {}", count, this);
+    }
+    return litmus.succeed();
   }
 
   /**
@@ -125,14 +128,14 @@ public boolean isNegated() {
   }
 
   @Override public SqlOperator not() {
-    return of(negated, flag == Flag.SYMMETRIC);
+    return of(!negated, flag == Flag.SYMMETRIC);
   }
 
   private static SqlBetweenOperator of(boolean negated, boolean symmetric) {
     if (symmetric) {
       return negated
-          ? SqlStdOperatorTable.SYMMETRIC_BETWEEN
-          : SqlStdOperatorTable.SYMMETRIC_NOT_BETWEEN;
+          ? SqlStdOperatorTable.SYMMETRIC_NOT_BETWEEN
+          : SqlStdOperatorTable.SYMMETRIC_BETWEEN;
     } else {
       return negated
           ? SqlStdOperatorTable.NOT_BETWEEN
diff --git 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java
 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java
index dca08b4999..0472604f30 100644
--- 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java
+++ 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterStructsTest.java
@@ -18,6 +18,7 @@
 
 import org.apache.calcite.sql.dialect.CalciteSqlDialect;
 import org.apache.calcite.sql.parser.SqlParser;
+import org.apache.calcite.sql2rel.StandardConvertletTable;
 import org.apache.calcite.test.CalciteAssert;
 
 import com.google.common.collect.ImmutableList;
@@ -36,7 +37,7 @@ class RelToSqlConverterStructsTest {
   private RelToSqlConverterTest.Sql sql(String sql) {
     return new RelToSqlConverterTest.Sql(CalciteAssert.SchemaSpec.MY_DB, sql,
         CalciteSqlDialect.DEFAULT, SqlParser.Config.DEFAULT, ImmutableSet.of(),
-        UnaryOperator.identity(), null, ImmutableList.of());
+        UnaryOperator.identity(), null, ImmutableList.of(), 
StandardConvertletTable.INSTANCE);
   }
 
   @Test void testNestedSchemaSelectStar() {
diff --git 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index 4250181e66..1b219255b4 100644
--- 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++ 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -74,6 +74,7 @@
 import org.apache.calcite.sql.dialect.PostgresqlSqlDialect;
 import org.apache.calcite.sql.dialect.PrestoSqlDialect;
 import org.apache.calcite.sql.dialect.SqliteSqlDialect;
+import org.apache.calcite.sql.fun.SqlBetweenOperator;
 import org.apache.calcite.sql.fun.SqlLibrary;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.parser.SqlParser;
@@ -82,7 +83,10 @@
 import org.apache.calcite.sql.util.SqlShuttle;
 import org.apache.calcite.sql.validate.SqlConformance;
 import org.apache.calcite.sql.validate.SqlConformanceEnum;
+import org.apache.calcite.sql2rel.SqlRexConvertlet;
+import org.apache.calcite.sql2rel.SqlRexConvertletTable;
 import org.apache.calcite.sql2rel.SqlToRelConverter;
+import org.apache.calcite.sql2rel.StandardConvertletTable;
 import org.apache.calcite.test.CalciteAssert;
 import org.apache.calcite.test.MockSqlOperatorTable;
 import org.apache.calcite.test.RelBuilderTest;
@@ -135,7 +139,7 @@ class RelToSqlConverterTest {
   private Sql fixture() {
     return new Sql(CalciteAssert.SchemaSpec.JDBC_FOODMART, "?",
         CalciteSqlDialect.DEFAULT, SqlParser.Config.DEFAULT, ImmutableSet.of(),
-        UnaryOperator.identity(), null, ImmutableList.of());
+        UnaryOperator.identity(), null, ImmutableList.of(), 
StandardConvertletTable.INSTANCE);
   }
 
   /** Initiates a test case with a given SQL query. */
@@ -153,12 +157,13 @@ private Sql relFn(Function<RelBuilder, RelNode> relFn) {
   private static Planner getPlanner(List<RelTraitDef> traitDefs,
       SqlParser.Config parserConfig, SchemaPlus schema,
       SqlToRelConverter.Config sqlToRelConf, Collection<SqlLibrary> librarySet,
-      RelDataTypeSystem typeSystem, Program... programs) {
+      RelDataTypeSystem typeSystem, SqlRexConvertletTable convertletTable, 
Program... programs) {
     final FrameworkConfig config = Frameworks.newConfigBuilder()
         .parserConfig(parserConfig)
         .defaultSchema(schema)
         .traitDefs(traitDefs)
         .sqlToRelConverterConfig(sqlToRelConf)
+        .convertletTable(convertletTable)
         .programs(programs)
         .operatorTable(MockSqlOperatorTable.standard()
             .plus(librarySet)
@@ -11293,12 +11298,14 @@ static class Sql {
     private final List<Function<RelNode, RelNode>> transforms;
     private final SqlParser.Config parserConfig;
     private final UnaryOperator<SqlToRelConverter.Config> config;
+    private final SqlRexConvertletTable convertletTable;
 
     Sql(CalciteAssert.SchemaSpec schemaSpec, String sql, SqlDialect dialect,
         SqlParser.Config parserConfig, Set<SqlLibrary> librarySet,
         UnaryOperator<SqlToRelConverter.Config> config,
         @Nullable Function<RelBuilder, RelNode> relFn,
-        List<Function<RelNode, RelNode>> transforms) {
+        List<Function<RelNode, RelNode>> transforms,
+        SqlRexConvertletTable convertletTable) {
       this.schemaSpec = schemaSpec;
       this.sql = sql;
       this.dialect = dialect;
@@ -11307,21 +11314,22 @@ static class Sql {
       this.transforms = ImmutableList.copyOf(transforms);
       this.parserConfig = parserConfig;
       this.config = config;
+      this.convertletTable = convertletTable;
     }
 
     Sql withSql(String sql) {
       return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, 
config,
-          relFn, transforms);
+          relFn, transforms, convertletTable);
     }
 
     Sql dialect(SqlDialect dialect) {
       return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, 
config,
-          relFn, transforms);
+          relFn, transforms, convertletTable);
     }
 
     Sql relFn(Function<RelBuilder, RelNode> relFn) {
       return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, 
config,
-          relFn, transforms);
+          relFn, transforms, convertletTable);
     }
 
     Sql withCalcite() {
@@ -11564,12 +11572,12 @@ Sql withOracleModifiedTypeSystem() {
 
     Sql parserConfig(SqlParser.Config parserConfig) {
       return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, 
config,
-          relFn, transforms);
+          relFn, transforms, convertletTable);
     }
 
     Sql withConfig(UnaryOperator<SqlToRelConverter.Config> config) {
       return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, 
config,
-          relFn, transforms);
+          relFn, transforms, convertletTable);
     }
 
     final Sql withLibrary(SqlLibrary library) {
@@ -11578,7 +11586,7 @@ final Sql withLibrary(SqlLibrary library) {
 
     Sql withLibrarySet(Iterable<? extends SqlLibrary> librarySet) {
       return new Sql(schemaSpec, sql, dialect, parserConfig,
-          ImmutableSet.copyOf(librarySet), config, relFn, transforms);
+          ImmutableSet.copyOf(librarySet), config, relFn, transforms, 
convertletTable);
     }
 
     Sql optimize(final RuleSet ruleSet,
@@ -11595,7 +11603,12 @@ Sql optimize(final RuleSet ruleSet,
                 ImmutableList.of(), ImmutableList.of());
           });
       return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, 
config,
-          relFn, transforms);
+          relFn, transforms, convertletTable);
+    }
+
+    Sql withConvertletTable(SqlRexConvertletTable convertletTable) {
+      return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, 
config,
+          relFn, transforms, convertletTable);
     }
 
     Sql ok(String expectedQuery) {
@@ -11631,7 +11644,8 @@ String exec() {
               .withTrimUnusedFields(false));
           RelDataTypeSystem typeSystem = dialect.getTypeSystem();
           final Planner planner =
-              getPlanner(null, parserConfig, defaultSchema, config, 
librarySet, typeSystem);
+              getPlanner(null, parserConfig, defaultSchema, config, 
librarySet, typeSystem,
+                  convertletTable);
           SqlNode parse = planner.parse(sql);
           SqlNode validate = planner.validate(parse);
           rel = planner.rel(validate).project();
@@ -11647,7 +11661,7 @@ String exec() {
 
     public Sql schema(CalciteAssert.SchemaSpec schemaSpec) {
       return new Sql(schemaSpec, sql, dialect, parserConfig, librarySet, 
config,
-          relFn, transforms);
+          relFn, transforms, convertletTable);
     }
   }
 
@@ -11835,4 +11849,31 @@ public Sql schema(CalciteAssert.SchemaSpec schemaSpec) 
{
     sql(sql).schema(CalciteAssert.SchemaSpec.JDBC_SCOTT).ok(expected);
   }
 
+  @Test void testNotBetween() {
+    Sql f = fixture().withConvertletTable(new SqlRexConvertletTable() {
+      @Override public @Nullable SqlRexConvertlet get(SqlCall call) {
+        // Override StandardConvertletTable::convertBetween to avoid 
converting SqlBetweenOperator
+        if (call != null && call.getOperator() instanceof SqlBetweenOperator) {
+          return StandardConvertletTable.INSTANCE::convertCall;
+        }
+        return StandardConvertletTable.INSTANCE.get(call);
+      }
+    });
+    final String query1 = "SELECT empno FROM emp WHERE NOT (empno BETWEEN 1000 
AND 2000)";
+    final String expected1 = "SELECT \"EMPNO\"\n"
+        + "FROM \"SCOTT\".\"EMP\"\n"
+        + "WHERE CAST(\"EMPNO\" AS INTEGER) NOT BETWEEN ASYMMETRIC 1000 AND 
2000";
+    f.withSql(query1)
+        .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+        .ok(expected1);
+
+    final String query2 = "SELECT empno FROM emp WHERE NOT (empno BETWEEN 
SYMMETRIC 1000 AND 2000)";
+    final String expected2 = "SELECT \"EMPNO\"\n"
+        + "FROM \"SCOTT\".\"EMP\"\n"
+        + "WHERE CAST(\"EMPNO\" AS INTEGER) NOT BETWEEN SYMMETRIC 1000 AND 
2000";
+    f.withSql(query2)
+        .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+        .ok(expected2);
+  }
+
 }

Reply via email to