postgres-notify-send-mode-v1.patch

text/x-patch

Filename: postgres-notify-send-mode-v1.patch
Type: text/x-patch
Part: 0
Message: Re: Re: proposal: make NOTIFY list de-duplication optional

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
Series: patch v1
File+
contrib/tcn/tcn.c 1 1
doc/src/sgml/ref/notify.sgml 48 15
src/backend/commands/async.c 58 11
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 33 11
src/backend/tcop/utility.c 4 4
src/backend/utils/adt/ruleutils.c 3 1
src/include/catalog/pg_proc.dat 4 0
src/include/commands/async.h 7 1
src/include/nodes/parsenodes.h 13 5
src/test/regress/expected/async.out 20 0
src/test/regress/sql/async.sql 9 0
 contrib/tcn/tcn.c                   |  2 +-
 doc/src/sgml/ref/notify.sgml        | 63 +++++++++++++++++++++++++--------
 src/backend/commands/async.c        | 69 +++++++++++++++++++++++++++++++------
 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           | 44 +++++++++++++++++------
 src/backend/tcop/utility.c          |  8 ++---
 src/backend/utils/adt/ruleutils.c   |  4 ++-
 src/include/catalog/pg_proc.dat     |  4 +++
 src/include/commands/async.h        |  8 ++++-
 src/include/nodes/parsenodes.h      | 18 +++++++---
 src/test/regress/expected/async.out | 20 +++++++++++
 src/test/regress/sql/async.sql      |  9 +++++
 15 files changed, 212 insertions(+), 57 deletions(-)

diff --git a/contrib/tcn/tcn.c b/contrib/tcn/tcn.c
index 5355a64c5e..196e0989a4 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, NOTIFY_SEND_UNIQUE);
 			}
 			ReleaseSysCache(indexTuple);
 			break;
diff --git a/doc/src/sgml/ref/notify.sgml b/doc/src/sgml/ref/notify.sgml
index e0e125a2a2..ad0795fd2d 100644
--- a/doc/src/sgml/ref/notify.sgml
+++ b/doc/src/sgml/ref/notify.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-NOTIFY <replaceable class="parameter">channel</replaceable> [ , <replaceable class="parameter">payload</replaceable> ]
+NOTIFY <replaceable class="parameter">channel</replaceable> [ , <replaceable class="parameter">payload</replaceable> [ , <replaceable class="parameter">send_mode</replaceable> ] ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -47,10 +47,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 +92,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 +139,23 @@ NOTIFY <replaceable class="parameter">channel</replaceable> [ , <replaceable cla
      </para>
     </listitem>
    </varlistentry>
+   <varlistentry>
+    <term><replaceable class="parameter">send_mode</replaceable></term>
+    <listitem>
+     <para>
+      Controls collapsing of repeated messages. Can be either
+      <literal>'unique'</literal> (the default) or <literal>'all'</literal>.
+
+      When set to <literal>'unique'</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>'all'</literal>, duplicates will not be collapsed.
+
+     </para>
+    </listitem>
+   </varlistentry>
   </variablelist>
  </refsect1>
 
@@ -190,6 +199,14 @@ 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>text</type>)</literal>. The third argument
+    corresponds to the <replaceable
+    class="parameter">send_mode</replaceable> parameter of the
+    <literal>NOTIFY</literal> command. 
+   </para>
   </refsect2>
  </refsect1>
 
@@ -210,6 +227,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 send_mode = 'all' */
+LISTEN bar;
+BEGIN;
+NOTIFY bar, 'Coffee please';
+NOTIFY bar, 'Coffee please';
+NOTIFY bar, 'Milk please';
+NOTIFY bar, 'Milk please', 'off';
+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..f953424986 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.
+ *	  In the default send_mode ('unique'), 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 send_mode is 'all', 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
@@ -523,7 +525,51 @@ 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_mode
+ *    SQL function to send a notification event, 3-argument version
+ */
+Datum
+pg_notify_mode(PG_FUNCTION_ARGS)
+{
+	const char *channel;
+	const char *payload;
+	const char *p_send_mode;
+	NotifySendMode send_mode;
+
+	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))
+	{
+		send_mode = NOTIFY_SEND_UNIQUE;
+	}
+	else
+	{
+		p_send_mode = text_to_cstring(PG_GETARG_TEXT_PP(2));
+		if (strcmp(p_send_mode, "all") == 0)
+			send_mode = NOTIFY_SEND_ALL;
+		else
+			send_mode = NOTIFY_SEND_UNIQUE;
+	}
+
+	/* For NOTIFY as a statement, this is checked in ProcessUtility */
+	PreventCommandDuringRecovery("NOTIFY");
+
+	Async_Notify(channel, payload, send_mode);
 
 	PG_RETURN_VOID();
 }
