This is an automated email from the ASF dual-hosted git repository.

mgrigorov pushed a commit to branch branch-1.11
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/branch-1.11 by this push:
     new 82fa91cde AVRO-3965: [Rust] Default values for fixed can be longer 
than size (#2907)
82fa91cde is described below

commit 82fa91cdeb8178568d19924d7dc25e9ab42ae601
Author: Martin Grigorov <[email protected]>
AuthorDate: Wed May 15 10:38:37 2024 +0300

    AVRO-3965: [Rust] Default values for fixed can be longer than size (#2907)
    
    Return an error if the default value's length is not the same as the
    specified size of a Fixed schema
    
    Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
    (cherry picked from commit 0661bfe71836be253626e1c85d7c6c12a48fe667)
---
 lang/rust/avro/src/decode.rs               |  4 +++
 lang/rust/avro/src/encode.rs               |  1 +
 lang/rust/avro/src/error.rs                |  3 ++
 lang/rust/avro/src/schema.rs               | 51 ++++++++++++++++++++++++++++--
 lang/rust/avro/src/schema_compatibility.rs |  2 ++
 lang/rust/avro/src/schema_equality.rs      |  2 ++
 lang/rust/avro/src/types.rs                |  5 +++
 lang/rust/avro/src/writer.rs               |  2 ++
 8 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/lang/rust/avro/src/decode.rs b/lang/rust/avro/src/decode.rs
index 41c3f24ab..9c685e9a8 100644
--- a/lang/rust/avro/src/decode.rs
+++ b/lang/rust/avro/src/decode.rs
@@ -149,6 +149,7 @@ pub(crate) fn decode_internal<R: Read, S: Borrow<Schema>>(
                         name: "uuid".into(),
                         aliases: None,
                         doc: None,
+                        default: None,
                         attributes: Default::default(),
                     }),
                     names,
@@ -419,6 +420,7 @@ mod tests {
             doc: None,
             name: Name::new("decimal")?,
             aliases: None,
+            default: None,
             attributes: Default::default(),
         }));
         let schema = Schema::Decimal(DecimalSchema {
@@ -448,6 +450,7 @@ mod tests {
             name: Name::new("decimal")?,
             aliases: None,
             doc: None,
+            default: None,
             attributes: Default::default(),
         }));
         let schema = Schema::Decimal(DecimalSchema {
@@ -893,6 +896,7 @@ mod tests {
             name: "uuid".into(),
             aliases: None,
             doc: None,
+            default: None,
             attributes: Default::default(),
         });
         let value = 
Value::Uuid(Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000")?);
diff --git a/lang/rust/avro/src/encode.rs b/lang/rust/avro/src/encode.rs
index a7d34a4f5..214673ec9 100644
--- a/lang/rust/avro/src/encode.rs
+++ b/lang/rust/avro/src/encode.rs
@@ -901,6 +901,7 @@ pub(crate) mod tests {
             name: "uuid".into(),
             aliases: None,
             doc: None,
+            default: None,
             attributes: Default::default(),
         });
         let value = 
Value::Uuid(Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000")?);
diff --git a/lang/rust/avro/src/error.rs b/lang/rust/avro/src/error.rs
index e46a9975c..b436f403f 100644
--- a/lang/rust/avro/src/error.rs
+++ b/lang/rust/avro/src/error.rs
@@ -370,6 +370,9 @@ pub enum Error {
     #[error("Fixed schema has no `size`")]
     GetFixedSizeField,
 
+    #[error("Fixed schema's default value length ({0}) does not match its size 
({1})")]
+    FixedDefaultLenSizeMismatch(usize, u64),
+
     #[error("Failed to compress with flate")]
     DeflateCompress(#[source] std::io::Error),
 
diff --git a/lang/rust/avro/src/schema.rs b/lang/rust/avro/src/schema.rs
index 3be37cd27..e3031f8fb 100644
--- a/lang/rust/avro/src/schema.rs
+++ b/lang/rust/avro/src/schema.rs
@@ -817,6 +817,8 @@ pub struct FixedSchema {
     pub doc: Documentation,
     /// The size of the fixed schema
     pub size: usize,
+    /// An optional default symbol used for compatibility
+    pub default: Option<String>,
     /// The custom attributes of the schema
     pub attributes: BTreeMap<String, Value>,
 }
@@ -1832,6 +1834,18 @@ impl Parser {
             None => Err(Error::GetFixedSizeField),
         }?;
 
+        let default = complex.get("default").and_then(|v| match &v {
+            Value::String(ref default) => Some(default.clone()),
+            _ => None,
+        });
+
+        if default.is_some() {
+            let len = default.clone().unwrap().len();
+            if len != size as usize {
+                return Err(Error::FixedDefaultLenSizeMismatch(len, size));
+            }
+        }
+
         let fully_qualified_name = Name::parse(complex, enclosing_namespace)?;
         let aliases = fix_aliases_namespace(complex.aliases(), 
&fully_qualified_name.namespace);
 
@@ -1840,6 +1854,7 @@ impl Parser {
             aliases: aliases.clone(),
             doc,
             size: size as usize,
+            default,
             attributes: self.get_custom_attributes(complex, vec!["size"]),
         });
 
@@ -2080,6 +2095,7 @@ impl Serialize for Schema {
                     aliases: None,
                     doc: None,
                     size: 12,
+                    default: None,
                     attributes: Default::default(),
                 });
                 map.serialize_entry("type", &inner)?;
@@ -3192,6 +3208,7 @@ mod tests {
                         aliases: None,
                         doc: None,
                         size: 456,
+                        default: None,
                         attributes: Default::default(),
                     }),
                     order: RecordFieldOrder::Ascending,
@@ -3211,6 +3228,7 @@ mod tests {
                         aliases: None,
                         doc: None,
                         size: 456,
+                        default: None,
                         attributes: Default::default(),
                     }),
                     order: RecordFieldOrder::Ascending,
