mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-09-21 11:18:49 +03:00
Large object mode parsing refactored
Added parsing of text/binary mode.
This commit is contained in:
parent
f63167a92c
commit
ba1d77a297
|
@ -514,15 +514,16 @@ 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;
|
Oid oid=InvalidOid, new_oid=InvalidOid;
|
||||||
char *smode = NULL, *new_file = NULL;
|
char *new_file = NULL;
|
||||||
int mode=0;
|
const char *smode = "";
|
||||||
PyObject *obj, *factory = NULL;
|
PyObject *factory = (PyObject *)&lobjectType;
|
||||||
|
PyObject *obj;
|
||||||
|
|
||||||
static char *kwlist[] = {"oid", "mode", "new_oid", "new_file",
|
static char *kwlist[] = {"oid", "mode", "new_oid", "new_file",
|
||||||
"cursor_factory", NULL};
|
"cursor_factory", NULL};
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izizO", kwlist,
|
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izizO", kwlist,
|
||||||
&oid, &smode, &new_oid, &new_file,
|
&oid, &smode, &new_oid, &new_file,
|
||||||
&factory)) {
|
&factory)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -537,33 +538,13 @@ psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds)
|
||||||
oid, smode);
|
oid, smode);
|
||||||
Dprintf("psyco_conn_lobject: parameters: new_oid = %d, new_file = %s",
|
Dprintf("psyco_conn_lobject: parameters: new_oid = %d, new_file = %s",
|
||||||
new_oid, new_file);
|
new_oid, new_file);
|
||||||
|
|
||||||
/* build a mode number out of the mode string: right now we only accept
|
|
||||||
'r', 'w' and 'rw' (but note that 'w' implies 'rw' because PostgreSQL
|
|
||||||
backend does that. */
|
|
||||||
if (smode) {
|
|
||||||
if (strncmp("rw", smode, 2) == 0)
|
|
||||||
mode = INV_READ+INV_WRITE;
|
|
||||||
else if (smode[0] == 'r')
|
|
||||||
mode = INV_READ;
|
|
||||||
else if (smode[0] == 'w')
|
|
||||||
mode = INV_WRITE;
|
|
||||||
else if (smode[0] == 'n')
|
|
||||||
mode = -1;
|
|
||||||
else {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"mode should be one of 'r', 'w' or 'rw'");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (factory == NULL) factory = (PyObject *)&lobjectType;
|
|
||||||
if (new_file)
|
if (new_file)
|
||||||
obj = PyObject_CallFunction(factory, "Oiiis",
|
obj = PyObject_CallFunction(factory, "Oisis",
|
||||||
self, oid, mode, new_oid, new_file);
|
self, oid, smode, new_oid, new_file);
|
||||||
else
|
else
|
||||||
obj = PyObject_CallFunction(factory, "Oiii",
|
obj = PyObject_CallFunction(factory, "Oisi",
|
||||||
self, oid, mode, new_oid);
|
self, oid, smode, new_oid);
|
||||||
|
|
||||||
if (obj == NULL) return NULL;
|
if (obj == NULL) return NULL;
|
||||||
if (PyObject_IsInstance(obj, (PyObject *)&lobjectType) == 0) {
|
if (PyObject_IsInstance(obj, (PyObject *)&lobjectType) == 0) {
|
||||||
|
@ -572,7 +553,7 @@ psyco_conn_lobject(connectionObject *self, PyObject *args, PyObject *keywds)
|
||||||
Py_DECREF(obj);
|
Py_DECREF(obj);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dprintf("psyco_conn_lobject: new lobject at %p: refcnt = "
|
Dprintf("psyco_conn_lobject: new lobject at %p: refcnt = "
|
||||||
FORMAT_CODE_PY_SSIZE_T,
|
FORMAT_CODE_PY_SSIZE_T,
|
||||||
obj, Py_REFCNT(obj));
|
obj, Py_REFCNT(obj));
|
||||||
|
|
|
@ -42,7 +42,8 @@ typedef struct {
|
||||||
connectionObject *conn; /* connection owning the lobject */
|
connectionObject *conn; /* connection owning the lobject */
|
||||||
long int mark; /* copied from conn->mark */
|
long int mark; /* copied from conn->mark */
|
||||||
|
|
||||||
const char *smode; /* string mode if lobject was opened */
|
char *smode; /* string mode if lobject was opened */
|
||||||
|
int mode; /* numeric version of smode */
|
||||||
|
|
||||||
int fd; /* the file descriptor for file-like ops */
|
int fd; /* the file descriptor for file-like ops */
|
||||||
Oid oid; /* the oid for this lobject */
|
Oid oid; /* the oid for this lobject */
|
||||||
|
@ -51,7 +52,7 @@ typedef struct {
|
||||||
/* functions exported from lobject_int.c */
|
/* functions exported from lobject_int.c */
|
||||||
|
|
||||||
HIDDEN int lobject_open(lobjectObject *self, connectionObject *conn,
|
HIDDEN int lobject_open(lobjectObject *self, connectionObject *conn,
|
||||||
Oid oid, int mode, 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);
|
HIDDEN int lobject_unlink(lobjectObject *self);
|
||||||
HIDDEN int lobject_export(lobjectObject *self, const char *filename);
|
HIDDEN int lobject_export(lobjectObject *self, const char *filename);
|
||||||
|
@ -87,6 +88,12 @@ if (self->conn->mark != self->mark) { \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Values for the lobject mode */
|
||||||
|
#define LOBJECT_READ 1
|
||||||
|
#define LOBJECT_WRITE 2
|
||||||
|
#define LOBJECT_BINARY 4
|
||||||
|
#define LOBJECT_TEXT 8
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,15 +43,118 @@ collect_error(connectionObject *conn, char **error)
|
||||||
*error = strdup(msg);
|
*error = strdup(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check if the mode passed to the large object is valid.
|
||||||
|
* In case of success return a value >= 0
|
||||||
|
* On error return a value < 0 and set an exception.
|
||||||
|
*
|
||||||
|
* Valid mode are [r|w|rw|n][t|b]
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
_lobject_parse_mode(const char *mode)
|
||||||
|
{
|
||||||
|
int rv = 0;
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
if (0 == strncmp("rw", mode, 2)) {
|
||||||
|
rv |= LOBJECT_READ | LOBJECT_WRITE;
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (mode[0]) {
|
||||||
|
case 'r':
|
||||||
|
rv |= LOBJECT_READ;
|
||||||
|
pos += 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
rv |= LOBJECT_WRITE;
|
||||||
|
pos += 1;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
pos += 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rv |= LOBJECT_READ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode[pos]) {
|
||||||
|
case 't':
|
||||||
|
rv |= LOBJECT_TEXT;
|
||||||
|
pos += 1;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
rv |= LOBJECT_BINARY;
|
||||||
|
pos += 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
rv |= LOBJECT_BINARY;
|
||||||
|
#else
|
||||||
|
rv |= LOBJECT_TEXT;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos != strlen(mode)) {
|
||||||
|
PyErr_Format(PyExc_ValueError,
|
||||||
|
"bad mode for lobject: '%s'", mode);
|
||||||
|
rv = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return a string representing the lobject mode.
|
||||||
|
*
|
||||||
|
* The return value is a new string allocated on the Python heap.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
_lobject_unparse_mode(int mode)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
char *c;
|
||||||
|
|
||||||
|
/* the longest is 'rwt' */
|
||||||
|
c = buf = PyMem_Malloc(4);
|
||||||
|
|
||||||
|
if (mode & LOBJECT_READ) { *c++ = 'r'; }
|
||||||
|
if (mode & LOBJECT_WRITE) { *c++ = 'w'; }
|
||||||
|
|
||||||
|
if (buf == c) {
|
||||||
|
/* neither read nor write */
|
||||||
|
*c++ = 'n';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (mode & LOBJECT_TEXT) {
|
||||||
|
*c++ = 't';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*c++ = 'b';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*c = '\0';
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
/* lobject_open - create a new/open an existing lo */
|
/* lobject_open - create a new/open an existing lo */
|
||||||
|
|
||||||
int
|
int
|
||||||
lobject_open(lobjectObject *self, connectionObject *conn,
|
lobject_open(lobjectObject *self, connectionObject *conn,
|
||||||
Oid oid, int mode, Oid new_oid, const char *new_file)
|
Oid oid, const char *smode, Oid new_oid, const char *new_file)
|
||||||
{
|
{
|
||||||
int retvalue = -1;
|
int retvalue = -1;
|
||||||
PGresult *pgres = NULL;
|
PGresult *pgres = NULL;
|
||||||
char *error = NULL;
|
char *error = NULL;
|
||||||
|
int pgmode = 0;
|
||||||
|
int mode;
|
||||||
|
|
||||||
|
if (0 > (mode = _lobject_parse_mode(smode))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
pthread_mutex_lock(&(self->conn->lock));
|
pthread_mutex_lock(&(self->conn->lock));
|
||||||
|
@ -78,19 +181,19 @@ lobject_open(lobjectObject *self, connectionObject *conn,
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
mode = INV_WRITE;
|
mode = (mode & ~LOBJECT_READ) | LOBJECT_WRITE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self->oid = oid;
|
self->oid = oid;
|
||||||
if (mode == 0) mode = INV_READ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if the oid is a real one we try to open with the given mode,
|
/* if the oid is a real one we try to open with the given mode */
|
||||||
unless the mode is -1, meaning "don't open!" */
|
if (mode & LOBJECT_READ) { pgmode |= INV_READ; }
|
||||||
if (mode != -1) {
|
if (mode & LOBJECT_WRITE) { pgmode |= INV_WRITE; }
|
||||||
self->fd = lo_open(self->conn->pgconn, self->oid, mode);
|
if (pgmode) {
|
||||||
Dprintf("lobject_open: large object opened with fd = %d",
|
self->fd = lo_open(self->conn->pgconn, self->oid, pgmode);
|
||||||
self->fd);
|
Dprintf("lobject_open: large object opened with mode = %i fd = %d",
|
||||||
|
pgmode, self->fd);
|
||||||
|
|
||||||
if (self->fd == -1) {
|
if (self->fd == -1) {
|
||||||
collect_error(self->conn, &error);
|
collect_error(self->conn, &error);
|
||||||
|
@ -98,17 +201,10 @@ lobject_open(lobjectObject *self, connectionObject *conn,
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set the mode for future reference */
|
/* set the mode for future reference */
|
||||||
switch (mode) {
|
self->mode = mode;
|
||||||
case -1:
|
self->smode = _lobject_unparse_mode(mode);
|
||||||
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;
|
retvalue = 0;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
|
|
@ -277,7 +277,7 @@ static struct PyMemberDef lobjectObject_members[] = {
|
||||||
{"oid", T_UINT, offsetof(lobjectObject, oid), READONLY,
|
{"oid", T_UINT, offsetof(lobjectObject, oid), READONLY,
|
||||||
"The backend OID associated to this lobject."},
|
"The backend OID associated to this lobject."},
|
||||||
{"mode", T_STRING, offsetof(lobjectObject, smode), READONLY,
|
{"mode", T_STRING, offsetof(lobjectObject, smode), READONLY,
|
||||||
"Open mode ('r', 'w', 'rw' or 'n')."},
|
"Open mode."},
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ static struct PyGetSetDef lobjectObject_getsets[] = {
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lobject_setup(lobjectObject *self, connectionObject *conn,
|
lobject_setup(lobjectObject *self, connectionObject *conn,
|
||||||
Oid oid, int mode, Oid new_oid, const char *new_file)
|
Oid oid, const char *smode, Oid new_oid, const char *new_file)
|
||||||
{
|
{
|
||||||
Dprintf("lobject_setup: init lobject object at %p", self);
|
Dprintf("lobject_setup: init lobject object at %p", self);
|
||||||
|
|
||||||
|
@ -311,7 +311,7 @@ lobject_setup(lobjectObject *self, connectionObject *conn,
|
||||||
self->fd = -1;
|
self->fd = -1;
|
||||||
self->oid = InvalidOid;
|
self->oid = InvalidOid;
|
||||||
|
|
||||||
if (lobject_open(self, conn, oid, mode, new_oid, new_file) == -1)
|
if (lobject_open(self, conn, oid, smode, new_oid, new_file) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
Dprintf("lobject_setup: good lobject object at %p, refcnt = "
|
Dprintf("lobject_setup: good lobject object at %p, refcnt = "
|
||||||
|
@ -328,6 +328,7 @@ lobject_dealloc(PyObject* obj)
|
||||||
if (lobject_close(self) < 0)
|
if (lobject_close(self) < 0)
|
||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
Py_XDECREF((PyObject*)self->conn);
|
Py_XDECREF((PyObject*)self->conn);
|
||||||
|
PyMem_Free(self->smode);
|
||||||
|
|
||||||
Dprintf("lobject_dealloc: deleted lobject object at %p, refcnt = "
|
Dprintf("lobject_dealloc: deleted lobject object at %p, refcnt = "
|
||||||
FORMAT_CODE_PY_SSIZE_T, obj, Py_REFCNT(obj));
|
FORMAT_CODE_PY_SSIZE_T, obj, Py_REFCNT(obj));
|
||||||
|
@ -339,16 +340,16 @@ static int
|
||||||
lobject_init(PyObject *obj, PyObject *args, PyObject *kwds)
|
lobject_init(PyObject *obj, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
Oid oid=InvalidOid, new_oid=InvalidOid;
|
Oid oid=InvalidOid, new_oid=InvalidOid;
|
||||||
int mode=0;
|
const char *smode = "";
|
||||||
const char *new_file = NULL;
|
const char *new_file = NULL;
|
||||||
PyObject *conn;
|
PyObject *conn;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O|iiis",
|
if (!PyArg_ParseTuple(args, "O|iziz",
|
||||||
&conn, &oid, &mode, &new_oid, &new_file))
|
&conn, &oid, &smode, &new_oid, &new_file))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return lobject_setup((lobjectObject *)obj,
|
return lobject_setup((lobjectObject *)obj,
|
||||||
(connectionObject *)conn, oid, mode, new_oid, new_file);
|
(connectionObject *)conn, oid, smode, new_oid, new_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
|
|
@ -84,7 +84,7 @@ class LargeObjectTests(LargeObjectMixin, unittest.TestCase):
|
||||||
def test_create(self):
|
def test_create(self):
|
||||||
lo = self.conn.lobject()
|
lo = self.conn.lobject()
|
||||||
self.assertNotEqual(lo, None)
|
self.assertNotEqual(lo, None)
|
||||||
self.assertEqual(lo.mode, "w")
|
self.assertEqual(lo.mode[0], "w")
|
||||||
|
|
||||||
def test_open_non_existent(self):
|
def test_open_non_existent(self):
|
||||||
# By creating then removing a large object, we get an Oid that
|
# By creating then removing a large object, we get an Oid that
|
||||||
|
@ -98,12 +98,12 @@ class LargeObjectTests(LargeObjectMixin, unittest.TestCase):
|
||||||
lo2 = self.conn.lobject(lo.oid)
|
lo2 = self.conn.lobject(lo.oid)
|
||||||
self.assertNotEqual(lo2, None)
|
self.assertNotEqual(lo2, None)
|
||||||
self.assertEqual(lo2.oid, lo.oid)
|
self.assertEqual(lo2.oid, lo.oid)
|
||||||
self.assertEqual(lo2.mode, "r")
|
self.assertEqual(lo2.mode[0], "r")
|
||||||
|
|
||||||
def test_open_for_write(self):
|
def test_open_for_write(self):
|
||||||
lo = self.conn.lobject()
|
lo = self.conn.lobject()
|
||||||
lo2 = self.conn.lobject(lo.oid, "w")
|
lo2 = self.conn.lobject(lo.oid, "w")
|
||||||
self.assertEqual(lo2.mode, "w")
|
self.assertEqual(lo2.mode[0], "w")
|
||||||
lo2.write(b("some data"))
|
lo2.write(b("some data"))
|
||||||
|
|
||||||
def test_open_mode_n(self):
|
def test_open_mode_n(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user