Я искал то же самое пару лет назад.Одна триггерная функция, чтобы управлять ими всеми!Я спрашивал в списках usenet, пробовал разные подходы, но безрезультатно.Консенсус по этому вопросу был , это не могло быть сделано .Недостаток PostgreSQL 8.3 или старше.
Начиная с PostgreSQL 8.4 вы можете просто:
EXECUTE 'INSERT INTO ' || TG_RELID::regclass::text || ' SELECT ($1).*'
USING NEW;
С pg 8.2 у вас возникла проблема:
- не может динамически обращаться к столбцам
NEW
/ OLD
.Вам нужно знать имена столбцов во время написания триггерной функции. NEW
/ OLD
не видны внутри EXECUTE
. EXECUTE .. USING
еще не родился.
Однако есть хитрость.
Каждое имя таблицы в системе может служить составным типом с таким же именем.Поэтому вы можете создать функцию, которая принимает NEW
/ OLD
в качестве параметра и выполнять ее.Вы можете динамически создавать и уничтожать эту функцию при каждом событии триггера:
Функция триггера:
CREATE OR REPLACE FUNCTION trg_cdc()
RETURNS trigger AS
$func$
DECLARE
op text := TG_OP || '_' || TG_WHEN;
tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
|| quote_ident(TG_TABLE_NAME);
cdc_tbl text := quote_ident(TG_TABLE_SCHEMA) || '.'
|| quote_ident('cdc_' || TG_TABLE_NAME);
BEGIN
EXECUTE 'CREATE FUNCTION f_cdc(n ' || tbl || ', op text)
RETURNS void AS $x$ BEGIN
INSERT INTO ' || cdc_tbl || ' SELECT op, (n).*;
END $x$ LANGUAGE plpgsql';
CASE TG_OP
WHEN 'INSERT', 'UPDATE' THEN
PERFORM f_cdc(NEW, op);
WHEN 'DELETE' THEN
PERFORM f_cdc(OLD, op);
ELSE
RAISE EXCEPTION 'Unknown TG_OP: "%". Should not occur!', TG_OP;
END CASE;
EXECUTE 'DROP FUNCTION f_cdc(' || tbl || ', text)';
IF TG_OP = 'DELETE' THEN
RETURN OLD;
ELSE
RETURN NEW;
END IF;
END
$func$ LANGUAGE plpgsql;
Триггер:
CREATE TRIGGER cdc
BEFORE INSERT OR UPDATE OR DELETE ON my_tbl
FOR EACH ROW EXECUTE PROCEDURE trg_cdc();
Имена таблиц должны обрабатываться как пользовательвход.Используйте quote_ident()
для защиты от внедрения SQL.
Однако , таким образом вы создаете и удаляете функцию для каждого отдельного события триггера.Довольно накладные расходы, я бы не пошел на это.Вам придется много пылесосить некоторые каталожные таблицы.
Средний уровень
PostgreSQL поддерживает перегрузку функции .Следовательно, одна функция на таблицу с одним и тем же базовым именем (но с другим типом параметра) может сосуществовать.Вы можете занять среднее положение и значительно уменьшить шум, создав f_cdc(..)
один раз для каждой таблицы в то же время, когда вы создаете триггер.Это одна крошечная функция на таблицу.Вы должны наблюдать за изменениями в определениях таблиц, но таблицы не должны так часто меняться.Удалите CREATE
и DROP FUNCTION
из функции триггера, чтобы получить небольшой, быстрый и элегантный триггер.
Я мог видеть, что я делаю это на стр. 8.2.За исключением того, что я больше не вижу, как я делаю что-нибудь в pg 8.2.В декабре 2011 года достиг конца жизни .Может быть, вы все-таки сможете как-нибудь обновить.