Ticket #5062: NewMSSQL.2.diff
File NewMSSQL.2.diff, 63.9 KB (added by , 17 years ago) |
---|
-
contrib/sessions/middleware.py
59 59 self._session_cache = {} 60 60 else: 61 61 try: 62 datenow = datetime.datetime.now() 63 if hasattr(datenow, 'microsecond'): 64 datenow = datenow.replace(microsecond=0) 62 65 s = Session.objects.get(session_key=self.session_key, 63 expire_date__gt=date time.datetime.now())66 expire_date__gt=datenow) 64 67 self._session_cache = s.get_decoded() 65 68 except (Session.DoesNotExist, SuspiciousOperation): 66 69 self._session_cache = {} -
db/backends/mssql/base.py
1 """ 2 Alpha Multi-plataform MSSQL database backend for Django. 3 4 Requires pymssql >= v0.8.0: http://pymssql.sourceforge.net/ 5 """ 6 if __name__ == '__main__': 7 import sys 8 import os 9 10 SETTINGS_MODULE = 'settings' 11 12 project_dir = r'E:\Proyectos\Python\mysite' 13 sys.path.append(os.path.join(project_dir, '..')) 14 sys.path.append("..") 15 sys.path.pop() 16 os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' 17 18 import datetime 19 from django.db.backends import util 20 from django.core.exceptions import ImproperlyConfigured 21 from django.utils.datastructures import SortedDict 22 23 try: 24 import pymssql as Database 25 except ImportError, e: 26 raise ImproperlyConfigured, "Error loading pymssql module: %s" % e 27 28 try: 29 import mx 30 except ImportError: 31 mx = None 32 33 try: 34 # Only exists in Python 2.4+ 35 from threading import local 36 except ImportError: 37 # Import copy of _thread_local.py from Python 2.4 38 from django.utils._threading_local import local 39 40 DatabaseError = Database.DatabaseError 41 IntegrityError = Database.IntegrityError 42 43 #Configure support options: 44 allows_group_by_ordinal = True 45 allows_unique_and_pk = True 46 autoindexes_primary_keys = True 47 needs_datetime_string_cast = True 48 needs_upper_for_iops = False 49 supports_constraints = True 50 supports_tablespaces = False 51 uses_case_insensitive_names = False 52 53 def complain(*args, **kwargs): 54 raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet." 55 56 def ignore(*args, **kwargs): 57 pass 58 59 class DatabaseError(Exception): 60 pass 61 62 class IntegrityError(DatabaseError): 63 pass 64 65 class DatabaseWrapper(local): 66 def __init__(self, **kwargs): 67 self.connection = None 68 self.queries = [] 69 70 def cursor(self): 71 from django.conf import settings 72 if self.connection is None: 73 if settings.DATABASE_NAME == '' or settings.DATABASE_USER == '': 74 raise ImproperlyConfigured, "You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file." 75 if not settings.DATABASE_HOST: 76 settings.DATABASE_HOST = "127.0.0.1" 77 78 if settings.DATABASE_PORT: 79 hostStr = '%s:%s' % ( settings.DATABASE_HOST ,settings.DATABASE_PORT) 80 else: 81 hostStr = settings.DATABASE_HOST 82 83 self.connection = Database.connect(host=hostStr,user=settings.DATABASE_USER,password=settings.DATABASE_PASSWORD,database=settings.DATABASE_NAME) 84 85 self.connection.cursor().execute("SET DATEFORMAT ymd\nGO") 86 87 cursor = self.connection.cursor() 88 if settings.DEBUG: 89 return util.CursorDebugWrapper(cursor, self) 90 return cursor 91 92 def _commit(self): 93 if self.connection is not None: 94 return self.connection.commit() 95 96 def _rollback(self): 97 if self.connection is not None: 98 return self.connection.rollback() 99 100 def close(self): 101 if self.connection is not None: 102 self.connection.close() 103 self.connection = None 104 105 ''' 106 Return the major version of the server. 7=Sql 7,8=Sql2000,9=Sql2005 107 ''' 108 def version(): 109 cur = DatabaseWrapper().cursor() 110 cur.execute("SELECT SERVERPROPERTY('ProductVersion')") 111 112 return int(cur.fetchone()[0].split('.')[0]) 113 114 def quote_name(name): 115 if name.startswith('[') and name.endswith(']'): 116 return name # Quoting once is enough. 117 return '[%s]' % name 118 119 dictfetchone = util.dictfetchone 120 dictfetchmany = util.dictfetchmany 121 dictfetchall = util.dictfetchall 122 123 def get_last_insert_id(cursor, table_name, pk_name): 124 cursor.execute("SELECT %s FROM %s WHERE %s = IDENT_CURRENT('%s')" % (pk_name, table_name, pk_name,table_name)) 125 return cursor.fetchone()[0] 126 127 def get_date_extract_sql(lookup_type, table_name): 128 # lookup_type is 'year', 'month', 'day' 129 return "DATEPART(%s, %s)" % (lookup_type, table_name) 130 131 def get_date_trunc_sql(lookup_type, field_name): 132 # lookup_type is 'year', 'month', 'day' 133 if lookup_type=='year': 134 return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name 135 if lookup_type=='month': 136 return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name) 137 if lookup_type=='day': 138 return "Convert(datetime, Convert(varchar(12), %s))" % field_name 139 140 def get_datetime_cast_sql(): 141 return None 142 143 def get_limit_offset_sql(limit, offset=None): 144 # Limits and offset are too complicated to be handled here. 145 # Look for a implementation similar to SqlServer backend 146 return "" 147 148 def get_random_function_sql(): 149 return "RAND()" 150 151 def get_deferrable_sql(): 152 # TODO: Workaround cicle paths... 153 # DEFERRABLE and INITALLY DEFFERRED are not apparently supported on constraints 154 # This cause SQL Server message 1750, severity 16, state 0, for example in the multiple joins path of comments. 155 # So, this left Sql Server as if have not relations :( 156 #return " ON DELETE CASCADE ON UPDATE CASCADE" 157 return "" 158 159 def get_fulltext_search_sql(field_name): 160 raise NotImplementedError 161 162 def get_drop_foreignkey_sql(): 163 return "DROP CONSTRAINT" 164 165 def get_pk_default_value(): 166 return "DEFAULT" 167 168 def get_max_name_length(): 169 return None 170 171 def get_start_transaction_sql(): 172 return "BEGIN;" 173 174 def get_tablespace_sql(tablespace, inline=False): 175 return "ON %s" % quote_name(tablespace) 176 177 def get_autoinc_sql(table): 178 return None 179 180 def get_sql_flush(sql_styler, full_table_list, sequences): 181 """Return a list of SQL statements required to remove all data from 182 all tables in the database (without actually removing the tables 183 themselves) and put the database in an empty 'initial' state 184 """ 185 # Cannot use TRUNCATE on tables that are reference by a FOREIGN KEY 186 # So must use the much slower DELETE 187 sql_list = ['%s %s %s;' % \ 188 (sql_styler.SQL_KEYWORD('DELETE'), 189 sql_styler.SQL_KEYWORD('FROM'), 190 sql_styler.SQL_FIELD(quote_name(table)) 191 ) for table in full_table_list] 192 #The reset the counters on each table. 193 sql_list.extend(['%s %s %s %s %s %s %s;' % ( 194 sql_styler.SQL_KEYWORD('DBCC'), 195 sql_styler.SQL_KEYWORD('CHECKIDENT'), 196 sql_styler.SQL_FIELD(quote_name(seq["table"])), 197 sql_styler.SQL_KEYWORD('RESEED'), 198 sql_styler.SQL_FIELD('1'), 199 sql_styler.SQL_KEYWORD('WITH'), 200 sql_styler.SQL_KEYWORD('NO_INFOMSGS'), 201 ) for seq in sequences]) 202 203 return sql_list 204 205 def get_sql_sequence_reset(style, model_list): 206 "Returns a list of the SQL statements to reset sequences for the given models." 207 # No sequence reset required 208 return [] 209 210 def get_trigger_name(table): 211 return '%s_TR' % table.upper() 212 213 def get_query_set_class(DefaultQuerySet): 214 "Create a custom QuerySet class for SqlServer." 215 216 from django.db import backend, connection 217 from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word 218 219 class SqlServerQuerySet(DefaultQuerySet): 220 221 def iterator(self): 222 "Performs the SELECT database lookup of this QuerySet." 223 224 from django.db.models.query import get_cached_row 225 226 # self._select is a dictionary, and dictionaries' key order is 227 # undefined, so we convert it to a list of tuples. 228 extra_select = self._select.items() 229 230 full_query = None 231 232 try: 233 try: 234 select, sql, params, full_query = self._get_sql_clause(get_full_query=True) 235 except TypeError: 236 select, sql, params = self._get_sql_clause() 237 except EmptyResultSet: 238 raise StopIteration 239 if not full_query: 240 full_query = "SELECT %s%s\n%s" % \ 241 ((self._distinct and "DISTINCT " or ""), 242 ', '.join(select), sql) 243 244 cursor = connection.cursor() 245 cursor.execute(full_query, params) 246 247 fill_cache = self._select_related 248 fields = self.model._meta.fields 249 index_end = len(fields) 250 251 # so here's the logic; 252 # 1. retrieve each row in turn 253 # 2. convert NCLOBs 254 255 while 1: 256 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 257 if not rows: 258 raise StopIteration 259 for row in rows: 260 row = self.resolve_columns(row, fields) 261 if fill_cache: 262 obj, index_end = get_cached_row(klass=self.model, row=row, 263 index_start=0, max_depth=self._max_related_depth) 264 else: 265 obj = self.model(*row[:index_end]) 266 for i, k in enumerate(extra_select): 267 setattr(obj, k[0], row[index_end+i]) 268 yield obj 269 270 271 def _get_sql_clause(self, get_full_query=False): 272 from django.db.models.query import fill_table_cache, \ 273 handle_legacy_orderlist, orderfield2column 274 275 opts = self.model._meta 276 277 # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. 278 select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields] 279 tables = [quote_only_if_word(t) for t in self._tables] 280 joins = SortedDict() 281 where = self._where[:] 282 params = self._params[:] 283 284 # Convert self._filters into SQL. 285 joins2, where2, params2 = self._filters.get_sql(opts) 286 joins.update(joins2) 287 where.extend(where2) 288 params.extend(params2) 289 290 # Add additional tables and WHERE clauses based on select_related. 291 if self._select_related: 292 fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table]) 293 294 # Add any additional SELECTs. 295 if self._select: 296 select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()]) 297 298 # Start composing the body of the SQL statement. 299 sql = [" FROM", backend.quote_name(opts.db_table)] 300 301 # Compose the join dictionary into SQL describing the joins. 302 if joins: 303 sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition) 304 for (alias, (table, join_type, condition)) in joins.items()])) 305 306 # Compose the tables clause into SQL. 307 if tables: 308 sql.append(", " + ", ".join(tables)) 309 310 # Compose the where clause into SQL. 311 if where: 312 sql.append(where and "WHERE " + " AND ".join(where)) 313 314 #copy a version suitable for LIMIT 315 sql2=[] 316 [sql2.append(x) for x in sql] 317 # ORDER BY clause 318 order_by = [] 319 if self._order_by is not None: 320 ordering_to_use = self._order_by 321 else: 322 ordering_to_use = opts.ordering 323 for f in handle_legacy_orderlist(ordering_to_use): 324 if f == '?': # Special case. 325 order_by.append(backend.get_random_function_sql()) 326 else: 327 if f.startswith('-'): 328 col_name = f[1:] 329 order = "DESC" 330 else: 331 col_name = f 332 order = "ASC" 333 if "." in col_name: 334 table_prefix, col_name = col_name.split('.', 1) 335 table_prefix = backend.quote_name(table_prefix) + '.' 336 else: 337 # Use the database table as a column prefix if it wasn't given, 338 # and if the requested column isn't a custom SELECT. 339 if "." not in col_name and col_name not in (self._select or ()): 340 table_prefix = backend.quote_name(opts.db_table) + '.' 341 else: 342 table_prefix = '' 343 order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order)) 344 if order_by: 345 sql.append("ORDER BY " + ", ".join(order_by)) 346 347 # Look for column name collisions in the select elements 348 # and fix them with an AS alias. This allows us to do a 349 # SELECT * later in the paging query. 350 cols = [clause.split('.')[-1] for clause in select] 351 for index, col in enumerate(cols): 352 if cols.count(col) > 1: 353 col = '%s%d' % (col.replace('[', '').replace(']',''), index) 354 cols[index] = backend.quote_name(col) 355 select[index] = '%s AS %s' % (select[index], backend.quote_name(col)) 356 357 # LIMIT and OFFSET clauses 358 # To support limits and offsets, SqlServer requires some funky rewriting of an otherwise normal looking query. 359 select_clause = ",".join(select) 360 distinct = (self._distinct and "DISTINCT " or "") 361 full_query = None 362 363 if self._limit is None: 364 assert self._offset is None, "'offset' is not allowed without 'limit'" 365 366 if self._offset is not None: 367 offset = int(self._offset) 368 else: 369 offset = 0 370 371 if self._limit is not None: 372 limit = int(self._limit) 373 else: 374 limit = None 375 376 limit_and_offset_clause = '' 377 378 if limit is not None: 379 limit_and_offset_clause = True 380 elif offset: 381 limit_and_offset_clause = True 382 383 if limit_and_offset_clause: 384 #Django give: 385 # Offset : Start row 386 # Limit : How much aditional rows fetch 387 388 # This must be transformed to Sql2005 to: 389 # Offset : First Row 390 # Limit : EndRow 391 StartRow = offset + 1 392 EndRow = StartRow + limit - 1 393 # and for Sql2000 394 # Offset : Top rows 395 # Limit: From where 396 limit = limit + offset 397 if offset==0: 398 offset = limit 399 else: 400 offset = offset + 1 401 #Must use a order. If not specified, use Id. 402 if len(order_by)==0: 403 order_by.append('%s.%s ASC' % 404 (backend.quote_name(opts.db_table), 405 backend.quote_name(opts.fields[0].db_column or opts.fields[0].column) 406 ) 407 ) 408 409 order_by_clause = ", ".join(order_by) 410 order_by_clauseReverse = "" 411 412 #For Sql2005+ use native implementation... 413 if version()>8: 414 fmt = \ 415 """ 416 SELECT * 417 FROM ( 418 SELECT %(distinc)s TOP %(EndRow)s 419 %(fields)s, ROW_NUMBER() 420 OVER( 421 ORDER BY %(orderby)s 422 ) AS row 423 %(sql)s ORDER BY %(orderby)s 424 ) AS x 425 WHERE x.row BETWEEN %(StartRow)s AND %(EndRow)s 426 """ 427 else: 428 #Is necesary reverse all the second order by for the trick to work... 429 order_by_clauseReverse= ", ".join(self.change_order_direction(order_by)) 430 431 fmt = \ 432 """ 433 SELECT * FROM ( 434 SELECT TOP %(offset)s * FROM ( 435 SELECT TOP %(limit)s %(distinc)s%(fields)s 436 %(sql)s 437 ORDER BY %(orderby)s 438 ) AS %(table)s 439 ORDER BY %(orderbyReverse)s) AS %(table)s 440 ORDER BY %(orderby)s 441 """ 442 443 full_query = fmt % {'distinc':distinct, 'fields':select_clause, 444 'sql':" ".join(sql2),'orderby':order_by_clause, 445 'orderbyReverse':order_by_clauseReverse, 446 'table':backend.quote_name(opts.db_table), 447 'offset':offset,'limit':limit, 448 'StartRow':StartRow,'EndRow':EndRow} 449 450 print full_query 451 if get_full_query: 452 return select, " ".join(sql), params, full_query 453 else: 454 return select, " ".join(sql), params 455 456 457 def change_order_direction(self,order_by): 458 newOrder=[] 459 460 for order in order_by: 461 if order.find(' ASC'): 462 newOrder.append(order.replace(' ASC',' DESC')) 463 else: 464 newOrder.append(order.replace(' DESC',' ASC')) 465 466 return newOrder 467 468 def resolve_columns(self, row, fields=()): 469 from django.db.models.fields import DateField, DateTimeField, \ 470 TimeField, BooleanField, NullBooleanField, DecimalField, Field 471 values = [] 472 for value, field in map(None, row, fields): 473 # Convert 1 or 0 to True or False 474 if value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)): 475 value = bool(value) 476 # Convert floats to decimals 477 elif value is not None and isinstance(field, DecimalField): 478 value = util.typecast_decimal(field.format_number(value)) 479 values.append(value) 480 return values 481 482 return SqlServerQuerySet 483 484 OPERATOR_MAPPING = { 485 'exact': '= %s', 486 'iexact': 'LIKE %s', 487 'contains': 'LIKE %s', 488 'icontains': 'LIKE %s', 489 'gt': '> %s', 490 'gte': '>= %s', 491 'lt': '< %s', 492 'lte': '<= %s', 493 'startswith': 'LIKE %s', 494 'endswith': 'LIKE %s', 495 'istartswith': 'LIKE %s', 496 'iendswith': 'LIKE %s', 497 } 498 499 if __name__ == '__main__': 500 from mysite.polls.models import Poll, Choice 501 from datetime import datetime 502 503 #Poll.objects.all().delete() 504 #i =0 505 #for i in range(i,150): 506 # p = Poll(question="%s" % i, pub_date=datetime.now()) 507 # p.save() 508 509 for poll in Poll.objects.all()[:10]: 510 print poll 511 No newline at end of file -
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 def get_table_list(cursor): 2 "Returns a list of table names in the current database." 3 cursor.execute("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'") 4 return [row[2] for row in cursor.fetchall()] 5 6 def _is_auto_field(cursor, table_name, column_name): 7 cursor.execute("SELECT COLUMNPROPERTY( OBJECT_ID('%s'),'%s','IsIdentity')" % (table_name, column_name)) 8 return cursor.fetchall()[0][0] 9 10 def get_table_description(cursor, table_name, identity_check=True): 11 """Returns a description of the table, with the DB-API cursor.description interface. 12 13 The 'auto_check' parameter has been added to the function argspec. 14 If set to True, the function will check each of the table's fields for the 15 IDENTITY property (the IDENTITY property is the MSSQL equivalent to an AutoField). 16 17 When a field is found with an IDENTITY property, it is given a custom field number 18 of -777, which maps to the 'AutoField' value in the DATA_TYPES_REVERSE dict. 19 """ 20 cursor.execute("SELECT TOP 1 * FROM %s" % table_name) 21 cursor.nextset() 22 items = [] 23 if identity_check: 24 for data in cursor.description: 25 if _is_auto_field(cursor, table_name, data[0]): 26 data = list(data) 27 data[1] = -777 28 items.append(list(data)) 29 else: 30 items = cursor.description 31 return items 32 33 def _name_to_index(cursor, table_name): 34 """ 35 Returns a dictionary of {field_name: field_index} for the given table. 36 Indexes are 0-based. 37 """ 38 return dict([(d[0], i) for i, d in enumerate(get_table_description(cursor, table_name, identity_check=False))]) 39 40 def get_relations(cursor, table_name): 41 """ 42 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 43 representing all relationships to the given table. Indexes are 0-based. 44 """ 45 table_index = _name_to_index(cursor, table_name) 46 sql = """SELECT e.COLUMN_NAME AS column_name, 47 c.TABLE_NAME AS referenced_table_name, 48 d.COLUMN_NAME AS referenced_column_name 49 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS a 50 INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS b 51 ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME 52 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE AS c 53 ON b.UNIQUE_CONSTRAINT_NAME = c.CONSTRAINT_NAME 54 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS d 55 ON c.CONSTRAINT_NAME = d.CONSTRAINT_NAME 56 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS e 57 ON a.CONSTRAINT_NAME = e.CONSTRAINT_NAME 58 WHERE a.TABLE_NAME = ? AND 59 a.CONSTRAINT_TYPE = 'FOREIGN KEY'""" 60 cursor = Cursor(cursor.db.connection) 61 cursor.execute(sql, (table_name,)) 62 return dict([(table_index[item[0]], (_name_to_index(cursor, item[1])[item[2]], item[1])) 63 for item in cursor.fetchall()]) 64 65 def get_indexes(cursor, table_name): 66 """ 67 Returns a dictionary of fieldname -> infodict for the given table, 68 where each infodict is in the format: 69 {'primary_key': boolean representing whether it's the primary key, 70 'unique': boolean representing whether it's a unique index} 71 """ 72 sql = """SELECT b.COLUMN_NAME, a.CONSTRAINT_TYPE 73 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS a INNER JOIN 74 INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS b 75 ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME AND 76 a.TABLE_NAME = b.TABLE_NAME 77 WHERE a.TABLE_NAME = ? AND 78 (CONSTRAINT_TYPE = 'PRIMARY KEY' OR 79 CONSTRAINT_TYPE = 'UNIQUE')""" 80 field_names = [item[0] for item in get_table_description(cursor, table_name, identity_check=False)] 81 cursor = Cursor(cursor.db.connection) 82 cursor.execute(sql, (table_name,)) 83 indexes = {} 84 results = {} 85 data = cursor.fetchall() 86 if data: 87 results.update(data) 88 for field in field_names: 89 val = results.get(field, None) 90 indexes[field] = dict(primary_key=(val=='PRIMARY KEY'), unique=(val=='UNIQUE')) 91 return indexes 92 93 # A reference for the values below: 94 # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ado270/htm/mdcstdatatypeenum.asp 95 DATA_TYPES_REVERSE = { 96 # 8192 : Array , 97 # 128 : Binary , 98 # 9 : IDispatch , 99 # 12 : Variant , 100 # 13 : IUnknown , 101 # 21 : UnsignedBigInt, 102 # 132 : UserDefined , 103 # 0 : Empty , 104 # 136 : Chapter , 105 # 138 : PropVariant , 106 # 204 : VarBinary , 107 # 205 : LongVarBinary , 108 -777: 'AutoField', # Custom number used to identify AutoFields 109 2 : 'SmallIntegerField', # SmallInt 110 3 : 'IntegerField', # Integer 111 4 : 'FloatField', # Single 112 5 : 'FloatField', # Decimal 113 6 : 'FloatField', # Currency 114 7 : 'DateField', # Date 115 8 : 'CharField', # BSTR 116 10 : 'IntegerField', # Error 117 11 : 'BooleanField', # Boolean 118 14 : 'FloatField', # Decimal 119 16 : 'SmallIntegerField', # TinyInt 120 17 : 'PositiveSmallIntegerField', # UnsignedTinyInt 121 18 : 'PositiveSmallIntegerField', # UnsignedSmallInt 122 19 : 'PositiveIntegerField', # UnsignedInt 123 20 : 'IntegerField', # BigInt 124 64 : 'DateTimeField', # FileTime 125 72 : 'CharField', # GUID 126 129 : 'CharField', # Char 127 130 : 'CharField', # WChar 128 131 : 'FloatField', # Numeric 129 133 : 'DateField', # DBDate 130 134 : 'TimeField', # DBTime 131 135 : 'DateTimeField', # DBTimeStamp 132 139 : 'FloatField', # VarNumeric 133 200 : 'CharField', # VarChar 134 201 : 'TextField', # LongVarChar 135 202 : 'CharField', # VarWChar 136 203 : 'TextField', # LongVarWChar 137 } 138 No newline at end of file -
db/backends/mssql/creation.py
1 DATA_TYPES = { 2 'AutoField': 'int IDENTITY (1, 1)', 3 'BooleanField': 'bit', 4 'CharField': 'varchar(%(maxlength)s)', 5 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', 6 'DateField': 'datetime', 7 'DateTimeField': 'datetime', 8 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 9 'FileField': 'varchar(254)', 10 'FilePathField': 'varchar(254)', 11 'FloatField': 'double precision', 12 'ImageField': 'varchar(254)', 13 'IntegerField': 'int', 14 'IPAddressField': 'char(15)', 15 'ManyToManyField': None, 16 'NullBooleanField': 'bit', 17 'OneToOneField': 'int', 18 'PhoneNumberField': 'varchar(20)', 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': 'varchar(%(maxlength)s)', 23 'SmallIntegerField': 'smallint', 24 'TextField': 'text', 25 'TimeField': 'datetime', 26 'USStateField': 'varchar(2)', 27 } -
db/backends/mssql/base.py
1 """ 2 Alpha Multi-plataform MSSQL database backend for Django. 3 4 Requires pymssql >= v0.8.0: http://pymssql.sourceforge.net/ 5 """ 6 if __name__ == '__main__': 7 import sys 8 import os 9 10 SETTINGS_MODULE = 'settings' 11 12 project_dir = r'E:\Proyectos\Python\mysite' 13 sys.path.append(os.path.join(project_dir, '..')) 14 sys.path.append("..") 15 sys.path.pop() 16 os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings' 17 18 import datetime 19 from django.db.backends import util 20 from django.core.exceptions import ImproperlyConfigured 21 from django.utils.datastructures import SortedDict 22 23 try: 24 import pymssql as Database 25 except ImportError, e: 26 raise ImproperlyConfigured, "Error loading pymssql module: %s" % e 27 28 try: 29 import mx 30 except ImportError: 31 mx = None 32 33 try: 34 # Only exists in Python 2.4+ 35 from threading import local 36 except ImportError: 37 # Import copy of _thread_local.py from Python 2.4 38 from django.utils._threading_local import local 39 40 DatabaseError = Database.DatabaseError 41 IntegrityError = Database.IntegrityError 42 43 #Configure support options: 44 allows_group_by_ordinal = True 45 allows_unique_and_pk = True 46 autoindexes_primary_keys = True 47 needs_datetime_string_cast = True 48 needs_upper_for_iops = False 49 supports_constraints = True 50 supports_tablespaces = False 51 uses_case_insensitive_names = False 52 53 def complain(*args, **kwargs): 54 raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet." 55 56 def ignore(*args, **kwargs): 57 pass 58 59 class DatabaseError(Exception): 60 pass 61 62 class IntegrityError(DatabaseError): 63 pass 64 65 class DatabaseWrapper(local): 66 def __init__(self, **kwargs): 67 self.connection = None 68 self.queries = [] 69 70 def cursor(self): 71 from django.conf import settings 72 if self.connection is None: 73 if settings.DATABASE_NAME == '' or settings.DATABASE_USER == '': 74 raise ImproperlyConfigured, "You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file." 75 if not settings.DATABASE_HOST: 76 settings.DATABASE_HOST = "127.0.0.1" 77 78 if settings.DATABASE_PORT: 79 hostStr = '%s:%s' % ( settings.DATABASE_HOST ,settings.DATABASE_PORT) 80 else: 81 hostStr = settings.DATABASE_HOST 82 83 self.connection = Database.connect(host=hostStr,user=settings.DATABASE_USER,password=settings.DATABASE_PASSWORD,database=settings.DATABASE_NAME) 84 85 self.connection.cursor().execute("SET DATEFORMAT ymd\nGO") 86 87 cursor = self.connection.cursor() 88 if settings.DEBUG: 89 return util.CursorDebugWrapper(cursor, self) 90 return cursor 91 92 def _commit(self): 93 if self.connection is not None: 94 return self.connection.commit() 95 96 def _rollback(self): 97 if self.connection is not None: 98 return self.connection.rollback() 99 100 def close(self): 101 if self.connection is not None: 102 self.connection.close() 103 self.connection = None 104 105 ''' 106 Return the major version of the server. 7=Sql 7,8=Sql2000,9=Sql2005 107 ''' 108 def version(): 109 cur = DatabaseWrapper().cursor() 110 cur.execute("SELECT SERVERPROPERTY('ProductVersion')") 111 112 return int(cur.fetchone()[0].split('.')[0]) 113 114 def quote_name(name): 115 if name.startswith('[') and name.endswith(']'): 116 return name # Quoting once is enough. 117 return '[%s]' % name 118 119 dictfetchone = util.dictfetchone 120 dictfetchmany = util.dictfetchmany 121 dictfetchall = util.dictfetchall 122 123 def get_last_insert_id(cursor, table_name, pk_name): 124 cursor.execute("SELECT %s FROM %s WHERE %s = IDENT_CURRENT('%s')" % (pk_name, table_name, pk_name,table_name)) 125 return cursor.fetchone()[0] 126 127 def get_date_extract_sql(lookup_type, table_name): 128 # lookup_type is 'year', 'month', 'day' 129 return "DATEPART(%s, %s)" % (lookup_type, table_name) 130 131 def get_date_trunc_sql(lookup_type, field_name): 132 # lookup_type is 'year', 'month', 'day' 133 if lookup_type=='year': 134 return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name 135 if lookup_type=='month': 136 return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name) 137 if lookup_type=='day': 138 return "Convert(datetime, Convert(varchar(12), %s))" % field_name 139 140 def get_datetime_cast_sql(): 141 return None 142 143 def get_limit_offset_sql(limit, offset=None): 144 # Limits and offset are too complicated to be handled here. 145 # Look for a implementation similar to SqlServer backend 146 return "" 147 148 def get_random_function_sql(): 149 return "RAND()" 150 151 def get_deferrable_sql(): 152 # TODO: Workaround cicle paths... 153 # DEFERRABLE and INITALLY DEFFERRED are not apparently supported on constraints 154 # This cause SQL Server message 1750, severity 16, state 0, for example in the multiple joins path of comments. 155 # So, this left Sql Server as if have not relations :( 156 #return " ON DELETE CASCADE ON UPDATE CASCADE" 157 return "" 158 159 def get_fulltext_search_sql(field_name): 160 raise NotImplementedError 161 162 def get_drop_foreignkey_sql(): 163 return "DROP CONSTRAINT" 164 165 def get_pk_default_value(): 166 return "DEFAULT" 167 168 def get_max_name_length(): 169 return None 170 171 def get_start_transaction_sql(): 172 return "BEGIN;" 173 174 def get_tablespace_sql(tablespace, inline=False): 175 return "ON %s" % quote_name(tablespace) 176 177 def get_autoinc_sql(table): 178 return None 179 180 def get_sql_flush(sql_styler, full_table_list, sequences): 181 """Return a list of SQL statements required to remove all data from 182 all tables in the database (without actually removing the tables 183 themselves) and put the database in an empty 'initial' state 184 """ 185 # Cannot use TRUNCATE on tables that are reference by a FOREIGN KEY 186 # So must use the much slower DELETE 187 sql_list = ['%s %s %s;' % \ 188 (sql_styler.SQL_KEYWORD('DELETE'), 189 sql_styler.SQL_KEYWORD('FROM'), 190 sql_styler.SQL_FIELD(quote_name(table)) 191 ) for table in full_table_list] 192 #The reset the counters on each table. 193 sql_list.extend(['%s %s %s %s %s %s %s;' % ( 194 sql_styler.SQL_KEYWORD('DBCC'), 195 sql_styler.SQL_KEYWORD('CHECKIDENT'), 196 sql_styler.SQL_FIELD(quote_name(seq["table"])), 197 sql_styler.SQL_KEYWORD('RESEED'), 198 sql_styler.SQL_FIELD('1'), 199 sql_styler.SQL_KEYWORD('WITH'), 200 sql_styler.SQL_KEYWORD('NO_INFOMSGS'), 201 ) for seq in sequences]) 202 203 return sql_list 204 205 def get_sql_sequence_reset(style, model_list): 206 "Returns a list of the SQL statements to reset sequences for the given models." 207 # No sequence reset required 208 return [] 209 210 def get_trigger_name(table): 211 return '%s_TR' % table.upper() 212 213 def get_query_set_class(DefaultQuerySet): 214 "Create a custom QuerySet class for SqlServer." 215 216 from django.db import backend, connection 217 from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word 218 219 class SqlServerQuerySet(DefaultQuerySet): 220 221 def iterator(self): 222 "Performs the SELECT database lookup of this QuerySet." 223 224 from django.db.models.query import get_cached_row 225 226 # self._select is a dictionary, and dictionaries' key order is 227 # undefined, so we convert it to a list of tuples. 228 extra_select = self._select.items() 229 230 full_query = None 231 232 try: 233 try: 234 select, sql, params, full_query = self._get_sql_clause(get_full_query=True) 235 except TypeError: 236 select, sql, params = self._get_sql_clause() 237 except EmptyResultSet: 238 raise StopIteration 239 if not full_query: 240 full_query = "SELECT %s%s\n%s" % \ 241 ((self._distinct and "DISTINCT " or ""), 242 ', '.join(select), sql) 243 244 cursor = connection.cursor() 245 cursor.execute(full_query, params) 246 247 fill_cache = self._select_related 248 fields = self.model._meta.fields 249 index_end = len(fields) 250 251 # so here's the logic; 252 # 1. retrieve each row in turn 253 # 2. convert NCLOBs 254 255 while 1: 256 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 257 if not rows: 258 raise StopIteration 259 for row in rows: 260 row = self.resolve_columns(row, fields) 261 if fill_cache: 262 obj, index_end = get_cached_row(klass=self.model, row=row, 263 index_start=0, max_depth=self._max_related_depth) 264 else: 265 obj = self.model(*row[:index_end]) 266 for i, k in enumerate(extra_select): 267 setattr(obj, k[0], row[index_end+i]) 268 yield obj 269 270 271 def _get_sql_clause(self, get_full_query=False): 272 from django.db.models.query import fill_table_cache, \ 273 handle_legacy_orderlist, orderfield2column 274 275 opts = self.model._meta 276 277 # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. 278 select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields] 279 tables = [quote_only_if_word(t) for t in self._tables] 280 joins = SortedDict() 281 where = self._where[:] 282 params = self._params[:] 283 284 # Convert self._filters into SQL. 285 joins2, where2, params2 = self._filters.get_sql(opts) 286 joins.update(joins2) 287 where.extend(where2) 288 params.extend(params2) 289 290 # Add additional tables and WHERE clauses based on select_related. 291 if self._select_related: 292 fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table]) 293 294 # Add any additional SELECTs. 295 if self._select: 296 select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()]) 297 298 # Start composing the body of the SQL statement. 299 sql = [" FROM", backend.quote_name(opts.db_table)] 300 301 # Compose the join dictionary into SQL describing the joins. 302 if joins: 303 sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition) 304 for (alias, (table, join_type, condition)) in joins.items()])) 305 306 # Compose the tables clause into SQL. 307 if tables: 308 sql.append(", " + ", ".join(tables)) 309 310 # Compose the where clause into SQL. 311 if where: 312 sql.append(where and "WHERE " + " AND ".join(where)) 313 314 #copy a version suitable for LIMIT 315 sql2=[] 316 [sql2.append(x) for x in sql] 317 # ORDER BY clause 318 order_by = [] 319 if self._order_by is not None: 320 ordering_to_use = self._order_by 321 else: 322 ordering_to_use = opts.ordering 323 for f in handle_legacy_orderlist(ordering_to_use): 324 if f == '?': # Special case. 325 order_by.append(backend.get_random_function_sql()) 326 else: 327 if f.startswith('-'): 328 col_name = f[1:] 329 order = "DESC" 330 else: 331 col_name = f 332 order = "ASC" 333 if "." in col_name: 334 table_prefix, col_name = col_name.split('.', 1) 335 table_prefix = backend.quote_name(table_prefix) + '.' 336 else: 337 # Use the database table as a column prefix if it wasn't given, 338 # and if the requested column isn't a custom SELECT. 339 if "." not in col_name and col_name not in (self._select or ()): 340 table_prefix = backend.quote_name(opts.db_table) + '.' 341 else: 342 table_prefix = '' 343 order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order)) 344 if order_by: 345 sql.append("ORDER BY " + ", ".join(order_by)) 346 347 # Look for column name collisions in the select elements 348 # and fix them with an AS alias. This allows us to do a 349 # SELECT * later in the paging query. 350 cols = [clause.split('.')[-1] for clause in select] 351 for index, col in enumerate(cols): 352 if cols.count(col) > 1: 353 col = '%s%d' % (col.replace('[', '').replace(']',''), index) 354 cols[index] = backend.quote_name(col) 355 select[index] = '%s AS %s' % (select[index], backend.quote_name(col)) 356 357 # LIMIT and OFFSET clauses 358 # To support limits and offsets, SqlServer requires some funky rewriting of an otherwise normal looking query. 359 select_clause = ",".join(select) 360 distinct = (self._distinct and "DISTINCT " or "") 361 full_query = None 362 363 if self._limit is None: 364 assert self._offset is None, "'offset' is not allowed without 'limit'" 365 366 if self._offset is not None: 367 offset = int(self._offset) 368 else: 369 offset = 0 370 371 if self._limit is not None: 372 limit = int(self._limit) 373 else: 374 limit = None 375 376 limit_and_offset_clause = '' 377 378 if limit is not None: 379 limit_and_offset_clause = True 380 elif offset: 381 limit_and_offset_clause = True 382 383 if limit_and_offset_clause: 384 #Django give: 385 # Offset : Start row 386 # Limit : How much aditional rows fetch 387 388 # This must be transformed to Sql2005 to: 389 # Offset : First Row 390 # Limit : EndRow 391 StartRow = offset + 1 392 EndRow = StartRow + limit - 1 393 # and for Sql2000 394 # Offset : Top rows 395 # Limit: From where 396 limit = limit + offset 397 if offset==0: 398 offset = limit 399 else: 400 offset = offset + 1 401 #Must use a order. If not specified, use Id. 402 if len(order_by)==0: 403 order_by.append('%s.%s ASC' % 404 (backend.quote_name(opts.db_table), 405 backend.quote_name(opts.fields[0].db_column or opts.fields[0].column) 406 ) 407 ) 408 409 order_by_clause = ", ".join(order_by) 410 order_by_clauseReverse = "" 411 412 #For Sql2005+ use native implementation... 413 if version()>8: 414 fmt = \ 415 """ 416 SELECT * 417 FROM ( 418 SELECT %(distinc)s TOP %(EndRow)s 419 %(fields)s, ROW_NUMBER() 420 OVER( 421 ORDER BY %(orderby)s 422 ) AS row 423 %(sql)s ORDER BY %(orderby)s 424 ) AS x 425 WHERE x.row BETWEEN %(StartRow)s AND %(EndRow)s 426 """ 427 else: 428 #Is necesary reverse all the second order by for the trick to work... 429 order_by_clauseReverse= ", ".join(self.change_order_direction(order_by)) 430 431 fmt = \ 432 """ 433 SELECT * FROM ( 434 SELECT TOP %(offset)s * FROM ( 435 SELECT TOP %(limit)s %(distinc)s%(fields)s 436 %(sql)s 437 ORDER BY %(orderby)s 438 ) AS %(table)s 439 ORDER BY %(orderbyReverse)s) AS %(table)s 440 ORDER BY %(orderby)s 441 """ 442 443 full_query = fmt % {'distinc':distinct, 'fields':select_clause, 444 'sql':" ".join(sql2),'orderby':order_by_clause, 445 'orderbyReverse':order_by_clauseReverse, 446 'table':backend.quote_name(opts.db_table), 447 'offset':offset,'limit':limit, 448 'StartRow':StartRow,'EndRow':EndRow} 449 450 print full_query 451 if get_full_query: 452 return select, " ".join(sql), params, full_query 453 else: 454 return select, " ".join(sql), params 455 456 457 def change_order_direction(self,order_by): 458 newOrder=[] 459 460 for order in order_by: 461 if order.find(' ASC'): 462 newOrder.append(order.replace(' ASC',' DESC')) 463 else: 464 newOrder.append(order.replace(' DESC',' ASC')) 465 466 return newOrder 467 468 def resolve_columns(self, row, fields=()): 469 from django.db.models.fields import DateField, DateTimeField, \ 470 TimeField, BooleanField, NullBooleanField, DecimalField, Field 471 values = [] 472 for value, field in map(None, row, fields): 473 # Convert 1 or 0 to True or False 474 if value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)): 475 value = bool(value) 476 # Convert floats to decimals 477 elif value is not None and isinstance(field, DecimalField): 478 value = util.typecast_decimal(field.format_number(value)) 479 values.append(value) 480 return values 481 482 return SqlServerQuerySet 483 484 OPERATOR_MAPPING = { 485 'exact': '= %s', 486 'iexact': 'LIKE %s', 487 'contains': 'LIKE %s', 488 'icontains': 'LIKE %s', 489 'gt': '> %s', 490 'gte': '>= %s', 491 'lt': '< %s', 492 'lte': '<= %s', 493 'startswith': 'LIKE %s', 494 'endswith': 'LIKE %s', 495 'istartswith': 'LIKE %s', 496 'iendswith': 'LIKE %s', 497 } 498 499 if __name__ == '__main__': 500 from mysite.polls.models import Poll, Choice 501 from datetime import datetime 502 503 #Poll.objects.all().delete() 504 #i =0 505 #for i in range(i,150): 506 # p = Poll(question="%s" % i, pub_date=datetime.now()) 507 # p.save() 508 509 for poll in Poll.objects.all()[:10]: 510 print poll 511 No newline at end of file -
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/creation.py
1 DATA_TYPES = { 2 'AutoField': 'int IDENTITY (1, 1)', 3 'BooleanField': 'bit', 4 'CharField': 'varchar(%(maxlength)s)', 5 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', 6 'DateField': 'datetime', 7 'DateTimeField': 'datetime', 8 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 9 'FileField': 'varchar(254)', 10 'FilePathField': 'varchar(254)', 11 'FloatField': 'double precision', 12 'ImageField': 'varchar(254)', 13 'IntegerField': 'int', 14 'IPAddressField': 'char(15)', 15 'ManyToManyField': None, 16 'NullBooleanField': 'bit', 17 'OneToOneField': 'int', 18 'PhoneNumberField': 'varchar(20)', 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': 'varchar(%(maxlength)s)', 23 'SmallIntegerField': 'smallint', 24 'TextField': 'text', 25 'TimeField': 'datetime', 26 'USStateField': 'varchar(2)', 27 } -
db/backends/mssql/introspection.py
1 def get_table_list(cursor): 2 "Returns a list of table names in the current database." 3 cursor.execute("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'") 4 return [row[2] for row in cursor.fetchall()] 5 6 def _is_auto_field(cursor, table_name, column_name): 7 cursor.execute("SELECT COLUMNPROPERTY( OBJECT_ID('%s'),'%s','IsIdentity')" % (table_name, column_name)) 8 return cursor.fetchall()[0][0] 9 10 def get_table_description(cursor, table_name, identity_check=True): 11 """Returns a description of the table, with the DB-API cursor.description interface. 12 13 The 'auto_check' parameter has been added to the function argspec. 14 If set to True, the function will check each of the table's fields for the 15 IDENTITY property (the IDENTITY property is the MSSQL equivalent to an AutoField). 16 17 When a field is found with an IDENTITY property, it is given a custom field number 18 of -777, which maps to the 'AutoField' value in the DATA_TYPES_REVERSE dict. 19 """ 20 cursor.execute("SELECT TOP 1 * FROM %s" % table_name) 21 cursor.nextset() 22 items = [] 23 if identity_check: 24 for data in cursor.description: 25 if _is_auto_field(cursor, table_name, data[0]): 26 data = list(data) 27 data[1] = -777 28 items.append(list(data)) 29 else: 30 items = cursor.description 31 return items 32 33 def _name_to_index(cursor, table_name): 34 """ 35 Returns a dictionary of {field_name: field_index} for the given table. 36 Indexes are 0-based. 37 """ 38 return dict([(d[0], i) for i, d in enumerate(get_table_description(cursor, table_name, identity_check=False))]) 39 40 def get_relations(cursor, table_name): 41 """ 42 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 43 representing all relationships to the given table. Indexes are 0-based. 44 """ 45 table_index = _name_to_index(cursor, table_name) 46 sql = """SELECT e.COLUMN_NAME AS column_name, 47 c.TABLE_NAME AS referenced_table_name, 48 d.COLUMN_NAME AS referenced_column_name 49 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS a 50 INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS b 51 ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME 52 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE AS c 53 ON b.UNIQUE_CONSTRAINT_NAME = c.CONSTRAINT_NAME 54 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS d 55 ON c.CONSTRAINT_NAME = d.CONSTRAINT_NAME 56 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS e 57 ON a.CONSTRAINT_NAME = e.CONSTRAINT_NAME 58 WHERE a.TABLE_NAME = ? AND 59 a.CONSTRAINT_TYPE = 'FOREIGN KEY'""" 60 cursor = Cursor(cursor.db.connection) 61 cursor.execute(sql, (table_name,)) 62 return dict([(table_index[item[0]], (_name_to_index(cursor, item[1])[item[2]], item[1])) 63 for item in cursor.fetchall()]) 64 65 def get_indexes(cursor, table_name): 66 """ 67 Returns a dictionary of fieldname -> infodict for the given table, 68 where each infodict is in the format: 69 {'primary_key': boolean representing whether it's the primary key, 70 'unique': boolean representing whether it's a unique index} 71 """ 72 sql = """SELECT b.COLUMN_NAME, a.CONSTRAINT_TYPE 73 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS a INNER JOIN 74 INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS b 75 ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME AND 76 a.TABLE_NAME = b.TABLE_NAME 77 WHERE a.TABLE_NAME = ? AND 78 (CONSTRAINT_TYPE = 'PRIMARY KEY' OR 79 CONSTRAINT_TYPE = 'UNIQUE')""" 80 field_names = [item[0] for item in get_table_description(cursor, table_name, identity_check=False)] 81 cursor = Cursor(cursor.db.connection) 82 cursor.execute(sql, (table_name,)) 83 indexes = {} 84 results = {} 85 data = cursor.fetchall() 86 if data: 87 results.update(data) 88 for field in field_names: 89 val = results.get(field, None) 90 indexes[field] = dict(primary_key=(val=='PRIMARY KEY'), unique=(val=='UNIQUE')) 91 return indexes 92 93 # A reference for the values below: 94 # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ado270/htm/mdcstdatatypeenum.asp 95 DATA_TYPES_REVERSE = { 96 # 8192 : Array , 97 # 128 : Binary , 98 # 9 : IDispatch , 99 # 12 : Variant , 100 # 13 : IUnknown , 101 # 21 : UnsignedBigInt, 102 # 132 : UserDefined , 103 # 0 : Empty , 104 # 136 : Chapter , 105 # 138 : PropVariant , 106 # 204 : VarBinary , 107 # 205 : LongVarBinary , 108 -777: 'AutoField', # Custom number used to identify AutoFields 109 2 : 'SmallIntegerField', # SmallInt 110 3 : 'IntegerField', # Integer 111 4 : 'FloatField', # Single 112 5 : 'FloatField', # Decimal 113 6 : 'FloatField', # Currency 114 7 : 'DateField', # Date 115 8 : 'CharField', # BSTR 116 10 : 'IntegerField', # Error 117 11 : 'BooleanField', # Boolean 118 14 : 'FloatField', # Decimal 119 16 : 'SmallIntegerField', # TinyInt 120 17 : 'PositiveSmallIntegerField', # UnsignedTinyInt 121 18 : 'PositiveSmallIntegerField', # UnsignedSmallInt 122 19 : 'PositiveIntegerField', # UnsignedInt 123 20 : 'IntegerField', # BigInt 124 64 : 'DateTimeField', # FileTime 125 72 : 'CharField', # GUID 126 129 : 'CharField', # Char 127 130 : 'CharField', # WChar 128 131 : 'FloatField', # Numeric 129 133 : 'DateField', # DBDate 130 134 : 'TimeField', # DBTime 131 135 : 'DateTimeField', # DBTimeStamp 132 139 : 'FloatField', # VarNumeric 133 200 : 'CharField', # VarChar 134 201 : 'TextField', # LongVarChar 135 202 : 'CharField', # VarWChar 136 203 : 'TextField', # LongVarWChar 137 } 138 No newline at end of file -
db/backends/util.py
1 from django.conf import settings 1 2 import datetime 2 3 import md5 3 4 from time import time … … 22 23 # formatting with '%' only works with tuples or dicts. 23 24 if not isinstance(params, (tuple, dict)): 24 25 params = tuple(params) 26 # ado_mssql uses '?' for parameter escaping, so all '?' 27 # must be replaced with the standard '%s' if the parameter 28 # substitution is going to work. 29 if settings.DATABASE_ENGINE == 'ado_mssql': 30 sql = sql.replace('?', '%s') 31 # There are many situations that will cause the string 32 # substituion below to fail (e.g. wildcard characters '%' 33 # in LIKE queries). Instead of attempting to figure out 34 # the many variations that can cause an error, the string substition 35 # will be attempted first; if it fails, then the sql 36 # and its parameters will be combined into a string similar to 37 # the one created in the executemany function below. 38 try: 39 sql = sql % tuple(params) 40 except: 41 sql = '%s SQL: %s' % (sql, str(tuple(params))) 25 42 self.db.queries.append({ 26 'sql': sql % params,43 'sql': sql, 27 44 'time': "%.3f" % (stop - start), 28 45 }) 29 46 -
db/models/base.py
239 239 (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column))) 240 240 db_values.append(getattr(self, self._meta.order_with_respect_to.attname)) 241 241 if db_values: 242 if pk_set and (settings.DATABASE_ENGINE=="ado_mssql" or settings.DATABASE_ENGINE=="mssql"): 243 # You can't insert an auto value into a column unless you do 244 # this in MSSQL 245 # TODO: Only works for auto-id's... how chek it properly? 246 if self._meta.pk.column == 'id': 247 cursor.execute("SET IDENTITY_INSERT %s ON" % \ 248 backend.quote_name(self._meta.db_table)) 249 242 250 cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \ 243 251 (backend.quote_name(self._meta.db_table), ','.join(field_names), 244 252 ','.join(placeholders)), db_values) 253 254 if pk_set and (settings.DATABASE_ENGINE=="ado_mssql" or settings.DATABASE_ENGINE=="mssql"): 255 if self._meta.pk.column == 'id': 256 cursor.execute("SET IDENTITY_INSERT %s OFF" %\ 257 backend.quote_name(self._meta.db_table)) 245 258 else: 246 259 # Create a new record with defaults for everything. 247 260 cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % -
db/models/fields/__init__.py
193 193 value = int(value) 194 194 except ValueError: 195 195 raise ValueError("The __year lookup type requires an integer argument") 196 return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.99 9999' % value]196 return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.99' % value] 197 197 raise TypeError("Field has invalid lookup: %s" % lookup_type) 198 198 199 199 def has_default(self): … … 541 541 if value is not None: 542 542 # MySQL will throw a warning if microseconds are given, because it 543 543 # doesn't support microseconds. 544 if settings.DATABASE_ENGINE == 'mysql'and hasattr(value, 'microsecond'):544 if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') and hasattr(value, 'microsecond'): 545 545 value = value.replace(microsecond=0) 546 546 value = str(value) 547 547 return Field.get_db_prep_save(self, value) 548 548 549 549 def get_db_prep_lookup(self, lookup_type, value): 550 # MSSQL doesn't like microseconds. 551 if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') and hasattr(value, 'microsecond'): 552 value = value.replace(microsecond=0) 550 553 if lookup_type == 'range': 551 554 value = [str(v) for v in value] 552 555 else: … … 908 911 # Casts dates into string format for entry into database. 909 912 if value is not None: 910 913 # MySQL will throw a warning if microseconds are given, because it 911 # doesn't support microseconds. 912 if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'): 914 # doesn't support microseconds. Ditto MSSQL 915 if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') \ 916 and hasattr(value, 'microsecond'): 913 917 value = value.replace(microsecond=0) 914 918 if settings.DATABASE_ENGINE == 'oracle': 915 919 # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field.