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 e2d16f6b fix: write manifest file metadata as Avro record (#743)
e2d16f6b is described below
commit e2d16f6bbbbe29b7768c2e485c067e55a2452e44
Author: shyjsarah <[email protected]>
AuthorDate: Tue Aug 25 17:17:14 2026 +0800
fix: write manifest file metadata as Avro record (#743)
---
crates/paimon/src/spec/manifest_entry.rs | 22 +++++++++++++++++++---
crates/paimon/src/spec/objects_file.rs | 12 +++++++++++-
2 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/crates/paimon/src/spec/manifest_entry.rs
b/crates/paimon/src/spec/manifest_entry.rs
index 0e66891a..63473247 100644
--- a/crates/paimon/src/spec/manifest_entry.rs
+++ b/crates/paimon/src/spec/manifest_entry.rs
@@ -192,7 +192,7 @@ pub const MANIFEST_ENTRY_SCHEMA: &str = r#"["null", {
{"name": "_PARTITION", "type": "bytes"},
{"name": "_BUCKET", "type": "int"},
{"name": "_TOTAL_BUCKETS", "type": "int"},
- {"name": "_FILE", "type": ["null", {
+ {"name": "_FILE", "type": {
"type": "record",
"name": "record__FILE",
"fields": [
@@ -233,14 +233,14 @@ pub const MANIFEST_ENTRY_SCHEMA: &str = r#"["null", {
{"name": "_FIRST_ROW_ID", "type": ["null", "long"], "default":
null},
{"name": "_WRITE_COLS", "type": ["null", {"type": "array",
"items": "string"}], "default": null}
]
- }], "default": null}
+ }}
]
}]"#;
#[cfg(test)]
mod tests {
use super::{Identifier, MANIFEST_ENTRY_SCHEMA};
- use crate::spec::avro::schema::WriterSchema;
+ use crate::spec::avro::schema::{FieldSchema, WriterSchema};
use std::collections::HashSet;
#[test]
@@ -265,6 +265,22 @@ mod tests {
);
}
+ #[test]
+ fn test_manifest_entry_file_schema_matches_java_record_type() {
+ let schema = WriterSchema::parse(MANIFEST_ENTRY_SCHEMA).unwrap();
+ let file = schema
+ .fields
+ .iter()
+ .find(|field| field.name == "_FILE")
+ .unwrap();
+
+ assert!(
+ !file.nullable,
+ "Java ManifestAvroReader requires _FILE to be a RECORD, not a
nullable UNION"
+ );
+ assert!(matches!(file.schema, FieldSchema::Record(_)));
+ }
+
fn ident(file_name: &str, level: i32) -> Identifier {
Identifier {
partition: vec![1, 2, 3],
diff --git a/crates/paimon/src/spec/objects_file.rs
b/crates/paimon/src/spec/objects_file.rs
index 7f2c1436..7db066fa 100644
--- a/crates/paimon/src/spec/objects_file.rs
+++ b/crates/paimon/src/spec/objects_file.rs
@@ -190,7 +190,7 @@ mod tests {
}
#[test]
- fn test_read_manifest_entry_with_legacy_rust_field_order() {
+ fn test_read_manifest_entry_with_legacy_rust_schema() {
let mut schema: serde_json::Value =
serde_json::from_str(MANIFEST_ENTRY_SCHEMA).unwrap();
let fields = schema.as_array_mut().unwrap()[1]
.as_object_mut()
@@ -199,6 +199,16 @@ mod tests {
.unwrap()
.as_array_mut()
.unwrap();
+ let file = fields
+ .iter_mut()
+ .find(|field| field.get("name").and_then(|name| name.as_str()) ==
Some("_FILE"))
+ .unwrap()
+ .as_object_mut()
+ .unwrap();
+ let file_type = file.remove("type").unwrap();
+ file.insert("type".to_string(), serde_json::json!(["null",
file_type]));
+ file.insert("default".to_string(), serde_json::Value::Null);
+
let version = fields.remove(0);
fields.push(version);
let legacy_schema = serde_json::to_string(&schema).unwrap();