@@ -539,7 +585,7 @@ pg_notify(PG_FUNCTION_ARGS)
  *		^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  */
 void
-Async_Notify(const char *channel, const char *payload)
+Async_Notify(const char *channel, const char *payload, NotifySendMode send_mode)
 {
 	Notification *n;
 	MemoryContext oldcontext;
@@ -569,9 +615,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 (send_mode == NOTIFY_SEND_UNIQUE)
+		/* remove duplicate entries in the list */
+		if (AsyncExistsPendingNotify(channel, payload))
+			return;
 
 	/*
 	 * The notification list needs to live until end of transaction, so store
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index a0c1389488..ddefeda8d3 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3622,8 +3622,9 @@ _copyNotifyStmt(const NotifyStmt *from)
 {
 	NotifyStmt *newnode = makeNode(NotifyStmt);
 
-	COPY_STRING_FIELD(conditionname);
+	COPY_STRING_FIELD(channel);
 	COPY_STRING_FIELD(payload);
+	COPY_SCALAR_FIELD(send_mode);
 
 	return newnode;
 }
@@ -3633,7 +3634,7 @@ _copyListenStmt(const ListenStmt *from)
 {
 	ListenStmt *newnode = makeNode(ListenStmt);
 
-	COPY_STRING_FIELD(conditionname);
+	COPY_STRING_FIELD(channel);
 
 	return newnode;
 }
@@ -3643,7 +3644,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..1c60b55b94 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_SCALAR_FIELD(send_mode);
 
 	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 d9a5e8cb6a..d228cd51bd 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2660,8 +2660,9 @@ _outNotifyStmt(StringInfo str, const NotifyStmt *node)
 {
 	WRITE_NODE_TYPE("NOTIFY");
 
-	WRITE_STRING_FIELD(conditionname);
+	WRITE_STRING_FIELD(channel);
 	WRITE_STRING_FIELD(payload);
+	WRITE_ENUM_FIELD(send_mode, NotifySendMode);
 }
 
 static void
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 0a34fd9684..a98211da45 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_ENUM_FIELD(send_mode, NotifySendMode);
 
 	READ_DONE();
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 753af6073f..ce44312ac6 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -525,6 +525,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 %type <ival>	Iconst SignedIconst
 %type <str>		Sconst comment_text notify_payload
+%type <boolean> notify_send_mode
 %type <str>		RoleId opt_boolean_or_string
 %type <list>	var_list
 %type <str>		ColId ColLabel var_name type_function_name param_name
@@ -9741,24 +9742,45 @@ opt_instead:
  *
  *****************************************************************************/
 
-NotifyStmt: NOTIFY ColId notify_payload
-				{
-					NotifyStmt *n = makeNode(NotifyStmt);
-					n->conditionname = $2;
-					n->payload = $3;
-					$$ = (Node *)n;
-				}
+NotifyStmt:
+		NOTIFY ColId
+		{
+			NotifyStmt *n = makeNode(NotifyStmt);
+			n->channel = $2;
+			n->payload = NULL;
+			n->send_mode = NOTIFY_SEND_UNIQUE;
+			$$ = (Node *)n;
+		}
+		| NOTIFY ColId notify_payload
+		{
+			NotifyStmt *n = makeNode(NotifyStmt);
+			n->channel = $2;
+			n->payload = $3;
+			n->send_mode = NOTIFY_SEND_UNIQUE;
+			$$ = (Node *)n;
+		}
+		| NOTIFY ColId notify_payload notify_send_mode
+		{
+			NotifyStmt *n = makeNode(NotifyStmt);
+			n->channel = $2;
+			n->payload = $3;
+			n->send_mode = $4;
+			$$ = (Node *)n;
+		}
 		;
 
 notify_payload:
 			',' Sconst							{ $$ = $2; }
-			| /*EMPTY*/							{ $$ = NULL; }
+		;
+
+notify_send_mode:
+			',' opt_boolean_or_string 			{ $$ = $2; }
 		;
 
 ListenStmt: LISTEN ColId
 				{
 					ListenStmt *n = makeNode(ListenStmt);
-					n->conditionname = $2;
+					n->channel = $2;
 					$$ = (Node *)n;
 				}
 		;
@@ -9767,13 +9789,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..c0fc895535 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(stmt->channel, stmt->payload, stmt->send_mode);
 			}
 			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..c4b83c50f3 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -6581,11 +6581,13 @@ 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, ", ");
 			simple_quote_literal(buf, stmt->payload);
