From 4676c4ab84605e70fd4540d5321c53de4da9f5d8 Mon Sep 17 00:00:00 2001 From: osipovartem Date: Wed, 16 Sep 2026 13:21:28 +0300 Subject: [PATCH 1/2] Snowflake: parse nested COPY transformation paths --- src/dialect/snowflake.rs | 12 ++++++++---- tests/sqlparser_snowflake.rs | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs index 41a8f8708..28d8d2ce8 100644 --- a/src/dialect/snowflake.rs +++ b/src/dialect/snowflake.rs @@ -1605,10 +1605,14 @@ fn parse_select_item_for_data_load( } } - // A trailing `::` means this is a cast expression (e.g. - // `$1:"col"::NUMBER(38,0)`), not a stage-load-select-item. - if matches!(parser.peek_token_ref().token, Token::DoubleColon) { - return parser.expected("stage load select item", parser.peek_token()); + // More complex paths and casts must fall back to the standard expression + // parser so it can preserve the complete JsonAccess / Cast expression. + if matches!( + parser.peek_token_ref().token, + Token::Colon | Token::Period | Token::LBracket | Token::DoubleColon + ) { + let token = parser.next_token(); + return parser.expected("end of simple staged field", token); } // as diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index 37222341b..b3db01e2b 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -2596,6 +2596,11 @@ fn test_copy_into_with_cast_transformation() { "COPY INTO my_company.emp_basic (a, b) FROM ", r#"(SELECT t.$1:plain AS plain, $1:"B"::TEXT FROM @stg AS t)"#, ), + // https://docs.snowflake.com/en/user-guide/tutorials/script-data-load-transform-parquet + concat!( + "COPY INTO my_company.emp_basic (a, b) FROM ", + "(SELECT $1:continent::VARCHAR, $1:country:name::VARCHAR FROM @stg)", + ), ]; for sql in variants { snowflake().verified_stmt(sql); From a9f00fc5313dba5da07e2e5704ff7166d847108b Mon Sep 17 00:00:00 2001 From: osipovartem Date: Wed, 23 Sep 2026 00:28:02 +0300 Subject: [PATCH 2/2] test: cover nested COPY path forms --- tests/sqlparser_snowflake.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/sqlparser_snowflake.rs b/tests/sqlparser_snowflake.rs index b3db01e2b..151040c20 100644 --- a/tests/sqlparser_snowflake.rs +++ b/tests/sqlparser_snowflake.rs @@ -2601,6 +2601,18 @@ fn test_copy_into_with_cast_transformation() { "COPY INTO my_company.emp_basic (a, b) FROM ", "(SELECT $1:continent::VARCHAR, $1:country:name::VARCHAR FROM @stg)", ), + concat!( + "COPY INTO my_company.emp_basic (a) FROM ", + "(SELECT $1:country.name::VARCHAR FROM @stg)", + ), + concat!( + "COPY INTO my_company.emp_basic (a) FROM ", + "(SELECT $1['country']['name']::VARCHAR FROM @stg)", + ), + concat!( + "COPY INTO my_company.emp_basic (a) FROM ", + "(SELECT t.$1:country.name::VARCHAR AS country FROM @stg AS t)", + ), ]; for sql in variants { snowflake().verified_stmt(sql);