mssql+zxjdbc support

original patch from Victor Ng
fixes #1505
This commit is contained in:
Philip Jenvey 2009-09-11 08:10:32 +00:00
parent 0c26713326
commit f385260987
6 changed files with 86 additions and 10 deletions

View File

@ -192,10 +192,15 @@ and an additional "owner" named "ed" is required:
MSSQL: Tests that involve multiple connections require Snapshot Isolation
ability implented on the test database in order to prevent deadlocks that will
occur with record locking isolation. This feature is only available with
MSSQL 2005 and greater. For example::
MSSQL 2005 and greater. You must enable snapshot isolation at the database level
and set the default cursor isolation with two SQL commands ::
ALTER DATABASE MyDatabase
SET ALLOW_SNAPSHOT_ISOLATION ON
ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON
MSSQL+zxJDBC: Trying to run the unit tests on Windows against SQL Server
requires using a test.cfg configuration file as the cmd.exe shell won't properly
pass the URL arguments into the nose test runner.

View File

@ -1,3 +1,3 @@
from sqlalchemy.dialects.mssql import base, pyodbc, adodbapi, pymssql
from sqlalchemy.dialects.mssql import base, pyodbc, adodbapi, pymssql, zxjdbc
base.dialect = pyodbc.dialect
base.dialect = pyodbc.dialect

View File

@ -0,0 +1,64 @@
"""Support for the Microsoft SQL Server database via the zxjdbc JDBC
connector.
JDBC Driver
-----------
Requires the jTDS driver, available from: http://jtds.sourceforge.net/
Connecting
----------
URLs are of the standard form of
``mssql+zxjdbc://user:pass@host:port/dbname[?key=value&key=value...]``.
Additional arguments which may be specified either as query string
arguments on the URL, or as keyword arguments to
:func:`~sqlalchemy.create_engine()` will be passed as Connection
properties to the underlying JDBC driver.
"""
from sqlalchemy.connectors.zxJDBC import ZxJDBCConnector
from sqlalchemy.dialects.mssql.base import MSDialect, MSExecutionContext
from sqlalchemy.engine import base
class MS_zxjdbcExecutionContext(MSExecutionContext):
_embedded_scope_identity = False
def pre_exec(self):
super(MS_zxjdbcExecutionContext, self).pre_exec()
# scope_identity after the fact returns null in jTDS so we must
# embed it
if self._select_lastrowid and self.dialect.use_scope_identity:
self._embedded_scope_identity = True
self.statement += "; SELECT scope_identity()"
def post_exec(self):
if self._embedded_scope_identity:
while True:
try:
row = self.cursor.fetchall()[0]
break
except self.dialect.dbapi.Error, e:
self.cursor.nextset()
self._lastrowid = int(row[0])
if (self.isinsert or self.isupdate or self.isdelete) and self.compiled.returning:
self._result_proxy = base.FullyBufferedResultProxy(self)
if self._enable_identity_insert:
table = self.dialect.identifier_preparer.format_table(self.compiled.statement.table)
self.cursor.execute("SET IDENTITY_INSERT %s OFF" % table)
class MS_zxjdbc(ZxJDBCConnector, MSDialect):
jdbc_db_name = 'jtds:sqlserver'
jdbc_driver_name = 'net.sourceforge.jtds.jdbc.Driver'
execution_ctx_cls = MS_zxjdbcExecutionContext
def _get_server_version_info(self, connection):
return tuple(int(x) for x in connection.connection.dbversion.split('.'))
dialect = MS_zxjdbc

View File

@ -70,7 +70,9 @@ def independent_connections(fn):
# ODBC as well.
return _chain_decorators_on(
fn,
no_support('sqlite', 'no driver support')
no_support('sqlite', 'no driver support'),
exclude('mssql', '<', (9, 0, 0),
'SQL Server 2005+ is required for independent connections'),
)
def row_triggers(fn):

View File

@ -243,7 +243,8 @@ class UnicodeSchemaTest(engine_base.AltEngineTest, _base.MappedTest):
def teardown_class(cls):
super(UnicodeSchemaTest, cls).teardown_class()
@testing.fails_on('mssql', 'pyodbc returns a non unicode encoding of the results description.')
@testing.fails_on('mssql+pyodbc',
'pyodbc returns a non unicode encoding of the results description.')
@testing.resolve_artifact_names
def test_mapping(self):
class A(_base.ComparableEntity):
@ -280,7 +281,8 @@ class UnicodeSchemaTest(engine_base.AltEngineTest, _base.MappedTest):
assert new_a1.t2s[0].d == b1.d
session.expunge_all()
@testing.fails_on('mssql', 'pyodbc returns a non unicode encoding of the results description.')
@testing.fails_on('mssql+pyodbc',
'pyodbc returns a non unicode encoding of the results description.')
@testing.resolve_artifact_names
def test_inheritance_mapping(self):
class A(_base.ComparableEntity):

View File

@ -99,13 +99,16 @@ class ReturningTest(TestBase, AssertsExecutionResults):
# return value is documented as failing with psycopg2/executemany
result2 = table.insert().returning(table).execute(
[{'persons': 2, 'full': False}, {'persons': 3, 'full': True}])
if testing.against('firebird', 'mssql'):
if testing.against('mssql+zxjdbc'):
# jtds apparently returns only the first row
eq_(result2.fetchall(), [(2, 2, False, None)])
elif testing.against('firebird', 'mssql'):
# Multiple inserts only return the last row
eq_(result2.fetchall(), [(3,3,True, None)])
eq_(result2.fetchall(), [(3, 3, True, None)])
else:
# nobody does this as far as we know (pg8000?)
eq_(result2.fetchall(), [(2, 2, False, None), (3,3,True, None)])
eq_(result2.fetchall(), [(2, 2, False, None), (3, 3, True, None)])
test_executemany()