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 6fbf0581c8 [CALCITE-6709] Parser accepts a call to TRIM() with no 
arguments
6fbf0581c8 is described below

commit 6fbf0581c8f62da624ffcad0d05582aeba8f7b81
Author: Mihai Budiu <[email protected]>
AuthorDate: Wed Nov 27 15:48:42 2024 -0800

    [CALCITE-6709] Parser accepts a call to TRIM() with no arguments
    
    Signed-off-by: Mihai Budiu <[email protected]>
---
 core/src/main/codegen/templates/Parser.jj          | 70 ++++++++++------------
 .../apache/calcite/runtime/CalciteResource.java    |  3 -
 .../calcite/runtime/CalciteResource.properties     |  1 -
 site/_docs/reference.md                            |  2 +-
 .../apache/calcite/sql/parser/SqlParserTest.java   | 10 +++-
 5 files changed, 39 insertions(+), 47 deletions(-)

diff --git a/core/src/main/codegen/templates/Parser.jj 
b/core/src/main/codegen/templates/Parser.jj
index b25d998eb1..09e33643f9 100644
--- a/core/src/main/codegen/templates/Parser.jj
+++ b/core/src/main/codegen/templates/Parser.jj
@@ -6397,59 +6397,49 @@ SqlNode BuiltinFunctionCall() :
         <TRIM> {
             SqlLiteral flag = null;
             SqlNode trimChars = null;
+            SqlParserPos fromPos = SqlParserPos.ZERO;
             s = span();
         }
         <LPAREN>
