mirror of
https://github.com/psycopg/psycopg2.git
synced 2025-01-31 09:24:07 +03:00
Merge remote-tracking branch 'piro/devel' into devel
This commit is contained in:
commit
a59d88c703
12
NEWS
12
NEWS
|
@ -1,3 +1,15 @@
|
||||||
|
What's new in psycopg 2.4.3
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
- Fixed segfault in case of transaction started with connection lost
|
||||||
|
(and possibly other events).
|
||||||
|
- Rollback connections in transaction or in error before putting them
|
||||||
|
back into a pool. Also discard broken connections (ticket #62).
|
||||||
|
- Lazy import of the slow uuid module, thanks to Marko Kreen.
|
||||||
|
- Fixed NamedTupleCursor.executemany() (ticket #65).
|
||||||
|
- Fixed --static-libpq setup option (ticket #64).
|
||||||
|
|
||||||
|
|
||||||
What's new in psycopg 2.4.2
|
What's new in psycopg 2.4.2
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,12 @@ directly into the client application.
|
||||||
|
|
||||||
Get a free connection and assign it to *key* if not `!None`.
|
Get a free connection and assign it to *key* if not `!None`.
|
||||||
|
|
||||||
.. method:: putconn(conn, key=None)
|
.. method:: putconn(conn, key=None, close=False)
|
||||||
|
|
||||||
Put away a connection.
|
Put away a connection.
|
||||||
|
|
||||||
|
If *close* is `!True`, discard the connection from the pool.
|
||||||
|
|
||||||
.. method:: closeall
|
.. method:: closeall
|
||||||
|
|
||||||
Close all the connections handled by the pool.
|
Close all the connections handled by the pool.
|
||||||
|
|
|
@ -275,7 +275,7 @@ class NamedTupleCursor(_cursor):
|
||||||
|
|
||||||
def executemany(self, query, vars):
|
def executemany(self, query, vars):
|
||||||
self.Record = None
|
self.Record = None
|
||||||
return _cursor.executemany(self, vars)
|
return _cursor.executemany(self, query, vars)
|
||||||
|
|
||||||
def callproc(self, procname, vars=None):
|
def callproc(self, procname, vars=None):
|
||||||
self.Record = None
|
self.Record = None
|
||||||
|
|
19
lib/pool.py
19
lib/pool.py
|
@ -25,6 +25,7 @@ This module implements thread-safe (and not) connection pools.
|
||||||
# License for more details.
|
# License for more details.
|
||||||
|
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
import psycopg2.extensions as _ext
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import logging
|
import logging
|
||||||
|
@ -115,13 +116,27 @@ class AbstractConnectionPool(object):
|
||||||
def _putconn(self, conn, key=None, close=False):
|
def _putconn(self, conn, key=None, close=False):
|
||||||
"""Put away a connection."""
|
"""Put away a connection."""
|
||||||
if self.closed: raise PoolError("connection pool is closed")
|
if self.closed: raise PoolError("connection pool is closed")
|
||||||
if key is None: key = self._rused[id(conn)]
|
if key is None: key = self._rused.get(id(conn))
|
||||||
|
|
||||||
if not key:
|
if not key:
|
||||||
raise PoolError("trying to put unkeyed connection")
|
raise PoolError("trying to put unkeyed connection")
|
||||||
|
|
||||||
if len(self._pool) < self.minconn and not close:
|
if len(self._pool) < self.minconn and not close:
|
||||||
self._pool.append(conn)
|
# Return the connection into a consistent state before putting
|
||||||
|
# it back into the pool
|
||||||
|
if not conn.closed:
|
||||||
|
status = conn.get_transaction_status()
|
||||||
|
if status == _ext.TRANSACTION_STATUS_UNKNOWN:
|
||||||
|
# server connection lost
|
||||||
|
conn.close()
|
||||||
|
elif status != _ext.TRANSACTION_STATUS_IDLE:
|
||||||
|
# connection in error or in transaction
|
||||||
|
conn.rollback()
|
||||||
|
self._pool.append(conn)
|
||||||
|
else:
|
||||||
|
# regular idle connection
|
||||||
|
self._pool.append(conn)
|
||||||
|
# If the connection is closed, we just discard it.
|
||||||
else:
|
else:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
|
@ -344,11 +344,13 @@ pq_execute_command_locked(connectionObject *conn, const char *query,
|
||||||
}
|
}
|
||||||
if (*pgres == NULL) {
|
if (*pgres == NULL) {
|
||||||
Dprintf("pq_execute_command_locked: PQexec returned NULL");
|
Dprintf("pq_execute_command_locked: PQexec returned NULL");
|
||||||
|
PyEval_RestoreThread(*tstate);
|
||||||
if (!PyErr_Occurred()) {
|
if (!PyErr_Occurred()) {
|
||||||
const char *msg;
|
const char *msg;
|
||||||
msg = PQerrorMessage(conn->pgconn);
|
msg = PQerrorMessage(conn->pgconn);
|
||||||
if (msg && *msg) { *error = strdup(msg); }
|
if (msg && *msg) { *error = strdup(msg); }
|
||||||
}
|
}
|
||||||
|
*tstate = PyEval_SaveThread();
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,11 +637,13 @@ pq_get_guc_locked(
|
||||||
|
|
||||||
if (*pgres == NULL) {
|
if (*pgres == NULL) {
|
||||||
Dprintf("pq_get_guc_locked: PQexec returned NULL");
|
Dprintf("pq_get_guc_locked: PQexec returned NULL");
|
||||||
|
PyEval_RestoreThread(*tstate);
|
||||||
if (!PyErr_Occurred()) {
|
if (!PyErr_Occurred()) {
|
||||||
const char *msg;
|
const char *msg;
|
||||||
msg = PQerrorMessage(conn->pgconn);
|
msg = PQerrorMessage(conn->pgconn);
|
||||||
if (msg && *msg) { *error = strdup(msg); }
|
if (msg && *msg) { *error = strdup(msg); }
|
||||||
}
|
}
|
||||||
|
*tstate = PyEval_SaveThread();
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (PQresultStatus(*pgres) != PGRES_TUPLES_OK) {
|
if (PQresultStatus(*pgres) != PGRES_TUPLES_OK) {
|
||||||
|
|
4
setup.py
4
setup.py
|
@ -73,7 +73,7 @@ except ImportError:
|
||||||
# Take a look at http://www.python.org/dev/peps/pep-0386/
|
# Take a look at http://www.python.org/dev/peps/pep-0386/
|
||||||
# for a consistent versioning pattern.
|
# for a consistent versioning pattern.
|
||||||
|
|
||||||
PSYCOPG_VERSION = '2.4.2'
|
PSYCOPG_VERSION = '2.4.3.dev0'
|
||||||
|
|
||||||
version_flags = ['dt', 'dec']
|
version_flags = ['dt', 'dec']
|
||||||
|
|
||||||
|
@ -362,7 +362,7 @@ class psycopg_build_ext(build_ext):
|
||||||
|
|
||||||
self.include_dirs.append(".")
|
self.include_dirs.append(".")
|
||||||
if self.static_libpq:
|
if self.static_libpq:
|
||||||
if not hasattr(self, 'link_objects'):
|
if not getattr(self, 'link_objects', None):
|
||||||
self.link_objects = []
|
self.link_objects = []
|
||||||
self.link_objects.append(
|
self.link_objects.append(
|
||||||
os.path.join(pg_config_helper.query("libdir"), "libpq.a"))
|
os.path.join(pg_config_helper.query("libdir"), "libpq.a"))
|
||||||
|
|
|
@ -171,6 +171,17 @@ class NamedTupleCursorTest(unittest.TestCase):
|
||||||
self.assertEqual(res[2].i, 3)
|
self.assertEqual(res[2].i, 3)
|
||||||
self.assertEqual(res[2].s, 'baz')
|
self.assertEqual(res[2].s, 'baz')
|
||||||
|
|
||||||
|
@skip_if_no_namedtuple
|
||||||
|
def test_executemany(self):
|
||||||
|
curs = self.conn.cursor()
|
||||||
|
curs.executemany("delete from nttest where i = %s",
|
||||||
|
[(1,), (2,)])
|
||||||
|
curs.execute("select * from nttest order by 1")
|
||||||
|
res = curs.fetchall()
|
||||||
|
self.assertEqual(1, len(res))
|
||||||
|
self.assertEqual(res[0].i, 3)
|
||||||
|
self.assertEqual(res[0].s, 'baz')
|
||||||
|
|
||||||
@skip_if_no_namedtuple
|
@skip_if_no_namedtuple
|
||||||
def test_iter(self):
|
def test_iter(self):
|
||||||
curs = self.conn.cursor()
|
curs = self.conn.cursor()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user