Re: async notification patch for dblink - Mailing list pgsql-hackers

From Joe Conway
Subject Re: async notification patch for dblink
Date
Msg-id 4A77B762.7070405@joeconway.com
Whole thread Raw
In response to Re: async notification patch for dblink  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: async notification patch for dblink  (Alvaro Herrera <alvherre@commandprompt.com>)
List pgsql-hackers
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Tom Lane wrote:
> [ thinks for awhile... ]  Actually, it seems to me that the present
> patch's definition of the function would be very hard to work with.
> You would normally want to work with the events one at a time.
> There isn't much you could do with the array result except unnest() it,
> and I'm a bit worried that careless usage could result in multiple
> evaluation of the function and hence loss of events.  I wonder whether
> it would be better to have the function return setof record.  Which, not
> incidentally, would greatly simplify adding in those extra result
> fields.

OK, how's this look?

Joe
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iQIcBAEBCAAGBQJKd7diAAoJEDfy90M199hlhlUP/0nsiVPY7wCRdGGs7LsTmnQR
o4Sd9f7R4XlZdakZLKHPf61Qxe33/Af9OdosLToBjssdDW4rrER1rql8+MwddKld
+H/5VZkMRTA91BLbt8kgSZzBj3sGtGpi4zCTgYrFNfTpvCNWK/YLb5rlmbyoCbST
AlnIr/MvcFGNj/JAzQFcoA+YHjEinMnnOA/VS03hbbzBUj2F3Q2uIhsx+YxxZpEQ
jeW54YMOolpsnmQBGIY/NKbU379zWdKtscgKiDO+OLM5OkowaKPbeAZTUBx4+OGR
juOfHH7A5bLZ9APPO/N1yLNHPOLr49DrsYKdkY0Ho97NBEFZhZSqKZQgUemMB+5Z
PNjxFrC2y6HTRabeV+yKQOM/jL8ZmSiSMOwrsdmomAjLNSYi2r2o+XTTDQbNwMqQ
MqHHXRNslooJft2iNWp8iF1L/wX5URroTP+7aZbdTqUqNp/ITJu4BFZTjajZP2zQ
waAAEIVz740yVL3V8mOWyHnHgH1vQEIZ7zMqd4ss0Nn+V9Yltby2hG2Cy9/MRMxt
AkzmE2H+f794mIiyp/jydLiqqgxzbSVOv3m2cx76srSkKY7/C/wZGm2DqjbXqzb/
Dcfs3TgOYozUD02lcnrC4tncdexru/sr6iiAsprslQtzsFxWlHqYqqIh1LfwThba
SJnCszfPpDHx98RA/9b8
=7koq
-----END PGP SIGNATURE-----
Index: contrib/dblink/dblink.c
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/dblink.c,v
retrieving revision 1.82
diff -c -r1.82 dblink.c
*** contrib/dblink/dblink.c    11 Jun 2009 14:48:50 -0000    1.82
--- contrib/dblink/dblink.c    4 Aug 2009 03:48:33 -0000
***************
*** 1635,1640 ****
--- 1635,1723 ----
      PG_RETURN_DATUM(current_query(fcinfo));
  }

+ /*
+  * Retrieve async notifications for a connection.
+  *
+  * Returns an setof record of notifications, or an empty set if none recieved.
+  * Can optionally take a named connection as parameter, but uses the unnamed connection per default.
+  *
+  */
+ #define DBLINK_NOTIFY_COLS        3
+
+ PG_FUNCTION_INFO_V1(dblink_get_notify);
+ Datum
+ dblink_get_notify(PG_FUNCTION_ARGS)
+ {
+     PGconn               *conn = NULL;
+     remoteConn           *rconn = NULL;
+     PGnotify           *notify;
+     ReturnSetInfo       *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+     TupleDesc            tupdesc;
+     Tuplestorestate       *tupstore;
+     MemoryContext        per_query_ctx;
+     MemoryContext        oldcontext;
+
+     DBLINK_INIT;
+     if (PG_NARGS() == 1)
+         DBLINK_GET_NAMED_CONN;
+     else
+         conn = pconn->conn;
+
+     /* create the tuplestore */
+     per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+     oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+     tupdesc = CreateTemplateTupleDesc(DBLINK_NOTIFY_COLS, false);
+     TupleDescInitEntry(tupdesc, (AttrNumber) 1, "notify_name",
+                        TEXTOID, -1, 0);
+     TupleDescInitEntry(tupdesc, (AttrNumber) 2, "be_pid",
+                        INT4OID, -1, 0);
+     TupleDescInitEntry(tupdesc, (AttrNumber) 3, "extra",
+                        TEXTOID, -1, 0);
+
+     tupstore = tuplestore_begin_heap(true, false, work_mem);
+     rsinfo->returnMode = SFRM_Materialize;
+     rsinfo->setResult = tupstore;
+     rsinfo->setDesc = tupdesc;
+
+     MemoryContextSwitchTo(oldcontext);
+
+     PQconsumeInput(conn);
+     while ((notify = PQnotifies(conn)) != NULL)
+     {
+         Datum        values[DBLINK_NOTIFY_COLS];
+         bool        nulls[DBLINK_NOTIFY_COLS];
+
+         memset(values, 0, sizeof(values));
+         memset(nulls, 0, sizeof(nulls));
+
+         if (notify->relname != NULL)
+             values[0] = CStringGetTextDatum(notify->relname);
+         else
+             nulls[0] = true;
+
+         values[1] = Int32GetDatum(notify->be_pid);
+
+         if (notify->extra != NULL)
+             values[2] = CStringGetTextDatum(notify->extra);
+         else
+             nulls[2] = true;
+
+         /* switch to appropriate context while storing the tuple */
+         MemoryContextSwitchTo(per_query_ctx);
+         tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+         MemoryContextSwitchTo(oldcontext);
+
+         PQfreemem(notify);
+         PQconsumeInput(conn);
+     }
+
+     /* clean up and return the tuplestore */
+     tuplestore_donestoring(tupstore);
+
+     return (Datum) 0;
+ }
+
  /*************************************************************
   * internal functions
   */
