pub trait RowLock: Dialect {
// Required method
fn lock_claim(
&self,
spec: &TableSpec<'_>,
shape: ClaimShape,
) -> Result<Statement, StatementError>;
}Expand description
The row lock form of a dialect: the claim that locks its rows until its transaction ends.
A table that declares neither #[field(locked_until)] nor advisory_lock takes its rows
this way. The claim selects the claimable rows under a lock, the handler runs while the
transaction holds them, and the settlement ends the transaction; after a crash the database
rolls back and the rows return at once. The transaction opens at the table’s isolation level,
with the statement Dialect::begin gives. A dialect implements this trait where its
database locks rows for a transaction, and a table in the row lock form does not compile
against a dialect that does not. Postgres and MySql
implement it; Sqlite does not, as its writer locks the whole database.
§Examples
use ruststream_sqlx_dialect::{
ClaimShape, Dialect, Param, RowLock, Statement, StatementError, TableSpec,
};
/// SQL Server, a database without a built-in dialect.
#[derive(Debug)]
pub struct Mssql;
// A table without `locked_until` or `advisory_lock` mounts on `Mssql`. The claim holds an
// update lock on each row it takes until its transaction ends, and skips the rows another claim
// holds.
impl RowLock for Mssql {
fn lock_claim(
&self,
_spec: &TableSpec<'_>,
shape: ClaimShape,
) -> Result<Statement, StatementError> {
let selected = match shape {
ClaimShape::Rows => "[job_id], [attempt], [payload]",
ClaimShape::Ids => "[job_id]",
ClaimShape::Roles => {
"[job_id] AS [id], [attempt] AS [attempt], [payload] AS [payload]"
}
};
Ok(Statement::new(
format!(
"SELECT TOP (@p1) {selected} FROM [email_jobs] \
WITH (UPDLOCK, READPAST, ROWLOCK) ORDER BY [job_id]"
),
[Param::Limit],
))
}
}Required Methods§
Sourcefn lock_claim(
&self,
spec: &TableSpec<'_>,
shape: ClaimShape,
) -> Result<Statement, StatementError>
fn lock_claim( &self, spec: &TableSpec<'_>, shape: ClaimShape, ) -> Result<Statement, StatementError>
The statement that claims up to Param::Limit rows of the
subscription’s group, in claim order, and locks them until the claim’s transaction ends.
A table with FIFO groups keeps one row of a group in work. Its claim takes the group’s
head, the first unfinished row of the group in claim order, and takes nothing while the
head is in work (another claim’s transaction holds it) or not yet due. It binds no
Param::Limit. The claim’s transaction first takes the group with
the statement fifo_guard gives and holds it until the delivery
settles, so a row that enters the group ahead of the head in work waits too.
§Errors
StatementError::FormMismatch for a table in another form. A dialect of the service’s
own that builds no claim for FIFO groups returns StatementError::UnsupportedFifo for a
table with them.
§Examples
use ruststream_sqlx_dialect::{
ClaimShape, Dialect, Param, RowLock, Statement, StatementError, TableSpec,
};
/// SQL Server, a database without a built-in dialect.
#[derive(Debug)]
pub struct Mssql;
impl RowLock for Mssql {
// The due rows of the subscription's group in `email_jobs`, in claim order. `UPDLOCK`
// keeps two claims apart until the transaction ends, `READPAST` skips the rows another
// claim holds, and `ROWLOCK` keeps the lock to the rows themselves.
fn lock_claim(
&self,
spec: &TableSpec<'_>,
_shape: ClaimShape,
) -> Result<Statement, StatementError> {
// This claim keeps no group in order.
if spec.is_fifo() {
return Err(StatementError::UnsupportedFifo { dialect: self.name() });
}
Ok(Statement::new(
"SELECT TOP (@p3) [job_id], [attempt], [payload] FROM [email_jobs] \
WITH (UPDLOCK, READPAST, ROWLOCK) \
WHERE [name] = @p1 AND [retry_after] <= @p2 \
ORDER BY [priority], [retry_after], [job_id]",
[Param::Group, Param::Now, Param::Limit],
))
}
}Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".