forked from nearform/temporal_tables
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathversioning_function_nochecks.sql
83 lines (73 loc) · 2.42 KB
/
versioning_function_nochecks.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
CREATE OR REPLACE FUNCTION versioning()
RETURNS TRIGGER AS $$
DECLARE
sys_period text;
history_table text;
manipulate jsonb;
commonColumns text[];
time_stamp_to_use timestamptz := current_timestamp;
range_lower timestamptz;
transaction_info txid_snapshot;
existing_range tstzrange;
BEGIN
-- version 0.0.1
sys_period := TG_ARGV[0];
history_table := TG_ARGV[1];
IF TG_OP = 'UPDATE' OR TG_OP = 'DELETE' THEN
-- Ignore rows already modified in this transaction
transaction_info := txid_current_snapshot();
IF OLD.xmin::text >= (txid_snapshot_xmin(transaction_info) % (2^32)::bigint)::text
AND OLD.xmin::text <= (txid_snapshot_xmax(transaction_info) % (2^32)::bigint)::text THEN
IF TG_OP = 'DELETE' THEN
RETURN OLD;
END IF;
RETURN NEW;
END IF;
EXECUTE format('SELECT $1.%I', sys_period) USING OLD INTO existing_range;
IF TG_ARGV[2] = 'true' THEN
-- mitigate update conflicts
range_lower := lower(existing_range);
IF range_lower >= time_stamp_to_use THEN
time_stamp_to_use := range_lower + interval '1 microseconds';
END IF;
END IF;
WITH history AS
(SELECT attname
FROM pg_attribute
WHERE attrelid = history_table::regclass
AND attnum > 0
AND NOT attisdropped),
main AS
(SELECT attname
FROM pg_attribute
WHERE attrelid = TG_RELID
AND attnum > 0
AND NOT attisdropped)
SELECT array_agg(quote_ident(history.attname)) INTO commonColumns
FROM history
INNER JOIN main
ON history.attname = main.attname
AND history.attname != sys_period;
EXECUTE ('INSERT INTO ' ||
CASE split_part(history_table, '.', 2)
WHEN '' THEN
quote_ident(history_table)
ELSE
quote_ident(split_part(history_table, '.', 1)) || '.' || quote_ident(split_part(history_table, '.', 2))
END ||
'(' ||
array_to_string(commonColumns , ',') ||
',' ||
quote_ident(sys_period) ||
') VALUES ($1.' ||
array_to_string(commonColumns, ',$1.') ||
',tstzrange($2, $3, ''[)''))')
USING OLD, range_lower, time_stamp_to_use;
END IF;
IF TG_OP = 'UPDATE' OR TG_OP = 'INSERT' THEN
manipulate := jsonb_set('{}'::jsonb, ('{' || sys_period || '}')::text[], to_jsonb(tstzrange(time_stamp_to_use, null, '[)')));
RETURN jsonb_populate_record(NEW, manipulate);
END IF;
RETURN OLD;
END;
$$ LANGUAGE plpgsql;