Generalize locking clause (#759)

Postgres supports more generalized locking clauses, for example:
FOR UPDATE OF <table_name> SKIP LOCKED

also, multiple locking clauses. Generalize the parser to support these.

Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
Audun Skaugen 2022-12-13 23:19:07 +01:00 committed by GitHub
parent 6c545195e1
commit fb02344131
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 187 additions and 36 deletions

View file

@ -253,7 +253,7 @@ fn parse_update_set_from() {
limit: None,
offset: None,
fetch: None,
lock: None,
locks: vec![],
}),
alias: Some(TableAlias {
name: Ident::new("t2"),
@ -2296,7 +2296,7 @@ fn parse_create_table_as_table() {
limit: None,
offset: None,
fetch: None,
lock: None,
locks: vec![],
});
match verified_stmt(sql1) {
@ -2319,7 +2319,7 @@ fn parse_create_table_as_table() {
limit: None,
offset: None,
fetch: None,
lock: None,
locks: vec![],
});
match verified_stmt(sql2) {
@ -3456,7 +3456,7 @@ fn parse_interval_and_or_xor() {
limit: None,
offset: None,
fetch: None,
lock: None,
locks: vec![],
}))];
assert_eq!(actual_ast, expected_ast);
@ -5604,7 +5604,7 @@ fn parse_merge() {
limit: None,
offset: None,
fetch: None,
lock: None,
locks: vec![],
}),
alias: Some(TableAlias {
name: Ident {
@ -5729,12 +5729,106 @@ fn test_merge_with_delimiter() {
#[test]
fn test_lock() {
let sql = "SELECT * FROM student WHERE id = '1' FOR UPDATE";
let ast = verified_query(sql);
assert_eq!(ast.lock.unwrap(), LockType::Update);
let mut ast = verified_query(sql);
assert_eq!(ast.locks.len(), 1);
let lock = ast.locks.pop().unwrap();
assert_eq!(lock.lock_type, LockType::Update);
assert!(lock.of.is_none());
assert!(lock.nonblock.is_none());
let sql = "SELECT * FROM student WHERE id = '1' FOR SHARE";
let ast = verified_query(sql);
assert_eq!(ast.lock.unwrap(), LockType::Share);
let mut ast = verified_query(sql);
assert_eq!(ast.locks.len(), 1);
let lock = ast.locks.pop().unwrap();
assert_eq!(lock.lock_type, LockType::Share);
assert!(lock.of.is_none());
assert!(lock.nonblock.is_none());
}
#[test]
fn test_lock_table() {
let sql = "SELECT * FROM student WHERE id = '1' FOR UPDATE OF school";
let mut ast = verified_query(sql);
assert_eq!(ast.locks.len(), 1);
let lock = ast.locks.pop().unwrap();
assert_eq!(lock.lock_type, LockType::Update);
assert_eq!(
lock.of.unwrap().0,
vec![Ident {
value: "school".to_string(),
quote_style: None
}]
);
assert!(lock.nonblock.is_none());
let sql = "SELECT * FROM student WHERE id = '1' FOR SHARE OF school";
let mut ast = verified_query(sql);
assert_eq!(ast.locks.len(), 1);
let lock = ast.locks.pop().unwrap();
assert_eq!(lock.lock_type, LockType::Share);
assert_eq!(
lock.of.unwrap().0,
vec![Ident {
value: "school".to_string(),
quote_style: None
}]
);
assert!(lock.nonblock.is_none());
let sql = "SELECT * FROM student WHERE id = '1' FOR SHARE OF school FOR UPDATE OF student";
let mut ast = verified_query(sql);
assert_eq!(ast.locks.len(), 2);
let lock = ast.locks.remove(0);
assert_eq!(lock.lock_type, LockType::Share);
assert_eq!(
lock.of.unwrap().0,
vec![Ident {
value: "school".to_string(),
quote_style: None
}]
);
assert!(lock.nonblock.is_none());
let lock = ast.locks.remove(0);
assert_eq!(lock.lock_type, LockType::Update);
assert_eq!(
lock.of.unwrap().0,
vec![Ident {
value: "student".to_string(),
quote_style: None
}]
);
assert!(lock.nonblock.is_none());
}
#[test]
fn test_lock_nonblock() {
let sql = "SELECT * FROM student WHERE id = '1' FOR UPDATE OF school SKIP LOCKED";
let mut ast = verified_query(sql);
assert_eq!(ast.locks.len(), 1);
let lock = ast.locks.pop().unwrap();
assert_eq!(lock.lock_type, LockType::Update);
assert_eq!(
lock.of.unwrap().0,
vec![Ident {
value: "school".to_string(),
quote_style: None
}]
);
assert_eq!(lock.nonblock.unwrap(), NonBlock::SkipLocked);
let sql = "SELECT * FROM student WHERE id = '1' FOR SHARE OF school NOWAIT";
let mut ast = verified_query(sql);
assert_eq!(ast.locks.len(), 1);
let lock = ast.locks.pop().unwrap();
assert_eq!(lock.lock_type, LockType::Share);
assert_eq!(
lock.of.unwrap().0,
vec![Ident {
value: "school".to_string(),
quote_style: None
}]
);
assert_eq!(lock.nonblock.unwrap(), NonBlock::Nowait);
}
#[test]