Use prepared sql statements

This commit is contained in:
Arnaud Vergnet 2021-01-08 11:31:52 +01:00
parent 68125c7c92
commit 728d65f220

View file

@ -186,7 +186,6 @@ public class DatabaseController {
dropTables(() -> initTables(callback, errorCallback), errorCallback);
}
/**
* Fetches the list of users for which we already have a chat history
*
@ -232,82 +231,6 @@ public class DatabaseController {
executor.start();
}
/**
* Adds a message to the database for this user.
* If the user does not exist, we create it.
*
* @param message The message to add to the database
* @param callback Function called when the request is done
* @param errorCallback The function to call on error
*/
public void addMessage(Message message, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
// Insert the correspondent if not already in the database
Log.v(getClass().getSimpleName(), "Inserting correspondent into db... ");
addUser(message.getCorrespondent(), () -> {
// Handle messages containing a file
String filePath = "NULL";
if (message instanceof FileMessage) {
filePath = "'" + ((FileMessage) message).getPath() + "'";
}
String recipientId = message.getRecipient().id;
String senderId = message.getSender().id;
// Insert the new message
@Language("SQL") String sql = "INSERT INTO message " +
"(timestamp, sender, recipient, text, file_path) " +
"VALUES (" +
message.getDate().getTime() + ", " +
"'" + senderId + "', " +
"'" + recipientId + "', " +
"'" + message.getText() + "', " +
filePath +
")";
Log.v(getClass().getSimpleName(), "Inserting message into db... ");
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
executor.start();
}, errorCallback);
}
/**
* Inserts the given user if not existing
*
* @param user The user information to store
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
public void addUser(UserInformation user, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql;
if (user.getUsername() != null) {
sql = "INSERT OR IGNORE INTO user (id, username) " +
"VALUES ('" + user.id + "', '" + user.getUsername() + "')";
} else {
sql = "INSERT OR IGNORE INTO user (id) " +
"VALUES ('" + user.id + "')";
}
Log.v(getClass().getSimpleName(), "Adding user to db: " + user.id + " / " + user.getUsername());
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
executor.start();
}
public void addCurrentUser(UserInformation user, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql;
if (user.getUsername() != null) {
sql = "INSERT OR IGNORE INTO current_user (id, username) " +
"VALUES ('" + user.id + "', '" + user.getUsername() + "')";
} else {
sql = "INSERT OR IGNORE INTO current_user (id) " +
"VALUES ('" + user.id + "')";
}
Log.v(getClass().getSimpleName(), "Adding current_user to db: " + user.id + " / " + user.getUsername());
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
executor.start();
}
/**
* Gets the chat history for a given time frame
*
@ -319,20 +242,14 @@ public class DatabaseController {
* @param errorCallback The function to call on error
*/
public void getChatHistory(UserInformation user1, UserInformation user2, Date from, Date to, HistoryCallback callback, ErrorCallback errorCallback) {
// TODO update to search in current_user table as well
@Language("SQL") String sql =
"SELECT timestamp," +
" sender," +
" recipient," +
" text," +
" file_path " +
"FROM message WHERE (sender = '" + user1.id + "'" +
" OR recipient = '" + user1.id + "')" +
" AND timestamp > " + from.getTime() + " AND timestamp < " + to.getTime() + " " +
"SELECT timestamp, sender, recipient, text, file_path " +
"FROM message WHERE (sender = ? OR recipient = ?)" +
" AND timestamp > ? AND timestamp < ? " +
"ORDER BY timestamp";
Log.v(getClass().getSimpleName(), "Fetching chat history from db... ");
QueryExecutor executor = new QueryExecutor(sql, res -> {
executeGetChatHistory(user1, from, to, sql, res -> {
ArrayList<Message> chatHistory = new ArrayList<>();
while (res.next()) {
Date date = new Date(res.getTimestamp("timestamp").getTime());
@ -365,20 +282,141 @@ public class DatabaseController {
Log.v(getClass().getSimpleName(), chatHistory.size() + " messages fetched");
callback.onHistoryFetched(chatHistory);
}, errorCallback);
}
private void executeGetChatHistory(UserInformation user, Date from, Date to, @Language("SQL") String sql, QueryCallback callback, ErrorCallback errorCallback) {
try {
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, user.id);
preparedStatement.setString(2, user.id);
preparedStatement.setLong(3, from.getTime());
preparedStatement.setLong(4, to.getTime());
QueryExecutor executor = new QueryExecutor(
preparedStatement,
callback,
errorCallback);
executor.start();
} catch (SQLException e) {
Log.e(this.getClass().getSimpleName(), "Could not prepare statement: ", e);
errorCallback.onError(e);
}
}
/**
* Adds a message to the database for this user.
* If the user does not exist, we create it.
*
* @param message The message to add to the database
* @param callback Function called when the request is done
* @param errorCallback The function to call on error
*/
public void addMessage(Message message, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
// Insert the correspondent if not already in the database
Log.v(getClass().getSimpleName(), "Inserting correspondent into db... ");
addUser(message.getCorrespondent(), () -> {
// Handle messages containing a file
String filePath = null;
if (message instanceof FileMessage) {
filePath = "'" + ((FileMessage) message).getPath() + "'";
}
@Language("SQL") String sql = "INSERT INTO message " +
"(timestamp, sender, recipient, text, file_path) VALUES (?, ?, ?, ?, ?)";
Log.v(getClass().getSimpleName(), "Inserting message into db... ");
executeAddMessage(message, filePath, sql, callback, errorCallback);
}, errorCallback);
}
private void executeAddMessage(Message message, String filePath, @Language("SQL") String sql, @Nullable UpdateCallback callback, ErrorCallback errorCallback) {
try {
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setLong(1, message.getDate().getTime());
preparedStatement.setString(2, message.getSender().id);
preparedStatement.setString(3, message.getRecipient().id);
preparedStatement.setString(4, message.getText());
preparedStatement.setString(5, filePath);
UpdateExecutor executor = new UpdateExecutor(
preparedStatement,
callback,
errorCallback);
executor.start();
} catch (SQLException e) {
Log.e(this.getClass().getSimpleName(), "Could not prepare statement: ", e);
errorCallback.onError(e);
}
}
/**
* Inserts the given user if not existing
*
* @param user The user information to store
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
public void addUser(UserInformation user, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql;
if (user.getUsername() != null) {
sql = "INSERT OR IGNORE INTO user (id, username) VALUES (?, ?)";
} else {
sql = "INSERT OR IGNORE INTO user (id) VALUES (?)";
}
Log.v(getClass().getSimpleName(), "Adding user to db: " + user.id + " / " + user.getUsername());
executeAddUser(user, sql, callback, errorCallback);
}
public void addCurrentUser(UserInformation user, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql;
if (user.getUsername() != null) {
sql = "INSERT OR IGNORE INTO current_user (id, username) VALUES (?, ?)";
} else {
sql = "INSERT OR IGNORE INTO current_user (id) VALUES (?)";
}
Log.v(getClass().getSimpleName(), "Adding current_user to db: " + user.id + " / " + user.getUsername());
executeAddUser(user, sql, callback, errorCallback);
}
private void executeAddUser(UserInformation user, @Language("SQL") String sql, @Nullable UpdateCallback callback, ErrorCallback errorCallback) {
try {
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, user.id);
if (user.getUsername() != null) {
preparedStatement.setString(2, user.getUsername());
}
UpdateExecutor executor = new UpdateExecutor(
preparedStatement,
callback,
errorCallback);
executor.start();
} catch (SQLException e) {
Log.e(this.getClass().getSimpleName(), "Could not prepare statement: ", e);
errorCallback.onError(e);
}
}
public void updateUsername(UserInformation user, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql = "UPDATE user SET username = '" + user.getUsername() + "' where id = '" + user.id + "'";
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
executor.start();
@Language("SQL") String sql = "UPDATE user SET username = ? where id = ?";
executeUsernameUpdate(user, sql, callback, errorCallback);
}
public void updateCurrentUsername(UserInformation user, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql = "UPDATE current_user SET username = '" + user.getUsername() + "' where id = '" + user.id + "'";
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
@Language("SQL") String sql = "UPDATE current_user SET username = ? where id = ?";
executeUsernameUpdate(user, sql, callback, errorCallback);
}
private void executeUsernameUpdate(UserInformation user, @Language("SQL") String sql, @Nullable UpdateCallback callback, ErrorCallback errorCallback) {
try {
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, user.getUsername());
preparedStatement.setString(2, user.id);
UpdateExecutor executor = new UpdateExecutor(
preparedStatement,
callback,
errorCallback);
executor.start();
} catch (SQLException e) {
Log.e(this.getClass().getSimpleName(), "Could not prepare statement: ", e);
errorCallback.onError(e);
}
}
public interface UsersCallback {
@ -389,11 +427,6 @@ public class DatabaseController {
void onFetched(UserInformation user);
}
public interface UsernameCallback {
void onUsernameFetched(String username);
}
public interface HistoryCallback {
void onHistoryFetched(ArrayList<Message> history);
}
@ -408,6 +441,7 @@ public class DatabaseController {
private class UpdateExecutor extends Thread {
private final String sqlQuery;
private final PreparedStatement preparedStatement;
private final UpdateCallback callback;
private final ErrorCallback errorCallback;
@ -419,18 +453,33 @@ public class DatabaseController {
* @param errorCallback The function to call on error
*/
public UpdateExecutor(@Language("SQL") String sqlQuery, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
this.preparedStatement = null;
this.sqlQuery = sqlQuery;
this.callback = callback;
this.errorCallback = errorCallback;
}
public UpdateExecutor(PreparedStatement preparedStatement, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
this.preparedStatement = preparedStatement;
this.sqlQuery = null;
this.callback = callback;
this.errorCallback = errorCallback;
}
@Override
public void run() {
try {
int rowsModified;
if (preparedStatement == null) {
Statement statement = connection.createStatement();
final int rowsModified = statement.executeUpdate(sqlQuery);
Log.v(getClass().getSimpleName(), rowsModified + " rows modified");
rowsModified = statement.executeUpdate(sqlQuery);
statement.close();
} else {
rowsModified = preparedStatement.executeUpdate();
preparedStatement.close();
}
Log.v(getClass().getSimpleName(), rowsModified + " rows modified");
if (callback != null) {
callback.onUpdateExecuted();
}
@ -443,6 +492,7 @@ public class DatabaseController {
private class QueryExecutor extends Thread {
private final String sqlQuery;
private final PreparedStatement preparedStatement;
private final QueryCallback callback;
private final ErrorCallback errorCallback;
@ -454,21 +504,40 @@ public class DatabaseController {
* @param errorCallback The function to call on error
*/
public QueryExecutor(@Language("SQL") String sqlQuery, @Nullable QueryCallback callback, ErrorCallback errorCallback) {
this.preparedStatement = null;
this.sqlQuery = sqlQuery;
this.callback = callback;
this.errorCallback = errorCallback;
}
public QueryExecutor(PreparedStatement preparedStatement, @Nullable QueryCallback callback, ErrorCallback errorCallback) {
this.preparedStatement = preparedStatement;
this.sqlQuery = null;
this.callback = callback;
this.errorCallback = errorCallback;
}
@Override
public void run() {
try {
Statement statement = connection.createStatement();
final ResultSet resultSet = statement.executeQuery(sqlQuery);
Statement statement = null;
final ResultSet resultSet;
if (preparedStatement == null) {
statement = connection.createStatement();
resultSet = statement.executeQuery(sqlQuery);
} else {
resultSet = preparedStatement.executeQuery();
}
if (callback != null) {
callback.onQueryExecuted(resultSet);
}
resultSet.close();
if (statement != null) {
statement.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
} catch (SQLException e) {
Log.e(this.getClass().getSimpleName(), "Error executing update: ", e);
errorCallback.onError(e);