@@ -3285,7 +3303,8 @@ mod tests {
             name: Name::new("test")?,
             aliases: None,
             doc: None,
-            size: 16usize,
+            size: 16_usize,
+            default: None,
             attributes: Default::default(),
         });
 
@@ -3304,7 +3323,8 @@ mod tests {
             name: Name::new("test")?,
             aliases: None,
             doc: Some(String::from("FixedSchema documentation")),
-            size: 16usize,
+            size: 16_usize,
+            default: None,
             attributes: Default::default(),
         });
 
@@ -6254,6 +6274,7 @@ mod tests {
             aliases: None,
             doc: None,
             size: 1,
+            default: None,
             attributes: attributes.clone(),
         });
         let serialized = serde_json::to_string(&schema)?;
@@ -6378,11 +6399,12 @@ mod tests {
                 aliases: None,
                 doc: None,
                 size: 6,
+                default: None,
                 attributes: BTreeMap::from([("logicalType".to_string(), 
"uuid".into())]),
             })
         );
         assert_logged(
-            r#"Ignoring uuid logical type for a Fixed schema because its size 
(6) is not 16! Schema: Fixed(FixedSchema { name: Name { name: "FixedUUID", 
namespace: None }, aliases: None, doc: None, size: 6, attributes: 
{"logicalType": String("uuid")} })"#,
+            r#"Ignoring uuid logical type for a Fixed schema because its size 
(6) is not 16! Schema: Fixed(FixedSchema { name: Name { name: "FixedUUID", 
namespace: None }, aliases: None, doc: None, size: 6, default: None, 
attributes: {"logicalType": String("uuid")} })"#,
         );
 
         Ok(())
@@ -6522,6 +6544,7 @@ mod tests {
                 aliases: None,
                 doc: None,
                 size: 16,
+                default: None,
                 attributes: Default::default(),
             })),
         });
@@ -6706,4 +6729,26 @@ mod tests {
 
         Ok(())
     }
