diff --git a/week10/ex1.sql b/week10/ex1.sql new file mode 100644 index 0000000..788b7e7 --- /dev/null +++ b/week10/ex1.sql @@ -0,0 +1,142 @@ +-- PART A +CREATE TABLE accounts (id SERIAL, name VARCHAR(50), credit numeric, currency VARCHAR(10)); +INSERT INTO accounts (name, credit, currency) VALUES('Account 1', 1000, 'RUB'); +INSERT INTO accounts (name, credit, currency) VALUES('Account 2', 1000, 'RUB'); +INSERT INTO accounts (name, credit, currency) VALUES('Account 3', 1000, 'RUB'); + +BEGIN; + -- T1 + UPDATE accounts SET credit=credit-500 WHERE name='Account 1'; + UPDATE accounts SET credit=credit+500 WHERE name='Account 3'; + SAVEPOINT T1; + + -- T2 + UPDATE accounts SET credit=credit-700 WHERE name='Account 2'; + UPDATE accounts SET credit=credit+700 WHERE name='Account 1'; + SAVEPOINT T2; + + -- T3 + UPDATE accounts SET credit=credit-100 WHERE name='Account 2'; + UPDATE accounts SET credit=credit+100 WHERE name='Account 3'; + SAVEPOINT T3; + + ROLLBACK TO T3; + ROLLBACK TO T2; + ROLLBACK TO T1; + + ROLLBACK; + +-- PART B +ALTER TABLE accounts ADD COLUMN BankName VARCHAR(30); +UPDATE accounts SET BankName='SberBank' WHERE name='Account 1' OR name='Account 3'; +UPDATE accounts SET BankName='Tinkoff' WHERE name='Account 2'; +INSERT INTO accounts (name, credit, currency) VALUES('Account 4', 1000, 'RUB'); + +BEGIN; + -- T1 + UPDATE accounts SET credit=credit-500 WHERE name='Account 1'; + UPDATE accounts SET credit=credit+500 WHERE name='Account 3'; + DO + $do$ + BEGIN + IF (SELECT COUNT(DISTINCT BankName) FROM accounts WHERE name='Account 1' OR name='Account 3') >= 2 THEN + UPDATE accounts SET credit=credit-30 WHERE name='Account 1'; + UPDATE accounts SET credit=credit+30 WHERE name='Account 4'; + END IF; + END + $do$; + SAVEPOINT T1; + + -- T2 + UPDATE accounts SET credit=credit-700 WHERE name='Account 2'; + UPDATE accounts SET credit=credit+700 WHERE name='Account 1'; + DO + $do$ + BEGIN + IF (SELECT COUNT(DISTINCT BankName) FROM accounts WHERE name='Account 2' OR name='Account 1') >= 2 THEN + UPDATE accounts SET credit=credit-30 WHERE name='Account 2'; + UPDATE accounts SET credit=credit+30 WHERE name='Account 4'; + END IF; + END + $do$; + SAVEPOINT T2; + + -- T3 + UPDATE accounts SET credit=credit-100 WHERE name='Account 2'; + UPDATE accounts SET credit=credit+100 WHERE name='Account 3'; + DO + $do$ + BEGIN + IF (SELECT COUNT(DISTINCT BankName) FROM accounts WHERE name='Account 2' OR name='Account 3') >= 2 THEN + UPDATE accounts SET credit=credit-30 WHERE name='Account 2'; + UPDATE accounts SET credit=credit+30 WHERE name='Account 4'; + END IF; + END + $do$; + SAVEPOINT T3; + + ROLLBACK TO T3; + ROLLBACK TO T2; + ROLLBACK TO T1; + + ROLLBACK; + +-- Part C +CREATE TABLE Ledger (id Serial, fromId int, toId int, fee numeric, amount numeric, transactionDateTime timestamp); +BEGIN; + -- T1 + UPDATE accounts SET credit=credit-500 WHERE name='Account 1'; + UPDATE accounts SET credit=credit+500 WHERE name='Account 3'; + DO + $do$ + BEGIN + IF (SELECT COUNT(DISTINCT BankName) FROM accounts WHERE name='Account 1' OR name='Account 3') >= 2 THEN + UPDATE accounts SET credit=credit-30 WHERE name='Account 1'; + UPDATE accounts SET credit=credit+30 WHERE name='Account 4'; + INSERT INTO Ledger (fromId, toId, fee, amount, transactionDateTime) Values(1, 3, 30, 500, CURRENT_TIMESTAMP); + ELSE + INSERT INTO Ledger (fromId, toId, fee, amount, transactionDateTime) Values(1, 3, 0, 500, CURRENT_TIMESTAMP); + END IF; + END + $do$; + SAVEPOINT T1; + + -- T2 + UPDATE accounts SET credit=credit-700 WHERE name='Account 2'; + UPDATE accounts SET credit=credit+700 WHERE name='Account 1'; + DO + $do$ + BEGIN + IF (SELECT COUNT(DISTINCT BankName) FROM accounts WHERE name='Account 2' OR name='Account 1') >= 2 THEN + UPDATE accounts SET credit=credit-30 WHERE name='Account 2'; + UPDATE accounts SET credit=credit+30 WHERE name='Account 4'; + INSERT INTO Ledger (fromId, toId, fee, amount, transactionDateTime) Values(2, 1, 30, 700, CURRENT_TIMESTAMP); + ELSE + INSERT INTO Ledger (fromId, toId, fee, amount, transactionDateTime) Values(2, 1, 0, 700, CURRENT_TIMESTAMP); + END IF; + END + $do$; + SAVEPOINT T2; + + -- T3 + UPDATE accounts SET credit=credit-100 WHERE name='Account 2'; + UPDATE accounts SET credit=credit+100 WHERE name='Account 3'; + DO + $do$ + BEGIN + IF (SELECT COUNT(DISTINCT BankName) FROM accounts WHERE name='Account 2' OR name='Account 3') >= 2 THEN + UPDATE accounts SET credit=credit-30 WHERE name='Account 2'; + UPDATE accounts SET credit=credit+30 WHERE name='Account 4'; + INSERT INTO Ledger (fromId, toId, fee, amount, transactionDateTime) Values(2, 4, 30, 100, CURRENT_TIMESTAMP); + ELSE + INSERT INTO Ledger (fromId, toId, fee, amount, transactionDateTime) Values(2, 4, 0, 100, CURRENT_TIMESTAMP); + END IF; + END + $do$; + SAVEPOINT T3; + + ROLLBACK TO T3; + ROLLBACK TO T2; + ROLLBACK TO T1; + + ROLLBACK; diff --git a/week10/ex2.sql b/week10/ex2.sql new file mode 100644 index 0000000..f595797 --- /dev/null +++ b/week10/ex2.sql @@ -0,0 +1,112 @@ +CREATE TABLE bank2 (id serial, username VARCHAR(50), fullname VARCHAR(50), balance numeric, Group_id int); +INSERT INTO bank2 (username, fullname, balance, Group_id) VALUES('jones', 'Alice Jones', 82, 1); +INSERT INTO bank2 (username, fullname, balance, Group_id) VALUES('bitdiddl', 'Ben Bitdiddle', 82, 1); +INSERT INTO bank2 (username, fullname, balance, Group_id) VALUES('mike', 'Michael Dole', 73, 2); +INSERT INTO bank2 (username, fullname, balance, Group_id) VALUES('alyssa', 'Alyssa P. Hacker', 79, 3); +INSERT INTO bank2 (username, fullname, balance, Group_id) VALUES('bbrown', 'Bob Brown', 100, 3); + +-- Terminal 1 +BEGIN; +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +SELECT * from bank2; +-- id | username | fullname | balance | group_id +-- ----+----------+------------------+---------+---------- +-- 1 | jones | Alice Jones | 82 | 1 +-- 2 | bitdiddl | Ben Bitdiddle | 82 | 1 +-- 3 | mike | Michael Dole | 73 | 2 +-- 4 | alyssa | Alyssa P. Hacker | 79 | 3 +-- 5 | bbrown | Bob Brown | 100 | 3 +SELECT * from bank2; +-- id | username | fullname | balance | group_id +-- ----+----------+------------------+---------+---------- +-- 1 | jones | Alice Jones | 82 | 1 +-- 2 | bitdiddl | Ben Bitdiddle | 82 | 1 +-- 3 | mike | Michael Dole | 73 | 2 +-- 4 | alyssa | Alyssa P. Hacker | 79 | 3 +-- 5 | bbrown | Bob Brown | 100 | 3 +-- Nothing changed after the change in second terminal + +-- Terminal 2 +BEGIN; +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +UPDATE bank2 SET username='ajones' WHERE fullname='Alice Jones'; +SELECT * from bank2; +-- id | username | fullname | balance | group_id +-- ----+----------+------------------+---------+---------- +-- 2 | bitdiddl | Ben Bitdiddle | 82 | 1 +-- 3 | mike | Michael Dole | 73 | 2 +-- 4 | alyssa | Alyssa P. Hacker | 79 | 3 +-- 5 | bbrown | Bob Brown | 100 | 3 +-- 1 | ajones | Alice Jones | 82 | 1 +-- The results are different because isolation level read commited allows to read only commited changes +COMMIT; +-- After commitment, they are the same + +-- Term 1 +UPDATE bank2 SET balance=balance+10 WHERE id=1; +-- Term 2 +UPDATE bank2 SET balance=balance+20 WHERE id=1; +-- it waits the commitment from term 1 +-- Term 1 +COMMIT; +-- Term 2 +ROLLBACK; + +-- Repetable read +UPDATE bank2 SET username='jones' WHERE fullname='Alice Jones'; +-- Term 1 +BEGIN; +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +SELECT * from bank2; +SELECT * from bank2; +SELECT * from bank2; +UPDATE bank2 SET balance=balance+10 WHERE id=1; +COMMIT; + +-- Term 2 +BEGIN; +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +UPDATE bank2 SET username='ajones' WHERE fullname='Alice Jones'; +COMMIT; +BEGIN; +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +UPDATE bank2 SET balance=balance+20 WHERE id=1; + +-- Even after COMMIT on term 2, the data doesn't change on Term 1 because of the transaction isolation repetable read +-- Also after the balance change on the second term this error shows up:ERROR: could not serialize access due to concurrent update + +-- PART 2 + +-- TERM 1 +BEGIN; +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +SELECT * from bank2 WHERE Group_id=2; +SELECT * from bank2 WHERE Group_id=2; +UPDATE bank2 SET balance=balance+15 WHERE Group_id=2; +-- Mike shows up + + +-- TERM 2 +BEGIN; +SET TRANSACTION ISOLATION LEVEL READ COMMITTED; +UPDATE bank2 SET Group_id=2 WHERE username='bbrown'; + +-- BOB's balance hasn't change because when READ COMMITTED is set, it's impossible to view changes in other running transaction, so only balance of mike changed + +-- REPEATABLE +UPDATE bank2 SET Group_id=3 WHERE username='bbrown'; +-- TERM 1 +BEGIN; +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +SELECT * from bank2 WHERE Group_id=2; +SELECT * from bank2 WHERE Group_id=2; +UPDATE bank2 SET balance=balance+15 WHERE Group_id=2; +-- Mike shows up + + +-- TERM 2 +BEGIN; +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +UPDATE bank2 SET Group_id=2 WHERE username='bbrown'; + +-- THE same result