From 8f77a96544cc26a89ec94bd6709a916e374dbc63 Mon Sep 17 00:00:00 2001 From: EoD <293499+EoD@users.noreply.github.com> Date: Sat, 19 Jul 2025 19:38:38 +0000 Subject: [PATCH 1/4] clarify executeUpdate variants with and without db --- .../vip/fubuki/playersync/PlayerSync.java | 12 +++++----- .../vip/fubuki/playersync/util/JDBCsetUp.java | 22 ++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/main/java/vip/fubuki/playersync/PlayerSync.java b/src/main/java/vip/fubuki/playersync/PlayerSync.java index 873d9f9..dc29afc 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); @@ -137,10 +137,10 @@ 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 @@ -154,8 +154,8 @@ public class PlayerSync { 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); + JDBCsetUp.executeUpdateWithoutDatabase("ALTER TABLE " + dbName + ".backpack_data ADD COLUMN uuid CHAR(36) NOT NULL"); + JDBCsetUp.executeUpdateWithoutDatabase("ALTER TABLE " + dbName + ".backpack_data ADD PRIMARY KEY (uuid)"); } rsBackpackCol.close(); backpackColCheck.connection().close(); @@ -173,7 +173,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(); diff --git a/src/main/java/vip/fubuki/playersync/util/JDBCsetUp.java b/src/main/java/vip/fubuki/playersync/util/JDBCsetUp.java index c2a14b0..19493a2 100644 --- a/src/main/java/vip/fubuki/playersync/util/JDBCsetUp.java +++ b/src/main/java/vip/fubuki/playersync/util/JDBCsetUp.java @@ -52,28 +52,30 @@ 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 sql) throws SQLException { 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 sql) throws SQLException { + executeUpdate(true, sql); + } + /** * 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 sql) throws SQLException { + executeUpdate(false, sql); } /** From e1ac7adb1186babc38144bf803aabb7e11ccb01e Mon Sep 17 00:00:00 2001 From: EoD <293499+EoD@users.noreply.github.com> Date: Sat, 19 Jul 2025 19:40:11 +0000 Subject: [PATCH 2/4] allow format strings within SQL queries This makes SQL queries more readable in some cases --- .../java/vip/fubuki/playersync/util/JDBCsetUp.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/vip/fubuki/playersync/util/JDBCsetUp.java b/src/main/java/vip/fubuki/playersync/util/JDBCsetUp.java index 19493a2..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); @@ -54,7 +55,8 @@ public class JDBCsetUp { /** * Executes an update using a connection with or without the database within the JDBC URL */ - private static void executeUpdate(boolean selectDatabase, 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(selectDatabase)) { try (PreparedStatement updateStatement = connection.prepareStatement(sql)) { @@ -66,16 +68,16 @@ public class JDBCsetUp { /** * Executes an update using a connection that includes the database in the JDBC URL */ - public static void executeUpdate(String sql) throws SQLException { - executeUpdate(true, sql); + 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 executeUpdateWithoutDatabase(String sql) throws SQLException { - executeUpdate(false, sql); + public static void executeUpdateWithoutDatabase(String sqlFormatString, Object... args) throws SQLException { + executeUpdate(false, sqlFormatString, args); } /** From 7f06aa7511c0122794c0011965efc3ddd059b0d6 Mon Sep 17 00:00:00 2001 From: EoD <293499+EoD@users.noreply.github.com> Date: Sat, 19 Jul 2025 19:41:02 +0000 Subject: [PATCH 3/4] reformat insert into server_info for readability Use the new format capabilities on SQL queries to make the insert more readable. --- .../vip/fubuki/playersync/PlayerSync.java | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main/java/vip/fubuki/playersync/PlayerSync.java b/src/main/java/vip/fubuki/playersync/PlayerSync.java index dc29afc..63e8e3f 100644 --- a/src/main/java/vip/fubuki/playersync/PlayerSync.java +++ b/src/main/java/vip/fubuki/playersync/PlayerSync.java @@ -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")) { From 4fe13bd24d3dbabd625b2e102532c4a6754951fb Mon Sep 17 00:00:00 2001 From: EoD <293499+EoD@users.noreply.github.com> Date: Mon, 28 Jul 2025 21:17:54 +0000 Subject: [PATCH 4/4] extract addColumnIfNotExists into separate method --- .../vip/fubuki/playersync/PlayerSync.java | 57 +++++++++++++------ 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/src/main/java/vip/fubuki/playersync/PlayerSync.java b/src/main/java/vip/fubuki/playersync/PlayerSync.java index 63e8e3f..072bacd 100644 --- a/src/main/java/vip/fubuki/playersync/PlayerSync.java +++ b/src/main/java/vip/fubuki/playersync/PlayerSync.java @@ -158,23 +158,8 @@ public class PlayerSync { "uuid CHAR(36) NOT NULL, backpack_nbt MEDIUMBLOB, PRIMARY KEY (uuid)" + ");" ); - // 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.executeUpdateWithoutDatabase("ALTER TABLE " + dbName + ".backpack_data ADD COLUMN uuid CHAR(36) NOT NULL"); - JDBCsetUp.executeUpdateWithoutDatabase("ALTER TABLE " + dbName + ".backpack_data ADD PRIMARY KEY (uuid)"); - } - 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 @@ -198,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); + } }