Skip to content

Range starting with Bound::Excluded(&vec![]) causes BadValSize error (aka MDB_BAD_VALSIZE) #358

@jasonaowen

Description

@jasonaowen

Trying to take a range starting with Bound::Excluded(&vec![]) used to work, but no longer does.

Example code that worked in v0.11:

[dependencies]
heed = { version = "0.11", default-features = false, features = ["lmdb"] }
mktemp = "0.5.1"
fn main() {
    let temp_file = mktemp::Temp::new_dir().unwrap();
    let env = heed::EnvOpenOptions::new().open(temp_file).unwrap();
    let db: heed::UntypedDatabase = env.create_database(None).unwrap();

    let txn = env.read_txn().unwrap();
    let iter = db
        .range(
            &txn,
            &(
                std::ops::Bound::Excluded::<&[u8]>(&vec![]),
                std::ops::Bound::Unbounded::<&[u8]>,
            ),
        )
        .unwrap();
    for _ in iter {
        assert!(false, "This is unreachable");
    }
}

And example code for v0.22, showing the error:

[dependencies]
heed = { version = "0.22", default-features = false }
mktemp = "0.5.1"
use heed::types::Bytes;

fn main() {
    let temp_file = mktemp::Temp::new_dir().unwrap();
    let env = unsafe { heed::EnvOpenOptions::new().open(temp_file).unwrap() };
    let mut wtxn = env.write_txn().unwrap();
    let db: heed::Database<Bytes, Bytes> = env.create_database(&mut wtxn, None).unwrap();

    let txn = env.read_txn().unwrap();
    let iter = db
        .range(
            &txn,
            &(
                std::ops::Bound::Excluded::<&[u8]>(&vec![]),
                std::ops::Bound::Unbounded::<&[u8]>,
            ),
        )
        .unwrap();
    for i in iter {
        println!("This should be unreachable, but is an error: {i:?}");
        if let Err(heed::Error::Mdb(e)) = i {
            assert_eq!(e, heed::MdbError::BadValSize);
        } else {
            assert!(false, "This is unreachable");
        }
    }
}

This appears to be related to PR #212. In particular, this removed code:

Bound::Excluded(start) => {
advance_key(start);
let result = cursor.move_on_key_greater_than_or_equal_to(start);

fn advance_key(bytes: &mut Vec<u8>) {
match bytes.last_mut() {
Some(&mut 255) | None => bytes.push(0),

Passing an empty Vec<u8> in a Bound::Excluded was explicitly handled, but no longer is. Should the old behavior still work?

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions