Thanks for all the input.

Finally I found time and motivation to revive this.

See attached patch... I'm ready to work on so it can get merged in the next CF.


On Thu, Mar 17, 2016 at 12:44 AM David Steele <da...@pgmasters.net> wrote:
>
> On 3/11/16 1:46 PM, David Steele wrote:
> > Hi Filip,
> >
> > On 2/20/16 8:00 AM, Filip Rembiałkowski wrote:
> >> On Fri, Feb 19, 2016 at 10:09 PM, Catalin Iacob <iacobcata...@gmail.com
> >>      On 2/9/16, Tom Lane <t...@sss.pgh.pa.us <mailto:t...@sss.pgh.pa.us>>
> >>      wrote:
> >>      > FWIW, I think it would be a good thing if the NOTIFY statement 
> >> syntax were
> >>      > not remarkably different from the syntax used in the pg_notify() 
> >> function
> >>      > call.  To do otherwise would certainly be confusing.  So on the 
> >> whole
> >>      > I'd go with the "NOTIFY channel [ , payload [ , mode ] ]" option.
> >>
> >>      Filip, do you agree with Tom's proposal? Do you plan to rework the
> >>      patch on these lines? If you are I'll try to review it, if not I could
> >>      give it a shot as I'm interested in having this in 9.6.
> >>
> >> I see that Tom's remarks give more flexibility, and your refinement
> >> makes sense.
> >
> > It looks like we are waiting on a new patch from you before this can be
> > reviewed.  Are you close to having that done?
> >
> > Meanwhile, I have marked it "Waiting on Author".
>
> Since there has been no activity on this thread since before the CF and
> no response from the author I have marked this "returned with feedback".
> Please feel free to resubmit for 9.7!
>
> --
> -David
> da...@pgmasters.net
 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 *;

Reply via email to