Отладка триггера 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();
Теперь сделаем это немного интереснее.. Как вы отлаживаете триггеры?
Ответы
Ответ 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
Тогда одна вещь, о которой я раньше не знал: срабатывает только при обновлении точной таблицы, на которой они определены. Если вы используете наследование, вы также должны определить их на дочерних таблицах!