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 3ea7799649 [CALCITE-6936] Table function parameter matching should 
always be case-insensitive
3ea7799649 is described below

commit 3ea77996491de99067abfdeeb18dc8ed123a40d2
Author: Mihai Budiu <[email protected]>
AuthorDate: Mon Apr 7 17:22:48 2025 -0700

    [CALCITE-6936] Table function parameter matching should always be 
case-insensitive
    
    Signed-off-by: Mihai Budiu <[email protected]>
---
 .../org/apache/calcite/sql/SqlCallBinding.java     | 15 ++--------
 .../org/apache/calcite/test/SqlValidatorTest.java  | 35 +++++++++-------------
 2 files changed, 17 insertions(+), 33 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java 
b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
index bf0bee7743..08e593c530 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
@@ -32,6 +32,7 @@
 import org.apache.calcite.sql.validate.SelectScope;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlNameMatcher;
+import org.apache.calcite.sql.validate.SqlNameMatchers;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorException;
 import org.apache.calcite.sql.validate.SqlValidatorNamespace;
@@ -39,7 +40,6 @@
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
 import org.apache.calcite.util.ImmutableNullableList;
 import org.apache.calcite.util.NlsString;
-import org.apache.calcite.util.Pair;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
@@ -183,10 +183,10 @@ private List<SqlNode> permutedOperands(final SqlCall 
call) {
                 + ", operator " + operator);
     final List<String> paramNames = operandMetadata.paramNames();
     final List<SqlNode> permuted = new ArrayList<>();
+    // Always use case-insensitive lookup for parameter names
     final SqlNameMatcher nameMatcher =
-        validator.getCatalogReader().nameMatcher();
+        SqlNameMatchers.withCaseSensitive(false);
     for (final String paramName : paramNames) {
-      Pair<String, SqlIdentifier> args = null;
       for (int j = 0; j < call.getOperandList().size(); j++) {
         final SqlCall call2 = call.operand(j);
         assert call2.getKind() == SqlKind.ARGUMENT_ASSIGNMENT;
@@ -195,18 +195,9 @@ private List<SqlNode> permutedOperands(final SqlCall call) 
{
         if (nameMatcher.matches(operandName, paramName)) {
           permuted.add(call2.operand(0));
           break;
-        } else if (args == null
-            && nameMatcher.isCaseSensitive()
-            && operandName.equalsIgnoreCase(paramName)) {
-          args = Pair.of(paramName, operandID);
         }
         // the last operand, there is still no match.
         if (j == call.getOperandList().size() - 1) {
-          if (args != null) {
-            throw SqlUtil.newContextException(args.right.getParserPosition(),
-                
RESOURCE.paramNotFoundInFunctionDidYouMean(args.right.getSimple(),
-                    operator.getName(), args.left));
-          }
           if (operandMetadata.isFixedParameters()) {
             // Not like user defined functions, we do not patch up the operands
             // with DEFAULT and then convert to nulls during sql-to-rel 
conversion.
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 ea5485b0b8..0b45476964 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -11059,13 +11059,6 @@ private void checkCustomColumnResolving(String table) {
             + "(TIMESTAMP\\(0\\) ROWTIME, INTEGER PRODUCTID, INTEGER 
ORDERID\\)>, <COLUMN_LIST>, "
             + "<INTERVAL HOUR>\\)'\\. Supported form\\(s\\): TUMBLE\\(TABLE 
table_name, "
             + "DESCRIPTOR\\(timecol\\), datetime interval\\[, datetime 
interval\\]\\)");
-    sql("select rowtime, productid, orderid, 'window_start', 'window_end'\n"
-        + "from table(\n"
-        + "tumble(\n"
-        + "^\"data\"^ => table orders,\n"
-        + "TIMECOL => descriptor(rowtime),\n"
-        + "SIZE => interval '2' hour))")
-        .fails("Param 'data' not found in function 'TUMBLE'; did you mean 
'DATA'\\?");
     sql("select rowtime, productid, orderid, 'window_start', 'window_end'\n"
         + "from table(\n"
         + "^tumble(\n"
@@ -11099,6 +11092,20 @@ private void checkCustomColumnResolving(String table) {
     sql("select * from table(\n"
         + "tumble(TABLE ^tabler_not_exist^, descriptor(rowtime), interval '2' 
hour))")
         .fails("Object 'TABLER_NOT_EXIST' not found");
+    // Test case for <a 
href="https://issues.apache.org/jira/browse/CALCITE-6936";>[CALCITE-6936]
+    // Table function parameter matching should always be case-insensitive</a>.
+    // We cannot use table "orders", since lookup fails with 
unquotedCasing.TO_LOWER,
+    // so we make up a new table o.
+    sql("with o as "
+        + "(select TIMESTAMP '2020-01-01 00:00:00' as rowtime, 2 as productid, 
3 as orderid)"
+        + "select rowtime, productid, orderid, 'window_start', 'window_end'\n"
+        + "from table(\n"
+        + "tumble(\n"
+        + "data => table o,\n"
+        + "timecol => descriptor(rowtime),\n"
+        + "size => interval '2' hour))")
+        .withUnquotedCasing(Casing.TO_LOWER)
+        .ok();
   }
 
   @Test void testHopTableFunction() {
@@ -11142,13 +11149,6 @@ private void checkCustomColumnResolving(String table) {
             + "<INTERVAL HOUR>, <INTERVAL HOUR>\\)'\\. Supported form\\(s\\): "
             + "HOP\\(TABLE table_name, DESCRIPTOR\\(timecol\\), "
             + "datetime interval, datetime interval\\[, datetime 
interval\\]\\)");
-    sql("select * from table(\n"
-        + "hop(\n"
-        + "^\"data\"^ => table orders,\n"
-        + "timecol => descriptor(rowtime),\n"
-        + "slide => interval '2' hour,\n"
-        + "size => interval '1' hour))")
-        .fails("Param 'data' not found in function 'HOP'; did you mean 
'DATA'\\?");
     sql("select * from table(\n"
         + "^hop(\n"
         + "data => table orders,\n"
@@ -11218,13 +11218,6 @@ private void checkCustomColumnResolving(String table) {
             + "0\\) ROWTIME, INTEGER PRODUCTID, INTEGER ORDERID\\)>, 
<COLUMN_LIST>, "
             + "<INTERVAL HOUR>\\)'. Supported form\\(s\\): SESSION\\(TABLE 
table_name, DESCRIPTOR\\("
             + "timecol\\), DESCRIPTOR\\(key\\) optional, datetime 
interval\\)");
-    sql("select * from table(\n"
-        + "session(\n"
-        + "^\"data\"^ => table orders,\n"
-        + "timecol => descriptor(rowtime),\n"
-        + "key => descriptor(productid),\n"
-        + "size => interval '1' hour))")
-        .fails("Param 'data' not found in function 'SESSION'; did you mean 
'DATA'\\?");
     sql("select * from table(\n"
         + "^session(table orders, descriptor(rowtime), descriptor(productid), 
'test')^)")
         .fails("Cannot apply 'SESSION' to arguments of type 
'SESSION\\(<RECORDTYPE\\(TIMESTAMP\\("

Reply via email to