Skip to content

Commit db55016

Browse files
committed
Implement support for "FOR UPDATE" modifiers
Format Add test Add compile test Fix compile fail test Add a second compile test Review changes Fix compile tests Remove error case Fix tests Implement for no key update Add test to check insert is blocked by for update Update for_update_clause.rs Update select.rs Implement "FOR SHARE" clause Fix rename Update mysql impls
1 parent a6b00b3 commit db55016

15 files changed

Lines changed: 845 additions & 99 deletions

File tree

diesel/src/expression/array_comparison.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ pub trait MaybeEmpty {
129129
fn is_empty(&self) -> bool;
130130
}
131131

132-
impl<ST, S, F, W, O, L, Of, G, FU> AsInExpression<ST> for SelectStatement<S, F, W, O, L, Of, G, FU>
132+
impl<ST, S, F, W, O, L, Of, G, LC> AsInExpression<ST> for SelectStatement<S, F, W, O, L, Of, G, LC>
133133
where
134134
Subselect<Self, ST>: Expression<SqlType = ST>,
135135
Self: SelectQuery<SqlType = ST>,

diesel/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,21 @@ pub mod helper_types {
225225
/// Represents the return type of `.for_update()`
226226
pub type ForUpdate<Source> = <Source as ForUpdateDsl>::Output;
227227

228+
/// Represents the return type of `.for_no_key_update()`
229+
pub type ForNoKeyUpdate<Source> = <Source as ForNoKeyUpdateDsl>::Output;
230+
231+
/// Represents the return type of `.for_share()`
232+
pub type ForShare<Source> = <Source as ForShareDsl>::Output;
233+
234+
/// Represents the return type of `.for_key_share()`
235+
pub type ForKeyShare<Source> = <Source as ForKeyShareDsl>::Output;
236+
237+
/// Represents the return type of `.skip_locked()`
238+
pub type SkipLocked<Source> = <Source as SkipLockedDsl>::Output;
239+
240+
/// Represents the return type of `.no_wait()`
241+
pub type NoWait<Source> = <Source as NoWaitDsl>::Output;
242+
228243
/// Represents the return type of `.find(pk)`
229244
pub type Find<Source, PK> = <Source as FindDsl<PK>>::Output;
230245

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,38 @@
11
use mysql::Mysql;
22
use query_builder::{AstPass, QueryFragment};
3-
use query_builder::for_update_clause::ForUpdateClause;
3+
use query_builder::locking_clause::{ForUpdate, ForShare, NoModifier, NoWait, SkipLocked};
44
use result::QueryResult;
55

6-
impl QueryFragment<Mysql> for ForUpdateClause {
6+
impl QueryFragment<Mysql> for ForUpdate {
77
fn walk_ast(&self, mut out: AstPass<Mysql>) -> QueryResult<()> {
88
out.push_sql(" FOR UPDATE");
99
Ok(())
1010
}
1111
}
12+
13+
impl QueryFragment<Mysql> for ForShare {
14+
fn walk_ast(&self, mut out: AstPass<Mysql>) -> QueryResult<()> {
15+
out.push_sql(" FOR SHARE");
16+
Ok(())
17+
}
18+
}
19+
20+
impl QueryFragment<Mysql> for NoModifier {
21+
fn walk_ast(&self, _out: AstPass<Mysql>) -> QueryResult<()> {
22+
Ok(())
23+
}
24+
}
25+
26+
impl QueryFragment<Mysql> for SkipLocked {
27+
fn walk_ast(&self, mut out: AstPass<Mysql>) -> QueryResult<()> {
28+
out.push_sql(" SKIP LOCKED");
29+
Ok(())
30+
}
31+
}
32+
33+
impl QueryFragment<Mysql> for NoWait {
34+
fn walk_ast(&self, mut out: AstPass<Mysql>) -> QueryResult<()> {
35+
out.push_sql(" NOWAIT");
36+
Ok(())
37+
}
38+
}

diesel/src/pg/query_builder/distinct_on.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ where
3939
self.limit,
4040
self.offset,
4141
self.group_by,
42-
self.for_update,
42+
self.locking,
4343
)
4444
}
4545
}
Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,52 @@
11
use pg::Pg;
22
use query_builder::{AstPass, QueryFragment};
3-
use query_builder::for_update_clause::ForUpdateClause;
3+
use query_builder::locking_clause::{ForUpdate, ForKeyShare, ForNoKeyUpdate, ForShare, NoModifier, NoWait, SkipLocked};
44
use result::QueryResult;
55

