protected Column getAffectedColumn(AddColumnStatement statement) {
   return new Column()
       .setRelation(
           new Table()
               .setName(statement.getTableName())
               .setSchema(new Schema(statement.getCatalogName(), statement.getSchemaName())))
       .setName(statement.getColumnName());
 }
 @Override
 public Sql[] generateSql(
     AddColumnStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {
   if (statement.isMultiple()) {
     return generateMultipleColumns(statement.getColumns(), database);
   } else {
     return generateSingleColumn(statement, database);
   }
 }
  protected void addForeignKeyStatements(
      AddColumnStatement statement, Database database, List<Sql> returnSql) {
    for (ColumnConstraint constraint : statement.getConstraints()) {
      if (constraint instanceof ForeignKeyConstraint) {
        ForeignKeyConstraint fkConstraint = (ForeignKeyConstraint) constraint;
        String refSchemaName = null;
        String refTableName;
        String refColName;
        if (fkConstraint.getReferences() != null) {
          Matcher referencesMatcher =
              Pattern.compile("([\\w\\._]+)\\(([\\w_]+)\\)").matcher(fkConstraint.getReferences());
          if (!referencesMatcher.matches()) {
            throw new UnexpectedLiquibaseException(
                "Don't know how to find table and column names from "
                    + fkConstraint.getReferences());
          }
          refTableName = referencesMatcher.group(1);
          refColName = referencesMatcher.group(2);
        } else {
          refTableName = ((ForeignKeyConstraint) constraint).getReferencedTableName();
          refColName = ((ForeignKeyConstraint) constraint).getReferencedColumnNames();
        }

        if (refTableName.indexOf(".") > 0) {
          refSchemaName = refTableName.split("\\.")[0];
          refTableName = refTableName.split("\\.")[1];
        }

        AddForeignKeyConstraintStatement addForeignKeyConstraintStatement =
            new AddForeignKeyConstraintStatement(
                fkConstraint.getForeignKeyName(),
                statement.getCatalogName(),
                statement.getSchemaName(),
                statement.getTableName(),
                ColumnConfig.arrayFromNames(statement.getColumnName()),
                null,
                refSchemaName,
                refTableName,
                ColumnConfig.arrayFromNames(refColName));
        returnSql.addAll(
            Arrays.asList(
                SqlGeneratorFactory.getInstance()
                    .generateSql(addForeignKeyConstraintStatement, database)));
      }
    }
  }
 private String getDefaultClause(AddColumnStatement statement, Database database) {
   String clause = "";
   Object defaultValue = statement.getDefaultValue();
   if (defaultValue != null) {
     if (database instanceof OracleDatabase
         && defaultValue.toString().startsWith("GENERATED ALWAYS ")) {
       clause +=
           " "
               + DataTypeFactory.getInstance()
                   .fromObject(defaultValue, database)
                   .objectToSql(defaultValue, database);
     } else {
       if (database instanceof MSSQLDatabase) {
         clause +=
             " CONSTRAINT "
                 + ((MSSQLDatabase) database)
                     .generateDefaultConstraintName(
                         statement.getTableName(), statement.getColumnName());
       }
       if (defaultValue instanceof DatabaseFunction) {
         clause +=
             " DEFAULT "
                 + DataTypeFactory.getInstance()
                     .fromObject(defaultValue, database)
                     .objectToSql(defaultValue, database);
       } else {
         clause +=
             " DEFAULT "
                 + DataTypeFactory.getInstance()
                     .fromDescription(statement.getColumnType(), database)
                     .objectToSql(defaultValue, database);
       }
     }
   }
   return clause;
 }
  @Override
  public ValidationErrors validate(
      AddColumnStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {
    if (statement.isMultiple()) {
      ValidationErrors validationErrors = new ValidationErrors();
      AddColumnStatement firstColumn = statement.getColumns().get(0);

      for (AddColumnStatement column : statement.getColumns()) {
        validationErrors.addAll(validateSingleColumn(column, database));
        if (firstColumn.getTableName() != null
            && !firstColumn.getTableName().equals(column.getTableName())) {
          validationErrors.addError("All columns must be targeted at the same table");
        }
        if (column.isMultiple()) {
          validationErrors.addError("Nested multiple add column statements are not supported");
        }
      }
      return validationErrors;
    } else {
      return validateSingleColumn(statement, database);
    }
  }
  private ValidationErrors validateSingleColumn(AddColumnStatement statement, Database database) {
    ValidationErrors validationErrors = new ValidationErrors();

    validationErrors.checkRequiredField("columnName", statement.getColumnName());
    validationErrors.checkRequiredField("columnType", statement.getColumnType());
    validationErrors.checkRequiredField("tableName", statement.getTableName());

    if (statement.isPrimaryKey()
        && (database instanceof H2Database
            || database instanceof DB2Database
            || database instanceof DerbyDatabase
            || database instanceof SQLiteDatabase)) {
      validationErrors.addError("Cannot add a primary key column");
    }

    // TODO HsqlDatabase autoincrement on non primary key? other databases?
    if (database instanceof MySQLDatabase
        && statement.isAutoIncrement()
        && !statement.isPrimaryKey()) {
      validationErrors.addError("Cannot add a non-primary key identity column");
    }

    // TODO is this feature valid for other databases?
    if ((statement.getAddAfterColumn() != null) && !(database instanceof MySQLDatabase)) {
      validationErrors.addError("Cannot add column on specific position");
    }
    if ((statement.getAddBeforeColumn() != null)
        && !((database instanceof H2Database) || (database instanceof HsqlDatabase))) {
      validationErrors.addError("Cannot add column on specific position");
    }
    if ((statement.getAddAtPosition() != null) && !(database instanceof FirebirdDatabase)) {
      validationErrors.addError("Cannot add column on specific position");
    }

    return validationErrors;
  }
 protected void addUniqueConstrantStatements(
     AddColumnStatement statement, Database database, List<Sql> returnSql) {
   if (statement.isUnique()) {
     AddUniqueConstraintStatement addConstraintStmt =
         new AddUniqueConstraintStatement(
             statement.getCatalogName(),
             statement.getSchemaName(),
             statement.getTableName(),
             ColumnConfig.arrayFromNames(statement.getColumnName()),
             statement.getUniqueStatementName());
     returnSql.addAll(
         Arrays.asList(
             SqlGeneratorFactory.getInstance().generateSql(addConstraintStmt, database)));
   }
 }
  protected String generateSingleColumnSQL(AddColumnStatement statement, Database database) {
    DatabaseDataType columnType =
        DataTypeFactory.getInstance()
            .fromDescription(
                statement.getColumnType()
                    + (statement.isAutoIncrement() ? "{autoIncrement:true}" : ""),
                database)
            .toDatabaseDataType(database);

    String alterTable =
        " ADD "
            + database.escapeColumnName(
                statement.getCatalogName(),
                statement.getSchemaName(),
                statement.getTableName(),
                statement.getColumnName())
            + " "
            + columnType;

    if (statement.isAutoIncrement() && database.supportsAutoIncrement()) {
      AutoIncrementConstraint autoIncrementConstraint = statement.getAutoIncrementConstraint();
      alterTable +=
          " "
              + database.getAutoIncrementClause(
                  autoIncrementConstraint.getStartWith(), autoIncrementConstraint.getIncrementBy());
    }

    alterTable += getDefaultClause(statement, database);

    if (!statement.isNullable()) {
      alterTable += " NOT NULL";
    } else {
      if (database instanceof SybaseDatabase
          || database instanceof SybaseASADatabase
          || database instanceof MySQLDatabase
          || (database instanceof MSSQLDatabase
              && columnType.toString().equalsIgnoreCase("timestamp"))) {
        alterTable += " NULL";
      }
    }

    if (statement.isPrimaryKey()) {
      alterTable += " PRIMARY KEY";
    }

    if (database instanceof MySQLDatabase && statement.getRemarks() != null) {
      alterTable += " COMMENT '" + statement.getRemarks() + "' ";
    }

    if (statement.getAddAfterColumn() != null && !statement.getAddAfterColumn().isEmpty()) {
      alterTable += " AFTER `" + statement.getAddAfterColumn() + "` ";
    }

    return alterTable;
  }
 protected String generateSingleColumBaseSQL(AddColumnStatement statement, Database database) {
   return "ALTER TABLE "
       + database.escapeTableName(
           statement.getCatalogName(), statement.getSchemaName(), statement.getTableName());
 }