2 ADO MSSQL database backend for Django.
4 Requires adodbapi 2.0.1: http://adodbapi.sourceforge.net/
7 from django
.db
.backends
import util
9 import adodbapi
as Database
10 except ImportError, e
:
11 from django
.core
.exceptions
import ImproperlyConfigured
12 raise ImproperlyConfigured
, "Error loading adodbapi module: %s" % e
19 DatabaseError
= Database
.DatabaseError
21 # We need to use a special Cursor class because adodbapi expects question-mark
22 # param style, but Django expects "%s". This cursor converts question marks to
23 # format-string style.
24 class Cursor(Database
.Cursor
):
25 def executeHelper(self
, operation
, isStoredProcedureCall
, parameters
=None):
26 if parameters
is not None and "%s" in operation
:
27 operation
= operation
.replace("%s", "?")
28 Database
.Cursor
.executeHelper(self
, operation
, isStoredProcedureCall
, parameters
)
30 class Connection(Database
.Connection
):
33 Database
.Connection
= Connection
35 origCVtoP
= Database
.convertVariantToPython
36 def variantToPython(variant
, adType
):
37 if type(variant
) == bool and adType
== 11:
38 return variant
# bool not 1/0
39 res
= origCVtoP(variant
, adType
)
40 if mx
is not None and type(res
) == mx
.DateTime
.mxDateTime
.DateTimeType
:
41 # Convert ms.DateTime objects to Python datetime.datetime objects.
42 tv
= list(res
.tuple()[:7])
44 return datetime
.datetime(*tuple(tv
))
45 if type(res
) == float and str(res
)[-2:] == ".0":
46 return int(res
) # If float but int, then int.
48 Database
.convertVariantToPython
= variantToPython
51 # Only exists in Python 2.4+
52 from threading
import local
54 # Import copy of _thread_local.py from Python 2.4
55 from django
.utils
._threading
_local
import local
57 class DatabaseWrapper(local
):
58 def __init__(self
, **kwargs
):
59 self
.connection
= None
63 from django
.conf
import settings
64 if self
.connection
is None:
65 if settings
.DATABASE_NAME
== '' or settings
.DATABASE_USER
== '':
66 from django
.core
.exceptions
import ImproperlyConfigured
67 raise ImproperlyConfigured
, "You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file."
68 if not settings
.DATABASE_HOST
:
69 settings
.DATABASE_HOST
= "127.0.0.1"
70 # TODO: Handle DATABASE_PORT.
71 conn_string
= "PROVIDER=SQLOLEDB;DATA SOURCE=%s;UID=%s;PWD=%s;DATABASE=%s" % (settings
.DATABASE_HOST
, settings
.DATABASE_USER
, settings
.DATABASE_PASSWORD
, settings
.DATABASE_NAME
)
72 self
.connection
= Database
.connect(conn_string
)
73 cursor
= self
.connection
.cursor()
75 return util
.CursorDebugWrapper(cursor
, self
)
79 if self
.connection
is not None:
80 return self
.connection
.commit()
83 if self
.connection
is not None:
84 return self
.connection
.rollback()
87 if self
.connection
is not None:
88 self
.connection
.close()
89 self
.connection
= None
91 supports_constraints
= True
94 if name
.startswith('[') and name
.endswith(']'):
95 return name
# Quoting once is enough.
98 dictfetchone
= util
.dictfetchone
99 dictfetchmany
= util
.dictfetchmany
100 dictfetchall
= util
.dictfetchall
102 def get_last_insert_id(cursor
, table_name
, pk_name
):
103 cursor
.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name
, table_name
, pk_name
))
104 return cursor
.fetchone()[0]
106 def get_date_extract_sql(lookup_type
, table_name
):
107 # lookup_type is 'year', 'month', 'day'
108 return "DATEPART(%s, %s)" % (lookup_type
, table_name
)
110 def get_date_trunc_sql(lookup_type
, field_name
):
111 # lookup_type is 'year', 'month', 'day'
112 if lookup_type
=='year':
113 return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name
114 if lookup_type
=='month':
115 return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name
, field_name
)
116 if lookup_type
=='day':
117 return "Convert(datetime, Convert(varchar(12), %s))" % field_name
119 def get_limit_offset_sql(limit
, offset
=None):
120 # TODO: This is a guess. Make sure this is correct.
121 sql
= "LIMIT %s" % limit
122 if offset
and offset
!= 0:
123 sql
+= " OFFSET %s" % offset
126 def get_random_function_sql():
129 def get_deferrable_sql():
130 return " DEFERRABLE INITIALLY DEFERRED"
132 def get_fulltext_search_sql(field_name
):
133 raise NotImplementedError
135 def get_drop_foreignkey_sql():
136 return "DROP CONSTRAINT"
138 def get_pk_default_value():
141 def get_sql_flush(sql_styler
, full_table_list
):
142 """Return a list of SQL statements required to remove all data from
143 all tables in the database (without actually removing the tables
144 themselves) and put the database in an empty 'initial' state
146 # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
147 # TODO - SQL not actually tested against ADO MSSQL yet!
148 # TODO - autoincrement indices reset required? See other get_sql_flush() implementations
149 sql_list
= ['%s %s;' % \
150 (sql_styler
.SQL_KEYWORD('TRUNCATE'),
151 sql_styler
.SQL_FIELD(quote_name(table
))
152 ) for table
in full_table_list
]
157 'contains': 'LIKE %s',
158 'icontains': 'LIKE %s',
163 'startswith': 'LIKE %s',
164 'endswith': 'LIKE %s',
165 'istartswith': 'LIKE %s',
166 'iendswith': 'LIKE %s',