CREATE OR REPLACE FUNCTION logs.tf_log_table() RETURNS trigger AS $BODY$ DECLARE query text; safe_table_name text; BEGIN SELECT quote_ident(nspname||'.'||relname) FROM pg_class cl INNER JOIN pg_namespace nsp ON (cl.relnamespace=nsp.oid) WHERE cl.oid=TG_RELID INTO safe_table_name; query='INSERT INTO logs.'||safe_table_name||' SELECT ($1).*, now(),$2,session_user;'; IF (TG_OP = 'DELETE') THEN EXECUTE query using OLD,'D'; RETURN OLD; ELSIF (TG_OP = 'UPDATE') THEN EXECUTE query using OLD,'U'; RETURN NEW; ELSIF (TG_OP = 'INSERT') THEN EXECUTE query using NEW,'I'; RETURN NEW; END IF; /* , , */ EXCEPTION WHEN SQLSTATE '42P01' OR SQLSTATE '42801' OR SQLSTATE '42804' THEN PERFORM logs.create_log_tables(TG_RELID::regclass); IF (TG_OP = 'DELETE') THEN EXECUTE query using OLD,'D'; RETURN OLD; ELSIF (TG_OP = 'UPDATE') THEN EXECUTE query using OLD,'U'; RETURN NEW; ELSIF (TG_OP = 'INSERT') THEN EXECUTE query using NEW,'I'; RETURN NEW; END IF; /* - , */ WHEN OTHERS then IF (TG_OP = 'DELETE') THEN RETURN OLD; ELSE RETURN NEW; END IF; END; $BODY$ LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
SELECT quote_ident (nspname || '.' || relname)
FROM pg_class cl INNER JOIN pg_namespace nsp ON (cl.relnamespace = nsp.oid)
WHERE cl.oid = TG_RELID INTO safe_table_name;
query = 'INSERT INTO logs.' || safe_table_name || ' SELECT ($ 1). *, Now (), $ 2, session_user; ';
IF (TG_OP = 'DELETE')
THEN
EXECUTE query USING OLD, 'D';
EXCEPTION
WHEN SQLSTATE '42P01' OR SQLSTATE '42801' OR SQLSTATE '42804' THEN
PERFORM logs.create_log_tables (TG_RELID :: regclass);
CREATE OR REPLACE FUNCTION logs.create_log_tables(table_oid oid) RETURNS int AS $BODY$ DECLARE log_namespace oid=(SELECT oid from pg_namespace WHERE nspname='logs'); p_relname text; new_tbl_name text; safe_table_name text; BEGIN SELECT relname FROM pg_class WHERE oid=table_oid INTO p_relname; SELECT quote_ident(nspname||'.'||relname) FROM pg_class cl inner join pg_namespace nsp ON (cl.relnamespace=nsp.oid) where cl.oid=table_oid INTO safe_table_name; /* */ SELECT safe_table_name||'_'||(now()::date)::text||'('||i||')' FROM generate_series(1,10) a(i) WHERE safe_table_name||'_'||(now()::date)::text||'('||i||')' not in(select relname from pg_class where relnamespace=log_namespace and relpersistence='p') ORDER BY i LIMIT 1 INTO new_tbl_name; /* */ EXECUTE 'ALTER TABLE IF EXISTS logs.'||safe_table_name|| ' RENAME TO '||quote_ident(new_tbl_name)||';'; /* , , */ EXECUTE 'create table logs.'||safe_table_name||' (like '||table_oid::regclass||');'; EXECUTE 'ALTER TABLE logs.'||safe_table_name||' ADD COLUMN "'||p_relname||'_timestamp" timestamp with time zone;'; EXECUTE 'ALTER TABLE logs.'||safe_table_name||' ADD COLUMN "'||p_relname||'_operation" char;'; EXECUTE 'ALTER TABLE logs.'||safe_table_name||' ADD COLUMN "'||p_relname||'_user" text;'; /* */ EXECUTE ' DROP TRIGGER IF exists tr_log_table ON '||table_oid::regclass::text||'; CREATE TRIGGER tr_log_table BEFORE UPDATE OR DELETE OR INSERT ON '||table_oid::regclass::text||' FOR EACH ROW EXECUTE PROCEDURE logs.tf_log_table();'; RETURN 0; end; $BODY$ LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
Source: https://habr.com/ru/post/323618/
All Articles