-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathsql.py
More file actions
279 lines (238 loc) · 6.07 KB
/
sql.py
File metadata and controls
279 lines (238 loc) · 6.07 KB
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
def create_transactions():
return """
CREATE TABLE IF NOT EXISTS transactions (
hash TEXT NOT NULL PRIMARY KEY,
contract TEXT NOT NULL,
function TEXT NOT NULL,
sender TEXT NOT NULL,
nonce INTEGER NOT NULL,
stamps INTEGER NOT NULL,
block_hash TEXT NOT NULL,
block_height INTEGER NOT NULL,
block_time BIGINT NOT NULL,
success BOOLEAN,
result TEXT,
json_content JSONB NOT NULL,
created TIMESTAMP NOT NULL
)
"""
def create_state_changes():
return """
CREATE TABLE IF NOT EXISTS state_changes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tx_hash TEXT REFERENCES transactions(hash),
key TEXT NOT NULL,
value JSONB,
created TIMESTAMP NOT NULL
)
"""
def create_state():
return """
CREATE TABLE IF NOT EXISTS state (
key TEXT PRIMARY KEY,
value JSONB,
updated TIMESTAMP NOT NULL
)
"""
def create_rewards():
return """
CREATE TABLE IF NOT EXISTS rewards (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tx_hash TEXT REFERENCES transactions(hash),
type TEXT NOT NULL,
key TEXT,
value DECIMAL NOT NULL,
created TIMESTAMP NOT NULL
)
"""
def create_addresses():
return """
CREATE TABLE IF NOT EXISTS addresses (
tx_hash TEXT REFERENCES transactions(hash),
address TEXT NOT NULL PRIMARY KEY,
created TIMESTAMP NOT NULL
)
"""
def create_contracts():
return """
CREATE TABLE IF NOT EXISTS contracts (
tx_hash TEXT REFERENCES transactions(hash),
name TEXT NOT NULL PRIMARY KEY,
code TEXT NOT NULL,
XSC0001 BOOLEAN DEFAULT FALSE,
created TIMESTAMP NOT NULL
)
"""
def create_readonly_role():
return """
DO $$
BEGIN
-- Create the read-only role
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'readonly_user') THEN
CREATE ROLE readonly_user WITH LOGIN PASSWORD 'readonly';
END IF;
-- Grant read-only permissions
GRANT CONNECT ON DATABASE xian TO readonly_user;
GRANT USAGE ON SCHEMA public TO readonly_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly_user;
-- Ensure future tables also get SELECT permission
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO readonly_user;
-- Set resource limits
ALTER ROLE readonly_user SET statement_timeout = '1s';
ALTER ROLE readonly_user SET max_parallel_workers_per_gather = 2;
END
$$;
"""
def enforce_table_limits():
return """
DO $$
DECLARE
rec RECORD;
schema_name TEXT := 'public'; -- Change this to your schema name
limit_value INT := 100; -- Change this to your desired limit
BEGIN
FOR rec IN
SELECT table_name
FROM information_schema.tables
WHERE table_schema = schema_name
LOOP
EXECUTE format('SELECT * FROM %I.%I LIMIT %s', schema_name, rec.table_name, limit_value);
END LOOP;
END $$;
"""
def select_db_size():
return """
SELECT pg_size_pretty(pg_database_size(%(n)s))
"""
def insert_transaction():
return """
INSERT INTO transactions(
hash, contract, function, sender, nonce, stamps, block_hash,
block_height, block_time, success, result, json_content, created)
VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
ON CONFLICT (hash) DO NOTHING;
"""
def insert_or_update_state():
return """
INSERT INTO state(
key, value, updated)
VALUES (
$1, $2, $3)
ON CONFLICT (key) DO UPDATE SET
value = EXCLUDED.value,
updated = EXCLUDED.updated;
"""
def insert_state_changes():
return """
INSERT INTO state_changes(
id, tx_hash, key, value, created)
VALUES (
COALESCE($1, gen_random_uuid()), $2, $3, $4, $5)
ON CONFLICT (id) DO NOTHING;
"""
def insert_rewards():
return """
INSERT INTO rewards(
id, tx_hash, type, key, value, created)
VALUES (
COALESCE($1, gen_random_uuid()), $2, $3, $4, $5, $6)
ON CONFLICT (id) DO NOTHING;
"""
def insert_addresses():
return """
INSERT INTO addresses(
tx_hash, address, created)
VALUES (
$1, $2, $3)
ON CONFLICT (address) DO NOTHING;
"""
def insert_contracts():
return """
INSERT INTO contracts(
tx_hash, name, code, XSC0001, created)
VALUES (
$1, $2, $3, $4, $5)
ON CONFLICT (name) DO NOTHING;
"""
def select_contracts():
return """
SELECT
*
FROM
contracts
ORDER BY
created ASC
LIMIT $1 OFFSET $2
"""
def select_state():
return """
WITH ranked_state_changes AS (
SELECT
key,
value,
ROW_NUMBER() OVER (PARTITION BY key ORDER BY created DESC) AS rn
FROM
state_changes
WHERE
key LIKE $1 || '%'
)
SELECT
key,
value
FROM
ranked_state_changes
WHERE
rn = 1
LIMIT $2 OFFSET $3;
"""
def select_state_by_key():
return """
SELECT value FROM state WHERE key = $1;
"""
def select_state_history():
return """
SELECT
key,
value,
tx_hash,
created
FROM
state_changes
WHERE
key = $1
ORDER BY
created DESC
LIMIT $2 OFFSET $3
"""
def select_state_tx():
return """
SELECT
key, value
FROM
state_changes
WHERE
tx_hash = $1;
"""
def select_state_block_height():
return """
SELECT
sc.key, sc.value
FROM
state_changes sc
JOIN
transactions t ON sc.tx_hash = t.hash
WHERE
t.block_height = $1;
"""
def select_state_block_hash():
return """
SELECT
sc.key, sc.value
FROM
state_changes sc
JOIN
transactions t ON sc.tx_hash = t.hash
WHERE
t.block_hash = $1;
"""