-
Notifications
You must be signed in to change notification settings - Fork 925
/
ddl.sql
146 lines (129 loc) · 3.56 KB
/
ddl.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
-- Create users table
CREATE UNLOGGED TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
balance INT NOT NULL,
account_limit INT NOT NULL DEFAULT 0
);
-- Create transactions table
CREATE UNLOGGED TABLE IF NOT EXISTS transactions (
id SERIAL PRIMARY KEY,
client_id INT NOT NULL,
value INT NOT NULL,
kind VARCHAR(1) NOT NULL,
description VARCHAR(10) NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);
-- Create index for transactions table
CREATE INDEX idx_client_id_transactions ON transactions (client_id, timestamp DESC);
-- Function to get bank statement
CREATE OR REPLACE FUNCTION fn_get_last_transactions(var_id INT) RETURNS TABLE (
fn_res_balance INT,
fn_res_account_limit INT,
fn_res_timestamp TIMESTAMP WITHOUT TIME ZONE,
fn_res_value INT,
fn_res_kind VARCHAR(1),
fn_res_description VARCHAR(10),
fn_res_transaction_timestamp TIMESTAMP,
fn_res_code INT
) AS $$
BEGIN
PERFORM 1 FROM users WHERE id = var_id;
IF NOT FOUND THEN
RETURN QUERY SELECT
0,
0,
CURRENT_TIMESTAMP AT TIME ZONE 'UTC',
0,
''::VARCHAR,
''::VARCHAR,
CURRENT_TIMESTAMP AT TIME ZONE 'UTC',
-1;
END IF;
RETURN QUERY SELECT
u.balance,
u.account_limit,
CURRENT_TIMESTAMP AT TIME ZONE 'UTC',
t.value,
t.kind,
t.description,
t.timestamp,
1
FROM
users u
LEFT JOIN
transactions t ON t.client_id = u.id
WHERE
u.id = var_id
ORDER BY
t.timestamp DESC
LIMIT 10;
END;
$$ LANGUAGE plpgsql;
-- Function for crediting
CREATE OR REPLACE FUNCTION fn_credit(
fn_client_id INT,
fn_description VARCHAR(10),
fn_kind VARCHAR(1),
fn_value INT
) RETURNS TABLE (
fn_res_limit INT,
fn_res_balance INT,
fn_res_code INT
) AS $$
DECLARE
var_balance INT;
var_limit INT;
BEGIN
PERFORM pg_advisory_xact_lock(fn_client_id);
SELECT balance, account_limit INTO var_balance, var_limit
FROM users
WHERE id = fn_client_id;
IF NOT FOUND THEN
RETURN QUERY SELECT 0, 0, 3;
END IF;
INSERT INTO transactions (client_id, description, kind, value)
VALUES (fn_client_id, fn_description, fn_kind, fn_value);
UPDATE users
SET balance = balance + fn_value
WHERE id = fn_client_id
RETURNING account_limit, balance, 1
INTO fn_res_limit, fn_res_balance, fn_res_code;
RETURN NEXT;
END;
$$ LANGUAGE plpgsql;
-- Function for debiting
CREATE OR REPLACE FUNCTION fn_debit(
fn_client_id INT,
fn_description VARCHAR(10),
fn_kind VARCHAR(1),
fn_value INT
) RETURNS TABLE (
fn_res_limit INT,
fn_res_balance INT,
fn_res_code INT
) AS $$
DECLARE
var_balance INT;
var_limit INT;
BEGIN
PERFORM pg_advisory_xact_lock(fn_client_id);
SELECT balance, account_limit INTO var_balance, var_limit
FROM users
WHERE id = fn_client_id;
IF NOT FOUND THEN
RETURN QUERY SELECT 0, 0, 3;
END IF;
IF var_balance - fn_value >= var_limit * -1 THEN
INSERT INTO transactions (client_id, description, kind, value)
VALUES (fn_client_id, fn_description, fn_kind, fn_value);
UPDATE users
SET balance = balance - fn_value
WHERE id = fn_client_id
RETURNING account_limit, balance, 1
INTO fn_res_limit, fn_res_balance, fn_res_code;
RETURN NEXT;
ELSE
RETURN QUERY SELECT var_limit, var_balance, 2;
END IF;
END;
$$ LANGUAGE plpgsql;