mirror of
				https://github.com/psycopg/psycopg2.git
				synced 2025-10-30 23:37:29 +03:00 
			
		
		
		
	Merge branch 'lo64'
This commit is contained in:
		
						commit
						b5ac992944
					
				
							
								
								
									
										4
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								NEWS
									
									
									
									
									
								
							|  | @ -4,6 +4,10 @@ Current release | ||||||
| What's new in psycopg 2.6 | What's new in psycopg 2.6 | ||||||
| ------------------------- | ------------------------- | ||||||
| 
 | 
 | ||||||
|  | New features: | ||||||
|  | 
 | ||||||
|  | - Added support for large objects larger than 2GB. | ||||||
|  | 
 | ||||||
| Bug fixes: | Bug fixes: | ||||||
| 
 | 
 | ||||||
| - Json apapter's `!str()` returns the adapted content instead of the `!repr()` | - Json apapter's `!str()` returns the adapted content instead of the `!repr()` | ||||||
|  |  | ||||||
|  | @ -47,11 +47,13 @@ functionalities defined by the |DBAPI|_. | ||||||
| 
 | 
 | ||||||
|         Database OID of the object. |         Database OID of the object. | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     .. attribute:: mode |     .. attribute:: mode | ||||||
| 
 | 
 | ||||||
|         The mode the database was open. See `connection.lobject()` for a |         The mode the database was open. See `connection.lobject()` for a | ||||||
|         description of the available modes. |         description of the available modes. | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     .. method:: read(bytes=-1) |     .. method:: read(bytes=-1) | ||||||
| 
 | 
 | ||||||
|         Read a chunk of data from the current file position. If -1 (default) |         Read a chunk of data from the current file position. If -1 (default) | ||||||
|  | @ -64,6 +66,7 @@ functionalities defined by the |DBAPI|_. | ||||||
|         .. versionchanged:: 2.4 |         .. versionchanged:: 2.4 | ||||||
|             added Unicode support. |             added Unicode support. | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     .. method:: write(str) |     .. method:: write(str) | ||||||
| 
 | 
 | ||||||
|         Write a string to the large object. Return the number of bytes |         Write a string to the large object. Return the number of bytes | ||||||
|  | @ -73,6 +76,7 @@ functionalities defined by the |DBAPI|_. | ||||||
|         .. versionchanged:: 2.4 |         .. versionchanged:: 2.4 | ||||||
|             added Unicode support. |             added Unicode support. | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     .. method:: export(file_name) |     .. method:: export(file_name) | ||||||
| 
 | 
 | ||||||
|         Export the large object content to the file system. |         Export the large object content to the file system. | ||||||
|  | @ -82,33 +86,50 @@ functionalities defined by the |DBAPI|_. | ||||||
|         .. |lo_export| replace:: `!lo_export()` |         .. |lo_export| replace:: `!lo_export()` | ||||||
|         .. _lo_export: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-EXPORT |         .. _lo_export: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-EXPORT | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|     .. method:: seek(offset, whence=0) |     .. method:: seek(offset, whence=0) | ||||||
| 
 | 
 | ||||||
|         Set the lobject current position. |         Set the lobject current position. | ||||||
| 
 | 
 | ||||||
|  |         .. versionchanged:: 2.6.0 | ||||||
|  |             added support for *offset* > 2GB. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     .. method:: tell() |     .. method:: tell() | ||||||
| 
 | 
 | ||||||
|         Return the lobject current position. |         Return the lobject current position. | ||||||
| 
 | 
 | ||||||
|     .. method:: truncate(len=0) |  | ||||||
| 
 |  | ||||||
|         .. versionadded:: 2.2.0 |         .. versionadded:: 2.2.0 | ||||||
| 
 | 
 | ||||||
|  |         .. versionchanged:: 2.6.0 | ||||||
|  |             added support for return value > 2GB. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     .. method:: truncate(len=0) | ||||||
|  | 
 | ||||||
|         Truncate the lobject to the given size. |         Truncate the lobject to the given size. | ||||||
| 
 | 
 | ||||||
|         The method will only be available if Psycopg has been built against libpq |         The method will only be available if Psycopg has been built against | ||||||
|         from PostgreSQL 8.3 or later and can only be used with PostgreSQL servers |         libpq from PostgreSQL 8.3 or later and can only be used with | ||||||
|         running these versions. It uses the |lo_truncate|_ libpq function. |         PostgreSQL servers running these versions. It uses the |lo_truncate|_ | ||||||
|  |         libpq function. | ||||||
| 
 | 
 | ||||||
