sqlstr/expr/
locking.rs

1use super::separator_optional;
2use crate::WriteSql;
3
4/// Row-level lock strength
5///
6/// - [Postgres row-level locks](https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-ROWS)
7/// - [MySQL locking reads](https://dev.mysql.com/doc/refman/8.2/en/innodb-locking-reads.html)
8#[derive(Clone, Copy, PartialEq, Eq)]
9pub enum RowLockStrength {
10    Update,
11    NoKeyUpdate,
12    Share,
13    KeyShare,
14}
15
16impl RowLockStrength {
17    pub const fn as_str(&self) -> &'static str {
18        match *self {
19            Self::Update => "UPDATE",
20            Self::NoKeyUpdate => "NO KEY UPDATE",
21            Self::Share => "SHARE",
22            Self::KeyShare => "KEY SHARE",
23        }
24    }
25}
26
27#[derive(Clone, Copy, PartialEq, Eq)]
28pub enum RowLockConcurrency {
29    NoWait,
30    SkipLocked,
31}
32
33impl RowLockConcurrency {
34    pub const fn as_str(&self) -> &'static str {
35        match *self {
36            Self::NoWait => "NOWAIT",
37            Self::SkipLocked => "SKIP LOCKED",
38        }
39    }
40}
41
42pub fn row_lock<'t, Sql, Arg, I>(
43    sql: &mut Sql,
44    strength: RowLockStrength,
45    tables: I,
46    concurrency: Option<RowLockConcurrency>,
47) where
48    Sql: WriteSql<Arg>,
49    I: IntoIterator<Item = &'t str>,
50{
51    separator_optional(sql);
52    sql.push_cmd("FOR ");
53    sql.push_cmd(strength.as_str());
54
55    let mut tables = tables.into_iter();
56    if let Some(table) = tables.next() {
57        sql.push_cmd(" OF ");
58        sql.push_cmd(table);
59    }
60    for table in tables {
61        sql.push_cmd(", ");
62        sql.push_cmd(table);
63    }
64
65    if let Some(concurr) = concurrency {
66        sql.push_cmd(" ");
67        sql.push_cmd(concurr.as_str());
68    }
69}
70
71/// Table-level lock mode
72///
73/// [Postgres table-level locks](https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-TABLES)
74#[derive(Clone, Copy, PartialEq, Eq)]
75pub enum TableLockMode {
76    AccessShare,
77    RowShare,
78    RowExclusive,
79    ShareUpdateExclusive,
80    Share,
81    ShareRowExclusive,
82    Exclusive,
83    AccessExclusive,
84}
85
86impl TableLockMode {
87    pub const fn as_str(&self) -> &'static str {
88        match *self {
89            Self::AccessShare => "ACCESS SHARE",
90            Self::RowShare => "ROW SHARE",
91            Self::RowExclusive => "ROW EXCLUSIVE",
92            Self::ShareUpdateExclusive => "SHARE UPDATE EXCLUSIVE",
93            Self::Share => "SHARE",
94            Self::ShareRowExclusive => "SHARE ROW EXCLUSIVE",
95            Self::Exclusive => "EXCLUSIVE",
96            Self::AccessExclusive => "ACCESS EXCLUSIVE",
97        }
98    }
99}
100
101#[derive(Clone, PartialEq, Eq)]
102pub enum TableLock<'t> {
103    Only(&'t str),
104    Tables(&'t [&'t str]),
105}
106
107#[derive(Default, Clone, Copy, PartialEq, Eq)]
108pub enum TableLockWait {
109    NoWait,
110    #[default]
111    None,
112}
113
114impl TableLockWait {
115    pub const fn as_str(&self) -> &'static str {
116        match *self {
117            Self::NoWait => "NOWAIT",
118            Self::None => "",
119        }
120    }
121}
122
123/// LOCK sql command
124///
125/// - [Postgres table lock](https://www.postgresql.org/docs/current/sql-lock.html)
126pub fn table_lock<Sql, Arg>(
127    sql: &mut Sql,
128    tables: TableLock<'_>,
129    lock_mode: Option<TableLockMode>,
130    nowait: TableLockWait,
131) where
132    Sql: WriteSql<Arg>,
133{
134    separator_optional(sql);
135    sql.push_cmd("LOCK TABLE ");
136
137    match tables {
138        TableLock::Only(table) => {
139            sql.push_cmd("ONLY ");
140            sql.push_cmd(table);
141        }
142        TableLock::Tables(tbls) => {
143            if let Some(tbl) = tbls.first() {
144                sql.push_cmd(tbl);
145            }
146            for tbl in &tbls[1..] {
147                sql.push_cmd(", ");
148                sql.push_cmd(tbl);
149            }
150        }
151    }
152
153    if let Some(mode) = lock_mode {
154        sql.push_cmd(" ");
155        sql.push_cmd(mode.as_str());
156    }
157
158    if nowait == TableLockWait::NoWait {
159        sql.push_cmd(" NOWAIT");
160    }
161}
162
163#[allow(unused_macros)]
164macro_rules! lock_strength {
165    (UPDATE) => {
166        "UPDATE"
167    };
168    (NO_KEY_UPDATE) => {
169        "NO KEY UPDATE"
170    };
171    (SHARE) => {
172        "SHARE"
173    };
174    (KEY_SHARE) => {
175        "KEY SHARE"
176    };
177}
178
179#[allow(unused)]
180pub(super) use lock_strength;
181
182/// Row-level lock
183///
184/// - [Postgres row-level locks](https://www.postgresql.org/docs/current/explicit-locking.html#LOCKING-ROWS)
185#[macro_export]
186macro_rules! static_row_lock {
187    (FOR $s1:tt) => {
188        concat!("FOR ", $crate::expr::lock_strength!($s1))
189    };
190    (FOR $s1:tt NOWAIT) => {
191        concat!("FOR ", $crate::expr::lock_strength!($s1), " NOWAIT")
192    };
193    (FOR $s1:tt SKIP LOCKED) => {
194        concat!("FOR ", $crate::expr::lock_strength!($s1), " SKIP LOCKED")
195    };
196
197    (FOR $s1:tt OF $ftbl:literal$(,)? $($tbl:literal),*) => {
198        concat!(
199            "FOR ",
200            $crate::expr::lock_strength!($s1),
201            " OF ",
202            $ftbl,
203            $(", ", $tbl),*
204        )
205    };
206    (FOR $s1:tt OF $ftbl:literal$(,)? $($tbl:literal),* NOWAIT) => {
207        concat!(
208            "FOR ",
209            $crate::expr::lock_strength!($s1),
210            " OF ",
211            $ftbl,
212            $(", ", $tbl,)*
213            " NOWAIT"
214        )
215    };
216    (FOR $s1:tt OF $ftbl:literal$(,)? $($tbl:literal),* SKIP LOCKED) => {
217        concat!(
218            "FOR ",
219            $crate::expr::lock_strength!($s1),
220            " OF ",
221            $ftbl,
222            $(", ", $tbl,)*
223            " SKIP LOCKED"
224        )
225    };
226}
227
228pub use static_row_lock;
229
230#[allow(unused_macros)]
231macro_rules! lockmode {
232    (ACCESS_SHARE) => {
233        "ACCESS SHARE"
234    };
235    (ROW_SHARE) => {
236        "ROW SHARE"
237    };
238    (ROW_EXCLUSIVE) => {
239        "ROW EXCLUSIVE"
240    };
241    (SHARE_UPDATE_EXCLUSIVE) => {
242        "SHARE UPDATE EXCLUSIVE"
243    };
244    (SHARE) => {
245        "SHARE"
246    };
247    (SHARE_ROW_EXCLUSIVE) => {
248        "SHARE ROW EXCLUSIVE"
249    };
250    (EXCLUSIVE) => {
251        "EXCLUSIVE"
252    };
253    (ACCESS_EXCLUSIVE) => {
254        "ACCESS EXCLUSIVE"
255    };
256}
257
258#[allow(unused)]
259pub(super) use lockmode;
260
261/// LOCK sql command
262///
263/// - [Postgres table lock](https://www.postgresql.org/docs/current/sql-lock.html)
264#[macro_export]
265macro_rules! static_table_lock {
266    (LOCK TABLE $table:literal$(,)? $($tables:literal),*) => {
267        concat!("LOCK TABLE ", $table, $(", ", $tables,)*)
268    };
269    (LOCK TABLE ONLY $table:literal) => {
270        concat!("LOCK TABLE ONLY ", $table)
271    };
272    (LOCK TABLE $table:literal$(,)? $($tables:literal),* NOWAIT) => {
273        concat!("LOCK TABLE ", $table, $(", ", $tables,)* " NOWAIT")
274    };
275    (LOCK TABLE ONLY $table:literal NOWAIT) => {
276        concat!("LOCK TABLE ONLY ", $table, " NOWAIT")
277    };
278
279    (LOCK TABLE $table:literal$(,)? $($tables:literal),* IN $mode:tt MODE) => {
280        concat!("LOCK TABLE ", $table, $(", ", $tables,)* " IN ", $crate::expr::lockmode!($mode), " MODE")
281    };
282	(LOCK TABLE ONLY $table:literal IN $mode:tt MODE) => {
283        concat!("LOCK TABLE ONLY ", $table, " IN ", $crate::expr::lockmode!($mode), " MODE")
284    };
285    (LOCK TABLE $table:literal$(,)? $($tables:literal),* IN $mode:tt MODE NOWAIT) => {
286        concat!("LOCK TABLE ", $table, $(", ", $tables,)* " IN ", $crate::expr::lockmode!($mode), " MODE NOWAIT")
287    };
288	(LOCK TABLE ONLY $table:literal IN $mode:tt MODE NOWAIT) => {
289        concat!("LOCK TABLE ONLY ", $table, " IN ", $crate::expr::lockmode!($mode), " MODE NOWAIT")
290    };
291}
292
293pub use static_table_lock;
294
295#[cfg(test)]
296mod row_lock_test {
297    use super::{row_lock, RowLockStrength};
298    use crate::{expr::RowLockConcurrency, SqlCommand, Void};
299
300    #[test]
301    fn row_locking_strength() {
302        let mut sql: SqlCommand<Void> = SqlCommand::default();
303
304        row_lock(&mut sql, RowLockStrength::NoKeyUpdate, [], None);
305
306        assert_eq!(sql.as_command(), "FOR NO KEY UPDATE");
307    }
308
309    #[test]
310    fn row_locking_strength_with_concurrency() {
311        let mut sql: SqlCommand<Void> = SqlCommand::default();
312
313        row_lock(
314            &mut sql,
315            RowLockStrength::Share,
316            [],
317            Some(RowLockConcurrency::NoWait),
318        );
319
320        assert_eq!(sql.as_command(), "FOR SHARE NOWAIT");
321    }
322
323    #[test]
324    fn row_locking_with_tables() {
325        let mut sql: SqlCommand<Void> = SqlCommand::default();
326
327        row_lock(
328            &mut sql,
329            RowLockStrength::Update,
330            ["user", "access_history"],
331            None,
332        );
333
334        assert_eq!(sql.as_command(), "FOR UPDATE OF user, access_history");
335    }
336
337    #[test]
338    fn row_locking_with_tables_and_concurrency() {
339        let mut sql: SqlCommand<Void> = SqlCommand::default();
340
341        row_lock(
342            &mut sql,
343            RowLockStrength::KeyShare,
344            ["customer"],
345            Some(RowLockConcurrency::SkipLocked),
346        );
347
348        assert_eq!(sql.as_command(), "FOR KEY SHARE OF customer SKIP LOCKED");
349    }
350}
351
352#[cfg(test)]
353mod table_lock_test {
354    use crate::{
355        expr::{table_lock, TableLock, TableLockMode, TableLockWait},
356        SqlCommand, Void,
357    };
358
359    #[test]
360    fn lock_table_only() {
361        let mut sql: SqlCommand<Void> = SqlCommand::default();
362
363        table_lock(&mut sql, TableLock::Only("user"), None, TableLockWait::None);
364
365        assert_eq!(sql.as_command(), "LOCK TABLE ONLY user");
366    }
367
368    #[test]
369    fn lock_table_only_with_lockmode() {
370        let mut sql: SqlCommand<Void> = SqlCommand::default();
371
372        table_lock(
373            &mut sql,
374            TableLock::Only("user"),
375            Some(TableLockMode::AccessExclusive),
376            TableLockWait::None,
377        );
378
379        assert_eq!(sql.as_command(), "LOCK TABLE ONLY user ACCESS EXCLUSIVE");
380    }
381
382    #[test]
383    fn lock_table_only_with_lockmode_and_wait() {
384        let mut sql: SqlCommand<Void> = SqlCommand::default();
385
386        table_lock(
387            &mut sql,
388            TableLock::Only("user"),
389            Some(TableLockMode::AccessExclusive),
390            TableLockWait::NoWait,
391        );
392
393        assert_eq!(
394            sql.as_command(),
395            "LOCK TABLE ONLY user ACCESS EXCLUSIVE NOWAIT"
396        );
397    }
398
399    #[test]
400    fn lock_table_only_with_onwait() {
401        let mut sql: SqlCommand<Void> = SqlCommand::default();
402
403        table_lock(
404            &mut sql,
405            TableLock::Only("user"),
406            None,
407            TableLockWait::NoWait,
408        );
409
410        assert_eq!(sql.as_command(), "LOCK TABLE ONLY user NOWAIT");
411    }
412
413    #[test]
414    fn lock_tables() {
415        let mut sql: SqlCommand<Void> = SqlCommand::default();
416
417        table_lock(
418            &mut sql,
419            TableLock::Tables(&["user", "customer"]),
420            None,
421            TableLockWait::None,
422        );
423
424        assert_eq!(sql.as_command(), "LOCK TABLE user, customer");
425    }
426
427    #[test]
428    fn lock_tables_with_lockmode() {
429        let mut sql: SqlCommand<Void> = SqlCommand::default();
430
431        table_lock(
432            &mut sql,
433            TableLock::Tables(&["user", "customer"]),
434            Some(TableLockMode::Share),
435            TableLockWait::None,
436        );
437
438        assert_eq!(sql.as_command(), "LOCK TABLE user, customer SHARE");
439    }
440
441    #[test]
442    fn lock_tables_with_lockmode_and_nowait() {
443        let mut sql: SqlCommand<Void> = SqlCommand::default();
444
445        table_lock(
446            &mut sql,
447            TableLock::Tables(&["user", "customer"]),
448            Some(TableLockMode::RowExclusive),
449            TableLockWait::NoWait,
450        );
451
452        assert_eq!(
453            sql.as_command(),
454            "LOCK TABLE user, customer ROW EXCLUSIVE NOWAIT"
455        );
456    }
457
458    #[test]
459    fn lock_tables_with_nowait() {
460        let mut sql: SqlCommand<Void> = SqlCommand::default();
461
462        table_lock(
463            &mut sql,
464            TableLock::Tables(&["user", "customer"]),
465            None,
466            TableLockWait::NoWait,
467        );
468
469        assert_eq!(sql.as_command(), "LOCK TABLE user, customer NOWAIT");
470    }
471}
472
473#[cfg(test)]
474mod static_row_lock_test {
475    #[test]
476    fn static_row_lock_macro() {
477        assert_eq!(static_row_lock!(FOR UPDATE), "FOR UPDATE");
478        assert_eq!(static_row_lock!(FOR NO_KEY_UPDATE), "FOR NO KEY UPDATE");
479        assert_eq!(static_row_lock!(FOR SHARE), "FOR SHARE");
480        assert_eq!(static_row_lock!(FOR KEY_SHARE), "FOR KEY SHARE");
481
482        assert_eq!(static_row_lock!(FOR UPDATE NOWAIT), "FOR UPDATE NOWAIT");
483        assert_eq!(
484            static_row_lock!(FOR NO_KEY_UPDATE NOWAIT),
485            "FOR NO KEY UPDATE NOWAIT"
486        );
487        assert_eq!(static_row_lock!(FOR SHARE NOWAIT), "FOR SHARE NOWAIT");
488        assert_eq!(
489            static_row_lock!(FOR KEY_SHARE NOWAIT),
490            "FOR KEY SHARE NOWAIT"
491        );
492
493        assert_eq!(
494            static_row_lock!(FOR UPDATE SKIP LOCKED),
495            "FOR UPDATE SKIP LOCKED"
496        );
497        assert_eq!(
498            static_row_lock!(FOR NO_KEY_UPDATE SKIP LOCKED),
499            "FOR NO KEY UPDATE SKIP LOCKED"
500        );
501        assert_eq!(
502            static_row_lock!(FOR SHARE SKIP LOCKED),
503            "FOR SHARE SKIP LOCKED"
504        );
505        assert_eq!(
506            static_row_lock!(FOR KEY_SHARE SKIP LOCKED),
507            "FOR KEY SHARE SKIP LOCKED"
508        );
509
510        assert_eq!(static_row_lock!(FOR UPDATE OF "user"), "FOR UPDATE OF user");
511        assert_eq!(
512            static_row_lock!(FOR NO_KEY_UPDATE OF "user"),
513            "FOR NO KEY UPDATE OF user"
514        );
515        assert_eq!(static_row_lock!(FOR SHARE OF "user"), "FOR SHARE OF user");
516        assert_eq!(
517            static_row_lock!(FOR KEY_SHARE OF "user"),
518            "FOR KEY SHARE OF user"
519        );
520
521        assert_eq!(
522            static_row_lock!(FOR UPDATE OF "user" NOWAIT),
523            "FOR UPDATE OF user NOWAIT"
524        );
525        assert_eq!(
526            static_row_lock!(FOR NO_KEY_UPDATE OF "user" NOWAIT),
527            "FOR NO KEY UPDATE OF user NOWAIT"
528        );
529        assert_eq!(
530            static_row_lock!(FOR SHARE OF "user" NOWAIT),
531            "FOR SHARE OF user NOWAIT"
532        );
533        assert_eq!(
534            static_row_lock!(FOR KEY_SHARE OF "user" NOWAIT),
535            "FOR KEY SHARE OF user NOWAIT"
536        );
537
538        assert_eq!(
539            static_row_lock!(FOR UPDATE OF "user" SKIP LOCKED),
540            "FOR UPDATE OF user SKIP LOCKED"
541        );
542        assert_eq!(
543            static_row_lock!(FOR NO_KEY_UPDATE OF "user" SKIP LOCKED),
544            "FOR NO KEY UPDATE OF user SKIP LOCKED"
545        );
546        assert_eq!(
547            static_row_lock!(FOR SHARE OF "user" SKIP LOCKED),
548            "FOR SHARE OF user SKIP LOCKED"
549        );
550        assert_eq!(
551            static_row_lock!(FOR KEY_SHARE OF "user" SKIP LOCKED),
552            "FOR KEY SHARE OF user SKIP LOCKED"
553        );
554
555        assert_eq!(
556            static_row_lock!(FOR UPDATE OF "user", "access", "customer"),
557            "FOR UPDATE OF user, access, customer"
558        );
559        assert_eq!(
560            static_row_lock!(FOR NO_KEY_UPDATE OF "user", "access", "customer"),
561            "FOR NO KEY UPDATE OF user, access, customer"
562        );
563        assert_eq!(
564            static_row_lock!(FOR SHARE OF "user", "access", "customer"),
565            "FOR SHARE OF user, access, customer"
566        );
567        assert_eq!(
568            static_row_lock!(FOR KEY_SHARE OF "user", "access", "customer"),
569            "FOR KEY SHARE OF user, access, customer"
570        );
571
572        assert_eq!(
573            static_row_lock!(FOR UPDATE OF "user", "access", "customer" NOWAIT),
574            "FOR UPDATE OF user, access, customer NOWAIT"
575        );
576        assert_eq!(
577            static_row_lock!(FOR NO_KEY_UPDATE OF "user", "access", "customer" NOWAIT),
578            "FOR NO KEY UPDATE OF user, access, customer NOWAIT"
579        );
580        assert_eq!(
581            static_row_lock!(FOR SHARE OF "user", "access", "customer" NOWAIT),
582            "FOR SHARE OF user, access, customer NOWAIT"
583        );
584        assert_eq!(
585            static_row_lock!(FOR KEY_SHARE OF "user", "access", "customer" NOWAIT),
586            "FOR KEY SHARE OF user, access, customer NOWAIT"
587        );
588
589        assert_eq!(
590            static_row_lock!(FOR UPDATE OF "user", "access", "customer" SKIP LOCKED),
591            "FOR UPDATE OF user, access, customer SKIP LOCKED"
592        );
593        assert_eq!(
594            static_row_lock!(FOR NO_KEY_UPDATE OF "user", "access", "customer" SKIP LOCKED),
595            "FOR NO KEY UPDATE OF user, access, customer SKIP LOCKED"
596        );
597        assert_eq!(
598            static_row_lock!(FOR SHARE OF "user", "access", "customer" SKIP LOCKED),
599            "FOR SHARE OF user, access, customer SKIP LOCKED"
600        );
601        assert_eq!(
602            static_row_lock!(FOR KEY_SHARE OF "user", "access", "customer" SKIP LOCKED),
603            "FOR KEY SHARE OF user, access, customer SKIP LOCKED"
604        );
605    }
606
607    #[test]
608    fn static_table_lock_macro() {
609        assert_eq!(static_table_lock!(LOCK TABLE "user"), "LOCK TABLE user");
610        assert_eq!(
611            static_table_lock!(LOCK TABLE "user", "customer", "access_record"),
612            "LOCK TABLE user, customer, access_record"
613        );
614        assert_eq!(
615            static_table_lock!(LOCK TABLE "user" IN ROW_EXCLUSIVE MODE),
616            "LOCK TABLE user IN ROW EXCLUSIVE MODE"
617        );
618
619        assert_eq!(
620            static_table_lock!(LOCK TABLE "user", "customer", "access_record" IN ACCESS_SHARE MODE),
621            "LOCK TABLE user, customer, access_record IN ACCESS SHARE MODE"
622        );
623        assert_eq!(
624            static_table_lock!(LOCK TABLE "user", "customer", "access_record" IN ROW_SHARE MODE),
625            "LOCK TABLE user, customer, access_record IN ROW SHARE MODE"
626        );
627        assert_eq!(
628            static_table_lock!(LOCK TABLE "user", "customer", "access_record" IN ROW_EXCLUSIVE MODE),
629            "LOCK TABLE user, customer, access_record IN ROW EXCLUSIVE MODE"
630        );
631        assert_eq!(
632            static_table_lock!(LOCK TABLE "user", "customer", "access_record" IN SHARE_UPDATE_EXCLUSIVE MODE),
633            "LOCK TABLE user, customer, access_record IN SHARE UPDATE EXCLUSIVE MODE"
634        );
635        assert_eq!(
636            static_table_lock!(LOCK TABLE "user", "customer", "access_record" IN SHARE MODE),
637            "LOCK TABLE user, customer, access_record IN SHARE MODE"
638        );
639        assert_eq!(
640            static_table_lock!(LOCK TABLE "user", "customer", "access_record" IN SHARE_ROW_EXCLUSIVE MODE),
641            "LOCK TABLE user, customer, access_record IN SHARE ROW EXCLUSIVE MODE"
642        );
643        assert_eq!(
644            static_table_lock!(LOCK TABLE "user", "customer", "access_record" IN EXCLUSIVE MODE),
645            "LOCK TABLE user, customer, access_record IN EXCLUSIVE MODE"
646        );
647        assert_eq!(
648            static_table_lock!(LOCK TABLE "user", "customer", "access_record" IN ACCESS_EXCLUSIVE MODE),
649            "LOCK TABLE user, customer, access_record IN ACCESS EXCLUSIVE MODE"
650        );
651
652        assert_eq!(
653            static_table_lock!(LOCK TABLE "user" NOWAIT),
654            "LOCK TABLE user NOWAIT"
655        );
656        assert_eq!(
657            static_table_lock!(LOCK TABLE "user", "customer", "access_record" NOWAIT),
658            "LOCK TABLE user, customer, access_record NOWAIT"
659        );
660        assert_eq!(
661            static_table_lock!(LOCK TABLE "user" IN ROW_EXCLUSIVE MODE NOWAIT),
662            "LOCK TABLE user IN ROW EXCLUSIVE MODE NOWAIT"
663        );
664
665        assert_eq!(
666            static_table_lock!(LOCK TABLE "user", "access_record" IN ACCESS_SHARE MODE NOWAIT),
667            "LOCK TABLE user, access_record IN ACCESS SHARE MODE NOWAIT"
668        );
669        assert_eq!(
670            static_table_lock!(LOCK TABLE "customer", "access_record" IN ROW_SHARE MODE NOWAIT),
671            "LOCK TABLE customer, access_record IN ROW SHARE MODE NOWAIT"
672        );
673        assert_eq!(
674            static_table_lock!(LOCK TABLE "user", "customer" IN ROW_EXCLUSIVE MODE NOWAIT),
675            "LOCK TABLE user, customer IN ROW EXCLUSIVE MODE NOWAIT"
676        );
677        assert_eq!(
678            static_table_lock!(LOCK TABLE "user", "customer", "access_record" IN SHARE_UPDATE_EXCLUSIVE MODE NOWAIT),
679            "LOCK TABLE user, customer, access_record IN SHARE UPDATE EXCLUSIVE MODE NOWAIT"
680        );
681        assert_eq!(
682            static_table_lock!(LOCK TABLE "user", "customer" IN SHARE MODE NOWAIT),
683            "LOCK TABLE user, customer IN SHARE MODE NOWAIT"
684        );
685        assert_eq!(
686            static_table_lock!(LOCK TABLE "access_record" IN SHARE_ROW_EXCLUSIVE MODE NOWAIT),
687            "LOCK TABLE access_record IN SHARE ROW EXCLUSIVE MODE NOWAIT"
688        );
689        assert_eq!(
690            static_table_lock!(LOCK TABLE "user", "customer", "access_record" IN EXCLUSIVE MODE NOWAIT),
691            "LOCK TABLE user, customer, access_record IN EXCLUSIVE MODE NOWAIT"
692        );
693        assert_eq!(
694            static_table_lock!(LOCK TABLE "user", "customer", "access_record" IN ACCESS_EXCLUSIVE MODE NOWAIT),
695            "LOCK TABLE user, customer, access_record IN ACCESS EXCLUSIVE MODE NOWAIT"
696        );
697    }
698}