View Javadoc

1   package liquibase.change.core;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import liquibase.change.AbstractChange;
7   import liquibase.change.Change;
8   import liquibase.change.ChangeMetaData;
9   import liquibase.change.ColumnConfig;
10  import liquibase.database.Database;
11  import liquibase.database.core.DB2Database;
12  import liquibase.database.core.SQLiteDatabase;
13  import liquibase.database.core.SQLiteDatabase.AlterTableVisitor;
14  import liquibase.database.structure.Index;
15  import liquibase.statement.SqlStatement;
16  import liquibase.statement.core.ReorganizeTableStatement;
17  import liquibase.statement.core.SetNullableStatement;
18  import liquibase.statement.core.UpdateStatement;
19  import liquibase.util.StringUtils;
20  
21  /**
22   * Adds a not-null constraint to an existing column.
23   */
24  public class AddNotNullConstraintChange extends AbstractChange {
25      private String schemaName;
26      private String tableName;
27      private String columnName;
28      private String defaultNullValue;
29      private String columnDataType;
30  
31      public AddNotNullConstraintChange() {
32          super("addNotNullConstraint", "Add Not-Null Constraint", ChangeMetaData.PRIORITY_DEFAULT);
33      }
34  
35      public String getSchemaName() {
36          return schemaName;
37      }
38  
39      public void setSchemaName(String schemaName) {
40          this.schemaName = StringUtils.trimToNull(schemaName);
41      }
42  
43      public String getTableName() {
44          return tableName;
45      }
46  
47      public void setTableName(String tableName) {
48          this.tableName = tableName;
49      }
50  
51      public String getColumnName() {
52          return columnName;
53      }
54  
55      public void setColumnName(String columnName) {
56          this.columnName = columnName;
57      }
58  
59      public String getDefaultNullValue() {
60          return defaultNullValue;
61      }
62  
63      public void setDefaultNullValue(String defaultNullValue) {
64          this.defaultNullValue = defaultNullValue;
65      }
66  
67      public String getColumnDataType() {
68          return columnDataType;
69      }
70  
71      public void setColumnDataType(String columnDataType) {
72          this.columnDataType = columnDataType;
73      }
74  
75      @Override
76      public SqlStatement[] generateStatements(Database database) {
77  
78          // // if (database instanceof SQLiteDatabase) {
79          // // return special statements for SQLite databases
80          // return generateStatementsForSQLiteDatabase(database);
81          // }
82  
83          List<SqlStatement> statements = new ArrayList<SqlStatement>();
84          String schemaName = getSchemaName() == null ? database.getDefaultSchemaName() : getSchemaName();
85  
86          if (defaultNullValue != null) {
87              statements.add(new UpdateStatement(schemaName, getTableName()).addNewColumnValue(getColumnName(),
88                      getDefaultNullValue()).setWhereClause(getColumnName() + " IS NULL"));
89          }
90  
91          statements
92                  .add(new SetNullableStatement(schemaName, getTableName(), getColumnName(), getColumnDataType(), false));
93          if (database instanceof DB2Database) {
94              statements.add(new ReorganizeTableStatement(schemaName, getTableName()));
95          }
96  
97          return statements.toArray(new SqlStatement[statements.size()]);
98      }
99  
100     private SqlStatement[] generateStatementsForSQLiteDatabase(Database database) {
101 
102         // SQLite does not support this ALTER TABLE operation until now.
103         // For more information see: http://www.sqlite.org/omitted.html.
104         // This is a small work around...
105 
106         List<SqlStatement> statements = new ArrayList<SqlStatement>();
107 
108         String schemaName = getSchemaName() == null ? database.getDefaultSchemaName() : getSchemaName();
109         if (defaultNullValue != null) {
110             statements.add(new UpdateStatement(schemaName, getTableName()).addNewColumnValue(getColumnName(),
111                     getDefaultNullValue()).setWhereClause(getColumnName() + " IS NULL"));
112         }
113 
114         // // ... test if column contains NULL values
115         // if (defaultNullValue == null) {
116         // List<Map> null_rows = null;
117         // try {
118         // null_rows = database.getExecutor().
119         // queryForList(new RawSqlStatement(
120         // "SELECT * FROM `"+
121         // database.escapeTableName(getSchemaName(), getTableName())+
122         // "` WHERE `"+getColumnName()+"` IS NULL;"));
123         // } catch (DatabaseException e) {
124         // e.printStackTrace();
125         // }
126         // if (null_rows.size()>0) {
127         // throw new UnsupportedChangeException(
128         // "Failed to add a Not-Null-Constraint because " +
129         // "some values are null. Use the " +
130         // "defaultNullValue attribute to define default " +
131         // "values for the existing null values.");
132         // }
133         // }
134 
135         // define alter table logic
136         AlterTableVisitor rename_alter_visitor = new AlterTableVisitor() {
137             @Override
138             public ColumnConfig[] getColumnsToAdd() {
139                 return new ColumnConfig[0];
140             }
141 
142             @Override
143             public boolean copyThisColumn(ColumnConfig column) {
144                 return true;
145             }
146 
147             @Override
148             public boolean createThisColumn(ColumnConfig column) {
149                 if (column.getName().equals(getColumnName())) {
150                     column.getConstraints().setNullable(false);
151                 }
152                 return true;
153             }
154 
155             @Override
156             public boolean createThisIndex(Index index) {
157                 return true;
158             }
159         };
160 
161         try {
162             // alter table
163             statements.addAll(SQLiteDatabase.getAlterTableStatements(rename_alter_visitor, database, getSchemaName(),
164                     getTableName()));
165         } catch (Exception e) {
166             e.printStackTrace();
167         }
168 
169         return statements.toArray(new SqlStatement[statements.size()]);
170     }
171 
172     @Override
173     protected Change[] createInverses() {
174         DropNotNullConstraintChange inverse = new DropNotNullConstraintChange();
175         inverse.setColumnName(getColumnName());
176         inverse.setSchemaName(getSchemaName());
177         inverse.setTableName(getTableName());
178         inverse.setColumnDataType(getColumnDataType());
179 
180         return new Change[] { inverse };
181     }
182 
183     @Override
184     public String getConfirmationMessage() {
185         return "Null constraint has been added to " + getTableName() + "." + getColumnName();
186     }
187 }