Merge 'Fix 8-bit serial type to encoding' from Preston Thorpe

This PR fixes #666
Limbo was treating all single byte integers properly in `core/types.rs`,
but when converted in `sqlite3_ondisk`, it was losing the sign for 8 bit
integers, treating them all as unsigned. Sqlite3 specifies in their file
format that the `1` record serial type is "Value is an 8-bit twos-
complement integer."  https://www.sqlite.org/fileformat.html
We now properly match sqlite3's output
![image](https://github.com/user-attachments/assets/567960ca-
bfc6-4210-9a0e-ae4203a63add)
![image](https://github.com/user-
attachments/assets/ed4e709b-63ea-4de9-bbdc-a3f8b4dfd0f9)

Closes #667
This commit is contained in:
Pekka Enberg
2025-01-13 20:59:54 +02:00

View File

@@ -912,7 +912,7 @@ fn read_payload(unread: &[u8], payload_size: usize, pager: Rc<Pager>) -> (Vec<u8
#[derive(Debug, PartialEq)]
pub enum SerialType {
Null,
UInt8,
Int8, // 8-bit twos-complement integer: https://www.sqlite.org/fileformat.html
BEInt16,
BEInt24,
BEInt32,
@@ -931,7 +931,7 @@ impl TryFrom<u64> for SerialType {
fn try_from(value: u64) -> Result<Self> {
match value {
0 => Ok(Self::Null),
1 => Ok(Self::UInt8),
1 => Ok(Self::Int8),
2 => Ok(Self::BEInt16),
3 => Ok(Self::BEInt24),
4 => Ok(Self::BEInt32),
@@ -974,11 +974,12 @@ pub fn read_record(payload: &[u8]) -> Result<OwnedRecord> {
pub fn read_value(buf: &[u8], serial_type: &SerialType) -> Result<(OwnedValue, usize)> {
match *serial_type {
SerialType::Null => Ok((OwnedValue::Null, 0)),
SerialType::UInt8 => {
SerialType::Int8 => {
if buf.is_empty() {
crate::bail_corrupt_error!("Invalid UInt8 value");
}
Ok((OwnedValue::Integer(buf[0] as i64), 1))
let val = buf[0] as i8;
Ok((OwnedValue::Integer(val as i64), 1))
}
SerialType::BEInt16 => {
if buf.len() < 2 {
@@ -1377,7 +1378,7 @@ mod tests {
#[rstest]
#[case(0, SerialType::Null)]
#[case(1, SerialType::UInt8)]
#[case(1, SerialType::Int8)]
#[case(2, SerialType::BEInt16)]
#[case(3, SerialType::BEInt24)]
#[case(4, SerialType::BEInt32)]
@@ -1403,8 +1404,9 @@ mod tests {
#[rstest]
#[case(&[], SerialType::Null, OwnedValue::Null)]
#[case(&[255], SerialType::UInt8, OwnedValue::Integer(255))]
#[case(&[255], SerialType::Int8, OwnedValue::Integer(-1))]
#[case(&[0x12, 0x34], SerialType::BEInt16, OwnedValue::Integer(0x1234))]
#[case(&[0xFE], SerialType::Int8, OwnedValue::Integer(-2))]
#[case(&[0x12, 0x34, 0x56], SerialType::BEInt24, OwnedValue::Integer(0x123456))]
#[case(&[0x12, 0x34, 0x56, 0x78], SerialType::BEInt32, OwnedValue::Integer(0x12345678))]
#[case(&[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC], SerialType::BEInt48, OwnedValue::Integer(0x123456789ABC))]
@@ -1424,7 +1426,7 @@ mod tests {
}
#[rstest]
#[case(&[], SerialType::UInt8)]
#[case(&[], SerialType::Int8)]
#[case(&[0x12], SerialType::BEInt16)]
#[case(&[0x12, 0x34], SerialType::BEInt24)]
#[case(&[0x12, 0x34, 0x56], SerialType::BEInt32)]