|         .. |lo_truncate| replace:: `!lo_truncate()` |         .. |lo_truncate| replace:: `!lo_truncate()` | ||||||
|         .. _lo_truncate: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-TRUNCATE |         .. _lo_truncate: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-TRUNCATE | ||||||
| 
 | 
 | ||||||
|  |         .. versionadded:: 2.2.0 | ||||||
|  | 
 | ||||||
|  |         .. versionchanged:: 2.6.0 | ||||||
|  |             added support for *len* > 2GB. | ||||||
|  | 
 | ||||||
|     .. warning:: |     .. warning:: | ||||||
| 
 | 
 | ||||||
|             If Psycopg is built with |lo_truncate| support (i.e. if the |         If Psycopg is built with |lo_truncate| support or with the 64 bits API | ||||||
|             :program:`pg_config` used during setup is version >= 8.3), but at |         support (resp. from PostgreSQL versions 8.3 and 9.3) but at runtime an | ||||||
|             runtime an older libpq is found, Psycopg will fail to import.  See |         older version of the dynamic library is found, the ``psycopg2`` module | ||||||
|             :ref:`the lo_truncate FAQ <faq-lo_truncate>` about the problem. |         will fail to import.  See :ref:`the lo_truncate FAQ <faq-lo_truncate>` | ||||||
|  |         about the problem. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     .. method:: close() |     .. method:: close() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -248,13 +248,20 @@ I can't compile `!psycopg2`: the compiler says *error: libpq-fe.h: No such file | ||||||
| .. cssclass:: faq | .. cssclass:: faq | ||||||
| 
 | 
 | ||||||
| `!psycopg2` raises `!ImportError` with message *_psycopg.so: undefined symbol: lo_truncate* when imported. | `!psycopg2` raises `!ImportError` with message *_psycopg.so: undefined symbol: lo_truncate* when imported. | ||||||
|     This means that Psycopg has been compiled with |lo_truncate|_ support, |     This means that Psycopg was compiled with |lo_truncate|_ support (*i.e.* | ||||||
|     which means that the libpq used at compile time was version >= 8.3, but at |     the libpq used at compile time was version >= 8.3) but at runtime an older | ||||||
|     runtime an older libpq library is found. You can use:: |     libpq dynamic library is found. | ||||||
|  | 
 | ||||||
|  |     Fast-forward several years, if the message reports *undefined symbol: | ||||||
|  |     lo_truncate64* it means that Psycopg was built with large objects 64 bits | ||||||
|  |     API support (*i.e.* the libpq used at compile time was at least 9.3) but | ||||||
|  |     at runtime an older libpq dynamic library is found. | ||||||
|  | 
 | ||||||
|  |     You can use:: | ||||||
| 
 | 
 | ||||||
|         $ ldd /path/to/packages/psycopg2/_psycopg.so | grep libpq |         $ ldd /path/to/packages/psycopg2/_psycopg.so | grep libpq | ||||||
| 
 | 
 | ||||||
|     to find what is the version used at runtime. |     to find what is the libpq dynamic library used at runtime. | ||||||
| 
 | 
 | ||||||
|     You can avoid the problem by using the same version of the |     You can avoid the problem by using the same version of the | ||||||
|     :program:`pg_config` at install time and the libpq at runtime. |     :program:`pg_config` at install time and the libpq at runtime. | ||||||
|  |  | ||||||
|  | @ -899,6 +899,18 @@ using the |lo_import|_ and |lo_export|_ libpq functions. | ||||||
| .. |lo_export| replace:: `!lo_export()` | .. |lo_export| replace:: `!lo_export()` | ||||||
| .. _lo_export: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-EXPORT | .. _lo_export: http://www.postgresql.org/docs/current/static/lo-interfaces.html#LO-EXPORT | ||||||
| 
 | 
 | ||||||
|  | .. versionchanged:: 2.6 | ||||||
|  |     added support for large objects greated than 2GB. Note that the support is | ||||||
|  |     enabled only if both these conditions are verified: | ||||||
|  | 
 | ||||||
|  |     - the extension was built against libpq at least 9.3 (you can check if | ||||||
|  |       `psycopg2.__version__` contains the ``lo64`` flag); | ||||||
|  |     - the server version is at least PostgreSQL 9.3 | ||||||
|  |       (`~connection.server_version` must be >= ``90300``). | ||||||
|  | 
 | ||||||
