/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at * * http://www.dspace.org/license/ */ package org.dspace.storage.rdbms.migration; import java.sql.Connection; import java.sql.SQLException; import org.apache.log4j.Logger; import org.dspace.browse.BrowseException; import org.dspace.browse.BrowseIndex; import org.dspace.storage.rdbms.DatabaseUtils; import org.flywaydb.core.api.migration.MigrationChecksumProvider; import org.flywaydb.core.api.migration.jdbc.JdbcMigration; /** * This Flyway Java migration deletes any legacy DBMS browse tables found in * the database. See https://jira.duraspace.org/browse/DS-2188. * * @author Tim Donohue */ public class V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables implements JdbcMigration, MigrationChecksumProvider { /** log4j category */ private static final Logger log = Logger.getLogger(V6_0_2016_01_26__DS_2188_Remove_DBMS_Browse_Tables.class); /* The checksum to report for this migration (when successful) */ private int checksum = -1; @Override public void migrate(Connection connection) throws Exception, SQLException { removeDBMSBrowseTables(connection); } /** * Delete all the existing DBMS browse tables. The DBMS browse system * has been replaced by Discovery / Solr. * <P> * NOTE: This method was based on the "clearDatabase()" method of the old * DSpace 5.x `IndexBrowse` class. As such, it is essentially performing * the same as the old "./dspace index-db-browse -f -d" command. But, it * also removes old, obsolete item_count tables and communities2item table * * @param connection Database Connection * @throws BrowseException */ private void removeDBMSBrowseTables(Connection connection) throws BrowseException { // Browse index tables start at index=1 int i = 1; // Keep looping (incrementing our index by 1) until we've hit three index // tables that have not been found. // We don't actually know how many index tables will be in each database, // and there are no guarrantees it'll match the highest index of the site's // existing "webui.browse.index.#" settings. // Since that's the case, we'll just keep searching for index tables, // until we encounter a total of three that are not found. int countTablesNotFound = 0; while(countTablesNotFound < 3) { String tableName = BrowseIndex.getTableName(i, false, false, false, false); String distinctTableName = BrowseIndex.getTableName(i, false, false, true, false); String distinctMapName = BrowseIndex.getTableName(i, false, false, false, true); String sequence = BrowseIndex.getSequenceName(i, false, false); String mapSequence = BrowseIndex.getSequenceName(i, false, true); String distinctSequence = BrowseIndex.getSequenceName(i, true, false); // These views have not been used for some time, but as we are // cleaning the database, they may exist and need to be removed String colViewName = BrowseIndex.getTableName(i, false, true, false, false); String comViewName = BrowseIndex.getTableName(i, true, false, false, false); String distinctColViewName = BrowseIndex.getTableName(i, false, true, false, true); String distinctComViewName = BrowseIndex.getTableName(i, true, false, false, true); if(DatabaseUtils.tableExists(connection, tableName, false)) { // Found an index table. Deleting it & everything related to it // Drop table dropTable(connection, tableName); // Drop Sequence dropSequence(connection, sequence); // Drop Collection View dropView(connection, colViewName); // Drop Community View dropView(connection, comViewName); } // Check for existence of "distinct table" if (DatabaseUtils.tableExists(connection, distinctTableName, false)) { // Found. Need to delete all its resources // Drop table dropTable(connection, distinctTableName); // Drop Map table dropTable(connection, distinctMapName); // Drop sequence dropSequence(connection, distinctSequence); // Drop Map Sequence dropSequence(connection, mapSequence); // Drop Collection View dropView(connection, distinctColViewName); // Drop Community View dropView(connection, distinctComViewName); } else { // increment our "not found" count countTablesNotFound++; } // increment our table index i++; } // Drop all Item browse index tables dropItemTables(connection, BrowseIndex.getItemBrowseIndex()); dropItemTables(connection, BrowseIndex.getWithdrawnBrowseIndex()); dropItemTables(connection, BrowseIndex.getPrivateBrowseIndex()); // Check for existence of "communities2item" table // This is no longer used, see DS-2578 if (DatabaseUtils.tableExists(connection, "communities2item", false)) { dropTable(connection, "communities2item"); dropSequence(connection, "communities2item_seq"); } // Check for existence of "community_item_count" table // This is no longer used, as item counts are now in Solr if (DatabaseUtils.tableExists(connection, "community_item_count", false)) { dropTable(connection, "community_item_count"); } // Check for existence of "collection_item_count" table // This is no longer used, as item counts are now in Solr if (DatabaseUtils.tableExists(connection, "collection_item_count", false)) { dropTable(connection, "collection_item_count"); } // NOTE: the old "community2item" View was already dropped by // V6.0_2015.03.07__DS-2701_Hibernate_migration.sql } /** * Drop a table by name. If an error occurs, just log a warning, as its possible * some sites may have deleted the table manually. * * @param connection Database Connection * @param tableName Table Name */ private void dropTable(Connection connection, String tableName) { try { // Drop table & increment our flyway checksum this.checksum += MigrationUtils.dropDBTable(connection, tableName); } catch(SQLException sqe){ // Ignore any errors (don't cause migration to fail), but log as warning log.warn("Database Table '" + tableName + " could not be dropped during migration. This warning may be ignored, if this table was already deleted.", sqe); } } /** * Drop a sequence by name. If an error occurs, just log a warning, as its possible * some sites may have deleted it manually. * * @param connection Database Connection * @param sequenceName Sequence Name */ private void dropSequence(Connection connection, String sequenceName) { try { // Drop sequence & increment our flyway checksum this.checksum += MigrationUtils.dropDBSequence(connection, sequenceName); } catch(SQLException sqe){ // Ignore any errors (don't cause migration to fail), but log as warning log.warn("Database Sequence '" + sequenceName + " could not be dropped during migration. This warning may be ignored, if this sequence was already deleted.", sqe); } } /** * Drop a view by name. If an error occurs, just log a warning, as its possible * some sites may have deleted the view manually. * * @param connection Database Connection * @param viewName View Name */ private void dropView(Connection connection, String viewName) { try { // Drop view & increment our flyway checksum this.checksum += MigrationUtils.dropDBView(connection, viewName); } catch(SQLException sqe){ // Ignore any errors (don't cause migration to fail), but log as warning log.warn("Database View '" + viewName + " could not be dropped during migration. This warning may be ignored, if this view was already deleted.", sqe); } } /** * drop the tables and related database entries for the internal * 'item' tables * @param connection Database Connection * @param bix BrowseIndex * @throws BrowseException */ private void dropItemTables(Connection connection, BrowseIndex bix) throws BrowseException { if(DatabaseUtils.tableExists(connection, bix.getTableName())) { String tableName = bix.getTableName(); String sequence = bix.getSequenceName(false, false); // Drop table dropTable(connection, tableName); // Drop sequence dropSequence(connection, sequence); // These views are no longer used, but as we are cleaning the database, // they may exist and need to be removed String colViewName = bix.getTableName(false, true, false, false); String comViewName = bix.getTableName(true, false, false, false); // Drop Collection View dropView(connection, colViewName); // Drop Community View dropView(connection, comViewName); } } @Override public Integer getChecksum() { return checksum; } }