Project

General

Profile

Download (8.97 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2009 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
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.
8
*/
9
package eu.etaxonomy.cdm.database.update;
10

    
11
import java.sql.Types;
12

    
13
import org.apache.log4j.Logger;
14

    
15
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
16
import eu.etaxonomy.cdm.database.DatabaseTypeEnum;
17
import eu.etaxonomy.cdm.database.ICdmDataSource;
18

    
19
/**
20
 * @author a.mueller
21
 * @date 16.09.2010
22
 *
23
 */
24
public class ColumnAdder extends AuditedSchemaUpdaterStepBase<ColumnAdder> implements ISchemaUpdaterStep {
25
	private static final Logger logger = Logger.getLogger(ColumnAdder.class);
26

    
27
	private final String newColumnName;
28
	private final String columnType;
29
	private final Object defaultValue;
30
	private boolean isNotNull;
31

    
32
	private final String referencedTable;
33

    
34
	/**
35
	 * Add ForeignKey.
36
	 * @param referencedTable
37
	 * @return
38
	 */
39
	public static final ColumnAdder NewIntegerInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull, String referencedTable){
40
		return new ColumnAdder(stepName, tableName, newColumnName, "int", includeAudTable, null, notNull, referencedTable);
41
	}
42

    
43
	public static final ColumnAdder NewIntegerInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable, Integer defaultValue, boolean notNull){
44
		return new ColumnAdder(stepName, tableName, newColumnName, "int", includeAudTable, defaultValue, notNull, null);
45
	}
46

    
47
	public static final ColumnAdder NewTinyIntegerInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull){
48
		return new ColumnAdder(stepName, tableName, newColumnName, "tinyint", includeAudTable, null, notNull, null);
49
	}
50

    
51
	public static final ColumnAdder NewDoubleInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull){
52
		return new ColumnAdder(stepName, tableName, newColumnName, "double", includeAudTable, null, notNull, null);
53
	}
54

    
55
	public static final ColumnAdder NewBooleanInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable, Boolean defaultValue){
56
		return new ColumnAdder(stepName, tableName, newColumnName, "bit", includeAudTable, defaultValue, false, null);
57
	}
58

    
59
	public static final ColumnAdder NewStringInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable){
60
		return new ColumnAdder(stepName, tableName, newColumnName, "nvarchar(255)", includeAudTable, null, false, null);
61
	}
62

    
63
	public static final ColumnAdder NewStringInstance(String stepName, String tableName, String newColumnName, int length, boolean includeAudTable){
64
		return new ColumnAdder(stepName, tableName, newColumnName, "nvarchar("+length+")", includeAudTable, null, false, null);
65
	}
66

    
67
	public static final ColumnAdder NewClobInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable){
68
		return new ColumnAdder(stepName, tableName, newColumnName, "clob", includeAudTable, null, false, null);
69
	}
70

    
71
	public static final ColumnAdder NewDateTimeInstance(String stepName, String tableName, String newColumnName, boolean includeAudTable, boolean notNull){
72
		return new ColumnAdder(stepName, tableName, newColumnName, "datetime", includeAudTable, null, notNull, null);
73
	}
74

    
75
	protected ColumnAdder(String stepName, String tableName, String newColumnName, String columnType, boolean includeAudTable, Object defaultValue, boolean notNull, String referencedTable) {
76
		super(stepName, tableName, includeAudTable);
77
		this.newColumnName = newColumnName;
78
		this.columnType = columnType;
79
		this.defaultValue = defaultValue;
80
		this.isNotNull = notNull;
81
		this.referencedTable = referencedTable;
82
	}
83

    
84
	public ColumnAdder setNotNull(boolean isNotNull) {
85
		this.isNotNull = isNotNull;
86
		return this;
87
	}
88

    
89
	@Override
90
	protected boolean invokeOnTable(String tableName, ICdmDataSource datasource, IProgressMonitor monitor, CaseType caseType) {
91
		boolean result = true;
92
		try {
93
			String updateQuery = getUpdateQueryString(tableName, datasource, monitor);
94
			datasource.executeUpdate(updateQuery);
95

    
96
			if (defaultValue instanceof Boolean){
97
				String defaultValueQuery = "UPDATE @tableName SET @columnName = " + (defaultValue == null ? "NULL" : getBoolean((Boolean) defaultValue, datasource));
98
				defaultValueQuery = defaultValueQuery.replace("@tableName", tableName);
99
				defaultValueQuery = defaultValueQuery.replace("@columnName", newColumnName);
100
				datasource.executeUpdate(defaultValueQuery);
101
			}else if (defaultValue instanceof Integer){
102
				String defaultValueQuery = "UPDATE @tableName SET @columnName = " + (defaultValue == null ? "NULL" : defaultValue);
103
				defaultValueQuery = defaultValueQuery.replace("@tableName", tableName);
104
				defaultValueQuery = defaultValueQuery.replace("@columnName", newColumnName);
105
				datasource.executeUpdate(defaultValueQuery);
106
			}else if (defaultValue != null){
107
				logger.warn("Default Value not implemented for type " + defaultValue.getClass().getName());
108
			}
109
			if (referencedTable != null){
110
				result &= TableCreator.makeForeignKey(tableName, datasource, monitor, newColumnName, referencedTable, caseType);
111
			}
112

    
113
			return result;
114
		} catch ( Exception e) {
115
			monitor.warning(e.getMessage(), e);
116
			logger.error(e);
117
			return false;
118
		}
119
	}
