001/* A program to upgrade the SQL provenance database. 002 003Copyright (c) 2010 The Regents of the University of California. 004All rights reserved. 005Permission is hereby granted, without written agreement and without 006license or royalty fees, to use, copy, modify, and distribute this 007software and its documentation for any purpose, provided that the above 008copyright notice and the following two paragraphs appear in all copies 009of this software. 010 011IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015SUCH DAMAGE. 016 017THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022ENHANCEMENTS, OR MODIFICATIONS. 023 024*/ 025package org.kepler.provenance.sql; 026 027import java.sql.SQLException; 028import java.sql.Statement; 029import java.util.List; 030import java.util.Map; 031 032import javax.swing.JOptionPane; 033 034import org.kepler.configuration.ConfigurationManager; 035import org.kepler.configuration.ConfigurationProperty; 036import org.kepler.configuration.ConfigurationUtilities; 037import org.kepler.objectmanager.lsid.KeplerLSID; 038import org.kepler.provenance.QueryException; 039import org.kepler.provenance.Queryable; 040import org.kepler.util.WorkflowRun; 041import org.kepler.util.sql.Column; 042import org.kepler.util.sql.DatabaseFactory; 043import org.kepler.util.sql.DatabaseType; 044import org.kepler.util.sql.Schema; 045import org.kepler.util.sql.Table; 046 047import ptolemy.util.MessageHandler; 048 049/* A program to upgrade the SQL provenance schema. 050 * 051 * @author Daniel Crawl 052 * @version $Id: Upgrade.java 34596 2017-08-10 23:33:56Z crawl $ 053 */ 054public class Upgrade 055{ 056 057 /** Upgrade the database. */ 058 public static void main(String[] args) 059 { 060 061 Schema schema = Schemas.createSchemaV8(); 062 063 ConfigurationProperty provenanceDefaultsProperty = 064 ConfigurationManager.getInstance().getProperty( 065 ConfigurationManager.getModule("provenance"), "provenance.defaultSettings"); 066 Map<String,String> dbParams = ConfigurationUtilities.getPairsMap(provenanceDefaultsProperty); 067 068 DatabaseType dbType = null; 069 070 try 071 { 072 dbType = DatabaseFactory.getConnectedDatabaseType(dbParams, "provenance"); 073 } 074 catch(SQLException e) 075 { 076 MessageHandler.error("Unable to connect to database.", e); 077 System.exit(-1); 078 } 079 080 int status = -1; 081 082 try 083 { 084 // see if we need to do an upgrade 085 if(dbType.hasOlderSchema(schema)) 086 { 087 if(askAndUpgrade(dbType, schema)) 088 { 089 MessageHandler.message("Upgrade successful."); 090 status = 0; 091 } 092 } 093 else 094 { 095 MessageHandler.message("Provenance database is already up to date!"); 096 status = 0; 097 } 098 } 099 catch (Exception e) 100 { 101 MessageHandler.error("Error upgrading database.", e); 102 status = -1; 103 } 104 105 System.exit(status); 106 } 107 108 /** Ask the user if she wants to upgrade the provenance database, and 109 * if the response is yes, upgrade the database. 110 */ 111 public static boolean askAndUpgrade(DatabaseType dbType, Schema schema) throws SQLException 112 { 113 String newVersionStr = schema.getVersionString(); 114 if(JOptionPane.showConfirmDialog(null, 115 "The provenance database needs to be upgraded to version " + 116 newVersionStr + ".\n" + 117 "Do you want to perform the upgrade now?\n" + 118 "\n" + 119 " If you select No, provenance and reporting will be disabled.", "Upgrade Provenance Database?", 120 JOptionPane.YES_NO_OPTION) == JOptionPane.OK_OPTION) 121 { 122 try 123 { 124 _upgradeDatabase(dbType, schema); 125 return true; 126 } 127 catch (QueryException e) 128 { 129 throw new SQLException(e); 130 } 131 } 132 return false; 133 } 134 135 /** Upgrade the database to the latest version. */ 136 private static void _upgradeDatabase(DatabaseType dbType, Schema schema) 137 throws SQLException, QueryException 138 { 139 140 // turn off auto-commit since we want only want to commit after 141 // each upgrade. 142 dbType.setAutoCommit(false); 143 try { 144 while(dbType.hasOlderSchema(schema)) 145 { 146 String versionStr = dbType.getVersionString(); 147 if(versionStr.equals("8.0")) 148 { 149 try { 150 _upgrade_from_8_0(dbType); 151 dbType.commit(); 152 } catch(SQLException | QueryException e) { 153 dbType.rollback(); 154 throw e; 155 } 156 } 157 else if(versionStr.equals("8.1")) 158 { 159 try { 160 _upgrade_from_8_1(dbType); 161 dbType.commit(); 162 } catch(SQLException | QueryException e) { 163 dbType.rollback(); 164 throw e; 165 } 166 } 167 else if(versionStr.equals("8.2")) 168 { 169 try { 170 _upgrade_from_8_2(dbType); 171 dbType.commit(); 172 } catch(SQLException | QueryException e) { 173 dbType.rollback(); 174 throw e; 175 } 176 } 177 else if(versionStr.equals("8.3")) 178 { 179 try { 180 _upgrade_from_8_3(dbType); 181 dbType.commit(); 182 } catch(SQLException | QueryException e) { 183 dbType.rollback(); 184 throw e; 185 } 186 } 187 else 188 { 189 MessageHandler.error("Unknown database version " + versionStr); 190 } 191 } 192 } finally { 193 dbType.setAutoCommit(true); 194 } 195 } 196 197 /** Upgrade the schema from 8.0 to 8.1. */ 198 private static void _upgrade_from_8_0(DatabaseType dbType) 199 throws SQLException, QueryException 200 { 201 // the following columns were added in 8.1: 202 // 203 // workflow_exec.module_dependencies 204 // workflow_exec.type 205 206 Schema schema = Schemas.createSchemaV8(1); 207 208 Statement statement = dbType.getStatement(); 209 try 210 { 211 Table workflowExecTable = schema.getTable("workflow_exec"); 212 213 dbType.createColumn(workflowExecTable.getColumn("module_dependencies"), statement); 214 dbType.createColumn(workflowExecTable.getColumn("type"), statement); 215 216 // now convert all the unknown types in workflow_exec table 217 String workflowExecStr = dbType.getTableName("workflow_exec"); 218 Queryable query = new SQLQueryV8(dbType); 219 220 List<KeplerLSID> runs = query.getExecutionsForType(WorkflowRun.type.Unknown); 221 for(KeplerLSID runId : runs) 222 { 223 WorkflowRun.type newType; 224 225 // see if it was an error 226 if(query.isErrorForExecution(runId)) 227 { 228 newType = WorkflowRun.type.Error; 229 } 230 // see if it appears to be an imported run 231 else if(query.isImportedExecution(runId)) 232 { 233 newType = WorkflowRun.type.Imported; 234 } 235 // set the type to be completed. 236 else 237 { 238 newType = WorkflowRun.type.Complete; 239 } 240 241 String updateStr = "UPDATE " + workflowExecStr + " SET type = '" + 242 newType + "' WHERE lsid = '" + runId + "'"; 243 244 statement.execute(updateStr); 245 } 246 247 // database schema is now at 8.1 248 dbType.updateMinorVersion(1); 249 } 250 finally 251 { 252 if(statement != null) 253 { 254 statement.close(); 255 } 256 } 257 } 258 259 /** Upgrade the schema from 8.1 to 8.2. */ 260 private static void _upgrade_from_8_1(DatabaseType dbType) 261 throws SQLException, QueryException 262 { 263 264 Schema schema81 = Schemas.createSchemaV8(1); 265 Schema schema82 = Schemas.createSchemaV8(2); 266 267 // change from 8.1 to 8.2: 268 // 269 // workflow_exec.module_dependencies changed to text unlimited 270 // actor state table added 271 // new indexes in entity table 272 273 // change workflow_exec.module_dependencies type 274 Column newColumn = schema82.getTable("workflow_exec").getColumn("module_dependencies"); 275 Column oldColumn = schema81.getTable("workflow_exec").getColumn("module_dependencies"); 276 dbType.changeColumnType(newColumn, oldColumn); 277 278 // add the actor state table 279 Table actorStateTable = schema82.getTable("actor_state"); 280 Schema newSchema = new Schema(0); 281 newSchema.putTable("actor_state", actorStateTable); 282 dbType.createTables(newSchema, false); 283 284 // add indexes to entity table 285 Table entityTable = schema82.getTable("entity"); 286 for(String indexName : entityTable.indexes()) 287 { 288 dbType.createIndex(indexName, "entity", entityTable.getIndexColumns(indexName)); 289 } 290 291 // database schema is now at 8.2 292 dbType.updateMinorVersion(2); 293 } 294 295 /** Upgrade the schema from 8.2 to 8.3. */ 296 private static void _upgrade_from_8_2(DatabaseType dbType) 297 throws SQLException, QueryException 298 { 299 Schema schema83 = Schemas.createSchemaV8(3); 300 301 String message = 302 "Upgrading to version 8.3 can take several minutes\n" + 303 "depending on the size of your provenance database."; 304 JOptionPane.showMessageDialog(null, message, "Warning", 305 JOptionPane.WARNING_MESSAGE); 306 307 // add index for port_event.write_id 308 Table portEventTable = schema83.getTable("port_event"); 309 dbType.createIndex("write_event_id_idx", 310 portEventTable.getName(), 311 "write_event_id"); 312 313 // change port_event.data_id to allow null values 314 dbType.setColumnNull(portEventTable.getColumn("data_id"), "port_event"); 315 316 // change port_event.type to allow null values 317 dbType.setColumnNull(portEventTable.getColumn("type"), "port_event"); 318 319 // add port_event.data 320 Column data = portEventTable.getColumn("data"); 321 dbType.createColumn(data, data.isNullAllowed()); 322 323 324 // database schema is now at 8.3 325 dbType.updateMinorVersion(3); 326 } 327 328 /** Upgrade the schema from 8.3 to 8.4. */ 329 private static void _upgrade_from_8_3(DatabaseType dbType) 330 throws SQLException, QueryException 331 { 332 Schema schema84 = Schemas.createSchemaV8(4); 333 334 String message = 335 "Upgrading to version 8.4 can take several minutes\n" + 336 "depending on the size of your provenance database."; 337 JOptionPane.showMessageDialog(null, message, "Warning", 338 JOptionPane.WARNING_MESSAGE); 339 340 // change port_event.data_id to allow null values 341 Table associatedDataTable = schema84.getTable("associated_data"); 342 dbType.setColumnNull(associatedDataTable.getColumn("data_id"), "associated_data"); 343 344 345 // database schema is now at 8.4 346 dbType.updateMinorVersion(4); 347 } 348}