This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
The following commit(s) were added to refs/heads/main by this push:
new 5b7bc1a5 Support two-argument `TRIM(string, characters)` in PostgreSQL
(#2240)
5b7bc1a5 is described below
commit 5b7bc1a52723cc91d4d0b90a44455d716db549d5
Author: Luca Cappelletti <[email protected]>
AuthorDate: Fri Feb 27 13:38:54 2026 +0100
Support two-argument `TRIM(string, characters)` in PostgreSQL (#2240)
---
src/ast/mod.rs | 2 +-
src/dialect/bigquery.rs | 4 ++++
src/dialect/clickhouse.rs | 4 ++++
src/dialect/duckdb.rs | 4 ++++
src/dialect/generic.rs | 4 ++++
src/dialect/mod.rs | 6 ++++++
src/dialect/postgresql.rs | 4 ++++
src/dialect/snowflake.rs | 4 ++++
src/dialect/sqlite.rs | 4 ++++
src/parser/mod.rs | 5 ++---
tests/sqlparser_common.rs | 53 +++++++++++++++++++++++++++++++++--------------
11 files changed, 75 insertions(+), 19 deletions(-)
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index 1e430171..97cc6193 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -1131,7 +1131,7 @@ pub enum Expr {
/// ```sql
/// TRIM([BOTH | LEADING | TRAILING] [<expr> FROM] <expr>)
/// TRIM(<expr>)
- /// TRIM(<expr>, [, characters]) -- only Snowflake or Bigquery
+ /// TRIM(<expr>, [, characters]) -- PostgreSQL, DuckDB, Snowflake,
BigQuery, Generic
/// ```
Trim {
/// The expression to trim from.
diff --git a/src/dialect/bigquery.rs b/src/dialect/bigquery.rs
index 6cef4606..8fca5151 100644
--- a/src/dialect/bigquery.rs
+++ b/src/dialect/bigquery.rs
@@ -162,4 +162,8 @@ impl Dialect for BigQueryDialect {
fn supports_select_wildcard_replace(&self) -> bool {
true
}
+
+ fn supports_comma_separated_trim(&self) -> bool {
+ true
+ }
}
diff --git a/src/dialect/clickhouse.rs b/src/dialect/clickhouse.rs
index ea4d7a97..87c762f0 100644
--- a/src/dialect/clickhouse.rs
+++ b/src/dialect/clickhouse.rs
@@ -141,4 +141,8 @@ impl Dialect for ClickHouseDialect {
fn supports_select_wildcard_replace(&self) -> bool {
true
}
+
+ fn supports_comma_separated_trim(&self) -> bool {
+ true
+ }
}
diff --git a/src/dialect/duckdb.rs b/src/dialect/duckdb.rs
index 32967c4c..e70efd69 100644
--- a/src/dialect/duckdb.rs
+++ b/src/dialect/duckdb.rs
@@ -129,4 +129,8 @@ impl Dialect for DuckDbDialect {
fn supports_select_wildcard_replace(&self) -> bool {
true
}
+
+ fn supports_comma_separated_trim(&self) -> bool {
+ true
+ }
}
diff --git a/src/dialect/generic.rs b/src/dialect/generic.rs
index a7a3c271..1d5461fe 100644
--- a/src/dialect/generic.rs
+++ b/src/dialect/generic.rs
@@ -284,4 +284,8 @@ impl Dialect for GenericDialect {
fn supports_key_column_option(&self) -> bool {
true
}
+
+ fn supports_comma_separated_trim(&self) -> bool {
+ true
+ }
}
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index 796b25f0..8703e402 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -1651,6 +1651,12 @@ pub trait Dialect: Debug + Any {
fn supports_select_format(&self) -> bool {
false
}
+
+ /// Returns true if the dialect supports the two-argument comma-separated
+ /// form of the `TRIM` function: `TRIM(expr, characters)`.
+ fn supports_comma_separated_trim(&self) -> bool {
+ false
+ }
}
/// Operators for which precedence must be defined.
diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs
index 89b677c4..b99a8b5c 100644
--- a/src/dialect/postgresql.rs
+++ b/src/dialect/postgresql.rs
@@ -306,4 +306,8 @@ impl Dialect for PostgreSqlDialect {
fn supports_create_table_like_parenthesized(&self) -> bool {
true
}
+
+ fn supports_comma_separated_trim(&self) -> bool {
+ true
+ }
}
diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs
index 984e384f..a9d71fc4 100644
--- a/src/dialect/snowflake.rs
+++ b/src/dialect/snowflake.rs
@@ -667,6 +667,10 @@ impl Dialect for SnowflakeDialect {
fn supports_lambda_functions(&self) -> bool {
true
}
+
+ fn supports_comma_separated_trim(&self) -> bool {
+ true
+ }
}
// Peeks ahead to identify tokens that are expected after
diff --git a/src/dialect/sqlite.rs b/src/dialect/sqlite.rs
index b44a1c5b..39ee622d 100644
--- a/src/dialect/sqlite.rs
+++ b/src/dialect/sqlite.rs
@@ -120,4 +120,8 @@ impl Dialect for SQLiteDialect {
fn supports_notnull_operator(&self) -> bool {
true
}
+
+ fn supports_comma_separated_trim(&self) -> bool {
+ true
+ }
}
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index a00eab34..8d8b55a3 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -2940,7 +2940,7 @@ impl<'a> Parser<'a> {
/// ```sql
/// TRIM ([WHERE] ['text' FROM] 'text')
/// TRIM ('text')
- /// TRIM(<expr>, [, characters]) -- only Snowflake or BigQuery
+ /// TRIM(<expr>, [, characters]) -- PostgreSQL, DuckDB, Snowflake,
BigQuery, Generic
/// ```
pub fn parse_trim_expr(&mut self) -> Result<Expr, ParserError> {
self.expect_token(&Token::LParen)?;
@@ -2961,8 +2961,7 @@ impl<'a> Parser<'a> {
trim_what: Some(trim_what),
trim_characters: None,
})
- } else if self.consume_token(&Token::Comma)
- && dialect_of!(self is DuckDbDialect | SnowflakeDialect |
BigQueryDialect | GenericDialect)
+ } else if self.dialect.supports_comma_separated_trim() &&
self.consume_token(&Token::Comma)
{
let characters = self.parse_comma_separated(Parser::parse_expr)?;
self.expect_token(&Token::RParen)?;
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 982bf108..8de460d7 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -8099,23 +8099,46 @@ fn parse_trim() {
parse_sql_statements("SELECT TRIM(FOO 'xyz' FROM
'xyzfooxyz')").unwrap_err()
);
- //keep Snowflake/BigQuery TRIM syntax failing
- let all_expected_snowflake = TestedDialects::new(vec![
- //Box::new(GenericDialect {}),
- Box::new(PostgreSqlDialect {}),
- Box::new(MsSqlDialect {}),
- Box::new(AnsiDialect {}),
- //Box::new(SnowflakeDialect {}),
- Box::new(HiveDialect {}),
- Box::new(RedshiftSqlDialect {}),
- Box::new(MySqlDialect {}),
- //Box::new(BigQueryDialect {}),
- Box::new(SQLiteDialect {}),
- ]);
+ // dialects that support comma-separated TRIM syntax
+ let dialects = all_dialects_where(|d| d.supports_comma_separated_trim());
+ let sql = "SELECT TRIM(' xyz ', ' ')";
+ let select = dialects.verified_only_select(sql);
assert_eq!(
- ParserError::ParserError("Expected: ), found: 'a'".to_owned()),
- all_expected_snowflake
+ &Expr::Trim {
+ expr: Box::new(Expr::Value(
+ Value::SingleQuotedString(" xyz
".to_owned()).with_empty_span()
+ )),
+ trim_where: None,
+ trim_what: None,
+ trim_characters: Some(vec![Expr::Value(
+ Value::SingleQuotedString(" ".to_owned()).with_empty_span()
+ )]),
+ },
+ expr_from_projection(only(&select.projection))
+ );
+
+ let sql = "SELECT TRIM('xyz', 'a')";
+ let select = dialects.verified_only_select(sql);
+ assert_eq!(
+ &Expr::Trim {
+ expr: Box::new(Expr::Value(
+ Value::SingleQuotedString("xyz".to_owned()).with_empty_span()
+ )),
+ trim_where: None,
+ trim_what: None,
+ trim_characters: Some(vec![Expr::Value(
+ Value::SingleQuotedString("a".to_owned()).with_empty_span()
+ )]),
+ },
+ expr_from_projection(only(&select.projection))
+ );
+
+ // dialects without comma-style TRIM syntax should fail
+ let unsupported_dialects = all_dialects_where(|d|
!d.supports_comma_separated_trim());
+ assert_eq!(
+ ParserError::ParserError("Expected: ), found: ,".to_owned()),
+ unsupported_dialects
.parse_sql_statements("SELECT TRIM('xyz', 'a')")
.unwrap_err()
);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]