|  |     If the contitions are not met several `!lobject` methods will fail if the | ||||||
|  |     arguments exceed 2GB. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. index:: | .. index:: | ||||||
|  |  | ||||||
|  | @ -60,8 +60,8 @@ RAISES_NEG HIDDEN int lobject_export(lobjectObject *self, const char *filename); | ||||||
| RAISES_NEG HIDDEN Py_ssize_t lobject_read(lobjectObject *self, char *buf, size_t len); | RAISES_NEG HIDDEN Py_ssize_t lobject_read(lobjectObject *self, char *buf, size_t len); | ||||||
| RAISES_NEG 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); | ||||||
| RAISES_NEG HIDDEN int lobject_seek(lobjectObject *self, int pos, int whence); | RAISES_NEG HIDDEN long lobject_seek(lobjectObject *self, long pos, int whence); | ||||||
| RAISES_NEG HIDDEN int lobject_tell(lobjectObject *self); | RAISES_NEG HIDDEN long lobject_tell(lobjectObject *self); | ||||||
| RAISES_NEG HIDDEN int lobject_truncate(lobjectObject *self, size_t len); | RAISES_NEG HIDDEN int lobject_truncate(lobjectObject *self, size_t len); | ||||||
| RAISES_NEG HIDDEN int lobject_close(lobjectObject *self); | RAISES_NEG HIDDEN int lobject_close(lobjectObject *self); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -376,21 +376,29 @@ 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 */ | ||||||
| 
 | 
 | ||||||
| RAISES_NEG int | RAISES_NEG long | ||||||
| lobject_seek(lobjectObject *self, int pos, int whence) | lobject_seek(lobjectObject *self, long pos, int whence) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|     char *error = NULL; |     char *error = NULL; | ||||||
|     int where; |     long where; | ||||||
| 
 | 
 | ||||||
|     Dprintf("lobject_seek: fd = %d, pos = %d, whence = %d", |     Dprintf("lobject_seek: fd = %d, pos = %ld, whence = %d", | ||||||
|             self->fd, pos, whence); |             self->fd, pos, whence); | ||||||
| 
 | 
 | ||||||
|     Py_BEGIN_ALLOW_THREADS; |     Py_BEGIN_ALLOW_THREADS; | ||||||
|     pthread_mutex_lock(&(self->conn->lock)); |     pthread_mutex_lock(&(self->conn->lock)); | ||||||
| 
 | 
 | ||||||
|     where = lo_lseek(self->conn->pgconn, self->fd, pos, whence); | #ifdef HAVE_LO64 | ||||||
|     Dprintf("lobject_seek: where = %d", where); |     if (self->conn->server_version < 90300) { | ||||||
|  |         where = (long)lo_lseek(self->conn->pgconn, self->fd, (int)pos, whence); | ||||||
|  |     } else { | ||||||
|  |         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); | ||||||
|     if (where < 0) |     if (where < 0) | ||||||
|         collect_error(self->conn, &error); |         collect_error(self->conn, &error); | ||||||
| 
 | 
 | ||||||
|  | @ -404,20 +412,28 @@ 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 */ | ||||||
| 
 | 
 | ||||||
| RAISES_NEG int | RAISES_NEG long | ||||||
| lobject_tell(lobjectObject *self) | lobject_tell(lobjectObject *self) | ||||||
| { | { | ||||||
|     PGresult *pgres = NULL; |     PGresult *pgres = NULL; | ||||||
|     char *error = NULL; |     char *error = NULL; | ||||||
|     int where; |     long where; | ||||||
| 
 | 
 | ||||||
|     Dprintf("lobject_tell: fd = %d", self->fd); |     Dprintf("lobject_tell: fd = %d", self->fd); | ||||||
| 
 | 
 | ||||||
|     Py_BEGIN_ALLOW_THREADS; |     Py_BEGIN_ALLOW_THREADS; | ||||||
|     pthread_mutex_lock(&(self->conn->lock)); |     pthread_mutex_lock(&(self->conn->lock)); | ||||||
| 
 | 
 | ||||||
|     where = lo_tell(self->conn->pgconn, self->fd); | #ifdef HAVE_LO64 | ||||||
|     Dprintf("lobject_tell: where = %d", where); |     if (self->conn->server_version < 90300) { | ||||||
|  |         where = (long)lo_tell(self->conn->pgconn, self->fd); | ||||||
|  |     } else { | ||||||
|  |         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); | ||||||
|     if (where < 0) |     if (where < 0) | ||||||
|         collect_error(self->conn, &error); |         collect_error(self->conn, &error); | ||||||
| 
 | 
 | ||||||
|  | @ -473,7 +489,15 @@ 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)); | ||||||
| 
 | 
 | ||||||
