protected void alterColumnDropForeignKey(DdlWrite writer, AlterColumn alter) throws IOException {

    writer
        .apply()
        .append(
            platformDdl.alterTableDropForeignKey(alter.getTableName(), alter.getDropForeignKey()))
        .endOfStatement();
  }
  protected void alterColumnNotnull(DdlWrite writer, AlterColumn alter) throws IOException {

    String ddl =
        platformDdl.alterColumnNotnull(
            alter.getTableName(), alter.getColumnName(), alter.isNotnull());
    if (hasValue(ddl)) {
      writer.apply().append(ddl).endOfStatement();
    }
  }
  protected void addUniqueConstraint(DdlWrite writer, AlterColumn alter, String uqName)
      throws IOException {

    String[] cols = {alter.getColumnName()};

    writer
        .apply()
        .append(platformDdl.alterTableAddUniqueConstraint(alter.getTableName(), uqName, cols))
        .endOfStatement();

    writer
        .rollbackForeignKeys()
        .append(platformDdl.dropIndex(uqName, alter.getTableName()))
        .endOfStatement();
  }
  /** This is mysql specific - alter all the base attributes of the column together. */
  protected void alterColumnBaseAttributes(DdlWrite writer, AlterColumn alter) throws IOException {

    String ddl = platformDdl.alterColumnBaseAttributes(alter);
    if (hasValue(ddl)) {
      writer.apply().append(ddl).endOfStatement();
      if (isTrue(alter.isWithHistory()) && alter.getType() != null) {
        // mysql and sql server column type change allowing nulls in the history table column
        AlterColumn alterHistoryColumn = new AlterColumn();
        alterHistoryColumn.setTableName(historyTable(alter.getTableName()));
        alterHistoryColumn.setColumnName(alter.getColumnName());
        alterHistoryColumn.setType(alter.getType());
        String histColumnDdl = platformDdl.alterColumnBaseAttributes(alterHistoryColumn);
        writer.apply().append(histColumnDdl).endOfStatement();
      }
    }
  }
  protected void alterColumnAddForeignKey(DdlWrite writer, AlterColumn alterColumn)
      throws IOException {

    String tableName = alterColumn.getTableName();
    String fkName = alterColumn.getForeignKeyName();
    String[] cols = {alterColumn.getColumnName()};
    String references = alterColumn.getReferences();
    int pos = references.lastIndexOf('.');
    if (pos == -1) {
      throw new IllegalStateException(
          "Expecting period '.' character for table.column split but not found in ["
              + references
              + "]");
    }
    String refTableName = references.substring(0, pos);
    String refColumnName = references.substring(pos + 1);
    String[] refCols = {refColumnName};

    alterTableAddForeignKey(writer.apply(), fkName, tableName, cols, refTableName, refCols);
  }
  protected void alterColumnType(DdlWrite writer, AlterColumn alter) throws IOException {

    String ddl =
        platformDdl.alterColumnType(alter.getTableName(), alter.getColumnName(), alter.getType());
    if (hasValue(ddl)) {
      writer.apply().append(ddl).endOfStatement();
      if (isTrue(alter.isWithHistory())) {
        // apply same type change to matching column in the history table
        ddl =
            platformDdl.alterColumnType(
                historyTable(alter.getTableName()), alter.getColumnName(), alter.getType());
        writer.apply().append(ddl).endOfStatement();
      }
    }
  }
  protected void alterColumnAddUniqueConstraint(DdlWrite writer, AlterColumn alter)
      throws IOException {

    addUniqueConstraint(writer, alter, alter.getUnique());
  }
  /** Add all the appropriate changes based on the column changes. */
  @Override
  public void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException {

    if (isTrue(alterColumn.isHistoryExclude())) {
      regenerateHistoryTriggers(
          alterColumn.getTableName(),
          HistoryTableUpdate.Change.EXCLUDE,
          alterColumn.getColumnName());
    } else if (isFalse(alterColumn.isHistoryExclude())) {
      regenerateHistoryTriggers(
          alterColumn.getTableName(),
          HistoryTableUpdate.Change.INCLUDE,
          alterColumn.getColumnName());
    }

    if (hasValue(alterColumn.getDropForeignKey())) {
      alterColumnDropForeignKey(writer, alterColumn);
    }
    if (hasValue(alterColumn.getReferences())) {
      alterColumnAddForeignKey(writer, alterColumn);
    }

    if (hasValue(alterColumn.getDropUnique())) {
      alterColumnDropUniqueConstraint(writer, alterColumn);
    }
    if (hasValue(alterColumn.getUnique())) {
      alterColumnAddUniqueConstraint(writer, alterColumn);
    }
    if (hasValue(alterColumn.getUniqueOneToOne())) {
      alterColumnAddUniqueOneToOneConstraint(writer, alterColumn);
    }

    boolean alterBaseAttributes = false;
    if (hasValue(alterColumn.getType())) {
      alterColumnType(writer, alterColumn);
      alterBaseAttributes = true;
    }
    if (hasValue(alterColumn.getDefaultValue())) {
      alterColumnDefaultValue(writer, alterColumn);
      alterBaseAttributes = true;
    }
    if (alterColumn.isNotnull() != null) {
      alterColumnNotnull(writer, alterColumn);
      alterBaseAttributes = true;
    }

    if (alterBaseAttributes) {
      alterColumnBaseAttributes(writer, alterColumn);
    }
  }