File: table_log--0.6.1.sql

package info (click to toggle)
tablelog 0.6.4-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 244 kB
  • sloc: ansic: 1,284; sql: 708; makefile: 12; sh: 2
file content (202 lines) | stat: -rw-r--r-- 6,517 bytes parent folder | download | duplicates (3)
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
--
-- table_log () -- log changes to another table
--
--
-- see README.md for details
--
--
-- written by Andreas ' ads' Scherbaum (ads@pgug.de)
--
--

-- create function

CREATE FUNCTION table_log_basic()
    RETURNS TRIGGER
    AS 'MODULE_PATHNAME' LANGUAGE C;
CREATE FUNCTION table_log ()
    RETURNS TRIGGER
    AS 'MODULE_PATHNAME' LANGUAGE C;
CREATE FUNCTION "table_log_restore_table" (VARCHAR, VARCHAR, CHAR, CHAR, CHAR, TIMESTAMPTZ, CHAR, INT, INT)
    RETURNS VARCHAR
    AS 'MODULE_PATHNAME', 'table_log_restore_table' LANGUAGE C;
CREATE FUNCTION "table_log_restore_table" (VARCHAR, VARCHAR, CHAR, CHAR, CHAR, TIMESTAMPTZ, CHAR, INT)
    RETURNS VARCHAR
    AS 'MODULE_PATHNAME', 'table_log_restore_table' LANGUAGE C;
CREATE FUNCTION "table_log_restore_table" (VARCHAR, VARCHAR, CHAR, CHAR, CHAR, TIMESTAMPTZ, CHAR)
    RETURNS VARCHAR
    AS 'MODULE_PATHNAME', 'table_log_restore_table' LANGUAGE C;
CREATE FUNCTION "table_log_restore_table" (VARCHAR, VARCHAR, CHAR, CHAR, CHAR, TIMESTAMPTZ)
    RETURNS VARCHAR
    AS 'MODULE_PATHNAME', 'table_log_restore_table' LANGUAGE C;

CREATE OR REPLACE FUNCTION table_log_init(int, text, text, text, text, text DEFAULT 'SINGLE',
                                          boolean DEFAULT false,
                                          text[] DEFAULT '{INSERT, UPDATE, DELETE}'::text[]) RETURNS void AS
$table_log_init$
DECLARE
    level        ALIAS FOR $1;
    orig_schema  ALIAS FOR $2;
    orig_name    ALIAS FOR $3;
    log_schema   ALIAS FOR $4;
    log_name     ALIAS FOR $5;
    partition_mode ALIAS FOR $6;
    basic_mode     ALIAS FOR $7;
    log_actions  ALIAS FOR $8;
    do_log_user  int = 0;
    level_create text = '';
    orig_qq      text;
    log_qq       text;
    log_part     text[];
    log_seq      text;
    num_log_tables integer;
    trigger_func text := 'table_log';
    trigger_actions text := '';
    i integer;
