[#860] Fixed MySQL Patch application (#867)

* Patch#dropTable no longer swallows exceptions

* Made TestRunnableFactory not run anything

* Drop some foreign keys during WorldsOptimization and SessionsOptimization patches (This is the fix)
This commit is contained in:
Risto Lahtela 2019-01-01 23:01:37 +02:00 committed by GitHub
parent b540786010
commit 6c5355369a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 91 deletions

View File

@ -22,6 +22,7 @@ import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStat
import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement;
import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser;
import com.djrapitops.plan.system.settings.paths.DatabaseSettings;
import com.djrapitops.plugin.utilities.Verify;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -120,11 +121,11 @@ public abstract class Patch {
}
protected void addColumn(String tableName, String columnInfo) {
db.executeUnsafe("ALTER TABLE " + tableName + " ADD " + (dbType.supportsMySQLQueries() ? "" : "COLUMN ") + columnInfo);
db.execute("ALTER TABLE " + tableName + " ADD " + (dbType.supportsMySQLQueries() ? "" : "COLUMN ") + columnInfo);
}
protected void dropTable(String name) {
db.executeUnsafe(TableSqlParser.dropTable(name));
db.execute(TableSqlParser.dropTable(name));
}
protected void renameTable(String from, String to) {
@ -144,6 +145,45 @@ public abstract class Patch {
}
}
protected void dropForeignKey(String table, String referencedTable, String referencedColumn) {
if (dbType != DBType.MYSQL) {
return;
}
String keyName = getForeignKeyConstraintName(table, referencedTable, referencedColumn);
// Uses information from https://stackoverflow.com/a/34574758
db.execute("ALTER TABLE " + table +
" DROP FOREIGN KEY " + keyName);
}
private String getForeignKeyConstraintName(String table, String referencedTable, String referencedColumn) {
// Uses information from https://stackoverflow.com/a/201678
String keySQL = "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE" +
" WHERE REFERENCED_TABLE_SCHEMA = ?" +
" AND TABLE_NAME = ?" +
" AND REFERENCED_TABLE_NAME = ?" +
" AND REFERENCED_COLUMN_NAME = ?";
String keyName = query(new QueryStatement<String>(keySQL) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, db.getConfig().get(DatabaseSettings.MYSQL_DATABASE));
statement.setString(2, table);
statement.setString(3, referencedTable);
statement.setString(4, referencedColumn);
}
@Override
public String processResults(ResultSet set) throws SQLException {
if (set.next()) {
return set.getString("CONSTRAINT_NAME");
} else {
return null;
}
}
});
return Verify.nullCheck(keyName, () -> new IllegalArgumentException("No constraint found with " + table + ", " + referencedTable + "." + referencedColumn));
}
protected UUID getServerUUID() {
return db.getServerUUIDSupplier().get();
}

View File

@ -18,8 +18,10 @@ package com.djrapitops.plan.system.database.databases.sql.patches;
import com.djrapitops.plan.api.exceptions.database.DBOpException;
import com.djrapitops.plan.system.database.databases.sql.SQLDB;
import com.djrapitops.plan.system.database.databases.sql.tables.KillsTable;
import com.djrapitops.plan.system.database.databases.sql.tables.SessionsTable;
import com.djrapitops.plan.system.database.databases.sql.tables.SessionsTable.Col;
import com.djrapitops.plan.system.database.databases.sql.tables.WorldTimesTable;
public class SessionsOptimizationPatch extends Patch {
@ -44,6 +46,9 @@ public class SessionsOptimizationPatch extends Patch {
@Override
public void apply() {
try {
dropForeignKey(WorldTimesTable.TABLE_NAME, tableName, Col.ID.get());
dropForeignKey(KillsTable.TABLE_NAME, tableName, Col.ID.get());
tempOldTable();
db.getSessionsTable().createTable();

View File

@ -20,6 +20,7 @@ import com.djrapitops.plan.api.exceptions.database.DBOpException;
import com.djrapitops.plan.system.database.databases.sql.SQLDB;
import com.djrapitops.plan.system.database.databases.sql.tables.WorldTable;
import com.djrapitops.plan.system.database.databases.sql.tables.WorldTable.Col;
import com.djrapitops.plan.system.database.databases.sql.tables.WorldTimesTable;
public class WorldsOptimizationPatch extends Patch {
@ -43,6 +44,8 @@ public class WorldsOptimizationPatch extends Patch {
@Override
public void apply() {
try {
dropForeignKey(WorldTimesTable.TABLE_NAME, tableName, Col.ID.get());
tempOldTable();
db.getWorldTable().createTable();

View File

@ -4,109 +4,29 @@
*/
package utilities.mocks.objects;
import com.djrapitops.plugin.api.TimeAmount;
import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.PluginRunnable;
import com.djrapitops.plugin.task.PluginTask;
import com.djrapitops.plugin.task.RunnableFactory;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static org.mockito.Mockito.mock;
/**
* @author Fuzzlemann
* Test implementation of {@link RunnableFactory}.
* <p>
* Does not run the {@link AbsRunnable} supplied to it to prevent test collisions
* from improperly scheduled tasks.
*
* @author Rsl1122
*/
public class TestRunnableFactory extends RunnableFactory {
private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
@Override
protected PluginRunnable createNewRunnable(String name, AbsRunnable absRunnable, long l) {
return new PluginRunnable() {
@Override
public String getTaskName() {
return name;
}
@Override
public void cancel() {
absRunnable.cancel();
}
@Override
public int getTaskId() {
return absRunnable.getTaskId();
}
@Override
public PluginTask runTask() {
absRunnable.run();
return createPluginTask(getTaskId(), true, absRunnable::cancel);
}
@Override
public PluginTask runTaskAsynchronously() {
executorService.submit(absRunnable);
return createPluginTask(getTaskId(), false, absRunnable::cancel);
}
@Override
public PluginTask runTaskLater(long l) {
return runTaskLaterAsynchronously(l);
}
@Override
public PluginTask runTaskLaterAsynchronously(long l) {
executorService.schedule(absRunnable, TimeAmount.ticksToMillis(l), TimeUnit.MILLISECONDS);
return createPluginTask(getTaskId(), false, absRunnable::cancel);
}
@Override
public PluginTask runTaskTimer(long l, long l1) {
return runTaskLaterAsynchronously(l);
}
@Override
public PluginTask runTaskTimerAsynchronously(long l, long l1) {
executorService.scheduleAtFixedRate(absRunnable, TimeAmount.ticksToMillis(l), TimeAmount.ticksToMillis(l1), TimeUnit.MILLISECONDS);
return createPluginTask(getTaskId(), false, absRunnable::cancel);
}
@Override
public long getTime() {
return l;
}
};
return mock(PluginRunnable.class);
}
@Override
public void cancelAllKnownTasks() {
executorService.shutdownNow();
}
private PluginTask createPluginTask(int taskID, boolean sync, ICloseTask closeTask) {
return new PluginTask() {
@Override
public int getTaskId() {
return taskID;
}
@Override
public boolean isSync() {
return sync;
}
@Override
public void cancel() {
if (closeTask != null) {
closeTask.close();
}
}
};
}
private interface ICloseTask {
void close();
/* Nothing to cancel, nothing is actually run. */
}
}