diff --git a/psycopg/connection_int.c b/psycopg/connection_int.c index de7083f7..0544957f 100644 --- a/psycopg/connection_int.c +++ b/psycopg/connection_int.c @@ -1042,6 +1042,13 @@ conn_switch_isolation_level(connectionObject *self, int level) { int curr_level; + /* use only supported levels on older PG versions */ + if (self->server_version < 80000) { + if (level == 1 || level == 3) { + ++level; + } + } + if (-1 == (curr_level = conn_get_isolation_level(self))) { return -1; } diff --git a/psycopg/connection_type.c b/psycopg/connection_type.c index 455abdae..3a5b7feb 100644 --- a/psycopg/connection_type.c +++ b/psycopg/connection_type.c @@ -384,10 +384,9 @@ psyco_conn_tpc_recover(connectionObject *self, PyObject *args) extern const IsolationLevel conn_isolevels[]; static const char * -_psyco_conn_parse_isolevel(PyObject *pyval) +_psyco_conn_parse_isolevel(connectionObject *self, PyObject *pyval) { - const char *rv = NULL; - const IsolationLevel *value = NULL; + const IsolationLevel *isolevel = NULL; Py_INCREF(pyval); /* for ensure_bytes */ @@ -400,22 +399,22 @@ _psyco_conn_parse_isolevel(PyObject *pyval) "isolation_level must be between 1 and 4"); goto exit; } - rv = conn_isolevels[level].name; + + isolevel = conn_isolevels + level; } /* parse from the string -- this includes "default" */ else { - value = conn_isolevels; - while ((++value)->name) { + isolevel = conn_isolevels; + while ((++isolevel)->name) { if (!(pyval = psycopg_ensure_bytes(pyval))) { goto exit; } - if (0 == strcasecmp(value->name, Bytes_AS_STRING(pyval))) { - rv = value->name; + if (0 == strcasecmp(isolevel->name, Bytes_AS_STRING(pyval))) { break; } } - if (!rv) { + if (!isolevel->name) { char msg[256]; snprintf(msg, sizeof(msg), "bad value for isolation_level: '%s'", Bytes_AS_STRING(pyval)); @@ -423,9 +422,17 @@ _psyco_conn_parse_isolevel(PyObject *pyval) } } + /* use only supported levels on older PG versions */ + if (isolevel && self->server_version < 80000) { + if (isolevel->value == 1 || isolevel->value == 3) { + ++isolevel; + } + } + exit: Py_XDECREF(pyval); - return rv; + + return isolevel ? isolevel->name : NULL; } /* convert True/False/"default" into a C string */ @@ -477,7 +484,7 @@ psyco_conn_set_transaction(connectionObject *self, PyObject *args, PyObject *kwa if (Py_None != isolation_level) { const char *value = NULL; - if (!(value = _psyco_conn_parse_isolevel(isolation_level))) { + if (!(value = _psyco_conn_parse_isolevel(self, isolation_level))) { return NULL; } if (0 != conn_set(self, "default_transaction_isolation", value)) { diff --git a/tests/test_connection.py b/tests/test_connection.py index 90014574..e62e51e3 100755 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -204,14 +204,23 @@ class IsolationLevelsTestCase(unittest.TestCase): conn = self.connect() curs = conn.cursor() - for name, level in ( + levels = ( (None, psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT), ('read uncommitted', psycopg2.extensions.ISOLATION_LEVEL_READ_UNCOMMITTED), ('read committed', psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED), ('repeatable read', psycopg2.extensions.ISOLATION_LEVEL_REPEATABLE_READ), ('serializable', psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE), - ): + ) + for name, level in levels: conn.set_isolation_level(level) + + # the only values available on prehistoric PG versions + if conn.server_version < 80000: + if level in ( + psycopg2.extensions.ISOLATION_LEVEL_READ_UNCOMMITTED, + psycopg2.extensions.ISOLATION_LEVEL_REPEATABLE_READ): + name, level = levels[levels.index((name, level)) + 1] + self.assertEqual(conn.isolation_level, level) curs.execute('show transaction_isolation;')