зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1555412 - Remove all the bookmark annotations but the last used one. r=Standard8
Differential Revision: https://phabricator.services.mozilla.com/D33044 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
68f8760568
Коммит
9793f55d17
|
@ -101,16 +101,6 @@
|
||||||
// How much time Sqlite can wait before returning a SQLITE_BUSY error.
|
// How much time Sqlite can wait before returning a SQLITE_BUSY error.
|
||||||
#define DATABASE_BUSY_TIMEOUT_MS 100
|
#define DATABASE_BUSY_TIMEOUT_MS 100
|
||||||
|
|
||||||
// Old Sync GUID annotation.
|
|
||||||
#define SYNCGUID_ANNO NS_LITERAL_CSTRING("sync/guid")
|
|
||||||
|
|
||||||
// Places string bundle, contains internationalized bookmark root names.
|
|
||||||
#define PLACES_BUNDLE "chrome://places/locale/places.properties"
|
|
||||||
|
|
||||||
// This is no longer used & obsolete except for during migration.
|
|
||||||
// Note: it may still be found in older places databases.
|
|
||||||
#define MOBILE_ROOT_ANNO "mobile/bookmarksRoot"
|
|
||||||
|
|
||||||
// This annotation is no longer used & is obsolete, but here for migration.
|
// This annotation is no longer used & is obsolete, but here for migration.
|
||||||
#define LAST_USED_ANNO \
|
#define LAST_USED_ANNO \
|
||||||
NS_LITERAL_CSTRING("bookmarkPropertiesDialog/folderLastUsed")
|
NS_LITERAL_CSTRING("bookmarkPropertiesDialog/folderLastUsed")
|
||||||
|
@ -123,6 +113,9 @@
|
||||||
// sets the title to the localized version when it creates the left pane query.
|
// sets the title to the localized version when it creates the left pane query.
|
||||||
#define MOBILE_ROOT_TITLE "mobile"
|
#define MOBILE_ROOT_TITLE "mobile"
|
||||||
|
|
||||||
|
// Legacy item annotation used by the old Sync engine.
|
||||||
|
#define SYNC_PARENT_ANNO "sync/parent"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
@ -1138,51 +1131,13 @@ nsresult Database::InitSchema(bool* aDatabaseMigrated) {
|
||||||
if (currentSchemaVersion < DATABASE_SCHEMA_VERSION) {
|
if (currentSchemaVersion < DATABASE_SCHEMA_VERSION) {
|
||||||
*aDatabaseMigrated = true;
|
*aDatabaseMigrated = true;
|
||||||
|
|
||||||
if (currentSchemaVersion < 30) {
|
if (currentSchemaVersion < 35) {
|
||||||
// These are versions older than Firefox 45 that are not supported
|
// These are versions older than Firefox 52 ESR that are not supported
|
||||||
// anymore. In this case it's safer to just replace the database.
|
// anymore. In this case it's safer to just replace the database.
|
||||||
// Note that Firefox 45 is the ESR release before the latest one (52),
|
|
||||||
// and Firefox 48 is a watershed release, so any version older than 48
|
|
||||||
// will first have to go through it.
|
|
||||||
return NS_ERROR_FILE_CORRUPTED;
|
return NS_ERROR_FILE_CORRUPTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Firefox 45 ESR uses schema version 30.
|
// Firefox 52 ESR uses schema version 35.
|
||||||
|
|
||||||
if (currentSchemaVersion < 31) {
|
|
||||||
rv = MigrateV31Up();
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Firefox 48 uses schema version 31.
|
|
||||||
|
|
||||||
if (currentSchemaVersion < 32) {
|
|
||||||
rv = MigrateV32Up();
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Firefox 49 uses schema version 32.
|
|
||||||
|
|
||||||
if (currentSchemaVersion < 33) {
|
|
||||||
rv = MigrateV33Up();
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Firefox 50 uses schema version 33.
|
|
||||||
|
|
||||||
if (currentSchemaVersion < 34) {
|
|
||||||
rv = MigrateV34Up();
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Firefox 51 uses schema version 34.
|
|
||||||
|
|
||||||
if (currentSchemaVersion < 35) {
|
|
||||||
rv = MigrateV35Up();
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Firefox 52 uses schema version 35.
|
|
||||||
|
|
||||||
if (currentSchemaVersion < 36) {
|
if (currentSchemaVersion < 36) {
|
||||||
rv = MigrateV36Up();
|
rv = MigrateV36Up();
|
||||||
|
@ -1208,7 +1163,7 @@ nsresult Database::InitSchema(bool* aDatabaseMigrated) {
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Firefox 57 uses schema version 39.
|
// Firefox 57 uses schema version 39. - This is a watershed version.
|
||||||
|
|
||||||
if (currentSchemaVersion < 40) {
|
if (currentSchemaVersion < 40) {
|
||||||
rv = MigrateV40Up();
|
rv = MigrateV40Up();
|
||||||
|
@ -1232,7 +1187,7 @@ nsresult Database::InitSchema(bool* aDatabaseMigrated) {
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Firefox 60 uses schema version 43.
|
// Firefox 60 uses schema version 43. - This is an ESR.
|
||||||
|
|
||||||
if (currentSchemaVersion < 44) {
|
if (currentSchemaVersion < 44) {
|
||||||
rv = MigrateV44Up();
|
rv = MigrateV44Up();
|
||||||
|
@ -1283,6 +1238,13 @@ nsresult Database::InitSchema(bool* aDatabaseMigrated) {
|
||||||
|
|
||||||
// Firefox 62 uses schema version 52.
|
// Firefox 62 uses schema version 52.
|
||||||
|
|
||||||
|
if (currentSchemaVersion < 53) {
|
||||||
|
rv = MigrateV53Up();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Firefox 69 uses schema version 53
|
||||||
|
|
||||||
// Schema Upgrades must add migration code here.
|
// Schema Upgrades must add migration code here.
|
||||||
// >>> IMPORTANT! <<<
|
// >>> IMPORTANT! <<<
|
||||||
// NEVER MIX UP SYNC AND ASYNC EXECUTION IN MIGRATORS, YOU MAY LOCK THE
|
// NEVER MIX UP SYNC AND ASYNC EXECUTION IN MIGRATORS, YOU MAY LOCK THE
|
||||||
|
@ -1694,247 +1656,6 @@ nsresult Database::InitTempEntities() {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult Database::MigrateV31Up() {
|
|
||||||
nsresult rv = mMainConn->ExecuteSimpleSQL(
|
|
||||||
NS_LITERAL_CSTRING("DROP TABLE IF EXISTS moz_bookmarks_roots"));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Database::MigrateV32Up() {
|
|
||||||
// Remove some old and no more used Places preferences that may be confusing
|
|
||||||
// for the user.
|
|
||||||
mozilla::Unused << Preferences::ClearUser(
|
|
||||||
"places.history.expiration.transient_optimal_database_size");
|
|
||||||
mozilla::Unused << Preferences::ClearUser("places.last_vacuum");
|
|
||||||
mozilla::Unused << Preferences::ClearUser("browser.history_expire_sites");
|
|
||||||
mozilla::Unused << Preferences::ClearUser(
|
|
||||||
"browser.history_expire_days.mirror");
|
|
||||||
mozilla::Unused << Preferences::ClearUser("browser.history_expire_days_min");
|
|
||||||
|
|
||||||
// For performance reasons we want to remove too long urls from history.
|
|
||||||
// We cannot use the moz_places triggers here, cause they are defined only
|
|
||||||
// after the schema migration. Thus we need to collect the hosts that need to
|
|
||||||
// be updated first.
|
|
||||||
nsresult rv = mMainConn->ExecuteSimpleSQL(
|
|
||||||
NS_LITERAL_CSTRING("CREATE TEMP TABLE moz_migrate_v32_temp ("
|
|
||||||
"host TEXT PRIMARY KEY "
|
|
||||||
") WITHOUT ROWID "));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
{
|
|
||||||
nsCOMPtr<mozIStorageStatement> stmt;
|
|
||||||
rv = mMainConn->CreateStatement(
|
|
||||||
NS_LITERAL_CSTRING("INSERT OR IGNORE INTO moz_migrate_v32_temp (host) "
|
|
||||||
"SELECT fixup_url(get_unreversed_host(rev_host)) "
|
|
||||||
"FROM moz_places WHERE LENGTH(url) > :maxlen AND "
|
|
||||||
"foreign_count = 0"),
|
|
||||||
getter_AddRefs(stmt));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("maxlen"), MaxUrlLength());
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
rv = stmt->Execute();
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
// Now remove the pages with a long url.
|
|
||||||
{
|
|
||||||
nsCOMPtr<mozIStorageStatement> stmt;
|
|
||||||
rv = mMainConn->CreateStatement(
|
|
||||||
NS_LITERAL_CSTRING("DELETE FROM moz_places WHERE LENGTH(url) > :maxlen "
|
|
||||||
"AND foreign_count = 0"),
|
|
||||||
getter_AddRefs(stmt));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("maxlen"), MaxUrlLength());
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
rv = stmt->Execute();
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expire orphan visits and update moz_hosts.
|
|
||||||
// These may be a bit more expensive and are not critical for the DB
|
|
||||||
// functionality, so we execute them asynchronously.
|
|
||||||
nsCOMPtr<mozIStorageAsyncStatement> expireOrphansStmt;
|
|
||||||
rv = mMainConn->CreateAsyncStatement(
|
|
||||||
NS_LITERAL_CSTRING(
|
|
||||||
"DELETE FROM moz_historyvisits "
|
|
||||||
"WHERE NOT EXISTS (SELECT 1 FROM moz_places WHERE id = place_id)"),
|
|
||||||
getter_AddRefs(expireOrphansStmt));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
nsCOMPtr<mozIStorageAsyncStatement> deleteHostsStmt;
|
|
||||||
rv = mMainConn->CreateAsyncStatement(
|
|
||||||
NS_LITERAL_CSTRING(
|
|
||||||
"DELETE FROM moz_hosts "
|
|
||||||
"WHERE host IN (SELECT host FROM moz_migrate_v32_temp) "
|
|
||||||
"AND NOT EXISTS("
|
|
||||||
"SELECT 1 FROM moz_places "
|
|
||||||
"WHERE rev_host = get_unreversed_host(host || '.') || '.' "
|
|
||||||
"OR rev_host = get_unreversed_host(host || '.') || '.www.' "
|
|
||||||
"); "),
|
|
||||||
getter_AddRefs(deleteHostsStmt));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
#define HOST_TO_REVHOST_PREDICATE \
|
|
||||||
"rev_host = get_unreversed_host(host || '.') || '.' " \
|
|
||||||
"OR rev_host = get_unreversed_host(host || '.') || '.www.'"
|
|
||||||
#define HOSTS_PREFIX_PRIORITY_FRAGMENT \
|
|
||||||
"SELECT CASE " \
|
|
||||||
"WHEN ( " \
|
|
||||||
"SELECT round(avg(substr(url,1,12) = 'https://www.')) FROM moz_places h " \
|
|
||||||
"WHERE (" HOST_TO_REVHOST_PREDICATE \
|
|
||||||
") AND +h.typed = 1 " \
|
|
||||||
") THEN 'https://www.' " \
|
|
||||||
"WHEN ( " \
|
|
||||||
"SELECT round(avg(substr(url,1,8) = 'https://')) FROM moz_places h " \
|
|
||||||
"WHERE (" HOST_TO_REVHOST_PREDICATE \
|
|
||||||
") AND +h.typed = 1 " \
|
|
||||||
") THEN 'https://' " \
|
|
||||||
"WHEN 1 = ( " \
|
|
||||||
"SELECT min(substr(url,1,4) = 'ftp:') FROM moz_places h " \
|
|
||||||
"WHERE (" HOST_TO_REVHOST_PREDICATE \
|
|
||||||
") AND +h.typed = 1 " \
|
|
||||||
") THEN 'ftp://' " \
|
|
||||||
"WHEN ( " \
|
|
||||||
"SELECT round(avg(substr(url,1,11) = 'http://www.')) FROM moz_places h " \
|
|
||||||
"WHERE (" HOST_TO_REVHOST_PREDICATE \
|
|
||||||
") AND +h.typed = 1 " \
|
|
||||||
") THEN 'www.' " \
|
|
||||||
"END "
|
|
||||||
|
|
||||||
nsCOMPtr<mozIStorageAsyncStatement> updateHostsStmt;
|
|
||||||
rv = mMainConn->CreateAsyncStatement(
|
|
||||||
NS_LITERAL_CSTRING(
|
|
||||||
"UPDATE moz_hosts "
|
|
||||||
"SET prefix = (" HOSTS_PREFIX_PRIORITY_FRAGMENT ") "
|
|
||||||
"WHERE host IN (SELECT host FROM moz_migrate_v32_temp) "),
|
|
||||||
getter_AddRefs(updateHostsStmt));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
#undef HOST_TO_REVHOST_PREDICATE
|
|
||||||
#undef HOSTS_PREFIX_PRIORITY_FRAGMENT
|
|
||||||
|
|
||||||
nsCOMPtr<mozIStorageAsyncStatement> dropTableStmt;
|
|
||||||
rv = mMainConn->CreateAsyncStatement(
|
|
||||||
NS_LITERAL_CSTRING("DROP TABLE IF EXISTS moz_migrate_v32_temp"),
|
|
||||||
getter_AddRefs(dropTableStmt));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
nsTArray<RefPtr<mozIStorageBaseStatement>> stmts = {
|
|
||||||
expireOrphansStmt.forget(),
|
|
||||||
deleteHostsStmt.forget(),
|
|
||||||
updateHostsStmt.forget(),
|
|
||||||
dropTableStmt.forget(),
|
|
||||||
};
|
|
||||||
nsCOMPtr<mozIStoragePendingStatement> ps;
|
|
||||||
rv = mMainConn->ExecuteAsync(stmts, nullptr, getter_AddRefs(ps));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Database::MigrateV33Up() {
|
|
||||||
nsresult rv = mMainConn->ExecuteSimpleSQL(
|
|
||||||
NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_places_url_uniqueindex"));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
// Add an url_hash column to moz_places.
|
|
||||||
nsCOMPtr<mozIStorageStatement> stmt;
|
|
||||||
rv = mMainConn->CreateStatement(
|
|
||||||
NS_LITERAL_CSTRING("SELECT url_hash FROM moz_places"),
|
|
||||||
getter_AddRefs(stmt));
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
rv = mMainConn->ExecuteSimpleSQL(
|
|
||||||
NS_LITERAL_CSTRING("ALTER TABLE moz_places ADD COLUMN url_hash INTEGER "
|
|
||||||
"DEFAULT 0 NOT NULL"));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
|
||||||
"UPDATE moz_places SET url_hash = hash(url) WHERE url_hash = 0"));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
// Create an index on url_hash.
|
|
||||||
rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_URL_HASH);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Database::MigrateV34Up() {
|
|
||||||
nsresult rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
|
||||||
"DELETE FROM moz_keywords WHERE id IN ( "
|
|
||||||
"SELECT id FROM moz_keywords k "
|
|
||||||
"WHERE NOT EXISTS (SELECT 1 FROM moz_places h WHERE k.place_id = h.id) "
|
|
||||||
")"));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Database::MigrateV35Up() {
|
|
||||||
int64_t mobileRootId = CreateMobileRoot();
|
|
||||||
if (mobileRootId <= 0) {
|
|
||||||
// Either the schema is broken or there isn't any root. The latter can
|
|
||||||
// happen if a consumer, for example Thunderbird, never used bookmarks.
|
|
||||||
// If there are no roots, this migration should not run.
|
|
||||||
nsCOMPtr<mozIStorageStatement> checkRootsStmt;
|
|
||||||
nsresult rv = mMainConn->CreateStatement(
|
|
||||||
NS_LITERAL_CSTRING("SELECT id FROM moz_bookmarks WHERE parent = 0"),
|
|
||||||
getter_AddRefs(checkRootsStmt));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
bool hasResult = false;
|
|
||||||
rv = checkRootsStmt->ExecuteStep(&hasResult);
|
|
||||||
if (NS_SUCCEEDED(rv) && !hasResult) {
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, we should have no more than two folders with the mobile
|
|
||||||
// bookmarks anno: the new root, and the old folder if one exists. If, for
|
|
||||||
// some reason, we have multiple folders with the anno, we append their
|
|
||||||
// children to the new root.
|
|
||||||
nsTArray<int64_t> folderIds;
|
|
||||||
nsresult rv =
|
|
||||||
GetItemsWithAnno(NS_LITERAL_CSTRING(MOBILE_ROOT_ANNO),
|
|
||||||
nsINavBookmarksService::TYPE_FOLDER, folderIds);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < folderIds.Length(); ++i) {
|
|
||||||
if (folderIds[i] == mobileRootId) {
|
|
||||||
// Ignore the new mobile root. We'll remove this anno from the root in
|
|
||||||
// bug 1306445.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append the folder's children to the new root.
|
|
||||||
nsCOMPtr<mozIStorageStatement> moveStmt;
|
|
||||||
rv = mMainConn->CreateStatement(
|
|
||||||
NS_LITERAL_CSTRING("UPDATE moz_bookmarks "
|
|
||||||
"SET parent = :root_id, "
|
|
||||||
"position = position + IFNULL("
|
|
||||||
"(SELECT MAX(position) + 1 FROM moz_bookmarks "
|
|
||||||
"WHERE parent = :root_id), 0)"
|
|
||||||
"WHERE parent = :folder_id"),
|
|
||||||
getter_AddRefs(moveStmt));
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
rv = moveStmt->BindInt64ByName(NS_LITERAL_CSTRING("root_id"), mobileRootId);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
rv = moveStmt->BindInt64ByName(NS_LITERAL_CSTRING("folder_id"),
|
|
||||||
folderIds[i]);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
rv = moveStmt->Execute();
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
// Delete the old folder.
|
|
||||||
rv = DeleteBookmarkItem(folderIds[i]);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Database::MigrateV36Up() {
|
nsresult Database::MigrateV36Up() {
|
||||||
// Add sync status and change counter tracking columns for bookmarks.
|
// Add sync status and change counter tracking columns for bookmarks.
|
||||||
nsCOMPtr<mozIStorageStatement> syncStatusStmt;
|
nsCOMPtr<mozIStorageStatement> syncStatusStmt;
|
||||||
|
@ -2688,6 +2409,44 @@ nsresult Database::MigrateV52Up() {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult Database::MigrateV53Up() {
|
||||||
|
nsCOMPtr<mozIStorageStatement> stmt;
|
||||||
|
nsresult rv = mMainConn->CreateStatement(
|
||||||
|
NS_LITERAL_CSTRING("SELECT 1 FROM moz_items_annos"),
|
||||||
|
getter_AddRefs(stmt));
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
// Likely we removed the table.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all item annotations but SYNC_PARENT_ANNO.
|
||||||
|
rv = mMainConn->CreateStatement(
|
||||||
|
NS_LITERAL_CSTRING(
|
||||||
|
"DELETE FROM moz_items_annos "
|
||||||
|
"WHERE anno_attribute_id NOT IN ( "
|
||||||
|
" SELECT id FROM moz_anno_attributes WHERE name = :anno_name "
|
||||||
|
") "),
|
||||||
|
getter_AddRefs(stmt));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
|
||||||
|
NS_LITERAL_CSTRING(SYNC_PARENT_ANNO));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
rv = stmt->Execute();
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
|
||||||
|
"DELETE FROM moz_anno_attributes WHERE id IN ( "
|
||||||
|
" SELECT id FROM moz_anno_attributes "
|
||||||
|
" EXCEPT "
|
||||||
|
" SELECT DISTINCT anno_attribute_id FROM moz_annos "
|
||||||
|
" EXCEPT "
|
||||||
|
" SELECT DISTINCT anno_attribute_id FROM moz_items_annos "
|
||||||
|
")"));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult Database::ConvertOldStyleQuery(nsCString& aURL) {
|
nsresult Database::ConvertOldStyleQuery(nsCString& aURL) {
|
||||||
AutoTArray<QueryKeyValuePair, 8> tokens;
|
AutoTArray<QueryKeyValuePair, 8> tokens;
|
||||||
nsresult rv = TokenizeQueryString(aURL, &tokens);
|
nsresult rv = TokenizeQueryString(aURL, &tokens);
|
||||||
|
@ -2765,67 +2524,6 @@ nsresult Database::ConvertOldStyleQuery(nsCString& aURL) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult Database::GetItemsWithAnno(const nsACString& aAnnoName,
|
|
||||||
int32_t aItemType,
|
|
||||||
nsTArray<int64_t>& aItemIds) {
|
|
||||||
nsCOMPtr<mozIStorageStatement> stmt;
|
|
||||||
nsresult rv = mMainConn->CreateStatement(
|
|
||||||
NS_LITERAL_CSTRING(
|
|
||||||
"SELECT b.id FROM moz_items_annos a "
|
|
||||||
"JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
|
|
||||||
"JOIN moz_bookmarks b ON b.id = a.item_id "
|
|
||||||
"WHERE n.name = :anno_name AND "
|
|
||||||
"b.type = :item_type"),
|
|
||||||
getter_AddRefs(stmt));
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aAnnoName);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_type"), aItemType);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
bool hasMore = false;
|
|
||||||
while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) && hasMore) {
|
|
||||||
int64_t itemId;
|
|
||||||
rv = stmt->GetInt64(0, &itemId);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
aItemIds.AppendElement(itemId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult Database::DeleteBookmarkItem(int32_t aItemId) {
|
|
||||||
// Delete the old bookmark.
|
|
||||||
nsCOMPtr<mozIStorageStatement> deleteStmt;
|
|
||||||
nsresult rv = mMainConn->CreateStatement(
|
|
||||||
NS_LITERAL_CSTRING("DELETE FROM moz_bookmarks WHERE id = :item_id"),
|
|
||||||
getter_AddRefs(deleteStmt));
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
rv = deleteStmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
rv = deleteStmt->Execute();
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
// Clean up orphan annotations.
|
|
||||||
nsCOMPtr<mozIStorageStatement> removeAnnosStmt;
|
|
||||||
rv = mMainConn->CreateStatement(
|
|
||||||
NS_LITERAL_CSTRING(
|
|
||||||
"DELETE FROM moz_items_annos WHERE item_id = :item_id"),
|
|
||||||
getter_AddRefs(removeAnnosStmt));
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
rv = removeAnnosStmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
rv = removeAnnosStmt->Execute();
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t Database::CreateMobileRoot() {
|
int64_t Database::CreateMobileRoot() {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
// This is the schema version. Update it at any schema change and add a
|
// This is the schema version. Update it at any schema change and add a
|
||||||
// corresponding migrateVxx method below.
|
// corresponding migrateVxx method below.
|
||||||
#define DATABASE_SCHEMA_VERSION 52
|
#define DATABASE_SCHEMA_VERSION 53
|
||||||
|
|
||||||
// Fired after Places inited.
|
// Fired after Places inited.
|
||||||
#define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
|
#define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
|
||||||
|
@ -319,11 +319,6 @@ class Database final : public nsIObserver, public nsSupportsWeakReference {
|
||||||
/**
|
/**
|
||||||
* Helpers used by schema upgrades.
|
* Helpers used by schema upgrades.
|
||||||
*/
|
*/
|
||||||
nsresult MigrateV31Up();
|
|
||||||
nsresult MigrateV32Up();
|
|
||||||
nsresult MigrateV33Up();
|
|
||||||
nsresult MigrateV34Up();
|
|
||||||
nsresult MigrateV35Up();
|
|
||||||
nsresult MigrateV36Up();
|
nsresult MigrateV36Up();
|
||||||
nsresult MigrateV37Up();
|
nsresult MigrateV37Up();
|
||||||
nsresult MigrateV38Up();
|
nsresult MigrateV38Up();
|
||||||
|
@ -341,6 +336,7 @@ class Database final : public nsIObserver, public nsSupportsWeakReference {
|
||||||
nsresult MigrateV50Up();
|
nsresult MigrateV50Up();
|
||||||
nsresult MigrateV51Up();
|
nsresult MigrateV51Up();
|
||||||
nsresult MigrateV52Up();
|
nsresult MigrateV52Up();
|
||||||
|
nsresult MigrateV53Up();
|
||||||
|
|
||||||
void MigrateV52OriginFrecencies();
|
void MigrateV52OriginFrecencies();
|
||||||
|
|
||||||
|
@ -350,9 +346,6 @@ class Database final : public nsIObserver, public nsSupportsWeakReference {
|
||||||
|
|
||||||
int64_t CreateMobileRoot();
|
int64_t CreateMobileRoot();
|
||||||
nsresult ConvertOldStyleQuery(nsCString& aURL);
|
nsresult ConvertOldStyleQuery(nsCString& aURL);
|
||||||
nsresult GetItemsWithAnno(const nsACString& aAnnoName, int32_t aItemType,
|
|
||||||
nsTArray<int64_t>& aItemIds);
|
|
||||||
nsresult DeleteBookmarkItem(int32_t aItemId);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~Database();
|
~Database();
|
||||||
|
|
|
@ -49,10 +49,6 @@ int64_t NS_NavBookmarksTotalSyncChanges() {
|
||||||
|
|
||||||
PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsNavBookmarks, gBookmarksService)
|
PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsNavBookmarks, gBookmarksService)
|
||||||
|
|
||||||
#define BOOKMARKS_ANNO_PREFIX "bookmarks/"
|
|
||||||
#define BOOKMARKS_TOOLBAR_FOLDER_ANNO \
|
|
||||||
NS_LITERAL_CSTRING(BOOKMARKS_ANNO_PREFIX "toolbarFolder")
|
|
||||||
#define SYNC_PARENT_ANNO "sync/parent"
|
|
||||||
#define SQLITE_MAX_VARIABLE_NUMBER 999
|
#define SQLITE_MAX_VARIABLE_NUMBER 999
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
|
@ -15,8 +15,8 @@ var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
// Put any other stuff relative to this test folder below.
|
// Put any other stuff relative to this test folder below.
|
||||||
|
|
||||||
const CURRENT_SCHEMA_VERSION = 52;
|
const CURRENT_SCHEMA_VERSION = 53;
|
||||||
const FIRST_UPGRADABLE_SCHEMA_VERSION = 30;
|
const FIRST_UPGRADABLE_SCHEMA_VERSION = 35;
|
||||||
|
|
||||||
async function assertAnnotationsRemoved(db, expectedAnnos) {
|
async function assertAnnotationsRemoved(db, expectedAnnos) {
|
||||||
for (let anno of expectedAnnos) {
|
for (let anno of expectedAnnos) {
|
||||||
|
|
Двоичные данные
toolkit/components/places/tests/migration/places_v31.sqlite
Двоичные данные
toolkit/components/places/tests/migration/places_v31.sqlite
Двоичный файл не отображается.
Двоичные данные
toolkit/components/places/tests/migration/places_v34.sqlite
Двоичные данные
toolkit/components/places/tests/migration/places_v34.sqlite
Двоичный файл не отображается.
|
@ -1,46 +0,0 @@
|
||||||
// Add pages.
|
|
||||||
let shorturl = "http://example.com/" + "a".repeat(1981);
|
|
||||||
let longurl = "http://example.com/" + "a".repeat(1982);
|
|
||||||
let bmurl = "http://example.com/" + "a".repeat(1983);
|
|
||||||
|
|
||||||
add_task(async function setup() {
|
|
||||||
await setupPlacesDatabase("places_v31.sqlite");
|
|
||||||
// Setup database contents to be migrated.
|
|
||||||
let path = OS.Path.join(OS.Constants.Path.profileDir, DB_FILENAME);
|
|
||||||
let db = await Sqlite.openConnection({ path });
|
|
||||||
|
|
||||||
await db.execute(`INSERT INTO moz_places (url, guid, foreign_count)
|
|
||||||
VALUES (:shorturl, "test1_______", 0)
|
|
||||||
, (:longurl, "test2_______", 0)
|
|
||||||
, (:bmurl, "test3_______", 1)
|
|
||||||
`, { shorturl, longurl, bmurl });
|
|
||||||
// Add visits.
|
|
||||||
await db.execute(`INSERT INTO moz_historyvisits (place_id)
|
|
||||||
VALUES ((SELECT id FROM moz_places WHERE url = :shorturl))
|
|
||||||
, ((SELECT id FROM moz_places WHERE url = :longurl))
|
|
||||||
`, { shorturl, longurl });
|
|
||||||
await db.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function database_is_valid() {
|
|
||||||
Assert.equal(PlacesUtils.history.databaseStatus,
|
|
||||||
PlacesUtils.history.DATABASE_STATUS_UPGRADED);
|
|
||||||
|
|
||||||
let db = await PlacesUtils.promiseDBConnection();
|
|
||||||
Assert.equal((await db.getSchemaVersion()), CURRENT_SCHEMA_VERSION);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_longurls() {
|
|
||||||
let db = await PlacesUtils.promiseDBConnection();
|
|
||||||
let rows = await db.execute(`SELECT 1 FROM moz_places where url = :longurl`,
|
|
||||||
{ longurl });
|
|
||||||
Assert.equal(rows.length, 0, "Long url should have been removed");
|
|
||||||
rows = await db.execute(`SELECT 1 FROM moz_places where url = :shorturl`,
|
|
||||||
{ shorturl });
|
|
||||||
Assert.equal(rows.length, 1, "Short url should have been retained");
|
|
||||||
rows = await db.execute(`SELECT 1 FROM moz_places where url = :bmurl`,
|
|
||||||
{ bmurl });
|
|
||||||
Assert.equal(rows.length, 1, "Bookmarked url should have been retained");
|
|
||||||
rows = await db.execute(`SELECT count(*) FROM moz_historyvisits`);
|
|
||||||
Assert.equal(rows.length, 1, "Orphan visists should have been removed");
|
|
||||||
});
|
|
|
@ -1,134 +0,0 @@
|
||||||
Cu.importGlobalProperties(["crypto"]);
|
|
||||||
|
|
||||||
const { TYPE_BOOKMARK, TYPE_FOLDER } = Ci.nsINavBookmarksService;
|
|
||||||
const { EXPIRE_NEVER, TYPE_INT32 } = Ci.nsIAnnotationService;
|
|
||||||
|
|
||||||
function makeGuid() {
|
|
||||||
return ChromeUtils.base64URLEncode(crypto.getRandomValues(new Uint8Array(9)), {
|
|
||||||
pad: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// These queries are more or less copied directly from Bookmarks.jsm, but
|
|
||||||
// operate on the old, pre-migration DB. We can't use any of the Places SQL
|
|
||||||
// functions yet, because those are only registered for the main connection.
|
|
||||||
async function insertItem(db, info) {
|
|
||||||
let [parentInfo] = await db.execute(`
|
|
||||||
SELECT b.id, (SELECT count(*) FROM moz_bookmarks
|
|
||||||
WHERE parent = b.id) AS childCount
|
|
||||||
FROM moz_bookmarks b
|
|
||||||
WHERE b.guid = :parentGuid`,
|
|
||||||
{ parentGuid: info.parentGuid });
|
|
||||||
|
|
||||||
let guid = makeGuid();
|
|
||||||
await db.execute(`
|
|
||||||
INSERT INTO moz_bookmarks (fk, type, parent, position, guid)
|
|
||||||
VALUES ((SELECT id FROM moz_places WHERE url = :url),
|
|
||||||
:type, :parent, :position, :guid)`,
|
|
||||||
{ url: info.url || "nonexistent", type: info.type, guid,
|
|
||||||
// Just append items.
|
|
||||||
position: parentInfo.getResultByName("childCount"),
|
|
||||||
parent: parentInfo.getResultByName("id") });
|
|
||||||
|
|
||||||
let id = (await db.execute(`
|
|
||||||
SELECT id FROM moz_bookmarks WHERE guid = :guid LIMIT 1`,
|
|
||||||
{ guid }))[0].getResultByName("id");
|
|
||||||
|
|
||||||
return { id, guid };
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertBookmark(db, info) {
|
|
||||||
return db.executeTransaction(async function() {
|
|
||||||
if (info.type == TYPE_BOOKMARK) {
|
|
||||||
// We don't have access to the hash function here, so we omit the
|
|
||||||
// `url_hash` column. These will be fixed up automatically during
|
|
||||||
// migration.
|
|
||||||
let url = new URL(info.url);
|
|
||||||
let placeGuid = makeGuid();
|
|
||||||
await db.execute(`
|
|
||||||
INSERT INTO moz_places (url, rev_host, hidden, frecency, guid)
|
|
||||||
VALUES (:url, :rev_host, 0, -1, :guid)`,
|
|
||||||
{ url: url.href, guid: placeGuid,
|
|
||||||
rev_host: PlacesUtils.getReversedHost(url) });
|
|
||||||
}
|
|
||||||
return insertItem(db, info);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function insertAnno(db, itemId, name, value) {
|
|
||||||
await db.execute(`INSERT OR IGNORE INTO moz_anno_attributes (name)
|
|
||||||
VALUES (:name)`, { name });
|
|
||||||
await db.execute(`
|
|
||||||
INSERT INTO moz_items_annos
|
|
||||||
(item_id, anno_attribute_id, content, flags,
|
|
||||||
expiration, type, dateAdded, lastModified)
|
|
||||||
VALUES (:itemId,
|
|
||||||
(SELECT id FROM moz_anno_attributes
|
|
||||||
WHERE name = :name),
|
|
||||||
1, 0, :expiration, :type, 0, 0)
|
|
||||||
`, { itemId, name, expiration: EXPIRE_NEVER, type: TYPE_INT32 });
|
|
||||||
}
|
|
||||||
|
|
||||||
function insertMobileFolder(db) {
|
|
||||||
return db.executeTransaction(async function() {
|
|
||||||
let item = await insertItem(db, {
|
|
||||||
type: TYPE_FOLDER,
|
|
||||||
parentGuid: "root________",
|
|
||||||
});
|
|
||||||
await insertAnno(db, item.id, "mobile/bookmarksRoot", 1);
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var mobileId, mobileGuid, fxGuid;
|
|
||||||
var dupeMobileId, dupeMobileGuid, tbGuid;
|
|
||||||
|
|
||||||
add_task(async function setup() {
|
|
||||||
await setupPlacesDatabase("places_v34.sqlite");
|
|
||||||
// Setup database contents to be migrated.
|
|
||||||
let path = OS.Path.join(OS.Constants.Path.profileDir, DB_FILENAME);
|
|
||||||
let db = await Sqlite.openConnection({ path });
|
|
||||||
|
|
||||||
info("Create mobile folder with bookmarks");
|
|
||||||
({ id: mobileId, guid: mobileGuid } = await insertMobileFolder(db));
|
|
||||||
({ guid: fxGuid } = await insertBookmark(db, {
|
|
||||||
type: TYPE_BOOKMARK,
|
|
||||||
url: "http://getfirefox.com",
|
|
||||||
parentGuid: mobileGuid,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// We should only have one mobile folder, but, in case an old version of Sync
|
|
||||||
// did the wrong thing and created multiple mobile folders, we should merge
|
|
||||||
// their contents into the new mobile root.
|
|
||||||
info("Create second mobile folder with different bookmarks");
|
|
||||||
({ id: dupeMobileId, guid: dupeMobileGuid } = await insertMobileFolder(db));
|
|
||||||
({ guid: tbGuid } = await insertBookmark(db, {
|
|
||||||
type: TYPE_BOOKMARK,
|
|
||||||
url: "http://getthunderbird.com",
|
|
||||||
parentGuid: dupeMobileGuid,
|
|
||||||
}));
|
|
||||||
|
|
||||||
await db.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function database_is_valid() {
|
|
||||||
// Accessing the database for the first time triggers migration.
|
|
||||||
Assert.equal(PlacesUtils.history.databaseStatus,
|
|
||||||
PlacesUtils.history.DATABASE_STATUS_UPGRADED);
|
|
||||||
|
|
||||||
let db = await PlacesUtils.promiseDBConnection();
|
|
||||||
Assert.equal((await db.getSchemaVersion()), CURRENT_SCHEMA_VERSION);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function test_mobile_root() {
|
|
||||||
let fxBmk = await PlacesUtils.bookmarks.fetch(fxGuid);
|
|
||||||
equal(fxBmk.parentGuid, PlacesUtils.bookmarks.mobileGuid,
|
|
||||||
"Firefox bookmark should be moved to new mobile root");
|
|
||||||
equal(fxBmk.index, 0, "Firefox bookmark should be first child of new root");
|
|
||||||
|
|
||||||
let tbBmk = await PlacesUtils.bookmarks.fetch(tbGuid);
|
|
||||||
equal(tbBmk.parentGuid, PlacesUtils.bookmarks.mobileGuid,
|
|
||||||
"Thunderbird bookmark should be moved to new mobile root");
|
|
||||||
equal(tbBmk.index, 1,
|
|
||||||
"Thunderbird bookmark should be second child of new root");
|
|
||||||
});
|
|
|
@ -1,21 +0,0 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
||||||
|
|
||||||
add_task(async function setup() {
|
|
||||||
await setupPlacesDatabase("places_v34.sqlite");
|
|
||||||
// Setup database contents to be migrated.
|
|
||||||
let path = OS.Path.join(OS.Constants.Path.profileDir, DB_FILENAME);
|
|
||||||
let db = await Sqlite.openConnection({ path });
|
|
||||||
// Remove all the roots.
|
|
||||||
await db.execute("DELETE FROM moz_bookmarks");
|
|
||||||
await db.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
add_task(async function database_is_valid() {
|
|
||||||
// Accessing the database for the first time triggers migration.
|
|
||||||
Assert.equal(PlacesUtils.history.databaseStatus,
|
|
||||||
PlacesUtils.history.DATABASE_STATUS_UPGRADED);
|
|
||||||
|
|
||||||
let db = await PlacesUtils.promiseDBConnection();
|
|
||||||
Assert.equal((await db.getSchemaVersion()), CURRENT_SCHEMA_VERSION);
|
|
||||||
});
|
|
|
@ -4,8 +4,6 @@ head = head_migration.js
|
||||||
support-files =
|
support-files =
|
||||||
favicons_v41.sqlite
|
favicons_v41.sqlite
|
||||||
places_outdated.sqlite
|
places_outdated.sqlite
|
||||||
places_v31.sqlite
|
|
||||||
places_v34.sqlite
|
|
||||||
places_v35.sqlite
|
places_v35.sqlite
|
||||||
places_v36.sqlite
|
places_v36.sqlite
|
||||||
places_v38.sqlite
|
places_v38.sqlite
|
||||||
|
@ -14,9 +12,6 @@ support-files =
|
||||||
|
|
||||||
[test_current_from_downgraded.js]
|
[test_current_from_downgraded.js]
|
||||||
[test_current_from_outdated.js]
|
[test_current_from_outdated.js]
|
||||||
[test_current_from_v31.js]
|
|
||||||
[test_current_from_v34.js]
|
|
||||||
[test_current_from_v34_no_roots.js]
|
|
||||||
[test_current_from_v35.js]
|
[test_current_from_v35.js]
|
||||||
[test_current_from_v36.js]
|
[test_current_from_v36.js]
|
||||||
[test_current_from_v38.js]
|
[test_current_from_v38.js]
|
||||||
|
|
Загрузка…
Ссылка в новой задаче