rendered paste body=== django/core/db/backends/mssql.py==================================================================--- django/core/db/backends/mssql.py (revision 8524)+++ django/core/db/backends/mssql.py (revision 8525)@@ -0,0 +1,214 @@+"""+SQL Server database backend for Django.++Requires ADODBAPI: http://adodbapi.sf.net+"""++import re++from django.core.db import base+from django.core.db.dicthelpers import *+import pymssql as Database+from itertools import repeat++DatabaseError = Database.DatabaseError++class CursorWrapper:+ def __init__(self, conn, cursor):+ self._conn = conn+ self._cursor = cursor+ self._limit_re = re.compile(r'(?:LIMIT\s+(\d+))?\s*(?:OFFSET\s+(\d+))?$')+ self.execute('')++ def execute(self, sql, params=None):+ self._conn.queries.append((sql, params))+ sql, offset = self._parse_sql(sql, params)+ result = self._cursor.execute(sql, params)+ if offset:+ self._cursor.fetchmany(offset) # discard offset amount+ return result++ def executemany(self, sql, paramseq):+ self._conn.queries.append((sql, params))+ sql, offset = self._parse_sql(sql, paramseq[0])+ return self._cursor.executemany(sql, paramseq)++ def _parse_sql(self, sql, params):+ limit, offset = self._limit_re.search(sql).groups()+ sql = self._limit_re.sub('', sql)++ if offset:+ offset = int(offset)+ else:+ offset = 0++ if not limit:+ return sql, offset++ limit = int(limit) + offset++ return (' TOP %s ' % limit).join(sql.split(None, 1)), offset++ def __getattr__(self, attr):+ return getattr(self._cursor, attr)+++class DatabaseWrapper:+ def __init__(self):+ self.connection = None+ self.queries = []++ def cursor(self):+ from django.conf.settings import DEBUG+ if DEBUG:+ return base.CursorDebugWrapper(self._cursor(), self)+ return self._cursor()++ def _cursor(self):+ if self.connection is None:+ from django.conf.settings import DATABASE_USER, DATABASE_NAME, \+ DATABASE_HOST, DATABASE_PASSWORD+ self.connection = Database.connect(host=DATABASE_HOST,+ database=DATABASE_NAME,+ user=DATABASE_USER,+ password=DATABASE_PASSWORD)+ return CursorWrapper(self, self.connection.cursor())++ def commit(self):+ self.connection.commit()++ def rollback(self):+ if self.connection is not None:+ self.connection.rollback()++ def close(self):+ if self.connection is not None:+ self.connection.close()+ self.connection = None++ def quote_name(self, name):+ if name.startswith('[') and name.endswith(']'):+ return name # Quoting once is enough.+ return '[%s]' % name++def get_last_insert_id(cursor, table_name, pk_name):+ cursor.execute("SELECT cast(@@IDENTITY AS int)") # or possibly SCOPE_IDENTITY() if necessary+ return cursor.fetchone()[0]++def get_date_extract_sql(lookup_type, table_name):+ # lookup_type is 'year', 'month', 'day'+ return "DATEPART(%s, %s)" % (lookup_type, table_name)++def get_date_trunc_sql(lookup_type, field_name):+ # lookup_type is 'year', 'month', 'day'+ if lookup_type=='year':+ return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name+ if lookup_type=='month':+ return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name)+ if lookup_type=='day':+ return "Convert(datetime, Convert(varchar(12), %s))" % field_name++def get_limit_offset_sql(limit, offset=None):+ sql = "LIMIT %s" % limit+ if offset and offset != 0:+ sql += " OFFSET %s" % offset+ return sql++def get_random_function_sql():+ return 'rand()'++def get_table_list(cursor):+ cursor.execute("select name from sysobjects where type='U'")+ return [row[0] for row in cursor.fetchall()]++def get_table_description(cursor, table_name):+ raise NotImplementedError++def get_relations(cursor, table_name):+ raise NotImplementedError++OPERATOR_MAPPING = {+ 'exact': '= %s',+ 'iexact': 'LIKE %s',+ 'contains': 'LIKE %s',+ 'icontains': 'LIKE %s',+ 'ne': '!= %s',+ 'gt': '> %s',+ 'gte': '>= %s',+ 'lt': '< %s',+ 'lte': '<= %s',+ 'startswith': 'LIKE %s',+ 'endswith': 'LIKE %s',+ 'istartswith': 'LIKE %s',+ 'iendswith': 'LIKE %s',+}++def get_relations(cursor, table_name):+ raise NotImplementedError+ """FIXME: something like below is a start on SQL:+ source:+ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsqlpro03/html/sp03l12.asp++SELECT + KCU1.CONSTRAINT_NAME AS 'FK_CONSTRAINT_NAME'+ , KCU1.TABLE_NAME AS 'FK_TABLE_NAME'+ , KCU1.COLUMN_NAME AS 'FK_COLUMN_NAME'+ , KCU1.ORDINAL_POSITION AS 'FK_ORDINAL_POSITION'+ , KCU2.CONSTRAINT_NAME AS 'UQ_CONSTRAINT_NAME'+ , KCU2.TABLE_NAME AS 'UQ_TABLE_NAME'+ , KCU2.COLUMN_NAME AS 'UQ_COLUMN_NAME'+ , KCU2.ORDINAL_POSITION AS 'UQ_ORDINAL_POSITION'+FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC+JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU1+ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG + AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA+ AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME+JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU2+ON KCU2.CONSTRAINT_CATALOG = +RC.UNIQUE_CONSTRAINT_CATALOG + AND KCU2.CONSTRAINT_SCHEMA = +RC.UNIQUE_CONSTRAINT_SCHEMA+ AND KCU2.CONSTRAINT_NAME = +RC.UNIQUE_CONSTRAINT_NAME+ AND KCU2.ORDINAL_POSITION = KCU1.ORDINAL_POSITION++ """++def quote_name(name):+ # TODO: Figure out how MS-SQL quotes database identifiers.+ return name+ ++# This dictionary maps Field objects to their associated SQL Server column+# types, as strings. Column-type strings can contain format strings; they'll+# be interpolated against the values of Field.__dict__ before being output.+# If a column type is set to None, it won't be included in the output.+DATA_TYPES = {+ 'AutoField': 'int identity',+ 'BooleanField': 'bit',+ 'CharField': 'varchar(%(maxlength)s)',+ 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',+ 'DateField': 'smalldatetime',+ 'DateTimeField': 'smalldatetime',+ 'FileField': 'varchar(100)',+ 'FilePathField': 'varchar(100)',+ 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',+ 'ImageField': 'nvarchar(100)',+ 'IntegerField': 'int',+ 'IPAddressField': 'nchar(15)',+ 'ManyToManyField': None,+ 'NullBooleanField': 'bit',+ 'OneToOneField': 'int',+ 'PhoneNumberField': 'varchar(20)',+ 'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)',+ 'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(column)s] CHECK ([%(column)s] > 0)',+ 'SlugField': 'varchar(50)',+ 'SmallIntegerField': 'smallint',+ 'TextField': 'ntext',+ 'TimeField': 'datetime',+ 'URLField': 'nvarchar(200)',+ 'USStateField': 'nvarchar(2)',+ 'XMLField': 'ntext',+}++DATA_TYPES_REVERSE = { }Property changes on: django/core/db/backends/mssql.py___________________________________________________________________Name: svn:eol-style +native=== django/core/db/backends/ado_mssql.py==================================================================--- django/core/db/backends/ado_mssql.py (revision 8524)+++ django/core/db/backends/ado_mssql.py (revision 8525)@@ -1,80 +1,107 @@ """-ADO MSSQL database backend for Django.+SQL Server database backend for Django. -Requires adodbapi 2.0.1: http://adodbapi.sourceforge.net/+Requires ADODBAPI: http://adodbapi.sf.net """ +import re+import threading+ from django.core.db import base from django.core.db.dicthelpers import * import adodbapi as Database-import datetime-try:- import mx-except ImportError:- mx = None+from itertools import repeat DatabaseError = Database.DatabaseError -# We need to use a special Cursor class because adodbapi expects question-mark-# param style, but Django expects "%s". This cursor converts question marks to-# format-string style.-class Cursor(Database.Cursor):- def executeHelper(self, operation, isStoredProcedureCall, parameters=None):- if parameters is not None and "%s" in operation:- operation = operation.replace("%s", "?")- Database.Cursor.executeHelper(self, operation, isStoredProcedureCall, parameters)+class CursorWrapper:+ def __init__(self, cursor):+ self._cursor = cursor+ self._limit_re = re.compile(r'(?:LIMIT\s+(\d+))?\s*(?:OFFSET\s+(\d+))?$') -class Connection(Database.Connection):- def cursor(self):- return Cursor(self)-Database.Connection = Connection+ def execute(self, sql, params=None):+ sql, offset = self._parse_sql(sql, params)+ result = self._cursor.execute(sql, params)+ if offset:+ self._cursor.fetchmany(offset) # discard offset amount+ return result -origCVtoP = Database.convertVariantToPython-def variantToPython(variant, adType):- if type(variant) == bool and adType == 11:- return variant # bool not 1/0- res = origCVtoP(variant, adType)- if mx is not None and type(res) == mx.DateTime.mxDateTime.DateTimeType:- # Convert ms.DateTime objects to Python datetime.datetime objects.- tv = list(res.tuple()[:7])- tv[-2] = int(tv[-2])- return datetime.datetime(*tuple(tv))- if type(res) == float and str(res)[-2:] == ".0":- return int(res) # If float but int, then int.- return res-Database.convertVariantToPython = variantToPython+ def executemany(self, sql, paramseq):+ sql, offset = self._parse_sql(sql, paramseq[0])+ return self._cursor.executemany(sql, paramseq) + def _parse_sql(self, sql, params):+ sql = sql.replace('%s', '?')+ #if params:+ #sql = sql % tuple(repeat('?', len(params)))++ limit, offset = self._limit_re.search(sql).groups()+ sql = self._limit_re.sub('', sql)++ if offset:+ offset = int(offset)+ else:+ offset = 0++ if not limit:+ return sql, offset++ limit = int(limit) + offset++ return (' TOP %s ' % limit).join(sql.split(None, 1)), offset++ def __getattr__(self, attr):+ return getattr(self._cursor, attr)++def connect(host, database, user, password):+ import pythoncom+ pythoncom.CoInitialize() # Make sure COM is initialized for this thread+ provider = 'sqlncli'+ #provider = 'sqloledb'+ return Database.connect('Provider=%s;Data Source=%s;Initial Catalog=%s;User Id=%s;Password=%s'+ % (provider, host, database, user, password))+ class DatabaseWrapper: def __init__(self):- self.connection = None+ self.local = threading.local() self.queries = [] + def connection():+ def fget(self):+ return getattr(self.local, 'connection', None)+ def fset(self, value):+ self.local.connection = value+ def fdel(self):+ del self.local.connection+ return property(fget, fset, fdel)+ connection = connection()+ def cursor(self):- from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PORT, DATABASE_PASSWORD, DEBUG- if self.connection is None:- if DATABASE_NAME == '' or DATABASE_USER == '':- from django.core.exceptions import ImproperlyConfigured- raise ImproperlyConfigured, "You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file."- if not DATABASE_HOST:- DATABASE_HOST = "127.0.0.1"- # TODO: Handle DATABASE_PORT.- conn_string = "PROVIDER=SQLOLEDB;DATA SOURCE=%s;UID=%s;PWD=%s;DATABASE=%s" % (DATABASE_HOST, DATABASE_USER, DATABASE_PASSWORD, DATABASE_NAME)- self.connection = Database.connect(conn_string)- cursor = self.connection.cursor()+ from django.conf.settings import DEBUG if DEBUG:- return base.CursorDebugWrapper(cursor, self)- return cursor+ return base.CursorDebugWrapper(self._cursor(), self)+ return self._cursor() + def _cursor(self):+ if self.connection is None:+ from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PASSWORD+ self.connection = connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD)+ return CursorWrapper(self.connection.cursor())+ def commit(self):- return self.connection.commit()+ self.connection.commit() def rollback(self):- if self.connection:- return self.connection.rollback()+ if self.connection is not None:+ self.connection.rollback() def close(self): if self.connection is not None:- self.connection.close()+ try:+ self.connection.close()+ except Database.InternalError:+ # ignore connection errors for 'No transaction is active.'+ pass self.connection = None def quote_name(self, name):@@ -83,7 +110,7 @@ return '[%s]' % name def get_last_insert_id(cursor, table_name, pk_name):- cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name))+ cursor.execute("SELECT cast(@@IDENTITY AS int)") # or possibly SCOPE_IDENTITY() if necessary return cursor.fetchone()[0] def get_date_extract_sql(lookup_type, table_name):@@ -100,17 +127,17 @@ return "Convert(datetime, Convert(varchar(12), %s))" % field_name def get_limit_offset_sql(limit, offset=None):- # TODO: This is a guess. Make sure this is correct. sql = "LIMIT %s" % limit if offset and offset != 0: sql += " OFFSET %s" % offset return sql def get_random_function_sql():- return "RAND()"+ return 'rand()' def get_table_list(cursor):- raise NotImplementedError+ cursor.execute("select name from sysobjects where type='U'")+ return [row[0] for row in cursor.fetchall()] def get_table_description(cursor, table_name): raise NotImplementedError@@ -134,8 +161,48 @@ 'iendswith': 'LIKE %s', } +def get_relations(cursor, table_name):+ raise NotImplementedError+ """FIXME: something like below is a start on SQL:+ source:+ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsqlpro03/html/sp03l12.asp++SELECT + KCU1.CONSTRAINT_NAME AS 'FK_CONSTRAINT_NAME'+ , KCU1.TABLE_NAME AS 'FK_TABLE_NAME'+ , KCU1.COLUMN_NAME AS 'FK_COLUMN_NAME'+ , KCU1.ORDINAL_POSITION AS 'FK_ORDINAL_POSITION'+ , KCU2.CONSTRAINT_NAME AS 'UQ_CONSTRAINT_NAME'+ , KCU2.TABLE_NAME AS 'UQ_TABLE_NAME'+ , KCU2.COLUMN_NAME AS 'UQ_COLUMN_NAME'+ , KCU2.ORDINAL_POSITION AS 'UQ_ORDINAL_POSITION'+FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC+JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU1+ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG + AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA+ AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME+JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU2+ON KCU2.CONSTRAINT_CATALOG = +RC.UNIQUE_CONSTRAINT_CATALOG + AND KCU2.CONSTRAINT_SCHEMA = +RC.UNIQUE_CONSTRAINT_SCHEMA+ AND KCU2.CONSTRAINT_NAME = +RC.UNIQUE_CONSTRAINT_NAME+ AND KCU2.ORDINAL_POSITION = KCU1.ORDINAL_POSITION++ """++def quote_name(name):+ # TODO: Figure out how MS-SQL quotes database identifiers.+ return name+ ++# This dictionary maps Field objects to their associated SQL Server column+# types, as strings. Column-type strings can contain format strings; they'll+# be interpolated against the values of Field.__dict__ before being output.+# If a column type is set to None, it won't be included in the output. DATA_TYPES = {- 'AutoField': 'int IDENTITY (1, 1)',+ 'AutoField': 'int identity', 'BooleanField': 'bit', 'CharField': 'varchar(%(maxlength)s)', 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',@@ -144,9 +211,9 @@ 'FileField': 'varchar(100)', 'FilePathField': 'varchar(100)', 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',- 'ImageField': 'varchar(100)',+ 'ImageField': 'nvarchar(100)', 'IntegerField': 'int',- 'IPAddressField': 'char(15)',+ 'IPAddressField': 'nchar(15)', 'ManyToManyField': None, 'NullBooleanField': 'bit', 'OneToOneField': 'int',@@ -155,10 +222,11 @@ 'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(column)s] CHECK ([%(column)s] > 0)', 'SlugField': 'varchar(50)', 'SmallIntegerField': 'smallint',- 'TextField': 'text',- 'TimeField': 'time',- 'URLField': 'varchar(200)',- 'USStateField': 'varchar(2)',+ 'TextField': 'ntext',+ 'TimeField': 'datetime',+ 'URLField': 'nvarchar(200)',+ 'USStateField': 'nvarchar(2)',+ 'XMLField': 'ntext', } -DATA_TYPES_REVERSE = {}+DATA_TYPES_REVERSE = { }=== django/core/meta/__init__.py==================================================================--- django/core/meta/__init__.py (revision 8524)+++ django/core/meta/__init__.py (revision 8525)@@ -1021,6 +1021,8 @@ placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \ (db.db.quote_name(opts.db_table), db.db.quote_name(opts.order_with_respect_to.column))) db_values.append(getattr(self, opts.order_with_respect_to.attname))+ if settings.DATABASE_ENGINE == 'mssql' and opts.has_auto_field and pk_set:+ cursor.execute("SET IDENTITY_INSERT %s ON" % db.db.quote_name(opts.db_table)) cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \ (db.db.quote_name(opts.db_table), ','.join(field_names), ','.join(placeholders)), db_values)@@ -1103,13 +1105,16 @@ val = getattr(self, field_with_rel.attname) mod = field_with_rel.rel.to.get_model_module() if val is None:- raise getattr(mod, '%sDoesNotExist' % field_with_rel.rel.to.object_name)- other_field = field_with_rel.rel.get_related_field()- if other_field.rel:- params = {'%s__%s__exact' % (field_with_rel.rel.field_name, other_field.rel.field_name): val}+ if not field_with_rel.null:+ raise getattr(mod, '%sDoesNotExist' % field_with_rel.rel.to.object_name)+ retrieved_obj = None else:- params = {'%s__exact'% field_with_rel.rel.field_name: val}- retrieved_obj = mod.get_object(**params)+ other_field = field_with_rel.rel.get_related_field()+ if other_field.rel:+ params = {'%s__%s__exact' % (field_with_rel.rel.field_name, other_field.rel.field_name): val}+ else:+ params = {'%s__exact'% field_with_rel.rel.field_name: val}+ retrieved_obj = mod.get_object(**params) setattr(self, cache_var, retrieved_obj) return getattr(self, cache_var)