diff --git a/src/main/java/vip/fubuki/playersync/PlayerSync.java b/src/main/java/vip/fubuki/playersync/PlayerSync.java index 873d9f9..072bacd 100644 --- a/src/main/java/vip/fubuki/playersync/PlayerSync.java +++ b/src/main/java/vip/fubuki/playersync/PlayerSync.java @@ -56,7 +56,7 @@ public class PlayerSync { String dbName = JdbcConfig.DATABASE_NAME.get(); // Step 1: Create the database using a connection that does not select a database. - JDBCsetUp.executeUpdate("CREATE DATABASE IF NOT EXISTS " + dbName, 1); + JDBCsetUp.executeUpdateWithoutDatabase("CREATE DATABASE IF NOT EXISTS " + dbName); // Step 2: Explicitly select the database on a connection obtained without default database. try (Connection conn = JDBCsetUp.getConnection(false); @@ -119,12 +119,28 @@ public class PlayerSync { ");" ); long current = System.currentTimeMillis(); - JDBCsetUp.executeUpdate( - "INSERT INTO " + dbName + ".server_info(id,enable,last_update) " + - "VALUES(" + JdbcConfig.SERVER_ID.get() + ",true," + current + ") " + - "ON DUPLICATE KEY UPDATE id= " + JdbcConfig.SERVER_ID.get() + ",enable = 1," + - "last_update=" + current + ";" - ); + JDBCsetUp.executeUpdate(""" + INSERT INTO %s.server_info + ( + id, + enable, + last_update + ) + VALUES ( + %d, + true, + %d + ) + ON DUPLICATE KEY UPDATE + id = %d, + enable = true, + last_update = %d; + """, + dbName, + JdbcConfig.SERVER_ID.get(), + current, + JdbcConfig.SERVER_ID.get(), + current); // Create curios table if the Curios mod is loaded if (ModList.get().isLoaded("curios")) { @@ -137,28 +153,13 @@ public class PlayerSync { // Create backpack_data table if (ModList.get().isLoaded("sophisticatedbackpacks")) { - JDBCsetUp.executeUpdate( + JDBCsetUp.executeUpdateWithoutDatabase( "CREATE TABLE IF NOT EXISTS " + dbName + ".backpack_data (" + "uuid CHAR(36) NOT NULL, backpack_nbt MEDIUMBLOB, PRIMARY KEY (uuid)" + - ");", 1 + ");" ); - // Check if backpack_data table has the 'uuid' column - JDBCsetUp.QueryResult backpackColCheck = JDBCsetUp.executeQuery( - "SELECT COUNT(*) AS colCount FROM INFORMATION_SCHEMA.COLUMNS " + - "WHERE TABLE_SCHEMA = '" + dbName + "' " + - "AND TABLE_NAME = 'backpack_data' " + - "AND COLUMN_NAME = 'uuid';" - ); - ResultSet rsBackpackCol = backpackColCheck.resultSet(); - if (rsBackpackCol.next() && rsBackpackCol.getInt("colCount") == 0) { - LOGGER.info("Altering backpack_data table to add missing 'uuid' column."); - // Add the missing column and set it as primary key. - JDBCsetUp.executeUpdate("ALTER TABLE " + dbName + ".backpack_data ADD COLUMN uuid CHAR(36) NOT NULL", 1); - JDBCsetUp.executeUpdate("ALTER TABLE " + dbName + ".backpack_data ADD PRIMARY KEY (uuid)", 1); - } - rsBackpackCol.close(); - backpackColCheck.connection().close(); + addColumnIfNotExists("backpack_data", "uuid", "CHAR(36) NOT NULL", true); } // Check and alter the 'advancements' column in player_data if necessary @@ -173,7 +174,7 @@ public class PlayerSync { String dataType = rsAdvCol.getString("DATA_TYPE"); if (!"mediumblob".equalsIgnoreCase(dataType)) { LOGGER.info("Altering player_data table to modify 'advancements' column from {} to MEDIUMBLOB.", dataType); - JDBCsetUp.executeUpdate("ALTER TABLE " + dbName + ".player_data MODIFY COLUMN advancements MEDIUMBLOB", 1); + JDBCsetUp.executeUpdateWithoutDatabase("ALTER TABLE " + dbName + ".player_data MODIFY COLUMN advancements MEDIUMBLOB"); } } rsAdvCol.close(); @@ -182,4 +183,44 @@ public class PlayerSync { LOGGER.info("PlayerSync is ready!"); } + private static void addColumnIfNotExists(String tableName, String columnName, String dataTypeDefaultNullness, + boolean makePrimaryKey) throws SQLException { + + // Making use of the AutoCloseable QueryResult here + try (JDBCsetUp.QueryResult backpackColCheck = JDBCsetUp.executeQuery( + "SELECT COUNT(*) AS colCount FROM INFORMATION_SCHEMA.COLUMNS " + + "WHERE TABLE_SCHEMA = DATABASE()" + + "AND TABLE_NAME = '" + tableName + "' " + + "AND COLUMN_NAME = '" + columnName + "';")) { + ResultSet rsBackpackCol = backpackColCheck.resultSet(); + + if (!rsBackpackCol.next()) { + LOGGER.warn("Warning: Unable to check existence of colum {} in table {}.", columnName, tableName); + return; + } + + if (rsBackpackCol.getInt("colCount") > 0) { + LOGGER.debug("Column {} already exists. Skipping creation.", columnName); + return; + } + } + + LOGGER.info("ALTER {} table to add missing {} column.", tableName, columnName); + // Add the missing column and set it as primary key. + JDBCsetUp.executeUpdate( + "ALTER TABLE %s ADD COLUMN %s %s", + tableName, columnName, dataTypeDefaultNullness); + + if (makePrimaryKey) { + LOGGER.info("Altering {} table to add primary key on {}.", tableName, columnName); + JDBCsetUp.executeUpdate( + "ALTER TABLE %s ADD PRIMARY KEY (%s)", + tableName, columnName); + } + } + + private static void addColumnIfNotExists(String tableName, String columnName, + String dataTypeDefaultNullness) throws SQLException { + addColumnIfNotExists(tableName, columnName, dataTypeDefaultNullness, false); + } } diff --git a/src/main/java/vip/fubuki/playersync/util/JDBCsetUp.java b/src/main/java/vip/fubuki/playersync/util/JDBCsetUp.java index c2a14b0..033c034 100644 --- a/src/main/java/vip/fubuki/playersync/util/JDBCsetUp.java +++ b/src/main/java/vip/fubuki/playersync/util/JDBCsetUp.java @@ -43,7 +43,8 @@ public class JDBCsetUp { /** * Executes a query using a connection that includes the database. */ - public static QueryResult executeQuery(String sql) throws SQLException { + public static QueryResult executeQuery(String sqlFormatString, Object... args) throws SQLException { + String sql = String.format(sqlFormatString, args); LOGGER.trace(sql); Connection connection = getConnection(); // With database selected (and "USE" already run) PreparedStatement queryStatement = connection.prepareStatement(sql); @@ -52,28 +53,31 @@ public class JDBCsetUp { } /** - * Executes an update using a connection that includes the database. + * Executes an update using a connection with or without the database within the JDBC URL */ - public static void executeUpdate(String sql) throws SQLException { + private static void executeUpdate(boolean selectDatabase, String sqlFormatString, Object... args) throws SQLException { + String sql = String.format(sqlFormatString, args); LOGGER.trace(sql); - try (Connection connection = getConnection()) { // With database selected + try (Connection connection = getConnection(selectDatabase)) { try (PreparedStatement updateStatement = connection.prepareStatement(sql)) { updateStatement.executeUpdate(); } } } + /** + * Executes an update using a connection that includes the database in the JDBC URL + */ + public static void executeUpdate(String sqlFormatString, Object... args) throws SQLException { + executeUpdate(true, sqlFormatString, args); + } + /** * Executes an update using a connection that does NOT include a default database. * This method is used for commands like "CREATE DATABASE IF NOT EXISTS ..." */ - public static void executeUpdate(String sql, int dummy) throws SQLException { - LOGGER.trace(sql); - try (Connection connection = getConnection(false)) { // Without default database - try (PreparedStatement updateStatement = connection.prepareStatement(sql)) { - updateStatement.executeUpdate(); - } - } + public static void executeUpdateWithoutDatabase(String sqlFormatString, Object... args) throws SQLException { + executeUpdate(false, sqlFormatString, args); } /**