| // Copyright (C) 2013 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.gerrit.server.schema; |
| |
| import com.google.common.collect.ImmutableMap; |
| import com.google.gerrit.reviewdb.server.ReviewDb; |
| import com.google.gwtorm.jdbc.JdbcExecutor; |
| import com.google.gwtorm.jdbc.JdbcSchema; |
| import com.google.gwtorm.schema.sql.DialectMySQL; |
| import com.google.gwtorm.schema.sql.SqlDialect; |
| import com.google.gwtorm.server.OrmException; |
| import com.google.inject.Inject; |
| import com.google.inject.Provider; |
| |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.util.Map; |
| import java.util.Set; |
| |
| public class Schema_82 extends SchemaVersion { |
| |
| private Map<String,String> tables = ImmutableMap.of( |
| "account_group_includes_by_uuid", "account_group_by_id", |
| "account_group_includes_by_uuid_audit", "account_group_by_id_aud"); |
| |
| private Map<String,Index> indexes = ImmutableMap.of( |
| "account_project_watches_byProject", |
| new Index("account_project_watches", "account_project_watches_byP"), |
| "patch_set_approvals_closedByUser", |
| new Index("patch_set_approvals", "patch_set_approvals_closedByU"), |
| "submodule_subscription_access_bySubscription", |
| new Index("submodule_subscriptions", "submodule_subscr_acc_byS") |
| ); |
| |
| @Inject |
| Schema_82(Provider<Schema_81> prior) { |
| super(prior); |
| } |
| |
| @Override |
| protected void preUpdateSchema(ReviewDb db) throws OrmException, SQLException { |
| final JdbcSchema s = (JdbcSchema) db; |
| final JdbcExecutor e = new JdbcExecutor(s); |
| renameTables(db, s, e); |
| renameColumn(db, s, e); |
| renameIndexes(db); |
| } |
| |
| private void renameTables(final ReviewDb db, final JdbcSchema s, |
| final JdbcExecutor e) throws OrmException, SQLException { |
| SqlDialect dialect = ((JdbcSchema) db).getDialect(); |
| final Set<String> existingTables = dialect.listTables(s.getConnection()); |
| for (Map.Entry<String, String> entry : tables.entrySet()) { |
| // Does source table exist? |
| if (existingTables.contains(entry.getKey())) { |
| // Does target table exist? |
| if (!existingTables.contains(entry.getValue())) { |
| s.renameTable(e, entry.getKey(), entry.getValue()); |
| } |
| } |
| } |
| } |
| |
| private void renameColumn(final ReviewDb db, final JdbcSchema s, |
| final JdbcExecutor e) throws SQLException, OrmException { |
| SqlDialect dialect = ((JdbcSchema) db).getDialect(); |
| final Set<String> existingColumns = |
| dialect.listColumns(s.getConnection(), "accounts"); |
| // Does source column exist? |
| if (!existingColumns.contains("show_username_in_review_category")) { |
| return; |
| } |
| // Does target column exist? |
| if (existingColumns.contains("show_user_in_review")) { |
| return; |
| } |
| s.renameColumn(e, "accounts", "show_username_in_review_category", |
| "show_user_in_review"); |
| // MySQL loose check constraint during the column renaming. |
| // Well it doesn't implemented anyway, |
| // check constraints are get parsed but do nothing |
| if (dialect instanceof DialectMySQL) { |
| Statement stmt = ((JdbcSchema) db).getConnection().createStatement(); |
| try { |
| addCheckConstraint(stmt); |
| } finally { |
| stmt.close(); |
| } |
| } |
| } |
| |
| private void renameIndexes(ReviewDb db) throws SQLException { |
| SqlDialect dialect = ((JdbcSchema) db).getDialect(); |
| Statement stmt = ((JdbcSchema) db).getConnection().createStatement(); |
| try { |
| // MySQL doesn't have alter index stmt, drop & create |
| if (dialect instanceof DialectMySQL) { |
| for (Map.Entry<String, Index> entry : indexes.entrySet()) { |
| stmt.executeUpdate("DROP INDEX " + entry.getKey() + " ON " |
| + entry.getValue().table); |
| } |
| stmt.executeUpdate("CREATE INDEX account_project_watches_byP ON " + |
| "account_project_watches (project_name)"); |
| stmt.executeUpdate("CREATE INDEX patch_set_approvals_closedByU ON " + |
| "patch_set_approvals (change_open, account_id, change_sort_key)"); |
| stmt.executeUpdate("CREATE INDEX submodule_subscr_acc_bys ON " + |
| "submodule_subscriptions (submodule_project_name, " + |
| "submodule_branch_name)"); |
| } else { |
| for (Map.Entry<String, Index> entry : indexes.entrySet()) { |
| stmt.executeUpdate("ALTER INDEX " + entry.getKey() + " RENAME TO " |
| + entry.getValue().index); |
| } |
| } |
| } catch (SQLException e) { |
| // we don't care |
| // better we would check if index was already renamed |
| // gwtorm doesn't expose this functionality |
| } finally { |
| stmt.close(); |
| } |
| } |
| |
| private void addCheckConstraint(Statement stmt) throws SQLException { |
| // add check constraint for the destination column |
| stmt.executeUpdate("ALTER TABLE accounts ADD CONSTRAINT " |
| + "show_user_in_review_check CHECK " |
| + "(show_user_in_review IN('Y', 'N'))"); |
| } |
| |
| static class Index { |
| String table; |
| String index; |
| |
| Index(String tableName, String indexName) { |
| this.table = tableName; |
| this.index = indexName; |
| } |
| } |
| } |