From 31812c01e6b4ba5476902a19430254ef8a6ab445 Mon Sep 17 00:00:00 2001
From: Daniele Varrazzo <daniele.varrazzo@gmail.com>
Date: Sun, 4 Mar 2012 04:38:44 +0000
Subject: [PATCH] Further modeling of exception raising

---
 psycopg/adapter_qstring.c   |  2 +-
 psycopg/lobject.h           | 22 +++++++++++-----------
 psycopg/lobject_int.c       | 22 +++++++++++-----------
 psycopg/psycopgmodule.c     | 22 ++++++++++------------
 psycopg/typecast.c          |  4 ++--
 psycopg/typecast.h          |  4 ++--
 psycopg/typecast_array.c    | 19 +++++++++----------
 psycopg/typecast_datetime.c |  2 +-
 psycopg/xid_type.c          |  2 +-
 9 files changed, 48 insertions(+), 51 deletions(-)

diff --git a/psycopg/adapter_qstring.c b/psycopg/adapter_qstring.c
index a9d4ec6e..4240d382 100644
--- a/psycopg/adapter_qstring.c
+++ b/psycopg/adapter_qstring.c
@@ -35,7 +35,7 @@
 
 /* qstring_quote - do the quote process on plain and unicode strings */
 
-static PyObject *
+BORROWED static PyObject *
 qstring_quote(qstringObject *self)
 {
     PyObject *str;
diff --git a/psycopg/lobject.h b/psycopg/lobject.h
index f52d85cf..6587198c 100644
--- a/psycopg/lobject.h
+++ b/psycopg/lobject.h
@@ -51,19 +51,19 @@ typedef struct {
 
 /* functions exported from lobject_int.c */
 
-HIDDEN int lobject_open(lobjectObject *self, connectionObject *conn,
-                        Oid oid, const char *smode, Oid new_oid,
-                        const char *new_file);
-HIDDEN int lobject_unlink(lobjectObject *self);
-HIDDEN int lobject_export(lobjectObject *self, const char *filename);
+RAISES_NEG HIDDEN int lobject_open(lobjectObject *self, connectionObject *conn,
+                                   Oid oid, const char *smode, Oid new_oid,
+                                   const char *new_file);
+RAISES_NEG HIDDEN int lobject_unlink(lobjectObject *self);
+RAISES_NEG HIDDEN int lobject_export(lobjectObject *self, const char *filename);
 
-HIDDEN Py_ssize_t lobject_read(lobjectObject *self, char *buf, size_t len);
-HIDDEN Py_ssize_t lobject_write(lobjectObject *self, const char *buf,
+RAISES_NEG HIDDEN Py_ssize_t lobject_read(lobjectObject *self, char *buf, size_t len);
+RAISES_NEG HIDDEN Py_ssize_t lobject_write(lobjectObject *self, const char *buf,
                                 size_t len);
-HIDDEN int lobject_seek(lobjectObject *self, int pos, int whence);
-HIDDEN int lobject_tell(lobjectObject *self);
-HIDDEN int lobject_truncate(lobjectObject *self, size_t len);
-HIDDEN int lobject_close(lobjectObject *self);
+RAISES_NEG HIDDEN int lobject_seek(lobjectObject *self, int pos, int whence);
+RAISES_NEG HIDDEN int lobject_tell(lobjectObject *self);
+RAISES_NEG HIDDEN int lobject_truncate(lobjectObject *self, size_t len);
+RAISES_NEG HIDDEN int lobject_close(lobjectObject *self);
 
 #define lobject_is_closed(self) \
     ((self)->fd < 0 || !(self)->conn || (self)->conn->closed)
diff --git a/psycopg/lobject_int.c b/psycopg/lobject_int.c
index f180c8c2..5f23ca25 100644
--- a/psycopg/lobject_int.c
+++ b/psycopg/lobject_int.c
@@ -50,7 +50,7 @@ collect_error(connectionObject *conn, char **error)
  *
  * Valid mode are [r|w|rw|n][t|b]
  */
-static int
+RAISES_NEG static int
 _lobject_parse_mode(const char *mode)
 {
     int rv = 0;
@@ -147,7 +147,7 @@ _lobject_unparse_mode(int mode)
 
 /* lobject_open - create a new/open an existing lo */
 
-int
+RAISES_NEG int
 lobject_open(lobjectObject *self, connectionObject *conn,
               Oid oid, const char *smode, Oid new_oid, const char *new_file)
 {
@@ -237,7 +237,7 @@ lobject_open(lobjectObject *self, connectionObject *conn,
 
 /* lobject_close - close an existing lo */
 
-static int
+RAISES_NEG static int
 lobject_close_locked(lobjectObject *self, char **error)
 {
     int retvalue;
@@ -270,7 +270,7 @@ lobject_close_locked(lobjectObject *self, char **error)
     return retvalue;
 }
 
-int
+RAISES_NEG int
 lobject_close(lobjectObject *self)
 {
     PGresult *pgres = NULL;
@@ -292,7 +292,7 @@ lobject_close(lobjectObject *self)
 
 /* lobject_unlink - remove an lo from database */
 
-int
+RAISES_NEG int
 lobject_unlink(lobjectObject *self)
 {
     PGresult *pgres = NULL;
@@ -326,7 +326,7 @@ lobject_unlink(lobjectObject *self)
 
 /* lobject_write - write bytes to a lo */
 
-Py_ssize_t
+RAISES_NEG Py_ssize_t
 lobject_write(lobjectObject *self, const char *buf, size_t len)
 {
     Py_ssize_t written;
@@ -353,7 +353,7 @@ lobject_write(lobjectObject *self, const char *buf, size_t len)
 
 /* lobject_read - read bytes from a lo */
 
-Py_ssize_t
+RAISES_NEG Py_ssize_t
 lobject_read(lobjectObject *self, char *buf, size_t len)
 {
     Py_ssize_t n_read;
@@ -377,7 +377,7 @@ lobject_read(lobjectObject *self, char *buf, size_t len)
 
 /* lobject_seek - move the current position in the lo */
 
-int
+RAISES_NEG int
 lobject_seek(lobjectObject *self, int pos, int whence)
 {
     PGresult *pgres = NULL;
@@ -405,7 +405,7 @@ lobject_seek(lobjectObject *self, int pos, int whence)
 
 /* lobject_tell - tell the current position in the lo */
 
-int
+RAISES_NEG int
 lobject_tell(lobjectObject *self)
 {
     PGresult *pgres = NULL;
@@ -432,7 +432,7 @@ lobject_tell(lobjectObject *self)
 
 /* lobject_export - export to a local file */
 
-int
+RAISES_NEG int
 lobject_export(lobjectObject *self, const char *filename)
 {
     PGresult *pgres = NULL;
@@ -461,7 +461,7 @@ lobject_export(lobjectObject *self, const char *filename)
 
 #if PG_VERSION_HEX >= 0x080300
 
-int
+RAISES_NEG int
 lobject_truncate(lobjectObject *self, size_t len)
 {
     int retvalue;
diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c
index 497c42ee..3328c609 100644
--- a/psycopg/psycopgmodule.c
+++ b/psycopg/psycopgmodule.c
@@ -143,14 +143,6 @@ psyco_connect(PyObject *self, PyObject *args, PyObject *keywds)
 "  * `name`: Name for the new type\n" \
 "  * `baseobj`: Adapter to perform type conversion of a single array item."
 
-static void
-_psyco_register_type_set(PyObject **dict, PyObject *type)
-{
-    if (*dict == NULL)
-        *dict = PyDict_New();
-    typecast_add(type, *dict, 0);
-}
-
 static PyObject *
 psyco_register_type(PyObject *self, PyObject *args)
 {
@@ -162,10 +154,16 @@ psyco_register_type(PyObject *self, PyObject *args)
 
     if (obj != NULL && obj != Py_None) {
         if (PyObject_TypeCheck(obj, &cursorType)) {
-            _psyco_register_type_set(&(((cursorObject*)obj)->string_types), type);
+            PyObject **dict = &(((cursorObject*)obj)->string_types);
+            if (*dict == NULL) {
+                if (!(*dict = PyDict_New())) { return NULL; }
+            }
+            if (0 > typecast_add(type, *dict, 0)) { return NULL; }
         }
         else if (PyObject_TypeCheck(obj, &connectionType)) {
-            typecast_add(type, ((connectionObject*)obj)->string_types, 0);
+            if (0 > typecast_add(type, ((connectionObject*)obj)->string_types, 0)) {
+                return NULL;
+            }
         }
         else {
             PyErr_SetString(PyExc_TypeError,
@@ -174,7 +172,7 @@ psyco_register_type(PyObject *self, PyObject *args)
         }
     }
     else {
-        typecast_add(type, NULL, 0);
+        if (0 > typecast_add(type, NULL, 0)) { return NULL; }
     }
 
     Py_INCREF(Py_None);
@@ -1001,7 +999,7 @@ INIT_MODULE(_psycopg)(void)
     }
 #endif
     /* initialize default set of typecasters */
-    typecast_init(dict);
+    if (0 != typecast_init(dict)) { goto exit; }
 
     /* initialize microprotocols layer */
     microprotocols_init(dict);
diff --git a/psycopg/typecast.c b/psycopg/typecast.c
index 8ede351c..e4abd8f7 100644
--- a/psycopg/typecast.c
+++ b/psycopg/typecast.c
@@ -250,7 +250,7 @@ PyObject *psyco_default_binary_cast;
 
 /* typecast_init - initialize the dictionary and create default types */
 
-int
+RAISES_NEG int
 typecast_init(PyObject *dict)
 {
     int i;
@@ -316,7 +316,7 @@ typecast_init(PyObject *dict)
 }
 
 /* typecast_add - add a type object to the dictionary */
-int
+RAISES_NEG int
 typecast_add(PyObject *obj, PyObject *dict, int binary)
 {
     PyObject *val;
diff --git a/psycopg/typecast.h b/psycopg/typecast.h
index 20def306..04976f31 100644
--- a/psycopg/typecast.h
+++ b/psycopg/typecast.h
@@ -71,8 +71,8 @@ extern HIDDEN PyObject *psyco_default_binary_cast;
 /** exported functions **/
 
 /* used by module.c to init the type system and register types */
-HIDDEN int typecast_init(PyObject *dict);
-HIDDEN int typecast_add(PyObject *obj, PyObject *dict, int binary);
+RAISES_NEG HIDDEN int typecast_init(PyObject *dict);
+RAISES_NEG HIDDEN int typecast_add(PyObject *obj, PyObject *dict, int binary);
 
 /* the C callable typecastObject creator function */
 HIDDEN PyObject *typecast_from_c(typecastObject_initlist *type, PyObject *d);
diff --git a/psycopg/typecast_array.c b/psycopg/typecast_array.c
index 75b84b50..6d825f42 100644
--- a/psycopg/typecast_array.c
+++ b/psycopg/typecast_array.c
@@ -166,7 +166,7 @@ typecast_array_tokenize(const char *str, Py_ssize_t strlength,
     return res;
 }
 
-static int
+RAISES_NEG static int
 typecast_array_scan(const char *str, Py_ssize_t strlength,
                     PyObject *curs, PyObject *base, PyObject *array)
 {
@@ -199,7 +199,7 @@ typecast_array_scan(const char *str, Py_ssize_t strlength,
 
             /* before anything else we free the memory */
             if (state == ASCAN_QUOTED) PyMem_Free(token);
-            if (obj == NULL) return 0;
+            if (obj == NULL) return -1;
 
             PyList_Append(array, obj);
             Py_DECREF(obj);
@@ -207,25 +207,25 @@ typecast_array_scan(const char *str, Py_ssize_t strlength,
 
         else if (state == ASCAN_BEGIN) {
             PyObject *sub = PyList_New(0);
-            if (sub == NULL) return 0;
+            if (sub == NULL) return -1;
 
             PyList_Append(array, sub);
             Py_DECREF(sub);
 
             if (stack_index == MAX_DIMENSIONS)
-                return 0;
+                return -1;
 
             stack[stack_index++] = array;
             array = sub;
         }
 
         else if (state == ASCAN_ERROR) {
-            return 0;
+            return -1;
         }
 
         else if (state == ASCAN_END) {
             if (--stack_index < 0)
-                return 0;
+                return -1;
             array = stack[stack_index];
         }
 
@@ -233,7 +233,7 @@ typecast_array_scan(const char *str, Py_ssize_t strlength,
             break;
     }
 
-    return 1;
+    return 0;
 }
 
 
@@ -263,9 +263,8 @@ typecast_GENERIC_ARRAY_cast(const char *str, Py_ssize_t len, PyObject *curs)
     obj = PyList_New(0);
 
     /* scan the array skipping the first level of {} */
-    if (typecast_array_scan(&str[1], len-2, curs, base, obj) == 0) {
-        Py_DECREF(obj);
-        obj = NULL;
+    if (typecast_array_scan(&str[1], len-2, curs, base, obj) < 0) {
+        Py_CLEAR(obj);
     }
 
     return obj;
diff --git a/psycopg/typecast_datetime.c b/psycopg/typecast_datetime.c
index 29149c05..7c1cfa45 100644
--- a/psycopg/typecast_datetime.c
+++ b/psycopg/typecast_datetime.c
@@ -26,7 +26,7 @@
 #include <math.h>
 #include "datetime.h"
 
-static int
+RAISES_NEG static int
 psyco_typecast_datetime_init(void)
 {
     Dprintf("psyco_typecast_datetime_init: datetime init");
diff --git a/psycopg/xid_type.c b/psycopg/xid_type.c
index 4de46b44..bc5e3ca5 100644
--- a/psycopg/xid_type.c
+++ b/psycopg/xid_type.c
@@ -486,7 +486,7 @@ exit:
  *
  * Return a borrowed reference. */
 
-static PyObject *
+BORROWED static PyObject *
 _xid_get_parse_regex(void) {
     static PyObject *rv;