Django

Code

Ticket #5062: NewMSSQL.2.diff

File NewMSSQL.2.diff, 63.9 kB (added by mamcx , 1 year ago)

New diff with limit/offset emulation

  • contrib/sessions/middleware.py

    old new  
    5959                self._session_cache = {} 
    6060            else: 
    6161                try: 
     62                    datenow = datetime.datetime.now() 
     63                    if hasattr(datenow, 'microsecond'): 
     64                        datenow = datenow.replace(microsecond=0) 
    6265                    s = Session.objects.get(session_key=self.session_key, 
    63                         expire_date__gt=datetime.datetime.now()
     66                        expire_date__gt=datenow
    6467                    self._session_cache = s.get_decoded() 
    6568                except (Session.DoesNotExist, SuspiciousOperation): 
    6669                    self._session_cache = {} 
  • 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""" 
     6if __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 
     18import datetime 
     19from django.db.backends import util 
     20from django.core.exceptions import ImproperlyConfigured 
     21from django.utils.datastructures import SortedDict 
     22 
     23try: 
     24    import pymssql as Database 
     25except ImportError, e: 
     26    raise ImproperlyConfigured, "Error loading pymssql module: %s" % e 
     27 
     28try: 
     29    import mx 
     30except ImportError: 
     31    mx = None 
     32 
     33try: 
     34    # Only exists in Python 2.4+ 
     35    from threading import local 
     36except ImportError: 
     37    # Import copy of _thread_local.py from Python 2.4 
     38    from django.utils._threading_local import local 
     39 
     40DatabaseError = Database.DatabaseError 
     41IntegrityError = Database.IntegrityError 
     42 
     43#Configure support options: 
     44allows_group_by_ordinal = True 
     45allows_unique_and_pk = True 
     46autoindexes_primary_keys = True 
     47needs_datetime_string_cast = True 
     48needs_upper_for_iops = False 
     49supports_constraints = True 
     50supports_tablespaces = False 
     51uses_case_insensitive_names = False 
     52 
     53def complain(*args, **kwargs): 
     54    raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet." 
     55 
     56def ignore(*args, **kwargs): 
     57    pass 
     58 
     59class DatabaseError(Exception): 
     60    pass 
     61 
     62class IntegrityError(DatabaseError): 
     63    pass 
     64 
     65class 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''' 
     108def version(): 
     109    cur = DatabaseWrapper().cursor() 
     110    cur.execute("SELECT SERVERPROPERTY('ProductVersion')") 
     111     
     112    return int(cur.fetchone()[0].split('.')[0]) 
     113 
     114def quote_name(name): 
     115    if name.startswith('[') and name.endswith(']'): 
     116        return name # Quoting once is enough. 
     117    return '[%s]' % name 
     118 
     119dictfetchone = util.dictfetchone 
     120dictfetchmany = util.dictfetchmany 
     121dictfetchall  = util.dictfetchall 
     122 
     123def 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 
     127def 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 
     131def 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 
     140def get_datetime_cast_sql(): 
     141    return None 
     142 
     143def 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 
     148def get_random_function_sql(): 
     149    return "RAND()" 
     150 
     151def 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 
     159def get_fulltext_search_sql(field_name): 
     160    raise NotImplementedError 
     161 
     162def get_drop_foreignkey_sql(): 
     163    return "DROP CONSTRAINT" 
     164 
     165def get_pk_default_value(): 
     166    return "DEFAULT" 
     167 
     168def get_max_name_length(): 
     169    return None 
     170 
     171def get_start_transaction_sql(): 
     172    return "BEGIN;" 
     173 
     174def get_tablespace_sql(tablespace, inline=False): 
     175    return "ON %s" % quote_name(tablespace) 
     176 
     177def get_autoinc_sql(table): 
     178    return None 
     179 
     180def 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 
     205def 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 
     210def get_trigger_name(table): 
     211    return '%s_TR' % table.upper() 
     212 
     213def 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""" 
     416SELECT * 
     417FROM ( 
     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""" 
     433SELECT * 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 
     440ORDER 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 
     484OPERATOR_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 
     499if __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 
  • 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/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(%(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

    old new  
     1""" 
     2Alpha Multi-plataform MSSQL database backend for Django. 
     3 
     4Requires pymssql >= v0.8.0: http://pymssql.sourceforge.net/ 
     5""" 
     6if __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 
     18import datetime 
     19from django.db.backends import util 
     20from django.core.exceptions import ImproperlyConfigured 
     21from django.utils.datastructures import SortedDict 
     22 
     23try: 
     24    import pymssql as Database 
     25except ImportError, e: 
     26    raise ImproperlyConfigured, "Error loading pymssql module: %s" % e 
     27 
     28try: 
     29    import mx 
     30except ImportError: 
     31    mx = None 
     32 
     33try: 
     34    # Only exists in Python 2.4+ 
     35    from threading import local 
     36except ImportError: 
     37    # Import copy of _thread_local.py from Python 2.4 
     38    from django.utils._threading_local import local 
     39 
     40DatabaseError = Database.DatabaseError 
     41IntegrityError = Database.IntegrityError 
     42 
     43#Configure support options: 
     44allows_group_by_ordinal = True 
     45allows_unique_and_pk = True 
     46autoindexes_primary_keys = True 
     47needs_datetime_string_cast = True 
     48needs_upper_for_iops = False 
     49supports_constraints = True 
     50supports_tablespaces = False 
     51uses_case_insensitive_names = False 
     52 
     53def complain(*args, **kwargs): 
     54    raise ImproperlyConfigured, "You haven't set the DATABASE_ENGINE setting yet." 
     55 
     56def ignore(*args, **kwargs): 
     57    pass 
     58 
     59class DatabaseError(Exception): 
     60    pass 
     61 
     62class IntegrityError(DatabaseError): 
     63    pass 
     64 
     65class 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''' 
     108def version(): 
     109    cur = DatabaseWrapper().cursor() 
     110    cur.execute("SELECT SERVERPROPERTY('ProductVersion')") 
     111     
     112    return int(cur.fetchone()[0].split('.')[0]) 
     113 
     114def quote_name(name): 
     115    if name.startswith('[') and name.endswith(']'): 
     116        return name # Quoting once is enough. 
     117    return '[%s]' % name 
     118 
     119dictfetchone = util.dictfetchone 
     120dictfetchmany = util.dictfetchmany 
     121dictfetchall  = util.dictfetchall 
     122 
     123def 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 
     127def 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 
     131def 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 
     140def get_datetime_cast_sql(): 
     141    return None 
     142 
     143def 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 
     148def get_random_function_sql(): 
     149    return "RAND()" 
     150 
     151def 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 
     159def get_fulltext_search_sql(field_name): 
     160    raise NotImplementedError 
     161 
     162def get_drop_foreignkey_sql(): 
     163    return "DROP CONSTRAINT" 
     164 
     165def get_pk_default_value(): 
     166    return "DEFAULT" 
     167 
     168def get_max_name_length(): 
     169    return None 
     170 
     171def get_start_transaction_sql(): 
     172    return "BEGIN;" 
     173 
     174def get_tablespace_sql(tablespace, inline=False): 
     175    return "ON %s" % quote_name(tablespace) 
     176 
     177def get_autoinc_sql(table): 
     178    return None 
     179 
     180def 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 
     205def 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 
     210def get_trigger_name(table): 
     211    return '%s_TR' % table.upper() 
     212 
     213def 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(DefaultQueryS