diff -Nru postgresql-8.0.2-vanilla/src/backend/catalog/Makefile postgresql-8.0.2/src/backend/catalog/Makefile --- postgresql-8.0.2-vanilla/src/backend/catalog/Makefile 2004-07-21 22:34:45.000000000 +0200 +++ postgresql-8.0.2/src/backend/catalog/Makefile 2005-05-07 05:51:05.840517947 +0200 @@ -30,7 +30,7 @@ pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h \ pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \ pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \ - pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \ + pg_rewrite.h pg_trigger.h pg_listener.h pg_notify.h pg_description.h pg_cast.h \ pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \ pg_tablespace.h pg_depend.h indexing.h \ ) diff -Nru postgresql-8.0.2-vanilla/src/backend/commands/async.c postgresql-8.0.2/src/backend/commands/async.c --- postgresql-8.0.2-vanilla/src/backend/commands/async.c 2004-12-31 22:59:41.000000000 +0100 +++ postgresql-8.0.2/src/backend/commands/async.c 2005-05-12 07:49:37.240803594 +0200 @@ -81,6 +81,7 @@ #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/pg_listener.h" +#include "catalog/pg_notify.h" #include "commands/async.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" @@ -131,7 +132,7 @@ static void Async_UnlistenAll(void); static void Async_UnlistenOnExit(int code, Datum arg); static void ProcessIncomingNotify(void); -static void NotifyMyFrontEnd(char *relname, int32 listenerPID); +static void NotifyMyFrontEnd(char *relname, int32 listenerPID, char *message); static bool AsyncExistsPendingNotify(const char *relname); static void ClearPendingNotifies(void); @@ -152,26 +153,25 @@ *-------------------------------------------------------------- */ void -Async_Notify(char *relname) +Async_Notify(NotifyStmt *stmt) { if (Trace_notify) - elog(DEBUG1, "Async_Notify(%s)", relname); + if (stmt->message[0] != '\0') + elog(DEBUG1, "Async_Notify(%s,%s)", stmt->relation->relname, stmt->message); + else + elog(DEBUG1, "Async_Notify(%s)", stmt->relation->relname); - /* no point in making duplicate entries in the list ... */ - if (!AsyncExistsPendingNotify(relname)) - { - /* - * The name list needs to live until end of transaction, so store - * it in the transaction context. - */ - MemoryContext oldcontext; + /* + * The notify list needs to live until end of transaction, so store + * it in the transaction context. + */ + MemoryContext oldcontext; - oldcontext = MemoryContextSwitchTo(CurTransactionContext); + oldcontext = MemoryContextSwitchTo(CurTransactionContext); - pendingNotifies = lcons(pstrdup(relname), pendingNotifies); + pendingNotifies = lcons(stmt, pendingNotifies); //FIXME: shouldn't we use a copy of the statement here? - MemoryContextSwitchTo(oldcontext); - } + MemoryContextSwitchTo(oldcontext); } /* @@ -242,7 +242,7 @@ i = 0; values[i++] = (Datum) relname; values[i++] = (Datum) pid; - values[i++] = (Datum) 0; /* no notifies pending */ + //values[i++] = (Datum) 0; /* no notifies pending */ tuple = heap_formtuple(RelationGetDescr(lRel), values, nulls); simple_heap_insert(lRel, tuple); @@ -433,14 +433,14 @@ void AtCommit_Notify(void) { - Relation lRel; + Relation lRel, + nRel; TupleDesc tdesc; HeapScanDesc scan; HeapTuple lTuple, - rTuple; - Datum value[Natts_pg_listener]; - char repl[Natts_pg_listener], - nulls[Natts_pg_listener]; + nTuple; + Datum value[Natts_pg_notify]; + char nulls[Natts_pg_notify]; if (pendingNotifies == NIL) return; /* no NOTIFY statements in this @@ -459,14 +459,16 @@ if (Trace_notify) elog(DEBUG1, "AtCommit_Notify"); - /* preset data to update notify column to MyProcPid */ - nulls[0] = nulls[1] = nulls[2] = ' '; - repl[0] = repl[1] = repl[2] = ' '; - repl[Anum_pg_listener_notify - 1] = 'r'; - value[0] = value[1] = value[2] = (Datum) 0; - value[Anum_pg_listener_notify - 1] = Int32GetDatum(MyProcPid); + for (i = 0; i < Natts_pg_listener; i++) + { + nulls[i] = ' '; + values[i] = PointerGetDatum(NULL); + } + + value[Anum_pg_notify_senderpid - 1] = Int32GetDatum(MyProcPid); lRel = heap_openr(ListenerRelationName, ExclusiveLock); + nRel = heap_openr(NotifyRelationName, ExclusiveLock); tdesc = RelationGetDescr(lRel); scan = heap_beginscan(lRel, SnapshotNow, 0, NULL); @@ -476,103 +478,61 @@ char *relname = NameStr(listener->relname); int32 listenerPID = listener->listenerpid; - if (!AsyncExistsPendingNotify(relname)) - continue; - - if (listenerPID == MyProcPid) - { - /* - * Self-notify: no need to bother with table update. Indeed, - * we *must not* clear the notification field in this path, or - * we could lose an outside notify, which'd be bad for - * applications that ignore self-notify messages. - */ + ListCell *cell; + foreach(cell, pendingNotifies) { + NotifyStmt *stmt = (NotifyStmt *) lfirst(cell); - if (Trace_notify) - elog(DEBUG1, "AtCommit_Notify: notifying self"); + if (strncmp(stmt->relation->relname, relname, NAMEDATALEN)) + continue; - NotifyMyFrontEnd(relname, listenerPID); - } - else - { - if (Trace_notify) - elog(DEBUG1, "AtCommit_Notify: notifying pid %d", - listenerPID); - - /* - * If someone has already notified this listener, we don't - * bother modifying the table, but we do still send a SIGUSR2 - * signal, just in case that backend missed the earlier signal - * for some reason. It's OK to send the signal first, because - * the other guy can't read pg_listener until we unlock it. - */ - if (kill(listenerPID, SIGUSR2) < 0) + if (listenerPID == MyProcPid) { /* - * Get rid of pg_listener entry if it refers to a PID that - * no longer exists. Presumably, that backend crashed - * without deleting its pg_listener entries. This code - * used to only delete the entry if errno==ESRCH, but as - * far as I can see we should just do it for any failure - * (certainly at least for EPERM too...) + * Self-notify: no need to bother with table update. Indeed, + * we *must not* clear the notification field in this path, or + * we could lose an outside notify, which'd be bad for + * applications that ignore self-notify messages. */ - simple_heap_delete(lRel, &lTuple->t_self); + + if (Trace_notify) + elog(DEBUG1, "AtCommit_Notify: notifying self"); + + NotifyMyFrontEnd(relname, listenerPID, message); } - else if (listener->notification == 0) + else { - ItemPointerData ctid; - int result; - - rTuple = heap_modifytuple(lTuple, lRel, - value, nulls, repl); + if (Trace_notify) + elog(DEBUG1, "AtCommit_Notify: notifying pid %d", + listenerPID); /* - * We cannot use simple_heap_update here because the tuple - * could have been modified by an uncommitted transaction; - * specifically, since UNLISTEN releases exclusive lock on - * the table before commit, the other guy could already - * have tried to unlisten. There are no other cases where - * we should be able to see an uncommitted update or - * delete. Therefore, our response to a - * HeapTupleBeingUpdated result is just to ignore it. We - * do *not* wait for the other guy to commit --- that - * would risk deadlock, and we don't want to block while - * holding the table lock anyway for performance reasons. - * We also ignore HeapTupleUpdated, which could occur if - * the other guy commits between our heap_getnext and - * heap_update calls. + * If someone has already notified this listener, we don't + * bother modifying the table, but we do still send a SIGUSR2 + * signal, just in case that backend missed the earlier signal + * for some reason. It's OK to send the signal first, because + * the other guy can't read pg_listener until we unlock it. */ - result = heap_update(lRel, &lTuple->t_self, rTuple, - &ctid, - GetCurrentCommandId(), InvalidSnapshot, - false /* no wait for commit */ ); - switch (result) + if (kill(listenerPID, SIGUSR2) < 0) { - case HeapTupleSelfUpdated: - /* Tuple was already updated in current command? */ - elog(ERROR, "tuple already updated by self"); - break; - - case HeapTupleMayBeUpdated: - /* done successfully */ - -#ifdef NOT_USED /* currently there are no indexes */ - CatalogUpdateIndexes(lRel, rTuple); -#endif - break; + /* + * Get rid of pg_listener entry if it refers to a PID that + * no longer exists. Presumably, that backend crashed + * without deleting its pg_listener entries. This code + * used to only delete the entry if errno==ESRCH, but as + * far as I can see we should just do it for any failure + * (certainly at least for EPERM too...) + */ + simple_heap_delete(lRel, &lTuple->t_self); + //FIXME: we ought to delete pending notifications from pg_notify as well + } + else // if (listener->notification == 0) // we want to insert each notification + { + value[Anum_pg_notify_relname - 1] = (Datum) relname; + value[Anum_pg_notify_recipientpid - 1] = Int32GetDatum(listenerPID); + value[Anum_pg_notify_message - 1] = (Datum) stmt->message; - case HeapTupleBeingUpdated: - /* ignore uncommitted tuples */ - break; - - case HeapTupleUpdated: - /* ignore just-committed tuples */ - break; - - default: - elog(ERROR, "unrecognized heap_update status: %u", - result); - break; + nTuple = heap_formtuple(RelationGetDescr(nRel), values, nulls); + simple_heap_insert(nRel, nTuple); } } } @@ -587,6 +547,7 @@ * Else they might disregard the signal, which would make the * application programmer very unhappy. */ + heap_close(nRel, NoLock); heap_close(lRel, NoLock); ClearPendingNotifies(); @@ -870,8 +831,7 @@ * Deal with arriving NOTIFYs from other backends. * This is called either directly from the SIGUSR2 signal handler, * or the next time control reaches the outer idle loop. - * Scan pg_listener for arriving notifies, report them to my front end, - * and clear the notification field in pg_listener until next time. + * Scan pg_notify for arriving notifies and report them to my front end. * * NOTE: since we are outside any transaction, we must create our own. * -------------------------------------------------------------- @@ -883,11 +843,7 @@ TupleDesc tdesc; ScanKeyData key[1]; HeapScanDesc scan; - HeapTuple lTuple, - rTuple; - Datum value[Natts_pg_listener]; - char repl[Natts_pg_listener], - nulls[Natts_pg_listener]; + HeapTuple lTuple; bool catchup_enabled; /* Must prevent SIGUSR1 interrupt while I am running */ @@ -902,53 +858,43 @@ StartTransactionCommand(); - lRel = heap_openr(ListenerRelationName, ExclusiveLock); + lRel = heap_openr(NotifyRelationName, ExclusiveLock); tdesc = RelationGetDescr(lRel); - /* Scan only entries with my listenerPID */ + /* Scan only entries with my recipientPID */ ScanKeyInit(&key[0], - Anum_pg_listener_pid, + Anum_pg_notify_recipientpid, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(MyProcPid)); scan = heap_beginscan(lRel, SnapshotNow, 1, key); - /* Prepare data for rewriting 0 into notification field */ - nulls[0] = nulls[1] = nulls[2] = ' '; - repl[0] = repl[1] = repl[2] = ' '; - repl[Anum_pg_listener_notify - 1] = 'r'; - value[0] = value[1] = value[2] = (Datum) 0; - value[Anum_pg_listener_notify - 1] = Int32GetDatum(0); - while ((lTuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { - Form_pg_listener listener = (Form_pg_listener) GETSTRUCT(lTuple); - char *relname = NameStr(listener->relname); - int32 sourcePID = listener->notification; + Form_pg_notify notify = (Form_pg_notify) GETSTRUCT(lTuple); + char *relname = NameStr(notify->relname); + int32 sourcePID = notify->senderpid; + char *message = NameStr(notify->message); + + /* Notify the frontend */ + + if (Trace_notify) + elog(DEBUG1, "ProcessIncomingNotify: received %s(%s) from %d", + relname, message, (int) sourcePID); - if (sourcePID != 0) - { - /* Notify the frontend */ + NotifyMyFrontEnd(relname, sourcePID, message); - if (Trace_notify) - elog(DEBUG1, "ProcessIncomingNotify: received %s from %d", - relname, (int) sourcePID); - - NotifyMyFrontEnd(relname, sourcePID); - - /* - * Rewrite the tuple with 0 in notification column. - * - * simple_heap_update is safe here because no one else would have - * tried to UNLISTEN us, so there can be no uncommitted - * changes. - */ - rTuple = heap_modifytuple(lTuple, lRel, value, nulls, repl); - simple_heap_update(lRel, &lTuple->t_self, rTuple); + /* + * Delete the tuple. + * + * simple_heap_delete is safe here because no one else would have + * tried to process notifies with our PID, so there can be no uncommitted + * changes. + */ + simple_heap_delete(lRel, &lTuple->t_self); #ifdef NOT_USED /* currently there are no indexes */ - CatalogUpdateIndexes(lRel, rTuple); + CatalogUpdateIndexes(lRel, rTuple); #endif - } } heap_endscan(scan); @@ -982,7 +928,7 @@ * Send NOTIFY message to my front end. */ static void -NotifyMyFrontEnd(char *relname, int32 listenerPID) +NotifyMyFrontEnd(char *relname, int32 listenerPID, char *message) { if (whereToSendOutput == Remote) { @@ -993,8 +939,7 @@ pq_sendstring(&buf, relname); if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) { - /* XXX Add parameter string here later */ - pq_sendstring(&buf, ""); + pq_sendstring(&buf, message); } pq_endmessage(&buf); @@ -1006,23 +951,17 @@ */ } else - elog(INFO, "NOTIFY for %s", relname); + if (message[0] != '\0') + elog(INFO, "NOTIFY for %s: %s", relname, message); + else + elog(INFO, "NOTIFY for %s", relname); } -/* Does pendingNotifies include the given relname? */ +/* Does pendingNotifies already have a statement identical to the given one? */ static bool -AsyncExistsPendingNotify(const char *relname) +AsyncExistsPendingNotify(NotifyStmt *stmt) { - ListCell *p; - - foreach(p, pendingNotifies) - { - /* Use NAMEDATALEN for relname comparison. DZ - 26-08-1996 */ - if (strncmp((const char *) lfirst(p), relname, NAMEDATALEN) == 0) - return true; - } - - return false; + return list_member(pendingNotifies, stmt); } /* Clear the pendingNotifies list. */ diff -Nru postgresql-8.0.2-vanilla/src/backend/nodes/copyfuncs.c postgresql-8.0.2/src/backend/nodes/copyfuncs.c --- postgresql-8.0.2-vanilla/src/backend/nodes/copyfuncs.c 2004-12-31 22:59:55.000000000 +0100 +++ postgresql-8.0.2/src/backend/nodes/copyfuncs.c 2005-05-07 05:59:04.948033379 +0200 @@ -1991,6 +1991,7 @@ NotifyStmt *newnode = makeNode(NotifyStmt); COPY_NODE_FIELD(relation); + COPY_STRING_FIELD(message); return newnode; } diff -Nru postgresql-8.0.2-vanilla/src/backend/nodes/equalfuncs.c postgresql-8.0.2/src/backend/nodes/equalfuncs.c --- postgresql-8.0.2-vanilla/src/backend/nodes/equalfuncs.c 2004-12-31 22:59:55.000000000 +0100 +++ postgresql-8.0.2/src/backend/nodes/equalfuncs.c 2005-05-12 07:54:25.612788790 +0200 @@ -1041,6 +1041,7 @@ _equalNotifyStmt(NotifyStmt *a, NotifyStmt *b) { COMPARE_NODE_FIELD(relation); + COMPARE_STRING_FIELD(message); return true; } diff -Nru postgresql-8.0.2-vanilla/src/backend/nodes/outfuncs.c postgresql-8.0.2/src/backend/nodes/outfuncs.c --- postgresql-8.0.2-vanilla/src/backend/nodes/outfuncs.c 2004-12-31 22:59:55.000000000 +0100 +++ postgresql-8.0.2/src/backend/nodes/outfuncs.c 2005-05-12 07:09:35.167695542 +0200 @@ -1172,6 +1172,7 @@ WRITE_NODE_TYPE("NOTIFY"); WRITE_NODE_FIELD(relation); + WRITE_STRING_FIELD(message); } static void diff -Nru postgresql-8.0.2-vanilla/src/backend/nodes/readfuncs.c postgresql-8.0.2/src/backend/nodes/readfuncs.c --- postgresql-8.0.2-vanilla/src/backend/nodes/readfuncs.c 2004-12-31 22:59:55.000000000 +0100 +++ postgresql-8.0.2/src/backend/nodes/readfuncs.c 2005-05-12 07:09:50.317705869 +0200 @@ -169,6 +169,7 @@ READ_LOCALS(NotifyStmt); READ_NODE_FIELD(relation); + READ_STRING_FIELD(message); READ_DONE(); } diff -Nru postgresql-8.0.2-vanilla/src/backend/parser/gram.y postgresql-8.0.2/src/backend/parser/gram.y --- postgresql-8.0.2-vanilla/src/backend/parser/gram.y 2004-12-31 23:00:27.000000000 +0100 +++ postgresql-8.0.2/src/backend/parser/gram.y 2005-05-07 06:15:48.957070922 +0200 @@ -3911,14 +3911,20 @@ * *****************************************************************************/ -NotifyStmt: NOTIFY qualified_name +NotifyStmt: NOTIFY qualified_name opt_notifymessage { NotifyStmt *n = makeNode(NotifyStmt); n->relation = $2; + n->message = $3; $$ = (Node *)n; } ; +opt_notifymessage: + Sconst { $$ = $1; } + | /*EMPTY*/ { $$ = ""; } + ; + ListenStmt: LISTEN qualified_name { ListenStmt *n = makeNode(ListenStmt); diff -Nru postgresql-8.0.2-vanilla/src/backend/tcop/utility.c postgresql-8.0.2/src/backend/tcop/utility.c --- postgresql-8.0.2-vanilla/src/backend/tcop/utility.c 2005-01-24 18:46:29.000000000 +0100 +++ postgresql-8.0.2/src/backend/tcop/utility.c 2005-05-07 05:10:28.696829622 +0200 @@ -779,7 +779,7 @@ { NotifyStmt *stmt = (NotifyStmt *) parsetree; - Async_Notify(stmt->relation->relname); + Async_Notify(stmt); } break; diff -Nru postgresql-8.0.2-vanilla/src/include/catalog/catname.h postgresql-8.0.2/src/include/catalog/catname.h --- postgresql-8.0.2-vanilla/src/include/catalog/catname.h 2004-12-31 23:03:24.000000000 +0100 +++ postgresql-8.0.2/src/include/catalog/catname.h 2005-05-07 05:26:05.552087319 +0200 @@ -32,6 +32,7 @@ #define LanguageRelationName "pg_language" #define LargeObjectRelationName "pg_largeobject" #define ListenerRelationName "pg_listener" +#define NotifyRelationName "pg_notify" #define NamespaceRelationName "pg_namespace" #define OperatorClassRelationName "pg_opclass" #define OperatorRelationName "pg_operator" diff -Nru postgresql-8.0.2-vanilla/src/include/catalog/pg_listener.h postgresql-8.0.2/src/include/catalog/pg_listener.h --- postgresql-8.0.2-vanilla/src/include/catalog/pg_listener.h 2004-12-31 23:03:24.000000000 +0100 +++ postgresql-8.0.2/src/include/catalog/pg_listener.h 2005-05-07 05:46:37.722805287 +0200 @@ -36,7 +36,6 @@ { NameData relname; int4 listenerpid; - int4 notification; } FormData_pg_listener; /* ---------------- @@ -50,10 +49,9 @@ * compiler constants for pg_listener * ---------------- */ -#define Natts_pg_listener 3 +#define Natts_pg_listener 2 #define Anum_pg_listener_relname 1 #define Anum_pg_listener_pid 2 -#define Anum_pg_listener_notify 3 /* ---------------- * initial contents of pg_listener are NOTHING. diff -Nru postgresql-8.0.2-vanilla/src/include/catalog/pg_notify.h postgresql-8.0.2/src/include/catalog/pg_notify.h --- postgresql-8.0.2-vanilla/src/include/catalog/pg_notify.h 1970-01-01 01:00:00.000000000 +0100 +++ postgresql-8.0.2/src/include/catalog/pg_notify.h 2005-05-07 08:00:53.316391409 +0200 @@ -0,0 +1,65 @@ +/*------------------------------------------------------------------------- + * + * pg_notify.h + * Asynchronous notification + * + * + * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * $PostgreSQL: pgsql/src/include/catalog/pg_notify.h,v 1.18 2004/12/31 22:03:24 pgsql Exp $ + * + * NOTES + * the genbki.sh script reads this file and generates .bki + * information from the DATA() statements. + * + *------------------------------------------------------------------------- + */ +#ifndef PG_NOTIFY_H +#define PG_NOTIFY_H + +/* ---------------- + * postgres.h contains the system type definitions and the + * CATALOG(), BOOTSTRAP and DATA() sugar words so this file + * can be read by both genbki.sh and the C compiler. + * ---------------- + */ + +/* ---------------------------------------------------------------- + * pg_notify definition. + * + * cpp turns this into typedef struct FormData_pg_notify + * ---------------------------------------------------------------- + */ + +CATALOG(pg_notify) BKI_WITHOUT_OIDS +{ + NameData relname; + int4 senderpid; + int4 recipientpid; + NameData message; //FIXME: what about type text instead? +} FormData_pg_notify; + +/* ---------------- + * Form_pg_notify corresponds to a pointer to a tuple with + * the format of pg_notify relation. + * ---------------- + */ +typedef FormData_pg_notify *Form_pg_notify; + +/* ---------------- + * compiler constants for pg_notify + * ---------------- + */ +#define Natts_pg_notify 4 +#define Anum_pg_notify_relname 1 +#define Anum_pg_notify_senderpid 2 +#define Anum_pg_notify_recipientpid 3 +#define Anum_pg_notify_message 4 + +/* ---------------- + * initial contents of pg_notify are NOTHING. + * ---------------- + */ + +#endif /* PG_NOTIFY_H */ diff -Nru postgresql-8.0.2-vanilla/src/include/commands/async.h postgresql-8.0.2/src/include/commands/async.h --- postgresql-8.0.2-vanilla/src/include/commands/async.h 2004-12-31 23:03:28.000000000 +0100 +++ postgresql-8.0.2/src/include/commands/async.h 2005-05-12 08:46:02.056984528 +0200 @@ -16,7 +16,7 @@ extern bool Trace_notify; /* notify-related SQL statements */ -extern void Async_Notify(char *relname); +extern void Async_Notify(NotifyStmt *stmt); extern void Async_Listen(char *relname, int pid); extern void Async_Unlisten(char *relname, int pid); diff -Nru postgresql-8.0.2-vanilla/src/include/nodes/parsenodes.h postgresql-8.0.2/src/include/nodes/parsenodes.h --- postgresql-8.0.2-vanilla/src/include/nodes/parsenodes.h 2004-12-31 23:03:34.000000000 +0100 +++ postgresql-8.0.2/src/include/nodes/parsenodes.h 2005-05-12 07:10:42.282451376 +0200 @@ -1500,6 +1500,7 @@ { NodeTag type; RangeVar *relation; /* qualified name to notify */ + char *message; /* message to send with notify */ } NotifyStmt; /* ---------------------- diff -Nru postgresql-8.0.2-vanilla/src/tools/pgindent/pgindent postgresql-8.0.2/src/tools/pgindent/pgindent --- postgresql-8.0.2-vanilla/src/tools/pgindent/pgindent 2004-10-07 16:15:50.000000000 +0200 +++ postgresql-8.0.2/src/tools/pgindent/pgindent 2005-05-07 05:49:01.211821875 +0200 @@ -497,6 +497,7 @@ -TFormData_pg_language \ -TFormData_pg_largeobject \ -TFormData_pg_listener \ +-TFormData_pg_notify \ -TFormData_pg_namespace \ -TFormData_pg_opclass \ -TFormData_pg_operator \ @@ -527,6 +528,7 @@ -TForm_pg_language \ -TForm_pg_largeobject \ -TForm_pg_listener \ +-TForm_pg_notify \ -TForm_pg_namespace \ -TForm_pg_opclass \ -TForm_pg_operator \