Signal-Android/app/src/main/java/org/thoughtcrime/securesms/util/SqlUtil.java

147 lines
4.2 KiB
Java

package org.thoughtcrime.securesms.util;
import android.content.ContentValues;
import android.database.Cursor;
import androidx.annotation.NonNull;
import net.sqlcipher.database.SQLiteDatabase;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.util.guava.Preconditions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
public final class SqlUtil {
private SqlUtil() {}
public static boolean tableExists(@NonNull SQLiteDatabase db, @NonNull String table) {
try (Cursor cursor = db.rawQuery("SELECT name FROM sqlite_master WHERE type=? AND name=?", new String[] { "table", table })) {
return cursor != null && cursor.moveToNext();
}
}
public static boolean columnExists(@NonNull SQLiteDatabase db, @NonNull String table, @NonNull String column) {
try (Cursor cursor = db.rawQuery("PRAGMA table_info(" + table + ")", null)) {
int nameColumnIndex = cursor.getColumnIndexOrThrow("name");
while (cursor.moveToNext()) {
String name = cursor.getString(nameColumnIndex);
if (name.equals(column)) {
return true;
}
}
}
return false;
}
public static String[] buildArgs(Object... objects) {
String[] args = new String[objects.length];
for (int i = 0; i < objects.length; i++) {
if (objects[i] == null) {
throw new NullPointerException("Cannot have null arg!");
} else if (objects[i] instanceof RecipientId) {
args[i] = ((RecipientId) objects[i]).serialize();
} else {
args[i] = objects[i].toString();
}
}
return args;
}
/**
* Returns an updated query and args pairing that will only update rows that would *actually*
* change. In other words, if {@link SQLiteDatabase#update(String, ContentValues, String, String[])}
* returns > 0, then you know something *actually* changed.
*/
public static @NonNull Query buildTrueUpdateQuery(@NonNull String selection,
@NonNull String[] args,
@NonNull ContentValues contentValues)
{
StringBuilder qualifier = new StringBuilder();
Set<Map.Entry<String, Object>> valueSet = contentValues.valueSet();
List<String> fullArgs = new ArrayList<>(args.length + valueSet.size());
fullArgs.addAll(Arrays.asList(args));
int i = 0;
for (Map.Entry<String, Object> entry : valueSet) {
if (entry.getValue() != null) {
qualifier.append(entry.getKey()).append(" != ? OR ").append(entry.getKey()).append(" IS NULL");
fullArgs.add(String.valueOf(entry.getValue()));
} else {
qualifier.append(entry.getKey()).append(" NOT NULL");
}
if (i != valueSet.size() - 1) {
qualifier.append(" OR ");
}
i++;
}
return new Query("(" + selection + ") AND (" + qualifier + ")", fullArgs.toArray(new String[0]));
}
public static @NonNull Query buildCollectionQuery(@NonNull String column, @NonNull Collection<? extends Object> values) {
Preconditions.checkArgument(values.size() > 0);
StringBuilder query = new StringBuilder();
Object[] args = new Object[values.size()];
int i = 0;
for (Object value : values) {
query.append("?");
args[i] = value;
if (i != values.size() - 1) {
query.append(", ");
}
i++;
}
return new Query(column + " IN (" + query.toString() + ")", buildArgs(args));
}
public static String[] appendArg(@NonNull String[] args, String addition) {
String[] output = new String[args.length + 1];
System.arraycopy(args, 0, output, 0, args.length);
output[output.length - 1] = addition;
return output;
}
public static class Query {
private final String where;
private final String[] whereArgs;
private Query(@NonNull String where, @NonNull String[] whereArgs) {
this.where = where;
this.whereArgs = whereArgs;
}
public String getWhere() {
return where;
}
public String[] getWhereArgs() {
return whereArgs;
}
}
}