From d3dbe4f7502c128a297e11f930643c1ed626a8b5 Mon Sep 17 00:00:00 2001 From: osipovartem Date: Wed, 16 Sep 2026 13:21:28 +0300 Subject: [PATCH] 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 0bbd859eca..988ca345af 100644 --- a/src/dialect/snowflake.rs +++ b/src/dialect/snowflake.rs @@ -1602,10 +1602,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 059560dcc9..c154fe023d 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);