Skip to main content

Client

Struct Client 

Source
pub struct Client<S: AsyncRead + AsyncWrite + Unpin + Send> { /* private fields */ }
Expand description

Client is the main entry point to the SQL Server, providing query execution capabilities.

A Client is created using the Config, defining the needed connection options and capabilities.

§Example

use tokio_util::compat::TokioAsyncWriteCompatExt;

let mut config = Config::new();

config.host("0.0.0.0");
config.port(1433);
config.authentication(AuthMethod::sql_server("SA", "<Mys3cureP4ssW0rD>"));

let tcp = tokio::net::TcpStream::connect(config.get_addr()).await?;
tcp.set_nodelay(true)?;
// Client is ready to use.
let client = tiberius::Client::connect(config, tcp.compat_write()).await?;

§Cancellation safety

A single Client drives one connection and one request at a time. If a query/execute/simple_query future — or the result stream it returns — is dropped before the request has been sent in full and the response fully consumed (for example under a tokio::time::timeout or a select! branch that loses the race), the connection may be left mid-message and out of sync with the server. A cancelled write is detected and any further use of that connection fails cleanly; a result stream dropped mid-response cannot be recovered. In both cases the safe course is to drop the Client and open a new connection (a connection pool should discard the connection on error) rather than reuse it.

Implementations§

Source§

impl<S: AsyncRead + AsyncWrite + Unpin + Send> Client<S>

Source

pub async fn connect(config: Config, tcp_stream: S) -> Result<Client<S>>

Uses an instance of Config to specify the connection options required to connect to the database using an established tcp connection

Note: tcp_stream is a connected stream, so some parts of the Config (such as multi-subnet failover, which selects between resolved addresses) must be handled while establishing that stream, outside of this constructor.

Source

pub async fn execute<'a>( &mut self, query: impl Into<Cow<'a, str>>, params: &[&dyn ToSql], ) -> Result<ExecuteResult>

Executes SQL statements in the SQL Server, returning the number rows affected. Useful for INSERT, UPDATE and DELETE statements. The query can define the parameter placement by annotating them with @PN, where N is the index of the parameter, starting from 1. If executing multiple queries at a time, delimit them with ; and refer to ExecuteResult how to get results for the separate queries.

For mapping of Rust types when writing, see the documentation for ToSql. For reading data from the database, see the documentation for FromSql.

This API is not quite suitable for dynamic query parameters. In these cases using a Query object might be easier.

§Example
let results = client
    .execute(
        "INSERT INTO ##Test (id) VALUES (@P1), (@P2), (@P3)",
        &[&1i32, &2i32, &3i32],
    )
    .await?;
Source

pub async fn query<'a, 'b>( &'a mut self, query: impl Into<Cow<'b, str>>, params: &'b [&'b dyn ToSql], ) -> Result<QueryStream<'a>>
where 'a: 'b,

Executes SQL statements in the SQL Server, returning resulting rows. Useful for SELECT statements. The query can define the parameter placement by annotating them with @PN, where N is the index of the parameter, starting from 1. If executing multiple queries at a time, delimit them with ; and refer to QueryStream on proper stream handling.

For mapping of Rust types when writing, see the documentation for ToSql. For reading data from the database, see the documentation for FromSql.

This API can be cumbersome for dynamic query parameters. In these cases, if fighting too much with the compiler, using a Query object might be easier.

§Example
let stream = client
    .query(
        "SELECT @P1, @P2, @P3",
        &[&1i32, &2i32, &3i32],
    )
    .await?;
Source

pub async fn simple_query<'a, 'b>( &'a mut self, query: impl Into<Cow<'b, str>>, ) -> Result<QueryStream<'a>>
where 'a: 'b,

Execute multiple queries, delimited with ; and return multiple result sets; one for each query.

§Example
let row = client.simple_query("SELECT 1 AS col").await?.into_row().await?.unwrap();
assert_eq!(Some(1i32), row.get("col"));
§Warning

Do not use this with any user specified input. Please resort to prepared statements using the query method.

Source

pub async fn bulk_insert<'a>( &'a mut self, table: &'a str, ) -> Result<BulkLoadRequest<'a, S>>

Execute a BULK INSERT statement, efficiently storing a large number of rows to a specified table. Note: make sure the input row follows the same schema as the table, otherwise calling send() will return an error.

This is equivalent to calling bulk_insert("table_name", &["*"]) to merge all of a tables columns.

§Example
let create_table = r#"
    CREATE TABLE ##bulk_test (
        id INT IDENTITY PRIMARY KEY,
        val INT NOT NULL
    )
"#;

client.simple_query(create_table).await?;

// Start the bulk insert with the client.
let mut req = client.bulk_insert("##bulk_test").await?;

for i in [0i32, 1i32, 2i32] {
    let row = (i).into_row();

    // The request will handle flushing to the wire in an optimal way,
    // balancing between memory usage and IO performance.
    req.send(row).await?;
}

// The request must be finalized.
let res = req.finalize().await?;
assert_eq!(3, res.total());
Source

