From 137fc3d50579cfc9c2db29dd86f19fc4cc202325 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 24 Mar 2018 22:53:30 +0100 Subject: [PATCH] #1539 Use columns handler in more datasource methods; fix case-insensitivity for SQLite --- .../fr/xephi/authme/datasource/MySQL.java | 81 +++++-------------- .../fr/xephi/authme/datasource/SQLite.java | 81 ++++--------------- .../columnshandler/AuthMeColumns.java | 3 + .../columnshandler/AuthMeColumnsHandler.java | 35 +++++++- .../datasource/MySqlIntegrationTest.java | 4 +- 5 files changed, 75 insertions(+), 129 deletions(-) diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java index 8e501ae0c..e7739fb18 100644 --- a/src/main/java/fr/xephi/authme/datasource/MySQL.java +++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java @@ -1,6 +1,7 @@ package fr.xephi.authme.datasource; import ch.jalu.datasourcecolumns.data.DataSourceValues; +import ch.jalu.datasourcecolumns.predicate.AlwaysTruePredicate; import com.google.common.annotations.VisibleForTesting; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException; @@ -23,11 +24,14 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import static ch.jalu.datasourcecolumns.data.UpdateValues.with; +import static ch.jalu.datasourcecolumns.predicate.StandardPredicates.eq; +import static ch.jalu.datasourcecolumns.predicate.StandardPredicates.eqIgnoreCase; import static fr.xephi.authme.datasource.SqlDataSourceUtils.getNullableLong; import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; @@ -269,24 +273,20 @@ public class MySQL implements DataSource { @Override public boolean isAuthAvailable(String user) { - String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user.toLowerCase()); - try (ResultSet rs = pst.executeQuery()) { - return rs.next(); - } - } catch (SQLException ex) { - logSqlException(ex); + try { + return columnsHandler.retrieve(user, AuthMeColumns.NAME).rowExists(); + } catch (SQLException e) { + logSqlException(e); + return false; } - return false; } @Override public HashedPassword getPassword(String user) { try { - DataSourceValues passwordResult = columnsHandler.retrieve(user, AuthMeColumns.PASSWORD, AuthMeColumns.SALT); - if (passwordResult.rowExists()) { - return new HashedPassword(passwordResult.get(AuthMeColumns.PASSWORD), passwordResult.get(AuthMeColumns.SALT)); + DataSourceValues values = columnsHandler.retrieve(user, AuthMeColumns.PASSWORD, AuthMeColumns.SALT); + if (values.rowExists()) { + return new HashedPassword(values.get(AuthMeColumns.PASSWORD), values.get(AuthMeColumns.SALT)); } } catch (SQLException e) { logSqlException(e); @@ -354,19 +354,7 @@ public class MySQL implements DataSource { @Override public boolean updateSession(PlayerAuth auth) { - String sql = "UPDATE " + tableName + " SET " - + col.LAST_IP + "=?, " + col.LAST_LOGIN + "=?, " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, auth.getLastIp()); - pst.setObject(2, auth.getLastLogin()); - pst.setString(3, auth.getRealName()); - pst.setString(4, auth.getNickname()); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; + return columnsHandler.update(auth, AuthMeColumns.LAST_IP, AuthMeColumns.LAST_LOGIN, AuthMeColumns.NICK_NAME); } @Override @@ -427,35 +415,17 @@ public class MySQL implements DataSource { @Override public List getAllAuthsByIp(String ip) { - List result = new ArrayList<>(); - String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_IP + "=?;"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, ip); - try (ResultSet rs = pst.executeQuery()) { - while (rs.next()) { - result.add(rs.getString(col.NAME)); - } - } - } catch (SQLException ex) { - logSqlException(ex); + try { + return columnsHandler.retrieve(eq(AuthMeColumns.LAST_IP, ip), AuthMeColumns.NAME); + } catch (SQLException e) { + logSqlException(e); + return Collections.emptyList(); } - return result; } @Override public int countAuthsByEmail(String email) { - String sql = "SELECT COUNT(1) FROM " + tableName + " WHERE UPPER(" + col.EMAIL + ") = UPPER(?)"; - try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, email); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return rs.getInt(1); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return 0; + return columnsHandler.count(eqIgnoreCase(AuthMeColumns.EMAIL, email)); } @Override @@ -566,18 +536,7 @@ public class MySQL implements DataSource { @Override public int getAccountsRegistered() { - int result = 0; - String sql = "SELECT COUNT(*) FROM " + tableName; - try (Connection con = getConnection(); - Statement st = con.createStatement(); - ResultSet rs = st.executeQuery(sql)) { - if (rs.next()) { - result = rs.getInt(1); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return result; + return columnsHandler.count(new AlwaysTruePredicate<>()); } @Override diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index 0b2361aa8..01f13a50e 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -1,6 +1,7 @@ package fr.xephi.authme.datasource; import ch.jalu.datasourcecolumns.data.DataSourceValues; +import ch.jalu.datasourcecolumns.predicate.AlwaysTruePredicate; import com.google.common.annotations.VisibleForTesting; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.data.auth.PlayerAuth; @@ -20,11 +21,14 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import static ch.jalu.datasourcecolumns.data.UpdateValues.with; +import static ch.jalu.datasourcecolumns.predicate.StandardPredicates.eq; +import static ch.jalu.datasourcecolumns.predicate.StandardPredicates.eqIgnoreCase; import static fr.xephi.authme.datasource.SqlDataSourceUtils.getNullableLong; import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; @@ -211,14 +215,10 @@ public class SQLite implements DataSource { @Override public boolean isAuthAvailable(String user) { - String sql = "SELECT 1 FROM " + tableName + " WHERE LOWER(" + col.NAME + ")=LOWER(?);"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, user); - try (ResultSet rs = pst.executeQuery()) { - return rs.next(); - } - } catch (SQLException ex) { - ConsoleLogger.warning(ex.getMessage()); + try { + return columnsHandler.retrieve(user, AuthMeColumns.NAME).rowExists(); + } catch (SQLException e) { + logSqlException(e); return false; } } @@ -273,19 +273,7 @@ public class SQLite implements DataSource { @Override public boolean updateSession(PlayerAuth auth) { - String sql = "UPDATE " + tableName + " SET " + col.LAST_IP + "=?, " + col.LAST_LOGIN + "=?, " - + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)){ - pst.setString(1, auth.getLastIp()); - pst.setObject(2, auth.getLastLogin()); - pst.setString(3, auth.getRealName()); - pst.setString(4, auth.getNickname()); - pst.executeUpdate(); - return true; - } catch (SQLException ex) { - logSqlException(ex); - } - return false; + return columnsHandler.update(auth, AuthMeColumns.LAST_IP, AuthMeColumns.LAST_LOGIN, AuthMeColumns.NICK_NAME); } @Override @@ -360,36 +348,17 @@ public class SQLite implements DataSource { @Override public List getAllAuthsByIp(String ip) { - List countIp = new ArrayList<>(); - String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_IP + "=?;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, ip); - try (ResultSet rs = pst.executeQuery()) { - while (rs.next()) { - countIp.add(rs.getString(col.NAME)); - } - return countIp; - } - } catch (SQLException ex) { - logSqlException(ex); + try { + return columnsHandler.retrieve(eq(AuthMeColumns.LAST_IP, ip), AuthMeColumns.NAME); + } catch (SQLException e) { + logSqlException(e); + return Collections.emptyList(); } - return new ArrayList<>(); } @Override public int countAuthsByEmail(String email) { - String sql = "SELECT COUNT(1) FROM " + tableName + " WHERE " + col.EMAIL + " = ? COLLATE NOCASE;"; - try (PreparedStatement pst = con.prepareStatement(sql)) { - pst.setString(1, email); - try (ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return rs.getInt(1); - } - } - } catch (SQLException ex) { - logSqlException(ex); - } - return 0; + return columnsHandler.count(eqIgnoreCase(AuthMeColumns.EMAIL, email)); } @Override @@ -491,15 +460,7 @@ public class SQLite implements DataSource { @Override public int getAccountsRegistered() { - String sql = "SELECT COUNT(*) FROM " + tableName + ";"; - try (PreparedStatement pst = con.prepareStatement(sql); ResultSet rs = pst.executeQuery()) { - if (rs.next()) { - return rs.getInt(1); - } - } catch (SQLException ex) { - logSqlException(ex); - } - return 0; + return columnsHandler.count(new AlwaysTruePredicate<>()); } @Override @@ -607,16 +568,6 @@ public class SQLite implements DataSource { + currentTimestamp + ", to all " + updatedRows + " rows"); } - private static void close(Statement st) { - if (st != null) { - try { - st.close(); - } catch (SQLException ex) { - logSqlException(ex); - } - } - } - private static void close(Connection con) { if (con != null) { try { diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumns.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumns.java index 246bf5581..109ea5a63 100644 --- a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumns.java +++ b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumns.java @@ -45,6 +45,9 @@ public final class AuthMeColumns implements DependentColumn GROUP_ID = createInteger( DatabaseSettings.MYSQL_COL_GROUP, PlayerAuth::getGroupId, OPTIONAL); + public static final AuthMeColumns LAST_LOGIN = createLong( + DatabaseSettings.MYSQL_COL_LASTLOGIN, PlayerAuth::getLastLogin); + public static final AuthMeColumns REGISTRATION_IP = createString( DatabaseSettings.MYSQL_COL_REGISTER_IP, PlayerAuth::getRegistrationIp); diff --git a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsHandler.java b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsHandler.java index a35c8c97c..08202e396 100644 --- a/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsHandler.java +++ b/src/main/java/fr/xephi/authme/datasource/columnshandler/AuthMeColumnsHandler.java @@ -3,7 +3,9 @@ package fr.xephi.authme.datasource.columnshandler; import ch.jalu.datasourcecolumns.data.DataSourceValue; import ch.jalu.datasourcecolumns.data.DataSourceValues; import ch.jalu.datasourcecolumns.data.UpdateValues; +import ch.jalu.datasourcecolumns.predicate.Predicate; import ch.jalu.datasourcecolumns.sqlimplementation.PredicateSqlGenerator; +import ch.jalu.datasourcecolumns.sqlimplementation.PreparedStatementGenerator; import ch.jalu.datasourcecolumns.sqlimplementation.ResultSetValueRetriever; import ch.jalu.datasourcecolumns.sqlimplementation.SqlColumnsHandler; import fr.xephi.authme.data.auth.PlayerAuth; @@ -12,6 +14,7 @@ import fr.xephi.authme.settings.properties.DatabaseSettings; import java.sql.Connection; import java.sql.SQLException; +import java.util.List; import static fr.xephi.authme.datasource.SqlDataSourceUtils.logSqlException; @@ -39,8 +42,9 @@ public final class AuthMeColumnsHandler { String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE); String nameColumn = settings.getProperty(DatabaseSettings.MYSQL_COL_NAME); - SqlColumnsHandler sqlColHandler = - new SqlColumnsHandler<>(connection, columnContext, tableName, nameColumn); + SqlColumnsHandler sqlColHandler = new SqlColumnsHandler<>( + PreparedStatementGenerator.fromConnection(connection), columnContext, tableName, nameColumn, + new ResultSetValueRetriever<>(columnContext), new PredicateSqlGenerator<>(columnContext, true)); return new AuthMeColumnsHandler(sqlColHandler); } @@ -135,6 +139,18 @@ public final class AuthMeColumnsHandler { return internalHandler.retrieve(name.toLowerCase(), columns); } + /** + * Retrieves a column's value for all rows that satisfy the given predicate. + * + * @param predicate the predicate to fulfill + * @param column the column to retrieve from the matching rows + * @param the column's value type + * @return the values of the matching rows + */ + public List retrieve(Predicate predicate, AuthMeColumns column) throws SQLException { + return internalHandler.retrieve(predicate, column); + } + /** * Inserts the given values into a new row, as taken from the player auth. * @@ -150,4 +166,19 @@ public final class AuthMeColumnsHandler { return false; } } + + /** + * Returns the number of rows that match the provided predicate. + * + * @param predicate the predicate to test the rows for + * @return number of rows fulfilling the predicate + */ + public int count(Predicate predicate) { + try { + return internalHandler.count(predicate); + } catch (SQLException e) { + logSqlException(e); + return 0; + } + } } diff --git a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java index eab6a4cc4..027608230 100644 --- a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java @@ -55,7 +55,9 @@ public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest { HikariConfig config = new HikariConfig(); config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource"); config.setConnectionTestQuery("VALUES 1"); - config.addDataSourceProperty("URL", "jdbc:h2:mem:test"); + // Note "ignorecase=true": H2 does not support `COLLATE NOCASE` for case-insensitive equals queries. + // MySQL is by default case-insensitive so this is OK to make as an assumption. + config.addDataSourceProperty("URL", "jdbc:h2:mem:test;ignorecase=true"); config.addDataSourceProperty("user", "sa"); config.addDataSourceProperty("password", "sa"); HikariDataSource ds = new HikariDataSource(config);