Was this page helpful?
Caution
You're viewing documentation for an unstable version of Scylla Rust Driver. Switch to the latest stable version.
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 SerializeRow
.
By default this can be a slice &[]
, a tuple ()
(max 16 elements) of values to send,
or a custom struct which derives from SerializeRow
.
A few examples:
// Empty slice means that there are no values to send
session.query_unpaged("INSERT INTO ks.tab (a) VALUES(1)", &[]).await?;
// Empty tuple/unit also means that there are no values to send
session.query_unpaged("INSERT INTO ks.tab (a) VALUES(1)", ()).await?;
// Sending three integers using a slice:
session
.query_unpaged("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_unpaged("INSERT INTO ks.tab (a, b) VALUES(?, ?)", (2_i32, "Some text"))
.await?;
// Sending an integer and a string using a named struct.
// Names of fields must match names of columns in request,
// but having them in the same order is not required.
// If the fields are in the same order, you can use attribute:
// `#[scylla(flavor = "enforce_order")]`
// in order to skip sorting the fields and just check if they
// are in the same order. See documentation of this macro
// for more information.
#[derive(SerializeRow)]
struct IntString {
a: i32,
b: String,
}
let int_string = IntString {
a: 42_i32,
b: "hello".to_owned(),
};
session
.query_unpaged("INSERT INTO ks.tab (a, b) VALUES(?, ?)", int_string)
.await?;
// You can use named bind markers in query if you want
// your names in struct to be different than column names.
#[derive(SerializeRow)]
struct IntStringCustom {
first_value: i32,
second_value: String,
}
let int_string_custom = IntStringCustom {
first_value: 42_i32,
second_value: "hello".to_owned(),
};
session
.query_unpaged("INSERT INTO ks.tab (a, b) VALUES(:first_value, :second_value)", int_string_custom)
.await?;
// Sending a single value as a tuple requires a trailing coma (Rust syntax):
session.query_unpaged("INSERT INTO ks.tab (a) VALUES(?)", (2_i32,)).await?;
// Each value can also be sent using a reference:
session
.query_unpaged("INSERT INTO ks.tab (a, b) VALUES(?, ?)", &(&2_i32, &"Some text"))
.await?;
// A map of named values can also be provided:
let mut vals: HashMap<&str, CqlValue> = HashMap::new();
vals.insert("avalue", CqlValue::Text("hello".to_string()));
vals.insert("bvalue", CqlValue::Int(17));
session
.query_unpaged("INSERT INTO ks.tab (a, b) VALUES(:avalue, :bvalue)", &vals)
.await?;
NULL
values¶Null values can be sent using Option<>
- sending a None
will make the value NULL
:
let null_i32: Option<i32> = None;
session
.query_unpaged("INSERT INTO ks.tab (a) VALUES(?)", (null_i32,))
.await?;
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:
use scylla::frame::value::{MaybeUnset, Unset};
// Inserting a null results in suboptimal performance
let null_i32: Option<i32> = None;
session
.query_unpaged("INSERT INTO ks.tab (a) VALUES(?)", (null_i32,))
.await?;
// Using MaybeUnset enum is better
let unset_i32: MaybeUnset<i32> = MaybeUnset::Unset;
session
.query_unpaged("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_unpaged("INSERT INTO ks.tab (a) VALUES(?)", (Unset,))
.await?;
See the issue for more information about Unset
See Data Types for instructions on sending other data types
Was this page helpful?