No, the lockups occur because SQL2000 doesn't really have independent
database connections.
test.orm.test_session:SessionTest.test_autoflush is a good example.
It starts a transaction, inserts a record and selects the record.
Before the transaction is closed, a different connection tries to
select records.
That causes deadlock since the testcase is running both connections in
one thread (the test runner) and SQL2000 doesn't support MVCC/SNAPSHOT
isolation at all.
You can reproduce this with raw SQL in the query analyzer with:
---snip--
begin transaction
go
insert into users (name) values ('ed');
go
select count(1) from users
go
waitfor delay '00:00:10'
-- open a separate connection to the database once the wait takes
place and run "select count(1) from users"
go
rollback
---snip--
For SQL2005+, you still have to manually enable MVCC isolation with:
ALTER DATABASE db_name SET ALLOW_SNAPSHOT_ISOLATION ON;
(
http://msdn.microsoft.com/en-us/library/ms175095.aspx)
So... I think the right thing to do is to make a new decorator that :
* checks dialect name
* checks the server version number (< 9 is unsupported) and
* checks the dialect isolation (must have SNAPSHOT enabled)
I'm a bit confused by sqlalchemy.test.testing - so my code 'works' but
it seems clunky.
I've added a new testing decorator filter like this:
def _dialect_isolation_level(bind=None):
"""Return a isolation_level from the dialect."""
if bind is None:
bind = config.db
# force metadata to be retrieved
conn = bind.connect()
isolation_level = getattr(bind.dialect, 'isolation_level', None)
conn.close()
return isolation_level
def check_required_isolation(db, op, spec, required_isolation_level,
reason=None):
"""
Skip a test if the isolation level doesn't match.
"""
spec = db_spec(db)
def decorate(fn):
fn_name = fn.__name__
def maybe(*args, **kw):
if _is_excluded(db, op, spec):
msg = "'%s' unsupported on DB %s version '%s':
Isolation level: %s : %s" % (
fn_name,
config.db.name, _server_version(),
_dialect_isolation_level(), reason)
print msg
return True
elif spec(config.db) and _dialect_isolation_level() <>
required_isolation_level:
msg = "'%s' unsupported on DB %s version '%s':
Isolation level: %s : %s" % (
fn_name,
config.db.name, _server_version(),
_dialect_isolation_level(), reason)
print msg
return True
else:
return fn(*args, **kw)
return function_named(maybe, fn_name)
return decorate
and I've changed the signature of
test.orm.test_session:SessionTest.test_autoflush to be :
@testing.check_required_isolation('mssql', '<', (9,0,0),
'SNAPSHOT', 'SQL Server 2008 or higher is required and SNAPSHOT
isolation must be enabled')
@engines.close_open_connections
@testing.resolve_artifact_names
def test_autoflush(self):
...
This still means that the database that the user is testing on needs
to manually set the ALLOW_SNAPSHOT_ISOLATION or else the tests will
lock up, but I think that's acceptable.
What do you think?
vic
Your remark about windowness made me laugh. It's also beyond my
windowness to get 2008 and 2005 running concurrently. I could barely
get 2000 and 2005 working concurrently.