From 980da08174bc627bd044a925566c959650bba8fc Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Tue, 10 Mar 2026 22:48:29 -0400 Subject: [PATCH 01/13] add SQLite compatiblity to sql.php --- common/webapp/public/sql.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/common/webapp/public/sql.php b/common/webapp/public/sql.php index 5cd1cbd8e..ad4fa7b3b 100644 --- a/common/webapp/public/sql.php +++ b/common/webapp/public/sql.php @@ -2,7 +2,8 @@ // !!! SET YOUR SQL-CONNECTION SETTINGS HERE: !!! -$driver = 'mysql'; // 'mysql' (MySQL) or 'pgsql' (PostgreSQL) +$driver = 'mysql'; // 'mysql' (MySQL), 'pgsql' (PostgreSQL) or 'sqlite' (SQLite) +$sqlfile = 'bluemap.db'; // Only applies when using 'sqlite' as the driver $hostname = '127.0.0.1'; $port = 3306; $username = 'root'; @@ -147,7 +148,11 @@ function send($data) { // Initialize PDO try { - $sql = new PDO("$driver:host=$hostname;port=$port;dbname=$database", $username, $password); + if ($driver === "sqlite") { + $sql = new PDO("$driver:file:$sqlfile?mode=ro"); + } else { + $sql = new PDO("$driver:host=$hostname;port=$port;dbname=$database", $username, $password); + } $sql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e ) { error_log($e->getMessage(), 0); // Logs the detailed error message From 46f314ef6c3d5779174368eea7862a023daae676 Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Wed, 11 Mar 2026 17:33:22 -0400 Subject: [PATCH 02/13] Commit current config --- .../bluemap/config/storages/sqlite.conf | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf diff --git a/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf new file mode 100644 index 000000000..259e4027c --- /dev/null +++ b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf @@ -0,0 +1,43 @@ +## ## +## BlueMap ## +## Storage-Config ## +## ## + +# The storage-type of this storage. +# Depending on this setting, different config entries are allowed/expected in this config file. +# Don't change this value! If you want a different storage-type, check out the other example configs. +storage-type: sqlite + +# The JDBC-Connection URL that is used to connect to the database. +# The format for this URL is usually something like: jdbc:[driver]://[host]:[port]/[database] +# The exact format of the URL is determined by the JDBC-Driver you are using. +connection-url: "jdbc:sqlite:file:bluemap/map.db" + +# The PRAGMA commands to run on the inital connection. +# Find PRAGMA commands at https://sqlite.org/pragma.html/ +pragma-commands: + - "journal_mode = WAL" + - "cache_size = -20000" + - "synchronous = NORMAL" + +# This can be used to load a custom JDBC-Driver from a .jar file. +# E.g. if your runtime environment is not already providing an SQLite driver, +# you could download the SQLite JDBC-Connector from https://github.com/xerial/sqlite-jdbc/releases/ +# If you set this value, you HAVE TO set the correct driver-class name below. +# Place it in the './bluemap' folder and use it like this: +#driver-jar: "bluemap/sqlite-jdbc-2.51.2.0" + +# This is the driver-class that BlueMap will try to load and use. +# Check the documentation of the driver you are using if you don't know this. +# Leaving this commented out means that BlueMap automatically tries to find a suitable driver in your classpath. +# If you added a custom driver-jar value above, you HAVE TO set the correct class name here. +#driver-class: "org.sqlite.JDBC" + +# The compression type that BlueMap will use to compress generated map data. +# Available compression types are: +# - gzip +# - zstd +# - deflate +# - none +# The default is: gzip +compression: gzip From 9f61aae64fa6374f5280c1f7263c48ff517c9054 Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Fri, 13 Mar 2026 03:38:26 -0400 Subject: [PATCH 03/13] I think this should write the config at least? --- .../bluemap/common/config/BlueMapConfigManager.java | 6 ++++++ .../bluecolored/bluemap/config/storages/sqlite.conf | 13 ++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java b/common/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java index ee48c2ec0..3beb44b67 100644 --- a/common/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java +++ b/common/src/main/java/de/bluecolored/bluemap/common/config/BlueMapConfigManager.java @@ -60,6 +60,7 @@ public class BlueMapConfigManager implements BlueMapConfiguration { public static final String FILE_STORAGE_CONFIG_NAME = STORAGES_CONFIG_FOLDER_NAME + "/file"; public static final String SQL_STORAGE_CONFIG_NAME = STORAGES_CONFIG_FOLDER_NAME + "/sql"; + public static final String SQLITE_STORAGE_CONFIG_NAME = STORAGES_CONFIG_FOLDER_NAME + "/sqlite"; private final ConfigManager configManager; @@ -350,6 +351,11 @@ private Map loadStorageConfigs(Path defaultWebroot) throw configManager.loadConfigTemplate(SQL_STORAGE_CONFIG_NAME).build(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING ); + Files.writeString( + configManager.resolveConfigFile(SQLITE_STORAGE_CONFIG_NAME), + configManager.loadConfigTemplate(SQLITE_STORAGE_CONFIG_NAME).build(), + StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING + ); } catch (IOException | NullPointerException ex) { throw new ConfigurationException("BlueMap failed to create default storage-configuration-files in\n" + storageConfigFolder.toAbsolutePath().normalize() + "\n" + diff --git a/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf index 259e4027c..1ff2b7dcd 100644 --- a/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf +++ b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf @@ -9,16 +9,19 @@ storage-type: sqlite # The JDBC-Connection URL that is used to connect to the database. -# The format for this URL is usually something like: jdbc:[driver]://[host]:[port]/[database] +# The format for this URL is usually something like: jdbc:sqlite:file:[folder/file]/[folder/file] # The exact format of the URL is determined by the JDBC-Driver you are using. connection-url: "jdbc:sqlite:file:bluemap/map.db" -# The PRAGMA commands to run on the inital connection. -# Find PRAGMA commands at https://sqlite.org/pragma.html/ +# The PRAGMA commands to run on initialization. +# Find PRAGMA command documentation at https://sqlite.org/pragma.html +# Some commands may improve render performance, hurt render performance, introduce possibly of corruption, use more RAM, etc. +# Add/change commands cautiously! pragma-commands: - "journal_mode = WAL" - - "cache_size = -20000" - - "synchronous = NORMAL" + - "journal_size_limit = 268435456" +# - "cache_size = -65536" # Will use more RAM, but otherwise generally improves read performance when multiple people are browsing the map. +# - "synchronous = NORMAL" # ONLY SAFE TO USE WITH WAL! Otherwise improves write performance while rendering. # This can be used to load a custom JDBC-Driver from a .jar file. # E.g. if your runtime environment is not already providing an SQLite driver, From 7f45ee47e5c2aadaa357649f2d02be3d2aefbbc5 Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Fri, 13 Mar 2026 15:08:01 -0400 Subject: [PATCH 04/13] commit what I currently have --- .../common/config/storage/SQLiteConfig.java | 204 ++++++++++++++++++ .../common/config/storage/StorageType.java | 4 +- .../bluemap/config/storages/sqlite.conf | 15 +- 3 files changed, 215 insertions(+), 8 deletions(-) create mode 100644 common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java diff --git a/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java new file mode 100644 index 000000000..9f146f0f1 --- /dev/null +++ b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java @@ -0,0 +1,204 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package de.bluecolored.bluemap.common.config.storage; + +import de.bluecolored.bluemap.common.config.ConfigurationException; +import de.bluecolored.bluemap.common.debug.DebugDump; +import de.bluecolored.bluemap.core.storage.compression.Compression; +import de.bluecolored.bluemap.core.storage.sql.Database; +import de.bluecolored.bluemap.core.storage.sql.SQLStorage; +import de.bluecolored.bluemap.core.storage.sql.commandset.CommandSet; +import lombok.AccessLevel; +import lombok.Getter; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.configurate.objectmapping.ConfigSerializable; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import javax.management.RuntimeErrorException; + +@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) +@ConfigSerializable +@Getter +public class SQLiteConfig extends StorageConfig { + + @DebugDump(exclude = true) + private String connectionUrl = "jdbc:sqlite:file:" + Path.of("bluemap", "web") + "/map.db"; + + @DebugDump(exclude = true) + private Map connectionProperties = new HashMap<>(); + + private String dialect = null; + + private String driverJar = null; + private String driverClass = null; + private int maxConnections = 1; + + private List pragmaCommands = new ArrayList<>(); + + private String compression = Compression.GZIP.getKey().getFormatted(); + + @Getter(AccessLevel.NONE) + private transient URL driverJarURL = null; + + public Optional getDriverJar() throws ConfigurationException { + try { + if (driverJar == null) return Optional.empty(); + + if (driverJarURL == null) { + driverJarURL = Paths.get(driverJar).toUri().toURL(); + } + + return Optional.of(driverJarURL); + } catch (MalformedURLException ex) { + throw new ConfigurationException(""" + The configured driver-jar path is not formatted correctly! + Please check your 'driver-jar' setting in your configuration and make sure you have the correct path configured. + """.strip(), ex); + } + } + + @SuppressWarnings("unused") + public Optional getDriverClass() { + return Optional.ofNullable(driverClass); + } + + public Compression getCompression() throws ConfigurationException { + return parseKey(Compression.REGISTRY, compression, "compression"); + } + + public Dialect getDialect() throws ConfigurationException { + String key = dialect; + + // default from connection-url + if (key == null) { + for (Dialect d : Dialect.REGISTRY.values()) { + if (d.supports(connectionUrl)) { + key = d.getKey().getFormatted(); + break; + } + } + + if (key == null) throw new ConfigurationException(""" + Could not find any sql-dialect that is matching the given connection-url. + Please check your 'connection-url' setting in your configuration and make sure it is in the correct format. + """.strip()); + } + + return parseKey(Dialect.REGISTRY, key, "dialect"); + } + + @Override + public SQLStorage createStorage() throws ConfigurationException { + Driver driver = createDriver(); + Database database; + if (driver != null) { + database = new Database(getConnectionUrl(), getConnectionProperties(), getMaxConnections(), driver); + } else { + database = new Database(getConnectionUrl(), getConnectionProperties(), getMaxConnections()); + } + + // @TODO: Move this, or maybe just fix the exceptions? + // @TODO: This doesn't work because this is in a transaction, which is wrong. + try { + database.run(connection -> { + try (Statement stmt = connection.createStatement()) { + connection.setAutoCommit(true); // @TODO: This is probably not the right solution. + for (String pragmaCommand : pragmaCommands) { + System.out.println("autocommit=" + connection.getAutoCommit()); + stmt.execute("PRAGMA " + pragmaCommand.trim()); + } + } catch (SQLException e) { + throw new RuntimeException("SQL exception while running PRAGMAs!", e); + } + }); + } catch(IOException e) { + throw new RuntimeException("IOException while running PRAGMAs!", e); + } + CommandSet commandSet = getDialect().createCommandSet(database); + return new SQLStorage(commandSet, getCompression()); + } + + private @Nullable Driver createDriver() throws ConfigurationException { + if (driverClass == null) return null; + + try { + // load driver class + Class driverClazz; + URL driverJarUrl = getDriverJar().orElse(null); + if (driverJarUrl != null) { + + // sanity-check if file exists + if (!Files.exists(Path.of(driverJarUrl.toURI()))) { + throw new ConfigurationException(""" + The configured driver-jar was not found! + Please check your 'driver-jar' setting in your configuration and make sure you have the correct path configured. + """.strip()); + } + + ClassLoader classLoader = new URLClassLoader(new URL[]{driverJarUrl}); + driverClazz = Class.forName(driverClass, true, classLoader); + } else { + driverClazz = Class.forName(driverClass); + } + + // create driver + return (Driver) driverClazz.getDeclaredConstructor().newInstance(); + } catch (ClassCastException ex) { + throw new ConfigurationException(""" + The configured driver-class was found but is not of the correct class-type! + Please check your 'driver-class' setting in your configuration and make sure you have the correct class configured. + """.strip(), ex); + } catch (ClassNotFoundException ex) { + throw new ConfigurationException(""" + The configured driver-class was not found! + Please check your 'driver-class' setting in your configuration and make sure you have the correct class configured. + """.strip(), ex); + } catch (ConfigurationException ex) { + throw ex; + } catch (Exception ex) { + throw new ConfigurationException(""" + BlueMap failed to load the configured SQLite-Driver! + Please check your 'driver-jar' and 'driver-class' settings in your configuration. + """.strip(), ex); + } + } + +} diff --git a/common/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageType.java b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageType.java index 0f8fa79cb..9540490cd 100644 --- a/common/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageType.java +++ b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/StorageType.java @@ -34,10 +34,12 @@ public interface StorageType extends Keyed { StorageType FILE = new Impl(Key.bluemap("file"), FileConfig.class); StorageType SQL = new Impl(Key.bluemap("sql"), SQLConfig.class); + StorageType SQLITE = new Impl(Key.bluemap("sqlite"), SQLiteConfig.class); Registry REGISTRY = new Registry<>( FILE, - SQL + SQL, + SQLITE ); Class getConfigType(); diff --git a/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf index 1ff2b7dcd..6411e339e 100644 --- a/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf +++ b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf @@ -10,25 +10,26 @@ storage-type: sqlite # The JDBC-Connection URL that is used to connect to the database. # The format for this URL is usually something like: jdbc:sqlite:file:[folder/file]/[folder/file] -# The exact format of the URL is determined by the JDBC-Driver you are using. +# The default is: "bluemap/maps" connection-url: "jdbc:sqlite:file:bluemap/map.db" # The PRAGMA commands to run on initialization. # Find PRAGMA command documentation at https://sqlite.org/pragma.html # Some commands may improve render performance, hurt render performance, introduce possibly of corruption, use more RAM, etc. # Add/change commands cautiously! -pragma-commands: - - "journal_mode = WAL" - - "journal_size_limit = 268435456" -# - "cache_size = -65536" # Will use more RAM, but otherwise generally improves read performance when multiple people are browsing the map. -# - "synchronous = NORMAL" # ONLY SAFE TO USE WITH WAL! Otherwise improves write performance while rendering. +pragma-commands = [ + "journal_mode = WAL" + "journal_size_limit = 268435456" +# "cache_size = -65536" # Will use more RAM, but otherwise generally improves read performance when multiple people are browsing the map. +# "synchronous = NORMAL" # ONLY SAFE TO USE WITH WAL! Otherwise improves write performance while rendering. +] # This can be used to load a custom JDBC-Driver from a .jar file. # E.g. if your runtime environment is not already providing an SQLite driver, # you could download the SQLite JDBC-Connector from https://github.com/xerial/sqlite-jdbc/releases/ # If you set this value, you HAVE TO set the correct driver-class name below. # Place it in the './bluemap' folder and use it like this: -#driver-jar: "bluemap/sqlite-jdbc-2.51.2.0" +#driver-jar: "bluemap/sqlite-jdbc-3.51.2.0.jar" # This is the driver-class that BlueMap will try to load and use. # Check the documentation of the driver you are using if you don't know this. From ff91beb279cfe492f78a3b2f877b1ea01d61396c Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Fri, 13 Mar 2026 16:32:50 -0400 Subject: [PATCH 05/13] commit working maybe --- .../common/config/storage/SQLiteConfig.java | 24 ++-------------- .../bluemap/core/storage/sql/Database.java | 28 +++++++++++++++---- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java index 9f146f0f1..2d665c850 100644 --- a/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java +++ b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java @@ -52,8 +52,6 @@ import java.util.Map; import java.util.Optional; -import javax.management.RuntimeErrorException; - @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) @ConfigSerializable @Getter @@ -130,27 +128,9 @@ public SQLStorage createStorage() throws ConfigurationException { Driver driver = createDriver(); Database database; if (driver != null) { - database = new Database(getConnectionUrl(), getConnectionProperties(), getMaxConnections(), driver); + database = new Database(getConnectionUrl(), getConnectionProperties(), getMaxConnections(), driver, pragmaCommands); } else { - database = new Database(getConnectionUrl(), getConnectionProperties(), getMaxConnections()); - } - - // @TODO: Move this, or maybe just fix the exceptions? - // @TODO: This doesn't work because this is in a transaction, which is wrong. - try { - database.run(connection -> { - try (Statement stmt = connection.createStatement()) { - connection.setAutoCommit(true); // @TODO: This is probably not the right solution. - for (String pragmaCommand : pragmaCommands) { - System.out.println("autocommit=" + connection.getAutoCommit()); - stmt.execute("PRAGMA " + pragmaCommand.trim()); - } - } catch (SQLException e) { - throw new RuntimeException("SQL exception while running PRAGMAs!", e); - } - }); - } catch(IOException e) { - throw new RuntimeException("IOException while running PRAGMAs!", e); + database = new Database(getConnectionUrl(), getConnectionProperties(), getMaxConnections(), pragmaCommands); } CommandSet commandSet = getDialect().createCommandSet(database); return new SQLStorage(commandSet, getCompression()); diff --git a/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java b/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java index d58e59aac..8ea540030 100644 --- a/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java +++ b/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java @@ -39,7 +39,10 @@ import java.sql.Driver; import java.sql.SQLException; import java.sql.SQLRecoverableException; +import java.sql.Statement; import java.time.Duration; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Properties; @@ -51,13 +54,21 @@ public class Database implements Closeable { private boolean isClosed = false; public Database(String url, Map properties, int maxPoolSize) { + this(url, properties, maxPoolSize, List.of()); + } + + public Database(String url, Map properties, int maxPoolSize, Driver driver) { + this(url, properties, maxPoolSize, driver, List.of()); + } + + public Database(String url, Map properties, int maxPoolSize, List initialCommands) { Properties props = new Properties(); props.putAll(properties); - this.dataSource = createDataSource(new DriverManagerConnectionFactory(url, props), maxPoolSize); + this.dataSource = createDataSource(new DriverManagerConnectionFactory(url, props), maxPoolSize, initialCommands); } - public Database(String url, Map properties, int maxPoolSize, Driver driver) { + public Database(String url, Map properties, int maxPoolSize, Driver driver, List initialCommands) { Properties props = new Properties(); props.putAll(properties); @@ -67,7 +78,7 @@ public Database(String url, Map properties, int maxPoolSize, Dri props ); - this.dataSource = createDataSource(connectionFactory, maxPoolSize); + this.dataSource = createDataSource(connectionFactory, maxPoolSize, initialCommands); } public void run(ConnectionConsumer action) throws IOException { @@ -121,11 +132,18 @@ public void close() throws IOException { } } - private DataSource createDataSource(ConnectionFactory connectionFactory, int maxPoolSize) { + private DataSource createDataSource(ConnectionFactory connectionFactory, int maxPoolSize, List initialCommands) { PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(() -> { Logger.global.logDebug("Creating new SQL-Connection..."); - return connectionFactory.createConnection(); + Connection conn = connectionFactory.createConnection(); + try (Statement stmt = conn.createStatement()) { + for (String initialCommand : initialCommands) { + Logger.global.logDebug("autocommit=" + conn.getAutoCommit()); + stmt.execute(initialCommand); + } + } + return conn; }, null); poolableConnectionFactory.setPoolStatements(true); poolableConnectionFactory.setMaxOpenPreparedStatements(20); From 9124b2a15f85d6daf54f0a4bc8d671b0d4e6552e Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Fri, 13 Mar 2026 16:47:43 -0400 Subject: [PATCH 06/13] Working :D still need to make sure existing functionality works, and solve the TODOs, but otherwise this is working, I think! --- .../bluemap/common/config/storage/SQLiteConfig.java | 6 ++---- .../de/bluecolored/bluemap/core/storage/sql/Database.java | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java index 2d665c850..e93a31111 100644 --- a/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java +++ b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java @@ -35,17 +35,13 @@ import org.jetbrains.annotations.Nullable; import org.spongepowered.configurate.objectmapping.ConfigSerializable; -import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.sql.Connection; import java.sql.Driver; -import java.sql.SQLException; -import java.sql.Statement; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -127,6 +123,8 @@ public Dialect getDialect() throws ConfigurationException { public SQLStorage createStorage() throws ConfigurationException { Driver driver = createDriver(); Database database; + // @TODO: Maybe make another variable called fixedPragmaCommands or something? + pragmaCommands.replaceAll(s -> "PRAGMA " + s); if (driver != null) { database = new Database(getConnectionUrl(), getConnectionProperties(), getMaxConnections(), driver, pragmaCommands); } else { diff --git a/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java b/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java index 8ea540030..751ce16d2 100644 --- a/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java +++ b/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java @@ -41,7 +41,6 @@ import java.sql.SQLRecoverableException; import java.sql.Statement; import java.time.Duration; -import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; From edb2be5d521d0b5b62b6a1fe455d9b61a025cc92 Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Fri, 13 Mar 2026 16:53:37 -0400 Subject: [PATCH 07/13] add new @TODO --- .../java/de/bluecolored/bluemap/core/storage/sql/Database.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java b/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java index 751ce16d2..a35a0896e 100644 --- a/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java +++ b/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java @@ -52,6 +52,8 @@ public class Database implements Closeable { private final DataSource dataSource; private boolean isClosed = false; + // @TODO: Figure out some better way to pass initialCommands rather than this. + public Database(String url, Map properties, int maxPoolSize) { this(url, properties, maxPoolSize, List.of()); } From 6d76c069f7bdc89c8798263190546e709dee654b Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Fri, 13 Mar 2026 18:20:26 -0400 Subject: [PATCH 08/13] Use file location instead of raw connection URL --- .../bluemap/common/config/storage/SQLiteConfig.java | 5 ++++- .../de/bluecolored/bluemap/config/storages/sqlite.conf | 7 +++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java index e93a31111..260c0b96f 100644 --- a/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java +++ b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java @@ -53,8 +53,11 @@ @Getter public class SQLiteConfig extends StorageConfig { + // @TODO: There must be some better way to do this.. + private String fileLocation = "bluemap/map.db"; + @DebugDump(exclude = true) - private String connectionUrl = "jdbc:sqlite:file:" + Path.of("bluemap", "web") + "/map.db"; + private String connectionUrl = "jdbc:sqlite:file:" + fileLocation; @DebugDump(exclude = true) private Map connectionProperties = new HashMap<>(); diff --git a/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf index 6411e339e..001c5c607 100644 --- a/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf +++ b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf @@ -8,10 +8,9 @@ # Don't change this value! If you want a different storage-type, check out the other example configs. storage-type: sqlite -# The JDBC-Connection URL that is used to connect to the database. -# The format for this URL is usually something like: jdbc:sqlite:file:[folder/file]/[folder/file] -# The default is: "bluemap/maps" -connection-url: "jdbc:sqlite:file:bluemap/map.db" +# The location of the SQLite database file. +# The default is: "bluemap/map.db" +file-location: "bluemap/map.db" # The PRAGMA commands to run on initialization. # Find PRAGMA command documentation at https://sqlite.org/pragma.html From 1fd47223d3aecfa1eb2588b84eaf62148f02dce8 Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Sat, 14 Mar 2026 02:49:29 -0400 Subject: [PATCH 09/13] use ': ' instead of '=' in the sqlite.conf --- .../de/bluecolored/bluemap/config/storages/sqlite.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf index 001c5c607..ba64e987b 100644 --- a/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf +++ b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf @@ -16,7 +16,7 @@ file-location: "bluemap/map.db" # Find PRAGMA command documentation at https://sqlite.org/pragma.html # Some commands may improve render performance, hurt render performance, introduce possibly of corruption, use more RAM, etc. # Add/change commands cautiously! -pragma-commands = [ +pragma-commands: [ "journal_mode = WAL" "journal_size_limit = 268435456" # "cache_size = -65536" # Will use more RAM, but otherwise generally improves read performance when multiple people are browsing the map. From 86a328a2d8573cfc7a34520e3801bc7c616a5ffa Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Sat, 14 Mar 2026 03:03:34 -0400 Subject: [PATCH 10/13] oops, remove debug --- .../java/de/bluecolored/bluemap/core/storage/sql/Database.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java b/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java index a35a0896e..1fc3f6aab 100644 --- a/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java +++ b/core/src/main/java/de/bluecolored/bluemap/core/storage/sql/Database.java @@ -140,7 +140,6 @@ private DataSource createDataSource(ConnectionFactory connectionFactory, int max Connection conn = connectionFactory.createConnection(); try (Statement stmt = conn.createStatement()) { for (String initialCommand : initialCommands) { - Logger.global.logDebug("autocommit=" + conn.getAutoCommit()); stmt.execute(initialCommand); } } From 210957d1fb8ede16fcab09cf0f7d9c137d8f0a38 Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Sat, 14 Mar 2026 03:09:17 -0400 Subject: [PATCH 11/13] solve TODO, add new TODO :3 --- .../common/config/storage/SQLiteConfig.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java index 260c0b96f..199cfc8cf 100644 --- a/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java +++ b/common/src/main/java/de/bluecolored/bluemap/common/config/storage/SQLiteConfig.java @@ -126,12 +126,21 @@ public Dialect getDialect() throws ConfigurationException { public SQLStorage createStorage() throws ConfigurationException { Driver driver = createDriver(); Database database; - // @TODO: Maybe make another variable called fixedPragmaCommands or something? - pragmaCommands.replaceAll(s -> "PRAGMA " + s); + List initialCommands = List.of(); + // @TODO: Ehh, I feel like there should be a better way of doing this + String pragmaPrefix = "PRAGMA"; + + // Prefix all pragma commands with PRAGMA if they don't already start with it + initialCommands.addAll( + pragmaCommands.stream() + .map(s -> s.startsWith(pragmaPrefix) ? s: pragmaPrefix + s) + .toList() + ); + if (driver != null) { - database = new Database(getConnectionUrl(), getConnectionProperties(), getMaxConnections(), driver, pragmaCommands); + database = new Database(getConnectionUrl(), getConnectionProperties(), getMaxConnections(), driver, initialCommands); } else { - database = new Database(getConnectionUrl(), getConnectionProperties(), getMaxConnections(), pragmaCommands); + database = new Database(getConnectionUrl(), getConnectionProperties(), getMaxConnections(), initialCommands); } CommandSet commandSet = getDialect().createCommandSet(database); return new SQLStorage(commandSet, getCompression()); From d02ad5dcc413d72a93b2f20bb0b9be55d5cadfae Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Sat, 14 Mar 2026 15:12:08 -0400 Subject: [PATCH 12/13] add cell size check commented option --- .../resources/de/bluecolored/bluemap/config/storages/sqlite.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf index ba64e987b..8c22ce3c0 100644 --- a/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf +++ b/common/src/main/resources/de/bluecolored/bluemap/config/storages/sqlite.conf @@ -21,6 +21,7 @@ pragma-commands: [ "journal_size_limit = 268435456" # "cache_size = -65536" # Will use more RAM, but otherwise generally improves read performance when multiple people are browsing the map. # "synchronous = NORMAL" # ONLY SAFE TO USE WITH WAL! Otherwise improves write performance while rendering. +# "cell_size_check = ON" # Detects corruption earlier and makes it less likely to "spread", comes with a small performance penalty! ] # This can be used to load a custom JDBC-Driver from a .jar file. From 62922da9bebe33482058064b2fbe3b5e8b4b657c Mon Sep 17 00:00:00 2001 From: Soapy7261 <81933267+Soapy7261@users.noreply.github.com> Date: Sat, 14 Mar 2026 20:24:36 -0400 Subject: [PATCH 13/13] [sql.php] Don't open in mode=ro Thanks to WAL, if you try to make a query but the DB has WAL enabled, you will get a "read-only database" error. --- common/webapp/public/sql.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/webapp/public/sql.php b/common/webapp/public/sql.php index ad4fa7b3b..25ff36185 100644 --- a/common/webapp/public/sql.php +++ b/common/webapp/public/sql.php @@ -149,7 +149,7 @@ function send($data) { // Initialize PDO try { if ($driver === "sqlite") { - $sql = new PDO("$driver:file:$sqlfile?mode=ro"); + $sql = new PDO("$driver:file:$sqlfile"); } else { $sql = new PDO("$driver:host=$hostname;port=$port;dbname=$database", $username, $password); }