Fix exception related to CONCAT on SQLite in Extension boolean storage

Affects issues:
- Fixed #3514
This commit is contained in:
Aurora Lahtela 2024-03-11 20:52:41 +02:00
parent 9fa1a94301
commit 7463d4e440
5 changed files with 96 additions and 6 deletions

View File

@ -155,7 +155,7 @@ public class StorePlayerBooleanResultTransaction extends ThrowawayTransaction {
"FROM plan_extension_providers indb " + "FROM plan_extension_providers indb " +
"JOIN plan_extension_providers unfulfilled ON unfulfilled.condition_name=" + "JOIN plan_extension_providers unfulfilled ON unfulfilled.condition_name=" +
// This gives the unfulfilled condition, eg. if value is true not_condition is unfulfilled. // This gives the unfulfilled condition, eg. if value is true not_condition is unfulfilled.
(value ? "CONCAT('not_', " : "") + "indb.provided_condition" + (value ? ")" : "") + (value ? Sql.concat(dbType, "'not_'", "indb.provided_condition") : "indb.provided_condition") +
" AND indb.plugin_id=unfulfilled.plugin_id" + " AND indb.plugin_id=unfulfilled.plugin_id" +
" WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID + " WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID +
" AND indb.provided_condition IS NOT NULL"; " AND indb.provided_condition IS NOT NULL";
@ -181,7 +181,7 @@ public class StorePlayerBooleanResultTransaction extends ThrowawayTransaction {
"FROM plan_extension_providers indb " + "FROM plan_extension_providers indb " +
"JOIN plan_extension_tables unfulfilled ON unfulfilled.condition_name=" + "JOIN plan_extension_tables unfulfilled ON unfulfilled.condition_name=" +
// This gives the unfulfilled condition, eg. if value is true not_condition is unfulfilled. // This gives the unfulfilled condition, eg. if value is true not_condition is unfulfilled.
(value ? "CONCAT('not_', " : "") + "indb.provided_condition" + (value ? ")" : "") + (value ? Sql.concat(dbType, "'not_'", "indb.provided_condition") : "indb.provided_condition") +
" AND indb.plugin_id=unfulfilled.plugin_id" + " AND indb.plugin_id=unfulfilled.plugin_id" +
" WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID + " WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID +
" AND indb.provided_condition IS NOT NULL"; " AND indb.provided_condition IS NOT NULL";

View File

@ -134,7 +134,7 @@ public class StoreServerBooleanResultTransaction extends ThrowawayTransaction {
"FROM plan_extension_providers indb " + "FROM plan_extension_providers indb " +
"JOIN plan_extension_providers unfulfilled ON unfulfilled.condition_name=" + "JOIN plan_extension_providers unfulfilled ON unfulfilled.condition_name=" +
// This gives the unfulfilled condition, eg. if value is true not_condition is unfulfilled. // This gives the unfulfilled condition, eg. if value is true not_condition is unfulfilled.
(value ? "CONCAT('not_', " : "") + "indb.provided_condition" + (value ? ")" : "") + (value ? Sql.concat(dbType, "'not_'", "indb.provided_condition") : "indb.provided_condition") +
" AND indb.plugin_id=unfulfilled.plugin_id" + " AND indb.plugin_id=unfulfilled.plugin_id" +
" WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID + " WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID +
" AND indb.provided_condition IS NOT NULL"; " AND indb.provided_condition IS NOT NULL";
@ -166,7 +166,7 @@ public class StoreServerBooleanResultTransaction extends ThrowawayTransaction {
"FROM plan_extension_providers indb " + "FROM plan_extension_providers indb " +
"JOIN plan_extension_tables unfulfilled ON unfulfilled.condition_name=" + "JOIN plan_extension_tables unfulfilled ON unfulfilled.condition_name=" +
// This gives the unfulfilled condition, eg. if value is true not_condition is unfulfilled. // This gives the unfulfilled condition, eg. if value is true not_condition is unfulfilled.
(value ? "CONCAT('not_', " : "") + "indb.provided_condition" + (value ? ")" : "") + (value ? Sql.concat(dbType, "'not_'", "indb.provided_condition") : "indb.provided_condition") +
" AND indb.plugin_id=unfulfilled.plugin_id" + " AND indb.plugin_id=unfulfilled.plugin_id" +
" WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID + " WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID +
" AND indb.provided_condition IS NOT NULL"; " AND indb.provided_condition IS NOT NULL";

View File

@ -16,6 +16,7 @@
*/ */
package com.djrapitops.plan.storage.database.sql.building; package com.djrapitops.plan.storage.database.sql.building;
import com.djrapitops.plan.storage.database.DBType;
import org.apache.commons.text.TextStringBuilder; import org.apache.commons.text.TextStringBuilder;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@ -96,6 +97,15 @@ public abstract class Sql {
} }
} }
public static String concat(DBType dbType, String one, String two) {
if (dbType == DBType.MYSQL) {
return "CONCAT(" + one + ',' + two + ")";
} else if (dbType == DBType.SQLITE) {
return one + " || " + two;
}
return one + two;
}
public abstract String epochSecondToDate(String sql); public abstract String epochSecondToDate(String sql);
public abstract String dateToEpochSecond(String sql); public abstract String dateToEpochSecond(String sql);

View File

@ -17,7 +17,7 @@
package com.djrapitops.plan.storage.database.transactions.patches; package com.djrapitops.plan.storage.database.transactions.patches;
import com.djrapitops.plan.exceptions.database.DBOpException; import com.djrapitops.plan.exceptions.database.DBOpException;
import com.djrapitops.plan.storage.database.DBType; import com.djrapitops.plan.storage.database.sql.building.Sql;
import com.djrapitops.plan.storage.database.sql.tables.webuser.SecurityTable; import com.djrapitops.plan.storage.database.sql.tables.webuser.SecurityTable;
import com.djrapitops.plan.storage.database.sql.tables.webuser.WebGroupTable; import com.djrapitops.plan.storage.database.sql.tables.webuser.WebGroupTable;
@ -71,7 +71,7 @@ public class SecurityTableGroupPatch extends Patch {
SecurityTable.USERNAME + ',' + SecurityTable.USERNAME + ',' +
SecurityTable.LINKED_TO + ',' + SecurityTable.LINKED_TO + ',' +
SecurityTable.SALT_PASSWORD_HASH + ',' + SecurityTable.SALT_PASSWORD_HASH + ',' +
"(" + SELECT + WebGroupTable.ID + FROM + WebGroupTable.TABLE_NAME + WHERE + WebGroupTable.NAME + "=" + (dbType == DBType.SQLITE ? "'legacy_level_' || permission_level" : "CONCAT('legacy_level_', permission_level)") + ")" + "(" + SELECT + WebGroupTable.ID + FROM + WebGroupTable.TABLE_NAME + WHERE + WebGroupTable.NAME + "=" + Sql.concat(dbType, "'legacy_level_'", "permission_level") + ")" +
FROM + tempTableName FROM + tempTableName
); );

