@@ -1902,6 +1902,111 @@ void testPartitionedAppendBasicIntegerPartitions() {
19021902 assertTableEquals (expected2 , fromIceberg2 .select ());
19031903 }
19041904
1905+ @ Test
1906+ void testPartitionOrdering () {
1907+ final Table part1 = TableTools .emptyTable (6 )
1908+ .update ("intCol = (int) 2 * i + 10" ,
1909+ "doubleCol = (double) 2.5 * i + 10" );
1910+ final Table part2 = TableTools .emptyTable (5 )
1911+ .update ("intCol = (int) 3 * i + 20" ,
1912+ "doubleCol = (double) 3.5 * i + 20" );
1913+ final Table part3 = TableTools .emptyTable (4 )
1914+ .update ("intCol = (int) 4 * i + 30" ,
1915+ "doubleCol = (double) 4.5 * i + 30" );
1916+ final TableIdentifier tableIdentifier = TableIdentifier .parse ("MyNamespace.PartitionOrderingTest" );
1917+
1918+ final TableDefinition tableDefinition1 = TableDefinition .of (
1919+ ColumnDefinition .ofInt ("intCol" ),
1920+ ColumnDefinition .ofDouble ("doubleCol" ),
1921+ ColumnDefinition .ofString ("InternalPartition" ).withPartitioning (),
1922+ ColumnDefinition .ofString ("Date" ).withPartitioning ());
1923+ final IcebergTableAdapter tableAdapter1 = catalogAdapter .createTable (tableIdentifier , tableDefinition1 );
1924+ final IcebergTableWriter tableWriter1 = tableAdapter1 .tableWriter (writerOptionsBuilder ()
1925+ .tableDefinition (tableDefinition1 )
1926+ .build ());
1927+
1928+ tableWriter1 .append (IcebergWriteInstructions .builder ()
1929+ .addTables (part1 , part2 , part3 )
1930+ .addAllPartitionPaths (List .of (
1931+ "InternalPartition=0/Date=2024-08-01" ,
1932+ "InternalPartition=1/Date=2024-08-02" ,
1933+ "InternalPartition=2/Date=2024-08-02" ))
1934+ .build ());
1935+ final Table fromIceberg1 = tableAdapter1 .table ();
1936+ final Table expected1 = TableTools .merge (
1937+ part1 .update ("InternalPartition = `0`" , "Date = `2024-08-01`" ),
1938+ part2 .update ("InternalPartition = `1`" , "Date = `2024-08-02`" ),
1939+ part3 .update ("InternalPartition = `2`" , "Date = `2024-08-02`" ));
1940+ assertTableEquals (expected1 , fromIceberg1 );
1941+
1942+ // Add another partition for same date, but with the partitions ordered differently
1943+ final TableDefinition tableDefinition2 = TableDefinition .of (
1944+ ColumnDefinition .ofInt ("intCol" ),
1945+ ColumnDefinition .ofDouble ("doubleCol" ),
1946+ ColumnDefinition .ofString ("Date" ).withPartitioning (), // NOTE: opposite order here!
1947+ ColumnDefinition .ofString ("InternalPartition" ).withPartitioning ());
1948+ final IcebergTableWriter tableWriter2 = tableAdapter1 .tableWriter (writerOptionsBuilder ()
1949+ .tableDefinition (tableDefinition2 )
1950+ .build ());
1951+
1952+ final Table part4 = TableTools .emptyTable (3 )
1953+ .update ("intCol = (int) 5 * i + 30" ,
1954+ "doubleCol = (double) 5.5 * i + 30" );
1955+ tableWriter2 .append (IcebergWriteInstructions .builder ()
1956+ .addTables (part4 )
1957+ .addPartitionPaths ("InternalPartition=1/Date=2024-08-02" )
1958+ .build ());
1959+ final Table fromIceberg2 = tableAdapter1 .table ();
1960+ final Table expected2 = TableTools .merge (
1961+ expected1 ,
1962+ part4 .update ("InternalPartition = `1`" , "Date = `2024-08-02`" ));
1963+ assertTableEquals (expected2 , fromIceberg2 );
1964+
1965+ // We have successfully written with the alternative partition-ordering. Make sure we can read it that way, too.
1966+ final Schema schema = tableAdapter1 .icebergTable ().schema ();
1967+ final IcebergTableAdapter tableAdapter2 = catalogAdapter .loadTable (LoadTableOptions .builder ()
1968+ .id (tableIdentifier )
1969+ .resolver (Resolver .builder ()
1970+ // NOTE: this `TableDefinition` has `Date` before `InternalPartition`
1971+ .definition (tableDefinition2 )
1972+ .schema (schema )
1973+ .spec (PartitionSpec .builderFor (schema )
1974+ .identity ("InternalPartition" )
1975+ .identity ("Date" )
1976+ .build ())
1977+ .putColumnInstructions ("intCol" , schemaField (schema .findField ("intCol" ).fieldId ()))
1978+ .putColumnInstructions ("doubleCol" , schemaField (schema .findField ("doubleCol" ).fieldId ()))
1979+ .putColumnInstructions ("InternalPartition" ,
1980+ schemaField (schema .findField ("InternalPartition" ).fieldId ()))
1981+ .putColumnInstructions ("Date" , schemaField (schema .findField ("Date" ).fieldId ()))
1982+ .build ())
1983+ .build ());
1984+ final Table fromIceberg3 = tableAdapter2 .table ();
1985+ // we've defined `Date` to be the first PartitioningColumn in the returned table instead of `InternalPartition`,
1986+ // so we need to re-order for the comparison (or tell it to ignore column-ordering differences)
1987+ assertTableEquals (expected2 .view ("intCol" , "doubleCol" , "Date" , "InternalPartition" ), fromIceberg3 );
1988+
1989+ // Try reading with no partitioning columns defined
1990+ final IcebergTableAdapter tableAdapter3 = catalogAdapter .loadTable (LoadTableOptions .builder ()
1991+ .id (tableIdentifier )
1992+ .resolver (Resolver .builder ()
1993+ // NOTE: this `TableDefinition` has no partitioning columns
1994+ .definition (TableDefinition .of (ColumnDefinition .ofInt ("intCol" ),
1995+ ColumnDefinition .ofDouble ("doubleCol" ),
1996+ ColumnDefinition .ofString ("InternalPartition" ),
1997+ ColumnDefinition .ofString ("Date" )))
1998+ .schema (schema )
1999+ .putColumnInstructions ("intCol" , schemaField (schema .findField ("intCol" ).fieldId ()))
2000+ .putColumnInstructions ("doubleCol" , schemaField (schema .findField ("doubleCol" ).fieldId ()))
2001+ .putColumnInstructions ("InternalPartition" ,
2002+ schemaField (schema .findField ("InternalPartition" ).fieldId ()))
2003+ .putColumnInstructions ("Date" , schemaField (schema .findField ("Date" ).fieldId ()))
2004+ .build ())
2005+ .build ());
2006+ final Table fromIceberg4 = tableAdapter3 .table ();
2007+ assertTableEquals (expected2 , fromIceberg4 );
2008+ }
2009+
19052010 @ Test
19062011 void testPartitionedAppendWithDeleting () {
19072012 final Table part1 = TableTools .emptyTable (6 )
@@ -1933,11 +2038,11 @@ void testPartitionedAppendWithDeleting() {
19332038 "InternalPartition=2/Date=2024-08-02" ))
19342039 .build ());
19352040 final Table fromIceberg = tableAdapter .table ();
1936- final Table expected = TableTools .merge (
2041+ final Table expected1 = TableTools .merge (
19372042 part1 .update ("InternalPartition = `0`" , "Date = `2024-08-01`" ),
19382043 part2 .update ("InternalPartition = `1`" , "Date = `2024-08-02`" ),
19392044 part3 .update ("InternalPartition = `2`" , "Date = `2024-08-02`" ));
1940- assertTableEquals (expected , fromIceberg . select () );
2045+ assertTableEquals (expected1 , fromIceberg );
19412046
19422047 // Add another partition for same date
19432048 final Table part4 = TableTools .emptyTable (3 )
@@ -1949,11 +2054,9 @@ void testPartitionedAppendWithDeleting() {
19492054 .build ());
19502055 final Table fromIceberg2 = tableAdapter .table ();
19512056 final Table expected2 = TableTools .merge (
1952- part1 .update ("InternalPartition = `0`" , "Date = `2024-08-01`" ),
1953- part2 .update ("InternalPartition = `1`" , "Date = `2024-08-02`" ),
1954- part3 .update ("InternalPartition = `2`" , "Date = `2024-08-02`" ),
2057+ expected1 ,
19552058 part4 .update ("InternalPartition = `1`" , "Date = `2024-08-02`" ));
1956- assertTableEquals (expected2 , fromIceberg2 . select () );
2059+ assertTableEquals (expected2 , fromIceberg2 );
19572060
19582061 // Now delete the partition for date 2024-08-02
19592062 final Expression delExpr = Expressions .equal ("Date" , "2024-08-02" );
@@ -1964,7 +2067,7 @@ void testPartitionedAppendWithDeleting() {
19642067 final IcebergTableAdapter latestTableAdapter = catalogAdapter .loadTable (tableIdentifier );
19652068 final Table fromIceberg3 = latestTableAdapter .table ();
19662069 final Table expected3 = part1 .update ("InternalPartition = `0`" , "Date = `2024-08-01`" );
1967- assertTableEquals (expected3 , fromIceberg3 . select () );
2070+ assertTableEquals (expected3 , fromIceberg3 );
19682071 }
19692072
19702073 @ Test
0 commit comments