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-mosaic.git


The following commit(s) were added to refs/heads/main by this push:
     new cd041fd  fix(core): validate writer batch schema (#70)
cd041fd is described below

commit cd041fd8548c4996895f36d98ef716a65050f4a8
Author: QuakeWang <[email protected]>
AuthorDate: Wed Sep 30 07:15:56 2026 +0800

    fix(core): validate writer batch schema (#70)
---
 core/src/writer.rs | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 101 insertions(+), 1 deletion(-)

diff --git a/core/src/writer.rs b/core/src/writer.rs
index 6de041e..a977049 100644
--- a/core/src/writer.rs
+++ b/core/src/writer.rs
@@ -334,6 +334,7 @@ impl<S: OutputFile> MosaicWriter<S> {
                 ),
             ));
         }
+        self.validate_batch_schema(batch)?;
 
         for (i, col) in self.schema.columns.iter().enumerate() {
             let array = batch.column(self.batch_col_map[i]);
@@ -391,6 +392,25 @@ impl<S: OutputFile> MosaicWriter<S> {
         Ok(())
     }
 
+    fn validate_batch_schema(&self, batch: &RecordBatch) -> io::Result<()> {
+        let batch_schema = batch.schema();
+        for (i, col) in self.schema.columns.iter().enumerate() {
+            let batch_field = batch_schema.field(self.batch_col_map[i]);
+            if batch_field.name() != &col.name {
+                return Err(io::Error::new(
+                    io::ErrorKind::InvalidInput,
+                    format!(
+                        "field name mismatch at column {}: schema has '{}' but 
batch has '{}'",
+                        self.batch_col_map[i],
+                        col.name,
+                        batch_field.name()
+                    ),
+                ));
+            }
+        }
+        Ok(())
+    }
+
     fn flush_row_group(&mut self) -> io::Result<()> {
         if self.current_row_group_rows == 0 {
             return Ok(());
@@ -1040,7 +1060,7 @@ mod tests {
 
         let batch2 = RecordBatch::try_new(
             Arc::new(Schema::new(vec![
-                Field::new("id", DataType::Int32, false),
+                Field::new("id", DataType::Int32, true),
                 Field::new("name", DataType::Utf8, true),
             ])),
             vec![
@@ -1051,6 +1071,86 @@ mod tests {
         .unwrap();
         let result = writer.write_batch(&batch2);
         assert!(result.is_ok());
+
+        let batch3 = RecordBatch::try_new(
+            Arc::new(Schema::new(vec![
+                Field::new("id", DataType::Int32, false),
+                Field::new("name", DataType::Utf8, true),
+            ])),
+            vec![
+                Arc::new(Int32Array::from(vec![1, 2])),
+                Arc::new(StringArray::from(vec![None, Some("world")])),
+            ],
+        )
+        .unwrap();
+        let result = writer.write_batch(&batch3);
+        assert!(result.is_ok());
+    }
+
+    #[test]
+    fn test_write_batch_rejects_reordered_schema() {
+        let arrow_schema = Schema::new(vec![
+            Field::new("a", DataType::Int32, false),
+            Field::new("b", DataType::Int32, false),
+        ]);
+        let out = MemOutputFile::new();
+        let mut writer = MosaicWriter::new(out, &arrow_schema, 
WriterOptions::default()).unwrap();
+
+        let batch = RecordBatch::try_new(
+            Arc::new(arrow_schema),
+            vec![
+                Arc::new(Int32Array::from(vec![1, 2])),
+                Arc::new(Int32Array::from(vec![10, 20])),
+            ],
+        )
+        .unwrap();
+        writer.write_batch(&batch).unwrap();
+
+        let reordered_schema = Schema::new(vec![
+            Field::new("b", DataType::Int32, false),
+            Field::new("a", DataType::Int32, false),
+        ]);
+        let reordered_batch = RecordBatch::try_new(
+            Arc::new(reordered_schema),
+            vec![
+                Arc::new(Int32Array::from(vec![30, 40])),
+                Arc::new(Int32Array::from(vec![3, 4])),
+            ],
+        )
+        .unwrap();
+
+        let err = writer.write_batch(&reordered_batch).unwrap_err();
+        assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+        assert!(err.to_string().contains("field name mismatch"));
+    }
+
+    #[test]
+    fn test_write_batch_name_mismatch_reports_mapped_batch_index() {
+        let arrow_schema = Schema::new(vec![
+            Field::new("z", DataType::Int32, false),
+            Field::new("a", DataType::Int32, false),
+        ]);
+        let out = MemOutputFile::new();
+        let mut writer = MosaicWriter::new(out, &arrow_schema, 
WriterOptions::default()).unwrap();
+
+        let mismatched_batch = RecordBatch::try_new(
+            Arc::new(Schema::new(vec![
+                Field::new("z", DataType::Int32, false),
+                Field::new("x", DataType::Int32, false),
+            ])),
+            vec![
+                Arc::new(Int32Array::from(vec![1, 2])),
+                Arc::new(Int32Array::from(vec![3, 4])),
+            ],
+        )
+        .unwrap();
+
+        let err = writer.write_batch(&mismatched_batch).unwrap_err();
+        assert_eq!(err.kind(), io::ErrorKind::InvalidInput);
+        assert_eq!(
+            err.to_string(),
+            "field name mismatch at column 1: schema has 'a' but batch has 'x'"
+        );
     }
 
     #[test]

Reply via email to