--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -72,32 +72,38 @@ struct VisitData {
VisitData()
: placeId(0)
, visitId(0)
, hidden(true)
, typed(false)
, transitionType(UINT32_MAX)
, visitTime(0)
, frecency(-1)
+ , lastVisitId(0)
+ , lastVisitTime(0)
+ , referrerVisitId(0)
, titleChanged(false)
, shouldUpdateFrecency(true)
{
guid.SetIsVoid(true);
title.SetIsVoid(true);
}
explicit VisitData(nsIURI* aURI,
nsIURI* aReferrer = nullptr)
: placeId(0)
, visitId(0)
, hidden(true)
, typed(false)
, transitionType(UINT32_MAX)
, visitTime(0)
, frecency(-1)
+ , lastVisitId(0)
+ , lastVisitTime(0)
+ , referrerVisitId(0)
, titleChanged(false)
, shouldUpdateFrecency(true)
{
MOZ_ASSERT(aURI);
if (aURI) {
(void)aURI->GetSpec(spec);
(void)GetReversedHostname(aURI, revHost);
}
@@ -116,56 +122,39 @@ struct VisitData {
* TRANSITION_ constants on nsINavHistoryService.
*/
void SetTransitionType(uint32_t aTransitionType)
{
typed = aTransitionType == nsINavHistoryService::TRANSITION_TYPED;
transitionType = aTransitionType;
}
- /**
- * Determines if this refers to the same url as aOther, and updates aOther
- * with missing information if so.
- *
- * @param aOther
- * The other place to check against.
- * @return true if this is a visit for the same place as aOther, false
- * otherwise.
- */
- bool IsSamePlaceAs(VisitData& aOther)
- {
- if (!spec.Equals(aOther.spec)) {
- return false;
- }
-
- aOther.placeId = placeId;
- aOther.guid = guid;
- return true;
- }
-
int64_t placeId;
nsCString guid;
int64_t visitId;
nsCString spec;
nsString revHost;
bool hidden;
bool typed;
uint32_t transitionType;
PRTime visitTime;
int32_t frecency;
+ int64_t lastVisitId;
+ PRTime lastVisitTime;
/**
* Stores the title. If this is empty (IsEmpty() returns true), then the
* title should be removed from the Place. If the title is void (IsVoid()
* returns true), then no title has been set on this object, and titleChanged
* should remain false.
*/
nsString title;
nsCString referrerSpec;
+ int64_t referrerVisitId;
// TODO bug 626836 hook up hidden and typed change tracking too!
bool titleChanged;
// Indicates whether frecency should be updated for this visit.
bool shouldUpdateFrecency;
};
@@ -618,20 +607,18 @@ NS_IMPL_ISUPPORTS_INHERITED(
)
/**
* Notifies observers about a visit.
*/
class NotifyVisitObservers : public Runnable
{
public:
- NotifyVisitObservers(VisitData& aPlace,
- VisitData& aReferrer)
+ NotifyVisitObservers(VisitData& aPlace)
: mPlace(aPlace)
- , mReferrer(aReferrer)
, mHistory(History::GetService())
{
}
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread(), "This should be called on the main thread");
@@ -652,17 +639,17 @@ public:
if (!uri) {
return NS_ERROR_UNEXPECTED;
}
// Notify the visit. Note that TRANSITION_EMBED visits are never added
// to the database, thus cannot be queried and we don't notify them.
if (mPlace.transitionType != nsINavHistoryService::TRANSITION_EMBED) {
navHistory->NotifyOnVisit(uri, mPlace.visitId, mPlace.visitTime,
- mReferrer.visitId, mPlace.transitionType,
+ mPlace.referrerVisitId, mPlace.transitionType,
mPlace.guid, mPlace.hidden);
}
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
if (obsService) {
DebugOnly<nsresult> rv =
obsService->NotifyObservers(uri, URI_VISIT_SAVED, nullptr);
@@ -673,17 +660,16 @@ public:
NS_ENSURE_STATE(history);
history->AppendToRecentlyVisitedURIs(uri);
history->NotifyVisited(uri);
return NS_OK;
}
private:
VisitData mPlace;
- VisitData mReferrer;
RefPtr<History> mHistory;
};
/**
* Notifies observers about a pages title changing.
*/
class NotifyTitleObservers : public Runnable
{
@@ -922,61 +908,68 @@ public:
}
mozStorageTransaction transaction(mDBConn, false,
mozIStorageConnection::TRANSACTION_IMMEDIATE);
VisitData* lastFetchedPlace = nullptr;
for (nsTArray<VisitData>::size_type i = 0; i < mPlaces.Length(); i++) {
VisitData& place = mPlaces.ElementAt(i);
- VisitData& referrer = mReferrers.ElementAt(i);
// Fetching from the database can overwrite this information, so save it
// apart.
bool typed = place.typed;
bool hidden = place.hidden;
// We can avoid a database lookup if it's the same place as the last
// visit we added.
- bool known = lastFetchedPlace && lastFetchedPlace->IsSamePlaceAs(place);
+ bool known = lastFetchedPlace && (*lastFetchedPlace).spec.Equals(place.spec);
if (!known) {
nsresult rv = mHistory->FetchPageInfo(place, &known);
if (NS_FAILED(rv)) {
if (!!mCallback) {
nsCOMPtr<nsIRunnable> event =
new NotifyPlaceInfoCallback(mCallback, place, true, rv);
return NS_DispatchToMainThread(event);
}
return NS_OK;
}
lastFetchedPlace = &mPlaces.ElementAt(i);
+ } else {
+ // Copy over the data from the already known place.
+ place.placeId = (*lastFetchedPlace).placeId;
+ place.guid = (*lastFetchedPlace).guid;
+ place.lastVisitId = (*lastFetchedPlace).visitId;
+ place.lastVisitTime = (*lastFetchedPlace).visitTime;
+ place.titleChanged = !(*lastFetchedPlace).title.Equals(place.title);
+ place.frecency = (*lastFetchedPlace).frecency;
}
// If any transition is typed, ensure the page is marked as typed.
if (typed != lastFetchedPlace->typed) {
place.typed = true;
}
// If any transition is visible, ensure the page is marked as visible.
if (hidden != lastFetchedPlace->hidden) {
place.hidden = false;
}
- FetchReferrerInfo(referrer, place);
-
- nsresult rv = DoDatabaseInserts(known, place, referrer);
+ FetchReferrerInfo(place);
+
+ nsresult rv = DoDatabaseInserts(known, place);
if (!!mCallback) {
nsCOMPtr<nsIRunnable> event =
new NotifyPlaceInfoCallback(mCallback, place, true, rv);
nsresult rv2 = NS_DispatchToMainThread(event);
NS_ENSURE_SUCCESS(rv2, rv2);
}
NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIRunnable> event = new NotifyVisitObservers(place, referrer);
+ nsCOMPtr<nsIRunnable> event = new NotifyVisitObservers(place);
rv = NS_DispatchToMainThread(event);
NS_ENSURE_SUCCESS(rv, rv);
// Notify about title change if needed.
if ((!known && !place.title.IsVoid()) || place.titleChanged) {
event = new NotifyTitleObservers(place.spec, place.title, place.guid);
rv = NS_DispatchToMainThread(event);
NS_ENSURE_SUCCESS(rv, rv);
@@ -994,325 +987,211 @@ private:
const nsMainThreadPtrHandle<mozIVisitInfoCallback>& aCallback)
: mDBConn(aConnection)
, mCallback(aCallback)
, mHistory(History::GetService())
{
MOZ_ASSERT(NS_IsMainThread(), "This should be called on the main thread");
mPlaces.SwapElements(aPlaces);
- mReferrers.SetLength(mPlaces.Length());
-
- for (nsTArray<VisitData>::size_type i = 0; i < mPlaces.Length(); i++) {
- mReferrers[i].spec = mPlaces[i].referrerSpec;
#ifdef DEBUG
+ for (nsTArray<VisitData>::size_type i = 0; i < mPlaces.Length(); i++) {
nsCOMPtr<nsIURI> uri;
MOZ_ASSERT(NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), mPlaces[i].spec)));
- NS_ASSERTION(CanAddURI(uri),
- "Passed a VisitData with a URI we cannot add to history!");
+ MOZ_ASSERT(CanAddURI(uri),
+ "Passed a VisitData with a URI we cannot add to history!");
+ }
#endif
- }
}
/**
* Inserts or updates the entry in moz_places for this visit, adds the visit,
* and updates the frecency of the place.
*
* @param aKnown
* True if we already have an entry for this place in moz_places, false
* otherwise.
* @param aPlace
* The place we are adding a visit for.
- * @param aReferrer
- * The referrer for aPlace.
*/
nsresult DoDatabaseInserts(bool aKnown,
- VisitData& aPlace,
- VisitData& aReferrer)
+ VisitData& aPlace)
{
MOZ_ASSERT(!NS_IsMainThread(), "This should not be called on the main thread");
// If the page was in moz_places, we need to update the entry.
nsresult rv;
if (aKnown) {
rv = mHistory->UpdatePlace(aPlace);
NS_ENSURE_SUCCESS(rv, rv);
}
// Otherwise, the page was not in moz_places, so now we have to add it.
else {
rv = mHistory->InsertPlace(aPlace);
NS_ENSURE_SUCCESS(rv, rv);
-
- // We need the place id and guid of the page we just inserted when we
- // have a callback or when the GUID isn't known. No point in doing the
- // disk I/O if we do not need it.
- if (!!mCallback || aPlace.guid.IsEmpty()) {
- bool exists;
- rv = mHistory->FetchPageInfo(aPlace, &exists);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (!exists) {
- NS_NOTREACHED("should have an entry in moz_places");
- }
- }
+ aPlace.placeId = nsNavHistory::sLastInsertedPlaceId;
}
-
- rv = AddVisit(aPlace, aReferrer);
+ MOZ_ASSERT(aPlace.placeId > 0);
+
+ rv = AddVisit(aPlace);
NS_ENSURE_SUCCESS(rv, rv);
// TODO (bug 623969) we shouldn't update this after each visit, but
// rather only for each unique place to save disk I/O.
// Don't update frecency if the page should not appear in autocomplete.
if (aPlace.shouldUpdateFrecency) {
rv = UpdateFrecency(aPlace);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
/**
- * Loads visit information about the page into _place.
- *
- * @param _place
- * The VisitData for the place we need to know visit information about.
- * @param [optional] aThresholdStart
- * The timestamp of a new visit (not represented by _place) used to
- * determine if the page was recently visited or not.
- * @return true if the page was recently (determined with aThresholdStart)
- * visited, false otherwise.
- */
- bool FetchVisitInfo(VisitData& _place,
- PRTime aThresholdStart = 0)
- {
- NS_PRECONDITION(!_place.spec.IsEmpty(), "must have a non-empty spec!");
-
- nsCOMPtr<mozIStorageStatement> stmt;
- // If we have a visitTime, we want information on that specific visit.
- if (_place.visitTime) {
- stmt = mHistory->GetStatement(
- "SELECT id, visit_date "
- "FROM moz_historyvisits "
- "WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url) "
- "AND visit_date = :visit_date "
- );
- NS_ENSURE_TRUE(stmt, false);
-
- mozStorageStatementScoper scoper(stmt);
- nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("visit_date"),
- _place.visitTime);
- NS_ENSURE_SUCCESS(rv, false);
-
- scoper.Abandon();
- }
- // Otherwise, we want information about the most recent visit.
- else {
- stmt = mHistory->GetStatement(
- "SELECT id, visit_date "
- "FROM moz_historyvisits "
- "WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url) "
- "ORDER BY visit_date DESC "
- );
- NS_ENSURE_TRUE(stmt, false);
- }
- mozStorageStatementScoper scoper(stmt);
-
- nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"),
- _place.spec);
- NS_ENSURE_SUCCESS(rv, false);
-
- bool hasResult;
- rv = stmt->ExecuteStep(&hasResult);
- NS_ENSURE_SUCCESS(rv, false);
- if (!hasResult) {
- return false;
- }
-
- rv = stmt->GetInt64(0, &_place.visitId);
- NS_ENSURE_SUCCESS(rv, false);
- rv = stmt->GetInt64(1, reinterpret_cast<int64_t*>(&_place.visitTime));
- NS_ENSURE_SUCCESS(rv, false);
-
- // If we have been given a visit threshold start time, go ahead and
- // calculate if we have been recently visited.
- if (aThresholdStart &&
- aThresholdStart - _place.visitTime <= RECENT_EVENT_THRESHOLD) {
- return true;
- }
-
- return false;
- }
-
- /**
* Fetches information about a referrer for aPlace if it was a recent
* visit or not.
*
- * @param aReferrer
- * The VisitData for the referrer. This will be populated with
- * FetchVisitInfo.
* @param aPlace
* The VisitData for the visit we will eventually add.
*
*/
- void FetchReferrerInfo(VisitData& aReferrer,
- VisitData& aPlace)
+ void FetchReferrerInfo(VisitData& aPlace)
{
- if (aReferrer.spec.IsEmpty()) {
+ if (aPlace.referrerSpec.IsEmpty()) {
return;
}
- if (!FetchVisitInfo(aReferrer, aPlace.visitTime)) {
- // We must change both the place and referrer to indicate that we will
- // not be using the referrer's data. This behavior has test coverage, so
- // if this invariant changes, we'll know.
+ VisitData referrer;
+ referrer.spec = aPlace.referrerSpec;
+ // If the referrer is the same as the page, we don't need to fetch it.
+ if (aPlace.referrerSpec.Equals(aPlace.spec)) {
+ referrer = aPlace;
+ // The page last visit id is also the referrer visit id.
+ aPlace.referrerVisitId = aPlace.lastVisitId;
+ } else {
+ bool exists = false;
+ if (NS_SUCCEEDED(mHistory->FetchPageInfo(referrer, &exists)) && exists) {
+ // Copy the referrer last visit id.
+ aPlace.referrerVisitId = referrer.lastVisitId;
+ }
+ }
+
+ // Check if the page has effectively been visited recently, otherwise
+ // discard the referrer info.
+ if (!aPlace.referrerVisitId || !referrer.lastVisitTime ||
+ aPlace.visitTime - referrer.lastVisitTime > RECENT_EVENT_THRESHOLD) {
+ // We will not be using the referrer data.
aPlace.referrerSpec.Truncate();
- aReferrer.visitId = 0;
+ aPlace.referrerVisitId = 0;
}
}
/**
* Adds a visit for _place and updates it with the right visit id.
*
* @param _place
* The VisitData for the place we need to know visit information about.
- * @param aReferrer
- * A reference to the referrer's visit data.
*/
- nsresult AddVisit(VisitData& _place,
- const VisitData& aReferrer)
+ nsresult AddVisit(VisitData& _place)
{
+ MOZ_ASSERT(_place.placeId > 0);
+
nsresult rv;
nsCOMPtr<mozIStorageStatement> stmt;
- if (_place.placeId) {
- stmt = mHistory->GetStatement(
- "INSERT INTO moz_historyvisits "
- "(from_visit, place_id, visit_date, visit_type, session) "
- "VALUES (:from_visit, :page_id, :visit_date, :visit_type, 0) "
- );
- NS_ENSURE_STATE(stmt);
- rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), _place.placeId);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- else {
- stmt = mHistory->GetStatement(
- "INSERT INTO moz_historyvisits "
- "(from_visit, place_id, visit_date, visit_type, session) "
- "VALUES (:from_visit, (SELECT id FROM moz_places WHERE url = :page_url), :visit_date, :visit_type, 0) "
- );
- NS_ENSURE_STATE(stmt);
- rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), _place.spec);
- NS_ENSURE_SUCCESS(rv, rv);
- }
+ stmt = mHistory->GetStatement(
+ "INSERT INTO moz_historyvisits "
+ "(from_visit, place_id, visit_date, visit_type, session) "
+ "VALUES (:from_visit, :page_id, :visit_date, :visit_type, 0) "
+ );
+ NS_ENSURE_STATE(stmt);
+ mozStorageStatementScoper scoper(stmt);
+
+ rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), _place.placeId);
+ NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("from_visit"),
- aReferrer.visitId);
+ _place.referrerVisitId);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("visit_date"),
_place.visitTime);
NS_ENSURE_SUCCESS(rv, rv);
uint32_t transitionType = _place.transitionType;
NS_ASSERTION(transitionType >= nsINavHistoryService::TRANSITION_LINK &&
transitionType <= nsINavHistoryService::TRANSITION_FRAMED_LINK,
"Invalid transition type!");
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("visit_type"),
transitionType);
NS_ENSURE_SUCCESS(rv, rv);
- mozStorageStatementScoper scoper(stmt);
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
- // Now that it should be in the database, we need to obtain the id of the
- // visit we just added.
- (void)FetchVisitInfo(_place);
+ _place.visitId = nsNavHistory::sLastInsertedVisitId;
+ MOZ_ASSERT(_place.visitId > 0);
return NS_OK;
}
/**
* Updates the frecency, and possibly the hidden-ness of aPlace.
*
* @param aPlace
* The VisitData for the place we want to update.
*/
nsresult UpdateFrecency(const VisitData& aPlace)
{
MOZ_ASSERT(aPlace.shouldUpdateFrecency);
+ MOZ_ASSERT(aPlace.placeId > 0);
nsresult rv;
{ // First, set our frecency to the proper value.
nsCOMPtr<mozIStorageStatement> stmt;
- if (aPlace.placeId) {
- stmt = mHistory->GetStatement(
- "UPDATE moz_places "
- "SET frecency = NOTIFY_FRECENCY("
- "CALCULATE_FRECENCY(:page_id), "
- "url, guid, hidden, last_visit_date"
- ") "
- "WHERE id = :page_id"
- );
- NS_ENSURE_STATE(stmt);
- rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), aPlace.placeId);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- else {
- stmt = mHistory->GetStatement(
- "UPDATE moz_places "
- "SET frecency = NOTIFY_FRECENCY("
- "CALCULATE_FRECENCY(id), url, guid, hidden, last_visit_date"
- ") "
- "WHERE url = :page_url"
- );
- NS_ENSURE_STATE(stmt);
- rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aPlace.spec);
- NS_ENSURE_SUCCESS(rv, rv);
- }
+ stmt = mHistory->GetStatement(
+ "UPDATE moz_places "
+ "SET frecency = NOTIFY_FRECENCY("
+ "CALCULATE_FRECENCY(:page_id), "
+ "url, guid, hidden, last_visit_date"
+ ") "
+ "WHERE id = :page_id"
+ );
+ NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
+ rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), aPlace.placeId);
+ NS_ENSURE_SUCCESS(rv, rv);
+
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
}
- if (!aPlace.hidden) {
+ if (!aPlace.hidden && aPlace.frecency == 0) {
// Mark the page as not hidden if the frecency is now nonzero.
nsCOMPtr<mozIStorageStatement> stmt;
- if (aPlace.placeId) {
- stmt = mHistory->GetStatement(
- "UPDATE moz_places "
- "SET hidden = 0 "
- "WHERE id = :page_id AND frecency <> 0"
- );
- NS_ENSURE_STATE(stmt);
- rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), aPlace.placeId);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- else {
- stmt = mHistory->GetStatement(
- "UPDATE moz_places "
- "SET hidden = 0 "
- "WHERE url = :page_url AND frecency <> 0"
- );
- NS_ENSURE_STATE(stmt);
- rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aPlace.spec);
- NS_ENSURE_SUCCESS(rv, rv);
- }
-
+ stmt = mHistory->GetStatement(
+ "UPDATE moz_places "
+ "SET hidden = 0 "
+ "WHERE id = :page_id AND frecency <> 0"
+ );
+ NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
+
+ rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), aPlace.placeId);
+ NS_ENSURE_SUCCESS(rv, rv);
+
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
mozIStorageConnection* mDBConn;
nsTArray<VisitData> mPlaces;
- nsTArray<VisitData> mReferrers;
nsMainThreadPtrHandle<mozIVisitInfoCallback> mCallback;
/**
* Strong reference to the History object because we do not want it to
* disappear out from under us.
*/
RefPtr<History> mHistory;
@@ -1423,18 +1302,18 @@ public:
NS_ENSURE_SUCCESS(rv, rv);
if (!exists || !mPlace.titleChanged) {
// We have no record of this page, or we have no title change, so there
// is no need to do any further work.
return NS_OK;
}
- NS_ASSERTION(mPlace.placeId > 0,
- "We somehow have an invalid place id here!");
+ MOZ_ASSERT(mPlace.placeId > 0,
+ "We somehow have an invalid place id here!");
// Now we can update our database record.
nsCOMPtr<mozIStorageStatement> stmt =
mHistory->GetStatement(
"UPDATE moz_places "
"SET title = :page_title "
"WHERE id = :page_id "
);
@@ -1949,18 +1828,17 @@ StoreAndNotifyEmbedVisit(VisitData& aPla
if (!!aCallback) {
nsMainThreadPtrHandle<mozIVisitInfoCallback>
callback(new nsMainThreadPtrHolder<mozIVisitInfoCallback>(aCallback));
nsCOMPtr<nsIRunnable> event =
new NotifyPlaceInfoCallback(callback, aPlace, true, NS_OK);
(void)NS_DispatchToMainThread(event);
}
- VisitData noReferrer;
- nsCOMPtr<nsIRunnable> event = new NotifyVisitObservers(aPlace, noReferrer);
+ nsCOMPtr<nsIRunnable> event = new NotifyVisitObservers(aPlace);
(void)NS_DispatchToMainThread(event);
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
//// History
@@ -2130,17 +2008,17 @@ History::GetIsVisitedStatement(mozIStora
NS_ENSURE_STATE(dbConn);
mConcurrentStatementsHolder = new ConcurrentStatementsHolder(dbConn);
}
mConcurrentStatementsHolder->GetIsVisitedStatement(aCallback);
return NS_OK;
}
nsresult
-History::InsertPlace(const VisitData& aPlace)
+History::InsertPlace(VisitData& aPlace)
{
NS_PRECONDITION(aPlace.placeId == 0, "should not have a valid place id!");
NS_PRECONDITION(!NS_IsMainThread(), "must be called off of the main thread!");
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) "
@@ -2167,30 +2045,30 @@ History::InsertPlace(const VisitData& aP
NS_ENSURE_SUCCESS(rv, rv);
// When inserting a page for a first visit that should not appear in
// autocomplete, for example an error page, use a zero frecency.
int32_t frecency = aPlace.shouldUpdateFrecency ? aPlace.frecency : 0;
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("frecency"), frecency);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("hidden"), aPlace.hidden);
NS_ENSURE_SUCCESS(rv, rv);
- nsAutoCString guid(aPlace.guid);
if (aPlace.guid.IsVoid()) {
- rv = GenerateGUID(guid);
+ rv = GenerateGUID(aPlace.guid);
NS_ENSURE_SUCCESS(rv, rv);
}
- rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("guid"), guid);
+ rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("guid"), aPlace.guid);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
// Post an onFrecencyChanged observer notification.
const nsNavHistory* navHistory = nsNavHistory::GetConstHistoryService();
NS_ENSURE_STATE(navHistory);
- navHistory->DispatchFrecencyChangedNotification(aPlace.spec, frecency, guid,
+ navHistory->DispatchFrecencyChangedNotification(aPlace.spec, frecency,
+ aPlace.guid,
aPlace.hidden,
aPlace.visitTime);
return NS_OK;
}
nsresult
History::UpdatePlace(const VisitData& aPlace)
@@ -2243,29 +2121,33 @@ History::FetchPageInfo(VisitData& _place
nsresult rv;
// URI takes precedence.
nsCOMPtr<mozIStorageStatement> stmt;
bool selectByURI = !_place.spec.IsEmpty();
if (selectByURI) {
stmt = GetStatement(
- "SELECT guid, id, title, hidden, typed, frecency "
- "FROM moz_places "
+ "SELECT guid, id, title, hidden, typed, frecency, last_visit_date, "
+ "(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 "
);
NS_ENSURE_STATE(stmt);
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), _place.spec);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
stmt = GetStatement(
- "SELECT url, id, title, hidden, typed, frecency "
- "FROM moz_places "
+ "SELECT url, id, title, hidden, typed, frecency, last_visit_date, "
+ "(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 guid = :guid "
);
NS_ENSURE_STATE(stmt);
rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("guid"), _place.guid);
NS_ENSURE_SUCCESS(rv, rv);
}
@@ -2318,16 +2200,21 @@ History::FetchPageInfo(VisitData& _place
int32_t typed;
rv = stmt->GetInt32(4, &typed);
NS_ENSURE_SUCCESS(rv, rv);
_place.typed = !!typed;
rv = stmt->GetInt32(5, &_place.frecency);
NS_ENSURE_SUCCESS(rv, rv);
+ rv = stmt->GetInt64(6, &_place.lastVisitTime);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = stmt->GetInt64(7, &_place.lastVisitId);
+ NS_ENSURE_SUCCESS(rv, rv);
+
return NS_OK;
}
MOZ_DEFINE_MALLOC_SIZE_OF(HistoryMallocSizeOf)
NS_IMETHODIMP
History::CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize)
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -398,18 +398,18 @@ nsNavHistory::GetOrCreateIdForPage(nsIUR
NS_ENSURE_SUCCESS(rv, rv);
if (*_pageId != 0) {
return NS_OK;
}
// Create a new hidden, untyped and unvisited entry.
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
- "INSERT OR IGNORE INTO moz_places (url, rev_host, hidden, frecency, guid) "
- "VALUES (:page_url, :rev_host, :hidden, :frecency, GENERATE_GUID()) "
+ "INSERT INTO moz_places (url, rev_host, hidden, frecency, guid) "
+ "VALUES (:page_url, :rev_host, :hidden, :frecency, :guid) "
);
NS_ENSURE_STATE(stmt);
mozStorageStatementScoper scoper(stmt);
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
NS_ENSURE_SUCCESS(rv, rv);
// host (reversed with trailing period)
nsAutoString revHost;
@@ -424,38 +424,26 @@ nsNavHistory::GetOrCreateIdForPage(nsIUR
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("hidden"), 1);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString spec;
rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("frecency"),
IsQueryURI(spec) ? 0 : -1);
NS_ENSURE_SUCCESS(rv, rv);
+ nsAutoCString guid;
+ rv = GenerateGUID(_GUID);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("guid"), _GUID);
+ NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->Execute();
NS_ENSURE_SUCCESS(rv, rv);
- {
- nsCOMPtr<mozIStorageStatement> getIdStmt = mDB->GetStatement(
- "SELECT id, guid FROM moz_places WHERE url = :page_url "
- );
- NS_ENSURE_STATE(getIdStmt);
- mozStorageStatementScoper getIdScoper(getIdStmt);
-
- rv = URIBinder::Bind(getIdStmt, NS_LITERAL_CSTRING("page_url"), aURI);
- NS_ENSURE_SUCCESS(rv, rv);
-
- bool hasResult = false;
- rv = getIdStmt->ExecuteStep(&hasResult);
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ASSERTION(hasResult, "hasResult is false but the call succeeded?");
- *_pageId = getIdStmt->AsInt64(0);
- rv = getIdStmt->GetUTF8String(1, _GUID);
- NS_ENSURE_SUCCESS(rv, rv);
- }
+ *_pageId = sLastInsertedPlaceId;
return NS_OK;
}
void
nsNavHistory::LoadPrefs()
{
@@ -605,16 +593,31 @@ nsNavHistory::DispatchFrecencyChangedNot
PRTime aLastVisitDate) const
{
nsCOMPtr<nsIRunnable> notif = new FrecencyNotification(aSpec, aNewFrecency,
aGUID, aHidden,
aLastVisitDate);
(void)NS_DispatchToMainThread(notif);
}
+Atomic<int64_t> nsNavHistory::sLastInsertedPlaceId(0);
+Atomic<int64_t> nsNavHistory::sLastInsertedVisitId(0);
+
+void // static
+nsNavHistory::StoreLastInsertedId(const nsACString& aTable,
+ const int64_t aLastInsertedId) {
+ if (aTable.Equals(NS_LITERAL_CSTRING("moz_places"))) {
+ nsNavHistory::sLastInsertedPlaceId = aLastInsertedId;
+ } else if (aTable.Equals(NS_LITERAL_CSTRING("moz_historyvisits"))) {
+ nsNavHistory::sLastInsertedVisitId = aLastInsertedId;
+ } else {
+ MOZ_ASSERT(false, "Trying to store the insert id for an unknown table?");
+ }
+}
+
int32_t
nsNavHistory::GetDaysOfHistory() {
MOZ_ASSERT(NS_IsMainThread(), "This can only be called on the main thread");
if (mDaysOfHistory != -1)
return mDaysOfHistory;
// SQLite doesn't have a CEIL() function, so we must do that later.