Merge branch 'gcc-python-plugin' into devel

This commit is contained in:
Daniele Varrazzo 2012-03-05 02:48:11 +00:00
commit b8c75d9de0
29 changed files with 570 additions and 448 deletions

4
NEWS
View File

@ -15,6 +15,10 @@ What's new in psycopg 2.4.5
Regression introduced in 2.4.4 (ticket #100). Regression introduced in 2.4.4 (ticket #100).
- Added support for 'inet' arrays. - Added support for 'inet' arrays.
- Fixed 'commit()' concurrency problem (ticket #103). - 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 What's new in psycopg 2.4.4

View File

@ -65,6 +65,13 @@ binary_quote(binaryObject *self)
int got_view = 0; int got_view = 0;
#endif #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 we got a plain string or a buffer we escape it and save the buffer */
#if HAS_MEMORYVIEW #if HAS_MEMORYVIEW
@ -93,7 +100,7 @@ binary_quote(binaryObject *self)
/* escape and build quoted buffer */ /* 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); &len, self->conn ? ((connectionObject*)self->conn)->pgconn : NULL);
if (to == NULL) { if (to == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
@ -113,12 +120,6 @@ exit:
if (got_view) { PyBuffer_Release(&view); } if (got_view) { PyBuffer_Release(&view); }
#endif #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 the wrapped object is not bytes or a buffer, this is an error */
if (!rv && !PyErr_Occurred()) { if (!rv && !PyErr_Occurred()) {
PyErr_Format(PyExc_TypeError, "can't escape %s to binary", PyErr_Format(PyExc_TypeError, "can't escape %s to binary",
@ -149,16 +150,14 @@ binary_str(binaryObject *self)
static PyObject * static PyObject *
binary_prepare(binaryObject *self, PyObject *args) 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; return NULL;
Py_XDECREF(self->conn); Py_XDECREF(self->conn);
if (conn) { self->conn = conn;
self->conn = (PyObject*)conn; Py_INCREF(self->conn);
Py_INCREF(self->conn);
}
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;

View File

@ -427,6 +427,10 @@ psyco_DateFromTicks(PyObject *self, PyObject *args)
Py_DECREF(args); Py_DECREF(args);
} }
} }
else {
PyErr_SetString(InterfaceError, "failed localtime call");
}
return res; return res;
} }
@ -451,6 +455,10 @@ psyco_TimeFromTicks(PyObject *self, PyObject *args)
Py_DECREF(args); Py_DECREF(args);
} }
} }
else {
PyErr_SetString(InterfaceError, "failed localtime call");
}
return res; return res;
} }
@ -473,6 +481,9 @@ psyco_TimestampFromTicks(PyObject *self, PyObject *args)
tm.tm_hour, tm.tm_min, (double)tm.tm_sec + ticks, tm.tm_hour, tm.tm_min, (double)tm.tm_sec + ticks,
pyPsycopgTzLOCAL); pyPsycopgTzLOCAL);
} }
else {
PyErr_SetString(InterfaceError, "failed localtime call");
}
return res; return res;
} }

View File

@ -98,9 +98,9 @@ list_getquoted(listObject *self, PyObject *args)
static PyObject * static PyObject *
list_prepare(listObject *self, PyObject *args) 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; return NULL;
/* note that we don't copy the encoding from the connection, but take a /* 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. */ work even without a connection to the backend. */
Py_CLEAR(self->connection); Py_CLEAR(self->connection);
Py_INCREF(conn); Py_INCREF(conn);
self->connection = (PyObject*)conn; self->connection = conn;
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;

View File

