summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS11
-rw-r--r--doc/src/extensions.rst12
-rw-r--r--doc/src/module.rst7
-rw-r--r--lib/__init__.py2
-rw-r--r--lib/extensions.py2
-rw-r--r--psycopg/adapter_binary.c2
-rw-r--r--psycopg/lobject_int.c4
-rw-r--r--psycopg/lobject_type.c6
-rw-r--r--psycopg/psycopgmodule.c18
-rw-r--r--psycopg/utils.c2
-rw-r--r--setup.py2
-rwxr-xr-xtests/test_module.py9
-rw-r--r--tests/testutils.py37
13 files changed, 103 insertions, 11 deletions
diff --git a/NEWS b/NEWS
index 3e8864f..de5ead3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,17 @@
Current release
---------------
+What's new in psycopg 2.7
+-------------------------
+
+New features:
+
+- Added `~psycopg2.__libpq_version__` and
+ `~psycopg2.extensions.libpq_version()` to inspect the version of the
+ ``libpq`` library the module was compiled/loaded with
+ (:tickets:`#35, #323`).
+
+
What's new in psycopg 2.6.1
^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/src/extensions.rst b/doc/src/extensions.rst
index dea1041..84e1241 100644
--- a/doc/src/extensions.rst
+++ b/doc/src/extensions.rst
@@ -197,6 +197,18 @@ functionalities defined by the |DBAPI|_.
.. versionadded:: 2.2.0
+.. function:: libpq_version()
+
+ Return the version number of the ``libpq`` dynamic library loaded as an
+ integer, in the same format of `~connection.server_version`.
+
+ Raise `~psycopg2.NotSupportedError` if the ``psycopg2`` module was
+ compiled with a ``libpq`` version lesser than 9.1 (which can be detected
+ by the `~psycopg2.__libpq_version__` constant).
+
+ .. seealso:: libpq docs for `PQlibVersion()`__.
+
+ .. __: http://www.postgresql.org/docs/current/static/libpq-misc.html#LIBPQ-PQLIBVERSION
.. _sql-adaptation-objects:
diff --git a/doc/src/module.rst b/doc/src/module.rst
index 8de9f87..bd121e9 100644
--- a/doc/src/module.rst
+++ b/doc/src/module.rst
@@ -109,6 +109,13 @@ The module interface respects the standard defined in the |DBAPI|_.
by the interface. For `psycopg2` is ``pyformat``. See also
:ref:`query-parameters`.
+.. data:: __libpq_version__
+
+ Integer constant reporting the version of the ``libpq`` library this
+ ``psycopg2`` module was compiled with (in the same format of
+ `~connection.server_version`). If this value is lesser than ``90100``
+ then you may query the version of the actually loaded library using the
+ `~psycopg2.extensions.libpq_version()` function.
.. index::
diff --git a/lib/__init__.py b/lib/__init__.py
index cf8c06a..994b15a 100644
--- a/lib/__init__.py
+++ b/lib/__init__.py
@@ -57,7 +57,7 @@ from psycopg2._psycopg import IntegrityError, InterfaceError, InternalError
from psycopg2._psycopg import NotSupportedError, OperationalError
from psycopg2._psycopg import _connect, apilevel, threadsafety, paramstyle
-from psycopg2._psycopg import __version__
+from psycopg2._psycopg import __version__, __libpq_version__
from psycopg2 import tz
diff --git a/lib/extensions.py b/lib/extensions.py
index 216d8ad..c40e336 100644
--- a/lib/extensions.py
+++ b/lib/extensions.py
@@ -56,7 +56,7 @@ try:
except ImportError:
pass
-from psycopg2._psycopg import adapt, adapters, encodings, connection, cursor, lobject, Xid
+from psycopg2._psycopg import adapt, adapters, encodings, connection, cursor, lobject, Xid, libpq_version
from psycopg2._psycopg import string_types, binary_types, new_type, new_array_type, register_type
from psycopg2._psycopg import ISQLQuote, Notify, Diagnostics, Column
diff --git a/psycopg/adapter_binary.c b/psycopg/adapter_binary.c
index 485dc5a..597048d 100644
--- a/psycopg/adapter_binary.c
+++ b/psycopg/adapter_binary.c
@@ -39,7 +39,7 @@ static unsigned char *
binary_escape(unsigned char *from, size_t from_length,
size_t *to_length, PGconn *conn)
{
-#if PG_VERSION_HEX >= 0x080104
+#if PG_VERSION_NUM >= 80104
if (conn)
return PQescapeByteaConn(conn, from, from_length, to_length);
else
diff --git a/psycopg/lobject_int.c b/psycopg/lobject_int.c
index 6b55d42..8788c10 100644
--- a/psycopg/lobject_int.c
+++ b/psycopg/lobject_int.c
@@ -474,7 +474,7 @@ lobject_export(lobjectObject *self, const char *filename)
return retvalue;
}
-#if PG_VERSION_HEX >= 0x080300
+#if PG_VERSION_NUM >= 80300
RAISES_NEG int
lobject_truncate(lobjectObject *self, size_t len)
@@ -511,4 +511,4 @@ lobject_truncate(lobjectObject *self, size_t len)
}
-#endif /* PG_VERSION_HEX >= 0x080300 */
+#endif /* PG_VERSION_NUM >= 80300 */
diff --git a/psycopg/lobject_type.c b/psycopg/lobject_type.c
index ec95b5c..a43325d 100644
--- a/psycopg/lobject_type.c
+++ b/psycopg/lobject_type.c
@@ -266,7 +266,7 @@ psyco_lobj_get_closed(lobjectObject *self, void *closure)
return closed;
}
-#if PG_VERSION_HEX >= 0x080300
+#if PG_VERSION_NUM >= 80300
#define psyco_lobj_truncate_doc \
"truncate(len=0) -- Truncate large object to given size."
@@ -327,10 +327,10 @@ static struct PyMethodDef lobjectObject_methods[] = {
METH_NOARGS, psyco_lobj_unlink_doc},
{"export",(PyCFunction)psyco_lobj_export,
METH_VARARGS, psyco_lobj_export_doc},
-#if PG_VERSION_HEX >= 0x080300
+#if PG_VERSION_NUM >= 80300
{"truncate",(PyCFunction)psyco_lobj_truncate,
METH_VARARGS, psyco_lobj_truncate_doc},
-#endif /* PG_VERSION_HEX >= 0x080300 */
+#endif /* PG_VERSION_NUM >= 80300 */
{NULL}
};
diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c
index 61e2de5..34fc25e 100644
--- a/psycopg/psycopgmodule.c
+++ b/psycopg/psycopgmodule.c
@@ -185,7 +185,7 @@ psyco_libcrypto_threads_init(void)
if (PyImport_ImportModule("ssl") != NULL) {
/* disable libcrypto setup in libpq, so it won't stomp on the callbacks
that have already been set up */
-#if PG_VERSION_HEX >= 0x080400
+#if PG_VERSION_NUM >= 80400
PQinitOpenSSL(1, 0);
#endif
}
@@ -300,6 +300,19 @@ exit:
return rv;
}
+#define psyco_libpq_version_doc "Query actual libpq version loaded."
+
+static PyObject*
+psyco_libpq_version(PyObject *self)
+{
+#if PG_VERSION_NUM >= 90100
+ return PyInt_FromLong(PQlibVersion());
+#else
+ PyErr_SetString(NotSupportedError, "version discovery is not supported in libpq < 9.1");
+ return NULL;
+#endif
+}
+
/* psyco_encodings_fill
Fill the module's postgresql<->python encoding table */
@@ -704,6 +717,8 @@ static PyMethodDef psycopgMethods[] = {
METH_VARARGS|METH_KEYWORDS, typecast_from_python_doc},
{"new_array_type", (PyCFunction)typecast_array_from_python,
METH_VARARGS|METH_KEYWORDS, typecast_array_from_python_doc},
+ {"libpq_version", (PyCFunction)psyco_libpq_version,
+ METH_NOARGS, psyco_libpq_version_doc},
{"Date", (PyCFunction)psyco_Date,
METH_VARARGS, psyco_Date_doc},
@@ -899,6 +914,7 @@ INIT_MODULE(_psycopg)(void)
/* set some module's parameters */
PyModule_AddStringConstant(module, "__version__", PSYCOPG_VERSION);
PyModule_AddStringConstant(module, "__doc__", "psycopg PostgreSQL driver");
+ PyModule_AddIntConstant(module, "__libpq_version__", PG_VERSION_NUM);
PyModule_AddObject(module, "apilevel", Text_FromUTF8(APILEVEL));
PyModule_AddObject(module, "threadsafety", PyInt_FromLong(THREADSAFETY));
PyModule_AddObject(module, "paramstyle", Text_FromUTF8(PARAMSTYLE));
diff --git a/psycopg/utils.c b/psycopg/utils.c
index 6b035cf..836f612 100644
--- a/psycopg/utils.c
+++ b/psycopg/utils.c
@@ -62,7 +62,7 @@ psycopg_escape_string(connectionObject *conn, const char *from, Py_ssize_t len,
}
{
- #if PG_VERSION_HEX >= 0x080104
+ #if PG_VERSION_NUM >= 80104
int err;
if (conn && conn->pgconn)
ql = PQescapeStringConn(conn->pgconn, to+eq+1, from, len, &err);
diff --git a/setup.py b/setup.py
index fc4f171..2de8c5e 100644
--- a/setup.py
+++ b/setup.py
@@ -416,7 +416,7 @@ class psycopg_build_ext(build_ext):
% pgversion)
sys.exit(1)
- define_macros.append(("PG_VERSION_HEX", "0x%02X%02X%02X" %
+ define_macros.append(("PG_VERSION_NUM", "%d%02d%02d" %
(pgmajor, pgminor, pgpatch)))
# enable lo64 if libpq >= 9.3 and Python 64 bits
diff --git a/tests/test_module.py b/tests/test_module.py
index 608f703..62b85ee 100755
--- a/tests/test_module.py
+++ b/tests/test_module.py
@@ -320,6 +320,15 @@ import _psycopg
self.assertEqual(0, proc.returncode)
+class TestVersionDiscovery(unittest.TestCase):
+ def test_libpq_version(self):
+ self.assertTrue(type(psycopg2.__libpq_version__) is int)
+ try:
+ self.assertTrue(type(psycopg2.extensions.libpq_version()) is int)
+ except NotSupportedError:
+ self.assertTrue(psycopg2.__libpq_version__ < 90100)
+
+
def test_suite():
return unittest.TestLoader().loadTestsFromName(__name__)
diff --git a/tests/testutils.py b/tests/testutils.py
index 6a78432..987bd7b 100644
--- a/tests/testutils.py
+++ b/tests/testutils.py
@@ -236,6 +236,43 @@ def skip_after_postgres(*ver):
return skip_after_postgres__
return skip_after_postgres_
+def libpq_version():
+ import psycopg2
+ v = psycopg2.__libpq_version__
+ if v >= 90100:
+ v = psycopg2.extensions.libpq_version()
+ return v
+
+def skip_before_libpq(*ver):
+ """Skip a test if libpq we're linked to is older than a certain version."""
+ ver = ver + (0,) * (3 - len(ver))
+ def skip_before_libpq_(f):
+ @wraps(f)
+ def skip_before_libpq__(self):
+ v = libpq_version()
+ if v < int("%d%02d%02d" % ver):
+ return self.skipTest("skipped because libpq %d" % v)
+ else:
+ return f(self)
+
+ return skip_before_libpq__
+ return skip_before_libpq_
+
+def skip_after_libpq(*ver):
+ """Skip a test if libpq we're linked to is newer than a certain version."""
+ ver = ver + (0,) * (3 - len(ver))
+ def skip_after_libpq_(f):
+ @wraps(f)
+ def skip_after_libpq__(self):
+ v = libpq_version()
+ if v >= int("%d%02d%02d" % ver):
+ return self.skipTest("skipped because libpq %s" % v)
+ else:
+ return f(self)
+
+ return skip_after_libpq__
+ return skip_after_libpq_
+
def skip_before_python(*ver):
"""Skip a test on Python before a certain version."""
def skip_before_python_(f):