Django

Code

Ticket #5062: mssql.r5986-2.diff

File mssql.r5986-2.diff, 32.9 kB (added by gregoire@audacy.fr, 11 months ago)

fixes in db/models/base.py for quote_name() and working implementation of sql_flush

  • db/models/base.py

    old new  
    246246                    (qn(self._meta.db_table), qn(self._meta.order_with_respect_to.column))) 
    247247                db_values.append(getattr(self, self._meta.order_with_respect_to.attname)) 
    248248            if db_values: 
     249                if pk_set and (settings.DATABASE_ENGINE=="ado_mssql" or settings.DATABASE_ENGINE=="mssql"): 
     250                    # You can't insert an auto value into a column unless you do 
     251                    # this in MSSQL 
     252                    # TODO: Only works for auto-id's... how chek it properly? 
     253                    if self._meta.pk.column == 'id': 
     254                        cursor.execute("SET IDENTITY_INSERT %s ON" % \ 
     255                            qn(self._meta.db_table)) 
     256                     
    249257                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \ 
    250258                    (qn(self._meta.db_table), ','.join(field_names), 
    251259                    ','.join(placeholders)), db_values) 
     260                     
     261                if pk_set and (settings.DATABASE_ENGINE=="ado_mssql" or settings.DATABASE_ENGINE=="mssql"): 
     262                    if self._meta.pk.column == 'id': 
     263                        cursor.execute("SET IDENTITY_INSERT %s OFF" %\ 
     264                            qn(self._meta.db_table)) 
    252265            else: 
    253266                # Create a new record with defaults for everything. 
    254267                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % 
  • db/models/fields/__init__.py

    old new  
    223223                value = int(value) 
    224224            except ValueError: 
    225225                raise ValueError("The __year lookup type requires an integer argument") 
    226             return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.999999' % value] 
     226            return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.99' % value] 
    227227        raise TypeError("Field has invalid lookup: %s" % lookup_type) 
    228228 
    229229    def has_default(self): 
     
    574574        if value is not None: 
    575575            # MySQL will throw a warning if microseconds are given, because it 
    576576            # doesn't support microseconds. 
    577             if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'): 
     577            if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') and hasattr(value, 'microsecond'): 
    578578                value = value.replace(microsecond=0) 
    579579            value = smart_unicode(value) 
    580580        return Field.get_db_prep_save(self, value) 
    581581 
    582582    def get_db_prep_lookup(self, lookup_type, value): 
     583        # MSSQL doesn't like microseconds. 
     584        if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') and hasattr(value, 'microsecond'): 
     585            value = value.replace(microsecond=0)         
    583586        if lookup_type == 'range': 
    584587            value = [smart_unicode(v) for v in value] 
    585588        else: 
     
    966969        # Casts dates into string format for entry into database. 
    967970        if value is not None: 
    968971            # MySQL will throw a warning if microseconds are given, because it 
    969             # doesn't support microseconds. 
    970             if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'): 
     972            # doesn't support microseconds. Ditto MSSQL 
     973            if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') \ 
     974                            and hasattr(value, 'microsecond'): 
    971975                value = value.replace(microsecond=0) 
    972976            if settings.DATABASE_ENGINE == 'oracle': 
    973977                # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field. 
  • db/backends/mssql/base.py

    old new  
     1""" 
     2Alpha Multi-plataform MSSQL database backend for Django. 
     3 
     4Requires pymssql >= v0.8.0: http://pymssql.sourceforge.net/ 
     5""" 
     6 
     7import datetime 
     8from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util 
     9from django.core.exceptions import ImproperlyConfigured 
     10from django.utils.datastructures import SortedDict 
     11 
     12try: 
     13    import pymssql as Database 
     14except ImportError, e: 
     15    raise ImproperlyConfigured("Error loading pymssql module: %s" % e) 
     16 
     17try: 
     18    import mx 
     19except ImportError: 
     20    mx = None 
     21 
     22try: 
     23    # Only exists in Python 2.4+ 
     24    from threading import local 
     25except ImportError: 
     26    # Import copy of _thread_local.py from Python 2.4 
     27    from django.utils._threading_local import local 
     28 
     29DatabaseError = Database.DatabaseError 
     30IntegrityError = Database.IntegrityError 
     31 
     32class DatabaseFeatures(BaseDatabaseFeatures): 
     33        pass 
     34 
     35class DatabaseOperations(BaseDatabaseOperations): 
     36    def last_insert_id(self, cursor, table_name, pk_name): 
     37            cursor.execute("SELECT %s FROM %s WHERE %s = IDENT_CURRENT('%s')" % (pk_name, table_name, pk_name,table_name))  
     38            return cursor.fetchone()[0] 
     39            
     40    def query_set_class(self, DefaultQuerySet): 
     41            "Create a custom QuerySet class for SqlServer." 
     42         
     43            from django.db import connection 
     44            from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE, quote_only_if_word 
     45         
     46            class SqlServerQuerySet(DefaultQuerySet): 
     47         
     48                def iterator(self): 
     49                    "Performs the SELECT database lookup of this QuerySet." 
     50         
     51                    from django.db.models.query import get_cached_row 
     52         
     53                    # self._select is a dictionary, and dictionaries' key order is 
     54                    # undefined, so we convert it to a list of tuples. 
     55                    extra_select = self._select.items() 
     56         
     57                    full_query = None 
     58         
     59                    try: 
     60                        try: 
     61                            select, sql, params, full_query = self._get_sql_clause(get_full_query=True) 
     62                        except TypeError: 
     63                            select, sql, params = self._get_sql_clause() 
     64                    except EmptyResultSet: 
     65                        raise StopIteration 
     66                    if not full_query: 
     67                        full_query = "SELECT %s%s\n%s" % \ 
     68                                     ((self._distinct and "DISTINCT " or ""), 
     69                                      ', '.join(select), sql) 
     70         
     71                    cursor = connection.cursor() 
     72                    cursor.execute(full_query, params) 
     73         
     74                    fill_cache = self._select_related 
     75                    fields = self.model._meta.fields 
     76                    index_end = len(fields) 
     77         
     78                    # so here's the logic; 
     79                    # 1. retrieve each row in turn 
     80                    # 2. convert NCLOBs 
     81         
     82                    while 1: 
     83                        rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 
     84                        if not rows: 
     85                            raise StopIteration 
     86                        for row in rows: 
     87                            row = self.resolve_columns(row, fields) 
     88                            if fill_cache: 
     89                                obj, index_end = get_cached_row(klass=self.model, row=row, 
     90                                                                index_start=0, max_depth=self._max_related_depth) 
     91                            else: 
     92                                obj = self.model(*row[:index_end]) 
     93                            for i, k in enumerate(extra_select): 
     94                                setattr(obj, k[0], row[index_end+i]) 
     95                            yield obj 
     96         
     97         
     98                def _get_sql_clause(self, get_full_query=False): 
     99                    from django.db.models.query import fill_table_cache, \ 
     100                        handle_legacy_orderlist, orderfield2column 
     101         
     102                    opts = self.model._meta 
     103                    qn = connection.ops.quote_name 
     104         
     105                    # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. 
     106                    select = ["%s.%s" % (qn(opts.db_table), qn(f.column)) for f in opts.fields] 
     107                    tables = [quote_only_if_word(t) for t in self._tables] 
     108                    joins = SortedDict() 
     109                    where = self._where[:] 
     110                    params = self._params[:] 
     111         
     112                    # Convert self._filters into SQL. 
     113                    joins2, where2, params2 = self._filters.get_sql(opts) 
     114                    joins.update(joins2) 
     115                    where.extend(where2) 
     116                    params.extend(params2) 
     117         
     118                    # Add additional tables and WHERE clauses based on select_related. 
     119                    if self._select_related: 
     120                        fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table]) 
     121         
     122                    # Add any additional SELECTs. 
     123                    if self._select: 
     124                        select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in self._select.items()]) 
     125         
     126                    # Start composing the body of the SQL statement. 
     127                    sql = [" FROM", qn(opts.db_table)] 
     128         
     129                    # Compose the join dictionary into SQL describing the joins. 
     130                    if joins: 
     131                        sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition) 
     132                                        for (alias, (table, join_type, condition)) in joins.items()])) 
     133         
     134                    # Compose the tables clause into SQL. 
     135                    if tables: 
     136                        sql.append(", " + ", ".join(tables)) 
     137         
     138                    # Compose the where clause into SQL. 
     139                    if where: 
     140                        sql.append(where and "WHERE " + " AND ".join(where)) 
     141                     
     142                    #copy a version suitable for LIMIT 
     143                    sql2=[] 
     144                    [sql2.append(x) for x in sql]             
     145                    # ORDER BY clause 
     146                    order_by = [] 
     147                    if self._order_by is not None: 
     148                        ordering_to_use = self._order_by 
     149                    else: 
     150                        ordering_to_use = opts.ordering 
     151                    for f in handle_legacy_orderlist(ordering_to_use): 
     152                        if f == '?': # Special case. 
     153                            order_by.append(connection.ops.get_random_function_sql()) 
     154                        else: 
     155                            if f.startswith('-'): 
     156                                col_name = f[1:] 
     157                                order = "DESC" 
     158                            else: 
     159                                col_name = f 
     160                                order = "ASC" 
     161                            if "." in col_name: 
     162                                table_prefix, col_name = col_name.split('.', 1) 
     163                                table_prefix = qn(table_prefix) + '.' 
     164                            else: 
     165                                # Use the database table as a column prefix if it wasn't given, 
     166                                # and if the requested column isn't a custom SELECT. 
     167                                if "." not in col_name and col_name not in (self._select or ()): 
     168                                    table_prefix = qn(opts.db_table) + '.' 
     169                                else: 
     170                                    table_prefix = '' 
     171                            order_by.append('%s%s %s' % (table_prefix, qn(orderfield2column(col_name, opts)), order)) 
     172                    if order_by: 
     173                        sql.append("ORDER BY " + ", ".join(order_by)) 
     174         
     175                    # Look for column name collisions in the select elements 
     176                    # and fix them with an AS alias.  This allows us to do a 
     177                    # SELECT * later in the paging query. 
     178                    cols = [clause.split('.')[-1] for clause in select] 
     179                    for index, col in enumerate(cols): 
     180                        if cols.count(col) > 1: 
     181                            col = '%s%d' % (col.replace('[', '').replace(']',''), index) 
     182                            cols[index] = qn(col) 
     183                            select[index] = '%s AS %s' % (select[index], qn(col)) 
     184         
     185                    # LIMIT and OFFSET clauses 
     186                    # To support limits and offsets, SqlServer requires some funky rewriting of an otherwise normal looking query. 
     187                    select_clause = ",".join(select) 
     188                    distinct = (self._distinct and "DISTINCT " or "")             
     189                    full_query = None 
     190                     
     191                    if self._limit is None: 
     192                        assert self._offset is None, "'offset' is not allowed without 'limit'" 
     193         
     194                    if self._offset is not None: 
     195                        offset = int(self._offset) 
     196                    else: 
     197                        offset = 0 
     198         
     199                    if self._limit is not None: 
     200                        limit = int(self._limit) 
     201                    else: 
     202                        limit = None 
     203                     
     204                    limit_and_offset_clause = '' 
     205         
     206                    if limit is not None: 
     207                        limit_and_offset_clause = True 
     208                    elif offset: 
     209                        limit_and_offset_clause = True 
     210                     
     211                    if limit_and_offset_clause: 
     212                        #Django give: 
     213                        # Offset : Start row 
     214                        # Limit : How much aditional rows fetch 
     215                         
     216                        # This must be transformed to Sql2005 to: 
     217                        # Offset : First Row 
     218                        # Limit : EndRow 
     219                        StartRow = offset + 1 
     220                        EndRow = StartRow + limit - 1 
     221                        # and for Sql2000 
     222                        # Offset : Top rows 
     223                        # Limit: From where 
     224                        limit = limit + offset 
     225                        if offset==0: 
     226                            offset = limit 
     227                        else: 
     228                            offset = offset + 1 
     229                        #Must use a order. If not specified, use Id. 
     230                        if len(order_by)==0: 
     231                            order_by.append('%s.%s ASC' % 
     232                                (qn(opts.db_table), 
     233                                qn(opts.fields[0].db_column or opts.fields[0].column) 
     234                                ) 
     235                            ) 
     236         
     237                        order_by_clause = ", ".join(order_by) 
     238                        order_by_clauseReverse = "" 
     239         
     240                        #For Sql2005+ use native implementation... 
     241                        if version()>8: 
     242                            fmt = \ 
     243""" 
     244SELECT * 
     245FROM ( 
     246    SELECT %(distinc)s TOP %(EndRow)s 
     247        %(fields)s, ROW_NUMBER() 
     248        OVER( 
     249            ORDER BY  %(orderby)s 
     250        ) AS row 
     251    %(sql)s ORDER BY %(orderby)s 
     252    ) AS x 
     253    WHERE x.row BETWEEN %(StartRow)s AND %(EndRow)s 
     254""" 
     255                        else:     
     256                            #Is necesary reverse all the second order by for the trick to work... 
     257                            order_by_clauseReverse= ", ".join(self.change_order_direction(order_by)) 
     258                             
     259                            fmt = \ 
     260""" 
     261SELECT * FROM ( 
     262  SELECT TOP %(offset)s * FROM ( 
     263    SELECT TOP %(limit)s %(distinc)s%(fields)s 
     264        %(sql)s     
     265    ORDER BY %(orderby)s 
     266  ) AS %(table)s 
     267  ORDER BY %(orderbyReverse)s) AS %(table)s 
     268ORDER BY %(orderby)s 
     269""" 
     270         
     271                        full_query = fmt % {'distinc':distinct, 'fields':select_clause, 
     272                                                'sql':" ".join(sql2),'orderby':order_by_clause, 
     273                                                'orderbyReverse':order_by_clauseReverse, 
     274                                                'table':qn(opts.db_table), 
     275                                                'offset':offset,'limit':limit, 
     276                                                'StartRow':StartRow,'EndRow':EndRow} 
     277                     
     278                    print full_query 
     279                    if get_full_query: 
     280                        return select, " ".join(sql), params, full_query 
     281                    else: 
     282                        return select, " ".join(sql), params 
     283         
     284         
     285                def change_order_direction(self,order_by): 
     286                    newOrder=[] 
     287                     
     288                    for order in order_by: 
     289                        if order.find(' ASC'): 
     290                            newOrder.append(order.replace(' ASC',' DESC')) 
     291                        else: 
     292                            newOrder.append(order.replace(' DESC',' ASC')) 
     293                     
     294                    return newOrder 
     295         
     296                def resolve_columns(self, row, fields=()): 
     297                    from django.db.models.fields import DateField, DateTimeField, \ 
     298                        TimeField, BooleanField, NullBooleanField, DecimalField, Field 
     299                    values = [] 
     300                    for value, field in map(None, row, fields): 
     301                        # Convert 1 or 0 to True or False 
     302                        if value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)): 
     303                            value = bool(value) 
     304                        # Convert floats to decimals 
     305                        elif value is not None and isinstance(field, DecimalField): 
     306                            value = util.typecast_decimal(field.format_number(value)) 
     307                        values.append(value) 
     308                    return values 
     309         
     310            return SqlServerQuerySet 
     311     
     312    def date_extract_sql(self, lookup_type, field_name): 
     313                # lookup_type is 'year', 'month', 'day' 
     314                return "DATEPART(%s, %s)" % (lookup_type, table_name) 
     315 
     316    def date_trunc_sql(self, lookup_type, field_name): 
     317                # lookup_type is 'year', 'month', 'day' 
     318                if lookup_type=='year': 
     319                        return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name 
     320                if lookup_type=='month': 
     321                        return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name) 
     322                if lookup_type=='day': 
     323                        return "Convert(datetime, Convert(varchar(12), %s))" % field_name 
     324 
     325    def limit_offset_sql(self, limit, offset=None): 
     326                # Limits and offset are too complicated to be handled here. 
     327                # Look for a implementation similar to SqlServer backend 
     328                return "" 
     329 
     330    def quote_name(self, name): 
     331        if name.startswith('[') and name.endswith(']'): 
     332                return name # Quoting once is enough. 
     333        return '[%s]' % name 
     334 
     335    def random_function_sql(self): 
     336        return "RAND()" 
     337        
     338    def tablespace_sql(self, tablespace, inline=False): 
     339     return "ON %s" % quote_name(tablespace) 
     340 
     341    def sql_flush(self, style, tables, sequences): 
     342                """Return a list of SQL statements required to remove all data from 
     343                all tables in the database (without actually removing the tables 
     344                themselves) and put the database in an empty 'initial' state 
     345                """ 
     346                # Cannot use TRUNCATE on tables that are referenced by a FOREIGN KEY 
     347                # So must use the much slower DELETE 
     348                from django.db import connection 
     349                cursor = connection.cursor() 
     350                cursor.execute("SELECT TABLE_NAME, CONSTRAINT_NAME FROM information_schema.table_constraints") 
     351                fks = cursor.fetchall() 
     352                sql_list = ['ALTER TABLE %s NOCHECK CONSTRAINT %s;' % \ 
     353                                (self.quote_name(fk[0]), self.quote_name(fk[1])) for fk in fks] 
     354                sql_list.extend(['%s %s %s;' % \ 
     355                                        (style.SQL_KEYWORD('DELETE'), 
     356                                        style.SQL_KEYWORD('FROM'), 
     357                                        style.SQL_FIELD(self.quote_name(table)) 
     358                                        )  for table in tables]) 
     359                #The reset the counters on each table. 
     360                sql_list.extend(['%s %s (%s, %s, %s) %s %s;' % ( 
     361                        style.SQL_KEYWORD('DBCC'), 
     362                        style.SQL_KEYWORD('CHECKIDENT'), 
     363                        style.SQL_FIELD(self.quote_name(seq["table"])), 
     364                        style.SQL_KEYWORD('RESEED'), 
     365                        style.SQL_FIELD('1'), 
     366                        style.SQL_KEYWORD('WITH'), 
     367                        style.SQL_KEYWORD('NO_INFOMSGS'), 
     368                        ) for seq in sequences]) 
     369                sql_list.extend(['ALTER TABLE %s CHECK CONSTRAINT %s;' % \ 
     370                                (self.quote_name(fk[0]), self.quote_name(fk[1])) for fk in fks]) 
     371                return sql_list  
     372 
     373 
     374 
     375def complain(*args, **kwargs): 
     376    raise ImproperlyConfigured("You haven't set the DATABASE_ENGINE setting yet.") 
     377 
     378def ignore(*args, **kwargs): 
     379    pass 
     380 
     381class DatabaseError(Exception): 
     382    pass 
     383 
     384class IntegrityError(DatabaseError): 
     385    pass 
     386 
     387class DatabaseWrapper(BaseDatabaseWrapper): 
     388    features = DatabaseFeatures()  
     389    ops = DatabaseOperations() 
     390    operators = { 
     391            'exact': '= %s', 
     392            'iexact': 'LIKE %s', 
     393            'contains': 'LIKE %s', 
     394            'icontains': 'LIKE %s', 
     395            'gt': '> %s', 
     396            'gte': '>= %s', 
     397            'lt': '< %s', 
     398            'lte': '<= %s', 
     399            'startswith': 'LIKE %s', 
     400            'endswith': 'LIKE %s', 
     401            'istartswith': 'LIKE %s', 
     402            'iendswith': 'LIKE %s', 
     403        } 
     404    def __init__(self, **kwargs): 
     405        self.connection = None 
     406        self.queries = [] 
     407 
     408    def cursor(self): 
     409        from django.conf import settings 
     410        if self.connection is None: 
     411            if settings.DATABASE_NAME == '' or settings.DATABASE_USER == '': 
     412                raise ImproperlyConfigured("You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file.") 
     413            if not settings.DATABASE_HOST: 
     414                settings.DATABASE_HOST = "127.0.0.1" 
     415 
     416            if settings.DATABASE_PORT: 
     417                hostStr = '%s:%s' % ( settings.DATABASE_HOST ,settings.DATABASE_PORT) 
     418            else: 
     419                hostStr = settings.DATABASE_HOST 
     420                                                         
     421            self.connection = Database.connect(host=hostStr,user=settings.DATABASE_USER,password=settings.DATABASE_PASSWORD,database=settings.DATABASE_NAME) 
     422         
     423        self.connection.cursor().execute("SET DATEFORMAT ymd\nGO") 
     424         
     425        cursor = self.connection.cursor() 
     426        if settings.DEBUG: 
     427            return util.CursorDebugWrapper(cursor, self) 
     428        return cursor 
     429 
     430    def _commit(self): 
     431        if self.connection is not None: 
     432            return self.connection.commit() 
     433 
     434    def _rollback(self): 
     435        if self.connection is not None: 
     436            return self.connection.rollback() 
     437 
     438    def close(self): 
     439        if self.connection is not None: 
     440            self.connection.close() 
     441            self.connection = None 
     442 
     443''' 
     444    Return the major version of the server. 7=Sql 7,8=Sql2000,9=Sql2005 
     445''' 
     446def version(): 
     447    cur = DatabaseWrapper().cursor() 
     448    cur.execute("SELECT SERVERPROPERTY('ProductVersion')") 
     449     
     450    return int(cur.fetchone()[0].split('.')[0]) 
     451 
     452 
     453if __name__ == '__main__':  
     454    from mysite.polls.models import Poll, Choice 
     455    from datetime import datetime 
     456     
     457    #Poll.objects.all().delete() 
     458    #i =0 
     459    #for i in range(i,150): 
     460    #    p = Poll(question="%s" % i, pub_date=datetime.now()) 
     461    #    p.save() 
     462 
     463    for poll in Poll.objects.all()[:10]: 
     464        print poll 
  • db/backends/mssql/client.py

    old new  
     1from django.conf import settings 
     2import os 
     3import sys 
     4 
     5def 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/__init__.py

    old new  
  • db/backends/mssql/introspection.py

    old new  
     1def 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 
     6def _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 
     10def 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 
     33def _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 
     40def 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     
     65def 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 
     95DATA_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 
     1092   : 'SmallIntegerField',          # SmallInt 
     1103   : 'IntegerField',               # Integer 
     1114   : 'FloatField',                 # Single 
     1125   : 'FloatField',                 # Decimal 
     1136   : 'FloatField',                 # Currency 
     1147   : 'DateField',                  # Date 
     1158   : 'CharField',                  # BSTR 
     11610  : 'IntegerField',               # Error 
     11711  : 'BooleanField',               # Boolean 
     11814  : 'FloatField',                 # Decimal 
     11916  : 'SmallIntegerField',          # TinyInt 
     12017  : 'PositiveSmallIntegerField',  # UnsignedTinyInt 
     12118  : 'PositiveSmallIntegerField',  # UnsignedSmallInt 
     12219  : 'PositiveIntegerField',       # UnsignedInt 
     12320  : 'IntegerField',               # BigInt 
     12464  : 'DateTimeField',              # FileTime 
     12572  : 'CharField',                  # GUID 
     126129 : 'CharField',                  # Char 
     127130 : 'CharField',                  # WChar 
     128131 : 'FloatField',                 # Numeric 
     129133 : 'DateField',                  # DBDate 
     130134 : 'TimeField',                  # DBTime 
     131135 : 'DateTimeField',              # DBTimeStamp 
     132139 : 'FloatField',                 # VarNumeric 
     133200 : 'CharField',                  # VarChar 
     134201 : 'TextField',                  # LongVarChar 
     135202 : 'CharField',                  # VarWChar 
     136203 : 'TextField',                  # LongVarWChar 
     137} 
  • db/backends/mssql/creation.py

    old new  
     1DATA_TYPES = { 
     2    'AutoField':         'int IDENTITY (1, 1)', 
     3    'BooleanField':      'bit', 
     4    'CharField':         'varchar(%(max_length)s)', 
     5    'CommaSeparatedIntegerField': 'varchar(%(max_length)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(%(max_length)s)', 
     23    'SmallIntegerField': 'smallint', 
     24    'TextField':         'text', 
     25    'TimeField':         'datetime', 
     26    'USStateField':      'varchar(2)', 
     27} 
  • db/backends/util.py

    old new  
     1from django.conf import settings 
    12import datetime 
    23import md5 
    34from time import time 
  • contrib/sessions/middleware.py

    old new  
    6161                self._session_cache = {} 
    6262            else: 
    6363                try: 
     64                    datenow = datetime.datetime.now() 
     65                    if hasattr(datenow, 'microsecond'): 
     66                        datenow = datenow.replace(microsecond=0) 
    6467                    s = Session.objects.get(session_key=self.session_key, 
    65                         expire_date__gt=datetime.datetime.now()
     68                        expire_date__gt=datenow
    6669                    self._session_cache = s.get_decoded() 
    6770                except (Session.DoesNotExist, SuspiciousOperation): 
    6871                    self._session_cache = {}