postgres-notify-options-20190310_01.patch
text/x-patch
Filename: postgres-notify-options-20190310_01.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| contrib/tcn/tcn.c | 1 | 1 |
| doc/src/sgml/ref/notify.sgml | 49 | 15 |
| src/backend/commands/async.c | 79 | 14 |
| src/backend/nodes/copyfuncs.c | 4 | 3 |
| src/backend/nodes/equalfuncs.c | 4 | 3 |
| src/backend/nodes/outfuncs.c | 2 | 1 |
| src/backend/nodes/readfuncs.c | 2 | 1 |
| src/backend/parser/gram.y | 66 | 12 |
| src/backend/tcop/utility.c | 4 | 4 |
| src/backend/utils/adt/ruleutils.c | 1 | 1 |
| src/include/catalog/pg_proc.dat | 4 | 0 |
| src/include/commands/async.h | 3 | 1 |
| src/include/nodes/parsenodes.h | 7 | 5 |
| src/test/regress/expected/async.out | 21 | 0 |
| src/test/regress/sql/async.sql | 10 | 0 |
contrib/tcn/tcn.c | 2 +-
doc/src/sgml/ref/notify.sgml | 64 +++++++++++++++++++------
src/backend/commands/async.c | 93 +++++++++++++++++++++++++++++++------
src/backend/nodes/copyfuncs.c | 7 +--
src/backend/nodes/equalfuncs.c | 7 +--
src/backend/nodes/outfuncs.c | 3 +-
src/backend/nodes/readfuncs.c | 3 +-
src/backend/parser/gram.y | 78 ++++++++++++++++++++++++++-----
src/backend/tcop/utility.c | 8 ++--
src/backend/utils/adt/ruleutils.c | 2 +-
src/include/catalog/pg_proc.dat | 4 ++
src/include/commands/async.h | 4 +-
src/include/nodes/parsenodes.h | 12 +++--
src/test/regress/expected/async.out | 21 +++++++++
src/test/regress/sql/async.sql | 10 ++++
15 files changed, 257 insertions(+), 61 deletions(-)
diff --git a/contrib/tcn/tcn.c b/contrib/tcn/tcn.c
index 5355a64c5e..b80337a5ce 100644
--- a/contrib/tcn/tcn.c
+++ b/contrib/tcn/tcn.c
@@ -161,7 +161,7 @@ triggered_change_notification(PG_FUNCTION_ARGS)
strcpy_quoted(payload, SPI_getvalue(trigtuple, tupdesc, colno), '\'');
}
- Async_Notify(channel, payload->data);
+ Async_Notify(channel, payload->data, true);
}
ReleaseSysCache(indexTuple);
break;
diff --git a/doc/src/sgml/ref/notify.sgml b/doc/src/sgml/ref/notify.sgml
index e0e125a2a2..e06b00f1f3 100644
--- a/doc/src/sgml/ref/notify.sgml
+++ b/doc/src/sgml/ref/notify.sgml
@@ -21,7 +21,11 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-NOTIFY <replaceable class="parameter">channel</replaceable> [ , <replaceable class="parameter">payload</replaceable> ]
+NOTIFY [ ( option [, ...] ) ] <replaceable class="parameter">channel</replaceable> [ , <replaceable class="parameter">payload</replaceable> ]
+
+<phrase>where <replaceable class="parameter">option</replaceable> can be one of:</phrase>
+
+COLLAPSE [ boolean ]
</synopsis>
</refsynopsisdiv>
@@ -47,10 +51,10 @@ NOTIFY <replaceable class="parameter">channel</replaceable> [ , <replaceable cla
</para>
<para>
- The information passed to the client for a notification event includes the
- notification channel
- name, the notifying session's server process <acronym>PID</acronym>, and the
- payload string, which is an empty string if it has not been specified.
+ The information passed to the client for a notification event includes
+ the notification channel name, the notifying session's server process
+ <acronym>PID</acronym>, and the payload string, which is an empty string
+ if it has not been specified.
</para>
<para>
@@ -92,21 +96,13 @@ NOTIFY <replaceable class="parameter">channel</replaceable> [ , <replaceable cla
is that applications using <command>NOTIFY</command> for real-time signaling
should try to keep their transactions short.
</para>
-
<para>
- If the same channel name is signaled multiple times from the same
- transaction with identical payload strings, the
- database server can decide to deliver a single notification only.
- On the other hand, notifications with distinct payload strings will
- always be delivered as distinct notifications. Similarly, notifications from
- different transactions will never get folded into one notification.
Except for dropping later instances of duplicate notifications,
<command>NOTIFY</command> guarantees that notifications from the same
transaction get delivered in the order they were sent. It is also
- guaranteed that messages from different transactions are delivered in
- the order in which the transactions committed.
+ guaranteed that messages from different transactions are delivered
+ in the order in which the transactions committed.
</para>
-
<para>
It is common for a client that executes <command>NOTIFY</command>
to be listening on the same notification channel itself. In that case
@@ -147,6 +143,21 @@ NOTIFY <replaceable class="parameter">channel</replaceable> [ , <replaceable cla
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><replaceable class="parameter">COLLAPSE</replaceable></term>
+ <listitem>
+ <para>
+ Controls collapsing of repeated messages.
+
+ When set to <literal>on</literal>, notification will be skipped if
+ the same channel was already signaled with identical payload in the same
+ transaction block (finished with <literal>COMMIT</literal>,
+ <literal>END</literal> or <literal>SAVEPOINT</literal>).
+
+ When set to <literal>off</literal>, duplicates will not be collapsed.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
@@ -190,6 +201,13 @@ NOTIFY <replaceable class="parameter">channel</replaceable> [ , <replaceable cla
to use than the <command>NOTIFY</command> command if you need to work with
non-constant channel names and payloads.
</para>
+ <para>
+ There is a three-argument version,
+ <literal><function>pg_notify</function>(<type>text</type>,
+ <type>text</type>, <type>boolean</type>)</literal>. The third argument
+ corresponds to the <replaceable class="parameter">COLLAPSE</replaceable>
+ option of the <literal>NOTIFY</literal> command.
+ </para>
</refsect2>
</refsect1>
@@ -210,6 +228,22 @@ Asynchronous notification "virtual" with payload "This is the payload" received
LISTEN foo;
SELECT pg_notify('fo' || 'o', 'pay' || 'load');
Asynchronous notification "foo" with payload "payload" received from server process with PID 14728.
+
+/* Identical messages from same (sub-) transaction will be eliminated,
+ unless you use COLLAPSE off */
+LISTEN bar;
+BEGIN;
+NOTIFY bar, 'Coffee please';
+NOTIFY bar, 'Coffee please';
+NOTIFY bar, 'Milk please';
+NOTIFY (COLLAPSE off) bar, 'Milk please';
+SAVEPOINT s;
+NOTIFY bar, 'Coffee please';
+COMMIT;
+Asynchronous notification "bar" with payload "Coffee please" received from server process with PID 31517.
+Asynchronous notification "bar" with payload "Milk please" received from server process with PID 31517.
+Asynchronous notification "bar" with payload "Milk please" received from server process with PID 31517.
+Asynchronous notification "bar" with payload "Coffee please" received from server process with PID 31517.
</programlisting></para>
</refsect1>
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 5a7ee0de4c..0f1280b3f5 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -49,12 +49,14 @@
* 4. The NOTIFY statement (routine Async_Notify) stores the notification in
* a backend-local list which will not be processed until transaction end.
*
- * Duplicate notifications from the same transaction are sent out as one
- * notification only. This is done to save work when for example a trigger
- * on a 2 million row table fires a notification for each row that has been
- * changed. If the application needs to receive every single notification
- * that has been sent, it can easily add some unique string into the extra
- * payload parameter.
+ * By default (COLLAPSE on), duplicate notifications from the
+ * same transaction are sent out as one notification only. This is done to
+ * save work when for example a trigger on a 2 million row table fires a
+ * notification for each row that has been changed. If the application needs
+ * to receive every single notification that has been sent, it can easily
+ * add some unique string into the extra payload parameter.
+ *
+ * If COLLAPSE off, de-duplication is not performed.
*
* When the transaction is ready to commit, PreCommit_Notify() adds the
* pending notifications to the head of the queue. The head pointer of the
@@ -123,6 +125,7 @@
#include "access/xact.h"
#include "catalog/pg_database.h"
#include "commands/async.h"
+#include "commands/defrem.h"
#include "funcapi.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
@@ -523,7 +526,42 @@ pg_notify(PG_FUNCTION_ARGS)
/* For NOTIFY as a statement, this is checked in ProcessUtility */
PreventCommandDuringRecovery("NOTIFY");
- Async_Notify(channel, payload);
+ Async_Notify(channel, payload, true);
+
+ PG_RETURN_VOID();
+}
+
+
+/*
+ * pg_notify_3args
+ * SQL function to send a notification event, 3-argument version
+ */
+Datum
+pg_notify_3args(PG_FUNCTION_ARGS)
+{
+ const char *channel;
+ const char *payload;
+ bool collapse;
+
+ if (PG_ARGISNULL(0))
+ channel = "";
+ else
+ channel = text_to_cstring(PG_GETARG_TEXT_PP(0));
+
+ if (PG_ARGISNULL(1))
+ payload = "";
+ else
+ payload = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (PG_ARGISNULL(2))
+ collapse = true;
+ else
+ collapse = PG_GETARG_BOOL(2);
+
+ /* For NOTIFY as a statement, this is checked in ProcessUtility */
+ PreventCommandDuringRecovery("NOTIFY");
+
+ Async_Notify(channel, payload, collapse);
PG_RETURN_VOID();
}
@@ -539,10 +577,10 @@ pg_notify(PG_FUNCTION_ARGS)
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/
void
-Async_Notify(const char *channel, const char *payload)
+Async_Notify(const char *channel, const char *payload, bool collapse)
{
- Notification *n;
- MemoryContext oldcontext;
+ Notification *n;
+ MemoryContext oldcontext;
if (IsParallelWorker())
elog(ERROR, "cannot send notifications from a parallel worker");
@@ -550,7 +588,7 @@ Async_Notify(const char *channel, const char *payload)
if (Trace_notify)
elog(DEBUG1, "Async_Notify(%s)", channel);
- /* a channel name must be specified */
+ /* channel name must be specified */
if (!channel || !strlen(channel))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -569,9 +607,10 @@ Async_Notify(const char *channel, const char *payload)
errmsg("payload string too long")));
}
- /* no point in making duplicate entries in the list ... */
- if (AsyncExistsPendingNotify(channel, payload))
- return;
+ if (collapse)
+ /* remove duplicate entries in the list */
+ if (AsyncExistsPendingNotify(channel, payload))
+ return;
/*
* The notification list needs to live until end of transaction, so store
@@ -595,6 +634,32 @@ Async_Notify(const char *channel, const char *payload)
MemoryContextSwitchTo(oldcontext);
}
+void
+Async_Notify_WithOptions(const char *channel,
+ const char *payload, List *options)
+{
+ ListCell *lc;
+
+ bool collapse;
+
+ collapse = true;
+
+ /* Parse options list. */
+ foreach(lc, options)
+ {
+ DefElem *opt = (DefElem *) lfirst(lc);
+
+ if (strcmp(opt->defname, "collapse") == 0)
+ collapse = defGetBoolean(opt);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("unrecognized NOTIFY option \"%s\"",
+ opt->defname)));
+ }
+ Async_Notify(channel, payload, collapse);
+}
+
/*
* queue_listen
* Common code for listen, unlisten, unlisten all commands.
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index a8a735c247..df91526429 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3623,8 +3623,9 @@ _copyNotifyStmt(const NotifyStmt *from)
{
NotifyStmt *newnode = makeNode(NotifyStmt);
- COPY_STRING_FIELD(conditionname);
+ COPY_STRING_FIELD(channel);
COPY_STRING_FIELD(payload);
+ COPY_NODE_FIELD(options);
return newnode;
}
@@ -3634,7 +3635,7 @@ _copyListenStmt(const ListenStmt *from)
{
ListenStmt *newnode = makeNode(ListenStmt);
- COPY_STRING_FIELD(conditionname);
+ COPY_STRING_FIELD(channel);
return newnode;
}
@@ -3644,7 +3645,7 @@ _copyUnlistenStmt(const UnlistenStmt *from)
{
UnlistenStmt *newnode = makeNode(UnlistenStmt);
- COPY_STRING_FIELD(conditionname);
+ COPY_STRING_FIELD(channel);
return newnode;
}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3cab90e9f8..3db593e63c 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1480,8 +1480,9 @@ _equalRuleStmt(const RuleStmt *a, const RuleStmt *b)
static bool
_equalNotifyStmt(const NotifyStmt *a, const NotifyStmt *b)
{
- COMPARE_STRING_FIELD(conditionname);
+ COMPARE_STRING_FIELD(channel);
COMPARE_STRING_FIELD(payload);
+ COMPARE_NODE_FIELD(options);
return true;
}
@@ -1489,7 +1490,7 @@ _equalNotifyStmt(const NotifyStmt *a, const NotifyStmt *b)
static bool
_equalListenStmt(const ListenStmt *a, const ListenStmt *b)
{
- COMPARE_STRING_FIELD(conditionname);
+ COMPARE_STRING_FIELD(channel);
return true;
}
@@ -1497,7 +1498,7 @@ _equalListenStmt(const ListenStmt *a, const ListenStmt *b)
static bool
_equalUnlistenStmt(const UnlistenStmt *a, const UnlistenStmt *b)
{
- COMPARE_STRING_FIELD(conditionname);
+ COMPARE_STRING_FIELD(channel);
return true;
}
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 69179a07c3..bebdd0a9e6 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2661,8 +2661,9 @@ _outNotifyStmt(StringInfo str, const NotifyStmt *node)
{
WRITE_NODE_TYPE("NOTIFY");
- WRITE_STRING_FIELD(conditionname);
+ WRITE_STRING_FIELD(channel);
WRITE_STRING_FIELD(payload);
+ WRITE_NODE_FIELD(options);
}
static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 4b845b1bb7..dfe64b5fec 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -296,8 +296,9 @@ _readNotifyStmt(void)
{
READ_LOCALS(NotifyStmt);
- READ_STRING_FIELD(conditionname);
+ READ_STRING_FIELD(channel);
READ_STRING_FIELD(payload);
+ READ_NODE_FIELD(options);
READ_DONE();
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e23e68fdb3..582c2ef692 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -524,7 +524,12 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <boolean> opt_varying opt_timezone opt_no_inherit
%type <ival> Iconst SignedIconst
-%type <str> Sconst comment_text notify_payload
+%type <str> Sconst comment_text
+%type <str> notify_option_name
+%type <node> notify_option_arg
+%type <defelt> notify_option_elem
+%type <list> notify_option_list
+
%type <str> RoleId opt_boolean_or_string
%type <list> var_list
%type <str> ColId ColLabel var_name type_function_name param_name
@@ -9741,24 +9746,73 @@ opt_instead:
*
*****************************************************************************/
-NotifyStmt: NOTIFY ColId notify_payload
+NotifyStmt:
+ NOTIFY ColId
+ {
+ NotifyStmt *n = makeNode(NotifyStmt);
+ n->channel = $2;
+ n->payload = NULL;
+ n->options = NIL;
+ $$ = (Node *)n;
+ }
+ | NOTIFY ColId ',' Sconst
+ {
+ NotifyStmt *n = makeNode(NotifyStmt);
+ n->channel = $2;
+ n->payload = $4;
+ n->options = NIL;
+ $$ = (Node *)n;
+ }
+ | NOTIFY '(' notify_option_list ')' ColId
+ {
+ NotifyStmt *n = makeNode(NotifyStmt);
+ n->options = $3;
+ n->channel = $5;
+ n->payload = NULL;
+ $$ = (Node *)n;
+ }
+ | NOTIFY '(' notify_option_list ')' ColId ',' Sconst
+ {
+ NotifyStmt *n = makeNode(NotifyStmt);
+ n->options = $3;
+ n->channel = $5;
+ n->payload = $7;
+ $$ = (Node *)n;
+ }
+ ;
+
+notify_option_list:
+ notify_option_elem
{
- NotifyStmt *n = makeNode(NotifyStmt);
- n->conditionname = $2;
- n->payload = $3;
- $$ = (Node *)n;
+ $$ = list_make1($1);
+ }
+ | notify_option_list ',' notify_option_elem
+ {
+ $$ = lappend($1, $3);
}
;
-notify_payload:
- ',' Sconst { $$ = $2; }
- | /*EMPTY*/ { $$ = NULL; }
+notify_option_elem:
+ notify_option_name notify_option_arg
+ {
+ $$ = makeDefElem($1, $2, @1);
+ }
+ ;
+
+notify_option_name:
+ NonReservedWord { $$ = $1; }
+ ;
+
+notify_option_arg:
+ opt_boolean_or_string { $$ = (Node *) makeString($1); }
+ | NumericOnly { $$ = (Node *) $1; }
+ | /* EMPTY */ { $$ = NULL; }
;
ListenStmt: LISTEN ColId
{
ListenStmt *n = makeNode(ListenStmt);
- n->conditionname = $2;
+ n->channel = $2;
$$ = (Node *)n;
}
;
@@ -9767,13 +9821,13 @@ UnlistenStmt:
UNLISTEN ColId
{
UnlistenStmt *n = makeNode(UnlistenStmt);
- n->conditionname = $2;
+ n->channel = $2;
$$ = (Node *)n;
}
| UNLISTEN '*'
{
UnlistenStmt *n = makeNode(UnlistenStmt);
- n->conditionname = NULL;
+ n->channel = NULL;
$$ = (Node *)n;
}
;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 6ec795f1b4..d6f8d09174 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -611,7 +611,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
NotifyStmt *stmt = (NotifyStmt *) parsetree;
PreventCommandDuringRecovery("NOTIFY");
- Async_Notify(stmt->conditionname, stmt->payload);
+ Async_Notify_WithOptions(stmt->channel, stmt->payload, stmt->options);
}
break;
@@ -621,7 +621,7 @@ standard_ProcessUtility(PlannedStmt *pstmt,
PreventCommandDuringRecovery("LISTEN");
CheckRestrictedOperation("LISTEN");
- Async_Listen(stmt->conditionname);
+ Async_Listen(stmt->channel);
}
break;
@@ -631,8 +631,8 @@ standard_ProcessUtility(PlannedStmt *pstmt,
/* we allow UNLISTEN during recovery, as it's a noop */
CheckRestrictedOperation("UNLISTEN");
- if (stmt->conditionname)
- Async_Unlisten(stmt->conditionname);
+ if (stmt->channel)
+ Async_Unlisten(stmt->channel);
else
Async_UnlistenAll();
}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 85055bbb95..1300347387 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -6581,7 +6581,7 @@ get_utility_query_def(Query *query, deparse_context *context)
appendContextKeyword(context, "",
0, PRETTYINDENT_STD, 1);
appendStringInfo(buf, "NOTIFY %s",
- quote_identifier(stmt->conditionname));
+ quote_identifier(stmt->channel));
if (stmt->payload)
{
appendStringInfoString(buf, ", ");
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 562c5408f8..94dbe5c70a 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7554,6 +7554,10 @@
proname => 'pg_notify', proisstrict => 'f', provolatile => 'v',
proparallel => 'r', prorettype => 'void', proargtypes => 'text text',
prosrc => 'pg_notify' },
+{ oid => '3998', descr => 'send a notification event',
+ proname => 'pg_notify', proisstrict => 'f', provolatile => 'v',
+ proparallel => 'r', prorettype => 'void', proargtypes => 'text text bool',
+ prosrc => 'pg_notify_3args' },
{ oid => '3296',
descr => 'get the fraction of the asynchronous notification queue currently in use',
proname => 'pg_notification_queue_usage', provolatile => 'v',
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index cfea78e039..36b39ff8bd 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -16,6 +16,7 @@
#include <signal.h>
#include "fmgr.h"
+#include "nodes/parsenodes.h"
/*
* The number of SLRU page buffers we use for the notification queue.
@@ -33,7 +34,8 @@ extern void NotifyMyFrontEnd(const char *channel,
int32 srcPid);
/* notify-related SQL statements */
-extern void Async_Notify(const char *channel, const char *payload);
+extern void Async_Notify(const char *channel, const char *payload, bool collapse);
+extern void Async_Notify_WithOptions(const char *channel, const char *payload, List *options);
extern void Async_Listen(const char *channel);
extern void Async_Unlisten(const char *channel);
extern void Async_UnlistenAll(void);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index fe35783359..94f24568e9 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -27,6 +27,7 @@
#include "nodes/primnodes.h"
#include "nodes/value.h"
#include "partitioning/partdefs.h"
+#include "commands/async.h"
typedef enum OverridingKind
@@ -2947,9 +2948,10 @@ typedef struct RuleStmt
*/
typedef struct NotifyStmt
{
- NodeTag type;
- char *conditionname; /* condition name to notify */
- char *payload; /* the payload string, or NULL if none */
+ NodeTag type;
+ char *channel; /* channel name to notify */
+ char *payload; /* the payload string, or NULL if none */
+ List *options; /* List of DefElem nodes */
} NotifyStmt;
/* ----------------------
@@ -2959,7 +2961,7 @@ typedef struct NotifyStmt
typedef struct ListenStmt
{
NodeTag type;
- char *conditionname; /* condition name to listen on */
+ char *channel; /* channel name to listen on */
} ListenStmt;
/* ----------------------
@@ -2969,7 +2971,7 @@ typedef struct ListenStmt
typedef struct UnlistenStmt
{
NodeTag type;
- char *conditionname; /* name to unlisten on, or NULL for all */
+ char *channel; /* channel name to unlisten, or NULL for all */
} UnlistenStmt;
/* ----------------------
diff --git a/src/test/regress/expected/async.out b/src/test/regress/expected/async.out
index 19cbe38e63..6d5726127c 100644
--- a/src/test/regress/expected/async.out
+++ b/src/test/regress/expected/async.out
@@ -8,6 +8,18 @@ SELECT pg_notify('notify_async1','sample message1');
(1 row)
+SELECT pg_notify('notify_async1','sample_message1',true);
+ pg_notify
+-----------
+
+(1 row)
+
+SELECT pg_notify('notify_async1','sample_message1',false);
+ pg_notify
+-----------
+
+(1 row)
+
SELECT pg_notify('notify_async1','');
pg_notify
-----------
@@ -29,9 +41,18 @@ SELECT pg_notify('notify_async_channel_name_too_long____________________________
ERROR: channel name too long
--Should work. Valid NOTIFY/LISTEN/UNLISTEN commands
NOTIFY notify_async2;
+NOTIFY (collapse off) notify_async2;
+NOTIFY notify_async2, '';
+NOTIFY (collapse on) notify_async2, '';
+NOTIFY (collapse off) notify_async2, '';
LISTEN notify_async2;
UNLISTEN notify_async2;
UNLISTEN *;
+-- Should fail. Invalid option syntax
+NOTIFY (collapse maybe) notify_async2;
+ERROR: collapse requires a Boolean value
+NOTIFY (wrong opt) notify_async2, 'test';
+ERROR: unrecognized NOTIFY option "wrong"
-- Should return zero while there are no pending notifications.
-- src/test/isolation/specs/async-notify.spec tests for actual usage.
SELECT pg_notification_queue_usage();
diff --git a/src/test/regress/sql/async.sql b/src/test/regress/sql/async.sql
index 40f6e01538..29f9681d2a 100644
--- a/src/test/regress/sql/async.sql
+++ b/src/test/regress/sql/async.sql
@@ -4,6 +4,8 @@
--Should work. Send a valid message via a valid channel name
SELECT pg_notify('notify_async1','sample message1');
+SELECT pg_notify('notify_async1','sample_message1',true);
+SELECT pg_notify('notify_async1','sample_message1',false);
SELECT pg_notify('notify_async1','');
SELECT pg_notify('notify_async1',NULL);
@@ -14,10 +16,18 @@ SELECT pg_notify('notify_async_channel_name_too_long____________________________
--Should work. Valid NOTIFY/LISTEN/UNLISTEN commands
NOTIFY notify_async2;
+NOTIFY (collapse off) notify_async2;
+NOTIFY notify_async2, '';
+NOTIFY (collapse on) notify_async2, '';
+NOTIFY (collapse off) notify_async2, '';
LISTEN notify_async2;
UNLISTEN notify_async2;
UNLISTEN *;
+-- Should fail. Invalid option syntax
+NOTIFY (collapse maybe) notify_async2;
+NOTIFY (wrong opt) notify_async2, 'test';
+
-- Should return zero while there are no pending notifications.
-- src/test/isolation/specs/async-notify.spec tests for actual usage.
SELECT pg_notification_queue_usage();