summaryrefslogtreecommitdiff
path: root/migrate/changeset/databases
diff options
context:
space:
mode:
authorjan.dittberner <unknown>2008-02-06 18:39:07 +0000
committerjan.dittberner <unknown>2008-02-06 18:39:07 +0000
commit2cfe1fc31c0dfa8241200f635d8e7f6cfce2b507 (patch)
tree69541da758ab44652badc59ec0ce659364bdfe7f /migrate/changeset/databases
downloadsqlalchemy-migrate-2cfe1fc31c0dfa8241200f635d8e7f6cfce2b507.tar.gz
moved trunk, branches and tags to project root
fixes Issue #5
Diffstat (limited to 'migrate/changeset/databases')
-rw-r--r--migrate/changeset/databases/__init__.py6
-rw-r--r--migrate/changeset/databases/mysql.py61
-rw-r--r--migrate/changeset/databases/oracle.py79
-rw-r--r--migrate/changeset/databases/postgres.py23
-rw-r--r--migrate/changeset/databases/sqlite.py49
-rw-r--r--migrate/changeset/databases/visitor.py20
6 files changed, 238 insertions, 0 deletions
diff --git a/migrate/changeset/databases/__init__.py b/migrate/changeset/databases/__init__.py
new file mode 100644
index 0000000..34b4f9d
--- /dev/null
+++ b/migrate/changeset/databases/__init__.py
@@ -0,0 +1,6 @@
+__all__=[
+'postgres',
+'sqlite',
+'mysql',
+'oracle',
+]
diff --git a/migrate/changeset/databases/mysql.py b/migrate/changeset/databases/mysql.py
new file mode 100644
index 0000000..3611f66
--- /dev/null
+++ b/migrate/changeset/databases/mysql.py
@@ -0,0 +1,61 @@
+from migrate.changeset import ansisql,exceptions
+from sqlalchemy.databases import mysql as sa_base
+#import sqlalchemy as sa
+
+MySQLSchemaGenerator = sa_base.MySQLSchemaGenerator
+
+class MySQLColumnGenerator(MySQLSchemaGenerator,ansisql.ANSIColumnGenerator):
+ pass
+class MySQLColumnDropper(ansisql.ANSIColumnDropper):
+ pass
+class MySQLSchemaChanger(MySQLSchemaGenerator,ansisql.ANSISchemaChanger):
+ def visit_column(self,delta):
+ keys = delta.keys()
+ if 'type' in keys or 'nullable' in keys or 'name' in keys:
+ self._run_subvisit(delta,self._visit_column_change)
+ if 'default' in keys:
+ # Column name might have changed above
+ col_name = delta.get('name',delta.current_name)
+ self._run_subvisit(delta,self._visit_column_default,col_name=col_name)
+ def _visit_column_change(self,table_name,col_name,delta):
+ if not hasattr(delta,'result_column'):
+ # Mysql needs the whole column definition, not just a lone name/type
+ raise exceptions.NotSupportedError(
+ "A column object is required to do this")
+
+ column = delta.result_column
+ colspec = self.get_column_specification(column)
+ self.start_alter_table(table_name)
+ self.append("CHANGE COLUMN ")
+ self.append(col_name)
+ self.append(' ')
+ self.append(colspec)
+ def visit_index(self,param):
+ # If MySQL can do this, I can't find how
+ raise exceptions.NotSupportedError("MySQL cannot rename indexes")
+class MySQLConstraintGenerator(ansisql.ANSIConstraintGenerator):
+ pass
+class MySQLConstraintDropper(ansisql.ANSIConstraintDropper):
+ #def visit_constraint(self,constraint):
+ # if isinstance(constraint,sqlalchemy.schema.PrimaryKeyConstraint):
+ # return self._visit_constraint_pk(constraint)
+ # elif isinstance(constraint,sqlalchemy.schema.ForeignKeyConstraint):
+ # return self._visit_constraint_fk(constraint)
+ # return super(MySQLConstraintDropper,self).visit_constraint(constraint)
+ def visit_migrate_primary_key_constraint(self,constraint):
+ self.start_alter_table(constraint)
+ self.append("DROP PRIMARY KEY")
+ self.execute()
+
+ def visit_migrate_foreign_key_constraint(self,constraint):
+ self.start_alter_table(constraint)
+ self.append("DROP FOREIGN KEY ")
+ self.append(constraint.name)
+ self.execute()
+
+class MySQLDialect(ansisql.ANSIDialect):
+ columngenerator = MySQLColumnGenerator
+ columndropper = MySQLColumnDropper
+ schemachanger = MySQLSchemaChanger
+ constraintgenerator = MySQLConstraintGenerator
+ constraintdropper = MySQLConstraintDropper
diff --git a/migrate/changeset/databases/oracle.py b/migrate/changeset/databases/oracle.py
new file mode 100644
index 0000000..f27245c
--- /dev/null
+++ b/migrate/changeset/databases/oracle.py
@@ -0,0 +1,79 @@
+from migrate.changeset import ansisql,exceptions
+from sqlalchemy.databases import oracle as sa_base
+import sqlalchemy as sa
+
+OracleSchemaGenerator = sa_base.OracleSchemaGenerator
+
+class OracleColumnGenerator(OracleSchemaGenerator,ansisql.ANSIColumnGenerator):
+ pass
+class OracleColumnDropper(ansisql.ANSIColumnDropper):
+ pass
+class OracleSchemaChanger(OracleSchemaGenerator,ansisql.ANSISchemaChanger):
+ def get_column_specification(self,column,**kwargs):
+ # Ignore the NOT NULL generated
+ override_nullable = kwargs.pop('override_nullable',None)
+ if override_nullable:
+ orig = column.nullable
+ column.nullable = True
+ ret=super(OracleSchemaChanger,self).get_column_specification(column,**kwargs)
+ if override_nullable:
+ column.nullable = orig
+ return ret
+
+ def visit_column(self,delta):
+ keys = delta.keys()
+ if 'type' in keys or 'nullable' in keys or 'default' in keys:
+ self._run_subvisit(delta,self._visit_column_change)
+ if 'name' in keys:
+ self._run_subvisit(delta,self._visit_column_name)
+ def _visit_column_change(self,table_name,col_name,delta):
+ if not hasattr(delta,'result_column'):
+ # Oracle needs the whole column definition, not just a lone name/type
+ raise exceptions.NotSupportedError(
+ "A column object is required to do this")
+
+ column = delta.result_column
+ # Oracle cannot drop a default once created, but it can set it to null.
+ # We'll do that if default=None
+ # http://forums.oracle.com/forums/message.jspa?messageID=1273234#1273234
+ dropdefault_hack = (column.default is None and 'default' in delta.keys())
+ # Oracle apparently doesn't like it when we say "not null" if the
+ # column's already not null. Fudge it, so we don't need a new function
+ notnull_hack = ((not column.nullable) and ('nullable' not in delta.keys()))
+ # We need to specify NULL if we're removing a NOT NULL constraint
+ null_hack = (column.nullable and ('nullable' in delta.keys()))
+
+
+ if dropdefault_hack:
+ column.default = sa.PassiveDefault(sa.func.null())
+ if notnull_hack:
+ column.nullable = True
+ colspec=self.get_column_specification(column,override_nullable=null_hack)
+ if null_hack:
+ colspec += ' NULL'
+ if notnull_hack:
+ column.nullable = False
+ if dropdefault_hack:
+ column.default = None
+
+ self.start_alter_table(table_name)
+ self.append("MODIFY ")
+ self.append(colspec)
+class OracleConstraintCommon(object):
+ def get_constraint_name(self,cons):
+ # Oracle constraints can't guess their name like other DBs
+ if not cons.name:
+ raise exceptions.NotSupportedError(
+ "Oracle constraint names must be explicitly stated")
+ return cons.name
+class OracleConstraintGenerator(OracleConstraintCommon,ansisql.ANSIConstraintGenerator):
+ pass
+class OracleConstraintDropper(OracleConstraintCommon,ansisql.ANSIConstraintDropper):
+ pass
+
+class OracleDialect(ansisql.ANSIDialect):
+ columngenerator = OracleColumnGenerator
+ columndropper = OracleColumnDropper
+ schemachanger = OracleSchemaChanger
+ constraintgenerator = OracleConstraintGenerator
+ constraintdropper = OracleConstraintDropper
diff --git a/migrate/changeset/databases/postgres.py b/migrate/changeset/databases/postgres.py
new file mode 100644
index 0000000..adbd3fb
--- /dev/null
+++ b/migrate/changeset/databases/postgres.py
@@ -0,0 +1,23 @@
+from migrate.changeset import ansisql
+from sqlalchemy.databases import postgres as sa_base
+#import sqlalchemy as sa
+
+PGSchemaGenerator = sa_base.PGSchemaGenerator
+
+class PGColumnGenerator(PGSchemaGenerator,ansisql.ANSIColumnGenerator):
+ pass
+class PGColumnDropper(ansisql.ANSIColumnDropper):
+ pass
+class PGSchemaChanger(ansisql.ANSISchemaChanger):
+ pass
+class PGConstraintGenerator(ansisql.ANSIConstraintGenerator):
+ pass
+class PGConstraintDropper(ansisql.ANSIConstraintDropper):
+ pass
+
+class PGDialect(ansisql.ANSIDialect):
+ columngenerator = PGColumnGenerator
+ columndropper = PGColumnDropper
+ schemachanger = PGSchemaChanger
+ constraintgenerator = PGConstraintGenerator
+ constraintdropper = PGConstraintDropper
diff --git a/migrate/changeset/databases/sqlite.py b/migrate/changeset/databases/sqlite.py
new file mode 100644
index 0000000..5893201
--- /dev/null
+++ b/migrate/changeset/databases/sqlite.py
@@ -0,0 +1,49 @@
+from migrate.changeset import ansisql,constraint,exceptions
+from sqlalchemy.databases import sqlite as sa_base
+#import sqlalchemy as sa
+
+SQLiteSchemaGenerator = sa_base.SQLiteSchemaGenerator
+
+class SQLiteColumnGenerator(SQLiteSchemaGenerator,ansisql.ANSIColumnGenerator):
+ pass
+class SQLiteColumnDropper(ansisql.ANSIColumnDropper):
+ def visit_column(self,column):
+ raise exceptions.NotSupportedError("SQLite does not support "
+ "DROP COLUMN; see http://www.sqlite.org/lang_altertable.html")
+class SQLiteSchemaChanger(ansisql.ANSISchemaChanger):
+ def _not_supported(self,op):
+ raise exceptions.NotSupportedError("SQLite does not support "
+ "%s; see http://www.sqlite.org/lang_altertable.html"%op)
+ def _visit_column_nullable(self,table_name,col_name,delta):
+ return self._not_supported('ALTER TABLE')
+ def _visit_column_default(self,table_name,col_name,delta):
+ return self._not_supported('ALTER TABLE')
+ def _visit_column_type(self,table_name,col_name,delta):
+ return self._not_supported('ALTER TABLE')
+ def _visit_column_name(self,table_name,col_name,delta):
+ return self._not_supported('ALTER TABLE')
+ def visit_index(self,param):
+ self._not_supported('ALTER INDEX')
+class SQLiteConstraintGenerator(ansisql.ANSIConstraintGenerator):
+ def visit_migrate_primary_key_constraint(self,constraint):
+ tmpl = "CREATE UNIQUE INDEX %s ON %s ( %s )"
+ cols = ','.join([c.name for c in constraint.columns])
+ tname = constraint.table.name
+ name = constraint.name
+ msg = tmpl%(name,tname,cols)
+ self.append(msg)
+ self.execute()
+class SQLiteConstraintDropper(object):
+ def visit_migrate_primary_key_constraint(self,constraint):
+ tmpl = "DROP INDEX %s "
+ name = constraint.name
+ msg = tmpl%(name)
+ self.append(msg)
+ self.execute()
+
+class SQLiteDialect(ansisql.ANSIDialect):
+ columngenerator = SQLiteColumnGenerator
+ columndropper = SQLiteColumnDropper
+ schemachanger = SQLiteSchemaChanger
+ constraintgenerator = SQLiteConstraintGenerator
+ constraintdropper = SQLiteConstraintDropper
diff --git a/migrate/changeset/databases/visitor.py b/migrate/changeset/databases/visitor.py
new file mode 100644
index 0000000..437dc68
--- /dev/null
+++ b/migrate/changeset/databases/visitor.py
@@ -0,0 +1,20 @@
+import sqlalchemy as sa
+from migrate.changeset.databases import sqlite,postgres,mysql,oracle
+from migrate.changeset import ansisql
+
+# Map SA dialects to the corresponding Migrate extensions
+dialects = {
+ sa.engine.default.DefaultDialect : ansisql.ANSIDialect,
+ sa.databases.sqlite.SQLiteDialect : sqlite.SQLiteDialect,
+ sa.databases.postgres.PGDialect : postgres.PGDialect,
+ sa.databases.mysql.MySQLDialect : mysql.MySQLDialect,
+ sa.databases.oracle.OracleDialect : oracle.OracleDialect,
+}
+
+def get_engine_visitor(engine,name):
+ return get_dialect_visitor(engine.dialect,name)
+
+def get_dialect_visitor(sa_dialect,name):
+ sa_dialect_cls = sa_dialect.__class__
+ migrate_dialect_cls = dialects[sa_dialect_cls]
+ return migrate_dialect_cls.visitor(name)