This is an automated email from the ASF dual-hosted git repository.
JingsongLi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/paimon-rust.git
The following commit(s) were added to refs/heads/main by this push:
new b6fb298 test: add mixed-format drop column schema evolution coverage
(#363)
b6fb298 is described below
commit b6fb2984939f92d83147a3a035321ff677ee1763
Author: Jiwen liu <[email protected]>
AuthorDate: Fri Jun 12 14:40:44 2026 +0800
test: add mixed-format drop column schema evolution coverage (#363)
---
crates/integration_tests/tests/read_tables.rs | 92 +++++++++++++++++++++++++++
dev/spark/provision.py | 44 +++++++++++++
2 files changed, 136 insertions(+)
diff --git a/crates/integration_tests/tests/read_tables.rs
b/crates/integration_tests/tests/read_tables.rs
index 82a69aa..e5c3b05 100644
--- a/crates/integration_tests/tests/read_tables.rs
+++ b/crates/integration_tests/tests/read_tables.rs
@@ -1583,6 +1583,98 @@ async fn test_read_schema_evolution_rename_column() {
);
}
+/// Test reading a mixed-format table after ALTER TABLE DROP COLUMN.
+/// Old Parquet/ORC data files have the dropped column; new Avro files do not.
+#[tokio::test]
+async fn test_read_mixed_format_schema_evolution_drop_column() {
+ let table_name = "mixed_format_schema_evolution_drop_column";
+ let (plan, batches) = scan_and_read_with_fs_catalog(table_name,
None).await;
+ assert_plan_file_formats(&plan, &["avro", "orc", "parquet"], table_name);
+
+ for batch in &batches {
+ assert!(
+ batch.column_by_name("score").is_none(),
+ "Dropped column 'score' should not appear in output"
+ );
+ }
+
+ let mut rows: Vec<(i32, String)> = Vec::new();
+ for batch in &batches {
+ let id = batch
+ .column_by_name("id")
+ .and_then(|c| c.as_any().downcast_ref::<Int32Array>())
+ .expect("id");
+ let name = batch
+ .column_by_name("name")
+ .and_then(|c| c.as_any().downcast_ref::<StringArray>())
+ .expect("name");
+ for i in 0..batch.num_rows() {
+ rows.push((id.value(i), name.value(i).to_string()));
+ }
+ }
+ rows.sort_by_key(|(id, _)| *id);
+
+ assert_eq!(
+ rows,
+ vec![
+ (1, "parquet-alice".into()),
+ (2, "parquet-bob".into()),
+ (3, "orc-carol".into()),
+ (4, "orc-dave".into()),
+ (5, "avro-eve".into()),
+ (6, "avro-frank".into()),
+ ],
+ "Mixed-format DROP COLUMN should expose only remaining columns from
all file formats"
+ );
+
+ let (_, projected_batches) = scan_and_read_with_fs_catalog(
+ "mixed_format_schema_evolution_drop_column",
+ Some(&["name", "id"]),
+ )
+ .await;
+
+ let mut projected_rows: Vec<(i32, String)> = Vec::new();
+ for batch in &projected_batches {
+ let schema = batch.schema();
+ let field_names: Vec<&str> = schema.fields().iter().map(|f|
f.name().as_str()).collect();
+ assert_eq!(
+ field_names,
+ vec!["name", "id"],
+ "Projection should preserve caller-specified order after DROP
COLUMN"
+ );
+ assert!(
+ batch.column_by_name("score").is_none(),
+ "Dropped column 'score' should not appear in projected output"
+ );
+
+ let name = batch
+ .column_by_name("name")
+ .and_then(|c| c.as_any().downcast_ref::<StringArray>())
+ .expect("projected name");
+ let id = batch
+ .column_by_name("id")
+ .and_then(|c| c.as_any().downcast_ref::<Int32Array>())
+ .expect("projected id");
+ for i in 0..batch.num_rows() {
+ projected_rows.push((id.value(i), name.value(i).to_string()));
+ }
+ }
+ projected_rows.sort_by_key(|(id, _)| *id);
+
+ assert_eq!(
+ projected_rows,
+ vec![
+ (1, "parquet-alice".into()),
+ (2, "parquet-bob".into()),
+ (3, "orc-carol".into()),
+ (4, "orc-dave".into()),
+ (5, "avro-eve".into()),
+ (6, "avro-frank".into()),
+ ],
+ "Projection should read remaining columns across old and new file
schemas"
+ );
+}
+
// ---------------------------------------------------------------------------
// Complex type integration tests
// ---------------------------------------------------------------------------
diff --git a/dev/spark/provision.py b/dev/spark/provision.py
index d56156e..44f981e 100644
--- a/dev/spark/provision.py
+++ b/dev/spark/provision.py
@@ -646,6 +646,50 @@ def main():
"""
)
+ # ===== Mixed-format Schema Evolution: Drop Column =====
+ # Old Parquet/ORC files have (id, name, score); after DROP COLUMN, Avro
files
+ # have only (id, name). Reader should ignore the dropped column in old
files.
+ spark.sql(
+ """
+ CREATE TABLE IF NOT EXISTS mixed_format_schema_evolution_drop_column (
+ id INT,
+ name STRING,
+ score INT
+ ) USING paimon
+ TBLPROPERTIES (
+ 'file.format' = 'parquet'
+ )
+ """
+ )
+ spark.sql(
+ """
+ INSERT INTO mixed_format_schema_evolution_drop_column VALUES
+ (1, 'parquet-alice', 100),
+ (2, 'parquet-bob', 200)
+ """
+ )
+ spark.sql(
+ "ALTER TABLE mixed_format_schema_evolution_drop_column SET
TBLPROPERTIES ('file.format' = 'orc')"
+ )
+ spark.sql(
+ """
+ INSERT INTO mixed_format_schema_evolution_drop_column VALUES
+ (3, 'orc-carol', 300),
+ (4, 'orc-dave', 400)
+ """
+ )
+ spark.sql("ALTER TABLE mixed_format_schema_evolution_drop_column DROP
COLUMN score")
+ spark.sql(
+ "ALTER TABLE mixed_format_schema_evolution_drop_column SET
TBLPROPERTIES ('file.format' = 'avro')"
+ )
+ spark.sql(
+ """
+ INSERT INTO mixed_format_schema_evolution_drop_column VALUES
+ (5, 'avro-eve'),
+ (6, 'avro-frank')
+ """
+ )
+
# ===== Complex Types table: ARRAY, MAP, STRUCT =====
spark.sql(
"""