@@ -2447,6 +2447,49 @@ fn test_copy_into_with_transformations() {
24472447 snowflake ( ) . parse_sql_statements ( sql1) . unwrap ( ) ;
24482448}
24492449
2450+ #[ test]
2451+ fn test_copy_into_with_cast_transformation ( ) {
2452+ // Snowflake `COPY INTO` transformation lists support casts like
2453+ // `$1:"col"::TYPE` and `$1::TYPE`. These are distinct from the bare
2454+ // `$<n>[.<col>][:<elem>]` stage-load-select-item shape, so the parser
2455+ // must fall through to the generic select-item parser to handle the
2456+ // `::` cast operator.
2457+ //
2458+ // Regression: the Snowflake-specific parser used to successfully
2459+ // consume `$1:"col"` as a stage-load-select-item, leaving `::TYPE`
2460+ // behind and causing "Expected: FROM, found: ::" once the COPY INTO
2461+ // body tried to expect `FROM`.
2462+ let variants = [
2463+ concat ! (
2464+ "COPY INTO my_company.emp_basic (a) FROM " ,
2465+ r#"(SELECT $1:"A"::NUMBER(38, 0) FROM @stg)"# ,
2466+ ) ,
2467+ concat ! (
2468+ "COPY INTO my_company.emp_basic (a) FROM " ,
2469+ "(SELECT $1::NUMBER(38, 0) FROM @stg)" ,
2470+ ) ,
2471+ concat ! (
2472+ "COPY INTO my_company.emp_basic (a) FROM " ,
2473+ "(SELECT $1:SEQUENCE::NUMBER(38, 0) FROM @stg)" ,
2474+ ) ,
2475+ concat ! (
2476+ "COPY INTO my_company.emp_basic (a, b) FROM " ,
2477+ r#"(SELECT $1:"A"::VARIANT, $1:"B"::TEXT FROM @stg)"# ,
2478+ ) ,
2479+ // Mix with an ordinary stage-load-select-item in the same list,
2480+ // so we don't over-correct and break the existing shape.
2481+ concat ! (
2482+ "COPY INTO my_company.emp_basic (a, b) FROM " ,
2483+ r#"(SELECT t.$1:plain AS plain, $1:"B"::TEXT FROM @stg AS t)"# ,
2484+ ) ,
2485+ ] ;
2486+ for sql in variants {
2487+ snowflake ( ) . parse_sql_statements ( sql) . unwrap_or_else ( |e| {
2488+ panic ! ( "expected {sql:?} to parse, got {e}" ) ;
2489+ } ) ;
2490+ }
2491+ }
2492+
24502493#[ test]
24512494fn test_copy_into_file_format ( ) {
24522495 let sql = concat ! (
0 commit comments