From ad85bc385a611399ba0625d4377346415c0f87b3 Mon Sep 17 00:00:00 2001 From: Rsl1122 Date: Sat, 5 Jan 2019 18:21:23 +0200 Subject: [PATCH] Rewrote foreign key drop code in Patch --- .../sql/objects/ForeignKeyConstraint.java | 71 ++++++++++++++++++ .../databases/sql/operation/Queries.java | 73 +++++++++++++++++++ .../database/databases/sql/patches/Patch.java | 68 ++++------------- .../patches/SessionsOptimizationPatch.java | 6 +- .../sql/patches/WorldsOptimizationPatch.java | 4 +- 5 files changed, 161 insertions(+), 61 deletions(-) create mode 100644 Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/objects/ForeignKeyConstraint.java create mode 100644 Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/Queries.java diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/objects/ForeignKeyConstraint.java b/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/objects/ForeignKeyConstraint.java new file mode 100644 index 000000000..0917cadff --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/objects/ForeignKeyConstraint.java @@ -0,0 +1,71 @@ +/* + * This file is part of Player Analytics (Plan). + * + * Plan is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License v3 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Plan is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Plan. If not, see . + */ +package com.djrapitops.plan.system.database.databases.sql.objects; + +/** + * Represents a FOREIGN KEY constraint in a MySQL database. + * + * @author Rsl1122 + */ +public class ForeignKeyConstraint { + + private final String table; + private final String referencedTable; + private final String column; + private final String refrencedColumn; + private final String constraintName; + + public ForeignKeyConstraint( + String table, String referencedTable, + String column, String refrencedColumn, + String constraintName + ) { + this.table = table; + this.referencedTable = referencedTable; + this.column = column; + this.refrencedColumn = refrencedColumn; + this.constraintName = constraintName; + } + + public String getTable() { + return table; + } + + public String getReferencedTable() { + return referencedTable; + } + + public String getColumn() { + return column; + } + + public String getRefrencedColumn() { + return refrencedColumn; + } + + public String getConstraintName() { + return constraintName; + } + + @Override + public String toString() { + return "FK '" + constraintName + "' " + + table + "." + column + + " references " + + referencedTable + "." + refrencedColumn; + } +} diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/Queries.java b/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/Queries.java new file mode 100644 index 000000000..c66d643d7 --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/operation/Queries.java @@ -0,0 +1,73 @@ +/* + * This file is part of Player Analytics (Plan). + * + * Plan is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License v3 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Plan is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Plan. If not, see . + */ +package com.djrapitops.plan.system.database.databases.sql.operation; + +import com.djrapitops.plan.system.database.databases.sql.objects.ForeignKeyConstraint; +import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Class that contains different SELECT statements. + * + * @author Rsl1122 + */ +public class Queries { + + private Queries() { + /* Static method class */ + } + + public static QueryStatement> foreignKeyConstraintsOf(String tableSchema, String referencedTable) { + String keySQL = "SELECT TABLE_NAME,COLUMN_NAME,CONSTRAINT_NAME,REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE" + + " WHERE REFERENCED_TABLE_SCHEMA = ?" + + " AND REFERENCED_TABLE_NAME = ?"; + return new QueryStatement>(keySQL) { + @Override + public void prepare(PreparedStatement statement) throws SQLException { + statement.setString(1, tableSchema); + statement.setString(2, referencedTable); + } + + @Override + public List processResults(ResultSet set) throws SQLException { + List constraints = new ArrayList<>(); + + while (set.next()) { + String table = set.getString("TABLE_NAME"); + String referencedTable = set.getString("REFERENCED_TABLE_NAME"); + String column = set.getString("COLUMN_NAME"); + String referencedColumn = set.getString("REFERENCED_COLUMN"); + String constraintName = set.getString("CONSTRAINT_NAME"); + + constraints.add(new ForeignKeyConstraint( + table, referencedTable, + column, referencedColumn, + constraintName + )); + } + + return constraints; + } + }; + } + +} diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/Patch.java b/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/Patch.java index 6184afc0d..bfdf24c57 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/Patch.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/Patch.java @@ -19,6 +19,8 @@ package com.djrapitops.plan.system.database.databases.sql.patches; import com.djrapitops.plan.api.exceptions.database.DBOpException; import com.djrapitops.plan.system.database.databases.DBType; import com.djrapitops.plan.system.database.databases.sql.SQLDB; +import com.djrapitops.plan.system.database.databases.sql.objects.ForeignKeyConstraint; +import com.djrapitops.plan.system.database.databases.sql.operation.Queries; import com.djrapitops.plan.system.database.databases.sql.processing.QueryAllStatement; import com.djrapitops.plan.system.database.databases.sql.processing.QueryStatement; import com.djrapitops.plan.system.database.databases.sql.statements.TableSqlParser; @@ -28,6 +30,7 @@ import com.djrapitops.plugin.utilities.Verify; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.List; import java.util.UUID; public abstract class Patch { @@ -146,71 +149,30 @@ public abstract class Patch { } } - protected void dropForeignKey(String table, String referencedTable, String referencedColumn) { + protected void dropForeignKeys(String referencedTable) { if (dbType != DBType.MYSQL) { return; } - String keyName = getForeignKeyConstraintName(table, referencedTable, referencedColumn); - if (keyName == null) { - return; - } - // Uses information from https://stackoverflow.com/a/34574758 - db.execute("ALTER TABLE " + table + - " DROP FOREIGN KEY " + keyName); + String schema = db.getConfig().get(DatabaseSettings.MYSQL_DATABASE); + List constraints = query(Queries.foreignKeyConstraintsOf(schema, referencedTable)); + + for (ForeignKeyConstraint constraint : constraints) { + // Uses information from https://stackoverflow.com/a/34574758 + db.execute("ALTER TABLE " + constraint.getTable() + + " DROP FOREIGN KEY " + constraint.getConstraintName()); + } } protected void ensureNoForeignKeyConstraints(String table) { if (dbType != DBType.MYSQL) { return; } - String keySQL = "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE" + - " WHERE REFERENCED_TABLE_SCHEMA = ?" + - " AND TABLE_NAME = ?"; - String keyName = query(new QueryStatement(keySQL) { - @Override - public void prepare(PreparedStatement statement) throws SQLException { - statement.setString(1, db.getConfig().get(DatabaseSettings.MYSQL_DATABASE)); - statement.setString(2, table); - } - @Override - public String processResults(ResultSet set) throws SQLException { - if (set.next()) { - return set.getString("CONSTRAINT_NAME"); - } else { - return null; - } - } - }); - Verify.isTrue(keyName == null, () -> new DBOpException("Table '" + table + "' has constraint '" + keyName + "'")); - } + String schema = db.getConfig().get(DatabaseSettings.MYSQL_DATABASE); + List constraints = query(Queries.foreignKeyConstraintsOf(schema, table)); - 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 = ?"; - return query(new QueryStatement(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; - } - } - }); + Verify.isTrue(constraints.isEmpty(), () -> new DBOpException("Table '" + table + "' has constraints '" + constraints + "'")); } protected UUID getServerUUID() { diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/SessionsOptimizationPatch.java b/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/SessionsOptimizationPatch.java index b626b9343..aad5ca4da 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/SessionsOptimizationPatch.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/SessionsOptimizationPatch.java @@ -18,10 +18,8 @@ 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 { @@ -46,9 +44,7 @@ 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()); - + dropForeignKeys(tableName); ensureNoForeignKeyConstraints(tableName); tempOldTable(); diff --git a/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/WorldsOptimizationPatch.java b/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/WorldsOptimizationPatch.java index c37e747cd..fda54f94e 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/WorldsOptimizationPatch.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/system/database/databases/sql/patches/WorldsOptimizationPatch.java @@ -20,7 +20,6 @@ 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 { @@ -44,8 +43,7 @@ public class WorldsOptimizationPatch extends Patch { @Override public void apply() { try { - dropForeignKey(WorldTimesTable.TABLE_NAME, tableName, Col.ID.get()); - + dropForeignKeys(tableName); ensureNoForeignKeyConstraints(tableName); tempOldTable();