Hi,

I was using PyGreSQL in one of my projects here, and
it was _really_ inconvenient that there was no way of
fetching NOTICEs and INFOs that came from the server.

Therefore I added such capability to the connection
object (pgobject), by means of (1) registering a
NoticeProcessor kind of callback which stores incoming
messages to the connection-specific circular buffer and
(2) method for fetching the buffered messages.

In the client python code it then looks like:

conn = connect(...)
conn.execute(...)

x = conn.notices()
now x is like [ "NOTICE: ('foo',)", "NOTICE: ('bar',)", ... ]
x = conn.notices()
now x is [], because notices() also clears the buffer.

The patch (against version 3.7) is included below.

Sincerely,
Dmitry Dvoinikov
http://www.targeted.org/

========================== CUT HERE ==========================
*** pgmodule.c.orig     Wed Sep 07 16:29:25 2005
--- pgmodule.c  Tue Nov 01 18:10:03 2005
***************
*** 91,96 ****
--- 91,100 ----
  #define DEFAULT_VARS  1               /* enables default variables use */
  #endif   /* NO_DEF_VAR */
  
+ #ifndef NO_NOTICES
+ #define HANDLE_NOTICES        1               /* enables notices handling */
+ #endif   /* NO_NOTICES */
+ 
  #ifdef MS_WIN32
  #define NO_SNPRINTF 1
  #endif
***************
*** 116,121 ****
--- 120,130 ----
  static PyObject *pg_default_passwd;           /* default password */
  #endif   /* DEFAULT_VARS */
  
+ #ifdef HANDLE_NOTICES
+ #define MAX_BUFFERED_NOTICES 101              /* max notices (+1) to keep for 
each connection */
+ static void notice_processor(void * arg, const char * message);
+ #endif /* HANDLE_NOTICES */
+ 
  DL_EXPORT(void) init_pg(void);
  int              *get_type_array(PGresult *result, int nfields);
  
***************
*** 130,135 ****
--- 139,149 ----
        int                     valid;                  /* validity flag */
        PGconn     *cnx;                        /* PostGres connection handle */
        PGresult   *last_result;        /* last result content */
+ #ifdef HANDLE_NOTICES
+       char      **notices;            /* dynamically allocated circular 
buffer for notices */
+       int                     notices_first;  /* index of first filled index 
in notices */
+       int                     notices_next;   /* index of first free index in 
notices */
+ #endif /* HANDLE_NOTICES */
  }     pgobject;
  
  staticforward PyTypeObject PgType;
***************
*** 147,152 ****
--- 161,171 ----
        pgobj->valid = 1;
        pgobj->last_result = NULL;
        pgobj->cnx = NULL;
+ #ifdef HANDLE_NOTICES
+       pgobj->notices = malloc(sizeof(char*) * MAX_BUFFERED_NOTICES);
+       pgobj->notices_first = 0;
+       pgobj->notices_next = 0;
+ #endif /* HANDLE_NOTICES */
        return (PyObject *) pgobj;
  }
  
***************
*** 1556,1561 ****
--- 1575,1584 ----
                return NULL;
        }
  
+ #ifdef HANDLE_NOTICES
+       PQsetNoticeProcessor(npgobj->cnx, notice_processor, npgobj);
+ #endif /* HANDLE_NOTICES */
+ 
        return (PyObject *) npgobj;
  }
  
***************
*** 1565,1570 ****
--- 1588,1598 ----
  static void
  pg_dealloc(pgobject * self)
  {
+ 
+ #ifdef HANDLE_NOTICES
+       free(self->notices);
+ #endif /* HANDLE_NOTICES */
+ 
        if (self->cnx)
                PQfinish(self->cnx);
  
***************
*** 2696,2701 ****
--- 2724,2799 ----
  }
  #endif   /* LARGE_OBJECTS */
  
+ #ifdef HANDLE_NOTICES
+ 
+ /* fetch accumulated backend notices */
+ static char pg_notices__doc__[] =
+ "notices() -- returns and clears the list of currently accumulated backend 
notices for the connection.";
+ 
+ static void 
+ notice_processor(void * arg, const char * message)
+ {
+       
+       pgobject *pgobj = (pgobject *)arg;
+ 
+       /* skip if memory allocation failed */
+       if (pgobj->notices == NULL) 
+       {
+               return;
+       }
+ 
+       pgobj->notices[pgobj->notices_next] = strdup(message);
+       pgobj->notices_next = (pgobj->notices_next + 1) % MAX_BUFFERED_NOTICES;
+       if (pgobj->notices_next == pgobj->notices_first)
+       {
+               free(pgobj->notices[pgobj->notices_first]);
+               pgobj->notices_first = (pgobj->notices_first + 1) % 
MAX_BUFFERED_NOTICES;
+       }
+ 
+ }
+ 
+ static PyObject *
+ pg_notices(pgobject * self, PyObject * args)
+ {
+ 
+       PyObject *reslist,
+                    *str;
+       int      i;
+ 
+       /* allocate list for result */
+       if ((reslist = PyList_New(0)) == NULL)
+               return NULL;
+ 
+       /* skip if memory allocation failed */
+       if (self->notices == NULL) 
+       {
+               return reslist;
+       }
+ 
+       /* builds result */
+       while (self->notices_first != self->notices_next)
+       {
+               
+               if (self->notices[self->notices_first] != NULL) /* skip if 
memory allocation failed */
+               {
+                       
+                       str = 
PyString_FromString(self->notices[self->notices_first]);
+                       PyList_Append(reslist, str);
+                       Py_DECREF(str);
+ 
+                       free(self->notices[self->notices_first]);
+ 
+               }
+ 
+               self->notices_first = (self->notices_first + 1) % 
MAX_BUFFERED_NOTICES;
+ 
+       }
+ 
+       return reslist;
+ 
+ }
+ 
+ #endif /* HANDLE_NOTICES */
  
  /* connection object methods */
  static struct PyMethodDef pgobj_methods[] = {
***************
*** 2724,2729 ****
--- 2822,2831 ----
        {"getlo", (PyCFunction) pg_getlo, 1, pg_getlo__doc__},
        {"loimport", (PyCFunction) pg_loimport, 1, pg_loimport__doc__},
  #endif   /* LARGE_OBJECTS */
+ 
+ #ifdef HANDLE_NOTICES
+       {"notices", (PyCFunction) pg_notices, 1, pg_notices__doc__},
+ #endif /* HANDLE_NOTICES */
  
        {NULL, NULL}                            /* sentinel */
  };
========================== CUT HERE ==========================


_______________________________________________
PyGreSQL mailing list
[email protected]
http://mailman.vex.net/mailman/listinfo/pygresql

Reply via email to