From ec20fa8912c2819b8acc7ea6e961ca4d84d7aa61 Mon Sep 17 00:00:00 2001 From: James Henstridge Date: Mon, 5 May 2008 12:07:24 +0800 Subject: [PATCH] Some changes to the lobject code to match changes in pqpath.[ch]. --- psycopg/lobject.h | 19 +++-- psycopg/lobject_int.c | 182 ++++++++++++++++++++++++++++------------- psycopg/lobject_type.c | 6 +- psycopg/pqpath.c | 2 +- psycopg/pqpath.h | 2 + 5 files changed, 144 insertions(+), 67 deletions(-) diff --git a/psycopg/lobject.h b/psycopg/lobject.h index 4b84021b..fabba2d1 100644 --- a/psycopg/lobject.h +++ b/psycopg/lobject.h @@ -26,6 +26,7 @@ #include #include +#include "psycopg/config.h" #include "psycopg/connection.h" #ifdef __cplusplus @@ -48,19 +49,19 @@ typedef struct { Oid oid; /* the oid for this lobject */ int fd; /* the file descriptor for file-like ops */ } lobjectObject; - + /* functions exported from lobject_int.c */ -extern int lobject_open(lobjectObject *self, connectionObject *conn, +HIDDEN int lobject_open(lobjectObject *self, connectionObject *conn, Oid oid, int mode, Oid new_oid, char *new_file); -extern int lobject_unlink(lobjectObject *self); -extern int lobject_export(lobjectObject *self, char *filename); +HIDDEN int lobject_unlink(lobjectObject *self); +HIDDEN int lobject_export(lobjectObject *self, char *filename); -extern size_t lobject_read(lobjectObject *self, char *buf, size_t len); -extern size_t lobject_write(lobjectObject *self, char *buf, size_t len); -extern int lobject_seek(lobjectObject *self, int pos, int whence); -extern int lobject_tell(lobjectObject *self); -extern void lobject_close(lobjectObject *self); +HIDDEN Py_ssize_t lobject_read(lobjectObject *self, char *buf, size_t len); +HIDDEN Py_ssize_t lobject_write(lobjectObject *self, char *buf, size_t len); +HIDDEN int lobject_seek(lobjectObject *self, int pos, int whence); +HIDDEN int lobject_tell(lobjectObject *self); +HIDDEN int lobject_close(lobjectObject *self); /* exception-raising macros */ diff --git a/psycopg/lobject_int.c b/psycopg/lobject_int.c index d4cc38f2..386c9451 100644 --- a/psycopg/lobject_int.c +++ b/psycopg/lobject_int.c @@ -31,16 +31,31 @@ #ifdef PSYCOPG_EXTENSIONS +static void +collect_error(connectionObject *conn, char **error) +{ + const char *msg = PQerrorMessage(conn->pgconn); + + if (msg) + *error = strdup(msg); +} + /* lobject_open - create a new/open an existing lo */ int lobject_open(lobjectObject *self, connectionObject *conn, Oid oid, int mode, Oid new_oid, char *new_file) { + int retvalue = -1; + PGresult *pgres = NULL; + char *error = NULL; + Py_BEGIN_ALLOW_THREADS; pthread_mutex_lock(&(self->conn->lock)); - pq_begin(self->conn); + retvalue = pq_begin_locked(self->conn, &pgres, &error); + if (retvalue < 0) + goto end; /* if the oid is InvalidOid we create a new lob before opening it or we import a file from the FS, depending on the value of @@ -54,8 +69,12 @@ lobject_open(lobjectObject *self, connectionObject *conn, Dprintf("lobject_open: large object created with oid = %d", self->oid); - if (self->oid == InvalidOid) goto end; - + if (self->oid == InvalidOid) { + collect_error(self->conn, &error); + retvalue = -1; + goto end; + } + mode = INV_WRITE; } else { @@ -69,37 +88,78 @@ lobject_open(lobjectObject *self, connectionObject *conn, self->fd = lo_open(self->conn->pgconn, self->oid, mode); Dprintf("lobject_open: large object opened with fd = %d", self->fd); + + if (self->fd == -1) { + collect_error(self->conn, &error); + retvalue = -1; + goto end; + } } else { /* this is necessary to make sure no function that needs and fd is called on unopened lobjects */ self->closed = 1; } + /* set the mode for future reference */ + self->mode = mode; + switch (mode) { + case -1: + self->smode = "n"; break; + case INV_READ: + self->smode = "r"; break; + case INV_WRITE: + self->smode = "w"; break; + case INV_READ+INV_WRITE: + self->smode = "rw"; break; + } + retvalue = 0; end: pthread_mutex_unlock(&(self->conn->lock)); Py_END_ALLOW_THREADS; - /* here we check for errors before returning 0 */ - if ((self->fd == -1 && mode != -1) || self->oid == InvalidOid) { - pq_raise(conn, NULL, NULL, NULL); - return -1; - } - else { - /* set the mode for future reference and return */ - self->mode = mode; - switch (mode) { - case -1: - self->smode = "n"; break; - case INV_READ: - self->smode = "r"; break; - case INV_WRITE: - self->smode = "w"; break; - case INV_READ+INV_WRITE: - self->smode = "rw"; break; - } + if (retvalue < 0) + pq_complete_error(self->conn, &pgres, &error); + return retvalue; +} + +/* lobject_close - close an existing lo */ + +static int +lobject_close_locked(lobjectObject *self, char **error) +{ + int retvalue; + + if (self->conn->isolation_level == 0 || + self->conn->mark != self->mark || + self->fd == -1) return 0; - } + + retvalue = lo_close(self->conn->pgconn, self->fd); + self->fd = -1; + if (retvalue < 0) + collect_error(self->conn, error); + + return retvalue; +} + +int +lobject_close(lobjectObject *self) +{ + char *error = NULL; + int retvalue; + + Py_BEGIN_ALLOW_THREADS; + pthread_mutex_lock(&(self->conn->lock)); + + retvalue = lobject_close_locked(self, &error); + + pthread_mutex_unlock(&(self->conn->lock)); + Py_END_ALLOW_THREADS; + + if (retvalue < 0) + pq_complete_error(self->conn, NULL, &error); + return retvalue; } /* lobject_unlink - remove an lo from database */ @@ -107,76 +167,79 @@ lobject_open(lobjectObject *self, connectionObject *conn, int lobject_unlink(lobjectObject *self) { - int res; + PGresult *pgres = NULL; + char *error = NULL; + int retvalue = -1; - /* first we make sure the lobject is closed and then we unlink */ - lobject_close(self); - Py_BEGIN_ALLOW_THREADS; pthread_mutex_lock(&(self->conn->lock)); - pq_begin(self->conn); + retvalue = pq_begin_locked(self->conn, &pgres, &error); + if (retvalue < 0) + goto end; - res = lo_unlink(self->conn->pgconn, self->oid); + /* first we make sure the lobject is closed and then we unlink */ + retvalue = lobject_close_locked(self, &error); + if (retvalue < 0) + goto end; + retvalue = lo_unlink(self->conn->pgconn, self->oid); + if (retvalue < 0) + collect_error(self->conn, &error); + + end: pthread_mutex_unlock(&(self->conn->lock)); Py_END_ALLOW_THREADS; - if (res == -1) - pq_raise(self->conn, NULL, NULL, NULL); - return res; -} - -/* lobject_close - close an existing lo */ - -void -lobject_close(lobjectObject *self) -{ - if (self->conn->isolation_level > 0 - && self->conn->mark == self->mark) { - if (self->fd != -1) - lo_close(self->conn->pgconn, self->fd); - } + if (retvalue < 0) + pq_complete_error(self->conn, &pgres, &error); + return retvalue; } /* lobject_write - write bytes to a lo */ -size_t +Py_ssize_t lobject_write(lobjectObject *self, char *buf, size_t len) { - size_t written; + Py_ssize_t written; + char *error = NULL; Py_BEGIN_ALLOW_THREADS; pthread_mutex_lock(&(self->conn->lock)); written = lo_write(self->conn->pgconn, self->fd, buf, len); + if (written < 0) + collect_error(self->conn, &error); pthread_mutex_unlock(&(self->conn->lock)); Py_END_ALLOW_THREADS; if (written < 0) - pq_raise(self->conn, NULL, NULL, NULL); + pq_complete_error(self->conn, NULL, &error); return written; } /* lobject_read - read bytes from a lo */ -size_t +Py_ssize_t lobject_read(lobjectObject *self, char *buf, size_t len) { - size_t readed; + Py_ssize_t n_read; + char *error = NULL; Py_BEGIN_ALLOW_THREADS; pthread_mutex_lock(&(self->conn->lock)); - readed = lo_read(self->conn->pgconn, self->fd, buf, len); + n_read = lo_read(self->conn->pgconn, self->fd, buf, len); + if (n_read < 0) + collect_error(self->conn, &error); pthread_mutex_unlock(&(self->conn->lock)); Py_END_ALLOW_THREADS; - if (readed < 0) - pq_raise(self->conn, NULL, NULL, NULL); - return readed; + if (n_read < 0) + pq_complete_error(self->conn, NULL, &error); + return n_read; } /* lobject_seek - move the current position in the lo */ @@ -185,17 +248,20 @@ int lobject_seek(lobjectObject *self, int pos, int whence) { int where; + char *error = NULL; Py_BEGIN_ALLOW_THREADS; pthread_mutex_lock(&(self->conn->lock)); where = lo_lseek(self->conn->pgconn, self->fd, pos, whence); + if (where < 0) + collect_error(self->conn, &error); pthread_mutex_unlock(&(self->conn->lock)); Py_END_ALLOW_THREADS; if (where < 0) - pq_raise(self->conn, NULL, NULL, NULL); + pq_complete_error(self->conn, NULL, &error); return where; } @@ -205,17 +271,20 @@ int lobject_tell(lobjectObject *self) { int where; + char *error = NULL; Py_BEGIN_ALLOW_THREADS; pthread_mutex_lock(&(self->conn->lock)); where = lo_tell(self->conn->pgconn, self->fd); + if (where < 0) + collect_error(self->conn, &error); pthread_mutex_unlock(&(self->conn->lock)); Py_END_ALLOW_THREADS; if (where < 0) - pq_raise(self->conn, NULL, NULL, NULL); + pq_complete_error(self->conn, NULL, &error); return where; } @@ -225,17 +294,20 @@ int lobject_export(lobjectObject *self, char *filename) { int res; + char *error = NULL; Py_BEGIN_ALLOW_THREADS; pthread_mutex_lock(&(self->conn->lock)); res = lo_export(self->conn->pgconn, self->oid, filename); + if (res < 0) + collect_error(self->conn, &error); pthread_mutex_unlock(&(self->conn->lock)); Py_END_ALLOW_THREADS; if (res < 0) - pq_raise(self->conn, NULL, NULL, NULL); + pq_complete_error(self->conn, NULL, &error); return res; } diff --git a/psycopg/lobject_type.c b/psycopg/lobject_type.c index 8d299e94..b559a588 100644 --- a/psycopg/lobject_type.c +++ b/psycopg/lobject_type.c @@ -57,7 +57,8 @@ psyco_lobj_close(lobjectObject *self, PyObject *args) && self->conn->mark == self->mark) { self->closed = 1; - lobject_close(self); + if (lobject_close(self) < 0) + return NULL; Dprintf("psyco_lobj_close: lobject at %p closed", self); } @@ -276,7 +277,8 @@ lobject_dealloc(PyObject* obj) { lobjectObject *self = (lobjectObject *)obj; - lobject_close(self); + if (lobject_close(self) < 0) + PyErr_Print(); Py_XDECREF((PyObject*)self->conn); Dprintf("lobject_dealloc: deleted lobject object at %p, refcnt = %d", diff --git a/psycopg/pqpath.c b/psycopg/pqpath.c index 16703b3c..afab3b1d 100644 --- a/psycopg/pqpath.c +++ b/psycopg/pqpath.c @@ -368,7 +368,7 @@ pq_complete_error(connectionObject *conn, PGresult **pgres, char **error) On error, -1 is returned, and the pgres argument will hold the relevant result structure. */ -static int +int pq_begin_locked(connectionObject *conn, PGresult **pgres, char **error) { const char *query[] = { diff --git a/psycopg/pqpath.h b/psycopg/pqpath.h index ee14fab4..8503c12f 100644 --- a/psycopg/pqpath.h +++ b/psycopg/pqpath.h @@ -33,6 +33,8 @@ /* exported functions */ HIDDEN int pq_fetch(cursorObject *curs); HIDDEN int pq_execute(cursorObject *curs, const char *query, int async); +HIDDEN int pq_begin_locked(connectionObject *conn, PGresult **pgres, + char **error); HIDDEN int pq_commit(connectionObject *conn); HIDDEN int pq_abort_locked(connectionObject *conn, PGresult **pgres, char **error);