diff --git a/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java b/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java index 9b38821202c0..9686a9ec1b5c 100644 --- a/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java +++ b/core/src/main/java/org/apache/calcite/sql/dialect/SnowflakeSqlDialect.java @@ -17,11 +17,17 @@ package org.apache.calcite.sql.dialect; import org.apache.calcite.avatica.util.Casing; +import org.apache.calcite.rel.type.RelDataType; +import org.apache.calcite.sql.SqlBasicCall; import org.apache.calcite.sql.SqlCall; import org.apache.calcite.sql.SqlDialect; +import org.apache.calcite.sql.SqlKind; +import org.apache.calcite.sql.SqlNode; +import org.apache.calcite.sql.SqlOperator; import org.apache.calcite.sql.SqlWriter; import org.apache.calcite.sql.fun.SqlLibraryOperators; import org.apache.calcite.sql.parser.SqlParserPos; +import org.apache.calcite.sql.type.SqlTypeName; /** * A SqlDialect implementation for the Snowflake database. @@ -73,6 +79,32 @@ public SnowflakeSqlDialect(Context context) { } } + @Override public SqlNode rewriteMaxMinExpr(SqlNode aggCall, RelDataType relDataType) { + return rewriteMaxMin(aggCall, relDataType); + } + + /** + * Helper for rewrites of MAX/MIN. + * Snowflake, rewrite as + * BOOLOR_AGG/BOOLAND_AGG if the return type is BOOLEAN. + */ + public static SqlNode rewriteMaxMin(SqlNode aggCall, RelDataType relDataType) { + // The behavior of this method depends on the argument type, + // and whether it is MIN/MAX + final SqlTypeName type = relDataType.getSqlTypeName(); + final boolean isMax = aggCall.getKind() == SqlKind.MAX; + // If the type is BOOLEAN, create a new call to the correct operator + if (type == SqlTypeName.BOOLEAN) { + final SqlOperator op = + isMax ? SqlLibraryOperators.BOOLOR_AGG + : SqlLibraryOperators.BOOLAND_AGG; + final SqlNode operand = ((SqlBasicCall) aggCall).operand(0); + return op.createCall(SqlParserPos.ZERO, operand); + } + // Otherwise, just return as it arrived + return aggCall; + } + @Override public boolean supportsApproxCountDistinct() { return true; } 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 1e8da43a2f66..af4ff86794d7 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 @@ -6968,10 +6968,15 @@ private void checkLiteral2(String expression, String expected) { + "BOOL_AND(\"brand_name\" = 'a'), " + "MIN(\"brand_name\")\n" + "FROM \"foodmart\".\"product\""; + final String expectedSnowflake = "SELECT BOOLOR_AGG(\"brand_name\" = 'a'), " + + "BOOLAND_AGG(\"brand_name\" = 'a'), " + + "MIN(\"brand_name\")\n" + + "FROM \"foodmart\".\"product\""; sql(query) .ok(expected) .withBigQuery().ok(expectedBigQuery) .withPostgresql().ok(expectedPostgres) + .withSnowflake().ok(expectedSnowflake) .withRedshift().ok(expectedPostgres); }