Changeset 5785
- Timestamp:
- 08/01/07 22:28:52 (1 year ago)
- Files:
-
- django/branches/schema-evolution/django/core/management.py (modified) (4 diffs)
- django/branches/schema-evolution/django/db/backends/ado_mssql/base.py (modified) (1 diff)
- django/branches/schema-evolution/django/db/backends/mysql/base.py (modified) (2 diffs)
- django/branches/schema-evolution/django/db/backends/mysql_old/base.py (modified) (1 diff)
- django/branches/schema-evolution/django/db/backends/postgresql/base.py (modified) (2 diffs)
- django/branches/schema-evolution/django/db/backends/postgresql/introspection.py (modified) (1 diff)
- django/branches/schema-evolution/django/db/backends/postgresql_psycopg2/base.py (modified) (1 diff)
- django/branches/schema-evolution/django/db/backends/sqlite3/base.py (modified) (5 diffs)
- django/branches/schema-evolution/django/db/backends/sqlite3/introspection.py (modified) (3 diffs)
- django/branches/schema-evolution/tests/modeltests/schema_evolution/models.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/schema-evolution/django/core/management.py
r5784 r5785 171 171 style.SQL_COLTYPE(col_type)] 172 172 field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or ''))) 173 if f.unique and (not f.primary_key or backend.allows_unique_and_pk):173 if (f.unique and (not f.primary_key or backend.allows_unique_and_pk)) or (f.primary_key and backend.pk_requires_unique): 174 174 field_output.append(style.SQL_KEYWORD('UNIQUE')) 175 175 if f.primary_key: … … 570 570 col_type = data_types[data_type] 571 571 if col_type is not None: 572 # field_output = []573 # field_output.append('ALTER TABLE')574 # field_output.append(db_table)575 # field_output.append('ADD COLUMN')576 # field_output.append(backend.quote_name(f.column))577 # field_output.append(style.SQL_COLTYPE(col_type % rel_field.__dict__))578 # field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))579 # if f.unique:580 # field_output.append(style.SQL_KEYWORD('UNIQUE'))581 # if f.primary_key:582 # field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))583 # output.append(' '.join(field_output) + ';')584 572 output.append( backend.get_add_column_sql( db_table, f.column, style.SQL_COLTYPE(col_type % rel_field.__dict__), f.null, f.unique, f.primary_key ) ) 585 573 return output … … 665 653 column_flags['primary_key']!=f.primary_key: 666 654 #column_flags['foreign_key']!=f.foreign_key: 667 # print 655 # print 'need to change' 668 656 # print db_table, f.column, column_flags 669 657 # print "column_flags['allow_null']!=f.null", column_flags['allow_null']!=f.null … … 704 692 if f.aka: suspect_fields.difference_update(f.aka) 705 693 if len(suspect_fields)>0: 706 output.append( '-- warning: as the following may cause data loss, it/they must be run manually' )694 output.append( '-- warning: the following may cause data loss' ) 707 695 for suspect_field in suspect_fields: 708 output. append( '-- '+backend.get_drop_column_sql( db_table, suspect_field ) )696 output.extend( backend.get_drop_column_sql( db_table, suspect_field ) ) 709 697 output.append( '-- end warning' ) 710 698 return output django/branches/schema-evolution/django/db/backends/ado_mssql/base.py
r5734 r5785 92 92 allows_group_by_ordinal = True 93 93 allows_unique_and_pk = True 94 pk_requires_unique = False 94 95 autoindexes_primary_keys = True 95 96 needs_datetime_string_cast = True django/branches/schema-evolution/django/db/backends/mysql/base.py
r5784 r5785 137 137 allows_group_by_ordinal = True 138 138 allows_unique_and_pk = True 139 pk_requires_unique = False 139 140 autoindexes_primary_keys = False 140 141 needs_datetime_string_cast = True # MySQLdb requires a typecast for dates … … 285 286 output = [] 286 287 output.append( 'ALTER TABLE '+ quote_name(table_name) +' DROP COLUMN '+ quote_name(col_name) + ';' ) 287 return '\n'.join(output)288 return output 288 289 289 290 django/branches/schema-evolution/django/db/backends/mysql_old/base.py
r5734 r5785 152 152 allows_group_by_ordinal = True 153 153 allows_unique_and_pk = True 154 pk_requires_unique = False 154 155 autoindexes_primary_keys = False 155 156 needs_datetime_string_cast = True # MySQLdb requires a typecast for dates django/branches/schema-evolution/django/db/backends/postgresql/base.py
r5784 r5785 118 118 allows_group_by_ordinal = True 119 119 allows_unique_and_pk = True 120 pk_requires_unique = False 120 121 autoindexes_primary_keys = True 121 122 needs_datetime_string_cast = True … … 322 323 output = [] 323 324 output.append( 'ALTER TABLE '+ quote_name(table_name) +' DROP COLUMN '+ quote_name(col_name) + ';' ) 324 return '\n'.join(output)325 return output 325 326 326 327 # Register these custom typecasts, because Django expects dates/times to be django/branches/schema-evolution/django/db/backends/postgresql/introspection.py
r5784 r5785 82 82 dict['unique'] = False 83 83 dict['default'] = '' 84 85 # dict['allow_null'] = False 84 dict['allow_null'] = False 85 86 86 for row in cursor.fetchall(): 87 87 if row[0] == column_name: django/branches/schema-evolution/django/db/backends/postgresql_psycopg2/base.py
r5734 r5785 80 80 allows_group_by_ordinal = True 81 81 allows_unique_and_pk = True 82 pk_requires_unique = False 82 83 autoindexes_primary_keys = True 83 84 needs_datetime_string_cast = False django/branches/schema-evolution/django/db/backends/sqlite3/base.py
r5784 r5785 3 3 """ 4 4 5 from django.core import management 5 6 from django.db.backends import util 6 7 try: … … 103 104 allows_group_by_ordinal = True 104 105 allows_unique_and_pk = True 106 pk_requires_unique = True # or else the constraint is never created 105 107 autoindexes_primary_keys = True 106 108 needs_datetime_string_cast = True … … 228 230 output.append( 'UPDATE '+ quote_name(table_name) +' SET '+ new_col_name +' = '+ old_col_name +' WHERE '+ pk_name +'=(select '+ pk_name +' from '+ table_name +');' ) 229 231 output.append( '-- FYI: sqlite does not support deleting columns, so '+ quote_name(old_col_name) +' remains as cruft' ) 230 # use the following when sqlite gets drop support231 #output.append( 'ALTER TABLE '+ quote_name(table_name) +' DROP COLUMN '+ quote_name(old_col_name) )232 232 return '\n'.join(output) 233 233 234 def get_change_column_def_sql( table_name, col_name, col_ def):234 def get_change_column_def_sql( table_name, col_name, col_type, null, unique, primary_key ): 235 235 # sqlite doesn't support column modifications, so we fake it 236 236 output = [] 237 col_def = col_type +' '+ ('%sNULL' % (not null and 'NOT ' or '')) 238 if unique or primary_key: 239 col_def += ' '+ 'UNIQUE' 240 if primary_key: 241 col_def += ' '+ 'PRIMARY KEY' 237 242 # TODO: fake via renaming the table, building a new one and deleting the old 238 243 output.append('-- sqlite does not support column modifications '+ quote_name(table_name) +'.'+ quote_name(col_name) +' to '+ col_def) … … 248 253 field_output.append(col_type) 249 254 field_output.append(('%sNULL' % (not null and 'NOT ' or ''))) 250 if unique :255 if unique or primary_key: 251 256 field_output.append(('UNIQUE')) 252 257 if primary_key: … … 256 261 257 262 def get_drop_column_sql( table_name, col_name ): 263 model = get_model_from_table_name(table_name) 258 264 output = [] 259 output.append( '-- FYI: sqlite does not support deleting columns, so '+ quote_name(old_col_name) +' remains as cruft' ) 260 # use the following when sqlite gets drop support 261 # output.append( '-- ALTER TABLE '+ quote_name(table_name) +' DROP COLUMN '+ quote_name(col_name) ) 262 return '\n'.join(output) 265 output.append( '-- FYI: sqlite does not support deleting columns, so we create a new '+ quote_name(col_name) +' and delete the old (ie, this could take a while)' ) 266 tmp_table_name = table_name + '_1337_TMP' # unlikely to produce a namespace conflict 267 output.append( get_change_table_name_sql( tmp_table_name, table_name ) ) 268 output.extend( management._get_sql_model_create(model, set())[0] ) 269 new_cols = [] 270 for f in model._meta.fields: 271 new_cols.append( quote_name(f.column) ) 272 output.append( 'INSERT INTO '+ quote_name(table_name) +' SELECT '+ ','.join(new_cols) +' FROM '+ quote_name(tmp_table_name) +';' ) 273 output.append( 'DROP TABLE '+ quote_name(tmp_table_name) +';' ) 274 return output 275 276 def get_model_from_table_name(table_name): 277 from django.db import models 278 for app in models.get_apps(): 279 app_name = app.__name__.split('.')[-2] 280 if app_name == table_name.split('_')[0] or app_name == '_'.join(table_name.split('_')[0:1]) or app_name == '_'.join(table_name.split('_')[0:2]): 281 for model in models.get_models(app): 282 if model._meta.db_table == table_name: 283 return model 284 return None 263 285 264 286 django/branches/schema-evolution/django/db/backends/sqlite3/introspection.py
r5735 r5785 54 54 cursor.execute("PRAGMA table_info(%s)" % quote_name(table_name)) 55 55 dict = {} 56 dict['primary_key'] = False 57 dict['foreign_key'] = False 58 dict['unique'] = False 59 dict['default'] = '' 60 dict['allow_null'] = True 61 56 62 for row in cursor.fetchall(): 63 # print row 57 64 if row[1] == column_name: 65 col_type = row[2] 58 66 59 67 # maxlength check goes here … … 62 70 63 71 # default flag check goes here 64 #if row[2]=='YES': dict['allow_null'] = True 65 #else: dict['allow_null'] = False 72 dict['allow_null'] = row[3]==0 66 73 74 # default value check goes here 75 dict['default'] = row[4] 76 77 cursor.execute("PRAGMA index_list(%s)" % quote_name(table_name)) 78 index_names = [] 79 for row in cursor.fetchall(): 80 index_names.append(row[1]) 81 for index_name in index_names: 82 cursor.execute("PRAGMA index_info(%s)" % quote_name(index_name)) 83 for row in cursor.fetchall(): 84 if row[2]==column_name: 85 if col_type=='integer': dict['primary_key'] = True # sqlite3 does not distinguish between unique and pk; all 86 else: dict['unique'] = True # unique integer columns are treated as part of the pk. 87 67 88 # primary/foreign/unique key flag check goes here 68 89 #if row[3]=='PRI': dict['primary_key'] = True … … 73 94 #else: dict['unique'] = False 74 95 75 # default value check goes here 76 # if row[4]=='NULL': dict['default'] = None 77 # else: dict['default'] = row[4] 78 #dict['default'] = row[4] 79 80 print table_name, column_name, dict 96 97 # print dict 81 98 return dict 82 99 django/branches/schema-evolution/tests/modeltests/schema_evolution/models.py
r5784 r5785 142 142 """ 143 143 144 if settings.DATABASE_ENGINE == 'sqlite3': 145 __test__['API_TESTS'] += """ 146 # the table as it is supposed to be 147 >>> create_table_sql = management.get_sql_all(app) 148 >>> print create_table_sql 149 ['CREATE TABLE "schema_evolution_person" (\\n "id" integer NOT NULL UNIQUE PRIMARY KEY,\\n "name" varchar(20) NOT NULL,\\n "gender" varchar(1) NOT NULL,\\n "gender2" varchar(1) NOT NULL\\n)\\n;'] 150 151 # make sure we don't evolve an unedited table 152 >>> management.get_sql_evolution(app) 153 [] 154 155 # delete a column, so it looks like we've recently added a field 156 >>> cursor.execute( 'DROP TABLE "schema_evolution_person";' ).__class__ 157 <class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 158 >>> cursor.execute( 'CREATE TABLE "schema_evolution_person" ( "id" integer NOT NULL UNIQUE PRIMARY KEY, "name" varchar(20) NOT NULL, "gender" varchar(1) NOT NULL );' ).__class__ 159 <class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 160 >>> management.get_sql_evolution(app) 161 ['ALTER TABLE "schema_evolution_person" ADD COLUMN "gender2" varchar(1) NOT NULL;'] 162 163 # reset the db 164 >>> cursor.execute('DROP TABLE schema_evolution_person;').__class__ 165 <class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 166 >>> cursor.execute(create_table_sql[0]).__class__ 167 <class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 168 169 # add a column, so it looks like we've recently deleted a field 170 >>> cursor.execute( 'DROP TABLE "schema_evolution_person";' ).__class__ 171 <class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 172 >>> cursor.execute( 'CREATE TABLE "schema_evolution_person" ( "id" integer NOT NULL UNIQUE PRIMARY KEY, "name" varchar(20) NOT NULL, "gender" varchar(1) NOT NULL, "gender2" varchar(1) NOT NULL, "gender_new" varchar(1) NOT NULL );' ).__class__ 173 <class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 174 >>> management.get_sql_evolution(app) 175 ['-- warning: the following may cause data loss', u'-- FYI: sqlite does not support deleting columns, so we create a new "gender_new" and delete the old (ie, this could take a while)', 'ALTER TABLE "schema_evolution_person" RENAME TO "schema_evolution_person_1337_TMP";', 'CREATE TABLE "schema_evolution_person" (\\n "id" integer NOT NULL UNIQUE PRIMARY KEY,\\n "name" varchar(20) NOT NULL,\\n "gender" varchar(1) NOT NULL,\\n "gender2" varchar(1) NOT NULL\\n)\\n;', 'INSERT INTO "schema_evolution_person" SELECT "id","name","gender","gender2" FROM "schema_evolution_person_1337_TMP";', 'DROP TABLE "schema_evolution_person_1337_TMP";', '-- end warning'] 176 177 # reset the db 178 >>> cursor.execute('DROP TABLE schema_evolution_person;').__class__ 179 <class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 180 >>> cursor.execute(create_table_sql[0]).__class__ 181 <class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 182 183 """ 184 185 crap = """ 186 187 # rename column, so it looks like we've recently renamed a field 188 >>> cursor.execute( backend.get_change_column_name_sql( 'schema_evolution_person', {}, 'gender2', 'gender_old', 'varchar(1)' ) ) 189 >>> management.get_sql_evolution(app) 190 ['ALTER TABLE "schema_evolution_person" RENAME COLUMN "gender_old" TO "gender2";'] 191 192 # reset the db 193 >>> cursor.execute('DROP TABLE schema_evolution_person;'); cursor.execute(create_table_sql[0]) 194 195 # rename table, so it looks like we've recently renamed a model 196 >>> cursor.execute( backend.get_change_table_name_sql( 'schema_evolution_personold', 'schema_evolution_person' ) ) 197 >>> management.get_sql_evolution(app) 198 ['ALTER TABLE "schema_evolution_personold" RENAME TO "schema_evolution_person";'] 199 200 # reset the db 201 >>> cursor.execute(create_table_sql[0]) 202 203 # change column flags, so it looks like we've recently changed a column flag 204 >>> cursor.execute( backend.get_change_column_def_sql( 'schema_evolution_person', 'name', 'varchar(10)', True, False, False ) ) 205 >>> management.get_sql_evolution(app) 206 ['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;'] 207 208 """ 209
