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 | LEADING | TRAILING } string1 FROM string2) |
Removes the longest string containing only the characters in *string1* from the
start/end/both ends of *string2*
+| TRIM( { BOTH | LEADING | 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() {