From bbdebbffa663fc4bf71b2fb55f27a3311b3bbbb6 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Sun, 16 Jan 2022 13:38:06 -0600 Subject: [PATCH] Update DB schemas for bigger blobs - make MySQL/MariaDB more common --- .../storage/mariadb/MariaDBMapStorage.java | 1078 +---------------- .../dynmap/storage/mysql/MySQLMapStorage.java | 65 +- .../postgresql/PostgreSQLMapStorage.java | 9 +- .../storage/sqllte/SQLiteMapStorage.java | 4 +- 4 files changed, 60 insertions(+), 1096 deletions(-) diff --git a/DynmapCore/src/main/java/org/dynmap/storage/mariadb/MariaDBMapStorage.java b/DynmapCore/src/main/java/org/dynmap/storage/mariadb/MariaDBMapStorage.java index d17d13e5..7da7a0b8 100644 --- a/DynmapCore/src/main/java/org/dynmap/storage/mariadb/MariaDBMapStorage.java +++ b/DynmapCore/src/main/java/org/dynmap/storage/mariadb/MariaDBMapStorage.java @@ -1,1092 +1,24 @@ package org.dynmap.storage.mariadb; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.charset.Charset; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; - -import org.dynmap.DynmapCore; -import org.dynmap.DynmapWorld; import org.dynmap.Log; -import org.dynmap.MapType; -import org.dynmap.WebAuthManager; -import org.dynmap.MapType.ImageVariant; -import org.dynmap.PlayerFaces.FaceType; -import org.dynmap.storage.MapStorage; -import org.dynmap.storage.MapStorageTile; -import org.dynmap.storage.MapStorageTileEnumCB; -import org.dynmap.storage.MapStorageBaseTileEnumCB; -import org.dynmap.storage.MapStorageTileSearchEndCB; -import org.dynmap.utils.BufferInputStream; -import org.dynmap.utils.BufferOutputStream; +import org.dynmap.storage.mysql.MySQLMapStorage; -public class MariaDBMapStorage extends MapStorage { - private String connectionString; - private String userid; - private String password; - private String database; - private String hostname; - private String prefix = ""; - private String tableTiles; - private String tableMaps; - private String tableFaces; - private String tableMarkerIcons; - private String tableMarkerFiles; - private String tableStandaloneFiles; - private String tableSchemaVersion; +public class MariaDBMapStorage extends MySQLMapStorage { - private int port; - private static final int POOLSIZE = 5; - private Connection[] cpool = new Connection[POOLSIZE]; - private int cpoolCount = 0; - private static final Charset UTF8 = Charset.forName("UTF-8"); - - public class StorageTile extends MapStorageTile { - private Integer mapkey; - private String uri; - protected StorageTile(DynmapWorld world, MapType map, int x, int y, - int zoom, ImageVariant var) { - super(world, map, x, y, zoom, var); - - mapkey = getMapKey(world, map, var); - - if (zoom > 0) { - uri = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + "zzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y + "." + map.getImageFormat().getFileExt(); - } - else { - uri = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + x + "_" + y + "." + map.getImageFormat().getFileExt(); - } - } - - @Override - public boolean exists() { - if (mapkey == null) return false; - boolean rslt = false; - Connection c = null; - boolean err = false; - try { - c = getConnection(); - Statement stmt = c.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT HashCode FROM " + tableTiles + " WHERE MapID=" + mapkey + " AND x=" + x + " AND y=" + y + " AND zoom=" + zoom + ";"); - rslt = rs.next(); - rs.close(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Tile exists error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - return rslt; - } - - @Override - public boolean matchesHashCode(long hash) { - if (mapkey == null) return false; - boolean rslt = false; - Connection c = null; - boolean err = false; - try { - c = getConnection(); - Statement stmt = c.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT HashCode FROM " + tableTiles + " WHERE MapID=" + mapkey + " AND x=" + x + " AND y=" + y + " AND zoom=" + zoom + ";"); - if (rs.next()) { - long v = rs.getLong("HashCode"); - rslt = (v == hash); - } - rs.close(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Tile matches hash error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - return rslt; - } - - @Override - public TileRead read() { - if (mapkey == null) return null; - TileRead rslt = null; - Connection c = null; - boolean err = false; - try { - c = getConnection(); - Statement stmt = c.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT HashCode,LastUpdate,Format,Image FROM " + tableTiles + " WHERE MapID=" + mapkey + " AND x=" + x + " AND y=" + y + " AND zoom=" + zoom + ";"); - if (rs.next()) { - rslt = new TileRead(); - rslt.hashCode = rs.getLong("HashCode"); - rslt.lastModified = rs.getLong("LastUpdate"); - rslt.format = MapType.ImageEncoding.fromOrd(rs.getInt("Format")); - byte[] img = rs.getBytes("Image"); - rslt.image = new BufferInputStream(img); - } - rs.close(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Tile read error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - return rslt; - } - - @Override - public boolean write(long hash, BufferOutputStream encImage, long timestamp) { - if (mapkey == null) return false; - Connection c = null; - boolean err = false; - boolean exists = exists(); - // If delete, and doesn't exist, quit - if ((encImage == null) && (!exists)) return false; - - try { - c = getConnection(); - PreparedStatement stmt; - if (encImage == null) { // If delete - stmt = c.prepareStatement("DELETE FROM " + tableTiles + " WHERE MapID=? AND x=? and y=? AND zoom=?;"); - stmt.setInt(1, mapkey); - stmt.setInt(2, x); - stmt.setInt(3, y); - stmt.setInt(4, zoom); - } - else if (exists) { - stmt = c.prepareStatement("UPDATE " + tableTiles + " SET HashCode=?, LastUpdate=?, Format=?, Image=? WHERE MapID=? AND x=? and y=? AND zoom=?;"); - stmt.setLong(1, hash); - stmt.setLong(2, timestamp); - stmt.setInt(3, map.getImageFormat().getEncoding().ordinal()); - stmt.setBinaryStream(4, new BufferInputStream(encImage.buf, encImage.len), encImage.len); - stmt.setInt(5, mapkey); - stmt.setInt(6, x); - stmt.setInt(7, y); - stmt.setInt(8, zoom); - } - else { - stmt = c.prepareStatement("INSERT INTO " + tableTiles + " (MapID,x,y,zoom,HashCode,LastUpdate,Format,Image) VALUES (?,?,?,?,?,?,?,?);"); - stmt.setInt(1, mapkey); - stmt.setInt(2, x); - stmt.setInt(3, y); - stmt.setInt(4, zoom); - stmt.setLong(5, hash); - stmt.setLong(6, timestamp); - stmt.setInt(7, map.getImageFormat().getEncoding().ordinal()); - stmt.setBinaryStream(8, new BufferInputStream(encImage.buf, encImage.len), encImage.len); - } - stmt.executeUpdate(); - stmt.close(); - // Signal update for zoom out - if (zoom == 0) { - world.enqueueZoomOutUpdate(this); - } - } catch (SQLException x) { - Log.severe("Tile write error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - return !err; - } - - @Override - public boolean getWriteLock() { - return MariaDBMapStorage.this.getWriteLock(uri); - } - - @Override - public void releaseWriteLock() { - MariaDBMapStorage.this.releaseWriteLock(uri); - } - - @Override - public boolean getReadLock(long timeout) { - return MariaDBMapStorage.this.getReadLock(uri, timeout); - } - - @Override - public void releaseReadLock() { - MariaDBMapStorage.this.releaseReadLock(uri); - } - - @Override - public void cleanup() { - } - - @Override - public String getURI() { - return uri; - } - - @Override - public void enqueueZoomOutUpdate() { - world.enqueueZoomOutUpdate(this); - } - - @Override - public MapStorageTile getZoomOutTile() { - int xx, yy; - int step = 1 << zoom; - if(x >= 0) - xx = x - (x % (2*step)); - else - xx = x + (x % (2*step)); - yy = -y; - if(yy >= 0) - yy = yy - (yy % (2*step)); - else - yy = yy + (yy % (2*step)); - yy = -yy; - return new StorageTile(world, map, xx, yy, zoom+1, var); - } - - @Override - public boolean equals(Object o) { - if (o instanceof StorageTile) { - StorageTile st = (StorageTile) o; - return uri.equals(st.uri); - } - return false; - } - - @Override - public int hashCode() { - return uri.hashCode(); - } - } - public MariaDBMapStorage() { } + // MariaDB specific driver check @Override - public boolean init(DynmapCore core) { - if (!super.init(core)) { - return false; - } - database = core.configuration.getString("storage/database", "dynmap"); - hostname = core.configuration.getString("storage/hostname", "localhost"); - port = core.configuration.getInteger("storage/port", 3306); - userid = core.configuration.getString("storage/userid", "dynmap"); - password = core.configuration.getString("storage/password", "dynmap"); - prefix = core.configuration.getString("storage/prefix", ""); - tableTiles = prefix + "Tiles"; - tableMaps = prefix + "Maps"; - tableFaces = prefix + "Faces"; - tableMarkerIcons = prefix + "MarkerIcons"; - tableMarkerFiles = prefix + "MarkerFiles"; - tableStandaloneFiles = prefix + "StandaloneFiles"; - tableSchemaVersion = prefix + "SchemaVersion"; - - connectionString = "jdbc:mariadb://" + hostname + ":" + port + "/" + database + "?allowReconnect=true&autoReconnect=true"; + protected boolean checkDriver() { + connectionString = "jdbc:mariadb://" + hostname + ":" + port + "/" + database + flags; Log.info("Opening MariaDB database " + hostname + ":" + port + "/" + database + " as map store"); try { Class.forName("org.mariadb.jdbc.Driver"); - // Initialize/update tables, if needed - if(!initializeTables()) { - return false; - } } catch (ClassNotFoundException cnfx) { Log.severe("MariaDB-JDBC classes not found - MariaDB data source not usable"); return false; } - return writeConfigPHP(core); - } - - private boolean writeConfigPHP(DynmapCore core) { - File cfgfile = new File(baseStandaloneDir, "MySQL_config.php"); - if (!core.isInternalWebServerDisabled) { // If using internal server - cfgfile.delete(); // Zap file (in case we left junk from last time) - return true; - } - FileWriter fw = null; - try { - fw = new FileWriter(cfgfile); - fw.write("\n"); - } catch (IOException iox) { - Log.severe("Error writing MySQL_config.php", iox); - return false; - } finally { - if (fw != null) { - try { fw.close(); } catch (IOException x) {} - } - } return true; } - private int getSchemaVersion() { - int ver = 0; - boolean err = false; - Connection c = null; - try { - c = getConnection(); // Get connection (create DB if needed) - Statement stmt = c.createStatement(); - ResultSet rs = stmt.executeQuery( "SELECT level FROM " + tableSchemaVersion + ";"); - if (rs.next()) { - ver = rs.getInt("level"); - } - rs.close(); - stmt.close(); - } catch (SQLException x) { - err = true; - } finally { - if (c != null) { releaseConnection(c, err); } - } - return ver; - } - - private void doUpdate(Connection c, String sql) throws SQLException { - Statement stmt = c.createStatement(); - stmt.executeUpdate(sql); - stmt.close(); - } - - private HashMap mapKey = new HashMap(); - - private void doLoadMaps() { - Connection c = null; - boolean err = false; - - mapKey.clear(); - // Read the maps table - cache results - try { - c = getConnection(); - Statement stmt = c.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT * from " + tableMaps + ";"); - while (rs.next()) { - int key = rs.getInt("ID"); - String worldID = rs.getString("WorldID"); - String mapID = rs.getString("MapID"); - String variant = rs.getString("Variant"); - long serverid = rs.getLong("ServerID"); - if (serverid == serverID) { // One of ours - mapKey.put(worldID + ":" + mapID + ":" + variant, key); - } - } - rs.close(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Error loading map table - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - c = null; - } - } - - private Integer getMapKey(DynmapWorld w, MapType mt, ImageVariant var) { - String id = w.getName() + ":" + mt.getPrefix() + ":" + var.toString(); - synchronized(mapKey) { - Integer k = mapKey.get(id); - if (k == null) { // No hit: new value so we need to add it to table - Connection c = null; - boolean err = false; - try { - c = getConnection(); - // Insert row - PreparedStatement stmt = c.prepareStatement("INSERT INTO " + tableMaps + " (WorldID,MapID,Variant,ServerID) VALUES (?, ?, ?, ?);"); - stmt.setString(1, w.getName()); - stmt.setString(2, mt.getPrefix()); - stmt.setString(3, var.toString()); - stmt.setLong(4, serverID); - stmt.executeUpdate(); - stmt.close(); - // Query key assigned - stmt = c.prepareStatement("SELECT ID FROM " + tableMaps + " WHERE WorldID = ? AND MapID = ? AND Variant = ? AND ServerID = ?;"); - stmt.setString(1, w.getName()); - stmt.setString(2, mt.getPrefix()); - stmt.setString(3, var.toString()); - stmt.setLong(4, serverID); - ResultSet rs = stmt.executeQuery(); - if (rs.next()) { - k = rs.getInt("ID"); - mapKey.put(id, k); - } - rs.close(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Error updating Maps table - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - } - - return k; - } - } - - private boolean initializeTables() { - Connection c = null; - boolean err = false; - int version = getSchemaVersion(); // Get the existing schema version for the DB (if any) - // If new, add our tables - if (version == 0) { - try { - c = getConnection(); - doUpdate(c, "CREATE TABLE " + tableMaps + " (ID INTEGER PRIMARY KEY AUTO_INCREMENT, WorldID VARCHAR(64) NOT NULL, MapID VARCHAR(64) NOT NULL, Variant VARCHAR(16) NOT NULL, ServerID BIGINT NOT NULL DEFAULT 0)"); - doUpdate(c, "CREATE TABLE " + tableTiles + " (MapID INT NOT NULL, x INT NOT NULL, y INT NOT NULL, zoom INT NOT NULL, HashCode BIGINT NOT NULL, LastUpdate BIGINT NOT NULL, Format INT NOT NULL, Image BLOB, PRIMARY KEY(MapID, x, y, zoom))"); - doUpdate(c, "CREATE TABLE " + tableFaces + " (PlayerName VARCHAR(64) NOT NULL, TypeID INT NOT NULL, Image BLOB, PRIMARY KEY(PlayerName, TypeID))"); - doUpdate(c, "CREATE TABLE " + tableMarkerIcons + " (IconName VARCHAR(128) PRIMARY KEY NOT NULL, Image BLOB)"); - doUpdate(c, "CREATE TABLE " + tableMarkerFiles + " (FileName VARCHAR(128) PRIMARY KEY NOT NULL, Content MEDIUMTEXT)"); - doUpdate(c, "CREATE TABLE " + tableStandaloneFiles + " (FileName VARCHAR(128) NOT NULL, ServerID BIGINT NOT NULL DEFAULT 0, Content MEDIUMTEXT, PRIMARY KEY (FileName, ServerID))"); - doUpdate(c, "CREATE TABLE " + tableSchemaVersion + " (level INT PRIMARY KEY NOT NULL)"); - doUpdate(c, "INSERT INTO " + tableSchemaVersion + " (level) VALUES (3)"); - } catch (SQLException x) { - Log.severe("Error creating tables - " + x.getMessage()); - err = true; - return false; - } finally { - releaseConnection(c, err); - c = null; - } - } - else if (version == 1) { - try { - c = getConnection(); - doUpdate(c, "CREATE TABLE " + tableStandaloneFiles + " (FileName VARCHAR(128) NOT NULL, ServerID BIGINT NOT NULL DEFAULT 0, Content MEDIUMTEXT, PRIMARY KEY (FileName, ServerID))"); - doUpdate(c, "ALTER TABLE " + tableMaps + " ADD COLUMN ServerID BIGINT NOT NULL DEFAULT 0 AFTER Variant"); - doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=3 WHERE level = 1;"); - } catch (SQLException x) { - Log.severe("Error creating tables - " + x.getMessage()); - err = true; - return false; - } finally { - releaseConnection(c, err); - c = null; - } - } - else if (version == 2) { - try { - c = getConnection(); - doUpdate(c, "DELETE FROM " + tableStandaloneFiles + ";"); - doUpdate(c, "ALTER TABLE " + tableStandaloneFiles + " DROP COLUMN Content;"); - doUpdate(c, "ALTER TABLE " + tableStandaloneFiles + " ADD COLUMN Content MEDIUMTEXT;"); - doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=3 WHERE level = 2;"); - } catch (SQLException x) { - Log.severe("Error creating tables - " + x.getMessage()); - err = true; - return false; - } finally { - releaseConnection(c, err); - c = null; - } - } - // Load maps table - cache results - doLoadMaps(); - - return true; - } - - private Connection getConnection() throws SQLException { - Connection c = null; - synchronized (cpool) { - while (c == null) { - for (int i = 0; i < cpool.length; i++) { // See if available connection - if (cpool[i] != null) { // Found one - c = cpool[i]; - cpool[i] = null; - break; - } - } - if (c == null) { - if (cpoolCount < POOLSIZE) { // Still more we can have - c = DriverManager.getConnection(connectionString, userid, password); - configureConnection(c); - cpoolCount++; - } - else { - try { - cpool.wait(); - } catch (InterruptedException e) { - throw new SQLException("Interruped"); - } - } - } - } - } - return c; - } - - private static Connection configureConnection(Connection conn) throws SQLException { - return conn; - } - - private void releaseConnection(Connection c, boolean err) { - if (c == null) return; - synchronized (cpool) { - if (!err) { // Find slot to keep it in pool - for (int i = 0; i < POOLSIZE; i++) { - if (cpool[i] == null) { - cpool[i] = c; - c = null; // Mark it recovered (no close needed - cpool.notifyAll(); - break; - } - } - } - if (c != null) { // If broken, just toss it - try { c.close(); } catch (SQLException x) {} - cpoolCount--; // And reduce count - cpool.notifyAll(); - } - } - } - - @Override - public MapStorageTile getTile(DynmapWorld world, MapType map, int x, int y, - int zoom, ImageVariant var) { - return new StorageTile(world, map, x, y, zoom, var); - } - - @Override - public MapStorageTile getTile(DynmapWorld world, String uri) { - String[] suri = uri.split("/"); - if (suri.length < 2) return null; - String mname = suri[0]; // Map URI - might include variant - MapType mt = null; - ImageVariant imgvar = null; - // Find matching map type and image variant - for (int mti = 0; (mt == null) && (mti < world.maps.size()); mti++) { - MapType type = world.maps.get(mti); - ImageVariant[] var = type.getVariants(); - for (int ivi = 0; (imgvar == null) && (ivi < var.length); ivi++) { - if (mname.equals(type.getPrefix() + var[ivi].variantSuffix)) { - mt = type; - imgvar = var[ivi]; - } - } - } - if (mt == null) { // Not found? - return null; - } - // Now, take the last section and parse out coordinates and zoom - String fname = suri[suri.length-1]; - String[] coord = fname.split("[_\\.]"); - if (coord.length < 3) { // 3 or 4 - return null; - } - int zoom = 0; - int x, y; - try { - if (coord[0].charAt(0) == 'z') { - zoom = coord[0].length(); - x = Integer.parseInt(coord[1]); - y = Integer.parseInt(coord[2]); - } - else { - x = Integer.parseInt(coord[0]); - y = Integer.parseInt(coord[1]); - } - return getTile(world, mt, x, y, zoom, imgvar); - } catch (NumberFormatException nfx) { - return null; - } - } - - @Override - public void enumMapTiles(DynmapWorld world, MapType map, - MapStorageTileEnumCB cb) { - List mtlist; - - if (map != null) { - mtlist = Collections.singletonList(map); - } - else { // Else, add all directories under world directory (for maps) - mtlist = new ArrayList(world.maps); - } - for (MapType mt : mtlist) { - ImageVariant[] vars = mt.getVariants(); - for (ImageVariant var : vars) { - processEnumMapTiles(world, mt, var, cb, null, null); - } - } - } - @Override - public void enumMapBaseTiles(DynmapWorld world, MapType map, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) { - List mtlist; - - if (map != null) { - mtlist = Collections.singletonList(map); - } - else { // Else, add all directories under world directory (for maps) - mtlist = new ArrayList(world.maps); - } - for (MapType mt : mtlist) { - ImageVariant[] vars = mt.getVariants(); - for (ImageVariant var : vars) { - processEnumMapTiles(world, mt, var, null, cbBase, cbEnd); - } - } - } - private void processEnumMapTiles(DynmapWorld world, MapType map, ImageVariant var, MapStorageTileEnumCB cb, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) { - Connection c = null; - boolean err = false; - Integer mapkey = getMapKey(world, map, var); - if (mapkey == null) { - if(cbEnd != null) - cbEnd.searchEnded(); - return; - } - try { - c = getConnection(); - // Query tiles for given mapkey - Statement stmt = c.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT x,y,zoom,Format FROM " + tableTiles + " WHERE MapID=" + mapkey + ";"); - while (rs.next()) { - StorageTile st = new StorageTile(world, map, rs.getInt("x"), rs.getInt("y"), rs.getInt("zoom"), var); - final MapType.ImageEncoding encoding = MapType.ImageEncoding.fromOrd(rs.getInt("Format")); - if(cb != null) - cb.tileFound(st, encoding); - if(cbBase != null && st.zoom == 0) - cbBase.tileFound(st, encoding); - st.cleanup(); - } - if(cbEnd != null) - cbEnd.searchEnded(); - rs.close(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Tile enum error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - } - - @Override - public void purgeMapTiles(DynmapWorld world, MapType map) { - List mtlist; - - if (map != null) { - mtlist = Collections.singletonList(map); - } - else { // Else, add all directories under world directory (for maps) - mtlist = new ArrayList(world.maps); - } - for (MapType mt : mtlist) { - ImageVariant[] vars = mt.getVariants(); - for (ImageVariant var : vars) { - processPurgeMapTiles(world, mt, var); - } - } - } - private void processPurgeMapTiles(DynmapWorld world, MapType map, ImageVariant var) { - Connection c = null; - boolean err = false; - Integer mapkey = getMapKey(world, map, var); - if (mapkey == null) return; - try { - c = getConnection(); - // Query tiles for given mapkey - Statement stmt = c.createStatement(); - stmt.executeUpdate("DELETE FROM " + tableTiles + " WHERE MapID=" + mapkey + ";"); - stmt.close(); - } catch (SQLException x) { - Log.severe("Tile purge error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - } - - @Override - public boolean setPlayerFaceImage(String playername, FaceType facetype, - BufferOutputStream encImage) { - Connection c = null; - boolean err = false; - boolean exists = hasPlayerFaceImage(playername, facetype); - // If delete, and doesn't exist, quit - if ((encImage == null) && (!exists)) return false; - - try { - c = getConnection(); - PreparedStatement stmt; - if (encImage == null) { // If delete - stmt = c.prepareStatement("DELETE FROM " + tableFaces + " WHERE PlayerName=? AND TypeIDx=?;"); - stmt.setString(1, playername); - stmt.setInt(2, facetype.typeID); - } - else if (exists) { - stmt = c.prepareStatement("UPDATE " + tableFaces + " SET Image=? WHERE PlayerName=? AND TypeID=?;"); - stmt.setBinaryStream(1, new BufferInputStream(encImage.buf, encImage.len), encImage.len); - stmt.setString(2, playername); - stmt.setInt(3, facetype.typeID); - } - else { - stmt = c.prepareStatement("INSERT INTO " + tableFaces + " (PlayerName,TypeID,Image) VALUES (?,?,?);"); - stmt.setString(1, playername); - stmt.setInt(2, facetype.typeID); - stmt.setBinaryStream(3, new BufferInputStream(encImage.buf, encImage.len), encImage.len); - } - stmt.executeUpdate(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Face write error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - return !err; - } - - @Override - public BufferInputStream getPlayerFaceImage(String playername, - FaceType facetype) { - Connection c = null; - boolean err = false; - BufferInputStream image = null; - try { - c = getConnection(); - PreparedStatement stmt = c.prepareStatement("SELECT Image FROM " + tableFaces + " WHERE PlayerName=? AND TypeID=?;"); - stmt.setString(1, playername); - stmt.setInt(2, facetype.typeID); - ResultSet rs = stmt.executeQuery(); - if (rs.next()) { - byte[] img = rs.getBytes("Image"); - image = new BufferInputStream(img); - } - rs.close(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Face read error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - return image; - } - - @Override - public boolean hasPlayerFaceImage(String playername, FaceType facetype) { - Connection c = null; - boolean err = false; - boolean exists = false; - try { - c = getConnection(); - PreparedStatement stmt = c.prepareStatement("SELECT TypeID FROM " + tableFaces + " WHERE PlayerName=? AND TypeID=?;"); - stmt.setString(1, playername); - stmt.setInt(2, facetype.typeID); - ResultSet rs = stmt.executeQuery(); - if (rs.next()) { - exists = true; - } - rs.close(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Face exists error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - return exists; - } - - @Override - public boolean setMarkerImage(String markerid, BufferOutputStream encImage) { - Connection c = null; - boolean err = false; - PreparedStatement stmt = null; - ResultSet rs = null; - - try { - c = getConnection(); - boolean exists = false; - stmt = c.prepareStatement("SELECT IconName FROM " + tableMarkerIcons + " WHERE IconName=?;"); - stmt.setString(1, markerid); - rs = stmt.executeQuery(); - if (rs.next()) { - exists = true; - } - rs.close(); - rs = null; - stmt.close(); - stmt = null; - if (encImage == null) { // If delete - // If delete, and doesn't exist, quit - if (!exists) return false; - stmt = c.prepareStatement("DELETE FROM " + tableMarkerIcons + " WHERE IconName=?;"); - stmt.setString(1, markerid); - stmt.executeUpdate(); - } - else if (exists) { - stmt = c.prepareStatement("UPDATE " + tableMarkerIcons + " SET Image=? WHERE IconName=?;"); - stmt.setBinaryStream(1, new BufferInputStream(encImage.buf, encImage.len), encImage.len); - stmt.setString(2, markerid); - } - else { - stmt = c.prepareStatement("INSERT INTO " + tableMarkerIcons + " (IconName,Image) VALUES (?,?);"); - stmt.setString(1, markerid); - stmt.setBinaryStream(2, new BufferInputStream(encImage.buf, encImage.len), encImage.len); - } - stmt.executeUpdate(); - } catch (SQLException x) { - Log.severe("Marker write error - " + x.getMessage()); - err = true; - } finally { - if (rs != null) { try { rs.close(); } catch (SQLException sx) {} } - if (stmt != null) { try { stmt.close(); } catch (SQLException sx) {} } - releaseConnection(c, err); - } - return !err; - } - - @Override - public BufferInputStream getMarkerImage(String markerid) { - Connection c = null; - boolean err = false; - BufferInputStream image = null; - try { - c = getConnection(); - PreparedStatement stmt = c.prepareStatement("SELECT Image FROM " + tableMarkerIcons + " WHERE IconName=?;"); - stmt.setString(1, markerid); - ResultSet rs = stmt.executeQuery(); - if (rs.next()) { - byte[] img = rs.getBytes("Image"); - image = new BufferInputStream(img); - } - rs.close(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Marker read error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - return image; - } - - @Override - public boolean setMarkerFile(String world, String content) { - Connection c = null; - boolean err = false; - PreparedStatement stmt = null; - ResultSet rs = null; - - try { - c = getConnection(); - boolean exists = false; - stmt = c.prepareStatement("SELECT FileName FROM " + tableMarkerFiles + " WHERE FileName=?;"); - stmt.setString(1, world); - rs = stmt.executeQuery(); - if (rs.next()) { - exists = true; - } - rs.close(); - rs = null; - stmt.close(); - stmt = null; - if (content == null) { // If delete - // If delete, and doesn't exist, quit - if (!exists) return false; - stmt = c.prepareStatement("DELETE FROM " + tableMarkerFiles + " WHERE FileName=?;"); - stmt.setString(1, world); - stmt.executeUpdate(); - } - else if (exists) { - stmt = c.prepareStatement("UPDATE " + tableMarkerFiles + " SET Content=? WHERE FileName=?;"); - stmt.setBytes(1, content.getBytes(UTF8)); - stmt.setString(2, world); - } - else { - stmt = c.prepareStatement("INSERT INTO " + tableMarkerFiles + " (FileName,Content) VALUES (?,?);"); - stmt.setString(1, world); - stmt.setBytes(2, content.getBytes(UTF8)); - } - stmt.executeUpdate(); - } catch (SQLException x) { - Log.severe("Marker file write error - " + x.getMessage()); - err = true; - } finally { - if (rs != null) { try { rs.close(); } catch (SQLException sx) {} } - if (stmt != null) { try { stmt.close(); } catch (SQLException sx) {} } - releaseConnection(c, err); - } - return !err; - } - - @Override - public String getMarkerFile(String world) { - Connection c = null; - boolean err = false; - String content = null; - try { - c = getConnection(); - PreparedStatement stmt = c.prepareStatement("SELECT Content FROM " + tableMarkerFiles + " WHERE FileName=?;"); - stmt.setString(1, world); - ResultSet rs = stmt.executeQuery(); - if (rs.next()) { - byte[] img = rs.getBytes("Content"); - content = new String(img, UTF8); - } - rs.close(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Marker file read error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - return content; - } - - @Override - // For external web server only - public String getMarkersURI(boolean login_enabled) { - return "standalone/MySQL_markers.php?marker="; - } - - @Override - // For external web server only - public String getTilesURI(boolean login_enabled) { - return "standalone/MySQL_tiles.php?tile="; - } - - @Override - // For external web server only - public String getConfigurationJSONURI(boolean login_enabled) { - return "standalone/MySQL_configuration.php"; // ?serverid={serverid}"; - } - - @Override - // For external web server only - public String getUpdateJSONURI(boolean login_enabled) { - return "standalone/MySQL_update.php?world={world}&ts={timestamp}"; // &serverid={serverid}"; - } - - @Override - // For external web server only - public String getSendMessageURI() { - return "standalone/MySQL_sendmessage.php"; - } - - @Override - public BufferInputStream getStandaloneFile(String fileid) { - Connection c = null; - boolean err = false; - BufferInputStream content = null; - try { - c = getConnection(); - PreparedStatement stmt = c.prepareStatement("SELECT Content FROM " + tableStandaloneFiles + " WHERE FileName=? AND ServerID=?;"); - stmt.setString(1, fileid); - stmt.setLong(2, serverID); - ResultSet rs = stmt.executeQuery(); - if (rs.next()) { - byte[] img = rs.getBytes("Content"); - content = new BufferInputStream(img); - } - rs.close(); - stmt.close(); - } catch (SQLException x) { - Log.severe("Standalone file read error - " + x.getMessage()); - err = true; - } finally { - releaseConnection(c, err); - } - return content; - } - - @Override - public boolean setStandaloneFile(String fileid, BufferOutputStream content) { - Connection c = null; - boolean err = false; - PreparedStatement stmt = null; - ResultSet rs = null; - - try { - c = getConnection(); - boolean exists = false; - stmt = c.prepareStatement("SELECT FileName FROM " + tableStandaloneFiles + " WHERE FileName=? AND ServerID=?;"); - stmt.setString(1, fileid); - stmt.setLong(2, serverID); - rs = stmt.executeQuery(); - if (rs.next()) { - exists = true; - } - rs.close(); - rs = null; - stmt.close(); - stmt = null; - if (content == null) { // If delete - // If delete, and doesn't exist, quit - if (!exists) return true; - stmt = c.prepareStatement("DELETE FROM " + tableStandaloneFiles + " WHERE FileName=? AND ServerID=?;"); - stmt.setString(1, fileid); - stmt.setLong(2, serverID); - stmt.executeUpdate(); - } - else if (exists) { - stmt = c.prepareStatement("UPDATE " + tableStandaloneFiles + " SET Content=? WHERE FileName=? AND ServerID=?;"); - stmt.setBinaryStream(1, new BufferInputStream(content.buf, content.len), content.len); - stmt.setString(2, fileid); - stmt.setLong(3, serverID); - } - else { - stmt = c.prepareStatement("INSERT INTO " + tableStandaloneFiles + " (FileName,ServerID,Content) VALUES (?,?,?);"); - stmt.setString(1, fileid); - stmt.setLong(2, serverID); - stmt.setBinaryStream(3, new BufferInputStream(content.buf, content.len), content.len); - } - stmt.executeUpdate(); - } catch (SQLException x) { - Log.severe("Standalone file write error - " + x.getMessage()); - err = true; - } finally { - if (rs != null) { try { rs.close(); } catch (SQLException sx) {} } - if (stmt != null) { try { stmt.close(); } catch (SQLException sx) {} } - releaseConnection(c, err); - } - return !err; - } - @Override - public boolean wrapStandaloneJSON(boolean login_enabled) { - return false; - } - @Override - public boolean wrapStandalonePHP() { - return false; - } - @Override - // For external web server only - public String getStandaloneLoginURI() { - return "standalone/MySQL_login.php"; - } - @Override - // For external web server only - public String getStandaloneRegisterURI() { - return "standalone/MySQL_register.php"; - } - @Override - public void setLoginEnabled(DynmapCore core) { - writeConfigPHP(core); - } } diff --git a/DynmapCore/src/main/java/org/dynmap/storage/mysql/MySQLMapStorage.java b/DynmapCore/src/main/java/org/dynmap/storage/mysql/MySQLMapStorage.java index 55e8c2fe..46152a6c 100644 --- a/DynmapCore/src/main/java/org/dynmap/storage/mysql/MySQLMapStorage.java +++ b/DynmapCore/src/main/java/org/dynmap/storage/mysql/MySQLMapStorage.java @@ -31,13 +31,13 @@ import org.dynmap.utils.BufferInputStream; import org.dynmap.utils.BufferOutputStream; public class MySQLMapStorage extends MapStorage { - private String connectionString; + protected String connectionString; private String userid; private String password; - private String database; - private String hostname; + protected String database; + protected String hostname; private String prefix = ""; - private String flags; + protected String flags; private String tableTiles; private String tableMaps; private String tableFaces; @@ -46,7 +46,7 @@ public class MySQLMapStorage extends MapStorage { private String tableStandaloneFiles; private String tableSchemaVersion; - private int port; + protected int port; private static final int POOLSIZE = 5; private Connection[] cpool = new Connection[POOLSIZE]; private int cpoolCount = 0; @@ -270,6 +270,18 @@ public class MySQLMapStorage extends MapStorage { public MySQLMapStorage() { } + // MySQL specific driver check + protected boolean checkDriver() { + connectionString = "jdbc:mysql://" + hostname + ":" + port + "/" + database + flags; + Log.info("Opening MySQL database " + hostname + ":" + port + "/" + database + " as map store"); + + if(!hasClass("com.mysql.cj.jdbc.Driver") && !hasClass("com.mysql.jdbc.Driver")){ + Log.severe("MySQL-JDBC classes not found - MySQL data source not usable"); + return false; + } + return true; + } + @Override public boolean init(DynmapCore core) { if (!super.init(core)) { @@ -290,13 +302,8 @@ public class MySQLMapStorage extends MapStorage { tableStandaloneFiles = prefix + "StandaloneFiles"; tableSchemaVersion = prefix + "SchemaVersion"; - connectionString = "jdbc:mysql://" + hostname + ":" + port + "/" + database + flags; - Log.info("Opening MySQL database " + hostname + ":" + port + "/" + database + " as map store"); - - if(!hasClass("com.mysql.cj.jdbc.Driver") && !hasClass("com.mysql.jdbc.Driver")){ - Log.severe("MySQL-JDBC classes not found - MySQL data source not usable"); - return false; - } + if (!checkDriver()) return false; + // Initialize/update tables, if needed if(!initializeTables()) { return false; @@ -465,12 +472,13 @@ public class MySQLMapStorage extends MapStorage { c = getConnection(); doUpdate(c, "CREATE TABLE " + tableMaps + " (ID INTEGER PRIMARY KEY AUTO_INCREMENT, WorldID VARCHAR(64) NOT NULL, MapID VARCHAR(64) NOT NULL, Variant VARCHAR(16) NOT NULL, ServerID BIGINT NOT NULL DEFAULT 0)"); doUpdate(c, "CREATE TABLE " + tableTiles + " (MapID INT NOT NULL, x INT NOT NULL, y INT NOT NULL, zoom INT NOT NULL, HashCode BIGINT NOT NULL, LastUpdate BIGINT NOT NULL, Format INT NOT NULL, Image MEDIUMBLOB, PRIMARY KEY(MapID, x, y, zoom))"); - doUpdate(c, "CREATE TABLE " + tableFaces + " (PlayerName VARCHAR(64) NOT NULL, TypeID INT NOT NULL, Image BLOB, PRIMARY KEY(PlayerName, TypeID))"); - doUpdate(c, "CREATE TABLE " + tableMarkerIcons + " (IconName VARCHAR(128) PRIMARY KEY NOT NULL, Image BLOB)"); + doUpdate(c, "CREATE TABLE " + tableFaces + " (PlayerName VARCHAR(64) NOT NULL, TypeID INT NOT NULL, Image MEDIUMBLOB, PRIMARY KEY(PlayerName, TypeID))"); + doUpdate(c, "CREATE TABLE " + tableMarkerIcons + " (IconName VARCHAR(128) PRIMARY KEY NOT NULL, Image MEDIUMBLOB)"); doUpdate(c, "CREATE TABLE " + tableMarkerFiles + " (FileName VARCHAR(128) PRIMARY KEY NOT NULL, Content MEDIUMTEXT)"); doUpdate(c, "CREATE TABLE " + tableStandaloneFiles + " (FileName VARCHAR(128) NOT NULL, ServerID BIGINT NOT NULL DEFAULT 0, Content MEDIUMTEXT, PRIMARY KEY (FileName, ServerID))"); doUpdate(c, "CREATE TABLE " + tableSchemaVersion + " (level INT PRIMARY KEY NOT NULL)"); - doUpdate(c, "INSERT INTO " + tableSchemaVersion + " (level) VALUES (3)"); + doUpdate(c, "INSERT INTO " + tableSchemaVersion + " (level) VALUES (4)"); + version = 4; // Initial - we have all the following updates already } catch (SQLException x) { Log.severe("Error creating tables - " + x.getMessage()); err = true; @@ -480,12 +488,13 @@ public class MySQLMapStorage extends MapStorage { c = null; } } - else if (version == 1) { + if (version == 1) { try { c = getConnection(); doUpdate(c, "CREATE TABLE " + tableStandaloneFiles + " (FileName VARCHAR(128) NOT NULL, ServerID BIGINT NOT NULL DEFAULT 0, Content MEDIUMTEXT, PRIMARY KEY (FileName, ServerID))"); doUpdate(c, "ALTER TABLE " + tableMaps + " ADD COLUMN ServerID BIGINT NOT NULL DEFAULT 0 AFTER Variant"); - doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=3 WHERE level = 1;"); + doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=2 WHERE level = 1;"); + version = 2; } catch (SQLException x) { Log.severe("Error creating tables - " + x.getMessage()); err = true; @@ -495,13 +504,14 @@ public class MySQLMapStorage extends MapStorage { c = null; } } - else if (version == 2) { + if (version == 2) { try { c = getConnection(); doUpdate(c, "DELETE FROM " + tableStandaloneFiles + ";"); doUpdate(c, "ALTER TABLE " + tableStandaloneFiles + " DROP COLUMN Content;"); doUpdate(c, "ALTER TABLE " + tableStandaloneFiles + " ADD COLUMN Content MEDIUMTEXT;"); doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=3 WHERE level = 2;"); + version = 3; } catch (SQLException x) { Log.severe("Error creating tables - " + x.getMessage()); err = true; @@ -511,12 +521,29 @@ public class MySQLMapStorage extends MapStorage { c = null; } } + if (version == 3) { + try { + c = getConnection(); + doUpdate(c, "ALTER TABLE " + tableTiles + " ALTER COLUMN Image MEDIUMBLOB;"); + doUpdate(c, "ALTER TABLE " + tableFaces + " ALTER COLUMN Image MEDIUMBLOB;"); + doUpdate(c, "ALTER TABLE " + tableMarkerIcons + " ALTER COLUMN Image MEDIUMBLOB;"); + doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=4 WHERE level = 3;"); + } catch (SQLException x) { + Log.severe("Error creating tables - " + x.getMessage()); + err = true; + return false; + } finally { + releaseConnection(c, err); + c = null; + } + + } // Load maps table - cache results doLoadMaps(); return true; } - + private Connection getConnection() throws SQLException { Connection c = null; synchronized (cpool) { diff --git a/DynmapCore/src/main/java/org/dynmap/storage/postgresql/PostgreSQLMapStorage.java b/DynmapCore/src/main/java/org/dynmap/storage/postgresql/PostgreSQLMapStorage.java index 55c97d64..185e1642 100644 --- a/DynmapCore/src/main/java/org/dynmap/storage/postgresql/PostgreSQLMapStorage.java +++ b/DynmapCore/src/main/java/org/dynmap/storage/postgresql/PostgreSQLMapStorage.java @@ -464,6 +464,7 @@ public class PostgreSQLMapStorage extends MapStorage { doUpdate(c, "CREATE TABLE " + tableStandaloneFiles + " (FileName VARCHAR(128) NOT NULL, ServerID BIGINT NOT NULL DEFAULT 0, Content BYTEA, PRIMARY KEY (FileName, ServerID))"); doUpdate(c, "CREATE TABLE " + tableSchemaVersion + " (level INT PRIMARY KEY NOT NULL)"); doUpdate(c, "INSERT INTO " + tableSchemaVersion + " (level) VALUES (3)"); + version = 3; // initialzed to current schema } catch (SQLException x) { Log.severe("Error creating tables - " + x.getMessage()); err = true; @@ -473,12 +474,13 @@ public class PostgreSQLMapStorage extends MapStorage { c = null; } } - else if (version == 1) { + if (version == 1) { try { c = getConnection(); doUpdate(c, "CREATE TABLE " + tableStandaloneFiles + " (FileName VARCHAR(128) NOT NULL, ServerID BIGINT NOT NULL DEFAULT 0, Content TEXT, PRIMARY KEY (FileName, ServerID))"); doUpdate(c, "ALTER TABLE " + tableMaps + " ADD COLUMN ServerID BIGINT NOT NULL DEFAULT 0 AFTER Variant"); - doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=3 WHERE level = 1;"); + doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=2 WHERE level = 1;"); + version = 2; } catch (SQLException x) { Log.severe("Error creating tables - " + x.getMessage()); err = true; @@ -488,13 +490,14 @@ public class PostgreSQLMapStorage extends MapStorage { c = null; } } - else if (version == 2) { + if (version == 2) { try { c = getConnection(); doUpdate(c, "DELETE FROM " + tableStandaloneFiles + ";"); doUpdate(c, "ALTER TABLE " + tableStandaloneFiles + " DROP COLUMN Content;"); doUpdate(c, "ALTER TABLE " + tableStandaloneFiles + " ADD COLUMN Content BYTEA;"); doUpdate(c, "UPDATE " + tableSchemaVersion + " SET level=3 WHERE level = 2;"); + version = 3; } catch (SQLException x) { Log.severe("Error creating tables - " + x.getMessage()); err = true; diff --git a/DynmapCore/src/main/java/org/dynmap/storage/sqllte/SQLiteMapStorage.java b/DynmapCore/src/main/java/org/dynmap/storage/sqllte/SQLiteMapStorage.java index 0d6678c1..48cdfbcc 100644 --- a/DynmapCore/src/main/java/org/dynmap/storage/sqllte/SQLiteMapStorage.java +++ b/DynmapCore/src/main/java/org/dynmap/storage/sqllte/SQLiteMapStorage.java @@ -402,6 +402,7 @@ public class SQLiteMapStorage extends MapStorage { doUpdate(c, "CREATE TABLE MarkerFiles (FileName STRING PRIMARY KEY NOT NULL, Content CLOB)"); doUpdate(c, "CREATE TABLE SchemaVersion (level INT PRIMARY KEY NOT NULL)"); doUpdate(c, "INSERT INTO SchemaVersion (level) VALUES (2)"); + version = 2; // Initializes to current schema } catch (SQLException x) { Log.severe("Error creating tables - " + x.getMessage()); err = true; @@ -411,13 +412,14 @@ public class SQLiteMapStorage extends MapStorage { c = null; } } - else if (version == 1) { // Add ImageLen columns + if (version == 1) { // Add ImageLen columns try { c = getConnection(); doUpdate(c, "ALTER TABLE Tiles ADD ImageLen INT"); doUpdate(c, "ALTER TABLE Faces ADD ImageLen INT"); doUpdate(c, "ALTER TABLE MarkerIcons ADD ImageLen INT"); doUpdate(c, "UPDATE SchemaVersion SET level=2"); + version = 2; } catch (SQLException x) { Log.severe("Error creating tables - " + x.getMessage()); err = true;