+			appendStringInfo(buf, ", '%s'",
+					(stmt->send_mode == NOTIFY_SEND_ALL ? "all" : "unique"));
 		}
 	}
 	else
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 2e9d6cf2f5..6d38bbcfc0 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -7549,6 +7549,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 text',
+  prosrc => 'pg_notify_mode' },
 { 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..1154f3c281 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -22,6 +22,12 @@
  */
 #define NUM_ASYNC_BUFFERS	8
 
+typedef enum NotifySendMode
+{
+	NOTIFY_SEND_UNIQUE,
+	NOTIFY_SEND_ALL
+} NotifySendMode;
+
 extern bool Trace_notify;
 extern volatile sig_atomic_t notifyInterruptPending;
 
@@ -33,7 +39,7 @@ 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, NotifySendMode send_mode);
 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..e669b76b39 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
@@ -2944,12 +2945,19 @@ typedef struct RuleStmt
 /* ----------------------
  *		Notify Statement
  * ----------------------
+typedef enum NotifySendMode
+{
+   NOTIFY_SEND_UNIQUE,
+   NOTIFY_SEND_ALL
+} NotifySendMode;
  */
+
 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 */
+	NotifySendMode	send_mode;	/* Send mode */
 } NotifyStmt;
 
 /* ----------------------
@@ -2959,7 +2967,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 +2977,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..7555d0bcc2 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','unique');
+ pg_notify 
+-----------
+ 
+(1 row)
+
+SELECT pg_notify('notify_async1','sample_message1','all');
+ pg_notify 
+-----------
+ 
+(1 row)
+
 SELECT pg_notify('notify_async1','');
  pg_notify 
 -----------
@@ -27,8 +39,16 @@ SELECT pg_notify(NULL,'sample message1');
 ERROR:  channel name cannot be empty
 SELECT pg_notify('notify_async_channel_name_too_long______________________________','sample_message1');
 ERROR:  channel name too long
+-- Should fail. Invalid 3rd parameter
+NOTIFY notify_async2, 'test', 'invalid';
+ERROR:  ?
+NOTIFY notify_async2, 'test', true;
+ERROR:  ?
 --Should work. Valid NOTIFY/LISTEN/UNLISTEN commands
 NOTIFY notify_async2;
+NOTIFY notify_async2, '';
+NOTIFY notify_async2, '', 'unique';
+NOTIFY notify_async2, '', 'all';
 LISTEN notify_async2;
 UNLISTEN notify_async2;
 UNLISTEN *;
diff --git a/src/test/regress/sql/async.sql b/src/test/regress/sql/async.sql
index 40f6e01538..ad349cce37 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','unique');
+SELECT pg_notify('notify_async1','sample_message1','all');
 SELECT pg_notify('notify_async1','');
 SELECT pg_notify('notify_async1',NULL);
 
@@ -12,8 +14,15 @@ SELECT pg_notify('','sample message1');
 SELECT pg_notify(NULL,'sample message1');
 SELECT pg_notify('notify_async_channel_name_too_long______________________________','sample_message1');
 
+-- Should fail. Invalid 3rd parameter
+NOTIFY notify_async2, 'test', 'invalid';
+NOTIFY notify_async2, 'test', true;
+
 --Should work. Valid NOTIFY/LISTEN/UNLISTEN commands
 NOTIFY notify_async2;
+NOTIFY notify_async2, '';
+NOTIFY notify_async2, '', 'unique';
+NOTIFY notify_async2, '', 'all';
 LISTEN notify_async2;
 UNLISTEN notify_async2;
 UNLISTEN *;