-// $Id$\r
-/**\r
-* Copyright (C) 2009 EDIT\r
-* European Distributed Institute of Taxonomy \r
-* http://www.e-taxonomy.eu\r
-* \r
-* The contents of this file are subject to the Mozilla Public License Version 1.1\r
-* See LICENSE.TXT at the top of this package for the full license terms.\r
-*/\r
-package eu.etaxonomy.cdm.database.update;\r
-\r
-import org.apache.log4j.Logger;\r
-\r
-import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;\r
-import eu.etaxonomy.cdm.database.DatabaseTypeEnum;\r
-import eu.etaxonomy.cdm.database.ICdmDataSource;\r
-\r
-/**\r
- * @author a.mueller\r
- * @date 16.09.2010\r
- *\r
- */\r
-public class ColumnAdder extends AuditedSchemaUpdaterStepBase<ColumnAdder> implements ISchemaUpdaterStep {\r
- private static final Logger logger = Logger.getLogger(ColumnAdder.class);\r
- \r
- private String newColumnName;\r
- private String columnType;\r
- private Object defaultValue;\r
- private boolean isNotNull;\r
-\r
- private String referencedTable;\r
-\r
- public static final ColumnAdder NewIntegerInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull, String referencedTable){\r
- return new ColumnAdder(stepName, tableName, newColumnName, "int", includeAudTable, null, notNull, referencedTable);\r
- }\r
- \r
- public static final ColumnAdder NewIntegerInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable, Integer defaultValue, boolean notNull){\r
- return new ColumnAdder(stepName, tableName, newColumnName, "int", includeAudTable, defaultValue, notNull, null);\r
- }\r
- \r
- public static final ColumnAdder NewTinyIntegerInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull){\r
- return new ColumnAdder(stepName, tableName, newColumnName, "tinyint", includeAudTable, null, notNull, null);\r
- }\r
- \r
- public static final ColumnAdder NewDoubleInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull){\r
- return new ColumnAdder(stepName, tableName, newColumnName, "double", includeAudTable, null, notNull, null);\r
- }\r
-\r
- public static final ColumnAdder NewBooleanInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable, Boolean defaultValue){\r
- return new ColumnAdder(stepName, tableName, newColumnName, "bit", includeAudTable, defaultValue, false, null);\r
- }\r
- \r
- public static final ColumnAdder NewStringInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable){\r
- return new ColumnAdder(stepName, tableName, newColumnName, "nvarchar(255)", includeAudTable, null, false, null);\r
- }\r
-\r
- public static final ColumnAdder NewStringInstance(String stepName, String tableName, String newColumnName, int length, boolean includeAudTable){\r
- return new ColumnAdder(stepName, tableName, newColumnName, "nvarchar("+length+")", includeAudTable, null, false, null);\r
- }\r
-\r
- public static final ColumnAdder NewClobInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable){\r
- return new ColumnAdder(stepName, tableName, newColumnName, "clob", includeAudTable, null, false, null);\r
- }\r
- \r
- public static final ColumnAdder NewDateTimeInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable){\r
- return new ColumnAdder(stepName, tableName, newColumnName, "datetime", includeAudTable, null, false, null);\r
- }\r
- \r
- protected ColumnAdder(String stepName, String tableName, String newColumnName, String columnType, boolean includeAudTable, Object defaultValue, boolean notNull, String referencedTable) {\r
- super(stepName);\r
- this.tableName = tableName;\r
- this.newColumnName = newColumnName;\r
- this.columnType = columnType;\r
- this.includeAudTable = includeAudTable;\r
- this.defaultValue = defaultValue;\r
- this.isNotNull = notNull;\r
- this.referencedTable = referencedTable;\r
- }\r
-\r
- public ColumnAdder setNotNull(boolean isNotNull) {\r
- this.isNotNull = isNotNull;\r
- return this;\r
- }\r
-\r
- @Override\r
- protected boolean invokeOnTable(String tableName, ICdmDataSource datasource, IProgressMonitor monitor) {\r
- boolean result = true;\r
- try {\r
- String updateQuery = getUpdateQueryString(tableName, datasource, monitor);\r
- datasource.executeUpdate(updateQuery);\r
- \r
- if (defaultValue instanceof Boolean){\r
- updateQuery = "UPDATE @tableName SET @columnName = " + (defaultValue == null ? "null" : getBoolean((Boolean) defaultValue, datasource));\r
- updateQuery = updateQuery.replace("@tableName", tableName);\r
- updateQuery = updateQuery.replace("@columnName", newColumnName);\r
- datasource.executeUpdate(updateQuery);\r
- }\r
- if (referencedTable != null){\r
- result &= TableCreator.makeForeignKey(tableName, datasource, monitor, newColumnName, referencedTable);\r
- }\r
- \r
- return result;\r
- } catch ( Exception e) {\r
- monitor.warning(e.getMessage(), e);\r
- logger.error(e);\r
- return false;\r
- }\r
- }\r
-\r
- public String getUpdateQueryString(String tableName, ICdmDataSource datasource, IProgressMonitor monitor) throws DatabaseTypeNotSupportedException {\r
- String updateQuery;\r
- DatabaseTypeEnum type = datasource.getDatabaseType();\r
- String databaseColumnType = getDatabaseColumnType(datasource, this.columnType);\r
-\r
- if (type.equals(DatabaseTypeEnum.SqlServer2005)){\r
- //MySQL allows both syntaxes\r
- updateQuery = "ALTER TABLE @tableName ADD @columnName @columnType";\r
- }else if (type.equals(DatabaseTypeEnum.H2) || type.equals(DatabaseTypeEnum.PostgreSQL) || type.equals(DatabaseTypeEnum.MySQL)){\r
- updateQuery = "ALTER TABLE @tableName @addSeparator @columnName @columnType";\r
- }else{\r
- updateQuery = null;\r
- String warning = "Update step '" + this.getStepName() + "' is not supported by " + type.getName();\r
- monitor.warning(warning);\r
- throw new DatabaseTypeNotSupportedException(warning);\r
- }\r
- if (isNotNull){\r
- updateQuery += " NOT NULL";\r
- }\r
- updateQuery = updateQuery.replace("@tableName", tableName);\r
- updateQuery = updateQuery.replace("@columnName", newColumnName);\r
- updateQuery = updateQuery.replace("@columnType", databaseColumnType);\r
- updateQuery = updateQuery.replace("@addSeparator", getAddColumnSeperator(datasource));\r
- \r
- return updateQuery;\r
- }\r
-\r
- protected static String getDatabaseColumnType(ICdmDataSource datasource, String columnType) {\r
- String result = columnType;\r
- DatabaseTypeEnum dbType = datasource.getDatabaseType();\r
- //nvarchar\r
- if (dbType.equals(DatabaseTypeEnum.PostgreSQL)){\r
- result = result.replace("nvarchar", "varchar");\r
- }\r
- //CLOB\r
- if (columnType.equalsIgnoreCase("clob")){\r
- //TODO use hibernate dialects\r
- if (dbType.equals(DatabaseTypeEnum.MySQL)){\r
- result = "longtext";\r
- }else if (dbType.equals(DatabaseTypeEnum.H2)){\r
- result = "CLOB"; //or NVARCHAR\r
- }else if (dbType.equals(DatabaseTypeEnum.PostgreSQL)){\r
- result = "text";\r
- }else if (dbType.equals(DatabaseTypeEnum.SqlServer2005)){\r
- result = "NVARCHAR(MAX)";\r
- }\r
- }\r
- return result;\r
- }\r
- \r
-\r
- /**\r
- * Returns the sql keywords for adding a column. This is usually 'ADD' or 'ADD COLUMN'\r
- * @param datasource\r
- * @return\r
- * @throws DatabaseTypeNotSupportedException\r
- */\r
- public static String getAddColumnSeperator(ICdmDataSource datasource) throws DatabaseTypeNotSupportedException {\r
- DatabaseTypeEnum type = datasource.getDatabaseType();\r
- if (type.equals(DatabaseTypeEnum.SqlServer2005)){\r
- return "ADD ";\r
- }else if (type.equals(DatabaseTypeEnum.H2) || type.equals(DatabaseTypeEnum.PostgreSQL) || type.equals(DatabaseTypeEnum.MySQL)){\r
- return "ADD COLUMN ";\r
- }else{\r
- throw new DatabaseTypeNotSupportedException(datasource.getName());\r
- }\r
- }\r
-\r
- public String getReferencedTable() {\r
- return referencedTable;\r
- }\r
- \r
-\r
- public String getNewColumnName() {\r
- return newColumnName;\r
- }\r
-\r
-}\r
+/**
+* Copyright (C) 2009 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.cdm.database.update;
+
+import java.util.List;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
+import eu.etaxonomy.cdm.database.DatabaseTypeEnum;
+import eu.etaxonomy.cdm.database.ICdmDataSource;
+
+/**
+ * @author a.mueller
+ * @since 16.09.2010
+ */
+public class ColumnAdder extends AuditedSchemaUpdaterStepBase {
+
+ private static final Logger logger = LogManager.getLogger();
+
+ private final String newColumnName;
+ private final Datatype columnType;
+ private final Integer size;
+ private final Integer scale;
+ private final Object defaultValue;
+ private boolean isNotNull;
+ private final String referencedTable;
+
+ /**
+ * Add ForeignKey.
+ */
+ public static final ColumnAdder NewIntegerInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull, String referencedTable){
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.INTEGER, null, null, includeAudTable, null, notNull, referencedTable);
+ }
+
+ public static final ColumnAdder NewIntegerInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, Integer defaultValue, boolean notNull){
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.INTEGER, null, null, includeAudTable, defaultValue, notNull, null);
+ }
+
+ public static final ColumnAdder NewTinyIntegerInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull){
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.TINYINTEGER, null, null, includeAudTable, null, notNull, null);
+ }
+
+ public static final ColumnAdder NewDoubleInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull){
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.DOUBLE, null, null, includeAudTable, null, notNull, null);
+ }
+
+ 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){
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.BIGDECIMAL, precision, scale, includeAudTable, defaultValue, notNull, null);
+ }
+
+ public static final ColumnAdder NewBooleanInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, Boolean defaultValue){
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.BIT, null, null, includeAudTable, defaultValue, false, null);
+ }
+
+ /**
+ * Adds a string column with length 255 and default value <code>null</code>
+ */
+ public static final ColumnAdder NewStringInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable){
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.VARCHAR, 255, null, includeAudTable, null, false, null);
+ }
+
+ public static final ColumnAdder NewDTYPEInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String defaultValue, boolean includeAudTable){
+ return new ColumnAdder(stepList, stepName, tableName, "DTYPE", Datatype.VARCHAR, 31, null, includeAudTable, defaultValue, true, null);
+ }
+
+ /**
+ * Adds a string column with the given length and default value <code>null</code>
+ */
+ public static final ColumnAdder NewStringInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, int length, boolean includeAudTable){
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.VARCHAR, length, null, includeAudTable, null, false, null);
+ }
+
+ /**
+ * Adds a string column with the given length and the given default value
+ */
+ public static final ColumnAdder NewStringInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, int length, String defaultValue, boolean includeAudTable){
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.VARCHAR, length, null, includeAudTable, defaultValue, false, null);
+ }
+
+ public static final ColumnAdder NewClobInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable){
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.CLOB, null, null, includeAudTable, null, false, null);
+ }
+
+ public static final ColumnAdder NewDateTimeInstance(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull){
+ return new ColumnAdder(stepList, stepName, tableName, newColumnName, Datatype.DATETIME, null, null, includeAudTable, null, notNull, null);
+ }
+
+ protected ColumnAdder(List<? extends ISchemaUpdaterStep> stepList, String stepName, String tableName, String newColumnName,
+ Datatype columnType, Integer size, Integer scale, boolean includeAudTable, Object defaultValue, boolean notNull, String referencedTable) {
+ super(stepList, stepName, tableName, includeAudTable);
+ this.newColumnName = newColumnName;
+ this.columnType = columnType;
+ this.size = size;
+ this.defaultValue = defaultValue;
+ this.isNotNull = notNull;
+ this.referencedTable = referencedTable;
+ this.scale = scale;
+ }
+
+ public ColumnAdder setNotNull(boolean isNotNull) {
+ this.isNotNull = isNotNull;
+ return this;
+ }
+
+ @Override
+ protected void invokeOnTable(String tableName, ICdmDataSource datasource,
+ IProgressMonitor monitor, CaseType caseType, SchemaUpdateResult result) {
+
+ try {
+ String updateQuery = getUpdateQueryString(tableName, datasource, monitor);
+ datasource.executeUpdate(updateQuery);
+
+ if (defaultValue instanceof Boolean){
+ String defaultValueQuery = "UPDATE @tableName SET @columnName = " + (defaultValue == null ? "NULL" : getBoolean((Boolean) defaultValue, datasource));
+ defaultValueQuery = defaultValueQuery.replace("@tableName", tableName);
+ defaultValueQuery = defaultValueQuery.replace("@columnName", newColumnName);
+ datasource.executeUpdate(defaultValueQuery);
+ }else if (defaultValue instanceof Integer){
+ String defaultValueQuery = "UPDATE @tableName SET @columnName = " + (defaultValue == null ? "NULL" : defaultValue);
+ defaultValueQuery = defaultValueQuery.replace("@tableName", tableName);
+ defaultValueQuery = defaultValueQuery.replace("@columnName", newColumnName);
+ datasource.executeUpdate(defaultValueQuery);
+ }else if (defaultValue instanceof String){
+ String defaultValueQuery = "UPDATE @tableName SET @columnName = " + (defaultValue == null ? "NULL" : "'" + defaultValue + "'");
+ defaultValueQuery = defaultValueQuery.replace("@tableName", tableName);
+ defaultValueQuery = defaultValueQuery.replace("@columnName", newColumnName);
+ datasource.executeUpdate(defaultValueQuery);
+ }else if (defaultValue != null){
+ logger.warn("Default Value not implemented for type " + defaultValue.getClass().getName());
+ }
+ if (referencedTable != null){
+ TableCreator.makeForeignKey(tableName, datasource, monitor, newColumnName, referencedTable, caseType, result);
+ }
+ return;
+ } catch ( Exception e) {
+ String message = "Unhandled exception when trying to add column " +
+ newColumnName + " for table " + tableName;
+ monitor.warning(message, e);
+ logger.error(e);
+ result.addException(e, message, getStepName());
+ return;
+ }
+ }
+
+ /**
+ * Returns the update query string. tableName must already be cased correctly. See {@link CaseType}.
+ * @param tableName correctly cased table name
+ * @param datasource data source
+ * @param monitor monitor
+ * @return the query string
+ * @throws DatabaseTypeNotSupportedException
+ */
+ public String getUpdateQueryString(String tableName, ICdmDataSource datasource, IProgressMonitor monitor) throws DatabaseTypeNotSupportedException {
+ String updateQuery;
+ DatabaseTypeEnum type = datasource.getDatabaseType();
+ String databaseColumnType = this.columnType.format(datasource, size, scale);
+
+ if (type.equals(DatabaseTypeEnum.SqlServer2005)){
+ //MySQL allows both syntaxes
+ updateQuery = "ALTER TABLE @tableName ADD @columnName @columnType";
+ }else if (type.equals(DatabaseTypeEnum.H2) || type.equals(DatabaseTypeEnum.PostgreSQL) || type.equals(DatabaseTypeEnum.MySQL)){
+ updateQuery = "ALTER TABLE @tableName @addSeparator @columnName @columnType";
+ }else{
+ updateQuery = null;
+ String warning = "Update step '" + this.getStepName() + "' is not supported by " + type.getName();
+ monitor.warning(warning);
+ throw new DatabaseTypeNotSupportedException(warning);
+ }
+ if (isNotNull && !isAuditing){
+ updateQuery += " NOT NULL";
+ }
+ updateQuery = updateQuery.replace("@tableName", tableName);
+ updateQuery = updateQuery.replace("@columnName", newColumnName);
+ updateQuery = updateQuery.replace("@columnType", databaseColumnType);
+ updateQuery = updateQuery.replace("@addSeparator", getAddColumnSeperator(datasource));
+
+ return updateQuery;
+ }
+
+ /**
+ * Returns the sql keywords for adding a column. This is usually 'ADD' or 'ADD COLUMN'
+ * @param datasource
+ * @return
+ * @throws DatabaseTypeNotSupportedException
+ */
+ public static String getAddColumnSeperator(ICdmDataSource datasource) throws DatabaseTypeNotSupportedException {
+ DatabaseTypeEnum type = datasource.getDatabaseType();
+ if (type.equals(DatabaseTypeEnum.SqlServer2005)){
+ return "ADD ";
+ }else if (type.equals(DatabaseTypeEnum.H2) || type.equals(DatabaseTypeEnum.PostgreSQL) || type.equals(DatabaseTypeEnum.MySQL)){
+ return "ADD COLUMN ";
+ }else{
+ throw new DatabaseTypeNotSupportedException(datasource.getName());
+ }
+ }
+
+ public String getReferencedTable() {
+ return referencedTable;
+ }
+
+ public String getNewColumnName() {
+ return newColumnName;
+ }
+}
\ No newline at end of file