mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-23 01:16:34 +03:00
Modify truncate to use lo_truncate64. Use HAVE_LO64 define to use new lo_*64 methods. Check size of offset and length for versions without LO64.
This commit is contained in:
parent
e13ec67da3
commit
cd67d3d2fe
|
@ -389,7 +389,11 @@ lobject_seek(lobjectObject *self, long pos, int whence)
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
pthread_mutex_lock(&(self->conn->lock));
|
pthread_mutex_lock(&(self->conn->lock));
|
||||||
|
|
||||||
|
#if HAVE_LO64
|
||||||
where = lo_lseek64(self->conn->pgconn, self->fd, pos, whence);
|
where = lo_lseek64(self->conn->pgconn, self->fd, pos, whence);
|
||||||
|
#else
|
||||||
|
where = (long)lo_lseek(self->conn->pgconn, self->fd, (int)pos, whence);
|
||||||
|
#endif
|
||||||
Dprintf("lobject_seek: where = %Ld", where);
|
Dprintf("lobject_seek: where = %Ld", where);
|
||||||
if (where < 0)
|
if (where < 0)
|
||||||
collect_error(self->conn, &error);
|
collect_error(self->conn, &error);
|
||||||
|
@ -416,7 +420,11 @@ lobject_tell(lobjectObject *self)
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
pthread_mutex_lock(&(self->conn->lock));
|
pthread_mutex_lock(&(self->conn->lock));
|
||||||
|
|
||||||
|
#if HAVE_LO64
|
||||||
where = lo_tell64(self->conn->pgconn, self->fd);
|
where = lo_tell64(self->conn->pgconn, self->fd);
|
||||||
|
#else
|
||||||
|
where = (long)lo_tell(self->conn->pgconn, self->fd);
|
||||||
|
#endif
|
||||||
Dprintf("lobject_tell: where = %Ld", where);
|
Dprintf("lobject_tell: where = %Ld", where);
|
||||||
if (where < 0)
|
if (where < 0)
|
||||||
collect_error(self->conn, &error);
|
collect_error(self->conn, &error);
|
||||||
|
@ -473,7 +481,11 @@ lobject_truncate(lobjectObject *self, size_t len)
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
pthread_mutex_lock(&(self->conn->lock));
|
pthread_mutex_lock(&(self->conn->lock));
|
||||||
|
|
||||||
|
#if HAVE_LO64
|
||||||
|
retvalue = lo_truncate64(self->conn->pgconn, self->fd, len);
|
||||||
|
#else
|
||||||
retvalue = lo_truncate(self->conn->pgconn, self->fd, len);
|
retvalue = lo_truncate(self->conn->pgconn, self->fd, len);
|
||||||
|
#endif
|
||||||
Dprintf("lobject_truncate: result = %d", retvalue);
|
Dprintf("lobject_truncate: result = %d", retvalue);
|
||||||
if (retvalue < 0)
|
if (retvalue < 0)
|
||||||
collect_error(self->conn, &error);
|
collect_error(self->conn, &error);
|
||||||
|
|
|
@ -175,6 +175,14 @@ psyco_lobj_seek(lobjectObject *self, PyObject *args)
|
||||||
EXC_IF_LOBJ_LEVEL0(self);
|
EXC_IF_LOBJ_LEVEL0(self);
|
||||||
EXC_IF_LOBJ_UNMARKED(self);
|
EXC_IF_LOBJ_UNMARKED(self);
|
||||||
|
|
||||||
|
#if !HAVE_LO64
|
||||||
|
if (offset > INT_MAX) {
|
||||||
|
psyco_set_error(InterfaceError, NULL,
|
||||||
|
"offset out of range");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((pos = lobject_seek(self, offset, whence)) < 0)
|
if ((pos = lobject_seek(self, offset, whence)) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -255,15 +263,23 @@ psyco_lobj_get_closed(lobjectObject *self, void *closure)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psyco_lobj_truncate(lobjectObject *self, PyObject *args)
|
psyco_lobj_truncate(lobjectObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
int len = 0;
|
long len = 0;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|i", &len))
|
if (!PyArg_ParseTuple(args, "|l", &len))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
EXC_IF_LOBJ_CLOSED(self);
|
EXC_IF_LOBJ_CLOSED(self);
|
||||||
EXC_IF_LOBJ_LEVEL0(self);
|
EXC_IF_LOBJ_LEVEL0(self);
|
||||||
EXC_IF_LOBJ_UNMARKED(self);
|
EXC_IF_LOBJ_UNMARKED(self);
|
||||||
|
|
||||||
|
#if !HAVE_LO64
|
||||||
|
if (len > INT_MAX) {
|
||||||
|
psyco_set_error(InterfaceError, NULL,
|
||||||
|
"len out of range");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (lobject_truncate(self, len) < 0)
|
if (lobject_truncate(self, len) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
7
setup.py
7
setup.py
|
@ -415,6 +415,13 @@ class psycopg_build_ext(build_ext):
|
||||||
|
|
||||||
define_macros.append(("PG_VERSION_HEX", "0x%02X%02X%02X" %
|
define_macros.append(("PG_VERSION_HEX", "0x%02X%02X%02X" %
|
||||||
(int(pgmajor), int(pgminor), int(pgpatch))))
|
(int(pgmajor), int(pgminor), int(pgpatch))))
|
||||||
|
|
||||||
|
# enable lo64 if postgres >= 9.3
|
||||||
|
if int(pgmajor) >= 9 and int(pgminor) >= 3:
|
||||||
|
define_macros.append(("HAVE_LO64", "1"))
|
||||||
|
else:
|
||||||
|
define_macros.append(("HAVE_LO64", "0"))
|
||||||
|
|
||||||
except Warning:
|
except Warning:
|
||||||
w = sys.exc_info()[1] # work around py 2/3 different syntax
|
w = sys.exc_info()[1] # work around py 2/3 different syntax
|
||||||
sys.stderr.write("Error: %s\n" % w)
|
sys.stderr.write("Error: %s\n" % w)
|
||||||
|
|
|
@ -225,24 +225,6 @@ class LargeObjectTests(LargeObjectTestCase):
|
||||||
self.assertEqual(lo.seek(-2, 2), length - 2)
|
self.assertEqual(lo.seek(-2, 2), length - 2)
|
||||||
self.assertEqual(lo.read(), "ta")
|
self.assertEqual(lo.read(), "ta")
|
||||||
|
|
||||||
def test_seek_tell_greater_than_2gb(self):
|
|
||||||
lo = self.conn.lobject()
|
|
||||||
|
|
||||||
# write chunks until its 3gb
|
|
||||||
length = 0
|
|
||||||
for _ in range(24):
|
|
||||||
# each chunk is written with 128mb
|
|
||||||
length += lo.write("data" * (1 << 25))
|
|
||||||
self.assertEqual(lo.tell(), length)
|
|
||||||
lo.close()
|
|
||||||
lo = self.conn.lobject(lo.oid)
|
|
||||||
|
|
||||||
# seek to 3gb - 4, last written text should be data
|
|
||||||
offset = (1 << 31) + (1 << 30) - 4 # 2gb + 1gb - 4
|
|
||||||
self.assertEqual(lo.seek(offset, 0), offset)
|
|
||||||
self.assertEqual(lo.tell(), offset)
|
|
||||||
self.assertEqual(lo.read(), "data")
|
|
||||||
|
|
||||||
def test_unlink(self):
|
def test_unlink(self):
|
||||||
lo = self.conn.lobject()
|
lo = self.conn.lobject()
|
||||||
lo.unlink()
|
lo.unlink()
|
||||||
|
@ -458,6 +440,55 @@ decorate_all_tests(LargeObjectTruncateTests,
|
||||||
skip_if_no_lo, skip_lo_if_green, skip_if_no_truncate)
|
skip_if_no_lo, skip_lo_if_green, skip_if_no_truncate)
|
||||||
|
|
||||||
|
|
||||||
|
def skip_if_no_lo64(f):
|
||||||
|
@wraps(f)
|
||||||
|
def skip_if_no_lo64_(self):
|
||||||
|
if self.conn.server_version < 90300:
|
||||||
|
return self.skipTest("large objects 64bit only supported from PG 9.3")
|
||||||
|
else:
|
||||||
|
return f(self)
|
||||||
|
|
||||||
|
return skip_if_no_lo64_
|
||||||
|
|
||||||
|
class LargeObject64Tests(LargeObjectTestCase):
|
||||||
|
def test_seek_tell_truncate_greater_than_2gb(self):
|
||||||
|
lo = self.conn.lobject()
|
||||||
|
|
||||||
|
length = (1 << 31) + (1 << 30) # 2gb + 1gb = 3gb
|
||||||
|
lo.truncate(length)
|
||||||
|
|
||||||
|
self.assertEqual(lo.seek(length, 0), length)
|
||||||
|
self.assertEqual(lo.tell(), length)
|
||||||
|
|
||||||
|
decorate_all_tests(LargeObject64Tests,
|
||||||
|
skip_if_no_lo, skip_lo_if_green, skip_if_no_truncate, skip_if_no_lo64)
|
||||||
|
|
||||||
|
|
||||||
|
def skip_if_lo64(f):
|
||||||
|
@wraps(f)
|
||||||
|
def skip_if_lo64_(self):
|
||||||
|
if self.conn.server_version >= 90300:
|
||||||
|
return self.skipTest("large objects 64bit only supported from PG 9.3")
|
||||||
|
else:
|
||||||
|
return f(self)
|
||||||
|
|
||||||
|
return skip_if_lo64_
|
||||||
|
|
||||||
|
class LargeObjectNot64Tests(LargeObjectTestCase):
|
||||||
|
def test_seek_larger_than_2gb(self):
|
||||||
|
lo = self.conn.lobject()
|
||||||
|
offset = 1 << 32 # 4gb
|
||||||
|
self.assertRaises(psycopg2.InterfaceError, lo.seek, offset, 0)
|
||||||
|
|
||||||
|
def test_truncate_larger_than_2gb(self):
|
||||||
|
lo = self.conn.lobject()
|
||||||
|
length = 1 << 32 # 4gb
|
||||||
|
self.assertRaises(psycopg2.InterfaceError, lo.truncate, length)
|
||||||
|
|
||||||
|
decorate_all_tests(LargeObjectNot64Tests,
|
||||||
|
skip_if_no_lo, skip_lo_if_green, skip_if_no_truncate, skip_if_lo64)
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
def test_suite():
|
||||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user