pub struct Client { /* private fields */ }Expand description
A connection to SQL Server.
Connect once and reuse it; every statement travels over the same connection.
use tdsql::{Client, Config};
let mut client = Client::connect(&Config::new()
.host("localhost")
.database("master")
.auth("sa", "YourStrong!Passw0rd")
.trust_cert()).await?;
let rows = client.query("SELECT id, name FROM users WHERE id > @P1", &[&10i32]).await?;
for row in &rows {
let id: i32 = row.get("id");
let name: String = row.get("name");
println!("{id}: {name}");
}§Cancelling
Stop waiting for a request – drop its future, let a timeout or
select! give up on it, abort the task running it, drop a RowStream
early – and it is cancelled on the server too, so it stops holding the
connection, the server’s time and any locks it has taken. The connection
stays usable. A request still queued behind another never runs; one
already running is stopped where it is, even before it has sent anything
back, and the statements after it in the same batch don’t run.
Transaction control – begin, commit, rollback, savepoints – always runs,
whatever became of its future. And cancelling stops a statement, not the
transaction around it: work finished before the cancel stays done, as it
would if the statement had failed, so put statements that must stand or
fall together in a Transaction.
Implementations§
Source§impl Client
impl Client
Sourcepub async fn connect(config: &Config) -> Result<Self>
pub async fn connect(config: &Config) -> Result<Self>
Connect using this configuration.
Gives up after the configuration’s connect timeout, 15 seconds unless
set. A named instance given without a port (host\INSTANCE) is found
through SQL Server Browser, and a redirect to another server, as Azure
SQL’s gateway sends, is followed.
Sourcepub async fn connect_str(connection_string: &str) -> Result<Self>
pub async fn connect_str(connection_string: &str) -> Result<Self>
Connect using an ADO.NET-style connection string.
Sourcepub async fn query(
&mut self,
sql: &str,
params: &[&dyn ToSql],
) -> Result<Vec<Row>>
pub async fn query( &mut self, sql: &str, params: &[&dyn ToSql], ) -> Result<Vec<Row>>
Run a query and collect every row of the first result set.
Parameters are positional: @P1 is params[0].
Sourcepub async fn query_stream(
&mut self,
sql: &str,
params: &[&dyn ToSql],
) -> Result<RowStream<'_>>
pub async fn query_stream( &mut self, sql: &str, params: &[&dyn ToSql], ) -> Result<RowStream<'_>>
Run a query and receive the rows of its first result set as the server sends them, rather than all at once after the last one arrives.
Returns as soon as the server has described the columns, so a statement
the server rejects fails here, just as it would from
query. A failure partway through arrives as the
stream’s last item instead, after the rows that came before it.
The stream borrows the client until it is dropped; see RowStream for
what that holds up, and what happens if it is dropped early.
let mut rows = client
.query_stream("SELECT id, name FROM users WHERE id > @P1", &[&10i32])
.await?;
while let Some(row) = rows.try_next().await? {
let name: String = row.get("name");
println!("{name}");
}Sourcepub async fn query_one(
&mut self,
sql: &str,
params: &[&dyn ToSql],
) -> Result<Row>
pub async fn query_one( &mut self, sql: &str, params: &[&dyn ToSql], ) -> Result<Row>
Run a query expecting exactly one row.
Fails with Error::UnexpectedRowCount for any other count.
Sourcepub async fn query_opt(
&mut self,
sql: &str,
params: &[&dyn ToSql],
) -> Result<Option<Row>>
pub async fn query_opt( &mut self, sql: &str, params: &[&dyn ToSql], ) -> Result<Option<Row>>
Run a query expecting at most one row.
Fails with Error::UnexpectedRowCount if more than one comes back.
Sourcepub async fn query_scalar<T: FromSql>(
&mut self,
sql: &str,
params: &[&dyn ToSql],
) -> Result<T>
pub async fn query_scalar<T: FromSql>( &mut self, sql: &str, params: &[&dyn ToSql], ) -> Result<T>
Run a query and read the first column of the first row.
Use Option<T> as T to accept a NULL. Fails with
Error::UnexpectedRowCount if the query returns no rows.
Sourcepub async fn execute(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<u64>
pub async fn execute(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<u64>
Run a statement that returns no rows, and report how many rows it affected.
If the batch holds several statements, the counts are summed.
Sourcepub async fn batch(&mut self, sql: &str) -> Result<Vec<Row>>
pub async fn batch(&mut self, sql: &str) -> Result<Vec<Row>>
Run a SQL batch verbatim, with no parameters, and collect its rows.
Parameterised statements are sent as an RPC, and some statements —
CREATE PROCEDURE, CREATE VIEW, CREATE TRIGGER — must be the first
statement of their own batch, so they cannot go that route. Use this for
DDL, and execute or query for
everything else.
Because the SQL is sent verbatim, never interpolate untrusted input into it; use parameters instead.
client
.batch("CREATE PROCEDURE dbo.sp_demo AS BEGIN SELECT 1; END")
.await?;Sourcepub async fn batch_dataset(&mut self, sql: &str) -> Result<DataSet>
pub async fn batch_dataset(&mut self, sql: &str) -> Result<DataSet>
Run a SQL batch verbatim and collect every result set it produces.
Sourcepub async fn query_dataset(&mut self, command: &Command) -> Result<DataSet>
pub async fn query_dataset(&mut self, command: &Command) -> Result<DataSet>
Run a Command and collect every result set it produces.
This is the path for stored procedures and for batches that return more than one result set.
Sourcepub async fn execute_command(&mut self, command: &Command) -> Result<u64>
pub async fn execute_command(&mut self, command: &Command) -> Result<u64>
Run a Command for its row count rather than its rows.
Sourcepub async fn transaction(&mut self) -> Result<Transaction<'_>>
pub async fn transaction(&mut self) -> Result<Transaction<'_>>
Begin a transaction at READ COMMITTED, SQL Server’s default isolation
level.
The returned Transaction borrows this client, so nothing else can
use the connection until it is committed, rolled back, or dropped.
let mut tx = client.transaction().await?;
tx.execute("INSERT INTO orders (id) VALUES (@P1)", &[&1i32]).await?;
tx.commit().await?;Sourcepub async fn transaction_with_isolation(
&mut self,
level: IsolationLevel,
) -> Result<Transaction<'_>>
pub async fn transaction_with_isolation( &mut self, level: IsolationLevel, ) -> Result<Transaction<'_>>
Begin a transaction at an explicit isolation level.
Once it ends, the connection goes back to READ COMMITTED.