| 1 | """ |
|---|
| 2 | Oracle database specific implementations of changeset classes. |
|---|
| 3 | """ |
|---|
| 4 | |
|---|
| 5 | from migrate.changeset import ansisql, exceptions |
|---|
| 6 | from sqlalchemy.databases import oracle as sa_base |
|---|
| 7 | import sqlalchemy as sa |
|---|
| 8 | |
|---|
| 9 | OracleSchemaGenerator = sa_base.OracleSchemaGenerator |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | class OracleColumnGenerator(OracleSchemaGenerator, |
|---|
| 13 | ansisql.ANSIColumnGenerator): |
|---|
| 14 | pass |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | class OracleColumnDropper(ansisql.ANSIColumnDropper): |
|---|
| 18 | pass |
|---|
| 19 | |
|---|
| 20 | |
|---|
| 21 | class OracleSchemaChanger(OracleSchemaGenerator, ansisql.ANSISchemaChanger): |
|---|
| 22 | |
|---|
| 23 | def get_column_specification(self, column, **kwargs): |
|---|
| 24 | # Ignore the NOT NULL generated |
|---|
| 25 | override_nullable = kwargs.pop('override_nullable', None) |
|---|
| 26 | if override_nullable: |
|---|
| 27 | orig = column.nullable |
|---|
| 28 | column.nullable = True |
|---|
| 29 | ret = super(OracleSchemaChanger, self).get_column_specification( |
|---|
| 30 | column, **kwargs) |
|---|
| 31 | if override_nullable: |
|---|
| 32 | column.nullable = orig |
|---|
| 33 | return ret |
|---|
| 34 | |
|---|
| 35 | def visit_column(self, delta): |
|---|
| 36 | keys = delta.keys() |
|---|
| 37 | if 'type' in keys or 'nullable' in keys or 'default' in keys \ |
|---|
| 38 | or 'server_default' in keys: |
|---|
| 39 | self._run_subvisit(delta, self._visit_column_change) |
|---|
| 40 | if 'name' in keys: |
|---|
| 41 | self._run_subvisit(delta, self._visit_column_name) |
|---|
| 42 | |
|---|
| 43 | def _visit_column_change(self, table_name, col_name, delta): |
|---|
| 44 | if not hasattr(delta, 'result_column'): |
|---|
| 45 | # Oracle needs the whole column definition, not just a |
|---|
| 46 | # lone name/type |
|---|
| 47 | raise exceptions.NotSupportedError( |
|---|
| 48 | "A column object is required to do this") |
|---|
| 49 | |
|---|
| 50 | column = delta.result_column |
|---|
| 51 | # Oracle cannot drop a default once created, but it can set it |
|---|
| 52 | # to null. We'll do that if default=None |
|---|
| 53 | # http://forums.oracle.com/forums/message.jspa?\ |
|---|
| 54 | # messageID=1273234#1273234 |
|---|
| 55 | dropdefault_hack = (column.server_default is None \ |
|---|
| 56 | and 'server_default' in delta.keys()) |
|---|
| 57 | # Oracle apparently doesn't like it when we say "not null" if |
|---|
| 58 | # the column's already not null. Fudge it, so we don't need a |
|---|
| 59 | # new function |
|---|
| 60 | notnull_hack = ((not column.nullable) \ |
|---|
| 61 | and ('nullable' not in delta.keys())) |
|---|
| 62 | # We need to specify NULL if we're removing a NOT NULL |
|---|
| 63 | # constraint |
|---|
| 64 | null_hack = (column.nullable and ('nullable' in delta.keys())) |
|---|
| 65 | |
|---|
| 66 | if dropdefault_hack: |
|---|
| 67 | column.server_default = sa.PassiveDefault(sa.sql.null()) |
|---|
| 68 | if notnull_hack: |
|---|
| 69 | column.nullable = True |
|---|
| 70 | colspec=self.get_column_specification(column, |
|---|
| 71 | override_nullable=null_hack) |
|---|
| 72 | if null_hack: |
|---|
| 73 | colspec += ' NULL' |
|---|
| 74 | if notnull_hack: |
|---|
| 75 | column.nullable = False |
|---|
| 76 | if dropdefault_hack: |
|---|
| 77 | column.server_default = None |
|---|
| 78 | |
|---|
| 79 | self.start_alter_table(table_name) |
|---|
| 80 | self.append("MODIFY ") |
|---|
| 81 | self.append(colspec) |
|---|
| 82 | |
|---|
| 83 | |
|---|
| 84 | class OracleConstraintCommon(object): |
|---|
| 85 | |
|---|
| 86 | def get_constraint_name(self, cons): |
|---|
| 87 | # Oracle constraints can't guess their name like other DBs |
|---|
| 88 | if not cons.name: |
|---|
| 89 | raise exceptions.NotSupportedError( |
|---|
| 90 | "Oracle constraint names must be explicitly stated") |
|---|
| 91 | return cons.name |
|---|
| 92 | |
|---|
| 93 | |
|---|
| 94 | class OracleConstraintGenerator(OracleConstraintCommon, |
|---|
| 95 | ansisql.ANSIConstraintGenerator): |
|---|
| 96 | pass |
|---|
| 97 | |
|---|
| 98 | |
|---|
| 99 | class OracleConstraintDropper(OracleConstraintCommon, |
|---|
| 100 | ansisql.ANSIConstraintDropper): |
|---|
| 101 | pass |
|---|
| 102 | |
|---|
| 103 | |
|---|
| 104 | class OracleDialect(ansisql.ANSIDialect): |
|---|
| 105 | columngenerator = OracleColumnGenerator |
|---|
| 106 | columndropper = OracleColumnDropper |
|---|
| 107 | schemachanger = OracleSchemaChanger |
|---|
| 108 | constraintgenerator = OracleConstraintGenerator |
|---|
| 109 | constraintdropper = OracleConstraintDropper |
|---|