diff --git a/.gitignore b/.gitignore index 42889b9cc..fe6126d6e 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ forge*changelog.txt # Sqlite databases *.sqlite +*.sqlite-journal diff --git a/core/src/main/java/com/seibel/distanthorizons/core/sql/DatabaseUpdater.java b/core/src/main/java/com/seibel/distanthorizons/core/sql/DatabaseUpdater.java index c6ce1ee99..ae5738e1d 100644 --- a/core/src/main/java/com/seibel/distanthorizons/core/sql/DatabaseUpdater.java +++ b/core/src/main/java/com/seibel/distanthorizons/core/sql/DatabaseUpdater.java @@ -41,6 +41,11 @@ public class DatabaseUpdater public static final String SCHEMA_TABLE_NAME = "Schema"; /** Since java can only run one sql query at a time this string is used to split up our scripts into individual queries. */ public static final String UPDATE_SCRIPT_BATCH_SEPARATOR = "--batch--"; + /** + * If this comment is present anywhere in the auto update script, then transactions won't be used.
+ * This is necessary for some commands that will auto-commit after running, IE: "PRAGMA journal_mode = TRUNCATE" + */ + public static final String UPDATE_SCRIPT_NO_TRANSACTION_FLAG = "--No Transactions--"; private static final String SQL_SCRIPT_RESOURCE_FOLDER = "sqlScripts/"; /** @@ -101,49 +106,43 @@ public class DatabaseUpdater // split up each individual statement so Java can handle the script as a whole String[] fileUpdateSqlArray = resource.queryString.split(UPDATE_SCRIPT_BATCH_SEPARATOR); + boolean transactScript = resource.queryString.contains(UPDATE_SCRIPT_NO_TRANSACTION_FLAG); + + + Connection connection = repo.getConnection(); + connection.setAutoCommit(!transactScript); + try (Statement statement = connection.createStatement()) { + statement.setQueryTimeout(AbstractDhRepo.TIMEOUT_SECONDS); + // adding the scripts to a batched statement allows them to execute together and rollback together if there are any issues for (String updateSql : fileUpdateSqlArray) { - statement.addBatch(updateSql); + statement.execute(updateSql); } - - statement.setQueryTimeout(AbstractDhRepo.TIMEOUT_SECONDS); - // TODO this should be a complete transaction, but doesn't appear to be - int[] numberOfRowsModifiedArray = statement.executeBatch(); - - - // confirm the scripts ran successfully - for (;sqlIndex < numberOfRowsModifiedArray.length; sqlIndex++) + if (transactScript) { - int numberOfRowsModified = numberOfRowsModifiedArray[sqlIndex]; - if (numberOfRowsModified >= 0) - { - // the statement completed successfully - continue; - } - else if (numberOfRowsModified == Statement.EXECUTE_FAILED) - { - LOGGER.error("Execute failed for auto update script: [" + resource.name + "], query: [" + fileUpdateSqlArray[sqlIndex] + "]. Changes have been rolled back.", new SQLException()); - } - else if (numberOfRowsModified == Statement.SUCCESS_NO_INFO) - { - LOGGER.error("Execute failed for auto update script: [" + resource.name + "], query: [" + fileUpdateSqlArray[sqlIndex] + "]. Changes may not have been rolled back.", new SQLException()); - } - else - { - LOGGER.error("Unexpected error state [" + numberOfRowsModified + "] returned for auto update script: [" + resource.name + "], query: [" + fileUpdateSqlArray[sqlIndex] + "].", new SQLException()); - } + connection.commit(); } } catch (SQLException e) { - LOGGER.error("Unexpected SQL Error: ["+e.getMessage()+"] returned for auto update script: [" + resource.name + "], query: [" + fileUpdateSqlArray[sqlIndex] + "].", new SQLException()); + connection.rollback(); + LOGGER.error( + "Unexpected SQL Error: ["+e.getMessage()+"] " + + "returned for auto update script: [" + resource.name + "], " + + "query: [" + fileUpdateSqlArray[sqlIndex] + "]. " + + "Changes should have been rolled back.", new SQLException()); throw e; } + + if (transactScript) + { + connection.setAutoCommit(true); + } } catch (RuntimeException e) { diff --git a/core/src/main/resources/sqlScripts/0030-sqlite-changeTableJournaling.sql b/core/src/main/resources/sqlScripts/0030-sqlite-changeTableJournaling.sql new file mode 100644 index 000000000..6dd0b6898 --- /dev/null +++ b/core/src/main/resources/sqlScripts/0030-sqlite-changeTableJournaling.sql @@ -0,0 +1,9 @@ + +-- this PRAGMA will automatically commit, so we have to disable +-- DH's automatic transactions, otherwise the connection will throw an error + +--No Transactions-- + +-- James ran into some issues where Windows had trouble deleting the Journal file, +-- using TRUNCATE should fix that issue +PRAGMA journal_mode = TRUNCATE; diff --git a/core/src/main/resources/sqlScripts/readme.md b/core/src/main/resources/sqlScripts/readme.md index 18fdb2456..683e39c0f 100644 --- a/core/src/main/resources/sqlScripts/readme.md +++ b/core/src/main/resources/sqlScripts/readme.md @@ -38,5 +38,14 @@ CREATE TABLE TableTwo( ); ``` +### PRAGMA Auto Commits +Certain queries will auto commit after running, specifically certain `PRAGMA` commands. In that case we have to disable DH's automatic transactions by putting `--No Transactions--` somewhere in the file. Otherwise, when the system attempts to commit, it will fail due to the PRAGMA having already committed itself. +Due to how these commands work it's best to only have a single command in the file to prevent confusion and potential database corruption. + +```roomsql +--No Transactions-- + +PRAGMA journal_mode = TRUNCATE; +``` diff --git a/core/src/main/resources/sqlScripts/scriptList.txt b/core/src/main/resources/sqlScripts/scriptList.txt index b41618ae7..ee42f56b0 100644 --- a/core/src/main/resources/sqlScripts/scriptList.txt +++ b/core/src/main/resources/sqlScripts/scriptList.txt @@ -1,3 +1,4 @@ 0010-sqlite-createInitialDataTables.sql 0020-sqlite-createFullDataSourceV2Tables.sql +0030-sqlite-changeTableJournaling.sql