Class: PgAuditLog::Function

Inherits:
ActiveRecord show all
Defined in:
lib/pg_audit_log/function.rb

Constant Summary collapse

DISABLED_USER =
-2396

Class Method Summary collapse

Class Method Details

.installObject



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
# File 'lib/pg_audit_log/function.rb', line 46

def install
  execute <<-SQL
  CREATE OR REPLACE PROCEDURAL LANGUAGE plpgsql;
  CREATE OR REPLACE FUNCTION #{name}() RETURNS trigger
  LANGUAGE plpgsql
  AS $_$
      DECLARE
        col information_schema.columns %ROWTYPE;
        new_value text;
        old_value text;
        primary_key_column varchar;
        primary_key_value varchar;
        user_identifier integer;
        unique_name varchar;
        column_name varchar;
      BEGIN
        user_identifier := #{pg_audit_log_old_style_user_id ? %q(current_setting('audit.user_id')) : 'pg_temp.pg_audit_log_user_identifier()'};
        IF user_identifier = #{DISABLED_USER} THEN
          RETURN NULL;
        END IF;
        unique_name := #{pg_audit_log_old_style_user_id ? %q(current_setting('audit.user_unique_name')) : 'pg_temp.pg_audit_log_user_unique_name()'};
        primary_key_column := NULL;
        EXECUTE 'SELECT pg_attribute.attname
                 FROM pg_index, pg_class, pg_attribute
                 WHERE pg_class.oid = $1::regclass
                 AND indrelid = pg_class.oid
                 AND pg_attribute.attrelid = pg_class.oid
                 AND pg_attribute.attnum = any(pg_index.indkey)
                 AND indisprimary'
        INTO primary_key_column USING TG_RELNAME;
        primary_key_value := NULL;

        FOR col IN SELECT * FROM information_schema.columns WHERE table_name = TG_RELNAME LOOP
          new_value := NULL;
          old_value := NULL;
          column_name := col.column_name;
          IF TG_RELNAME = '#{users_table_name}' AND column_name = '#{users_access_column}' THEN
            NULL;
          ELSE
            IF TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN
              EXECUTE 'SELECT CAST($1 . '|| column_name ||' AS TEXT)' INTO new_value USING NEW;
              IF primary_key_value IS NULL AND primary_key_column IS NOT NULL THEN
                EXECUTE 'SELECT CAST($1 . '|| primary_key_column ||' AS VARCHAR)' INTO primary_key_value USING NEW;
              END IF;
            END IF;
            IF TG_OP = 'DELETE' OR TG_OP = 'UPDATE' THEN
              EXECUTE 'SELECT CAST($1 . '|| column_name ||' AS TEXT)' INTO old_value USING OLD;
              IF primary_key_value IS NULL AND primary_key_column IS NOT NULL THEN
                EXECUTE 'SELECT CAST($1 . '|| primary_key_column ||' AS VARCHAR)' INTO primary_key_value USING OLD;
              END IF;
            END IF;

            IF TG_OP != 'UPDATE' OR new_value != old_value OR (TG_OP = 'UPDATE' AND ( (new_value IS NULL AND old_value IS NOT NULL) OR (new_value IS NOT NULL AND old_value IS NULL))) THEN
              INSERT INTO audit_log("operation",
                                    "table_name",
                                    "primary_key",
                                    "field_name",
                                    "field_value_old",
                                    "field_value_new",
                                    "user_id",
                                    "user_unique_name",
                                    "occurred_at"
                                   )
              VALUES(TG_OP,
                    TG_RELNAME,
                    primary_key_value,
                    column_name,
                    old_value,
                    new_value,
                    user_identifier,
                    unique_name,
                    current_timestamp);
            END IF;
          END IF;
        END LOOP;
        RETURN NULL;
      END
      $_$;
  SQL
end

.installed?Boolean

Returns:

  • (Boolean)


131
132
133
134
135
136
137
# File 'lib/pg_audit_log/function.rb', line 131

def installed?
  connection.select_values(<<-SQL).first.to_i == 1
    SELECT COUNT(pg_proc.proname)
    FROM pg_proc
    WHERE pg_proc.proname = '#{name}'
  SQL
end

.nameObject



6
7
8
# File 'lib/pg_audit_log/function.rb', line 6

def name
  'audit_changes'
end

.pg_audit_log_old_style_user_idObject



26
27
28
# File 'lib/pg_audit_log/function.rb', line 26

def pg_audit_log_old_style_user_id
  defined?(Rails) && Rails.configuration.pg_audit_log_old_style_user_id rescue false
end

.uninstallObject



127
128
129
# File 'lib/pg_audit_log/function.rb', line 127

def uninstall
  execute "DROP FUNCTION IF EXISTS #{name}() CASCADE"
end

.user_id_fieldObject



14
15
16
# File 'lib/pg_audit_log/function.rb', line 14

def user_id_field
  'user_id'
end

.user_identifier_temporary_function(user_id) ⇒ Object



30
31
32
33
34
35
36
# File 'lib/pg_audit_log/function.rb', line 30

def user_identifier_temporary_function(user_id)
  if pg_audit_log_old_style_user_id
    "SET audit.user_id = #{user_id || -1};"
  else
    "CREATE OR REPLACE FUNCTION pg_temp.pg_audit_log_user_identifier() RETURNS integer AS 'SELECT #{user_id}' LANGUAGE SQL STABLE;"
  end
end

.user_name_fieldObject



18
19
20
# File 'lib/pg_audit_log/function.rb', line 18

def user_name_field
  'user_unique_name'
end

.user_unique_name_temporary_function(username) ⇒ Object



38
39
40
41
42
43
44
# File 'lib/pg_audit_log/function.rb', line 38

def user_unique_name_temporary_function(username)
  if pg_audit_log_old_style_user_id
    "SET audit.user_unique_name = '#{PGconn.escape_bytea(username)}';"
  else
    "CREATE OR REPLACE FUNCTION pg_temp.pg_audit_log_user_unique_name() RETURNS varchar AS $_$ SELECT '#{PGconn.escape_bytea(username)}'::varchar $_$ LANGUAGE SQL STABLE;"
  end
end

.users_access_columnObject



22
23
24
# File 'lib/pg_audit_log/function.rb', line 22

def users_access_column
  'last_accessed_at'
end

.users_table_nameObject



10
11
12
# File 'lib/pg_audit_log/function.rb', line 10

def users_table_name
  'users'
end