11"""
22MS SQL Server database backend for Django.
33"""
4-
5- import logging
64import os
75import re
8- import warnings
6+
7+ from django .core .exceptions import ImproperlyConfigured
98
109try :
1110 import pyodbc as Database
1211except ImportError , e :
13- from django .core .exceptions import ImproperlyConfigured
1412 raise ImproperlyConfigured ("Error loading pyodbc module: %s" % e )
1513
1614m = re .match (r'(\d+)\.(\d+)\.(\d+)(?:-beta(\d+))?' , Database .version )
1715vlist = list (m .groups ())
1816if vlist [3 ] is None : vlist [3 ] = '9999'
1917pyodbc_ver = tuple (map (int , vlist ))
2018if pyodbc_ver < (2 , 0 , 38 , 9999 ):
21- from django .core .exceptions import ImproperlyConfigured
2219 raise ImproperlyConfigured ("pyodbc 2.0.38 or newer is required; you have %s" % Database .version )
2320
2421from django .db .backends import BaseDatabaseWrapper , BaseDatabaseFeatures , BaseDatabaseValidation
4138from django_pyodbc .creation import DatabaseCreation
4239from django_pyodbc .introspection import DatabaseIntrospection
4340
44- warnings .filterwarnings ('error' , 'The DATABASE_ODBC.+ is deprecated' , DeprecationWarning , __name__ , 0 )
45-
46- logger = logging .getLogger (__name__ )
47-
48- collation = 'Latin1_General_CI_AS'
49- try :
50- if hasattr (settings , 'DATABASE_COLLATION' ):
51- warnings .warn (
52- "The DATABASE_COLLATION setting is going to be deprecated, use DATABASE_OPTIONS['collation'] instead." ,
53- DeprecationWarning
54- )
55- collation = settings .DATABASE_COLLATION
56- elif 'collation' in settings .DATABASE_OPTIONS :
57- collation = settings .DATABASE_OPTIONS ['collation' ]
58- except AttributeError :
59- pass
60-
61- deprecated = (
62- ('DATABASE_ODBC_DRIVER' , 'driver' ),
63- ('DATABASE_ODBC_DSN' , 'dsn' ),
64- ('DATABASE_ODBC_EXTRA_PARAMS' , 'extra_params' ),
65- )
66- for old , new in deprecated :
67- if hasattr (settings , old ):
68- warnings .warn (
69- "The %s setting is deprecated, use DATABASE_OPTIONS['%s'] instead." % (old , new ),
70- DeprecationWarning
71- )
72-
7341DatabaseError = Database .DatabaseError
7442IntegrityError = Database .IntegrityError
7543
@@ -101,33 +69,46 @@ class DatabaseWrapper(BaseDatabaseWrapper):
10169 # database collation.
10270 'exact' : '= %s' ,
10371 'iexact' : "= UPPER(%s)" ,
104- 'contains' : "LIKE %s ESCAPE '\\ ' COLLATE " + collation ,
105- 'icontains' : "LIKE UPPER(%s) ESCAPE '\\ ' COLLATE " + collation ,
72+ 'contains' : "LIKE %s ESCAPE '\\ '" ,
73+ 'icontains' : "LIKE UPPER(%s) ESCAPE '\\ '" ,
10674 'gt' : '> %s' ,
10775 'gte' : '>= %s' ,
10876 'lt' : '< %s' ,
10977 'lte' : '<= %s' ,
110- 'startswith' : "LIKE %s ESCAPE '\\ ' COLLATE " + collation ,
111- 'endswith' : "LIKE %s ESCAPE '\\ ' COLLATE " + collation ,
112- 'istartswith' : "LIKE UPPER(%s) ESCAPE '\\ ' COLLATE " + collation ,
113- 'iendswith' : "LIKE UPPER(%s) ESCAPE '\\ ' COLLATE " + collation ,
78+ 'startswith' : "LIKE %s ESCAPE '\\ '" ,
79+ 'endswith' : "LIKE %s ESCAPE '\\ '" ,
80+ 'istartswith' : "LIKE UPPER(%s) ESCAPE '\\ '" ,
81+ 'iendswith' : "LIKE UPPER(%s) ESCAPE '\\ '" ,
11482
11583 # TODO: remove, keep native T-SQL LIKE wildcards support
11684 # or use a "compatibility layer" and replace '*' with '%'
11785 # and '.' with '_'
118- 'regex' : 'LIKE %s COLLATE ' + collation ,
119- 'iregex' : 'LIKE %s COLLATE ' + collation ,
86+ 'regex' : 'LIKE %s' ,
87+ 'iregex' : 'LIKE %s' ,
12088
12189 # TODO: freetext, full-text contains...
12290 }
12391
12492 def __init__ (self , * args , ** kwargs ):
12593 super (DatabaseWrapper , self ).__init__ (* args , ** kwargs )
12694
127- if 'OPTIONS' in self .settings_dict :
128- self .MARS_Connection = self .settings_dict ['OPTIONS' ].get ('MARS_Connection' , False )
129- self .datefirst = self .settings_dict ['OPTIONS' ].get ('datefirst' , 7 )
130- self .unicode_results = self .settings_dict ['OPTIONS' ].get ('unicode_results' , False )
95+ options = self .settings_dict .get ('OPTIONS' , None )
96+
97+ if options :
98+ self .MARS_Connection = options .get ('MARS_Connection' , False )
99+ self .datefirst = options .get ('datefirst' , 7 )
100+ self .unicode_results = options .get ('unicode_results' , False )
101+
102+ # make lookup operators to be collation-sensitive if needed
103+ self .collation = options .get ('collation' , None )
104+ if self .collation :
105+ self .operators = dict (self .__class__ .operators )
106+ ops = {}
107+ for op in self .operators :
108+ sql = self .operators [op ]
109+ if sql .startswith ('LIKE ' ):
110+ ops [op ] = '%s COLLATE %s' % (sql , self .collation )
111+ self .operators .update (ops )
131112
132113 if _DJANGO_VERSION >= 13 :
133114 self .features = DatabaseFeatures (self )
@@ -145,38 +126,24 @@ def _cursor(self):
145126 new_conn = False
146127 settings_dict = self .settings_dict
147128 db_str , user_str , passwd_str , port_str = None , None , "" , None
148- if _DJANGO_VERSION >= 12 :
149- options = settings_dict ['OPTIONS' ]
150- if settings_dict ['NAME' ]:
151- db_str = settings_dict ['NAME' ]
152- if settings_dict ['HOST' ]:
153- host_str = settings_dict ['HOST' ]
154- else :
155- host_str = 'localhost'
156- if settings_dict ['USER' ]:
157- user_str = settings_dict ['USER' ]
158- if settings_dict ['PASSWORD' ]:
159- passwd_str = settings_dict ['PASSWORD' ]
160- if settings_dict ['PORT' ]:
161- port_str = settings_dict ['PORT' ]
129+
130+ options = settings_dict ['OPTIONS' ]
131+ if settings_dict ['NAME' ]:
132+ db_str = settings_dict ['NAME' ]
133+ if settings_dict ['HOST' ]:
134+ host_str = settings_dict ['HOST' ]
162135 else :
163- options = settings_dict ['DATABASE_OPTIONS' ]
164- if settings_dict ['DATABASE_NAME' ]:
165- db_str = settings_dict ['DATABASE_NAME' ]
166- if settings_dict ['DATABASE_HOST' ]:
167- host_str = settings_dict ['DATABASE_HOST' ]
168- else :
169- host_str = 'localhost'
170- if settings_dict ['DATABASE_USER' ]:
171- user_str = settings_dict ['DATABASE_USER' ]
172- if settings_dict ['DATABASE_PASSWORD' ]:
173- passwd_str = settings_dict ['DATABASE_PASSWORD' ]
174- if settings_dict ['DATABASE_PORT' ]:
175- port_str = settings_dict ['DATABASE_PORT' ]
136+ host_str = 'localhost'
137+ if settings_dict ['USER' ]:
138+ user_str = settings_dict ['USER' ]
139+ if settings_dict ['PASSWORD' ]:
140+ passwd_str = settings_dict ['PASSWORD' ]
141+ if settings_dict ['PORT' ]:
142+ port_str = settings_dict ['PORT' ]
143+
176144 if self .connection is None :
177145 new_conn = True
178146 if not db_str :
179- from django .core .exceptions import ImproperlyConfigured
180147 raise ImproperlyConfigured ('You need to specify NAME in your Django settings file.' )
181148
182149 cstr_parts = []
0 commit comments