Query values
Query text is constant, but the values might change.
You can pass changing values to a query by specifying a list of variables as bound values.
Each ?
in query text will be filled with the matching value.
Never pass values by adding strings, this could lead to SQL Injection
Each list of values to send in a query must implement the trait ValueList
.
By default this can be a slice &[]
, a tuple ()
(max 16 elements) of values to send,
or a custom struct which derives from ValueList
.
A few examples:
#![allow(unused)] fn main() { extern crate scylla; use scylla::{Session, ValueList}; use std::error::Error; async fn check_only_compiles(session: &Session) -> Result<(), Box<dyn Error>> { // Empty slice means that there are no values to send session.query("INSERT INTO ks.tab (a) VALUES(1)", &[]).await?; // Empty tuple/unit also means that there are no values to send session.query("INSERT INTO ks.tab (a) VALUES(1)", ()).await?; // Sending three integers using a slice: session .query("INSERT INTO ks.tab (a, b, c) VALUES(?, ?, ?)", [1_i32, 2, 3].as_ref()) .await?; // Sending an integer and a string using a tuple session .query("INSERT INTO ks.tab (a, b) VALUES(?, ?)", (2_i32, "Some text")) .await?; // Sending an integer and a string using a named struct. // The values will be passed in the order from the struct definition #[derive(ValueList)] struct IntString { first_col: i32, second_col: String, } let int_string = IntString { first_col: 42_i32, second_col: "hello".to_owned(), }; session .query("INSERT INTO ks.tab (a, b) VALUES(?, ?)", int_string) .await?; // Sending a single value as a tuple requires a trailing coma (Rust syntax): session.query("INSERT INTO ks.tab (a) VALUES(?)", (2_i32,)).await?; // Each value can also be sent using a reference: session .query("INSERT INTO ks.tab (a, b) VALUES(?, ?)", &(&2_i32, &"Some text")) .await?; Ok(()) } }
NULL
values
Null values can be sent using Option<>
- sending a None
will make the value NULL
:
#![allow(unused)] fn main() { extern crate scylla; use scylla::Session; use std::error::Error; async fn check_only_compiles(session: &Session) -> Result<(), Box<dyn Error>> { let null_i32: Option<i32> = None; session .query("INSERT INTO ks.tab (a) VALUES(?)", (null_i32,)) .await?; Ok(()) } }
Unset
values
When performing an insert with values which might be NULL
, it's better to use Unset
.
Database treats inserting NULL
as a delete operation and will generate a tombstone.
Using Unset
results in better performance:
#![allow(unused)] fn main() { extern crate scylla; use scylla::Session; use std::error::Error; async fn check_only_compiles(session: &Session) -> Result<(), Box<dyn Error>> { use scylla::frame::value::{MaybeUnset, Unset}; // Inserting a null results in suboptimal performance let null_i32: Option<i32> = None; session .query("INSERT INTO ks.tab (a) VALUES(?)", (null_i32,)) .await?; // Using MaybeUnset enum is better let unset_i32: MaybeUnset<i32> = MaybeUnset::Unset; session .query("INSERT INTO ks.tab (a) VALUES(?)", (unset_i32,)) .await?; // If we are sure that a value should be unset we can simply use Unset session .query("INSERT INTO ks.tab (a) VALUES(?)", (Unset,)) .await?; Ok(()) } }
See the issue for more information about Unset
Other data types
See Data Types for instructions on sending other data types