|
1 | 1 | import logging
|
2 | 2 |
|
3 | 3 | from typing import Optional
|
| 4 | +from typing import Any |
4 | 5 |
|
5 | 6 | from sqlalchemy.ext.compiler import compiles
|
6 | 7 | from sqlalchemy.sql.base import Executable
|
7 | 8 | from sqlalchemy.sql.elements import ClauseElement
|
| 9 | +from sqlalchemy.sql.type_api import TypeEngine |
| 10 | +from sqlalchemy.sql import table |
| 11 | +from sqlalchemy import types |
8 | 12 |
|
9 | 13 | from alembic.ddl import DefaultImpl
|
10 | 14 | from alembic.ddl.base import ColumnNullable
|
11 | 15 | from alembic.ddl.base import ColumnType
|
12 | 16 | from alembic.ddl.base import ColumnName
|
| 17 | +from alembic.ddl.base import AddColumn |
| 18 | +from alembic.ddl.base import DropColumn |
13 | 19 | from alembic.ddl.base import Column
|
14 | 20 | from alembic.ddl.base import alter_table
|
15 | 21 | from alembic.ddl.base import alter_column
|
16 | 22 | from alembic.ddl.base import format_type
|
17 | 23 | from alembic.ddl.base import format_column_name
|
18 |
| - |
19 | 24 | from .base import IRISDDLCompiler
|
20 | 25 |
|
21 | 26 | log = logging.getLogger(__name__)
|
22 | 27 |
|
| 28 | +# IRIS Interprets these types as %Streams, and no direct type change is available |
| 29 | +_as_stream = [ |
| 30 | + types.LargeBinary, |
| 31 | + types.BLOB, |
| 32 | + types.CLOB, |
| 33 | +] |
| 34 | + |
23 | 35 |
|
24 | 36 | class IRISImpl(DefaultImpl):
|
25 | 37 | __dialect__ = "iris"
|
@@ -77,6 +89,60 @@ def drop_column(
|
77 | 89 | self._exec(_ExecDropForeignKey(table_name, fkey[0], schema))
|
78 | 90 | super().drop_column(table_name, column, schema, **kw)
|
79 | 91 |
|
| 92 | + def alter_column( |
| 93 | + self, |
| 94 | + table_name: str, |
| 95 | + column_name: str, |
| 96 | + type_: Optional[TypeEngine] = None, |
| 97 | + existing_type: Optional[TypeEngine] = None, |
| 98 | + schema: Optional[str] = None, |
| 99 | + name: Optional[str] = None, |
| 100 | + **kw: Any, |
| 101 | + ) -> None: |
| 102 | + if existing_type.__class__ not in _as_stream and type_.__class__ in _as_stream: |
| 103 | + """ |
| 104 | + To change column type to %Stream |
| 105 | + * rename the column with a new name with suffix `__superset_tmp` |
| 106 | + * create a new column with the old name |
| 107 | + * copy data from an old column to new column |
| 108 | + * drop old column |
| 109 | + * fix missing parameters, such as nullable |
| 110 | + """ |
| 111 | + tmp_column = f"{column_name}__superset_tmp" |
| 112 | + self._exec(ColumnName(table_name, column_name, tmp_column, schema=schema)) |
| 113 | + new_kw = {} |
| 114 | + self._exec( |
| 115 | + AddColumn( |
| 116 | + table_name, |
| 117 | + Column(column_name, type_=type_, **new_kw), |
| 118 | + schema=schema, |
| 119 | + ) |
| 120 | + ) |
| 121 | + tab = table( |
| 122 | + table_name, |
| 123 | + Column(column_name, key="new_col"), |
| 124 | + Column(tmp_column, key="old_col"), |
| 125 | + schema=schema, |
| 126 | + ) |
| 127 | + self._exec(tab.update().values({tab.c.new_col: tab.c.old_col})) |
| 128 | + self._exec(DropColumn(table_name, Column(tmp_column), schema=schema)) |
| 129 | + new_kw = {} |
| 130 | + for k in ["server_default", "nullable", "autoincrement"]: |
| 131 | + if f"existing_{k}" in kw: |
| 132 | + new_kw[k] = kw[f"existing_{k}"] |
| 133 | + return super().alter_column( |
| 134 | + table_name, column_name, schema=schema, name=name, **new_kw |
| 135 | + ) |
| 136 | + return super().alter_column( |
| 137 | + table_name, |
| 138 | + column_name, |
| 139 | + type_=type_, |
| 140 | + existing_type=existing_type, |
| 141 | + schema=schema, |
| 142 | + name=name, |
| 143 | + **kw, |
| 144 | + ) |
| 145 | + |
80 | 146 |
|
81 | 147 | class _ExecDropForeignKey(Executable, ClauseElement):
|
82 | 148 | inherit_cache = False
|
|
0 commit comments