forked from adamlaska/datatracker
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyodbc.py
More file actions
148 lines (126 loc) · 5.26 KB
/
Copy pathpyodbc.py
File metadata and controls
148 lines (126 loc) · 5.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
from django.db import connection
from django.db.models.fields import *
from south.db import generic
class DatabaseOperations(generic.DatabaseOperations):
"""
django-pyodbc (sql_server.pyodbc) implementation of database operations.
"""
backend_name = "pyodbc"
add_column_string = 'ALTER TABLE %s ADD %s;'
alter_string_set_type = 'ALTER COLUMN %(column)s %(type)s'
alter_string_drop_null = 'ALTER COLUMN %(column)s %(type)s NOT NULL'
allows_combined_alters = False
drop_index_string = 'DROP INDEX %(index_name)s ON %(table_name)s'
drop_constraint_string = 'ALTER TABLE %(table_name)s DROP CONSTRAINT %(constraint_name)s'
delete_column_string = 'ALTER TABLE %s DROP COLUMN %s'
def delete_column(self, table_name, name):
qn = connection.ops.quote_name
q_table_name, q_name = (qn(table_name), qn(name))
# Zap the indexes
for ind in self._find_indexes_for_column(table_name,name):
params = {'table_name':q_table_name, 'index_name': ind}
sql = self.drop_index_string % params
self.execute(sql, [])
# Zap the constraints
for const in self._find_constraints_for_column(table_name,name):
params = {'table_name':q_table_name, 'constraint_name': const}
sql = self.drop_constraint_string % params
self.execute(sql, [])
# Finally zap the column itself
self.execute(self.delete_column_string % (q_table_name, q_name), [])
def _find_indexes_for_column(self, table_name, name):
"Find the indexes that apply to a column, needed when deleting"
qn = connection.ops.quote_name
q_table_name, q_name = (qn(table_name), qn(name))
sql = """
SELECT si.name, si.id, sik.colid, sc.name
FROM dbo.sysindexes SI WITH (NOLOCK)
INNER JOIN dbo.sysindexkeys SIK WITH (NOLOCK)
ON SIK.id = Si.id
AND SIK.indid = SI.indid
INNER JOIN dbo.syscolumns SC WITH (NOLOCK)
ON SI.id = SC.id
AND SIK.colid = SC.colid
WHERE SI.indid !=0
AND Si.id = OBJECT_ID('%s')
AND SC.name = '%s'
"""
idx = self.execute(sql % (table_name, name), [])
return [i[0] for i in idx]
def _find_constraints_for_column(self, table_name, name):
"Find the constraints that apply to a column, needed when deleting"
qn = connection.ops.quote_name
q_table_name, q_name = (qn(table_name), qn(name))
sql = """
SELECT
Cons.xtype,
Cons.id,
Cons.[name]
FROM dbo.sysobjects AS Cons WITH(NOLOCK)
INNER JOIN (
SELECT [id], colid, name
FROM dbo.syscolumns WITH(NOLOCK)
WHERE id = OBJECT_ID('%s')
AND name = '%s'
) AS Cols
ON Cons.parent_obj = Cols.id
WHERE Cons.parent_obj = OBJECT_ID('%s')
AND (
(OBJECTPROPERTY(Cons.[id],'IsConstraint') = 1
AND Cons.info = Cols.colid)
OR (OBJECTPROPERTY(Cons.[id],'IsForeignKey') = 1
AND LEFT(Cons.name,%d) = '%s')
)
"""
cons = self.execute(sql % (table_name, name, table_name, len(name), name), [])
return [c[2] for c in cons]
def drop_column_default_sql(self, table_name, name, q_name):
"MSSQL specific drop default, which is a pain"
sql = """
SELECT object_name(cdefault)
FROM syscolumns
WHERE id = object_id('%s')
AND name = '%s'
"""
cons = self.execute(sql % (table_name, name), [])
if cons and cons[0] and cons[0][0]:
return "DROP CONSTRAINT %s" % cons[0][0]
return None
def _fix_field_definition(self, field):
if isinstance(field, BooleanField):
if field.default == True:
field.default = 1
if field.default == False:
field.default = 0
def add_column(self, table_name, name, field, keep_default=True):
self._fix_field_definition(field)
generic.DatabaseOperations.add_column(self, table_name, name, field, keep_default)
def create_table(self, table_name, fields):
# Tweak stuff as needed
for name,f in fields:
self._fix_field_definition(f)
# Run
generic.DatabaseOperations.create_table(self, table_name, fields)
def rename_column(self, table_name, old, new):
"""
Renames the column of 'table_name' from 'old' to 'new'.
WARNING - This isn't transactional on MSSQL!
"""
if old == new:
# No Operation
return
# Examples on the MS site show the table name not being quoted...
qn = connection.ops.quote_name
params = (table_name,qn(old), qn(new))
self.execute("EXEC sp_rename '%s.%s', %s, 'COLUMN'" % params)
def rename_table(self, old_table_name, table_name):
"""
Renames the table 'old_table_name' to 'table_name'.
WARNING - This isn't transactional on MSSQL!
"""
if old_table_name == table_name:
# No Operation
return
qn = connection.ops.quote_name
params = (qn(old_table_name), qn(table_name))
self.execute('EXEC sp_rename %s, %s' % params)