Optional Features
Sibyl provides one optional opt-in feature - unsafe-direct-binds
.
By default Sibyl creates shadow buffers for arguments that are bound to IN
parameter placeholders. With unsafe-direct-binds
Sibyl instead binds arguments directly. This, of course, is somewhat more performant and conserves memory. However, unsafe-direct-binds
makes it possible to violate Rust's immutability of references when a reference is mistakenly bound to the OUT
or INOUT
placeholder.
Example
let stmt = session.prepare("
SELECT country_name
FROM hr.countries
WHERE country_id = :COUNTRY_ID
")?;
let row = stmt.query_single("UK")?.unwrap();
let name : String = row.get(0)?;
// note that the `name` is not declared mutable
let stmt = session.prepare("
BEGIN
SELECT country_name
INTO :COUNTRY_NAME
FROM hr.countries
WHERE country_id = :COUNTRY_ID
AND country_name != :COUNTRY_NAME;
END;
")?;
stmt.execute((
("COUNTRY_ID", "NL"),
("COUNTRY_NAME", &name),
// `:COUNTRY_NAME` is INOUT but `name` is bound only for reading
))?;
println!("country_name={name}");
Default (Safe) Binding
#[cfg(not(feature="unsafe-direct-binds"))]
// `name` has not changed despite the binding mistake
assert_eq!(name, "United Kingdom");
The OCI actually did change the value as values bound to OUT placeholders are always changed. However, that has happened in the shadow buffer that Sibyl created to bind the value, thus actual value in Rust was not affected.
Unsafe Direct Binding
The binding mistake allows unacceptable mutation of the bound value:
#[cfg(feature="unsafe-direct-binds")]
assert_eq!(name, "Netherlandsdom");
Note also that because the string was bound via a (read-only) reference Sibyl used read-only binding for it and thus the code that sets the String
length to match the loaded value was not executed. As the result the new name still has the last 3 characters from the original name.