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

tanner 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 50a20824c4 [CALCITE-5955] BigQuery PERCENTILE functions are unparsed 
incorrectly
50a20824c4 is described below

commit 50a20824c4536450dcae963b5e757cf4bbc7e406
Author: Tanner Clary <[email protected]>
AuthorDate: Thu Aug 24 13:31:54 2023 -0700

    [CALCITE-5955] BigQuery PERCENTILE functions are unparsed incorrectly
---
 .../apache/calcite/runtime/CalciteResource.java    |  2 +-
 .../calcite/sql/dialect/BigQuerySqlDialect.java    |  5 +++
 .../calcite/sql/fun/SqlBasicAggFunction.java       | 39 +++++++++++++++-------
 .../calcite/sql/fun/SqlLibraryOperators.java       |  6 ++--
 .../calcite/sql/fun/SqlStdOperatorTable.java       |  6 ++--
 .../calcite/runtime/CalciteResource.properties     |  2 +-
 .../calcite/rel/rel2sql/RelToSqlConverterTest.java | 36 ++++++++++++++++++++
 .../org/apache/calcite/test/SqlValidatorTest.java  |  2 +-
 8 files changed, 79 insertions(+), 19 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java 
b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
index b32f752ad2..2791918382 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -490,7 +490,7 @@ public interface CalciteResource {
   @BaseMessage("QUALIFY expression ''{0}'' must contain a window function")
   ExInst<SqlValidatorException> 
qualifyExpressionMustContainWindowFunction(String a0);
 
-  @BaseMessage("ROW/RANGE not allowed with RANK, DENSE_RANK or ROW_NUMBER 
functions")
+  @BaseMessage("ROW/RANGE not allowed with RANK, DENSE_RANK, ROW_NUMBER or 
PERCENTILE_CONT/DISC functions")
   ExInst<SqlValidatorException> rankWithFrame();
 
   @BaseMessage("RANK or DENSE_RANK functions require ORDER BY clause in window 
specification")
diff --git 
a/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java 
b/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java
index c36e25a1da..5fa7382112 100644
--- a/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java
+++ b/core/src/main/java/org/apache/calcite/sql/dialect/BigQuerySqlDialect.java
@@ -209,6 +209,11 @@ public class BigQuerySqlDialect extends SqlDialect {
       }
       unparseItem(writer, call, leftPrec);
       break;
+    case OVER:
+      call.operand(0).unparse(writer, leftPrec, rightPrec);
+      writer.keyword("OVER");
+      call.operand(1).unparse(writer, leftPrec, rightPrec);
+      break;
     default:
       super.unparseCall(writer, call, leftPrec, rightPrec);
     }
diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlBasicAggFunction.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlBasicAggFunction.java
index 0c1009d098..b63b37cf29 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlBasicAggFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlBasicAggFunction.java
@@ -54,6 +54,7 @@ public final class SqlBasicAggFunction extends SqlAggFunction 
{
   private final boolean allowsNullTreatment;
   private final boolean allowsSeparator;
   private final boolean percentile;
+  private final boolean allowsFraming;
 
   //~ Constructors -----------------------------------------------------------
 
@@ -66,7 +67,7 @@ public final class SqlBasicAggFunction extends SqlAggFunction 
{
       boolean requiresOrder, boolean requiresOver,
       Optionality requiresGroupOrder, Optionality distinctOptionality,
       SqlSyntax syntax, boolean allowsNullTreatment, boolean allowsSeparator,
-      boolean percentile) {
+      boolean percentile, boolean allowsFraming) {
     super(name, sqlIdentifier, kind,
         requireNonNull(returnTypeInference, "returnTypeInference"), 
operandTypeInference,
         requireNonNull(operandTypeChecker, "operandTypeChecker"),
@@ -79,6 +80,7 @@ public final class SqlBasicAggFunction extends SqlAggFunction 
{
     this.allowsNullTreatment = allowsNullTreatment;
     this.allowsSeparator = allowsSeparator;
     this.percentile = percentile;
+    this.allowsFraming = allowsFraming;
   }
 
   /** Creates a SqlBasicAggFunction whose name is the same as its kind. */
@@ -95,7 +97,7 @@ public final class SqlBasicAggFunction extends SqlAggFunction 
{
     return new SqlBasicAggFunction(name, null, kind, returnTypeInference, null,
         operandTypeChecker, null, SqlFunctionCategory.NUMERIC, false, false,
         Optionality.FORBIDDEN, Optionality.OPTIONAL, SqlSyntax.FUNCTION, false,
-        false, false);
+        false, false, true);
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -147,7 +149,7 @@ public final class SqlBasicAggFunction extends 
SqlAggFunction {
         getReturnTypeInference(), getOperandTypeInference(),
         getOperandTypeChecker(), staticFun, getFunctionType(), requiresOrder(),
         requiresOver(), requiresGroupOrder(), distinctOptionality, syntax,
-        allowsNullTreatment, allowsSeparator, percentile);
+        allowsNullTreatment, allowsSeparator, percentile, allowsFraming);
   }
 
   /** Sets {@link #getDistinctOptionality()}. */
@@ -156,7 +158,7 @@ public final class SqlBasicAggFunction extends 
SqlAggFunction {
         getReturnTypeInference(), getOperandTypeInference(),
         getOperandTypeChecker(), staticFun, getFunctionType(), requiresOrder(),
         requiresOver(), requiresGroupOrder(), distinctOptionality, syntax,
-        allowsNullTreatment, allowsSeparator, percentile);
+        allowsNullTreatment, allowsSeparator, percentile, allowsFraming);
   }
 
   /** Sets {@link #getFunctionType()}. */
@@ -165,7 +167,7 @@ public final class SqlBasicAggFunction extends 
SqlAggFunction {
         getReturnTypeInference(), getOperandTypeInference(),
         getOperandTypeChecker(), staticFun, category, requiresOrder(),
         requiresOver(), requiresGroupOrder(), distinctOptionality, syntax,
-        allowsNullTreatment, allowsSeparator, percentile);
+        allowsNullTreatment, allowsSeparator, percentile, allowsFraming);
   }
 
   @Override public SqlSyntax getSyntax() {
@@ -178,7 +180,7 @@ public final class SqlBasicAggFunction extends 
SqlAggFunction {
         getReturnTypeInference(), getOperandTypeInference(),
         getOperandTypeChecker(), staticFun, getFunctionType(), requiresOrder(),
         requiresOver(), requiresGroupOrder(), distinctOptionality, syntax,
-        allowsNullTreatment, allowsSeparator, percentile);
+        allowsNullTreatment, allowsSeparator, percentile, allowsFraming);
   }
 
   @Override public boolean allowsNullTreatment() {
@@ -191,7 +193,7 @@ public final class SqlBasicAggFunction extends 
SqlAggFunction {
         getReturnTypeInference(), getOperandTypeInference(),
         getOperandTypeChecker(), staticFun, getFunctionType(), requiresOrder(),
         requiresOver(), requiresGroupOrder(), distinctOptionality, syntax,
-        allowsNullTreatment, allowsSeparator, percentile);
+        allowsNullTreatment, allowsSeparator, percentile, allowsFraming);
   }
 
   /** Returns whether this aggregate function allows '{@code SEPARATOR string}'
@@ -206,7 +208,7 @@ public final class SqlBasicAggFunction extends 
SqlAggFunction {
         getReturnTypeInference(), getOperandTypeInference(),
         getOperandTypeChecker(), staticFun, getFunctionType(), requiresOrder(),
         requiresOver(), requiresGroupOrder(), distinctOptionality, syntax,
-        allowsNullTreatment, allowsSeparator, percentile);
+        allowsNullTreatment, allowsSeparator, percentile, allowsFraming);
   }
 
   @Override public boolean isPercentile() {
@@ -219,7 +221,20 @@ public final class SqlBasicAggFunction extends 
SqlAggFunction {
         getReturnTypeInference(), getOperandTypeInference(),
         getOperandTypeChecker(), staticFun, getFunctionType(), requiresOrder(),
         requiresOver(), requiresGroupOrder(), distinctOptionality, syntax,
-        allowsNullTreatment, allowsSeparator, percentile);
+        allowsNullTreatment, allowsSeparator, percentile, allowsFraming);
+  }
+
+  @Override public boolean allowsFraming() {
+    return allowsFraming;
+  }
+
+  /** Sets {@link #allowsFraming()}. */
+  public SqlBasicAggFunction withAllowsFraming(boolean allowsFraming) {
+    return new SqlBasicAggFunction(getName(), getSqlIdentifier(), kind,
+        getReturnTypeInference(), getOperandTypeInference(),
+        getOperandTypeChecker(), staticFun, getFunctionType(), requiresOrder(),
+        requiresOver(), requiresGroupOrder(), distinctOptionality, syntax,
+        allowsNullTreatment, allowsSeparator, percentile, allowsFraming);
   }
 
   /** Sets {@link #requiresOver()}. */
