Another update - separated new internal function to satisfy opr_sanity.sql
diff --git a/contrib/tcn/tcn.c b/contrib/tcn/tcn.c
index 7352b29..3a6d4f5 100644
--- a/contrib/tcn/tcn.c
+++ b/contrib/tcn/tcn.c
@@ -160,7 +160,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, false);
}
ReleaseSysCache(indexTuple);
break;
diff --git a/doc/src/sgml/ref/notify.sgml b/doc/src/sgml/ref/notify.sgml
index 4dd5608..933c76c 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 [ ALL | DISTINCT ] <replaceable class="PARAMETER">channel</replaceable> [ , <replaceable class="PARAMETER">payload</replaceable> ]
</synopsis>
</refsynopsisdiv>
@@ -105,6 +105,10 @@ NOTIFY <replaceable class="PARAMETER">channel</replaceable> [ , <replaceable cla
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.
+ If <literal>ALL</> is specified (contrary to <literal>DISTINCT</>, the
+ default), the server will deliver all notifications, including duplicates.
+ Removal of duplicate notifications takes place within transaction block,
+ finished with <literal>COMMIT</>, <literal>END</> or <literal>SAVEPOINT</>.
</para>
<para>
@@ -190,6 +194,12 @@ 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>pg_notify(<type>text</>,
+ <type>text</>, <type>boolean</>)</literal>. The third argument acts like
+ the <literal>ALL</> keyword when set to <literal>true</>, and
+ <literal>DISTINCT</> when set to <literal>false</>.
+ </para>
</refsect2>
</refsect1>
@@ -210,6 +220,21 @@ 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 can be eliminated - unless you use the ALL keyword */
+LISTEN bar;
+BEGIN;
+NOTIFY bar, 'Coffee please';
+NOTIFY bar, 'Coffee please';
+NOTIFY bar, 'Milk please';
+NOTIFY ALL 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 c39ac3a..54d1680 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -524,7 +524,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, false);
+
+ 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 use_all;
+
+ 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))
+ use_all = false;
+ else
+ use_all = PG_GETARG_BOOL(2);
+
+ /* For NOTIFY as a statement, this is checked in ProcessUtility */
+ PreventCommandDuringRecovery("NOTIFY");
+
+ Async_Notify(channel, payload, use_all);
PG_RETURN_VOID();
}
@@ -540,7 +575,7 @@ pg_notify(PG_FUNCTION_ARGS)
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*/
void
-Async_Notify(const char *channel, const char *payload)
+Async_Notify(const char *channel, const char *payload, bool use_all)
{
Notification *n;
MemoryContext oldcontext;
@@ -570,9 +605,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 (!use_all)
+ /* 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/parser/gram.y b/src/backend/parser/gram.y
index b307b48..7203f4a 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -8528,11 +8528,12 @@ DropRuleStmt:
*
*****************************************************************************/
-NotifyStmt: NOTIFY ColId notify_payload
+NotifyStmt: NOTIFY all_or_distinct ColId notify_payload
{
NotifyStmt *n = makeNode(NotifyStmt);
- n->conditionname = $2;
- n->payload = $3;
+ n->use_all = $2;
+ n->conditionname = $3;
+ n->payload = $4;
$$ = (Node *)n;
}
;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 045f7f0..0e50561 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -599,7 +599,7 @@ standard_ProcessUtility(Node *parsetree,
NotifyStmt *stmt = (NotifyStmt *) parsetree;
PreventCommandDuringRecovery("NOTIFY");
- Async_Notify(stmt->conditionname, stmt->payload);
+ Async_Notify(stmt->conditionname, stmt->payload, stmt->use_all);
}
break;
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 2222e8f..7df163e 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4005,6 +4005,8 @@ DESCR("trigger description with pretty-print option");
/* asynchronous notifications */
DATA(insert OID = 3035 ( pg_listening_channels PGNSP PGUID 12 1 10 0 0 f f f f t t s r 0 0 25 "" _null_ _null_ _null_ _null_ _null_ pg_listening_channels _null_ _null_ _null_ ));
DESCR("get the channels that the current backend listens to");
+DATA(insert OID = 2561 ( pg_notify PGNSP PGUID 12 1 0 0 0 f f f f f f v r 3 0 2278 "25 25 16" _null_ _null_ _null_ _null_ _null_ pg_notify_3args _null_ _null_ _null_ ));
+DESCR("send a notification event");
DATA(insert OID = 3036 ( pg_notify PGNSP PGUID 12 1 0 0 0 f f f f f f v r 2 0 2278 "25 25" _null_ _null_ _null_ _null_ _null_ pg_notify _null_ _null_ _null_ ));
DESCR("send a notification event");
DATA(insert OID = 3296 ( pg_notification_queue_usage PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 701 "" _null_ _null_ _null_ _null_ _null_ pg_notification_queue_usage _null_ _null_ _null_ ));
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index b4c13fa..3a2c1c2 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -29,7 +29,7 @@ extern Size AsyncShmemSize(void);
extern void AsyncShmemInit(void);
/* 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 use_all);
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 2fd0629..7f1f01d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2590,6 +2590,7 @@ typedef struct NotifyStmt
NodeTag type;
char *conditionname; /* condition name to notify */
char *payload; /* the payload string, or NULL if none */
+ bool use_all; /* ALL option */
} NotifyStmt;
/* ----------------------
diff --git a/src/test/regress/expected/async.out b/src/test/regress/expected/async.out
index 19cbe38..c650b90 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',false);
+ pg_notify
+-----------
+
+(1 row)
+
+SELECT pg_notify('notify_async1','sample_message1',true);
+ pg_notify
+-----------
+
+(1 row)
+
SELECT pg_notify('notify_async1','');
pg_notify
-----------
@@ -29,6 +41,8 @@ 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 DISTINCT notify_async2;
+NOTIFY ALL notify_async2;
LISTEN notify_async2;
UNLISTEN notify_async2;
UNLISTEN *;
diff --git a/src/test/regress/sql/async.sql b/src/test/regress/sql/async.sql
index 40f6e01..6e53b86 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',false);
+SELECT pg_notify('notify_async1','sample_message1',true);
SELECT pg_notify('notify_async1','');
SELECT pg_notify('notify_async1',NULL);
@@ -14,6 +16,8 @@ SELECT pg_notify('notify_async_channel_name_too_long____________________________
--Should work. Valid NOTIFY/LISTEN/UNLISTEN commands
NOTIFY notify_async2;
+NOTIFY DISTINCT notify_async2;
+NOTIFY ALL notify_async2;
LISTEN notify_async2;
UNLISTEN notify_async2;
UNLISTEN *;
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers