summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--psycopg/adapter_binary.c25
-rw-r--r--psycopg/adapter_datetime.c11
-rw-r--r--psycopg/adapter_list.c6
-rw-r--r--psycopg/adapter_qstring.c16
-rw-r--r--psycopg/bytes_format.c2
-rw-r--r--psycopg/config.h29
-rw-r--r--psycopg/connection.h18
-rw-r--r--psycopg/connection_int.c82
-rw-r--r--psycopg/connection_type.c22
-rw-r--r--psycopg/cursor.h2
-rw-r--r--psycopg/cursor_int.c2
-rw-r--r--psycopg/cursor_type.c264
-rw-r--r--psycopg/lobject.h24
-rw-r--r--psycopg/lobject_int.c22
-rw-r--r--psycopg/lobject_type.c4
-rw-r--r--psycopg/microprotocols.c37
-rw-r--r--psycopg/pqpath.c64
-rw-r--r--psycopg/pqpath.h14
-rw-r--r--psycopg/psycopg.h10
-rw-r--r--psycopg/psycopgmodule.c256
-rw-r--r--psycopg/typecast.c46
-rw-r--r--psycopg/typecast.h4
-rw-r--r--psycopg/typecast_array.c21
-rw-r--r--psycopg/typecast_basic.c2
-rw-r--r--psycopg/typecast_datetime.c4
-rw-r--r--psycopg/typecast_mxdatetime.c2
-rw-r--r--psycopg/utils.c21
-rw-r--r--psycopg/xid_type.c6
29 files changed, 571 insertions, 449 deletions
diff --git a/NEWS b/NEWS
index 4c94a98..71ef733 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,10 @@ What's new in psycopg 2.4.5
Regression introduced in 2.4.4 (ticket #100).
- Added support for 'inet' arrays.
- Fixed 'commit()' concurrency problem (ticket #103).
+ - Codebase cleaned up using the GCC Python plugin's static analysis
+ tool, which has revealed several unchecked return values, possible
+ NULL dereferences, reference counting problems. Many thanks to David
+ Malcolm for the useful tool and the assistance provided using it.
What's new in psycopg 2.4.4
diff --git a/psycopg/adapter_binary.c b/psycopg/adapter_binary.c
index 2574c60..b08c144 100644
--- a/psycopg/adapter_binary.c
+++ b/psycopg/adapter_binary.c
@@ -65,6 +65,13 @@ binary_quote(binaryObject *self)
int got_view = 0;
#endif
+ /* Allow Binary(None) to work */
+ if (self->wrapped == Py_None) {
+ Py_INCREF(psyco_null);
+ rv = psyco_null;
+ goto exit;
+ }
+
/* if we got a plain string or a buffer we escape it and save the buffer */
#if HAS_MEMORYVIEW
@@ -93,7 +100,7 @@ binary_quote(binaryObject *self)
/* escape and build quoted buffer */
- to = (char *)binary_escape((unsigned char*)buffer, (size_t) buffer_len,
+ to = (char *)binary_escape((unsigned char*)buffer, (size_t)buffer_len,
&len, self->conn ? ((connectionObject*)self->conn)->pgconn : NULL);
if (to == NULL) {
PyErr_NoMemory();
@@ -113,12 +120,6 @@ exit:
if (got_view) { PyBuffer_Release(&view); }
#endif
- /* Allow Binary(None) to work */
- if (self->wrapped == Py_None) {
- Py_INCREF(psyco_null);
- rv = psyco_null;
- }
-
/* if the wrapped object is not bytes or a buffer, this is an error */
if (!rv && !PyErr_Occurred()) {
PyErr_Format(PyExc_TypeError, "can't escape %s to binary",
@@ -149,16 +150,14 @@ binary_str(binaryObject *self)
static PyObject *
binary_prepare(binaryObject *self, PyObject *args)
{
- connectionObject *conn;
+ PyObject *conn;
- if (!PyArg_ParseTuple(args, "O", &conn))
+ if (!PyArg_ParseTuple(args, "O!", &connectionType, &conn))
return NULL;
Py_XDECREF(self->conn);
- if (conn) {
- self->conn = (PyObject*)conn;
- Py_INCREF(self->conn);
- }
+ self->conn = conn;
+ Py_INCREF(self->conn);
Py_INCREF(Py_None);
return Py_None;
diff --git a/psycopg/adapter_datetime.c b/psycopg/adapter_datetime.c
index 5850be8..bf31cfa 100644
--- a/psycopg/adapter_datetime.c
+++ b/psycopg/adapter_datetime.c
@@ -427,6 +427,10 @@ psyco_DateFromTicks(PyObject *self, PyObject *args)
Py_DECREF(args);
}
}
+ else {
+ PyErr_SetString(InterfaceError, "failed localtime call");
+ }
+
return res;
}
@@ -451,6 +455,10 @@ psyco_TimeFromTicks(PyObject *self, PyObject *args)
Py_DECREF(args);
}
}
+ else {
+ PyErr_SetString(InterfaceError, "failed localtime call");
+ }
+
return res;
}
@@ -473,6 +481,9 @@ psyco_TimestampFromTicks(PyObject *self, PyObject *args)
tm.tm_hour, tm.tm_min, (double)tm.tm_sec + ticks,
pyPsycopgTzLOCAL);
}
+ else {
+ PyErr_SetString(InterfaceError, "failed localtime call");
+ }
return res;
}
diff --git a/psycopg/adapter_list.c b/psycopg/adapter_list.c
index cbb7542..d97ecfb 100644
--- a/psycopg/adapter_list.c
+++ b/psycopg/adapter_list.c
@@ -98,9 +98,9 @@ list_getquoted(listObject *self, PyObject *args)
static PyObject *
list_prepare(listObject *self, PyObject *args)
{
- connectionObject *conn;
+ PyObject *conn;
- if (!PyArg_ParseTuple(args, "O", &conn))
+ if (!PyArg_ParseTuple(args, "O!", &connectionType, &conn))
return NULL;
/* note that we don't copy the encoding from the connection, but take a
@@ -109,7 +109,7 @@ list_prepare(listObject *self, PyObject *args)
work even without a connection to the backend. */
Py_CLEAR(self->connection);
Py_INCREF(conn);
- self->connection = (PyObject*)conn;
+ self->connection = conn;
Py_INCREF(Py_None);
return Py_None;
diff --git a/psycopg/adapter_qstring.c b/psycopg/adapter_qstring.c
index a9d4ec6..773cfa0 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;
@@ -124,24 +124,22 @@ qstring_str(qstringObject *self)
static PyObject *
qstring_prepare(qstringObject *self, PyObject *args)
{
- connectionObject *conn;
+ PyObject *conn;
- if (!PyArg_ParseTuple(args, "O", &conn))
+ if (!PyArg_ParseTuple(args, "O!", &connectionType, &conn))
return NULL;
/* we bother copying the encoding only if the wrapped string is unicode,
we don't need the encoding if that's not the case */
if (PyUnicode_Check(self->wrapped)) {
if (self->encoding) free(self->encoding);
- self->encoding = strdup(conn->codec);
- Dprintf("qstring_prepare: set encoding to %s", conn->codec);
+ self->encoding = strdup(((connectionObject *)conn)->codec);
+ Dprintf("qstring_prepare: set encoding to %s", self->encoding);
}
Py_CLEAR(self->conn);
- if (conn) {
- Py_INCREF(conn);
- self->conn = (PyObject*)conn;
- }
+ Py_INCREF(conn);
+ self->conn = conn;
Py_INCREF(Py_None);
return Py_None;
diff --git a/psycopg/bytes_format.c b/psycopg/bytes_format.c
index 1e729e4..6866207 100644
--- a/psycopg/bytes_format.c
+++ b/psycopg/bytes_format.c
@@ -86,7 +86,7 @@
/* Helpers for formatstring */
-Py_LOCAL_INLINE(PyObject *)
+BORROWED Py_LOCAL_INLINE(PyObject *)
getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx)
{
Py_ssize_t argidx = *p_argidx;
diff --git a/psycopg/config.h b/psycopg/config.h
index 2112043..f309449 100644
--- a/psycopg/config.h
+++ b/psycopg/config.h
@@ -160,4 +160,33 @@ static double round(double num)
#define isinf(x) (!finite((x)) && (x)==(x))
#endif
+/* decorators for the gcc cpychecker plugin */
+#if defined(WITH_CPYCHECKER_RETURNS_BORROWED_REF_ATTRIBUTE)
+#define BORROWED \
+ __attribute__((cpychecker_returns_borrowed_ref))
+#else
+#define BORROWED
+#endif
+
+#if defined(WITH_CPYCHECKER_STEALS_REFERENCE_TO_ARG_ATTRIBUTE)
+#define STEALS(n) \
+ __attribute__((cpychecker_steals_reference_to_arg(n)))
+#else
+#define STEALS(n)
+#endif
+
+#if defined(WITH_CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION_ATTRIBUTE)
+#define RAISES_NEG \
+ __attribute__((cpychecker_negative_result_sets_exception))
+#else
+#define RAISES_NEG
+#endif
+
+#if defined(WITH_CPYCHECKER_SETS_EXCEPTION_ATTRIBUTE)
+#define RAISES \
+ __attribute__((cpychecker_sets_exception))
+#else
+#define RAISES
+#endif
+
#endif /* !defined(PSYCOPG_CONFIG_H) */
diff --git a/psycopg/connection.h b/psycopg/connection.h
index 9a9ea42..9647ffd 100644
--- a/psycopg/connection.h
+++ b/psycopg/connection.h
@@ -131,27 +131,27 @@ typedef struct {
/* C-callable functions in connection_int.c and connection_ext.c */
HIDDEN PyObject *conn_text_from_chars(connectionObject *pgconn, const char *str);
HIDDEN int conn_get_standard_conforming_strings(PGconn *pgconn);
-HIDDEN int conn_get_isolation_level(connectionObject *self);
+RAISES_NEG HIDDEN int conn_get_isolation_level(connectionObject *self);
HIDDEN int conn_get_protocol_version(PGconn *pgconn);
HIDDEN int conn_get_server_version(PGconn *pgconn);
HIDDEN PGcancel *conn_get_cancel(PGconn *pgconn);
HIDDEN void conn_notice_process(connectionObject *self);
HIDDEN void conn_notice_clean(connectionObject *self);
HIDDEN void conn_notifies_process(connectionObject *self);
-HIDDEN int conn_setup(connectionObject *self, PGconn *pgconn);
+RAISES_NEG HIDDEN int conn_setup(connectionObject *self, PGconn *pgconn);
HIDDEN int conn_connect(connectionObject *self, long int async);
HIDDEN void conn_close(connectionObject *self);
-HIDDEN int conn_commit(connectionObject *self);
-HIDDEN int conn_rollback(connectionObject *self);
-HIDDEN int conn_set_session(connectionObject *self, const char *isolevel,
+RAISES_NEG HIDDEN int conn_commit(connectionObject *self);
+RAISES_NEG HIDDEN int conn_rollback(connectionObject *self);
+RAISES_NEG HIDDEN int conn_set_session(connectionObject *self, const char *isolevel,
const char *readonly, const char *deferrable,
int autocommit);
HIDDEN int conn_set_autocommit(connectionObject *self, int value);
-HIDDEN int conn_switch_isolation_level(connectionObject *self, int level);
-HIDDEN int conn_set_client_encoding(connectionObject *self, const char *enc);
+RAISES_NEG HIDDEN int conn_switch_isolation_level(connectionObject *self, int level);
+RAISES_NEG HIDDEN int conn_set_client_encoding(connectionObject *self, const char *enc);
HIDDEN int conn_poll(connectionObject *self);
-HIDDEN int conn_tpc_begin(connectionObject *self, XidObject *xid);
-HIDDEN int conn_tpc_command(connectionObject *self,
+RAISES_NEG HIDDEN int conn_tpc_begin(connectionObject *self, XidObject *xid);
+RAISES_NEG HIDDEN int conn_tpc_command(connectionObject *self,
const char *cmd, XidObject *xid);
HIDDEN PyObject *conn_tpc_recover(connectionObject *self);
diff --git a/psycopg/connection_int.c b/psycopg/connection_int.c
index 2395c00..8c8fed4 100644
--- a/psycopg/connection_int.c
+++ b/psycopg/connection_int.c
@@ -120,8 +120,16 @@ conn_notice_process(connectionObject *self)
/* Respect the order in which notices were produced,
because in notice_list they are reversed (see ticket #9) */
- PyList_Insert(self->notice_list, nnotices, msg);
- Py_DECREF(msg);
+ if (msg) {
+ PyList_Insert(self->notice_list, nnotices, msg);
+ Py_DECREF(msg);
+ }
+ else {
+ /* We don't really have a way to report errors, so gulp it.
+ * The function should only fail for out of memory, so we are
+ * likely going to die anyway. */
+ PyErr_Clear();
+ }
notice = notice->next;
}
@@ -242,19 +250,20 @@ conn_get_standard_conforming_strings(PGconn *pgconn)
/* Remove irrelevant chars from encoding name and turn it uppercase.
*
- * Return a buffer allocated on Python heap,
- * NULL and set an exception on error.
+ * Return a buffer allocated on Python heap into 'clean' and return 0 on
+ * success, otherwise return -1 and set an exception.
*/
-static char *
-clean_encoding_name(const char *enc)
+RAISES_NEG static int
+clear_encoding_name(const char *enc, char **clean)
{
const char *i = enc;
- char *rv, *j;
+ char *j, *buf;
+ int rv = -1;
/* convert to upper case and remove '-' and '_' from string */
- if (!(j = rv = PyMem_Malloc(strlen(enc) + 1))) {
+ if (!(j = buf = PyMem_Malloc(strlen(enc) + 1))) {
PyErr_NoMemory();
- return NULL;
+ goto exit;
}
while (*i) {
@@ -267,25 +276,28 @@ clean_encoding_name(const char *enc)
}
*j = '\0';
- Dprintf("clean_encoding_name: %s -> %s", enc, rv);
+ Dprintf("clear_encoding_name: %s -> %s", enc, buf);
+ *clean = buf;
+ rv = 0;
+exit:
return rv;
}
/* Convert a PostgreSQL encoding to a Python codec.
*
- * Return a new copy of the codec name allocated on the Python heap,
- * NULL with exception in case of error.
+ * Set 'codec' to a new copy of the codec name allocated on the Python heap.
+ * Return 0 in case of success, else -1 and set an exception.
*
* 'enc' should be already normalized (uppercase, no - or _).
*/
-static char *
-conn_encoding_to_codec(const char *enc)
+RAISES_NEG static int
+conn_encoding_to_codec(const char *enc, char **codec)
{
char *tmp;
Py_ssize_t size;
PyObject *pyenc = NULL;
- char *rv = NULL;
+ int rv = -1;
/* Find the Py codec name from the PG encoding */
if (!(pyenc = PyDict_GetItemString(psycoEncodings, enc))) {
@@ -305,7 +317,7 @@ conn_encoding_to_codec(const char *enc)
}
/* have our own copy of the python codec name */
- rv = psycopg_strdup(tmp, size);
+ rv = psycopg_strdup(codec, tmp, size);
exit:
Py_XDECREF(pyenc);
@@ -320,7 +332,7 @@ exit:
*
* Return 0 on success, else nonzero.
*/
-static int
+RAISES_NEG static int
conn_read_encoding(connectionObject *self, PGconn *pgconn)
{
char *enc = NULL, *codec = NULL;
@@ -335,12 +347,12 @@ conn_read_encoding(connectionObject *self, PGconn *pgconn)
goto exit;
}
- if (!(enc = clean_encoding_name(tmp))) {
+ if (0 > clear_encoding_name(tmp, &enc)) {
goto exit;
}
/* Look for this encoding in Python codecs. */
- if (!(codec = conn_encoding_to_codec(enc))) {
+ if (0 > conn_encoding_to_codec(enc, &codec)) {
goto exit;
}
@@ -362,7 +374,7 @@ exit:
}
-int
+RAISES_NEG int
conn_get_isolation_level(connectionObject *self)
{
PGresult *pgres = NULL;
@@ -456,7 +468,7 @@ conn_is_datestyle_ok(PGconn *pgconn)
/* conn_setup - setup and read basic information about the connection */
-int
+RAISES_NEG int
conn_setup(connectionObject *self, PGconn *pgconn)
{
PGresult *pgres = NULL;
@@ -470,7 +482,7 @@ conn_setup(connectionObject *self, PGconn *pgconn)
return -1;
}
- if (conn_read_encoding(self, pgconn)) {
+ if (0 > conn_read_encoding(self, pgconn)) {
return -1;
}
@@ -484,7 +496,7 @@ conn_setup(connectionObject *self, PGconn *pgconn)
pthread_mutex_lock(&self->lock);
Py_BLOCK_THREADS;
- if (psyco_green() && (pq_set_non_blocking(self, 1, 1) != 0)) {
+ if (psyco_green() && (0 > pq_set_non_blocking(self, 1))) {
return -1;
}
@@ -762,7 +774,7 @@ _conn_poll_setup_async(connectionObject *self)
switch (self->status) {
case CONN_STATUS_CONNECTING:
/* Set the connection to nonblocking now. */
- if (pq_set_non_blocking(self, 1, 1) != 0) {
+ if (pq_set_non_blocking(self, 1) != 0) {
break;
}
@@ -773,7 +785,7 @@ _conn_poll_setup_async(connectionObject *self)
PyErr_SetString(InterfaceError, "only protocol 3 supported");
break;
}
- if (conn_read_encoding(self, self->pgconn)) {
+ if (0 > conn_read_encoding(self, self->pgconn)) {
break;
}
self->cancel = conn_get_cancel(self->pgconn);
@@ -942,7 +954,7 @@ conn_close(connectionObject *self)
/* conn_commit - commit on a connection */
-int
+RAISES_NEG int
conn_commit(connectionObject *self)
{
int res;
@@ -953,7 +965,7 @@ conn_commit(connectionObject *self)
/* conn_rollback - rollback a connection */
-int
+RAISES_NEG int
conn_rollback(connectionObject *self)
{
int res;
@@ -962,7 +974,7 @@ conn_rollback(connectionObject *self)
return res;
}
-int
+RAISES_NEG int
conn_set_session(connectionObject *self,
const char *isolevel, const char *readonly, const char *deferrable,
int autocommit)
@@ -1035,7 +1047,7 @@ conn_set_autocommit(connectionObject *self, int value)
/* conn_switch_isolation_level - switch isolation level on the connection */
-int
+RAISES_NEG int
conn_switch_isolation_level(connectionObject *self, int level)
{
PGresult *pgres = NULL;
@@ -1117,12 +1129,12 @@ endlock:
/* conn_set_client_encoding - switch client encoding on connection */
-int
+RAISES_NEG int
conn_set_client_encoding(connectionObject *self, const char *enc)
{
PGresult *pgres = NULL;
char *error = NULL;
- int res = 1;
+ int res = -1;
char *codec = NULL;
char *clean_enc = NULL;
@@ -1131,8 +1143,8 @@ conn_set_client_encoding(connectionObject *self, const char *enc)
if (strcmp(self->encoding, enc) == 0) return 0;
/* We must know what python codec this encoding is. */
- if (!(clean_enc = clean_encoding_name(enc))) { goto exit; }
- if (!(codec = conn_encoding_to_codec(clean_enc))) { goto exit; }
+ if (0 > clear_encoding_name(enc, &clean_enc)) { goto exit; }
+ if (0 > conn_encoding_to_codec(clean_enc, &codec)) { goto exit; }
Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&self->lock);
@@ -1190,7 +1202,7 @@ exit:
* in regular transactions, as PostgreSQL won't even know we are in a TPC
* until PREPARE. */
-int
+RAISES_NEG int
conn_tpc_begin(connectionObject *self, XidObject *xid)
{
PGresult *pgres = NULL;
@@ -1224,7 +1236,7 @@ conn_tpc_begin(connectionObject *self, XidObject *xid)
* The function doesn't change the connection state as it can be used
* for many commands and for recovered transactions. */
-int
+RAISES_NEG int
conn_tpc_command(connectionObject *self, const char *cmd, XidObject *xid)
{
PGresult *pgres = NULL;
diff --git a/psycopg/connection_type.c b/psycopg/connection_type.c
index 09ced62..4e5b617 100644
--- a/psycopg/connection_type.c
+++ b/psycopg/connection_type.c
@@ -526,7 +526,7 @@ psyco_conn_set_session(connectionObject *self, PyObject *args, PyObject *kwargs)
if (-1 == c_autocommit) { return NULL; }
}
- if (0 != conn_set_session(self,
+ if (0 > conn_set_session(self,
c_isolevel, c_readonly, c_deferrable, c_autocommit)) {
return NULL;
}
@@ -548,7 +548,7 @@ psyco_conn_autocommit_get(connectionObject *self)
return ret;
}
-static PyObject *
+BORROWED static PyObject *
_psyco_conn_autocommit_set_checks(connectionObject *self)
{
/* wrapper to use the EXC_IF macros.
@@ -635,7 +635,7 @@ psyco_conn_set_client_encoding(connectionObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s", &enc)) return NULL;
- if (conn_set_client_encoding(self, enc) == 0) {
+ if (conn_set_client_encoding(self, enc) >= 0) {
Py_INCREF(Py_None);
rv = Py_None;
}
@@ -699,8 +699,8 @@ psyco_conn_get_parameter_status(connectionObject *self, PyObject *args)
static PyObject *
psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds)
{
- Oid oid=InvalidOid, new_oid=InvalidOid;
- char *new_file = NULL;
+ int oid = (int)InvalidOid, new_oid = (int)InvalidOid;
+ const char *new_file = NULL;
const char *smode = "";
PyObject *factory = (PyObject *)&lobjectType;
PyObject *obj;
@@ -752,7 +752,7 @@ psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds)
"get_backend_pid() -- Get backend process id."
static PyObject *
-psyco_conn_get_backend_pid(connectionObject *self)
+psyco_conn_get_backend_pid(connectionObject *self, PyObject *args)
{
EXC_IF_CONN_CLOSED(self);
@@ -765,7 +765,7 @@ psyco_conn_get_backend_pid(connectionObject *self)
"reset() -- Reset current connection to defaults."
static PyObject *
-psyco_conn_reset(connectionObject *self)
+psyco_conn_reset(connectionObject *self, PyObject *args)
{
int res;
@@ -793,7 +793,7 @@ psyco_conn_get_exception(PyObject *self, void *closure)
}
static PyObject *
-psyco_conn_poll(connectionObject *self)
+psyco_conn_poll(connectionObject *self, PyObject *args)
{
int res;
@@ -815,7 +815,7 @@ psyco_conn_poll(connectionObject *self)
"fileno() -> int -- Return file descriptor associated to database connection."
static PyObject *
-psyco_conn_fileno(connectionObject *self)
+psyco_conn_fileno(connectionObject *self, PyObject *args)
{
long int socket;
@@ -834,7 +834,7 @@ psyco_conn_fileno(connectionObject *self)
"executing an asynchronous operation."
static PyObject *
-psyco_conn_isexecuting(connectionObject *self)
+psyco_conn_isexecuting(connectionObject *self, PyObject *args)
{
/* synchronous connections will always return False */
if (self->async == 0) {
@@ -866,7 +866,7 @@ psyco_conn_isexecuting(connectionObject *self)
"cancel() -- cancel the current operation"
static PyObject *
-psyco_conn_cancel(connectionObject *self)
+psyco_conn_cancel(connectionObject *self, PyObject *args)
{
char errbuf[256];
diff --git a/psycopg/cursor.h b/psycopg/cursor.h
index eecaa8f..723bd17 100644
--- a/psycopg/cursor.h
+++ b/psycopg/cursor.h
@@ -85,7 +85,7 @@ struct cursorObject {
/* C-callable functions in cursor_int.c and cursor_ext.c */
-HIDDEN PyObject *curs_get_cast(cursorObject *self, PyObject *oid);
+BORROWED HIDDEN PyObject *curs_get_cast(cursorObject *self, PyObject *oid);
HIDDEN void curs_reset(cursorObject *self);
/* exception-raising macros */
diff --git a/psycopg/cursor_int.c b/psycopg/cursor_int.c
index 40e0bae..1ac3f55 100644
--- a/psycopg/cursor_int.c
+++ b/psycopg/cursor_int.c
@@ -38,7 +38,7 @@
* Return a borrowed reference.
*/
-PyObject *
+BORROWED PyObject *
curs_get_cast(cursorObject *self, PyObject *oid)
{
PyObject *cast;
diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c
index 4de0163..bcbefc5 100644
--- a/psycopg/cursor_type.c
+++ b/psycopg/cursor_type.c
@@ -79,7 +79,7 @@ exit:
/* mogrify a query string and build argument array or dict */
-static int
+RAISES_NEG static int
_mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new)
{
PyObject *key, *value, *n;
@@ -221,7 +221,10 @@ _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new)
}
if (n == NULL) {
- n = PyTuple_New(PyObject_Length(var));
+ if (!(n = PyTuple_New(PyObject_Length(var)))) {
+ Py_DECREF(value);
+ return -1;
+ }
}
/* let's have d point just after the '%' */
@@ -360,11 +363,12 @@ _psyco_curs_merge_query_args(cursorObject *self,
#define psyco_curs_execute_doc \
"execute(query, vars=None) -- Execute query with bound vars."
-static int
+RAISES_NEG static int
_psyco_curs_execute(cursorObject *self,
PyObject *operation, PyObject *vars, long int async)
{
- int res = 0;
+ int res = -1;
+ int tmp;
PyObject *fquery, *cvt = NULL;
operation = _psyco_curs_validate_sql_basic(self, operation);
@@ -372,7 +376,7 @@ _psyco_curs_execute(cursorObject *self,
/* Any failure from here forward should 'goto fail' rather than 'return 0'
directly. */
- if (operation == NULL) { goto fail; }
+ if (operation == NULL) { goto exit; }
IFCLEARPGRES(self->pgres);
@@ -389,12 +393,12 @@ _psyco_curs_execute(cursorObject *self,
if (vars && vars != Py_None)
{
- if(_mogrify(vars, operation, self, &cvt) == -1) { goto fail; }
+ if (0 > _mogrify(vars, operation, self, &cvt)) { goto exit; }
}
if (vars && cvt) {
if (!(fquery = _psyco_curs_merge_query_args(self, operation, cvt))) {
- goto fail;
+ goto exit;
}
if (self->name != NULL) {
@@ -428,25 +432,20 @@ _psyco_curs_execute(cursorObject *self,
/* At this point, the SQL statement must be str, not unicode */
- res = pq_execute(self, Bytes_AS_STRING(self->query), async);
- Dprintf("psyco_curs_execute: res = %d, pgres = %p", res, self->pgres);
- if (res == -1) { goto fail; }
+ tmp = pq_execute(self, Bytes_AS_STRING(self->query), async);
+ Dprintf("psyco_curs_execute: res = %d, pgres = %p", tmp, self->pgres);
+ if (tmp < 0) { goto exit; }
- res = 1; /* Success */
- goto cleanup;
+ res = 0; /* Success */
- fail:
- res = 0;
- /* Fall through to cleanup */
- cleanup:
- /* Py_XDECREF(operation) is safe because the original reference passed
- by the caller was overwritten with either NULL or a new
- reference */
- Py_XDECREF(operation);
-
- Py_XDECREF(cvt);
+exit:
+ /* Py_XDECREF(operation) is safe because the original reference passed
+ by the caller was overwritten with either NULL or a new
+ reference */
+ Py_XDECREF(operation);
+ Py_XDECREF(cvt);
- return res;
+ return res;
}
static PyObject *
@@ -480,13 +479,13 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs)
EXC_IF_ASYNC_IN_PROGRESS(self, execute);
EXC_IF_TPC_PREPARED(self->conn, execute);
- if (_psyco_curs_execute(self, operation, vars, self->conn->async)) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- else {
+ if (0 > _psyco_curs_execute(self, operation, vars, self->conn->async)) {
return NULL;
}
+
+ /* success */
+ Py_INCREF(Py_None);
+ return Py_None;
}
#define psyco_curs_executemany_doc \
@@ -525,7 +524,7 @@ psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs)
}
while ((v = PyIter_Next(vars)) != NULL) {
- if (_psyco_curs_execute(self, operation, v, 0) == 0) {
+ if (0 > _psyco_curs_execute(self, operation, v, 0)) {
Py_DECREF(v);
Py_XDECREF(iter);
return NULL;
@@ -572,7 +571,7 @@ _psyco_curs_mogrify(cursorObject *self,
if (vars && vars != Py_None)
{
- if (_mogrify(vars, operation, self, &cvt) == -1) {
+ if (0 > _mogrify(vars, operation, self, &cvt)) {
goto cleanup;
}
}
@@ -648,7 +647,7 @@ psyco_curs_cast(cursorObject *self, PyObject *args)
"default) or using the sequence factory previously set in the\n" \
"`row_factory` attribute. Return `!None` when no more data is available.\n"
-static int
+RAISES_NEG static int
_psyco_curs_prefetch(cursorObject *self)
{
int i = 0;
@@ -665,13 +664,14 @@ _psyco_curs_prefetch(cursorObject *self)
return i;
}
-static PyObject *
+RAISES_NEG static int
_psyco_curs_buildrow_fill(cursorObject *self, PyObject *res,
int row, int n, int istuple)
{
int i, len, err;
const char *str;
PyObject *val;
+ int rv = -1;
for (i=0; i < n; i++) {
if (PQgetisnull(self->pgres, row, i)) {
@@ -686,59 +686,59 @@ _psyco_curs_buildrow_fill(cursorObject *self, PyObject *res,
Dprintf("_psyco_curs_buildrow: row %ld, element %d, len %d",
self->row, i, len);
- val = typecast_cast(PyTuple_GET_ITEM(self->casts, i), str, len,
- (PyObject*)self);
+ if (!(val = typecast_cast(PyTuple_GET_ITEM(self->casts, i), str, len,
+ (PyObject*)self))) {
+ goto exit;
+ }
- if (val) {
- Dprintf("_psyco_curs_buildrow: val->refcnt = "
- FORMAT_CODE_PY_SSIZE_T,
- Py_REFCNT(val)
- );
- if (istuple) {
- PyTuple_SET_ITEM(res, i, val);
- }
- else {
- err = PySequence_SetItem(res, i, val);
- Py_DECREF(val);
- if (err == -1) {
- Py_DECREF(res);
- res = NULL;
- break;
- }
- }
+ Dprintf("_psyco_curs_buildrow: val->refcnt = "
+ FORMAT_CODE_PY_SSIZE_T,
+ Py_REFCNT(val)
+ );
+ if (istuple) {
+ PyTuple_SET_ITEM(res, i, val);
}
else {
- /* an error occurred in the type system, we return NULL to raise
- an exception. the typecast code should already have set the
- exception type and text */
- Py_DECREF(res);
- res = NULL;
- break;
+ err = PySequence_SetItem(res, i, val);
+ Py_DECREF(val);
+ if (err == -1) { goto exit; }
}
}
- return res;
+
+ rv = 0;
+
+exit:
+ return rv;
}
static PyObject *
_psyco_curs_buildrow(cursorObject *self, int row)
{
int n;
+ int istuple;
+ PyObject *t = NULL;
+ PyObject *rv = NULL;
n = PQnfields(self->pgres);
- return _psyco_curs_buildrow_fill(self, PyTuple_New(n), row, n, 1);
-}
+ istuple = (self->tuple_factory == Py_None);
-static PyObject *
-_psyco_curs_buildrow_with_factory(cursorObject *self, int row)
-{
- int n;
- PyObject *res;
+ if (istuple) {
+ t = PyTuple_New(n);
+ }
+ else {
+ t = PyObject_CallFunctionObjArgs(self->tuple_factory, self, NULL);
+ }
+ if (!t) { goto exit; }
- n = PQnfields(self->pgres);
- if (!(res = PyObject_CallFunctionObjArgs(self->tuple_factory, self, NULL)))
- return NULL;
+ if (0 <= _psyco_curs_buildrow_fill(self, t, row, n, istuple)) {
+ rv = t;
+ t = NULL;
+ }
+
+exit:
+ Py_XDECREF(t);
+ return rv;
- return _psyco_curs_buildrow_fill(self, res, row, n, 0);
}
static PyObject *
@@ -770,11 +770,7 @@ psyco_curs_fetchone(cursorObject *self, PyObject *args)
return Py_None;
}
- if (self->tuple_factory == Py_None)
- res = _psyco_curs_buildrow(self, self->row);
- else
- res = _psyco_curs_buildrow_with_factory(self, self->row);
-
+ res = _psyco_curs_buildrow(self, self->row);
self->row++; /* move the counter to next line */
/* if the query was async aggresively free pgres, to allow
@@ -821,11 +817,7 @@ psyco_curs_next_named(cursorObject *self)
return NULL;
}
- if (self->tuple_factory == Py_None)
- res = _psyco_curs_buildrow(self, self->row);
- else
- res = _psyco_curs_buildrow_with_factory(self, self->row);
-
+ res = _psyco_curs_buildrow(self, self->row);
self->row++; /* move the counter to next line */
/* if the query was async aggresively free pgres, to allow
@@ -852,7 +844,9 @@ static PyObject *
psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords)
{
int i;
- PyObject *list, *res;
+ PyObject *list = NULL;
+ PyObject *row = NULL;
+ PyObject *rv = NULL;
PyObject *pysize = NULL;
long int size = self->arraysize;
@@ -883,8 +877,8 @@ psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords)
EXC_IF_TPC_PREPARED(self->conn, fetchone);
PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM \"%s\"",
(int)size, self->name);
- if (pq_execute(self, buffer, 0) == -1) return NULL;
- if (_psyco_curs_prefetch(self) < 0) return NULL;
+ if (pq_execute(self, buffer, 0) == -1) { goto exit; }
+ if (_psyco_curs_prefetch(self) < 0) { goto exit; }
}
/* make sure size is not > than the available number of rows */
@@ -895,26 +889,21 @@ psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords)
Dprintf("psyco_curs_fetchmany: size = %ld", size);
if (size <= 0) {
- return PyList_New(0);
+ rv = PyList_New(0);
+ goto exit;
}
- list = PyList_New(size);
+ if (!(list = PyList_New(size))) { goto exit; }
for (i = 0; i < size; i++) {
- if (self->tuple_factory == Py_None)
- res = _psyco_curs_buildrow(self, self->row);
- else
- res = _psyco_curs_buildrow_with_factory(self, self->row);
-
+ row = _psyco_curs_buildrow(self, self->row);
self->row++;
- if (res == NULL) {
- Py_DECREF(list);
- return NULL;
- }
+ if (row == NULL) { goto exit; }
- PyList_SET_ITEM(list, i, res);
+ PyList_SET_ITEM(list, i, row);
}
+ row = NULL;
/* if the query was async aggresively free pgres, to allow
successive requests to reallocate it */
@@ -923,7 +912,15 @@ psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords)
&& PyWeakref_GetObject(self->conn->async_cursor) == (PyObject*)self)
IFCLEARPGRES(self->pgres);
- return list;
+ /* success */
+ rv = list;
+ list = NULL;
+
+exit:
+ Py_XDECREF(list);
+ Py_XDECREF(row);
+
+ return rv;
}
@@ -940,7 +937,9 @@ static PyObject *
psyco_curs_fetchall(cursorObject *self, PyObject *args)
{
int i, size;
- PyObject *list, *res;
+ PyObject *list = NULL;
+ PyObject *row = NULL;
+ PyObject *rv = NULL;
EXC_IF_CURS_CLOSED(self);
if (_psyco_curs_prefetch(self) < 0) return NULL;
@@ -953,33 +952,27 @@ psyco_curs_fetchall(cursorObject *self, PyObject *args)
EXC_IF_ASYNC_IN_PROGRESS(self, fetchall);
EXC_IF_TPC_PREPARED(self->conn, fetchall);
PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM \"%s\"", self->name);
- if (pq_execute(self, buffer, 0) == -1) return NULL;
- if (_psyco_curs_prefetch(self) < 0) return NULL;
+ if (pq_execute(self, buffer, 0) == -1) { goto exit; }
+ if (_psyco_curs_prefetch(self) < 0) { goto exit; }
}
size = self->rowcount - self->row;
if (size <= 0) {
- return PyList_New(0);
+ rv = PyList_New(0);
+ goto exit;
}
- list = PyList_New(size);
+ if (!(list = PyList_New(size))) { goto exit; }
for (i = 0; i < size; i++) {
- if (self->tuple_factory == Py_None)
- res = _psyco_curs_buildrow(self, self->row);
- else
- res = _psyco_curs_buildrow_with_factory(self, self->row);
-
+ row = _psyco_curs_buildrow(self, self->row);
self->row++;
+ if (row == NULL) { goto exit; }
- if (res == NULL) {
- Py_DECREF(list);
- return NULL;
- }
-
- PyList_SET_ITEM(list, i, res);
+ PyList_SET_ITEM(list, i, row);
}
+ row = NULL;
/* if the query was async aggresively free pgres, to allow
successive requests to reallocate it */
@@ -988,7 +981,15 @@ psyco_curs_fetchall(cursorObject *self, PyObject *args)
&& PyWeakref_GetObject(self->conn->async_cursor) == (PyObject*)self)
IFCLEARPGRES(self->pgres);
- return list;
+ /* success */
+ rv = list;
+ list = NULL;
+
+exit:
+ Py_XDECREF(list);
+ Py_XDECREF(row);
+
+ return rv;
}
@@ -998,7 +999,7 @@ psyco_curs_fetchall(cursorObject *self, PyObject *args)
"callproc(procname, parameters=None) -- Execute stored procedure."
static PyObject *
-psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
+psyco_curs_callproc(cursorObject *self, PyObject *args)
{
const char *procname = NULL;
char *sql = NULL;
@@ -1010,7 +1011,7 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
if (!PyArg_ParseTuple(args, "s#|O",
&procname, &procname_len, &parameters
))
- { return NULL; }
+ { goto exit; }
EXC_IF_CURS_CLOSED(self);
EXC_IF_ASYNC_IN_PROGRESS(self, callproc);
@@ -1019,10 +1020,10 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
if (self->name != NULL) {
psyco_set_error(ProgrammingError, self,
"can't call .callproc() on named cursors", NULL, NULL);
- return NULL;
+ goto exit;
}
- if(parameters != Py_None) {
+ if (parameters != Py_None) {
nparameters = PyObject_Length(parameters);
if (nparameters < 0) nparameters = 0;
}
@@ -1031,7 +1032,8 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
sl = procname_len + 17 + nparameters*3 - (nparameters ? 1 : 0);
sql = (char*)PyMem_Malloc(sl);
if (sql == NULL) {
- return PyErr_NoMemory();
+ PyErr_NoMemory();
+ goto exit;
}
sprintf(sql, "SELECT * FROM %s(", procname);
@@ -1041,15 +1043,16 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
sql[sl-2] = ')';
sql[sl-1] = '\0';
- operation = Bytes_FromString(sql);
- PyMem_Free((void*)sql);
+ if (!(operation = Bytes_FromString(sql))) { goto exit; }
- if (_psyco_curs_execute(self, operation, parameters, self->conn->async)) {
+ if (0 <= _psyco_curs_execute(self, operation, parameters, self->conn->async)) {
Py_INCREF(parameters);
res = parameters;
}
- Py_DECREF(operation);
+exit:
+ Py_XDECREF(operation);
+ PyMem_Free((void*)sql);
return res;
}
@@ -1206,6 +1209,7 @@ static char *_psyco_curs_copy_columns(PyObject *columns)
}
if (NULL == (columnlist = PyMem_Malloc(bufsize))) {
+ Py_DECREF(coliter);
PyErr_NoMemory();
goto error;
}
@@ -1262,8 +1266,8 @@ exit:
#define psyco_curs_copy_from_doc \
"copy_from(file, table, sep='\\t', null='\\\\N', size=8192, columns=None) -- Copy table from file."
-static int
-_psyco_curs_has_read_check(PyObject* o, void* var)
+STEALS(1) static int
+_psyco_curs_has_read_check(PyObject *o, PyObject **var)
{
if (PyObject_HasAttrString(o, "readline")
&& PyObject_HasAttrString(o, "read")) {
@@ -1273,7 +1277,7 @@ _psyco_curs_has_read_check(PyObject* o, void* var)
* which could invoke the garbage collector. We thus need an
* INCREF/DECREF pair if we store this pointer in a GC object, such as
* a cursorObject */
- *((PyObject**)var) = o;
+ *var = o;
return 1;
}
else {
@@ -1348,7 +1352,7 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
Py_INCREF(file);
self->copyfile = file;
- if (pq_execute(self, query, 0) == 1) {
+ if (pq_execute(self, query, 0) >= 0) {
res = Py_None;
Py_INCREF(Py_None);
}
@@ -1369,11 +1373,11 @@ exit:
#define psyco_curs_copy_to_doc \
"copy_to(file, table, sep='\\t', null='\\\\N', columns=None) -- Copy table to file."
-static int
-_psyco_curs_has_write_check(PyObject* o, void* var)
+STEALS(1) static int
+_psyco_curs_has_write_check(PyObject *o, PyObject **var)
{
if (PyObject_HasAttrString(o, "write")) {
- *((PyObject**)var) = o;
+ *var = o;
return 1;
}
else {
@@ -1444,7 +1448,7 @@ psyco_curs_copy_to(cursorObject *self, PyObject *args, PyObject *kwargs)
Py_INCREF(file);
self->copyfile = file;
- if (pq_execute(self, query, 0) == 1) {
+ if (pq_execute(self, query, 0) >= 0) {
res = Py_None;
Py_INCREF(Py_None);
}
@@ -1518,7 +1522,7 @@ psyco_curs_copy_expert(cursorObject *self, PyObject *args, PyObject *kwargs)
self->copyfile = file;
/* At this point, the SQL statement must be str, not unicode */
- if (pq_execute(self, Bytes_AS_STRING(sql), 0) == 1) {
+ if (pq_execute(self, Bytes_AS_STRING(sql), 0) >= 0) {
res = Py_None;
Py_INCREF(res);
}
diff --git a/psycopg/lobject.h b/psycopg/lobject.h
index f52d85c..6587198 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);
-
-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 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);
+
+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 f180c8c..5f23ca2 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/lobject_type.c b/psycopg/lobject_type.c
index a55272c..625a293 100644
--- a/psycopg/lobject_type.c
+++ b/psycopg/lobject_type.c
@@ -373,7 +373,7 @@ lobject_dealloc(PyObject* obj)
static int
lobject_init(PyObject *obj, PyObject *args, PyObject *kwds)
{
- Oid oid=InvalidOid, new_oid=InvalidOid;
+ int oid = (int)InvalidOid, new_oid = (int)InvalidOid;
const char *smode = "";
const char *new_file = NULL;
PyObject *conn;
@@ -383,7 +383,7 @@ lobject_init(PyObject *obj, PyObject *args, PyObject *kwds)
return -1;
return lobject_setup((lobjectObject *)obj,
- (connectionObject *)conn, oid, smode, new_oid, new_file);
+ (connectionObject *)conn, (Oid)oid, smode, (Oid)new_oid, new_file);
}
static PyObject *
diff --git a/psycopg/microprotocols.c b/psycopg/microprotocols.c
index f48c0fb..23f1279 100644
--- a/psycopg/microprotocols.c
+++ b/psycopg/microprotocols.c
@@ -52,29 +52,35 @@ microprotocols_init(PyObject *dict)
}
-/* microprotocols_add - add a reverse type-caster to the dictionary */
-
+/* microprotocols_add - add a reverse type-caster to the dictionary
+ *
+ * Return 0 on success, else -1 and set an exception.
+ */
int
microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast)
{
- PyObject *key;
+ PyObject *key = NULL;
+ int rv = -1;
if (proto == NULL) proto = (PyObject*)&isqlquoteType;
Dprintf("microprotocols_add: cast %p for (%s, ?)", cast, type->tp_name);
- key = PyTuple_Pack(2, (PyObject*)type, proto);
- PyDict_SetItem(psyco_adapters, key, cast);
- Py_DECREF(key);
+ if (!(key = PyTuple_Pack(2, (PyObject*)type, proto))) { goto exit; }
+ if (0 != PyDict_SetItem(psyco_adapters, key, cast)) { goto exit; }
- return 0;
+ rv = 0;
+
+exit:
+ Py_XDECREF(key);
+ return rv;
}
/* Check if one of `obj` superclasses has an adapter for `proto`.
*
- * If it does, return a *borrowed reference* to the adapter, else NULL.
+ * If it does, return a *borrowed reference* to the adapter, else to None.
*/
-static PyObject *
+BORROWED static PyObject *
_get_superclass_adapter(PyObject *obj, PyObject *proto)
{
PyTypeObject *type;
@@ -89,14 +95,14 @@ _get_superclass_adapter(PyObject *obj, PyObject *proto)
#endif
type->tp_mro)) {
/* has no mro */
- return NULL;
+ return Py_None;
}
/* Walk the mro from the most specific subclass. */
mro = type->tp_mro;
for (i = 1, ii = PyTuple_GET_SIZE(mro); i < ii; ++i) {
st = PyTuple_GET_ITEM(mro, i);
- key = PyTuple_Pack(2, st, proto);
+ if (!(key = PyTuple_Pack(2, st, proto))) { return NULL; }
adapter = PyDict_GetItem(psyco_adapters, key);
Py_DECREF(key);
@@ -119,7 +125,7 @@ _get_superclass_adapter(PyObject *obj, PyObject *proto)
return adapter;
}
}
- return NULL;
+ return Py_None;
}
@@ -139,7 +145,7 @@ microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt)
Py_TYPE(obj)->tp_name);
/* look for an adapter in the registry */
- key = PyTuple_Pack(2, Py_TYPE(obj), proto);
+ if (!(key = PyTuple_Pack(2, Py_TYPE(obj), proto))) { return NULL; }
adapter = PyDict_GetItem(psyco_adapters, key);
Py_DECREF(key);
if (adapter) {
@@ -148,7 +154,10 @@ microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt)
}
/* Check if a superclass can be adapted and use the same adapter. */
- if (NULL != (adapter = _get_superclass_adapter(obj, proto))) {
+ if (!(adapter = _get_superclass_adapter(obj, proto))) {
+ return NULL;
+ }
+ if (Py_None != adapter) {
adapted = PyObject_CallFunctionObjArgs(adapter, obj, NULL);
return adapted;
}
diff --git a/psycopg/pqpath.c b/psycopg/pqpath.c
index adbaa74..6ba4eca 100644
--- a/psycopg/pqpath.c
+++ b/psycopg/pqpath.c
@@ -64,7 +64,7 @@ strip_severity(const char *msg)
code. A list of error codes can be found at:
http://www.postgresql.org/docs/current/static/errcodes-appendix.html */
-static PyObject *
+BORROWED static PyObject *
exception_from_sqlstate(const char *sqlstate)
{
switch (sqlstate[0]) {
@@ -151,7 +151,7 @@ exception_from_sqlstate(const char *sqlstate)
This function should be called while holding the GIL. */
-static void
+RAISES static void
pq_raise(connectionObject *conn, cursorObject *curs, PGresult *pgres)
{
PyObject *exc = NULL;
@@ -164,7 +164,7 @@ pq_raise(connectionObject *conn, cursorObject *curs, PGresult *pgres)
"psycopg went psycotic and raised a null error");
return;
}
-
+
/* if the connection has somehow beed broken, we mark the connection
object as closed but requiring cleanup */
if (conn->pgconn != NULL && PQstatus(conn->pgconn) == CONNECTION_BAD)
@@ -249,7 +249,9 @@ pq_clear_critical(connectionObject *conn)
}
}
-static PyObject *
+/* return -1 if the exception is set (i.e. if conn->critical is set),
+ * else 0 */
+RAISES_NEG static int
pq_resolve_critical(connectionObject *conn, int close)
{
Dprintf("pq_resolve_critical: resolving %s", conn->critical);
@@ -264,11 +266,13 @@ pq_resolve_critical(connectionObject *conn, int close)
/* we don't want to destroy this connection but just close it */
if (close == 1) conn_close(conn);
-
+
/* remember to clear the critical! */
- pq_clear_critical(conn);
+ pq_clear_critical(conn);
+
+ return -1;
}
- return NULL;
+ return 0;
}
/* pq_clear_async - clear the effects of a previous async query
@@ -300,19 +304,16 @@ pq_clear_async(connectionObject *conn)
Accepted arg values are 1 (nonblocking) and 0 (blocking).
- Return 0 if everything ok, else nonzero.
-
- In case of error, if pyerr is nonzero, set a Python exception.
+ Return 0 if everything ok, else < 0 and set an exception.
*/
-int
-pq_set_non_blocking(connectionObject *conn, int arg, int pyerr)
+RAISES_NEG int
+pq_set_non_blocking(connectionObject *conn, int arg)
{
int ret = PQsetnonblocking(conn->pgconn, arg);
if (0 != ret) {
Dprintf("PQsetnonblocking(%d) FAILED", arg);
- if (pyerr) {
- PyErr_SetString(OperationalError, "PQsetnonblocking() failed");
- }
+ PyErr_SetString(OperationalError, "PQsetnonblocking() failed");
+ ret = -1;
}
return ret;
}
@@ -382,7 +383,7 @@ cleanup:
This function should be called while holding the global interpreter
lock.
*/
-void
+RAISES void
pq_complete_error(connectionObject *conn, PGresult **pgres, char **error)
{
Dprintf("pq_complete_error: pgconn = %p, pgres = %p, error = %s",
@@ -476,7 +477,7 @@ pq_commit(connectionObject *conn)
return retvalue;
}
-int
+RAISES_NEG int
pq_abort_locked(connectionObject *conn, PGresult **pgres, char **error,
PyThreadState **tstate)
{
@@ -503,7 +504,7 @@ pq_abort_locked(connectionObject *conn, PGresult **pgres, char **error,
This function should be called while holding the global interpreter
lock. */
-int
+RAISES_NEG int
pq_abort(connectionObject *conn)
{
int retvalue = -1;
@@ -540,7 +541,7 @@ pq_abort(connectionObject *conn)
connection without holding the global interpreter lock.
*/
-int
+RAISES_NEG int
pq_reset_locked(connectionObject *conn, PGresult **pgres, char **error,
PyThreadState **tstate)
{
@@ -832,7 +833,7 @@ pq_flush(connectionObject *conn)
this fucntion locks the connection object
this function call Py_*_ALLOW_THREADS macros */
-int
+RAISES_NEG int
pq_execute(cursorObject *curs, const char *query, int async)
{
PGresult *pgres = NULL;
@@ -842,8 +843,7 @@ pq_execute(cursorObject *curs, const char *query, int async)
/* if the status of the connection is critical raise an exception and
definitely close the connection */
if (curs->conn->critical) {
- pq_resolve_critical(curs->conn, 1);
- return -1;
+ return pq_resolve_critical(curs->conn, 1);
}
/* check status of connection, raise error if not OK */
@@ -938,12 +938,13 @@ pq_execute(cursorObject *curs, const char *query, int async)
to respect the old DBAPI-2.0 compatible behaviour */
if (async == 0) {
Dprintf("pq_execute: entering syncronous DBAPI compatibility mode");
- if (pq_fetch(curs) == -1) return -1;
+ if (pq_fetch(curs) < 0) return -1;
}
else {
+ PyObject *tmp;
curs->conn->async_status = async_status;
- curs->conn->async_cursor = PyWeakref_NewRef((PyObject *)curs, NULL);
- if (!curs->conn->async_cursor) {
+ curs->conn->async_cursor = tmp = PyWeakref_NewRef((PyObject *)curs, NULL);
+ if (!tmp) {
/* weakref creation failed */
return -1;
}
@@ -1012,7 +1013,7 @@ pq_get_last_result(connectionObject *conn)
1 - result from backend (possibly data is ready)
*/
-static int
+RAISES_NEG static int
_pq_fetch_tuples(cursorObject *curs)
{
int i, *dsize = NULL;
@@ -1412,8 +1413,7 @@ pq_fetch(cursorObject *curs)
Dprintf("pq_fetch: got a NULL pgres, checking for critical");
pq_set_critical(curs->conn);
if (curs->conn->critical) {
- pq_resolve_critical(curs->conn);
- return -1;
+ return pq_resolve_critical(curs->conn);
}
else {
return 0;
@@ -1489,13 +1489,7 @@ pq_fetch(cursorObject *curs)
raise the exception but we avoid to close the connection) */
Dprintf("pq_fetch: fetching done; check for critical errors");
if (curs->conn->critical) {
- if (ex == -1) {
- pq_resolve_critical(curs->conn, 1);
- }
- else {
- pq_resolve_critical(curs->conn, 0);
- }
- return -1;
+ return pq_resolve_critical(curs->conn, ex == -1 ? 1 : 0);
}
return ex;
diff --git a/psycopg/pqpath.h b/psycopg/pqpath.h
index bf012ad..a8f39c1 100644
--- a/psycopg/pqpath.h
+++ b/psycopg/pqpath.h
@@ -35,18 +35,18 @@
/* exported functions */
HIDDEN PGresult *pq_get_last_result(connectionObject *conn);
-HIDDEN int pq_fetch(cursorObject *curs);
-HIDDEN int pq_execute(cursorObject *curs, const char *query, int async);
+RAISES_NEG HIDDEN int pq_fetch(cursorObject *curs);
+RAISES_NEG HIDDEN int pq_execute(cursorObject *curs, const char *query, int async);
HIDDEN int pq_send_query(connectionObject *conn, const char *query);
HIDDEN int pq_begin_locked(connectionObject *conn, PGresult **pgres,
char **error, PyThreadState **tstate);
HIDDEN int pq_commit(connectionObject *conn);
-HIDDEN int pq_abort_locked(connectionObject *conn, PGresult **pgres,
+RAISES_NEG HIDDEN int pq_abort_locked(connectionObject *conn, PGresult **pgres,
char **error, PyThreadState **tstate);
-HIDDEN int pq_abort(connectionObject *conn);
+RAISES_NEG HIDDEN int pq_abort(connectionObject *conn);
HIDDEN int pq_reset_locked(connectionObject *conn, PGresult **pgres,
char **error, PyThreadState **tstate);
-HIDDEN int pq_reset(connectionObject *conn);
+RAISES_NEG HIDDEN int pq_reset(connectionObject *conn);
HIDDEN char *pq_get_guc_locked(connectionObject *conn, const char *param,
PGresult **pgres,
char **error, PyThreadState **tstate);
@@ -61,7 +61,7 @@ HIDDEN int pq_is_busy(connectionObject *conn);
HIDDEN int pq_is_busy_locked(connectionObject *conn);
HIDDEN int pq_flush(connectionObject *conn);
HIDDEN void pq_clear_async(connectionObject *conn);
-HIDDEN int pq_set_non_blocking(connectionObject *conn, int arg, int pyerr);
+RAISES_NEG HIDDEN int pq_set_non_blocking(connectionObject *conn, int arg);
HIDDEN void pq_set_critical(connectionObject *conn, const char *msg);
@@ -69,7 +69,7 @@ HIDDEN int pq_execute_command_locked(connectionObject *conn,
const char *query,
PGresult **pgres, char **error,
PyThreadState **tstate);
-HIDDEN void pq_complete_error(connectionObject *conn, PGresult **pgres,
+RAISES HIDDEN void pq_complete_error(connectionObject *conn, PGresult **pgres,
char **error);
#endif /* !defined(PSYCOPG_PQPATH_H) */
diff --git a/psycopg/psycopg.h b/psycopg/psycopg.h
index 2f06c37..2e86dca 100644
--- a/psycopg/psycopg.h
+++ b/psycopg/psycopg.h
@@ -120,17 +120,19 @@ HIDDEN PyObject *psyco_GetDecimalType(void);
typedef struct cursorObject cursorObject;
/* some utility functions */
-HIDDEN void psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg,
+RAISES HIDDEN void psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg,
const char *pgerror, const char *pgcode);
HIDDEN char *psycopg_escape_string(PyObject *conn,
const char *from, Py_ssize_t len, char *to, Py_ssize_t *tolen);
HIDDEN char *psycopg_escape_identifier_easy(const char *from, Py_ssize_t len);
-HIDDEN char *psycopg_strdup(const char *from, Py_ssize_t len);
-HIDDEN PyObject * psycopg_ensure_bytes(PyObject *obj);
-HIDDEN PyObject * psycopg_ensure_text(PyObject *obj);
+HIDDEN int psycopg_strdup(char **to, const char *from, Py_ssize_t len);
HIDDEN int psycopg_is_text_file(PyObject *f);
+STEALS(1) HIDDEN PyObject * psycopg_ensure_bytes(PyObject *obj);
+
+STEALS(1) HIDDEN PyObject * psycopg_ensure_text(PyObject *obj);
+
/* Exceptions docstrings */
#define Error_doc \
"Base class for error exceptions."
diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c
index 438b018..3328c60 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);
@@ -182,66 +180,108 @@ psyco_register_type(PyObject *self, PyObject *args)
}
-/* default adapters */
-
-static void
+/* Initialize the default adapters map
+ *
+ * Return 0 on success, else -1 and set an exception.
+ */
+static int
psyco_adapters_init(PyObject *mod)
{
- PyObject *call;
+ PyObject *call = NULL;
+ int rv = -1;
- microprotocols_add(&PyFloat_Type, NULL, (PyObject*)&pfloatType);
+ if (0 != microprotocols_add(&PyFloat_Type, NULL, (PyObject*)&pfloatType)) {
+ goto exit;
+ }
#if PY_MAJOR_VERSION < 3
- microprotocols_add(&PyInt_Type, NULL, (PyObject*)&pintType);
+ if (0 != microprotocols_add(&PyInt_Type, NULL, (PyObject*)&pintType)) {
+ goto exit;
+ }
#endif
- microprotocols_add(&PyLong_Type, NULL, (PyObject*)&pintType);
- microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType);
+ if (0 != microprotocols_add(&PyLong_Type, NULL, (PyObject*)&pintType)) {
+ goto exit;
+ }
+ if (0 != microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType)) {
+ goto exit;
+ }
/* strings */
#if PY_MAJOR_VERSION < 3
- microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType);
+ if (0 != microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType)) {
+ goto exit;
+ }
#endif
- microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType);
+ if (0 != microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType)) {
+ goto exit;
+ }
/* binary */
#if PY_MAJOR_VERSION < 3
- microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType);
+ if (0 != microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType)) {
+ goto exit;
+ }
#else
- microprotocols_add(&PyBytes_Type, NULL, (PyObject*)&binaryType);
+ if (0 != microprotocols_add(&PyBytes_Type, NULL, (PyObject*)&binaryType)) {
+ goto exit;
+ }
#endif
#if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 6
- microprotocols_add(&PyByteArray_Type, NULL, (PyObject*)&binaryType);
+ if (0 != microprotocols_add(&PyByteArray_Type, NULL, (PyObject*)&binaryType)) {
+ goto exit;
+ }
#endif
#if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 7
- microprotocols_add(&PyMemoryView_Type, NULL, (PyObject*)&binaryType);
+ if (0 != microprotocols_add(&PyMemoryView_Type, NULL, (PyObject*)&binaryType)) {
+ goto exit;
+ }
#endif
- microprotocols_add(&PyList_Type, NULL, (PyObject*)&listType);
+ if (0 != microprotocols_add(&PyList_Type, NULL, (PyObject*)&listType)) {
+ goto exit;
+ }
/* the module has already been initialized, so we can obtain the callable
objects directly from its dictionary :) */
- call = PyMapping_GetItemString(mod, "DateFromPy");
- microprotocols_add(PyDateTimeAPI->DateType, NULL, call);
- call = PyMapping_GetItemString(mod, "TimeFromPy");
- microprotocols_add(PyDateTimeAPI->TimeType, NULL, call);
- call = PyMapping_GetItemString(mod, "TimestampFromPy");
- microprotocols_add(PyDateTimeAPI->DateTimeType, NULL, call);
- call = PyMapping_GetItemString(mod, "IntervalFromPy");
- microprotocols_add(PyDateTimeAPI->DeltaType, NULL, call);
+ if (!(call = PyMapping_GetItemString(mod, "DateFromPy"))) { goto exit; }
+ if (0 != microprotocols_add(PyDateTimeAPI->DateType, NULL, call)) { goto exit; }
+ Py_CLEAR(call);
+
+ if (!(call = PyMapping_GetItemString(mod, "TimeFromPy"))) { goto exit; }
+ if (0 != microprotocols_add(PyDateTimeAPI->TimeType, NULL, call)) { goto exit; }
+ Py_CLEAR(call);
+
+ if (!(call = PyMapping_GetItemString(mod, "TimestampFromPy"))) { goto exit; }
+ if (0 != microprotocols_add(PyDateTimeAPI->DateTimeType, NULL, call)) { goto exit; }
+ Py_CLEAR(call);
+
+ if (!(call = PyMapping_GetItemString(mod, "IntervalFromPy"))) { goto exit; }
+ if (0 != microprotocols_add(PyDateTimeAPI->DeltaType, NULL, call)) { goto exit; }
+ Py_CLEAR(call);
#ifdef HAVE_MXDATETIME
/* as above, we use the callable objects from the psycopg module */
if (NULL != (call = PyMapping_GetItemString(mod, "TimestampFromMx"))) {
- microprotocols_add(mxDateTime.DateTime_Type, NULL, call);
+ if (0 != microprotocols_add(mxDateTime.DateTime_Type, NULL, call)) { goto exit; }
+ Py_CLEAR(call);
/* if we found the above, we have this too. */
- call = PyMapping_GetItemString(mod, "TimeFromMx");
- microprotocols_add(mxDateTime.DateTimeDelta_Type, NULL, call);
+ if (!(call = PyMapping_GetItemString(mod, "TimeFromMx"))) { goto exit; }
+ if (0 != microprotocols_add(mxDateTime.DateTimeDelta_Type, NULL, call)) { goto exit; }
+ Py_CLEAR(call);
}
else {
PyErr_Clear();
}
#endif
+
+ /* Success! */
+ rv = 0;
+
+exit:
+ Py_XDECREF(call);
+
+ return rv;
}
/* psyco_encodings_fill
@@ -326,15 +366,27 @@ static encodingPair encodings[] = {
{NULL, NULL}
};
-static void psyco_encodings_fill(PyObject *dict)
+/* Initialize the encodings table.
+ *
+ * Return 0 on success, else -1 and set an exception.
+ */
+static int psyco_encodings_fill(PyObject *dict)
{
+ PyObject *value = NULL;
encodingPair *enc;
+ int rv = -1;
for (enc = encodings; enc->pgenc != NULL; enc++) {
- PyObject *value = Text_FromUTF8(enc->pyenc);
- PyDict_SetItemString(dict, enc->pgenc, value);
- Py_DECREF(value);
+ if (!(value = Text_FromUTF8(enc->pyenc))) { goto exit; }
+ if (0 != PyDict_SetItemString(dict, enc->pgenc, value)) { goto exit; }
+ Py_CLEAR(value);
}
+ rv = 0;
+
+exit:
+ Py_XDECREF(value);
+
+ return rv;
}
/* psyco_errors_init, psyco_errors_fill (callable from C)
@@ -440,21 +492,22 @@ psyco_errors_init(void)
live in _psycopg */
int i;
- PyObject *dict;
+ PyObject *dict = NULL;
PyObject *base;
- PyObject *str;
- PyObject *descr;
+ PyObject *str = NULL;
+ PyObject *descr = NULL;
int rv = -1;
static PyMethodDef psyco_error_reduce_ex_def =
{"__reduce_ex__", psyco_error_reduce_ex, METH_VARARGS, "pickle helper"};
for (i=0; exctable[i].name; i++) {
- dict = PyDict_New();
+ if (!(dict = PyDict_New())) { goto exit; }
if (exctable[i].docstr) {
- str = Text_FromUTF8(exctable[i].docstr);
- PyDict_SetItemString(dict, "__doc__", str);
+ if (!(str = Text_FromUTF8(exctable[i].docstr))) { goto exit; }
+ if (0 != PyDict_SetItemString(dict, "__doc__", str)) { goto exit; }
+ Py_CLEAR(str);
}
if (exctable[i].base == 0) {
@@ -468,7 +521,11 @@ psyco_errors_init(void)
else
base = *exctable[i].base;
- *exctable[i].exc = PyErr_NewException(exctable[i].name, base, dict);
+ if (!(*exctable[i].exc = PyErr_NewException(
+ exctable[i].name, base, dict))) {
+ goto exit;
+ }
+ Py_CLEAR(dict);
}
/* Make pgerror, pgcode and cursor default to None on psycopg
@@ -492,60 +549,56 @@ psyco_errors_init(void)
psyco_error_reduce_ex_def.ml_name, descr)) {
goto exit;
}
- Py_DECREF(descr);
#endif
rv = 0;
exit:
+ Py_XDECREF(descr);
+ Py_XDECREF(str);
+ Py_XDECREF(dict);
return rv;
}
void
psyco_errors_fill(PyObject *dict)
{
- PyDict_SetItemString(dict, "Error", Error);
- PyDict_SetItemString(dict, "Warning", Warning);
- PyDict_SetItemString(dict, "InterfaceError", InterfaceError);
- PyDict_SetItemString(dict, "DatabaseError", DatabaseError);
- PyDict_SetItemString(dict, "InternalError", InternalError);
- PyDict_SetItemString(dict, "OperationalError", OperationalError);
- PyDict_SetItemString(dict, "ProgrammingError", ProgrammingError);
- PyDict_SetItemString(dict, "IntegrityError", IntegrityError);
- PyDict_SetItemString(dict, "DataError", DataError);
- PyDict_SetItemString(dict, "NotSupportedError", NotSupportedError);
-#ifdef PSYCOPG_EXTENSIONS
- PyDict_SetItemString(dict, "QueryCanceledError", QueryCanceledError);
- PyDict_SetItemString(dict, "TransactionRollbackError",
- TransactionRollbackError);
-#endif
+ int i;
+ char *name;
+
+ for (i = 0; exctable[i].name; i++) {
+ if (NULL == exctable[i].exc) { continue; }
+
+ /* the name is the part after the last dot */
+ name = strrchr(exctable[i].name, '.');
+ name = name ? name + 1 : exctable[i].name;
+
+ PyDict_SetItemString(dict, name, *exctable[i].exc);
+ }
}
void
psyco_errors_set(PyObject *type)
{
- PyObject_SetAttrString(type, "Error", Error);
- PyObject_SetAttrString(type, "Warning", Warning);
- PyObject_SetAttrString(type, "InterfaceError", InterfaceError);
- PyObject_SetAttrString(type, "DatabaseError", DatabaseError);
- PyObject_SetAttrString(type, "InternalError", InternalError);
- PyObject_SetAttrString(type, "OperationalError", OperationalError);
- PyObject_SetAttrString(type, "ProgrammingError", ProgrammingError);
- PyObject_SetAttrString(type, "IntegrityError", IntegrityError);
- PyObject_SetAttrString(type, "DataError", DataError);
- PyObject_SetAttrString(type, "NotSupportedError", NotSupportedError);
-#ifdef PSYCOPG_EXTENSIONS
- PyObject_SetAttrString(type, "QueryCanceledError", QueryCanceledError);
- PyObject_SetAttrString(type, "TransactionRollbackError",
- TransactionRollbackError);
-#endif
+ int i;
+ char *name;
+
+ for (i = 0; exctable[i].name; i++) {
+ if (NULL == exctable[i].exc) { continue; }
+
+ /* the name is the part after the last dot */
+ name = strrchr(exctable[i].name, '.');
+ name = name ? name + 1 : exctable[i].name;
+
+ PyObject_SetAttrString(type, name, *exctable[i].exc);
+ }
}
-/* psyco_error_new
+/* psyco_set_error
Create a new error of the given type with extra attributes. */
-void
+RAISES void
psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg,
const char *pgerror, const char *pgcode)
{
@@ -574,15 +627,17 @@ psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg,
}
if (pgerror) {
- t = conn_text_from_chars(conn, pgerror);
- PyObject_SetAttrString(err, "pgerror", t);
- Py_DECREF(t);
+ if ((t = conn_text_from_chars(conn, pgerror))) {
+ PyObject_SetAttrString(err, "pgerror", t);
+ Py_DECREF(t);
+ }
}
if (pgcode) {
- t = conn_text_from_chars(conn, pgcode);
- PyObject_SetAttrString(err, "pgcode", t);
- Py_DECREF(t);
+ if ((t = conn_text_from_chars(conn, pgcode))) {
+ PyObject_SetAttrString(err, "pgcode", t);
+ Py_DECREF(t);
+ }
}
PyErr_SetObject(exc, err);
@@ -649,7 +704,7 @@ psyco_GetDecimalType(void)
}
/* Store the object from future uses. */
- if (can_cache && !cachedType) {
+ if (can_cache && !cachedType && decimalType) {
Py_INCREF(decimalType);
cachedType = decimalType;
}
@@ -673,15 +728,11 @@ psyco_make_description_type(void)
/* Try to import collections.namedtuple */
if (!(coll = PyImport_ImportModule("collections"))) {
Dprintf("psyco_make_description_type: collections import failed");
- PyErr_Clear();
- rv = Py_None;
- goto exit;
+ goto error;
}
if (!(nt = PyObject_GetAttrString(coll, "namedtuple"))) {
Dprintf("psyco_make_description_type: no collections.namedtuple");
- PyErr_Clear();
- rv = Py_None;
- goto exit;
+ goto error;
}
/* Build the namedtuple */
@@ -693,6 +744,13 @@ exit:
Py_XDECREF(nt);
return rv;
+
+error:
+ /* controlled error: we will fall back to regular tuples. Return None. */
+ PyErr_Clear();
+ rv = Py_None;
+ Py_INCREF(rv);
+ goto exit;
}
@@ -905,10 +963,10 @@ INIT_MODULE(_psycopg)(void)
#endif
/* other mixed initializations of module-level variables */
- psycoEncodings = PyDict_New();
- psyco_encodings_fill(psycoEncodings);
+ if (!(psycoEncodings = PyDict_New())) { goto exit; }
+ if (0 != psyco_encodings_fill(psycoEncodings)) { goto exit; }
psyco_null = Bytes_FromString("NULL");
- psyco_DescriptionType = psyco_make_description_type();
+ if (!(psyco_DescriptionType = psyco_make_description_type())) { goto exit; }
/* set some module's parameters */
PyModule_AddStringConstant(module, "__version__", PSYCOPG_VERSION);
@@ -941,11 +999,11 @@ 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);
- psyco_adapters_init(dict);
+ if (0 != psyco_adapters_init(dict)) { goto exit; }
/* create a standard set of exceptions and add them to the module's dict */
if (0 != psyco_errors_init()) { goto exit; }
diff --git a/psycopg/typecast.c b/psycopg/typecast.c
index 8ede351..8504631 100644
--- a/psycopg/typecast.c
+++ b/psycopg/typecast.c
@@ -250,34 +250,28 @@ PyObject *psyco_default_binary_cast;
/* typecast_init - initialize the dictionary and create default types */
-int
+RAISES_NEG int
typecast_init(PyObject *dict)
{
int i;
+ int rv = -1;
+ typecastObject *t = NULL;
/* create type dictionary and put it in module namespace */
- psyco_types = PyDict_New();
- psyco_binary_types = PyDict_New();
-
- if (!psyco_types || !psyco_binary_types) {
- Py_XDECREF(psyco_types);
- Py_XDECREF(psyco_binary_types);
- return -1;
- }
-
+ if (!(psyco_types = PyDict_New())) { goto exit; }
PyDict_SetItemString(dict, "string_types", psyco_types);
+
+ if (!(psyco_binary_types = PyDict_New())) { goto exit; }
PyDict_SetItemString(dict, "binary_types", psyco_binary_types);
/* insert the cast types into the 'types' dictionary and register them in
the module dictionary */
for (i = 0; typecast_builtins[i].name != NULL; i++) {
- typecastObject *t;
-
Dprintf("typecast_init: initializing %s", typecast_builtins[i].name);
t = (typecastObject *)typecast_from_c(&(typecast_builtins[i]), dict);
- if (t == NULL) return -1;
- if (typecast_add((PyObject *)t, NULL, 0) != 0) return -1;
+ if (t == NULL) { goto exit; }
+ if (typecast_add((PyObject *)t, NULL, 0) < 0) { goto exit; }
PyDict_SetItem(dict, t->name, (PyObject *)t);
@@ -285,6 +279,8 @@ typecast_init(PyObject *dict)
if (typecast_builtins[i].values == typecast_BINARY_types) {
psyco_default_binary_cast = (PyObject *)t;
}
+ Py_DECREF((PyObject *)t);
+ t = NULL;
}
/* create and save a default cast object (but does not register it) */
@@ -294,29 +290,35 @@ typecast_init(PyObject *dict)
#ifdef HAVE_MXDATETIME
if (0 == psyco_typecast_mxdatetime_init()) {
for (i = 0; typecast_mxdatetime[i].name != NULL; i++) {
- typecastObject *t;
Dprintf("typecast_init: initializing %s", typecast_mxdatetime[i].name);
t = (typecastObject *)typecast_from_c(&(typecast_mxdatetime[i]), dict);
- if (t == NULL) return -1;
+ if (t == NULL) { goto exit; }
PyDict_SetItem(dict, t->name, (PyObject *)t);
+ Py_DECREF((PyObject *)t);
+ t = NULL;
}
}
#endif
- if (psyco_typecast_datetime_init()) { return -1; }
+ if (0 > psyco_typecast_datetime_init()) { goto exit; }
for (i = 0; typecast_pydatetime[i].name != NULL; i++) {
- typecastObject *t;
Dprintf("typecast_init: initializing %s", typecast_pydatetime[i].name);
t = (typecastObject *)typecast_from_c(&(typecast_pydatetime[i]), dict);
- if (t == NULL) return -1;
+ if (t == NULL) { goto exit; }
PyDict_SetItem(dict, t->name, (PyObject *)t);
+ Py_DECREF((PyObject *)t);
+ t = NULL;
}
- return 0;
+ rv = 0;
+
+exit:
+ Py_XDECREF((PyObject *)t);
+ return rv;
}
/* typecast_add - add a type object to the dictionary */
-int
+RAISES_NEG int
typecast_add(PyObject *obj, PyObject *dict, int binary)
{
PyObject *val;
@@ -466,7 +468,7 @@ typecast_repr(PyObject *self)
static PyObject *
typecast_call(PyObject *obj, PyObject *args, PyObject *kwargs)
{
- char *string;
+ const char *string;
Py_ssize_t length;
PyObject *cursor;
diff --git a/psycopg/typecast.h b/psycopg/typecast.h
index 20def30..04976f3 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 75b84b5..b5f1062 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;
}
@@ -260,12 +260,11 @@ typecast_GENERIC_ARRAY_cast(const char *str, Py_ssize_t len, PyObject *curs)
Dprintf("typecast_GENERIC_ARRAY_cast: str = '%s',"
" len = " FORMAT_CODE_PY_SSIZE_T, str, len);
- obj = PyList_New(0);
+ if (!(obj = PyList_New(0))) { return NULL; }
/* 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_basic.c b/psycopg/typecast_basic.c
index 20c7b81..5e2a93e 100644
--- a/psycopg/typecast_basic.c
+++ b/psycopg/typecast_basic.c
@@ -65,7 +65,7 @@ typecast_FLOAT_cast(const char *s, Py_ssize_t len, PyObject *curs)
PyObject *str = NULL, *flo = NULL;
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
- str = Text_FromUTF8AndSize(s, len);
+ if (!(str = Text_FromUTF8AndSize(s, len))) { return NULL; }
#if PY_MAJOR_VERSION < 3
flo = PyFloat_FromString(str, NULL);
#else
diff --git a/psycopg/typecast_datetime.c b/psycopg/typecast_datetime.c
index 29149c0..18e9d0d 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");
@@ -239,7 +239,7 @@ typecast_PYINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs)
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- v = v*10 + (double)*str - (double)'0';
+ v = v * 10.0 + (double)(*str - '0');
if (part == 6){
denominator *= 10;
}
diff --git a/psycopg/typecast_mxdatetime.c b/psycopg/typecast_mxdatetime.c
index e61224d..bf69af5 100644
--- a/psycopg/typecast_mxdatetime.c
+++ b/psycopg/typecast_mxdatetime.c
@@ -142,7 +142,7 @@ typecast_MXINTERVAL_cast(const char *str, Py_ssize_t len, PyObject *curs)
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- v = v*10 + (double)*str - (double)'0';
+ v = v * 10.0 + (double)(*str - '0');
Dprintf("typecast_MXINTERVAL_cast: v = %f", v);
if (part == 6){
denominator *= 10;
diff --git a/psycopg/utils.c b/psycopg/utils.c
index 2e81c11..57586c5 100644
--- a/psycopg/utils.c
+++ b/psycopg/utils.c
@@ -113,20 +113,19 @@ psycopg_escape_identifier_easy(const char *from, Py_ssize_t len)
* Allocate a new buffer on the Python heap containing the new string.
* 'len' is optional: if 0 the length is calculated.
*
- * Return NULL and set an exception in case of error.
+ * Store the return in 'to' and return 0 in case of success, else return -1
+ * and raise an exception.
*/
-char *
-psycopg_strdup(const char *from, Py_ssize_t len)
+RAISES_NEG int
+psycopg_strdup(char **to, const char *from, Py_ssize_t len)
{
- char *rv;
-
if (!len) { len = strlen(from); }
- if (!(rv = PyMem_Malloc(len + 1))) {
+ if (!(*to = PyMem_Malloc(len + 1))) {
PyErr_NoMemory();
- return NULL;
+ return -1;
}
- strcpy(rv, from);
- return rv;
+ strcpy(*to, from);
+ return 0;
}
/* Ensure a Python object is a bytes string.
@@ -139,7 +138,7 @@ psycopg_strdup(const char *from, Py_ssize_t len)
*
* It is safe to call the function on NULL.
*/
-PyObject *
+STEALS(1) PyObject *
psycopg_ensure_bytes(PyObject *obj)
{
PyObject *rv = NULL;
@@ -169,7 +168,7 @@ psycopg_ensure_bytes(PyObject *obj)
* The function is ref neutral: steals a ref from obj and adds one to the
* return value. It is safe to call it on NULL.
*/
-PyObject *
+STEALS(1) PyObject *
psycopg_ensure_text(PyObject *obj)
{
#if PY_MAJOR_VERSION < 3
diff --git a/psycopg/xid_type.c b/psycopg/xid_type.c
index 4de46b4..b28543c 100644
--- a/psycopg/xid_type.c
+++ b/psycopg/xid_type.c
@@ -78,7 +78,9 @@ static PyMemberDef xid_members[] = {
static PyObject *
xid_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
- XidObject *self = (XidObject *)type->tp_alloc(type, 0);
+ XidObject *self;
+
+ if (!(self = (XidObject *)type->tp_alloc(type, 0))) { return NULL; }
Py_INCREF(Py_None);
self->format_id = Py_None;
@@ -486,7 +488,7 @@ exit:
*
* Return a borrowed reference. */
-static PyObject *
+BORROWED static PyObject *
_xid_get_parse_regex(void) {
static PyObject *rv;