Index: contrib/dblink/dblink.h
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/dblink.h,v
retrieving revision 1.22
diff -c -r1.22 dblink.h
*** contrib/dblink/dblink.h    9 Jun 2009 17:41:02 -0000    1.22
--- contrib/dblink/dblink.h    4 Aug 2009 02:35:59 -0000
***************
*** 57,61 ****
--- 57,62 ----
  extern Datum dblink_build_sql_delete(PG_FUNCTION_ARGS);
  extern Datum dblink_build_sql_update(PG_FUNCTION_ARGS);
  extern Datum dblink_current_query(PG_FUNCTION_ARGS);
+ extern Datum dblink_get_notify(PG_FUNCTION_ARGS);

  #endif   /* DBLINK_H */
Index: contrib/dblink/dblink.sql.in
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/dblink.sql.in,v
retrieving revision 1.18
diff -c -r1.18 dblink.sql.in
*** contrib/dblink/dblink.sql.in    9 Jun 2009 17:41:02 -0000    1.18
--- contrib/dblink/dblink.sql.in    4 Aug 2009 03:51:03 -0000
***************
*** 202,204 ****
--- 202,221 ----
  RETURNS text
  AS 'MODULE_PATHNAME', 'dblink_error_message'
  LANGUAGE C STRICT;
+
+ CREATE TYPE dblink_get_notify_type AS
+ (
+     notify_name TEXT,
+     be_pid INT4,
+     extra TEXT
+ );
+
+ CREATE OR REPLACE FUNCTION dblink_get_notify()
+ RETURNS setof dblink_get_notify_type
+ AS 'MODULE_PATHNAME', 'dblink_get_notify'
+ LANGUAGE C STRICT;
+
+ CREATE OR REPLACE FUNCTION dblink_get_notify(conname text)
+ RETURNS setof dblink_get_notify_type
+ AS 'MODULE_PATHNAME', 'dblink_get_notify'
+ LANGUAGE C STRICT;
Index: contrib/dblink/uninstall_dblink.sql
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/uninstall_dblink.sql,v
retrieving revision 1.7
diff -c -r1.7 uninstall_dblink.sql
*** contrib/dblink/uninstall_dblink.sql    5 Apr 2008 02:26:14 -0000    1.7
--- contrib/dblink/uninstall_dblink.sql    4 Aug 2009 02:35:59 -0000
***************
*** 76,78 ****
--- 76,82 ----
  DROP FUNCTION dblink_is_busy(text);

  DROP FUNCTION dblink_send_query(text, text);
+
+ DROP FUNCTION dblink_get_notify();
+
+ DROP FUNCTION dblink_get_notify(text);
Index: contrib/dblink/expected/dblink.out
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/expected/dblink.out,v
retrieving revision 1.25
diff -c -r1.25 dblink.out
*** contrib/dblink/expected/dblink.out    6 Jun 2009 21:27:56 -0000    1.25
--- contrib/dblink/expected/dblink.out    4 Aug 2009 04:07:05 -0000
***************
*** 827,829 ****
--- 827,870 ----
  DROP USER MAPPING FOR public SERVER fdtest;
  DROP SERVER fdtest;
  DROP FOREIGN DATA WRAPPER postgresql;
