mirror of
https://github.com/psycopg/psycopg2.git
synced 2024-11-29 12:23:42 +03:00
Added enum with possilbe isolation level states.
Also, general isolation levels cleanup and tests added.
This commit is contained in:
parent
4074635629
commit
bcacdc8461
|
@ -1,3 +1,8 @@
|
||||||
|
2010-11-18 Daniele Varrazzo <daniele.varrazzo@gmail.com>
|
||||||
|
|
||||||
|
* psycopg/connection.h: Added enum with possilbe isolation level states.
|
||||||
|
Also, general isolation levels cleanup and tests added.
|
||||||
|
|
||||||
2010-11-17 Daniele Varrazzo <daniele.varrazzo@gmail.com>
|
2010-11-17 Daniele Varrazzo <daniele.varrazzo@gmail.com>
|
||||||
|
|
||||||
* psycopg/connection_type.c: don't clobber exception if
|
* psycopg/connection_type.c: don't clobber exception if
|
||||||
|
|
|
@ -66,6 +66,13 @@ extern "C" {
|
||||||
#define psyco_datestyle "SET DATESTYLE TO 'ISO'"
|
#define psyco_datestyle "SET DATESTYLE TO 'ISO'"
|
||||||
#define psyco_transaction_isolation "SHOW default_transaction_isolation"
|
#define psyco_transaction_isolation "SHOW default_transaction_isolation"
|
||||||
|
|
||||||
|
/* possible values for isolation_level */
|
||||||
|
typedef enum {
|
||||||
|
ISOLATION_LEVEL_AUTOCOMMIT = 0,
|
||||||
|
ISOLATION_LEVEL_READ_COMMITTED = 1,
|
||||||
|
ISOLATION_LEVEL_SERIALIZABLE = 2,
|
||||||
|
} conn_isolation_level_t;
|
||||||
|
|
||||||
extern HIDDEN PyTypeObject connectionType;
|
extern HIDDEN PyTypeObject connectionType;
|
||||||
|
|
||||||
struct connectionObject_notice {
|
struct connectionObject_notice {
|
||||||
|
|
|
@ -265,11 +265,11 @@ conn_get_isolation_level(PGresult *pgres)
|
||||||
|
|
||||||
char *isolation_level = PQgetvalue(pgres, 0, 0);
|
char *isolation_level = PQgetvalue(pgres, 0, 0);
|
||||||
|
|
||||||
if ((strncmp(lvl1a, isolation_level, strlen(isolation_level)) == 0)
|
if ((strcmp(lvl1b, isolation_level) == 0) /* most likely */
|
||||||
|| (strncmp(lvl1b, isolation_level, strlen(isolation_level)) == 0))
|
|| (strcmp(lvl1a, isolation_level) == 0))
|
||||||
rv = 1;
|
rv = ISOLATION_LEVEL_READ_COMMITTED;
|
||||||
else /* if it's not one of the lower ones, it's SERIALIZABLE */
|
else /* if it's not one of the lower ones, it's SERIALIZABLE */
|
||||||
rv = 2;
|
rv = ISOLATION_LEVEL_SERIALIZABLE;
|
||||||
|
|
||||||
CLEARPGRES(pgres);
|
CLEARPGRES(pgres);
|
||||||
|
|
||||||
|
@ -659,7 +659,7 @@ _conn_poll_setup_async(connectionObject *self)
|
||||||
* expected to manage the transactions himself, by sending
|
* expected to manage the transactions himself, by sending
|
||||||
* (asynchronously) BEGIN and COMMIT statements.
|
* (asynchronously) BEGIN and COMMIT statements.
|
||||||
*/
|
*/
|
||||||
self->isolation_level = 0;
|
self->isolation_level = ISOLATION_LEVEL_AUTOCOMMIT;
|
||||||
|
|
||||||
/* If the datestyle is ISO or anything else good,
|
/* If the datestyle is ISO or anything else good,
|
||||||
* we can skip the CONN_STATUS_DATESTYLE step. */
|
* we can skip the CONN_STATUS_DATESTYLE step. */
|
||||||
|
@ -830,20 +830,21 @@ conn_switch_isolation_level(connectionObject *self, int level)
|
||||||
char *error = NULL;
|
char *error = NULL;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
/* if the current isolation level is equal to the requested one don't switch */
|
|
||||||
if (self->isolation_level == level) return 0;
|
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS;
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
pthread_mutex_lock(&self->lock);
|
pthread_mutex_lock(&self->lock);
|
||||||
|
|
||||||
|
/* if the current isolation level is equal to the requested one don't switch */
|
||||||
|
if (self->isolation_level != level) {
|
||||||
|
|
||||||
/* if the current isolation level is > 0 we need to abort the current
|
/* if the current isolation level is > 0 we need to abort the current
|
||||||
transaction before changing; that all folks! */
|
transaction before changing; that all folks! */
|
||||||
if (self->isolation_level != level && self->isolation_level > 0) {
|
if (self->isolation_level != ISOLATION_LEVEL_AUTOCOMMIT) {
|
||||||
res = pq_abort_locked(self, &pgres, &error, &_save);
|
res = pq_abort_locked(self, &pgres, &error, &_save);
|
||||||
}
|
}
|
||||||
self->isolation_level = level;
|
self->isolation_level = level;
|
||||||
|
|
||||||
Dprintf("conn_switch_isolation_level: switched to level %d", level);
|
Dprintf("conn_switch_isolation_level: switched to level %d", level);
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&self->lock);
|
pthread_mutex_unlock(&self->lock);
|
||||||
Py_END_ALLOW_THREADS;
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
|
@ -209,7 +209,7 @@ psyco_conn_tpc_begin(connectionObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* two phase commit and autocommit make no point */
|
/* two phase commit and autocommit make no point */
|
||||||
if (self->isolation_level == 0) {
|
if (self->isolation_level == ISOLATION_LEVEL_AUTOCOMMIT) {
|
||||||
PyErr_SetString(ProgrammingError,
|
PyErr_SetString(ProgrammingError,
|
||||||
"tpc_begin can't be called in autocommit mode");
|
"tpc_begin can't be called in autocommit mode");
|
||||||
goto exit;
|
goto exit;
|
||||||
|
@ -410,7 +410,7 @@ psyco_conn_set_isolation_level(connectionObject *self, PyObject *args)
|
||||||
|
|
||||||
if (level < 0 || level > 2) {
|
if (level < 0 || level > 2) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"isolation level out of bounds (0,3)");
|
"isolation level must be between 0 and 2");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -476,7 +476,7 @@ psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs)
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (self->conn->isolation_level == 0) {
|
if (self->conn->isolation_level == ISOLATION_LEVEL_AUTOCOMMIT) {
|
||||||
psyco_set_error(ProgrammingError, (PyObject*)self,
|
psyco_set_error(ProgrammingError, (PyObject*)self,
|
||||||
"can't use a named cursor outside of transactions", NULL, NULL);
|
"can't use a named cursor outside of transactions", NULL, NULL);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -129,7 +129,7 @@ lobject_close_locked(lobjectObject *self, char **error)
|
||||||
{
|
{
|
||||||
int retvalue;
|
int retvalue;
|
||||||
|
|
||||||
if (self->conn->isolation_level == 0 ||
|
if (self->conn->isolation_level == ISOLATION_LEVEL_AUTOCOMMIT ||
|
||||||
self->conn->mark != self->mark ||
|
self->conn->mark != self->mark ||
|
||||||
self->fd == -1)
|
self->fd == -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -55,7 +55,7 @@ psyco_lobj_close(lobjectObject *self, PyObject *args)
|
||||||
closing the current transaction is equivalent to close all the
|
closing the current transaction is equivalent to close all the
|
||||||
opened large objects */
|
opened large objects */
|
||||||
if (!lobject_is_closed(self)
|
if (!lobject_is_closed(self)
|
||||||
&& self->conn->isolation_level > 0
|
&& self->conn->isolation_level != ISOLATION_LEVEL_AUTOCOMMIT
|
||||||
&& self->conn->mark == self->mark)
|
&& self->conn->mark == self->mark)
|
||||||
{
|
{
|
||||||
Dprintf("psyco_lobj_close: closing lobject at %p", self);
|
Dprintf("psyco_lobj_close: closing lobject at %p", self);
|
||||||
|
@ -300,7 +300,7 @@ lobject_setup(lobjectObject *self, connectionObject *conn,
|
||||||
{
|
{
|
||||||
Dprintf("lobject_setup: init lobject object at %p", self);
|
Dprintf("lobject_setup: init lobject object at %p", self);
|
||||||
|
|
||||||
if (conn->isolation_level == 0) {
|
if (conn->isolation_level == ISOLATION_LEVEL_AUTOCOMMIT) {
|
||||||
psyco_set_error(ProgrammingError, (PyObject*)self,
|
psyco_set_error(ProgrammingError, (PyObject*)self,
|
||||||
"can't use a lobject outside of transactions", NULL, NULL);
|
"can't use a lobject outside of transactions", NULL, NULL);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -409,7 +409,8 @@ pq_begin_locked(connectionObject *conn, PGresult **pgres, char **error,
|
||||||
Dprintf("pq_begin_locked: pgconn = %p, isolevel = %ld, status = %d",
|
Dprintf("pq_begin_locked: pgconn = %p, isolevel = %ld, status = %d",
|
||||||
conn->pgconn, conn->isolation_level, conn->status);
|
conn->pgconn, conn->isolation_level, conn->status);
|
||||||
|
|
||||||
if (conn->isolation_level == 0 || conn->status != CONN_STATUS_READY) {
|
if (conn->isolation_level == ISOLATION_LEVEL_AUTOCOMMIT
|
||||||
|
|| conn->status != CONN_STATUS_READY) {
|
||||||
Dprintf("pq_begin_locked: transaction in progress");
|
Dprintf("pq_begin_locked: transaction in progress");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -438,7 +439,8 @@ pq_commit(connectionObject *conn)
|
||||||
Dprintf("pq_commit: pgconn = %p, isolevel = %ld, status = %d",
|
Dprintf("pq_commit: pgconn = %p, isolevel = %ld, status = %d",
|
||||||
conn->pgconn, conn->isolation_level, conn->status);
|
conn->pgconn, conn->isolation_level, conn->status);
|
||||||
|
|
||||||
if (conn->isolation_level == 0 || conn->status != CONN_STATUS_BEGIN) {
|
if (conn->isolation_level == ISOLATION_LEVEL_AUTOCOMMIT
|
||||||
|
|| conn->status != CONN_STATUS_BEGIN) {
|
||||||
Dprintf("pq_commit: no transaction to commit");
|
Dprintf("pq_commit: no transaction to commit");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -473,7 +475,8 @@ pq_abort_locked(connectionObject *conn, PGresult **pgres, char **error,
|
||||||
Dprintf("pq_abort_locked: pgconn = %p, isolevel = %ld, status = %d",
|
Dprintf("pq_abort_locked: pgconn = %p, isolevel = %ld, status = %d",
|
||||||
conn->pgconn, conn->isolation_level, conn->status);
|
conn->pgconn, conn->isolation_level, conn->status);
|
||||||
|
|
||||||
if (conn->isolation_level == 0 || conn->status != CONN_STATUS_BEGIN) {
|
if (conn->isolation_level == ISOLATION_LEVEL_AUTOCOMMIT
|
||||||
|
|| conn->status != CONN_STATUS_BEGIN) {
|
||||||
Dprintf("pq_abort_locked: no transaction to abort");
|
Dprintf("pq_abort_locked: no transaction to abort");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -501,7 +504,8 @@ pq_abort(connectionObject *conn)
|
||||||
Dprintf("pq_abort: pgconn = %p, isolevel = %ld, status = %d",
|
Dprintf("pq_abort: pgconn = %p, isolevel = %ld, status = %d",
|
||||||
conn->pgconn, conn->isolation_level, conn->status);
|
conn->pgconn, conn->isolation_level, conn->status);
|
||||||
|
|
||||||
if (conn->isolation_level == 0 || conn->status != CONN_STATUS_BEGIN) {
|
if (conn->isolation_level == ISOLATION_LEVEL_AUTOCOMMIT
|
||||||
|
|| conn->status != CONN_STATUS_BEGIN) {
|
||||||
Dprintf("pq_abort: no transaction to abort");
|
Dprintf("pq_abort: no transaction to abort");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -542,7 +546,8 @@ pq_reset_locked(connectionObject *conn, PGresult **pgres, char **error,
|
||||||
|
|
||||||
conn->mark += 1;
|
conn->mark += 1;
|
||||||
|
|
||||||
if (conn->isolation_level > 0 && conn->status == CONN_STATUS_BEGIN) {
|
if (conn->isolation_level != ISOLATION_LEVEL_AUTOCOMMIT
|
||||||
|
&& conn->status == CONN_STATUS_BEGIN) {
|
||||||
retvalue = pq_execute_command_locked(conn, "ABORT", pgres, error, tstate);
|
retvalue = pq_execute_command_locked(conn, "ABORT", pgres, error, tstate);
|
||||||
if (retvalue != 0) return retvalue;
|
if (retvalue != 0) return retvalue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,20 @@ class ConnectionTests(unittest.TestCase):
|
||||||
conn = self.connect()
|
conn = self.connect()
|
||||||
self.assert_(conn.protocol_version in (2,3), conn.protocol_version)
|
self.assert_(conn.protocol_version in (2,3), conn.protocol_version)
|
||||||
|
|
||||||
|
|
||||||
|
class IsolationLevelsTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
conn = self.connect()
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute("drop table if exists isolevel;")
|
||||||
|
cur.execute("create table isolevel (id integer);")
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
return psycopg2.connect(tests.dsn)
|
||||||
|
|
||||||
def test_isolation_level(self):
|
def test_isolation_level(self):
|
||||||
conn = self.connect()
|
conn = self.connect()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -92,22 +106,78 @@ class ConnectionTests(unittest.TestCase):
|
||||||
conn = self.connect()
|
conn = self.connect()
|
||||||
self.assert_(conn.encoding in psycopg2.extensions.encodings)
|
self.assert_(conn.encoding in psycopg2.extensions.encodings)
|
||||||
|
|
||||||
|
def test_set_isolation_level(self):
|
||||||
|
conn = self.connect()
|
||||||
|
|
||||||
|
conn.set_isolation_level(
|
||||||
|
psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
|
||||||
|
self.assertEqual(conn.isolation_level,
|
||||||
|
psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
|
||||||
|
|
||||||
|
conn.set_isolation_level(
|
||||||
|
psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED)
|
||||||
|
self.assertEqual(conn.isolation_level,
|
||||||
|
psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED)
|
||||||
|
|
||||||
|
conn.set_isolation_level(
|
||||||
|
psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE)
|
||||||
|
self.assertEqual(conn.isolation_level,
|
||||||
|
psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE)
|
||||||
|
|
||||||
|
self.assertRaises(ValueError, conn.set_isolation_level, -1)
|
||||||
|
self.assertRaises(ValueError, conn.set_isolation_level, 3)
|
||||||
|
|
||||||
|
def test_set_isolation_level_abort(self):
|
||||||
|
conn = self.connect()
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
self.assertEqual(psycopg2.extensions.TRANSACTION_STATUS_IDLE,
|
||||||
|
conn.get_transaction_status())
|
||||||
|
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_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])
|
||||||
|
|
||||||
def test_isolation_level_autocommit(self):
|
def test_isolation_level_autocommit(self):
|
||||||
cnn1 = self.connect()
|
cnn1 = self.connect()
|
||||||
cnn2 = self.connect()
|
cnn2 = self.connect()
|
||||||
cnn2.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
|
cnn2.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
|
||||||
|
|
||||||
cur1 = cnn1.cursor()
|
cur1 = cnn1.cursor()
|
||||||
cur1.execute("drop table if exists isolevel;")
|
|
||||||
cur1.execute("create table isolevel (id integer);")
|
|
||||||
cur1.execute("select count(*) from isolevel;")
|
cur1.execute("select count(*) from isolevel;")
|
||||||
self.assertEqual(0, cur1.fetchone()[0])
|
self.assertEqual(0, cur1.fetchone()[0])
|
||||||
cnn1.commit()
|
cnn1.commit()
|
||||||
|
|
||||||
cur2 = cnn2.cursor()
|
cur2 = cnn2.cursor()
|
||||||
cur2.execute("insert into isolevel values (10);")
|
cur2.execute("insert into isolevel values (10);")
|
||||||
cur1.execute("select count(*) from isolevel;")
|
|
||||||
|
|
||||||
|
cur1.execute("select count(*) from isolevel;")
|
||||||
self.assertEqual(1, cur1.fetchone()[0])
|
self.assertEqual(1, cur1.fetchone()[0])
|
||||||
|
|
||||||
def test_isolation_level_read_committed(self):
|
def test_isolation_level_read_committed(self):
|
||||||
|
@ -116,47 +186,52 @@ class ConnectionTests(unittest.TestCase):
|
||||||
cnn2.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED)
|
cnn2.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_READ_COMMITTED)
|
||||||
|
|
||||||
cur1 = cnn1.cursor()
|
cur1 = cnn1.cursor()
|
||||||
cur1.execute("drop table if exists isolevel;")
|
|
||||||
cur1.execute("create table isolevel (id integer);")
|
|
||||||
cur1.execute("select count(*) from isolevel;")
|
cur1.execute("select count(*) from isolevel;")
|
||||||
self.assertEqual(0, cur1.fetchone()[0])
|
self.assertEqual(0, cur1.fetchone()[0])
|
||||||
cnn1.commit()
|
cnn1.commit()
|
||||||
|
|
||||||
cur2 = cnn2.cursor()
|
cur2 = cnn2.cursor()
|
||||||
cur2.execute("insert into isolevel values (10);")
|
cur2.execute("insert into isolevel values (10);")
|
||||||
|
cur1.execute("insert into isolevel values (20);")
|
||||||
|
|
||||||
cur2.execute("select count(*) from isolevel;")
|
cur2.execute("select count(*) from isolevel;")
|
||||||
self.assertEqual(1, cur2.fetchone()[0])
|
self.assertEqual(1, cur2.fetchone()[0])
|
||||||
|
|
||||||
cur1.execute("insert into isolevel values (20);")
|
|
||||||
cnn1.commit()
|
cnn1.commit()
|
||||||
|
|
||||||
cur2.execute("select count(*) from isolevel;")
|
cur2.execute("select count(*) from isolevel;")
|
||||||
self.assertEqual(2, cur2.fetchone()[0])
|
self.assertEqual(2, cur2.fetchone()[0])
|
||||||
|
|
||||||
|
cur1.execute("select count(*) from isolevel;")
|
||||||
|
self.assertEqual(1, cur1.fetchone()[0])
|
||||||
|
cnn2.commit()
|
||||||
|
cur1.execute("select count(*) from isolevel;")
|
||||||
|
self.assertEqual(2, cur1.fetchone()[0])
|
||||||
|
|
||||||
def test_isolation_level_serializable(self):
|
def test_isolation_level_serializable(self):
|
||||||
cnn1 = self.connect()
|
cnn1 = self.connect()
|
||||||
cnn2 = self.connect()
|
cnn2 = self.connect()
|
||||||
cnn2.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE)
|
cnn2.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_SERIALIZABLE)
|
||||||
|
|
||||||
cur1 = cnn1.cursor()
|
cur1 = cnn1.cursor()
|
||||||
cur1.execute("drop table if exists isolevel;")
|
|
||||||
cur1.execute("create table isolevel (id integer);")
|
|
||||||
cur1.execute("select count(*) from isolevel;")
|
cur1.execute("select count(*) from isolevel;")
|
||||||
self.assertEqual(0, cur1.fetchone()[0])
|
self.assertEqual(0, cur1.fetchone()[0])
|
||||||
cnn1.commit()
|
cnn1.commit()
|
||||||
|
|
||||||
cur2 = cnn2.cursor()
|
cur2 = cnn2.cursor()
|
||||||
cur2.execute("insert into isolevel values (10);")
|
cur2.execute("insert into isolevel values (10);")
|
||||||
cur2.execute("select count(*) from isolevel;")
|
|
||||||
self.assertEqual(1, cur2.fetchone()[0])
|
|
||||||
|
|
||||||
cur1.execute("insert into isolevel values (20);")
|
cur1.execute("insert into isolevel values (20);")
|
||||||
cnn1.commit()
|
|
||||||
|
|
||||||
|
cur2.execute("select count(*) from isolevel;")
|
||||||
|
self.assertEqual(1, cur2.fetchone()[0])
|
||||||
|
cnn1.commit()
|
||||||
cur2.execute("select count(*) from isolevel;")
|
cur2.execute("select count(*) from isolevel;")
|
||||||
self.assertEqual(1, cur2.fetchone()[0])
|
self.assertEqual(1, cur2.fetchone()[0])
|
||||||
|
|
||||||
|
cur1.execute("select count(*) from isolevel;")
|
||||||
|
self.assertEqual(1, cur1.fetchone()[0])
|
||||||
cnn2.commit()
|
cnn2.commit()
|
||||||
|
cur1.execute("select count(*) from isolevel;")
|
||||||
|
self.assertEqual(2, cur1.fetchone()[0])
|
||||||
|
|
||||||
cur2.execute("select count(*) from isolevel;")
|
cur2.execute("select count(*) from isolevel;")
|
||||||
self.assertEqual(2, cur2.fetchone()[0])
|
self.assertEqual(2, cur2.fetchone()[0])
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user