diff --git a/common/pom.xml b/common/pom.xml
index 695c5eab..41863dbd 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -74,6 +74,13 @@
1.4.192
provided
+
+
+ org.postgresql
+ postgresql
+ 9.4.1212
+ provided
+
org.mongodb
diff --git a/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java b/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java
index f902fac5..f406d673 100644
--- a/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java
+++ b/common/src/main/java/me/lucko/luckperms/common/dependencies/Dependency.java
@@ -30,6 +30,7 @@ import lombok.Getter;
public enum Dependency {
MYSQL_DRIVER("https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.6/mysql-connector-java-5.1.6.jar", "5.1.6", "com.mysql.jdbc.jdbc2.optional.MysqlDataSource"),
+ POSTGRESQL_DRIVER("https://repo1.maven.org/maven2/org/postgresql/postgresql/9.4.1212/postgresql-9.4.1212.jar", "9.4.1212", "org.postgresql.ds.PGSimpleDataSource"),
H2_DRIVER("https://repo1.maven.org/maven2/com/h2database/h2/1.4.193/h2-1.4.193.jar", "1.4.193", "org.h2.Driver"),
SQLITE_DRIVER("https://repo1.maven.org/maven2/org/xerial/sqlite-jdbc/3.15.1/sqlite-jdbc-3.15.1.jar", "3.15.1", "org.sqlite.JDBC"),
HIKARI("https://repo1.maven.org/maven2/com/zaxxer/HikariCP/2.5.1/HikariCP-2.5.1.jar", "2.5.1", "com.zaxxer.hikari.HikariDataSource"),
diff --git a/common/src/main/java/me/lucko/luckperms/common/dependencies/DependencyManager.java b/common/src/main/java/me/lucko/luckperms/common/dependencies/DependencyManager.java
index 067ef19e..fa5a3fe9 100644
--- a/common/src/main/java/me/lucko/luckperms/common/dependencies/DependencyManager.java
+++ b/common/src/main/java/me/lucko/luckperms/common/dependencies/DependencyManager.java
@@ -60,6 +60,7 @@ public class DependencyManager {
.put(StorageType.YAML, ImmutableList.of())
.put(StorageType.MONGODB, ImmutableList.of(Dependency.MONGODB_DRIVER))
.put(StorageType.MYSQL, ImmutableList.of(Dependency.MYSQL_DRIVER, Dependency.SLF4J_API, Dependency.SLF4J_SIMPLE, Dependency.HIKARI))
+ .put(StorageType.POSTGRESQL, ImmutableList.of(Dependency.POSTGRESQL_DRIVER, Dependency.SLF4J_API, Dependency.SLF4J_SIMPLE, Dependency.HIKARI))
.put(StorageType.SQLITE, ImmutableList.of(Dependency.SQLITE_DRIVER))
.put(StorageType.H2, ImmutableList.of(Dependency.H2_DRIVER))
.build();
diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/StorageFactory.java b/common/src/main/java/me/lucko/luckperms/common/storage/StorageFactory.java
index d0d7438a..32979dcb 100644
--- a/common/src/main/java/me/lucko/luckperms/common/storage/StorageFactory.java
+++ b/common/src/main/java/me/lucko/luckperms/common/storage/StorageFactory.java
@@ -30,7 +30,7 @@ import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.storage.backing.AbstractBacking;
import me.lucko.luckperms.common.storage.backing.JSONBacking;
import me.lucko.luckperms.common.storage.backing.MongoDBBacking;
-import me.lucko.luckperms.common.storage.backing.SQLBacking;
+import me.lucko.luckperms.common.storage.backing.SQLLegacyBacking;
import me.lucko.luckperms.common.storage.backing.YAMLBacking;
import me.lucko.luckperms.common.storage.backing.sqlprovider.H2Provider;
import me.lucko.luckperms.common.storage.backing.sqlprovider.MySQLProvider;
@@ -120,11 +120,11 @@ public class StorageFactory {
private static AbstractBacking makeBacking(StorageType method, LuckPermsPlugin plugin) {
switch (method) {
case MYSQL:
- return new SQLBacking(plugin, new MySQLProvider(plugin.getConfiguration().getDatabaseValues()));
+ return new SQLLegacyBacking(plugin, new MySQLProvider(plugin.getConfiguration().getDatabaseValues()));
case SQLITE:
- return new SQLBacking(plugin, new SQLiteProvider(new File(plugin.getDataFolder(), "luckperms.sqlite")));
+ return new SQLLegacyBacking(plugin, new SQLiteProvider(new File(plugin.getDataFolder(), "luckperms.sqlite")));
case H2:
- return new SQLBacking(plugin, new H2Provider(new File(plugin.getDataFolder(), "luckperms.db")));
+ return new SQLLegacyBacking(plugin, new H2Provider(new File(plugin.getDataFolder(), "luckperms.db")));
case MONGODB:
return new MongoDBBacking(plugin, plugin.getConfiguration().getDatabaseValues());
case YAML:
diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/StorageType.java b/common/src/main/java/me/lucko/luckperms/common/storage/StorageType.java
index 7249d068..4ca8b083 100644
--- a/common/src/main/java/me/lucko/luckperms/common/storage/StorageType.java
+++ b/common/src/main/java/me/lucko/luckperms/common/storage/StorageType.java
@@ -34,6 +34,7 @@ public enum StorageType {
YAML("yaml", "yml"),
MONGODB("mongodb"),
MYSQL("mysql"),
+ POSTGRESQL("postgresql"),
SQLITE("sqlite"),
H2("h2");
diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java
index 8eaf7007..066caa3a 100644
--- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java
+++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java
@@ -22,106 +22,76 @@
package me.lucko.luckperms.common.storage.backing;
-import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import me.lucko.luckperms.api.LogEntry;
+import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.LuckPermsPlugin;
import me.lucko.luckperms.common.core.UserIdentifier;
import me.lucko.luckperms.common.core.model.Group;
import me.lucko.luckperms.common.core.model.Track;
import me.lucko.luckperms.common.core.model.User;
import me.lucko.luckperms.common.data.Log;
-import me.lucko.luckperms.common.managers.GroupManager;
import me.lucko.luckperms.common.managers.TrackManager;
import me.lucko.luckperms.common.managers.impl.GenericUserManager;
-import me.lucko.luckperms.common.storage.backing.sqlprovider.H2Provider;
-import me.lucko.luckperms.common.storage.backing.sqlprovider.MySQLProvider;
import me.lucko.luckperms.common.storage.backing.sqlprovider.SQLProvider;
-import me.lucko.luckperms.common.storage.backing.sqlprovider.SQLiteProvider;
+import me.lucko.luckperms.common.storage.backing.utils.NodeDataHolder;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.UUID;
-
-import static me.lucko.luckperms.common.core.model.PermissionHolder.exportToLegacy;
-import static me.lucko.luckperms.common.storage.backing.sqlprovider.SQLProvider.QueryPS;
-import static me.lucko.luckperms.common.storage.backing.sqlprovider.SQLProvider.QueryRS;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
+import java.util.stream.Collectors;
public class SQLBacking extends AbstractBacking {
- private static final Type NM_TYPE = new TypeToken