Подтвердить что ты не робот

Отладка триггера postgresql

У меня есть Trigger в Postgresql, что я не могу просто работать (ничего не делает). Для понимания, как я это определил:

CREATE TABLE documents (
    ...
    modification_time timestamp with time zone DEFAULT now()
);

CREATE FUNCTION documents_update_mod_time() RETURNS trigger
AS $$
    begin
    new.modification_time := now();
    return new;
    end
$$
    LANGUAGE plpgsql;

CREATE TRIGGER documents_modification_time
    BEFORE INSERT OR UPDATE ON documents
    FOR EACH ROW
    EXECUTE PROCEDURE documents_update_mod_time();

Теперь сделаем это немного интереснее.. Как вы отлаживаете триггеры?

4b9b3361

Ответ 1

  • Используйте следующий код в функции триггера, затем просмотрите вкладку "сообщения" в pgAdmin3 или вывод в psql:

    RAISE NOTICE 'myplpgsqlval is currently %', myplpgsqlval;       -- either this
    RAISE EXCEPTION 'failed';  -- or that
    
  • Чтобы узнать, какие триггеры на самом деле вызываются, сколько раз и т.д., следующее выражение является спасением жизни:

    EXPLAIN ANALYZE UPDATE table SET foo='bar'; -- shows the called triggers
    

    Обратите внимание, что если ваш триггер не вызван и вы используете наследование, возможно, вы указали только триггер в родительской таблице, тогда как триггеры автоматически не наследуются дочерними таблицами.

  • Чтобы выполнить эту функцию, вы можете использовать отладчик, встроенный в pgAdmin3, который по умолчанию включен по умолчанию; все, что вам нужно сделать, это выполнить код, найденный в ...\8.3\share\contrib\pldbgapi.sql, в отношении отлаживаемой базы данных, перезапустить pgAdmin3, щелкнуть правой кнопкой мыши по вашей функции запуска, нажать "Установить точку останова", а затем выполнить инструкцию, которая приведет к срабатыванию триггера, например, над выражением UPDATE.

Ответ 2

Вы можете использовать операторы "raise notice" внутри своей триггерной функции для ее отладки. Отладка триггера, не вызываемого вообще, - это еще одна история.

Если вы добавите "исключение для повышения" внутри вашей функции триггера, можете ли вы по-прежнему вставлять/обновлять?

Кроме того, если ваш тест обновления происходит в той же транзакции, что и ваш тест insert, now() будет таким же (поскольку он вычисляется только один раз за транзакцию), и поэтому обновление ничего не сделает. Если это так, либо делайте их в отдельных транзакциях, либо если это unit test, и вы не можете этого сделать, используйте clock_timestamp().

У меня есть unit test, который зависит от некоторого времени между транзакциями, поэтому в начале unit test у меня есть что-то вроде:

ALTER TABLE documents
   ALTER COLUMN modification_time SET DEFAULT clock_timestamp();

Затем в триггере используйте "set modify_time = default".

Таким образом, обычно он не выполняет дополнительный расчет, но во время unit test это позволяет мне делать вставки с pg_sleep между ними, чтобы имитировать прохождение времени и фактически иметь это отражение в данных.

Ответ 3

Оказывается, я использовал наследование в вышеупомянутой проблеме и забыл упомянуть об этом. Теперь для всех, кто может столкнуться с этим, вот некоторые отладочные подсказки:

Используйте следующий код для отладки того, что делает триггер:

RAISE NOTICE 'test';       -- either this
RAISE EXCEPTION 'failed';  -- or that

Чтобы узнать, какие триггеры действительно вызываются, сколько раз и т.д., следующий оператор является спасателем по выбору:

EXPLAIN ANALYZE UPDATE table SET foo='bar'; -- shows the called triggers

Тогда одна вещь, о которой я раньше не знал: срабатывает только при обновлении точной таблицы, на которой они определены. Если вы используете наследование, вы также должны определить их на дочерних таблицах!