mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-22 17:06:33 +03:00
Set default_transaction_* GUC if session state is changed in autocomit
This commit is contained in:
parent
665e9dc665
commit
9054eeccc0
|
@ -41,7 +41,7 @@ const char *srv_isolevels[] = {
|
|||
"REPEATABLE READ",
|
||||
"SERIALIZABLE",
|
||||
"READ UNCOMMITTED",
|
||||
"" /* default */
|
||||
"default" /* only to set GUC, not for BEGIN */
|
||||
};
|
||||
|
||||
/* Read only false, true */
|
||||
|
@ -58,6 +58,15 @@ const char *srv_deferrable[] = {
|
|||
"" /* default */
|
||||
};
|
||||
|
||||
/* On/Off/Default GUC states
|
||||
*/
|
||||
const char *srv_state_guc[] = {
|
||||
"off",
|
||||
"on",
|
||||
"default"
|
||||
};
|
||||
|
||||
|
||||
/* Return a new "string" from a char* from the database.
|
||||
*
|
||||
* On Py2 just get a string, on Py3 decode it in the connection codec.
|
||||
|
@ -1186,6 +1195,10 @@ RAISES_NEG int
|
|||
conn_set_session(connectionObject *self, int autocommit,
|
||||
int isolevel, int readonly, int deferrable)
|
||||
{
|
||||
int rv = -1;
|
||||
PGresult *pgres = NULL;
|
||||
char *error = NULL;
|
||||
|
||||
/* Promote an isolation level to one of the levels supported by the server */
|
||||
if (self->server_version < 80000) {
|
||||
if (isolevel == ISOLATION_LEVEL_READ_UNCOMMITTED) {
|
||||
|
@ -1199,19 +1212,75 @@ conn_set_session(connectionObject *self, int autocommit,
|
|||
Py_BEGIN_ALLOW_THREADS;
|
||||
pthread_mutex_lock(&self->lock);
|
||||
|
||||
if (autocommit) {
|
||||
/* we are in autocommit state, so no BEGIN will be issued:
|
||||
* configure the session with the characteristics requested */
|
||||
if (isolevel != self->isolevel) {
|
||||
if (0 > pq_set_guc_locked(self,
|
||||
"default_transaction_isolation", srv_isolevels[isolevel],
|
||||
&pgres, &error, &_save)) {
|
||||
goto endlock;
|
||||
}
|
||||
}
|
||||
if (readonly != self->readonly) {
|
||||
if (0 > pq_set_guc_locked(self,
|
||||
"default_transaction_read_only", srv_state_guc[readonly],
|
||||
&pgres, &error, &_save)) {
|
||||
goto endlock;
|
||||
}
|
||||
}
|
||||
if (deferrable != self->deferrable && self->server_version >= 90100) {
|
||||
if (0 > pq_set_guc_locked(self,
|
||||
"default_transaction_deferrable", srv_state_guc[deferrable],
|
||||
&pgres, &error, &_save)) {
|
||||
goto endlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (self->autocommit) {
|
||||
/* we are moving from autocommit to not autocommit, so revert the
|
||||
* characteristics to defaults to let BEGIN do its work */
|
||||
if (0 > pq_set_guc_locked(self,
|
||||
"default_transaction_isolation", "default",
|
||||
&pgres, &error, &_save)) {
|
||||
goto endlock;
|
||||
}
|
||||
if (0 > pq_set_guc_locked(self,
|
||||
"default_transaction_read_only", "default",
|
||||
&pgres, &error, &_save)) {
|
||||
goto endlock;
|
||||
}
|
||||
if (self->server_version >= 90100) {
|
||||
if (0 > pq_set_guc_locked(self,
|
||||
"default_transaction_deferrable", "default",
|
||||
&pgres, &error, &_save)) {
|
||||
goto endlock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self->autocommit = autocommit;
|
||||
self->isolevel = isolevel;
|
||||
self->readonly = readonly;
|
||||
self->deferrable = deferrable;
|
||||
self->autocommit = autocommit;
|
||||
rv = 0;
|
||||
|
||||
endlock:
|
||||
pthread_mutex_unlock(&self->lock);
|
||||
Py_END_ALLOW_THREADS;
|
||||
|
||||
if (rv < 0) {
|
||||
pq_complete_error(self, &pgres, &error);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
Dprintf(
|
||||
"conn_set_session: autocommit %d, isolevel %d, readonly %d, deferrable %d",
|
||||
autocommit, isolevel, readonly, deferrable);
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -671,7 +671,7 @@ psyco_conn_set_isolation_level(connectionObject *self, PyObject *args)
|
|||
|
||||
if (!PyArg_ParseTuple(args, "i", &level)) return NULL;
|
||||
|
||||
if (level < 0 || level > 4) {
|
||||
if (level < 0 || level > 5) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"isolation level must be between 0 and 4");
|
||||
return NULL;
|
||||
|
|
|
@ -495,8 +495,10 @@ pq_begin_locked(connectionObject *conn, PGresult **pgres, char **error,
|
|||
|
||||
snprintf(buf, bufsize, "BEGIN%s%s%s%s%s",
|
||||
conn->server_version < 80000 ? ";SET TRANSACTION" : "",
|
||||
(conn->isolevel >= 1 && conn->isolevel <= 4) ? " ISOLATION LEVEL " : "",
|
||||
srv_isolevels[conn->isolevel],
|
||||
(conn->isolevel >= 1 && conn->isolevel <= 4)
|
||||
? " ISOLATION LEVEL " : "",
|
||||
(conn->isolevel >= 1 && conn->isolevel <= 4)
|
||||
? srv_isolevels[conn->isolevel] : "",
|
||||
srv_readonly[conn->readonly],
|
||||
srv_deferrable[conn->deferrable]);
|
||||
|
||||
|
|
|
@ -529,7 +529,26 @@ class IsolationLevelsTestCase(ConnectingTestCase):
|
|||
conn.commit()
|
||||
|
||||
self.assertRaises(ValueError, conn.set_isolation_level, -1)
|
||||
self.assertRaises(ValueError, conn.set_isolation_level, 5)
|
||||
self.assertRaises(ValueError, conn.set_isolation_level, 6)
|
||||
|
||||
def test_set_isolation_level_default(self):
|
||||
conn = self.connect()
|
||||
curs = conn.cursor()
|
||||
|
||||
conn.autocommit = True
|
||||
curs.execute("set default_transaction_isolation to 'read committed'")
|
||||
|
||||
conn.autocommit = False
|
||||
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE)
|
||||
self.assertEqual(conn.isolation_level,
|
||||
psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE)
|
||||
curs.execute("show transaction_isolation")
|
||||
self.assertEqual(curs.fetchone()[0], "serializable")
|
||||
|
||||
conn.rollback()
|
||||
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_DEFAULT)
|
||||
curs.execute("show transaction_isolation")
|
||||
self.assertEqual(curs.fetchone()[0], "read committed")
|
||||
|
||||
def test_set_isolation_level_abort(self):
|
||||
conn = self.connect()
|
||||
|
@ -541,32 +560,14 @@ class IsolationLevelsTestCase(ConnectingTestCase):
|
|||
self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_INTRANS,
|
||||
conn.get_transaction_status())
|
||||
|
||||
conn.set_isolation_level(
|
||||
# changed in psycopg 2.7
|
||||
self.assertRaises(psycopg2.ProgrammingError,
|
||||
conn.set_isolation_level,
|
||||
psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE)
|
||||
self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_IDLE,
|
||||
conn.get_transaction_status())
|
||||
cur.execute("select count(*) from isolevel;")
|
||||
self.assertEqual(0, cur.fetchone()[0])
|
||||
|
||||
cur.execute("insert into isolevel values (10);")
|
||||
self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_INTRANS,
|
||||
conn.get_transaction_status())
|
||||
conn.set_isolation_level(
|
||||
psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
|
||||
self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_IDLE,
|
||||
conn.get_transaction_status())
|
||||
cur.execute("select count(*) from isolevel;")
|
||||
self.assertEqual(0, cur.fetchone()[0])
|
||||
|
||||
cur.execute("insert into isolevel values (10);")
|
||||
self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_IDLE,
|
||||
conn.get_transaction_status())
|
||||
conn.set_isolation_level(
|
||||
psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED)
|
||||
self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_IDLE,
|
||||
conn.get_transaction_status())
|
||||
cur.execute("select count(*) from isolevel;")
|
||||
self.assertEqual(1, cur.fetchone()[0])
|
||||
self.assertEqual(conn.isolation_level,
|
||||
psycopg2.extensions.ISOLATION_LEVEL_DEFAULT)
|
||||
|
||||
def test_isolation_level_autocommit(self):
|
||||
cnn1 = self.connect()
|
||||
|
|
Loading…
Reference in New Issue
Block a user