diff --git a/lang/en.yml b/lang/en.yml
index d2fcd5dfc..1d31f816d 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -125,6 +125,7 @@ MISSING_PARAMETERS: "Please use \"{0}\"."
MISSING_ROLLBACK_RADIUS: "You did not specify a {rollback|restore} radius."
MISSING_ROLLBACK_USER: "You did not specify a {rollback|restore} user."
MYSQL_UNAVAILABLE: "Unable to connect to MySQL server."
+PGSQL_UNAVAILABLE: "Unable to connect to PostgreSQL server."
NETWORK_CONNECTION: "Connection by {0} {successful|failed}. Using {1} {2}."
NETWORK_TEST: "Network test data has been successful sent."
NO_DATA: "No data found at {0}."
@@ -196,6 +197,7 @@ UPGRADE_IN_PROGRESS: "Upgrade in progress. Please try again later."
USER_NOT_FOUND: "User \"{0}\" not found."
USER_OFFLINE: "The user \"{0}\" is not online."
USING_MYSQL: "Using MySQL for data storage."
+USING_PGSQL: "Using PostgreSQL for data storage."
USING_SQLITE: "Using SQLite for data storage."
VALID_DONATION_KEY: "Valid donation key."
VERSION_NOTICE: "Version {0} is now available."
diff --git a/pom.xml b/pom.xml
index 0c035ad77..a60a4d823 100755
--- a/pom.xml
+++ b/pom.xml
@@ -129,5 +129,10 @@
HikariCP
5.0.1
+
+ org.postgresql
+ postgresql
+ 42.7.1
+
\ No newline at end of file
diff --git a/src/main/java/net/coreprotect/CoreProtect.java b/src/main/java/net/coreprotect/CoreProtect.java
index 7530af160..21e28afba 100755
--- a/src/main/java/net/coreprotect/CoreProtect.java
+++ b/src/main/java/net/coreprotect/CoreProtect.java
@@ -88,11 +88,19 @@ public void onEnable() {
if (start) {
PluginDescriptionFile pluginDescription = this.getDescription();
Util.sendConsoleComponentStartup(Bukkit.getServer().getConsoleSender(), Phrase.build(Phrase.ENABLE_SUCCESS, ConfigHandler.EDITION_NAME));
- if (Config.getGlobal().MYSQL) {
- Chat.console(Phrase.build(Phrase.USING_MYSQL));
- }
- else {
- Chat.console(Phrase.build(Phrase.USING_SQLITE));
+ switch (Config.getGlobal().DB_TYPE) {
+ case MYSQL: {
+ Chat.console(Phrase.build(Phrase.USING_MYSQL));
+ break;
+ }
+ case PGSQL: {
+ Chat.console(Phrase.build(Phrase.USING_PGSQL));
+ break;
+ }
+ case SQLITE: {
+ Chat.console(Phrase.build(Phrase.USING_SQLITE));
+ break;
+ }
}
Chat.console("--------------------");
diff --git a/src/main/java/net/coreprotect/api/BlockAPI.java b/src/main/java/net/coreprotect/api/BlockAPI.java
index 203363bb5..e9e1bcf6a 100644
--- a/src/main/java/net/coreprotect/api/BlockAPI.java
+++ b/src/main/java/net/coreprotect/api/BlockAPI.java
@@ -1,8 +1,8 @@
package net.coreprotect.api;
import java.sql.Connection;
+import java.sql.PreparedStatement;
import java.sql.ResultSet;
-import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
@@ -10,6 +10,7 @@
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
+import net.coreprotect.database.StatementUtils;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.utility.Util;
@@ -37,32 +38,34 @@ public static List performLookup(Block block, int offset) {
return result;
}
- Statement statement = connection.createStatement();
- String query = "SELECT time,user,action,type,data,blockdata,rolled_back FROM " + ConfigHandler.prefix + "block " + Util.getWidIndex("block") + "WHERE wid = '" + worldId + "' AND x = '" + x + "' AND z = '" + z + "' AND y = '" + y + "' AND time > '" + checkTime + "' ORDER BY rowid DESC";
- ResultSet results = statement.executeQuery(query);
+ try (PreparedStatement ps = connection.prepareStatement("SELECT time, \"user\", action, type, data, blockdata, rolled_back FROM " + StatementUtils.getTableName("block") + " " + Util.getWidIndex("block") + "WHERE wid = ? AND x = ? AND z = ? AND y = ? AND time > ? ORDER BY rowid DESC")) {
+ ps.setInt(1, worldId);
+ ps.setInt(2, x);
+ ps.setInt(3, z);
+ ps.setInt(4, y);
+ ps.setInt(5, checkTime);
+ try (ResultSet rs = ps.executeQuery()) {
+ while (rs.next()) {
+ String resultTime = rs.getString("time");
+ int resultUserId = rs.getInt("user");
+ String resultAction = rs.getString("action");
+ int resultType = rs.getInt("type");
+ String resultData = rs.getString("data");
+ byte[] resultBlockData = rs.getBytes("blockdata");
+ String resultRolledBack = rs.getString("rolled_back");
+ if (ConfigHandler.playerIdCacheReversed.get(resultUserId) == null) {
+ UserStatement.loadName(connection, resultUserId);
+ }
+ String resultUser = ConfigHandler.playerIdCacheReversed.get(resultUserId);
+ String blockData = Util.byteDataToString(resultBlockData, resultType);
- while (results.next()) {
- String resultTime = results.getString("time");
- int resultUserId = results.getInt("user");
- String resultAction = results.getString("action");
- int resultType = results.getInt("type");
- String resultData = results.getString("data");
- byte[] resultBlockData = results.getBytes("blockdata");
- String resultRolledBack = results.getString("rolled_back");
- if (ConfigHandler.playerIdCacheReversed.get(resultUserId) == null) {
- UserStatement.loadName(connection, resultUserId);
+ String[] lookupData = new String[] { resultTime, resultUser, String.valueOf(x), String.valueOf(y), String.valueOf(z), String.valueOf(resultType), resultData, resultAction, resultRolledBack, String.valueOf(worldId), blockData };
+ String[] lineData = Util.toStringArray(lookupData);
+ result.add(lineData);
+ }
}
- String resultUser = ConfigHandler.playerIdCacheReversed.get(resultUserId);
- String blockData = Util.byteDataToString(resultBlockData, resultType);
-
- String[] lookupData = new String[] { resultTime, resultUser, String.valueOf(x), String.valueOf(y), String.valueOf(z), String.valueOf(resultType), resultData, resultAction, resultRolledBack, String.valueOf(worldId), blockData };
- String[] lineData = Util.toStringArray(lookupData);
- result.add(lineData);
}
- results.close();
- statement.close();
- }
- catch (Exception e) {
+ } catch (Exception e) {
e.printStackTrace();
}
diff --git a/src/main/java/net/coreprotect/api/SessionLookup.java b/src/main/java/net/coreprotect/api/SessionLookup.java
index 60500697a..4f24af9b2 100644
--- a/src/main/java/net/coreprotect/api/SessionLookup.java
+++ b/src/main/java/net/coreprotect/api/SessionLookup.java
@@ -1,8 +1,8 @@
package net.coreprotect.api;
import java.sql.Connection;
+import java.sql.PreparedStatement;
import java.sql.ResultSet;
-import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -10,6 +10,7 @@
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
import net.coreprotect.database.Database;
+import net.coreprotect.database.StatementUtils;
import net.coreprotect.database.statement.UserStatement;
public class SessionLookup {
@@ -43,27 +44,28 @@ public static List performLookup(String user, int offset) {
}
int userId = ConfigHandler.playerIdCache.get(user.toLowerCase(Locale.ROOT));
- try (Statement statement = connection.createStatement()) {
- String query = "SELECT time,user,wid,x,y,z,action FROM " + ConfigHandler.prefix + "session WHERE user = '" + userId + "' AND time > '" + checkTime + "' ORDER BY rowid DESC";
- ResultSet results = statement.executeQuery(query);
- while (results.next()) {
- String resultTime = results.getString("time");
- int resultUserId = results.getInt("user");
- String resultWorldId = results.getString("wid");
- String resultX = results.getString("x");
- String resultY = results.getString("y");
- String resultZ = results.getString("z");
- String resultAction = results.getString("action");
+ try (PreparedStatement statement = connection.prepareStatement("SELECT time, \"user\", wid, x, y, z, action FROM " + StatementUtils.getTableName("session") + " WHERE \"user\" = ? AND time > ? ORDER BY rowid DESC")) {
+ statement.setInt(1, userId);
+ statement.setInt(2, checkTime);
+ try (ResultSet results = statement.executeQuery()) {
+ while (results.next()) {
+ String resultTime = results.getString("time");
+ int resultUserId = results.getInt("user");
+ String resultWorldId = results.getString("wid");
+ String resultX = results.getString("x");
+ String resultY = results.getString("y");
+ String resultZ = results.getString("z");
+ String resultAction = results.getString("action");
- if (ConfigHandler.playerIdCacheReversed.get(resultUserId) == null) {
- UserStatement.loadName(connection, resultUserId);
- }
- String resultUser = ConfigHandler.playerIdCacheReversed.get(resultUserId);
+ if (ConfigHandler.playerIdCacheReversed.get(resultUserId) == null) {
+ UserStatement.loadName(connection, resultUserId);
+ }
+ String resultUser = ConfigHandler.playerIdCacheReversed.get(resultUserId);
- String[] lookupData = new String[] { resultTime, resultUser, resultX, resultY, resultZ, resultWorldId, type, resultAction };
- result.add(lookupData);
+ String[] lookupData = new String[] { resultTime, resultUser, resultX, resultY, resultZ, resultWorldId, type, resultAction };
+ result.add(lookupData);
+ }
}
- results.close();
}
}
catch (Exception e) {
diff --git a/src/main/java/net/coreprotect/command/PurgeCommand.java b/src/main/java/net/coreprotect/command/PurgeCommand.java
index 59850c193..71b267765 100755
--- a/src/main/java/net/coreprotect/command/PurgeCommand.java
+++ b/src/main/java/net/coreprotect/command/PurgeCommand.java
@@ -15,8 +15,10 @@
import net.coreprotect.config.Config;
import net.coreprotect.config.ConfigHandler;
+import net.coreprotect.config.DatabaseType;
import net.coreprotect.consumer.Consumer;
import net.coreprotect.database.Database;
+import net.coreprotect.database.StatementUtils;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
import net.coreprotect.patch.Patch;
@@ -132,16 +134,13 @@ public void run() {
}
Consumer.isPaused = true;
- String query = "";
- PreparedStatement preparedStmt = null;
boolean abort = false;
String purgePrefix = "tmp_" + ConfigHandler.prefix;
- if (!Config.getGlobal().MYSQL) {
- query = "ATTACH DATABASE '" + ConfigHandler.path + ConfigHandler.sqlite + ".tmp' AS tmp_db";
- preparedStmt = connection.prepareStatement(query);
- preparedStmt.execute();
- preparedStmt.close();
+ if (Config.getGlobal().DB_TYPE == DatabaseType.SQLITE) {
+ try (PreparedStatement ps = connection.prepareStatement("ATTACH DATABASE '" + ConfigHandler.path + ConfigHandler.sqlite + ".tmp' AS tmp_db")) {
+ ps.execute();
+ }
purgePrefix = "tmp_db." + ConfigHandler.prefix;
}
@@ -154,15 +153,11 @@ public void run() {
return;
}
- if (!Config.getGlobal().MYSQL) {
+ if (Config.getGlobal().DB_TYPE == DatabaseType.SQLITE) {
for (String table : ConfigHandler.databaseTables) {
- try {
- query = "DROP TABLE IF EXISTS " + purgePrefix + table + "";
- preparedStmt = connection.prepareStatement(query);
- preparedStmt.execute();
- preparedStmt.close();
- }
- catch (Exception e) {
+ try (PreparedStatement ps = connection.prepareStatement("DROP TABLE IF EXISTS " + purgePrefix + table)) {
+ ps.execute();
+ } catch (Exception e) {
e.printStackTrace();
}
}
@@ -177,21 +172,22 @@ public void run() {
String tableName = table.replaceAll("_", " ");
Chat.sendGlobalMessage(player, Phrase.build(Phrase.PURGE_PROCESSING, tableName));
- if (!Config.getGlobal().MYSQL) {
+ if (Config.getGlobal().DB_TYPE == DatabaseType.SQLITE) {
String columns = "";
- ResultSet rs = connection.createStatement().executeQuery("SELECT * FROM " + purgePrefix + table);
- ResultSetMetaData resultSetMetaData = rs.getMetaData();
- int columnCount = resultSetMetaData.getColumnCount();
- for (int i = 1; i <= columnCount; i++) {
- String name = resultSetMetaData.getColumnName(i);
- if (columns.length() == 0) {
- columns = name;
- }
- else {
- columns = columns + "," + name;
+ try (PreparedStatement ps = connection.prepareStatement("SELECT * FROM " + purgePrefix + table);
+ ResultSet rs = ps.executeQuery();) {
+ ResultSetMetaData resultSetMetaData = rs.getMetaData();
+ int columnCount = resultSetMetaData.getColumnCount();
+ for (int i = 1; i <= columnCount; i++) {
+ String name = resultSetMetaData.getColumnName(i);
+ if (columns.length() == 0) {
+ columns = name;
+ }
+ else {
+ columns = columns + "," + name;
+ }
}
}
- rs.close();
boolean error = false;
if (!excludeTables.contains(table)) {
@@ -205,10 +201,9 @@ else if (argWid == 0) {
timeLimit = " WHERE (time >= '" + timeEnd + "' OR time < '" + timeStart + "')";
}
}
- query = "INSERT INTO " + purgePrefix + table + " SELECT " + columns + " FROM " + ConfigHandler.prefix + table + timeLimit;
- preparedStmt = connection.prepareStatement(query);
- preparedStmt.execute();
- preparedStmt.close();
+ try (PreparedStatement ps = connection.prepareStatement("INSERT INTO " + purgePrefix + table + " SELECT " + columns + " FROM " + StatementUtils.getTableName(table) + timeLimit)) {
+ ps.execute();
+ }
}
catch (Exception e) {
error = true;
@@ -220,21 +215,15 @@ else if (argWid == 0) {
Chat.sendGlobalMessage(player, Phrase.build(Phrase.PURGE_ERROR, tableName));
Chat.sendGlobalMessage(player, Phrase.build(Phrase.PURGE_REPAIRING));
- try {
- query = "DELETE FROM " + purgePrefix + table;
- preparedStmt = connection.prepareStatement(query);
- preparedStmt.execute();
- preparedStmt.close();
+ try (PreparedStatement ps = connection.prepareStatement("DELETE FROM " + purgePrefix + table)) {
+ ps.execute();
}
catch (Exception e) {
e.printStackTrace();
}
- try {
- query = "REINDEX " + ConfigHandler.prefix + table;
- preparedStmt = connection.prepareStatement(query);
- preparedStmt.execute();
- preparedStmt.close();
+ try (PreparedStatement ps = connection.prepareStatement("REINDEX " + StatementUtils.getTableName(table))) {
+ ps.execute();
}
catch (Exception e) {
e.printStackTrace();
@@ -242,10 +231,9 @@ else if (argWid == 0) {
try {
String index = " NOT INDEXED";
- query = "INSERT INTO " + purgePrefix + table + " SELECT " + columns + " FROM " + ConfigHandler.prefix + table + index;
- preparedStmt = connection.prepareStatement(query);
- preparedStmt.execute();
- preparedStmt.close();
+ try (PreparedStatement ps = connection.prepareStatement("INSERT INTO " + purgePrefix + table + " SELECT " + columns + " FROM " + StatementUtils.getTableName(table) + index)) {
+ ps.execute();
+ }
}
catch (Exception e) {
e.printStackTrace();
@@ -265,10 +253,9 @@ else if (argWid > 0) {
}
if (purge) {
- query = "DELETE FROM " + purgePrefix + table + " WHERE time < '" + timeEnd + "' AND time >= '" + timeStart + "'" + worldRestriction;
- preparedStmt = connection.prepareStatement(query);
- preparedStmt.execute();
- preparedStmt.close();
+ try (PreparedStatement ps = connection.prepareStatement("DELETE FROM " + purgePrefix + table + " WHERE time < '" + timeEnd + "' AND time >= '" + timeStart + "'" + worldRestriction)) {
+ ps.execute();
+ }
}
}
catch (Exception e) {
@@ -278,32 +265,22 @@ else if (argWid > 0) {
if (purgeTables.contains(table)) {
int oldCount = 0;
- try {
- query = "SELECT COUNT(*) as count FROM " + ConfigHandler.prefix + table + " LIMIT 0, 1";
- preparedStmt = connection.prepareStatement(query);
- ResultSet resultSet = preparedStmt.executeQuery();
+ try (PreparedStatement ps = connection.prepareStatement("SELECT COUNT(*) as count FROM " + StatementUtils.getTableName(table) + " LIMIT 1");
+ ResultSet resultSet = ps.executeQuery();) {
while (resultSet.next()) {
oldCount = resultSet.getInt("count");
}
- resultSet.close();
- preparedStmt.close();
- }
- catch (Exception e) {
+ } catch (Exception e) {
e.printStackTrace();
}
int new_count = 0;
- try {
- query = "SELECT COUNT(*) as count FROM " + purgePrefix + table + " LIMIT 0, 1";
- preparedStmt = connection.prepareStatement(query);
- ResultSet resultSet = preparedStmt.executeQuery();
+ try (PreparedStatement ps = connection.prepareStatement("SELECT COUNT(*) as count FROM " + purgePrefix + table + " LIMIT 1");
+ ResultSet resultSet = ps.executeQuery();) {
while (resultSet.next()) {
new_count = resultSet.getInt("count");
}
- resultSet.close();
- preparedStmt.close();
- }
- catch (Exception e) {
+ } catch (Exception e) {
e.printStackTrace();
}
@@ -311,24 +288,28 @@ else if (argWid > 0) {
}
}
- if (Config.getGlobal().MYSQL) {
+ if (Config.getGlobal().DB_TYPE != DatabaseType.SQLITE) {
try {
boolean purge = purgeTables.contains(table);
String worldRestriction = "";
if (argWid > 0 && worldTables.contains(table)) {
- worldRestriction = " AND wid = '" + argWid + "'";
+ worldRestriction = " AND wid = ?";
}
else if (argWid > 0) {
purge = false;
}
if (purge) {
- query = "DELETE FROM " + ConfigHandler.prefix + table + " WHERE time < '" + timeEnd + "' AND time >= '" + timeStart + "'" + worldRestriction;
- preparedStmt = connection.prepareStatement(query);
- preparedStmt.execute();
- removed = removed + preparedStmt.getUpdateCount();
- preparedStmt.close();
+ try (PreparedStatement preparedStmt = connection.prepareStatement("DELETE FROM " + StatementUtils.getTableName(table) + " WHERE time < ? AND time >= ?" + worldRestriction)) {
+ preparedStmt.setLong(1, timeEnd);
+ preparedStmt.setLong(2, timeStart);
+ if (!worldRestriction.isEmpty()) {
+ preparedStmt.setInt(3, argWid);
+ }
+ preparedStmt.execute();
+ removed = removed + preparedStmt.getUpdateCount();
+ }
}
}
catch (Exception e) {
@@ -342,20 +323,37 @@ else if (argWid > 0) {
}
}
- if (Config.getGlobal().MYSQL && optimize) {
- Chat.sendGlobalMessage(player, Phrase.build(Phrase.PURGE_OPTIMIZING));
- for (String table : ConfigHandler.databaseTables) {
- query = "OPTIMIZE LOCAL TABLE " + ConfigHandler.prefix + table + "";
- preparedStmt = connection.prepareStatement(query);
- preparedStmt.execute();
- preparedStmt.close();
+ if (optimize) {
+ switch (Config.getGlobal().DB_TYPE) {
+ case MYSQL: {
+ Chat.sendGlobalMessage(player, Phrase.build(Phrase.PURGE_OPTIMIZING));
+ for (String table : ConfigHandler.databaseTables) {
+ try (PreparedStatement preparedStmt = connection.prepareStatement("OPTIMIZE LOCAL TABLE " + StatementUtils.getTableName(table))) {
+ preparedStmt.execute();
+ }
+ }
+ break;
+ }
+ case PGSQL: {
+ Chat.sendGlobalMessage(player, Phrase.build(Phrase.PURGE_OPTIMIZING));
+ for (String table : ConfigHandler.databaseTables) {
+ try (PreparedStatement preparedStmt = connection.prepareStatement("VACUUM ANALYZE " + StatementUtils.getTableName(table))) {
+ preparedStmt.execute();
+ }
+ }
+ break;
+ }
+ default: {
+ // no optimization options for SQLite
+ break;
+ }
}
}
connection.close();
if (abort) {
- if (!Config.getGlobal().MYSQL) {
+ if (Config.getGlobal().DB_TYPE == DatabaseType.SQLITE) {
(new File(ConfigHandler.path + ConfigHandler.sqlite + ".tmp")).delete();
}
ConfigHandler.loadDatabase();
@@ -365,7 +363,7 @@ else if (argWid > 0) {
return;
}
- if (!Config.getGlobal().MYSQL) {
+ if (Config.getGlobal().DB_TYPE == DatabaseType.SQLITE) {
(new File(ConfigHandler.path + ConfigHandler.sqlite)).delete();
(new File(ConfigHandler.path + ConfigHandler.sqlite + ".tmp")).renameTo(new File(ConfigHandler.path + ConfigHandler.sqlite));
}
diff --git a/src/main/java/net/coreprotect/command/StatusCommand.java b/src/main/java/net/coreprotect/command/StatusCommand.java
index 2d806fc2f..bfc7544b8 100755
--- a/src/main/java/net/coreprotect/command/StatusCommand.java
+++ b/src/main/java/net/coreprotect/command/StatusCommand.java
@@ -65,11 +65,19 @@ Items processed (last 60 minutes)
if (firstVersion.length() > 0) {
firstVersion = " (" + Phrase.build(Phrase.FIRST_VERSION, firstVersion) + ")";
}
- if (Config.getGlobal().MYSQL) {
- Chat.sendMessage(player, Color.DARK_AQUA + Phrase.build(Phrase.STATUS_DATABASE, Color.WHITE, "MySQL") + firstVersion);
- }
- else {
- Chat.sendMessage(player, Color.DARK_AQUA + Phrase.build(Phrase.STATUS_DATABASE, Color.WHITE, "SQLite") + firstVersion);
+ switch (Config.getGlobal().DB_TYPE) {
+ case MYSQL: {
+ Chat.sendMessage(player, Color.DARK_AQUA + Phrase.build(Phrase.STATUS_DATABASE, Color.WHITE, "MySQL") + firstVersion);
+ break;
+ }
+ case PGSQL: {
+ Chat.sendMessage(player, Color.DARK_AQUA + Phrase.build(Phrase.STATUS_DATABASE, Color.WHITE, "PostgreSQL") + firstVersion);
+ break;
+ }
+ case SQLITE: {
+ Chat.sendMessage(player, Color.DARK_AQUA + Phrase.build(Phrase.STATUS_DATABASE, Color.WHITE, "SQLite") + firstVersion);
+ break;
+ }
}
if (ConfigHandler.worldeditEnabled) {
diff --git a/src/main/java/net/coreprotect/config/Config.java b/src/main/java/net/coreprotect/config/Config.java
index bae4f1617..cd75cb5ce 100644
--- a/src/main/java/net/coreprotect/config/Config.java
+++ b/src/main/java/net/coreprotect/config/Config.java
@@ -11,6 +11,7 @@
import java.nio.file.Files;
import java.util.HashMap;
import java.util.LinkedHashMap;
+import java.util.Locale;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
@@ -36,11 +37,14 @@ public class Config extends Language {
private Config defaults;
public String DONATION_KEY;
- public String PREFIX;
- public String MYSQL_HOST;
- public String MYSQL_DATABASE;
- public String MYSQL_USERNAME;
- public String MYSQL_PASSWORD;
+ public DatabaseType DB_TYPE;
+ public String DB_PREFIX;
+ public String DB_HOST;
+ public int DB_PORT;
+ public String DB_DATABASE;
+ public String DB_USERNAME;
+ public String DB_PASSWORD;
+ public String DB_JDBC_PARAMETERS;
public String LANGUAGE;
public boolean ENABLE_AWE;
public boolean ENABLE_SSL;
@@ -51,7 +55,6 @@ public class Config extends Language {
public boolean HOPPER_FILTER_META;
public boolean EXCLUDE_TNT;
public boolean NETWORK_DEBUG;
- public boolean MYSQL;
public boolean CHECK_UPDATES;
public boolean API_ENABLED;
public boolean VERBOSE;
@@ -91,19 +94,19 @@ public class Config extends Language {
public boolean USERNAME_CHANGES;
public boolean WORLDEDIT;
public int MAXIMUM_POOL_SIZE;
- public int MYSQL_PORT;
public int DEFAULT_RADIUS;
public int MAX_RADIUS;
static {
DEFAULT_VALUES.put("donation-key", "");
- DEFAULT_VALUES.put("use-mysql", "false");
+ DEFAULT_VALUES.put("db-type", "sqlite");
DEFAULT_VALUES.put("table-prefix", "co_");
- DEFAULT_VALUES.put("mysql-host", "127.0.0.1");
- DEFAULT_VALUES.put("mysql-port", "3306");
- DEFAULT_VALUES.put("mysql-database", "database");
- DEFAULT_VALUES.put("mysql-username", "root");
- DEFAULT_VALUES.put("mysql-password", "");
+ DEFAULT_VALUES.put("db-host", "127.0.0.1");
+ DEFAULT_VALUES.put("db-port", "3306");
+ DEFAULT_VALUES.put("db-database", "database");
+ DEFAULT_VALUES.put("db-username", "root");
+ DEFAULT_VALUES.put("db-password", "");
+ DEFAULT_VALUES.put("db-jdbc-parameters", "");
DEFAULT_VALUES.put("language", "en");
DEFAULT_VALUES.put("check-updates", "true");
DEFAULT_VALUES.put("api-enabled", "true");
@@ -146,7 +149,8 @@ public class Config extends Language {
DEFAULT_VALUES.put("worldedit", "true");
HEADERS.put("donation-key", new String[] { "# CoreProtect is donationware. Obtain a donation key from coreprotect.net/donate/" });
- HEADERS.put("use-mysql", new String[] { "# MySQL is optional and not required.", "# If you prefer to use MySQL, enable the following and fill out the fields." });
+ HEADERS.put("db-type", new String[] { "# The database type to use. By default this is \"sqlite\"", "# Available options: sqlite, mysql, pgsql" });
+ HEADERS.put("db-jdbc-parameters", new String[] { "# Extra parameters to append to the JDBC connection string. Only needed for advanced cases." });
HEADERS.put("language", new String[] { "# If modified, will automatically attempt to translate languages phrases.", "# List of language codes: https://coreprotect.net/languages/" });
HEADERS.put("check-updates", new String[] { "# If enabled, CoreProtect will check for updates when your server starts up.", "# If an update is available, you'll be notified via your server console.", });
HEADERS.put("api-enabled", new String[] { "# If enabled, other plugins will be able to utilize the CoreProtect API.", });
@@ -202,13 +206,34 @@ private void readValues() {
this.UNKNOWN_LOGGING = this.getBoolean("unknown-logging", false);
this.MAXIMUM_POOL_SIZE = this.getInt("maximum-pool-size", 10);
this.DONATION_KEY = this.getString("donation-key");
- this.MYSQL = this.getBoolean("use-mysql");
- this.PREFIX = this.getString("table-prefix");
- this.MYSQL_HOST = this.getString("mysql-host");
- this.MYSQL_PORT = this.getInt("mysql-port");
- this.MYSQL_DATABASE = this.getString("mysql-database");
- this.MYSQL_USERNAME = this.getString("mysql-username");
- this.MYSQL_PASSWORD = this.getString("mysql-password");
+ this.DB_TYPE = DatabaseType.valueOf(DatabaseType.class, this.getString("db-type", "sqlite").toUpperCase(Locale.ROOT));
+ if (this.has("use-mysql") && this.getBoolean("use-mysql")) {
+ // legacy configuration has mysql enabled
+ this.DB_TYPE = DatabaseType.MYSQL;
+ DEFAULT_VALUES.put("db-type", DatabaseType.MYSQL.toString().toLowerCase(Locale.ROOT));
+ }
+ this.DB_PREFIX = this.getString("table-prefix");
+ this.DB_HOST = this.getString("db-host");
+ if (this.DB_HOST == null && this.has("mysql-host")) {
+ this.DB_HOST = this.getString("mysql-host");
+ }
+ this.DB_PORT = this.getInt("db-port");
+ if (this.DB_PORT == 0 && this.has("mysql-port")) {
+ this.DB_PORT = this.getInt("mysql-port");
+ }
+ this.DB_DATABASE = this.getString("db-database");
+ if (this.DB_DATABASE == null && this.has("mysql-database")) {
+ this.DB_DATABASE = this.getString("mysql-database");
+ }
+ this.DB_USERNAME = this.getString("db-username");
+ if (this.DB_USERNAME == null && this.has("mysql-username")) {
+ this.DB_USERNAME = this.getString("mysql-username");
+ }
+ this.DB_PASSWORD = this.getString("db-password");
+ if (this.DB_PASSWORD == null && this.has("mysql-password")) {
+ this.DB_PASSWORD = this.getString("mysql-password");
+ }
+ this.DB_JDBC_PARAMETERS = this.getString("db-jdbc-parameters");
this.LANGUAGE = this.getString("language");
this.CHECK_UPDATES = this.getBoolean("check-updates");
this.API_ENABLED = this.getBoolean("api-enabled");
@@ -278,6 +303,10 @@ public void setDefaults(final Config defaults) {
this.defaults = defaults;
}
+ private boolean has(final String key) {
+ return this.config.containsKey(key);
+ }
+
private String get(final String key, final String dfl) {
String configured = this.config.get(key);
if (configured == null) {
@@ -325,6 +354,11 @@ private String getString(final String key) {
return configured == null ? "" : configured;
}
+ private String getString(final String key, final String dfl) {
+ final String configured = this.get(key, dfl);
+ return configured == null ? "" : configured;
+ }
+
public void clearConfig() {
this.config.clear();
}
diff --git a/src/main/java/net/coreprotect/config/ConfigHandler.java b/src/main/java/net/coreprotect/config/ConfigHandler.java
index a1cd7f7ad..85618e88e 100644
--- a/src/main/java/net/coreprotect/config/ConfigHandler.java
+++ b/src/main/java/net/coreprotect/config/ConfigHandler.java
@@ -26,6 +26,7 @@
import net.coreprotect.bukkit.BukkitAdapter;
import net.coreprotect.consumer.Queue;
import net.coreprotect.database.Database;
+import net.coreprotect.database.StatementUtils;
import net.coreprotect.database.statement.UserStatement;
import net.coreprotect.language.Phrase;
import net.coreprotect.listener.ListenerHandler;
@@ -51,6 +52,7 @@ public class ConfigHandler extends Queue {
public static String database = "database";
public static String username = "root";
public static String password = "";
+ public static String jdbcParameters = "";
public static String prefix = "co_";
public static int maximumPoolSize = 10;
@@ -167,17 +169,18 @@ private static void loadConfig() {
ConfigFile.init(ConfigFile.LANGUAGE_CACHE); // load translation cache
// Enforce "co_" table prefix if using SQLite.
- if (!Config.getGlobal().MYSQL) {
- Config.getGlobal().PREFIX = "co_";
+ if (Config.getGlobal().DB_TYPE == DatabaseType.SQLITE) {
+ Config.getGlobal().DB_PREFIX = "co_";
}
- ConfigHandler.host = Config.getGlobal().MYSQL_HOST;
- ConfigHandler.port = Config.getGlobal().MYSQL_PORT;
- ConfigHandler.database = Config.getGlobal().MYSQL_DATABASE;
- ConfigHandler.username = Config.getGlobal().MYSQL_USERNAME;
- ConfigHandler.password = Config.getGlobal().MYSQL_PASSWORD;
+ ConfigHandler.host = Config.getGlobal().DB_HOST;
+ ConfigHandler.port = Config.getGlobal().DB_PORT;
+ ConfigHandler.database = Config.getGlobal().DB_DATABASE;
+ ConfigHandler.username = Config.getGlobal().DB_USERNAME;
+ ConfigHandler.password = Config.getGlobal().DB_PASSWORD;
+ ConfigHandler.jdbcParameters = Config.getGlobal().DB_JDBC_PARAMETERS;
ConfigHandler.maximumPoolSize = Config.getGlobal().MAXIMUM_POOL_SIZE;
- ConfigHandler.prefix = Config.getGlobal().PREFIX;
+ ConfigHandler.prefix = Config.getGlobal().DB_PREFIX;
ConfigHandler.loadBlacklist(); // Load the blacklist file if it exists.
}
@@ -190,7 +193,7 @@ public static void loadDatabase() {
// close old pool when we reload the database, e.g. in purge command
Database.closeConnection();
- if (!Config.getGlobal().MYSQL) {
+ if (Config.getGlobal().DB_TYPE == DatabaseType.SQLITE) {
try {
File tempFile = File.createTempFile("CoreProtect_" + System.currentTimeMillis(), ".tmp");
tempFile.setExecutable(true);
@@ -219,8 +222,7 @@ public static void loadDatabase() {
catch (Exception e) {
e.printStackTrace();
}
- }
- else {
+ } else if (Config.getGlobal().DB_TYPE == DatabaseType.MYSQL){
HikariConfig config = new HikariConfig();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
@@ -230,7 +232,7 @@ public static void loadDatabase() {
config.setDriverClassName("com.mysql.jdbc.Driver");
}
- config.setJdbcUrl("jdbc:mysql://" + ConfigHandler.host + ":" + ConfigHandler.port + "/" + ConfigHandler.database);
+ config.setJdbcUrl("jdbc:mysql://" + ConfigHandler.host + ":" + ConfigHandler.port + "/" + ConfigHandler.database + ConfigHandler.jdbcParameters);
config.setUsername(ConfigHandler.username);
config.setPassword(ConfigHandler.password);
config.setMaximumPoolSize(ConfigHandler.maximumPoolSize);
@@ -251,6 +253,21 @@ public static void loadDatabase() {
config.addDataSourceProperty("allowPublicKeyRetrieval", "true");
config.addDataSourceProperty("useSSL", Config.getGlobal().ENABLE_SSL);
+ ConfigHandler.hikariDataSource = new HikariDataSource(config);
+ } else if (Config.getGlobal().DB_TYPE == DatabaseType.PGSQL) {
+ HikariConfig config = new HikariConfig();
+ try {
+ Class.forName("org.postgresql.Driver");
+ config.setDriverClassName("org.postgresql.Driver");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ config.setJdbcUrl("jdbc:postgresql://" + ConfigHandler.host + ":" + ConfigHandler.port + "/" + ConfigHandler.database + ConfigHandler.jdbcParameters);
+ config.setUsername(ConfigHandler.username);
+ config.setPassword(ConfigHandler.password);
+ config.setMaxLifetime(300000);
+ config.setKeepaliveTime(60000);
+
ConfigHandler.hikariDataSource = new HikariDataSource(config);
}
@@ -259,7 +276,7 @@ public static void loadDatabase() {
public static void loadTypes(Statement statement) {
try {
- String query = "SELECT id,material FROM " + ConfigHandler.prefix + "material_map";
+ String query = "SELECT id,material FROM " + StatementUtils.getTableName("material_map");
ResultSet rs = statement.executeQuery(query);
ConfigHandler.materials.clear();
ConfigHandler.materialsReversed.clear();
@@ -276,7 +293,7 @@ public static void loadTypes(Statement statement) {
}
rs.close();
- query = "SELECT id,data FROM " + ConfigHandler.prefix + "blockdata_map";
+ query = "SELECT id,data FROM " + StatementUtils.getTableName("blockdata_map");
rs = statement.executeQuery(query);
ConfigHandler.blockdata.clear();
ConfigHandler.blockdataReversed.clear();
@@ -293,7 +310,7 @@ public static void loadTypes(Statement statement) {
}
rs.close();
- query = "SELECT id,art FROM " + ConfigHandler.prefix + "art_map";
+ query = "SELECT id, art FROM " + StatementUtils.getTableName("art_map");
rs = statement.executeQuery(query);
ConfigHandler.art.clear();
ConfigHandler.artReversed.clear();
@@ -310,7 +327,7 @@ public static void loadTypes(Statement statement) {
}
rs.close();
- query = "SELECT id,entity FROM " + ConfigHandler.prefix + "entity_map";
+ query = "SELECT id,entity FROM " + StatementUtils.getTableName("entity_map");
rs = statement.executeQuery(query);
ConfigHandler.entities.clear();
ConfigHandler.entitiesReversed.clear();
@@ -334,7 +351,7 @@ public static void loadTypes(Statement statement) {
public static void loadWorlds(Statement statement) {
try {
- String query = "SELECT id,world FROM " + ConfigHandler.prefix + "world";
+ String query = "SELECT id,world FROM " + StatementUtils.getTableName("world");
ResultSet rs = statement.executeQuery(query);
ConfigHandler.worlds.clear();
ConfigHandler.worldsReversed.clear();
@@ -379,7 +396,7 @@ private static boolean checkDatabaseLock(Statement statement) {
locked = false;
unixtimestamp = (int) (System.currentTimeMillis() / 1000L);
int checkTime = unixtimestamp - 15;
- String query = "SELECT * FROM " + ConfigHandler.prefix + "database_lock WHERE rowid='1' AND status='1' AND time >= '" + checkTime + "' LIMIT 1";
+ String query = "SELECT * FROM " + StatementUtils.getTableName("database_lock") + " WHERE rowid='1' AND status='1' AND time >= '" + checkTime + "' LIMIT 1";
ResultSet rs = statement.executeQuery(query);
while (rs.next()) {
if (unixtimestamp < waitTime) {
diff --git a/src/main/java/net/coreprotect/config/DatabaseType.java b/src/main/java/net/coreprotect/config/DatabaseType.java
new file mode 100644
index 000000000..0b4963003
--- /dev/null
+++ b/src/main/java/net/coreprotect/config/DatabaseType.java
@@ -0,0 +1,7 @@
+package net.coreprotect.config;
+
+public enum DatabaseType {
+ SQLITE,
+ MYSQL,
+ PGSQL; // PostgreSQL
+}
\ No newline at end of file
diff --git a/src/main/java/net/coreprotect/consumer/process/ArtInsertProcess.java b/src/main/java/net/coreprotect/consumer/process/ArtInsertProcess.java
index 1479f7f8f..9a0ac7e02 100644
--- a/src/main/java/net/coreprotect/consumer/process/ArtInsertProcess.java
+++ b/src/main/java/net/coreprotect/consumer/process/ArtInsertProcess.java
@@ -4,6 +4,7 @@
import java.sql.Statement;
import net.coreprotect.config.ConfigHandler;
+import net.coreprotect.database.StatementUtils;
import net.coreprotect.database.statement.MaterialStatement;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
@@ -13,7 +14,7 @@ class ArtInsertProcess {
static void process(PreparedStatement preparedStmt, Statement statement, int batchCount, Object name, int materialId) {
if (name instanceof String) {
- String query = "SELECT id FROM " + ConfigHandler.prefix + "art_map WHERE id = '" + materialId + "' LIMIT 0, 1";
+ String query = "SELECT id FROM " + StatementUtils.getTableName("art_map") + " WHERE id = '" + materialId + "' LIMIT 1";
boolean hasMaterial = MaterialStatement.hasMaterial(statement, query);
if (!hasMaterial) {
MaterialStatement.insert(preparedStmt, batchCount, materialId, (String) name);
diff --git a/src/main/java/net/coreprotect/consumer/process/BlockDataInsertProcess.java b/src/main/java/net/coreprotect/consumer/process/BlockDataInsertProcess.java
index 2e53366ac..2487674a9 100644
--- a/src/main/java/net/coreprotect/consumer/process/BlockDataInsertProcess.java
+++ b/src/main/java/net/coreprotect/consumer/process/BlockDataInsertProcess.java
@@ -4,6 +4,7 @@
import java.sql.Statement;
import net.coreprotect.config.ConfigHandler;
+import net.coreprotect.database.StatementUtils;
import net.coreprotect.database.statement.MaterialStatement;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
@@ -13,7 +14,7 @@ class BlockDataInsertProcess {
static void process(PreparedStatement preparedStmt, Statement statement, int batchCount, Object name, int materialId) {
if (name instanceof String) {
- String query = "SELECT id FROM " + ConfigHandler.prefix + "blockdata_map WHERE id = '" + materialId + "' LIMIT 0, 1";
+ String query = "SELECT id FROM " + StatementUtils.getTableName("blockdata_map") + " WHERE id = '" + materialId + "' LIMIT 1";
boolean hasMaterial = MaterialStatement.hasMaterial(statement, query);
if (!hasMaterial) {
MaterialStatement.insert(preparedStmt, batchCount, materialId, (String) name);
diff --git a/src/main/java/net/coreprotect/consumer/process/EntityInsertProcess.java b/src/main/java/net/coreprotect/consumer/process/EntityInsertProcess.java
index f6bae6783..84e5f2d2e 100644
--- a/src/main/java/net/coreprotect/consumer/process/EntityInsertProcess.java
+++ b/src/main/java/net/coreprotect/consumer/process/EntityInsertProcess.java
@@ -4,6 +4,7 @@
import java.sql.Statement;
import net.coreprotect.config.ConfigHandler;
+import net.coreprotect.database.StatementUtils;
import net.coreprotect.database.statement.MaterialStatement;
import net.coreprotect.language.Phrase;
import net.coreprotect.language.Selector;
@@ -13,7 +14,7 @@ class EntityInsertProcess {
static void process(PreparedStatement preparedStmt, Statement statement, int batchCount, Object name, int materialId) {
if (name instanceof String) {
- String query = "SELECT id FROM " + ConfigHandler.prefix + "entity_map WHERE id = '" + materialId + "' LIMIT 0, 1";
+ String query = "SELECT id FROM " + StatementUtils.getTableName("entity_map") + " WHERE id = '" + materialId + "' LIMIT 1";
boolean hasMaterial = MaterialStatement.hasMaterial(statement, query);
if (!hasMaterial) {
MaterialStatement.insert(preparedStmt, batchCount, materialId, (String) name);
diff --git a/src/main/java/net/coreprotect/consumer/process/EntitySpawnProcess.java b/src/main/java/net/coreprotect/consumer/process/EntitySpawnProcess.java
index f9dbbe43d..25611f595 100644
--- a/src/main/java/net/coreprotect/consumer/process/EntitySpawnProcess.java
+++ b/src/main/java/net/coreprotect/consumer/process/EntitySpawnProcess.java
@@ -6,7 +6,7 @@
import org.bukkit.block.BlockState;
import org.bukkit.entity.EntityType;
-import net.coreprotect.config.ConfigHandler;
+import net.coreprotect.database.StatementUtils;
import net.coreprotect.database.statement.EntityStatement;
import net.coreprotect.utility.entity.EntityUtil;
@@ -16,7 +16,7 @@ static void process(Statement statement, Object object, int rowId) {
if (object instanceof Object[]) {
BlockState block = (BlockState) ((Object[]) object)[0];
EntityType type = (EntityType) ((Object[]) object)[1];
- String query = "SELECT data FROM " + ConfigHandler.prefix + "entity WHERE rowid='" + rowId + "' LIMIT 0, 1";
+ String query = "SELECT data FROM " + StatementUtils.getTableName("entity") + " WHERE rowid='" + rowId + "' LIMIT 1";
List