Django

Code

Ticket #2358: mssql_update9_NOT_WORKING.patch

File mssql_update9_NOT_WORKING.patch, 18.4 kB (added by moof@metamoof.net, 1 year ago)

Not working patch that resolves some issues towards getting the test suite running.

  • django/contrib/sessions/middleware.py

    old new  
    5555                self._session_cache = {} 
    5656            else: 
    5757                try: 
     58                    datenow = datetime.datetime.now() 
     59                    if hasattr(datenow, 'microsecond'): 
     60                        datenow = datenow.replace(microsecond=0) 
    5861                    s = Session.objects.get(session_key=self.session_key, 
    59                         expire_date__gt=datetime.datetime.now()
     62                        expire_date__gt=datenow
    6063                    self._session_cache = s.get_decoded() 
    6164                except (Session.DoesNotExist, SuspiciousOperation): 
    6265                    self._session_cache = {} 
  • django/db/backends/ado_mssql/base.py

    old new  
    33 
    44Requires adodbapi 2.0.1: http://adodbapi.sourceforge.net/ 
    55""" 
     6import pythoncom 
    67 
     8from django.conf import settings 
    79from django.db.backends import util 
     10 
    811try: 
    9     import adodbapi as Database 
     12    import adodbapi.adodbapi as Database 
    1013except ImportError, e: 
    1114    from django.core.exceptions import ImproperlyConfigured 
    1215    raise ImproperlyConfigured, "Error loading adodbapi module: %s" % e 
     
    2528    def executeHelper(self, operation, isStoredProcedureCall, parameters=None): 
    2629        if parameters is not None and "%s" in operation: 
    2730            operation = operation.replace("%s", "?") 
     31        pythoncom.CoInitialize() 
    2832        Database.Cursor.executeHelper(self, operation, isStoredProcedureCall, parameters) 
     33        pythoncom.CoUninitialize() 
    2934 
    3035class Connection(Database.Connection): 
    3136    def cursor(self): 
     
    4449        return datetime.datetime(*tuple(tv)) 
    4550    if type(res) == float and str(res)[-2:] == ".0": 
    4651        return int(res) # If float but int, then int. 
     52    if type(res) == unicode: 
     53        return res.encode(settings.DEFAULT_CHARSET) 
    4754    return res 
    4855Database.convertVariantToPython = variantToPython 
    4956 
     
    6976                settings.DATABASE_HOST = "127.0.0.1" 
    7077            # TODO: Handle DATABASE_PORT. 
    7178            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() 
    7283            self.connection = Database.connect(conn_string) 
    73         cursor = self.connection.cursor() 
     84            #pythoncom.CoUninitialize() 
     85         
     86        cursor = Cursor(self.connection)  
    7487        if settings.DEBUG: 
    7588            return util.CursorDebugWrapper(cursor, self) 
    7689        return cursor 
     
    100113dictfetchall  = util.dictfetchall 
    101114 
    102115def 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)) 
    104117    return cursor.fetchone()[0] 
    105118 
    106119def get_date_extract_sql(lookup_type, table_name): 
     
    118131 
    119132def get_limit_offset_sql(limit, offset=None): 
    120133    # 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  
    125141 
    126142def get_random_function_sql(): 
    127143    return "RAND()" 
    128144 
    129145def 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 
    131153 
    132154def get_fulltext_search_sql(field_name): 
    133155    raise NotImplementedError 
     
    138160def get_pk_default_value(): 
    139161    return "DEFAULT" 
    140162 
    141 def get_sql_flush(sql_styler, full_table_list): 
     163def get_sql_flush(sql_styler, full_table_list, sequences): 
    142164    """Return a list of SQL statements required to remove all data from 
    143165    all tables in the database (without actually removing the tables 
    144166    themselves) and put the database in an empty 'initial' state 
    145167    """ 
    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'), 
    151174                 sql_styler.SQL_FIELD(quote_name(table)) 
    152175                 )  for table in full_table_list] 
    153176 
     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 
    154190OPERATOR_MAPPING = { 
    155191    'exact': '= %s', 
    156192    'iexact': 'LIKE %s', 
  • django/db/backends/ado_mssql/introspection.py

    old new  
     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. 
     3from django.db.backends.ado_mssql.base import Cursor 
     4 
    15def 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()] 
    315 
    4 def get_table_description(cursor, table_name): 
    5     raise NotImplementedError 
     16def _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] 
    619 
     20def 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 
     43def _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 
    750def 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     
    1075def 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 
    12102 
    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 
     105DATA_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 
     1192   : 'SmallIntegerField',          # SmallInt 
     1203   : 'IntegerField',               # Integer 
     1214   : 'FloatField',                 # Single 
     1225   : 'FloatField',                 # Decimal 
     1236   : 'FloatField',                 # Currency 
     1247   : 'DateField',                  # Date 
     1258   : 'CharField',                  # BSTR 
     12610  : 'IntegerField',               # Error 
     12711  : 'BooleanField',               # Boolean 
     12814  : 'FloatField',                 # Decimal 
     12916  : 'SmallIntegerField',          # TinyInt 
     13017  : 'PositiveSmallIntegerField',  # UnsignedTinyInt 
     13118  : 'PositiveSmallIntegerField',  # UnsignedSmallInt 
     13219  : 'PositiveIntegerField',       # UnsignedInt 
     13320  : 'IntegerField',               # BigInt 
     13464  : 'DateTimeField',              # FileTime 
     13572  : 'CharField',                  # GUID 
     136129 : 'CharField',                  # Char 
     137130 : 'CharField',                  # WChar 
     138131 : 'FloatField',                 # Numeric 
     139133 : 'DateField',                  # DBDate 
     140134 : 'TimeField',                  # DBTime 
     141135 : 'DateTimeField',              # DBTimeStamp 
     142139 : 'FloatField',                 # VarNumeric 
     143200 : 'CharField',                  # VarChar 
     144201 : 'TextField',                  # LongVarChar 
     145202 : 'CharField',                  # VarWChar 
     146203 : 'TextField',                  # LongVarWChar 
     147
  • django/db/backends/util.py

    old new  
     1from django.conf import settings 
    12import datetime 
    23from time import time 
    34 
     
    1617            # formatting with '%' only works with tuples or dicts. 
    1718            if not isinstance(params, (tuple, dict)): 
    1819                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))) 
    1936            self.db.queries.append({ 
    20                 'sql': sql % params
     37                'sql': sql
    2138                'time': "%.3f" % (stop - start), 
    2239            }) 
    2340 
  • django/db/models/base.py

    old new  
    205205        record_exists = True 
    206206        if pk_set: 
    207207            # 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" %  
    209209                (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val]) 
    210210            # If it does already exist, do an UPDATE. 
    211211            if cursor.fetchone(): 
     
    233233                    (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column))) 
    234234                db_values.append(getattr(self, self._meta.order_with_respect_to.attname)) 
    235235            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                     
    236242                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \ 
    237243                    (backend.quote_name(self._meta.db_table), ','.join(field_names), 
    238244                    ','.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)) 
    239249            else: 
    240250                # Create a new record with defaults for everything. 
    241251                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % 
  • django/db/models/fields/__init__.py

    old new  
    530530        if value is not None: 
    531531            # MySQL will throw a warning if microseconds are given, because it 
    532532            # 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'): 
    534534                value = value.replace(microsecond=0) 
    535535            value = str(value) 
    536536        return Field.get_db_prep_save(self, value) 
    537537 
    538538    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) 
    539542        if lookup_type == 'range': 
    540543            value = [str(v) for v in value] 
    541544        else: 
     
    826829        # Casts dates into string format for entry into database. 
    827830        if value is not None: 
    828831            # 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'): 
    831835                value = value.replace(microsecond=0) 
    832836            value = str(value) 
    833837        return Field.get_db_prep_save(self, value)