mirror of
https://github.com/django/django.git
synced 2025-07-05 10:19:20 +00:00
schema-evolution:
fixed postgresql constraint lookup after a table rename bug pulled table renames into the backends added postgresql unit tests git-svn-id: http://code.djangoproject.com/svn/django/branches/schema-evolution@5784 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
4629092d79
commit
0b4c2c7ab1
@ -5,6 +5,7 @@ import django
|
|||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
from django.utils import termcolors
|
from django.utils import termcolors
|
||||||
|
from django.conf import settings
|
||||||
import os, re, shutil, sys, textwrap
|
import os, re, shutil, sys, textwrap
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -591,9 +592,9 @@ def get_sql_evolution_check_for_changed_model_name(klass):
|
|||||||
if klass._meta.db_table in table_list:
|
if klass._meta.db_table in table_list:
|
||||||
return [], None
|
return [], None
|
||||||
if klass._meta.aka in table_list:
|
if klass._meta.aka in table_list:
|
||||||
return [ 'ALTER TABLE '+ backend.quote_name(klass._meta.aka) +' RENAME TO '+ backend.quote_name(klass._meta.db_table) + ';' ], klass._meta.aka
|
return [ backend.get_change_table_name_sql( klass._meta.db_table, klass._meta.aka) ], klass._meta.aka
|
||||||
elif len(set(klass._meta.aka) & set(table_list))==1:
|
elif len(set(klass._meta.aka) & set(table_list))==1:
|
||||||
return [ 'ALTER TABLE '+ backend.quote_name(klass._meta.aka[0]) +' RENAME TO '+ backend.quote_name(klass._meta.db_table) + ';' ], klass._meta.aka[0]
|
return [ backend.get_change_table_name_sql( klass._meta.db_table, klass._meta.aka[0]) ], klass._meta.aka[0]
|
||||||
else:
|
else:
|
||||||
return [], None
|
return [], None
|
||||||
|
|
||||||
@ -643,6 +644,7 @@ def get_sql_evolution_check_for_changed_field_flags(klass, new_table_name):
|
|||||||
db_table = new_table_name
|
db_table = new_table_name
|
||||||
for f in opts.fields:
|
for f in opts.fields:
|
||||||
existing_fields = introspection.get_columns(cursor,db_table)
|
existing_fields = introspection.get_columns(cursor,db_table)
|
||||||
|
# print existing_fields
|
||||||
cf = None # current field, ie what it is before any renames
|
cf = None # current field, ie what it is before any renames
|
||||||
if f.column in existing_fields:
|
if f.column in existing_fields:
|
||||||
cf = f.column
|
cf = f.column
|
||||||
@ -655,10 +657,11 @@ def get_sql_evolution_check_for_changed_field_flags(klass, new_table_name):
|
|||||||
data_type = f.get_internal_type()
|
data_type = f.get_internal_type()
|
||||||
if data_types.has_key(data_type):
|
if data_types.has_key(data_type):
|
||||||
column_flags = introspection.get_known_column_flags(cursor, db_table, cf)
|
column_flags = introspection.get_known_column_flags(cursor, db_table, cf)
|
||||||
|
# print db_table, cf, column_flags
|
||||||
if column_flags['allow_null']!=f.null or \
|
if column_flags['allow_null']!=f.null or \
|
||||||
( not f.primary_key and isinstance(f, CharField) and column_flags['maxlength']!=str(f.maxlength) ) or \
|
( not f.primary_key and isinstance(f, CharField) and column_flags['maxlength']!=str(f.maxlength) ) or \
|
||||||
( not f.primary_key and isinstance(f, SlugField) and column_flags['maxlength']!=str(f.maxlength) ) or \
|
( not f.primary_key and isinstance(f, SlugField) and column_flags['maxlength']!=str(f.maxlength) ) or \
|
||||||
column_flags['unique']!=f.unique or \
|
( column_flags['unique']!=f.unique and ( settings.DATABASE_ENGINE!='postgresql' or not f.primary_key ) ) or \
|
||||||
column_flags['primary_key']!=f.primary_key:
|
column_flags['primary_key']!=f.primary_key:
|
||||||
#column_flags['foreign_key']!=f.foreign_key:
|
#column_flags['foreign_key']!=f.foreign_key:
|
||||||
# print
|
# print
|
||||||
|
@ -242,6 +242,9 @@ def get_sql_sequence_reset(style, model_list):
|
|||||||
# No sequence reset required
|
# No sequence reset required
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def get_change_table_name_sql( table_name, old_table_name ):
|
||||||
|
return 'ALTER TABLE '+ quote_name(old_table_name) +' RENAME TO '+ quote_name(table_name) + ';'
|
||||||
|
|
||||||
def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ):
|
def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ):
|
||||||
# mysql doesn't support column renames (AFAIK), so we fake it
|
# mysql doesn't support column renames (AFAIK), so we fake it
|
||||||
# TODO: only supports a single primary key so far
|
# TODO: only supports a single primary key so far
|
||||||
|
@ -282,6 +282,11 @@ def typecast_string(s):
|
|||||||
return s
|
return s
|
||||||
return smart_unicode(s)
|
return smart_unicode(s)
|
||||||
|
|
||||||
|
def get_change_table_name_sql( table_name, old_table_name ):
|
||||||
|
output = []
|
||||||
|
output.append('ALTER TABLE '+ quote_name(old_table_name) +' RENAME TO '+ quote_name(table_name) + ';')
|
||||||
|
return '\n'.join(output)
|
||||||
|
|
||||||
def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ):
|
def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ):
|
||||||
# TODO: only supports a single primary key so far
|
# TODO: only supports a single primary key so far
|
||||||
pk_name = None
|
pk_name = None
|
||||||
|
@ -97,8 +97,9 @@ def get_known_column_flags( cursor, table_name, column_name ):
|
|||||||
# print "select pg_constraint.conname, pg_constraint.contype, pg_attribute.attname from pg_constraint, pg_attribute where pg_constraint.conrelid=pg_attribute.attrelid and pg_attribute.attnum=any(pg_constraint.conkey) and pg_constraint.conname~'^%s'" % table_name
|
# print "select pg_constraint.conname, pg_constraint.contype, pg_attribute.attname from pg_constraint, pg_attribute where pg_constraint.conrelid=pg_attribute.attrelid and pg_attribute.attnum=any(pg_constraint.conkey) and pg_constraint.conname~'^%s'" % table_name
|
||||||
unique_conname = None
|
unique_conname = None
|
||||||
shared_unique_connames = set()
|
shared_unique_connames = set()
|
||||||
cursor.execute("select pg_constraint.conname, pg_constraint.contype, pg_attribute.attname from pg_constraint, pg_attribute where pg_constraint.conrelid=pg_attribute.attrelid and pg_attribute.attnum=any(pg_constraint.conkey) and pg_constraint.conname~'^%s'" % table_name )
|
cursor.execute("select pg_constraint.conname, pg_constraint.contype, pg_attribute.attname from pg_constraint, pg_attribute, pg_class where pg_constraint.conrelid=pg_class.oid and pg_constraint.conrelid=pg_attribute.attrelid and pg_attribute.attnum=any(pg_constraint.conkey) and pg_class.relname='%s'" % table_name )
|
||||||
for row in cursor.fetchall():
|
for row in cursor.fetchall():
|
||||||
|
# print row
|
||||||
if row[2] == column_name:
|
if row[2] == column_name:
|
||||||
if row[1]=='p': dict['primary_key'] = True
|
if row[1]=='p': dict['primary_key'] = True
|
||||||
if row[1]=='f': dict['foreign_key'] = True
|
if row[1]=='f': dict['foreign_key'] = True
|
||||||
|
@ -214,6 +214,9 @@ def _sqlite_regexp(re_pattern, re_string):
|
|||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_change_table_name_sql( table_name, old_table_name ):
|
||||||
|
return 'ALTER TABLE '+ quote_name(old_table_name) +' RENAME TO '+ quote_name(table_name) + ';'
|
||||||
|
|
||||||
def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ):
|
def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ):
|
||||||
# sqlite doesn't support column renames, so we fake it
|
# sqlite doesn't support column renames, so we fake it
|
||||||
# TODO: only supports a single primary key so far
|
# TODO: only supports a single primary key so far
|
||||||
|
@ -3,6 +3,7 @@ Schema Evolution Tests
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
GENDER_CHOICES = (
|
GENDER_CHOICES = (
|
||||||
('M', 'Male'),
|
('M', 'Male'),
|
||||||
@ -27,7 +28,10 @@ __test__ = {'API_TESTS':"""
|
|||||||
>>> from django.db import connection, get_introspection_module
|
>>> from django.db import connection, get_introspection_module
|
||||||
>>> app = models.get_apps()[-1]
|
>>> app = models.get_apps()[-1]
|
||||||
>>> cursor = connection.cursor()
|
>>> cursor = connection.cursor()
|
||||||
|
"""}
|
||||||
|
|
||||||
|
if settings.DATABASE_ENGINE == 'mysql':
|
||||||
|
__test__['API_TESTS'] += """
|
||||||
# the table as it is supposed to be
|
# the table as it is supposed to be
|
||||||
>>> create_table_sql = management.get_sql_all(app)
|
>>> create_table_sql = management.get_sql_all(app)
|
||||||
>>> print create_table_sql
|
>>> print create_table_sql
|
||||||
@ -85,7 +89,55 @@ ALTER TABLE `schema_evolution_person` DROP COLUMN `gender`;
|
|||||||
0L
|
0L
|
||||||
>>> management.get_sql_evolution(app)
|
>>> management.get_sql_evolution(app)
|
||||||
['ALTER TABLE `schema_evolution_person` MODIFY COLUMN `name` varchar(20) NOT NULL;']
|
['ALTER TABLE `schema_evolution_person` MODIFY COLUMN `name` varchar(20) NOT NULL;']
|
||||||
|
"""
|
||||||
|
|
||||||
|
if settings.DATABASE_ENGINE == 'postgresql':
|
||||||
|
__test__['API_TESTS'] += """
|
||||||
|
# the table as it is supposed to be
|
||||||
|
>>> create_table_sql = management.get_sql_all(app)
|
||||||
|
>>> print create_table_sql
|
||||||
|
['CREATE TABLE "schema_evolution_person" (\\n "id" serial NOT NULL PRIMARY KEY,\\n "name" varchar(20) NOT NULL,\\n "gender" varchar(1) NOT NULL,\\n "gender2" varchar(1) NOT NULL\\n)\\n;']
|
||||||
|
|
||||||
"""}
|
# make sure we don't evolve an unedited table
|
||||||
|
>>> management.get_sql_evolution(app)
|
||||||
|
[]
|
||||||
|
|
||||||
|
# delete a column, so it looks like we've recently added a field
|
||||||
|
>>> cursor.execute( backend.get_drop_column_sql( 'schema_evolution_person', 'gender' ) )
|
||||||
|
>>> management.get_sql_evolution(app)
|
||||||
|
['ALTER TABLE "schema_evolution_person" ADD COLUMN "gender" varchar(1);\\nALTER TABLE "schema_evolution_person" ALTER COLUMN "gender" SET NOT NULL;']
|
||||||
|
|
||||||
|
# reset the db
|
||||||
|
>>> cursor.execute('DROP TABLE schema_evolution_person;'); cursor.execute(create_table_sql[0])
|
||||||
|
|
||||||
|
# add a column, so it looks like we've recently deleted a field
|
||||||
|
>>> cursor.execute( backend.get_add_column_sql( 'schema_evolution_person', 'gender_nothere', 'varchar(1)', True, False, False ) )
|
||||||
|
>>> management.get_sql_evolution(app)
|
||||||
|
['-- warning: as the following may cause data loss, it/they must be run manually', u'-- ALTER TABLE "schema_evolution_person" DROP COLUMN "gender_nothere";', '-- end warning']
|
||||||
|
|
||||||
|
# reset the db
|
||||||
|
>>> cursor.execute('DROP TABLE schema_evolution_person;'); cursor.execute(create_table_sql[0])
|
||||||
|
|
||||||
|
# rename column, so it looks like we've recently renamed a field
|
||||||
|
>>> cursor.execute( backend.get_change_column_name_sql( 'schema_evolution_person', {}, 'gender2', 'gender_old', 'varchar(1)' ) )
|
||||||
|
>>> management.get_sql_evolution(app)
|
||||||
|
['ALTER TABLE "schema_evolution_person" RENAME COLUMN "gender_old" TO "gender2";']
|
||||||
|
|
||||||
|
# reset the db
|
||||||
|
>>> cursor.execute('DROP TABLE schema_evolution_person;'); cursor.execute(create_table_sql[0])
|
||||||
|
|
||||||
|
# rename table, so it looks like we've recently renamed a model
|
||||||
|
>>> cursor.execute( backend.get_change_table_name_sql( 'schema_evolution_personold', 'schema_evolution_person' ) )
|
||||||
|
>>> management.get_sql_evolution(app)
|
||||||
|
['ALTER TABLE "schema_evolution_personold" RENAME TO "schema_evolution_person";']
|
||||||
|
|
||||||
|
# reset the db
|
||||||
|
>>> cursor.execute(create_table_sql[0])
|
||||||
|
|
||||||
|
# change column flags, so it looks like we've recently changed a column flag
|
||||||
|
>>> cursor.execute( backend.get_change_column_def_sql( 'schema_evolution_person', 'name', 'varchar(10)', True, False, False ) )
|
||||||
|
>>> management.get_sql_evolution(app)
|
||||||
|
['ALTER TABLE "schema_evolution_person" ADD COLUMN "name_tmp" varchar(20);\\nUPDATE "schema_evolution_person" SET "name_tmp" = "name";\\nALTER TABLE "schema_evolution_person" DROP COLUMN "name";\\nALTER TABLE "schema_evolution_person" RENAME COLUMN "name_tmp" TO "name";\\nALTER TABLE "schema_evolution_person" ALTER COLUMN "name" SET NOT NULL;']
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user