120

    
121
	/**
122
	 * Returns the update query string. tableName must already be cased correctly. See {@link CaseType}.
123
	 * @param tableName correctly cased table name
124
	 * @param datasource data source
125
	 * @param monitor monitor
126
	 * @return the query string
127
	 * @throws DatabaseTypeNotSupportedException
128
	 */
129
	public String getUpdateQueryString(String tableName, ICdmDataSource datasource, IProgressMonitor monitor) throws DatabaseTypeNotSupportedException {
130
		String updateQuery;
131
		DatabaseTypeEnum type = datasource.getDatabaseType();
132
		String databaseColumnType = getDatabaseColumnType(datasource, this.columnType);
133

    
134
		if (type.equals(DatabaseTypeEnum.SqlServer2005)){
135
			//MySQL allows both syntaxes
136
			updateQuery = "ALTER TABLE @tableName ADD @columnName @columnType";
137
		}else if (type.equals(DatabaseTypeEnum.H2) || type.equals(DatabaseTypeEnum.PostgreSQL) || type.equals(DatabaseTypeEnum.MySQL)){
138
			updateQuery = "ALTER TABLE @tableName @addSeparator @columnName @columnType";
139
		}else{
140
			updateQuery = null;
141
			String warning = "Update step '" + this.getStepName() + "' is not supported by " + type.getName();
142
			monitor.warning(warning);
143
			throw new DatabaseTypeNotSupportedException(warning);
144
		}
145
		if (isNotNull){
146
			updateQuery += " NOT NULL";
147
		}
148
		updateQuery = updateQuery.replace("@tableName", tableName);
149
		updateQuery = updateQuery.replace("@columnName", newColumnName);
150
		updateQuery = updateQuery.replace("@columnType", databaseColumnType);
151
		updateQuery = updateQuery.replace("@addSeparator", getAddColumnSeperator(datasource));
152

    
153
		return updateQuery;
154
	}
155

    
156
	protected static String getDatabaseColumnType(ICdmDataSource datasource, String columnType) {
157
		String result = columnType;
158
		DatabaseTypeEnum dbType = datasource.getDatabaseType();
159
		//nvarchar
160
		if (dbType.equals(DatabaseTypeEnum.PostgreSQL)){  //TODO use PostgeSQL82 Dialect infos
161
			result = result.replace("nvarchar", "varchar");
162
			result = result.replace("double", "float8");
163
			result = result.replace("bit", DatabaseTypeEnum.PostgreSQL.getHibernateDialect().getTypeName(Types.BIT));
164
			result = result.replace("datetime", DatabaseTypeEnum.PostgreSQL.getHibernateDialect().getTypeName(Types.TIMESTAMP));
165
			result = result.replace("tinyint", DatabaseTypeEnum.PostgreSQL.getHibernateDialect().getTypeName(Types.TINYINT));
166
		}
167
		//CLOB
168
		if (columnType.equalsIgnoreCase("clob")){
169
			//TODO use hibernate dialects
170
			if (dbType.equals(DatabaseTypeEnum.MySQL)){
171
				result = "longtext";
172
			}else if (dbType.equals(DatabaseTypeEnum.H2)){
173
				result = "CLOB";  //or NVARCHAR
174
			}else if (dbType.equals(DatabaseTypeEnum.PostgreSQL)){
175
				result = "text";
176
			}else if (dbType.equals(DatabaseTypeEnum.SqlServer2005)){
177
				result = "NVARCHAR(MAX)";
178
			}
179
		}
180
		return result;
181
	}
182

    
183

    
184
	/**
185
	 * Returns the sql keywords for adding a column. This is usually 'ADD' or 'ADD COLUMN'
186
	 * @param datasource
187
	 * @return
188
	 * @throws DatabaseTypeNotSupportedException
189
	 */
190
	public static String getAddColumnSeperator(ICdmDataSource datasource) throws DatabaseTypeNotSupportedException {
191
		DatabaseTypeEnum type = datasource.getDatabaseType();
192
		if (type.equals(DatabaseTypeEnum.SqlServer2005)){
193
			return "ADD ";
194
		}else if (type.equals(DatabaseTypeEnum.H2) || type.equals(DatabaseTypeEnum.PostgreSQL) || type.equals(DatabaseTypeEnum.MySQL)){
195
			return "ADD COLUMN ";
196
		}else{
197
			throw new DatabaseTypeNotSupportedException(datasource.getName());
198
		}
199
	}
200

    
201
	public String getReferencedTable() {
202
		return referencedTable;
203
	}
204

    
205

    
206
	public String getNewColumnName() {
207
		return newColumnName;
208
	}
209

    
210
}
(6-6/36)