+
+    #[test]
+    fn avro_3965_fixed_schema_with_default_bigger_than_size() -> TestResult {
+        match Schema::parse_str(
+            r#"{
+                "type": "fixed",
+                "name": "test",
+                "size": 1,
+                "default": "123456789"
+               }"#,
+        ) {
+            Ok(_schema) => panic!("Must fail!"),
+            Err(err) => {
+                assert_eq!(
+                    err.to_string(),
+                    "Fixed schema's default value length (9) does not match 
its size (1)"
+                );
+            }
+        }
+
+        Ok(())
+    }
 }
diff --git a/lang/rust/avro/src/schema_compatibility.rs 
b/lang/rust/avro/src/schema_compatibility.rs
index 5681dde10..63c1ca847 100644
--- a/lang/rust/avro/src/schema_compatibility.rs
+++ b/lang/rust/avro/src/schema_compatibility.rs
@@ -393,6 +393,7 @@ impl SchemaCompatibility {
                         aliases: _,
                         doc: _w_doc,
                         size: w_size,
+                        default: _w_default,
                         attributes: _,
                     }) = writers_schema
                     {
@@ -401,6 +402,7 @@ impl SchemaCompatibility {
                             aliases: _,
                             doc: _r_doc,
                             size: r_size,
+                            default: _r_default,
                             attributes: _,
                         }) = readers_schema
                         {
diff --git a/lang/rust/avro/src/schema_equality.rs 
b/lang/rust/avro/src/schema_equality.rs
index ae90c3f3f..c9eaa2a11 100644
--- a/lang/rust/avro/src/schema_equality.rs
+++ b/lang/rust/avro/src/schema_equality.rs
@@ -424,6 +424,7 @@ mod tests {
             name: Name::from("fixed"),
             doc: None,
             size: 10,
+            default: None,
             aliases: None,
             attributes: BTreeMap::new(),
         });
@@ -434,6 +435,7 @@ mod tests {
             name: Name::from("fixed"),
             doc: None,
             size: 10,
+            default: None,
             aliases: None,
             attributes: BTreeMap::new(),
         });
diff --git a/lang/rust/avro/src/types.rs b/lang/rust/avro/src/types.rs
index e172a5fb8..cb19d1da0 100644
--- a/lang/rust/avro/src/types.rs
+++ b/lang/rust/avro/src/types.rs
@@ -1367,6 +1367,7 @@ mod tests {
             name: Name::new("some_fixed").unwrap(),
             aliases: None,
             doc: None,
+            default: None,
             attributes: Default::default(),
         });
 
@@ -1722,6 +1723,7 @@ Field with name '"b"' is not a member of the map items"#,
                     aliases: None,
                     size: 20,
                     doc: None,
+                    default: None,
                     attributes: Default::default(),
                 }))
             }))
@@ -3020,6 +3022,7 @@ Field with name '"b"' is not a member of the map items"#,
                 aliases: None,
                 doc: None,
                 size: 3,
+                default: None,
                 attributes: Default::default()
             }))?,
             Value::Fixed(3, vec![97, 98, 99])
@@ -3032,6 +3035,7 @@ Field with name '"b"' is not a member of the map items"#,
                 aliases: None,
                 doc: None,
                 size: 3,
+                default: None,
                 attributes: Default::default()
             }))
             .is_err(),);
@@ -3043,6 +3047,7 @@ Field with name '"b"' is not a member of the map items"#,
                 aliases: None,
                 doc: None,
                 size: 3,
+                default: None,
                 attributes: Default::default()
             }))
             .is_err(),);
diff --git a/lang/rust/avro/src/writer.rs b/lang/rust/avro/src/writer.rs
index dc6fd55e8..90bb2da4c 100644
--- a/lang/rust/avro/src/writer.rs
+++ b/lang/rust/avro/src/writer.rs
@@ -790,6 +790,7 @@ mod tests {
             aliases: None,
             doc: None,
             size,
+            default: None,
             attributes: Default::default(),
         });
         let value = vec![0u8; size];
@@ -830,6 +831,7 @@ mod tests {
             aliases: None,
             doc: None,
             size: 12,
+            default: None,
             attributes: Default::default(),
         });
         let value = Value::Duration(Duration::new(

Reply via email to