|  | #ifdef HAVE_LO64 | ||||||
|  |     if (self->conn->server_version < 90300) { | ||||||
|         retvalue = lo_truncate(self->conn->pgconn, self->fd, len); |         retvalue = lo_truncate(self->conn->pgconn, self->fd, len); | ||||||
|  |     } else { | ||||||
|  |         retvalue = lo_truncate64(self->conn->pgconn, self->fd, len); | ||||||
|  |     } | ||||||
|  | #else | ||||||
|  |     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); | ||||||
|  |  | ||||||
|  | @ -121,7 +121,7 @@ static PyObject * | ||||||
| psyco_lobj_read(lobjectObject *self, PyObject *args) | psyco_lobj_read(lobjectObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     PyObject *res; |     PyObject *res; | ||||||
|     int where, end; |     long where, end; | ||||||
|     Py_ssize_t size = -1; |     Py_ssize_t size = -1; | ||||||
|     char *buffer; |     char *buffer; | ||||||
| 
 | 
 | ||||||
|  | @ -165,20 +165,39 @@ psyco_lobj_read(lobjectObject *self, PyObject *args) | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_lobj_seek(lobjectObject *self, PyObject *args) | psyco_lobj_seek(lobjectObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     int offset, whence=0; |     long offset, pos=0; | ||||||
|     int pos=0; |     int whence=0; | ||||||
| 
 | 
 | ||||||
|     if (!PyArg_ParseTuple(args, "i|i", &offset, &whence)) |     if (!PyArg_ParseTuple(args, "l|i", &offset, &whence)) | ||||||
|         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); | ||||||
| 
 | 
 | ||||||
|  | #ifdef HAVE_LO64 | ||||||
|  |     if ((offset < INT_MIN || offset > INT_MAX) | ||||||
|  |             && self->conn->server_version < 90300) { | ||||||
|  |         PyErr_Format(NotSupportedError, | ||||||
|  |             "offset out of range (%ld): server version %d " | ||||||
|  |             "does not support the lobject 64 API", | ||||||
|  |             offset, self->conn->server_version); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  | #else | ||||||
|  |     if (offset < INT_MIN || offset > INT_MAX) { | ||||||
|  |         PyErr_Format(InterfaceError, | ||||||
|  |             "offset out of range (%ld): this psycopg version was not built " | ||||||
|  |             "with lobject 64 API support", | ||||||
|  |             offset); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|     if ((pos = lobject_seek(self, offset, whence)) < 0) |     if ((pos = lobject_seek(self, offset, whence)) < 0) | ||||||
|         return NULL; |         return NULL; | ||||||
| 
 | 
 | ||||||
|     return PyInt_FromLong((long)pos); |     return PyLong_FromLong(pos); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* tell method - tell current position in the lobject */ | /* tell method - tell current position in the lobject */ | ||||||
|  | @ -189,7 +208,7 @@ psyco_lobj_seek(lobjectObject *self, PyObject *args) | ||||||
| static PyObject * | static PyObject * | ||||||
| psyco_lobj_tell(lobjectObject *self, PyObject *args) | psyco_lobj_tell(lobjectObject *self, PyObject *args) | ||||||
| { | { | ||||||
|     int pos; |     long pos; | ||||||
| 
 | 
 | ||||||
|     EXC_IF_LOBJ_CLOSED(self); |     EXC_IF_LOBJ_CLOSED(self); | ||||||
|     EXC_IF_LOBJ_LEVEL0(self); |     EXC_IF_LOBJ_LEVEL0(self); | ||||||
|  | @ -198,7 +217,7 @@ psyco_lobj_tell(lobjectObject *self, PyObject *args) | ||||||
|     if ((pos = lobject_tell(self)) < 0) |     if ((pos = lobject_tell(self)) < 0) | ||||||
|         return NULL; |         return NULL; | ||||||
| 
 | 
 | ||||||
|     return PyInt_FromLong((long)pos); |     return PyLong_FromLong(pos); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* unlink method - unlink (destroy) the lobject */ | /* unlink method - unlink (destroy) the lobject */ | ||||||
|  | @ -255,15 +274,33 @@ 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); | ||||||
| 
 | 
 | ||||||
|  | #ifdef HAVE_LO64 | ||||||
|  |     if (len > INT_MAX && self->conn->server_version < 90300) { | ||||||
|  |         PyErr_Format(NotSupportedError, | ||||||
|  |             "len out of range (%ld): server version %d " | ||||||
|  |             "does not support the lobject 64 API", | ||||||
|  |             len, self->conn->server_version); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  | #else | ||||||
|  |     if (len > INT_MAX) { | ||||||
|  |         PyErr_Format(InterfaceError, | ||||||
|  |             "len out of range (%ld): this psycopg version was not built " | ||||||
|  |             "with lobject 64 API support", | ||||||
|  |             len); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|     if (lobject_truncate(self, len) < 0) |     if (lobject_truncate(self, len) < 0) | ||||||
|         return NULL; |         return NULL; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										20
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								setup.py
									
									
									
									
									
								
							|  | @ -407,6 +407,9 @@ class psycopg_build_ext(build_ext): | ||||||
|                 pgmajor, pgminor, pgpatch = m.group(1, 2, 3) |                 pgmajor, pgminor, pgpatch = m.group(1, 2, 3) | ||||||
|                 if pgpatch is None or not pgpatch.isdigit(): |                 if pgpatch is None or not pgpatch.isdigit(): | ||||||
|                     pgpatch = 0 |                     pgpatch = 0 | ||||||
|  |                 pgmajor = int(pgmajor) | ||||||
|  |                 pgminor = int(pgminor) | ||||||
|  |                 pgpatch = int(pgpatch) | ||||||
|             else: |             else: | ||||||
|                 sys.stderr.write( |                 sys.stderr.write( | ||||||
|                     "Error: could not determine PostgreSQL version from '%s'" |                     "Error: could not determine PostgreSQL version from '%s'" | ||||||
|  | @ -414,7 +417,22 @@ class psycopg_build_ext(build_ext): | ||||||
|                 sys.exit(1) |                 sys.exit(1) | ||||||
| 
 | 
 | ||||||
|             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)))) |                                   (pgmajor, pgminor, pgpatch))) | ||||||
|  | 
 | ||||||
|  |             # enable lo64 if libpq >= 9.3 and Python 64 bits | ||||||
|  |             if (pgmajor, pgminor) >= (9, 3) and sys.maxint > (1 << 32): | ||||||
|  |                 define_macros.append(("HAVE_LO64", "1")) | ||||||
|  | 
 | ||||||
|  |                 # Inject the flag in the version string already packed up | ||||||
|  |                 # because we didn't know the version before. | ||||||
|  |                 # With distutils everything is complicated. | ||||||
|  |                 for i, t in enumerate(define_macros): | ||||||
|  |                     if t[0] == 'PSYCOPG_VERSION': | ||||||
|  |                         n = t[1].find(')') | ||||||
|  |                         if n > 0: | ||||||
|  |                             define_macros[i] = ( | ||||||
|  |                                 t[0], t[1][:n] + ' lo64' + t[1][n:]) | ||||||
|  | 
 | ||||||
|         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) | ||||||
|  |  | ||||||
|  | @ -440,6 +440,68 @@ 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 _has_lo64(conn): | ||||||
|  |     """Return (bool, msg) about the lo64 support""" | ||||||
|  |     if conn.server_version < 90300: | ||||||
|  |         return (False, "server version %s doesn't support the lo64 API" | ||||||
|  |                 % conn.server_version) | ||||||
|  | 
 | ||||||
|  |     if 'lo64' not in psycopg2.__version__: | ||||||
|  |         return (False, "this psycopg build doesn't support the lo64 API") | ||||||
|  | 
 | ||||||
|  |     return (True, "this server and build support the lo64 API") | ||||||
|  | 
 | ||||||
|  | def skip_if_no_lo64(f): | ||||||
|  |     @wraps(f) | ||||||
|  |     def skip_if_no_lo64_(self): | ||||||
|  |         lo64, msg = _has_lo64(self.conn) | ||||||
|  |         if not lo64: return self.skipTest(msg) | ||||||
|  |         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): | ||||||
|  |         lo64, msg = _has_lo64(self.conn) | ||||||
|  |         if lo64: return self.skipTest(msg) | ||||||
|  |         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, psycopg2.NotSupportedError), | ||||||
|  |             lo.seek, offset, 0) | ||||||
|  | 
 | ||||||
|  |     def test_truncate_larger_than_2gb(self): | ||||||
|  |         lo = self.conn.lobject() | ||||||
|  |         length = 1 << 32  # 4gb | ||||||
|  |         self.assertRaises( | ||||||
|  |             (psycopg2.InterfaceError, psycopg2.NotSupportedError), | ||||||
|  |             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