@ -35,7 +35,7 @@
/* qstring_quote - do the quote process on plain and unicode strings */ /* qstring_quote - do the quote process on plain and unicode strings */
static PyObject * BORROWED static PyObject *
qstring_quote(qstringObject *self) qstring_quote(qstringObject *self)
{ {
PyObject *str; PyObject *str;
@ -124,24 +124,22 @@ qstring_str(qstringObject *self)
static PyObject * static PyObject *
qstring_prepare(qstringObject *self, PyObject *args) 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; return NULL;
/* we bother copying the encoding only if the wrapped string is unicode, /* we bother copying the encoding only if the wrapped string is unicode,
we don't need the encoding if that's not the case */ we don't need the encoding if that's not the case */
if (PyUnicode_Check(self->wrapped)) { if (PyUnicode_Check(self->wrapped)) {
if (self->encoding) free(self->encoding); if (self->encoding) free(self->encoding);
self->encoding = strdup(conn->codec); self->encoding = strdup(((connectionObject *)conn)->codec);
Dprintf("qstring_prepare: set encoding to %s", conn->codec); Dprintf("qstring_prepare: set encoding to %s", self->encoding);
} }
Py_CLEAR(self->conn); Py_CLEAR(self->conn);
if (conn) { Py_INCREF(conn);
Py_INCREF(conn); self->conn = conn;
self->conn = (PyObject*)conn;
}
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;

View File

@ -86,7 +86,7 @@
/* Helpers for formatstring */ /* Helpers for formatstring */
Py_LOCAL_INLINE(PyObject *) BORROWED Py_LOCAL_INLINE(PyObject *)
getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx)
{ {
Py_ssize_t argidx = *p_argidx; Py_ssize_t argidx = *p_argidx;

View File

@ -160,4 +160,33 @@ static double round(double num)
#define isinf(x) (!finite((x)) && (x)==(x)) #define isinf(x) (!finite((x)) && (x)==(x))
#endif #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) */ #endif /* !defined(PSYCOPG_CONFIG_H) */

View File

@ -131,27 +131,27 @@ typedef struct {
/* C-callable functions in connection_int.c and connection_ext.c */ /* C-callable functions in connection_int.c and connection_ext.c */
HIDDEN PyObject *conn_text_from_chars(connectionObject *pgconn, const char *str); HIDDEN PyObject *conn_text_from_chars(connectionObject *pgconn, const char *str);
HIDDEN int conn_get_standard_conforming_strings(PGconn *pgconn); 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_protocol_version(PGconn *pgconn);
HIDDEN int conn_get_server_version(PGconn *pgconn); HIDDEN int conn_get_server_version(PGconn *pgconn);
HIDDEN PGcancel *conn_get_cancel(PGconn *pgconn); HIDDEN PGcancel *conn_get_cancel(PGconn *pgconn);
HIDDEN void conn_notice_process(connectionObject *self); HIDDEN void conn_notice_process(connectionObject *self);
HIDDEN void conn_notice_clean(connectionObject *self); HIDDEN void conn_notice_clean(connectionObject *self);
HIDDEN void conn_notifies_process(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 int conn_connect(connectionObject *self, long int async);
HIDDEN void conn_close(connectionObject *self); HIDDEN void conn_close(connectionObject *self);
HIDDEN int conn_commit(connectionObject *self); RAISES_NEG HIDDEN int conn_commit(connectionObject *self);
HIDDEN int conn_rollback(connectionObject *self); RAISES_NEG HIDDEN int conn_rollback(connectionObject *self);
HIDDEN int conn_set_session(connectionObject *self, const char *isolevel, RAISES_NEG HIDDEN int conn_set_session(connectionObject *self, const char *isolevel,
const char *readonly, const char *deferrable, const char *readonly, const char *deferrable,
int autocommit); int autocommit);
HIDDEN int conn_set_autocommit(connectionObject *self, int value); HIDDEN int conn_set_autocommit(connectionObject *self, int value);
HIDDEN int conn_switch_isolation_level(connectionObject *self, int level); RAISES_NEG 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_set_client_encoding(connectionObject *self, const char *enc);
HIDDEN int conn_poll(connectionObject *self); HIDDEN int conn_poll(connectionObject *self);
HIDDEN int conn_tpc_begin(connectionObject *self, XidObject *xid); RAISES_NEG HIDDEN int conn_tpc_begin(connectionObject *self, XidObject *xid);
HIDDEN int conn_tpc_command(connectionObject *self, RAISES_NEG HIDDEN int conn_tpc_command(connectionObject *self,
const char *cmd, XidObject *xid); const char *cmd, XidObject *xid);
HIDDEN PyObject *conn_tpc_recover(connectionObject *self); HIDDEN PyObject *conn_tpc_recover(connectionObject *self);

View File

@ -120,8 +120,16 @@ conn_notice_process(connectionObject *self)
/* Respect the order in which notices were produced, /* Respect the order in which notices were produced,
because in notice_list they are reversed (see ticket #9) */ because in notice_list they are reversed (see ticket #9) */
PyList_Insert(self->notice_list, nnotices, msg); if (msg) {
Py_DECREF(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; notice = notice->next;
} }
@ -242,19 +250,20 @@ conn_get_standard_conforming_strings(PGconn *pgconn)
/* Remove irrelevant chars from encoding name and turn it uppercase. /* Remove irrelevant chars from encoding name and turn it uppercase.
* *
* Return a buffer allocated on Python heap, * Return a buffer allocated on Python heap into 'clean' and return 0 on
* NULL and set an exception on error. * success, otherwise return -1 and set an exception.
*/ */
static char * RAISES_NEG static int
clean_encoding_name(const char *enc) clear_encoding_name(const char *enc, char **clean)
{ {
const char *i = enc; const char *i = enc;
char *rv, *j; char *j, *buf;
int rv = -1;
/* convert to upper case and remove '-' and '_' from string */ /* 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(); PyErr_NoMemory();
return NULL; goto exit;
} }
while (*i) { while (*i) {
@ -267,25 +276,28 @@ clean_encoding_name(const char *enc)
} }
*j = '\0'; *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; return rv;
} }
/* Convert a PostgreSQL encoding to a Python codec. /* Convert a PostgreSQL encoding to a Python codec.
* *
* Return a new copy of the codec name allocated on the Python heap, * Set 'codec' to a new copy of the codec name allocated on the Python heap.
* NULL with exception in case of error. * Return 0 in case of success, else -1 and set an exception.
* *
* 'enc' should be already normalized (uppercase, no - or _). * 'enc' should be already normalized (uppercase, no - or _).
*/ */
static char * RAISES_NEG static int
conn_encoding_to_codec(const char *enc) conn_encoding_to_codec(const char *enc, char **codec)
{ {
char *tmp; char *tmp;
Py_ssize_t size; Py_ssize_t size;
PyObject *pyenc = NULL; PyObject *pyenc = NULL;
char *rv = NULL; int rv = -1;
/* Find the Py codec name from the PG encoding */ /* Find the Py codec name from the PG encoding */
if (!(pyenc = PyDict_GetItemString(psycoEncodings, enc))) { 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 */ /* have our own copy of the python codec name */
rv = psycopg_strdup(tmp, size); rv = psycopg_strdup(codec, tmp, size);
exit: exit:
Py_XDECREF(pyenc); Py_XDECREF(pyenc);
@ -320,7 +332,7 @@ exit:
* *
* Return 0 on success, else nonzero. * Return 0 on success, else nonzero.
*/ */
static int RAISES_NEG static int
conn_read_encoding(connectionObject *self, PGconn *pgconn) conn_read_encoding(connectionObject *self, PGconn *pgconn)
{ {
char *enc = NULL, *codec = NULL; char *enc = NULL, *codec = NULL;
@ -335,12 +347,12 @@ conn_read_encoding(connectionObject *self, PGconn *pgconn)
goto exit; goto exit;
} }
if (!(enc = clean_encoding_name(tmp))) { if (0 > clear_encoding_name(tmp, &enc)) {
goto exit; goto exit;
} }
/* Look for this encoding in Python codecs. */ /* Look for this encoding in Python codecs. */
if (!(codec = conn_encoding_to_codec(enc))) { if (0 > conn_encoding_to_codec(enc, &codec)) {
goto exit; goto exit;
} }
@ -362,7 +374,7 @@ exit:
} }
int RAISES_NEG int
conn_get_isolation_level(connectionObject *self) conn_get_isolation_level(connectionObject *self)
{ {
PGresult *pgres = NULL; PGresult *pgres = NULL;
@ -456,7 +468,7 @@ conn_is_datestyle_ok(PGconn *pgconn)
/* conn_setup - setup and read basic information about the connection */ /* conn_setup - setup and read basic information about the connection */
int RAISES_NEG int
conn_setup(connectionObject *self, PGconn *pgconn) conn_setup(connectionObject *self, PGconn *pgconn)
{ {
PGresult *pgres = NULL; PGresult *pgres = NULL;
@ -470,7 +482,7 @@ conn_setup(connectionObject *self, PGconn *pgconn)
return -1; return -1;
} }
if (conn_read_encoding(self, pgconn)) { if (0 > conn_read_encoding(self, pgconn)) {
return -1; return -1;
} }
@ -484,7 +496,7 @@ conn_setup(connectionObject *self, PGconn *pgconn)
pthread_mutex_lock(&self->lock); pthread_mutex_lock(&self->lock);
Py_BLOCK_THREADS; 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; return -1;
} }
@ -762,7 +774,7 @@ _conn_poll_setup_async(connectionObject *self)
switch (self->status) { switch (self->status) {
case CONN_STATUS_CONNECTING: case CONN_STATUS_CONNECTING:
/* Set the connection to nonblocking now. */ /* Set the connection to nonblocking now. */
if (pq_set_non_blocking(self, 1, 1) != 0) { if (pq_set_non_blocking(self, 1) != 0) {
break; break;
} }
@ -773,7 +785,7 @@ _conn_poll_setup_async(connectionObject *self)
PyErr_SetString(InterfaceError, "only protocol 3 supported"); PyErr_SetString(InterfaceError, "only protocol 3 supported");
break; break;
} }
if (conn_read_encoding(self, self->pgconn)) { if (0 > conn_read_encoding(self, self->pgconn)) {
break; break;
} }
self->cancel = conn_get_cancel(self->pgconn); self->cancel = conn_get_cancel(self->pgconn);
@ -942,7 +954,7 @@ conn_close(connectionObject *self)
/* conn_commit - commit on a connection */ /* conn_commit - commit on a connection */
int RAISES_NEG int
conn_commit(connectionObject *self) conn_commit(connectionObject *self)
{ {
int res; int res;
@ -953,7 +965,7 @@ conn_commit(connectionObject *self)
/* conn_rollback - rollback a connection */ /* conn_rollback - rollback a connection */
int RAISES_NEG int
conn_rollback(connectionObject *self) conn_rollback(connectionObject *self)
{ {
int res; int res;
@ -962,7 +974,7 @@ conn_rollback(connectionObject *self)
return res; return res;
} }
int RAISES_NEG int
conn_set_session(connectionObject *self, conn_set_session(connectionObject *self,
const char *isolevel, const char *readonly, const char *deferrable, const char *isolevel, const char *readonly, const char *deferrable,
int autocommit) int autocommit)
@ -1035,7 +1047,7 @@ conn_set_autocommit(connectionObject *self, int value)
/* conn_switch_isolation_level - switch isolation level on the connection */ /* conn_switch_isolation_level - switch isolation level on the connection */
int RAISES_NEG int
conn_switch_isolation_level(connectionObject *self, int level) conn_switch_isolation_level(connectionObject *self, int level)
{ {
PGresult *pgres = NULL; PGresult *pgres = NULL;
@ -1117,12 +1129,12 @@ endlock:
/* conn_set_client_encoding - switch client encoding on connection */ /* conn_set_client_encoding - switch client encoding on connection */
int RAISES_NEG int
conn_set_client_encoding(connectionObject *self, const char *enc) conn_set_client_encoding(connectionObject *self, const char *enc)
{ {
PGresult *pgres = NULL; PGresult *pgres = NULL;
char *error = NULL; char *error = NULL;
int res = 1; int res = -1;
char *codec = NULL; char *codec = NULL;
char *clean_enc = 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; if (strcmp(self->encoding, enc) == 0) return 0;
/* We must know what python codec this encoding is. */ /* We must know what python codec this encoding is. */
if (!(clean_enc = clean_encoding_name(enc))) { goto exit; } if (0 > clear_encoding_name(enc, &clean_enc)) { goto exit; }
if (!(codec = conn_encoding_to_codec(clean_enc))) { goto exit; } if (0 > conn_encoding_to_codec(clean_enc, &codec)) { goto exit; }
Py_BEGIN_ALLOW_THREADS; Py_BEGIN_ALLOW_THREADS;
pthread_mutex_lock(&self->lock); pthread_mutex_lock(&self->lock);
@ -1190,7 +1202,7 @@ exit:
* in regular transactions, as PostgreSQL won't even know we are in a TPC * in regular transactions, as PostgreSQL won't even know we are in a TPC
* until PREPARE. */ * until PREPARE. */
int RAISES_NEG int
conn_tpc_begin(connectionObject *self, XidObject *xid) conn_tpc_begin(connectionObject *self, XidObject *xid)
{ {
PGresult *pgres = NULL; 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 * The function doesn't change the connection state as it can be used
* for many commands and for recovered transactions. */ * for many commands and for recovered transactions. */
int RAISES_NEG int
conn_tpc_command(connectionObject *self, const char *cmd, XidObject *xid) conn_tpc_command(connectionObject *self, const char *cmd, XidObject *xid)
{ {
PGresult *pgres = NULL; PGresult *pgres = NULL;

View File

@ -526,7 +526,7 @@ psyco_conn_set_session(connectionObject *self, PyObject *args, PyObject *kwargs)
if (-1 == c_autocommit) { return NULL; } 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)) { c_isolevel, c_readonly, c_deferrable, c_autocommit)) {
return NULL; return NULL;
} }
@ -548,7 +548,7 @@ psyco_conn_autocommit_get(connectionObject *self)
return ret; return ret;
} }
static PyObject * BORROWED static PyObject *
_psyco_conn_autocommit_set_checks(connectionObject *self) _psyco_conn_autocommit_set_checks(connectionObject *self)
{ {
/* wrapper to use the EXC_IF macros. /* 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 (!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); Py_INCREF(Py_None);
rv = Py_None; rv = Py_None;
} }
@ -699,8 +699,8 @@ psyco_conn_get_parameter_status(connectionObject *self, PyObject *args)
static PyObject * static PyObject *
psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds) psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds)
{ {
Oid oid=InvalidOid, new_oid=InvalidOid; int oid = (int)InvalidOid, new_oid = (int)InvalidOid;
char *new_file = NULL; const char *new_file = NULL;
const char *smode = ""; const char *smode = "";
PyObject *factory = (PyObject *)&lobjectType; PyObject *factory = (PyObject *)&lobjectType;
PyObject *obj; PyObject *obj;
@ -752,7 +752,7 @@ psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds)
"get_backend_pid() -- Get backend process id." "get_backend_pid() -- Get backend process id."
static PyObject * static PyObject *
psyco_conn_get_backend_pid(connectionObject *self) psyco_conn_get_backend_pid(connectionObject *self, PyObject *args)
{ {
EXC_IF_CONN_CLOSED(self); EXC_IF_CONN_CLOSED(self);
@ -765,7 +765,7 @@ psyco_conn_get_backend_pid(connectionObject *self)
"reset() -- Reset current connection to defaults." "reset() -- Reset current connection to defaults."
static PyObject * static PyObject *
psyco_conn_reset(connectionObject *self) psyco_conn_reset(connectionObject *self, PyObject *args)
{ {
int res; int res;
@ -793,7 +793,7 @@ psyco_conn_get_exception(PyObject *self, void *closure)
} }
static PyObject * static PyObject *
psyco_conn_poll(connectionObject *self) psyco_conn_poll(connectionObject *self, PyObject *args)
{ {
int res; int res;
@ -815,7 +815,7 @@ psyco_conn_poll(connectionObject *self)
"fileno() -> int -- Return file descriptor associated to database connection." "fileno() -> int -- Return file descriptor associated to database connection."
static PyObject * static PyObject *
psyco_conn_fileno(connectionObject *self) psyco_conn_fileno(connectionObject *self, PyObject *args)
{ {
long int socket; long int socket;
@ -834,7 +834,7 @@ psyco_conn_fileno(connectionObject *self)
"executing an asynchronous operation." "executing an asynchronous operation."
static PyObject * static PyObject *
psyco_conn_isexecuting(connectionObject *self) psyco_conn_isexecuting(connectionObject *self, PyObject *args)
{ {
/* synchronous connections will always return False */ /* synchronous connections will always return False */
if (self->async == 0) { if (self->async == 0) {
@ -866,7 +866,7 @@ psyco_conn_isexecuting(connectionObject *self)
"cancel() -- cancel the current operation" "cancel() -- cancel the current operation"
static PyObject * static PyObject *
psyco_conn_cancel(connectionObject *self) psyco_conn_cancel(connectionObject *self, PyObject *args)
{ {
char errbuf[256]; char errbuf[256];

View File

@ -85,7 +85,7 @@ struct cursorObject {
/* C-callable functions in cursor_int.c and cursor_ext.c */ /* 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); HIDDEN void curs_reset(cursorObject *self);
/* exception-raising macros */ /* exception-raising macros */

View File

@ -38,7 +38,7 @@
* Return a borrowed reference. * Return a borrowed reference.
*/ */
PyObject * BORROWED PyObject *
curs_get_cast(cursorObject *self, PyObject *oid) curs_get_cast(cursorObject *self, PyObject *oid)
{ {
PyObject *cast; PyObject *cast;

View File

@ -79,7 +79,7 @@ exit:
/* mogrify a query string and build argument array or dict */ /* 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) _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new)
{ {
PyObject *key, *value, *n; PyObject *key, *value, *n;
@ -221,7 +221,10 @@ _mogrify(PyObject *var, PyObject *fmt, cursorObject *curs, PyObject **new)
} }
if (n == NULL) { 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 '%' */ /* let's have d point just after the '%' */
@ -360,11 +363,12 @@ _psyco_curs_merge_query_args(cursorObject *self,
#define psyco_curs_execute_doc \ #define psyco_curs_execute_doc \
"execute(query, vars=None) -- Execute query with bound vars." "execute(query, vars=None) -- Execute query with bound vars."
static int RAISES_NEG static int
_psyco_curs_execute(cursorObject *self, _psyco_curs_execute(cursorObject *self,
PyObject *operation, PyObject *vars, long int async) PyObject *operation, PyObject *vars, long int async)
{ {
int res = 0; int res = -1;
int tmp;
PyObject *fquery, *cvt = NULL; PyObject *fquery, *cvt = NULL;
operation = _psyco_curs_validate_sql_basic(self, operation); 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' /* Any failure from here forward should 'goto fail' rather than 'return 0'
directly. */ directly. */
if (operation == NULL) { goto fail; } if (operation == NULL) { goto exit; }
IFCLEARPGRES(self->pgres); IFCLEARPGRES(self->pgres);
@ -389,12 +393,12 @@ _psyco_curs_execute(cursorObject *self,
if (vars && vars != Py_None) 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 (vars && cvt) {
if (!(fquery = _psyco_curs_merge_query_args(self, operation, cvt))) { if (!(fquery = _psyco_curs_merge_query_args(self, operation, cvt))) {
goto fail; goto exit;
} }
if (self->name != NULL) { if (self->name != NULL) {
@ -428,25 +432,20 @@ _psyco_curs_execute(cursorObject *self,
/* At this point, the SQL statement must be str, not unicode */ /* At this point, the SQL statement must be str, not unicode */
res = pq_execute(self, Bytes_AS_STRING(self->query), async); tmp = pq_execute(self, Bytes_AS_STRING(self->query), async);
Dprintf("psyco_curs_execute: res = %d, pgres = %p", res, self->pgres); Dprintf("psyco_curs_execute: res = %d, pgres = %p", tmp, self->pgres);
if (res == -1) { goto fail; } if (tmp < 0) { goto exit; }
res = 1; /* Success */ res = 0; /* Success */
goto cleanup;
fail: exit:
res = 0; /* Py_XDECREF(operation) is safe because the original reference passed
/* Fall through to cleanup */ by the caller was overwritten with either NULL or a new
cleanup: reference */
/* Py_XDECREF(operation) is safe because the original reference passed Py_XDECREF(operation);
by the caller was overwritten with either NULL or a new Py_XDECREF(cvt);
reference */
Py_XDECREF(operation);
Py_XDECREF(cvt); return res;
return res;
} }
static PyObject * static PyObject *
@ -480,13 +479,13 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs)
EXC_IF_ASYNC_IN_PROGRESS(self, execute); EXC_IF_ASYNC_IN_PROGRESS(self, execute);
EXC_IF_TPC_PREPARED(self->conn, execute); EXC_IF_TPC_PREPARED(self->conn, execute);
if (_psyco_curs_execute(self, operation, vars, self->conn->async)) { if (0 > _psyco_curs_execute(self, operation, vars, self->conn->async)) {
Py_INCREF(Py_None);
return Py_None;
}
else {
return NULL; return NULL;
} }
/* success */
Py_INCREF(Py_None);
return Py_None;
} }
#define psyco_curs_executemany_doc \ #define psyco_curs_executemany_doc \
@ -525,7 +524,7 @@ psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs)
} }
while ((v = PyIter_Next(vars)) != NULL) { 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_DECREF(v);
Py_XDECREF(iter); Py_XDECREF(iter);
return NULL; return NULL;
@ -572,7 +571,7 @@ _psyco_curs_mogrify(cursorObject *self,
if (vars && vars != Py_None) if (vars && vars != Py_None)
{ {
if (_mogrify(vars, operation, self, &cvt) == -1) { if (0 > _mogrify(vars, operation, self, &cvt)) {
goto cleanup; goto cleanup;
} }
} }
@ -648,7 +647,7 @@ psyco_curs_cast(cursorObject *self, PyObject *args)
"default) or using the sequence factory previously set in the\n" \ "default) or using the sequence factory previously set in the\n" \
"`row_factory` attribute. Return `!None` when no more data is available.\n" "`row_factory` attribute. Return `!None` when no more data is available.\n"
static int RAISES_NEG static int
_psyco_curs_prefetch(cursorObject *self) _psyco_curs_prefetch(cursorObject *self)
{ {
int i = 0; int i = 0;
@ -665,13 +664,14 @@ _psyco_curs_prefetch(cursorObject *self)
return i; return i;
} }
static PyObject * RAISES_NEG static int
_psyco_curs_buildrow_fill(cursorObject *self, PyObject *res, _psyco_curs_buildrow_fill(cursorObject *self, PyObject *res,
int row, int n, int istuple) int row, int n, int istuple)
{ {
int i, len, err; int i, len, err;
const char *str; const char *str;
PyObject *val; PyObject *val;
int rv = -1;
for (i=0; i < n; i++) { for (i=0; i < n; i++) {
if (PQgetisnull(self->pgres, row, 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", Dprintf("_psyco_curs_buildrow: row %ld, element %d, len %d",
self->row, i, len); self->row, i, len);
val = typecast_cast(PyTuple_GET_ITEM(self->casts, i), str, len, if (!(val = typecast_cast(PyTuple_GET_ITEM(self->casts, i), str, len,
(PyObject*)self); (PyObject*)self))) {
goto exit;
}
if (val) { Dprintf("_psyco_curs_buildrow: val->refcnt = "
Dprintf("_psyco_curs_buildrow: val->refcnt = " FORMAT_CODE_PY_SSIZE_T,
FORMAT_CODE_PY_SSIZE_T, Py_REFCNT(val)
Py_REFCNT(val) );
); if (istuple) {
if (istuple) { PyTuple_SET_ITEM(res, i, val);
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;
}
}
} }
else { else {
/* an error occurred in the type system, we return NULL to raise err = PySequence_SetItem(res, i, val);
an exception. the typecast code should already have set the Py_DECREF(val);
exception type and text */ if (err == -1) { goto exit; }
Py_DECREF(res);
res = NULL;
break;
} }
} }
return res;
rv = 0;
exit:
return rv;
} }
static PyObject * static PyObject *
_psyco_curs_buildrow(cursorObject *self, int row) _psyco_curs_buildrow(cursorObject *self, int row)
{ {
int n; int n;
int istuple;
PyObject *t = NULL;
PyObject *rv = NULL;
n = PQnfields(self->pgres); n = PQnfields(self->pgres);
return _psyco_curs_buildrow_fill(self, PyTuple_New(n), row, n, 1); istuple = (self->tuple_factory == Py_None);
}
static PyObject * if (istuple) {
_psyco_curs_buildrow_with_factory(cursorObject *self, int row) t = PyTuple_New(n);
{ }
int n; else {
PyObject *res; t = PyObject_CallFunctionObjArgs(self->tuple_factory, self, NULL);
}
if (!t) { goto exit; }
n = PQnfields(self->pgres); if (0 <= _psyco_curs_buildrow_fill(self, t, row, n, istuple)) {
if (!(res = PyObject_CallFunctionObjArgs(self->tuple_factory, self, NULL))) rv = t;
return NULL; t = NULL;
}
exit:
Py_XDECREF(t);
return rv;
return _psyco_curs_buildrow_fill(self, res, row, n, 0);
} }
static PyObject * static PyObject *
@ -770,11 +770,7 @@ psyco_curs_fetchone(cursorObject *self, PyObject *args)
return Py_None; return Py_None;
} }
if (self->tuple_factory == Py_None) res = _psyco_curs_buildrow(self, self->row);
res = _psyco_curs_buildrow(self, self->row);
else
res = _psyco_curs_buildrow_with_factory(self, self->row);
self->row++; /* move the counter to next line */ self->row++; /* move the counter to next line */
/* if the query was async aggresively free pgres, to allow /* if the query was async aggresively free pgres, to allow
@ -821,11 +817,7 @@ psyco_curs_next_named(cursorObject *self)
return NULL; return NULL;
} }
if (self->tuple_factory == Py_None) res = _psyco_curs_buildrow(self, self->row);
res = _psyco_curs_buildrow(self, self->row);
else
res = _psyco_curs_buildrow_with_factory(self, self->row);
self->row++; /* move the counter to next line */ self->row++; /* move the counter to next line */
/* if the query was async aggresively free pgres, to allow /* 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) psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords)
{ {
int i; int i;
PyObject *list, *res; PyObject *list = NULL;
PyObject *row = NULL;
PyObject *rv = NULL;
PyObject *pysize = NULL; PyObject *pysize = NULL;
long int size = self->arraysize; 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); EXC_IF_TPC_PREPARED(self->conn, fetchone);
PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM \"%s\"", PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM \"%s\"",
(int)size, self->name); (int)size, self->name);
if (pq_execute(self, buffer, 0) == -1) return NULL; if (pq_execute(self, buffer, 0) == -1) { goto exit; }
if (_psyco_curs_prefetch(self) < 0) return NULL; if (_psyco_curs_prefetch(self) < 0) { goto exit; }
} }
/* make sure size is not > than the available number of rows */ /* 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); Dprintf("psyco_curs_fetchmany: size = %ld", size);
if (size <= 0) { 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++) { for (i = 0; i < size; i++) {
if (self->tuple_factory == Py_None) row = _psyco_curs_buildrow(self, self->row);
res = _psyco_curs_buildrow(self, self->row);
else
res = _psyco_curs_buildrow_with_factory(self, self->row);
self->row++; self->row++;
if (res == NULL) { if (row == NULL) { goto exit; }
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 /* if the query was async aggresively free pgres, to allow
successive requests to reallocate it */ 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) && PyWeakref_GetObject(self->conn->async_cursor) == (PyObject*)self)
IFCLEARPGRES(self->pgres); 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) psyco_curs_fetchall(cursorObject *self, PyObject *args)
{ {
int i, size; int i, size;
PyObject *list, *res; PyObject *list = NULL;
PyObject *row = NULL;
PyObject *rv = NULL;
EXC_IF_CURS_CLOSED(self); EXC_IF_CURS_CLOSED(self);
if (_psyco_curs_prefetch(self) < 0) return NULL; 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_ASYNC_IN_PROGRESS(self, fetchall);
EXC_IF_TPC_PREPARED(self->conn, fetchall); EXC_IF_TPC_PREPARED(self->conn, fetchall);
PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM \"%s\"", self->name); PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM \"%s\"", self->name);
if (pq_execute(self, buffer, 0) == -1) return NULL; if (pq_execute(self, buffer, 0) == -1) { goto exit; }
if (_psyco_curs_prefetch(self) < 0) return NULL; if (_psyco_curs_prefetch(self) < 0) { goto exit; }
} }
size = self->rowcount - self->row; size = self->rowcount - self->row;
if (size <= 0) { 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++) { for (i = 0; i < size; i++) {
if (self->tuple_factory == Py_None) row = _psyco_curs_buildrow(self, self->row);
res = _psyco_curs_buildrow(self, self->row);
else
res = _psyco_curs_buildrow_with_factory(self, self->row);
self->row++; self->row++;
if (row == NULL) { goto exit; }
if (res == NULL) { PyList_SET_ITEM(list, i, row);
Py_DECREF(list);
return NULL;
}
PyList_SET_ITEM(list, i, res);
} }
row = NULL;
/* if the query was async aggresively free pgres, to allow /* if the query was async aggresively free pgres, to allow
successive requests to reallocate it */ successive requests to reallocate it */
@ -988,7 +981,15 @@ psyco_curs_fetchall(cursorObject *self, PyObject *args)
&& PyWeakref_GetObject(self->conn->async_cursor) == (PyObject*)self) && PyWeakref_GetObject(self->conn->async_cursor) == (PyObject*)self)
IFCLEARPGRES(self->pgres); 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." "callproc(procname, parameters=None) -- Execute stored procedure."
static PyObject * static PyObject *
psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs) psyco_curs_callproc(cursorObject *self, PyObject *args)
{ {
const char *procname = NULL; const char *procname = NULL;
char *sql = NULL; char *sql = NULL;
@ -1010,7 +1011,7 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
if (!PyArg_ParseTuple(args, "s#|O", if (!PyArg_ParseTuple(args, "s#|O",
&procname, &procname_len, &parameters &procname, &procname_len, &parameters
)) ))
{ return NULL; } { goto exit; }
EXC_IF_CURS_CLOSED(self); EXC_IF_CURS_CLOSED(self);
EXC_IF_ASYNC_IN_PROGRESS(self, callproc); EXC_IF_ASYNC_IN_PROGRESS(self, callproc);
@ -1019,10 +1020,10 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
if (self->name != NULL) { if (self->name != NULL) {
psyco_set_error(ProgrammingError, self, psyco_set_error(ProgrammingError, self,
"can't call .callproc() on named cursors", NULL, NULL); "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); nparameters = PyObject_Length(parameters);
if (nparameters < 0) nparameters = 0; 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); sl = procname_len + 17 + nparameters*3 - (nparameters ? 1 : 0);
sql = (char*)PyMem_Malloc(sl); sql = (char*)PyMem_Malloc(sl);
if (sql == NULL) { if (sql == NULL) {
return PyErr_NoMemory(); PyErr_NoMemory();
goto exit;
} }
sprintf(sql, "SELECT * FROM %s(", procname); sprintf(sql, "SELECT * FROM %s(", procname);
@ -1041,15 +1043,16 @@ psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs)
sql[sl-2] = ')'; sql[sl-2] = ')';
sql[sl-1] = '\0'; sql[sl-1] = '\0';
operation = Bytes_FromString(sql); if (!(operation = Bytes_FromString(sql))) { goto exit; }
PyMem_Free((void*)sql);
if (_psyco_curs_execute(self, operation, parameters, self->conn->async)) { if (0 <= _psyco_curs_execute(self, operation, parameters, self->conn->async)) {
Py_INCREF(parameters); Py_INCREF(parameters);
res = parameters; res = parameters;
} }
Py_DECREF(operation); exit:
Py_XDECREF(operation);
PyMem_Free((void*)sql);
return res; return res;
} }
@ -1206,6 +1209,7 @@ static char *_psyco_curs_copy_columns(PyObject *columns)
} }
if (NULL == (columnlist = PyMem_Malloc(bufsize))) { if (NULL == (columnlist = PyMem_Malloc(bufsize))) {
Py_DECREF(coliter);
PyErr_NoMemory(); PyErr_NoMemory();
goto error; goto error;
} }
@ -1262,8 +1266,8 @@ exit:
#define psyco_curs_copy_from_doc \ #define psyco_curs_copy_from_doc \
"copy_from(file, table, sep='\\t', null='\\\\N', size=8192, columns=None) -- Copy table from file." "copy_from(file, table, sep='\\t', null='\\\\N', size=8192, columns=None) -- Copy table from file."
static int STEALS(1) static int
_psyco_curs_has_read_check(PyObject* o, void* var) _psyco_curs_has_read_check(PyObject *o, PyObject **var)
{ {
if (PyObject_HasAttrString(o, "readline") if (PyObject_HasAttrString(o, "readline")
&& PyObject_HasAttrString(o, "read")) { && 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 * which could invoke the garbage collector. We thus need an
* INCREF/DECREF pair if we store this pointer in a GC object, such as * INCREF/DECREF pair if we store this pointer in a GC object, such as
* a cursorObject */ * a cursorObject */
*((PyObject**)var) = o; *var = o;
return 1; return 1;
} }
else { else {
@ -1348,7 +1352,7 @@ psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs)
Py_INCREF(file); Py_INCREF(file);
self->copyfile = file; self->copyfile = file;
if (pq_execute(self, query, 0) == 1) { if (pq_execute(self, query, 0) >= 0) {
res = Py_None; res = Py_None;
Py_INCREF(Py_None); Py_INCREF(Py_None);
} }
@ -1369,11 +1373,11 @@ exit:
#define psyco_curs_copy_to_doc \ #define psyco_curs_copy_to_doc \
"copy_to(file, table, sep='\\t', null='\\\\N', columns=None) -- Copy table to file." "copy_to(file, table, sep='\\t', null='\\\\N', columns=None) -- Copy table to file."
static int STEALS(1) static int
_psyco_curs_has_write_check(PyObject* o, void* var) _psyco_curs_has_write_check(PyObject *o, PyObject **var)
{ {
if (PyObject_HasAttrString(o, "write")) { if (PyObject_HasAttrString(o, "write")) {
*((PyObject**)var) = o; *var = o;
return 1; return 1;
} }
else { else {
@ -1444,7 +1448,7 @@ psyco_curs_copy_to(cursorObject *self, PyObject *args, PyObject *kwargs)
Py_INCREF(file); Py_INCREF(file);
self->copyfile = file; self->copyfile = file;
if (pq_execute(self, query, 0) == 1) { if (pq_execute(self, query, 0) >= 0) {
res = Py_None; res = Py_None;
Py_INCREF(Py_None); Py_INCREF(Py_None);
} }
@ -1518,7 +1522,7 @@ psyco_curs_copy_expert(cursorObject *self, PyObject *args, PyObject *kwargs)
self->copyfile = file; self->copyfile = file;
/* At this point, the SQL statement must be str, not unicode */ /* 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; res = Py_None;
Py_INCREF(res); Py_INCREF(res);
} }

View File

@ -51,19 +51,19 @@ typedef struct {
/* functions exported from lobject_int.c */ /* functions exported from lobject_int.c */
HIDDEN int lobject_open(lobjectObject *self, connectionObject *conn, RAISES_NEG HIDDEN int lobject_open(lobjectObject *self, connectionObject *conn,
Oid oid, const char *smode, Oid new_oid, Oid oid, const char *smode, Oid new_oid,
const char *new_file); const char *new_file);
HIDDEN int lobject_unlink(lobjectObject *self); RAISES_NEG HIDDEN int lobject_unlink(lobjectObject *self);
HIDDEN int lobject_export(lobjectObject *self, const char *filename); RAISES_NEG HIDDEN int lobject_export(lobjectObject *self, const char *filename);
HIDDEN Py_ssize_t lobject_read(lobjectObject *self, char *buf, size_t len); RAISES_NEG 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_write(lobjectObject *self, const char *buf,
size_t len); size_t len);
HIDDEN int lobject_seek(lobjectObject *self, int pos, int whence); RAISES_NEG HIDDEN int lobject_seek(lobjectObject *self, int pos, int whence);
HIDDEN int lobject_tell(lobjectObject *self); RAISES_NEG HIDDEN int lobject_tell(lobjectObject *self);
HIDDEN int lobject_truncate(lobjectObject *self, size_t len); RAISES_NEG HIDDEN int lobject_truncate(lobjectObject *self, size_t len);
HIDDEN int lobject_close(lobjectObject *self); RAISES_NEG HIDDEN int lobject_close(lobjectObject *self);
#define lobject_is_closed(self) \ #define lobject_is_closed(self) \
((self)->fd < 0 || !(self)->conn || (self)->conn->closed) ((self)->fd < 0 || !(self)->conn || (self)->conn->closed)

View File

@ -50,7 +50,7 @@ collect_error(connectionObject *conn, char **error)
* *
* Valid mode are [r|w|rw|n][t|b] * Valid mode are [r|w|rw|n][t|b]
*/ */
static int RAISES_NEG static int
_lobject_parse_mode(const char *mode) _lobject_parse_mode(const char *mode)
{ {
int rv = 0; int rv = 0;
@ -147,7 +147,7 @@ _lobject_unparse_mode(int mode)
/* lobject_open - create a new/open an existing lo */ /* lobject_open - create a new/open an existing lo */
int RAISES_NEG int
lobject_open(lobjectObject *self, connectionObject *conn, lobject_open(lobjectObject *self, connectionObject *conn,
Oid oid, const char *smode, Oid new_oid, const char *new_file) 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 */ /* lobject_close - close an existing lo */
static int RAISES_NEG static int
lobject_close_locked(lobjectObject *self, char **error) lobject_close_locked(lobjectObject *self, char **error)
{ {
int retvalue; int retvalue;
@ -270,7 +270,7 @@ lobject_close_locked(lobjectObject *self, char **error)
return retvalue; return retvalue;
} }
int RAISES_NEG int
lobject_close(lobjectObject *self) lobject_close(lobjectObject *self)
{ {
PGresult *pgres = NULL; PGresult *pgres = NULL;
@ -292,7 +292,7 @@ lobject_close(lobjectObject *self)
/* lobject_unlink - remove an lo from database */ /* lobject_unlink - remove an lo from database */
int RAISES_NEG int
lobject_unlink(lobjectObject *self) lobject_unlink(lobjectObject *self)
{ {
PGresult *pgres = NULL; PGresult *pgres = NULL;
@ -326,7 +326,7 @@ lobject_unlink(lobjectObject *self)
/* lobject_write - write bytes to a lo */ /* 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) lobject_write(lobjectObject *self, const char *buf, size_t len)
{ {
Py_ssize_t written; 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 */ /* lobject_read - read bytes from a lo */
Py_ssize_t RAISES_NEG Py_ssize_t
lobject_read(lobjectObject *self, char *buf, size_t len) lobject_read(lobjectObject *self, char *buf, size_t len)
{ {
Py_ssize_t n_read; 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 */ /* lobject_seek - move the current position in the lo */
int RAISES_NEG int
lobject_seek(lobjectObject *self, int pos, int whence) lobject_seek(lobjectObject *self, int pos, int whence)
{ {
PGresult *pgres = NULL; PGresult *pgres = NULL;
@ -405,7 +405,7 @@ lobject_seek(lobjectObject *self, int pos, int whence)
/* lobject_tell - tell the current position in the lo */ /* lobject_tell - tell the current position in the lo */
int RAISES_NEG int
lobject_tell(lobjectObject *self) lobject_tell(lobjectObject *self)
{ {
PGresult *pgres = NULL; PGresult *pgres = NULL;
@ -432,7 +432,7 @@ lobject_tell(lobjectObject *self)
/* lobject_export - export to a local file */ /* lobject_export - export to a local file */
int RAISES_NEG int
lobject_export(lobjectObject *self, const char *filename) lobject_export(lobjectObject *self, const char *filename)
{ {
PGresult *pgres = NULL; PGresult *pgres = NULL;
@ -461,7 +461,7 @@ lobject_export(lobjectObject *self, const char *filename)
#if PG_VERSION_HEX >= 0x080300 #if PG_VERSION_HEX >= 0x080300
int RAISES_NEG int
lobject_truncate(lobjectObject *self, size_t len) lobject_truncate(lobjectObject *self, size_t len)
{ {
int retvalue; int retvalue;

View File

@ -373,7 +373,7 @@ lobject_dealloc(PyObject* obj)
static int static int
lobject_init(PyObject *obj, PyObject *args, PyObject *kwds) 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 *smode = "";
const char *new_file = NULL; const char *new_file = NULL;
PyObject *conn; PyObject *conn;
@ -383,7 +383,7 @@ lobject_init(PyObject *obj, PyObject *args, PyObject *kwds)
return -1; return -1;
return lobject_setup((lobjectObject *)obj, 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 * static PyObject *

View File

@ -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 int
microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast) microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast)
{ {
PyObject *key; PyObject *key = NULL;
int rv = -1;
if (proto == NULL) proto = (PyObject*)&isqlquoteType; if (proto == NULL) proto = (PyObject*)&isqlquoteType;
Dprintf("microprotocols_add: cast %p for (%s, ?)", cast, type->tp_name); Dprintf("microprotocols_add: cast %p for (%s, ?)", cast, type->tp_name);
key = PyTuple_Pack(2, (PyObject*)type, proto); if (!(key = PyTuple_Pack(2, (PyObject*)type, proto))) { goto exit; }
PyDict_SetItem(psyco_adapters, key, cast); if (0 != PyDict_SetItem(psyco_adapters, key, cast)) { goto exit; }
Py_DECREF(key);
return 0; rv = 0;
exit:
Py_XDECREF(key);
return rv;
} }
/* Check if one of `obj` superclasses has an adapter for `proto`. /* 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) _get_superclass_adapter(PyObject *obj, PyObject *proto)
{ {
PyTypeObject *type; PyTypeObject *type;
@ -89,14 +95,14 @@ _get_superclass_adapter(PyObject *obj, PyObject *proto)
#endif #endif
type->tp_mro)) { type->tp_mro)) {
/* has no mro */ /* has no mro */
return NULL; return Py_None;
} }
/* Walk the mro from the most specific subclass. */ /* Walk the mro from the most specific subclass. */
mro = type->tp_mro; mro = type->tp_mro;
for (i = 1, ii = PyTuple_GET_SIZE(mro); i < ii; ++i) { for (i = 1, ii = PyTuple_GET_SIZE(mro); i < ii; ++i) {
st = PyTuple_GET_ITEM(mro, 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); adapter = PyDict_GetItem(psyco_adapters, key);
Py_DECREF(key); Py_DECREF(key);
@ -119,7 +125,7 @@ _get_superclass_adapter(PyObject *obj, PyObject *proto)
return adapter; return adapter;
} }
} }
return NULL; return Py_None;
} }
@ -139,7 +145,7 @@ microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt)
Py_TYPE(obj)->tp_name); Py_TYPE(obj)->tp_name);
/* look for an adapter in the registry */ /* 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); adapter = PyDict_GetItem(psyco_adapters, key);
Py_DECREF(key); Py_DECREF(key);
if (adapter) { 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. */ /* 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); adapted = PyObject_CallFunctionObjArgs(adapter, obj, NULL);
return adapted; return adapted;
} }

View File

@ -64,7 +64,7 @@ strip_severity(const char *msg)
code. A list of error codes can be found at: code. A list of error codes can be found at:
http://www.postgresql.org/docs/current/static/errcodes-appendix.html */ http://www.postgresql.org/docs/current/static/errcodes-appendix.html */
static PyObject * BORROWED static PyObject *
exception_from_sqlstate(const char *sqlstate) exception_from_sqlstate(const char *sqlstate)
{ {
switch (sqlstate[0]) { switch (sqlstate[0]) {
@ -151,7 +151,7 @@ exception_from_sqlstate(const char *sqlstate)
This function should be called while holding the GIL. */ This function should be called while holding the GIL. */
static void RAISES static void
pq_raise(connectionObject *conn, cursorObject *curs, PGresult *pgres) pq_raise(connectionObject *conn, cursorObject *curs, PGresult *pgres)
{ {
PyObject *exc = NULL; PyObject *exc = NULL;
@ -164,7 +164,7 @@ pq_raise(connectionObject *conn, cursorObject *curs, PGresult *pgres)
"psycopg went psycotic and raised a null error"); "psycopg went psycotic and raised a null error");
return; return;
} }
/* if the connection has somehow beed broken, we mark the connection /* if the connection has somehow beed broken, we mark the connection
object as closed but requiring cleanup */ object as closed but requiring cleanup */
if (conn->pgconn != NULL && PQstatus(conn->pgconn) == CONNECTION_BAD) 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) pq_resolve_critical(connectionObject *conn, int close)
{ {
Dprintf("pq_resolve_critical: resolving %s", conn->critical); 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 */ /* we don't want to destroy this connection but just close it */
if (close == 1) conn_close(conn); if (close == 1) conn_close(conn);
/* remember to clear the critical! */ /* 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 /* 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). Accepted arg values are 1 (nonblocking) and 0 (blocking).
Return 0 if everything ok, else nonzero. Return 0 if everything ok, else < 0 and set an exception.
In case of error, if pyerr is nonzero, set a Python exception.
*/ */
int RAISES_NEG int
pq_set_non_blocking(connectionObject *conn, int arg, int pyerr) pq_set_non_blocking(connectionObject *conn, int arg)
{ {
int ret = PQsetnonblocking(conn->pgconn, arg); int ret = PQsetnonblocking(conn->pgconn, arg);
if (0 != ret) { if (0 != ret) {
Dprintf("PQsetnonblocking(%d) FAILED", arg); Dprintf("PQsetnonblocking(%d) FAILED", arg);
if (pyerr) { PyErr_SetString(OperationalError, "PQsetnonblocking() failed");
PyErr_SetString(OperationalError, "PQsetnonblocking() failed"); ret = -1;
}
} }
return ret; return ret;
} }
@ -382,7 +383,7 @@ cleanup:
This function should be called while holding the global interpreter This function should be called while holding the global interpreter
lock. lock.
*/ */
void RAISES void
pq_complete_error(connectionObject *conn, PGresult **pgres, char **error) pq_complete_error(connectionObject *conn, PGresult **pgres, char **error)
{ {
Dprintf("pq_complete_error: pgconn = %p, pgres = %p, error = %s", Dprintf("pq_complete_error: pgconn = %p, pgres = %p, error = %s",
@ -476,7 +477,7 @@ pq_commit(connectionObject *conn)
return retvalue; return retvalue;
} }
int RAISES_NEG int
pq_abort_locked(connectionObject *conn, PGresult **pgres, char **error, pq_abort_locked(connectionObject *conn, PGresult **pgres, char **error,
PyThreadState **tstate) 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 This function should be called while holding the global interpreter
lock. */ lock. */
int RAISES_NEG int
pq_abort(connectionObject *conn) pq_abort(connectionObject *conn)
{ {
int retvalue = -1; int retvalue = -1;
@ -540,7 +541,7 @@ pq_abort(connectionObject *conn)
connection without holding the global interpreter lock. connection without holding the global interpreter lock.
*/ */
int RAISES_NEG int
pq_reset_locked(connectionObject *conn, PGresult **pgres, char **error, pq_reset_locked(connectionObject *conn, PGresult **pgres, char **error,
PyThreadState **tstate) PyThreadState **tstate)
{ {
@ -832,7 +833,7 @@ pq_flush(connectionObject *conn)
this fucntion locks the connection object this fucntion locks the connection object
this function call Py_*_ALLOW_THREADS macros */ this function call Py_*_ALLOW_THREADS macros */
int RAISES_NEG int
pq_execute(cursorObject *curs, const char *query, int async) pq_execute(cursorObject *curs, const char *query, int async)
{ {
PGresult *pgres = NULL; 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 /* if the status of the connection is critical raise an exception and
definitely close the connection */ definitely close the connection */
if (curs->conn->critical) { if (curs->conn->critical) {
pq_resolve_critical(curs->conn, 1); return pq_resolve_critical(curs->conn, 1);
return -1;
} }
/* check status of connection, raise error if not OK */ /* 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 */ to respect the old DBAPI-2.0 compatible behaviour */
if (async == 0) { if (async == 0) {
Dprintf("pq_execute: entering syncronous DBAPI compatibility mode"); Dprintf("pq_execute: entering syncronous DBAPI compatibility mode");
if (pq_fetch(curs) == -1) return -1; if (pq_fetch(curs) < 0) return -1;
} }
else { else {
PyObject *tmp;
curs->conn->async_status = async_status; curs->conn->async_status = async_status;
curs->conn->async_cursor = PyWeakref_NewRef((PyObject *)curs, NULL); curs->conn->async_cursor = tmp = PyWeakref_NewRef((PyObject *)curs, NULL);
if (!curs->conn->async_cursor) { if (!tmp) {
/* weakref creation failed */ /* weakref creation failed */
return -1; return -1;
} }
@ -1012,7 +1013,7 @@ pq_get_last_result(connectionObject *conn)
1 - result from backend (possibly data is ready) 1 - result from backend (possibly data is ready)
*/ */
static int RAISES_NEG static int
_pq_fetch_tuples(cursorObject *curs) _pq_fetch_tuples(cursorObject *curs)
{ {
int i, *dsize = NULL; int i, *dsize = NULL;
@ -1412,8 +1413,7 @@ pq_fetch(cursorObject *curs)
Dprintf("pq_fetch: got a NULL pgres, checking for critical"); Dprintf("pq_fetch: got a NULL pgres, checking for critical");
pq_set_critical(curs->conn); pq_set_critical(curs->conn);
if (curs->conn->critical) { if (curs->conn->critical) {
pq_resolve_critical(curs->conn); return pq_resolve_critical(curs->conn);
return -1;
} }
else { else {
return 0; return 0;
@ -1489,13 +1489,7 @@ pq_fetch(cursorObject *curs)
raise the exception but we avoid to close the connection) */ raise the exception but we avoid to close the connection) */
Dprintf("pq_fetch: fetching done; check for critical errors"); Dprintf("pq_fetch: fetching done; check for critical errors");
if (curs->conn->critical) { if (curs->conn->critical) {
if (ex == -1) { return pq_resolve_critical(curs->conn, ex == -1 ? 1 : 0);
pq_resolve_critical(curs->conn, 1);
}
else {
pq_resolve_critical(curs->conn, 0);
}
return -1;
} }
return ex; return ex;

View File

@ -35,18 +35,18 @@
/* exported functions */ /* exported functions */
HIDDEN PGresult *pq_get_last_result(connectionObject *conn); HIDDEN PGresult *pq_get_last_result(connectionObject *conn);
HIDDEN int pq_fetch(cursorObject *curs); RAISES_NEG HIDDEN int pq_fetch(cursorObject *curs);
HIDDEN int pq_execute(cursorObject *curs, const char *query, int async); 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_send_query(connectionObject *conn, const char *query);
HIDDEN int pq_begin_locked(connectionObject *conn, PGresult **pgres, HIDDEN int pq_begin_locked(connectionObject *conn, PGresult **pgres,
char **error, PyThreadState **tstate); char **error, PyThreadState **tstate);
HIDDEN int pq_commit(connectionObject *conn); 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); 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, HIDDEN int pq_reset_locked(connectionObject *conn, PGresult **pgres,
char **error, PyThreadState **tstate); 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, HIDDEN char *pq_get_guc_locked(connectionObject *conn, const char *param,
PGresult **pgres, PGresult **pgres,
char **error, PyThreadState **tstate); 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_is_busy_locked(connectionObject *conn);
HIDDEN int pq_flush(connectionObject *conn); HIDDEN int pq_flush(connectionObject *conn);
HIDDEN void pq_clear_async(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); 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, const char *query,
PGresult **pgres, char **error, PGresult **pgres, char **error,
PyThreadState **tstate); PyThreadState **tstate);
HIDDEN void pq_complete_error(connectionObject *conn, PGresult **pgres, RAISES HIDDEN void pq_complete_error(connectionObject *conn, PGresult **pgres,
char **error); char **error);
#endif /* !defined(PSYCOPG_PQPATH_H) */ #endif /* !defined(PSYCOPG_PQPATH_H) */

View File

@ -120,17 +120,19 @@ HIDDEN PyObject *psyco_GetDecimalType(void);
typedef struct cursorObject cursorObject; typedef struct cursorObject cursorObject;
/* some utility functions */ /* 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); const char *pgerror, const char *pgcode);
HIDDEN char *psycopg_escape_string(PyObject *conn, HIDDEN char *psycopg_escape_string(PyObject *conn,
const char *from, Py_ssize_t len, char *to, Py_ssize_t *tolen); 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_escape_identifier_easy(const char *from, Py_ssize_t len);
HIDDEN char *psycopg_strdup(const char *from, Py_ssize_t len); HIDDEN int psycopg_strdup(char **to, const char *from, Py_ssize_t len);
HIDDEN PyObject * psycopg_ensure_bytes(PyObject *obj);
HIDDEN PyObject * psycopg_ensure_text(PyObject *obj);
HIDDEN int psycopg_is_text_file(PyObject *f); 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 */ /* Exceptions docstrings */
#define Error_doc \ #define Error_doc \
"Base class for error exceptions." "Base class for error exceptions."

View File

@ -143,14 +143,6 @@ psyco_connect(PyObject *self, PyObject *args, PyObject *keywds)
" * `name`: Name for the new type\n" \ " * `name`: Name for the new type\n" \
" * `baseobj`: Adapter to perform type conversion of a single array item." " * `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 * static PyObject *
psyco_register_type(PyObject *self, PyObject *args) 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 (obj != NULL && obj != Py_None) {
if (PyObject_TypeCheck(obj, &cursorType)) { 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)) { 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 { else {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
@ -174,7 +172,7 @@ psyco_register_type(PyObject *self, PyObject *args)
} }
} }
else { else {
typecast_add(type, NULL, 0); if (0 > typecast_add(type, NULL, 0)) { return NULL; }
} }
Py_INCREF(Py_None); Py_INCREF(Py_None);
@ -182,66 +180,108 @@ psyco_register_type(PyObject *self, PyObject *args)
} }
/* default adapters */ /* Initialize the default adapters map
*
static void * Return 0 on success, else -1 and set an exception.
*/
static int
psyco_adapters_init(PyObject *mod) 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 #if PY_MAJOR_VERSION < 3
microprotocols_add(&PyInt_Type, NULL, (PyObject*)&pintType); if (0 != microprotocols_add(&PyInt_Type, NULL, (PyObject*)&pintType)) {
goto exit;
}
#endif #endif
microprotocols_add(&PyLong_Type, NULL, (PyObject*)&pintType); if (0 != microprotocols_add(&PyLong_Type, NULL, (PyObject*)&pintType)) {
microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType); goto exit;
}
if (0 != microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType)) {
goto exit;
}
/* strings */ /* strings */
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType); if (0 != microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType)) {
goto exit;
}
#endif #endif
microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType); if (0 != microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType)) {
goto exit;
}
/* binary */ /* binary */
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3
microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType); if (0 != microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType)) {
goto exit;
}
#else #else
microprotocols_add(&PyBytes_Type, NULL, (PyObject*)&binaryType); if (0 != microprotocols_add(&PyBytes_Type, NULL, (PyObject*)&binaryType)) {
goto exit;
}
#endif #endif
#if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 6 #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 #endif
#if PY_MAJOR_VERSION >= 3 || PY_MINOR_VERSION >= 7 #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 #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 /* the module has already been initialized, so we can obtain the callable
objects directly from its dictionary :) */ objects directly from its dictionary :) */
call = PyMapping_GetItemString(mod, "DateFromPy"); if (!(call = PyMapping_GetItemString(mod, "DateFromPy"))) { goto exit; }
microprotocols_add(PyDateTimeAPI->DateType, NULL, call); if (0 != microprotocols_add(PyDateTimeAPI->DateType, NULL, call)) { goto exit; }
call = PyMapping_GetItemString(mod, "TimeFromPy"); Py_CLEAR(call);
microprotocols_add(PyDateTimeAPI->TimeType, NULL, call);
call = PyMapping_GetItemString(mod, "TimestampFromPy"); if (!(call = PyMapping_GetItemString(mod, "TimeFromPy"))) { goto exit; }
microprotocols_add(PyDateTimeAPI->DateTimeType, NULL, call); if (0 != microprotocols_add(PyDateTimeAPI->TimeType, NULL, call)) { goto exit; }
call = PyMapping_GetItemString(mod, "IntervalFromPy"); Py_CLEAR(call);
microprotocols_add(PyDateTimeAPI->DeltaType, NULL, 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 #ifdef HAVE_MXDATETIME
/* as above, we use the callable objects from the psycopg module */ /* as above, we use the callable objects from the psycopg module */
if (NULL != (call = PyMapping_GetItemString(mod, "TimestampFromMx"))) { 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. */ /* if we found the above, we have this too. */
call = PyMapping_GetItemString(mod, "TimeFromMx"); if (!(call = PyMapping_GetItemString(mod, "TimeFromMx"))) { goto exit; }
microprotocols_add(mxDateTime.DateTimeDelta_Type, NULL, call); if (0 != microprotocols_add(mxDateTime.DateTimeDelta_Type, NULL, call)) { goto exit; }
Py_CLEAR(call);
} }
else { else {
PyErr_Clear(); PyErr_Clear();
} }
#endif #endif
/* Success! */
rv = 0;
exit:
Py_XDECREF(call);
return rv;
} }
/* psyco_encodings_fill /* psyco_encodings_fill
@ -326,15 +366,27 @@ static encodingPair encodings[] = {
{NULL, NULL} {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; encodingPair *enc;
int rv = -1;
for (enc = encodings; enc->pgenc != NULL; enc++) { for (enc = encodings; enc->pgenc != NULL; enc++) {
PyObject *value = Text_FromUTF8(enc->pyenc); if (!(value = Text_FromUTF8(enc->pyenc))) { goto exit; }
PyDict_SetItemString(dict, enc->pgenc, value); if (0 != PyDict_SetItemString(dict, enc->pgenc, value)) { goto exit; }
Py_DECREF(value); Py_CLEAR(value);
} }
rv = 0;
exit:
Py_XDECREF(value);
return rv;
} }
/* psyco_errors_init, psyco_errors_fill (callable from C) /* psyco_errors_init, psyco_errors_fill (callable from C)
@ -440,21 +492,22 @@ psyco_errors_init(void)
live in _psycopg */ live in _psycopg */
int i; int i;
PyObject *dict; PyObject *dict = NULL;
PyObject *base; PyObject *base;
PyObject *str; PyObject *str = NULL;
PyObject *descr; PyObject *descr = NULL;
int rv = -1; int rv = -1;
static PyMethodDef psyco_error_reduce_ex_def = static PyMethodDef psyco_error_reduce_ex_def =
{"__reduce_ex__", psyco_error_reduce_ex, METH_VARARGS, "pickle helper"}; {"__reduce_ex__", psyco_error_reduce_ex, METH_VARARGS, "pickle helper"};
for (i=0; exctable[i].name; i++) { for (i=0; exctable[i].name; i++) {
dict = PyDict_New(); if (!(dict = PyDict_New())) { goto exit; }
if (exctable[i].docstr) { if (exctable[i].docstr) {
str = Text_FromUTF8(exctable[i].docstr); if (!(str = Text_FromUTF8(exctable[i].docstr))) { goto exit; }
PyDict_SetItemString(dict, "__doc__", str); if (0 != PyDict_SetItemString(dict, "__doc__", str)) { goto exit; }
Py_CLEAR(str);
} }
if (exctable[i].base == 0) { if (exctable[i].base == 0) {
@ -468,7 +521,11 @@ psyco_errors_init(void)
else else
base = *exctable[i].base; 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 /* 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)) { psyco_error_reduce_ex_def.ml_name, descr)) {
goto exit; goto exit;
} }
Py_DECREF(descr);
#endif #endif
rv = 0; rv = 0;
exit: exit:
Py_XDECREF(descr);
Py_XDECREF(str);
Py_XDECREF(dict);
return rv; return rv;
} }
void void
psyco_errors_fill(PyObject *dict) psyco_errors_fill(PyObject *dict)
{ {
PyDict_SetItemString(dict, "Error", Error); int i;
PyDict_SetItemString(dict, "Warning", Warning); char *name;
PyDict_SetItemString(dict, "InterfaceError", InterfaceError);
PyDict_SetItemString(dict, "DatabaseError", DatabaseError); for (i = 0; exctable[i].name; i++) {
PyDict_SetItemString(dict, "InternalError", InternalError); if (NULL == exctable[i].exc) { continue; }
PyDict_SetItemString(dict, "OperationalError", OperationalError);
PyDict_SetItemString(dict, "ProgrammingError", ProgrammingError); /* the name is the part after the last dot */
PyDict_SetItemString(dict, "IntegrityError", IntegrityError); name = strrchr(exctable[i].name, '.');
PyDict_SetItemString(dict, "DataError", DataError); name = name ? name + 1 : exctable[i].name;
PyDict_SetItemString(dict, "NotSupportedError", NotSupportedError);
#ifdef PSYCOPG_EXTENSIONS PyDict_SetItemString(dict, name, *exctable[i].exc);
PyDict_SetItemString(dict, "QueryCanceledError", QueryCanceledError); }
PyDict_SetItemString(dict, "TransactionRollbackError",
TransactionRollbackError);
#endif
} }
void void
psyco_errors_set(PyObject *type) psyco_errors_set(PyObject *type)
{ {
PyObject_SetAttrString(type, "Error", Error); int i;
PyObject_SetAttrString(type, "Warning", Warning); char *name;
PyObject_SetAttrString(type, "InterfaceError", InterfaceError);
PyObject_SetAttrString(type, "DatabaseError", DatabaseError); for (i = 0; exctable[i].name; i++) {
PyObject_SetAttrString(type, "InternalError", InternalError); if (NULL == exctable[i].exc) { continue; }
PyObject_SetAttrString(type, "OperationalError", OperationalError);
PyObject_SetAttrString(type, "ProgrammingError", ProgrammingError); /* the name is the part after the last dot */
PyObject_SetAttrString(type, "IntegrityError", IntegrityError); name = strrchr(exctable[i].name, '.');
PyObject_SetAttrString(type, "DataError", DataError); name = name ? name + 1 : exctable[i].name;
PyObject_SetAttrString(type, "NotSupportedError", NotSupportedError);
#ifdef PSYCOPG_EXTENSIONS PyObject_SetAttrString(type, name, *exctable[i].exc);
PyObject_SetAttrString(type, "QueryCanceledError", QueryCanceledError); }
PyObject_SetAttrString(type, "TransactionRollbackError",
TransactionRollbackError);
#endif
} }
/* psyco_error_new /* psyco_set_error
Create a new error of the given type with extra attributes. */ Create a new error of the given type with extra attributes. */
void RAISES void
psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg, psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg,
const char *pgerror, const char *pgcode) const char *pgerror, const char *pgcode)
{ {
@ -574,15 +627,17 @@ psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg,
} }
if (pgerror) { if (pgerror) {
t = conn_text_from_chars(conn, pgerror); if ((t = conn_text_from_chars(conn, pgerror))) {
PyObject_SetAttrString(err, "pgerror", t); PyObject_SetAttrString(err, "pgerror", t);
Py_DECREF(t); Py_DECREF(t);
}
} }
if (pgcode) { if (pgcode) {
t = conn_text_from_chars(conn, pgcode); if ((t = conn_text_from_chars(conn, pgcode))) {
PyObject_SetAttrString(err, "pgcode", t); PyObject_SetAttrString(err, "pgcode", t);
Py_DECREF(t); Py_DECREF(t);
}
} }
PyErr_SetObject(exc, err); PyErr_SetObject(exc, err);
@ -649,7 +704,7 @@ psyco_GetDecimalType(void)
} }
/* Store the object from future uses. */ /* Store the object from future uses. */
if (can_cache && !cachedType) { if (can_cache && !cachedType && decimalType) {
Py_INCREF(decimalType); Py_INCREF(decimalType);
cachedType = decimalType; cachedType = decimalType;
} }
@ -673,15 +728,11 @@ psyco_make_description_type(void)
/* Try to import collections.namedtuple */ /* Try to import collections.namedtuple */
if (!(coll = PyImport_ImportModule("collections"))) { if (!(coll = PyImport_ImportModule("collections"))) {
Dprintf("psyco_make_description_type: collections import failed"); Dprintf("psyco_make_description_type: collections import failed");
PyErr_Clear(); goto error;
rv = Py_None;
goto exit;
} }
if (!(nt = PyObject_GetAttrString(coll, "namedtuple"))) { if (!(nt = PyObject_GetAttrString(coll, "namedtuple"))) {
Dprintf("psyco_make_description_type: no collections.namedtuple"); Dprintf("psyco_make_description_type: no collections.namedtuple");
PyErr_Clear(); goto error;
rv = Py_None;
goto exit;
} }
/* Build the namedtuple */ /* Build the namedtuple */
@ -693,6 +744,13 @@ exit:
Py_XDECREF(nt); Py_XDECREF(nt);
return rv; 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 #endif
/* other mixed initializations of module-level variables */ /* other mixed initializations of module-level variables */
psycoEncodings = PyDict_New(); if (!(psycoEncodings = PyDict_New())) { goto exit; }
psyco_encodings_fill(psycoEncodings); if (0 != psyco_encodings_fill(psycoEncodings)) { goto exit; }
psyco_null = Bytes_FromString("NULL"); 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 */ /* set some module's parameters */
PyModule_AddStringConstant(module, "__version__", PSYCOPG_VERSION); PyModule_AddStringConstant(module, "__version__", PSYCOPG_VERSION);
@ -941,11 +999,11 @@ INIT_MODULE(_psycopg)(void)
} }
#endif #endif
/* initialize default set of typecasters */ /* initialize default set of typecasters */
typecast_init(dict); if (0 != typecast_init(dict)) { goto exit; }
/* initialize microprotocols layer */ /* initialize microprotocols layer */
microprotocols_init(dict); 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 */ /* create a standard set of exceptions and add them to the module's dict */
if (0 != psyco_errors_init()) { goto exit; } if (0 != psyco_errors_init()) { goto exit; }

View File

@ -250,34 +250,28 @@ PyObject *psyco_default_binary_cast;
/* typecast_init - initialize the dictionary and create default types */ /* typecast_init - initialize the dictionary and create default types */
int RAISES_NEG int
typecast_init(PyObject *dict) typecast_init(PyObject *dict)
{ {
int i; int i;
int rv = -1;
typecastObject *t = NULL;
/* create type dictionary and put it in module namespace */ /* create type dictionary and put it in module namespace */
psyco_types = PyDict_New(); if (!(psyco_types = PyDict_New())) { goto exit; }
psyco_binary_types = PyDict_New();
if (!psyco_types || !psyco_binary_types) {
Py_XDECREF(psyco_types);
Py_XDECREF(psyco_binary_types);
return -1;
}
PyDict_SetItemString(dict, "string_types", psyco_types); PyDict_SetItemString(dict, "string_types", psyco_types);
if (!(psyco_binary_types = PyDict_New())) { goto exit; }
PyDict_SetItemString(dict, "binary_types", psyco_binary_types); PyDict_SetItemString(dict, "binary_types", psyco_binary_types);
/* insert the cast types into the 'types' dictionary and register them in /* insert the cast types into the 'types' dictionary and register them in
the module dictionary */ the module dictionary */
for (i = 0; typecast_builtins[i].name != NULL; i++) { for (i = 0; typecast_builtins[i].name != NULL; i++) {
typecastObject *t;
Dprintf("typecast_init: initializing %s", typecast_builtins[i].name); Dprintf("typecast_init: initializing %s", typecast_builtins[i].name);
t = (typecastObject *)typecast_from_c(&(typecast_builtins[i]), dict); t = (typecastObject *)typecast_from_c(&(typecast_builtins[i]), dict);
if (t == NULL) return -1; if (t == NULL) { goto exit; }
if (typecast_add((PyObject *)t, NULL, 0) != 0) return -1; if (typecast_add((PyObject *)t, NULL, 0) < 0) { goto exit; }
PyDict_SetItem(dict, t->name, (PyObject *)t); PyDict_SetItem(dict, t->name, (PyObject *)t);
@ -285,6 +279,8 @@ typecast_init(PyObject *dict)
if (typecast_builtins[i].values == typecast_BINARY_types) { if (typecast_builtins[i].values == typecast_BINARY_types) {
psyco_default_binary_cast = (PyObject *)t; psyco_default_binary_cast = (PyObject *)t;
} }
Py_DECREF((PyObject *)t);
t = NULL;
} }
/* create and save a default cast object (but does not register it) */ /* create and save a default cast object (but does not register it) */
@ -294,29 +290,35 @@ typecast_init(PyObject *dict)
#ifdef HAVE_MXDATETIME #ifdef HAVE_MXDATETIME
if (0 == psyco_typecast_mxdatetime_init()) { if (0 == psyco_typecast_mxdatetime_init()) {
for (i = 0; typecast_mxdatetime[i].name != NULL; i++) { for (i = 0; typecast_mxdatetime[i].name != NULL; i++) {
typecastObject *t;
Dprintf("typecast_init: initializing %s", typecast_mxdatetime[i].name); Dprintf("typecast_init: initializing %s", typecast_mxdatetime[i].name);
t = (typecastObject *)typecast_from_c(&(typecast_mxdatetime[i]), dict); 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); PyDict_SetItem(dict, t->name, (PyObject *)t);
Py_DECREF((PyObject *)t);
t = NULL;
} }
} }
#endif #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++) { for (i = 0; typecast_pydatetime[i].name != NULL; i++) {
typecastObject *t;
Dprintf("typecast_init: initializing %s", typecast_pydatetime[i].name); Dprintf("typecast_init: initializing %s", typecast_pydatetime[i].name);
t = (typecastObject *)typecast_from_c(&(typecast_pydatetime[i]), dict); 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); 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 */ /* typecast_add - add a type object to the dictionary */
int RAISES_NEG int
typecast_add(PyObject *obj, PyObject *dict, int binary) typecast_add(PyObject *obj, PyObject *dict, int binary)
{ {
PyObject *val; PyObject *val;
@ -466,7 +468,7 @@ typecast_repr(PyObject *self)
static PyObject * static PyObject *
typecast_call(PyObject *obj, PyObject *args, PyObject *kwargs) typecast_call(PyObject *obj, PyObject *args, PyObject *kwargs)
{ {
char *string; const char *string;
Py_ssize_t length; Py_ssize_t length;
PyObject *cursor; PyObject *cursor;

View File

@ -71,8 +71,8 @@ extern HIDDEN PyObject *psyco_default_binary_cast;
/** exported functions **/ /** exported functions **/
/* used by module.c to init the type system and register types */ /* used by module.c to init the type system and register types */
HIDDEN int typecast_init(PyObject *dict); RAISES_NEG HIDDEN int typecast_init(PyObject *dict);
HIDDEN int typecast_add(PyObject *obj, PyObject *dict, int binary); RAISES_NEG HIDDEN int typecast_add(PyObject *obj, PyObject *dict, int binary);
/* the C callable typecastObject creator function */ /* the C callable typecastObject creator function */
HIDDEN PyObject *typecast_from_c(typecastObject_initlist *type, PyObject *d); HIDDEN PyObject *typecast_from_c(typecastObject_initlist *type, PyObject *d);

View File

@ -166,7 +166,7 @@ typecast_array_tokenize(const char *str, Py_ssize_t strlength,
return res; return res;
} }
static int RAISES_NEG static int
typecast_array_scan(const char *str, Py_ssize_t strlength, typecast_array_scan(const char *str, Py_ssize_t strlength,
PyObject *curs, PyObject *base, PyObject *array) 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 */ /* before anything else we free the memory */
if (state == ASCAN_QUOTED) PyMem_Free(token); if (state == ASCAN_QUOTED) PyMem_Free(token);
if (obj == NULL) return 0; if (obj == NULL) return -1;
PyList_Append(array, obj); PyList_Append(array, obj);
Py_DECREF(obj); Py_DECREF(obj);
@ -207,25 +207,25 @@ typecast_array_scan(const char *str, Py_ssize_t strlength,
else if (state == ASCAN_BEGIN) { else if (state == ASCAN_BEGIN) {
PyObject *sub = PyList_New(0); PyObject *sub = PyList_New(0);
if (sub == NULL) return 0; if (sub == NULL) return -1;
PyList_Append(array, sub); PyList_Append(array, sub);
Py_DECREF(sub); Py_DECREF(sub);
if (stack_index == MAX_DIMENSIONS) if (stack_index == MAX_DIMENSIONS)
return 0; return -1;
stack[stack_index++] = array; stack[stack_index++] = array;
array = sub; array = sub;
} }
else if (state == ASCAN_ERROR) { else if (state == ASCAN_ERROR) {
return 0; return -1;
} }
else if (state == ASCAN_END) { else if (state == ASCAN_END) {
if (--stack_index < 0) if (--stack_index < 0)
return 0; return -1;
array = stack[stack_index]; array = stack[stack_index];
} }
@ -233,7 +233,7 @@ typecast_array_scan(const char *str, Py_ssize_t strlength,
break; 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'," Dprintf("typecast_GENERIC_ARRAY_cast: str = '%s',"
" len = " FORMAT_CODE_PY_SSIZE_T, str, len); " 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 {} */ /* scan the array skipping the first level of {} */
if (typecast_array_scan(&str[1], len-2, curs, base, obj) == 0) { if (typecast_array_scan(&str[1], len-2, curs, base, obj) < 0) {
Py_DECREF(obj); Py_CLEAR(obj);
obj = NULL;
} }
return obj; return obj;

View File

@ -65,7 +65,7 @@ typecast_FLOAT_cast(const char *s, Py_ssize_t len, PyObject *curs)
PyObject *str = NULL, *flo = NULL; PyObject *str = NULL, *flo = NULL;
if (s == NULL) {Py_INCREF(Py_None); return Py_None;} 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 #if PY_MAJOR_VERSION < 3
flo = PyFloat_FromString(str, NULL); flo = PyFloat_FromString(str, NULL);
#else #else

View File

@ -26,7 +26,7 @@
#include <math.h> #include <math.h>
#include "datetime.h" #include "datetime.h"
static int RAISES_NEG static int
psyco_typecast_datetime_init(void) psyco_typecast_datetime_init(void)
{ {
Dprintf("psyco_typecast_datetime_init: datetime init"); 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 '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': 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){ if (part == 6){
denominator *= 10; denominator *= 10;
} }

View File

@ -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 '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': 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); Dprintf("typecast_MXINTERVAL_cast: v = %f", v);
if (part == 6){ if (part == 6){
denominator *= 10; denominator *= 10;

View File

@ -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. * Allocate a new buffer on the Python heap containing the new string.
* 'len' is optional: if 0 the length is calculated. * '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 * RAISES_NEG int
psycopg_strdup(const char *from, Py_ssize_t len) psycopg_strdup(char **to, const char *from, Py_ssize_t len)
{ {
char *rv;
if (!len) { len = strlen(from); } if (!len) { len = strlen(from); }
if (!(rv = PyMem_Malloc(len + 1))) { if (!(*to = PyMem_Malloc(len + 1))) {
PyErr_NoMemory(); PyErr_NoMemory();
return NULL; return -1;
} }
strcpy(rv, from); strcpy(*to, from);
return rv; return 0;
} }
/* Ensure a Python object is a bytes string. /* 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. * It is safe to call the function on NULL.
*/ */
PyObject * STEALS(1) PyObject *
psycopg_ensure_bytes(PyObject *obj) psycopg_ensure_bytes(PyObject *obj)
{ {
PyObject *rv = NULL; 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 * 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. * return value. It is safe to call it on NULL.
*/ */
PyObject * STEALS(1) PyObject *
psycopg_ensure_text(PyObject *obj) psycopg_ensure_text(PyObject *obj)
{ {
#if PY_MAJOR_VERSION < 3 #if PY_MAJOR_VERSION < 3

View File

@ -78,7 +78,9 @@ static PyMemberDef xid_members[] = {
static PyObject * static PyObject *
xid_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) 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); Py_INCREF(Py_None);
self->format_id = Py_None; self->format_id = Py_None;
@ -486,7 +488,7 @@ exit:
* *
* Return a borrowed reference. */ * Return a borrowed reference. */
static PyObject * BORROWED static PyObject *
_xid_get_parse_regex(void) { _xid_get_parse_regex(void) {
static PyObject *rv; static PyObject *rv;