pub async fn bulk_insert_columns<'a>( &'a mut self, table: &'a str, columns: &'a [&'a str], ) -> Result<BulkLoadRequest<'a, S>>

Execute a BULK INSERT statement, efficiently storing a large number of rows to a specified table. Note: make sure the input row follows the same schema as the column list, otherwise calling send() will return an error.

§Example
let create_table = r#"
    CREATE TABLE ##bulk_test_columns (
        id INT IDENTITY PRIMARY KEY,
        foo INT NOT NULL,
        bar FLOAT NOT NULL
    )
"#;

client.simple_query(create_table).await?;

// Start the bulk insert with the client.
let mut req = client.bulk_insert_columns("##bulk_test_columns", &["foo", "bar"]).await?;

for (i, j) in [(0i32, 0f64), (1i32, 1f64), (2i32, 2f64)] {
    let row = (i, j).into_row();

    // The request will handle flushing to the wire in an optimal way,
    // balancing between memory usage and IO performance.
    req.send(row).await?;
}

// The request must be finalized.
let res = req.finalize().await?;
assert_eq!(3, res.total());
Source

pub async fn column_metadata( &mut self, table: &str, columns: &[&str], ) -> Result<Vec<MetaDataColumn<'static>>>

Retrieve the column metadata for a set of columns of a table, including the column names, types (with their size, precision and scale) and flags such as nullability and whether a column is an identity column.

Pass &["*"] as columns to return the metadata for every column of the table.

let meta = client.column_metadata("some_table", &["*"]).await?;
assert!(meta[0].base().is_identity());
Source

pub async fn cancel_query(&mut self) -> Result<()>

Sends a TDS Attention signal to the server (packet type 0x06, MS-TDS section 2.2.1.6) to cancel the request that is currently in flight on this connection, and drains the acknowledging token stream so the connection can be reused for further queries.

The server responds to the Attention signal by aborting the running batch or RPC and returning a DONE token with the DONE_ATTN status bit set. This method waits for that acknowledgement before returning, discarding any remaining rows or tokens from the cancelled request.

§Query cancellation and futures

Dropping a query, execute or simple_query future (for example when a tokio::time::timeout elapses or a select! branch is cancelled) stops the client from polling the stream, but it does not tell the server to stop working on the request. To actually cancel the in-flight work on the server, keep the Client and call cancel_query on it. Because cancel_query borrows the client mutably, it can only be issued once the borrowing result stream has been dropped — typically from a separate task holding the client, or after a cancelled/timed-out future has released its borrow.

Source

pub async fn close(self) -> Result<()>

Closes this database connection explicitly.

Source

pub async fn begin_transaction(&mut self) -> Result<()>

Begins a new transaction using a Transaction Manager request (TM_BEGIN_XACT, MS-TDS 2.2.6.8) instead of a BEGIN TRAN T-SQL batch.

On success the server replies with a BeginTransaction environment change token whose descriptor is stored in the connection context and automatically attached to subsequent requests, scoping them to the transaction. Commit the work with commit_transaction or discard it with rollback_transaction.

The transaction uses the server’s default isolation level. Use begin_transaction_with_isolation to request a specific one.

Source

pub async fn begin_transaction_with_isolation( &mut self, isolation_level: IsolationLevel, ) -> Result<()>

Begins a new transaction with an explicit isolation level using a Transaction Manager request (TM_BEGIN_XACT, MS-TDS 2.2.6.8).

See begin_transaction for details on transaction scoping.

Source

pub async fn commit_transaction(&mut self) -> Result<()>

Commits the active transaction using a Transaction Manager request (TM_COMMIT_XACT, MS-TDS 2.2.6.8).

After a successful commit the connection is no longer scoped to a transaction.

Source

pub async fn rollback_transaction(&mut self) -> Result<()>

Rolls back the active transaction using a Transaction Manager request (TM_ROLLBACK_XACT, MS-TDS 2.2.6.8).

After a successful rollback the connection is no longer scoped to a transaction.

Source

pub async fn save_transaction<'a>( &mut self, name: impl Into<Cow<'a, str>>, ) -> Result<()>

Creates a named savepoint in the active transaction using a Transaction Manager request (TM_SAVE_XACT, MS-TDS 2.2.6.8).

The savepoint can later be targeted by a T-SQL ROLLBACK TRANSACTION <name> to undo work performed after it while keeping the surrounding transaction open.

Trait Implementations§

Source§

impl<S: Debug + AsyncRead + AsyncWrite + Unpin + Send> Debug for Client<S>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<S> Freeze for Client<S>
where Connection<S>: Freeze,

§

impl<S> RefUnwindSafe for Client<S>
where Connection<S>: RefUnwindSafe,

§

impl<S> Send for Client<S>
where Connection<S>: Send,

§

impl<S> Sync for Client<S>
where Connection<S>: Sync,

§

impl<S> Unpin for Client<S>
where Connection<S>: Unpin,

§

impl<S> UnsafeUnpin for Client<S>
where Connection<S>: UnsafeUnpin,

§

impl<S> UnwindSafe for Client<S>
where Connection<S>: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more