BEGIN
    -- Handle if someone doesn't want an explicit log table name
    log_name := COALESCE(log_name, orig_name || '_log');

    -- Quoted qualified names
    orig_qq := quote_ident(orig_schema) || '.' || quote_ident(orig_name);
    log_qq := quote_ident(log_schema) || '.'  || quote_ident(log_name);
    log_seq := quote_ident(log_schema) || '.' || quote_ident(log_name || '_seq');
    log_part[0] := quote_ident(log_schema) || '.' || quote_ident(log_name || '_0');
    log_part[1] := quote_ident(log_schema) || '.' || quote_ident(log_name || '_1');

    -- Valid trigger actions?
    IF (COALESCE(array_length(log_actions, 1), 0) = 0) THEN
       RAISE EXCEPTION 'table_log_init: at least one trigger action must be specified';
    END IF;

    -- Valid partition mode ?
    IF (partition_mode NOT IN ('SINGLE', 'PARTITION')) THEN
        RAISE EXCEPTION 'table_log_init: unsupported partition mode %', partition_mode;
    END IF;

    IF level <> 3 THEN

       --
       -- Create a sequence used by trigger_id, if requested.
       --
       EXECUTE 'CREATE SEQUENCE ' || log_seq;

       level_create := level_create
           || ', trigger_id BIGINT'
           || ' DEFAULT nextval($$' || log_seq || '$$::regclass)'
           || ' NOT NULL PRIMARY KEY';

       IF level <> 4 THEN
           level_create := level_create
               || ', trigger_user VARCHAR(32) NOT NULL';
           do_log_user := 1;
           IF level <> 5 THEN
               RAISE EXCEPTION
                   'table_log_init: First arg has to be 3, 4 or 5.';
           END IF;
       END IF;
    END IF;

    IF (partition_mode = 'SINGLE') THEN
        EXECUTE  'CREATE TABLE ' || log_qq
              || '(LIKE ' || orig_qq
              || ', trigger_mode VARCHAR(10) NOT NULL'
              || ', trigger_tuple VARCHAR(5) NOT NULL'
              || ', trigger_changed TIMESTAMPTZ NOT NULL'
              || level_create
              || ')';

    ELSE
        -- Partitioned mode requested...
        EXECUTE  'CREATE TABLE ' || log_part[0]
              || '(LIKE ' || orig_qq
              || ', trigger_mode VARCHAR(10) NOT NULL'
              || ', trigger_tuple VARCHAR(5) NOT NULL'
              || ', trigger_changed TIMESTAMPTZ NOT NULL'
              || level_create
              || ')';

        EXECUTE  'CREATE TABLE ' || log_part[1]
              || '(LIKE ' || orig_qq
              || ', trigger_mode VARCHAR(10) NOT NULL'
              || ', trigger_tuple VARCHAR(5) NOT NULL'
              || ', trigger_changed TIMESTAMPTZ NOT NULL'
              || level_create
              || ')';

        EXECUTE 'CREATE VIEW ' || log_qq
              || ' AS SELECT * FROM ' || log_part[0] || ' UNION ALL '
              || 'SELECT * FROM ' || log_part[1] || '';
    END IF;

    --
    -- Either use basic or full trigger mode
    --
    IF basic_mode THEN
       trigger_func := 'table_log_basic';
    END IF;

    --
    -- Build action string for trigger DDL
    --
    FOR i IN 1..array_length(log_actions, 1)
    LOOP

        trigger_actions := trigger_actions || log_actions[i];

        IF i < array_length(log_actions, 1) THEN
           trigger_actions := trigger_actions || ' OR ';
        END IF;

    END LOOP;

    EXECUTE 'CREATE TRIGGER "table_log_trigger" AFTER ' || trigger_actions || ' ON '
            || orig_qq || ' FOR EACH ROW EXECUTE PROCEDURE ' || trigger_func || '('
            || quote_literal(log_name) || ','
            || do_log_user || ','
            || quote_literal(log_schema) || ','
            || quote_literal(partition_mode)
            || ')';

    RETURN;
END;
$table_log_init$
LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION table_log_init(int, text) RETURNS void AS '
DECLARE
    level        ALIAS FOR $1;
    orig_name    ALIAS FOR $2;
BEGIN
    PERFORM table_log_init(level, orig_name, current_schema());
    RETURN;
END;
' LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION table_log_init(int, text, text) RETURNS void AS '
DECLARE
    level        ALIAS FOR $1;
    orig_name    ALIAS FOR $2;
    log_schema   ALIAS FOR $3;
BEGIN
    PERFORM table_log_init(level, current_schema(), orig_name, log_schema);
    RETURN;
END;
' LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION table_log_init(int, text, text, text) RETURNS void AS '
DECLARE
    level        ALIAS FOR $1;
    orig_schema  ALIAS FOR $2;
    orig_name    ALIAS FOR $3;
    log_schema   ALIAS FOR $4;
BEGIN
    PERFORM table_log_init(level, orig_schema, orig_name, log_schema,
        CASE WHEN orig_schema=log_schema
            THEN orig_name||''_log'' ELSE orig_name END);
    RETURN;
END;
' LANGUAGE plpgsql;