Armadilha no LISTEN e NOTIFY (PostgreSQL)

por Walter Cruz on 14/03/2007
in PostgreSQL

Tradução do texto de Greg Sabino Mullane em seu blog. O título original é LISTEN AND NOTIFY gotcha. Resolvi traduzir gotcha como armadilha. Primeiro, a definição de gotcha da wikipedia: Em programação, um gotcha é uma característica de um sistema, um programa, ou uma linguagem de programação que funciona da forma como está documentado mas é contra-intuitivo e quase sempre propícia à erro porque é fácil de usar e impredizível em seu resultado.

Existe um problema sutil com os comandos LISTEN e NOTIFY. Enquanto o nome que você atribui no comando LISTEN parece um texto comum, ele é na verdade aquilo que é chamado de "nome" no PostgreSQL, que significa que está sujeito às mesmas estranhas regras e comportamento. Eu pessoalmente adoraria ver isso mudado de uma nome de relação para uma string normal, mas até que isso ocorra, seja cuidadoso com a forma que você usa essa dupla. Aqui está um exemplo de uso comum:

$ LISTEN employee;
LISTEN

$ NOTIFY employee;
NOTIFY
Asynchronous notification "employee" received from server process with PID 8875.

No exemplo acima, nós começamos a ouvir por evemtos com o nome "employee", então disparamos um NOTIFY com o mesmo nome e obtemos uma notificação imediata sobre isso. Porém, como o nome está sujeito a todas as regras de nomes de relações, existem outros problemas:

$ LISTEN host;
LISTEN

$ LISTEN user;
ERROR:  syntax error at or near "user"
LINE 1: listen user;
               ^

$ LISTEN "user";
LISTEN

$ SELECT * FROM pg_listener;
 relname  | listenerpid | notification 
----------+-------------+--------------
 employee |        8875 |            0
 user     |        8875 |            0
 host     |        8875 |            0
(3 rows)

$ NOTIFY user;
ERROR:  syntax error at or near "user"
LINE 1: listen user;
               ^

$ NOTIFY "user";
NOTIFY
Asynchronous notification "employee" received from server process with PID 8875.

Observe que precisamos colocar a palavra "user" entre aspas, pois a palavra user não é válida como um nome de relação sem aspas. Agora note que a tabela pg_listener não nos dá nenhuma dica que isso precisa estar entre aspas. O problema real acontece quando adicionamos pontos ao nosso "nome". O Postgres trata isso como uma sequência de esquema, tabela, e coluna e remove tudo, exceto a parte final do nome:

$ LISTEN newyork.employee;
LISTEN

$ NOTIFY newyork.emplyee;
NOTIFY
Asynchronous notification "employee" received from server process with PID 8875.

$ NOTIFY losangeles.employee;
NOTIFY
Asynchronous notification "employee" received from server process with PID 8875.

$ NOTIFY elephants.makeagood.employee;
NOTIFY
Asynchronous notification "employee" received from server process with PID 8875.

$ LISTEN thisworks.forunquoted.user;
LISTEN

$ LISTEN cannot.handle.three.dots;                       
ERROR:  improper qualified name (too many dotted names): cannot.handle.three.dots                                           

Eu enviei uma correção para a documentação, mas tome cuidado, principalmente se você escreve código que gera nomes automáticos para os seus argumentos LISTEN.