Coverage Report - liquibase.sqlgenerator.core.AddColumnGenerator
 
Classes in this File Line Coverage Branch Coverage Complexity
AddColumnGenerator
20%
10/49
38%
17/44
6.75
 
 1  
 package liquibase.sqlgenerator.core;
 2  
 
 3  
 import java.util.ArrayList;
 4  
 import java.util.Arrays;
 5  
 import java.util.List;
 6  
 import java.util.regex.Matcher;
 7  
 import java.util.regex.Pattern;
 8  
 
 9  
 import liquibase.database.Database;
 10  
 import liquibase.database.core.CacheDatabase;
 11  
 import liquibase.database.core.DB2Database;
 12  
 import liquibase.database.core.DerbyDatabase;
 13  
 import liquibase.database.core.H2Database;
 14  
 import liquibase.database.core.MSSQLDatabase;
 15  
 import liquibase.database.core.MySQLDatabase;
 16  
 import liquibase.database.core.SQLiteDatabase;
 17  
 import liquibase.database.core.SybaseASADatabase;
 18  
 import liquibase.database.core.SybaseDatabase;
 19  
 import liquibase.database.structure.Column;
 20  
 import liquibase.database.structure.Table;
 21  
 import liquibase.database.typeconversion.TypeConverterFactory;
 22  
 import liquibase.exception.UnexpectedLiquibaseException;
 23  
 import liquibase.exception.ValidationErrors;
 24  
 import liquibase.sql.Sql;
 25  
 import liquibase.sql.UnparsedSql;
 26  
 import liquibase.sqlgenerator.SqlGeneratorChain;
 27  
 import liquibase.sqlgenerator.SqlGeneratorFactory;
 28  
 import liquibase.statement.ColumnConstraint;
 29  
 import liquibase.statement.ForeignKeyConstraint;
 30  
 import liquibase.statement.core.AddColumnStatement;
 31  
 import liquibase.statement.core.AddForeignKeyConstraintStatement;
 32  
 
 33  60
 public class AddColumnGenerator extends AbstractSqlGenerator<AddColumnStatement> {
 34  
 
 35  
     @Override
 36  
     public ValidationErrors validate(AddColumnStatement statement, Database database,
 37  
             SqlGeneratorChain sqlGeneratorChain) {
 38  41
         ValidationErrors validationErrors = new ValidationErrors();
 39  
 
 40  41
         validationErrors.checkRequiredField("columnName", statement.getColumnName());
 41  41
         validationErrors.checkRequiredField("columnType", statement.getColumnType());
 42  41
         validationErrors.checkRequiredField("tableName", statement.getTableName());
 43  
 
 44  41
         if (statement.isPrimaryKey()
 45  
                 && (database instanceof CacheDatabase || database instanceof H2Database
 46  
                         || database instanceof DB2Database || database instanceof DerbyDatabase || database instanceof SQLiteDatabase)) {
 47  10
             validationErrors.addError("Cannot add a primary key column");
 48  
         }
 49  
 
 50  41
         if (database instanceof MySQLDatabase && statement.isAutoIncrement() && !statement.isPrimaryKey()) {
 51  4
             validationErrors.addError("Cannot add a non-primary key identity column");
 52  
         }
 53  41
         return validationErrors;
 54  
     }
 55  
 
 56  
     @Override
 57  
     public Sql[] generateSql(AddColumnStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {
 58  
 
 59  0
         String alterTable = "ALTER TABLE "
 60  
                 + database.escapeTableName(statement.getSchemaName(), statement.getTableName())
 61  
                 + " ADD "
 62  
                 + database.escapeColumnName(statement.getSchemaName(), statement.getTableName(),
 63  
                         statement.getColumnName())
 64  
                 + " "
 65  
                 + TypeConverterFactory.getInstance().findTypeConverter(database)
 66  
                         .getDataType(statement.getColumnType(), statement.isAutoIncrement());
 67  
 
 68  0
         if (statement.isAutoIncrement() && database.supportsAutoIncrement()) {
 69  0
             alterTable += " " + database.getAutoIncrementClause();
 70  
         }
 71  
 
 72  0
         if (!statement.isNullable()) {
 73  0
             alterTable += " NOT NULL";
 74  
         } else {
 75  0
             if (database instanceof SybaseDatabase || database instanceof SybaseASADatabase) {
 76  0
                 alterTable += " NULL";
 77  
             }
 78  
         }
 79  
 
 80  0
         if (statement.isPrimaryKey()) {
 81  0
             alterTable += " PRIMARY KEY";
 82  
         }
 83  
 
 84  0
         if (statement.isUnique()) {
 85  0
             alterTable += " UNIQUE ";
 86  
         }
 87  
 
 88  0
         alterTable += getDefaultClause(statement, database);
 89  
 
 90  0
         List<Sql> returnSql = new ArrayList<Sql>();
 91  0
         returnSql.add(new UnparsedSql(alterTable, new Column().setTable(
 92  
                 new Table(statement.getTableName()).setSchema(statement.getSchemaName())).setName(
 93  
                 statement.getColumnName())));
 94  
 
 95  0
         addForeignKeyStatements(statement, database, returnSql);
 96  
 
 97  0
         return returnSql.toArray(new Sql[returnSql.size()]);
 98  
     }
 99  
 
 100  
     protected void addForeignKeyStatements(AddColumnStatement statement, Database database, List<Sql> returnSql) {
 101  0
         for (ColumnConstraint constraint : statement.getConstraints()) {
 102  0
             if (constraint instanceof ForeignKeyConstraint) {
 103  0
                 ForeignKeyConstraint fkConstraint = (ForeignKeyConstraint) constraint;
 104  0
                 Matcher referencesMatcher = Pattern.compile("([\\w\\._]+)\\(([\\w_]+)\\)").matcher(
 105  
                         fkConstraint.getReferences());
 106  0
                 if (!referencesMatcher.matches()) {
 107  0
                     throw new UnexpectedLiquibaseException("Don't know how to find table and column names from "
 108  
                             + fkConstraint.getReferences());
 109  
                 }
 110  0
                 String refSchemaName = null;
 111  0
                 String refTableName = referencesMatcher.group(1);
 112  0
                 if (refTableName.indexOf(".") > 0) {
 113  0
                     refSchemaName = refTableName.split("\\.")[0];
 114  0
                     refTableName = refTableName.split("\\.")[0];
 115  
                 }
 116  0
                 String refColName = referencesMatcher.group(2);
 117  
 
 118  0
                 AddForeignKeyConstraintStatement addForeignKeyConstraintStatement = new AddForeignKeyConstraintStatement(
 119  
                         fkConstraint.getForeignKeyName(), statement.getSchemaName(), statement.getTableName(),
 120  
                         statement.getColumnName(), refSchemaName, refTableName, refColName);
 121  0
                 returnSql.addAll(Arrays.asList(SqlGeneratorFactory.getInstance().generateSql(
 122  
                         addForeignKeyConstraintStatement, database)));
 123  0
             }
 124  
         }
 125  0
     }
 126  
 
 127  
     private String getDefaultClause(AddColumnStatement statement, Database database) {
 128  0
         String clause = "";
 129  0
         Object defaultValue = statement.getDefaultValue();
 130  0
         if (defaultValue != null) {
 131  0
             if (database instanceof MSSQLDatabase) {
 132  0
                 clause += " CONSTRAINT "
 133  
                         + ((MSSQLDatabase) database).generateDefaultConstraintName(statement.getTableName(),
 134  
                                 statement.getColumnName());
 135  
             }
 136  0
             clause += " DEFAULT "
 137  
                     + TypeConverterFactory.getInstance().findTypeConverter(database).getDataType(defaultValue)
 138  
                             .convertObjectToString(defaultValue, database);
 139  
         }
 140  0
         return clause;
 141  
     }
 142  
 
 143  
 }