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 3be82f50 fix(arrow): read CSV boolean columns like Java's CsvParser 
(#980)
3be82f50 is described below

commit 3be82f501ba8995da57d31a8595438775cf266a1
Author: jackylee <[email protected]>
AuthorDate: Fri Oct 2 10:08:19 2026 +0800

    fix(arrow): read CSV boolean columns like Java's CsvParser (#980)
---
 crates/paimon/src/arrow/format/text.rs | 55 +++++++++++++++++++++++++++++++++-
 1 file changed, 54 insertions(+), 1 deletion(-)

diff --git a/crates/paimon/src/arrow/format/text.rs 
b/crates/paimon/src/arrow/format/text.rs
index 2f851951..d46c5411 100644
--- a/crates/paimon/src/arrow/format/text.rs
+++ b/crates/paimon/src/arrow/format/text.rs
@@ -25,7 +25,8 @@ use crate::spec::DataField;
 use crate::table::{ArrowRecordBatchStream, RowRange};
 use crate::Error;
 use arrow_array::{
-    Array, ArrayRef, BinaryArray, FixedSizeBinaryArray, LargeBinaryArray, 
RecordBatch, StringArray,
+    Array, ArrayRef, BinaryArray, BooleanArray, FixedSizeBinaryArray, 
LargeBinaryArray,
+    RecordBatch, StringArray,
 };
 use arrow_schema::{DataType, SchemaRef};
 use async_trait::async_trait;
@@ -1081,6 +1082,22 @@ fn csv_cast_column(column: &ArrayRef, target: &DataType) 
-> crate::Result<ArrayR
             _ => unreachable!(),
         });
     }
+    if matches!(target, DataType::Boolean) {
+        // Java `CsvParser` reads BOOLEAN via `Boolean.parseBoolean`: only 
"true"
+        // (case-insensitive) is true, every other non-null token is false, and
+        // it never yields null. arrow-cast instead maps "1"/"yes"/"t"/"on"/"y"
+        // to true and unrecognized tokens (e.g. "2", "invalid") to null, so 
the
+        // same CSV file read through Rust would flip boolean values or turn 
them
+        // null relative to Java. Match Java so a format table reads the same
+        // across engines. (Null fields are already `None` from CSV decoding 
and
+        // stay null.)
+        let values = column.as_any().downcast_ref::<StringArray>().unwrap();
+        let booleans: BooleanArray = values
+            .iter()
+            .map(|value| value.map(|value| value.eq_ignore_ascii_case("true")))
+            .collect();
+        return Ok(Arc::new(booleans));
+    }
     arrow_cast::cast(column, target).map_err(arrow_error)
 }
 
@@ -1430,4 +1447,40 @@ mod tests {
             serde_json::json!(["false", null, "true"])
         );
     }
+
+    #[test]
+    fn csv_boolean_matches_java_parse_boolean() {
+        // Java `CsvParser` reads BOOLEAN via `Boolean.parseBoolean`: only 
"true"
+        // (case-insensitive) is true, every other non-null token is false, and
+        // null stays null. arrow-cast would instead read "1"/"yes"/"t" as true
+        // and "invalid" as null, flipping values for the same CSV file.
+        let input: ArrayRef = Arc::new(StringArray::from(vec![
+            Some("true"),
+            Some("TRUE"),
+            Some("1"),
+            Some("yes"),
+            Some("t"),
+            Some("invalid"),
+            Some("false"),
+            Some("0"),
+            None,
+        ]));
+        let result = csv_cast_column(&input, &DataType::Boolean).unwrap();
+        let booleans = result.as_any().downcast_ref::<BooleanArray>().unwrap();
+        let got: Vec<Option<bool>> = booleans.iter().collect();
+        assert_eq!(
+            got,
+            vec![
+                Some(true),  // "true"
+                Some(true),  // "TRUE"
+                Some(false), // "1"  (arrow-cast would say true)
+                Some(false), // "yes" (arrow-cast would say true)
+                Some(false), // "t"  (arrow-cast would say true)
+                Some(false), // "invalid" (arrow-cast would say null)
+                Some(false), // "false"
+                Some(false), // "0"
+                None,        // null stays null
+            ]
+        );
+    }
 }

Reply via email to