1
"""Global database feature support policy.
3
Provides decorators to mark tests requiring specific feature support from the
9
_block_unconditionally as no_support, \
10
_chain_decorators_on, \
16
fails_on_everything_except,\
18
from sqlalchemy import util
19
from test.lib import config
23
def deferrable_constraints(fn):
24
"""Target database must support derferable constraints."""
25
return _chain_decorators_on(
27
no_support('firebird', 'not supported by database'),
28
no_support('mysql', 'not supported by database'),
29
no_support('mssql', 'not supported by database'),
33
"""Target database must support foreign keys."""
34
return _chain_decorators_on(
36
no_support('sqlite', 'not supported by database'),
40
def unbounded_varchar(fn):
41
"""Target database must support VARCHAR with no length"""
42
return _chain_decorators_on(
44
no_support('firebird', 'not supported by database'),
45
no_support('oracle', 'not supported by database'),
46
no_support('mysql', 'not supported by database'),
49
def boolean_col_expressions(fn):
50
"""Target database must support boolean expressions as columns"""
51
return _chain_decorators_on(
53
no_support('firebird', 'not supported by database'),
54
no_support('oracle', 'not supported by database'),
55
no_support('mssql', 'not supported by database'),
56
no_support('sybase', 'not supported by database'),
57
no_support('maxdb', 'FIXME: verify not supported by database'),
58
no_support('informix', 'not supported by database'),
62
"""Target database must support GENERATED AS IDENTITY or a facsimile.
64
Includes GENERATED AS IDENTITY, AUTOINCREMENT, AUTO_INCREMENT, or other
65
column DDL feature that fills in a DB-generated identifier at INSERT-time
66
without requiring pre-execution of a SEQUENCE or other artifact.
69
return _chain_decorators_on(
71
no_support('firebird', 'not supported by database'),
72
no_support('oracle', 'not supported by database'),
73
no_support('postgresql', 'not supported by database'),
74
no_support('sybase', 'not supported by database'),
77
def independent_cursors(fn):
78
"""Target must support simultaneous, independent database cursors on a single connection."""
80
return _chain_decorators_on(
82
no_support('mssql+pyodbc', 'no driver support'),
83
no_support('mssql+mxodbc', 'no driver support'),
86
def independent_connections(fn):
87
"""Target must support simultaneous, independent database connections."""
89
# This is also true of some configurations of UnixODBC and probably win32
91
return _chain_decorators_on(
93
no_support('sqlite', 'Independent connections disabled when '
94
':memory: connections are used'),
95
exclude('mssql', '<', (9, 0, 0),
96
'SQL Server 2005+ is required for independent connections'),
99
def isolation_level(fn):
100
return _chain_decorators_on(
102
only_on(('postgresql', 'sqlite'), "DBAPI has no isolation level support"),
103
fails_on('postgresql+pypostgresql',
104
'pypostgresql bombs on multiple isolation level calls')
107
def row_triggers(fn):
108
"""Target must support standard statement-running EACH ROW triggers."""
109
return _chain_decorators_on(
111
# no access to same table
112
no_support('mysql', 'requires SUPER priv'),
113
exclude('mysql', '<', (5, 0, 10), 'not supported by database'),
115
# huh? TODO: implement triggers for PG tests, remove this
116
no_support('postgresql', 'PG triggers need to be implemented for tests'),
119
def correlated_outer_joins(fn):
120
"""Target must support an outer join to a subquery which correlates to the parent."""
122
return _chain_decorators_on(
124
no_support('oracle', 'Raises "ORA-01799: a column may not be outer-joined to a subquery"')
128
"""Target database must support savepoints."""
129
return _chain_decorators_on(
131
emits_warning_on('mssql', 'Savepoint support in mssql is experimental and may lead to data loss.'),
132
no_support('access', 'savepoints not supported'),
133
no_support('sqlite', 'savepoints not supported'),
134
no_support('sybase', 'savepoints not supported'),
135
exclude('mysql', '<', (5, 0, 3), 'savepoints not supported'),
136
exclude('informix', '<', (11, 55, 'xC3'), 'savepoints not supported'),
139
def denormalized_names(fn):
140
"""Target database must have 'denormalized', i.e. UPPERCASE as case insensitive names."""
143
lambda: not testing.db.dialect.requires_name_normalize,
144
"Backend does not require denomralized names."
148
"""Target database must support external schemas, and have one named 'test_schema'."""
150
return _chain_decorators_on(
152
no_support('sqlite', 'no schema support'),
153
no_support('firebird', 'no schema support')
157
"""Target database must support SEQUENCEs."""
158
return _chain_decorators_on(
160
no_support('access', 'no SEQUENCE support'),
161
no_support('drizzle', 'no SEQUENCE support'),
162
no_support('mssql', 'no SEQUENCE support'),
163
no_support('mysql', 'no SEQUENCE support'),
164
no_support('sqlite', 'no SEQUENCE support'),
165
no_support('sybase', 'no SEQUENCE support'),
166
no_support('informix', 'no SEQUENCE support'),
169
def update_nowait(fn):
170
"""Target database must support SELECT...FOR UPDATE NOWAIT"""
171
return _chain_decorators_on(
173
no_support('access', 'no FOR UPDATE NOWAIT support'),
174
no_support('firebird', 'no FOR UPDATE NOWAIT support'),
175
no_support('mssql', 'no FOR UPDATE NOWAIT support'),
176
no_support('mysql', 'no FOR UPDATE NOWAIT support'),
177
no_support('sqlite', 'no FOR UPDATE NOWAIT support'),
178
no_support('sybase', 'no FOR UPDATE NOWAIT support'),
182
"""Target database must support subqueries."""
183
return _chain_decorators_on(
185
exclude('mysql', '<', (4, 1, 1), 'no subquery support'),
189
"""Target database must support INTERSECT or equivlaent."""
190
return _chain_decorators_on(
192
fails_on('firebird', 'no support for INTERSECT'),
193
fails_on('mysql', 'no support for INTERSECT'),
194
fails_on('sybase', 'no support for INTERSECT'),
195
fails_on('informix', 'no support for INTERSECT'),
199
"""Target database must support EXCEPT or equivlaent (i.e. MINUS)."""
200
return _chain_decorators_on(
202
fails_on('firebird', 'no support for EXCEPT'),
203
fails_on('mysql', 'no support for EXCEPT'),
204
fails_on('sybase', 'no support for EXCEPT'),
205
fails_on('informix', 'no support for EXCEPT'),
209
"""Target database must support some method of adding OFFSET or equivalent to a result set."""
210
return _chain_decorators_on(
212
fails_on('sybase', 'no support for OFFSET or equivalent'),
215
def window_functions(fn):
216
return _chain_decorators_on(
218
only_on(('postgresql', 'mssql', 'oracle'),
219
"Backend does not support window functions"),
223
return _chain_decorators_on(
225
no_support('access', "'returning' not supported by database"),
226
no_support('sqlite', "'returning' not supported by database"),
227
no_support('mysql', "'returning' not supported by database"),
228
no_support('maxdb', "'returning' not supported by database"),
229
no_support('sybase', "'returning' not supported by database"),
230
no_support('informix', "'returning' not supported by database"),
233
def two_phase_transactions(fn):
234
"""Target database must support two-phase transactions."""
235
return _chain_decorators_on(
237
no_support('access', 'not supported by database'),
238
no_support('firebird', 'no SA implementation'),
239
no_support('maxdb', 'not supported by database'),
240
no_support('mssql', 'FIXME: guessing, needs confirmation'),
241
no_support('oracle', 'no SA implementation'),
242
no_support('drizzle', 'not supported by database'),
243
no_support('sqlite', 'not supported by database'),
244
no_support('sybase', 'FIXME: guessing, needs confirmation'),
245
no_support('postgresql+zxjdbc', 'FIXME: JDBC driver confuses the transaction state, may '
246
'need separate XA implementation'),
247
exclude('mysql', '<', (5, 0, 3), 'not supported by database'),
251
"""Target database must support VIEWs."""
252
return _chain_decorators_on(
254
no_support('drizzle', 'no VIEW support'),
257
def unicode_connections(fn):
258
"""Target driver must support some encoding of Unicode across the wire."""
259
# TODO: expand to exclude MySQLdb versions w/ broken unicode
260
return _chain_decorators_on(
262
exclude('mysql', '<', (4, 1, 1), 'no unicode connection support'),
266
"""Target driver must support some encoding of Unicode across the wire."""
267
# TODO: expand to exclude MySQLdb versions w/ broken unicode
268
return _chain_decorators_on(
270
no_support('maxdb', 'database support flakey'),
271
no_support('oracle', 'FIXME: no support in database?'),
272
no_support('sybase', 'FIXME: guessing, needs confirmation'),
273
no_support('mssql+pymssql', 'no FreeTDS support'),
274
exclude('mysql', '<', (4, 1, 1), 'no unicode connection support'),
277
def sane_rowcount(fn):
278
return _chain_decorators_on(
280
skip_if(lambda: not testing.db.dialect.supports_sane_rowcount)
284
return _chain_decorators_on(
286
skip_if(lambda: not _has_cextensions(), "C extensions not installed")
289
def dbapi_lastrowid(fn):
291
return _chain_decorators_on(
293
fails_if(lambda:True)
296
return _chain_decorators_on(
298
fails_on_everything_except('mysql+mysqldb', 'mysql+oursql',
299
'sqlite+pysqlite', 'mysql+pymysql'),
302
def sane_multi_rowcount(fn):
303
return _chain_decorators_on(
305
skip_if(lambda: not testing.db.dialect.supports_sane_multi_rowcount)
308
def nullsordering(fn):
309
"""Target backends that support nulls ordering."""
310
return _chain_decorators_on(
312
fails_on_everything_except('postgresql', 'oracle', 'firebird')
315
def reflects_pk_names(fn):
316
"""Target driver reflects the name of primary key constraints."""
317
return _chain_decorators_on(
319
fails_on_everything_except('postgresql', 'oracle')
323
return _chain_decorators_on(
326
lambda: sys.version_info >= (3,),
327
"Python version 2.xx is required."
332
return _chain_decorators_on(
335
lambda: sys.version_info < (2, 6),
336
"Python version 2.6 or greater is required"
341
return _chain_decorators_on(
344
lambda: sys.version_info < (2, 5),
345
"Python version 2.5 or greater is required"
350
return _chain_decorators_on(
352
skip_if(lambda: util.jython or util.pypy,
353
"cPython interpreter needed"
357
def _has_cextensions():
359
from sqlalchemy import cresultproxy, cprocessors
365
from sqlalchemy import create_engine
367
e = create_engine('sqlite://')
372
def _has_mysql_on_windows():
373
return testing.against('mysql') and \
374
testing.db.dialect._server_casing == 1
376
def _has_mysql_fully_case_sensitive():
377
return testing.against('mysql') and \
378
testing.db.dialect._server_casing == 0
381
return _chain_decorators_on(
383
skip_if(lambda: not _has_sqlite())
386
def ad_hoc_engines(fn):
387
"""Test environment must allow ad-hoc engine/connection creation.
389
DBs that scale poorly for many connections, even when closed, i.e.
390
Oracle, may use the "--low-connections" option which flags this requirement
394
return _chain_decorators_on(
396
skip_if(lambda: config.options.low_connections)
399
def skip_mysql_on_windows(fn):
400
"""Catchall for a large variety of MySQL on Windows failures"""
402
return _chain_decorators_on(
404
skip_if(_has_mysql_on_windows,
405
"Not supported on MySQL + Windows"
409
def english_locale_on_postgresql(fn):
410
return _chain_decorators_on(
412
skip_if(lambda: testing.against('postgresql') \
413
and not testing.db.scalar('SHOW LC_COLLATE').startswith('en'))