-        [
-            LOOKAHEAD(2)
-            [
-                <BOTH> {
-                    s.add(this);
-                    flag = SqlTrimFunction.Flag.BOTH.symbol(getPos());
-                }
-            |
-                <TRAILING> {
-                    s.add(this);
-                    flag = SqlTrimFunction.Flag.TRAILING.symbol(getPos());
-                }
-            |
-                <LEADING> {
-                    s.add(this);
-                    flag = SqlTrimFunction.Flag.LEADING.symbol(getPos());
-                }
-            ]
-            [ trimChars = Expression(ExprContext.ACCEPT_SUB_QUERY) ]
+        (
             (
-                <FROM> {
-                    if (null == flag && null == trimChars) {
-                        throw SqlUtil.newContextException(getPos(),
-                            RESOURCE.illegalFromEmpty());
+                (
+                    <BOTH> {
+                        s.add(this);
+                        flag = SqlTrimFunction.Flag.BOTH.symbol(getPos());
                     }
-                }
-            |
-                <RPAREN> {
-                    // This is to handle the case of TRIM(x)
-                    // (FRG-191).
-                    if (flag == null) {
-                        flag = 
SqlTrimFunction.Flag.BOTH.symbol(SqlParserPos.ZERO);
+                |
+                    <TRAILING> {
+                        s.add(this);
+                        flag = SqlTrimFunction.Flag.TRAILING.symbol(getPos());
                     }
-                    args.add(flag);
-                    args.add(null); // no trim chars
-                    args.add(trimChars); // reinterpret trimChars as source
-                    return SqlStdOperatorTable.TRIM.createCall(s.end(this),
-                        args);
-                }
+                |
+                    <LEADING> {
+                        s.add(this);
+                        flag = SqlTrimFunction.Flag.LEADING.symbol(getPos());
+                    }
+                )
+                [ trimChars = Expression(ExprContext.ACCEPT_SUB_QUERY) ]
+                <FROM> { fromPos = getPos(); }
+                e = Expression(ExprContext.ACCEPT_SUB_QUERY)
             )
-        ]
-        e = Expression(ExprContext.ACCEPT_SUB_QUERY) {
+            |
+            (
+                e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+                [
+                    <FROM> { trimChars = e; fromPos = getPos(); }
+                    e = Expression(ExprContext.ACCEPT_SUB_QUERY)
+                ]
+            )
+        )
+        <RPAREN> {
             if (flag == null) {
                 flag = SqlTrimFunction.Flag.BOTH.symbol(SqlParserPos.ZERO);
             }
             args.add(flag);
+            // trimChars can be null
             args.add(trimChars);
             args.add(e);
-        }
-        <RPAREN> {
             return SqlStdOperatorTable.TRIM.createCall(s.end(this), args);
         }
     |
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 e35be6fee9..6efa71d734 100644
--- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
+++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java
@@ -103,9 +103,6 @@ public interface CalciteResource {
   @BaseMessage("Illegal array expression ''{0}''")
   ExInst<CalciteException> illegalArrayExpression(String a0);
 
-  @BaseMessage("''FROM'' without operands preceding it is illegal")
-  ExInst<CalciteException> illegalFromEmpty();
-
   @BaseMessage("ROW expression encountered in illegal context")
   ExInst<CalciteException> illegalRowExpression();
 
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 214acea201..f46d05a116 100644
--- 
a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
+++ 
b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties
@@ -43,7 +43,6 @@ ExpectedQueryOrJoinExpression=Expected query or join
 IllegalBinaryString=Illegal binary string {0}
 IllegalArrayExpression=Illegal array expression ''{0}''
 ArrayIndexOutOfBounds=Array index {0,number,#} is out of bounds
-IllegalFromEmpty=''FROM'' without operands preceding it is illegal
 IllegalRowExpression=ROW expression encountered in illegal context
 IllegalColon=Unexpected symbol '':''. Was expecting ''VALUE''
 IllegalComma=Unexpected symbol '',''. Was expecting ''VALUE''
diff --git a/site/_docs/reference.md b/site/_docs/reference.md
index 915353d0ce..d2aa0b8799 100644
--- a/site/_docs/reference.md
+++ b/site/_docs/reference.md
@@ -1403,7 +1403,7 @@ comp:
 | LOWER(string)              | Returns a character string converted to lower 
case
 | POSITION(substring IN string) | Returns the position of the first occurrence 
of *substring* in *string*
 | POSITION(substring IN string FROM integer) | Returns the position of the 
first occurrence of *substring* in *string* starting at a given point (not 
standard SQL)
-| TRIM( { BOTH &#124; LEADING &#124; TRAILING } string1 FROM string2) | 
Removes the longest string containing only the characters in *string1* from the 
start/end/both ends of *string2*
+| TRIM( { BOTH &#124; LEADING &#124; TRAILING } [[ string1 ] FROM ] string2) | 
Removes the longest string containing only the characters in *string1* from the 
start/end/both ends of *string2*.  If *string1* is missing a single space is 
used.
 | OVERLAY(string1 PLACING string2 FROM integer [ FOR integer2 ]) | Replaces a 
substring of *string1* with *string2*, starting at the specified position 
*integer* in *string1* and optionally for a specified length *integer2*
 | SUBSTRING(string FROM integer)  | Returns a substring of a character string 
starting at a given point. If starting point is less than 1, the returned 
expression will begin at the first character that is specified in expression
 | SUBSTRING(string FROM integer FOR integer) | Returns a substring of a 
character string starting at a given point with a given length. If start point 
is less than 1 in this case, the number of characters that are returned is the 
largest value of either the start + length - 1 or 0
diff --git 
a/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java 
b/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java
index 806179469a..c6f06280aa 100644
--- a/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java
+++ b/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java
@@ -5701,8 +5701,14 @@ public class SqlParserTest {
         .ok("TRIM(BOTH ' ' FROM ((COALESCE(CAST(NULL AS VARCHAR(2))) || "
             + "' ') || COALESCE('junk ', '')))");
 
-    sql("trim(^from^ 'beard')")
-        .fails("(?s).*'FROM' without operands preceding it is illegal.*");
+    expr("trim(^from^ 'beard')")
+        .fails("(?s).*Encountered \"from\" at line 1, column 6\\..*");
+    expr("trim('beard ')")
+        .ok("TRIM(BOTH ' ' FROM 'beard ')");
+    // Test case for [CALCITE-6709] 
https://issues.apache.org/jira/browse/CALCITE-6709
+    // Parser accepts a call to TRIM() with no arguments
+    expr("trim(^)^")
+        .fails("(?s).*Encountered \"\\)\" at line 1, column 6\\..*");
   }
 
   @Test void testConvertAndTranslate() {

Reply via email to