Add MySQL to SQLite and SQLite to MySQL DB migration support

This commit is contained in:
GeorgH93 2018-08-07 17:53:48 +02:00
parent eef444d0bd
commit f697c728c1
No known key found for this signature in database
GPG Key ID: D1630D37F9E4B3C8
3 changed files with 174 additions and 7 deletions

View File

@ -18,9 +18,10 @@
package at.pcgamingfreaks.Minepacks.Bukkit.Database.Migration;
import at.pcgamingfreaks.ConsoleColor;
import at.pcgamingfreaks.Minepacks.Bukkit.Database.Database;
import at.pcgamingfreaks.Minepacks.Bukkit.Database.Files;
import at.pcgamingfreaks.Minepacks.Bukkit.Database.*;
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
import at.pcgamingfreaks.PluginLib.Bukkit.PluginLib;
import at.pcgamingfreaks.PluginLib.Database.DatabaseConnectionPool;
import at.pcgamingfreaks.Reflection;
import org.bukkit.event.HandlerList;
@ -100,17 +101,38 @@ public void migrateDB(final String targetDatabaseType, final MigrationCallback c
//endregion
}
public Migration getMigrationPerformer(final String targetDatabaseType)
public Migration getMigrationPerformer(String targetDatabaseType)
{
try
{
boolean global = false;
if(targetDatabaseType.toLowerCase().equals("external") ||targetDatabaseType.toLowerCase().equals("global") || targetDatabaseType.toLowerCase().equals("shared"))
{
DatabaseConnectionPool pool = PluginLib.getInstance().getDatabaseConnectionPool();
if(pool == null)
{
plugin.getLogger().warning(ConsoleColor.RED + "The shared connection pool is not initialized correctly!" + ConsoleColor.RESET);
return null;
}
targetDatabaseType = pool.getDatabaseType().toLowerCase();
global = true;
}
switch(targetDatabaseType.toLowerCase())
{
case "flat":
case "file":
case "files":
if(plugin.getDatabase() instanceof Files) return null;
return new SQLtoFilesMigration(plugin, plugin.getDatabase());
if(!(plugin.getDatabase() instanceof SQL)) return null;
return new SQLtoFilesMigration(plugin, (SQL) plugin.getDatabase());
case "mysql":
if(global && plugin.getDatabase() instanceof MySQLShared || !global && plugin.getDatabase() instanceof MySQL) return null;
if(plugin.getDatabase() instanceof SQL) return new SQLtoSQLMigration(plugin, (SQL) plugin.getDatabase(), "mysql", global);
else {} //TODO Files to SQL
case "sqlite":
default:
if(global && plugin.getDatabase() instanceof SQLiteShared || !global && plugin.getDatabase() instanceof SQLite) return null;
if(plugin.getDatabase() instanceof SQL) return new SQLtoSQLMigration(plugin, (SQL) plugin.getDatabase(), "sqlite", global);
else {} //TODO Files to SQL
}
}
catch(Exception e)

View File

@ -17,7 +17,6 @@
package at.pcgamingfreaks.Minepacks.Bukkit.Database.Migration;
import at.pcgamingfreaks.Minepacks.Bukkit.Database.Database;
import at.pcgamingfreaks.Minepacks.Bukkit.Database.Files;
import at.pcgamingfreaks.Minepacks.Bukkit.Database.SQL;
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
@ -39,7 +38,7 @@ public class SQLtoFilesMigration extends Migration
private final String sqlQuery;
private final File saveFolder;
protected SQLtoFilesMigration(@NotNull Minepacks plugin, @NotNull Database oldDb) throws InvocationTargetException, IllegalAccessException
protected SQLtoFilesMigration(@NotNull Minepacks plugin, @NotNull SQL oldDb) throws InvocationTargetException, IllegalAccessException
{
super(plugin, oldDb);
@Language("SQL") String query = "SELECT " + (plugin.getConfiguration().getUseUUIDs() ? "{FieldUUID}" : "{FieldName}") + ",{FieldBPITS},{FieldBPVersion} FROM {TablePlayers} INNER JOIN {TableBackpacks} ON {FieldPlayerID}={FieldBPOwner};";

View File

@ -0,0 +1,146 @@
/*
* Copyright (C) 2018 GeorgH93
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package at.pcgamingfreaks.Minepacks.Bukkit.Database.Migration;
import at.pcgamingfreaks.Minepacks.Bukkit.Database.*;
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
import at.pcgamingfreaks.PluginLib.Bukkit.PluginLib;
import at.pcgamingfreaks.PluginLib.Database.DatabaseConnectionPool;
import at.pcgamingfreaks.Reflection;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SQLtoSQLMigration extends Migration
{
private static final Method METHOD_REPLACE_PLACEHOLDERS = Reflection.getMethod(SQL.class, "replacePlaceholders", String.class);
private static final Field FIELD_PLAYER_ID = Reflection.getField(SQL.class, "fieldPlayerID");
private static final Field FIELD_PLAYER_UUID = Reflection.getField(SQL.class, "fieldPlayerUUID");
private static final Field FIELD_PLAYER_NAME = Reflection.getField(SQL.class, "fieldPlayerName");
private static final Field FIELD_BP_OWNER = Reflection.getField(SQL.class, "fieldBpOwner");
private static final Field FIELD_BP_ITS = Reflection.getField(SQL.class, "fieldBpIts");
private static final Field FIELD_BP_VERSION = Reflection.getField(SQL.class, "fieldBpVersion");
private static final Field FIELD_BP_LAST_UPDATE = Reflection.getField(SQL.class, "fieldBpLastUpdate");
private static final DateFormat SQLITE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
private final SQL newDb;
private final @Language("SQL") String queryInsertUsers, queryInsertBackpacks;
private final boolean uuid;
private int autoIndex = 0;
protected SQLtoSQLMigration(@NotNull Minepacks plugin, @NotNull SQL oldDb, @NonNls String dbType, boolean global) throws Exception
{
super(plugin, oldDb);
if(global)
{
newDb = (SQL) Reflection.getConstructor((dbType.equals("mysql")) ? MySQLShared.class : SQLiteShared.class, Minepacks.class, DatabaseConnectionPool.class).newInstance(plugin, PluginLib.getInstance().getDatabaseConnectionPool());
}
else
{
newDb = (SQL) Reflection.getConstructor((dbType.equals("mysql")) ? MySQL.class : SQLite.class, Minepacks.class).newInstance(plugin);
}
uuid = plugin.getConfiguration().getUseUUIDs();
//setup insert querys
if(uuid)
{
queryInsertUsers = replacePlaceholders(newDb, "INSERT INTO {TablePlayers} ({FieldPlayerID},{FieldName},{FieldUUID}) VALUES (?,?,?);");
}
else
{
queryInsertUsers = replacePlaceholders(newDb, "INSERT INTO {TablePlayers} ({FieldPlayerID},{FieldName}) VALUES (?,?);");
}
queryInsertBackpacks = replacePlaceholders(newDb, "INSERT INTO {TableBackpacks} ({FieldBPOwner},{FieldBPITS},{FieldBPVersion},{FieldBPLastUpdate}) VALUES (?,?,?,?);");
}
@Override
public @Nullable MigrationResult migrate() throws Exception
{
try(Connection readConnection = ((SQL) oldDb).getConnection(); Connection writeConnection = newDb.getConnection(); Statement readStatement = readConnection.createStatement())
{
int users = migrate("users", writeConnection, readStatement, "SELECT * FROM {TablePlayers};", queryInsertUsers);
int backpacks = migrate("backpacks", writeConnection, readStatement, "SELECT * FROM {TableBackpacks};", queryInsertBackpacks);
return new MigrationResult("Migrated " + users + " users and " + backpacks + " backpacks from " + oldDb.getClass().getSimpleName() + " to " + newDb.getClass().getSimpleName() + ".", MigrationResult.MigrationResultType.SUCCESS);
}
finally
{
newDb.close();
}
}
private int migrate(@NonNls String type, @NotNull Connection writeConnection, @NotNull Statement readStatement, @Language("SQL") String readQuery, @Language("SQL") String insertQuery) throws Exception
{
int count = 0;
byte mode = (byte) ((type.equals("users")) ? 0 : 1);
plugin.getLogger().info("Migrate " + type + " ...");
try(ResultSet resultSet = readStatement.executeQuery(replacePlaceholders((SQL) oldDb, readQuery));
PreparedStatement preparedStatement = writeConnection.prepareStatement(replacePlaceholders(newDb, insertQuery)))
{
while(resultSet.next())
{
switch(mode)
{
case 0: migrateUser(resultSet, preparedStatement);
case 1: migrateBackpack(resultSet, preparedStatement);
}
preparedStatement.addBatch();
count++;
}
preparedStatement.executeBatch();
}
plugin.getLogger().info("Migrated " + count + " " + type + ".");
return count;
}
private void migrateUser(@NotNull ResultSet usersResultSet, @NotNull PreparedStatement preparedStatement) throws Exception
{
int userId = usersResultSet.getInt((String) FIELD_PLAYER_ID.get(oldDb));
preparedStatement.setInt(1, userId);
preparedStatement.setString(2, usersResultSet.getString((String) FIELD_PLAYER_NAME.get(oldDb)));
if(uuid) preparedStatement.setString(3, usersResultSet.getString((String) FIELD_PLAYER_UUID.get(oldDb)));
if(userId > autoIndex) autoIndex = userId;
}
private void migrateBackpack(@NotNull ResultSet backpacksResultSet, @NotNull PreparedStatement preparedStatement) throws Exception
{
preparedStatement.setInt(1, backpacksResultSet.getInt((String) FIELD_BP_OWNER.get(oldDb)));
preparedStatement.setBytes(2, backpacksResultSet.getBytes((String) FIELD_BP_ITS.get(oldDb)));
preparedStatement.setInt(3, backpacksResultSet.getInt((String) FIELD_BP_VERSION.get(oldDb)));
if(oldDb instanceof SQLite)
{
preparedStatement.setTimestamp(4, new Timestamp(SQLITE_DATE_FORMAT.parse(backpacksResultSet.getString((String) FIELD_BP_LAST_UPDATE.get(oldDb))).getTime()));
}
else
{
preparedStatement.setString(4, SQLITE_DATE_FORMAT.format(new Date(backpacksResultSet.getTimestamp((String) FIELD_BP_LAST_UPDATE.get(oldDb)).getTime())));
}
}
private @Language("SQL") String replacePlaceholders(SQL database, @Language("SQL") String query) throws Exception
{
return (String) METHOD_REPLACE_PLACEHOLDERS.invoke(database, query);
}
}