You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/10/15 17:58:42 UTC
(datafusion-sqlparser-rs) 01/01: Assert exact errors in negative tests (2/4): common and parser unit tests (#2629)
This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-2629-a6f518bf7ef58ec6e7a00da286f9185b0de01b2d
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit 6434b5a224a77ee9e1830b2a840eca0bf6bdc9fb
Author: Luca Cappelletti <ca...@gmail.com>
AuthorDate: Thu Oct 15 17:58:19 2026 +0000
Assert exact errors in negative tests (2/4): common and parser unit tests (#2629)
---
src/parser/mod.rs | 36 +++++-
tests/sqlparser_common.rs | 312 +++++++++++++++++++++++++---------------------
2 files changed, 202 insertions(+), 146 deletions(-)
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 37e9997c..24947764 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -22344,28 +22344,54 @@ mod tests {
fn test_replace_into_placeholders() {
let sql = "REPLACE INTO t (a) VALUES (&a)";
- assert!(Parser::parse_sql(&GenericDialect {}, sql).is_err());
+ assert_eq!(
+ ParserError::ParserError(
+ "Expected: an expression, found: & at Line: 1, Column: 28".to_string()
+ ),
+ Parser::parse_sql(&GenericDialect {}, sql).unwrap_err()
+ );
}
#[test]
fn test_replace_into_set_placeholder() {
let sql = "REPLACE INTO t SET ?";
- assert!(Parser::parse_sql(&GenericDialect {}, sql).is_err());
+ assert_eq!(
+ ParserError::ParserError(
+ "Expected: SELECT, VALUES, or a subquery in the query body, found: SET at Line: 1, Column: 16"
+ .to_string()
+ ),
+ Parser::parse_sql(&GenericDialect {}, sql).unwrap_err()
+ );
}
#[test]
fn test_replace_incomplete() {
let sql = r#"REPLACE"#;
- assert!(Parser::parse_sql(&MySqlDialect {}, sql).is_err());
+ assert_eq!(
+ ParserError::ParserError("Expected: identifier, found: EOF".to_string()),
+ Parser::parse_sql(&MySqlDialect {}, sql).unwrap_err()
+ );
}
#[test]
fn test_placeholder_invalid_whitespace() {
- for w in [" ", "/*invalid*/"] {
+ for (w, expected) in [
+ (
+ " ",
+ "Expected: placeholder, found: at Line: 3, Column: 4",
+ ),
+ (
+ "/*invalid*/",
+ "Expected: placeholder, found: /*invalid*/ at Line: 3, Column: 4",
+ ),
+ ] {
let sql = format!("\nSELECT\n :{w}fooBar");
- assert!(Parser::parse_sql(&GenericDialect, &sql).is_err());
+ assert_eq!(
+ ParserError::ParserError(expected.to_string()),
+ Parser::parse_sql(&GenericDialect, &sql).unwrap_err()
+ );
}
}
}
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index f153a59d..bfe5bf67 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -723,13 +723,21 @@ fn parse_invalid_table_name() {
let ast = all_dialects().run_parser_method("db.public..customer", |parser| {
parser.parse_object_name(false)
});
- assert!(ast.is_err());
+ assert_eq!(
+ ParserError::ParserError(
+ "Expected: identifier, found: . at Line: 1, Column: 11".to_string()
+ ),
+ ast.unwrap_err()
+ );
}
#[test]
fn parse_no_table_name() {
let ast = all_dialects().run_parser_method("", |parser| parser.parse_object_name(false));
- assert!(ast.is_err());
+ assert_eq!(
+ ParserError::ParserError("Expected: identifier, found: EOF".to_string()),
+ ast.unwrap_err()
+ );
}
#[test]
@@ -12410,9 +12418,12 @@ fn parse_non_latin_identifiers() {
Box::new(DuckDbDialect {}),
Box::new(MsSqlDialect {}),
]);
- assert!(supported_dialects
- .parse_sql_statements("SELECT 💝 FROM table1")
- .is_err());
+ assert_eq!(
+ ParserError::ParserError("Expected: an expression, found: 💝".to_string()),
+ supported_dialects
+ .parse_sql_statements("SELECT 💝 FROM table1")
+ .unwrap_err()
+ );
}
#[test]
@@ -17638,128 +17649,134 @@ fn parse_pipeline_operator_negative_tests() {
);
// Test that CALL without function name fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> CALL")
- .is_err());
-
- // Test that CALL without parentheses fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> CALL my_function")
- .is_err());
-
- // Test that CALL with invalid function syntax fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> CALL 123 invalid")
- .is_err());
-
- // Test that CALL with malformed arguments fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> CALL my_function(,)")
- .is_err());
-
- // Test that CALL with invalid alias syntax fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> CALL my_function() AS")
- .is_err());
-
- // Test that PIVOT without parentheses fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> PIVOT SUM(amount) FOR month IN ('Jan')")
- .is_err());
-
- // Test that PIVOT without FOR keyword fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> PIVOT(SUM(amount) month IN ('Jan'))")
- .is_err());
-
- // Test that PIVOT without IN keyword fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> PIVOT(SUM(amount) FOR month ('Jan'))")
- .is_err());
-
- // Test that PIVOT with empty IN list fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> PIVOT(SUM(amount) FOR month IN ())")
- .is_err());
-
- // Test that PIVOT with invalid alias syntax fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> PIVOT(SUM(amount) FOR month IN ('Jan')) AS")
- .is_err());
-
- // Test UNPIVOT negative cases
-
- // Test that UNPIVOT without parentheses fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> UNPIVOT value FOR name IN col1, col2")
- .is_err());
-
- // Test that UNPIVOT without FOR keyword fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> UNPIVOT(value name IN (col1, col2))")
- .is_err());
-
- // Test that UNPIVOT without IN keyword fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> UNPIVOT(value FOR name (col1, col2))")
- .is_err());
-
- // Test that UNPIVOT with missing value column fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> UNPIVOT(FOR name IN (col1, col2))")
- .is_err());
-
- // Test that UNPIVOT with missing name column fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> UNPIVOT(value FOR IN (col1, col2))")
- .is_err());
-
- // Test that UNPIVOT with empty IN list fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> UNPIVOT(value FOR name IN ())")
- .is_err());
-
- // Test that UNPIVOT with invalid alias syntax fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> UNPIVOT(value FOR name IN (col1, col2)) AS")
- .is_err());
-
- // Test that UNPIVOT with missing closing parenthesis fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> UNPIVOT(value FOR name IN (col1, col2)")
- .is_err());
-
- // Test that JOIN without table name fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> JOIN ON users.id = orders.user_id")
- .is_err());
-
- // Test that CROSS JOIN with ON condition fails
- assert!(dialects
- .parse_sql_statements(
- "SELECT * FROM users |> CROSS JOIN orders ON users.id = orders.user_id"
- )
- .is_err());
-
- // Test that CROSS JOIN with USING condition fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> CROSS JOIN orders USING (user_id)")
- .is_err());
-
- // Test that JOIN with empty USING list fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> JOIN orders USING ()")
- .is_err());
-
- // Test that JOIN with malformed ON condition fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> JOIN orders ON")
- .is_err());
-
- // Test that JOIN with invalid USING syntax fails
- assert!(dialects
- .parse_sql_statements("SELECT * FROM users |> JOIN orders USING user_id")
- .is_err());
+ for (sql, err_msg) in [
+ (
+ "SELECT * FROM users |> CALL",
+ "Expected: identifier, found: EOF",
+ ),
+ // Test that CALL without parentheses fails
+ (
+ "SELECT * FROM users |> CALL my_function",
+ "Expected: (, found: EOF",
+ ),
+ // Test that CALL with invalid function syntax fails
+ (
+ "SELECT * FROM users |> CALL 123 invalid",
+ "Expected: identifier, found: 123",
+ ),
+ // Test that CALL with malformed arguments fails
+ (
+ "SELECT * FROM users |> CALL my_function(,)",
+ "Expected: an expression, found: ,",
+ ),
+ // Test that CALL with invalid alias syntax fails
+ (
+ "SELECT * FROM users |> CALL my_function() AS",
+ "Expected: identifier, found: EOF",
+ ),
+ // Test that PIVOT without parentheses fails
+ (
+ "SELECT * FROM users |> PIVOT SUM(amount) FOR month IN ('Jan')",
+ "Expected: (, found: SUM",
+ ),
+ // Test that PIVOT without FOR keyword fails
+ (
+ "SELECT * FROM users |> PIVOT(SUM(amount) month IN ('Jan'))",
+ "Expected: FOR, found: IN",
+ ),
+ // Test that PIVOT without IN keyword fails
+ (
+ "SELECT * FROM users |> PIVOT(SUM(amount) FOR month ('Jan'))",
+ "Expected: IN, found: (",
+ ),
+ // Test that PIVOT with empty IN list fails
+ (
+ "SELECT * FROM users |> PIVOT(SUM(amount) FOR month IN ())",
+ "Expected: an expression, found: )",
+ ),
+ // Test that PIVOT with invalid alias syntax fails
+ (
+ "SELECT * FROM users |> PIVOT(SUM(amount) FOR month IN ('Jan')) AS",
+ "Expected: identifier, found: EOF",
+ ),
+ // Test UNPIVOT negative cases
+ // Test that UNPIVOT without parentheses fails
+ (
+ "SELECT * FROM users |> UNPIVOT value FOR name IN col1, col2",
+ "Expected: (, found: value",
+ ),
+ // Test that UNPIVOT without FOR keyword fails
+ (
+ "SELECT * FROM users |> UNPIVOT(value name IN (col1, col2))",
+ "Expected: FOR, found: name",
+ ),
+ // Test that UNPIVOT without IN keyword fails
+ (
+ "SELECT * FROM users |> UNPIVOT(value FOR name (col1, col2))",
+ "Expected: IN, found: (",
+ ),
+ // Test that UNPIVOT with missing value column fails
+ (
+ "SELECT * FROM users |> UNPIVOT(FOR name IN (col1, col2))",
+ "Expected: FOR, found: name",
+ ),
+ // Test that UNPIVOT with missing name column fails
+ (
+ "SELECT * FROM users |> UNPIVOT(value FOR IN (col1, col2))",
+ "Expected: IN, found: (",
+ ),
+ // Test that UNPIVOT with empty IN list fails
+ (
+ "SELECT * FROM users |> UNPIVOT(value FOR name IN ())",
+ "Expected: identifier, found: )",
+ ),
+ // Test that UNPIVOT with invalid alias syntax fails
+ (
+ "SELECT * FROM users |> UNPIVOT(value FOR name IN (col1, col2)) AS",
+ "Expected: identifier, found: EOF",
+ ),
+ // Test that UNPIVOT with missing closing parenthesis fails
+ (
+ "SELECT * FROM users |> UNPIVOT(value FOR name IN (col1, col2)",
+ "Expected: ), found: EOF",
+ ),
+ // Test that JOIN without table name fails
+ (
+ "SELECT * FROM users |> JOIN ON users.id = orders.user_id",
+ "Expected: end of statement, found: .",
+ ),
+ // Test that CROSS JOIN with ON condition fails
+ (
+ "SELECT * FROM users |> CROSS JOIN orders ON users.id = orders.user_id",
+ "Expected: end of statement, found: ON",
+ ),
+ // Test that CROSS JOIN with USING condition fails
+ (
+ "SELECT * FROM users |> CROSS JOIN orders USING (user_id)",
+ "Expected: end of statement, found: USING",
+ ),
+ // Test that JOIN with empty USING list fails
+ (
+ "SELECT * FROM users |> JOIN orders USING ()",
+ "Expected: identifier, found: )",
+ ),
+ // Test that JOIN with malformed ON condition fails
+ (
+ "SELECT * FROM users |> JOIN orders ON",
+ "Expected: an expression, found: EOF",
+ ),
+ // Test that JOIN with invalid USING syntax fails
+ (
+ "SELECT * FROM users |> JOIN orders USING user_id",
+ "Expected: a list of columns in parentheses, found: user_id",
+ ),
+ ] {
+ let res = dialects.parse_sql_statements(sql);
+ assert_eq!(
+ ParserError::ParserError(err_msg.to_string()),
+ res.unwrap_err()
+ );
+ }
}
#[test]
@@ -19828,10 +19845,11 @@ fn parse_select_item_multi_column_alias() {
all_dialects_where(|d| d.supports_select_item_multi_column_alias())
.verified_stmt("SELECT stack(2, 'a', 'b', 'c', 'd') AS (col1, col2) FROM t");
- assert!(
+ assert_eq!(
+ ParserError::ParserError("Expected: an identifier after AS, found: (".to_string()),
all_dialects_where(|d| !d.supports_select_item_multi_column_alias())
.parse_sql_statements("SELECT stack(2, 'a', 'b') AS (col1, col2)")
- .is_err()
+ .unwrap_err()
);
}
@@ -19852,9 +19870,12 @@ fn parse_aliased_function_args() {
dialects.verified_only_select("SELECT foo(lower(a) AS x, b AS y)");
dialects.verified_only_select(r#"SELECT foo(a AS "x y")"#);
dialects.verified_only_select("SELECT foo(bar(a AS x) AS y)");
- assert!(all_dialects_except(|d| d.supports_aliased_function_args())
- .parse_sql_statements("SELECT foo(a AS x)")
- .is_err());
+ assert_eq!(
+ ParserError::ParserError("Expected: ), found: AS".to_string()),
+ all_dialects_except(|d| d.supports_aliased_function_args())
+ .parse_sql_statements("SELECT foo(a AS x)")
+ .unwrap_err()
+ );
}
#[test]
@@ -19889,9 +19910,12 @@ fn parse_xmlparse() {
}
// XMLPARSE needs both a mode word and a value.
- assert!(dialects
- .parse_sql_statements("SELECT xmlparse('<a/>')")
- .is_err());
+ assert_eq!(
+ ParserError::ParserError("Expected: an expression, found: )".to_string()),
+ dialects
+ .parse_sql_statements("SELECT xmlparse('<a/>')")
+ .unwrap_err()
+ );
// Going through the ordinary function-call path, XMLPARSE accepts the same
// trailing clauses as any other function.
@@ -19902,9 +19926,12 @@ fn parse_xmlparse() {
// and the special `CONTENT <expr>` syntax is rejected.
let others = all_dialects_except(|d| d.supports_xml_expressions());
others.verified_only_select("SELECT xmlparse(1)");
- assert!(others
- .parse_sql_statements("SELECT xmlparse(content '<a/>')")
- .is_err());
+ assert_eq!(
+ ParserError::ParserError("Expected: ), found: '<a/>'".to_string()),
+ others
+ .parse_sql_statements("SELECT xmlparse(content '<a/>')")
+ .unwrap_err()
+ );
}
/// Regression test for the 2^N parse-time blowup in `parse_compound_expr` on
@@ -20235,9 +20262,12 @@ fn parse_alter_table_column_position() {
),
_ => unreachable!(),
}
- assert!(dialects
- .parse_sql_statements("ALTER TABLE tab ADD COLUMN c INT AFTER")
- .is_err());
+ assert_eq!(
+ ParserError::ParserError("Expected: identifier, found: EOF".to_string()),
+ dialects
+ .parse_sql_statements("ALTER TABLE tab ADD COLUMN c INT AFTER")
+ .unwrap_err()
+ );
let dialects = all_dialects_where(|d| !d.supports_alter_column_position());
for sql in [
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org