2 * Copyright (C) 2009 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
9 package eu
.etaxonomy
.cdm
.database
.update
;
11 import java
.util
.List
;
13 import org
.apache
.logging
.log4j
.LogManager
;
14 import org
.apache
.logging
.log4j
.Logger
;
16 import eu
.etaxonomy
.cdm
.common
.monitor
.IProgressMonitor
;
17 import eu
.etaxonomy
.cdm
.database
.DatabaseTypeEnum
;
18 import eu
.etaxonomy
.cdm
.database
.ICdmDataSource
;
24 public class ColumnAdder
extends AuditedSchemaUpdaterStepBase
{
26 private static final Logger logger
= LogManager
.getLogger();
28 private final String newColumnName
;
29 private final Datatype columnType
;
30 private final Integer size
;
31 private final Integer scale
;
32 private final Object defaultValue
;
33 private boolean isNotNull
;
34 private final String referencedTable
;
39 public static final ColumnAdder
NewIntegerInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
, boolean includeAudTable
, boolean notNull
, String referencedTable
){
40 return new ColumnAdder(stepList
, stepName
, tableName
, newColumnName
, Datatype
.INTEGER
, null, null, includeAudTable
, null, notNull
, referencedTable
);
43 public static final ColumnAdder
NewIntegerInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
, boolean includeAudTable
, Integer defaultValue
, boolean notNull
){
44 return new ColumnAdder(stepList
, stepName
, tableName
, newColumnName
, Datatype
.INTEGER
, null, null, includeAudTable
, defaultValue
, notNull
, null);
47 public static final ColumnAdder
NewTinyIntegerInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
, boolean includeAudTable
, boolean notNull
){
48 return new ColumnAdder(stepList
, stepName
, tableName
, newColumnName
, Datatype
.TINYINTEGER
, null, null, includeAudTable
, null, notNull
, null);
51 public static final ColumnAdder
NewDoubleInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
, boolean includeAudTable
, boolean notNull
){
52 return new ColumnAdder(stepList
, stepName
, tableName
, newColumnName
, Datatype
.DOUBLE
, null, null, includeAudTable
, null, notNull
, null);
55 public static final ColumnAdder
NewDecimalInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
, int precision
, int scale
, boolean includeAudTable
, Integer defaultValue
, boolean notNull
){
56 return new ColumnAdder(stepList
, stepName
, tableName
, newColumnName
, Datatype
.BIGDECIMAL
, precision
, scale
, includeAudTable
, defaultValue
, notNull
, null);
59 public static final ColumnAdder
NewBooleanInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
, boolean includeAudTable
, Boolean defaultValue
){
60 return new ColumnAdder(stepList
, stepName
, tableName
, newColumnName
, Datatype
.BIT
, null, null, includeAudTable
, defaultValue
, false, null);
64 * Adds a string column with length 255 and default value <code>null</code>
66 public static final ColumnAdder
NewStringInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
, boolean includeAudTable
){
67 return new ColumnAdder(stepList
, stepName
, tableName
, newColumnName
, Datatype
.VARCHAR
, 255, null, includeAudTable
, null, false, null);
70 public static final ColumnAdder
NewDTYPEInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String defaultValue
, boolean includeAudTable
){
71 return new ColumnAdder(stepList
, stepName
, tableName
, "DTYPE", Datatype
.VARCHAR
, 31, null, includeAudTable
, defaultValue
, true, null);
75 * Adds a string column with the given length and default value <code>null</code>
77 public static final ColumnAdder
NewStringInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
, int length
, boolean includeAudTable
){
78 return new ColumnAdder(stepList
, stepName
, tableName
, newColumnName
, Datatype
.VARCHAR
, length
, null, includeAudTable
, null, false, null);
82 * Adds a string column with the given length and the given default value
84 public static final ColumnAdder
NewStringInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
, int length
, String defaultValue
, boolean includeAudTable
){
85 return new ColumnAdder(stepList
, stepName
, tableName
, newColumnName
, Datatype
.VARCHAR
, length
, null, includeAudTable
, defaultValue
, false, null);
88 public static final ColumnAdder
NewClobInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
, boolean includeAudTable
){
89 return new ColumnAdder(stepList
, stepName
, tableName
, newColumnName
, Datatype
.CLOB
, null, null, includeAudTable
, null, false, null);
92 public static final ColumnAdder
NewDateTimeInstance(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
, boolean includeAudTable
, boolean notNull
){
93 return new ColumnAdder(stepList
, stepName
, tableName
, newColumnName
, Datatype
.DATETIME
, null, null, includeAudTable
, null, notNull
, null);
96 protected ColumnAdder(List
<?
extends ISchemaUpdaterStep
> stepList
, String stepName
, String tableName
, String newColumnName
,
97 Datatype columnType
, Integer size
, Integer scale
, boolean includeAudTable
, Object defaultValue
, boolean notNull
, String referencedTable
) {
98 super(stepList
, stepName
, tableName
, includeAudTable
);
99 this.newColumnName
= newColumnName
;
100 this.columnType
= columnType
;
102 this.defaultValue
= defaultValue
;
103 this.isNotNull
= notNull
;
104 this.referencedTable
= referencedTable
;
108 public ColumnAdder
setNotNull(boolean isNotNull
) {
109 this.isNotNull
= isNotNull
;
114 protected void invokeOnTable(String tableName
, ICdmDataSource datasource
,
115 IProgressMonitor monitor
, CaseType caseType
, SchemaUpdateResult result
) {
118 String updateQuery
= getUpdateQueryString(tableName
, datasource
, monitor
);
119 datasource
.executeUpdate(updateQuery
);
121 if (defaultValue
instanceof Boolean
){
122 String defaultValueQuery
= "UPDATE @tableName SET @columnName = " + (defaultValue
== null ?
"NULL" : getBoolean((Boolean
) defaultValue
, datasource
));
123 defaultValueQuery
= defaultValueQuery
.replace("@tableName", tableName
);
124 defaultValueQuery
= defaultValueQuery
.replace("@columnName", newColumnName
);
125 datasource
.executeUpdate(defaultValueQuery
);
126 }else if (defaultValue
instanceof Integer
){
127 String defaultValueQuery
= "UPDATE @tableName SET @columnName = " + (defaultValue
== null ?
"NULL" : defaultValue
);
128 defaultValueQuery
= defaultValueQuery
.replace("@tableName", tableName
);
129 defaultValueQuery
= defaultValueQuery
.replace("@columnName", newColumnName
);
130 datasource
.executeUpdate(defaultValueQuery
);
131 }else if (defaultValue
instanceof String
){
132 String defaultValueQuery
= "UPDATE @tableName SET @columnName = " + (defaultValue
== null ?
"NULL" : "'" + defaultValue
+ "'");
133 defaultValueQuery
= defaultValueQuery
.replace("@tableName", tableName
);
134 defaultValueQuery
= defaultValueQuery
.replace("@columnName", newColumnName
);
135 datasource
.executeUpdate(defaultValueQuery
);
136 }else if (defaultValue
!= null){
137 logger
.warn("Default Value not implemented for type " + defaultValue
.getClass().getName());
139 if (referencedTable
!= null){
140 TableCreator
.makeForeignKey(tableName
, datasource
, monitor
, newColumnName
, referencedTable
, caseType
, result
);
143 } catch ( Exception e
) {
144 String message
= "Unhandled exception when trying to add column " +
145 newColumnName
+ " for table " + tableName
;
146 monitor
.warning(message
, e
);
148 result
.addException(e
, message
, getStepName());
154 * Returns the update query string. tableName must already be cased correctly. See {@link CaseType}.
155 * @param tableName correctly cased table name
156 * @param datasource data source
157 * @param monitor monitor
158 * @return the query string
159 * @throws DatabaseTypeNotSupportedException
161 public String
getUpdateQueryString(String tableName
, ICdmDataSource datasource
, IProgressMonitor monitor
) throws DatabaseTypeNotSupportedException
{
163 DatabaseTypeEnum type
= datasource
.getDatabaseType();
164 String databaseColumnType
= this.columnType
.format(datasource
, size
, scale
);
166 if (type
.equals(DatabaseTypeEnum
.SqlServer2005
)){
167 //MySQL allows both syntaxes
168 updateQuery
= "ALTER TABLE @tableName ADD @columnName @columnType";
169 }else if (type
.equals(DatabaseTypeEnum
.H2
) || type
.equals(DatabaseTypeEnum
.PostgreSQL
) || type
.equals(DatabaseTypeEnum
.MySQL
)){
170 updateQuery
= "ALTER TABLE @tableName @addSeparator @columnName @columnType";
173 String warning
= "Update step '" + this.getStepName() + "' is not supported by " + type
.getName();
174 monitor
.warning(warning
);
175 throw new DatabaseTypeNotSupportedException(warning
);
177 if (isNotNull
&& !isAuditing
){
178 updateQuery
+= " NOT NULL";
180 updateQuery
= updateQuery
.replace("@tableName", tableName
);
181 updateQuery
= updateQuery
.replace("@columnName", newColumnName
);
182 updateQuery
= updateQuery
.replace("@columnType", databaseColumnType
);
183 updateQuery
= updateQuery
.replace("@addSeparator", getAddColumnSeperator(datasource
));
189 * Returns the sql keywords for adding a column. This is usually 'ADD' or 'ADD COLUMN'
192 * @throws DatabaseTypeNotSupportedException
194 public static String
getAddColumnSeperator(ICdmDataSource datasource
) throws DatabaseTypeNotSupportedException
{
195 DatabaseTypeEnum type
= datasource
.getDatabaseType();
196 if (type
.equals(DatabaseTypeEnum
.SqlServer2005
)){
198 }else if (type
.equals(DatabaseTypeEnum
.H2
) || type
.equals(DatabaseTypeEnum
.PostgreSQL
) || type
.equals(DatabaseTypeEnum
.MySQL
)){
199 return "ADD COLUMN ";
201 throw new DatabaseTypeNotSupportedException(datasource
.getName());
205 public String
getReferencedTable() {
206 return referencedTable
;
209 public String
getNewColumnName() {
210 return newColumnName
;