Report NotSupportedError for PGRES_COPY_BOTH and PGRES_SINGLE_TUPLE

Fixes #352.
This commit is contained in:
Daniele Varrazzo 2015-09-30 12:15:35 +01:00
parent 3e31fb359e
commit abf1f28c44
5 changed files with 59 additions and 5 deletions

2
NEWS
View File

@ -5,6 +5,8 @@ What's new in psycopg 2.6.2
^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Report the server response status on errors (such as :ticket:`#281`).
- Raise NotSupportedError on unhandled server response status
(:ticket:`#352`).
What's new in psycopg 2.6.1

View File

@ -1597,11 +1597,26 @@ pq_fetch(cursorObject *curs, int no_result)
ex = -1;
break;
default:
Dprintf("pq_fetch: uh-oh, something FAILED: pgconn = %p", curs->conn);
case PGRES_BAD_RESPONSE:
case PGRES_NONFATAL_ERROR:
case PGRES_FATAL_ERROR:
Dprintf("pq_fetch: uh-oh, something FAILED: status = %d pgconn = %p",
status, curs->conn);
pq_raise(curs->conn, curs, NULL);
ex = -1;
break;
default:
/* PGRES_COPY_BOTH, PGRES_SINGLE_TUPLE, future statuses */
Dprintf("pq_fetch: got unsupported result: status = %d pgconn = %p",
status, curs->conn);
PyErr_Format(NotSupportedError,
"got server response with unsupported status %s",
PQresStatus(curs->pgres == NULL ?
PQstatus(curs->conn->pgconn) : PQresultStatus(curs->pgres)));
CLEARPGRES(curs->pgres);
ex = -1;
break;
}
/* error checking, close the connection if necessary (some critical errors

View File

@ -26,6 +26,7 @@ import os
import time
import threading
from operator import attrgetter
from StringIO import StringIO
import psycopg2
import psycopg2.errorcodes
@ -1067,6 +1068,17 @@ class AutocommitTests(ConnectingTestCase):
self.assertEqual(cur.fetchone()[0], 'on')
class ReplicationTest(ConnectingTestCase):
@skip_before_postgres(9, 0)
def test_replication_not_supported(self):
conn = self.repl_connect()
if conn is None: return
cur = conn.cursor()
f = StringIO()
self.assertRaises(psycopg2.NotSupportedError,
cur.copy_expert, "START_REPLICATION 0/0", f)
def test_suite():
return unittest.TestLoader().loadTestsFromName(__name__)

View File

@ -7,6 +7,8 @@ dbhost = os.environ.get('PSYCOPG2_TESTDB_HOST', None)
dbport = os.environ.get('PSYCOPG2_TESTDB_PORT', None)
dbuser = os.environ.get('PSYCOPG2_TESTDB_USER', None)
dbpass = os.environ.get('PSYCOPG2_TESTDB_PASSWORD', None)
repl_dsn = os.environ.get('PSYCOPG2_TEST_REPL_DSN',
"dbname=psycopg2_test replication=1")
# Check if we want to test psycopg's green path.
green = os.environ.get('PSYCOPG2_TEST_GREEN', None)

View File

@ -28,7 +28,7 @@ import os
import platform
import sys
from functools import wraps
from testconfig import dsn
from testconfig import dsn, repl_dsn
try:
import unittest2
@ -103,11 +103,35 @@ class ConnectingTestCase(unittest.TestCase):
"%s (did you remember calling ConnectingTestCase.setUp()?)"
% e)
if 'dsn' in kwargs:
conninfo = kwargs.pop('dsn')
else:
conninfo = dsn
import psycopg2
conn = psycopg2.connect(dsn, **kwargs)
conn = psycopg2.connect(conninfo, **kwargs)
self._conns.append(conn)
return conn
def repl_connect(self, **kwargs):
"""Return a connection set up for replication
The connection is on "PSYCOPG2_TEST_REPL_DSN" unless overridden by
a *dsn* kwarg.
Should raise a skip test if not available, but guard for None on
old Python versions.
"""
if 'dsn' not in kwargs:
kwargs['dsn'] = repl_dsn
import psycopg2
try:
conn = self.connect(**kwargs)
except psycopg2.OperationalError, e:
return self.skipTest("replication db not configured: %s" % e)
conn.autocommit = True
return conn
def _get_conn(self):
if not hasattr(self, '_the_conn'):
self._the_conn = self.connect()
@ -351,4 +375,3 @@ class py3_raises_typeerror(object):
if sys.version_info[0] >= 3:
assert type is TypeError
return True