Django

Code

Ticket #2358: mssql_update5.diff

File mssql_update5.diff, 14.0 kB (added by sdelatorre+django@gmail.com, 2 years ago)

Added another fix to the util.py file. If '%' wildcards are used in a custom query, the CursorDebugWrapper?.execute function fails. This was patched by wrapping the string substituion in a try/except block to prevent the exception from halting execution.

  • django/db/models/base.py

    old new  
    171171        record_exists = True 
    172172        if pk_set: 
    173173            # Determine whether a record with the primary key already exists. 
    174             cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % \ 
     174            cursor.execute("SELECT 1 FROM %s WHERE %s=%%s" %  
    175175                (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val]) 
    176176            # If it does already exist, do an UPDATE. 
    177177            if cursor.fetchone(): 
  • django/db/models/fields/__init__.py

    old new  
    490490        if value is not None: 
    491491            # MySQL will throw a warning if microseconds are given, because it 
    492492            # doesn't support microseconds. 
    493             if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'): 
     493            if (settings.DATABASE_ENGINE == 'mysql' or settings.DATABASE_ENGINE == 'ado_mssql') and hasattr(value, 'microsecond'): 
    494494                value = value.replace(microsecond=0) 
    495495            value = str(value) 
    496496        return Field.get_db_prep_save(self, value) 
    497497 
    498     def get_db_prep_lookup(self, lookup_type, value): 
     498    def get_db_prep_lookup(self, lookup_type, value): 
     499        # MSSQL doesn't like microseconds. 
     500        if settings.DATABASE_ENGINE == 'ado_mssql' and hasattr(value, 'microsecond'): 
     501            value = value.replace(microsecond=0) 
    499502        if lookup_type == 'range': 
    500503            value = [str(v) for v in value] 
    501504        else: 
     
    754757        if value is not None: 
    755758            # MySQL will throw a warning if microseconds are given, because it 
    756759            # doesn't support microseconds. 
    757             if settings.DATABASE_ENGINE == 'mysql'
     760            if settings.DATABASE_ENGINE == 'mysql' or settings.DATABASE_ENGINE == 'ado_mssql'
    758761                value = value.replace(microsecond=0) 
    759762            value = str(value) 
    760763        return Field.get_db_prep_save(self, value) 
  • django/db/backends/ado_mssql/base.py

    old new  
    33 
    44Requires adodbapi 2.0.1: http://adodbapi.sourceforge.net/ 
    55""" 
     6import pythoncom 
    67 
    78from django.db.backends import util 
    89try: 
     
    6970                settings.DATABASE_HOST = "127.0.0.1" 
    7071            # TODO: Handle DATABASE_PORT. 
    7172            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) 
    72             self.connection = Database.connect(conn_string) 
    73         cursor = self.connection.cursor() 
     73            pythoncom.CoInitialize() 
     74            self.connection = Database.connect(conn_string) 
     75            pythoncom.CoUninitialize() 
     76         
     77        cursor = Cursor(self.connection)  
    7478        if settings.DEBUG: 
    7579            return util.CursorDebugWrapper(cursor, self) 
    7680        return cursor 
     
    115119    if lookup_type=='day': 
    116120        return "Convert(datetime, Convert(varchar(12), %s))" % field_name 
    117121 
    118 def get_limit_offset_sql(limit, offset=None): 
    119     # TODO: This is a guess. Make sure this is correct. 
    120     sql = "LIMIT %s" % limit 
    121     if offset and offset != 0: 
    122         sql += " OFFSET %s" % offset 
    123     return sql 
     122def get_limit_offset_sql(limit, offset=None): 
     123    # TODO: This is a guess. Make sure this is correct. 
     124    # should be "SELECT TOP %s" % limit  
     125    # not LIMIT at the end  
     126    return ""  
     127    #sql = "LIMIT %s" % limit  
     128    #if offset and offset != 0:  
     129    #    sql += " OFFSET %s" % offset  
     130    #return sql  
    124131 
    125132def get_random_function_sql(): 
    126133    return "RAND()" 
  • django/db/backends/ado_mssql/introspection.py

    old new  
    1 def get_table_list(cursor): 
    2     raise NotImplementedError 
     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 
     5def get_table_list(cursor): 
     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()] 
     15 
     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] 
    319 
    4 def get_table_description(cursor, table_name): 
    5     raise NotImplementedError 
     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))]) 
    649 
    7 def get_relations(cursor, table_name): 
    8     raise NotImplementedError 
    9  
    10 def get_indexes(cursor, table_name): 
    11     raise NotImplementedError 
    12  
    13 DATA_TYPES_REVERSE = {} 
     50def get_relations(cursor, table_name): 
     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     
     75def get_indexes(cursor, table_name): 
     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 
     102 
     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 
     
    1516            # If params was a list, convert it to a tuple, because string 
    1617            # formatting with '%' only works with tuples or dicts. 
    1718            if not isinstance(params, (tuple, dict)): 
    18                 params = tuple(params) 
     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))) 
    1936            self.db.queries.append({ 
    20                 'sql': sql % tuple(params)
     37                'sql': sql
    2138                'time': "%.3f" % (stop - start), 
    2239            }) 
    2340 
  • django/contrib/sessions/middleware.py

    old new  
    5151            if self.session_key is None: 
    5252                self._session_cache = {} 
    5353            else: 
    54                 try: 
    55                     s = Session.objects.get(session_key=self.session_key, 
    56                         expire_date__gt=datetime.datetime.now()) 
     54                try: 
     55                    datenow = datetime.datetime.now() 
     56                    if hasattr(datenow, 'microsecond'): 
     57                        datenow = datenow.replace(microsecond=0) 
     58                    s = Session.objects.get(session_key=self.session_key, 
     59                        expire_date__gt=datenow) 
    5760                    self._session_cache = s.get_decoded() 
    5861                except Session.DoesNotExist: 
    5962                    self._session_cache = {}