Ticket #5062: NewMSSQL.2.diff

File NewMSSQL.2.diff, 63.9 KB (added by mamcx , 17 years ago)

New diff with limit/offset emulation

  • contrib/sessions/middleware.py

     
    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

     
     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
     511 No newline at end of file
  • db/backends/mssql/client.py

     
     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

     
     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}
     138 No newline at end of file
  • db/backends/mssql/creation.py

     
     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

     
     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
     511 No newline at end of file
  • db/backends/mssql/client.py

     
     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/creation.py

     
     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/introspection.py

     
     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}
     138 No newline at end of file
  • db/backends/util.py

     
     1from django.conf import settings
    12import datetime
    23import md5
    34from time import time
     
    2223            # formatting with '%' only works with tuples or dicts.
    2324            if not isinstance(params, (tuple, dict)):
    2425                params = tuple(params)
     26            # ado_mssql uses '?' for parameter escaping, so all '?'
     27            # must be replaced with the standard '%s' if the parameter
     28            # substitution is going to work.
     29            if settings.DATABASE_ENGINE == 'ado_mssql':
     30                sql = sql.replace('?', '%s')
     31            # There are many situations that will cause the string
     32            # substituion below to fail (e.g. wildcard characters '%'
     33            # in LIKE queries).  Instead of attempting to figure out
     34            # the many variations that can cause an error, the string substition
     35            # will be attempted first; if it fails, then the sql
     36            # and its parameters will be combined into a string similar to
     37            # the one created in the executemany function below.
     38            try:
     39                sql = sql % tuple(params)
     40            except:
     41                sql = '%s SQL: %s' % (sql, str(tuple(params)))
    2542            self.db.queries.append({
    26                 'sql': sql % params,
     43                'sql': sql,
    2744                'time': "%.3f" % (stop - start),
    2845            })
    2946
  • db/models/base.py

     
    239239                    (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column)))
    240240                db_values.append(getattr(self, self._meta.order_with_respect_to.attname))
    241241            if db_values:
     242                if pk_set and (settings.DATABASE_ENGINE=="ado_mssql" or settings.DATABASE_ENGINE=="mssql"):
     243                    # You can't insert an auto value into a column unless you do
     244                    # this in MSSQL
     245                    # TODO: Only works for auto-id's... how chek it properly?
     246                    if self._meta.pk.column == 'id':
     247                        cursor.execute("SET IDENTITY_INSERT %s ON" % \
     248                            backend.quote_name(self._meta.db_table))
     249                   
    242250                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
    243251                    (backend.quote_name(self._meta.db_table), ','.join(field_names),
    244252                    ','.join(placeholders)), db_values)
     253                   
     254                if pk_set and (settings.DATABASE_ENGINE=="ado_mssql" or settings.DATABASE_ENGINE=="mssql"):
     255                    if self._meta.pk.column == 'id':
     256                        cursor.execute("SET IDENTITY_INSERT %s OFF" %\
     257                            backend.quote_name(self._meta.db_table))
    245258            else:
    246259                # Create a new record with defaults for everything.
    247260                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" %
  • db/models/fields/__init__.py

     
    193193                value = int(value)
    194194            except ValueError:
    195195                raise ValueError("The __year lookup type requires an integer argument")
    196             return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.999999' % value]
     196            return ['%s-01-01 00:00:00' % value, '%s-12-31 23:59:59.99' % value]
    197197        raise TypeError("Field has invalid lookup: %s" % lookup_type)
    198198
    199199    def has_default(self):
     
    541541        if value is not None:
    542542            # MySQL will throw a warning if microseconds are given, because it
    543543            # doesn't support microseconds.
    544             if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
     544            if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') and hasattr(value, 'microsecond'):
    545545                value = value.replace(microsecond=0)
    546546            value = str(value)
    547547        return Field.get_db_prep_save(self, value)
    548548
    549549    def get_db_prep_lookup(self, lookup_type, value):
     550        # MSSQL doesn't like microseconds.
     551        if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') and hasattr(value, 'microsecond'):
     552            value = value.replace(microsecond=0)
    550553        if lookup_type == 'range':
    551554            value = [str(v) for v in value]
    552555        else:
     
    908911        # Casts dates into string format for entry into database.
    909912        if value is not None:
    910913            # MySQL will throw a warning if microseconds are given, because it
    911             # doesn't support microseconds.
    912             if settings.DATABASE_ENGINE == 'mysql' and hasattr(value, 'microsecond'):
     914            # doesn't support microseconds. Ditto MSSQL
     915            if settings.DATABASE_ENGINE in ('mysql', 'ado_mssql','mssql') \
     916                            and hasattr(value, 'microsecond'):
    913917                value = value.replace(microsecond=0)
    914918            if settings.DATABASE_ENGINE == 'oracle':
    915919                # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field.
Back to Top