package com.nicewuerfel.blockown.database;
import com.nicewuerfel.blockown.Ownable;
import com.nicewuerfel.blockown.OwnedBlock;
import com.nicewuerfel.blockown.OwnedEntity;
import com.nicewuerfel.blockown.User;
import com.nicewuerfel.blockown.output.Output;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class SqliteDatabase extends CachedDatabase {
private static final String FILENAME = "world.db";
private static final String CREATE_BLOCK_TABLE_QUERY = String.format(
"CREATE TABLE IF NOT EXISTS %1$s (%2$s VARCHAR(50), %3$s INT, %4$s INT, %5$s INT, %6$s CHAR(36) NOT NULL, PRIMARY KEY (%2$s, %3$s, %4$s, %5$s));",
Database.BLOCK_TABLE, Database.WORLD_COLUMN, Database.X_COLUMN, Database.Y_COLUMN,
Database.Z_COLUMN, Database.PLAYER_ID_COLUMN);
private static final String CREATE_ENTITY_TABLE_QUERY = String.format(
"CREATE TABLE IF NOT EXISTS %1$s (%2$s VARCHAR(50) NOT NULL, %3$s CHAR(36), %4$s CHAR(36) NOT NULL, PRIMARY KEY (%3$s));",
Database.ENTITY_TABLE, Database.WORLD_COLUMN, Database.ENTITY_ID_COLUMN,
Database.PLAYER_ID_COLUMN);
private static final String GET_BLOCK_OWNER_QUERY =
String.format("SELECT %1$s FROM %2$s WHERE %3$s=? AND %4$s=? AND %5$s=? AND %6$s=?;",
Database.PLAYER_ID_COLUMN, Database.BLOCK_TABLE, Database.WORLD_COLUMN, Database.X_COLUMN,
Database.Y_COLUMN, Database.Z_COLUMN);
private static final String GET_ENTITY_OWNER_QUERY =
String.format("SELECT %1$s FROM %2$s WHERE %3$s=? AND %4$s=?;", Database.PLAYER_ID_COLUMN,
Database.ENTITY_TABLE, Database.WORLD_COLUMN, Database.ENTITY_ID_COLUMN);
private static final String UNOWN_BLOCK_QUERY = String.format(
"DELETE FROM %1$s WHERE %2$s=? AND %3$s=? AND %4$s=? AND %5$s=?;", Database.BLOCK_TABLE,
Database.WORLD_COLUMN, Database.X_COLUMN, Database.Y_COLUMN, Database.Z_COLUMN);
private static final String UNOWN_ENTITY_QUERY =
String.format("DELETE FROM %1$s WHERE %2$s=? AND %3$s=?;", Database.ENTITY_TABLE,
Database.WORLD_COLUMN, Database.ENTITY_ID_COLUMN);
private static final String OWN_BLOCK_QUERY = String.format(
"INSERT OR REPLACE INTO %1$s(%2$s, %3$s, %4$s, %5$s, %6$s) VALUES(?, ?, ?, ?, ?);",
Database.BLOCK_TABLE, Database.WORLD_COLUMN, Database.X_COLUMN, Database.Y_COLUMN,
Database.Z_COLUMN, Database.PLAYER_ID_COLUMN);
private static final String OWN_ENTITY_QUERY = String.format(
"INSERT OR REPLACE INTO %1$s(%2$s, %3$s, %4$s) VALUES(?, ?, ?);", Database.ENTITY_TABLE,
Database.WORLD_COLUMN, Database.ENTITY_ID_COLUMN, Database.PLAYER_ID_COLUMN);
private static final String DROP_USER_BLOCK_QUERY = String
.format("DELETE FROM %1$s WHERE %2$s=?;", Database.BLOCK_TABLE, Database.PLAYER_ID_COLUMN);
private static final String DROP_USER_ENTITY_QUERY = String
.format("DELETE FROM %1$s WHERE %2$s=?;", Database.ENTITY_TABLE, Database.PLAYER_ID_COLUMN);
private final File pluginDataFolder;
public SqliteDatabase(Output output, File pluginFolder)
throws SQLException, ClassNotFoundException {
super(output, pluginFolder);
this.pluginDataFolder = pluginFolder.getAbsoluteFile();
HikariConfig config = new HikariConfig();
config.setDataSourceClassName("org.sqlite.SQLiteDataSource");
File file = new File(pluginDataFolder, FILENAME);
config.addDataSourceProperty("url", "jdbc:sqlite:" + file.getPath());
// Since Spigot/CraftBukkit use a very old version of the SQLite JDBC, JDBC4 operations like
// Connection.isValid() are not supported
config.setConnectionTestQuery("SELECT 1;");
config.setMaximumPoolSize(1);
// Possible fix for ClassLoader error
try {
Plugin plugin = Bukkit.getPluginManager().getPlugin("BlockOwn");
plugin.getPluginLoader().getClass().getClassLoader().loadClass("org.sqlite.SQLiteDataSource");
} catch (NullPointerException ignored) {
// Should only happen while testing
}
connectionPool = new HikariDataSource(config);
createTables();
}
@Override
PreparedStatement[] createCreateTablesStatements() throws SQLException {
Connection connection = getConnection();
PreparedStatement[] stmnts = {connection.prepareStatement(CREATE_BLOCK_TABLE_QUERY),
connection.prepareStatement(CREATE_ENTITY_TABLE_QUERY)};
return stmnts;
}
@Override
PreparedStatement createGetOwnerStatement(Ownable ownable) throws SQLException {
PreparedStatement stmnt;
if (ownable instanceof OwnedBlock) {
OwnedBlock block = (OwnedBlock) ownable;
stmnt = getConnection().prepareStatement(GET_BLOCK_OWNER_QUERY);
stmnt.setString(1, block.getWorldName());
stmnt.setInt(2, block.getX());
stmnt.setInt(3, block.getY());
stmnt.setInt(4, block.getZ());
} else if (ownable instanceof OwnedEntity) {
OwnedEntity entity = (OwnedEntity) ownable;
stmnt = getConnection().prepareStatement(GET_ENTITY_OWNER_QUERY);
stmnt.setString(1, entity.getWorldName());
stmnt.setString(2, entity.getUniqueId().toString());
} else {
throw new IllegalArgumentException("Invalid Ownable type");
}
return stmnt;
}
@Override
PreparedStatement createSetOwnerStatement(DatabaseAction databaseAction) throws SQLException {
PreparedStatement stmnt;
if (databaseAction.getActionType() == DatabaseAction.Type.UNOWN) {
if (databaseAction.getOwnable() instanceof OwnedBlock) {
OwnedBlock block = (OwnedBlock) databaseAction.getOwnable();
stmnt = getConnection().prepareStatement(UNOWN_BLOCK_QUERY);
stmnt.setString(1, block.getWorldName());
stmnt.setInt(2, block.getX());
stmnt.setInt(3, block.getY());
stmnt.setInt(4, block.getZ());
} else if (databaseAction.getOwnable() instanceof OwnedEntity) {
OwnedEntity entity = (OwnedEntity) databaseAction.getOwnable();
stmnt = getConnection().prepareStatement(UNOWN_ENTITY_QUERY);
stmnt.setString(1, entity.getWorldName());
stmnt.setString(2, entity.getUniqueId().toString());
} else {
throw new IllegalArgumentException("Invalid Ownable type");
}
} else if (databaseAction.getActionType() == DatabaseAction.Type.OWN) {
if (databaseAction.getOwnable() instanceof OwnedBlock) {
OwnedBlock block = (OwnedBlock) databaseAction.getOwnable();
stmnt = getConnection().prepareStatement(OWN_BLOCK_QUERY);
stmnt.setString(1, block.getWorldName());
stmnt.setInt(2, block.getX());
stmnt.setInt(3, block.getY());
stmnt.setInt(4, block.getZ());
stmnt.setString(5, databaseAction.getUser().getUniqueId().toString());
} else if (databaseAction.getOwnable() instanceof OwnedEntity) {
OwnedEntity entity = (OwnedEntity) databaseAction.getOwnable();
stmnt = getConnection().prepareStatement(OWN_ENTITY_QUERY);
stmnt.setString(1, entity.getWorldName());
stmnt.setString(2, entity.getUniqueId().toString());
stmnt.setString(3, databaseAction.getUser().getUniqueId().toString());
} else {
throw new IllegalArgumentException("Invalid Ownable type");
}
} else {
// Should never happen
getOutput().printException(new IllegalArgumentException("Invalid DatabaseActionType"));
return null;
}
return stmnt;
}
@Override
PreparedStatement[] createDropUserStatements(User user) throws SQLException {
Connection connection = getConnection();
PreparedStatement stmnt1 = connection.prepareStatement(DROP_USER_BLOCK_QUERY);
stmnt1.setString(1, user.getUniqueId().toString());
PreparedStatement stmnt2 = connection.prepareStatement(DROP_USER_ENTITY_QUERY);
stmnt2.setString(1, user.getUniqueId().toString());
return new PreparedStatement[]{stmnt1, stmnt2};
}
}