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:
Marco Bonardo 2019-06-05 10:25:13 +00:00
Родитель 68f8760568
Коммит 9793f55d17
10 изменённых файлов: 57 добавлений и 576 удалений

Просмотреть файл

@ -101,16 +101,6 @@
// How much time Sqlite can wait before returning a SQLITE_BUSY error.
#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.
#define LAST_USED_ANNO \
NS_LITERAL_CSTRING("bookmarkPropertiesDialog/folderLastUsed")
@ -123,6 +113,9 @@
// sets the title to the localized version when it creates the left pane query.
#define MOBILE_ROOT_TITLE "mobile"
// Legacy item annotation used by the old Sync engine.
#define SYNC_PARENT_ANNO "sync/parent"
using namespace mozilla;
namespace mozilla {
@ -1138,51 +1131,13 @@ nsresult Database::InitSchema(bool* aDatabaseMigrated) {
if (currentSchemaVersion < DATABASE_SCHEMA_VERSION) {
*aDatabaseMigrated = true;
if (currentSchemaVersion < 30) {
// These are versions older than Firefox 45 that are not supported
if (currentSchemaVersion < 35) {
// These are versions older than Firefox 52 ESR that are not supported
// 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;
}
// Firefox 45 ESR uses schema version 30.
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.
// Firefox 52 ESR uses schema version 35.
if (currentSchemaVersion < 36) {
rv = MigrateV36Up();
@ -1208,7 +1163,7 @@ nsresult Database::InitSchema(bool* aDatabaseMigrated) {
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) {
rv = MigrateV40Up();
@ -1232,7 +1187,7 @@ nsresult Database::InitSchema(bool* aDatabaseMigrated) {
NS_ENSURE_SUCCESS(rv, rv);
}
// Firefox 60 uses schema version 43.
// Firefox 60 uses schema version 43. - This is an ESR.
if (currentSchemaVersion < 44) {
rv = MigrateV44Up();
@ -1283,6 +1238,13 @@ nsresult Database::InitSchema(bool* aDatabaseMigrated) {
// 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.
// >>> IMPORTANT! <<<
// NEVER MIX UP SYNC AND ASYNC EXECUTION IN MIGRATORS, YOU MAY LOCK THE
@ -1694,247 +1656,6 @@ nsresult Database::InitTempEntities() {
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() {
// Add sync status and change counter tracking columns for bookmarks.
nsCOMPtr<mozIStorageStatement> syncStatusStmt;
@ -2688,6 +2409,44 @@ nsresult Database::MigrateV52Up() {
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) {
AutoTArray<QueryKeyValuePair, 8> tokens;
nsresult rv = TokenizeQueryString(aURL, &tokens);
@ -2765,67 +2524,6 @@ nsresult Database::ConvertOldStyleQuery(nsCString& aURL) {
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() {
MOZ_ASSERT(NS_IsMainThread());

Просмотреть файл

@ -19,7 +19,7 @@
// This is the schema version. Update it at any schema change and add a
// corresponding migrateVxx method below.
#define DATABASE_SCHEMA_VERSION 52
#define DATABASE_SCHEMA_VERSION 53
// Fired after Places inited.
#define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
@ -319,11 +319,6 @@ class Database final : public nsIObserver, public nsSupportsWeakReference {
/**
* Helpers used by schema upgrades.
*/
nsresult MigrateV31Up();
nsresult MigrateV32Up();
nsresult MigrateV33Up();
nsresult MigrateV34Up();
nsresult MigrateV35Up();
nsresult MigrateV36Up();
nsresult MigrateV37Up();
nsresult MigrateV38Up();
@ -341,6 +336,7 @@ class Database final : public nsIObserver, public nsSupportsWeakReference {
nsresult MigrateV50Up();
nsresult MigrateV51Up();
nsresult MigrateV52Up();
nsresult MigrateV53Up();
void MigrateV52OriginFrecencies();
@ -350,9 +346,6 @@ class Database final : public nsIObserver, public nsSupportsWeakReference {
int64_t CreateMobileRoot();
nsresult ConvertOldStyleQuery(nsCString& aURL);
nsresult GetItemsWithAnno(const nsACString& aAnnoName, int32_t aItemType,
nsTArray<int64_t>& aItemIds);
nsresult DeleteBookmarkItem(int32_t aItemId);
private:
~Database();

Просмотреть файл

@ -49,10 +49,6 @@ int64_t NS_NavBookmarksTotalSyncChanges() {
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
namespace {

Просмотреть файл

@ -15,8 +15,8 @@ var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
// Put any other stuff relative to this test folder below.
const CURRENT_SCHEMA_VERSION = 52;
const FIRST_UPGRADABLE_SCHEMA_VERSION = 30;
const CURRENT_SCHEMA_VERSION = 53;
const FIRST_UPGRADABLE_SCHEMA_VERSION = 35;
async function assertAnnotationsRemoved(db, expectedAnnos) {
for (let anno of expectedAnnos) {

Двоичный файл не отображается.

Двоичный файл не отображается.

Просмотреть файл

@ -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 =
favicons_v41.sqlite
places_outdated.sqlite
places_v31.sqlite
places_v34.sqlite
places_v35.sqlite
places_v36.sqlite
places_v38.sqlite
@ -14,9 +12,6 @@ support-files =
[test_current_from_downgraded.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_v36.js]
[test_current_from_v38.js]