Skip to content

Commit

Permalink
Fix exception related to CONCAT on SQLite in Extension boolean storage
Browse files Browse the repository at this point in the history
Affects issues:
- Fixed #3514
  • Loading branch information
AuroraLS3 committed Mar 11, 2024
1 parent 9fa1a94 commit 7463d4e
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ private List<Integer> selectUnfulfilledProviderIds() {
"FROM plan_extension_providers indb " +
"JOIN plan_extension_providers unfulfilled ON unfulfilled.condition_name=" +
// 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" +
" WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID +
" AND indb.provided_condition IS NOT NULL";
Expand All @@ -181,7 +181,7 @@ private List<Integer> selectUnfulfilledTableIds() {
"FROM plan_extension_providers indb " +
"JOIN plan_extension_tables unfulfilled ON unfulfilled.condition_name=" +
// 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" +
" WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID +
" AND indb.provided_condition IS NOT NULL";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ private List<Integer> selectUnfulfilledProviderIds() {
"FROM plan_extension_providers indb " +
"JOIN plan_extension_providers unfulfilled ON unfulfilled.condition_name=" +
// 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" +
" WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID +
" AND indb.provided_condition IS NOT NULL";
Expand Down Expand Up @@ -166,7 +166,7 @@ private List<Integer> selectUnfulfilledTableIds() {
"FROM plan_extension_providers indb " +
"JOIN plan_extension_tables unfulfilled ON unfulfilled.condition_name=" +
// 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" +
" WHERE indb.id=" + ExtensionProviderTable.STATEMENT_SELECT_PROVIDER_ID +
" AND indb.provided_condition IS NOT NULL";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package com.djrapitops.plan.storage.database.sql.building;

import com.djrapitops.plan.storage.database.DBType;
import org.apache.commons.text.TextStringBuilder;

import java.sql.PreparedStatement;
Expand Down Expand Up @@ -96,6 +97,15 @@ public static void setStringOrNull(PreparedStatement statement, int index, Strin
}
}

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 dateToEpochSecond(String sql);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package com.djrapitops.plan.storage.database.transactions.patches;

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.WebGroupTable;

Expand Down Expand Up @@ -71,7 +71,7 @@ protected void applyPatch() {
SecurityTable.USERNAME + ',' +
SecurityTable.LINKED_TO + ',' +
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
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,58 @@ default void unsatisfiedPlayerConditionalResultsAreCleaned() {
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) {
if (condition) { // Condition is true, conditional values exist
List<ExtensionData> ofServer = db().query(new ExtensionPlayerDataQuery(playerUUID)).get(serverUUID());
Expand Down Expand Up @@ -437,6 +489,34 @@ public String unconditional() {
}
}

@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")
class ServerExtension implements DataExtension {
@NumberProvider(text = "a number")
Expand Down

0 comments on commit 7463d4e

Please sign in to comment.