Ticket #2358: mssql_update9_NOT_WORKING.patch
File mssql_update9_NOT_WORKING.patch, 18.4 KB (added by , 18 years ago) |
---|
-
django/contrib/sessions/middleware.py
55 55 self._session_cache = {} 56 56 else: 57 57 try: 58 datenow = datetime.datetime.now() 59 if hasattr(datenow, 'microsecond'): 60 datenow = datenow.replace(microsecond=0) 58 61 s = Session.objects.get(session_key=self.session_key, 59 expire_date__gt=date time.datetime.now())62 expire_date__gt=datenow) 60 63 self._session_cache = s.get_decoded() 61 64 except (Session.DoesNotExist, SuspiciousOperation): 62 65 self._session_cache = {} -
django/db/backends/ado_mssql/base.py
3 3 4 4 Requires adodbapi 2.0.1: http://adodbapi.sourceforge.net/ 5 5 """ 6 import pythoncom 6 7 8 from django.conf import settings 7 9 from django.db.backends import util 10 8 11 try: 9 import adodbapi as Database12 import adodbapi.adodbapi as Database 10 13 except ImportError, e: 11 14 from django.core.exceptions import ImproperlyConfigured 12 15 raise ImproperlyConfigured, "Error loading adodbapi module: %s" % e … … 25 28 def executeHelper(self, operation, isStoredProcedureCall, parameters=None): 26 29 if parameters is not None and "%s" in operation: 27 30 operation = operation.replace("%s", "?") 31 pythoncom.CoInitialize() 28 32 Database.Cursor.executeHelper(self, operation, isStoredProcedureCall, parameters) 33 pythoncom.CoUninitialize() 29 34 30 35 class Connection(Database.Connection): 31 36 def cursor(self): … … 44 49 return datetime.datetime(*tuple(tv)) 45 50 if type(res) == float and str(res)[-2:] == ".0": 46 51 return int(res) # If float but int, then int. 52 if type(res) == unicode: 53 return res.encode(settings.DEFAULT_CHARSET) 47 54 return res 48 55 Database.convertVariantToPython = variantToPython 49 56 … … 69 76 settings.DATABASE_HOST = "127.0.0.1" 70 77 # TODO: Handle DATABASE_PORT. 71 78 conn_string = "PROVIDER=SQLOLEDB;DATA SOURCE=%s;UID=%s;PWD=%s;DATABASE=%s" % (settings.DATABASE_HOST, settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME) 79 # The driver claims to be threadsafe, surely it should handle this? 80 # Either way, I'm not convinced this is the right place. 81 # It should be done per thread 82 #pythoncom.CoInitialize() 72 83 self.connection = Database.connect(conn_string) 73 cursor = self.connection.cursor() 84 #pythoncom.CoUninitialize() 85 86 cursor = Cursor(self.connection) 74 87 if settings.DEBUG: 75 88 return util.CursorDebugWrapper(cursor, self) 76 89 return cursor … … 100 113 dictfetchall = util.dictfetchall 101 114 102 115 def get_last_insert_id(cursor, table_name, pk_name): 103 cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name))116 cursor.execute("SELECT %s FROM %s WHERE %s = IDENT_CURRENT('%s')" % (pk_name, table_name, pk_name,table_name)) 104 117 return cursor.fetchone()[0] 105 118 106 119 def get_date_extract_sql(lookup_type, table_name): … … 118 131 119 132 def get_limit_offset_sql(limit, offset=None): 120 133 # TODO: This is a guess. Make sure this is correct. 121 sql = "LIMIT %s" % limit 122 if offset and offset != 0: 123 sql += " OFFSET %s" % offset 124 return sql 134 # should be "SELECT TOP %s" % limit 135 # not LIMIT at the end 136 return "" 137 #sql = "LIMIT %s" % limit 138 #if offset and offset != 0: 139 # sql += " OFFSET %s" % offset 140 #return sql 125 141 126 142 def get_random_function_sql(): 127 143 return "RAND()" 128 144 129 145 def get_deferrable_sql(): 130 return " DEFERRABLE INITIALLY DEFERRED" 146 return " ON DELETE CASCADE ON UPDATE CASCADE" 147 # DEFERRABLE and INITALLY DEFFERRED are not apparently supported on constraints 148 # Never actually specified, but implied by: 149 # http://msdn2.microsoft.com/en-us/library/ms178011.aspx 150 # and the fact that DEFERRABLE and INITALLY DEFERRED don't appear in the 151 # ALTER TABLE syntax 152 # HOWEVER, You can put a much needed ON DELETE CASCADE thing here 131 153 132 154 def get_fulltext_search_sql(field_name): 133 155 raise NotImplementedError … … 138 160 def get_pk_default_value(): 139 161 return "DEFAULT" 140 162 141 def get_sql_flush(sql_styler, full_table_list ):163 def get_sql_flush(sql_styler, full_table_list, sequences): 142 164 """Return a list of SQL statements required to remove all data from 143 165 all tables in the database (without actually removing the tables 144 166 themselves) and put the database in an empty 'initial' state 145 167 """ 146 # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements 147 # TODO - SQL not actually tested against ADO MSSQL yet! 148 # TODO - autoincrement indices reset required? See other get_sql_flush() implementations 149 sql_list = ['%s %s;' % \ 150 (sql_styler.SQL_KEYWORD('TRUNCATE'), 168 # Cannot use TRUNCATE on tables that are reference by a FOREIGN KEY 169 # So must use the much slower DELETE 170 171 sql_list = ['%s %s %s;' % \ 172 (sql_styler.SQL_KEYWORD('DELETE'), 173 sql_styler.SQL_KEYWORD('FROM'), 151 174 sql_styler.SQL_FIELD(quote_name(table)) 152 175 ) for table in full_table_list] 153 176 177 #The reset the counters on each table. 178 sql_list.extend(['%s %s %s %s %s %s %s;' % ( 179 sql_styler.SQL_KEYWORD('DBCC'), 180 sql_styler.SQL_KEYWORD('CHECKIDENT'), 181 sql_styler.SQL_FIELD(quote_name(seq["table"])), 182 sql_styler.SQL_KEYWORD('RESEED'), 183 sql_styler.SQL_FIELD('1'), 184 sql_styler.SQL_KEYWORD('WITH'), 185 sql_styler.SQL_KEYWORD('NO_INFOMSGS'), 186 ) for seq in sequences]) 187 return sql_list 188 189 154 190 OPERATOR_MAPPING = { 155 191 'exact': '= %s', 156 192 'iexact': 'LIKE %s', -
django/db/backends/ado_mssql/introspection.py
1 # Tested against MSDE and SQL Server 2000 using adodbapi 2.0.1 2 # Python 2.4.2 and 2.4.3 were used during testing. 3 from django.db.backends.ado_mssql.base import Cursor 4 1 5 def get_table_list(cursor): 2 raise NotImplementedError 6 "Returns a list of table names in the current database." 7 print "# Note: Any fields that are named 'id', are of type 'AutoField', and" 8 print "# and are Primary Keys will NOT appear in the model output below." 9 print "# By default Django assumes that the each model's Primary Key is an " 10 print "# AutoField with a name of 'id', so there is no need to add it to the" 11 print "# model description." 12 print 13 cursor.execute("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'") 14 return [row[2] for row in cursor.fetchall()] 3 15 4 def get_table_description(cursor, table_name): 5 raise NotImplementedError 16 def _is_auto_field(cursor, table_name, column_name): 17 cursor.execute("SELECT COLUMNPROPERTY( OBJECT_ID('%s'),'%s','IsIdentity')" % (table_name, column_name)) 18 return cursor.fetchall()[0][0] 6 19 20 def get_table_description(cursor, table_name, identity_check=True): 21 """Returns a description of the table, with the DB-API cursor.description interface. 22 23 The 'auto_check' parameter has been added to the function argspec. 24 If set to True, the function will check each of the table's fields for the 25 IDENTITY property (the IDENTITY property is the MSSQL equivalent to an AutoField). 26 27 When a field is found with an IDENTITY property, it is given a custom field number 28 of -777, which maps to the 'AutoField' value in the DATA_TYPES_REVERSE dict. 29 """ 30 cursor.execute("SELECT TOP 1 * FROM %s" % table_name) 31 cursor.nextset() 32 items = [] 33 if identity_check: 34 for data in cursor.description: 35 if _is_auto_field(cursor, table_name, data[0]): 36 data = list(data) 37 data[1] = -777 38 items.append(list(data)) 39 else: 40 items = cursor.description 41 return items 42 43 def _name_to_index(cursor, table_name): 44 """ 45 Returns a dictionary of {field_name: field_index} for the given table. 46 Indexes are 0-based. 47 """ 48 return dict([(d[0], i) for i, d in enumerate(get_table_description(cursor, table_name, identity_check=False))]) 49 7 50 def get_relations(cursor, table_name): 8 raise NotImplementedError 9 51 """ 52 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 53 representing all relationships to the given table. Indexes are 0-based. 54 """ 55 table_index = _name_to_index(cursor, table_name) 56 sql = """SELECT e.COLUMN_NAME AS column_name, 57 c.TABLE_NAME AS referenced_table_name, 58 d.COLUMN_NAME AS referenced_column_name 59 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS a 60 INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS b 61 ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME 62 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE AS c 63 ON b.UNIQUE_CONSTRAINT_NAME = c.CONSTRAINT_NAME 64 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS d 65 ON c.CONSTRAINT_NAME = d.CONSTRAINT_NAME 66 INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS e 67 ON a.CONSTRAINT_NAME = e.CONSTRAINT_NAME 68 WHERE a.TABLE_NAME = ? AND 69 a.CONSTRAINT_TYPE = 'FOREIGN KEY'""" 70 cursor = Cursor(cursor.db.connection) 71 cursor.execute(sql, (table_name,)) 72 return dict([(table_index[item[0]], (_name_to_index(cursor, item[1])[item[2]], item[1])) 73 for item in cursor.fetchall()]) 74 10 75 def get_indexes(cursor, table_name): 11 raise NotImplementedError 76 """ 77 Returns a dictionary of fieldname -> infodict for the given table, 78 where each infodict is in the format: 79 {'primary_key': boolean representing whether it's the primary key, 80 'unique': boolean representing whether it's a unique index} 81 """ 82 sql = """SELECT b.COLUMN_NAME, a.CONSTRAINT_TYPE 83 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS a INNER JOIN 84 INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS b 85 ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME AND 86 a.TABLE_NAME = b.TABLE_NAME 87 WHERE a.TABLE_NAME = ? AND 88 (CONSTRAINT_TYPE = 'PRIMARY KEY' OR 89 CONSTRAINT_TYPE = 'UNIQUE')""" 90 field_names = [item[0] for item in get_table_description(cursor, table_name, identity_check=False)] 91 cursor = Cursor(cursor.db.connection) 92 cursor.execute(sql, (table_name,)) 93 indexes = {} 94 results = {} 95 data = cursor.fetchall() 96 if data: 97 results.update(data) 98 for field in field_names: 99 val = results.get(field, None) 100 indexes[field] = dict(primary_key=(val=='PRIMARY KEY'), unique=(val=='UNIQUE')) 101 return indexes 12 102 13 DATA_TYPES_REVERSE = {} 103 # A reference for the values below: 104 # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ado270/htm/mdcstdatatypeenum.asp 105 DATA_TYPES_REVERSE = { 106 # 8192 : Array , 107 # 128 : Binary , 108 # 9 : IDispatch , 109 # 12 : Variant , 110 # 13 : IUnknown , 111 # 21 : UnsignedBigInt, 112 # 132 : UserDefined , 113 # 0 : Empty , 114 # 136 : Chapter , 115 # 138 : PropVariant , 116 # 204 : VarBinary , 117 # 205 : LongVarBinary , 118 -777: 'AutoField', # Custom number used to identify AutoFields 119 2 : 'SmallIntegerField', # SmallInt 120 3 : 'IntegerField', # Integer 121 4 : 'FloatField', # Single 122 5 : 'FloatField', # Decimal 123 6 : 'FloatField', # Currency 124 7 : 'DateField', # Date 125 8 : 'CharField', # BSTR 126 10 : 'IntegerField', # Error 127 11 : 'BooleanField', # Boolean 128 14 : 'FloatField', # Decimal 129 16 : 'SmallIntegerField', # TinyInt 130 17 : 'PositiveSmallIntegerField', # UnsignedTinyInt 131 18 : 'PositiveSmallIntegerField', # UnsignedSmallInt 132 19 : 'PositiveIntegerField', # UnsignedInt 133 20 : 'IntegerField', # BigInt 134 64 : 'DateTimeField', # FileTime 135 72 : 'CharField', # GUID 136 129 : 'CharField', # Char 137 130 : 'CharField', # WChar 138 131 : 'FloatField', # Numeric 139 133 : 'DateField', # DBDate 140 134 : 'TimeField', # DBTime 141 135 : 'DateTimeField', # DBTimeStamp 142 139 : 'FloatField', # VarNumeric 143 200 : 'CharField', # VarChar 144 201 : 'TextField', # LongVarChar 145 202 : 'CharField', # VarWChar 146 203 : 'TextField', # LongVarWChar 147 } -
django/db/backends/util.py
1 from django.conf import settings 1 2 import datetime 2 3 from time import time 3 4 … … 16 17 # formatting with '%' only works with tuples or dicts. 17 18 if not isinstance(params, (tuple, dict)): 18 19 params = tuple(params) 20 # ado_mssql uses '?' for parameter escaping, so all '?' 21 # must be replaced with the standard '%s' if the parameter 22 # substitution is going to work. 23 if settings.DATABASE_ENGINE == 'ado_mssql': 24 sql = sql.replace('?', '%s') 25 # There are many situations that will cause the string 26 # substituion below to fail (e.g. wildcard characters '%' 27 # in LIKE queries). Instead of attempting to figure out 28 # the many variations that can cause an error, the string substition 29 # will be attempted first; if it fails, then the sql 30 # and its parameters will be combined into a string similar to 31 # the one created in the executemany function below. 32 try: 33 sql = sql % tuple(params) 34 except: 35 sql = '%s SQL: %s' % (sql, str(tuple(params))) 19 36 self.db.queries.append({ 20 'sql': sql % params,37 'sql': sql, 21 38 'time': "%.3f" % (stop - start), 22 39 }) 23 40 -
django/db/models/base.py
205 205 record_exists = True 206 206 if pk_set: 207 207 # Determine whether a record with the primary key already exists. 208 cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % \208 cursor.execute("SELECT 1 FROM %s WHERE %s=%%s" % 209 209 (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val]) 210 210 # If it does already exist, do an UPDATE. 211 211 if cursor.fetchone(): … … 233 233 (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column))) 234 234 db_values.append(getattr(self, self._meta.order_with_respect_to.attname)) 235 235 if db_values: 236 if pk_set and settings.DATABASE_ENGINE=="ado_mssql": 237 # You can't insert an auto value into a column unless you do 238 # this in MSSQL 239 cursor.execute("SET IDENTITY_INSERT %s ON" % \ 240 backend.quote_name(self._meta.db_table)) 241 236 242 cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \ 237 243 (backend.quote_name(self._meta.db_table), ','.join(field_names), 238 244 ','.join(placeholders)), db_values) 245 246 if pk_set and settings.DATABASE_ENGINE=="ado_mssql": 247 cursor.execute("SET IDENTITY_INSERT %s OFF" %\ 248 backend.quote_name(self._meta.db_table)) 239 249 else: 240 250 # Create a new record with defaults for everything. 241 251 cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % -
django/db/models/fields/__init__.py
530 530 if value is not None: 531 531 # MySQL will throw a warning if microseconds are given, because it 532 532 # doesn't support microseconds. 533 if settings.DATABASE_ENGINE == 'mysql'and hasattr(value, 'microsecond'):533 if (settings.DATABASE_ENGINE == 'mysql' or settings.DATABASE_ENGINE == 'ado_mssql') and hasattr(value, 'microsecond'): 534 534 value = value.replace(microsecond=0) 535 535 value = str(value) 536 536 return Field.get_db_prep_save(self, value) 537 537 538 538 def get_db_prep_lookup(self, lookup_type, value): 539 # MSSQL doesn't like microseconds. 540 if settings.DATABASE_ENGINE == 'ado_mssql' and hasattr(value, 'microsecond'): 541 value = value.replace(microsecond=0) 539 542 if lookup_type == 'range': 540 543 value = [str(v) for v in value] 541 544 else: … … 826 829 # Casts dates into string format for entry into database. 827 830 if value is not None: 828 831 # MySQL will throw a warning if microseconds are given, because it 829 # doesn't support microseconds. 830 if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'): 832 # doesn't support microseconds. Ditto MSSQL 833 if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql') \ 834 and hasattr(value, 'microsecond'): 831 835 value = value.replace(microsecond=0) 832 836 value = str(value) 833 837 return Field.get_db_prep_save(self, value)