Ticket #5246: mssql_pyodbc.patch
File mssql_pyodbc.patch, 41.8 KB (added by , 17 years ago) |
---|
-
contrib/sessions/middleware.py
61 61 self._session_cache = {} 62 62 else: 63 63 try: 64 datenow = datetime.datetime.now() 65 if hasattr(datenow, 'microsecond'): 66 datenow = datenow.replace(microsecond=0) 64 67 s = Session.objects.get(session_key=self.session_key, 65 expire_date__gt=date time.datetime.now())68 expire_date__gt=datenow) 66 69 self._session_cache = s.get_decoded() 67 70 except (Session.DoesNotExist, SuspiciousOperation): 68 71 self._session_cache = {} -
mssql/__init__.py
1 # Placeholder -
db/backends/mssql/base.py
1 """ 2 Alpha Multi-plataform MSSQL database backend for Django. 3 4 Requires pyodbc http://pyodbc.sourceforge.net/ 5 6 The configurable settings in the settings file are: 7 DATABASE_NAME - Database name. Required. 8 DATABASE_HOST - SQL Server instance in "server\instance" format. 9 DATABASE_PORT - SQL Server instance port. 10 DATABASE_USER - Database user name. If not given then the 11 Integrated Security will be used. 12 DATABASE_PASSWORD - Database user password. 13 DATABASE_ODBC_DSN - A named DSN can be used instead of DATABASE_HOST. 14 DATABASE_ODBC_DRIVER - ODBC Driver. Defalut is "{Sql Server}". 15 DATABASE_ODBC_EXTRA_PARAMS - Additional parameters for the ODBC connection. 16 The format is "param=value;param=value". 17 """ 18 19 from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, util 20 from django.core.exceptions import ImproperlyConfigured 21 from operations import DatabaseOperations 22 23 try: 24 import pyodbc as Database 25 except ImportError, e: 26 raise ImproperlyConfigured("Error loading pyodbc module: %s" % e) 27 28 try: 29 # Only exists in Python 2.4+ 30 from threading import local 31 except ImportError: 32 # Import copy of _thread_local.py from Python 2.4 33 from django.utils._threading_local import local 34 35 DatabaseError = Database.DatabaseError 36 IntegrityError = Database.IntegrityError 37 38 class DatabaseFeatures(BaseDatabaseFeatures): 39 allows_group_by_ordinal = False 40 allows_unique_and_pk = True 41 autoindexes_primary_keys = True 42 needs_datetime_string_cast = True 43 needs_upper_for_iops = False 44 supports_constraints = True 45 supports_tablespaces = True 46 uses_case_insensitive_names = True 47 uses_custom_queryset = True 48 49 class DatabaseWrapper(BaseDatabaseWrapper): 50 features = DatabaseFeatures() 51 ops = DatabaseOperations() 52 53 operators = { 54 'exact': '= %s', 55 'iexact': 'LIKE %s COLLATE SQL_Latin1_General_CP1_CI_AS', 56 'contains': 'LIKE %s COLLATE SQL_Latin1_General_CP1_CS_AS', 57 'icontains': 'LIKE %s COLLATE SQL_Latin1_General_CP1_CI_AS', 58 'gt': '> %s', 59 'gte': '>= %s', 60 'lt': '< %s', 61 'lte': '<= %s', 62 'startswith': 'LIKE %s COLLATE SQL_Latin1_General_CP1_CS_AS', 63 'endswith': 'LIKE %s COLLATE SQL_Latin1_General_CP1_CI_AS', 64 'istartswith': 'LIKE %s COLLATE SQL_Latin1_General_CP1_CS_AS', 65 'iendswith': 'LIKE %s COLLATE SQL_Latin1_General_CP1_CI_AS', 66 } 67 def __init__(self, autocommit=False, **kwargs): 68 super(DatabaseWrapper, self).__init__(autocommit=autocommit, **kwargs) 69 self.connection = None 70 self.queries = [] 71 72 def cursor(self): 73 from django.conf import settings 74 if self.connection is None: 75 if settings.DATABASE_NAME == '': 76 raise ImproperlyConfigured("You need to specify DATABASE_NAME in your Django settings file.") 77 78 if not settings.DATABASE_HOST and not hasattr(settings, "DATABASE_ODBC_DSN"): 79 raise ImproperlyConfigured("You need to specify DATABASE_HOST or DATABASE_ODBC_DSN in your Django settings file.") 80 81 if settings.DATABASE_PORT: 82 host_str = '%s:%s' % ( settings.DATABASE_HOST ,settings.DATABASE_PORT) 83 else: 84 host_str = settings.DATABASE_HOST 85 86 if hasattr(settings, "DATABASE_ODBC_DRIVER"): 87 odbc_driver = settings.DATABASE_ODBC_DRIVER 88 else: 89 odbc_driver = "{Sql Server}" 90 91 odbc_string = "Driver=%s;" % (odbc_driver) 92 93 if hasattr(settings, "DATABASE_ODBC_DSN"): 94 odbc_string += "DSN=%s;" % settings.DATABASE_ODBC_DSN 95 else: 96 odbc_string += "Server=%s;" % host_str 97 98 if settings.DATABASE_USER: 99 odbc_string += "Uid=%s;Pwd=%s;" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD) 100 else: 101 odbc_string += "Integrated Security=SSPI;" 102 103 odbc_string += "Database=%s" % settings.DATABASE_NAME 104 105 if hasattr(settings, "DATABASE_ODBC_EXTRA_PARAMS"): 106 odbc_string += ";" + settings.DATABASE_ODBC_EXTRA_PARAMS 107 108 self.connection = Database.connect(odbc_string, self.options["autocommit"]) 109 110 self.connection.cursor().execute("SET DATEFORMAT ymd") 111 112 cursor = CursorWrapper(self.connection.cursor()) 113 if settings.DEBUG: 114 return util.CursorDebugWrapper(cursor, self) 115 return cursor 116 117 class CursorWrapper(object): 118 """ 119 A wrapper around the pyodbc cursor that: 120 1. Converts input strings to unicde. 121 2. Replaces '%s' parameter placeholder in sql queries to '?' (pyodbc specific). 122 """ 123 def __init__(self, cursor): 124 self.cursor = cursor 125 126 def format_params(self, params, encoding='utf-8', errors='strict'): 127 new_params = [] 128 for param in params: 129 if isinstance(param, str): 130 # Ensure that plain strings are converted to unicode. 131 # Assumed input encoding is 'utf-8' 132 # TODO: Verify this with upper layers 133 param = unicode(param, encoding, errors) 134 new_params.append(param) 135 return tuple(new_params) 136 137 def format_sql(self, sql): 138 # pyodbc uses '?' instead of '%s' as parameter placeholder. 139 if "%s" in sql: 140 sql = sql.replace('%s', '?') 141 return sql 142 143 def execute(self, sql, params=()): 144 if params: 145 params = self.format_params(params) 146 sql = self.format_sql(sql) 147 return self.cursor.execute(sql, params) 148 149 def executemany(self, sql, param_list): 150 if param_list: 151 param_list = [self.format_params(params) for params in param_list] 152 sql = self.format_sql(sql) 153 return self.cursor.executemany(sql, param_list) 154 155 def fetchone(self): 156 row = self.cursor.fetchone() 157 if row is not None: 158 # Convert row to tuple (pyodbc Rows are not sliceable). 159 return tuple(row) 160 return row 161 162 def fetchmany(self, chunk): 163 return [tuple(row) for row in self.cursor.fetchmany(chunk)] 164 165 def fetchall(self): 166 return [tuple(row) for row in self.cursor.fetchall()] 167 168 def __getattr__(self, attr): 169 if attr in self.__dict__: 170 return self.__dict__[attr] 171 else: 172 return getattr(self.cursor, attr) -
db/backends/mssql/client.py
1 from django.conf import settings 2 import os 3 import sys 4 5 def runshell(): 6 if os.name=='nt': 7 args = [''] 8 db = settings.DATABASE_OPTIONS.get('db', settings.DATABASE_NAME) 9 user = settings.DATABASE_OPTIONS.get('user', settings.DATABASE_USER) 10 passwd = settings.DATABASE_OPTIONS.get('passwd', settings.DATABASE_PASSWORD) 11 host = settings.DATABASE_OPTIONS.get('host', settings.DATABASE_HOST) 12 port = settings.DATABASE_OPTIONS.get('port', settings.DATABASE_PORT) 13 defaults_file = settings.DATABASE_OPTIONS.get('read_default_file') 14 # Seems to be no good way to set sql_mode with CLI 15 16 if defaults_file: 17 args += ["-i %s" % defaults_file] 18 if user: 19 args += ["-U %s" % user] 20 if passwd: 21 args += ["-P %s" % passwd] 22 if host: 23 args += ["-E %s" % host] 24 if db: 25 args += ["-d %s" % db] 26 27 cmd = "osql %s" % ' '.join(args) 28 29 rv = os.system(cmd) 30 if (rv): 31 print "Error al ejecutar %s " % rv 32 sys.exit(rv) 33 else: 34 raise NotImplementedError 35 36 37 -
db/backends/mssql/introspection.py
1 try: 2 import pyodbc as Database 3 except ImportError, e: 4 raise ImproperlyConfigured, "Error loading pyodbc module: %s" % e 5 6 SQL_AUTOFIELD = -777555 7 8 def get_table_list(cursor): 9 "Returns a list of table names in the current database." 10 cursor.execute("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'") 11 return [row[2] for row in cursor.fetchall()] 12 13 def _is_auto_field(cursor, table_name, column_name): 14 cursor.execute("SELECT COLUMNPROPERTY( OBJECT_ID('%s'),'%s','IsIdentity')" % (table_name, column_name)) 15 return cursor.fetchall()[0][0] 16 17 def get_table_description(cursor, table_name, identity_check=True): 18 """Returns a description of the table, with the DB-API cursor.description interface. 19 20 The 'auto_check' parameter has been added to the function argspec. 21 If set to True, the function will check each of the table's fields for the 22 IDENTITY property (the IDENTITY property is the MSSQL equivalent to an AutoField). 23 24 When a field is found with an IDENTITY property, it is given a custom field number 25 of SQL_AUTOFIELD, which maps to the 'AutoField' value in the DATA_TYPES_REVERSE dict. 26 """ 27 cursor.execute("SELECT TOP 1 * FROM %s" % table_name) 28 items = [] 29 if identity_check: 30 for data in cursor.description: 31 if _is_auto_field(cursor, table_name, data[0]): 32 data = list(data) 33 data[1] = SQL_AUTOFIELD 34 items.append(list(data)) 35 else: 36 items = cursor.description 37 return items 38 39 def _name_to_index(cursor, table_name): 40 """ 41 Returns a dictionary of {field_name: field_index} for the given table. 42 Indexes are 0-based. 43 """ 44 return dict([(d[0], i) for i, d in enumerate(get_table_description(cursor, table_name, identity_check=False))]) 45 46 def get_relations(cursor, table_name): 47 """ 48 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 49 representing all relationships to the given table. Indexes are 0-based. 50 """ 51 table_index = _name_to_index(cursor, table_name) 52 sql = """SELECT e.COLUMN_NAME AS column_name, 53 c.TABLE_NAME AS referenced_table_name, 54 d.COLUMN_NAME AS referenced_column_name 55 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS a 56 INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS b 57 ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME 58 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE AS c 59 ON b.UNIQUE_CONSTRAINT_NAME = c.CONSTRAINT_NAME 60 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS d 61 ON c.CONSTRAINT_NAME = d.CONSTRAINT_NAME 62 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS e 63 ON a.CONSTRAINT_NAME = e.CONSTRAINT_NAME 64 WHERE a.TABLE_NAME = ? AND 65 a.CONSTRAINT_TYPE = 'FOREIGN KEY'""" 66 cursor = Cursor(cursor.db.connection) 67 cursor.execute(sql, (table_name,)) 68 return dict([(table_index[item[0]], (_name_to_index(cursor, item[1])[item[2]], item[1])) 69 for item in cursor.fetchall()]) 70 71 def get_indexes(cursor, table_name): 72 """ 73 Returns a dictionary of fieldname -> infodict for the given table, 74 where each infodict is in the format: 75 {'primary_key': boolean representing whether it's the primary key, 76 'unique': boolean representing whether it's a unique index} 77 """ 78 sql = """SELECT b.COLUMN_NAME, a.CONSTRAINT_TYPE 79 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS a INNER JOIN 80 INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS b 81 ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME AND 82 a.TABLE_NAME = b.TABLE_NAME 83 WHERE a.TABLE_NAME = ? AND 84 (CONSTRAINT_TYPE = 'PRIMARY KEY' OR 85 CONSTRAINT_TYPE = 'UNIQUE')""" 86 field_names = [item[0] for item in get_table_description(cursor, table_name, identity_check=False)] 87 cursor = Cursor(cursor.db.connection) 88 cursor.execute(sql, (table_name,)) 89 indexes = {} 90 results = {} 91 data = cursor.fetchall() 92 if data: 93 results.update(data) 94 for field in field_names: 95 val = results.get(field, None) 96 indexes[field] = dict(primary_key=(val=='PRIMARY KEY'), unique=(val=='UNIQUE')) 97 return indexes 98 99 DATA_TYPES_REVERSE = { 100 SQL_AUTOFIELD: 'AutoField', 101 Database.SQL_BIGINT: 'IntegerField', 102 #Database.SQL_BINARY: , 103 Database.SQL_BIT: 'BooleanField', 104 Database.SQL_CHAR: 'CharField', 105 Database.SQL_DECIMAL: 'DecimalField', 106 Database.SQL_DOUBLE: 'FloatField', 107 Database.SQL_FLOAT: 'FloatField', 108 Database.SQL_GUID: 'TextField', 109 Database.SQL_INTEGER: 'IntegerField', 110 #Database.SQL_LONGVARBINARY: , 111 #Database.SQL_LONGVARCHAR: , 112 Database.SQL_NUMERIC: 'DecimalField', 113 Database.SQL_REAL: 'FloatField', 114 Database.SQL_SMALLINT: 'SmallIntegerField', 115 Database.SQL_TINYINT: 'SmallIntegerField', 116 Database.SQL_TYPE_DATE: 'DateField', 117 Database.SQL_TYPE_TIME: 'TimeField', 118 Database.SQL_TYPE_TIMESTAMP: 'DateTimeField', 119 #Database.SQL_VARBINARY: , 120 Database.SQL_VARCHAR: 'TextField', 121 Database.SQL_WCHAR: 'TextField', 122 Database.SQL_WLONGVARCHAR: 'TextField', 123 Database.SQL_WVARCHAR: 'TextField', 124 } -
db/backends/mssql/operations.py
1 from django.db.backends import BaseDatabaseOperations, util 2 from django.utils.datastructures import SortedDict 3 4 SQL_SERVER_7_8_LIMIT_QUERY = \ 5 """ 6 SELECT * FROM ( 7 SELECT TOP %(limit)s * FROM ( 8 SELECT TOP %(end_row)s %(distinc)s%(fields)s 9 %(sql)s 10 ORDER BY %(orderby)s 11 ) AS %(table)s 12 ORDER BY %(orderby_reversed)s) AS %(table)s 13 ORDER BY %(orderby)s 14 """ 15 16 SQL_SERVER_9_LIMIT_QUERY = \ 17 """ 18 SELECT * 19 FROM ( 20 SELECT %(distinc)s TOP %(end_row)s 21 %(fields)s, ROW_NUMBER() 22 OVER( 23 ORDER BY %(orderby)s 24 ) AS row 25 %(sql)s ORDER BY %(orderby)s 26 ) AS x 27 WHERE x.row BETWEEN %(start_row)s AND %(end_row)s 28 """ 29 30 ORDER_ASC = "ASC" 31 ORDER_DESC = "DESC" 32 33 SQL_SERVER_2005_VERSION = 9 34 SQL_SERVER_VERSION = None 35 36 def sql_server_version(): 37 """ 38 Returns the major version of the SQL Server: 39 7 -> 7 40 2000 -> 8 41 2005 -> 9 42 """ 43 global SQL_SERVER_VERSION 44 if SQL_SERVER_VERSION is not None: 45 return SQL_SERVER_VERSION 46 else: 47 from django.db import connection 48 cur = connection.cursor() 49 cur.execute("SELECT cast(SERVERPROPERTY('ProductVersion') as varchar)") 50 SQL_SERVER_VERSION = int(cur.fetchone()[0].split('.')[0]) 51 return SQL_SERVER_VERSION 52 53 class DatabaseOperations(BaseDatabaseOperations): 54 def last_insert_id(self, cursor, table_name, pk_name): 55 #http://msdn2.microsoft.com/en-us/library/ms190315.aspx 56 cursor.execute("SELECT %s FROM %s WHERE %s = IDENT_CURRENT('%s')" % (pk_name, table_name, pk_name,table_name)) 57 return cursor.fetchone()[0] 58 59 def query_set_class(self, DefaultQuerySet): 60 "Create a custom QuerySet class for SQL Server." 61 62 from django.db import connection 63 from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word 64 65 class SqlServerQuerySet(DefaultQuerySet): 66 67 def iterator(self): 68 "Performs the SELECT database lookup of this QuerySet." 69 70 from django.db.models.query import get_cached_row 71 72 # self._select is a dictionary, and dictionaries' key order is 73 # undefined, so we convert it to a list of tuples. 74 extra_select = self._select.items() 75 76 full_query = None 77 78 try: 79 try: 80 select, sql, params, full_query = self._get_sql_clause(get_full_query=True) 81 except TypeError: 82 select, sql, params = self._get_sql_clause() 83 except EmptyResultSet: 84 raise StopIteration 85 if not full_query: 86 full_query = "SELECT %s%s\n%s" % ((self._distinct and "DISTINCT " or ""), ', '.join(select), sql) 87 88 cursor = connection.cursor() 89 cursor.execute(full_query, params) 90 91 fill_cache = self._select_related 92 fields = self.model._meta.fields 93 index_end = len(fields) 94 95 while 1: 96 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 97 if not rows: 98 raise StopIteration 99 for row in rows: 100 row = self.resolve_columns(row, fields) 101 if fill_cache: 102 obj, index_end = get_cached_row(klass=self.model, row=row, 103 index_start=0, max_depth=self._max_related_depth) 104 else: 105 obj = self.model(*row[:index_end]) 106 for i, k in enumerate(extra_select): 107 setattr(obj, k[0], row[index_end+i]) 108 yield obj 109 110 def _get_sql_clause(self, get_full_query=False): 111 from django.db.models.query import fill_table_cache, \ 112 handle_legacy_orderlist, orderfield2column 113 114 opts = self.model._meta 115 qn = connection.ops.quote_name 116 117 # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. 118 select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields] 119 tables = [quote_only_if_word(t) for t in self._tables] 120 joins = SortedDict() 121 where = self._where[:] 122 params = self._params[:] 123 124 # Convert self._filters into SQL. 125 joins2, where2, params2 = self._filters.get_sql(opts) 126 joins.update(joins2) 127 where.extend(where2) 128 params.extend(params2) 129 130 # Add additional tables and WHERE clauses based on select_related. 131 if self._select_related: 132 fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table]) 133 134 # Add any additional SELECTs. 135 if self._select: 136 select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in self._select.items()]) 137 138 # Start composing the body of the SQL statement. 139 sql = [" FROM", qn(opts.db_table)] 140 141 # Compose the join dictionary into SQL describing the joins. 142 if joins: 143 sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition) 144 for (alias, (table, join_type, condition)) in joins.items()])) 145 146 # Compose the tables clause into SQL. 147 if tables: 148 sql.append(", " + ", ".join(tables)) 149 150 # Compose the where clause into SQL. 151 if where: 152 sql.append(where and "WHERE " + " AND ".join(where)) 153 154 # Copy version suitable for LIMIT 155 sql2 = sql[:] 156 157 # ORDER BY clause 158 order_by = [] 159 if self._order_by is not None: 160 ordering_to_use = self._order_by 161 else: 162 ordering_to_use = opts.ordering 163 for f in handle_legacy_orderlist(ordering_to_use): 164 if f == '?': # Special case. 165 order_by.append(connection.ops.get_random_function_sql()) 166 else: 167 if f.startswith('-'): 168 col_name = f[1:] 169 order = ORDER_DESC 170 else: 171 col_name = f 172 order = ORDER_ASC 173 if "." in col_name: 174 table_prefix, col_name = col_name.split('.', 1) 175 table_prefix = qn(table_prefix) + '.' 176 else: 177 # Use the database table as a column prefix if it wasn't given, 178 # and if the requested column isn't a custom SELECT. 179 if "." not in col_name and col_name not in (self._select or ()): 180 table_prefix = qn(opts.db_table) + '.' 181 else: 182 table_prefix = '' 183 order_by.append('%s%s %s' % (table_prefix, qn(orderfield2column(col_name, opts)), order)) 184 if order_by: 185 sql.append("ORDER BY " + ", ".join(order_by)) 186 187 # Look for column name collisions in the select elements 188 # and fix them with an AS alias. This allows us to do a 189 # SELECT * later in the paging query. 190 cols = [clause.split('.')[-1] for clause in select] 191 for index, col in enumerate(cols): 192 if cols.count(col) > 1: 193 col = '%s%d' % (col.replace('[', '').replace(']',''), index) 194 cols[index] = qn(col) 195 select[index] = '%s AS %s' % (select[index], qn(col)) 196 197 # LIMIT and OFFSET clauses 198 # To support limits and offsets, SQL Server requires some funky rewriting of an otherwise normal looking query. Yay.. 199 select_clause = ",".join(select) 200 distinct = (self._distinct and "DISTINCT " or "") 201 full_query = None 202 203 if self._limit is None: 204 assert self._offset is None, "'offset' is not allowed without 'limit'" # TODO: actually, why not? 205 206 if self._limit is not None: 207 limit = int(self._limit) 208 else: 209 limit = None 210 211 if self._offset is not None and limit > 0: 212 offset = int(self._offset) 213 else: 214 offset = 0 215 216 limit_and_offset_clause = '' 217 218 if limit is not None: 219 limit_and_offset_clause = True 220 elif offset: 221 limit_and_offset_clause = True 222 223 if limit_and_offset_clause: 224 # Input: 225 # offset: start row 226 # limit: chunk size 227 228 # For SQL Server 2005 this becomes indices: 229 start_row = offset + 1 230 end_row = start_row + limit - 1 231 232 # And for SQL Server 2000 we use: 233 # end_row: the upper indice 234 # limit: chunk size 235 236 # TOP and ROW_NUMBER in T-SQL requires an order. 237 # If order is not specified the use id column. 238 if len(order_by)==0: 239 order_by.append('%s.%s %s' % (qn(opts.db_table), qn(opts.fields[0].db_column or opts.fields[0].column), ORDER_ASC)) 240 241 order_by_clause = ", ".join(order_by) 242 order_by_clause_reverse = "" 243 244 if sql_server_version() >= SQL_SERVER_2005_VERSION: 245 fmt = SQL_SERVER_9_LIMIT_QUERY 246 else: 247 # Compatibility mode for older versions 248 order_by_clause_reverse = ", ".join(self.change_order_direction(order_by)) 249 fmt = SQL_SERVER_7_8_LIMIT_QUERY 250 251 full_query = fmt % {'distinc': distinct, 'fields': select_clause, 252 'sql': " ".join(sql2), 'orderby': order_by_clause, 253 'orderby_reversed': order_by_clause_reverse, 254 'table': qn(opts.db_table), 255 'limit': limit, #'offset': offset, 256 'start_row': start_row, 'end_row': end_row} 257 if get_full_query: 258 return select, " ".join(sql), params, full_query 259 else: 260 return select, " ".join(sql), params 261 262 def change_order_direction(self, order_by): 263 new_order = [] 264 for order in order_by: 265 if order.endswith(ORDER_ASC): 266 new_order.append(order[:-len(ORDER_ASC)] + ORDER_DESC) 267 elif order.endswith(ORDER_DESC): 268 new_order.append(order[:-len(ORDER_DESC)] + ORDER_ASC) 269 else: 270 # TODO: check special case '?' -- random order 271 new_order.append(order) 272 return new_order 273 274 def resolve_columns(self, row, fields=()): 275 from django.db.models.fields import DateField, DateTimeField, \ 276 TimeField, DecimalField 277 values = [] 278 for value, field in map(None, row, fields): 279 if value is not None: 280 # Convert floats to decimals. TODO: check if needed 281 if isinstance(field, DecimalField): 282 value = util.typecast_decimal(field.format_number(value)) 283 elif isinstance(field, DateTimeField): 284 pass # do nothing 285 elif isinstance(field, DateField): 286 value = value.date() # extract date 287 elif isinstance(field, TimeField): 288 value = value.time() # extract time 289 elif isinstance(value, buffer): 290 # Convert Binary Object to sting. 291 # TODO: This does not work for inserting into Binary columns 292 value = str(value) 293 values.append(value) 294 return values 295 296 return SqlServerQuerySet 297 298 def date_extract_sql(self, lookup_type, field_name): 299 """ 300 Given a lookup_type of 'year', 'month' or 'day', returns the SQL that 301 extracts a value from the given date field field_name. 302 """ 303 return "DATEPART(%s, %s)" % (lookup_type, field_name) 304 305 def date_trunc_sql(self, lookup_type, field_name): 306 """ 307 Given a lookup_type of 'year', 'month' or 'day', returns the SQL that 308 truncates the given date field field_name to a DATE object with only 309 the given specificity. 310 """ 311 if lookup_type=='year': 312 return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name 313 if lookup_type=='month': 314 return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name) 315 if lookup_type=='day': 316 return "Convert(datetime, Convert(varchar(12), %s))" % field_name 317 318 def limit_offset_sql(self, limit, offset=None): 319 # Limits and offset are too complicated to be handled here. 320 # Look for a implementation similar to SQL Server backend 321 return "" 322 323 def quote_name(self, name): 324 """ 325 Returns a quoted version of the given table, index or column name. Does 326 not quote the given name if it's already been quoted. 327 """ 328 if name.startswith('[') and name.endswith(']'): 329 return name # Quoting once is enough. 330 return '[%s]' % name 331 332 def get_random_function_sql(self): 333 """ 334 Returns a SQL expression that returns a random value. 335 """ 336 return "RAND()" 337 338 def tablespace_sql(self, tablespace, inline=False): 339 """ 340 Returns the tablespace SQL, or None if the backend doesn't use 341 tablespaces. 342 """ 343 return "ON %s" % quote_name(tablespace) 344 345 def sql_flush(self, style, tables, sequences): 346 """ 347 Returns a list of SQL statements required to remove all data from 348 the given database tables (without actually removing the tables 349 themselves). 350 351 The `style` argument is a Style object as returned by either 352 color_style() or no_style() in django.core.management.color. 353 """ 354 # Cannot use TRUNCATE on tables that are referenced by a FOREIGN KEY 355 # So must use the much slower DELETE 356 from django.db import connection 357 cursor = connection.cursor() 358 cursor.execute("SELECT TABLE_NAME, CONSTRAINT_NAME FROM information_schema.table_constraints") 359 fks = cursor.fetchall() 360 sql_list = ['ALTER TABLE %s NOCHECK CONSTRAINT %s;' % \ 361 (self.quote_name(fk[0]), self.quote_name(fk[1])) for fk in fks] 362 sql_list.extend(['%s %s %s;' % \ 363 (style.SQL_KEYWORD('DELETE'), 364 style.SQL_KEYWORD('FROM'), 365 style.SQL_FIELD(self.quote_name(table)) 366 ) for table in tables]) 367 # The reset the counters on each table. 368 sql_list.extend(['%s %s (%s, %s, %s) %s %s;' % ( 369 style.SQL_KEYWORD('DBCC'), 370 style.SQL_KEYWORD('CHECKIDENT'), 371 style.SQL_FIELD(self.quote_name(seq["table"])), 372 style.SQL_KEYWORD('RESEED'), 373 style.SQL_FIELD('1'), 374 style.SQL_KEYWORD('WITH'), 375 style.SQL_KEYWORD('NO_INFOMSGS'), 376 ) for seq in sequences]) 377 sql_list.extend(['ALTER TABLE %s CHECK CONSTRAINT %s;' % \ 378 (self.quote_name(fk[0]), self.quote_name(fk[1])) for fk in fks]) 379 return sql_list 380 381 def start_transaction_sql(self): 382 """ 383 Returns the SQL statement required to start a transaction. 384 """ 385 return "BEGIN TRANSACTION" -
db/backends/mssql/creation.py
1 DATA_TYPES = { 2 'AutoField': 'int IDENTITY (1, 1)', 3 'BooleanField': 'bit', 4 'CharField': 'nvarchar(%(max_length)s) %(collation)s', 5 'CommaSeparatedIntegerField': 'nvarchar(%(max_length)s) %(collation)s', 6 'DateField': 'datetime', 7 'DateTimeField': 'datetime', 8 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 9 'FileField': 'nvarchar(254) %(collation)s', 10 'FilePathField': 'nvarchar(254) %(collation)s', 11 'FloatField': 'double precision', 12 'ImageField': 'nvarchar(254) %(collation)s', 13 'IntegerField': 'int', 14 'IPAddressField': 'char(15)', 15 'ManyToManyField': None, 16 'NullBooleanField': 'bit', 17 'OneToOneField': 'int', 18 'PhoneNumberField': 'nvarchar(20) %(collation)s', 19 #The check must be unique in for the database. Put random so the regresion test not complain about duplicate names 20 'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(creation_counter)s_%(column)s] CHECK ([%(column)s] > 0)', 21 'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(creation_counter)s_%(column)s] CHECK ([%(column)s] > 0)', 22 'SlugField': 'nvarchar(%(max_length)s) %(collation)s', 23 'SmallIntegerField': 'smallint', 24 'TextField': 'ntext %(collation)s', 25 'TimeField': 'datetime', 26 'USStateField': 'nchar(2) %(collation)s', 27 } 28 29 from operations import sql_server_version, SQL_SERVER_2005_VERSION 30 if sql_server_version() >= SQL_SERVER_2005_VERSION: 31 DATA_TYPES['TextField'] = 'nvarchar(max) %(collation)s' -
db/models/base.py
1 1 import django.db.models.manipulators 2 2 import django.db.models.manager 3 import django.db 3 4 from django.core import validators 4 5 from django.core.exceptions import ObjectDoesNotExist 5 6 from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist … … 246 247 (qn(self._meta.db_table), qn(self._meta.order_with_respect_to.column))) 247 248 db_values.append(getattr(self, self._meta.order_with_respect_to.attname)) 248 249 if db_values: 249 cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \ 250 (qn(self._meta.db_table), ','.join(field_names), 251 ','.join(placeholders)), db_values) 250 try: 251 if pk_set and settings.DATABASE_ENGINE.endswith("mssql"): 252 # You can't insert an auto value into a column unless you do this in MSSQL 253 if [None for f in self._meta.fields if isinstance(f, AutoField)]: 254 cursor.execute("SET IDENTITY_INSERT %s ON" % qn(self._meta.db_table)) 255 cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \ 256 (qn(self._meta.db_table), ','.join(field_names), 257 ','.join(placeholders)), db_values) 258 finally: 259 if pk_set and settings.DATABASE_ENGINE.endswith("mssql"): 260 try: 261 if [None for f in self._meta.fields if isinstance(f, AutoField)]: 262 cursor.execute("SET IDENTITY_INSERT %s OFF" % qn(self._meta.db_table)) 263 except django.db.DatabaseError: 264 pass 252 265 else: 253 266 # Create a new record with defaults for everything. 254 267 cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % -
db/models/fields/__init__.py
29 29 BLANK_CHOICE_NONE = [("", "None")] 30 30 31 31 # prepares a value for use in a LIKE query 32 prep_for_like_query = lambda x: smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_") 32 # TODO: refactor database specific code 33 if settings.DATABASE_ENGINE == 'mssql': 34 prep_for_like_query = lambda x: smart_unicode(x).replace("%", "[%]").replace("_", "[_]") 35 else: 36 prep_for_like_query = lambda x: smart_unicode(x).replace("\\", "\\\\").replace("%", "\%").replace("_", "\_") 33 37 34 38 # returns the <ul> class for a given radio_admin value 35 39 get_ul_class = lambda x: 'radiolist%s' % ((x == HORIZONTAL) and ' inline' or '') … … 80 84 core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True, 81 85 prepopulate_from=None, unique_for_date=None, unique_for_month=None, 82 86 unique_for_year=None, validator_list=None, choices=None, radio_admin=None, 83 help_text='', db_column=None, db_tablespace=None): 87 help_text='', db_column=None, db_tablespace=None, 88 collation=None): 84 89 self.name = name 85 90 self.verbose_name = verbose_name 86 91 self.primary_key = primary_key … … 102 107 self.help_text = help_text 103 108 self.db_column = db_column 104 109 self.db_tablespace = db_tablespace 105 110 # TODO: refactor database specific code 111 if settings.DATABASE_ENGINE == 'mssql': 112 self.collation = (collation and "COLLATE %s" % collation) or '' 113 106 114 # Set db_index to True if the field has a relationship and doesn't explicitly set db_index. 107 115 self.db_index = db_index 108 116 … … 223 231 value = int(value) 224 232 except ValueError: 225 233 raise ValueError("The __year lookup type requires an integer argument") 226 return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.99 9999' % value]234 return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.99' % value] 227 235 raise TypeError("Field has invalid lookup: %s" % lookup_type) 228 236 229 237 def has_default(self): … … 574 582 if value is not None: 575 583 # MySQL will throw a warning if microseconds are given, because it 576 584 # doesn't support microseconds. 577 if settings.DATABASE_ENGINE == 'mysql'and hasattr(value, 'microsecond'):585 if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') and hasattr(value, 'microsecond'): 578 586 value = value.replace(microsecond=0) 579 587 value = smart_unicode(value) 580 588 return Field.get_db_prep_save(self, value) 581 589 582 590 def get_db_prep_lookup(self, lookup_type, value): 591 # MSSQL doesn't like microseconds. 592 if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') and hasattr(value, 'microsecond'): 593 value = value.replace(microsecond=0) 583 594 if lookup_type == 'range': 584 595 value = [smart_unicode(v) for v in value] 585 596 else: … … 940 951 Field.__init__(self, verbose_name, name, **kwargs) 941 952 942 953 def get_db_prep_lookup(self, lookup_type, value): 943 if settings.DATABASE_ENGINE == 'oracle':954 if settings.DATABASE_ENGINE in ('oracle', 'mssql'): 944 955 # Oracle requires a date in order to parse. 945 956 def prep(value): 946 957 if isinstance(value, datetime.time): … … 966 977 # Casts dates into string format for entry into database. 967 978 if value is not None: 968 979 # MySQL will throw a warning if microseconds are given, because it 969 # doesn't support microseconds. 970 if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'): 980 # doesn't support microseconds. Ditto MSSQL 981 if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') \ 982 and hasattr(value, 'microsecond'): 971 983 value = value.replace(microsecond=0) 972 if settings.DATABASE_ENGINE == 'oracle':984 if settings.DATABASE_ENGINE in ('oracle', 'mssql'): 973 985 # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field. 986 # SQL Server does not have TIME type. 974 987 if isinstance(value, datetime.time): 975 988 value = datetime.datetime(1900, 1, 1, value.hour, value.minute, 976 989 value.second, value.microsecond) -
test/utils.py
70 70 71 71 def _set_autocommit(connection): 72 72 "Make sure a connection is in autocommit mode." 73 if hasattr(connection.connection, "autocommit") :73 if hasattr(connection.connection, "autocommit") and callable(connection.connection.autocommit): 74 74 connection.connection.autocommit(True) 75 75 elif hasattr(connection.connection, "set_isolation_level"): 76 76 connection.connection.set_isolation_level(0)