schema.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. import binascii
  2. import datetime
  3. from logging import getLogger
  4. from django.db.backends.utils import truncate_name
  5. from django.db.models.fields import AutoField
  6. from django.db.models.fields.related import ManyToManyField
  7. from django.db.utils import NotSupportedError
  8. from django.utils import six
  9. from django.utils.text import force_text
  10. from django.db.backends.base.schema import BaseDatabaseSchemaEditor
  11. logger = getLogger('django.db.backends.schema')
  12. def _related_non_m2m_objects(old_field, new_field):
  13. # Filters out m2m objects from reverse relations.
  14. # Returns (old_relation, new_relation) tuples.
  15. return zip(
  16. (obj for obj in old_field.model._meta.related_objects if not obj.field.many_to_many),
  17. (obj for obj in new_field.model._meta.related_objects if not obj.field.many_to_many)
  18. )
  19. class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
  20. sql_rename_table = "sp_rename '%(old_table)s', '%(new_table)s'"
  21. sql_delete_table = "DROP TABLE %(table)s"
  22. sql_create_column = "ALTER TABLE %(table)s ADD %(column)s %(definition)s"
  23. sql_alter_column_type = "ALTER COLUMN %(column)s %(type)s"
  24. sql_alter_column_null = "ALTER COLUMN %(column)s %(type)s NULL"
  25. sql_alter_column_not_null = "ALTER COLUMN %(column)s %(type)s NOT NULL"
  26. sql_alter_column_default = "ADD CONSTRAINT %(constraint_name)s DEFAULT %(default)s FOR %(column)s"
  27. sql_alter_column_no_default = "ALTER COLUMN %(column)s DROP CONSTRAINT %(constraint_name)s"
  28. sql_delete_column = "ALTER TABLE %(table)s DROP COLUMN %(column)s"
  29. sql_rename_column = "sp_rename '%(table)s.%(old_column)s', '%(new_column)s', 'COLUMN'"
  30. sql_create_fk = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s" \
  31. " FOREIGN KEY (%(column)s) REFERENCES %(to_table)s (%(to_column)s)"
  32. sql_delete_index = "DROP INDEX %(name)s ON %(table)s"
  33. _sql_drop_inbound_foreign_keys = '''
  34. DECLARE @sql nvarchar(max)
  35. WHILE 1=1
  36. BEGIN
  37. SELECT TOP 1
  38. @sql = N'ALTER TABLE [' + OBJECT_SCHEMA_NAME(parent_object_id) + N'].[' +
  39. OBJECT_NAME(parent_object_id) +'] DROP CONSTRAINT [' + name + N']'
  40. FROM sys.foreign_keys
  41. WHERE referenced_object_id = object_id(%s)
  42. IF @@ROWCOUNT = 0 BREAK
  43. EXEC (@sql)
  44. END'''
  45. _sql_drop_primary_key = '''
  46. DECLARE @sql nvarchar(max)
  47. WHILE 1=1
  48. BEGIN
  49. SELECT TOP 1
  50. @sql = N'ALTER TABLE [' + CONSTRAINT_SCHEMA + N'].[' + TABLE_NAME +
  51. N'] DROP CONSTRAINT [' + CONSTRAINT_NAME+ N']'
  52. FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
  53. JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu ON tc.CONSTRAINT_NAME = ccu.Constraint_name
  54. WHERE CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME LIKE %s AND COLUMN_NAME = %s
  55. IF @@ROWCOUNT = 0 BREAK
  56. EXEC (@sql)
  57. END'''
  58. # Map provides a concise prefix for constraints of the same type
  59. constraint_type_prefix_map = {
  60. 'UNIQUE': 'UX_',
  61. 'INDEX': 'IX_',
  62. 'DEFAULT': 'DF_',
  63. 'CHECK': 'CK_',
  64. 'PK': 'PK_',
  65. 'FK': 'FK_',
  66. '': '',
  67. }
  68. def _create_constraint_name(self, model, column_names, constraint_type='', suffix=""):
  69. """
  70. Generates a unique name for a constraint.
  71. """
  72. column = '_'.join(column_names) if isinstance(column_names, (list, tuple)) else column_names
  73. name = '%s%s_%s%s' % (
  74. self.constraint_type_prefix_map.get(constraint_type.upper(), ''),
  75. model._meta.db_table,
  76. column,
  77. suffix,
  78. )
  79. return truncate_name(name, length=self.connection.ops.max_name_length(), hash_len=8)
  80. def alter_db_table(self, model, old_db_table, new_db_table):
  81. # sp_rename requires that objects not be quoted because they are string literals
  82. self.execute(self.sql_rename_table % {
  83. "old_table": old_db_table,
  84. "new_table": new_db_table,
  85. })
  86. def delete_model(self, model):
  87. # Drop all inbound FKs before dropping table
  88. self.execute(self._sql_drop_inbound_foreign_keys, [model._meta.db_table])
  89. super(DatabaseSchemaEditor, self).delete_model(model)
  90. def delete_db_column(self, model, column):
  91. # drop all of the column constraints to avoid the database blocking the column removal
  92. with self.connection.cursor() as cursor:
  93. constraints = self.connection.introspection.get_constraints(cursor, model._meta.db_table)
  94. for name, constraint in six.iteritems(constraints):
  95. if column in constraint['columns']:
  96. sql = 'ALTER TABLE %(table)s DROP CONSTRAINT [%(constraint)s]' % {
  97. 'table': model._meta.db_table,
  98. 'constraint': name,
  99. }
  100. cursor.execute(sql)
  101. super(DatabaseSchemaEditor, self).delete_db_column(model, column)
  102. def remove_field(self, model, field):
  103. """
  104. Removes a field from a model. Usually involves deleting a column,
  105. but for M2Ms may involve deleting a table.
  106. """
  107. # Special-case implicit M2M tables
  108. if isinstance(field, ManyToManyField) and field.rel.through._meta.auto_created:
  109. return self.delete_model(field.rel.through)
  110. # It might not actually have a column behind it
  111. if field.db_parameters(connection=self.connection)['type'] is None:
  112. return
  113. # Drop all constraints
  114. constraint_types = [
  115. (self.sql_delete_fk, {'foreign_key': True}),
  116. (self.sql_delete_pk, {'primary_key': True}),
  117. (self.sql_delete_index, {'index': True}),
  118. (self.sql_delete_unique, {'unique': True}),
  119. (self.sql_delete_check, {'check': True}),
  120. ]
  121. for template, kwargs in constraint_types:
  122. names = self._constraint_names(model, [field.column], **kwargs)
  123. for name in names:
  124. self.execute(self._delete_constraint_sql(template, model, name))
  125. # Delete the column
  126. sql = self.sql_delete_column % {
  127. "table": self.quote_name(model._meta.db_table),
  128. "column": self.quote_name(field.column),
  129. }
  130. self.execute(sql)
  131. # Reset connection if required
  132. if self.connection.features.connection_persists_old_columns:
  133. self.connection.close()
  134. def _alter_field(self, model, old_field, new_field, old_type, new_type,
  135. old_db_params, new_db_params, strict=False):
  136. """Actually perform a "physical" (non-ManyToMany) field update."""
  137. # Has changed to AutoField
  138. if not isinstance(old_field, AutoField) and isinstance(new_field, AutoField):
  139. raise NotSupportedError('Cannot alter a non-AutoField to an AutoField')
  140. # Drop any FK constraints, we'll remake them later
  141. fks_dropped = set()
  142. if old_field.rel and old_field.db_constraint:
  143. fk_names = self._constraint_names(model, [old_field.column], foreign_key=True)
  144. if strict and len(fk_names) != 1:
  145. raise ValueError("Found wrong number (%s) of foreign key constraints for %s.%s" % (
  146. len(fk_names),
  147. model._meta.db_table,
  148. old_field.column,
  149. ))
  150. for fk_name in fk_names:
  151. fks_dropped.add((old_field.column,))
  152. self.execute(self._delete_constraint_sql(self.sql_delete_fk, model, fk_name))
  153. # Has unique been removed?
  154. if old_field.unique and (not new_field.unique or (not old_field.primary_key and new_field.primary_key)):
  155. # Find the unique constraint for this field
  156. constraint_names = self._constraint_names(model, [old_field.column], unique=True)
  157. if strict and len(constraint_names) != 1:
  158. raise ValueError("Found wrong number (%s) of unique constraints for %s.%s" % (
  159. len(constraint_names),
  160. model._meta.db_table,
  161. old_field.column,
  162. ))
  163. for constraint_name in constraint_names:
  164. self.execute(self._delete_constraint_sql(self.sql_delete_unique, model, constraint_name))
  165. # Drop incoming FK constraints if we're a primary key and things are going
  166. # to change.
  167. if old_field.primary_key and new_field.primary_key and old_type != new_type:
  168. # '_meta.related_field' also contains M2M reverse fields, these
  169. # will be filtered out
  170. for _old_rel, new_rel in _related_non_m2m_objects(old_field, new_field):
  171. rel_fk_names = self._constraint_names(
  172. new_rel.related_model, [new_rel.field.column], foreign_key=True
  173. )
  174. for fk_name in rel_fk_names:
  175. self.execute(self._delete_constraint_sql(self.sql_delete_fk, new_rel.related_model, fk_name))
  176. # Removed an index? (no strict check, as multiple indexes are possible)
  177. if (old_field.db_index and not new_field.db_index and
  178. not old_field.unique and not
  179. (not new_field.unique and old_field.unique)):
  180. # Find the index for this field
  181. index_names = self._constraint_names(model, [old_field.column], index=True)
  182. for index_name in index_names:
  183. self.execute(self._delete_constraint_sql(self.sql_delete_index, model, index_name))
  184. # Change check constraints?
  185. if old_db_params['check'] != new_db_params['check'] and old_db_params['check']:
  186. constraint_names = self._constraint_names(model, [old_field.column], check=True)
  187. if strict and len(constraint_names) != 1:
  188. raise ValueError("Found wrong number (%s) of check constraints for %s.%s" % (
  189. len(constraint_names),
  190. model._meta.db_table,
  191. old_field.column,
  192. ))
  193. for constraint_name in constraint_names:
  194. self.execute(self._delete_constraint_sql(self.sql_delete_check, model, constraint_name))
  195. # Have they renamed the column?
  196. if old_field.column != new_field.column:
  197. self.execute(self._rename_field_sql(model._meta.db_table, old_field, new_field, new_type))
  198. # Next, start accumulating actions to do
  199. actions = []
  200. null_actions = []
  201. post_actions = []
  202. # Type change?
  203. if old_type != new_type:
  204. fragment, other_actions = self._alter_column_type_sql(
  205. model._meta.db_table, old_field, new_field, new_type
  206. )
  207. actions.append(fragment)
  208. post_actions.extend(other_actions)
  209. # When changing a column NULL constraint to NOT NULL with a given
  210. # default value, we need to perform 4 steps:
  211. # 1. Add a default for new incoming writes
  212. # 2. Update existing NULL rows with new default
  213. # 3. Replace NULL constraint with NOT NULL
  214. # 4. Drop the default again.
  215. # Default change?
  216. old_default = self.effective_default(old_field)
  217. new_default = self.effective_default(new_field)
  218. needs_database_default = (
  219. old_default != new_default and
  220. new_default is not None and
  221. not self.skip_default(new_field)
  222. )
  223. if needs_database_default:
  224. constraint_name = self._create_constraint_name(model, new_field.column, constraint_type='default')
  225. if self.connection.features.requires_literal_defaults:
  226. # Some databases can't take defaults as a parameter (oracle)
  227. # If this is the case, the individual schema backend should
  228. # implement prepare_default
  229. actions.append((
  230. self.sql_alter_column_default % {
  231. "column": self.quote_name(new_field.column),
  232. "default": self.prepare_default(new_default),
  233. "constraint_name": constraint_name,
  234. },
  235. [],
  236. ))
  237. else:
  238. actions.append((
  239. self.sql_alter_column_default % {
  240. "column": self.quote_name(new_field.column),
  241. "default": "%s",
  242. "constraint_name": constraint_name,
  243. },
  244. [new_default],
  245. ))
  246. # Nullability change?
  247. if old_field.null != new_field.null or old_type != new_type:
  248. if (self.connection.features.interprets_empty_strings_as_nulls and
  249. new_field.get_internal_type() in ("CharField", "TextField")):
  250. # The field is nullable in the database anyway, leave it alone
  251. pass
  252. elif new_field.null:
  253. null_actions.append((
  254. self.sql_alter_column_null % {
  255. "column": self.quote_name(new_field.column),
  256. "type": new_type,
  257. },
  258. [],
  259. ))
  260. else:
  261. null_actions.append((
  262. self.sql_alter_column_not_null % {
  263. "column": self.quote_name(new_field.column),
  264. "type": new_type,
  265. },
  266. [],
  267. ))
  268. # Only if we have a default and there is a change from NULL to NOT NULL
  269. four_way_default_alteration = (
  270. new_field.has_default() and
  271. (old_field.null and not new_field.null)
  272. )
  273. if actions or null_actions:
  274. if not four_way_default_alteration:
  275. # If we don't have to do a 4-way default alteration we can
  276. # directly run a (NOT) NULL alteration
  277. actions = actions + null_actions
  278. # Combine actions together if we can (e.g. postgres)
  279. if self.connection.features.supports_combined_alters and actions:
  280. sql, params = tuple(zip(*actions))
  281. actions = [(", ".join(sql), sum(params, []))]
  282. # Apply those actions
  283. for sql, params in actions:
  284. self.execute(
  285. self.sql_alter_column % {
  286. "table": self.quote_name(model._meta.db_table),
  287. "changes": sql,
  288. },
  289. params,
  290. )
  291. if four_way_default_alteration:
  292. # Update existing rows with default value
  293. self.execute(
  294. self.sql_update_with_default % {
  295. "table": self.quote_name(model._meta.db_table),
  296. "column": self.quote_name(new_field.column),
  297. "default": "%s",
  298. },
  299. [new_default],
  300. )
  301. # Since we didn't run a NOT NULL change before we need to do it
  302. # now
  303. for sql, params in null_actions:
  304. self.execute(
  305. self.sql_alter_column % {
  306. "table": self.quote_name(model._meta.db_table),
  307. "changes": sql,
  308. },
  309. params,
  310. )
  311. if post_actions:
  312. for sql, params in post_actions:
  313. self.execute(sql, params)
  314. # Added a unique?
  315. if (not old_field.unique and new_field.unique) or (
  316. old_field.primary_key and not new_field.primary_key and new_field.unique
  317. ):
  318. self.execute(self._create_unique_sql(model, [new_field.column]))
  319. # Added an index?
  320. if (not old_field.db_index and new_field.db_index and
  321. not new_field.unique and not
  322. (not old_field.unique and new_field.unique)):
  323. self.execute(self._create_index_sql(model, [new_field], suffix="_uniq"))
  324. # Type alteration on primary key? Then we need to alter the column
  325. # referring to us.
  326. rels_to_update = []
  327. if old_field.primary_key and new_field.primary_key and old_type != new_type:
  328. rels_to_update.extend(_related_non_m2m_objects(old_field, new_field))
  329. # Changed to become primary key?
  330. # Note that we don't detect unsetting of a PK, as we assume another field
  331. # will always come along and replace it.
  332. if not old_field.primary_key and new_field.primary_key:
  333. # First, drop the old PK
  334. constraint_names = self._constraint_names(model, primary_key=True)
  335. if strict and len(constraint_names) != 1:
  336. raise ValueError("Found wrong number (%s) of PK constraints for %s" % (
  337. len(constraint_names),
  338. model._meta.db_table,
  339. ))
  340. for constraint_name in constraint_names:
  341. self.execute(self._delete_constraint_sql(self.sql_delete_pk, model, constraint_name))
  342. # Make the new one
  343. self.execute(
  344. self.sql_create_pk % {
  345. "table": self.quote_name(model._meta.db_table),
  346. "name": self.quote_name(self._create_index_name(model, [new_field.column], suffix="_pk")),
  347. "columns": self.quote_name(new_field.column),
  348. }
  349. )
  350. # Update all referencing columns
  351. rels_to_update.extend(_related_non_m2m_objects(old_field, new_field))
  352. # Handle our type alters on the other end of rels from the PK stuff above
  353. for old_rel, new_rel in rels_to_update:
  354. rel_db_params = new_rel.field.db_parameters(connection=self.connection)
  355. rel_type = rel_db_params['type']
  356. fragment, other_actions = self._alter_column_type_sql(
  357. new_rel.related_model._meta.db_table, old_rel.field, new_rel.field, rel_type
  358. )
  359. self.execute(
  360. self.sql_alter_column % {
  361. "table": self.quote_name(new_rel.related_model._meta.db_table),
  362. "changes": fragment[0],
  363. },
  364. fragment[1],
  365. )
  366. for sql, params in other_actions:
  367. self.execute(sql, params)
  368. # Does it have a foreign key?
  369. if (new_field.rel and
  370. (fks_dropped or not old_field.rel or not old_field.db_constraint) and
  371. new_field.db_constraint):
  372. self.execute(self._create_fk_sql(model, new_field, "_fk_%(to_table)s_%(to_column)s"))
  373. # Rebuild FKs that pointed to us if we previously had to drop them
  374. if old_field.primary_key and new_field.primary_key and old_type != new_type:
  375. for rel in new_field.model._meta.related_objects:
  376. if not rel.many_to_many:
  377. self.execute(self._create_fk_sql(rel.related_model, rel.field, "_fk"))
  378. # Does it have check constraints we need to add?
  379. if old_db_params['check'] != new_db_params['check'] and new_db_params['check']:
  380. self.execute(
  381. self.sql_create_check % {
  382. "table": self.quote_name(model._meta.db_table),
  383. "name": self.quote_name(self._create_index_name(model, [new_field.column], suffix="_check")),
  384. "column": self.quote_name(new_field.column),
  385. "check": new_db_params['check'],
  386. }
  387. )
  388. # Drop the default if we need to
  389. # (Django usually does not use in-database defaults)
  390. if needs_database_default:
  391. sql, params = self._drop_default_column(model, new_field.column)
  392. self.execute(sql, params)
  393. # Reset connection if required
  394. if self.connection.features.connection_persists_old_columns:
  395. self.connection.close()
  396. def add_field(self, model, field):
  397. """
  398. Creates a field on a model.
  399. Usually involves adding a column, but may involve adding a
  400. table instead (for M2M fields)
  401. """
  402. # Special-case implicit M2M tables
  403. if isinstance(field, ManyToManyField) and field.rel.through._meta.auto_created:
  404. return self.create_model(field.rel.through)
  405. # Get the column's definition
  406. definition, params = self.column_sql(model, field, include_default=True)
  407. # It might not actually have a column behind it
  408. if definition is None:
  409. return
  410. # Check constraints can go on the column SQL here
  411. db_params = field.db_parameters(connection=self.connection)
  412. if db_params['check']:
  413. definition += " CHECK (%s)" % db_params['check']
  414. # Build the SQL and run it
  415. sql = self.sql_create_column % {
  416. "table": self.quote_name(model._meta.db_table),
  417. "column": self.quote_name(field.column),
  418. "definition": definition,
  419. }
  420. self.execute(sql, params)
  421. # Drop the default if we need to
  422. # (Django usually does not use in-database defaults)
  423. if not self.skip_default(field) and field.default is not None:
  424. sql, params = self._drop_default_column(model, field.column)
  425. self.execute(sql, params)
  426. # Add an index, if required
  427. if field.db_index and not field.unique:
  428. self.deferred_sql.append(self._create_index_sql(model, [field]))
  429. # Add any FK constraints later
  430. if field.rel and self.connection.features.supports_foreign_keys and field.db_constraint:
  431. self.deferred_sql.append(self._create_fk_sql(model, field, "_fk_%(to_table)s_%(to_column)s"))
  432. # Reset connection if required
  433. if self.connection.features.connection_persists_old_columns:
  434. self.connection.close()
  435. def _rename_field_sql(self, table, old_field, new_field, new_type):
  436. return self.sql_rename_column % {
  437. "table": self.quote_name(table),
  438. "old_column": self.quote_name(old_field.column),
  439. "new_column": new_field.column, # not quoting because it's a string literal
  440. "type": new_type,
  441. }
  442. def _drop_default_column(self, model, column):
  443. """
  444. Drop the default constraint for a column on a model.
  445. """
  446. sql = '''
  447. DECLARE @sql nvarchar(max)
  448. WHILE 1=1
  449. BEGIN
  450. SELECT TOP 1 @sql = N'ALTER TABLE %(table)s DROP CONSTRAINT [' + dc.NAME + N']'
  451. FROM sys.default_constraints dc
  452. JOIN sys.columns c
  453. ON c.default_object_id = dc.object_id
  454. WHERE
  455. dc.parent_object_id = OBJECT_ID(%%s)
  456. AND c.name = %%s
  457. IF @@ROWCOUNT = 0 BREAK
  458. EXEC (@sql)
  459. END''' % {'table': model._meta.db_table}
  460. params = [model._meta.db_table, column]
  461. return sql, params
  462. def prepare_default(self, value):
  463. return self.quote_value(value)
  464. def quote_value(self, value):
  465. if isinstance(value, (datetime.date, datetime.time, datetime.datetime)):
  466. return "'%s'" % value
  467. elif isinstance(value, six.string_types):
  468. return "'%s'" % six.text_type(value).replace("\'", "\'\'")
  469. elif isinstance(value, six.buffer_types):
  470. return '0x%s' % force_text(binascii.hexlify(value))
  471. elif isinstance(value, bool):
  472. return "1" if value else "0"
  473. elif value is None:
  474. return "NULL"
  475. else:
  476. return str(value)
  477. # def execute(self, sql, params=[]):
  478. # """
  479. # Executes the given SQL statement, with optional parameters.
  480. # """
  481. # # Log the command we're running, then run it
  482. # logger.debug("%s; (params %r)" % (sql, params))
  483. # if self.collect_sql:
  484. # ending = "" if sql.endswith(";") else ";"
  485. # if params is not None:
  486. # self.collected_sql.append((sql % tuple(map(self.quote_value, params))) + ending)
  487. # else:
  488. # self.collected_sql.append(sql + ending)
  489. # else:
  490. # print('sql=', sql)
  491. # print(' params=', params)
  492. # with self.connection.cursor() as cursor:
  493. # cursor.execute(sql, params)