Project

General

Profile

Download (5.25 KB) Statistics
| Branch: | Tag: | Revision:
1
// $Id$
2
/**
3
* Copyright (C) 2007 EDIT
4
* European Distributed Institute of Taxonomy 
5
* http://www.e-taxonomy.eu
6
* 
7
* The contents of this file are subject to the Mozilla Public License Version 1.1
8
* See LICENSE.TXT at the top of this package for the full license terms.
9
*/
10

    
11
package eu.etaxonomy.cdm.database.update.v25_30;
12

    
13
import java.sql.DatabaseMetaData;
14
import java.sql.ResultSet;
15
import java.sql.SQLException;
16

    
17
import org.apache.log4j.Logger;
18

    
19
import com.mysql.jdbc.exceptions.MySQLSyntaxErrorException;
20

    
21
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
22
import eu.etaxonomy.cdm.database.DatabaseTypeEnum;
23
import eu.etaxonomy.cdm.database.ICdmDataSource;
24
import eu.etaxonomy.cdm.database.update.SchemaUpdaterStepBase;
25

    
26
/**
27
 * Creates the table needed by the {@link org.hibernate.id.enhanced.TableGenerator}
28
 * We expect the generator to be configured with <code>prefer_entity_table_as_segment_value</code> 
29
 * set to <code>true</code> (the generator does not make lots of sense without this option)
30
 * 
31
 * We also create sequences for all tables that are not empty. Otherwise we would run into 
32
 * id conflicts, because the generator expects the database to be empty and creates sequences,
33
 * if they do not exist, as needed.
34
 * 
35
 * @author n.hoffmann
36
 * @created Oct 27, 2010
37
 * @version 1.0
38
 */
39
public class SequenceTableCreator extends SchemaUpdaterStepBase {
40

    
41
	@SuppressWarnings("unused")
42
	private static final Logger logger = Logger.getLogger(SequenceTableCreator.class);
43
	
44
	// TODO These values are configurable in the enhanced.TableGenerator
45
	// can we retrieve these values from the identity generator directly?
46
	private static final String TABLE_NAME = "hibernate_sequences";
47
	private static final String SEGMENT_COLUMN_NAME = "sequence_name";
48
	private static final String VALUE_COLUMN_NAME = "next_val";
49
	private static final int INCREMENT_SIZE = 10;
50
		
51
	/**
52
	 * @param stepName
53
	 */
54
	protected SequenceTableCreator(String stepName) {
55
		super(stepName);
56
	}
57

    
58
	public static SequenceTableCreator NewInstance(String stepName){
59
		return new SequenceTableCreator(stepName);
60
	}
61
	
62
	/* (non-Javadoc)
63
	 * @see eu.etaxonomy.cdm.database.update.SchemaUpdaterStepBase#invoke(eu.etaxonomy.cdm.database.ICdmDataSource, eu.etaxonomy.cdm.common.IProgressMonitor)
64
	 */
65
	@Override
66
	public Integer invoke(ICdmDataSource datasource, IProgressMonitor monitor){
67
		boolean result = true;
68
		try {
69
			createSequenceTable(datasource, monitor);
70
			makeEntriesForEntityTables(datasource, monitor);
71
		} catch (SQLException e) {
72
			monitor.warning(e.getMessage(), e);
73
			result = false;
74
		}
75
		
76
		return (result == true ) ? 0 : null;
77
	}
78

    
79
	/**
80
	 * @param monitor 
81
	 * @param datasource 
82
	 * @return
83
	 * @throws SQLException 
84
	 */
85
	private boolean createSequenceTable(ICdmDataSource datasource, IProgressMonitor monitor) throws SQLException {
86
		boolean result = true;
87
		String createTableQuery = null;
88
		// TODO add create table statements for other supported databases
89
		if(datasource.getDatabaseType().equals(DatabaseTypeEnum.MySQL)){
90
			createTableQuery = "CREATE TABLE `" + TABLE_NAME + "` (" +
91
				"  `" + SEGMENT_COLUMN_NAME + "` varchar(255) NOT NULL," +
92
				"  `" + VALUE_COLUMN_NAME + "` bigint(20) default NULL," +
93
				"  PRIMARY KEY  (`" + SEGMENT_COLUMN_NAME + "`)" +
94
				");";
95
		}else{
96
			throw new RuntimeException("Database type " + datasource.getDatabaseType() + " is currently not supported by the updater");
97
		}
98
		
99
		datasource.executeUpdate(createTableQuery);
100
		
101
		return result;
102
	}
103
	
104
	/**
105
	 * @param monitor 
106
	 * @param datasource 
107
	 * @return
108
	 * @throws SQLException 
109
	 */
110
	private void makeEntriesForEntityTables(ICdmDataSource datasource, IProgressMonitor monitor) throws SQLException {
111
		
112
		DatabaseMetaData metaData = datasource.getMetaData();
113
		ResultSet resultSet = metaData.getTables(datasource.getDatabase(), null, null, null);
114
				
115
		String maxIdQuery = "SELECT MAX(ID) FROM @tableName";
116
		String insertQuery = "INSERT INTO " + TABLE_NAME + " ( " + SEGMENT_COLUMN_NAME + ", " + VALUE_COLUMN_NAME + ")" +
117
				" VALUES ('@tableName', (@maxId + " + INCREMENT_SIZE + "))";
118
		
119
		Object maxId = null;
120
		
121
		while(resultSet.next()){
122
			// through debugging we found out that the table name is in column 3. 
123
			// TODO improve this if you know that this will not always be the case for all database types 
124
			// and/or if you know of a good way to do it in more generic way
125
			String tableName = resultSet.getString(3);
126
			// this way we simply filter out all relation tables, could have done this with a tableNamePattern passed to getTables(...)
127
			// but this was faster. 
128
			if(tableName.contains("_")){
129
				continue;
130
			}
131
			
132
			try{
133
				String query = maxIdQuery.replace("@tableName", tableName);
134
				maxId = datasource.getSingleValue(query);
135
			}catch(MySQLSyntaxErrorException e){
136
				// table does not have a column id, so it is not an entity table
137
				maxId = null;
138
			}
139
			
140
			// empty tables will not set the maxId. 
141
			// Empty tables will also not need to be updated, because the identity generator creates sequences for tables it did not have before
142
			if(maxId != null){
143
				monitor.subTask("Inserting sequence for table: " + tableName + " with maxId: " + maxId);
144
				
145
				String query = insertQuery.replace("@tableName", tableName);
146
				query = query.replace("@maxId", maxId.toString());
147
				
148
				datasource.executeUpdate(query);
149
			}
150
		}
151
	}
152

    
153
}
(4-4/5)