Postgres implementation (#1142)

* WIP for https://github.com/BentoBoxWorld/BentoBox/issues/1093

* JSON based PostGresql

* Completes PostgreSQL suport

* Changed Postgres connector comments

* Put back rest of Postgres jdbc URL

* Update PostgreSQLDatabaseHandler.java
This commit is contained in:
tastybento 2020-01-23 07:56:30 -08:00 committed by GitHub
parent ac850907cc
commit 5ab5954f47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 79 additions and 11 deletions

View File

@ -221,6 +221,11 @@
<artifactId>mongodb-driver</artifactId>
<version>${mongodb.version}</version>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901-1.jdbc4</version>
</dependency>
<!-- Vault: as their maven repo is down, we need to get it from jitpack -->
<!-- See https://github.com/MilkBowl/VaultAPI/issues/69 -->
<dependency>
@ -339,13 +344,13 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<configuration>
<source>8</source>
<show>private</show>
<failOnError>false</failOnError>
<additionalJOption>-Xdoclint:none</additionalJOption>
<!-- To compile with Java 11, this tag may be required -->
<!-- <javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>-->
<!-- <javadocExecutable>${java.home}/bin/javadoc</javadocExecutable> -->
</configuration>
<executions>
<execution>

View File

@ -51,17 +51,18 @@ public class Settings implements ConfigObject {
private boolean useEconomy = true;
// Database
@ConfigComment("JSON, MYSQL, MARIADB, MONGODB, SQLITE and YAML(deprecated).")
@ConfigComment("JSON, MYSQL, MARIADB, MONGODB, SQLITE, POSTGRESQL and YAML(deprecated).")
@ConfigComment("Transition database options are:")
@ConfigComment(" YAML2JSON, YAML2MARIADB, YAML2MYSQL, YAML2MONGODB, YAML2SQLITE")
@ConfigComment(" JSON2MARIADB, JSON2MYSQL, JSON2MONGODB, JSON2SQLITE,")
@ConfigComment(" MYSQL2JSON, MARIADB2JSON, MONGODB2JSON, SQLITE2JSON")
@ConfigComment(" JSON2MARIADB, JSON2MYSQL, JSON2MONGODB, JSON2SQLITE, JSON2POSTGRESQL")
@ConfigComment(" MYSQL2JSON, MARIADB2JSON, MONGODB2JSON, SQLITE2JSON, POSTGRES2JSON")
@ConfigComment("If you need others, please make a feature request.")
@ConfigComment("Minimum required versions:")
@ConfigComment(" MySQL versions 5.7 or later")
@ConfigComment(" MariaDB versions 10.2.3 or later")
@ConfigComment(" MongoDB versions 3.6 or later")
@ConfigComment(" SQLite versions 3.28 or later")
@ConfigComment(" PostgreSQL versions 9.4 or later")
@ConfigComment("Transition options enable migration from one database type to another. Use /bbox migrate.")
@ConfigComment("YAML and JSON are file-based databases.")
@ConfigComment("MYSQL might not work with all implementations: if available, use a dedicated database type (e.g. MARIADB).")

View File

@ -1,6 +1,7 @@
package world.bentobox.bentobox.database.sql.postgresql;
import org.eclipse.jdt.annotation.NonNull;
import org.postgresql.Driver;
import world.bentobox.bentobox.database.DatabaseConnectionSettingsImpl;
import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
@ -11,6 +12,17 @@ import world.bentobox.bentobox.database.sql.SQLDatabaseConnector;
*/
public class PostgreSQLDatabaseConnector extends SQLDatabaseConnector {
/*
* Ensure the driver is loaded as JDBC Driver might be invisible to Java's ServiceLoader.
* Usually, this is not required as {@link DriverManager} detects JDBC drivers
* via {@code META-INF/services/java.sql.Driver} entries. However there might be cases when the driver
* is located at the application level classloader, thus it might be required to perform manual
* registration of the driver.
*/
static {
new Driver();
}
/**
* Class for PostgreSQL database connections using the settings provided
* @param dbSettings - database settings

View File

@ -1,7 +1,13 @@
package world.bentobox.bentobox.database.sql.postgresql;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.google.gson.Gson;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.database.DatabaseConnector;
import world.bentobox.bentobox.database.objects.DataObject;
import world.bentobox.bentobox.database.sql.SQLConfiguration;
import world.bentobox.bentobox.database.sql.SQLDatabaseHandler;
@ -9,8 +15,8 @@ import world.bentobox.bentobox.database.sql.SQLDatabaseHandler;
*
* @param <T>
*
* @since 1.6.0
* @author tastybento, Poslovitch
* @since 1.11.0
* @author tastybento
*/
public class PostgreSQLDatabaseHandler<T> extends SQLDatabaseHandler<T> {
@ -23,7 +29,50 @@ public class PostgreSQLDatabaseHandler<T> extends SQLDatabaseHandler<T> {
* @param databaseConnector Contains the settings to create a connection to the database
*/
PostgreSQLDatabaseHandler(BentoBox plugin, Class<T> type, DatabaseConnector databaseConnector) {
super(plugin, type, databaseConnector, new SQLConfiguration(type.getCanonicalName()));
super(plugin, type, databaseConnector, new SQLConfiguration(type.getCanonicalName())
// Set uniqueid as the primary key (index). Postgresql convention is to use lower case field names
// Postgresql also uses double quotes (") instead of (`) around tables names with dots.
.schema("CREATE TABLE IF NOT EXISTS \"" + type.getCanonicalName() + "\" (uniqueid VARCHAR PRIMARY KEY, json jsonb NOT NULL)")
.loadObject("SELECT * FROM \"" + type.getCanonicalName() + "\" WHERE uniqueid = ? LIMIT 1")
.deleteObject("DELETE FROM \"" + type.getCanonicalName() + "\" WHERE uniqueid = ?")
// uniqueId has to be added into the row explicitly so we need to override the saveObject method
// The json value is a string but has to be cast to json when done in Java
.saveObject("INSERT INTO \"" + type.getCanonicalName() + "\" (uniqueid, json) VALUES (?, cast(? as json)) "
// This is the Postgresql version of UPSERT.
+ "ON CONFLICT (uniqueid) "
+ "DO UPDATE SET json = cast(? as json)")
.loadObjects("SELECT json FROM \"" + type.getCanonicalName() + "\"")
// Postgres exists function returns true or false natively
.objectExists("SELECT EXISTS(SELECT * FROM \"" + type.getCanonicalName() + "\" WHERE uniqueid = ?)")
);
}
/* (non-Javadoc)
* @see world.bentobox.bentobox.database.sql.SQLDatabaseHandler#saveObject(java.lang.Object)
*/
@Override
public void saveObject(T instance) {
// Null check
if (instance == null) {
plugin.logError("Postgres database request to store a null. ");
return;
}
if (!(instance instanceof DataObject)) {
plugin.logError("This class is not a DataObject: " + instance.getClass().getName());
return;
}
Gson gson = getGson();
String toStore = gson.toJson(instance);
String uniqueId = ((DataObject)instance).getUniqueId();
processQueue.add(() -> {
try (PreparedStatement preparedStatement = getConnection().prepareStatement(getSqlConfig().getSaveObjectSQL())) {
preparedStatement.setString(1, uniqueId); // INSERT
preparedStatement.setString(2, toStore); // INSERT
preparedStatement.setString(3, toStore); // ON CONFLICT
preparedStatement.execute();
} catch (SQLException e) {
plugin.logError("Could not save object " + instance.getClass().getName() + " " + e.getMessage());
}
});
}
}

View File

@ -29,17 +29,18 @@ general:
# If there is no economy plugin present anyway, money will be automatically disabled.
use-economy: true
database:
# JSON, MYSQL, MARIADB, MONGODB, SQLITE and YAML(deprecated).
# JSON, MYSQL, MARIADB, MONGODB, SQLITE, POSTGRESQL and YAML(deprecated).
# Transition database options are:
# YAML2JSON, YAML2MARIADB, YAML2MYSQL, YAML2MONGODB, YAML2SQLITE
# JSON2MARIADB, JSON2MYSQL, JSON2MONGODB, JSON2SQLITE,
# MYSQL2JSON, MARIADB2JSON, MONGODB2JSON, SQLITE2JSON
# JSON2MARIADB, JSON2MYSQL, JSON2MONGODB, JSON2SQLITE, JSON2POSTGRESQL
# MYSQL2JSON, MARIADB2JSON, MONGODB2JSON, SQLITE2JSON, POSTGRESQL2JSON
# If you need others, please make a feature request.
# Minimum required versions:
# MySQL versions 5.7 or later
# MariaDB versions 10.2.3 or later
# MongoDB versions 3.6 or later
# SQLite versions 3.28 or later
# PostgreSQL versions 9.4 or later
# Transition options enable migration from one database type to another. Use /bbox migrate.
# YAML and JSON are file-based databases.
# MYSQL might not work with all implementations: if available, use a dedicated database type (e.g. MARIADB).