Django

Code

Changeset 5792

Show
Ignore:
Timestamp:
08/03/07 15:49:19 (1 year ago)
Author:
danderson
Message:

schema-evolution:
added the postgresql_psycopg2 backend
added more unit tests

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/schema-evolution/django/db/backends/postgresql_psycopg2/base.py

    r5785 r5792  
    226226    return output 
    227227 
     228def get_change_table_name_sql( table_name, old_table_name ): 
     229    output = [] 
     230    output.append('ALTER TABLE '+ quote_name(old_table_name) +' RENAME TO '+ quote_name(table_name) + ';') 
     231    return output 
     232 
     233def get_change_column_name_sql( table_name, indexes, old_col_name, new_col_name, col_def ): 
     234    # TODO: only supports a single primary key so far 
     235    pk_name = None 
     236    for key in indexes.keys(): 
     237        if indexes[key]['primary_key']: pk_name = key 
     238    output = [] 
     239    output.append( 'ALTER TABLE '+ quote_name(table_name) +' RENAME COLUMN '+ quote_name(old_col_name) +' TO '+ quote_name(new_col_name) +';' ) 
     240    return output 
     241 
     242def get_change_column_def_sql( table_name, col_name, col_type, null, unique, primary_key ): 
     243    output = [] 
     244    output.append( 'ALTER TABLE '+ quote_name(table_name) +' ADD COLUMN '+ quote_name(col_name+'_tmp') +' '+ col_type + ';' ) 
     245    output.append( 'UPDATE '+ quote_name(table_name) +' SET '+ quote_name(col_name+'_tmp') +' = '+ quote_name(col_name) + ';' ) 
     246    output.append( 'ALTER TABLE '+ quote_name(table_name) +' DROP COLUMN '+ quote_name(col_name) +';' ) 
     247    output.append( 'ALTER TABLE '+ quote_name(table_name) +' RENAME COLUMN '+ quote_name(col_name+'_tmp') +' TO '+ quote_name(col_name) + ';' ) 
     248    if not null: 
     249        output.append( 'ALTER TABLE '+ quote_name(table_name) +' ALTER COLUMN '+ quote_name(col_name) +' SET NOT NULL;' ) 
     250    if unique: 
     251        output.append( 'ALTER TABLE '+ quote_name(table_name) +' ADD CONSTRAINT '+ table_name +'_'+ col_name +'_unique_constraint UNIQUE('+ col_name +');' ) 
     252     
     253    return output 
     254 
     255def get_add_column_sql( table_name, col_name, col_type, null, unique, primary_key  ): 
     256    output = [] 
     257    output.append( 'ALTER TABLE '+ quote_name(table_name) +' ADD COLUMN '+ quote_name(col_name) +' '+ col_type + ';' ) 
     258    if not null: 
     259        output.append( 'ALTER TABLE '+ quote_name(table_name) +' ALTER COLUMN '+ quote_name(col_name) +' SET NOT NULL;' ) 
     260    if unique: 
     261        output.append( 'ALTER TABLE '+ quote_name(table_name) +' ADD CONSTRAINT '+ table_name +'_'+ col_name +'_unique_constraint UNIQUE('+ col_name +');' ) 
     262    return output 
     263     
     264def get_drop_column_sql( table_name, col_name ): 
     265    output = [] 
     266    output.append( 'ALTER TABLE '+ quote_name(table_name) +' DROP COLUMN '+ quote_name(col_name) + ';' ) 
     267    return output 
     268 
    228269OPERATOR_MAPPING = { 
    229270    'exact': '= %s', 
  • django/branches/schema-evolution/django/db/backends/postgresql_psycopg2/introspection.py

    r5734 r5792  
    6464    return indexes 
    6565 
     66def get_columns(cursor, table_name): 
     67    try: 
     68        cursor.execute("SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), (SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef), a.attnotnull, a.attnum, pg_catalog.col_description(a.attrelid, a.attnum) FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid from pg_catalog.pg_class c where c.relname ~ '^%s$') AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum" % table_name) 
     69        return [row[0] for row in cursor.fetchall()] 
     70    except: 
     71        return [] 
     72     
     73def get_known_column_flags( cursor, table_name, column_name ): 
     74#    print "SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), (SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef), a.attnotnull, a.attnum, pg_catalog.col_description(a.attrelid, a.attnum) FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid from pg_catalog.pg_class c where c.relname ~ '^%s$') AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum" % table_name 
     75    cursor.execute("SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), (SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef), a.attnotnull, a.attnum, pg_catalog.col_description(a.attrelid, a.attnum) FROM pg_catalog.pg_attribute a WHERE a.attrelid = (SELECT c.oid from pg_catalog.pg_class c where c.relname ~ '^%s$') AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum" % table_name) 
     76    dict = {} 
     77    dict['primary_key'] = False 
     78    dict['foreign_key'] = False 
     79    dict['unique'] = False 
     80    dict['default'] = '' 
     81    dict['allow_null'] = False 
     82 
     83    for row in cursor.fetchall(): 
     84        if row[0] == column_name: 
     85 
     86            # maxlength check goes here 
     87            if row[1][0:17]=='character varying': 
     88                dict['maxlength'] = row[1][18:len(row[1])-1] 
     89             
     90            # null flag check goes here 
     91            dict['allow_null'] = not row[3] 
     92 
     93    # pk, fk and unique checks go here 
     94#    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  
     95    unique_conname = None 
     96    shared_unique_connames = set() 
     97    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 ) 
     98    for row in cursor.fetchall(): 
     99#        print row 
     100        if row[2] == column_name: 
     101            if row[1]=='p': dict['primary_key'] = True 
     102            if row[1]=='f': dict['foreign_key'] = True 
     103            if row[1]=='u': unique_conname = row[0] 
     104        else: 
     105            if row[1]=='u': shared_unique_connames.add( row[0] ) 
     106    if unique_conname and unique_conname not in shared_unique_connames: 
     107        dict['unique'] = True 
     108         
     109            # default value check goes here 
     110    cursor.execute("select pg_attribute.attname, adsrc from pg_attrdef, pg_attribute WHERE pg_attrdef.adrelid=pg_attribute.attrelid and pg_attribute.attnum=pg_attrdef.adnum and pg_attrdef.adrelid = (SELECT c.oid from pg_catalog.pg_class c where c.relname ~ '^%s$')" % table_name ) 
     111    for row in cursor.fetchall(): 
     112        if row[0] == column_name: 
     113            if row[1][0:7] == 'nextval': continue 
     114            dict['default'] = row[1][1:row[1].index("'",1)] 
     115             
     116#    print table_name, column_name, dict 
     117    return dict 
     118 
    66119# Maps type codes to Django Field types. 
    67120DATA_TYPES_REVERSE = { 
  • django/branches/schema-evolution/tests/modeltests/schema_evolution/models.py

    r5787 r5792  
    2121    class Meta: 
    2222        aka = ('PersonOld', 'OtherBadName') 
     23 
     24class Muebles(models.Model): 
     25    tipo = models.CharField(maxlength=40) 
     26    # new fields 
     27    fecha_publicacion = models.DateTimeField('date published') 
    2328 
    2429__test__ = {'API_TESTS':""" 
     
    3540# the table as it is supposed to be 
    3641>>> create_table_sql = management.get_sql_all(app) 
    37 >>> print create_table_sql 
    38 ['CREATE TABLE `schema_evolution_person` (\\n    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\\n    `name` varchar(20) NOT NULL,\\n    `gender` varchar(1) NOT NULL,\\n    `gender2` varchar(1) NOT NULL\\n)\\n;'] 
    3942 
    4043# make sure we don't evolve an unedited table 
     
    9093>>> management.get_sql_evolution(app) 
    9194['ALTER TABLE `schema_evolution_person` MODIFY COLUMN `name` varchar(20) NOT NULL;'] 
    92 """ 
    93  
    94 if settings.DATABASE_ENGINE == 'postgresql': 
     95 
     96# reset the db 
     97>>> cursor.execute('DROP TABLE schema_evolution_person;'); cursor.execute(create_table_sql[0]) 
     980L\n0L 
     99 
     100# delete a datetime column pair, so it looks like we've recently added a datetime field 
     101>>> for sql in backend.get_drop_column_sql( 'schema_evolution_muebles', 'fecha_publicacion' ): print sql; cursor.execute(sql) 
     102ALTER TABLE `schema_evolution_muebles` DROP COLUMN `fecha_publicacion`; 
     1030L 
     104>>> management.get_sql_evolution(app) 
     105['ALTER TABLE `schema_evolution_muebles` ADD COLUMN `fecha_publicacion` datetime NOT NULL;'] 
     106 
     107""" 
     108 
     109if settings.DATABASE_ENGINE == 'postgresql' or settings.DATABASE_ENGINE == 'postgresql_psycopg2' : 
    95110    __test__['API_TESTS'] += """ 
    96111# the table as it is supposed to be 
    97112>>> create_table_sql = management.get_sql_all(app) 
    98 >>> print create_table_sql 
    99 ['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;'] 
    100113 
    101114# make sure we don't evolve an unedited table 
     
    140153['ALTER TABLE "schema_evolution_person" ADD COLUMN "name_tmp" varchar(20);', 'UPDATE "schema_evolution_person" SET "name_tmp" = "name";', 'ALTER TABLE "schema_evolution_person" DROP COLUMN "name";', 'ALTER TABLE "schema_evolution_person" RENAME COLUMN "name_tmp" TO "name";', 'ALTER TABLE "schema_evolution_person" ALTER COLUMN "name" SET NOT NULL;'] 
    141154 
     155# reset the db 
     156>>> cursor.execute('DROP TABLE schema_evolution_person;'); cursor.execute(create_table_sql[0]) 
     157 
     158# delete a datetime column pair, so it looks like we've recently added a datetime field 
     159>>> for sql in backend.get_drop_column_sql( 'schema_evolution_muebles', 'fecha_publicacion' ): print sql; cursor.execute(sql) 
     160ALTER TABLE "schema_evolution_muebles" DROP COLUMN "fecha_publicacion"; 
     161>>> management.get_sql_evolution(app) 
     162['ALTER TABLE "schema_evolution_muebles" ADD COLUMN "fecha_publicacion" timestamp with time zone;', 'ALTER TABLE "schema_evolution_muebles" ALTER COLUMN "fecha_publicacion" SET NOT NULL;'] 
    142163""" 
    143164 
     
    146167# the table as it is supposed to be 
    147168>>> 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;'] 
    150169 
    151170# make sure we don't evolve an unedited table 
     
    244263>>> management.get_sql_evolution(app) 
    245264['-- FYI: sqlite does not support changing columns, so we create a new "schema_evolution_person" 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";'] 
    246 """ 
    247  
     265 
     266# reset the db 
     267>>> cursor.execute('DROP TABLE schema_evolution_person;').__class__ 
     268<class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 
     269>>> cursor.execute(create_table_sql[0]).__class__ 
     270<class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 
     271 
     272# delete a datetime column pair, so it looks like we've recently added a datetime field 
     273>>> for sql in ['DROP TABLE schema_evolution_muebles;','CREATE TABLE "schema_evolution_muebles" ("id" integer NOT NULL UNIQUE PRIMARY KEY,"tipo" varchar(40) NOT NULL);']: cursor.execute(sql).__class__ 
     274<class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 
     275<class 'django.db.backends.sqlite3.base.SQLiteCursorWrapper'> 
     276>>> management.get_sql_evolution(app) 
     277['ALTER TABLE "schema_evolution_muebles" ADD COLUMN "fecha_publicacion" datetime NOT NULL;'] 
     278 
     279 
     280""" 
     281