Fix preUpdateSchema to support multiple version steps
The preUpdateSchema method ran too late when declared in schema version 81 and the installation was updating from version 79 through 80 to 81. During the 79->80 step gwtorm created missing tables and columns, failing to give version 81's preUpdateSchema method a chance to rename tables and columns from an old name to a new name. Run all intermediate preUpdateSchema methods before running the gwtorm black magic, then run migrateData after all current columns and tables are in place. Change-Id: Id5a9b5c7f39bd0e25a38cad37abaea2c7077a6ca
This commit is contained in:
		| @@ -61,7 +61,7 @@ public class SchemaUpdater { | ||||
|  | ||||
|       } else { | ||||
|         try { | ||||
|           u.check(ui, version, db, true); | ||||
|           u.check(ui, version, db); | ||||
|         } catch (SQLException e) { | ||||
|           throw new OrmException("Cannot upgrade schema", e); | ||||
|         } | ||||
|   | ||||
| @@ -14,6 +14,7 @@ | ||||
|  | ||||
| package com.google.gerrit.server.schema; | ||||
|  | ||||
| import com.google.common.collect.Lists; | ||||
| import com.google.gerrit.reviewdb.client.CurrentSchemaVersion; | ||||
| import com.google.gerrit.reviewdb.server.ReviewDb; | ||||
| import com.google.gwtorm.jdbc.JdbcExecutor; | ||||
| @@ -25,7 +26,6 @@ import com.google.inject.Provider; | ||||
|  | ||||
| import java.sql.SQLException; | ||||
| import java.sql.Statement; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
|  | ||||
| @@ -68,59 +68,83 @@ public abstract class SchemaVersion { | ||||
|     return versionNbr; | ||||
|   } | ||||
|  | ||||
|   public final void check(UpdateUI ui, CurrentSchemaVersion curr, ReviewDb db, boolean toTargetVersion) | ||||
|   public final void check(UpdateUI ui, CurrentSchemaVersion curr, ReviewDb db) | ||||
|       throws OrmException, SQLException { | ||||
|     if (curr.versionNbr == versionNbr) { | ||||
|       // Nothing to do, we are at the correct schema. | ||||
|       // | ||||
|     } else if (curr.versionNbr > versionNbr) { | ||||
|       throw new OrmException("Cannot downgrade database schema from version " | ||||
|           + curr.versionNbr + " to " + versionNbr + "."); | ||||
|     } else { | ||||
|       upgradeFrom(ui, curr, db, toTargetVersion); | ||||
|       upgradeFrom(ui, curr, db); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** Runs check on the prior schema version, and then upgrades. */ | ||||
|   protected void upgradeFrom(UpdateUI ui, CurrentSchemaVersion curr, ReviewDb db, boolean toTargetVersion) | ||||
|   private void upgradeFrom(UpdateUI ui, CurrentSchemaVersion curr, ReviewDb db) | ||||
|       throws OrmException, SQLException { | ||||
|     final JdbcSchema s = (JdbcSchema) db; | ||||
|     List<SchemaVersion> pending = pending(curr.versionNbr); | ||||
|     updateSchema(pending, ui, db); | ||||
|     migrateData(pending, ui, curr, db); | ||||
|  | ||||
|     if (curr.versionNbr > versionNbr) { | ||||
|       throw new OrmException("Cannot downgrade database schema from version " + curr.versionNbr | ||||
|           + " to " + versionNbr + "."); | ||||
|     } | ||||
|  | ||||
|     prior.get().check(ui, curr, db, false); | ||||
|  | ||||
|     ui.message("Upgrading database schema from version " + curr.versionNbr | ||||
|         + " to " + versionNbr + " ..."); | ||||
|  | ||||
|     preUpdateSchema(db); | ||||
|     final JdbcExecutor e = new JdbcExecutor(s); | ||||
|     JdbcSchema s = (JdbcSchema) db; | ||||
|     JdbcExecutor e = new JdbcExecutor(s); | ||||
|     try { | ||||
|       s.updateSchema(e); | ||||
|       migrateData(db, ui); | ||||
|  | ||||
|       if (toTargetVersion) { | ||||
|         final List<String> pruneList = new ArrayList<String>(); | ||||
|         s.pruneSchema(new StatementExecutor() { | ||||
|           public void execute(String sql) { | ||||
|             pruneList.add(sql); | ||||
|           } | ||||
|         }); | ||||
|  | ||||
|         if (!pruneList.isEmpty()) { | ||||
|           ui.pruneSchema(e, pruneList); | ||||
|       final List<String> pruneList = Lists.newArrayList(); | ||||
|       s.pruneSchema(new StatementExecutor() { | ||||
|         public void execute(String sql) { | ||||
|           pruneList.add(sql); | ||||
|         } | ||||
|       }); | ||||
|  | ||||
|       if (!pruneList.isEmpty()) { | ||||
|         ui.pruneSchema(e, pruneList); | ||||
|       } | ||||
|     } finally { | ||||
|       e.close(); | ||||
|     } | ||||
|     finish(curr, db); | ||||
|   } | ||||
|  | ||||
|   private List<SchemaVersion> pending(int curr) { | ||||
|     List<SchemaVersion> r = Lists.newArrayListWithCapacity(versionNbr - curr); | ||||
|     for (SchemaVersion v = this; curr < v.getVersionNbr(); v = v.prior.get()) { | ||||
|       r.add(v); | ||||
|     } | ||||
|     Collections.reverse(r); | ||||
|     return r; | ||||
|   } | ||||
|  | ||||
|   private void updateSchema(List<SchemaVersion> pending, UpdateUI ui, | ||||
|       ReviewDb db) throws OrmException, SQLException { | ||||
|     for (SchemaVersion v : pending) { | ||||
|       ui.message(String.format("Upgrading schema to %d ...", v.getVersionNbr())); | ||||
|       v.preUpdateSchema(db); | ||||
|     } | ||||
|  | ||||
|     JdbcSchema s = (JdbcSchema) db; | ||||
|     JdbcExecutor e = new JdbcExecutor(s); | ||||
|     try { | ||||
|       s.updateSchema(e); | ||||
|     } finally { | ||||
|       e.close(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** Invoke before updateSchema adds new columns/tables. */ | ||||
|   protected void preUpdateSchema(ReviewDb db) throws OrmException, SQLException { | ||||
|   } | ||||
|  | ||||
|   private void migrateData(List<SchemaVersion> pending, UpdateUI ui, | ||||
|       CurrentSchemaVersion curr, ReviewDb db) throws OrmException, SQLException { | ||||
|     for (SchemaVersion v : pending) { | ||||
|       ui.message(String.format( | ||||
|           "Migrating data to schema %d ...", | ||||
|           v.getVersionNbr())); | ||||
|       v.migrateData(db, ui); | ||||
|       v.finish(curr, db); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Invoked between updateSchema (adds new columns/tables) and pruneSchema | ||||
|    * (removes deleted columns/tables). | ||||
|   | ||||
| @@ -14,9 +14,6 @@ | ||||
|  | ||||
| package com.google.gerrit.server.schema; | ||||
|  | ||||
| import com.google.gerrit.reviewdb.client.CurrentSchemaVersion; | ||||
| import com.google.gerrit.reviewdb.server.ReviewDb; | ||||
| import com.google.gwtorm.server.OrmException; | ||||
| import com.google.inject.Inject; | ||||
| import com.google.inject.Provider; | ||||
| import com.google.inject.ProvisionException; | ||||
| @@ -30,12 +27,4 @@ public class Schema_52 extends SchemaVersion { | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   protected void upgradeFrom(UpdateUI ui, CurrentSchemaVersion curr, | ||||
|       ReviewDb db, boolean toTargetVersion) throws OrmException { | ||||
|     throw new OrmException("Cannot upgrade from schema " + curr.versionNbr | ||||
|         + "; manually run init from Gerrit Code Review 2.1.7" | ||||
|         + " and restart this version to continue."); | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Shawn Pearce
					Shawn Pearce