mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
Bug 889561 - Reduce the size of places.sqlite by removing the url unique index from moz_places. r=adw
MozReview-Commit-ID: 2kxaXnUYIwT --HG-- extra : rebase_source : e03928033aa795c9a1cdb34d4f4618b0eb1d6890
This commit is contained in:
parent
ea25947578
commit
67c3ad7930
@ -58,7 +58,8 @@ function* getTransitionForUrl(url) {
|
||||
let rows = yield db.execute(`
|
||||
SELECT visit_type
|
||||
FROM moz_historyvisits
|
||||
WHERE place_id = (SELECT id FROM moz_places WHERE url = :url)`,
|
||||
JOIN moz_places h ON place_id = h.id
|
||||
WHERE url_hash = hash(:url) AND url = :url`,
|
||||
{ url });
|
||||
if (rows.length) {
|
||||
return rows[0].getResultByName("visit_type");
|
||||
|
@ -1094,7 +1094,7 @@ BookmarksStore.prototype = {
|
||||
return this._getStmt(
|
||||
"SELECT frecency " +
|
||||
"FROM moz_places " +
|
||||
"WHERE url = :url " +
|
||||
"WHERE url_hash = hash(:url) AND url = :url " +
|
||||
"LIMIT 1");
|
||||
},
|
||||
_frecencyCols: ["frecency"],
|
||||
|
@ -105,7 +105,7 @@ HistoryStore.prototype = {
|
||||
return this._getStmt(
|
||||
"UPDATE moz_places " +
|
||||
"SET guid = :guid " +
|
||||
"WHERE url = :page_url");
|
||||
"WHERE url_hash = hash(:page_url) AND url = :page_url");
|
||||
},
|
||||
|
||||
// Some helper functions to handle GUIDs
|
||||
@ -127,7 +127,7 @@ HistoryStore.prototype = {
|
||||
return this._getStmt(
|
||||
"SELECT guid " +
|
||||
"FROM moz_places " +
|
||||
"WHERE url = :page_url");
|
||||
"WHERE url_hash = hash(:page_url) AND url = :page_url");
|
||||
},
|
||||
_guidCols: ["guid"],
|
||||
|
||||
@ -146,12 +146,12 @@ HistoryStore.prototype = {
|
||||
},
|
||||
|
||||
get _visitStm() {
|
||||
return this._getStmt(
|
||||
"/* do not warn (bug 599936) */ " +
|
||||
"SELECT visit_type type, visit_date date " +
|
||||
"FROM moz_historyvisits " +
|
||||
"WHERE place_id = (SELECT id FROM moz_places WHERE url = :url) " +
|
||||
"ORDER BY date DESC LIMIT 20");
|
||||
return this._getStmt(`/* do not warn (bug 599936) */
|
||||
SELECT visit_type type, visit_date date
|
||||
FROM moz_historyvisits
|
||||
JOIN moz_places h ON h.id = place_id
|
||||
WHERE url_hash = hash(:url) AND url = :url
|
||||
ORDER BY date DESC LIMIT 20`);
|
||||
},
|
||||
_visitCols: ["date", "type"],
|
||||
|
||||
|
@ -24,7 +24,7 @@ add_task(function* test_ignore_invalid_uri() {
|
||||
// Now update moz_places with an invalid url.
|
||||
yield PlacesUtils.withConnectionWrapper("test_ignore_invalid_uri", Task.async(function* (db) {
|
||||
yield db.execute(
|
||||
`UPDATE moz_places SET url = :url
|
||||
`UPDATE moz_places SET url = :url, url_hash = hash(:url)
|
||||
WHERE id = (SELECT b.fk FROM moz_bookmarks b
|
||||
WHERE b.id = :id LIMIT 1)`,
|
||||
{ id: bmid, url: "<invalid url>" });
|
||||
|
@ -189,8 +189,8 @@ add_test(function test_invalid_records() {
|
||||
.DBConnection;
|
||||
let stmt = connection.createAsyncStatement(
|
||||
"INSERT INTO moz_places "
|
||||
+ "(url, title, rev_host, visit_count, last_visit_date) "
|
||||
+ "VALUES ('invalid-uri', 'Invalid URI', '.', 1, " + TIMESTAMP3 + ")"
|
||||
+ "(url, url_hash, title, rev_host, visit_count, last_visit_date) "
|
||||
+ "VALUES ('invalid-uri', hash('invalid-uri'), 'Invalid URI', '.', 1, " + TIMESTAMP3 + ")"
|
||||
);
|
||||
Async.querySpinningly(stmt);
|
||||
stmt.finalize();
|
||||
@ -198,7 +198,7 @@ add_test(function test_invalid_records() {
|
||||
stmt = connection.createAsyncStatement(
|
||||
"INSERT INTO moz_historyvisits "
|
||||
+ "(place_id, visit_date, visit_type, session) "
|
||||
+ "VALUES ((SELECT id FROM moz_places WHERE url = 'invalid-uri'), "
|
||||
+ "VALUES ((SELECT id FROM moz_places WHERE url_hash = hash('invalid-uri') AND url = 'invalid-uri'), "
|
||||
+ TIMESTAMP3 + ", " + Ci.nsINavHistoryService.TRANSITION_TYPED + ", 1)"
|
||||
);
|
||||
Async.querySpinningly(stmt);
|
||||
|
@ -70,7 +70,7 @@ var HistoryEntry = {
|
||||
"WHERE place_id = (" +
|
||||
"SELECT id " +
|
||||
"FROM moz_places " +
|
||||
"WHERE url = :url) " +
|
||||
"WHERE url_hash = hash(:url) AND url = :url) " +
|
||||
"ORDER BY date DESC LIMIT 20");
|
||||
this.__defineGetter__("_visitStm", () => stm);
|
||||
return stm;
|
||||
|
@ -776,14 +776,10 @@ function updateBookmark(info, item, newParent) {
|
||||
yield db.executeTransaction(function* () {
|
||||
if (info.hasOwnProperty("url")) {
|
||||
// Ensure a page exists in moz_places for this URL.
|
||||
yield db.executeCached(
|
||||
`INSERT OR IGNORE INTO moz_places (url, rev_host, hidden, frecency, guid)
|
||||
VALUES (:url, :rev_host, 0, :frecency, GENERATE_GUID())
|
||||
`, { url: info.url ? info.url.href : null,
|
||||
rev_host: PlacesUtils.getReversedHost(info.url),
|
||||
frecency: info.url.protocol == "place:" ? 0 : -1 });
|
||||
yield maybeInsertPlace(db, info.url);
|
||||
// Update tuples for the update query.
|
||||
tuples.set("url", { value: info.url.href
|
||||
, fragment: "fk = (SELECT id FROM moz_places WHERE url = :url)" });
|
||||
, fragment: "fk = (SELECT id FROM moz_places WHERE url_hash = hash(:url) AND url = :url)" });
|
||||
}
|
||||
|
||||
if (newParent) {
|
||||
@ -864,11 +860,8 @@ function insertBookmark(item, parent) {
|
||||
yield db.executeTransaction(function* transaction() {
|
||||
if (item.type == Bookmarks.TYPE_BOOKMARK) {
|
||||
// Ensure a page exists in moz_places for this URL.
|
||||
yield db.executeCached(
|
||||
`INSERT OR IGNORE INTO moz_places (url, rev_host, hidden, frecency, guid)
|
||||
VALUES (:url, :rev_host, 0, :frecency, GENERATE_GUID())
|
||||
`, { url: item.url.href, rev_host: PlacesUtils.getReversedHost(item.url),
|
||||
frecency: item.url.protocol == "place:" ? 0 : -1 });
|
||||
// The IGNORE conflict can trigger on `guid`.
|
||||
yield maybeInsertPlace(db, item.url);
|
||||
}
|
||||
|
||||
// Adjust indices.
|
||||
@ -882,7 +875,7 @@ function insertBookmark(item, parent) {
|
||||
yield db.executeCached(
|
||||
`INSERT INTO moz_bookmarks (fk, type, parent, position, title,
|
||||
dateAdded, lastModified, guid)
|
||||
VALUES ((SELECT id FROM moz_places WHERE url = :url), :type, :parent,
|
||||
VALUES ((SELECT id FROM moz_places WHERE url_hash = hash(:url) AND url = :url), :type, :parent,
|
||||
:index, :title, :date_added, :last_modified, :guid)
|
||||
`, { url: item.hasOwnProperty("url") ? item.url.href : "nonexistent",
|
||||
type: item.type, parent: parent._id, index: item.index,
|
||||
@ -1018,7 +1011,7 @@ function fetchBookmarksByURL(info) {
|
||||
FROM moz_bookmarks b
|
||||
LEFT JOIN moz_bookmarks p ON p.id = b.parent
|
||||
LEFT JOIN moz_places h ON h.id = b.fk
|
||||
WHERE h.url = :url
|
||||
WHERE h.url_hash = hash(:url) AND h.url = :url
|
||||
AND _grandParentId <> :tags_folder
|
||||
ORDER BY b.lastModified DESC
|
||||
`, { url: info.url.href,
|
||||
@ -1398,17 +1391,18 @@ function validateBookmarkObject(input, behavior={}) {
|
||||
* the array of URLs to update.
|
||||
*/
|
||||
var updateFrecency = Task.async(function* (db, urls) {
|
||||
// We just use the hashes, since updating a few additional urls won't hurt.
|
||||
yield db.execute(
|
||||
`UPDATE moz_places
|
||||
SET frecency = NOTIFY_FRECENCY(
|
||||
CALCULATE_FRECENCY(id), url, guid, hidden, last_visit_date
|
||||
) WHERE url IN ( ${urls.map(url => JSON.stringify(url.href)).join(", ")} )
|
||||
) WHERE url_hash IN ( ${urls.map(url => `hash("${url.href}")`).join(", ")} )
|
||||
`);
|
||||
|
||||
yield db.execute(
|
||||
`UPDATE moz_places
|
||||
SET hidden = 0
|
||||
WHERE url IN ( ${urls.map(url => JSON.stringify(url.href)).join(", ")} )
|
||||
WHERE url_hash IN ( ${urls.map(url => `hash(${JSON.stringify(url.href)})`).join(", ")} )
|
||||
AND frecency <> 0
|
||||
`);
|
||||
});
|
||||
@ -1564,3 +1558,21 @@ Task.async(function* (db, folderGuids) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Tries to insert a new place if it doesn't exist yet.
|
||||
* @param url
|
||||
* A valid URL object.
|
||||
* @return {Promise} resolved when the operation is complete.
|
||||
*/
|
||||
function maybeInsertPlace(db, url) {
|
||||
// The IGNORE conflict can trigger on `guid`.
|
||||
return db.executeCached(
|
||||
`INSERT OR IGNORE INTO moz_places (url, url_hash, rev_host, hidden, frecency, guid)
|
||||
VALUES (:url, hash(:url), :rev_host, 0, :frecency,
|
||||
IFNULL((SELECT guid FROM moz_places WHERE url_hash = hash(:url) AND url = :url),
|
||||
GENERATE_GUID()))
|
||||
`, { url: url.href,
|
||||
rev_host: PlacesUtils.getReversedHost(url),
|
||||
frecency: url.protocol == "place:" ? 0 : -1 });
|
||||
}
|
||||
|
@ -847,6 +847,13 @@ Database::InitSchema(bool* aDatabaseMigrated)
|
||||
|
||||
// Firefox 49 uses schema version 32.
|
||||
|
||||
if (currentSchemaVersion < 33) {
|
||||
rv = MigrateV33Up();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Firefox 50 uses schema version 33.
|
||||
|
||||
// Schema Upgrades must add migration code here.
|
||||
|
||||
rv = UpdateBookmarkRootTitles();
|
||||
@ -861,7 +868,7 @@ Database::InitSchema(bool* aDatabaseMigrated)
|
||||
// moz_places.
|
||||
rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_PLACES);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_URL);
|
||||
rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_URL_HASH);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_FAVICON);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -1039,6 +1046,8 @@ Database::InitFunctions()
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = StoreLastInsertedIdFunction::create(mMainConn);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = HashFunction::create(mMainConn);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1771,6 +1780,39 @@ Database::MigrateV32Up() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Database::MigrateV33Up() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
Database::Shutdown()
|
||||
{
|
||||
@ -1802,7 +1844,7 @@ Database::Shutdown()
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
rv = stmt->ExecuteStep(&haveNullGuids);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
MOZ_ASSERT(!haveNullGuids && "Found a page without a GUID!");
|
||||
MOZ_ASSERT(!haveNullGuids, "Found a page without a GUID!");
|
||||
|
||||
rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT 1 "
|
||||
@ -1812,7 +1854,7 @@ Database::Shutdown()
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
rv = stmt->ExecuteStep(&haveNullGuids);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
MOZ_ASSERT(!haveNullGuids && "Found a bookmark without a GUID!");
|
||||
MOZ_ASSERT(!haveNullGuids, "Found a bookmark without a GUID!");
|
||||
}
|
||||
|
||||
{ // Sanity check for unrounded dateAdded and lastModified values (bug
|
||||
@ -1828,7 +1870,31 @@ Database::Shutdown()
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
rv = stmt->ExecuteStep(&hasUnroundedDates);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
MOZ_ASSERT(!hasUnroundedDates && "Found unrounded dates!");
|
||||
MOZ_ASSERT(!hasUnroundedDates, "Found unrounded dates!");
|
||||
}
|
||||
|
||||
{ // Sanity check url_hash
|
||||
bool hasNullHash = false;
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT 1 FROM moz_places WHERE url_hash = 0"
|
||||
), getter_AddRefs(stmt));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
rv = stmt->ExecuteStep(&hasNullHash);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
MOZ_ASSERT(!hasNullHash, "Found a place without a hash!");
|
||||
}
|
||||
|
||||
{ // Sanity check unique urls
|
||||
bool hasDupeUrls = false;
|
||||
nsCOMPtr<mozIStorageStatement> stmt;
|
||||
nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT 1 FROM moz_places GROUP BY url HAVING count(*) > 1 "
|
||||
), getter_AddRefs(stmt));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
rv = stmt->ExecuteStep(&hasDupeUrls);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
MOZ_ASSERT(!hasDupeUrls, "Found a duplicate url!");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
// This is the schema version. Update it at any schema change and add a
|
||||
// corresponding migrateVxx method below.
|
||||
#define DATABASE_SCHEMA_VERSION 32
|
||||
#define DATABASE_SCHEMA_VERSION 33
|
||||
|
||||
// Fired after Places inited.
|
||||
#define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
|
||||
@ -268,6 +268,7 @@ protected:
|
||||
nsresult MigrateV30Up();
|
||||
nsresult MigrateV31Up();
|
||||
nsresult MigrateV32Up();
|
||||
nsresult MigrateV33Up();
|
||||
|
||||
nsresult UpdateBookmarkRootTitles();
|
||||
|
||||
|
@ -63,7 +63,7 @@ FetchPageInfo(const RefPtr<Database>& aDB,
|
||||
"AND EXISTS(SELECT 1 FROM moz_bookmarks b WHERE b.fk = r_place_id) "
|
||||
"LIMIT 1 "
|
||||
") "
|
||||
") FROM moz_places h WHERE h.url = :page_url",
|
||||
") FROM moz_places h WHERE h.url_hash = hash(:page_url) AND h.url = :page_url",
|
||||
nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
|
||||
nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY,
|
||||
nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
|
||||
@ -248,7 +248,7 @@ FetchIconURL(const RefPtr<Database>& aDB,
|
||||
"SELECT f.url "
|
||||
"FROM moz_places h "
|
||||
"JOIN moz_favicons f ON h.favicon_id = f.id "
|
||||
"WHERE h.url = :page_url"
|
||||
"WHERE h.url_hash = hash(:page_url) AND h.url = :page_url"
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
@ -696,7 +696,8 @@ AsyncAssociateIconToPage::Run()
|
||||
}
|
||||
else {
|
||||
stmt = DB->GetStatement(
|
||||
"UPDATE moz_places SET favicon_id = :icon_id WHERE url = :page_url"
|
||||
"UPDATE moz_places SET favicon_id = :icon_id "
|
||||
"WHERE url_hash = hash(:page_url) AND url = :page_url"
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mPage.spec);
|
||||
|
@ -1957,7 +1957,7 @@ public:
|
||||
if (!mIsVisitedStatement) {
|
||||
(void)mReadOnlyDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT 1 FROM moz_places h "
|
||||
"WHERE url = ?1 AND last_visit_date NOTNULL "
|
||||
"WHERE url_hash = hash(?1) AND url = ?1 AND last_visit_date NOTNULL "
|
||||
), getter_AddRefs(mIsVisitedStatement));
|
||||
MOZ_ASSERT(mIsVisitedStatement);
|
||||
nsresult result = mIsVisitedStatement ? NS_OK : NS_ERROR_NOT_AVAILABLE;
|
||||
@ -2037,8 +2037,8 @@ History::InsertPlace(VisitData& aPlace)
|
||||
|
||||
nsCOMPtr<mozIStorageStatement> stmt = GetStatement(
|
||||
"INSERT INTO moz_places "
|
||||
"(url, title, rev_host, hidden, typed, frecency, guid) "
|
||||
"VALUES (:url, :title, :rev_host, :hidden, :typed, :frecency, :guid) "
|
||||
"(url, url_hash, title, rev_host, hidden, typed, frecency, guid) "
|
||||
"VALUES (:url, hash(:url), :title, :rev_host, :hidden, :typed, :frecency, :guid) "
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
@ -2147,7 +2147,7 @@ History::FetchPageInfo(VisitData& _place, bool* _exists)
|
||||
"(SELECT id FROM moz_historyvisits "
|
||||
"WHERE place_id = h.id AND visit_date = h.last_visit_date) AS last_visit_id "
|
||||
"FROM moz_places h "
|
||||
"WHERE url = :page_url "
|
||||
"WHERE url_hash = hash(:page_url) AND url = :page_url "
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
|
||||
|
@ -638,7 +638,8 @@ var clear = Task.async(function* (db) {
|
||||
yield db.execute(
|
||||
`UPDATE moz_places SET frecency =
|
||||
(CASE
|
||||
WHEN url BETWEEN 'place:' AND 'place;'
|
||||
WHEN url_hash BETWEEN hash("place", "prefix_lo") AND
|
||||
hash("place", "prefix_hi")
|
||||
THEN 0
|
||||
ELSE -1
|
||||
END)
|
||||
@ -862,10 +863,12 @@ var removeVisitsByFilter = Task.async(function*(db, filter, onResult = null) {
|
||||
var remove = Task.async(function*(db, {guids, urls}, onResult = null) {
|
||||
// 1. Find out what needs to be removed
|
||||
let query =
|
||||
`SELECT id, url, guid, foreign_count, title, frecency FROM moz_places
|
||||
`SELECT id, url, guid, foreign_count, title, frecency
|
||||
FROM moz_places
|
||||
WHERE guid IN (${ sqlList(guids) })
|
||||
OR url IN (${ sqlList(urls) })
|
||||
`;
|
||||
OR (url_hash IN (${ urls.map(u => "hash(" + JSON.stringify(u) + ")").join(",") })
|
||||
AND url IN (${ sqlList(urls) }))
|
||||
`;
|
||||
|
||||
let onResultData = onResult ? [] : null;
|
||||
let pages = [];
|
||||
|
@ -718,9 +718,15 @@ this.PlacesDBUtils = {
|
||||
// L.4 recalculate foreign_count.
|
||||
let fixForeignCount = DBConn.createAsyncStatement(
|
||||
`UPDATE moz_places SET foreign_count =
|
||||
(SELECT count(*) FROM moz_bookmarks WHERE fk = moz_places.id )`);
|
||||
(SELECT count(*) FROM moz_bookmarks WHERE fk = moz_places.id ) +
|
||||
(SELECT count(*) FROM moz_keywords WHERE place_id = moz_places.id )`);
|
||||
cleanupStatements.push(fixForeignCount);
|
||||
|
||||
// L.5 recalculate missing hashes.
|
||||
let fixMissingHashes = DBConn.createAsyncStatement(
|
||||
`UPDATE moz_places SET url_hash = hash(url) WHERE url_hash = 0`);
|
||||
cleanupStatements.push(fixMissingHashes);
|
||||
|
||||
// MAINTENANCE STATEMENTS SHOULD GO ABOVE THIS POINT!
|
||||
|
||||
return cleanupStatements;
|
||||
|
@ -1304,7 +1304,7 @@ this.PlacesUtils = {
|
||||
let conn = yield this.promiseDBConnection();
|
||||
const QUERY_STR = `SELECT b.id FROM moz_bookmarks b
|
||||
JOIN moz_places h on h.id = b.fk
|
||||
WHERE h.url = :url`;
|
||||
WHERE h.url_hash = hash(:url) AND h.url = :url`;
|
||||
let spec = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
|
||||
yield conn.executeCached(QUERY_STR, { url: spec }, aRow => {
|
||||
if (abort)
|
||||
@ -2061,22 +2061,24 @@ var Keywords = {
|
||||
if (oldEntry) {
|
||||
yield db.executeCached(
|
||||
`UPDATE moz_keywords
|
||||
SET place_id = (SELECT id FROM moz_places WHERE url = :url),
|
||||
SET place_id = (SELECT id FROM moz_places WHERE url_hash = hash(:url) AND url = :url),
|
||||
post_data = :post_data
|
||||
WHERE keyword = :keyword
|
||||
`, { url: url.href, keyword: keyword, post_data: postData });
|
||||
yield notifyKeywordChange(oldEntry.url.href, "");
|
||||
} else {
|
||||
// An entry for the given page could be missing, in such a case we need to
|
||||
// create it.
|
||||
// create it. The IGNORE conflict can trigger on `guid`.
|
||||
yield db.executeCached(
|
||||
`INSERT OR IGNORE INTO moz_places (url, rev_host, hidden, frecency, guid)
|
||||
VALUES (:url, :rev_host, 0, :frecency, GENERATE_GUID())
|
||||
`INSERT OR IGNORE INTO moz_places (url, url_hash, rev_host, hidden, frecency, guid)
|
||||
VALUES (:url, hash(:url), :rev_host, 0, :frecency,
|
||||
IFNULL((SELECT guid FROM moz_places WHERE url_hash = hash(:url) AND url = :url),
|
||||
GENERATE_GUID()))
|
||||
`, { url: url.href, rev_host: PlacesUtils.getReversedHost(url),
|
||||
frecency: url.protocol == "place:" ? 0 : -1 });
|
||||
yield db.executeCached(
|
||||
`INSERT INTO moz_keywords (keyword, place_id, post_data)
|
||||
VALUES (:keyword, (SELECT id FROM moz_places WHERE url = :url), :post_data)
|
||||
VALUES (:keyword, (SELECT id FROM moz_places WHERE url_hash = hash(:url) AND url = :url), :post_data)
|
||||
`, { url: url.href, keyword: keyword, post_data: postData });
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "nsNavHistory.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "nsVariant.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
|
||||
// Maximum number of chars to search through.
|
||||
// MatchAutoCompleteFunction won't look for matches over this threshold.
|
||||
@ -183,13 +184,6 @@ namespace places {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// AutoComplete Matching Function
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// MatchAutoCompleteFunction
|
||||
|
||||
MatchAutoCompleteFunction::~MatchAutoCompleteFunction()
|
||||
{
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
MatchAutoCompleteFunction::create(mozIStorageConnection *aDBConn)
|
||||
@ -328,9 +322,6 @@ namespace places {
|
||||
mozIStorageFunction
|
||||
)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// mozIStorageFunction
|
||||
|
||||
NS_IMETHODIMP
|
||||
MatchAutoCompleteFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
|
||||
nsIVariant **_result)
|
||||
@ -438,13 +429,6 @@ namespace places {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Frecency Calculation Function
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// CalculateFrecencyFunction
|
||||
|
||||
CalculateFrecencyFunction::~CalculateFrecencyFunction()
|
||||
{
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
CalculateFrecencyFunction::create(mozIStorageConnection *aDBConn)
|
||||
@ -465,9 +449,6 @@ namespace places {
|
||||
mozIStorageFunction
|
||||
)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// mozIStorageFunction
|
||||
|
||||
NS_IMETHODIMP
|
||||
CalculateFrecencyFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
|
||||
nsIVariant **_result)
|
||||
@ -628,13 +609,6 @@ namespace places {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// GUID Creation Function
|
||||
|
||||
GenerateGUIDFunction::~GenerateGUIDFunction()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// GenerateGUIDFunction
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
GenerateGUIDFunction::create(mozIStorageConnection *aDBConn)
|
||||
@ -653,9 +627,6 @@ namespace places {
|
||||
mozIStorageFunction
|
||||
)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// mozIStorageFunction
|
||||
|
||||
NS_IMETHODIMP
|
||||
GenerateGUIDFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
|
||||
nsIVariant **_result)
|
||||
@ -671,13 +642,6 @@ namespace places {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Get Unreversed Host Function
|
||||
|
||||
GetUnreversedHostFunction::~GetUnreversedHostFunction()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// GetUnreversedHostFunction
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
GetUnreversedHostFunction::create(mozIStorageConnection *aDBConn)
|
||||
@ -696,9 +660,6 @@ namespace places {
|
||||
mozIStorageFunction
|
||||
)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// mozIStorageFunction
|
||||
|
||||
NS_IMETHODIMP
|
||||
GetUnreversedHostFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
|
||||
nsIVariant **_result)
|
||||
@ -727,13 +688,6 @@ namespace places {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Fixup URL Function
|
||||
|
||||
FixupURLFunction::~FixupURLFunction()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// FixupURLFunction
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
FixupURLFunction::create(mozIStorageConnection *aDBConn)
|
||||
@ -752,9 +706,6 @@ namespace places {
|
||||
mozIStorageFunction
|
||||
)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//// mozIStorageFunction
|
||||
|
||||
NS_IMETHODIMP
|
||||
FixupURLFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
|
||||
nsIVariant **_result)
|
||||
@ -787,10 +738,6 @@ namespace places {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Frecency Changed Notification Function
|
||||
|
||||
FrecencyNotificationFunction::~FrecencyNotificationFunction()
|
||||
{
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
FrecencyNotificationFunction::create(mozIStorageConnection *aDBConn)
|
||||
@ -847,10 +794,6 @@ namespace places {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Store Last Inserted Id Function
|
||||
|
||||
StoreLastInsertedIdFunction::~StoreLastInsertedIdFunction()
|
||||
{
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
StoreLastInsertedIdFunction::create(mozIStorageConnection *aDBConn)
|
||||
@ -894,5 +837,83 @@ namespace places {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Hash Function
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
HashFunction::create(mozIStorageConnection *aDBConn)
|
||||
{
|
||||
RefPtr<HashFunction> function = new HashFunction();
|
||||
return aDBConn->CreateFunction(
|
||||
NS_LITERAL_CSTRING("hash"), -1, function
|
||||
);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(
|
||||
HashFunction,
|
||||
mozIStorageFunction
|
||||
)
|
||||
|
||||
NS_IMETHODIMP
|
||||
HashFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
|
||||
nsIVariant **_result)
|
||||
{
|
||||
// Must have non-null function arguments.
|
||||
MOZ_ASSERT(aArguments);
|
||||
|
||||
// Fetch arguments. Use default values if they were omitted.
|
||||
uint32_t numEntries;
|
||||
nsresult rv = aArguments->GetNumEntries(&numEntries);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(numEntries >= 1 && numEntries <= 2, NS_ERROR_FAILURE);
|
||||
|
||||
nsString str;
|
||||
aArguments->GetString(0, str);
|
||||
nsAutoCString mode;
|
||||
if (numEntries > 1) {
|
||||
aArguments->GetUTF8String(1, mode);
|
||||
}
|
||||
|
||||
RefPtr<nsVariant> result = new nsVariant();
|
||||
if (mode.IsEmpty()) {
|
||||
// URI-like strings (having a prefix before a colon), are handled specially,
|
||||
// as a 48 bit hash, where first 16 bits are the prefix hash, while the
|
||||
// other 32 are the string hash.
|
||||
// The 16 bits have been decided based on the fact hashing all of the IANA
|
||||
// known schemes, plus "places", does not generate collisions.
|
||||
nsAString::const_iterator start, tip, end;
|
||||
str.BeginReading(tip);
|
||||
start = tip;
|
||||
str.EndReading(end);
|
||||
if (FindInReadable(NS_LITERAL_STRING(":"), tip, end)) {
|
||||
const nsDependentSubstring& prefix = Substring(start, tip);
|
||||
uint64_t prefixHash = static_cast<uint64_t>(HashString(prefix) & 0x0000FFFF);
|
||||
// The second half of the url is more likely to be unique, so we add it.
|
||||
uint32_t srcHash = HashString(str);
|
||||
uint64_t hash = (prefixHash << 32) + srcHash;
|
||||
result->SetAsInt64(hash);
|
||||
} else {
|
||||
uint32_t hash = HashString(str);
|
||||
result->SetAsInt64(hash);
|
||||
}
|
||||
} else if (mode.Equals(NS_LITERAL_CSTRING("prefix_lo"))) {
|
||||
// Keep only 16 bits.
|
||||
uint64_t hash = static_cast<uint64_t>(HashString(str) & 0x0000FFFF) << 32;
|
||||
result->SetAsInt64(hash);
|
||||
} else if (mode.Equals(NS_LITERAL_CSTRING("prefix_hi"))) {
|
||||
// Keep only 16 bits.
|
||||
uint64_t hash = static_cast<uint64_t>(HashString(str) & 0x0000FFFF) << 32;
|
||||
// Make this a prefix upper bound by filling the lowest 32 bits.
|
||||
hash += 0xFFFFFFFF;
|
||||
result->SetAsInt64(hash);
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
result.forget(_result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace places
|
||||
} // namespace mozilla
|
||||
|
@ -71,7 +71,7 @@ public:
|
||||
static nsresult create(mozIStorageConnection *aDBConn);
|
||||
|
||||
private:
|
||||
~MatchAutoCompleteFunction();
|
||||
~MatchAutoCompleteFunction() {}
|
||||
|
||||
/**
|
||||
* Argument Indexes
|
||||
@ -174,7 +174,6 @@ private:
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Frecency Calculation Function
|
||||
|
||||
@ -197,7 +196,6 @@ private:
|
||||
*/
|
||||
class CalculateFrecencyFunction final : public mozIStorageFunction
|
||||
{
|
||||
~CalculateFrecencyFunction();
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
@ -209,6 +207,8 @@ public:
|
||||
* The database connection to register with.
|
||||
*/
|
||||
static nsresult create(mozIStorageConnection *aDBConn);
|
||||
private:
|
||||
~CalculateFrecencyFunction() {}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -219,7 +219,6 @@ public:
|
||||
*/
|
||||
class GenerateGUIDFunction final : public mozIStorageFunction
|
||||
{
|
||||
~GenerateGUIDFunction();
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
@ -231,6 +230,8 @@ public:
|
||||
* The database connection to register with.
|
||||
*/
|
||||
static nsresult create(mozIStorageConnection *aDBConn);
|
||||
private:
|
||||
~GenerateGUIDFunction() {}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -243,7 +244,6 @@ public:
|
||||
*/
|
||||
class GetUnreversedHostFunction final : public mozIStorageFunction
|
||||
{
|
||||
~GetUnreversedHostFunction();
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
@ -255,6 +255,8 @@ public:
|
||||
* The database connection to register with.
|
||||
*/
|
||||
static nsresult create(mozIStorageConnection *aDBConn);
|
||||
private:
|
||||
~GetUnreversedHostFunction() {}
|
||||
};
|
||||
|
||||
|
||||
@ -272,7 +274,6 @@ public:
|
||||
*/
|
||||
class FixupURLFunction final : public mozIStorageFunction
|
||||
{
|
||||
~FixupURLFunction();
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
@ -284,6 +285,8 @@ public:
|
||||
* The database connection to register with.
|
||||
*/
|
||||
static nsresult create(mozIStorageConnection *aDBConn);
|
||||
private:
|
||||
~FixupURLFunction() {}
|
||||
};
|
||||
|
||||
|
||||
@ -309,7 +312,6 @@ public:
|
||||
*/
|
||||
class FrecencyNotificationFunction final : public mozIStorageFunction
|
||||
{
|
||||
~FrecencyNotificationFunction();
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
@ -321,6 +323,8 @@ public:
|
||||
* The database connection to register with.
|
||||
*/
|
||||
static nsresult create(mozIStorageConnection *aDBConn);
|
||||
private:
|
||||
~FrecencyNotificationFunction() {}
|
||||
};
|
||||
|
||||
|
||||
@ -338,7 +342,6 @@ public:
|
||||
*/
|
||||
class StoreLastInsertedIdFunction final : public mozIStorageFunction
|
||||
{
|
||||
~StoreLastInsertedIdFunction();
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
@ -350,6 +353,37 @@ public:
|
||||
* The database connection to register with.
|
||||
*/
|
||||
static nsresult create(mozIStorageConnection *aDBConn);
|
||||
private:
|
||||
~StoreLastInsertedIdFunction() {}
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Hash Function
|
||||
|
||||
/**
|
||||
* Calculates hash for a given string using the mfbt AddToHash function.
|
||||
*
|
||||
* @param string
|
||||
* A string.
|
||||
* @return
|
||||
* The hash for the string.
|
||||
*/
|
||||
class HashFunction final : public mozIStorageFunction
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_MOZISTORAGEFUNCTION
|
||||
|
||||
/**
|
||||
* Registers the function with the specified database connection.
|
||||
*
|
||||
* @param aDBConn
|
||||
* The database connection to register with.
|
||||
*/
|
||||
static nsresult create(mozIStorageConnection *aDBConn);
|
||||
private:
|
||||
~HashFunction() {}
|
||||
};
|
||||
|
||||
} // namespace places
|
||||
|
@ -132,7 +132,7 @@ const SQL_SWITCHTAB_QUERY =
|
||||
`SELECT :query_type, t.url, t.url, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
t.open_count, NULL
|
||||
FROM moz_openpages_temp t
|
||||
LEFT JOIN moz_places h ON h.url = t.url
|
||||
LEFT JOIN moz_places h ON h.url_hash = hash(t.url) AND h.url = t.url
|
||||
WHERE h.id IS NULL
|
||||
AND AUTOCOMPLETE_MATCH(:searchString, t.url, t.url, NULL,
|
||||
NULL, NULL, NULL, t.open_count,
|
||||
|
@ -1260,7 +1260,7 @@ nsAnnotationService::GetAnnotationNamesTArray(nsIURI* aURI,
|
||||
"FROM moz_anno_attributes n "
|
||||
"JOIN moz_annos a ON a.anno_attribute_id = n.id "
|
||||
"JOIN moz_places h ON h.id = a.place_id "
|
||||
"WHERE h.url = :page_url"
|
||||
"WHERE h.url_hash = hash(:page_url) AND h.url = :page_url"
|
||||
);
|
||||
}
|
||||
NS_ENSURE_STATE(statement);
|
||||
@ -1382,7 +1382,8 @@ nsAnnotationService::RemoveAnnotationInternal(nsIURI* aURI,
|
||||
else {
|
||||
statement = mDB->GetStatement(
|
||||
"DELETE FROM moz_annos "
|
||||
"WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url) "
|
||||
"WHERE place_id = "
|
||||
"(SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url) "
|
||||
"AND anno_attribute_id = "
|
||||
"(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)"
|
||||
);
|
||||
@ -1445,7 +1446,7 @@ nsAnnotationService::RemovePageAnnotations(nsIURI* aURI)
|
||||
// Should this be precompiled or a getter?
|
||||
nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(
|
||||
"DELETE FROM moz_annos WHERE place_id = "
|
||||
"(SELECT id FROM moz_places WHERE url = :page_url)"
|
||||
"(SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url)"
|
||||
);
|
||||
NS_ENSURE_STATE(statement);
|
||||
mozStorageStatementScoper scoper(statement);
|
||||
@ -1508,7 +1509,7 @@ nsAnnotationService::CopyPageAnnotations(nsIURI* aSourceURI,
|
||||
"JOIN moz_annos a ON a.place_id = h.id "
|
||||
"JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
|
||||
"LEFT JOIN moz_annos a2 ON a2.place_id = "
|
||||
"(SELECT id FROM moz_places WHERE url = :dest_url) "
|
||||
"(SELECT id FROM moz_places WHERE url_hash = hash(:dest_url) AND url = :dest_url) "
|
||||
"AND a2.anno_attribute_id = n.id "
|
||||
"WHERE url = :source_url"
|
||||
);
|
||||
@ -1524,7 +1525,7 @@ nsAnnotationService::CopyPageAnnotations(nsIURI* aSourceURI,
|
||||
"INSERT INTO moz_annos "
|
||||
"(place_id, anno_attribute_id, content, flags, expiration, "
|
||||
"type, dateAdded, lastModified) "
|
||||
"SELECT (SELECT id FROM moz_places WHERE url = :page_url), "
|
||||
"SELECT (SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url), "
|
||||
"anno_attribute_id, content, flags, expiration, type, "
|
||||
":date, :date "
|
||||
"FROM moz_annos "
|
||||
@ -1703,7 +1704,7 @@ nsAnnotationService::HasAnnotationInternal(nsIURI* aURI,
|
||||
"FROM moz_places h "
|
||||
"LEFT JOIN moz_annos a ON a.place_id = h.id "
|
||||
"AND a.anno_attribute_id = nameid "
|
||||
"WHERE h.url = :page_url"
|
||||
"WHERE h.url_hash = hash(:page_url) AND h.url = :page_url"
|
||||
);
|
||||
}
|
||||
NS_ENSURE_STATE(stmt);
|
||||
@ -1770,7 +1771,7 @@ nsAnnotationService::StartGetAnnotation(nsIURI* aURI,
|
||||
"FROM moz_anno_attributes n "
|
||||
"JOIN moz_annos a ON n.id = a.anno_attribute_id "
|
||||
"JOIN moz_places h ON h.id = a.place_id "
|
||||
"WHERE h.url = :page_url "
|
||||
"WHERE h.url_hash = hash(:page_url) AND h.url = :page_url "
|
||||
"AND n.name = :anno_name"
|
||||
);
|
||||
}
|
||||
@ -1864,7 +1865,7 @@ nsAnnotationService::StartSetAnnotation(nsIURI* aURI,
|
||||
"FROM moz_places h "
|
||||
"LEFT JOIN moz_annos a ON a.place_id = h.id "
|
||||
"AND a.anno_attribute_id = nameid "
|
||||
"WHERE h.url = :page_url"
|
||||
"WHERE h.url_hash = hash(:page_url) AND h.url = :page_url"
|
||||
);
|
||||
}
|
||||
NS_ENSURE_STATE(stmt);
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
"SELECT b.id, b.guid, b.parent, b.lastModified, t.guid, t.parent "
|
||||
"FROM moz_bookmarks b "
|
||||
"JOIN moz_bookmarks t on t.id = b.parent "
|
||||
"WHERE b.fk = (SELECT id FROM moz_places WHERE url = :page_url) "
|
||||
"WHERE b.fk = (SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url) "
|
||||
"ORDER BY b.lastModified DESC, b.id DESC "
|
||||
);
|
||||
if (stmt) {
|
||||
@ -1853,7 +1853,7 @@ nsNavBookmarks::IsBookmarked(nsIURI* aURI, bool* aBookmarked)
|
||||
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
|
||||
"SELECT 1 FROM moz_bookmarks b "
|
||||
"JOIN moz_places h ON b.fk = h.id "
|
||||
"WHERE h.url = :page_url"
|
||||
"WHERE h.url_hash = hash(:page_url) AND h.url = :page_url"
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
@ -2059,7 +2059,7 @@ nsNavBookmarks::GetBookmarkIdsForURITArray(nsIURI* aURI,
|
||||
"SELECT b.id, b.guid, b.parent, b.lastModified, t.guid, t.parent "
|
||||
"FROM moz_bookmarks b "
|
||||
"JOIN moz_bookmarks t on t.id = b.parent "
|
||||
"WHERE b.fk = (SELECT id FROM moz_places WHERE url = :page_url) "
|
||||
"WHERE b.fk = (SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url) "
|
||||
"ORDER BY b.lastModified DESC, b.id DESC "
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
@ -2103,7 +2103,7 @@ nsNavBookmarks::GetBookmarksForURI(nsIURI* aURI,
|
||||
"SELECT b.id, b.guid, b.parent, b.lastModified, t.guid, t.parent "
|
||||
"FROM moz_bookmarks b "
|
||||
"JOIN moz_bookmarks t on t.id = b.parent "
|
||||
"WHERE b.fk = (SELECT id FROM moz_places WHERE url = :page_url) "
|
||||
"WHERE b.fk = (SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url) "
|
||||
"ORDER BY b.lastModified DESC, b.id DESC "
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
|
@ -369,7 +369,7 @@ nsNavHistory::GetIdForPage(nsIURI* aURI,
|
||||
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
|
||||
"SELECT id, url, title, rev_host, visit_count, guid "
|
||||
"FROM moz_places "
|
||||
"WHERE url = :page_url "
|
||||
"WHERE url_hash = hash(:page_url) AND url = :page_url "
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
@ -405,8 +405,8 @@ nsNavHistory::GetOrCreateIdForPage(nsIURI* aURI,
|
||||
|
||||
// Create a new hidden, untyped and unvisited entry.
|
||||
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
|
||||
"INSERT INTO moz_places (url, rev_host, hidden, frecency, guid) "
|
||||
"VALUES (:page_url, :rev_host, :hidden, :frecency, :guid) "
|
||||
"INSERT INTO moz_places (url, url_hash, rev_host, hidden, frecency, guid) "
|
||||
"VALUES (:page_url, hash(:page_url), :rev_host, :hidden, :frecency, :guid) "
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
@ -1029,7 +1029,8 @@ nsNavHistory::invalidateFrecencies(const nsCString& aPlaceIdsQueryString)
|
||||
invalidFrecenciesSQLFragment.AppendLiteral("NOTIFY_FRECENCY(");
|
||||
invalidFrecenciesSQLFragment.AppendLiteral(
|
||||
"(CASE "
|
||||
"WHEN url BETWEEN 'place:' AND 'place;' "
|
||||
"WHEN url_hash BETWEEN hash('place', 'prefix_lo') AND "
|
||||
"hash('place', 'prefix_hi') "
|
||||
"THEN 0 "
|
||||
"ELSE -1 "
|
||||
"END) "
|
||||
@ -1833,7 +1834,8 @@ PlacesSQLQueryBuilder::SelectAsSite()
|
||||
"%s "
|
||||
"WHERE h.hidden = 0 "
|
||||
"AND h.visit_count > 0 "
|
||||
"AND h.url BETWEEN 'file://' AND 'file:/~' "
|
||||
"AND h.url_hash BETWEEN hash('file', 'prefix_lo') AND "
|
||||
"hash('file', 'prefix_hi') "
|
||||
"%s "
|
||||
"LIMIT 1 "
|
||||
") "
|
||||
@ -2901,7 +2903,7 @@ nsNavHistory::GetPageTitle(nsIURI* aURI, nsAString& aTitle)
|
||||
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
|
||||
"SELECT id, url, title, rev_host, visit_count, guid "
|
||||
"FROM moz_places "
|
||||
"WHERE url = :page_url "
|
||||
"WHERE url_hash = hash(:page_url) AND url = :page_url "
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
@ -3447,7 +3449,8 @@ nsNavHistory::QueryToSelectClause(nsNavHistoryQuery* aQuery, // const
|
||||
|
||||
if (excludeQueries) {
|
||||
// Serching by terms implicitly exclude queries.
|
||||
clause.Condition("NOT h.url BETWEEN 'place:' AND 'place;'");
|
||||
clause.Condition("NOT h.url_hash BETWEEN hash('place', 'prefix_lo') AND "
|
||||
"hash('place', 'prefix_hi')");
|
||||
}
|
||||
|
||||
clause.GetClauseString(*aClause);
|
||||
@ -4201,7 +4204,7 @@ nsNavHistory::URIToResultNode(nsIURI* aURI,
|
||||
"FROM moz_places h "
|
||||
"LEFT JOIN moz_bookmarks b ON b.fk = h.id "
|
||||
"LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
|
||||
"WHERE h.url = :page_url ")
|
||||
"WHERE h.url_hash = hash(:page_url) AND h.url = :page_url ")
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
mozStorageStatementScoper scoper(stmt);
|
||||
@ -4536,7 +4539,7 @@ nsNavHistory::AutoCompleteFeedback(int32_t aIndex,
|
||||
"SELECT h.id, IFNULL(i.input, :input_text), IFNULL(i.use_count, 0) * .9 + 1 "
|
||||
"FROM moz_places h "
|
||||
"LEFT JOIN moz_inputhistory i ON i.place_id = h.id AND i.input = :input_text "
|
||||
"WHERE url = :page_url "
|
||||
"WHERE url_hash = hash(:page_url) AND url = :page_url "
|
||||
);
|
||||
NS_ENSURE_STATE(stmt);
|
||||
|
||||
|
@ -191,7 +191,7 @@ nsNavHistoryResultNode::GetTags(nsAString& aTags) {
|
||||
"SELECT t.title AS tag_title "
|
||||
"FROM moz_bookmarks b "
|
||||
"JOIN moz_bookmarks t ON t.id = +b.parent "
|
||||
"WHERE b.fk = (SELECT id FROM moz_places WHERE url = :page_url) "
|
||||
"WHERE b.fk = (SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url) "
|
||||
"AND t.parent = :tags_folder "
|
||||
"ORDER BY t.title COLLATE NOCASE ASC "
|
||||
") "
|
||||
|
@ -384,7 +384,7 @@ function nsPlacesAutoComplete()
|
||||
`SELECT t.url, t.url, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
:query_type, t.open_count, NULL
|
||||
FROM moz_openpages_temp t
|
||||
LEFT JOIN moz_places h ON h.url = t.url
|
||||
LEFT JOIN moz_places h ON h.url_hash = hash(t.url) AND h.url = t.url
|
||||
WHERE h.id IS NULL
|
||||
AND AUTOCOMPLETE_MATCH(:searchString, t.url, t.url, NULL,
|
||||
NULL, NULL, NULL, t.open_count,
|
||||
|
@ -26,6 +26,7 @@ const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
@ -41,6 +42,8 @@ const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished";
|
||||
const TOPIC_IDLE_BEGIN = "idle";
|
||||
const TOPIC_IDLE_END = "active";
|
||||
const TOPIC_IDLE_DAILY = "idle-daily";
|
||||
const TOPIC_TESTING_MODE = "testing-mode";
|
||||
const TOPIC_TEST_INTERVAL_CHANGED = "test-interval-changed";
|
||||
|
||||
// Branch for all expiration preferences.
|
||||
const PREF_BRANCH = "places.history.expiration.";
|
||||
@ -72,7 +75,7 @@ const DATABASE_TO_MEMORY_PERC = 4;
|
||||
const DATABASE_TO_DISK_PERC = 2;
|
||||
// Maximum size of the optimal database. High-end hardware has plenty of
|
||||
// memory and disk space, but performances don't grow linearly.
|
||||
const DATABASE_MAX_SIZE = 167772160; // 160MiB
|
||||
const DATABASE_MAX_SIZE = 62914560; // 60MiB
|
||||
// If the physical memory size is bogus, fallback to this.
|
||||
const MEMSIZE_FALLBACK_BYTES = 268435456; // 256 MiB
|
||||
// If the disk available space is bogus, fallback to this.
|
||||
@ -100,9 +103,8 @@ const EXPIRE_AGGRESSIVITY_MULTIPLIER = 3;
|
||||
// This is the average size in bytes of an URI entry in the database.
|
||||
// Magic numbers are determined through analysis of the distribution of a ratio
|
||||
// between number of unique URIs and database size among our users.
|
||||
// Based on these values we evaluate how many unique URIs we can handle before
|
||||
// starting expiring some.
|
||||
const URIENTRY_AVG_SIZE = 1600;
|
||||
// Used as a fall back value when it's not possible to calculate the real value.
|
||||
const URIENTRY_AVG_SIZE = 600;
|
||||
|
||||
// Seconds of idle time before starting a larger expiration step.
|
||||
// Notice during idle we stop the expiration timer since we don't want to hurt
|
||||
@ -482,9 +484,6 @@ function nsPlacesExpiration()
|
||||
return db;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "_sys",
|
||||
"@mozilla.org/system-info;1",
|
||||
"nsIPropertyBag2");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "_idle",
|
||||
"@mozilla.org/widget/idleservice;1",
|
||||
"nsIIdleService");
|
||||
@ -492,18 +491,19 @@ function nsPlacesExpiration()
|
||||
this._prefBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefService).
|
||||
getBranch(PREF_BRANCH);
|
||||
this._loadPrefs();
|
||||
|
||||
// Observe our preferences branch for changes.
|
||||
this._prefBranch.addObserver("", this, false);
|
||||
this._loadPrefs().then(() => {
|
||||
// Observe our preferences branch for changes.
|
||||
this._prefBranch.addObserver("", this, true);
|
||||
|
||||
// Create our expiration timer.
|
||||
this._newTimer();
|
||||
}, Cu.reportError);
|
||||
|
||||
// Register topic observers.
|
||||
Services.obs.addObserver(this, TOPIC_SHUTDOWN, false);
|
||||
Services.obs.addObserver(this, TOPIC_DEBUG_START_EXPIRATION, false);
|
||||
Services.obs.addObserver(this, TOPIC_IDLE_DAILY, false);
|
||||
|
||||
// Create our expiration timer.
|
||||
this._newTimer();
|
||||
Services.obs.addObserver(this, TOPIC_SHUTDOWN, true);
|
||||
Services.obs.addObserver(this, TOPIC_DEBUG_START_EXPIRATION, true);
|
||||
Services.obs.addObserver(this, TOPIC_IDLE_DAILY, true);
|
||||
}
|
||||
|
||||
nsPlacesExpiration.prototype = {
|
||||
@ -513,14 +513,12 @@ nsPlacesExpiration.prototype = {
|
||||
|
||||
observe: function PEX_observe(aSubject, aTopic, aData)
|
||||
{
|
||||
if (this._shuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aTopic == TOPIC_SHUTDOWN) {
|
||||
this._shuttingDown = true;
|
||||
Services.obs.removeObserver(this, TOPIC_SHUTDOWN);
|
||||
Services.obs.removeObserver(this, TOPIC_DEBUG_START_EXPIRATION);
|
||||
Services.obs.removeObserver(this, TOPIC_IDLE_DAILY);
|
||||
|
||||
this._prefBranch.removeObserver("", this);
|
||||
|
||||
this.expireOnIdle = false;
|
||||
|
||||
if (this._timer) {
|
||||
@ -540,12 +538,12 @@ nsPlacesExpiration.prototype = {
|
||||
this._finalizeInternalStatements();
|
||||
}
|
||||
else if (aTopic == TOPIC_PREF_CHANGED) {
|
||||
this._loadPrefs();
|
||||
|
||||
if (aData == PREF_INTERVAL_SECONDS) {
|
||||
// Renew the timer with the new interval value.
|
||||
this._newTimer();
|
||||
}
|
||||
this._loadPrefs().then(() => {
|
||||
if (aData == PREF_INTERVAL_SECONDS) {
|
||||
// Renew the timer with the new interval value.
|
||||
this._newTimer();
|
||||
}
|
||||
}, Cu.reportError);
|
||||
}
|
||||
else if (aTopic == TOPIC_DEBUG_START_EXPIRATION) {
|
||||
// The passed-in limit is the maximum number of visits to expire when
|
||||
@ -590,6 +588,9 @@ nsPlacesExpiration.prototype = {
|
||||
else if (aTopic == TOPIC_IDLE_DAILY) {
|
||||
this._expireWithActionAndLimit(ACTION.IDLE_DAILY, LIMIT.LARGE);
|
||||
}
|
||||
else if (aTopic == TOPIC_TESTING_MODE) {
|
||||
this._testingMode = true;
|
||||
}
|
||||
},
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@ -817,25 +818,27 @@ nsPlacesExpiration.prototype = {
|
||||
return this._expireOnIdle;
|
||||
},
|
||||
|
||||
_loadPrefs: function PEX__loadPrefs() {
|
||||
_loadPrefs: Task.async(function* () {
|
||||
// Get the user's limit, if it was set.
|
||||
try {
|
||||
// We want to silently fail since getIntPref throws if it does not exist,
|
||||
// and use a default to fallback to.
|
||||
this._urisLimit = this._prefBranch.getIntPref(PREF_MAX_URIS);
|
||||
}
|
||||
catch(e) {}
|
||||
} catch(ex) { /* User limit not set */ }
|
||||
|
||||
if (this._urisLimit < 0) {
|
||||
// The preference did not exist or has a negative value.
|
||||
// Calculate the number of unique places that may fit an optimal database
|
||||
// size on this hardware. If there are more than these unique pages,
|
||||
// some will be expired.
|
||||
// Some testing code expects a pref change to be synchronous, so
|
||||
// temporarily set this to a large value, while we asynchronously update
|
||||
// to the correct value.
|
||||
this._urisLimit = 300000;
|
||||
|
||||
// The user didn't specify a custom limit, so we calculate the number of
|
||||
// unique places that may fit an optimal database size on this hardware.
|
||||
// Oldest pages over this threshold will be expired.
|
||||
let memSizeBytes = MEMSIZE_FALLBACK_BYTES;
|
||||
try {
|
||||
// Limit the size on systems with small memory.
|
||||
memSizeBytes = this._sys.getProperty("memsize");
|
||||
memSizeBytes = Services.sysinfo.getProperty("memsize");
|
||||
} catch (ex) {}
|
||||
if (memSizeBytes <= 0) {
|
||||
memsize = MEMSIZE_FALLBACK_BYTES;
|
||||
@ -858,7 +861,20 @@ nsPlacesExpiration.prototype = {
|
||||
DATABASE_MAX_SIZE
|
||||
);
|
||||
|
||||
this._urisLimit = Math.ceil(optimalDatabaseSize / URIENTRY_AVG_SIZE);
|
||||
// Calculate avg size of a URI in the database.
|
||||
let db = yield PlacesUtils.promiseDBConnection();
|
||||
let pageSize = (yield db.execute(`PRAGMA page_size`))[0].getResultByIndex(0);
|
||||
let pageCount = (yield db.execute(`PRAGMA page_count`))[0].getResultByIndex(0);
|
||||
let freelistCount = (yield db.execute(`PRAGMA freelist_count`))[0].getResultByIndex(0);
|
||||
let dbSize = (pageCount - freelistCount) * pageSize;
|
||||
let uriCount = (yield db.execute(`SELECT count(*) FROM moz_places`))[0].getResultByIndex(0);
|
||||
let avgURISize = Math.ceil(dbSize / uriCount);
|
||||
// For new profiles this value may be too large, due to the Sqlite header,
|
||||
// or Infinity when there are no pages. Thus we must limit it.
|
||||
if (avgURISize > (URIENTRY_AVG_SIZE * 3)) {
|
||||
avgURISize = URIENTRY_AVG_SIZE;
|
||||
}
|
||||
this._urisLimit = Math.ceil(optimalDatabaseSize / avgURISize);
|
||||
}
|
||||
|
||||
// Expose the calculated limit to other components.
|
||||
@ -870,11 +886,11 @@ nsPlacesExpiration.prototype = {
|
||||
// We want to silently fail since getIntPref throws if it does not exist,
|
||||
// and use a default to fallback to.
|
||||
this._interval = this._prefBranch.getIntPref(PREF_INTERVAL_SECONDS);
|
||||
}
|
||||
catch (e) {}
|
||||
if (this._interval <= 0)
|
||||
} catch (ex) { /* User interval not set */ }
|
||||
if (this._interval <= 0) {
|
||||
this._interval = PREF_INTERVAL_SECONDS_NOTSET;
|
||||
},
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Evaluates the real number of pages in the database and the value currently
|
||||
@ -1069,6 +1085,10 @@ nsPlacesExpiration.prototype = {
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(this, interval * 1000,
|
||||
Ci.nsITimer.TYPE_REPEATING_SLACK);
|
||||
if (this._testingMode) {
|
||||
Services.obs.notifyObservers(null, TOPIC_TEST_INTERVAL_CHANGED,
|
||||
interval);
|
||||
}
|
||||
return this._timer = timer;
|
||||
},
|
||||
|
||||
@ -1084,6 +1104,7 @@ nsPlacesExpiration.prototype = {
|
||||
, Ci.nsINavHistoryObserver
|
||||
, Ci.nsITimerCallback
|
||||
, Ci.mozIStorageStatementCallback
|
||||
, Ci.nsISupportsWeakReference
|
||||
])
|
||||
};
|
||||
|
||||
|
@ -16,9 +16,9 @@
|
||||
/**
|
||||
* moz_places
|
||||
*/
|
||||
#define CREATE_IDX_MOZ_PLACES_URL \
|
||||
#define CREATE_IDX_MOZ_PLACES_URL_HASH \
|
||||
CREATE_PLACES_IDX( \
|
||||
"url_uniqueindex", "moz_places", "url", "UNIQUE" \
|
||||
"url_hashindex", "moz_places", "url_hash", "" \
|
||||
)
|
||||
|
||||
#define CREATE_IDX_MOZ_PLACES_FAVICON \
|
||||
|
@ -22,6 +22,7 @@
|
||||
", last_visit_date INTEGER " \
|
||||
", guid TEXT" \
|
||||
", foreign_count INTEGER DEFAULT 0 NOT NULL" \
|
||||
", url_hash INTEGER DEFAULT 0 NOT NULL " \
|
||||
")" \
|
||||
)
|
||||
|
||||
|
@ -66,7 +66,7 @@ TaggingService.prototype = {
|
||||
let stmt = db.createStatement(
|
||||
`SELECT id FROM moz_bookmarks
|
||||
WHERE parent = :tag_id
|
||||
AND fk = (SELECT id FROM moz_places WHERE url = :page_url)`
|
||||
AND fk = (SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url)`
|
||||
);
|
||||
stmt.params.tag_id = tagId;
|
||||
stmt.params.page_url = aURI.spec;
|
||||
@ -380,7 +380,7 @@ TaggingService.prototype = {
|
||||
let stmt = db.createStatement(
|
||||
`SELECT id, parent
|
||||
FROM moz_bookmarks
|
||||
WHERE fk = (SELECT id FROM moz_places WHERE url = :page_url)`
|
||||
WHERE fk = (SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url)`
|
||||
);
|
||||
stmt.params.page_url = aURI.spec;
|
||||
try {
|
||||
|
@ -64,7 +64,7 @@ this.PlacesTestUtils = Object.freeze({
|
||||
}
|
||||
if (typeof place.referrer == "string") {
|
||||
place.referrer = NetUtil.newURI(place.referrer);
|
||||
} else if (place.referrer instanceof URL) {
|
||||
} else if (place.referrer && place.referrer instanceof URL) {
|
||||
place.referrer = NetUtil.newURI(place.referrer.href);
|
||||
}
|
||||
place.visits = [{
|
||||
@ -149,7 +149,7 @@ this.PlacesTestUtils = Object.freeze({
|
||||
let url = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
|
||||
let db = yield PlacesUtils.promiseDBConnection();
|
||||
let rows = yield db.executeCached(
|
||||
"SELECT id FROM moz_places WHERE url = :url",
|
||||
"SELECT id FROM moz_places WHERE url_hash = hash(:url) AND url = :url",
|
||||
{ url });
|
||||
return rows.length > 0;
|
||||
}),
|
||||
@ -169,7 +169,7 @@ this.PlacesTestUtils = Object.freeze({
|
||||
let rows = yield db.executeCached(
|
||||
`SELECT count(*) FROM moz_historyvisits v
|
||||
JOIN moz_places h ON h.id = v.place_id
|
||||
WHERE url = :url`,
|
||||
WHERE url_hash = hash(:url) AND url = :url`,
|
||||
{ url });
|
||||
return rows[0].getResultByIndex(0);
|
||||
})
|
||||
|
@ -15,7 +15,8 @@ function* getForeignCountForURL(conn, url) {
|
||||
yield PlacesTestUtils.promiseAsyncUpdates();
|
||||
url = url instanceof Ci.nsIURI ? url.spec : url;
|
||||
let rows = yield conn.executeCached(
|
||||
"SELECT foreign_count FROM moz_places WHERE url = :t_url ", { t_url: url });
|
||||
`SELECT foreign_count FROM moz_places WHERE url_hash = hash(:t_url)
|
||||
AND url = :t_url`, { t_url: url });
|
||||
return rows[0].getResultByName("foreign_count");
|
||||
}
|
||||
|
||||
@ -68,7 +69,8 @@ add_task(function* maintenance_foreign_count_test() {
|
||||
// Adjust the foreign_count for the added entry to an incorrect value
|
||||
let deferred = Promise.defer();
|
||||
let stmt = DBConn().createAsyncStatement(
|
||||
"UPDATE moz_places SET foreign_count = 10 WHERE url = :t_url ");
|
||||
`UPDATE moz_places SET foreign_count = 10 WHERE url_hash = hash(:t_url)
|
||||
AND url = :t_url `);
|
||||
stmt.params.t_url = T_URI.spec;
|
||||
stmt.executeAsync({
|
||||
handleCompletion: function(){
|
||||
|
@ -120,34 +120,13 @@ function* checkHistoryItems() {
|
||||
let visitedUri = visitedURIs[i];
|
||||
ok((yield promiseIsURIVisited(visitedUri)), "");
|
||||
if (/embed/.test(visitedUri.spec)) {
|
||||
is(!!pageInDatabase(visitedUri), false, "Check if URI is in database");
|
||||
is((yield PlacesTestUtils.isPageInDB(visitedUri)), false, "Check if URI is in database");
|
||||
} else {
|
||||
ok(!!pageInDatabase(visitedUri), "Check if URI is in database");
|
||||
ok((yield PlacesTestUtils.isPageInDB(visitedUri)), "Check if URI is in database");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an address is found in the database.
|
||||
* @param aURI
|
||||
* nsIURI or address to look for.
|
||||
* @return place id of the page or 0 if not found
|
||||
*/
|
||||
function pageInDatabase(aURI) {
|
||||
let url = (aURI instanceof Ci.nsIURI ? aURI.spec : aURI);
|
||||
let stmt = DBConn().createStatement(
|
||||
"SELECT id FROM moz_places WHERE url = :url"
|
||||
);
|
||||
stmt.params.url = url;
|
||||
try {
|
||||
if (!stmt.executeStep())
|
||||
return 0;
|
||||
return stmt.getInt64(0);
|
||||
} finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function attempts to check if Bookmark-A has been visited
|
||||
* during private browsing mode, function should return false
|
||||
|
@ -34,7 +34,7 @@ add_task(function* () {
|
||||
WHERE from_visit IN
|
||||
(SELECT v.id FROM moz_historyvisits v
|
||||
JOIN moz_places p ON p.id = v.place_id
|
||||
WHERE p.url = :url)
|
||||
WHERE p.url_hash = hash(:url) AND p.url = :url)
|
||||
`, { url: TEST_URI.spec });
|
||||
|
||||
is(rows.length, 1, "Found right number of visits");
|
||||
|
@ -18,11 +18,6 @@ add_task(function* () {
|
||||
});
|
||||
let visited = yield promiseIsURIVisited(SJS_URI);
|
||||
ok(!visited, "The POST page should not be added to history");
|
||||
let db = yield PlacesUtils.promiseDBConnection();
|
||||
let rows = yield db.execute(
|
||||
"SELECT 1 FROM moz_places WHERE url = :page_url",
|
||||
{page_url: SJS_URI.spec});
|
||||
is(rows.length, 0, "The page should not be in the database");
|
||||
yield db.close();
|
||||
ok(!(yield PlacesTestUtils.isPageInDB(SJS_URI.spec)), "The page should not be in the database");
|
||||
}));
|
||||
});
|
||||
|
@ -1,20 +1,14 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var conn = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
|
||||
|
||||
/**
|
||||
* Gets a single column value from either the places or historyvisits table.
|
||||
*/
|
||||
function getColumn(table, column, fromColumnName, fromColumnValue)
|
||||
function getColumn(table, column, url)
|
||||
{
|
||||
var stmt = conn.createStatement(
|
||||
`SELECT ${column} FROM ${table} WHERE ${fromColumnName} = :val
|
||||
LIMIT 1`);
|
||||
`SELECT ${column} FROM ${table} WHERE url_hash = hash(:val) AND url = :val`);
|
||||
try {
|
||||
stmt.params.val = fromColumnValue;
|
||||
stmt.params.val = url;
|
||||
stmt.executeStep();
|
||||
return stmt.row[column];
|
||||
}
|
||||
@ -69,10 +63,10 @@ add_task(function* ()
|
||||
let data = yield titleChangedPromise;
|
||||
is(data[0].uri.spec, "http://example.com/tests/toolkit/components/places/tests/browser/title2.html");
|
||||
is(data[0].title, "Some title");
|
||||
is(data[0].guid, getColumn("moz_places", "guid", "url", data[0].uri.spec));
|
||||
is(data[0].guid, getColumn("moz_places", "guid", data[0].uri.spec));
|
||||
|
||||
data.forEach(function(item) {
|
||||
var title = getColumn("moz_places", "title", "url", data[0].uri.spec);
|
||||
var title = getColumn("moz_places", "title", data[0].uri.spec);
|
||||
is(title, item.title);
|
||||
});
|
||||
|
||||
|
@ -1,8 +1,3 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/**
|
||||
* One-time observer callback.
|
||||
*/
|
||||
@ -26,6 +21,7 @@ function getColumn(table, column, fromColumnName, fromColumnValue) {
|
||||
let sql = `SELECT ${column}
|
||||
FROM ${table}
|
||||
WHERE ${fromColumnName} = :val
|
||||
${fromColumnName == "url" ? "AND url_hash = hash(:val)" : ""}
|
||||
LIMIT 1`;
|
||||
let stmt = conn.createStatement(sql);
|
||||
try {
|
||||
|
@ -28,7 +28,7 @@ function fieldForUrl(aURI, aFieldName, aCallback)
|
||||
let url = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
|
||||
let stmt = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
|
||||
.DBConnection.createAsyncStatement(
|
||||
`SELECT ${aFieldName} FROM moz_places WHERE url = :page_url`
|
||||
`SELECT ${aFieldName} FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url`
|
||||
);
|
||||
stmt.params.page_url = url;
|
||||
stmt.executeAsync({
|
||||
@ -216,7 +216,7 @@ function doGetGuidForURI(aURI) {
|
||||
let stmt = DBConn().createStatement(
|
||||
`SELECT guid
|
||||
FROM moz_places
|
||||
WHERE url = :url`
|
||||
WHERE url_hash = hash(:url) AND url = :url`
|
||||
);
|
||||
stmt.params.url = aURI.spec;
|
||||
ok(stmt.executeStep(), "Check get guid for uri from moz_places");
|
||||
|
@ -269,7 +269,7 @@ do_get_place(nsIURI* aURI, PlaceRecord& result)
|
||||
|
||||
rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
|
||||
"SELECT id, hidden, typed, visit_count, guid FROM moz_places "
|
||||
"WHERE url=?1 "
|
||||
"WHERE url_hash = hash(?1) AND url = ?1"
|
||||
), getter_AddRefs(stmt));
|
||||
do_check_success(rv);
|
||||
|
||||
|
@ -34,7 +34,9 @@ function shutdownExpiration()
|
||||
* history notification.
|
||||
*/
|
||||
function force_expiration_start() {
|
||||
Cc["@mozilla.org/places/expiration;1"].getService(Ci.nsISupports);
|
||||
Cc["@mozilla.org/places/expiration;1"]
|
||||
.getService(Ci.nsIObserver)
|
||||
.observe(null, "testing-mode", null);
|
||||
}
|
||||
|
||||
|
||||
|
@ -52,7 +52,7 @@ function add_old_anno(aIdentifier, aName, aValue, aExpirePolicy,
|
||||
sql = "UPDATE moz_annos SET dateAdded = :expire_date, lastModified = :last_modified " +
|
||||
"WHERE id = (SELECT a.id FROM moz_annos a " +
|
||||
"LEFT JOIN moz_places h on h.id = a.place_id " +
|
||||
"WHERE h.url = :id " +
|
||||
"WHERE h.url_hash = hash(:id) AND h.url = :id " +
|
||||
"ORDER BY a.dateAdded DESC LIMIT 1)";
|
||||
}
|
||||
else
|
||||
|
@ -55,7 +55,7 @@ function add_old_anno(aIdentifier, aName, aValue, aExpirePolicy,
|
||||
"SELECT a.id FROM moz_annos a " +
|
||||
"JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " +
|
||||
"JOIN moz_places h on h.id = a.place_id " +
|
||||
"WHERE h.url = :id " +
|
||||
"WHERE h.url_hash = hash(:id) AND h.url = :id " +
|
||||
"AND n.name = :anno_name " +
|
||||
"ORDER BY a.dateAdded DESC LIMIT 1 " +
|
||||
")";
|
||||
|
@ -52,7 +52,7 @@ function run_test() {
|
||||
let stmt = DBConn().createAsyncStatement(
|
||||
"SELECT (SELECT COUNT(*) FROM moz_places) - "
|
||||
+ "(SELECT SUBSTR(stat,1,LENGTH(stat)-2) FROM sqlite_stat1 "
|
||||
+ "WHERE idx = 'moz_places_url_uniqueindex')"
|
||||
+ "WHERE idx = 'moz_places_url_hashindex')"
|
||||
);
|
||||
stmt.executeAsync({
|
||||
handleResult: function(aResultSet) {
|
||||
|
@ -1,9 +1,3 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* What this is aimed to test:
|
||||
*
|
||||
@ -21,46 +15,6 @@ const DEFAULT_TIMER_DELAY_SECONDS = 3 * 60;
|
||||
// Sync this with the const value in the component.
|
||||
const EXPIRE_AGGRESSIVITY_MULTIPLIER = 3;
|
||||
|
||||
Cu.import("resource://testing-common/MockRegistrar.jsm");
|
||||
// Provide a mock timer implementation, so there is no need to wait seconds to
|
||||
// achieve test results.
|
||||
const TIMER_CONTRACT_ID = "@mozilla.org/timer;1";
|
||||
var mockCID;
|
||||
|
||||
var mockTimerImpl = {
|
||||
initWithCallback: function MTI_initWithCallback(aCallback, aDelay, aType) {
|
||||
print("Checking timer delay equals expected interval value");
|
||||
if (!currentTest)
|
||||
return;
|
||||
// History status is not dirty, so the timer is delayed.
|
||||
do_check_eq(aDelay, currentTest.expectedTimerDelay * 1000 * EXPIRE_AGGRESSIVITY_MULTIPLIER)
|
||||
|
||||
do_execute_soon(runNextTest);
|
||||
},
|
||||
|
||||
cancel: function() {},
|
||||
initWithFuncCallback: function() {},
|
||||
init: function() {},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsITimer,
|
||||
])
|
||||
}
|
||||
|
||||
function replace_timer_factory() {
|
||||
mockCID = MockRegistrar.register(TIMER_CONTRACT_ID, mockTimerImpl);
|
||||
}
|
||||
|
||||
do_register_cleanup(function() {
|
||||
// Shutdown expiration before restoring original timer, otherwise we could
|
||||
// leak due to the different implementation.
|
||||
shutdownExpiration();
|
||||
|
||||
// Restore original timer factory.
|
||||
MockRegistrar.unregister(mockCID);
|
||||
});
|
||||
|
||||
|
||||
var tests = [
|
||||
|
||||
// This test should be the first, so the interval won't be influenced by
|
||||
@ -89,32 +43,21 @@ var tests = [
|
||||
|
||||
var currentTest;
|
||||
|
||||
function run_test() {
|
||||
add_task(function* test() {
|
||||
// The pref should not exist by default.
|
||||
try {
|
||||
getInterval();
|
||||
do_throw("interval pref should not exist by default");
|
||||
}
|
||||
catch (ex) {}
|
||||
|
||||
// Use our own mock timer implementation.
|
||||
replace_timer_factory();
|
||||
Assert.throws(() => getInterval());
|
||||
|
||||
// Force the component, so it will start observing preferences.
|
||||
force_expiration_start();
|
||||
|
||||
runNextTest();
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (tests.length) {
|
||||
currentTest = tests.shift();
|
||||
for (let currentTest of tests) {
|
||||
print(currentTest.desc);
|
||||
let promise = promiseTopicObserved("test-interval-changed");
|
||||
setInterval(currentTest.interval);
|
||||
let [, data] = yield promise;
|
||||
Assert.equal(data, currentTest.expectedTimerDelay * EXPIRE_AGGRESSIVITY_MULTIPLIER);
|
||||
}
|
||||
else {
|
||||
clearInterval();
|
||||
do_test_finished();
|
||||
}
|
||||
}
|
||||
|
||||
clearInterval();
|
||||
});
|
||||
|
||||
|
@ -88,7 +88,7 @@ add_task(function* test_pref_maxpages() {
|
||||
}
|
||||
|
||||
// Observe history.
|
||||
historyObserver = {
|
||||
let historyObserver = {
|
||||
onBeginUpdateBatch: function PEX_onBeginUpdateBatch() {},
|
||||
onEndUpdateBatch: function PEX_onEndUpdateBatch() {},
|
||||
onClearHistory: function() {},
|
||||
|
@ -18,6 +18,4 @@ skip-if = os == "android"
|
||||
[test_notifications_onDeleteVisits.js]
|
||||
[test_outdated_analyze.js]
|
||||
[test_pref_interval.js]
|
||||
# Crashes when timer is used on non-main thread due to JS implemetation in this test
|
||||
skip-if = "JS implementation of nsITimer"
|
||||
[test_pref_maxpages.js]
|
||||
|
@ -3,7 +3,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const CURRENT_SCHEMA_VERSION = 32;
|
||||
const CURRENT_SCHEMA_VERSION = 33;
|
||||
const FIRST_UPGRADABLE_SCHEMA_VERSION = 11;
|
||||
|
||||
const NS_APP_USER_PROFILE_50_DIR = "ProfD";
|
||||
@ -299,7 +299,7 @@ function page_in_database(aURI)
|
||||
{
|
||||
let url = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
|
||||
let stmt = DBConn().createStatement(
|
||||
"SELECT id FROM moz_places WHERE url = :url"
|
||||
"SELECT id FROM moz_places WHERE url_hash = hash(:url) AND url = :url"
|
||||
);
|
||||
stmt.params.url = url;
|
||||
try {
|
||||
@ -324,7 +324,7 @@ function visits_in_database(aURI)
|
||||
let stmt = DBConn().createStatement(
|
||||
`SELECT count(*) FROM moz_historyvisits v
|
||||
JOIN moz_places h ON h.id = v.place_id
|
||||
WHERE url = :url`
|
||||
WHERE url_hash = hash(:url) AND url = :url`
|
||||
);
|
||||
stmt.params.url = url;
|
||||
try {
|
||||
@ -542,7 +542,7 @@ function frecencyForUrl(aURI)
|
||||
url = aURI.href;
|
||||
}
|
||||
let stmt = DBConn().createStatement(
|
||||
"SELECT frecency FROM moz_places WHERE url = ?1"
|
||||
"SELECT frecency FROM moz_places WHERE url_hash = hash(?1) AND url = ?1"
|
||||
);
|
||||
stmt.bindByIndex(0, url);
|
||||
try {
|
||||
@ -566,7 +566,7 @@ function isUrlHidden(aURI)
|
||||
{
|
||||
let url = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
|
||||
let stmt = DBConn().createStatement(
|
||||
"SELECT hidden FROM moz_places WHERE url = ?1"
|
||||
"SELECT hidden FROM moz_places WHERE url_hash = hash(?1) AND url = ?1"
|
||||
);
|
||||
stmt.bindByIndex(0, url);
|
||||
if (!stmt.executeStep())
|
||||
@ -643,7 +643,7 @@ function do_get_guid_for_uri(aURI,
|
||||
let stmt = DBConn().createStatement(
|
||||
`SELECT guid
|
||||
FROM moz_places
|
||||
WHERE url = :url`
|
||||
WHERE url_hash = hash(:url) AND url = :url`
|
||||
);
|
||||
stmt.params.url = aURI.spec;
|
||||
do_check_true(stmt.executeStep(), aStack);
|
||||
@ -866,7 +866,7 @@ function* foreign_count(url) {
|
||||
let db = yield PlacesUtils.promiseDBConnection();
|
||||
let rows = yield db.executeCached(
|
||||
`SELECT foreign_count FROM moz_places
|
||||
WHERE url = :url
|
||||
WHERE url_hash = hash(:url) AND url = :url
|
||||
`, { url });
|
||||
return rows.length == 0 ? 0 : rows[0].getResultByName("foreign_count");
|
||||
}
|
||||
|
BIN
toolkit/components/places/tests/migration/places_v33.sqlite
Normal file
BIN
toolkit/components/places/tests/migration/places_v33.sqlite
Normal file
Binary file not shown.
@ -19,6 +19,7 @@ support-files =
|
||||
places_v30.sqlite
|
||||
places_v31.sqlite
|
||||
places_v32.sqlite
|
||||
places_v33.sqlite
|
||||
|
||||
[test_current_from_downgraded.js]
|
||||
[test_current_from_v6.js]
|
||||
|
@ -60,7 +60,7 @@ function* task_populateDB(aArray)
|
||||
// Set a fake visit_count, this is not a real count but can be used
|
||||
// to test sorting by visit_count.
|
||||
let stmt = DBConn().createAsyncStatement(
|
||||
"UPDATE moz_places SET visit_count = :vc WHERE url = :url");
|
||||
"UPDATE moz_places SET visit_count = :vc WHERE url_hash = hash(:url) AND url = :url");
|
||||
stmt.params.vc = qdata.visitCount;
|
||||
stmt.params.url = qdata.uri;
|
||||
try {
|
||||
@ -79,7 +79,7 @@ function* task_populateDB(aArray)
|
||||
// This must be async to properly enqueue after the updateFrecency call
|
||||
// done by the visit addition.
|
||||
let stmt = DBConn().createAsyncStatement(
|
||||
"UPDATE moz_places SET hidden = 1 WHERE url = :url");
|
||||
"UPDATE moz_places SET hidden = 1 WHERE url_hash = hash(:url) AND url = :url");
|
||||
stmt.params.url = qdata.uri;
|
||||
try {
|
||||
stmt.executeAsync();
|
||||
|
@ -1,6 +1,3 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* This file tests the async history API exposed by mozIAsyncHistory.
|
||||
*/
|
||||
@ -131,7 +128,7 @@ function do_check_title_for_uri(aURI,
|
||||
let stmt = DBConn().createStatement(
|
||||
`SELECT title
|
||||
FROM moz_places
|
||||
WHERE url = :url`
|
||||
WHERE url_hash = hash(:url) AND url = :url`
|
||||
);
|
||||
stmt.params.url = aURI.spec;
|
||||
do_check_true(stmt.executeStep(), stack);
|
||||
@ -548,7 +545,8 @@ add_task(function* test_old_referrer_ignored() {
|
||||
let stmt = DBConn().createStatement(
|
||||
`SELECT COUNT(1) AS count
|
||||
FROM moz_historyvisits
|
||||
WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url)
|
||||
JOIN moz_places h ON h.id = place_id
|
||||
WHERE url_hash = hash(:page_url) AND url = :page_url
|
||||
AND from_visit = 0`
|
||||
);
|
||||
stmt.params.page_url = place.uri.spec;
|
||||
@ -740,7 +738,7 @@ add_task(function* test_properties_saved() {
|
||||
FROM moz_places h
|
||||
JOIN moz_historyvisits v
|
||||
ON h.id = v.place_id
|
||||
WHERE h.url = :page_url
|
||||
WHERE h.url_hash = hash(:page_url) AND h.url = :page_url
|
||||
AND v.visit_date = :visit_date`
|
||||
);
|
||||
stmt.params.page_url = uri.spec;
|
||||
@ -755,7 +753,7 @@ add_task(function* test_properties_saved() {
|
||||
FROM moz_places h
|
||||
JOIN moz_historyvisits v
|
||||
ON h.id = v.place_id
|
||||
WHERE h.url = :page_url
|
||||
WHERE h.url_hash = hash(:page_url) AND h.url = :page_url
|
||||
AND v.visit_type = :transition_type`
|
||||
);
|
||||
stmt.params.page_url = uri.spec;
|
||||
@ -768,7 +766,7 @@ add_task(function* test_properties_saved() {
|
||||
stmt = DBConn().createStatement(
|
||||
`SELECT COUNT(1) AS count
|
||||
FROM moz_places h
|
||||
WHERE h.url = :page_url
|
||||
WHERE h.url_hash = hash(:page_url) AND h.url = :page_url
|
||||
AND h.title = :title`
|
||||
);
|
||||
stmt.params.page_url = uri.spec;
|
||||
@ -841,11 +839,13 @@ add_task(function* test_referrer_saved() {
|
||||
let stmt = DBConn().createStatement(
|
||||
`SELECT COUNT(1) AS count
|
||||
FROM moz_historyvisits
|
||||
WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url)
|
||||
JOIN moz_places h ON h.id = place_id
|
||||
WHERE url_hash = hash(:page_url) AND url = :page_url
|
||||
AND from_visit = (
|
||||
SELECT id
|
||||
FROM moz_historyvisits
|
||||
WHERE place_id = (SELECT id FROM moz_places WHERE url = :referrer)
|
||||
SELECT v.id
|
||||
FROM moz_historyvisits v
|
||||
JOIN moz_places h ON h.id = place_id
|
||||
WHERE url_hash = hash(:referrer) AND url = :referrer
|
||||
)`
|
||||
);
|
||||
stmt.params.page_url = uri.spec;
|
||||
@ -1117,8 +1117,9 @@ add_task(function* test_typed_hidden_not_overwritten() {
|
||||
yield promiseUpdatePlaces(places);
|
||||
|
||||
let db = yield PlacesUtils.promiseDBConnection();
|
||||
let rows = yield db.execute("SELECT hidden, typed FROM moz_places WHERE url = :url",
|
||||
{ url: "http://mozilla.org/" });
|
||||
let rows = yield db.execute(
|
||||
"SELECT hidden, typed FROM moz_places WHERE url_hash = hash(:url) AND url = :url",
|
||||
{ url: "http://mozilla.org/" });
|
||||
Assert.equal(rows[0].getResultByName("typed"), 1,
|
||||
"The page should be marked as typed");
|
||||
Assert.equal(rows[0].getResultByName("hidden"), 0,
|
||||
|
@ -131,7 +131,8 @@ add_task(function* test_history_clear()
|
||||
|
||||
// Check that all moz_places entries except bookmarks and place: have been removed
|
||||
stmt = mDBConn.createStatement(
|
||||
`SELECT h.id FROM moz_places h WHERE SUBSTR(h.url, 1, 6) <> 'place:'
|
||||
`SELECT h.id FROM moz_places h WHERE
|
||||
url_hash NOT BETWEEN hash('place', 'prefix_lo') AND hash('place', 'prefix_hi')
|
||||
AND NOT EXISTS (SELECT id FROM moz_bookmarks WHERE fk = h.id) LIMIT 1`);
|
||||
do_check_false(stmt.executeStep());
|
||||
stmt.finalize();
|
||||
@ -160,7 +161,9 @@ add_task(function* test_history_clear()
|
||||
// Check that place:uris have frecency 0
|
||||
stmt = mDBConn.createStatement(
|
||||
`SELECT h.id FROM moz_places h
|
||||
WHERE SUBSTR(h.url, 1, 6) = 'place:' AND h.frecency <> 0 LIMIT 1`);
|
||||
WHERE url_hash BETWEEN hash('place', 'prefix_lo')
|
||||
AND hash('place', 'prefix_hi')
|
||||
AND h.frecency <> 0 LIMIT 1`);
|
||||
do_check_false(stmt.executeStep());
|
||||
stmt.finalize();
|
||||
});
|
||||
|
@ -18,7 +18,7 @@ function isHostInMozPlaces(aURI)
|
||||
let stmt = DBConn().createStatement(
|
||||
`SELECT url
|
||||
FROM moz_places
|
||||
WHERE url = :host`
|
||||
WHERE url_hash = hash(:host) AND url = :host`
|
||||
);
|
||||
let result = false;
|
||||
stmt.params.host = aURI.spec;
|
||||
|
@ -42,7 +42,7 @@ function cleanDatabase() {
|
||||
|
||||
function addPlace(aUrl, aFavicon) {
|
||||
let stmt = mDBConn.createStatement(
|
||||
"INSERT INTO moz_places (url, favicon_id) VALUES (:url, :favicon)");
|
||||
"INSERT INTO moz_places (url, url_hash, favicon_id) VALUES (:url, hash(:url), :favicon)");
|
||||
stmt.params["url"] = aUrl || "http://www.mozilla.org";
|
||||
stmt.params["favicon"] = aFavicon || null;
|
||||
stmt.execute();
|
||||
@ -1077,7 +1077,8 @@ tests.push({
|
||||
setup: function* () {
|
||||
function setVisitCount(aURL, aValue) {
|
||||
let stmt = mDBConn.createStatement(
|
||||
"UPDATE moz_places SET visit_count = :count WHERE url = :url"
|
||||
`UPDATE moz_places SET visit_count = :count WHERE url_hash = hash(:url)
|
||||
AND url = :url`
|
||||
);
|
||||
stmt.params.count = aValue;
|
||||
stmt.params.url = aURL;
|
||||
@ -1086,7 +1087,8 @@ tests.push({
|
||||
}
|
||||
function setLastVisitDate(aURL, aValue) {
|
||||
let stmt = mDBConn.createStatement(
|
||||
"UPDATE moz_places SET last_visit_date = :date WHERE url = :url"
|
||||
`UPDATE moz_places SET last_visit_date = :date WHERE url_hash = hash(:url)
|
||||
AND url = :url`
|
||||
);
|
||||
stmt.params.date = aValue;
|
||||
stmt.params.url = aURL;
|
||||
@ -1151,8 +1153,8 @@ tests.push({
|
||||
name: "L.3",
|
||||
desc: "recalculate hidden for redirects.",
|
||||
|
||||
setup: function() {
|
||||
PlacesTestUtils.addVisits([
|
||||
*setup() {
|
||||
yield PlacesTestUtils.addVisits([
|
||||
{ uri: NetUtil.newURI("http://l3.moz.org/"),
|
||||
transition: TRANSITION_TYPED },
|
||||
{ uri: NetUtil.newURI("http://l3.moz.org/redirecting/"),
|
||||
@ -1197,6 +1199,61 @@ tests.push({
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
tests.push({
|
||||
name: "L.4",
|
||||
desc: "recalculate foreign_count.",
|
||||
|
||||
*setup() {
|
||||
this._pageGuid = (yield PlacesUtils.history.insert({ url: "http://l4.moz.org/",
|
||||
visits: [{ date: new Date() }] })).guid;
|
||||
yield PlacesUtils.bookmarks.insert({ url: "http://l4.moz.org/",
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid});
|
||||
yield PlacesUtils.keywords.insert({ url: "http://l4.moz.org/", keyword: "kw" });
|
||||
Assert.equal((yield this._getForeignCount()), 2);
|
||||
},
|
||||
|
||||
*_getForeignCount() {
|
||||
let db = yield PlacesUtils.promiseDBConnection();
|
||||
let rows = yield db.execute(`SELECT foreign_count FROM moz_places
|
||||
WHERE guid = :guid`, { guid: this._pageGuid });
|
||||
return rows[0].getResultByName("foreign_count");
|
||||
},
|
||||
|
||||
*check() {
|
||||
Assert.equal((yield this._getForeignCount()), 2);
|
||||
}
|
||||
});
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
tests.push({
|
||||
name: "L.5",
|
||||
desc: "recalculate hashes when missing.",
|
||||
|
||||
*setup() {
|
||||
this._pageGuid = (yield PlacesUtils.history.insert({ url: "http://l5.moz.org/",
|
||||
visits: [{ date: new Date() }] })).guid;
|
||||
Assert.ok((yield this._getHash()) > 0);
|
||||
yield PlacesUtils.withConnectionWrapper("change url hash", Task.async(function* (db) {
|
||||
yield db.execute(`UPDATE moz_places SET url_hash = 0`);
|
||||
}));
|
||||
Assert.equal((yield this._getHash()), 0);
|
||||
},
|
||||
|
||||
*_getHash() {
|
||||
let db = yield PlacesUtils.promiseDBConnection();
|
||||
let rows = yield db.execute(`SELECT url_hash FROM moz_places
|
||||
WHERE guid = :guid`, { guid: this._pageGuid });
|
||||
return rows[0].getResultByName("url_hash");
|
||||
},
|
||||
|
||||
*check() {
|
||||
Assert.ok((yield this._getHash()) > 0);
|
||||
}
|
||||
});
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
tests.push({
|
||||
name: "Z",
|
||||
desc: "Sanity: Preventive maintenance does not touch valid items",
|
||||
@ -1261,19 +1318,8 @@ tests.push({
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// main
|
||||
function run_test()
|
||||
{
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* test_preventive_maintenance()
|
||||
{
|
||||
// Force initialization of the bookmarks hash. This test could cause
|
||||
// it to go out of sync due to direct queries on the database.
|
||||
yield PlacesTestUtils.addVisits(uri("http://force.bookmarks.hash"));
|
||||
do_check_false(bs.isBookmarked(uri("http://force.bookmarks.hash")));
|
||||
|
||||
// Get current bookmarks max ID for cleanup
|
||||
let stmt = mDBConn.createStatement("SELECT MAX(id) FROM moz_bookmarks");
|
||||
stmt.executeStep();
|
||||
|
@ -931,9 +931,10 @@ function openConnection(options) {
|
||||
try {
|
||||
resolve(
|
||||
new OpenedConnection(connection.QueryInterface(Ci.mozIStorageAsyncConnection),
|
||||
identifier, openedOptions));
|
||||
identifier, openedOptions));
|
||||
} catch (ex) {
|
||||
log.warn("Could not open database", ex);
|
||||
connection.asyncClose();
|
||||
reject(ex);
|
||||
}
|
||||
});
|
||||
@ -1012,6 +1013,7 @@ function cloneStorageConnection(options) {
|
||||
resolve(new OpenedConnection(conn, identifier, openedOptions));
|
||||
} catch (ex) {
|
||||
log.warn("Could not clone database", ex);
|
||||
connection.asyncClose();
|
||||
reject(ex);
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user