Repository: scylladb/scylla-rust-driver
Pull request #402 (2022-02-18 08:14:18)

value: fix serialization of CqlValue::Empty
Serialization of CqlValue::Empty was implemented improperly. Instead of
writing a 4-byte zero integer, nothing was being written, as if the
empty value wasn't present at all in the value list. Now, it is
serialized as it should.

## Pre-review checklist

<!--
    Make sure you took care of the issues on the list.
    Put 'x' into those boxes which apply.
    You can also create the PR now and click on all relevant checkboxes.
    See CONTRIBUTING.md for more details.
-->

- [x] I have split my patch into logically separate commits.
- [x] All commit messages clearly explain what they change and why.
- [x] I added relevant tests for new features and bug fixes.
- [ ] All commits compile, pass static checks and pass test.
- [x] PR description sums up the changes and reasons why they should be introduced.
- [ ] I added appropriate `Fixes:` annotations to PR description.



Patch:
diff --git a/scylla/src/frame/response/result.rs b/scylla/src/frame/response/result.rs
index bc333d46..f1529998 100644
--- a/scylla/src/frame/response/result.rs
+++ b/scylla/src/frame/response/result.rs
@@ -1221,6 +1221,18 @@ mod tests {
             );
         }
     }
+
+    #[test]
+    fn test_serialize_empty() {
+        use crate::frame::value::Value;
+
+        let empty = CqlValue::Empty;
+        let mut v = Vec::new();
+        empty.serialize(&mut v).unwrap();
+
+        assert_eq!(v, vec![0, 0, 0, 0]);
+    }
+
     #[test]
     fn test_deserialize_empty_payload() {
         for (test_type, res_cql) in [
diff --git a/scylla/src/frame/value.rs b/scylla/src/frame/value.rs
index 0a4bf002..88576bfc 100644
--- a/scylla/src/frame/value.rs
+++ b/scylla/src/frame/value.rs
@@ -568,6 +568,11 @@ fn serialize_tuple<V: Value>(
     Ok(())
 }
 
+fn serialize_empty(buf: &mut Vec<u8>) -> Result<(), ValueTooBig> {
+    buf.put_i32(0);
+    Ok(())
+}
+
 impl Value for CqlValue {
     fn serialize(&self, buf: &mut Vec<u8>) -> Result<(), ValueTooBig> {
         match self {
@@ -602,7 +607,7 @@ impl Value for CqlValue {
             CqlValue::Uuid(u) => u.serialize(buf),
             CqlValue::Varint(v) => v.serialize(buf),
 
-            CqlValue::Empty => Ok(()),
+            CqlValue::Empty => serialize_empty(buf),
         }
     }
 }


Test patch:
diff --git a/scylla/src/frame/cql_types_test.rs b/scylla/src/frame/cql_types_test.rs
index 8d262739..ab434917 100644
--- a/scylla/src/frame/cql_types_test.rs
+++ b/scylla/src/frame/cql_types_test.rs
@@ -900,3 +900,42 @@ async fn test_udt_after_schema_update() {
         }
     );
 }
+
+#[tokio::test]
+async fn test_empty() {
+    let session: Session = init_test("empty_tests", "int").await;
+
+    session
+        .query(
+            "INSERT INTO empty_tests (id, val) VALUES (0, blobasint(0x))",
+            (),
+        )
+        .await
+        .unwrap();
+
+    let (empty,) = session
+        .query("SELECT val FROM empty_tests WHERE id = 0", ())
+        .await
+        .unwrap()
+        .first_row_typed::<(CqlValue,)>()
+        .unwrap();
+
+    assert_eq!(empty, CqlValue::Empty);
+
+    session
+        .query(
+            "INSERT INTO empty_tests (id, val) VALUES (1, ?)",
+            (CqlValue::Empty,),
+        )
+        .await
+        .unwrap();
+
+    let (empty,) = session
+        .query("SELECT val FROM empty_tests WHERE id = 1", ())
+        .await
+        .unwrap()
+        .first_row_typed::<(CqlValue,)>()
+        .unwrap();
+
+    assert_eq!(empty, CqlValue::Empty);
+}