@@ -1519,16 +1519,10 @@ async fn test_read_schema_evolution_rename_column() {
15191519 let ( plan, batches) =
15201520 scan_and_read_with_fs_catalog ( "schema_evolution_rename_column" , None ) . await ;
15211521
1522- let formats: HashSet < & str > = plan
1523- . splits ( )
1524- . iter ( )
1525- . flat_map ( |split| split. data_files ( ) )
1526- . filter_map ( |file| file. file_name . rsplit_once ( '.' ) . map ( |( _, ext) | ext) )
1527- . collect ( ) ;
1528- assert_eq ! (
1529- formats,
1530- HashSet :: from( [ "avro" , "orc" , "parquet" ] ) ,
1531- "schema_evolution_rename_column should scan all provisioned file formats"
1522+ assert_plan_file_formats (
1523+ & plan,
1524+ & [ "avro" , "orc" , "parquet" ] ,
1525+ "schema_evolution_rename_column" ,
15321526 ) ;
15331527
15341528 let mut rows: Vec < ( i32 , String ) > = Vec :: new ( ) ;
@@ -1686,6 +1680,109 @@ async fn test_read_mixed_format_schema_evolution_drop_column() {
16861680 ) ;
16871681}
16881682
1683+ /// Test reading a mixed-format table after ALTER COLUMN ... FIRST/AFTER.
1684+ /// Old files keep the original physical column order; new files use moved columns.
1685+ #[ tokio:: test]
1686+ async fn test_read_mixed_format_schema_evolution_reorder_move_column ( ) {
1687+ let ( plan, batches) =
1688+ scan_and_read_with_fs_catalog ( "mixed_format_schema_evolution_reorder_move_column" , None )
1689+ . await ;
1690+
1691+ assert_plan_file_formats (
1692+ & plan,
1693+ & [ "avro" , "orc" , "parquet" ] ,
1694+ "mixed_format_schema_evolution_reorder_move_column" ,
1695+ ) ;
1696+
1697+ for batch in & batches {
1698+ let schema = batch. schema ( ) ;
1699+ let field_names: Vec < & str > = schema. fields ( ) . iter ( ) . map ( |f| f. name ( ) . as_str ( ) ) . collect ( ) ;
1700+ assert_eq ! (
1701+ field_names,
1702+ vec![ "right_value" , "left_value" , "id" ] ,
1703+ "Full read should expose the current table schema order"
1704+ ) ;
1705+ }
1706+
1707+ let mut rows: Vec < ( i32 , String , String ) > = Vec :: new ( ) ;
1708+ for batch in & batches {
1709+ let right_value = batch
1710+ . column_by_name ( "right_value" )
1711+ . and_then ( |c| c. as_any ( ) . downcast_ref :: < StringArray > ( ) )
1712+ . expect ( "right_value" ) ;
1713+ let left_value = batch
1714+ . column_by_name ( "left_value" )
1715+ . and_then ( |c| c. as_any ( ) . downcast_ref :: < StringArray > ( ) )
1716+ . expect ( "left_value" ) ;
1717+ let id = batch
1718+ . column_by_name ( "id" )
1719+ . and_then ( |c| c. as_any ( ) . downcast_ref :: < Int32Array > ( ) )
1720+ . expect ( "id" ) ;
1721+ for i in 0 ..batch. num_rows ( ) {
1722+ rows. push ( (
1723+ id. value ( i) ,
1724+ left_value. value ( i) . to_string ( ) ,
1725+ right_value. value ( i) . to_string ( ) ,
1726+ ) ) ;
1727+ }
1728+ }
1729+ rows. sort_by_key ( |( id, _, _) | * id) ;
1730+
1731+ assert_eq ! (
1732+ rows,
1733+ vec![
1734+ ( 1 , "parquet-left-1" . into( ) , "parquet-right-1" . into( ) ) ,
1735+ ( 2 , "parquet-left-2" . into( ) , "parquet-right-2" . into( ) ) ,
1736+ ( 3 , "orc-left-3" . into( ) , "orc-right-3" . into( ) ) ,
1737+ ( 4 , "orc-left-4" . into( ) , "orc-right-4" . into( ) ) ,
1738+ ( 5 , "avro-left-5" . into( ) , "avro-right-5" . into( ) ) ,
1739+ ( 6 , "avro-left-6" . into( ) , "avro-right-6" . into( ) ) ,
1740+ ] ,
1741+ "Mixed-format REORDER/MOVE COLUMN should read values by field id, not physical position"
1742+ ) ;
1743+
1744+ let ( _, projected_batches) = scan_and_read_with_fs_catalog (
1745+ "mixed_format_schema_evolution_reorder_move_column" ,
1746+ Some ( & [ "id" , "right_value" ] ) ,
1747+ )
1748+ . await ;
1749+ let mut projected_rows: Vec < ( i32 , String ) > = Vec :: new ( ) ;
1750+ for batch in & projected_batches {
1751+ let schema = batch. schema ( ) ;
1752+ let field_names: Vec < & str > = schema. fields ( ) . iter ( ) . map ( |f| f. name ( ) . as_str ( ) ) . collect ( ) ;
1753+ assert_eq ! (
1754+ field_names,
1755+ vec![ "id" , "right_value" ] ,
1756+ "Projection should follow caller-specified order"
1757+ ) ;
1758+
1759+ let id = batch
1760+ . column_by_name ( "id" )
1761+ . and_then ( |c| c. as_any ( ) . downcast_ref :: < Int32Array > ( ) )
1762+ . expect ( "projected id" ) ;
1763+ let right_value = batch
1764+ . column_by_name ( "right_value" )
1765+ . and_then ( |c| c. as_any ( ) . downcast_ref :: < StringArray > ( ) )
1766+ . expect ( "projected right_value" ) ;
1767+ for i in 0 ..batch. num_rows ( ) {
1768+ projected_rows. push ( ( id. value ( i) , right_value. value ( i) . to_string ( ) ) ) ;
1769+ }
1770+ }
1771+ projected_rows. sort_by_key ( |( id, _) | * id) ;
1772+ assert_eq ! (
1773+ projected_rows,
1774+ vec![
1775+ ( 1 , "parquet-right-1" . into( ) ) ,
1776+ ( 2 , "parquet-right-2" . into( ) ) ,
1777+ ( 3 , "orc-right-3" . into( ) ) ,
1778+ ( 4 , "orc-right-4" . into( ) ) ,
1779+ ( 5 , "avro-right-5" . into( ) ) ,
1780+ ( 6 , "avro-right-6" . into( ) ) ,
1781+ ] ,
1782+ "Projection should still map reordered old and new files by field id"
1783+ ) ;
1784+ }
1785+
16891786// ---------------------------------------------------------------------------
16901787// Complex type integration tests
16911788// ---------------------------------------------------------------------------
0 commit comments