CREATE SEQUENCE activity_seq; CREATE TABLE patch_audit ( patch_id integer not null, change_type varchar not null, changed_fields varchar[] not null, commitfest_id integer not null, original_name varchar not null, from_commitfest_id integer, to_commitfest_id integer, commitfest_topic_id integer not null, name varchar not null, patch_status_id integer not null, author varchar not null, reviewers varchar not null, date_closed date, last_updater varchar, last_updated_time timestamp with time zone not null ); ALTER TABLE patch_audit ADD COLUMN activity_id INTEGER NOT NULL DEFAULT nextval('activity_seq'); ALTER TABLE patch_audit ADD COLUMN committer VARCHAR NOT NULL DEFAULT ''; CREATE OR REPLACE FUNCTION patch_audit() RETURNS trigger AS $$ DECLARE cf varchar[] := '{}'::varchar[]; acid integer; cid integer; oname varchar; BEGIN IF (TG_OP = 'DELETE') THEN NEW := OLD; NEW.last_updated_time := now(); END IF; IF (TG_OP = 'UPDATE') THEN IF (OLD.last_updated_time = NEW.last_updated_time) THEN -- Some kind of system update, just ignore it. RETURN NULL; END IF; cf := CASE WHEN OLD.commitfest_topic_id != NEW.commitfest_topic_id THEN '{commitfest_topic_id}'::varchar[] ELSE '{}'::varchar[] END || CASE WHEN OLD.name != NEW.name THEN '{name}'::varchar[] ELSE '{}'::varchar[] END || CASE WHEN OLD.patch_status_id != NEW.patch_status_id THEN '{patch_status_id}'::varchar[] ELSE '{}'::varchar[] END || CASE WHEN OLD.author != NEW.author THEN '{author}'::varchar[] ELSE '{}'::varchar[] END || CASE WHEN OLD.reviewers != NEW.reviewers THEN '{reviewers}'::varchar[] ELSE '{}'::varchar[] END || CASE WHEN OLD.committer != NEW.committer THEN '{committer}'::varchar[] ELSE '{}'::varchar[] END || CASE WHEN OLD.date_closed IS DISTINCT FROM NEW.date_closed THEN '{date_closed}'::varchar[] ELSE '{}'::varchar[] END; SELECT INTO cid commitfest_id FROM commitfest_topic WHERE id = NEW.commitfest_topic_id; SELECT INTO acid commitfest_id FROM commitfest_topic WHERE id = OLD.commitfest_topic_id; oname := OLD.name; ELSE SELECT INTO cid, acid commitfest_id, commitfest_id FROM commitfest_topic WHERE id = NEW.commitfest_topic_id; oname := NEW.name; END IF; IF (TG_OP = 'INSERT') THEN cf := ARRAY['commitfest_id', 'commitfest_topic_id', 'name', 'patch_status_id', 'author', 'reviewers', 'committer', 'date_closed']; END IF; INSERT INTO patch_audit (patch_id, change_type, changed_fields, commitfest_id, original_name, to_commitfest_id, commitfest_topic_id, name, patch_status_id, author, reviewers, committer, date_closed, last_updater, last_updated_time) VALUES (NEW.id, TG_OP, cf, acid, oname, CASE WHEN cid != acid THEN cid ELSE NULL END, NEW.commitfest_topic_id, NEW.name, NEW.patch_status_id, NEW.author, NEW.reviewers, NEW.committer, NEW.date_closed, NEW.last_updater, NEW.last_updated_time); -- For an update that changes the CommitFest, we enter two audit records, -- one under each CommitFest. IF (cid != acid) THEN INSERT INTO patch_audit (patch_id, change_type, changed_fields, commitfest_id, original_name, from_commitfest_id, commitfest_topic_id, name, patch_status_id, author, reviewers, committer, date_closed, last_updater, last_updated_time) VALUES (NEW.id, TG_OP, cf, cid, oname, acid, NEW.commitfest_topic_id, NEW.name, NEW.patch_status_id, NEW.author, NEW.reviewers, NEW.committer, NEW.date_closed, NEW.last_updater, NEW.last_updated_time); END IF; RETURN NULL; END $$ LANGUAGE plpgsql; CREATE TRIGGER patch_audit AFTER INSERT OR UPDATE OR DELETE ON patch FOR EACH ROW EXECUTE PROCEDURE patch_audit(); CREATE OR REPLACE FUNCTION patch_audit_details(patch_audit) RETURNS text AS $$ DECLARE v varchar[]; BEGIN IF ('name' = ANY($1.changed_fields)) THEN v := v || ('Name = ' || $1.name)::varchar; END IF; IF ($1.from_commitfest_id IS NOT NULL) THEN v := v || ('Moved From CommitFest = ' || COALESCE((SELECT name FROM commitfest WHERE id = $1.from_commitfest_id), '???'))::varchar; END IF; IF ($1.to_commitfest_id IS NOT NULL) THEN v := v || ('Moved To CommitFest = ' || COALESCE((SELECT name FROM commitfest WHERE id = $1.to_commitfest_id), '???'))::varchar; END IF; IF ('commitfest_topic_id' = ANY($1.changed_fields)) THEN v := v || ('Topic = ' || COALESCE((SELECT name FROM commitfest_topic WHERE id = $1.commitfest_topic_id), '???'))::varchar; END IF; IF ('patch_status_id' = ANY($1.changed_fields)) THEN v := v || ('Patch Status = ' || COALESCE((SELECT name FROM patch_status WHERE id = $1.patch_status_id), '???'))::varchar; END IF; IF ('author' = ANY($1.changed_fields)) THEN v := v || ('Author = ' || $1.author)::varchar; END IF; IF ('reviewers' = ANY($1.changed_fields)) THEN v := v || ('Reviewers = ' || CASE WHEN $1.reviewers = '' THEN 'Nobody' ELSE $1.reviewers END)::varchar; END IF; IF ('committer' = ANY($1.changed_fields)) THEN v := v || ('Committer = ' || CASE WHEN $1.committer = '' THEN 'Nobody' ELSE $1.committer END)::varchar; END IF; IF ('date_closed' = ANY($1.changed_fields)) THEN v := v || ('Date Closed = ' || COALESCE($1.date_closed::varchar, 'NULL'))::varchar; END IF; RETURN array_to_string(v, ', '); END $$ LANGUAGE plpgsql; CREATE TABLE patch_comment_audit ( id integer not null, patch_id integer not null, change_type varchar not null, changed_fields varchar[] not null, commitfest_id integer not null, patch_name varchar not null, patch_comment_type_id integer not null, message_id varchar, content varchar, last_updater varchar, last_updated_time timestamp with time zone not null ); ALTER TABLE patch_comment_audit ADD COLUMN activity_id INTEGER NOT NULL DEFAULT nextval('activity_seq'); CREATE OR REPLACE FUNCTION patch_comment_audit() RETURNS trigger AS $$ DECLARE cf varchar[] := '{}'::varchar[]; cid integer; pname varchar; BEGIN IF (TG_OP = 'DELETE') THEN NEW := OLD; NEW.last_updated_time := now(); END IF; IF (TG_OP = 'UPDATE') THEN IF (OLD.last_updated_time = NEW.last_updated_time) THEN -- Some kind of system update, just ignore it. RETURN NULL; END IF; cf := CASE WHEN OLD.patch_comment_type_id != NEW.patch_comment_type_id THEN '{patch_comment_type_id}'::varchar[] ELSE '{}'::varchar[] END || CASE WHEN OLD.message_id != NEW.message_id THEN '{message_id}'::varchar[] ELSE '{}'::varchar[] END || CASE WHEN OLD.content != NEW.content THEN '{content}'::varchar[] ELSE '{}'::varchar[] END; END IF; SELECT INTO cid, pname t.commitfest_id, p.name FROM patch p JOIN commitfest_topic t ON p.commitfest_topic_id = t.id WHERE p.id = NEW.patch_id; IF (TG_OP = 'INSERT') THEN cf := ARRAY['patch_comment_type_id', 'message_id', 'content' ]; END IF; INSERT INTO patch_comment_audit (id, patch_id, change_type, changed_fields, commitfest_id, patch_name, patch_comment_type_id, message_id, content, last_updater, last_updated_time) VALUES (NEW.id, NEW.patch_id, TG_OP, cf, cid, pname, NEW.patch_comment_type_id, NEW.message_id, NEW.content, NEW.last_updater, NEW.last_updated_time); RETURN NULL; END $$ LANGUAGE plpgsql; CREATE TRIGGER patch_comment_audit AFTER INSERT OR UPDATE OR DELETE ON patch_comment FOR EACH ROW EXECUTE PROCEDURE patch_comment_audit(); CREATE OR REPLACE FUNCTION patch_comment_audit_details(patch_comment_audit) RETURNS text AS $$ SELECT (SELECT name FROM patch_comment_type WHERE id = $1.patch_comment_type_id) || ': ' || $1.content || CASE WHEN $1.message_id != '' THEN ' (Message-ID: ' || $1.message_id || ')' ELSE '' END $$ LANGUAGE sql;