mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-23 01:16:34 +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",
|
"REPEATABLE READ",
|
||||||
"SERIALIZABLE",
|
"SERIALIZABLE",
|
||||||
"READ UNCOMMITTED",
|
"READ UNCOMMITTED",
|
||||||
"" /* default */
|
"default" /* only to set GUC, not for BEGIN */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Read only false, true */
|
/* Read only false, true */
|
||||||
|
@ -58,6 +58,15 @@ const char *srv_deferrable[] = {
|
||||||
"" /* default */
|
"" /* default */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* On/Off/Default GUC states
|
||||||
|
*/
|
||||||
|
const char *srv_state_guc[] = {
|
||||||
|
"off",
|
||||||
|
"on",
|
||||||
|
"default"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Return a new "string" from a char* from the database.
|
/* Return a new "string" from a char* from the database.
|
||||||
*
|
*
|
||||||
* On Py2 just get a string, on Py3 decode it in the connection codec.
|
* 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,
|
conn_set_session(connectionObject *self, int autocommit,
|
||||||
int isolevel, int readonly, int deferrable)
|
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 */
|
/* Promote an isolation level to one of the levels supported by the server */
|
||||||
if (self->server_version < 80000) {
|
if (self->server_version < 80000) {
|
||||||
if (isolevel == ISOLATION_LEVEL_READ_UNCOMMITTED) {
|
if (isolevel == ISOLATION_LEVEL_READ_UNCOMMITTED) {
|
||||||
|
@ -1199,19 +1212,75 @@ conn_set_session(connectionObject *self, int autocommit,
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
pthread_mutex_lock(&self->lock);
|
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->isolevel = isolevel;
|
||||||
self->readonly = readonly;
|
self->readonly = readonly;
|
||||||
self->deferrable = deferrable;
|
self->deferrable = deferrable;
|
||||||
self->autocommit = autocommit;
|
rv = 0;
|
||||||
|
|
||||||
|
endlock:
|
||||||
pthread_mutex_unlock(&self->lock);
|
pthread_mutex_unlock(&self->lock);
|
||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
if (rv < 0) {
|
||||||
|
pq_complete_error(self, &pgres, &error);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
Dprintf(
|
Dprintf(
|
||||||
"conn_set_session: autocommit %d, isolevel %d, readonly %d, deferrable %d",
|
"conn_set_session: autocommit %d, isolevel %d, readonly %d, deferrable %d",
|
||||||
autocommit, isolevel, readonly, deferrable);
|
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 (!PyArg_ParseTuple(args, "i", &level)) return NULL;
|
||||||
|
|
||||||
if (level < 0 || level > 4) {
|
if (level < 0 || level > 5) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"isolation level must be between 0 and 4");
|
"isolation level must be between 0 and 4");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -495,8 +495,10 @@ pq_begin_locked(connectionObject *conn, PGresult **pgres, char **error,
|
||||||
|
|
||||||
snprintf(buf, bufsize, "BEGIN%s%s%s%s%s",
|
snprintf(buf, bufsize, "BEGIN%s%s%s%s%s",
|
||||||
conn->server_version < 80000 ? ";SET TRANSACTION" : "",
|
conn->server_version < 80000 ? ";SET TRANSACTION" : "",
|
||||||
(conn->isolevel >= 1 && conn->isolevel <= 4) ? " ISOLATION LEVEL " : "",
|
(conn->isolevel >= 1 && conn->isolevel <= 4)
|
||||||
srv_isolevels[conn->isolevel],
|
? " ISOLATION LEVEL " : "",
|
||||||
|
(conn->isolevel >= 1 && conn->isolevel <= 4)
|
||||||
|
? srv_isolevels[conn->isolevel] : "",
|
||||||
srv_readonly[conn->readonly],
|
srv_readonly[conn->readonly],
|
||||||
srv_deferrable[conn->deferrable]);
|
srv_deferrable[conn->deferrable]);
|
||||||
|
|
||||||
|
|
|
@ -529,7 +529,26 @@ class IsolationLevelsTestCase(ConnectingTestCase):
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
self.assertRaises(ValueError, conn.set_isolation_level, -1)
|
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):
|
def test_set_isolation_level_abort(self):
|
||||||
conn = self.connect()
|
conn = self.connect()
|
||||||
|
@ -541,32 +560,14 @@ class IsolationLevelsTestCase(ConnectingTestCase):
|
||||||
self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_INTRANS,
|
self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_INTRANS,
|
||||||
conn.get_transaction_status())
|
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)
|
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,
|
self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_INTRANS,
|
||||||
conn.get_transaction_status())
|
conn.get_transaction_status())
|
||||||
conn.set_isolation_level(
|
self.assertEqual(conn.isolation_level,
|
||||||
psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
|
psycopg2.extensions.ISOLATION_LEVEL_DEFAULT)
|
||||||
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])
|
|
||||||
|
|
||||||
def test_isolation_level_autocommit(self):
|
def test_isolation_level_autocommit(self):
|
||||||
cnn1 = self.connect()
|
cnn1 = self.connect()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user