@@ -3341,16 +3341,13 @@ pub enum Statement {
3341
3341
value : Option < Value > ,
3342
3342
is_eq : bool ,
3343
3343
} ,
3344
- /// ```sql
3345
- /// LOCK TABLES <table_name> [READ [LOCAL] | [LOW_PRIORITY] WRITE]
3346
- /// ```
3347
- /// Note: this is a MySQL-specific statement. See <https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
3348
- LockTables { tables : Vec < LockTable > } ,
3344
+ /// See [`LockTables`].
3345
+ LockTables ( LockTables ) ,
3349
3346
/// ```sql
3350
3347
/// UNLOCK TABLES
3351
3348
/// ```
3352
3349
/// Note: this is a MySQL-specific statement. See <https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
3353
- UnlockTables ,
3350
+ UnlockTables ( bool ) ,
3354
3351
/// ```sql
3355
3352
/// UNLOAD(statement) TO <destination> [ WITH options ]
3356
3353
/// ```
@@ -4925,11 +4922,15 @@ impl fmt::Display for Statement {
4925
4922
}
4926
4923
Ok ( ( ) )
4927
4924
}
4928
- Statement :: LockTables { tables } => {
4929
- write ! ( f, "LOCK TABLES {}" , display_comma_separated ( tables ) )
4925
+ Statement :: LockTables ( lock_tables ) => {
4926
+ write ! ( f, "{}" , lock_tables )
4930
4927
}
4931
- Statement :: UnlockTables => {
4932
- write ! ( f, "UNLOCK TABLES" )
4928
+ Statement :: UnlockTables ( pluralized) => {
4929
+ if * pluralized {
4930
+ write ! ( f, "UNLOCK TABLES" )
4931
+ } else {
4932
+ write ! ( f, "UNLOCK TABLE" )
4933
+ }
4933
4934
}
4934
4935
Statement :: Unload { query, to, with } => {
4935
4936
write ! ( f, "UNLOAD({query}) TO {to}" ) ?;
@@ -7278,16 +7279,126 @@ impl fmt::Display for SearchModifier {
7278
7279
}
7279
7280
}
7280
7281
7282
+ /// A `LOCK TABLE ..` statement. MySQL and Postgres variants are supported.
7283
+ ///
7284
+ /// The MySQL and Postgres syntax variants are significant enough that they
7285
+ /// are explicitly represented as enum variants. In order to support additional
7286
+ /// databases in the future, this enum is marked as `#[non_exhaustive]`.
7287
+ ///
7288
+ /// In MySQL, when multiple tables are mentioned in the statement the lock mode
7289
+ /// can vary per table.
7290
+ ///
7291
+ /// In contrast, Postgres only allows specifying a single mode which is applied
7292
+ /// to all mentioned tables.
7293
+ ///
7294
+ /// MySQL: see <https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html>
7295
+ ///
7296
+ /// ```sql
7297
+ /// LOCK [TABLE | TABLES] name [[AS] alias] locktype [,name [[AS] alias] locktype]
7298
+ /// ````
7299
+ ///
7300
+ /// Where *locktype* is:
7301
+ /// ```sql
7302
+ /// READ [LOCAL] | [LOW_PRIORITY] WRITE
7303
+ /// ```
7304
+ ///
7305
+ /// Postgres: See <https://www.postgresql.org/docs/current/sql-lock.html>
7306
+ ///
7307
+ /// ```sql
7308
+ /// LOCK [ TABLE ] [ ONLY ] name [, ...] [ IN lockmode MODE ] [ NOWAIT ]
7309
+ /// ```
7310
+ /// Where *lockmode* is one of:
7311
+ ///
7312
+ /// ```sql
7313
+ /// ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE
7314
+ /// | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE
7315
+ /// ``````
7281
7316
#[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
7282
7317
#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
7283
7318
#[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
7284
- pub struct LockTable {
7285
- pub table : Ident ,
7319
+ #[ non_exhaustive]
7320
+ pub enum LockTables {
7321
+ /// The MySQL syntax variant
7322
+ MySql {
7323
+ /// Whether the `TABLE` or `TABLES` keyword was used.
7324
+ pluralized_table_keyword : bool ,
7325
+ /// The tables to lock and their per-table lock mode.
7326
+ tables : Vec < MySqlTableLock > ,
7327
+ } ,
7328
+
7329
+ /// The Postgres syntax variant.
7330
+ Postgres {
7331
+ /// One or more optionally schema-qualified table names to lock.
7332
+ tables : Vec < ObjectName > ,
7333
+ /// The lock type applied to all mentioned tables.
7334
+ lock_mode : Option < LockTableType > ,
7335
+ /// Whether the optional `TABLE` keyword was present (to support round-trip parse & render)
7336
+ has_table_keyword : bool ,
7337
+ /// Whether the `ONLY` option was specified.
7338
+ only : bool ,
7339
+ /// Whether the `NOWAIT` option was specified.
7340
+ no_wait : bool ,
7341
+ } ,
7342
+ }
7343
+
7344
+ impl Display for LockTables {
7345
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
7346
+ match self {
7347
+ LockTables :: MySql {
7348
+ pluralized_table_keyword,
7349
+ tables,
7350
+ } => {
7351
+ write ! (
7352
+ f,
7353
+ "LOCK {tbl_kwd} " ,
7354
+ tbl_kwd = if * pluralized_table_keyword {
7355
+ "TABLES"
7356
+ } else {
7357
+ "TABLE"
7358
+ }
7359
+ ) ?;
7360
+ write ! ( f, "{}" , display_comma_separated( tables) ) ?;
7361
+ Ok ( ( ) )
7362
+ }
7363
+ LockTables :: Postgres {
7364
+ tables,
7365
+ lock_mode,
7366
+ has_table_keyword,
7367
+ only,
7368
+ no_wait,
7369
+ } => {
7370
+ write ! (
7371
+ f,
7372
+ "LOCK{tbl_kwd}" ,
7373
+ tbl_kwd = if * has_table_keyword { " TABLE" } else { "" }
7374
+ ) ?;
7375
+ if * only {
7376
+ write ! ( f, " ONLY" ) ?;
7377
+ }
7378
+ write ! ( f, " {}" , display_comma_separated( tables) ) ?;
7379
+ if let Some ( lock_mode) = lock_mode {
7380
+ write ! ( f, " IN {} MODE" , lock_mode) ?;
7381
+ }
7382
+ if * no_wait {
7383
+ write ! ( f, " NOWAIT" ) ?;
7384
+ }
7385
+ Ok ( ( ) )
7386
+ }
7387
+ }
7388
+ }
7389
+ }
7390
+
7391
+ /// A locked table from a MySQL `LOCK TABLE` statement.
7392
+ #[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
7393
+ #[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
7394
+ #[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
7395
+ pub struct MySqlTableLock {
7396
+ pub table : ObjectName ,
7286
7397
pub alias : Option < Ident > ,
7287
- pub lock_type : LockTableType ,
7398
+ pub lock_type : Option < LockTableType > ,
7288
7399
}
7289
7400
7290
- impl fmt:: Display for LockTable {
7401
+ impl fmt:: Display for MySqlTableLock {
7291
7402
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
7292
7403
let Self {
7293
7404
table : tbl_name,
@@ -7299,17 +7410,34 @@ impl fmt::Display for LockTable {
7299
7410
if let Some ( alias) = alias {
7300
7411
write ! ( f, "AS {alias} " ) ?;
7301
7412
}
7302
- write ! ( f, "{lock_type}" ) ?;
7413
+ if let Some ( lock_type) = lock_type {
7414
+ write ! ( f, "{lock_type}" ) ?;
7415
+ }
7303
7416
Ok ( ( ) )
7304
7417
}
7305
7418
}
7306
7419
7420
+ /// Table lock types.
7421
+ ///
7422
+ /// `Read` & `Write` are MySQL-specfic.
7423
+ ///
7424
+ /// AccessShare, RowShare, RowExclusive, ShareUpdateExclusive, Share,
7425
+ /// ShareRowExclusive, Exclusive, AccessExclusive are Postgres-specific.
7307
7426
#[ derive( Debug , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
7308
7427
#[ cfg_attr( feature = "serde" , derive( Serialize , Deserialize ) ) ]
7309
7428
#[ cfg_attr( feature = "visitor" , derive( Visit , VisitMut ) ) ]
7429
+ #[ non_exhaustive]
7310
7430
pub enum LockTableType {
7311
7431
Read { local : bool } ,
7312
7432
Write { low_priority : bool } ,
7433
+ AccessShare ,
7434
+ RowShare ,
7435
+ RowExclusive ,
7436
+ ShareUpdateExclusive ,
7437
+ Share ,
7438
+ ShareRowExclusive ,
7439
+ Exclusive ,
7440
+ AccessExclusive ,
7313
7441
}
7314
7442
7315
7443
impl fmt:: Display for LockTableType {
@@ -7327,6 +7455,30 @@ impl fmt::Display for LockTableType {
7327
7455
}
7328
7456
write ! ( f, "WRITE" ) ?;
7329
7457
}
7458
+ Self :: AccessShare => {
7459
+ write ! ( f, "ACCESS SHARE" ) ?;
7460
+ }
7461
+ Self :: RowShare => {
7462
+ write ! ( f, "ROW SHARE" ) ?;
7463
+ }
7464
+ Self :: RowExclusive => {
7465
+ write ! ( f, "ROW EXCLUSIVE" ) ?;
7466
+ }
7467
+ Self :: ShareUpdateExclusive => {
7468
+ write ! ( f, "SHARE UPDATE EXCLUSIVE" ) ?;
7469
+ }
7470
+ Self :: Share => {
7471
+ write ! ( f, "SHARE" ) ?;
7472
+ }
7473
+ Self :: ShareRowExclusive => {
7474
+ write ! ( f, "SHARE ROW EXCLUSIVE" ) ?;
7475
+ }
7476
+ Self :: Exclusive => {
7477
+ write ! ( f, "EXCLUSIVE" ) ?;
7478
+ }
7479
+ Self :: AccessExclusive => {
7480
+ write ! ( f, "ACCESS EXCLUSIVE" ) ?;
7481
+ }
7330
7482
}
7331
7483
7332
7484
Ok ( ( ) )
0 commit comments