@@ -228,7 +243,7 @@ public final class SqlBasicAggFunction extends 
SqlAggFunction {
         getReturnTypeInference(), getOperandTypeInference(),
         getOperandTypeChecker(), staticFun, getFunctionType(), requiresOrder(),
         over, requiresGroupOrder(), distinctOptionality, syntax,
-        allowsNullTreatment, allowsSeparator, percentile);
+        allowsNullTreatment, allowsSeparator, percentile, allowsFraming);
   }
 
   /** Sets {@link #requiresGroupOrder()}. */
@@ -237,7 +252,7 @@ public final class SqlBasicAggFunction extends 
SqlAggFunction {
         getReturnTypeInference(), getOperandTypeInference(),
         getOperandTypeChecker(), staticFun, getFunctionType(), requiresOrder(),
         requiresOver(), groupOrder, distinctOptionality, syntax,
-        allowsNullTreatment, allowsSeparator, percentile);
+        allowsNullTreatment, allowsSeparator, percentile, allowsFraming);
   }
 
   /** Sets that value to be returned when {@link #unwrap} is applied to
@@ -247,6 +262,6 @@ public final class SqlBasicAggFunction extends 
SqlAggFunction {
         getReturnTypeInference(), getOperandTypeInference(),
         getOperandTypeChecker(), staticFun, getFunctionType(), requiresOrder(),
         requiresOver(), requiresGroupOrder(), distinctOptionality, syntax,
-        allowsNullTreatment, allowsSeparator, percentile);
+        allowsNullTreatment, allowsSeparator, percentile, allowsFraming);
   }
 }
diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
index 427e305d50..0abce560e5 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlLibraryOperators.java
@@ -699,7 +699,8 @@ public abstract class SqlLibraryOperators {
           .withFunctionType(SqlFunctionCategory.SYSTEM)
           .withOver(true)
           .withPercentile(true)
-          .withAllowsNullTreatment(true);
+          .withAllowsNullTreatment(true)
+          .withAllowsFraming(false);
 
   /** The {@code PERCENTILE_DISC} function, BigQuery's
    * equivalent to {@link SqlStdOperatorTable#PERCENTILE_DISC},
@@ -713,7 +714,8 @@ public abstract class SqlLibraryOperators {
           .withFunctionType(SqlFunctionCategory.SYSTEM)
           .withOver(true)
           .withPercentile(true)
-          .withAllowsNullTreatment(true);
+          .withAllowsNullTreatment(true)
+          .withAllowsFraming(false);
 
   /** The "DATE" function. It has the following overloads:
    *
diff --git 
a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java 
b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index e6ee9734e0..40ec61d624 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -2265,7 +2265,8 @@ public class SqlStdOperatorTable extends 
ReflectiveSqlOperatorTable {
               OperandTypes.UNIT_INTERVAL_NUMERIC_LITERAL)
           .withFunctionType(SqlFunctionCategory.SYSTEM)
           .withGroupOrder(Optionality.MANDATORY)
-          .withPercentile(true);
+          .withPercentile(true)
+          .withAllowsFraming(false);
 
   /**
    * {@code PERCENTILE_DISC} inverse distribution aggregate function.
@@ -2280,7 +2281,8 @@ public class SqlStdOperatorTable extends 
ReflectiveSqlOperatorTable {
               OperandTypes.UNIT_INTERVAL_NUMERIC_LITERAL)
           .withFunctionType(SqlFunctionCategory.SYSTEM)
           .withGroupOrder(Optionality.MANDATORY)
-          .withPercentile(true);
+          .withPercentile(true)
+          .withAllowsFraming(false);
 
   /**
    * The LISTAGG operator. String aggregator function.
diff --git 
a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties 
b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
index ba13eabd2c..10aae01fb0 100644
--- 
a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++ 
b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -168,7 +168,7 @@ DuplicateWindowName=Duplicate window names not allowed
 EmptyWindowSpec=Empty window specification not allowed
 DupWindowSpec=Duplicate window specification not allowed in the same window 
clause
 QualifyExpressionMustContainWindowFunction=QUALIFY expression ''{0}'' must 
contain a window function
-RankWithFrame=ROW/RANGE not allowed with RANK, DENSE_RANK or ROW_NUMBER 
functions
+RankWithFrame=ROW/RANGE not allowed with RANK, DENSE_RANK, ROW_NUMBER or 
PERCENTILE_CONT/DISC functions
 FuncNeedsOrderBy=RANK or DENSE_RANK functions require ORDER BY clause in 
window specification
 PartitionNotAllowed=PARTITION BY not allowed with existing window reference
 OrderByOverlap=ORDER BY not allowed in both base and referenced windows
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 9eeabcceae..ba235f3d6f 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
@@ -1312,6 +1312,42 @@ class RelToSqlConverterTest {
         .withPostgresql().ok(expectedPostgresql);
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5955";>[CALCITE-5955]
+   * BigQuery PERCENTILE functions are unparsed incorrectly</a>. */
+  @Test void testPercentileContWindow() {
+    final String partitionQuery = "select percentile_cont(\"product_id\", 
0.5)\n"
+        + "over(partition by \"product_id\")\n"
+        + "from \"foodmart\".\"product\"";
+    final String expectedPartition = "SELECT PERCENTILE_CONT(product_id, 0.5) "
+        + "OVER (PARTITION BY product_id)\n"
+        + "FROM foodmart.product";
+    final String query = "select percentile_cont(\"product_id\", 0.5) over()\n"
+        + "from \"foodmart\".\"product\"";
+    final String expectedQuery = "SELECT PERCENTILE_CONT(product_id, 0.5) OVER 
()\n"
+        + "FROM foodmart.product";
+    
sql(partitionQuery).withBigQuery().withLibrary(SqlLibrary.BIG_QUERY).ok(expectedPartition);
+    
sql(query).withBigQuery().withLibrary(SqlLibrary.BIG_QUERY).ok(expectedQuery);
+  }
+
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-5955";>[CALCITE-5955]
+   * BigQuery PERCENTILE functions are unparsed incorrectly</a>. */
+  @Test void testPercentileDiscWindowFrameClause() {
+    final String partitionQuery = "select percentile_disc(\"product_id\", 
0.5)\n"
+        + "over(partition by \"product_id\")\n"
+        + "from \"foodmart\".\"product\"";
+    final String expectedPartition = "SELECT PERCENTILE_DISC(product_id, 0.5) "
+        + "OVER (PARTITION BY product_id)\n"
+        + "FROM foodmart.product";
+    final String query = "select percentile_disc(\"product_id\", 0.5) over()\n"
+        + "from \"foodmart\".\"product\"";
+    final String expectedQuery = "SELECT PERCENTILE_DISC(product_id, 0.5) OVER 
()\n"
+        + "FROM foodmart.product";
+    
sql(partitionQuery).withBigQuery().withLibrary(SqlLibrary.BIG_QUERY).ok(expectedPartition);
+    
sql(query).withBigQuery().withLibrary(SqlLibrary.BIG_QUERY).ok(expectedQuery);
+  }
+
   /** Test case for
    * <a 
href="https://issues.apache.org/jira/browse/CALCITE-2722";>[CALCITE-2722]
    * SqlImplementor createLeftCall method throws StackOverflowError</a>. */
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java 
b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index 4dc78de70d..3e9269b783 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -150,7 +150,7 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
       "Set operator cannot combine streaming and non-streaming inputs";
 
   private static final String ROW_RANGE_NOT_ALLOWED_WITH_RANK =
-      "ROW/RANGE not allowed with RANK, DENSE_RANK or ROW_NUMBER functions";
+      "ROW/RANGE not allowed with RANK, DENSE_RANK, ROW_NUMBER or 
PERCENTILE_CONT/DISC functions";
 
   private static final String RANK_REQUIRES_ORDER_BY = "RANK or DENSE_RANK "
       + "functions require ORDER BY clause in window specification";

Reply via email to