Skip to content

Commit 3e6ade6

Browse files
sqwishyelprans
authored andcommitted
Quoting channel name in LISTEN and UNLISTEN.
We surround channel identifiers in double-quotes. Otherwise, channel names containing some non-alphanumeric characters or beginning with numbers cause syntax errors when we try to LISTEN on them. Also, this means pgsql will treat them in a case-sensitive way. db=# listen FOO; LISTEN db=# notify FOO, 'bar'; NOTIFY Asynchronous notification "foo" with payload "bar" received from server process with PID 15176. db=# notify "FOO", 'bar'; NOTIFY ... db=# listen "FOO"; LISTEN db=# notify FOO, 'bar'; NOTIFY db=# notify "FOO", 'bar'; NOTIFY Asynchronous notification "FOO" with payload "bar" received from server process with PID 15162.
1 parent dca0f56 commit 3e6ade6

File tree

2 files changed

+20
-2
lines changed

2 files changed

+20
-2
lines changed

asyncpg/connection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ async def add_listener(self, channel, callback):
112112
"""
113113
self._check_open()
114114
if channel not in self._listeners:
115-
await self.fetch('LISTEN {}'.format(channel))
115+
await self.fetch('LISTEN "{}"'.format(channel))
116116
self._listeners[channel] = set()
117117
self._listeners[channel].add(callback)
118118

@@ -127,7 +127,7 @@ async def remove_listener(self, channel, callback):
127127
self._listeners[channel].remove(callback)
128128
if not self._listeners[channel]:
129129
del self._listeners[channel]
130-
await self.fetch('UNLISTEN {}'.format(channel))
130+
await self.fetch('UNLISTEN "{}"'.format(channel))
131131

132132
def add_log_listener(self, callback):
133133
"""Add a listener for Postgres log messages.

tests/test_listeners.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,24 @@ def listener1(*args):
7878

7979
await con1.remove_listener('ipc', listener1)
8080

81+
async def test_listen_notletters(self):
82+
async with self.create_pool(database='postgres') as pool:
83+
async with pool.acquire() as con1, pool.acquire() as con2:
84+
85+
q1 = asyncio.Queue(loop=self.loop)
86+
87+
def listener1(*args):
88+
q1.put_nowait(args)
89+
90+
await con1.add_listener('12+34', listener1)
91+
await con2.execute("""NOTIFY "12+34", 'hello'""")
92+
93+
self.assertEqual(
94+
await q1.get(),
95+
(con1, con2.get_server_pid(), '12+34', 'hello'))
96+
97+
await con1.remove_listener('12+34', listener1)
98+
8199
async def test_dangling_listener_warns(self):
82100
async with self.create_pool(database='postgres') as pool:
83101
with self.assertWarnsRegex(

0 commit comments

Comments
 (0)