def _gen_col_sql()

in core/lib/sqlparse/diff.py [0:0]


    def _gen_col_sql(self):
        """
        Generate the column section for ALTER TABLE statement
        """
        segments = []
        old_columns = {col.name: col for col in self.left.column_list}
        new_columns = {col.name: col for col in self.right.column_list}
        old_column_names = [col.name for col in self.left.column_list]
        new_column_names = [col.name for col in self.right.column_list]

        # Drop columns
        for col in self.left.column_list:
            if col.name not in new_columns.keys():
                segments.append("DROP `{}`".format(escape(col.name)))
                old_column_names.remove(col.name)
                self.add_alter_type(ColAlterType.DROP_COL)

        # Add columns
        # If the added column is not at the end, recognize that as reordering columns
        handled_cols = []
        for idx, col in enumerate(self.right.column_list):
            if col.name not in old_columns.keys():
                if idx == 0:
                    position = "FIRST"
                    if (
                        old_column_names
                        and ColAlterType.DROP_COL not in self._alter_types
                    ):
                        self.add_alter_type(ColAlterType.REORDER_COL)
                    old_column_names = [col.name] + old_column_names
                else:
                    position = "AFTER `{}`".format(
                        escape(self.right.column_list[idx - 1].name)
                    )
                    new_idx = (
                        old_column_names.index(self.right.column_list[idx - 1].name) + 1
                    )
                    if (
                        new_idx != len(old_column_names)
                        and ColAlterType.DROP_COL not in self._alter_types
                    ):
                        self.add_alter_type(ColAlterType.REORDER_COL)
                    old_column_names = (
                        old_column_names[:new_idx]
                        + [col.name]
                        + old_column_names[new_idx:]
                    )
                handled_cols.append(col.name)
                self.add_alter_type(ColAlterType.ADD_COL)
                if col.column_type == "JSON":
                    self.add_alter_type(NewMysql80FeatureAlterType.JSON)
                if col.auto_increment:
                    self.add_alter_type(ColAlterType.ADD_AUTO_INC_COL)
                segments.append("ADD {} {}".format(col.to_sql(), position))

        # Adjust position
        # The idea here is to compare column ancestor if they are the same between
        # old and new column list, this means the position of this particular
        # column hasn't been changed. Otherwise add a MODIFY clause to change the
        # position
        for idx, col_name in enumerate(new_column_names):
            # If the column is recently added, then skip because it's already
            # in the DDL
            if col_name in handled_cols:
                continue
            # Get column definition
            col = new_columns[col_name]
            old_pos = old_column_names.index(col_name)

            # If the first column is diferent, we need to adjust the sequence
            if idx == 0:
                if old_pos == 0:
                    continue
                segments.append("MODIFY {} FIRST".format(col.to_sql()))
                handled_cols.append(col_name)
                self.add_alter_type(ColAlterType.REORDER_COL)
                continue

            # If this column has the same ancestor then it means there's no sequence
            # adjustment needed
            if new_column_names[idx - 1] == old_column_names[old_pos - 1]:
                continue

            segments.append(
                "MODIFY {} AFTER `{}`".format(
                    col.to_sql(), escape(new_column_names[idx - 1])
                )
            )
            handled_cols.append(col_name)
            self.add_alter_type(ColAlterType.REORDER_COL)

        # Modify columns
        for col in self.right.column_list:
            if col.name in old_columns and col != old_columns[col.name]:
                # If the column has been taken care of because of sequence change
                # previously we can skip the work here
                if col.name in handled_cols:
                    continue
                self._update_col_attrs_changes(col, old_columns[col.name])
                segments.append("MODIFY {}".format(col.to_sql()))
        return segments