Merge branch 'fix-511--database-constants-everywhere' into 'master'

Ensure database fields referred to by `Schema.*Table.Cols.*` constants

**This is based on top of !346.** When that is merged, I'll rebase this again and then remove the WIP.

The goal of this is to ensure that all string literals which refer to database columns are replaced with constants from the relevant `Schema.*Table.Cols` interface.

The only exceptions are fields which no longer exist and are referred to in the `DBHelper` class (e.g. the `fdroid_repo` table had an `id` column but that is now `_id`).

This should not change **any** behaviour in the client app, all semantics should stay **exactly** the same.

See merge request !347
This commit is contained in:
Daniel Martí 2016-07-04 12:50:09 +00:00
commit e38624626c
9 changed files with 240 additions and 254 deletions

View File

@ -199,7 +199,7 @@ public class RepoUpdater {
reader.setContentHandler(repoXMLHandler); reader.setContentHandler(repoXMLHandler);
reader.parse(new InputSource(indexInputStream)); reader.parse(new InputSource(indexInputStream));
long timestamp = repoDetailsToSave.getAsLong("timestamp"); long timestamp = repoDetailsToSave.getAsLong(RepoTable.Cols.TIMESTAMP);
if (timestamp < repo.timestamp) { if (timestamp < repo.timestamp) {
throw new UpdateException(repo, "index.jar is older that current index! " throw new UpdateException(repo, "index.jar is older that current index! "
+ timestamp + " < " + repo.timestamp); + timestamp + " < " + repo.timestamp);

View File

@ -350,8 +350,8 @@ public class ApkProvider extends FDroidProvider {
appendField("rowid", "apk", "_id"); appendField("rowid", "apk", "_id");
} else if (field.equals(Cols._COUNT)) { } else if (field.equals(Cols._COUNT)) {
appendField("COUNT(*) AS " + Cols._COUNT); appendField("COUNT(*) AS " + Cols._COUNT);
} else if (field.equals(Cols._COUNT_DISTINCT_ID)) { } else if (field.equals(Cols._COUNT_DISTINCT)) {
appendField("COUNT(DISTINCT apk.id) AS " + Cols._COUNT_DISTINCT_ID); appendField("COUNT(DISTINCT apk." + Cols.PACKAGE_NAME + ") AS " + Cols._COUNT_DISTINCT);
} else { } else {
appendField(field, "apk"); appendField(field, "apk");
} }
@ -360,7 +360,7 @@ public class ApkProvider extends FDroidProvider {
private void addRepoField(String field, String alias) { private void addRepoField(String field, String alias) {
if (!repoTableRequired) { if (!repoTableRequired) {
repoTableRequired = true; repoTableRequired = true;
leftJoin(RepoTable.NAME, "repo", "apk.repo = repo._id"); leftJoin(RepoTable.NAME, "repo", "apk." + Cols.REPO_ID + " = repo." + RepoTable.Cols._ID);
} }
appendField(field, "repo", alias); appendField(field, "repo", alias);
} }
@ -374,7 +374,7 @@ public class ApkProvider extends FDroidProvider {
} }
private QuerySelection querySingle(Uri uri) { private QuerySelection querySingle(Uri uri) {
final String selection = " vercode = ? and id = ? "; final String selection = Cols.VERSION_CODE + " = ? and " + Cols.PACKAGE_NAME + " = ? ";
final String[] args = { final String[] args = {
// First (0th) path segment is the word "apk", // First (0th) path segment is the word "apk",
// and we are not interested in it. // and we are not interested in it.
@ -412,7 +412,7 @@ public class ApkProvider extends FDroidProvider {
if (i != 0) { if (i != 0) {
sb.append(" OR "); sb.append(" OR ");
} }
sb.append(" ( id = ? AND vercode = ? ) "); sb.append(" ( " + Cols.PACKAGE_NAME + " = ? AND " + Cols.VERSION_CODE + " = ? ) ");
} }
return new QuerySelection(sb.toString(), args); return new QuerySelection(sb.toString(), args);
} }

View File

@ -247,8 +247,8 @@ public class AppProvider extends FDroidProvider {
final String repo = RepoTable.NAME; final String repo = RepoTable.NAME;
return app + return app +
" LEFT JOIN " + apk + " ON ( " + apk + ".id = " + app + ".id ) " + " LEFT JOIN " + apk + " ON (" + apk + "." + ApkTable.Cols.PACKAGE_NAME + " = " + app + "." + Cols.PACKAGE_NAME + ") " +
" LEFT JOIN " + repo + " ON ( " + apk + ".repo = " + repo + "._id )"; " LEFT JOIN " + repo + " ON (" + apk + "." + ApkTable.Cols.REPO_ID + " = " + repo + "." + RepoTable.Cols._ID + ") ";
} }
@Override @Override
@ -259,7 +259,7 @@ public class AppProvider extends FDroidProvider {
@Override @Override
protected String groupBy() { protected String groupBy() {
// If the count field has been requested, then we want to group all rows together. // If the count field has been requested, then we want to group all rows together.
return countFieldAppended ? null : getTableName() + ".id"; return countFieldAppended ? null : getTableName() + "." + Cols.PACKAGE_NAME;
} }
public void addSelection(AppQuerySelection selection) { public void addSelection(AppQuerySelection selection) {
@ -276,7 +276,7 @@ public class AppProvider extends FDroidProvider {
join( join(
InstalledAppTable.NAME, InstalledAppTable.NAME,
"installed", "installed",
"installed." + InstalledAppTable.Cols.PACKAGE_NAME + " = " + getTableName() + ".id"); "installed." + InstalledAppTable.Cols.PACKAGE_NAME + " = " + getTableName() + "." + Cols.PACKAGE_NAME);
requiresInstalledTable = true; requiresInstalledTable = true;
} }
} }
@ -286,7 +286,7 @@ public class AppProvider extends FDroidProvider {
leftJoin( leftJoin(
InstalledAppTable.NAME, InstalledAppTable.NAME,
"installed", "installed",
"installed." + InstalledAppTable.Cols.PACKAGE_NAME + " = " + getTableName() + ".id"); "installed." + InstalledAppTable.Cols.PACKAGE_NAME + " = " + getTableName() + "." + Cols.PACKAGE_NAME);
requiresInstalledTable = true; requiresInstalledTable = true;
} }
} }
@ -320,7 +320,7 @@ public class AppProvider extends FDroidProvider {
private void appendCountField() { private void appendCountField() {
countFieldAppended = true; countFieldAppended = true;
appendField("COUNT( DISTINCT " + getTableName() + ".id ) AS " + Cols._COUNT); appendField("COUNT( DISTINCT " + getTableName() + "." + Cols.PACKAGE_NAME + " ) AS " + Cols._COUNT);
} }
private void addSuggestedApkVersionField() { private void addSuggestedApkVersionField() {
@ -335,7 +335,7 @@ public class AppProvider extends FDroidProvider {
leftJoin( leftJoin(
getApkTableName(), getApkTableName(),
"suggestedApk", "suggestedApk",
getTableName() + ".suggestedVercode = suggestedApk.vercode AND " + getTableName() + ".id = suggestedApk.id"); getTableName() + "." + Cols.SUGGESTED_VERSION_CODE + " = suggestedApk." + ApkTable.Cols.VERSION_CODE + " AND " + getTableName() + "." + Cols.PACKAGE_NAME + " = suggestedApk." + ApkTable.Cols.PACKAGE_NAME);
} }
appendField(fieldName, "suggestedApk", alias); appendField(fieldName, "suggestedApk", alias);
} }
@ -547,15 +547,16 @@ public class AppProvider extends FDroidProvider {
} }
private AppQuerySelection queryCanUpdate() { private AppQuerySelection queryCanUpdate() {
final String ignoreCurrent = getTableName() + ".ignoreThisUpdate != " + getTableName() + ".suggestedVercode "; final String app = getTableName();
final String ignoreAll = getTableName() + ".ignoreAllUpdates != 1 "; final String ignoreCurrent = app + "." + Cols.IGNORE_THISUPDATE + "!= " + app + "." + Cols.SUGGESTED_VERSION_CODE;
final String ignore = " ( " + ignoreCurrent + " AND " + ignoreAll + " ) "; final String ignoreAll = app + "." + Cols.IGNORE_ALLUPDATES + " != 1";
final String where = ignore + " AND " + getTableName() + "." + Cols.SUGGESTED_VERSION_CODE + " > installed.versionCode"; final String ignore = " (" + ignoreCurrent + " AND " + ignoreAll + ") ";
final String where = ignore + " AND " + app + "." + Cols.SUGGESTED_VERSION_CODE + " > installed." + InstalledAppTable.Cols.VERSION_CODE;
return new AppQuerySelection(where).requireNaturalInstalledTable(); return new AppQuerySelection(where).requireNaturalInstalledTable();
} }
private AppQuerySelection queryRepo(long repoId) { private AppQuerySelection queryRepo(long repoId) {
final String selection = getApkTableName() + ".repo = ? "; final String selection = getApkTableName() + "." + ApkTable.Cols.REPO_ID + " = ? ";
final String[] args = {String.valueOf(repoId)}; final String[] args = {String.valueOf(repoId)};
return new AppQuerySelection(selection, args); return new AppQuerySelection(selection, args);
} }
@ -580,11 +581,12 @@ public class AppProvider extends FDroidProvider {
iKeyword++; iKeyword++;
} }
final String app = getTableName();
final String[] columns = { final String[] columns = {
getTableName() + ".id", app + "." + Cols.PACKAGE_NAME,
getTableName() + ".name", app + "." + Cols.NAME,
getTableName() + ".summary", app + "." + Cols.SUMMARY,
getTableName() + ".description", app + "." + Cols.DESCRIPTION,
}; };
// Build selection string and fill out keyword arguments // Build selection string and fill out keyword arguments
@ -596,7 +598,7 @@ public class AppProvider extends FDroidProvider {
if (firstColumn) { if (firstColumn) {
firstColumn = false; firstColumn = false;
} else { } else {
selection.append("OR "); selection.append(" OR ");
} }
selection.append('('); selection.append('(');
boolean firstKeyword = true; boolean firstKeyword = true;
@ -606,7 +608,7 @@ public class AppProvider extends FDroidProvider {
} else { } else {
selection.append(" AND "); selection.append(" AND ");
} }
selection.append(column).append(" like ?"); selection.append(column).append(" LIKE ?");
selectionKeywords[iKeyword] = keyword; selectionKeywords[iKeyword] = keyword;
iKeyword++; iKeyword++;
} }
@ -616,15 +618,15 @@ public class AppProvider extends FDroidProvider {
} }
protected AppQuerySelection querySingle(String packageName) { protected AppQuerySelection querySingle(String packageName) {
final String selection = getTableName() + ".id = ?"; final String selection = getTableName() + "." + Cols.PACKAGE_NAME + " = ?";
final String[] args = {packageName}; final String[] args = {packageName};
return new AppQuerySelection(selection, args); return new AppQuerySelection(selection, args);
} }
private AppQuerySelection queryIgnored() { private AppQuerySelection queryIgnored() {
final String table = getTableName(); final String table = getTableName();
final String selection = table + ".ignoreAllUpdates = 1 OR " + final String selection = table + "." + Cols.IGNORE_ALLUPDATES + " = 1 OR " +
table + ".ignoreThisUpdate >= " + table + ".suggestedVercode"; table + "." + Cols.IGNORE_THISUPDATE + " >= " + table + "." + Cols.SUGGESTED_VERSION_CODE;
return new AppQuerySelection(selection); return new AppQuerySelection(selection);
} }
@ -632,19 +634,21 @@ public class AppProvider extends FDroidProvider {
// fdroid_repo will have null fields if the LEFT JOIN didn't resolve, e.g. due to there // fdroid_repo will have null fields if the LEFT JOIN didn't resolve, e.g. due to there
// being no apks for the app in the result set. In that case, we can't tell if it is from // being no apks for the app in the result set. In that case, we can't tell if it is from
// a swap repo or not. // a swap repo or not.
final String selection = " fdroid_repo.isSwap = 0 OR fdroid_repo.isSwap is null "; final String isSwap = RepoTable.NAME + "." + RepoTable.Cols.IS_SWAP;
final String selection = isSwap + " = 0 OR " + isSwap + " IS NULL";
return new AppQuerySelection(selection); return new AppQuerySelection(selection);
} }
private AppQuerySelection queryNewlyAdded() { private AppQuerySelection queryNewlyAdded() {
final String selection = getTableName() + ".added > ?"; final String selection = getTableName() + "." + Cols.ADDED + " > ?";
final String[] args = {Utils.formatDate(Preferences.get().calcMaxHistory(), "")}; final String[] args = {Utils.formatDate(Preferences.get().calcMaxHistory(), "")};
return new AppQuerySelection(selection, args); return new AppQuerySelection(selection, args);
} }
private AppQuerySelection queryRecentlyUpdated() { private AppQuerySelection queryRecentlyUpdated() {
final String app = getTableName(); final String app = getTableName();
final String selection = app + ".added != " + app + ".lastUpdated AND " + app + ".lastUpdated > ?"; final String lastUpdated = app + "." + Cols.LAST_UPDATED;
final String selection = app + "." + Cols.ADDED + " != " + lastUpdated + " AND " + lastUpdated + " > ?";
final String[] args = {Utils.formatDate(Preferences.get().calcMaxHistory(), "")}; final String[] args = {Utils.formatDate(Preferences.get().calcMaxHistory(), "")};
return new AppQuerySelection(selection, args); return new AppQuerySelection(selection, args);
} }
@ -652,11 +656,12 @@ public class AppProvider extends FDroidProvider {
private AppQuerySelection queryCategory(String category) { private AppQuerySelection queryCategory(String category) {
// TODO: In the future, add a new table for categories, // TODO: In the future, add a new table for categories,
// so we can join onto it. // so we can join onto it.
final String app = getTableName();
final String selection = final String selection =
getTableName() + ".categories = ? OR " + // Only category e.g. "internet" app + "." + Cols.CATEGORIES + " = ? OR " + // Only category e.g. "internet"
getTableName() + ".categories LIKE ? OR " + // First category e.g. "internet,%" app + "." + Cols.CATEGORIES + " LIKE ? OR " + // First category e.g. "internet,%"
getTableName() + ".categories LIKE ? OR " + // Last category e.g. "%,internet" app + "." + Cols.CATEGORIES + " LIKE ? OR " + // Last category e.g. "%,internet"
getTableName() + ".categories LIKE ? "; // One of many categories e.g. "%,internet,%" app + "." + Cols.CATEGORIES + " LIKE ? "; // One of many categories e.g. "%,internet,%"
final String[] args = { final String[] args = {
category, category,
category + ",%", category + ",%",
@ -667,18 +672,20 @@ public class AppProvider extends FDroidProvider {
} }
private AppQuerySelection queryNoApks() { private AppQuerySelection queryNoApks() {
String selection = "(SELECT COUNT(*) FROM " + getApkTableName() + " WHERE " + getApkTableName() + ".id = " + getTableName() + ".id) = 0"; final String apk = getApkTableName();
final String app = getTableName();
String selection = "(SELECT COUNT(*) FROM " + apk + " WHERE " + apk + "." + ApkTable.Cols.PACKAGE_NAME + " = " + app + "." + Cols.PACKAGE_NAME + ") = 0";
return new AppQuerySelection(selection); return new AppQuerySelection(selection);
} }
static AppQuerySelection queryApps(String packageNames, String idField) { static AppQuerySelection queryApps(String packageNames, String packageNameField) {
String[] args = packageNames.split(","); String[] args = packageNames.split(",");
String selection = idField + " IN (" + generateQuestionMarksForInClause(args.length) + ")"; String selection = packageNameField + " IN (" + generateQuestionMarksForInClause(args.length) + ")";
return new AppQuerySelection(selection, args); return new AppQuerySelection(selection, args);
} }
private AppQuerySelection queryApps(String packageNames) { private AppQuerySelection queryApps(String packageNames) {
return queryApps(packageNames, getTableName() + ".id"); return queryApps(packageNames, getTableName() + "." + Cols.PACKAGE_NAME);
} }
@Override @Override
@ -749,13 +756,13 @@ public class AppProvider extends FDroidProvider {
break; break;
case RECENTLY_UPDATED: case RECENTLY_UPDATED:
sortOrder = getTableName() + ".lastUpdated DESC"; sortOrder = getTableName() + "." + Cols.LAST_UPDATED + " DESC";
selection = selection.add(queryRecentlyUpdated()); selection = selection.add(queryRecentlyUpdated());
includeSwap = false; includeSwap = false;
break; break;
case NEWLY_ADDED: case NEWLY_ADDED:
sortOrder = getTableName() + ".added DESC"; sortOrder = getTableName() + "." + Cols.ADDED + " DESC";
selection = selection.add(queryNewlyAdded()); selection = selection.add(queryNewlyAdded());
includeSwap = false; includeSwap = false;
break; break;
@ -846,26 +853,18 @@ public class AppProvider extends FDroidProvider {
/** /**
* For each app, we want to set the isCompatible flag to 1 if any of the apks we know * For each app, we want to set the isCompatible flag to 1 if any of the apks we know
* about are compatible, and 0 otherwise. * about are compatible, and 0 otherwise.
*
* Readable SQL code:
*
* UPDATE fdroid_app SET compatible = (
* SELECT TOTAL( fdroid_apk.compatible ) > 0
* FROM fdroid_apk
* WHERE fdroid_apk.id = fdroid_app.id );
*/ */
private void updateCompatibleFlags() { private void updateCompatibleFlags() {
Utils.debugLog(TAG, "Calculating whether apps are compatible, based on whether any of their apks are compatible"); Utils.debugLog(TAG, "Calculating whether apps are compatible, based on whether any of their apks are compatible");
final String apk = getApkTableName(); final String apk = getApkTableName();
final String app = getTableName(); final String app = getTableName();
String updateSql = String updateSql =
"UPDATE " + app + " SET compatible = ( " + "UPDATE " + app + " SET " + Cols.IS_COMPATIBLE + " = ( " +
" SELECT TOTAL( " + apk + ".compatible ) > 0 " + " SELECT TOTAL( " + apk + "." + ApkTable.Cols.IS_COMPATIBLE + ") > 0 " +
" FROM " + apk + " FROM " + apk +
" WHERE " + apk + ".id = " + app + ".id );"; " WHERE " + apk + "." + ApkTable.Cols.PACKAGE_NAME + " = " + app + "." + Cols.PACKAGE_NAME + " );";
db().execSQL(updateSql); db().execSQL(updateSql);
} }
@ -875,38 +874,24 @@ public class AppProvider extends FDroidProvider {
* with the closest version code to that, without going over. * with the closest version code to that, without going over.
* If the app is not compatible at all (i.e. no versions were compatible) * If the app is not compatible at all (i.e. no versions were compatible)
* then we take the highest, otherwise we take the highest compatible version. * then we take the highest, otherwise we take the highest compatible version.
*
* Readable SQL code:
*
* UPDATE fdroid_app
* SET suggestedVercode = (
* SELECT MAX(fdroid_apk.vercode)
* FROM fdroid_apk
* WHERE
* fdroid_app.id = fdroid_apk.id AND
* fdroid_apk.vercode <= fdroid_app.upstreamVercode AND
* ( fdroid_app.compatible = 0 OR fdroid_apk.compatible = 1 )
* )
* WHERE upstreamVercode > 0
*/ */
private void updateSuggestedFromUpstream() { private void updateSuggestedFromUpstream() {
Utils.debugLog(TAG, "Calculating suggested versions for all apps which specify an upstream version code."); Utils.debugLog(TAG, "Calculating suggested versions for all apps which specify an upstream version code.");
final String apk = getApkTableName(); final String apk = getApkTableName();
final String app = getTableName(); final String app = getTableName();
final boolean unstableUpdates = Preferences.get().getUnstableUpdates(); final boolean unstableUpdates = Preferences.get().getUnstableUpdates();
String restrictToStable = unstableUpdates ? "" : (apk + ".vercode <= " + app + ".upstreamVercode AND "); String restrictToStable = unstableUpdates ? "" : (apk + "." + ApkTable.Cols.VERSION_CODE + " <= " + app + "." + Cols.UPSTREAM_VERSION_CODE + " AND ");
String updateSql = String updateSql =
"UPDATE " + app + " SET suggestedVercode = ( " + "UPDATE " + app + " SET " + Cols.SUGGESTED_VERSION_CODE + " = ( " +
" SELECT MAX( " + apk + ".vercode ) " + " SELECT MAX( " + apk + "." + ApkTable.Cols.VERSION_CODE + " ) " +
" FROM " + apk + " FROM " + apk +
" WHERE " + " WHERE " +
app + ".id = " + apk + ".id AND " + app + "." + Cols.PACKAGE_NAME + " = " + apk + "." + ApkTable.Cols.PACKAGE_NAME + " AND " +
restrictToStable + restrictToStable +
" ( " + app + ".compatible = 0 OR " + apk + ".compatible = 1 ) ) " + " ( " + app + "." + Cols.IS_COMPATIBLE + " = 0 OR " + apk + "." + Cols.IS_COMPATIBLE + " = 1 ) ) " +
" WHERE upstreamVercode > 0 "; " WHERE " + Cols.UPSTREAM_VERSION_CODE + " > 0 ";
db().execSQL(updateSql); db().execSQL(updateSql);
} }
@ -918,33 +903,21 @@ public class AppProvider extends FDroidProvider {
* If the suggested version is null, it means that we could not figure it * If the suggested version is null, it means that we could not figure it
* out from the upstream vercode. In such a case, fall back to the simpler * out from the upstream vercode. In such a case, fall back to the simpler
* algorithm as if upstreamVercode was 0. * algorithm as if upstreamVercode was 0.
*
* Readable SQL code:
*
* UPDATE fdroid_app SET suggestedVercode = (
* SELECT MAX(fdroid_apk.vercode)
* FROM fdroid_apk
* WHERE
* fdroid_app.id = fdroid_apk.id AND
* ( fdroid_app.compatible = 0 OR fdroid_apk.compatible = 1 )
* )
* WHERE upstreamVercode = 0 OR upstreamVercode IS NULL OR suggestedVercode IS NULL;
*/ */
private void updateSuggestedFromLatest() { private void updateSuggestedFromLatest() {
Utils.debugLog(TAG, "Calculating suggested versions for all apps which don't specify an upstream version code."); Utils.debugLog(TAG, "Calculating suggested versions for all apps which don't specify an upstream version code.");
final String apk = getApkTableName(); final String apk = getApkTableName();
final String app = getTableName(); final String app = getTableName();
String updateSql = String updateSql =
"UPDATE " + app + " SET suggestedVercode = ( " + "UPDATE " + app + " SET " + Cols.SUGGESTED_VERSION_CODE + " = ( " +
" SELECT MAX( " + apk + ".vercode ) " + " SELECT MAX( " + apk + "." + ApkTable.Cols.VERSION_CODE + " ) " +
" FROM " + apk + " FROM " + apk +
" WHERE " + " WHERE " +
app + ".id = " + apk + ".id AND " + app + "." + Cols.PACKAGE_NAME + " = " + apk + "." + ApkTable.Cols.PACKAGE_NAME + " AND " +
" ( " + app + ".compatible = 0 OR " + apk + ".compatible = 1 ) ) " + " ( " + app + "." + Cols.IS_COMPATIBLE + " = 0 OR " + apk + "." + ApkTable.Cols.IS_COMPATIBLE + " = 1 ) ) " +
" WHERE upstreamVercode = 0 OR upstreamVercode IS NULL OR suggestedVercode IS NULL "; " WHERE " + Cols.UPSTREAM_VERSION_CODE + " = 0 OR " + Cols.UPSTREAM_VERSION_CODE + " IS NULL OR " + Cols.SUGGESTED_VERSION_CODE + " IS NULL ";
db().execSQL(updateSql); db().execSQL(updateSql);
} }
@ -958,8 +931,7 @@ public class AppProvider extends FDroidProvider {
final String iconsDir = Utils.getIconsDir(context, 1.0); final String iconsDir = Utils.getIconsDir(context, 1.0);
final String iconsDirLarge = Utils.getIconsDir(context, 1.5); final String iconsDirLarge = Utils.getIconsDir(context, 1.5);
String repoVersion = Integer.toString(Repo.VERSION_DENSITY_SPECIFIC_ICONS); String repoVersion = Integer.toString(Repo.VERSION_DENSITY_SPECIFIC_ICONS);
Utils.debugLog(TAG, "Updating icon paths for apps belonging to repos with version >= " Utils.debugLog(TAG, "Updating icon paths for apps belonging to repos with version >= " + repoVersion);
+ repoVersion);
Utils.debugLog(TAG, "Using icons dir '" + iconsDir + "'"); Utils.debugLog(TAG, "Using icons dir '" + iconsDir + "'");
Utils.debugLog(TAG, "Using large icons dir '" + iconsDirLarge + "'"); Utils.debugLog(TAG, "Using large icons dir '" + iconsDirLarge + "'");
String query = getIconUpdateQuery(appTable, apkTable); String query = getIconUpdateQuery(appTable, apkTable);
@ -980,38 +952,33 @@ public class AppProvider extends FDroidProvider {
final String repo = RepoTable.NAME; final String repo = RepoTable.NAME;
final String iconUrlQuery = final String iconUrlQuery =
" SELECT " + "SELECT " +
// Concatenate (using the "||" operator) the address, the // Concatenate (using the "||" operator) the address, the
// icons directory (bound to the ? as the second parameter // icons directory (bound to the ? as the second parameter
// when executing the query) and the icon path. // when executing the query) and the icon path.
" ( " + "( " +
repo + ".address " + repo + "." + RepoTable.Cols.ADDRESS +
" || " + " || " +
// If the repo has the relevant version, then use a more // If the repo has the relevant version, then use a more
// intelligent icons dir, otherwise revert to the default // intelligent icons dir, otherwise revert to the default
// one // one
" CASE WHEN " + repo + ".version >= ? THEN ? ELSE ? END " + " CASE WHEN " + repo + "." + RepoTable.Cols.VERSION + " >= ? THEN ? ELSE ? END " +
" || " + " || " +
app + ".icon " + app + "." + Cols.ICON +
") " + ") " +
" FROM " + " FROM " +
apk + apk +
" JOIN " + repo + " ON (" + repo + "._id = " + apk + ".repo) " + " JOIN " + repo + " ON (" + repo + "." + RepoTable.Cols._ID + " = " + apk + "." + ApkTable.Cols.REPO_ID + ") " +
" WHERE " + " WHERE " +
app + ".id = " + apk + ".id AND " + app + "." + Cols.PACKAGE_NAME + " = " + apk + "." + ApkTable.Cols.PACKAGE_NAME + " AND " +
apk + ".vercode = " + app + ".suggestedVercode "; apk + "." + ApkTable.Cols.VERSION_CODE + " = " + app + "." + Cols.SUGGESTED_VERSION_CODE;
return return "UPDATE " + app + " SET "
" UPDATE " + app + " SET " + + Cols.ICON_URL + " = ( " + iconUrlQuery + " ), "
" iconUrl = ( " + + Cols.ICON_URL_LARGE + " = ( " + iconUrlQuery + " )";
iconUrlQuery +
" ), " +
" iconUrlLarge = ( " +
iconUrlQuery +
" ) ";
} }
} }

View File

@ -5,6 +5,7 @@ import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
@ -24,74 +25,81 @@ class DBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "fdroid"; private static final String DATABASE_NAME = "fdroid";
private static final String CREATE_TABLE_REPO = "create table " private static final String CREATE_TABLE_REPO = "create table "
+ RepoTable.NAME + " (_id integer primary key, " + RepoTable.NAME + " ("
+ "address text not null, " + RepoTable.Cols._ID + " integer primary key, "
+ "name text, description text, inuse integer not null, " + RepoTable.Cols.ADDRESS + " text not null, "
+ "priority integer not null, pubkey text, fingerprint text, " + RepoTable.Cols.NAME + " text, "
+ "maxage integer not null default 0, " + RepoTable.Cols.DESCRIPTION + " text, "
+ "version integer not null default 0, " + RepoTable.Cols.IN_USE + " integer not null, "
+ "lastetag text, lastUpdated string," + RepoTable.Cols.PRIORITY + " integer not null, "
+ "isSwap integer boolean default 0," + RepoTable.Cols.SIGNING_CERT + " text, "
+ "username string, password string," + RepoTable.Cols.FINGERPRINT + " text, "
+ "timestamp integer not null default 0" + RepoTable.Cols.MAX_AGE + " integer not null default 0, "
+ RepoTable.Cols.VERSION + " integer not null default 0, "
+ RepoTable.Cols.LAST_ETAG + " text, "
+ RepoTable.Cols.LAST_UPDATED + " string,"
+ RepoTable.Cols.IS_SWAP + " integer boolean default 0,"
+ RepoTable.Cols.USERNAME + " string, "
+ RepoTable.Cols.PASSWORD + " string,"
+ RepoTable.Cols.TIMESTAMP + " integer not null default 0"
+ ");"; + ");";
private static final String CREATE_TABLE_APK = private static final String CREATE_TABLE_APK =
"CREATE TABLE " + ApkTable.NAME + " ( " "CREATE TABLE " + ApkTable.NAME + " ( "
+ "id text not null, " + ApkTable.Cols.PACKAGE_NAME + " text not null, "
+ "version text not null, " + ApkTable.Cols.VERSION_NAME + " text not null, "
+ "repo integer not null, " + ApkTable.Cols.REPO_ID + " integer not null, "
+ "hash text not null, " + ApkTable.Cols.HASH + " text not null, "
+ "vercode int not null," + ApkTable.Cols.VERSION_CODE + " int not null,"
+ "apkName text not null, " + ApkTable.Cols.NAME + " text not null, "
+ "size int not null, " + ApkTable.Cols.SIZE + " int not null, "
+ "sig string, " + ApkTable.Cols.SIGNATURE + " string, "
+ "srcname string, " + ApkTable.Cols.SOURCE_NAME + " string, "
+ "minSdkVersion integer, " + ApkTable.Cols.MIN_SDK_VERSION + " integer, "
+ "targetSdkVersion integer, " + ApkTable.Cols.TARGET_SDK_VERSION + " integer, "
+ "maxSdkVersion integer, " + ApkTable.Cols.MAX_SDK_VERSION + " integer, "
+ "permissions string, " + ApkTable.Cols.PERMISSIONS + " string, "
+ "features string, " + ApkTable.Cols.FEATURES + " string, "
+ "nativecode string, " + ApkTable.Cols.NATIVE_CODE + " string, "
+ "hashType string, " + ApkTable.Cols.HASH_TYPE + " string, "
+ "added string, " + ApkTable.Cols.ADDED_DATE + " string, "
+ "compatible int not null, " + ApkTable.Cols.IS_COMPATIBLE + " int not null, "
+ "incompatibleReasons text, " + ApkTable.Cols.INCOMPATIBLE_REASONS + " text, "
+ "primary key(id, vercode)" + "primary key(" + ApkTable.Cols.PACKAGE_NAME + ", " + ApkTable.Cols.VERSION_CODE + ")"
+ ");"; + ");";
private static final String CREATE_TABLE_APP = "CREATE TABLE " + AppTable.NAME private static final String CREATE_TABLE_APP = "CREATE TABLE " + AppTable.NAME
+ " ( " + " ( "
+ "id text not null, " + AppTable.Cols.PACKAGE_NAME + " text not null, "
+ "name text not null, " + AppTable.Cols.NAME + " text not null, "
+ "summary text not null, " + AppTable.Cols.SUMMARY + " text not null, "
+ "icon text, " + AppTable.Cols.ICON + " text, "
+ "description text not null, " + AppTable.Cols.DESCRIPTION + " text not null, "
+ "license text not null, " + AppTable.Cols.LICENSE + " text not null, "
+ "author text, " + AppTable.Cols.AUTHOR + " text, "
+ "email text, " + AppTable.Cols.EMAIL + " text, "
+ "webURL text, " + AppTable.Cols.WEB_URL + " text, "
+ "trackerURL text, " + AppTable.Cols.TRACKER_URL + " text, "
+ "sourceURL text, " + AppTable.Cols.SOURCE_URL + " text, "
+ "changelogURL text, " + AppTable.Cols.CHANGELOG_URL + " text, "
+ "suggestedVercode text," + AppTable.Cols.SUGGESTED_VERSION_CODE + " text,"
+ "upstreamVersion text," + AppTable.Cols.UPSTREAM_VERSION_NAME + " text,"
+ "upstreamVercode integer," + AppTable.Cols.UPSTREAM_VERSION_CODE + " integer,"
+ "antiFeatures string," + AppTable.Cols.ANTI_FEATURES + " string,"
+ "donateURL string," + AppTable.Cols.DONATE_URL + " string,"
+ "bitcoinAddr string," + AppTable.Cols.BITCOIN_ADDR + " string,"
+ "litecoinAddr string," + AppTable.Cols.LITECOIN_ADDR + " string,"
+ "flattrID string," + AppTable.Cols.FLATTR_ID + " string,"
+ "requirements string," + AppTable.Cols.REQUIREMENTS + " string,"
+ "categories string," + AppTable.Cols.CATEGORIES + " string,"
+ "added string," + AppTable.Cols.ADDED + " string,"
+ "lastUpdated string," + AppTable.Cols.LAST_UPDATED + " string,"
+ "compatible int not null," + AppTable.Cols.IS_COMPATIBLE + " int not null,"
+ "ignoreAllUpdates int not null," + AppTable.Cols.IGNORE_ALLUPDATES + " int not null,"
+ "ignoreThisUpdate int not null," + AppTable.Cols.IGNORE_THISUPDATE + " int not null,"
+ "iconUrl text, " + AppTable.Cols.ICON_URL + " text, "
+ "iconUrlLarge text, " + AppTable.Cols.ICON_URL_LARGE + " text, "
+ "primary key(id));"; + "primary key(" + AppTable.Cols.PACKAGE_NAME + "));";
private static final String CREATE_TABLE_INSTALLED_APP = "CREATE TABLE " + InstalledAppTable.NAME private static final String CREATE_TABLE_INSTALLED_APP = "CREATE TABLE " + InstalledAppTable.NAME
+ " ( " + " ( "
@ -120,9 +128,9 @@ class DBHelper extends SQLiteOpenHelper {
return; return;
} }
Utils.debugLog(TAG, "Populating repo names from the url"); Utils.debugLog(TAG, "Populating repo names from the url");
final String[] columns = {"address", "_id"}; final String[] columns = {RepoTable.Cols.ADDRESS, RepoTable.Cols._ID};
Cursor cursor = db.query(RepoTable.NAME, columns, Cursor cursor = db.query(RepoTable.NAME, columns,
"name IS NULL OR name = ''", null, null, null, null); RepoTable.Cols.NAME + " IS NULL OR " + RepoTable.Cols.NAME + " = ''", null, null, null, null);
if (cursor != null) { if (cursor != null) {
if (cursor.getCount() > 0) { if (cursor.getCount() > 0) {
cursor.moveToFirst(); cursor.moveToFirst();
@ -131,10 +139,10 @@ class DBHelper extends SQLiteOpenHelper {
long id = cursor.getInt(1); long id = cursor.getInt(1);
ContentValues values = new ContentValues(1); ContentValues values = new ContentValues(1);
String name = Repo.addressToName(address); String name = Repo.addressToName(address);
values.put("name", name); values.put(RepoTable.Cols.NAME, name);
final String[] args = {Long.toString(id)}; final String[] args = {Long.toString(id)};
Utils.debugLog(TAG, "Setting repo name to '" + name + "' for repo " + address); Utils.debugLog(TAG, "Setting repo name to '" + name + "' for repo " + address);
db.update(RepoTable.NAME, values, "_id = ?", args); db.update(RepoTable.NAME, values, RepoTable.Cols._ID + " = ?", args);
cursor.moveToNext(); cursor.moveToNext();
} }
} }
@ -143,11 +151,11 @@ class DBHelper extends SQLiteOpenHelper {
} }
private void renameRepoId(SQLiteDatabase db, int oldVersion) { private void renameRepoId(SQLiteDatabase db, int oldVersion) {
if (oldVersion >= 36 || columnExists(db, RepoTable.NAME, "_id")) { if (oldVersion >= 36 || columnExists(db, RepoTable.NAME, RepoTable.Cols._ID)) {
return; return;
} }
Utils.debugLog(TAG, "Renaming " + RepoTable.NAME + ".id to _id"); Utils.debugLog(TAG, "Renaming " + RepoTable.NAME + ".id to " + RepoTable.Cols._ID);
db.beginTransaction(); db.beginTransaction();
try { try {
@ -163,33 +171,44 @@ class DBHelper extends SQLiteOpenHelper {
// statement. Therefore, I've put a copy of CREATE_TABLE_REPO // statement. Therefore, I've put a copy of CREATE_TABLE_REPO
// here that is the same as it was at DBVersion 36. // here that is the same as it was at DBVersion 36.
String createTableDdl = "create table " + RepoTable.NAME + " (" String createTableDdl = "create table " + RepoTable.NAME + " ("
+ "_id integer not null primary key, " + RepoTable.Cols._ID + " integer not null primary key, "
+ "address text not null, " + RepoTable.Cols.ADDRESS + " text not null, "
+ "name text, " + RepoTable.Cols.NAME + " text, "
+ "description text, " + RepoTable.Cols.DESCRIPTION + " text, "
+ "inuse integer not null, " + RepoTable.Cols.IN_USE + " integer not null, "
+ "priority integer not null, " + RepoTable.Cols.PRIORITY + " integer not null, "
+ "pubkey text, " + RepoTable.Cols.SIGNING_CERT + " text, "
+ "fingerprint text, " + RepoTable.Cols.FINGERPRINT + " text, "
+ "maxage integer not null default 0, " + RepoTable.Cols.MAX_AGE + " integer not null default 0, "
+ "version integer not null default 0, " + RepoTable.Cols.VERSION + " integer not null default 0, "
+ "lastetag text, " + RepoTable.Cols.LAST_ETAG + " text, "
+ "lastUpdated string);"; + RepoTable.Cols.LAST_UPDATED + " string);";
db.execSQL(createTableDdl); db.execSQL(createTableDdl);
String nonIdFields = "address, name, description, inuse, priority, " + String nonIdFields = TextUtils.join(", ", new String[] {
"pubkey, fingerprint, maxage, version, lastetag, lastUpdated"; RepoTable.Cols.ADDRESS,
RepoTable.Cols.NAME,
RepoTable.Cols.DESCRIPTION,
RepoTable.Cols.IN_USE,
RepoTable.Cols.PRIORITY,
RepoTable.Cols.SIGNING_CERT,
RepoTable.Cols.FINGERPRINT,
RepoTable.Cols.MAX_AGE,
RepoTable.Cols.VERSION,
RepoTable.Cols.LAST_ETAG,
RepoTable.Cols.LAST_UPDATED,
});
String insertSql = "INSERT INTO " + RepoTable.NAME + String insertSql = "INSERT INTO " + RepoTable.NAME +
"(_id, " + nonIdFields + " ) " + "(" + RepoTable.Cols._ID + ", " + nonIdFields + " ) " +
"SELECT id, " + nonIdFields + " FROM " + tempTableName + ";"; "SELECT id, " + nonIdFields + " FROM " + tempTableName + ";";
db.execSQL(insertSql); db.execSQL(insertSql);
db.execSQL("DROP TABLE " + tempTableName + ";"); db.execSQL("DROP TABLE " + tempTableName + ";");
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Error renaming id to _id", e); Log.e(TAG, "Error renaming id to " + RepoTable.Cols._ID, e);
} }
db.endTransaction(); db.endTransaction();
} }
@ -308,7 +327,7 @@ class DBHelper extends SQLiteOpenHelper {
} }
List<Repo> oldrepos = new ArrayList<>(); List<Repo> oldrepos = new ArrayList<>();
Cursor cursor = db.query(RepoTable.NAME, Cursor cursor = db.query(RepoTable.NAME,
new String[] {"address", "inuse", "pubkey"}, new String[] {RepoTable.Cols.ADDRESS, RepoTable.Cols.IN_USE, RepoTable.Cols.SIGNING_CERT},
null, null, null, null, null); null, null, null, null, null);
if (cursor != null) { if (cursor != null) {
if (cursor.getCount() > 0) { if (cursor.getCount() > 0) {
@ -328,11 +347,11 @@ class DBHelper extends SQLiteOpenHelper {
db.execSQL(CREATE_TABLE_REPO); db.execSQL(CREATE_TABLE_REPO);
for (final Repo repo : oldrepos) { for (final Repo repo : oldrepos) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put("address", repo.address); values.put(RepoTable.Cols.ADDRESS, repo.address);
values.put("inuse", repo.inuse); values.put(RepoTable.Cols.IN_USE, repo.inuse);
values.put("priority", 10); values.put(RepoTable.Cols.PRIORITY, 10);
values.put("pubkey", repo.signingCertificate); values.put(RepoTable.Cols.SIGNING_CERT, repo.signingCertificate);
values.put("lastetag", (String) null); values.put(RepoTable.Cols.LAST_ETAG, (String) null);
db.insert(RepoTable.NAME, null, values); db.insert(RepoTable.NAME, null, values);
} }
} }
@ -341,9 +360,9 @@ class DBHelper extends SQLiteOpenHelper {
int addressResId, int nameResId, int descriptionResId) { int addressResId, int nameResId, int descriptionResId) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.clear(); values.clear();
values.put("name", context.getString(nameResId)); values.put(RepoTable.Cols.NAME, context.getString(nameResId));
values.put("description", context.getString(descriptionResId)); values.put(RepoTable.Cols.DESCRIPTION, context.getString(descriptionResId));
db.update(RepoTable.NAME, values, "address = ?", new String[] { db.update(RepoTable.NAME, values, RepoTable.Cols.ADDRESS + " = ?", new String[] {
context.getString(addressResId), context.getString(addressResId),
}); });
} }
@ -353,16 +372,16 @@ class DBHelper extends SQLiteOpenHelper {
* default repos with values from strings.xml. * default repos with values from strings.xml.
*/ */
private void addNameAndDescriptionToRepo(SQLiteDatabase db, int oldVersion) { private void addNameAndDescriptionToRepo(SQLiteDatabase db, int oldVersion) {
boolean nameExists = columnExists(db, RepoTable.NAME, "name"); boolean nameExists = columnExists(db, RepoTable.NAME, RepoTable.Cols.NAME);
boolean descriptionExists = columnExists(db, RepoTable.NAME, "description"); boolean descriptionExists = columnExists(db, RepoTable.NAME, RepoTable.Cols.DESCRIPTION);
if (oldVersion >= 21 || (nameExists && descriptionExists)) { if (oldVersion >= 21 || (nameExists && descriptionExists)) {
return; return;
} }
if (!nameExists) { if (!nameExists) {
db.execSQL("alter table " + RepoTable.NAME + " add column name text"); db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.NAME + " text");
} }
if (!descriptionExists) { if (!descriptionExists) {
db.execSQL("alter table " + RepoTable.NAME + " add column description text"); db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.DESCRIPTION + " text");
} }
insertNameAndDescription(db, R.string.fdroid_repo_address, insertNameAndDescription(db, R.string.fdroid_repo_address,
R.string.fdroid_repo_name, R.string.fdroid_repo_description); R.string.fdroid_repo_name, R.string.fdroid_repo_description);
@ -383,12 +402,12 @@ class DBHelper extends SQLiteOpenHelper {
if (oldVersion >= 44) { if (oldVersion >= 44) {
return; return;
} }
if (!columnExists(db, RepoTable.NAME, "fingerprint")) { if (!columnExists(db, RepoTable.NAME, RepoTable.Cols.FINGERPRINT)) {
db.execSQL("alter table " + RepoTable.NAME + " add column fingerprint text"); db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.FINGERPRINT + " text");
} }
List<Repo> oldrepos = new ArrayList<>(); List<Repo> oldrepos = new ArrayList<>();
Cursor cursor = db.query(RepoTable.NAME, Cursor cursor = db.query(RepoTable.NAME,
new String[] {"address", "pubkey"}, new String[] {RepoTable.Cols.ADDRESS, RepoTable.Cols.SIGNING_CERT},
null, null, null, null, null); null, null, null, null, null);
if (cursor != null) { if (cursor != null) {
if (cursor.getCount() > 0) { if (cursor.getCount() > 0) {
@ -405,70 +424,70 @@ class DBHelper extends SQLiteOpenHelper {
} }
for (final Repo repo : oldrepos) { for (final Repo repo : oldrepos) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put("fingerprint", Utils.calcFingerprint(repo.signingCertificate)); values.put(RepoTable.Cols.FINGERPRINT, Utils.calcFingerprint(repo.signingCertificate));
db.update(RepoTable.NAME, values, "address = ?", new String[] {repo.address}); db.update(RepoTable.NAME, values, RepoTable.Cols.ADDRESS + " = ?", new String[] {repo.address});
} }
} }
private void addMaxAgeToRepo(SQLiteDatabase db, int oldVersion) { private void addMaxAgeToRepo(SQLiteDatabase db, int oldVersion) {
if (oldVersion >= 30 || columnExists(db, RepoTable.NAME, "maxage")) { if (oldVersion >= 30 || columnExists(db, RepoTable.NAME, RepoTable.Cols.MAX_AGE)) {
return; return;
} }
db.execSQL("alter table " + RepoTable.NAME + " add column maxage integer not null default 0"); db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.MAX_AGE + " integer not null default 0");
} }
private void addVersionToRepo(SQLiteDatabase db, int oldVersion) { private void addVersionToRepo(SQLiteDatabase db, int oldVersion) {
if (oldVersion >= 33 || columnExists(db, RepoTable.NAME, "version")) { if (oldVersion >= 33 || columnExists(db, RepoTable.NAME, RepoTable.Cols.VERSION)) {
return; return;
} }
db.execSQL("alter table " + RepoTable.NAME + " add column version integer not null default 0"); db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.VERSION + " integer not null default 0");
} }
private void addLastUpdatedToRepo(SQLiteDatabase db, int oldVersion) { private void addLastUpdatedToRepo(SQLiteDatabase db, int oldVersion) {
if (oldVersion >= 35 || columnExists(db, RepoTable.NAME, "lastUpdated")) { if (oldVersion >= 35 || columnExists(db, RepoTable.NAME, RepoTable.Cols.LAST_UPDATED)) {
return; return;
} }
Utils.debugLog(TAG, "Adding lastUpdated column to " + RepoTable.NAME); Utils.debugLog(TAG, "Adding " + RepoTable.Cols.LAST_UPDATED + " column to " + RepoTable.NAME);
db.execSQL("Alter table " + RepoTable.NAME + " add column lastUpdated string"); db.execSQL("Alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.LAST_UPDATED + " string");
} }
private void addIsSwapToRepo(SQLiteDatabase db, int oldVersion) { private void addIsSwapToRepo(SQLiteDatabase db, int oldVersion) {
if (oldVersion >= 47 || columnExists(db, RepoTable.NAME, "isSwap")) { if (oldVersion >= 47 || columnExists(db, RepoTable.NAME, RepoTable.Cols.IS_SWAP)) {
return; return;
} }
Utils.debugLog(TAG, "Adding isSwap field to " + RepoTable.NAME + " table in db."); Utils.debugLog(TAG, "Adding " + RepoTable.Cols.IS_SWAP + " field to " + RepoTable.NAME + " table in db.");
db.execSQL("alter table " + RepoTable.NAME + " add column isSwap boolean default 0;"); db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.IS_SWAP + " boolean default 0;");
} }
private void addCredentialsToRepo(SQLiteDatabase db, int oldVersion) { private void addCredentialsToRepo(SQLiteDatabase db, int oldVersion) {
if (oldVersion >= 52) { if (oldVersion >= 52) {
return; return;
} }
if (!columnExists(db, Schema.RepoTable.NAME, "username")) { if (!columnExists(db, Schema.RepoTable.NAME, RepoTable.Cols.USERNAME)) {
Utils.debugLog(TAG, "Adding username field to " + RepoTable.NAME + " table in db."); Utils.debugLog(TAG, "Adding " + RepoTable.Cols.USERNAME + " field to " + RepoTable.NAME + " table in db.");
db.execSQL("alter table " + RepoTable.NAME + " add column username string;"); db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.USERNAME + " string;");
} }
if (!columnExists(db, RepoTable.NAME, "password")) { if (!columnExists(db, RepoTable.NAME, RepoTable.Cols.PASSWORD)) {
Utils.debugLog(TAG, "Adding password field to " + RepoTable.NAME + " table in db."); Utils.debugLog(TAG, "Adding " + RepoTable.Cols.PASSWORD + " field to " + RepoTable.NAME + " table in db.");
db.execSQL("alter table " + RepoTable.NAME + " add column password string;"); db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.PASSWORD + " string;");
} }
} }
private void addChangelogToApp(SQLiteDatabase db, int oldVersion) { private void addChangelogToApp(SQLiteDatabase db, int oldVersion) {
if (oldVersion >= 48 || columnExists(db, AppTable.NAME, "changelogURL")) { if (oldVersion >= 48 || columnExists(db, AppTable.NAME, AppTable.Cols.CHANGELOG_URL)) {
return; return;
} }
Utils.debugLog(TAG, "Adding changelogURL column to " + AppTable.NAME); Utils.debugLog(TAG, "Adding " + AppTable.Cols.CHANGELOG_URL + " column to " + AppTable.NAME);
db.execSQL("alter table " + AppTable.NAME + " add column changelogURL text"); db.execSQL("alter table " + AppTable.NAME + " add column " + AppTable.Cols.CHANGELOG_URL + " text");
} }
private void addIconUrlLargeToApp(SQLiteDatabase db, int oldVersion) { private void addIconUrlLargeToApp(SQLiteDatabase db, int oldVersion) {
if (oldVersion >= 49 || columnExists(db, AppTable.NAME, "iconUrlLarge")) { if (oldVersion >= 49 || columnExists(db, AppTable.NAME, AppTable.Cols.ICON_URL_LARGE)) {
return; return;
} }
Utils.debugLog(TAG, "Adding iconUrlLarge columns to " + AppTable.NAME); Utils.debugLog(TAG, "Adding " + AppTable.Cols.ICON_URL_LARGE + " columns to " + AppTable.NAME);
db.execSQL("alter table " + AppTable.NAME + " add column iconUrlLarge text"); db.execSQL("alter table " + AppTable.NAME + " add column " + AppTable.Cols.ICON_URL_LARGE + " text");
} }
private void updateIconUrlLarge(SQLiteDatabase db, int oldVersion) { private void updateIconUrlLarge(SQLiteDatabase db, int oldVersion) {
@ -484,13 +503,13 @@ class DBHelper extends SQLiteOpenHelper {
if (oldVersion >= 53) { if (oldVersion >= 53) {
return; return;
} }
if (!columnExists(db, AppTable.NAME, "author")) { if (!columnExists(db, AppTable.NAME, AppTable.Cols.AUTHOR)) {
Utils.debugLog(TAG, "Adding author column to " + AppTable.NAME); Utils.debugLog(TAG, "Adding " + AppTable.Cols.AUTHOR + " column to " + AppTable.NAME);
db.execSQL("alter table " + AppTable.NAME + " add column author text"); db.execSQL("alter table " + AppTable.NAME + " add column " + AppTable.Cols.AUTHOR + " text");
} }
if (!columnExists(db, AppTable.NAME, "email")) { if (!columnExists(db, AppTable.NAME, AppTable.Cols.EMAIL)) {
Utils.debugLog(TAG, "Adding email column to " + AppTable.NAME); Utils.debugLog(TAG, "Adding " + AppTable.Cols.EMAIL + " column to " + AppTable.NAME);
db.execSQL("alter table " + AppTable.NAME + " add column email text"); db.execSQL("alter table " + AppTable.NAME + " add column " + AppTable.Cols.EMAIL + " text");
} }
} }
@ -498,7 +517,7 @@ class DBHelper extends SQLiteOpenHelper {
if (oldVersion >= 54) { if (oldVersion >= 54) {
return; return;
} }
Utils.debugLog(TAG, "Converting maxSdkVersion value 0 to " + Byte.MAX_VALUE); Utils.debugLog(TAG, "Converting " + ApkTable.Cols.MAX_SDK_VERSION + " value 0 to " + Byte.MAX_VALUE);
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(ApkTable.Cols.MAX_SDK_VERSION, Byte.MAX_VALUE); values.put(ApkTable.Cols.MAX_SDK_VERSION, Byte.MAX_VALUE);
db.update(ApkTable.NAME, values, ApkTable.Cols.MAX_SDK_VERSION + " < 1", null); db.update(ApkTable.NAME, values, ApkTable.Cols.MAX_SDK_VERSION + " < 1", null);
@ -526,7 +545,7 @@ class DBHelper extends SQLiteOpenHelper {
*/ */
private void clearRepoEtags(SQLiteDatabase db) { private void clearRepoEtags(SQLiteDatabase db) {
Utils.debugLog(TAG, "Clearing repo etags, so next update will not be skipped with \"Repos up to date\"."); Utils.debugLog(TAG, "Clearing repo etags, so next update will not be skipped with \"Repos up to date\".");
db.execSQL("update " + RepoTable.NAME + " set lastetag = NULL"); db.execSQL("update " + RepoTable.NAME + " set " + RepoTable.Cols.LAST_ETAG + " = NULL");
} }
private void resetTransient(SQLiteDatabase db, int oldVersion) { private void resetTransient(SQLiteDatabase db, int oldVersion) {
@ -548,10 +567,10 @@ class DBHelper extends SQLiteOpenHelper {
private static void createAppApk(SQLiteDatabase db) { private static void createAppApk(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_APP); db.execSQL(CREATE_TABLE_APP);
db.execSQL("create index app_id on " + AppTable.NAME + " (id);"); db.execSQL("create index app_id on " + AppTable.NAME + " (" + AppTable.Cols.PACKAGE_NAME + ");");
db.execSQL(CREATE_TABLE_APK); db.execSQL(CREATE_TABLE_APK);
db.execSQL("create index apk_vercode on " + ApkTable.NAME + " (vercode);"); db.execSQL("create index apk_vercode on " + ApkTable.NAME + " (" + ApkTable.Cols.VERSION_CODE + ");");
db.execSQL("create index apk_id on " + ApkTable.NAME + " (id);"); db.execSQL("create index apk_id on " + ApkTable.NAME + " (" + AppTable.Cols.PACKAGE_NAME + ");");
} }
/** /**

View File

@ -118,11 +118,11 @@ public class InstalledAppProvider extends FDroidProvider {
} }
private QuerySelection queryApp(String packageName) { private QuerySelection queryApp(String packageName) {
return new QuerySelection("appId = ?", new String[]{packageName}); return new QuerySelection(Cols.PACKAGE_NAME + " = ?", new String[]{packageName});
} }
private QuerySelection querySearch(String query) { private QuerySelection querySearch(String query) {
return new QuerySelection("applicationLabel LIKE ?", return new QuerySelection(Cols.APPLICATION_LABEL + " LIKE ?",
new String[]{"%" + query + "%"}); new String[]{"%" + query + "%"});
} }

View File

@ -141,8 +141,8 @@ public class RepoProvider extends FDroidProvider {
} else if (!fingerprint.equals(calcedFingerprint)) { } else if (!fingerprint.equals(calcedFingerprint)) {
// TODO the UI should represent this error! // TODO the UI should represent this error!
Log.e(TAG, "The stored and calculated fingerprints do not match!"); Log.e(TAG, "The stored and calculated fingerprints do not match!");
Log.e(TAG, "stored: " + fingerprint); Log.e(TAG, "Stored: " + fingerprint);
Log.e(TAG, "calced: " + calcedFingerprint); Log.e(TAG, "Calculated: " + calcedFingerprint);
} }
} }
} else if (!TextUtils.isEmpty(publicKey)) { } else if (!TextUtils.isEmpty(publicKey)) {
@ -195,7 +195,7 @@ public class RepoProvider extends FDroidProvider {
public static int countAppsForRepo(Context context, long repoId) { public static int countAppsForRepo(Context context, long repoId) {
ContentResolver resolver = context.getContentResolver(); ContentResolver resolver = context.getContentResolver();
final String[] projection = {Schema.ApkTable.Cols._COUNT_DISTINCT_ID}; final String[] projection = {Schema.ApkTable.Cols._COUNT_DISTINCT};
Uri apkUri = ApkProvider.getRepoUri(repoId); Uri apkUri = ApkProvider.getRepoUri(repoId);
Cursor cursor = resolver.query(apkUri, projection, null, null, null); Cursor cursor = resolver.query(apkUri, projection, null, null, null);
int count = 0; int count = 0;
@ -327,14 +327,14 @@ public class RepoProvider extends FDroidProvider {
@Override @Override
public int delete(Uri uri, String where, String[] whereArgs) { public int delete(Uri uri, String where, String[] whereArgs) {
QuerySelection selection = new QuerySelection(where, whereArgs);
switch (MATCHER.match(uri)) { switch (MATCHER.match(uri)) {
case CODE_LIST: case CODE_LIST:
// Don't support deleting of multiple repos. // Don't support deleting of multiple repos.
return 0; return 0;
case CODE_SINGLE: case CODE_SINGLE:
where = (where == null ? "" : where + " AND ") + selection.add(Cols._ID + " = ?", new String[] {uri.getLastPathSegment()});
"_ID = " + uri.getLastPathSegment();
break; break;
default: default:
@ -342,7 +342,7 @@ public class RepoProvider extends FDroidProvider {
throw new UnsupportedOperationException("Invalid URI for repo content provider: " + uri); throw new UnsupportedOperationException("Invalid URI for repo content provider: " + uri);
} }
int rowsAffected = db().delete(getTableName(), where, whereArgs); int rowsAffected = db().delete(getTableName(), selection.getSelection(), selection.getArgs());
Utils.debugLog(TAG, "Deleted repos. Notifying provider change: '" + uri + "'."); Utils.debugLog(TAG, "Deleted repos. Notifying provider change: '" + uri + "'.");
getContext().getContentResolver().notifyChange(uri, null); getContext().getContentResolver().notifyChange(uri, null);
return rowsAffected; return rowsAffected;

View File

@ -80,7 +80,7 @@ public interface Schema {
String NAME = "fdroid_apk"; String NAME = "fdroid_apk";
interface Cols extends BaseColumns { interface Cols extends BaseColumns {
String _COUNT_DISTINCT_ID = "countDistinct"; String _COUNT_DISTINCT = "countDistinct";
String PACKAGE_NAME = "id"; String PACKAGE_NAME = "id";
String VERSION_NAME = "version"; String VERSION_NAME = "version";

View File

@ -131,9 +131,9 @@ public class TempApkProvider extends ApkProvider {
final SQLiteDatabase db = db(); final SQLiteDatabase db = db();
final String memoryDbName = TempAppProvider.DB; final String memoryDbName = TempAppProvider.DB;
db.execSQL("CREATE TABLE " + memoryDbName + "." + getTableName() + " AS SELECT * FROM main." + ApkTable.NAME); db.execSQL("CREATE TABLE " + memoryDbName + "." + getTableName() + " AS SELECT * FROM main." + ApkTable.NAME);
db.execSQL("CREATE INDEX IF NOT EXISTS " + memoryDbName + ".apk_vercode on " + getTableName() + " (vercode);"); db.execSQL("CREATE INDEX IF NOT EXISTS " + memoryDbName + ".apk_vercode on " + getTableName() + " (" + ApkTable.Cols.VERSION_CODE + ");");
db.execSQL("CREATE INDEX IF NOT EXISTS " + memoryDbName + ".apk_id on " + getTableName() + " (id);"); db.execSQL("CREATE INDEX IF NOT EXISTS " + memoryDbName + ".apk_id on " + getTableName() + " (" + ApkTable.Cols.PACKAGE_NAME + ");");
db.execSQL("CREATE INDEX IF NOT EXISTS " + memoryDbName + ".apk_compatible ON " + getTableName() + " (compatible);"); db.execSQL("CREATE INDEX IF NOT EXISTS " + memoryDbName + ".apk_compatible ON " + getTableName() + " (" + ApkTable.Cols.IS_COMPATIBLE + ");");
} }
} }

View File

@ -131,9 +131,9 @@ public class TempAppProvider extends AppProvider {
ensureTempTableDetached(db); ensureTempTableDetached(db);
db.execSQL("ATTACH DATABASE ':memory:' AS " + DB); db.execSQL("ATTACH DATABASE ':memory:' AS " + DB);
db.execSQL("CREATE TABLE " + DB + "." + getTableName() + " AS SELECT * FROM main." + AppTable.NAME); db.execSQL("CREATE TABLE " + DB + "." + getTableName() + " AS SELECT * FROM main." + AppTable.NAME);
db.execSQL("CREATE INDEX IF NOT EXISTS " + DB + ".app_id ON " + getTableName() + " (id);"); db.execSQL("CREATE INDEX IF NOT EXISTS " + DB + ".app_id ON " + getTableName() + " (" + AppTable.Cols.PACKAGE_NAME + ");");
db.execSQL("CREATE INDEX IF NOT EXISTS " + DB + ".app_upstreamVercode ON " + getTableName() + " (upstreamVercode);"); db.execSQL("CREATE INDEX IF NOT EXISTS " + DB + ".app_upstreamVercode ON " + getTableName() + " (" + AppTable.Cols.UPSTREAM_VERSION_CODE + ");");
db.execSQL("CREATE INDEX IF NOT EXISTS " + DB + ".app_compatible ON " + getTableName() + " (compatible);"); db.execSQL("CREATE INDEX IF NOT EXISTS " + DB + ".app_compatible ON " + getTableName() + " (" + AppTable.Cols.IS_COMPATIBLE + ");");
} }
private void commitTable() { private void commitTable() {