+ -- test asynchronous notifications
+ SELECT dblink_connect('dbname=contrib_regression');
+  dblink_connect
+ ----------------
+  OK
+ (1 row)
+
+ --should return listen
+ SELECT dblink_exec('LISTEN regression');
+  dblink_exec
+ -------------
+  LISTEN
+ (1 row)
+
+ --should return listen
+ SELECT dblink_exec('LISTEN foobar');
+  dblink_exec
+ -------------
+  LISTEN
+ (1 row)
+
+ NOTIFY regression;
+ NOTIFY foobar;
+ SELECT notify_name, be_pid/be_pid as be_pid, extra from dblink_get_notify();
+  notify_name | be_pid | extra
+ -------------+--------+-------
+  regression  |      1 |
+  foobar      |      1 |
+ (2 rows)
+
+ SELECT * from dblink_get_notify();
+  notify_name | be_pid | extra
+ -------------+--------+-------
+ (0 rows)
+
+ SELECT dblink_disconnect();
+  dblink_disconnect
+ -------------------
+  OK
+ (1 row)
+
Index: contrib/dblink/sql/dblink.sql
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/sql/dblink.sql,v
retrieving revision 1.21
diff -c -r1.21 dblink.sql
*** contrib/dblink/sql/dblink.sql    6 Jun 2009 21:27:56 -0000    1.21
--- contrib/dblink/sql/dblink.sql    4 Aug 2009 04:06:37 -0000
***************
*** 389,391 ****
--- 389,408 ----
  DROP USER MAPPING FOR public SERVER fdtest;
  DROP SERVER fdtest;
  DROP FOREIGN DATA WRAPPER postgresql;
+
+ -- test asynchronous notifications
+ SELECT dblink_connect('dbname=contrib_regression');
+
+ --should return listen
+ SELECT dblink_exec('LISTEN regression');
+ --should return listen
+ SELECT dblink_exec('LISTEN foobar');
+
+ NOTIFY regression;
+ NOTIFY foobar;
+
+ SELECT notify_name, be_pid/be_pid as be_pid, extra from dblink_get_notify();
+
+ SELECT * from dblink_get_notify();
+
+ SELECT dblink_disconnect();
Index: doc/src/sgml/dblink.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql/doc/src/sgml/dblink.sgml,v
retrieving revision 1.8
diff -c -r1.8 dblink.sgml
*** doc/src/sgml/dblink.sgml    18 Jun 2009 14:34:36 -0000    1.8
--- doc/src/sgml/dblink.sgml    4 Aug 2009 04:13:45 -0000
***************
*** 1260,1265 ****
--- 1260,1338 ----
    </refsect1>
   </refentry>

+  <refentry id="CONTRIB-DBLINK-GET-NOTIFY">
+   <refnamediv>
+    <refname>dblink_get_notify</refname>
+    <refpurpose>retrieve async notifications on a connection</refpurpose>
+   </refnamediv>
+
+   <refsynopsisdiv>
+    <synopsis>
+     dblink_get_notify() returns setof (notify_name text, be_pid int, extra text)
+     dblink_get_notify(text connname) returns setof (notify_name text, be_pid int, extra text)
+    </synopsis>
+   </refsynopsisdiv>
+
+   <refsect1>
+    <title>Description</title>
+
+    <para>
+     <function>dblink_get_notify</> retrieves notifications on either
+     the unnamed connection, or on a named connection if specified.
+     To receive notifications via dblink, <function>LISTEN</> must
+     first be issued, using <function>dblink_exec</>.
+     For details see <xref linkend="sql-listen"> and <xref linkend="sql-notify">.
+    </para>
+
+   </refsect1>
+
+   <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+     <varlistentry>
+      <term><parameter>conname</parameter></term>
+      <listitem>
+       <para>
+        The name of a named connection to get notifications on.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+   </refsect1>
+
+   <refsect1>
+    <title>Return Value</title>
+     <para>Returns setof (notify_name text, be_pid int, extra text), or an empty set if none.</para>
+   </refsect1>
+
+   <refsect1>
+    <title>Example</title>
+
+    <programlisting>
+ test=# SELECT dblink_exec('LISTEN virtual');
+  dblink_exec
+ -------------
+  LISTEN
+ (1 row)
+
+ test=# SELECT * FROM dblink_get_notify();
+  notify_name | be_pid | extra
+ -------------+--------+-------
+ (0 rows)
+
+ test=# NOTIFY virtual;
+ NOTIFY
+
+ SELECT * FROM dblink_get_notify();
+  notify_name | be_pid | extra
+ -------------+--------+-------
+  virtual     |   1229 |
+ (1 row)
+    </programlisting>
+   </refsect1>
+  </refentry>
+
   <refentry id="CONTRIB-DBLINK-GET-RESULT">
    <refmeta>
     <refentrytitle>dblink_get_result</refentrytitle>

pgsql-hackers by date:

Previous
From: KaiGai Kohei
Date:
Subject: Re: SE-PostgreSQL Specifications
Next
From: Pavel Stehule
Date:
Subject: Re: Patch for 8.5, transformationHook