pub struct Session { /* private fields */ }
Expand description
Session
manages connections to the cluster and allows to execute CQL requests.
Implementations§
Source§impl Session
impl Session
Sourcepub async fn query_unpaged(
&self,
statement: impl Into<Statement>,
values: impl SerializeRow,
) -> Result<QueryResult, ExecutionError>
pub async fn query_unpaged( &self, statement: impl Into<Statement>, values: impl SerializeRow, ) -> Result<QueryResult, ExecutionError>
Sends a request to the database and receives a response.
Executes an unprepared CQL statement without paging, i.e. all results are received in a single response.
This is the easiest way to execute a CQL statement, but performance is worse than that of prepared statements.
It is discouraged to use this method with non-empty values argument (SerializeRow::is_empty()
trait method returns false). In such case, statement first needs to be prepared (on a single connection), so
driver will perform 2 round trips instead of 1. Please use Session::execute_unpaged()
instead.
As all results come in one response (no paging is done!), the memory footprint and latency may be huge for statements returning rows (i.e. SELECTs)! Prefer this method for non-SELECTs, and for SELECTs it is best to use paged requests:
- to receive multiple pages and transparently iterate through them, use query_iter.
- to manually receive multiple pages and iterate through them, use query_single_page.
See the book for more information
§Arguments
statement
- statement to be executed, can be just a&str
or theStatement
struct.values
- values bound to the statement, the easiest way is to use a tuple of bound values.
§Examples
// Insert an int and text into a table.
session
.query_unpaged(
"INSERT INTO ks.tab (a, b) VALUES(?, ?)",
(2_i32, "some text")
)
.await?;
// Read rows containing an int and text.
// Keep in mind that all results come in one response (no paging is done!),
// so the memory footprint and latency may be huge!
// To prevent that, use `Session::query_iter` or `Session::query_single_page`.
let query_rows = session
.query_unpaged("SELECT a, b FROM ks.tab", &[])
.await?
.into_rows_result()?;
for row in query_rows.rows()? {
// Parse row as int and text.
let (int_val, text_val): (i32, &str) = row?;
}
Sourcepub async fn query_single_page(
&self,
statement: impl Into<Statement>,
values: impl SerializeRow,
paging_state: PagingState,
) -> Result<(QueryResult, PagingStateResponse), ExecutionError>
pub async fn query_single_page( &self, statement: impl Into<Statement>, values: impl SerializeRow, paging_state: PagingState, ) -> Result<(QueryResult, PagingStateResponse), ExecutionError>
Queries a single page from the database, optionally continuing from a saved point.
It is discouraged to use this method with non-empty values argument (SerializeRow::is_empty()
trait method returns false). In such case, CQL statement first needs to be prepared (on a single connection), so
driver will perform 2 round trips instead of 1. Please use Session::execute_single_page()
instead.
§Arguments
statement
- statement to be executedvalues
- values bound to the statementpaging_state
- previously received paging state or PagingState::start()
§Example
use std::ops::ControlFlow;
use scylla::response::PagingState;
// Manual paging in a loop, unprepared statement.
let mut paging_state = PagingState::start();
loop {
let (res, paging_state_response) = session
.query_single_page("SELECT a, b, c FROM ks.tbl", &[], paging_state)
.await?;
// Do something with a single page of results.
for row in res
.into_rows_result()?
.rows::<(i32, &str)>()?
{
let (a, b) = row?;
}
match paging_state_response.into_paging_control_flow() {
ControlFlow::Break(()) => {
// No more pages to be fetched.
break;
}
ControlFlow::Continue(new_paging_state) => {
// Update paging state from the response, so that query
// will be resumed from where it ended the last time.
paging_state = new_paging_state;
}
}
}
Sourcepub async fn query_iter(
&self,
statement: impl Into<Statement>,
values: impl SerializeRow,
) -> Result<QueryPager, PagerExecutionError>
pub async fn query_iter( &self, statement: impl Into<Statement>, values: impl SerializeRow, ) -> Result<QueryPager, PagerExecutionError>
Execute an unprepared CQL statement with paging
This method will query all pages of the result\
Returns an async iterator (stream) over all received rows
Page size can be specified in the Statement
passed to the function
It is discouraged to use this method with non-empty values argument (SerializeRow::is_empty()
trait method returns false). In such case, statement first needs to be prepared (on a single connection), so
driver will initially perform 2 round trips instead of 1. Please use Session::execute_iter()
instead.
See the book for more information.
§Arguments
statement
- statement to be executed, can be just a&str
or theStatement
struct.values
- values bound to the statement, the easiest way is to use a tuple of bound values.
§Example
use futures::stream::StreamExt;
let mut rows_stream = session
.query_iter("SELECT a, b FROM ks.t", &[])
.await?
.rows_stream::<(i32, i32)>()?;
while let Some(next_row_res) = rows_stream.next().await {
let (a, b): (i32, i32) = next_row_res?;
println!("a, b: {}, {}", a, b);
}
Sourcepub async fn execute_unpaged(
&self,
prepared: &PreparedStatement,
values: impl SerializeRow,
) -> Result<QueryResult, ExecutionError>
pub async fn execute_unpaged( &self, prepared: &PreparedStatement, values: impl SerializeRow, ) -> Result<QueryResult, ExecutionError>
Execute a prepared statement. Requires a PreparedStatement
generated using Session::prepare
.
Performs an unpaged request, i.e. all results are received in a single response.
As all results come in one response (no paging is done!), the memory footprint and latency may be huge for statements returning rows (i.e. SELECTs)! Prefer this method for non-SELECTs, and for SELECTs it is best to use paged requests:
- to receive multiple pages and transparently iterate through them, use execute_iter.
- to manually receive multiple pages and iterate through them, use execute_single_page.
Prepared statements are much faster than unprepared statements:
- Database doesn’t need to parse the statement string upon each execution (only once)
- They are properly load balanced using token aware routing
Warning
For token/shard aware load balancing to work properly, all partition key values must be sent as bound values (see performance section).
See the book for more information.
§Arguments
prepared
- the prepared statement to execute, generated usingSession::prepare
values
- values bound to the statement, the easiest way is to use a tuple of bound values
§Example
use scylla::statement::prepared::PreparedStatement;
// Prepare the statement for later execution
let prepared: PreparedStatement = session
.prepare("INSERT INTO ks.tab (a) VALUES(?)")
.await?;
// Execute the prepared statement with some values, just like an unprepared statement.
let to_insert: i32 = 12345;
session.execute_unpaged(&prepared, (to_insert,)).await?;
Sourcepub async fn execute_single_page(
&self,
prepared: &PreparedStatement,
values: impl SerializeRow,
paging_state: PagingState,
) -> Result<(QueryResult, PagingStateResponse), ExecutionError>
pub async fn execute_single_page( &self, prepared: &PreparedStatement, values: impl SerializeRow, paging_state: PagingState, ) -> Result<(QueryResult, PagingStateResponse), ExecutionError>
Executes a prepared statement, restricting results to single page. Optionally continues fetching results from a saved point.
§Arguments
prepared
- a statement prepared with preparevalues
- values bound to the statementpaging_state
- continuation based on a paging state received from a previous paged query or None
§Example
use std::ops::ControlFlow;
use scylla::statement::unprepared::Statement;
use scylla::response::{PagingState, PagingStateResponse};
let paged_prepared = session
.prepare(
Statement::new("SELECT a, b FROM ks.tbl")
.with_page_size(100.try_into().unwrap()),
)
.await?;
// Manual paging in a loop, prepared statement.
let mut paging_state = PagingState::start();
loop {
let (res, paging_state_response) = session
.execute_single_page(&paged_prepared, &[], paging_state)
.await?;
// Do something with a single page of results.
for row in res
.into_rows_result()?
.rows::<(i32, &str)>()?
{
let (a, b) = row?;
}
match paging_state_response.into_paging_control_flow() {
ControlFlow::Break(()) => {
// No more pages to be fetched.
break;
}
ControlFlow::Continue(new_paging_state) => {
// Update paging continuation from the paging state, so that query
// will be resumed from where it ended the last time.
paging_state = new_paging_state;
}
}
}
Sourcepub async fn execute_iter(
&self,
prepared: impl Into<PreparedStatement>,
values: impl SerializeRow,
) -> Result<QueryPager, PagerExecutionError>
pub async fn execute_iter( &self, prepared: impl Into<PreparedStatement>, values: impl SerializeRow, ) -> Result<QueryPager, PagerExecutionError>
Execute a prepared statement with paging.
This method will query all pages of the result.\
Returns an async iterator (stream) over all received rows.
Page size can be specified in the PreparedStatement passed to the function.
See the book for more information.
§Arguments
prepared
- the prepared statement to execute, generated usingSession::prepare
values
- values bound to the statement, the easiest way is to use a tuple of bound values
§Example
use scylla::statement::prepared::PreparedStatement;
// Prepare the statement for later execution
let prepared: PreparedStatement = session
.prepare("SELECT a, b FROM ks.t")
.await?;
// Execute the statement and receive all pages
let mut rows_stream = session
.execute_iter(prepared, &[])
.await?
.rows_stream::<(i32, i32)>()?;
while let Some(next_row_res) = rows_stream.next().await {
let (a, b): (i32, i32) = next_row_res?;
println!("a, b: {}, {}", a, b);
}
Sourcepub async fn batch(
&self,
batch: &Batch,
values: impl BatchValues,
) -> Result<QueryResult, ExecutionError>
pub async fn batch( &self, batch: &Batch, values: impl BatchValues, ) -> Result<QueryResult, ExecutionError>
Execute a batch statement
Batch contains many unprepared
or prepared
statements which are executed at once
Batch doesn’t return any rows.
Batch values must contain values for each of the statements.
Avoid using non-empty values (SerializeRow::is_empty()
return false) for unprepared statements
inside the batch. Such statements will first need to be prepared, so the driver will need to
send (numer_of_unprepared_statements_with_values + 1) requests instead of 1 request, severly
affecting performance.
See the book for more information
§Arguments
batch
- Batch to be performedvalues
- List of values for each statement, it’s the easiest to use a tuple of tuples
§Example
use scylla::statement::batch::Batch;
let mut batch: Batch = Default::default();
// A statement with two bound values
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(?, ?)");
// A statement with one bound value
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(3, ?)");
// A statement with no bound values
batch.append_statement("INSERT INTO ks.tab(a, b) VALUES(5, 6)");
// Batch values is a tuple of 3 tuples containing values for each statement
let batch_values = ((1_i32, 2_i32), // Tuple with two values for the first statement
(4_i32,), // Tuple with one value for the second statement
()); // Empty tuple/unit for the third statement
// Run the batch
session.batch(&batch, batch_values).await?;
Source§impl Session
Represents a CQL session, which can be used to communicate
with the database
impl Session
Represents a CQL session, which can be used to communicate with the database
Sourcepub async fn connect(config: SessionConfig) -> Result<Self, NewSessionError>
pub async fn connect(config: SessionConfig) -> Result<Self, NewSessionError>
Estabilishes a CQL session with the database
Usually it’s easier to use SessionBuilder
instead of calling Session::connect
directly, because it’s more convenient.
§Arguments
config
- Connection configuration - known nodes, Compression, etc. Must contain at least one known node.
§Example
use scylla::client::session::{Session, SessionConfig};
use scylla::cluster::KnownNode;
let mut config = SessionConfig::new();
config.known_nodes.push(KnownNode::Hostname("127.0.0.1:9042".to_string()));
let session: Session = Session::connect(config).await?;
Sourcepub async fn prepare(
&self,
statement: impl Into<Statement>,
) -> Result<PreparedStatement, PrepareError>
pub async fn prepare( &self, statement: impl Into<Statement>, ) -> Result<PreparedStatement, PrepareError>
Prepares a statement on the server side and returns a prepared statement, which can later be used to perform more efficient requests.
Prepared statements are much faster than unprepared statements:
- Database doesn’t need to parse the statement string upon each execution (only once)
- They are properly load balanced using token aware routing
Warning
For token/shard aware load balancing to work properly, all partition key values must be sent as bound values (see performance section)
See the book for more information.
See the documentation of PreparedStatement
.
§Arguments
statement
- statement to prepare, can be just a&str
or theStatement
struct.
§Example
use scylla::statement::prepared::PreparedStatement;
// Prepare the statement for later execution
let prepared: PreparedStatement = session
.prepare("INSERT INTO ks.tab (a) VALUES(?)")
.await?;
// Execute the prepared statement with some values, just like an unprepared statement.
let to_insert: i32 = 12345;
session.execute_unpaged(&prepared, (to_insert,)).await?;
Sourcepub async fn prepare_batch(&self, batch: &Batch) -> Result<Batch, PrepareError>
pub async fn prepare_batch(&self, batch: &Batch) -> Result<Batch, PrepareError>
Prepares all statements within the batch and returns a new batch where every statement is prepared. /// # Example
use scylla::statement::batch::Batch;
// Create a batch statement with unprepared statements
let mut batch: Batch = Default::default();
batch.append_statement("INSERT INTO ks.simple_unprepared1 VALUES(?, ?)");
batch.append_statement("INSERT INTO ks.simple_unprepared2 VALUES(?, ?)");
// Prepare all statements in the batch at once
let prepared_batch: Batch = session.prepare_batch(&batch).await?;
// Specify bound values to use with each statement
let batch_values = ((1_i32, 2_i32),
(3_i32, 4_i32));
// Run the prepared batch
session.batch(&prepared_batch, batch_values).await?;
Sourcepub async fn use_keyspace(
&self,
keyspace_name: impl Into<String>,
case_sensitive: bool,
) -> Result<(), UseKeyspaceError>
pub async fn use_keyspace( &self, keyspace_name: impl Into<String>, case_sensitive: bool, ) -> Result<(), UseKeyspaceError>
Sends USE <keyspace_name>
request on all connections
This allows to write SELECT * FROM table
instead of SELECT * FROM keyspace.table
\
Note that even failed use_keyspace
can change currently used keyspace - the request is sent on all connections and
can overwrite previously used keyspace.
Call only one use_keyspace
at a time.
Trying to do two use_keyspace
requests simultaneously with different names
can end with some connections using one keyspace and the rest using the other.
See the book for more information
§Arguments
keyspace_name
- keyspace name to use, keyspace names can have up to 48 alphanumeric characters and contain underscorescase_sensitive
- if set to true the generated statement will put keyspace name in quotes
§Example
session
.query_unpaged("INSERT INTO my_keyspace.tab (a) VALUES ('test1')", &[])
.await?;
session.use_keyspace("my_keyspace", false).await?;
// Now we can omit keyspace name in the statement
session
.query_unpaged("INSERT INTO tab (a) VALUES ('test2')", &[])
.await?;
Sourcepub async fn refresh_metadata(&self) -> Result<(), MetadataError>
pub async fn refresh_metadata(&self) -> Result<(), MetadataError>
Manually trigger a metadata refresh
The driver will fetch current nodes in the cluster and update its metadata
Normally this is not needed, the driver should automatically detect all metadata changes in the cluster
Sourcepub fn get_cluster_state(&self) -> Arc<ClusterState>
pub fn get_cluster_state(&self) -> Arc<ClusterState>
Access cluster state visible by the driver.
Driver collects various information about network topology or schema. It can be read using this method.
Sourcepub async fn get_tracing_info(
&self,
tracing_id: &Uuid,
) -> Result<TracingInfo, TracingError>
pub async fn get_tracing_info( &self, tracing_id: &Uuid, ) -> Result<TracingInfo, TracingError>
Get TracingInfo
of a traced query performed earlier
See the book for more information about query tracing
Sourcepub fn get_keyspace(&self) -> Option<Arc<String>>
pub fn get_keyspace(&self) -> Option<Arc<String>>
Gets the name of the keyspace that is currently set, or None
if no
keyspace was set.
It will initially return the name of the keyspace that was set
in the session configuration, but calling use_keyspace
will update
it.
Note: the return value might be wrong if use_keyspace
was called
concurrently or it previously failed. It is also unspecified
if get_keyspace
is called concurrently with use_keyspace
.
pub async fn await_schema_agreement(&self) -> Result<Uuid, SchemaAgreementError>
pub async fn check_schema_agreement( &self, ) -> Result<Option<Uuid>, SchemaAgreementError>
Sourcepub fn get_default_execution_profile_handle(&self) -> &ExecutionProfileHandle
pub fn get_default_execution_profile_handle(&self) -> &ExecutionProfileHandle
Retrieves the handle to execution profile that is used by this session by default, i.e. when an executed statement does not define its own handle.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Session
impl !RefUnwindSafe for Session
impl Send for Session
impl Sync for Session
impl Unpin for Session
impl !UnwindSafe for Session
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more