From cf9ae1697876ec127f4cfac740aba05e36f6c810 Mon Sep 17 00:00:00 2001 From: Andriy Romanov Date: Wed, 4 Mar 2026 14:32:29 -0800 Subject: [PATCH 1/3] Fixed stage name parsing for snowflake --- src/dialect/snowflake.rs | 2 ++ tests/sqlparser_snowflake.rs | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs index f756c4159..c95f0ef6e 100644 --- a/src/dialect/snowflake.rs +++ b/src/dialect/snowflake.rs @@ -1247,6 +1247,8 @@ pub fn parse_stage_name_identifier(parser: &mut Parser) -> Result ident.push('/'), Token::Plus => ident.push('+'), Token::Minus => ident.push('-'), + Token::Eq => ident.push('='), + Token::Colon => ident.push(':'), Token::Number(n, _) => ident.push_str(n), Token::Word(w) => ident.push_str(&w.to_string()), _ => return parser.expected_ref("stage name identifier", parser.peek_token_ref()), diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index c51cf3bdf..cc265dfe9 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -2640,6 +2640,29 @@ fn test_snowflake_copy_into_stage_name_ends_with_parens() { } } +#[test] +fn test_snowflake_stage_name_with_special_chars() { + // Stage path with '=' (Hive-style partitioning) + let sql = "SELECT * FROM @stage/day=18/23.parquet"; + let stmt = snowflake().parse_sql_statements(sql).unwrap(); + assert_eq!(1, stmt.len()); + + // Stage path with ':' (time-based partitioning) + let sql = "SELECT * FROM @stage/0:18:23/23.parquet"; + let stmt = snowflake().parse_sql_statements(sql).unwrap(); + assert_eq!(1, stmt.len()); + + // COPY INTO with '=' in stage path + snowflake().parse_sql_statements( + "COPY INTO my_table FROM @stage/day=18/file.parquet", + ).unwrap(); + + // COPY INTO with ':' in stage path + snowflake().parse_sql_statements( + "COPY INTO my_table FROM @stage/0:18:23/file.parquet", + ).unwrap(); +} + #[test] fn test_snowflake_trim() { let real_sql = r#"SELECT customer_id, TRIM(sub_items.value:item_price_id, '"', "a") AS item_price_id FROM models_staging.subscriptions"#; From 7ff3c636529f2c7d8a81b03090a5b1849a4ad5a1 Mon Sep 17 00:00:00 2001 From: Andriy Romanov Date: Wed, 4 Mar 2026 14:34:15 -0800 Subject: [PATCH 2/3] Fmt fix --- tests/sqlparser_snowflake.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index cc265dfe9..ab6fb441f 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -2653,14 +2653,14 @@ fn test_snowflake_stage_name_with_special_chars() { assert_eq!(1, stmt.len()); // COPY INTO with '=' in stage path - snowflake().parse_sql_statements( - "COPY INTO my_table FROM @stage/day=18/file.parquet", - ).unwrap(); + snowflake() + .parse_sql_statements("COPY INTO my_table FROM @stage/day=18/file.parquet") + .unwrap(); // COPY INTO with ':' in stage path - snowflake().parse_sql_statements( - "COPY INTO my_table FROM @stage/0:18:23/file.parquet", - ).unwrap(); + snowflake() + .parse_sql_statements("COPY INTO my_table FROM @stage/0:18:23/file.parquet") + .unwrap(); } #[test] From 3afac0afea272941c0f8c9452fb02d55fb7b113b Mon Sep 17 00:00:00 2001 From: Andriy Romanov Date: Mon, 9 Mar 2026 16:52:54 -0700 Subject: [PATCH 3/3] Update based on comment --- tests/sqlparser_snowflake.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index ab6fb441f..6abb3ef54 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -2643,24 +2643,16 @@ fn test_snowflake_copy_into_stage_name_ends_with_parens() { #[test] fn test_snowflake_stage_name_with_special_chars() { // Stage path with '=' (Hive-style partitioning) - let sql = "SELECT * FROM @stage/day=18/23.parquet"; - let stmt = snowflake().parse_sql_statements(sql).unwrap(); - assert_eq!(1, stmt.len()); + snowflake().verified_stmt("SELECT * FROM @stage/day=18/23.parquet"); // Stage path with ':' (time-based partitioning) - let sql = "SELECT * FROM @stage/0:18:23/23.parquet"; - let stmt = snowflake().parse_sql_statements(sql).unwrap(); - assert_eq!(1, stmt.len()); + snowflake().verified_stmt("SELECT * FROM @stage/0:18:23/23.parquet"); // COPY INTO with '=' in stage path - snowflake() - .parse_sql_statements("COPY INTO my_table FROM @stage/day=18/file.parquet") - .unwrap(); + snowflake().verified_stmt("COPY INTO my_table FROM @stage/day=18/file.parquet"); // COPY INTO with ':' in stage path - snowflake() - .parse_sql_statements("COPY INTO my_table FROM @stage/0:18:23/file.parquet") - .unwrap(); + snowflake().verified_stmt("COPY INTO my_table FROM @stage/0:18:23/file.parquet"); } #[test]