Я открываю psql
(PostgreSQL 9.5.4 на Arch Linux) в одном терминале A и выдаю LISTEN "notif";
Затем в другом терминале B я запускаю следующий скрипт (psql -f myscript.sql
).
Это создает таблицу с двумя триггерами. Один триггер срабатывает, если добавляется строка, где send
имеет значение ИСТИНА, а другой срабатывает, если строка обновляется таким образом, что send
переходит из состояния ЛОЖЬ в значение ИСТИНА. Оба триггера отправляют уведомление.
DROP TRIGGER IF EXISTS do_notif ON notif;
DROP TRIGGER IF EXISTS do_notif2 ON notif;
DROP TABLE IF EXISTS notif;
CREATE TABLE notif (id INT PRIMARY KEY, send BOOLEAN, msg TEXT);
CREATE OR REPLACE FUNCTION post() RETURNS TRIGGER AS $$
BEGIN
PERFORM pg_notify('notif', '+' || NEW.id::TEXT || ',' || coalesce(NEW.msg, '(null)'));
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION post2() RETURNS TRIGGER AS $$
BEGIN
PERFORM pg_notify('notif', '~' || NEW.id::TEXT || ',' || coalesce(NEW.msg, '(null)'));
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER do_notif AFTER INSERT ON notif
FOR EACH ROW WHEN (NEW.send)
EXECUTE PROCEDURE post();
CREATE TRIGGER do_notif2 AFTER UPDATE OF send ON notif
FOR EACH ROW WHEN (NEW.send AND NOT OLD.send)
EXECUTE PROCEDURE post2();
-- LISTEN "notif";
INSERT INTO notif VALUES (1, FALSE, 'update');
INSERT INTO notif VALUES (2, TRUE, 'insert');
UPDATE notif SET send = TRUE;
UPDATE notif SET send = FALSE;
UPDATE notif SET send = TRUE;
START TRANSACTION;
INSERT INTO notif VALUES (10, FALSE, 'a'), (11, TRUE, 'b'), (12, TRUE, 'c');
UPDATE notif SET send = TRUE WHERE id = 10;
COMMIT
Я ожидаю, что соответствующие запросы INSERT и UPDATE должны привести к вызову триггеров, которые отправляют уведомления, которые будут получены в терминале A.
Этого не происходит. Мне приходится снова вручную запускать LISTEN "notif";
в терминале A, который мгновенно выдает мне недостающие уведомления.
Если я раскомментирую LISTEN "notif";
в этом скрипте, то экземпляр psql
, выполняющий скрипт (B), будет писать уведомления на терминал в соответствующих местах (после нетранзакционной вставки/обновления, которая устанавливает send
в TRUE, и после транзакции тоже).
Но A по-прежнему не показывает их, пока я снова не запущу LISTEN "notif";
в A (или любой другой запрос, например SELECT TRUE;
). Это не какая-то проблема буферизации терминала, так как простое нажатие ENTER в A не приводит к появлению уведомлений.
PostgreSQL, похоже, не сразу доставляет уведомления ни по разным соединениям, ни по разным процессам, но доставляет немедленно, когда слушателем является тот же процесс, который сгенерировал уведомления.