-
Notifications
You must be signed in to change notification settings - Fork 0
/
pg_drop_events--0.1.sql
207 lines (192 loc) · 7.7 KB
/
pg_drop_events--0.1.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
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
/* pg_drop_events/pg_drop_events--0.1.sql */
-- complain if script is sourced in psql, rather than via create extension
\echo Use "CREATE EXTENSION pg_drop_events VERSION '0.1'" to load this file. \quit
DO $$
DECLARE pg_version int;
BEGIN
pg_version := pg_catalog.current_setting('server_version_num')::int;
IF pg_version < 130000 THEN
CREATE TABLE public.pg_drop_events (
pid int,
usename text,
query text,
xact_id bigint,
wal_position pg_lsn,
objid oid,
object_name text,
object_type text,
xact_time timestamp with time zone
);
ELSE
CREATE TABLE public.pg_drop_events (
pid int,
usename text,
query text,
xact_id xid8,
wal_position pg_lsn,
objid oid,
object_name text,
object_type text,
xact_time timestamp with time zone
);
END IF;
IF pg_version < 100000 THEN
CREATE OR REPLACE FUNCTION public.pg_drop_events()
RETURNS event_trigger AS $LD$
DECLARE
tbd record;
BEGIN
FOR tbd IN
SELECT
o.objid,
o.object_type,
o.object_identity
FROM pg_catalog.pg_event_trigger_dropped_objects() o
JOIN pg_catalog.pg_class c ON c.oid = o.classid
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE NOT o.is_temporary
AND c.relname = 'pg_class'
AND n.nspname = 'pg_catalog'
AND o.classid = c.oid
AND o.object_type = ANY ('{table, table column, materialized view}')
LOOP
RAISE NOTICE '% % dropped by transaction %.', tbd.object_type, tbd.object_identity, pg_catalog.txid_current();
INSERT INTO public.pg_drop_events (
pid,
usename,
query,
xact_id,
wal_position,
objid,
object_name,
object_type,
xact_time
)
SELECT
pg_catalog.pg_backend_pid(),
pg_catalog.session_user(),
trim(trailing ';' from pg_catalog.current_query()),
pg_catalog.txid_current(),
pg_catalog.pg_current_xlog_location(),
tbd.objid,
tbd.object_identity,
tbd.object_type,
pg_catalog.now();
END LOOP;
END;
$LD$ LANGUAGE plpgsql;
ELSIF pg_version >= 130000 THEN
CREATE OR REPLACE FUNCTION public.pg_drop_events()
RETURNS event_trigger AS $LD$
DECLARE
tbd record;
BEGIN
FOR tbd IN
SELECT
o.objid,
o.object_type,
o.object_identity
FROM pg_catalog.pg_event_trigger_dropped_objects() o
JOIN pg_catalog.pg_class c ON c.oid = o.classid
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE NOT o.is_temporary
AND c.relname = 'pg_class'
AND n.nspname = 'pg_catalog'
AND o.classid = c.oid
AND o.object_type = ANY ('{table, table column, materialized view}')
LOOP
RAISE NOTICE '% % dropped by transaction %.', tbd.object_type, tbd.object_identity, pg_catalog.pg_current_xact_id();
INSERT INTO public.pg_drop_events (
pid,
usename,
query,
xact_id,
wal_position,
objid,
object_name,
object_type,
xact_time
)
SELECT
pg_catalog.pg_backend_pid(),
pg_catalog.session_user(),
trim(trailing ';' from pg_catalog.current_query()),
pg_catalog.pg_current_xact_id(),
pg_catalog.pg_current_wal_lsn(),
tbd.objid,
tbd.object_identity,
tbd.object_type,
pg_catalog.now();
END LOOP;
END;
$LD$ LANGUAGE plpgsql;
ELSE
CREATE OR REPLACE FUNCTION public.pg_drop_events()
RETURNS event_trigger AS $LD$
DECLARE
tbd record;
BEGIN
FOR tbd IN
SELECT
o.objid,
o.object_type,
o.object_identity
FROM pg_event_trigger_dropped_objects() o
JOIN pg_catalog.pg_class c ON c.oid = o.classid
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE NOT o.is_temporary
AND c.relname = 'pg_class'
AND n.nspname = 'pg_catalog'
AND o.classid = c.oid
AND o.object_type = ANY ('{table, table column, materialized view}')
LOOP
RAISE NOTICE '% % dropped by transaction %.', tbd.object_type, tbd.object_identity, pg_catalog.txid_current();
INSERT INTO public.pg_drop_events (
pid,
usename,
query,
xact_id,
wal_position,
objid,
object_name,
object_type,
xact_time
)
SELECT
pg_catalog.pg_backend_pid(),
pg_catalog.session_user(),
trim(trailing ';' from pg_catalog.current_query()),
pg_catalog.txid_current(),
pg_catalog.pg_current_wal_lsn(),
tbd.objid,
tbd.object_identity,
tbd.object_type,
pg_catalog.now();
END LOOP;
END;
$LD$ LANGUAGE plpgsql;
END IF;
COMMENT ON FUNCTION public.pg_drop_events() IS 'logs transaction ids of drop table, drop column, drop materialized view statements to aid point in time recovery.';
CREATE OR REPLACE FUNCTION public.pg_drop_events_reset()
RETURNS void AS $ST$
TRUNCATE public.pg_drop_events;
$ST$ LANGUAGE sql;
COMMENT ON FUNCTION public.pg_drop_events_reset() IS 'reset all logged transaction ids of drop table, drop column, drop materialized view statements.';
CREATE OR REPLACE FUNCTION public.pg_drop_events_reset_single(poid oid)
RETURNS void AS $ST$
DELETE FROM public.pg_drop_events
WHERE objid = poid;
$ST$ LANGUAGE sql;
COMMENT ON FUNCTION public.pg_drop_events_reset_single(oid) IS 'reset logged transaction id of a particular object.';
--- Privileges management
REVOKE ALL ON TABLE public.pg_drop_events FROM PUBLIC;
REVOKE ALL ON FUNCTION public.pg_drop_events_reset() FROM PUBLIC;
REVOKE ALL ON FUNCTION public.pg_drop_events_reset_single(oid) FROM PUBLIC;
GRANT SELECT, INSERT ON TABLE public.pg_drop_events TO PUBLIC;
GRANT EXECUTE ON FUNCTION public.pg_drop_events_reset() TO postgres;
GRANT EXECUTE ON FUNCTION public.pg_drop_events_reset_single(oid) TO postgres;
END;
$$;
DROP EVENT TRIGGER IF EXISTS ZZZ_pg_drop_events;
CREATE EVENT TRIGGER ZZZ_pg_drop_events ON sql_drop
EXECUTE PROCEDURE public.pg_drop_events();