View File

@ -234,6 +234,58 @@ public interface ExtensionsDatabaseTest extends DatabaseTestPreparer {
checkThatPlayerDataExists(ConditionalExtension.condition); checkThatPlayerDataExists(ConditionalExtension.condition);
} }
@Test
default void unsatisfiedPlayerConditionalResultsAreCleanedCompletely() {
db().executeTransaction(new PlayerRegisterTransaction(playerUUID, System::currentTimeMillis, TestConstants.PLAYER_ONE_NAME));
ExtensionSvc extensionService = extensionService();
extensionService.register(new RemovingConditionalExtension());
RemovingConditionalExtension.condition = true;
extensionService.updatePlayerValues(playerUUID, TestConstants.PLAYER_ONE_NAME, CallEvents.MANUAL);
List<ExtensionData> ofServer = db().query(new ExtensionPlayerDataQuery(playerUUID)).get(serverUUID());
assertTrue(ofServer != null && !ofServer.isEmpty() && !ofServer.get(0).getTabs().isEmpty(), "There was no data left");
ExtensionTabData tabData = ofServer.get(0).getTabs().get(0);
assertEquals(RemovingConditionalExtension.condition, tabData.getString("conditionalValue").isPresent());
// Reverse condition
RemovingConditionalExtension.condition = false;
extensionService.updatePlayerValues(playerUUID, TestConstants.PLAYER_ONE_NAME, CallEvents.MANUAL);
ofServer = db().query(new ExtensionPlayerDataQuery(playerUUID)).get(serverUUID());
assertTrue(ofServer != null && !ofServer.isEmpty() && !ofServer.get(0).getTabs().isEmpty(), "There was no data left");
tabData = ofServer.get(0).getTabs().get(0);
assertEquals(RemovingConditionalExtension.condition, tabData.getString("conditionalValue").isPresent());
}
@Test
default void unsatisfiedServerConditionalResultsAreCleanedCompletely() {
db().executeTransaction(new PlayerRegisterTransaction(playerUUID, System::currentTimeMillis, TestConstants.PLAYER_ONE_NAME));
ExtensionSvc extensionService = extensionService();
extensionService.register(new RemovingConditionalExtension());
RemovingConditionalExtension.condition = true;
extensionService.updateServerValues(CallEvents.MANUAL);
List<ExtensionData> ofServer = db().query(new ExtensionServerDataQuery(serverUUID()));
assertTrue(ofServer != null && !ofServer.isEmpty() && !ofServer.get(0).getTabs().isEmpty(), "There was no data left");
ExtensionTabData tabData = ofServer.get(0).getTabs().get(0);
assertEquals(RemovingConditionalExtension.condition, tabData.getString("conditionalValue").isPresent());
// Reverse condition
RemovingConditionalExtension.condition = false;
extensionService.updateServerValues(CallEvents.MANUAL);
ofServer = db().query(new ExtensionServerDataQuery(serverUUID()));
assertTrue(ofServer != null && !ofServer.isEmpty() && !ofServer.get(0).getTabs().isEmpty(), "There was no data left");
tabData = ofServer.get(0).getTabs().get(0);
assertEquals(RemovingConditionalExtension.condition, tabData.getString("conditionalValue").isPresent());
}
default void checkThatPlayerDataExists(boolean condition) { default void checkThatPlayerDataExists(boolean condition) {
if (condition) { // Condition is true, conditional values exist if (condition) { // Condition is true, conditional values exist
List<ExtensionData> ofServer = db().query(new ExtensionPlayerDataQuery(playerUUID)).get(serverUUID()); List<ExtensionData> ofServer = db().query(new ExtensionPlayerDataQuery(playerUUID)).get(serverUUID());
@ -437,6 +489,34 @@ public interface ExtensionsDatabaseTest extends DatabaseTestPreparer {
} }
} }
@PluginInfo(name = "ConditionalExtension")
class RemovingConditionalExtension implements DataExtension {
static boolean condition = true;
@BooleanProvider(text = "a boolean", conditionName = "condition")
public boolean isCondition(UUID playerUUID) {
return condition;
}
@StringProvider(text = "Conditional Value")
@Conditional("condition")
public String conditionalValue(UUID playerUUID) {
return "Conditional";
}
@BooleanProvider(text = "a boolean", conditionName = "condition")
public boolean isCondition() {
return condition;
}
@StringProvider(text = "Conditional Value")
@Conditional("condition")
public String conditionalValue() {
return "Conditional";
}
}
@PluginInfo(name = "ServerExtension") @PluginInfo(name = "ServerExtension")
class ServerExtension implements DataExtension { class ServerExtension implements DataExtension {
@NumberProvider(text = "a number") @NumberProvider(text = "a number")