6-
impl QueryFragment<Pg> for ForUpdateClause {
6+
impl QueryFragment<Pg> for ForUpdate {
77
fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
88
out.push_sql(" FOR UPDATE");
99
Ok(())
1010
}
1111
}
12+
13+
impl QueryFragment<Pg> for ForNoKeyUpdate {
14+
fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
15+
out.push_sql(" FOR NO KEY UPDATE");
16+
Ok(())
17+
}
18+
}
19+
20+
impl QueryFragment<Pg> for ForShare {
21+
fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
22+
out.push_sql(" FOR SHARE");
23+
Ok(())
24+
}
25+
}
26+
27+
impl QueryFragment<Pg> for ForKeyShare {
28+
fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
29+
out.push_sql(" FOR KEY SHARE");
30+
Ok(())
31+
}
32+
}
33+
34+
impl QueryFragment<Pg> for NoModifier {
35+
fn walk_ast(&self, _out: AstPass<Pg>) -> QueryResult<()> {
36+
Ok(())
37+
}
38+
}
39+
40+
impl QueryFragment<Pg> for SkipLocked {
41+
fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
42+
out.push_sql(" SKIP LOCKED");
43+
Ok(())
44+
}
45+
}
46+
47+
impl QueryFragment<Pg> for NoWait {
48+
fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
49+
out.push_sql(" NOWAIT");
50+
Ok(())
51+
}
52+
}

diesel/src/query_builder/for_update_clause.rs

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use backend::Backend;
2+
use query_builder::{AstPass, QueryFragment};
3+
use result::QueryResult;
4+
5+
#[derive(Debug, Clone, Copy, QueryId)]
6+
pub struct NoLockingClause;
7+
8+
impl<DB: Backend> QueryFragment<DB> for NoLockingClause {
9+
fn walk_ast(&self, _: AstPass<DB>) -> QueryResult<()> {
10+
Ok(())
11+
}
12+
}
13+
14+
#[derive(Debug, Clone, Copy, QueryId)]
15+
pub struct LockingClause<LockMode = ForUpdate, Modifier = NoModifier> {
16+
pub(crate) lock_mode: LockMode,
17+
modifier: Modifier,
18+
}
19+
20+
impl<LockMode, Modifier> LockingClause<LockMode, Modifier> {
21+
pub(crate) fn new(lock_mode: LockMode, modifier: Modifier) -> Self {
22+
LockingClause { lock_mode, modifier }
23+
}
24+
}
25+
26+
impl<DB: Backend, L: QueryFragment<DB>, M: QueryFragment<DB>> QueryFragment<DB> for LockingClause<L, M> {
27+
fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
28+
self.lock_mode.walk_ast(out.reborrow())?;
29+
self.modifier.walk_ast(out.reborrow())
30+
}
31+
}
32+
33+
/// LockMode parameters
34+
/// All the different types of row locks that can be acquired.
35+
#[derive(Debug, Clone, Copy, QueryId)]
36+
pub struct ForUpdate;
37+
38+
#[derive(Debug, Clone, Copy, QueryId)]
39+
pub struct ForNoKeyUpdate;
40+
41+
#[derive(Debug, Clone, Copy, QueryId)]
42+
pub struct ForShare;
43+
44+
#[derive(Debug, Clone, Copy, QueryId)]
45+
pub struct ForKeyShare;
46+
47+
/// Modifiers
48+
/// To be used in conjunction with a lock mode.
49+
#[derive(Debug, Clone, Copy, QueryId)]
50+
pub struct NoModifier;
51+
52+
#[derive(Debug, Clone, Copy, QueryId)]
53+
pub struct SkipLocked;
54+
55+
#[derive(Debug, Clone, Copy, QueryId)]
56+
pub struct NoWait;

diesel/src/query_builder/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub mod functions;
1818
#[doc(hidden)]
1919
pub mod nodes;
2020
mod distinct_clause;
21-
pub(crate) mod for_update_clause;
21+
pub(crate) mod locking_clause;
2222
mod group_by_clause;
2323
mod limit_clause;
2424
mod offset_clause;

0 commit comments

Comments
 (0)