--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -188,20 +188,20 @@ NS_INTERFACE_MAP_END
// We don't care about flattening everything
NS_IMPL_CI_INTERFACE_GETTER(nsNavHistory,
nsINavHistoryService,
nsIBrowserHistory)
namespace {
-static int64_t GetSimpleBookmarksQueryFolder(nsNavHistoryQuery* aQuery,
- nsNavHistoryQueryOptions* aOptions);
-static void ParseSearchTermsFromQueries(const nsCOMArray<nsNavHistoryQuery>& aQueries,
- nsTArray<nsTArray<nsString>*>* aTerms);
+static int64_t GetSimpleBookmarksQueryFolder(const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions);
+static void ParseSearchTermsFromQuery(const RefPtr<nsNavHistoryQuery>& aQuery,
+ nsTArray<nsString>* aTerms);
void GetTagsSqlFragment(int64_t aTagsFolder,
const nsACString& aRelation,
bool aHasSearchTerms,
nsACString& _sqlFragment) {
if (!aHasSearchTerms)
_sqlFragment.AssignLiteral("null");
else {
@@ -785,57 +785,46 @@ nsNavHistory::NormalizeTime(uint32_t aRe
// QUERYUPDATE_NONE:
// A query that never updates, e.g. the left-pane root query.
//
// aHasSearchTerms will be set to true if the query has any dependence on
// keywords. When there is no dependence on keywords, we can handle title
// change operations as simple instead of complex.
uint32_t
-nsNavHistory::GetUpdateRequirements(const nsCOMArray<nsNavHistoryQuery>& aQueries,
+nsNavHistory::GetUpdateRequirements(const RefPtr<nsNavHistoryQuery>& aQuery,
nsNavHistoryQueryOptions* aOptions,
bool* aHasSearchTerms)
{
- NS_ASSERTION(aQueries.Count() > 0, "Must have at least one query");
-
// first check if there are search terms
*aHasSearchTerms = false;
- int32_t i;
- for (i = 0; i < aQueries.Count(); i ++) {
- aQueries[i]->GetHasSearchTerms(aHasSearchTerms);
- if (*aHasSearchTerms)
- break;
- }
+ aQuery->GetHasSearchTerms(aHasSearchTerms);
bool nonTimeBasedItems = false;
bool domainBasedItems = false;
- for (i = 0; i < aQueries.Count(); i ++) {
- nsNavHistoryQuery* query = aQueries[i];
-
- bool hasSearchTerms = !query->SearchTerms().IsEmpty();
- if (query->Folders().Length() > 0 ||
- query->OnlyBookmarked() ||
- query->Tags().Length() > 0 ||
- (aOptions->QueryType() == nsINavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS &&
- hasSearchTerms)) {
- return QUERYUPDATE_COMPLEX_WITH_BOOKMARKS;
- }
-
- // Note: we don't currently have any complex non-bookmarked items, but these
- // are expected to be added. Put detection of these items here.
- if (hasSearchTerms ||
- !query->Domain().IsVoid() ||
- query->Uri() != nullptr)
- nonTimeBasedItems = true;
-
- if (!query->Domain().IsVoid())
- domainBasedItems = true;
+ bool hasSearchTerms = !aQuery->SearchTerms().IsEmpty();
+ if (aQuery->Folders().Length() > 0 ||
+ aQuery->OnlyBookmarked() ||
+ aQuery->Tags().Length() > 0 ||
+ (aOptions->QueryType() == nsINavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS &&
+ hasSearchTerms)) {
+ return QUERYUPDATE_COMPLEX_WITH_BOOKMARKS;
}
+ // Note: we don't currently have any complex non-bookmarked items, but these
+ // are expected to be added. Put detection of these items here.
+ if (hasSearchTerms ||
+ !aQuery->Domain().IsVoid() ||
+ aQuery->Uri() != nullptr)
+ nonTimeBasedItems = true;
+
+ if (!aQuery->Domain().IsVoid())
+ domainBasedItems = true;
+
if (aOptions->ResultType() ==
nsINavHistoryQueryOptions::RESULTS_AS_TAG_QUERY)
return QUERYUPDATE_COMPLEX_WITH_BOOKMARKS;
if (aOptions->ResultType() ==
nsINavHistoryQueryOptions::RESULTS_AS_ROOTS_QUERY)
return QUERYUPDATE_MOBILEPREF;
@@ -845,146 +834,136 @@ nsNavHistory::GetUpdateRequirements(cons
// Whenever there is a maximum number of results,
// and we are not a bookmark query we must requery. This
// is because we can't generally know if any given addition/change causes
// the item to be in the top N items in the database.
if (aOptions->MaxResults() > 0)
return QUERYUPDATE_COMPLEX;
- if (aQueries.Count() == 1 && domainBasedItems)
+ if (domainBasedItems)
return QUERYUPDATE_HOST;
- if (aQueries.Count() == 1 && !nonTimeBasedItems)
+ if (!nonTimeBasedItems)
return QUERYUPDATE_TIME;
return QUERYUPDATE_SIMPLE;
}
// nsNavHistory::EvaluateQueryForNode
//
-// This runs the node through the given queries to see if satisfies the
+// This runs the node through the given query to see if satisfies the
// query conditions. Not every query parameters are handled by this code,
// but we handle the most common ones so that performance is better.
//
// We assume that the time on the node is the time that we want to compare.
// This is not necessarily true because URL nodes have the last access time,
// which is not necessarily the same. However, since this is being called
// to update the list, we assume that the last access time is the current
// access time that we are being asked to compare so it works out.
//
// Returns true if node matches the query, false if not.
bool
-nsNavHistory::EvaluateQueryForNode(const nsCOMArray<nsNavHistoryQuery>& aQueries,
+nsNavHistory::EvaluateQueryForNode(const RefPtr<nsNavHistoryQuery>& aQuery,
nsNavHistoryQueryOptions* aOptions,
nsNavHistoryResultNode* aNode)
{
// lazily created from the node's string when we need to match URIs
nsCOMPtr<nsIURI> nodeUri;
// --- hidden ---
if (aNode->mHidden && !aOptions->IncludeHidden())
return false;
- for (int32_t i = 0; i < aQueries.Count(); i ++) {
- bool hasIt;
- nsCOMPtr<nsNavHistoryQuery> query = aQueries[i];
-
- // --- begin time ---
- query->GetHasBeginTime(&hasIt);
- if (hasIt) {
- PRTime beginTime = NormalizeTime(query->BeginTimeReference(),
- query->BeginTime());
- if (aNode->mTime < beginTime)
- continue; // before our time range
- }
-
- // --- end time ---
- query->GetHasEndTime(&hasIt);
- if (hasIt) {
- PRTime endTime = NormalizeTime(query->EndTimeReference(),
- query->EndTime());
- if (aNode->mTime > endTime)
- continue; // after our time range
- }
-
- // --- search terms ---
- if (! query->SearchTerms().IsEmpty()) {
- // we can use the existing filtering code, just give it our one object in
- // an array.
- nsCOMArray<nsNavHistoryResultNode> inputSet;
- inputSet.AppendObject(aNode);
- nsCOMArray<nsNavHistoryQuery> queries;
- queries.AppendObject(query);
- nsCOMArray<nsNavHistoryResultNode> filteredSet;
- nsresult rv = FilterResultSet(nullptr, inputSet, &filteredSet, queries, aOptions);
- if (NS_FAILED(rv))
- continue;
- if (! filteredSet.Count())
- continue; // did not make it through the filter, doesn't match
+ bool hasIt;
+ // --- begin time ---
+ aQuery->GetHasBeginTime(&hasIt);
+ if (hasIt) {
+ PRTime beginTime = NormalizeTime(aQuery->BeginTimeReference(),
+ aQuery->BeginTime());
+ if (aNode->mTime < beginTime)
+ return false;
+ }
+
+ // --- end time ---
+ aQuery->GetHasEndTime(&hasIt);
+ if (hasIt) {
+ PRTime endTime = NormalizeTime(aQuery->EndTimeReference(),
+ aQuery->EndTime());
+ if (aNode->mTime > endTime)
+ return false;
+ }
+
+ // --- search terms ---
+ if (!aQuery->SearchTerms().IsEmpty()) {
+ // we can use the existing filtering code, just give it our one object in
+ // an array.
+ nsCOMArray<nsNavHistoryResultNode> inputSet;
+ inputSet.AppendObject(aNode);
+ nsCOMArray<nsNavHistoryResultNode> filteredSet;
+ nsresult rv = FilterResultSet(nullptr, inputSet, &filteredSet, aQuery, aOptions);
+ if (NS_FAILED(rv))
+ return false;
+ if (!filteredSet.Count())
+ return false;
+ }
+
+ // --- domain/host matching ---
+ aQuery->GetHasDomain(&hasIt);
+ if (hasIt) {
+ if (!nodeUri) {
+ // lazy creation of nodeUri, which might be checked for multiple queries
+ if (NS_FAILED(NS_NewURI(getter_AddRefs(nodeUri), aNode->mURI)))
+ return false;
}
-
- // --- domain/host matching ---
- query->GetHasDomain(&hasIt);
- if (hasIt) {
- if (! nodeUri) {
- // lazy creation of nodeUri, which might be checked for multiple queries
- if (NS_FAILED(NS_NewURI(getter_AddRefs(nodeUri), aNode->mURI)))
- continue;
- }
- nsAutoCString asciiRequest;
- if (NS_FAILED(AsciiHostNameFromHostString(query->Domain(), asciiRequest)))
- continue;
-
- if (query->DomainIsHost()) {
- nsAutoCString host;
- if (NS_FAILED(nodeUri->GetAsciiHost(host)))
- continue;
-
- if (! asciiRequest.Equals(host))
- continue; // host names don't match
- }
- // check domain names
- nsAutoCString domain;
- DomainNameFromURI(nodeUri, domain);
- if (! asciiRequest.Equals(domain))
- continue; // domain names don't match
+ nsAutoCString asciiRequest;
+ if (NS_FAILED(AsciiHostNameFromHostString(aQuery->Domain(), asciiRequest)))
+ return false;
+
+ if (aQuery->DomainIsHost()) {
+ nsAutoCString host;
+ if (NS_FAILED(nodeUri->GetAsciiHost(host)))
+ return false;
+
+ if (!asciiRequest.Equals(host))
+ return false;
}
-
- // --- URI matching ---
- if (query->Uri()) {
- if (! nodeUri) { // lazy creation of nodeUri
- if (NS_FAILED(NS_NewURI(getter_AddRefs(nodeUri), aNode->mURI)))
- continue;
- }
-
- bool equals;
- nsresult rv = query->Uri()->Equals(nodeUri, &equals);
- NS_ENSURE_SUCCESS(rv, false);
- if (! equals)
- continue;
+ // check domain names
+ nsAutoCString domain;
+ DomainNameFromURI(nodeUri, domain);
+ if (!asciiRequest.Equals(domain))
+ return false;
+ }
+
+ // --- URI matching ---
+ if (aQuery->Uri()) {
+ if (!nodeUri) { // lazy creation of nodeUri
+ if (NS_FAILED(NS_NewURI(getter_AddRefs(nodeUri), aNode->mURI)))
+ return false;
}
- // Transitions matching.
- const nsTArray<uint32_t>& transitions = query->Transitions();
- if (aNode->mTransitionType > 0 &&
- transitions.Length() &&
- !transitions.Contains(aNode->mTransitionType)) {
- continue; // transition doesn't match.
- }
-
- // If we ever make it to the bottom of this loop, that means it passed all
- // tests for the given query. Since queries are ORed together, that means
- // it passed everything and we are done.
- return true;
+ bool equals;
+ nsresult rv = aQuery->Uri()->Equals(nodeUri, &equals);
+ NS_ENSURE_SUCCESS(rv, false);
+ if (!equals)
+ return false;
}
- // didn't match any query
- return false;
+ // Transitions matching.
+ const nsTArray<uint32_t>& transitions = aQuery->Transitions();
+ if (aNode->mTransitionType > 0 &&
+ transitions.Length() &&
+ !transitions.Contains(aNode->mTransitionType)) {
+ return false;
+ }
+
+ // If we ever make it to the bottom, that means it passed all the tests for
+ // the given query.
+ return true;
}
// nsNavHistory::AsciiHostNameFromHostString
//
// We might have interesting encodings and different case in the host name.
// This will convert that host name into an ASCII host name by sending it
// through the URI canonicalization. The result can be used for comparison
@@ -1239,85 +1218,79 @@ nsNavHistory::ExecuteQuery(nsINavHistory
nsINavHistoryQueryOptions *aOptions,
nsINavHistoryResult** _retval)
{
NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
NS_ENSURE_ARG(aQuery);
NS_ENSURE_ARG(aOptions);
NS_ENSURE_ARG_POINTER(_retval);
- nsresult rv;
- // concrete options
- nsCOMPtr<nsNavHistoryQueryOptions> options = do_QueryInterface(aOptions);
- NS_ENSURE_TRUE(options, NS_ERROR_INVALID_ARG);
-
- // concrete queries array
- nsCOMArray<nsNavHistoryQuery> queries;
- RefPtr<nsNavHistoryQuery> query = do_QueryObject(aQuery);
+ // Clone the input query and options, because the caller might change the
+ // objects, but we always want to reflect the original parameters.
+ nsCOMPtr<nsINavHistoryQuery> queryClone;
+ aQuery->Clone(getter_AddRefs(queryClone));
+ NS_ENSURE_STATE(queryClone);
+ RefPtr<nsNavHistoryQuery> query = do_QueryObject(queryClone);
NS_ENSURE_STATE(query);
- queries.AppendObject(query);
+ nsCOMPtr<nsINavHistoryQueryOptions> optionsClone;
+ aOptions->Clone(getter_AddRefs(optionsClone));
+ NS_ENSURE_STATE(optionsClone);
+ RefPtr<nsNavHistoryQueryOptions> options = do_QueryObject(optionsClone);
+ NS_ENSURE_STATE(options);
// Create the root node.
RefPtr<nsNavHistoryContainerResultNode> rootNode;
int64_t folderId = GetSimpleBookmarksQueryFolder(query, options);
if (folderId) {
// In the simple case where we're just querying children of a single
// bookmark folder, we can more efficiently generate results.
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
RefPtr<nsNavHistoryResultNode> tempRootNode;
- rv = bookmarks->ResultNodeForContainer(folderId, options,
- getter_AddRefs(tempRootNode));
+ nsresult rv = bookmarks->ResultNodeForContainer(folderId, options,
+ getter_AddRefs(tempRootNode));
if (NS_SUCCEEDED(rv)) {
rootNode = tempRootNode->GetAsContainer();
}
else {
NS_WARNING("Generating a generic empty node for a broken query!");
// This is a perf hack to generate an empty query that skips filtering.
options->SetExcludeItems(true);
}
}
if (!rootNode) {
// Either this is not a folder shortcut, or is a broken one. In both cases
// just generate a query node.
rootNode = new nsNavHistoryQueryResultNode(EmptyCString(),
- queries, options);
+ query, options);
}
// Create the result that will hold nodes. Inject batching status into it.
- RefPtr<nsNavHistoryResult> result;
- rv = nsNavHistoryResult::NewHistoryResult(queries, 1, options,
- rootNode, isBatching(),
- getter_AddRefs(result));
- NS_ENSURE_SUCCESS(rv, rv);
-
+ RefPtr<nsNavHistoryResult> result = new nsNavHistoryResult(rootNode,
+ query, options,
+ isBatching());
result.forget(_retval);
return NS_OK;
}
// determine from our nsNavHistoryQuery array and nsNavHistoryQueryOptions
// if this is the place query from the history menu.
// from browser-menubar.inc, our history menu query is:
// place:sort=4&maxResults=10
// note, any maxResult > 0 will still be considered a history menu query
// or if this is the place query from the "Most Visited" item in the
// "Smart Bookmarks" folder: place:sort=8&maxResults=10
// note, any maxResult > 0 will still be considered a Most Visited menu query
static
-bool IsOptimizableHistoryQuery(const nsCOMArray<nsNavHistoryQuery>& aQueries,
- nsNavHistoryQueryOptions *aOptions,
- uint16_t aSortMode)
+bool IsOptimizableHistoryQuery(const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions,
+ uint16_t aSortMode)
{
- if (aQueries.Count() != 1)
- return false;
-
- nsNavHistoryQuery *aQuery = aQueries[0];
-
if (aOptions->QueryType() != nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY)
return false;
if (aOptions->ResultType() != nsINavHistoryQueryOptions::RESULTS_AS_URI)
return false;
if (aOptions->SortingMode() != aSortMode)
return false;
@@ -1360,18 +1333,18 @@ bool IsOptimizableHistoryQuery(const nsC
if (aQuery->Transitions().Length() > 0)
return false;
return true;
}
static
-bool NeedToFilterResultSet(const nsCOMArray<nsNavHistoryQuery>& aQueries,
- nsNavHistoryQueryOptions *aOptions)
+bool NeedToFilterResultSet(const RefPtr<nsNavHistoryQuery>& aQuery,
+ nsNavHistoryQueryOptions *aOptions)
{
uint16_t resultType = aOptions->ResultType();
return resultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS ||
aOptions->ExcludeQueries();
}
// ** Helper class for ConstructQueryString **/
@@ -2181,18 +2154,18 @@ PlacesSQLQueryBuilder::Limit()
mQueryString.AppendInt(mMaxResults);
mQueryString.Append(' ');
}
return NS_OK;
}
nsresult
nsNavHistory::ConstructQueryString(
- const nsCOMArray<nsNavHistoryQuery>& aQueries,
- nsNavHistoryQueryOptions* aOptions,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions,
nsCString& queryString,
bool& aParamsPresent,
nsNavHistory::StringHash& aAddParams)
{
// For information about visit_type see nsINavHistoryService.idl.
// visitType == 0 is undefined (see bug #375777 for details).
// Some sites, especially Javascript-heavy ones, load things in frames to
// display them, resulting in a lot of these entries. This is the reason
@@ -2201,29 +2174,27 @@ nsNavHistory::ConstructQueryString(
aParamsPresent = false;
int32_t sortingMode = aOptions->SortingMode();
NS_ASSERTION(sortingMode >= nsINavHistoryQueryOptions::SORT_BY_NONE &&
sortingMode <= nsINavHistoryQueryOptions::SORT_BY_FRECENCY_DESCENDING,
"Invalid sortingMode found while building query!");
bool hasSearchTerms = false;
- for (int32_t i = 0; i < aQueries.Count() && !hasSearchTerms; i++) {
- aQueries[i]->GetHasSearchTerms(&hasSearchTerms);
- }
+ aQuery->GetHasSearchTerms(&hasSearchTerms);
nsAutoCString tagsSqlFragment;
GetTagsSqlFragment(GetTagsFolder(),
NS_LITERAL_CSTRING("h.id"),
hasSearchTerms,
tagsSqlFragment);
- if (IsOptimizableHistoryQuery(aQueries, aOptions,
+ if (IsOptimizableHistoryQuery(aQuery, aOptions,
nsINavHistoryQueryOptions::SORT_BY_DATE_DESCENDING) ||
- IsOptimizableHistoryQuery(aQueries, aOptions,
+ IsOptimizableHistoryQuery(aQuery, aOptions,
nsINavHistoryQueryOptions::SORT_BY_VISITCOUNT_DESCENDING)) {
// Generate an optimized query for the history menu and most visited
// smart bookmark.
queryString = NS_LITERAL_CSTRING(
"SELECT h.id, h.url, h.title AS page_title, h.rev_host, h.visit_count, h.last_visit_date, "
"null, null, null, null, null, ") +
tagsSqlFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden, h.guid, "
"null, null, null "
@@ -2250,33 +2221,29 @@ nsNavHistory::ConstructQueryString(
nsAutoCString additionalQueryOptions;
queryString.ReplaceSubstring("{QUERY_OPTIONS}",
additionalQueryOptions.get());
return NS_OK;
}
nsAutoCString conditions;
- for (int32_t i = 0; i < aQueries.Count(); i++) {
- nsCString queryClause;
- rv = QueryToSelectClause(aQueries[i], aOptions, i, &queryClause);
- NS_ENSURE_SUCCESS(rv, rv);
- if (! queryClause.IsEmpty()) {
- aParamsPresent = true;
- if (! conditions.IsEmpty()) // exists previous clause: multiple ones are ORed
- conditions += NS_LITERAL_CSTRING(" OR ");
- conditions += NS_LITERAL_CSTRING("(") + queryClause +
- NS_LITERAL_CSTRING(")");
- }
+ nsCString queryClause;
+ rv = QueryToSelectClause(aQuery, aOptions, &queryClause);
+ NS_ENSURE_SUCCESS(rv, rv);
+ if (!queryClause.IsEmpty()) {
+ // TODO: This should be set on a case basis, not blindly.
+ aParamsPresent = true;
+ conditions += queryClause;
}
- // Determine whether we can push maxResults constraints into the queries
+ // Determine whether we can push maxResults constraints into the query
// as LIMIT, or if we need to do result count clamping later
// using FilterResultSet()
- bool useLimitClause = !NeedToFilterResultSet(aQueries, aOptions);
+ bool useLimitClause = !NeedToFilterResultSet(aQuery, aOptions);
PlacesSQLQueryBuilder queryStringBuilder(conditions, aOptions,
useLimitClause, aAddParams,
hasSearchTerms);
rv = queryStringBuilder.GetQueryString(queryString);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@@ -2293,29 +2260,29 @@ nsNavHistory::ConstructQueryString(
// statistics that will be built from the perspective of the tree. See
// nsNavHistoryQueryResultNode::FillChildren
//
// FIXME: This only does keyword searching for the first query, and does
// it ANDed with the all the rest of the queries.
nsresult
nsNavHistory::GetQueryResults(nsNavHistoryQueryResultNode *aResultNode,
- const nsCOMArray<nsNavHistoryQuery>& aQueries,
- nsNavHistoryQueryOptions *aOptions,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions,
nsCOMArray<nsNavHistoryResultNode>* aResults)
{
+ NS_ENSURE_ARG_POINTER(aQuery);
NS_ENSURE_ARG_POINTER(aOptions);
NS_ASSERTION(aResults->Count() == 0, "Initial result array must be empty");
- if (! aQueries.Count())
- return NS_ERROR_INVALID_ARG;
+
nsCString queryString;
bool paramsPresent = false;
nsNavHistory::StringHash addParams(HISTORY_DATE_CONT_LENGTH);
- nsresult rv = ConstructQueryString(aQueries, aOptions, queryString,
+ nsresult rv = ConstructQueryString(aQuery, aOptions, queryString,
paramsPresent, addParams);
NS_ENSURE_SUCCESS(rv,rv);
// create statement
nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(queryString);
#ifdef DEBUG
if (!statement) {
nsCOMPtr<mozIStorageConnection> conn = mDB->MainConn();
@@ -2328,39 +2295,35 @@ nsNavHistory::GetQueryResults(nsNavHisto
queryString.get(), lastError, lastErrorString.get());
}
}
#endif
NS_ENSURE_STATE(statement);
mozStorageStatementScoper scoper(statement);
if (paramsPresent) {
- // bind parameters
- int32_t i;
- for (i = 0; i < aQueries.Count(); i++) {
- rv = BindQueryClauseParameters(statement, i, aQueries[i], aOptions);
- NS_ENSURE_SUCCESS(rv, rv);
- }
+ rv = BindQueryClauseParameters(statement, aQuery, aOptions);
+ NS_ENSURE_SUCCESS(rv, rv);
}
for (auto iter = addParams.Iter(); !iter.Done(); iter.Next()) {
nsresult rv = statement->BindUTF8StringByName(iter.Key(), iter.Data());
if (NS_FAILED(rv)) {
break;
}
}
// Optimize the case where there is no need for any post-query filtering.
- if (NeedToFilterResultSet(aQueries, aOptions)) {
+ if (NeedToFilterResultSet(aQuery, aOptions)) {
// Generate the top-level results.
nsCOMArray<nsNavHistoryResultNode> toplevel;
rv = ResultsAsList(statement, aOptions, &toplevel);
NS_ENSURE_SUCCESS(rv, rv);
- FilterResultSet(aResultNode, toplevel, aResults, aQueries, aOptions);
+ FilterResultSet(aResultNode, toplevel, aResults, aQuery, aOptions);
} else {
rv = ResultsAsList(statement, aOptions, aResults);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
@@ -2911,28 +2874,25 @@ nsNavHistory::AsyncExecuteLegacyQuery(ns
mozIStoragePendingStatement** _stmt)
{
NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
NS_ENSURE_ARG(aQuery);
NS_ENSURE_ARG(aOptions);
NS_ENSURE_ARG(aCallback);
NS_ENSURE_ARG_POINTER(_stmt);
- nsCOMPtr<nsNavHistoryQuery> query = do_QueryObject(aQuery);
+ RefPtr<nsNavHistoryQuery> query = do_QueryObject(aQuery);
NS_ENSURE_STATE(query);
- nsCOMArray<nsNavHistoryQuery> queries;
- queries.AppendObject(query);
-
- nsCOMPtr<nsNavHistoryQueryOptions> options = do_QueryInterface(aOptions);
+ RefPtr<nsNavHistoryQueryOptions> options = do_QueryObject(aOptions);
NS_ENSURE_ARG(options);
nsCString queryString;
bool paramsPresent = false;
nsNavHistory::StringHash addParams(HISTORY_DATE_CONT_LENGTH);
- nsresult rv = ConstructQueryString(queries, options, queryString,
+ nsresult rv = ConstructQueryString(query, options, queryString,
paramsPresent, addParams);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr<mozIStorageAsyncStatement> statement =
mDB->GetAsyncStatement(queryString);
NS_ENSURE_STATE(statement);
#ifdef DEBUG
@@ -2946,22 +2906,18 @@ nsNavHistory::AsyncExecuteLegacyQuery(ns
printf("Places failed to create a statement from this query:\n%s\nStorage error (%d): %s\n",
queryString.get(), lastError, lastErrorString.get());
}
}
#endif
NS_ENSURE_SUCCESS(rv, rv);
if (paramsPresent) {
- // bind parameters
- int32_t i;
- for (i = 0; i < queries.Count(); i++) {
- rv = BindQueryClauseParameters(statement, i, queries[i], options);
- NS_ENSURE_SUCCESS(rv, rv);
- }
+ rv = BindQueryClauseParameters(statement, query, options);
+ NS_ENSURE_SUCCESS(rv, rv);
}
for (auto iter = addParams.Iter(); !iter.Done(); iter.Next()) {
nsresult rv = statement->BindUTF8StringByName(iter.Key(), iter.Data());
if (NS_FAILED(rv)) {
break;
}
}
@@ -3153,28 +3109,21 @@ nsNavHistory::DecayFrecency()
return NS_OK;
}
// Query stuff *****************************************************************
// Helper class for QueryToSelectClause
//
-// This class helps to build part of the WHERE clause. It supports
-// multiple queries by appending the query index to the parameter name.
-// For the query with index 0 the parameter name is not altered what
-// allows using this parameter in other situations (see SelectAsSite).
+// This class helps to build part of the WHERE clause.
class ConditionBuilder
{
public:
-
- explicit ConditionBuilder(int32_t aQueryIndex): mQueryIndex(aQueryIndex)
- { }
-
ConditionBuilder& Condition(const char* aStr)
{
if (!mClause.IsEmpty())
mClause.AppendLiteral(" AND ");
Str(aStr);
return *this;
}
@@ -3184,56 +3133,50 @@ public:
mClause.Append(aStr);
mClause.Append(' ');
return *this;
}
ConditionBuilder& Param(const char* aParam)
{
mClause.Append(' ');
- if (!mQueryIndex)
- mClause.Append(aParam);
- else
- mClause += nsPrintfCString("%s%d", aParam, mQueryIndex);
-
+ mClause.Append(aParam);
mClause.Append(' ');
return *this;
}
void GetClauseString(nsCString& aResult)
{
aResult = mClause;
}
private:
- int32_t mQueryIndex;
nsCString mClause;
};
// nsNavHistory::QueryToSelectClause
//
// THE BEHAVIOR SHOULD BE IN SYNC WITH BindQueryClauseParameters
//
// I don't check return values from the query object getters because there's
// no way for those to fail.
nsresult
-nsNavHistory::QueryToSelectClause(nsNavHistoryQuery* aQuery, // const
- nsNavHistoryQueryOptions* aOptions,
- int32_t aQueryIndex,
+nsNavHistory::QueryToSelectClause(const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions,
nsCString* aClause)
{
bool hasIt;
// We don't use the value from options here - we post filter if that
// is set.
bool excludeQueries = false;
- ConditionBuilder clause(aQueryIndex);
+ ConditionBuilder clause;
if ((NS_SUCCEEDED(aQuery->GetHasBeginTime(&hasIt)) && hasIt) ||
(NS_SUCCEEDED(aQuery->GetHasEndTime(&hasIt)) && hasIt)) {
clause.Condition("EXISTS (SELECT 1 FROM moz_historyvisits "
"WHERE place_id = h.id");
// begin time
if (NS_SUCCEEDED(aQuery->GetHasBeginTime(&hasIt)) && hasIt)
clause.Condition("visit_date >=").Param(":begin_time");
@@ -3386,150 +3329,123 @@ nsNavHistory::QueryToSelectClause(nsNavH
// nsNavHistory::BindQueryClauseParameters
//
// THE BEHAVIOR SHOULD BE IN SYNC WITH QueryToSelectClause
nsresult
nsNavHistory::BindQueryClauseParameters(mozIStorageBaseStatement* statement,
- int32_t aQueryIndex,
- nsNavHistoryQuery* aQuery, // const
- nsNavHistoryQueryOptions* aOptions)
+ const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions)
{
nsresult rv;
bool hasIt;
- // Append numbered index to param names, to replace them correctly in
- // case of multiple queries. If we have just one query we don't change the
- // param name though.
- nsAutoCString qIndex;
- if (aQueryIndex > 0)
- qIndex.AppendInt(aQueryIndex);
-
// begin time
if (NS_SUCCEEDED(aQuery->GetHasBeginTime(&hasIt)) && hasIt) {
PRTime time = NormalizeTime(aQuery->BeginTimeReference(),
aQuery->BeginTime());
- rv = statement->BindInt64ByName(
- NS_LITERAL_CSTRING("begin_time") + qIndex, time);
+ rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("begin_time"), time);
NS_ENSURE_SUCCESS(rv, rv);
}
// end time
if (NS_SUCCEEDED(aQuery->GetHasEndTime(&hasIt)) && hasIt) {
PRTime time = NormalizeTime(aQuery->EndTimeReference(),
aQuery->EndTime());
- rv = statement->BindInt64ByName(
- NS_LITERAL_CSTRING("end_time") + qIndex, time
- );
+ rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("end_time"), time);
NS_ENSURE_SUCCESS(rv, rv);
}
// search terms
if (NS_SUCCEEDED(aQuery->GetHasSearchTerms(&hasIt)) && hasIt) {
- rv = statement->BindStringByName(
- NS_LITERAL_CSTRING("search_string") + qIndex,
- aQuery->SearchTerms()
- );
+ rv = statement->BindStringByName(NS_LITERAL_CSTRING("search_string"),
+ aQuery->SearchTerms());
NS_ENSURE_SUCCESS(rv, rv);
}
// min and max visit count
int32_t visits = aQuery->MinVisits();
if (visits >= 0) {
- rv = statement->BindInt32ByName(
- NS_LITERAL_CSTRING("min_visits") + qIndex, visits
- );
+ rv = statement->BindInt32ByName(NS_LITERAL_CSTRING("min_visits"), visits);
NS_ENSURE_SUCCESS(rv, rv);
}
visits = aQuery->MaxVisits();
if (visits >= 0) {
- rv = statement->BindInt32ByName(
- NS_LITERAL_CSTRING("max_visits") + qIndex, visits
- );
+ rv = statement->BindInt32ByName(NS_LITERAL_CSTRING("max_visits"), visits);
NS_ENSURE_SUCCESS(rv, rv);
}
// domain (see GetReversedHostname for more info on reversed host names)
if (NS_SUCCEEDED(aQuery->GetHasDomain(&hasIt)) && hasIt) {
nsString revDomain;
GetReversedHostname(NS_ConvertUTF8toUTF16(aQuery->Domain()), revDomain);
if (aQuery->DomainIsHost()) {
- rv = statement->BindStringByName(
- NS_LITERAL_CSTRING("domain_lower") + qIndex, revDomain
- );
+ rv = statement->BindStringByName(NS_LITERAL_CSTRING("domain_lower"),
+ revDomain);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// for "mozilla.org" do query >= "gro.allizom." AND < "gro.allizom/"
// which will get everything starting with "gro.allizom." while using the
// index (using SUBSTRING() causes indexes to be discarded).
NS_ASSERTION(revDomain[revDomain.Length() - 1] == '.', "Invalid rev. host");
- rv = statement->BindStringByName(
- NS_LITERAL_CSTRING("domain_lower") + qIndex, revDomain
- );
+ rv = statement->BindStringByName(NS_LITERAL_CSTRING("domain_lower"),
+ revDomain);
NS_ENSURE_SUCCESS(rv, rv);
revDomain.Truncate(revDomain.Length() - 1);
revDomain.Append(char16_t('/'));
- rv = statement->BindStringByName(
- NS_LITERAL_CSTRING("domain_upper") + qIndex, revDomain
- );
+ rv = statement->BindStringByName(NS_LITERAL_CSTRING("domain_upper"),
+ revDomain);
NS_ENSURE_SUCCESS(rv, rv);
}
}
// URI
if (aQuery->Uri()) {
- rv = URIBinder::Bind(
- statement, NS_LITERAL_CSTRING("uri") + qIndex, aQuery->Uri()
- );
+ rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("uri"), aQuery->Uri());
NS_ENSURE_SUCCESS(rv, rv);
}
// annotation
if (!aQuery->Annotation().IsEmpty()) {
- rv = statement->BindUTF8StringByName(
- NS_LITERAL_CSTRING("anno") + qIndex, aQuery->Annotation()
- );
+ rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("anno"),
+ aQuery->Annotation());
NS_ENSURE_SUCCESS(rv, rv);
}
// tags
const nsTArray<nsString> &tags = aQuery->Tags();
if (tags.Length() > 0) {
for (uint32_t i = 0; i < tags.Length(); ++i) {
nsPrintfCString paramName("tag%d_", i);
NS_ConvertUTF16toUTF8 tag(tags[i]);
ToLowerCase(tag);
- rv = statement->BindUTF8StringByName(paramName + qIndex, tag);
+ rv = statement->BindUTF8StringByName(paramName, tag);
NS_ENSURE_SUCCESS(rv, rv);
}
int64_t tagsFolder = GetTagsFolder();
- rv = statement->BindInt64ByName(
- NS_LITERAL_CSTRING("tags_folder") + qIndex, tagsFolder
- );
+ rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("tags_folder"),
+ tagsFolder);
NS_ENSURE_SUCCESS(rv, rv);
if (!aQuery->TagsAreNot()) {
- rv = statement->BindInt32ByName(
- NS_LITERAL_CSTRING("tag_count") + qIndex, tags.Length()
- );
+ rv = statement->BindInt32ByName(NS_LITERAL_CSTRING("tag_count"),
+ tags.Length());
NS_ENSURE_SUCCESS(rv, rv);
}
}
// transitions
const nsTArray<uint32_t>& transitions = aQuery->Transitions();
- if (transitions.Length() > 0) {
- for (uint32_t i = 0; i < transitions.Length(); ++i) {
- nsPrintfCString paramName("transition%d_", i);
- rv = statement->BindInt64ByName(paramName + qIndex, transitions[i]);
- NS_ENSURE_SUCCESS(rv, rv);
- }
+ for (uint32_t i = 0; i < transitions.Length(); ++i) {
+ nsPrintfCString paramName("transition%d_", i);
+ rv = statement->BindInt64ByName(paramName, transitions[i]);
+ NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
// nsNavHistory::ResultsAsList
//
@@ -3608,26 +3524,26 @@ nsNavHistory::GetTagsFolder()
//
// Note: changes to filtering in FilterResultSet()
// may require changes to NeedToFilterResultSet()
nsresult
nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode,
const nsCOMArray<nsNavHistoryResultNode>& aSet,
nsCOMArray<nsNavHistoryResultNode>* aFiltered,
- const nsCOMArray<nsNavHistoryQuery>& aQueries,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
nsNavHistoryQueryOptions *aOptions)
{
// get the bookmarks service
nsNavBookmarks *bookmarks = nsNavBookmarks::GetBookmarksService();
NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
// parse the search terms
- nsTArray<nsTArray<nsString>*> terms;
- ParseSearchTermsFromQueries(aQueries, &terms);
+ nsTArray<nsString> terms;
+ ParseSearchTermsFromQuery(aQuery, &terms);
uint16_t resultType = aOptions->ResultType();
bool excludeQueries = aOptions->ExcludeQueries();
for (int32_t nodeIndex = 0; nodeIndex < aSet.Count(); nodeIndex++) {
if (excludeQueries && aSet[nodeIndex]->IsQuery()) {
continue;
}
@@ -3643,65 +3559,50 @@ nsNavHistory::FilterResultSet(nsNavHisto
if (aSet[nodeIndex]->mItemId != -1 && aQueryNode &&
aQueryNode->mItemId == aSet[nodeIndex]->mItemId) {
continue;
}
// If there are search terms, we are already getting only uri nodes,
// thus we don't need to filter node types. Though, we must check for
// matching terms.
- bool appendNode = false;
- for (int32_t queryIndex = 0;
- queryIndex < aQueries.Count() && !appendNode; queryIndex++) {
-
- if (terms[queryIndex]->Length()) {
- // Filter based on search terms.
- // Convert title and url for the current node to UTF16 strings.
- NS_ConvertUTF8toUTF16 nodeTitle(aSet[nodeIndex]->mTitle);
- // Unescape the URL for search terms matching.
- nsAutoCString cNodeURL(aSet[nodeIndex]->mURI);
- NS_ConvertUTF8toUTF16 nodeURL(NS_UnescapeURL(cNodeURL));
-
- // Determine if every search term matches anywhere in the title, url or
- // tag.
- bool matchAll = true;
- for (int32_t termIndex = terms[queryIndex]->Length() - 1;
- termIndex >= 0 && matchAll;
- termIndex--) {
- nsString& term = terms[queryIndex]->ElementAt(termIndex);
-
- // True if any of them match; false makes us quit the loop
- matchAll = CaseInsensitiveFindInReadable(term, nodeTitle) ||
- CaseInsensitiveFindInReadable(term, nodeURL) ||
- CaseInsensitiveFindInReadable(term, aSet[nodeIndex]->mTags);
- }
-
- // Skip the node if we don't match all terms in the title, url or tag
- if (!matchAll)
- continue;
+ if (terms.Length()) {
+ // Filter based on search terms.
+ // Convert title and url for the current node to UTF16 strings.
+ NS_ConvertUTF8toUTF16 nodeTitle(aSet[nodeIndex]->mTitle);
+ // Unescape the URL for search terms matching.
+ nsAutoCString cNodeURL(aSet[nodeIndex]->mURI);
+ NS_ConvertUTF8toUTF16 nodeURL(NS_UnescapeURL(cNodeURL));
+
+ // Determine if every search term matches anywhere in the title, url or
+ // tag.
+ bool matchAllTerms = true;
+ for (int32_t termIndex = terms.Length() - 1;
+ termIndex >= 0 && matchAllTerms;
+ termIndex--) {
+ nsString& term = terms.ElementAt(termIndex);
+ // True if any of them match; false makes us quit the loop
+ matchAllTerms = CaseInsensitiveFindInReadable(term, nodeTitle) ||
+ CaseInsensitiveFindInReadable(term, nodeURL) ||
+ CaseInsensitiveFindInReadable(term, aSet[nodeIndex]->mTags);
}
-
- // We passed all filters, so we can append the node to filtered results.
- appendNode = true;
+ // Skip the node if we don't match all terms in the title, url or tag
+ if (!matchAllTerms) {
+ continue;
+ }
}
- if (appendNode)
- aFiltered->AppendObject(aSet[nodeIndex]);
+ aFiltered->AppendObject(aSet[nodeIndex]);
// Stop once we have reached max results.
if (aOptions->MaxResults() > 0 &&
(uint32_t)aFiltered->Count() >= aOptions->MaxResults())
break;
}
- // De-allocate the temporary matrixes.
- for (int32_t i = 0; i < aQueries.Count(); i++) {
- delete terms[i];
- }
-
return NS_OK;
}
void
nsNavHistory::registerEmbedVisit(nsIURI* aURI,
int64_t aTime)
{
NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
@@ -4004,19 +3905,17 @@ nsNavHistory::QueryRowToResult(int64_t i
// concrete folder title).
if (!aTitle.IsEmpty()) {
resultNode->mTitle = aTitle;
}
}
}
else {
// This is a regular query.
- nsCOMArray<nsNavHistoryQuery> queries;
- queries.AppendObject(queryObj);
- resultNode = new nsNavHistoryQueryResultNode(aTitle, aTime, queries, optionsObj);
+ resultNode = new nsNavHistoryQueryResultNode(aTitle, aTime, queryObj, optionsObj);
resultNode->mItemId = itemId;
resultNode->mBookmarkGuid = aBookmarkGuid;
}
}
if (NS_FAILED(rv)) {
NS_WARNING("Generating a generic empty node for a broken query!");
// This is a broken query, that either did not parse or points to not
@@ -4287,18 +4186,18 @@ namespace {
// folder with no other constraints. In these common cases, we can more
// efficiently compute the results.
//
// A simple bookmarks query will result in a hierarchical tree of
// bookmark items, folders and separators.
//
// Returns the folder ID if it is a simple folder query, 0 if not.
static int64_t
-GetSimpleBookmarksQueryFolder(nsNavHistoryQuery* aQuery,
- nsNavHistoryQueryOptions* aOptions)
+GetSimpleBookmarksQueryFolder(const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions)
{
if (aQuery->Folders().Length() != 1)
return 0;
bool hasIt;
aQuery->GetHasBeginTime(&hasIt);
if (hasIt)
return 0;
@@ -4316,73 +4215,67 @@ GetSimpleBookmarksQueryFolder(nsNavHisto
return 0;
if (aQuery->Tags().Length() > 0)
return 0;
if (aOptions->MaxResults() > 0)
return 0;
// RESULTS_AS_TAG_CONTENTS is quite similar to a folder shortcut, but it must
// not be treated like that, since it needs all query options.
- if(aOptions->ResultType() == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS)
+ if (aOptions->ResultType() == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS)
return 0;
// Don't care about onlyBookmarked flag, since specifying a bookmark
// folder is inferring onlyBookmarked.
return aQuery->Folders()[0];
}
-// ParseSearchTermsFromQueries
+// ParseSearchTermsFromQuery
//
-// Construct a matrix of search terms from the given queries array.
-// All of the query objects are ORed together. Within a query, all the terms
-// are ANDed together. See nsINavHistoryService.idl.
+// Construct an array of search terms from the given query.
+// Within a query, all the terms are ANDed together.
//
// This just breaks the query up into words. We don't do anything fancy,
// not even quoting. We do, however, strip quotes, because people might
// try to input quotes expecting them to do something and get no results
// back.
inline bool isQueryWhitespace(char16_t ch)
{
return ch == ' ';
}
-void ParseSearchTermsFromQueries(const nsCOMArray<nsNavHistoryQuery>& aQueries,
- nsTArray<nsTArray<nsString>*>* aTerms)
+void ParseSearchTermsFromQuery(const RefPtr<nsNavHistoryQuery>& aQuery,
+ nsTArray<nsString>* aTerms)
{
int32_t lastBegin = -1;
- for (int32_t i = 0; i < aQueries.Count(); i++) {
- nsTArray<nsString> *queryTerms = new nsTArray<nsString>();
- bool hasSearchTerms;
- if (NS_SUCCEEDED(aQueries[i]->GetHasSearchTerms(&hasSearchTerms)) &&
- hasSearchTerms) {
- const nsString& searchTerms = aQueries[i]->SearchTerms();
- for (uint32_t j = 0; j < searchTerms.Length(); j++) {
- if (isQueryWhitespace(searchTerms[j]) ||
- searchTerms[j] == '"') {
- if (lastBegin >= 0) {
- // found the end of a word
- queryTerms->AppendElement(Substring(searchTerms, lastBegin,
- j - lastBegin));
- lastBegin = -1;
- }
- } else {
- if (lastBegin < 0) {
- // found the beginning of a word
- lastBegin = j;
- }
+ bool hasSearchTerms;
+ if (NS_SUCCEEDED(aQuery->GetHasSearchTerms(&hasSearchTerms)) &&
+ hasSearchTerms) {
+ const nsString& searchTerms = aQuery->SearchTerms();
+ for (uint32_t j = 0; j < searchTerms.Length(); j++) {
+ if (isQueryWhitespace(searchTerms[j]) ||
+ searchTerms[j] == '"') {
+ if (lastBegin >= 0) {
+ // found the end of a word
+ aTerms->AppendElement(Substring(searchTerms, lastBegin, j - lastBegin));
+ lastBegin = -1;
+ }
+ } else {
+ if (lastBegin < 0) {
+ // found the beginning of a word
+ lastBegin = j;
}
}
- // last word
- if (lastBegin >= 0)
- queryTerms->AppendElement(Substring(searchTerms, lastBegin));
}
- aTerms->AppendElement(queryTerms);
+ // last word
+ if (lastBegin >= 0)
+ aTerms->AppendElement(Substring(searchTerms, lastBegin));
}
}
} // namespace
nsresult
nsNavHistory::UpdateFrecency(int64_t aPlaceId)
--- a/toolkit/components/places/nsNavHistory.h
+++ b/toolkit/components/places/nsNavHistory.h
@@ -253,18 +253,18 @@ public:
static const int32_t kGetInfoIndex_FromVisitId;
static const int32_t kGetInfoIndex_VisitType;
int64_t GetTagsFolder();
// this actually executes a query and gives you results, it is used by
// nsNavHistoryQueryResultNode
nsresult GetQueryResults(nsNavHistoryQueryResultNode *aResultNode,
- const nsCOMArray<nsNavHistoryQuery>& aQueries,
- nsNavHistoryQueryOptions *aOptions,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions,
nsCOMArray<nsNavHistoryResultNode>* aResults);
// Take a row of kGetInfoIndex_* columns and construct a ResultNode.
// The row must contain the full set of columns.
nsresult RowToResult(mozIStorageValueArray* aRow,
nsNavHistoryQueryOptions* aOptions,
nsNavHistoryResultNode** aResult);
nsresult QueryRowToResult(int64_t aItemId,
@@ -293,20 +293,20 @@ public:
const nsACString& aGUID);
/**
* Returns current number of days stored in history.
*/
int32_t GetDaysOfHistory();
// used by query result nodes to update: see comment on body of CanLiveUpdateQuery
- static uint32_t GetUpdateRequirements(const nsCOMArray<nsNavHistoryQuery>& aQueries,
+ static uint32_t GetUpdateRequirements(const RefPtr<nsNavHistoryQuery>& aQuery,
nsNavHistoryQueryOptions* aOptions,
bool* aHasSearchTerms);
- bool EvaluateQueryForNode(const nsCOMArray<nsNavHistoryQuery>& aQueries,
+ bool EvaluateQueryForNode(const RefPtr<nsNavHistoryQuery>& aQuery,
nsNavHistoryQueryOptions* aOptions,
nsNavHistoryResultNode* aNode);
static nsresult AsciiHostNameFromHostString(const nsACString& aHostName,
nsACString& aAscii);
void DomainNameFromURI(nsIURI* aURI,
nsACString& aDomainName);
static PRTime NormalizeTime(uint32_t aRelative, PRTime aOffset);
@@ -534,41 +534,39 @@ protected:
PRTime GetNow();
PRTime mCachedNow;
nsCOMPtr<nsITimer> mExpireNowTimer;
/**
* Called when the cached now value is expired and needs renewal.
*/
static void expireNowTimerCallback(nsITimer* aTimer, void* aClosure);
- nsresult ConstructQueryString(const nsCOMArray<nsNavHistoryQuery>& aQueries,
- nsNavHistoryQueryOptions* aOptions,
+ nsresult ConstructQueryString(const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions,
nsCString& queryString,
bool& aParamsPresent,
StringHash& aAddParams);
- nsresult QueryToSelectClause(nsNavHistoryQuery* aQuery,
- nsNavHistoryQueryOptions* aOptions,
- int32_t aQueryIndex,
+ nsresult QueryToSelectClause(const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions,
nsCString* aClause);
nsresult BindQueryClauseParameters(mozIStorageBaseStatement* statement,
- int32_t aQueryIndex,
- nsNavHistoryQuery* aQuery,
- nsNavHistoryQueryOptions* aOptions);
+ const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions);
nsresult ResultsAsList(mozIStorageStatement* statement,
nsNavHistoryQueryOptions* aOptions,
nsCOMArray<nsNavHistoryResultNode>* aResults);
void TitleForDomain(const nsCString& domain, nsACString& aTitle);
nsresult FilterResultSet(nsNavHistoryQueryResultNode *aParentNode,
const nsCOMArray<nsNavHistoryResultNode>& aSet,
nsCOMArray<nsNavHistoryResultNode>* aFiltered,
- const nsCOMArray<nsNavHistoryQuery>& aQueries,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
nsNavHistoryQueryOptions* aOptions);
// observers
nsMaybeWeakPtrArray<nsINavHistoryObserver> mObservers;
// effective tld service
nsCOMPtr<nsIEffectiveTLDService> mTLDService;
nsCOMPtr<nsIIDNService> mIDNService;
--- a/toolkit/components/places/nsNavHistoryQuery.cpp
+++ b/toolkit/components/places/nsNavHistoryQuery.cpp
@@ -802,26 +802,27 @@ nsNavHistoryQuery::nsNavHistoryQuery()
mTagsAreNot(false)
{
// differentiate not set (IsVoid) from empty string (local files)
mDomain.SetIsVoid(true);
}
nsNavHistoryQuery::nsNavHistoryQuery(const nsNavHistoryQuery& aOther)
: mMinVisits(aOther.mMinVisits), mMaxVisits(aOther.mMaxVisits),
- mBeginTime(aOther.mBeginTime),
- mBeginTimeReference(aOther.mBeginTimeReference),
+ mBeginTime(aOther.mBeginTime), mBeginTimeReference(aOther.mBeginTimeReference),
mEndTime(aOther.mEndTime), mEndTimeReference(aOther.mEndTimeReference),
mSearchTerms(aOther.mSearchTerms), mOnlyBookmarked(aOther.mOnlyBookmarked),
mDomainIsHost(aOther.mDomainIsHost), mDomain(aOther.mDomain),
- mUri(aOther.mUri),
- mAnnotationIsNot(aOther.mAnnotationIsNot),
- mAnnotation(aOther.mAnnotation), mTags(aOther.mTags),
- mTagsAreNot(aOther.mTagsAreNot), mTransitions(aOther.mTransitions)
-{}
+ mUri(aOther.mUri), mAnnotationIsNot(aOther.mAnnotationIsNot),
+ mAnnotation(aOther.mAnnotation),
+ mFolders(aOther.mFolders),
+ mTags(aOther.mTags), mTagsAreNot(aOther.mTagsAreNot),
+ mTransitions(aOther.mTransitions)
+{
+}
NS_IMETHODIMP nsNavHistoryQuery::GetBeginTime(PRTime *aBeginTime)
{
*aBeginTime = mBeginTime;
return NS_OK;
}
NS_IMETHODIMP nsNavHistoryQuery::SetBeginTime(PRTime aBeginTime)
{
@@ -1209,31 +1210,66 @@ NS_IMETHODIMP nsNavHistoryQuery::SetTran
{
if (!mTransitions.ReplaceElementsAt(0, mTransitions.Length(), aTransitions,
aCount))
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
-NS_IMETHODIMP nsNavHistoryQuery::Clone(nsINavHistoryQuery** _retval)
+NS_IMETHODIMP
+nsNavHistoryQuery::Clone(nsINavHistoryQuery** _clone)
{
- *_retval = nullptr;
+ nsNavHistoryQuery *clone = nullptr;
+ Unused << Clone(&clone);
+ *_clone = clone;
+ return NS_OK;
+}
+nsresult
+nsNavHistoryQuery::Clone(nsNavHistoryQuery** _clone)
+{
+ *_clone = nullptr;
RefPtr<nsNavHistoryQuery> clone = new nsNavHistoryQuery(*this);
- NS_ENSURE_TRUE(clone, NS_ERROR_OUT_OF_MEMORY);
-
- clone.forget(_retval);
+ clone.forget(_clone);
return NS_OK;
}
-
// nsNavHistoryQueryOptions
NS_IMPL_ISUPPORTS(nsNavHistoryQueryOptions, nsNavHistoryQueryOptions, nsINavHistoryQueryOptions)
+nsNavHistoryQueryOptions::nsNavHistoryQueryOptions()
+: mSort(0)
+, mResultType(0)
+, mExcludeItems(false)
+, mExcludeQueries(false)
+, mExcludeReadOnlyFolders(false)
+, mExpandQueries(true)
+, mIncludeHidden(false)
+, mMaxResults(0)
+, mQueryType(nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY)
+, mAsyncEnabled(false)
+{
+}
+
+nsNavHistoryQueryOptions::nsNavHistoryQueryOptions(const nsNavHistoryQueryOptions& other)
+: mSort(other.mSort)
+, mSortingAnnotation(other.mSortingAnnotation)
+, mResultType(other.mResultType)
+, mExcludeItems(other.mExcludeItems)
+, mExcludeQueries(other.mExcludeQueries)
+, mExcludeReadOnlyFolders(other.mExcludeReadOnlyFolders)
+, mExpandQueries(other.mExpandQueries)
+, mIncludeHidden(other.mIncludeHidden)
+, mMaxResults(other.mMaxResults)
+, mQueryType(other.mQueryType)
+, mAsyncEnabled(other.mAsyncEnabled)
+{
+}
+
// sortingMode
NS_IMETHODIMP
nsNavHistoryQueryOptions::GetSortingMode(uint16_t* aMode)
{
*aMode = mSort;
return NS_OK;
}
NS_IMETHODIMP
@@ -1393,48 +1429,34 @@ nsNavHistoryQueryOptions::GetAsyncEnable
}
NS_IMETHODIMP
nsNavHistoryQueryOptions::SetAsyncEnabled(bool aAsyncEnabled)
{
mAsyncEnabled = aAsyncEnabled;
return NS_OK;
}
-
NS_IMETHODIMP
-nsNavHistoryQueryOptions::Clone(nsINavHistoryQueryOptions** aResult)
+nsNavHistoryQueryOptions::Clone(nsINavHistoryQueryOptions** _clone)
{
nsNavHistoryQueryOptions *clone = nullptr;
- nsresult rv = Clone(&clone);
- *aResult = clone;
- return rv;
+ Unused << Clone(&clone);
+ *_clone = clone;
+ return NS_OK;
}
nsresult
-nsNavHistoryQueryOptions::Clone(nsNavHistoryQueryOptions **aResult)
+nsNavHistoryQueryOptions::Clone(nsNavHistoryQueryOptions** _clone)
{
- *aResult = nullptr;
- nsNavHistoryQueryOptions *result = new nsNavHistoryQueryOptions();
-
- RefPtr<nsNavHistoryQueryOptions> resultHolder(result);
- result->mSort = mSort;
- result->mResultType = mResultType;
- result->mExcludeItems = mExcludeItems;
- result->mExcludeQueries = mExcludeQueries;
- result->mExpandQueries = mExpandQueries;
- result->mMaxResults = mMaxResults;
- result->mQueryType = mQueryType;
- result->mParentAnnotationToExclude = mParentAnnotationToExclude;
- result->mAsyncEnabled = mAsyncEnabled;
-
- resultHolder.forget(aResult);
+ *_clone = nullptr;
+ RefPtr<nsNavHistoryQueryOptions> clone = new nsNavHistoryQueryOptions(*this);
+ clone.forget(_clone);
return NS_OK;
}
-
// AppendBoolKeyValueIfTrue
void // static
AppendBoolKeyValueIfTrue(nsACString& aString, const nsCString& aName,
nsINavHistoryQuery* aQuery,
BoolQueryGetter getter)
{
bool value;
--- a/toolkit/components/places/nsNavHistoryQuery.h
+++ b/toolkit/components/places/nsNavHistoryQuery.h
@@ -61,21 +61,25 @@ public:
{
if (!mTransitions.ReplaceElementsAt(0, mTransitions.Length(),
aTransitions))
return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
+ nsresult Clone(nsNavHistoryQuery **_clone);
+
private:
~nsNavHistoryQuery() {}
protected:
+ // IF YOU ADD MORE ITEMS:
+ // * Add to the copy constructor
int32_t mMinVisits;
int32_t mMaxVisits;
PRTime mBeginTime;
uint32_t mBeginTimeReference;
PRTime mEndTime;
uint32_t mEndTimeReference;
nsString mSearchTerms;
bool mOnlyBookmarked;
@@ -95,28 +99,18 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHisto
// nsNavHistoryQueryOptions
#define NS_NAVHISTORYQUERYOPTIONS_IID \
{0x95f8ba3b, 0xd681, 0x4d89, {0xab, 0xd1, 0xfd, 0xae, 0xf2, 0xa3, 0xde, 0x18}}
class nsNavHistoryQueryOptions final : public nsINavHistoryQueryOptions
{
public:
- nsNavHistoryQueryOptions()
- : mSort(0)
- , mResultType(0)
- , mExcludeItems(false)
- , mExcludeQueries(false)
- , mExcludeReadOnlyFolders(false)
- , mExpandQueries(true)
- , mIncludeHidden(false)
- , mMaxResults(0)
- , mQueryType(nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY)
- , mAsyncEnabled(false)
- { }
+ nsNavHistoryQueryOptions();
+ nsNavHistoryQueryOptions(const nsNavHistoryQueryOptions& other);
NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYQUERYOPTIONS_IID)
NS_DECL_ISUPPORTS
NS_DECL_NSINAVHISTORYQUERYOPTIONS
uint16_t SortingMode() const { return mSort; }
uint16_t ResultType() const { return mResultType; }
@@ -124,31 +118,29 @@ public:
bool ExcludeQueries() const { return mExcludeQueries; }
bool ExcludeReadOnlyFolders() const { return mExcludeReadOnlyFolders; }
bool ExpandQueries() const { return mExpandQueries; }
bool IncludeHidden() const { return mIncludeHidden; }
uint32_t MaxResults() const { return mMaxResults; }
uint16_t QueryType() const { return mQueryType; }
bool AsyncEnabled() const { return mAsyncEnabled; }
- nsresult Clone(nsNavHistoryQueryOptions **aResult);
+ nsresult Clone(nsNavHistoryQueryOptions **_clone);
private:
~nsNavHistoryQueryOptions() {}
- nsNavHistoryQueryOptions(const nsNavHistoryQueryOptions& other) {} // no copy
// IF YOU ADD MORE ITEMS:
+ // * Add to the copy constructor
// * Add a new getter for C++ above if it makes sense
// * Add to the serialization code (see nsNavHistory::QueriesToQueryString())
// * Add to the deserialization code (see nsNavHistory::QueryStringToQueries)
- // * Add to the nsNavHistoryQueryOptions::Clone() function
// * Add to the nsNavHistory.cpp::GetSimpleBookmarksQueryFolder function if applicable
uint16_t mSort;
nsCString mSortingAnnotation;
- nsCString mParentAnnotationToExclude;
uint16_t mResultType;
bool mExcludeItems;
bool mExcludeQueries;
bool mExcludeReadOnlyFolders;
bool mExpandQueries;
bool mIncludeHidden;
uint32_t mMaxResults;
uint16_t mQueryType;
--- a/toolkit/components/places/nsNavHistoryResult.cpp
+++ b/toolkit/components/places/nsNavHistoryResult.cpp
@@ -1635,23 +1635,24 @@ nsNavHistoryContainerResultNode::GetChil
return NS_ERROR_NOT_AVAILABLE;
*aChildCount = mChildren.Count();
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryContainerResultNode::GetChild(uint32_t aIndex,
- nsINavHistoryResultNode** _retval)
+ nsINavHistoryResultNode** _child)
{
if (!mExpanded)
return NS_ERROR_NOT_AVAILABLE;
if (aIndex >= uint32_t(mChildren.Count()))
return NS_ERROR_INVALID_ARG;
- NS_ADDREF(*_retval = mChildren[aIndex]);
+ nsCOMPtr<nsINavHistoryResultNode> child = mChildren[aIndex];
+ child.forget(_child);
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryContainerResultNode::GetChildIndex(nsINavHistoryResultNode* aNode,
uint32_t* _retval)
{
@@ -1696,77 +1697,53 @@ nsNavHistoryQueryResultNode::nsNavHistor
mLiveUpdate(QUERYUPDATE_COMPLEX_WITH_BOOKMARKS),
mHasSearchTerms(false),
mContentsValid(false),
mBatchChanges(0)
{
}
nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode(
- const nsACString& aTitle, const nsCOMArray<nsNavHistoryQuery>& aQueries,
+ const nsACString& aTitle, const RefPtr<nsNavHistoryQuery>& aQuery,
nsNavHistoryQueryOptions* aOptions) :
nsNavHistoryContainerResultNode(EmptyCString(), aTitle,
nsNavHistoryResultNode::RESULT_TYPE_QUERY,
aOptions),
- mQueries(aQueries),
+ mQuery(aQuery),
mContentsValid(false),
mBatchChanges(0),
- mTransitions(mQueries[0]->Transitions())
+ mTransitions(aQuery->Transitions())
{
- NS_ASSERTION(aQueries.Count() > 0, "Must have at least one query");
-
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ASSERTION(history, "History service missing");
if (history) {
- mLiveUpdate = history->GetUpdateRequirements(mQueries, mOptions,
+ mLiveUpdate = history->GetUpdateRequirements(mQuery, mOptions,
&mHasSearchTerms);
}
-
- // Collect transitions shared by all queries.
- for (int32_t i = 1; i < mQueries.Count(); ++i) {
- const nsTArray<uint32_t>& queryTransitions = mQueries[i]->Transitions();
- for (uint32_t j = 0; j < mTransitions.Length() ; ++j) {
- uint32_t transition = mTransitions.SafeElementAt(j, 0);
- if (transition && !queryTransitions.Contains(transition))
- mTransitions.RemoveElement(transition);
- }
- }
}
nsNavHistoryQueryResultNode::nsNavHistoryQueryResultNode(
const nsACString& aTitle,
PRTime aTime,
- const nsCOMArray<nsNavHistoryQuery>& aQueries,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
nsNavHistoryQueryOptions* aOptions) :
nsNavHistoryContainerResultNode(EmptyCString(), aTitle, aTime,
nsNavHistoryResultNode::RESULT_TYPE_QUERY,
aOptions),
- mQueries(aQueries),
+ mQuery(aQuery),
mContentsValid(false),
mBatchChanges(0),
- mTransitions(mQueries[0]->Transitions())
+ mTransitions(aQuery->Transitions())
{
- NS_ASSERTION(aQueries.Count() > 0, "Must have at least one query");
-
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ASSERTION(history, "History service missing");
if (history) {
- mLiveUpdate = history->GetUpdateRequirements(mQueries, mOptions,
+ mLiveUpdate = history->GetUpdateRequirements(mQuery, mOptions,
&mHasSearchTerms);
}
-
- // Collect transitions shared by all queries.
- for (int32_t i = 1; i < mQueries.Count(); ++i) {
- const nsTArray<uint32_t>& queryTransitions = mQueries[i]->Transitions();
- for (uint32_t j = 0; j < mTransitions.Length() ; ++j) {
- uint32_t transition = mTransitions.SafeElementAt(j, 0);
- if (transition && !queryTransitions.Contains(transition))
- mTransitions.RemoveElement(transition);
- }
- }
}
nsNavHistoryQueryResultNode::~nsNavHistoryQueryResultNode() {
// Remove this node from result's observers. We don't need to be notified
// anymore.
if (mResult && mResult->mAllBookmarksObservers.Contains(this))
mResult->RemoveAllBookmarksObserver(this);
if (mResult && mResult->mHistoryObservers.Contains(this))
@@ -1929,17 +1906,17 @@ nsNavHistoryQueryResultNode::GetHasChild
/**
* This doesn't just return mURI because in the case of queries that may
* be lazily constructed from the query objects.
*/
NS_IMETHODIMP
nsNavHistoryQueryResultNode::GetUri(nsACString& aURI)
{
- nsresult rv = VerifyQueriesSerialized();
+ nsresult rv = VerifyQuerySerialized();
NS_ENSURE_SUCCESS(rv, rv);
aURI = mURI;
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::GetFolderItemId(int64_t* aItemId)
@@ -1952,91 +1929,89 @@ NS_IMETHODIMP
nsNavHistoryQueryResultNode::GetTargetFolderGuid(nsACString& aGuid) {
aGuid = EmptyCString();
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryQueryResultNode::GetQuery(nsINavHistoryQuery** _query)
{
- nsresult rv = VerifyQueriesParsed();
+ nsresult rv = VerifyQueryParsed();
NS_ENSURE_SUCCESS(rv, rv);
- NS_ASSERTION(mQueries.Count() > 0, "Must have >= 1 query");
-
- nsCOMPtr<nsINavHistoryQuery> query = mQueries[0];
+
+ nsCOMPtr<nsINavHistoryQuery> query = do_QueryInterface(mQuery);
query.forget(_query);
return NS_OK;
}
NS_IMETHODIMP
-nsNavHistoryQueryResultNode::GetQueryOptions(
- nsINavHistoryQueryOptions** aQueryOptions)
+nsNavHistoryQueryResultNode::GetQueryOptions(nsINavHistoryQueryOptions** _options)
{
- *aQueryOptions = Options();
- NS_ADDREF(*aQueryOptions);
+ MOZ_ASSERT(mOptions, "Options should be valid");
+ nsCOMPtr<nsINavHistoryQueryOptions> options = do_QueryInterface(mOptions);
+ options.forget(_options);
return NS_OK;
}
/**
- * Safe options getter, ensures queries are parsed first.
+ * Safe options getter, ensures query is parsed first.
*/
nsNavHistoryQueryOptions*
nsNavHistoryQueryResultNode::Options()
{
- nsresult rv = VerifyQueriesParsed();
+ nsresult rv = VerifyQueryParsed();
if (NS_FAILED(rv))
return nullptr;
MOZ_ASSERT(mOptions, "Options invalid, cannot generate from URI");
return mOptions;
}
nsresult
-nsNavHistoryQueryResultNode::VerifyQueriesParsed()
+nsNavHistoryQueryResultNode::VerifyQueryParsed()
{
- if (mQueries.Count() > 0) {
+ if (mQuery) {
MOZ_ASSERT(mOriginalOptions && mOptions,
- "If a result has queries, it also needs options");
+ "A result with a parsed query must have options");
return NS_OK;
}
NS_ASSERTION(!mURI.IsEmpty(),
"Query nodes must have either a URI or query/options");
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsINavHistoryQuery> query;
nsCOMPtr<nsINavHistoryQueryOptions> options;
nsresult rv = history->QueryStringToQuery(mURI, getter_AddRefs(query),
getter_AddRefs(options));
NS_ENSURE_SUCCESS(rv, rv);
mOptions = do_QueryObject(options);
NS_ENSURE_STATE(mOptions);
- RefPtr<nsNavHistoryQuery> queryObj = do_QueryObject(query);
- NS_ENSURE_STATE(queryObj);
- mQueries.AppendObject(queryObj);
- mLiveUpdate = history->GetUpdateRequirements(mQueries, mOptions,
+ mQuery = do_QueryObject(query);
+ NS_ENSURE_STATE(mQuery);
+ mLiveUpdate = history->GetUpdateRequirements(mQuery, mOptions,
&mHasSearchTerms);
return NS_OK;
}
nsresult
-nsNavHistoryQueryResultNode::VerifyQueriesSerialized()
+nsNavHistoryQueryResultNode::VerifyQuerySerialized()
{
if (!mURI.IsEmpty()) {
return NS_OK;
}
- MOZ_ASSERT(mQueries.Count() > 0 && mOptions,
+ MOZ_ASSERT(mQuery && mOptions,
"Query nodes must have either a URI or query/options");
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
- nsCOMPtr<nsINavHistoryQuery> query = do_QueryInterface(mQueries[0]);
+ nsCOMPtr<nsINavHistoryQuery> query = do_QueryInterface(mQuery);
nsresult rv = history->QueryToQueryString(query, mOriginalOptions, mURI);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_STATE(!mURI.IsEmpty());
return NS_OK;
}
nsresult
@@ -2046,19 +2021,19 @@ nsNavHistoryQueryResultNode::FillChildre
"Don't call FillChildren when contents are valid");
NS_ASSERTION(mChildren.Count() == 0,
"We are trying to fill children when there already are some");
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
// get the results from the history service
- nsresult rv = VerifyQueriesParsed();
+ nsresult rv = VerifyQueryParsed();
NS_ENSURE_SUCCESS(rv, rv);
- rv = history->GetQueryResults(this, mQueries, mOptions, &mChildren);
+ rv = history->GetQueryResults(this, mQuery, mOptions, &mChildren);
NS_ENSURE_SUCCESS(rv, rv);
// it is important to call FillStats to fill in the parents on all
// nodes and the result node pointers on the containers
FillStats();
uint16_t sortType = GetSortType();
@@ -2367,82 +2342,74 @@ nsNavHistoryQueryResultNode::OnVisit(nsI
switch(mLiveUpdate) {
case QUERYUPDATE_MOBILEPREF: {
return NS_OK;
}
case QUERYUPDATE_HOST: {
// For these simple yet common cases we can check the host ourselves
// before doing the overhead of creating a new result node.
- MOZ_ASSERT(mQueries.Count() == 1,
- "Host updated queries can have only one object");
- RefPtr<nsNavHistoryQuery> query = do_QueryObject(mQueries[0]);
-
bool hasDomain;
- query->GetHasDomain(&hasDomain);
+ mQuery->GetHasDomain(&hasDomain);
if (!hasDomain)
return NS_OK;
nsAutoCString host;
if (NS_FAILED(aURI->GetAsciiHost(host)))
return NS_OK;
- if (!query->Domain().Equals(host))
+ if (!mQuery->Domain().Equals(host))
return NS_OK;
// Fall through to check the time, if the time is not present it will
// still match.
MOZ_FALLTHROUGH;
}
case QUERYUPDATE_TIME: {
// For these simple yet common cases we can check the time ourselves
// before doing the overhead of creating a new result node.
- MOZ_ASSERT(mQueries.Count() == 1,
- "Time updated queries can have only one object");
- RefPtr<nsNavHistoryQuery> query = do_QueryObject(mQueries[0]);
-
bool hasIt;
- query->GetHasBeginTime(&hasIt);
+ mQuery->GetHasBeginTime(&hasIt);
if (hasIt) {
- PRTime beginTime = history->NormalizeTime(query->BeginTimeReference(),
- query->BeginTime());
+ PRTime beginTime = history->NormalizeTime(mQuery->BeginTimeReference(),
+ mQuery->BeginTime());
if (aTime < beginTime)
return NS_OK; // before our time range
}
- query->GetHasEndTime(&hasIt);
+ mQuery->GetHasEndTime(&hasIt);
if (hasIt) {
- PRTime endTime = history->NormalizeTime(query->EndTimeReference(),
- query->EndTime());
+ PRTime endTime = history->NormalizeTime(mQuery->EndTimeReference(),
+ mQuery->EndTime());
if (aTime > endTime)
return NS_OK; // after our time range
}
// Now we know that our visit satisfies the time range, fall through to
// the QUERYUPDATE_SIMPLE case below.
MOZ_FALLTHROUGH;
}
case QUERYUPDATE_SIMPLE: {
- // If all of the queries are filtered by some transitions, skip the
+ // If the query is filtered by some transitions, skip the
// update if aTransitionType doesn't match any of them.
if (mTransitions.Length() > 0 && !mTransitions.Contains(aTransitionType))
return NS_OK;
// The history service can tell us whether the new item should appear
// in the result. We first have to construct a node for it to check.
RefPtr<nsNavHistoryResultNode> addition;
nsresult rv = history->VisitIdToResultNode(aVisitId, mOptions,
getter_AddRefs(addition));
NS_ENSURE_SUCCESS(rv, rv);
if (!addition) {
// Certain result types manage the nodes by themselves.
return NS_OK;
}
addition->mTransitionType = aTransitionType;
- if (!history->EvaluateQueryForNode(mQueries, mOptions, addition))
+ if (!history->EvaluateQueryForNode(mQuery, mOptions, addition))
return NS_OK; // don't need to include in our query
if (mOptions->ResultType() == nsNavHistoryQueryOptions::RESULTS_AS_VISIT) {
// If this is a visit type query, just insert the new visit. We never
// update visits, only add or remove them.
rv = InsertSortedChild(addition);
NS_ENSURE_SUCCESS(rv, rv);
} else {
@@ -2518,48 +2485,48 @@ nsNavHistoryQueryResultNode::OnTitleChan
// compute what the new title should be
NS_ConvertUTF16toUTF8 newTitle(aPageTitle);
bool onlyOneEntry =
mOptions->ResultType() == nsINavHistoryQueryOptions::RESULTS_AS_URI ||
mOptions->ResultType() == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS;
- // See if our queries have any search term matching.
+ // See if our query has any search term matching.
if (mHasSearchTerms) {
// Find all matching URI nodes.
nsCOMArray<nsNavHistoryResultNode> matches;
nsAutoCString spec;
nsresult rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
RecursiveFindURIs(onlyOneEntry, this, spec, &matches);
if (matches.Count() == 0) {
// This could be a new node matching the query, thus we could need
// to add it to the result.
RefPtr<nsNavHistoryResultNode> node;
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
rv = history->URIToResultNode(aURI, mOptions, getter_AddRefs(node));
NS_ENSURE_SUCCESS(rv, rv);
- if (history->EvaluateQueryForNode(mQueries, mOptions, node)) {
+ if (history->EvaluateQueryForNode(mQuery, mOptions, node)) {
rv = InsertSortedChild(node);
NS_ENSURE_SUCCESS(rv, rv);
}
}
for (int32_t i = 0; i < matches.Count(); ++i) {
// For each matched node we check if it passes the query filter, if not
// we remove the node from the result, otherwise we'll update the title
// later.
nsNavHistoryResultNode* node = matches[i];
// We must check the node with the new title.
node->mTitle = newTitle;
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
- if (!history->EvaluateQueryForNode(mQueries, mOptions, node)) {
+ if (!history->EvaluateQueryForNode(mQuery, mOptions, node)) {
nsNavHistoryContainerResultNode* parent = node->mParent;
// URI nodes should always have parents
NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
int32_t childIndex = parent->FindChild(node);
NS_ASSERTION(childIndex >= 0, "Child not found in parent");
parent->RemoveChildAt(childIndex);
}
}
@@ -2743,33 +2710,33 @@ nsNavHistoryQueryResultNode::NotifyIfTag
nsCOMArray<nsNavHistoryResultNode> matches;
RecursiveFindURIs(onlyOneEntry, this, spec, &matches);
if (matches.Count() == 0 && mHasSearchTerms) {
// A new tag has been added, it's possible it matches our query.
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
rv = history->URIToResultNode(aURI, mOptions, getter_AddRefs(node));
NS_ENSURE_SUCCESS(rv, rv);
- if (history->EvaluateQueryForNode(mQueries, mOptions, node)) {
+ if (history->EvaluateQueryForNode(mQuery, mOptions, node)) {
rv = InsertSortedChild(node);
NS_ENSURE_SUCCESS(rv, rv);
}
}
for (int32_t i = 0; i < matches.Count(); ++i) {
nsNavHistoryResultNode* node = matches[i];
// Force a tags update before checking the node.
node->mTags.SetIsVoid(true);
nsAutoString tags;
rv = node->GetTags(tags);
NS_ENSURE_SUCCESS(rv, rv);
// It's possible now this node does not respect anymore the conditions.
// In such a case it should be removed.
if (mHasSearchTerms &&
- !history->EvaluateQueryForNode(mQueries, mOptions, node)) {
+ !history->EvaluateQueryForNode(mQuery, mOptions, node)) {
nsNavHistoryContainerResultNode* parent = node->mParent;
// URI nodes should always have parents
NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
int32_t childIndex = parent->FindChild(node);
NS_ASSERTION(childIndex >= 0, "Child not found in parent");
parent->RemoveChildAt(childIndex);
}
else {
@@ -3125,23 +3092,21 @@ nsNavHistoryFolderResultNode::GetQuery(n
}
/**
* Options for the query that gives you this bookmarks folder. This is just
* the options for the folder with the current folder ID set.
*/
NS_IMETHODIMP
-nsNavHistoryFolderResultNode::GetQueryOptions(
- nsINavHistoryQueryOptions** aQueryOptions)
+nsNavHistoryFolderResultNode::GetQueryOptions(nsINavHistoryQueryOptions** _options)
{
- NS_ASSERTION(mOptions, "Options invalid");
-
- *aQueryOptions = mOptions;
- NS_ADDREF(*aQueryOptions);
+ MOZ_ASSERT(mOptions, "Options should be valid");
+ nsCOMPtr<nsINavHistoryQueryOptions> options = do_QueryInterface(mOptions);
+ options.forget(_options);
return NS_OK;
}
nsresult
nsNavHistoryFolderResultNode::FillChildren()
{
NS_ASSERTION(!mContentsValid,
@@ -4004,28 +3969,39 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsINavHistoryResult)
NS_INTERFACE_MAP_STATIC_AMBIGUOUS(nsNavHistoryResult)
NS_INTERFACE_MAP_ENTRY(nsINavHistoryResult)
NS_INTERFACE_MAP_ENTRY(nsINavBookmarkObserver)
NS_INTERFACE_MAP_ENTRY(nsINavHistoryObserver)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END
-nsNavHistoryResult::nsNavHistoryResult(nsNavHistoryContainerResultNode* aRoot)
- : mRootNode(aRoot)
+nsNavHistoryResult::nsNavHistoryResult(nsNavHistoryContainerResultNode* aRoot,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions,
+ bool aBatchInProgress
+) : mRootNode(aRoot)
+ , mQuery(aQuery)
+ , mOptions(aOptions)
, mNeedsToApplySortingMode(false)
, mIsHistoryObserver(false)
, mIsBookmarkFolderObserver(false)
, mIsAllBookmarksObserver(false)
, mIsMobilePrefObserver(false)
, mBookmarkFolderObservers(64)
- , mBatchInProgress(false)
+ , mBatchInProgress(aBatchInProgress)
, mSuppressNotifications(false)
{
+ mSortingMode = aOptions->SortingMode();
+ MOZ_ALWAYS_SUCCEEDS(aOptions->GetSortingAnnotation(mSortingAnnotation));
+
mRootNode->mResult = this;
+ MOZ_ASSERT(mRootNode->mIndentLevel == -1,
+ "Root node's indent level initialized wrong");
+ mRootNode->FillStats();
}
nsNavHistoryResult::~nsNavHistoryResult()
{
// Delete all heap-allocated bookmark folder observer arrays.
for (auto it = mBookmarkFolderObservers.Iter(); !it.Done(); it.Next()) {
delete it.Data();
it.Remove();
@@ -4053,81 +4029,16 @@ nsNavHistoryResult::StopObserving()
nsNavHistory* history = nsNavHistory::GetHistoryService();
if (history) {
history->RemoveObserver(this);
mIsHistoryObserver = false;
}
}
}
-/**
- * @note you must call AddRef before this, since we may do things like
- * register ourselves.
- */
-nsresult
-nsNavHistoryResult::Init(nsCOMArray<nsNavHistoryQuery>& aQueries,
- uint32_t aQueryCount,
- nsNavHistoryQueryOptions *aOptions)
-{
- nsresult rv;
- NS_ASSERTION(aOptions, "Must have valid options");
- NS_ASSERTION(aQueries.Count() == aQueryCount && aQueryCount > 0, "Must have >1 query in result");
-
- // Fill saved source queries with copies of the original (the caller might
- // change their original objects, and we always want to reflect the source
- // parameters).
- for (uint32_t i = 0; i < aQueryCount; ++i) {
- nsCOMPtr<nsINavHistoryQuery> queryClone;
- rv = aQueries[i]->Clone(getter_AddRefs(queryClone));
- NS_ENSURE_SUCCESS(rv, rv);
- if (!mQueries.AppendObject(queryClone))
- return NS_ERROR_OUT_OF_MEMORY;
- }
- rv = aOptions->Clone(getter_AddRefs(mOptions));
- NS_ENSURE_SUCCESS(rv, rv);
- mSortingMode = aOptions->SortingMode();
- rv = aOptions->GetSortingAnnotation(mSortingAnnotation);
- NS_ENSURE_SUCCESS(rv, rv);
-
- NS_ASSERTION(mRootNode->mIndentLevel == -1,
- "Root node's indent level initialized wrong");
- mRootNode->FillStats();
-
- return NS_OK;
-}
-
-
-/**
- * Constructs a new history result object.
- */
-nsresult // static
-nsNavHistoryResult::NewHistoryResult(nsCOMArray<nsNavHistoryQuery>& aQueries,
- uint32_t aQueryCount,
- nsNavHistoryQueryOptions* aOptions,
- nsNavHistoryContainerResultNode* aRoot,
- bool aBatchInProgress,
- nsNavHistoryResult** result)
-{
- *result = new nsNavHistoryResult(aRoot);
- if (!*result)
- return NS_ERROR_OUT_OF_MEMORY;
- NS_ADDREF(*result); // must happen before Init
- // Correctly set mBatchInProgress for the result based on the root node value.
- (*result)->mBatchInProgress = aBatchInProgress;
- nsresult rv = (*result)->Init(aQueries, aQueryCount, aOptions);
- if (NS_FAILED(rv)) {
- NS_RELEASE(*result);
- *result = nullptr;
- return rv;
- }
-
- return NS_OK;
-}
-
-
void
nsNavHistoryResult::AddHistoryObserver(nsNavHistoryQueryResultNode* aNode)
{
if (!mIsHistoryObserver) {
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ASSERTION(history, "Can't create history service");
history->AddObserver(this, true);
mIsHistoryObserver = true;
--- a/toolkit/components/places/nsNavHistoryResult.h
+++ b/toolkit/components/places/nsNavHistoryResult.h
@@ -96,23 +96,16 @@ private:
{ 0x455d1d40, 0x1b9b, 0x40e6, { 0xa6, 0x41, 0x8b, 0xb7, 0xe8, 0x82, 0x23, 0x87 } }
class nsNavHistoryResult final : public nsSupportsWeakReference,
public nsINavHistoryResult,
public nsINavBookmarkObserver,
public nsINavHistoryObserver
{
public:
- static nsresult NewHistoryResult(nsCOMArray<nsNavHistoryQuery>& aQueries,
- uint32_t aQueryCount,
- nsNavHistoryQueryOptions* aOptions,
- nsNavHistoryContainerResultNode* aRoot,
- bool aBatchInProgress,
- nsNavHistoryResult** result);
-
NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYRESULT_IID)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSINAVHISTORYRESULT
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNavHistoryResult, nsINavHistoryResult)
NS_DECL_BOOKMARK_HISTORY_OBSERVER_EXTERNAL(override)
NS_IMETHOD OnVisits(nsIVisitData** aVisits,
uint32_t aVisitsCount) override;
@@ -128,26 +121,25 @@ public:
void StopObserving();
nsresult OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
uint32_t aTransitionType, const nsACString& aGUID,
bool aHidden, uint32_t aVisitCount,
const nsAString& aLastKnownTitle);
public:
- // two-stage init, use NewHistoryResult to construct
- explicit nsNavHistoryResult(nsNavHistoryContainerResultNode* mRoot);
- nsresult Init(nsCOMArray<nsNavHistoryQuery>& aQueries,
- uint32_t aQueryCount,
- nsNavHistoryQueryOptions *aOptions);
+ explicit nsNavHistoryResult(nsNavHistoryContainerResultNode* mRoot,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
+ const RefPtr<nsNavHistoryQueryOptions>& aOptions,
+ bool aBatchInProgress);
RefPtr<nsNavHistoryContainerResultNode> mRootNode;
- nsCOMArray<nsINavHistoryQuery> mQueries;
- nsCOMPtr<nsNavHistoryQueryOptions> mOptions;
+ RefPtr<nsNavHistoryQuery> mQuery;
+ RefPtr<nsNavHistoryQueryOptions> mOptions;
// One of nsNavHistoryQueryOptions.SORY_BY_* This is initialized to mOptions.sortingMode,
// but may be overridden if the user clicks on one of the columns.
uint16_t mSortingMode;
// If root node is closed and we try to apply a sortingMode, it would not
// work. So we will apply it when the node will be reopened and populated.
// This var states the fact we need to apply sortingMode in such a situation.
bool mNeedsToApplySortingMode;
@@ -228,17 +220,17 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHisto
// This is used by the base classes instead of
// NS_FORWARD_NSINAVHISTORYRESULTNODE(nsNavHistoryResultNode) because they
// need to redefine GetType and GetUri rather than forwarding them. This
// implements all the simple getters instead of forwarding because they are so
// short and we can save a virtual function call.
//
// (GetUri is redefined only by QueryResultNode and FolderResultNode because
-// the queries might not necessarily be parsed. The rest just return the node's
+// the query might not necessarily be parsed. The rest just return the node's
// buffer.)
#define NS_FORWARD_COMMON_RESULTNODE_TO_BASE \
NS_IMPLEMENT_SIMPLE_RESULTNODE \
NS_IMETHOD GetIcon(nsACString& aIcon) override \
{ return nsNavHistoryResultNode::GetIcon(aIcon); } \
NS_IMETHOD GetParent(nsINavHistoryContainerResultNode** aParent) override \
{ return nsNavHistoryResultNode::GetParent(aParent); } \
NS_IMETHOD GetParentResult(nsINavHistoryResult** aResult) override \
@@ -483,18 +475,18 @@ public:
nsCOMArray<nsNavHistoryResultNode> mChildren;
// mOriginalOptions is the options object used to _define_ this specific
// container node. It may differ from mOptions, that is the options used
// to _fill_ this container node, because mOptions may be modified by
// the direct parent of this container node, see SetAsParentOfNode. For
// example, if the parent has excludeItems, options will have it too, even if
// originally this object was not defined with that option.
- nsCOMPtr<nsNavHistoryQueryOptions> mOriginalOptions;
- nsCOMPtr<nsNavHistoryQueryOptions> mOptions;
+ RefPtr<nsNavHistoryQueryOptions> mOriginalOptions;
+ RefPtr<nsNavHistoryQueryOptions> mOptions;
void FillStats();
// Sets this container as parent of aNode, propagating the appropriate options.
void SetAsParentOfNode(nsNavHistoryResultNode* aNode);
nsresult ReverseUpdateStats(int32_t aAccessCountChange);
// Sorting methods.
typedef nsCOMArray<nsNavHistoryResultNode>::nsCOMArrayComparatorFunc SortComparator;
@@ -624,21 +616,21 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHisto
class nsNavHistoryQueryResultNode final : public nsNavHistoryContainerResultNode,
public nsINavHistoryQueryResultNode,
public nsINavBookmarkObserver
{
public:
nsNavHistoryQueryResultNode(const nsACString& aTitle,
const nsACString& aQueryURI);
nsNavHistoryQueryResultNode(const nsACString& aTitle,
- const nsCOMArray<nsNavHistoryQuery>& aQueries,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
nsNavHistoryQueryOptions* aOptions);
nsNavHistoryQueryResultNode(const nsACString& aTitle,
PRTime aTime,
- const nsCOMArray<nsNavHistoryQuery>& aQueries,
+ const RefPtr<nsNavHistoryQuery>& aQuery,
nsNavHistoryQueryOptions* aOptions);
NS_DECL_ISUPPORTS_INHERITED
NS_FORWARD_COMMON_RESULTNODE_TO_BASE
NS_IMETHOD GetType(uint32_t* type) override
{ *type = nsNavHistoryResultNode::RESULT_TYPE_QUERY; return NS_OK; }
NS_IMETHOD GetUri(nsACString& aURI) override; // does special lazy creation
NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN
@@ -658,28 +650,28 @@ public:
// query nodes when the visited uri belongs to them. If no such query exists,
// the history result creates a new query node dynamically.
nsresult OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
uint32_t aTransitionType, bool aHidden,
uint32_t* aAdded);
virtual void OnRemoving() override;
public:
- // this constructs lazily mURI from mQueries and mOptions, call
- // VerifyQueriesSerialized either this or mQueries/mOptions should be valid
- nsresult VerifyQueriesSerialized();
+ // This constructs lazily mURI from mQuery and mOptions.
+ // Either this or mQuery/mOptions should be valid.
+ nsresult VerifyQuerySerialized();
- // these may be constructed lazily from mURI, call VerifyQueriesParsed
- // either this or mURI should be valid
- nsCOMArray<nsNavHistoryQuery> mQueries;
+ // This may be constructed lazily from mURI, call VerifyQueryParsed.
+ // Either this or mURI should be valid.
+ RefPtr<nsNavHistoryQuery> mQuery;
uint32_t mLiveUpdate; // one of QUERYUPDATE_* in nsNavHistory.h
bool mHasSearchTerms;
- nsresult VerifyQueriesParsed();
+ nsresult VerifyQueryParsed();
- // safe options getter, ensures queries are parsed
+ // safe options getter, ensures query is parsed
nsNavHistoryQueryOptions* Options();
// this indicates whether the query contents are valid, they don't go away
// after the container is closed until a notification comes in
bool mContentsValid;
nsresult FillChildren();
void ClearChildren(bool unregister);
@@ -689,17 +681,17 @@ public:
virtual void GetSortingAnnotation(nsACString& aSortingAnnotation) override;
virtual void RecursiveSort(const char* aData,
SortComparator aComparator) override;
nsresult NotifyIfTagsChanged(nsIURI* aURI);
uint32_t mBatchChanges;
- // Tracks transition type filters shared by all mQueries.
+ // Tracks transition type filters.
nsTArray<uint32_t> mTransitions;
protected:
virtual ~nsNavHistoryQueryResultNode();
};
// nsNavHistoryFolderResultNode
--- a/toolkit/components/places/tests/unit/test_annotations.js
+++ b/toolkit/components/places/tests/unit/test_annotations.js
@@ -292,17 +292,17 @@ add_task(async function test_execute() {
});
annosvc.removeItemAnnotation(testItemId, int32Key);
testItem = await PlacesUtils.bookmarks.fetch(testItem.guid);
var lastModified4 = testItem.lastModified;
info("verify that removing an annotation updates the last modified date");
info("lastModified3 = " + lastModified3);
info("lastModified4 = " + lastModified4);
- Assert.ok(lastModified4 > lastModified3);
+ Assert.ok(is_time_ordered(lastModified3, lastModified4));
Assert.equal(annoObserver.PAGE_lastRemoved_URI, testURI.spec);
Assert.equal(annoObserver.PAGE_lastRemoved_AnnoName, int32Key);
Assert.equal(annoObserver.ITEM_lastRemoved_Id, testItemId);
Assert.equal(annoObserver.ITEM_lastRemoved_AnnoName, int32Key);
// test that getItems/PagesWithAnnotation returns an empty array after
// removing all items/pages which had the annotation set, see bug 380317.