3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
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.
11 package eu
.etaxonomy
.cdm
.database
.update
.v25_30
;
13 import java
.sql
.DatabaseMetaData
;
14 import java
.sql
.ResultSet
;
15 import java
.sql
.SQLException
;
17 import org
.apache
.log4j
.Logger
;
19 import com
.mysql
.jdbc
.exceptions
.MySQLSyntaxErrorException
;
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
;
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)
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.
36 * @created Oct 27, 2010
38 public class SequenceTableCreator
extends SchemaUpdaterStepBase
{
40 @SuppressWarnings("unused")
41 private static final Logger logger
= Logger
.getLogger(SequenceTableCreator
.class);
43 // TODO These values are configurable in the enhanced.TableGenerator
44 // can we retrieve these values from the identity generator directly?
45 private static final String TABLE_NAME
= "hibernate_sequences";
46 private static final String SEGMENT_COLUMN_NAME
= "sequence_name";
47 private static final String VALUE_COLUMN_NAME
= "next_val";
48 private static final int INCREMENT_SIZE
= 10;
53 protected SequenceTableCreator(String stepName
) {
57 public static SequenceTableCreator
NewInstance(String stepName
){
58 return new SequenceTableCreator(stepName
);
62 public Integer
invoke(ICdmDataSource datasource
, IProgressMonitor monitor
){
63 boolean result
= true;
65 result
&= createSequenceTable(datasource
, monitor
);
66 result
&= makeEntriesForEntityTables(datasource
, monitor
);
67 } catch (Exception e
) {
68 monitor
.warning(e
.getMessage(), e
);
72 return (result
== true ) ?
0 : null;
79 * @throws SQLException
81 private boolean createSequenceTable(ICdmDataSource datasource
, IProgressMonitor monitor
) throws SQLException
{
82 boolean result
= true;
83 String createTableQuery
= null;
84 // TODO add create table statements for other supported databases
85 if(datasource
.getDatabaseType().equals(DatabaseTypeEnum
.MySQL
)){
86 createTableQuery
= "CREATE TABLE `" + TABLE_NAME
+ "` (" +
87 " `" + SEGMENT_COLUMN_NAME
+ "` varchar(255) NOT NULL," +
88 " `" + VALUE_COLUMN_NAME
+ "` bigint(20) default NULL," +
89 " PRIMARY KEY (`" + SEGMENT_COLUMN_NAME
+ "`)" +
92 throw new RuntimeException("Database type " + datasource
.getDatabaseType() + " is currently not supported by the updater");
95 datasource
.executeUpdate(createTableQuery
);
104 * @throws SQLException
106 private boolean makeEntriesForEntityTables(ICdmDataSource datasource
, IProgressMonitor monitor
) throws SQLException
{
108 DatabaseMetaData metaData
= datasource
.getMetaData();
109 ResultSet resultSet
= metaData
.getTables(datasource
.getDatabase(), null, null, null);
111 String maxIdQuery
= "SELECT MAX(ID) FROM @tableName";
112 String insertQuery
= "INSERT INTO " + TABLE_NAME
+ " ( " + SEGMENT_COLUMN_NAME
+ ", " + VALUE_COLUMN_NAME
+ ")" +
113 " VALUES ('@tableName', (@maxId + " + INCREMENT_SIZE
+ "))";
117 while(resultSet
.next()){
118 // through debugging we found out that the table name is in column 3.
119 // TODO improve this if you know that this will not always be the case for all database types
120 // and/or if you know of a good way to do it in more generic way
121 String tableName
= resultSet
.getString(3);
122 // this way we simply filter out all relation tables, could have done this with a tableNamePattern passed to getTables(...)
123 // but this was faster.
124 if(tableName
.contains("_")){
129 String query
= maxIdQuery
.replace("@tableName", tableName
);
130 maxId
= datasource
.getSingleValue(query
);
131 }catch(MySQLSyntaxErrorException e
){
132 // table does not have a column id, so it is not an entity table
136 // empty tables will not set the maxId.
137 // Empty tables will also not need to be updated, because the identity generator creates sequences for tables it did not have before
139 monitor
.subTask("Inserting sequence for table: " + tableName
+ " with maxId: " + maxId
);
141 String query
= insertQuery
.replace("@tableName", tableName
);
142 query
= query
.replace("@maxId", maxId
.toString());
144 datasource
.executeUpdate(query
);