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 11fe80d  fix(core): reject empty column names in writers (#93)
11fe80d is described below

commit 11fe80d16808f9893b30264f134b09f8c72c4dfe
Author: jianguotian <[email protected]>
AuthorDate: Wed Sep 30 07:16:12 2026 +0800

    fix(core): reject empty column names in writers (#93)
---
 core/src/schema.rs |  3 +++
 core/src/writer.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)

diff --git a/core/src/schema.rs b/core/src/schema.rs
index ecfc6d1..eef791d 100644
--- a/core/src/schema.rs
+++ b/core/src/schema.rs
@@ -47,6 +47,9 @@ impl MosaicSchema {
     pub fn validate(columns: &[(String, DataType, bool)]) -> Result<(), 
String> {
         let mut seen = HashSet::new();
         for (name, data_type, _nullable) in columns {
+            if name.is_empty() {
+                return Err("empty column name".to_string());
+            }
             if !seen.insert(name.as_str()) {
                 return Err(format!("duplicate column name: {}", name));
             }
diff --git a/core/src/writer.rs b/core/src/writer.rs
index a977049..d503a06 100644
--- a/core/src/writer.rs
+++ b/core/src/writer.rs
@@ -170,6 +170,19 @@ impl<S: OutputFile> MosaicWriter<S> {
         schema: MosaicSchema,
         options: WriterOptions,
     ) -> io::Result<Self> {
+        let columns = schema
+            .columns
+            .iter()
+            .map(|column| {
+                (
+                    column.name.clone(),
+                    column.data_type.clone(),
+                    column.nullable,
+                )
+            })
+            .collect::<Vec<_>>();
+        MosaicSchema::validate(&columns)
+            .map_err(|error| io::Error::new(io::ErrorKind::InvalidInput, 
error))?;
         let batch_col_map: Vec<usize> = (0..schema.columns.len()).collect();
         Self::from_mosaic_schema_with_map(out, schema, options, batch_col_map)
     }
@@ -892,6 +905,58 @@ mod tests {
         assert_eq!(batch_column_map(&mosaic_schema), vec![1, 2, 0]);
     }
 
+    #[test]
+    fn test_new_rejects_empty_column_name_before_writing() {
+        let arrow_schema = Schema::new(vec![Field::new("", DataType::Int32, 
true)]);
+        let state = Arc::new(Mutex::new(FailingOutputState::default()));
+        let out = FailOnceOutputFile {
+            state: Arc::clone(&state),
+            fail: false,
+        };
+
+        let result = MosaicWriter::new(out, &arrow_schema, 
WriterOptions::default());
+        let error = match result {
+            Ok(writer) => {
+                std::mem::forget(writer);
+                panic!("empty column name should be rejected");
+            }
+            Err(error) => error,
+        };
+
+        assert_eq!(io::ErrorKind::InvalidInput, error.kind());
+        assert!(error.to_string().contains("empty column name"));
+        let state = state.lock().unwrap();
+        assert_eq!(0, state.write_calls);
+        assert_eq!(0, state.flush_calls);
+        assert!(state.bytes.is_empty());
+    }
+
+    #[test]
+    fn test_from_mosaic_schema_rejects_empty_column_name_before_writing() {
+        let schema = MosaicSchema::new(vec![("".to_string(), DataType::Int32, 
true)], 1);
+        let state = Arc::new(Mutex::new(FailingOutputState::default()));
+        let out = FailOnceOutputFile {
+            state: Arc::clone(&state),
+            fail: false,
+        };
+
+        let result = MosaicWriter::from_mosaic_schema(out, schema, 
WriterOptions::default());
+        let error = match result {
+            Ok(writer) => {
+                std::mem::forget(writer);
+                panic!("empty column name should be rejected");
+            }
+            Err(error) => error,
+        };
+
+        assert_eq!(io::ErrorKind::InvalidInput, error.kind());
+        assert!(error.to_string().contains("empty column name"));
+        let state = state.lock().unwrap();
+        assert_eq!(0, state.write_calls);
+        assert_eq!(0, state.flush_calls);
+        assert!(state.bytes.is_empty());
+    }
+
     #[test]
     fn test_write_simple_file() {
         let arrow_schema = Schema::new(vec![

Reply via email to