Bug 824502 - Change folder=<id> to parent=<guid> in Places' bookmark queries. r?mak draft
authorMark Banner <standard8@mozilla.com>
Thu, 26 Apr 2018 09:05:00 +0100
changeset 799741 9ff051238dd7f8ec683d9dde11657f3f392efeb3
parent 799714 1bdf8e7d1cfe6d8b9bfa891f43473345210ee281
child 799742 17bb5160cb43d6efd658d9483302f6a0e016ebe8
push id111160
push userbmo:standard8@mozilla.com
push dateFri, 25 May 2018 10:21:09 +0000
reviewersmak
bugs824502
milestone62.0a1
Bug 824502 - Change folder=<id> to parent=<guid> in Places' bookmark queries. r?mak This allows queries to be stable across devices, and requires less work to obtain the ids. MozReview-Commit-ID: 5KAKKags7o9
browser/base/content/browser-menubar.inc
browser/base/content/browser-places.js
browser/base/content/browser.xul
browser/components/places/content/bookmarksSidebar.js
browser/components/places/content/places.js
browser/components/places/content/tree.xml
toolkit/components/places/Database.cpp
toolkit/components/places/nsINavHistoryService.idl
toolkit/components/places/nsNavBookmarks.cpp
toolkit/components/places/nsNavBookmarks.h
toolkit/components/places/nsNavHistory.cpp
toolkit/components/places/nsNavHistory.h
toolkit/components/places/nsNavHistoryQuery.cpp
toolkit/components/places/nsNavHistoryQuery.h
toolkit/components/places/nsNavHistoryResult.cpp
toolkit/components/places/tests/queries/test_queryMultipleFolder.js
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -382,17 +382,17 @@
 #endif
                context="placesContext"
                openInTabs="children"
                onmouseup="BookmarksEventHandler.onMouseUp(event);"
                oncommand="BookmarksEventHandler.onCommand(event);"
                onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
                onpopupshowing="BookmarkingUI.onMainMenuPopupShowing(event);
                                if (!this.parentNode._placesView)
-                                 new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
+                                 new PlacesMenu(event, `place:parent=${PlacesUtils.bookmarks.menuGuid}`);"
                tooltip="bhTooltip" popupsinherittooltip="true">
       <menuitem id="bookmarksShowAll"
                 label="&showAllBookmarks2.label;"
                 command="Browser:ShowAllBookmarks"
                 key="manBookmarkKb"/>
       <menuseparator id="organizeBookmarksSeparator"/>
       <menuitem id="menu_bookmarkThisPage"
                 command="Browser:AddBookmarkAs"
@@ -428,42 +428,42 @@
             label="&personalbarCmd.label;"
             container="true">
         <menupopup id="bookmarksToolbarFolderPopup"
 #ifndef XP_MACOSX
                    placespopup="true"
 #endif
                    context="placesContext"
                    onpopupshowing="if (!this.parentNode._placesView)
-                                     new PlacesMenu(event, 'place:folder=TOOLBAR');"/>
+                                     new PlacesMenu(event, `place:parent=${PlacesUtils.bookmarks.toolbarGuid}`);"/>
       </menu>
       <menu id="menu_unsortedBookmarks"
             class="menu-iconic bookmark-item"
             label="&otherBookmarksCmd.label;"
             container="true">
         <menupopup id="otherBookmarksFolderPopup"
 #ifndef XP_MACOSX
                    placespopup="true"
 #endif
                    context="placesContext"
                    onpopupshowing="if (!this.parentNode._placesView)
-                                     new PlacesMenu(event, 'place:folder=UNFILED_BOOKMARKS');"/>
+                                     new PlacesMenu(event, `place:parent=${PlacesUtils.bookmarks.unfiledGuid}`);"/>
       </menu>
       <menu id="menu_mobileBookmarks"
             class="menu-iconic bookmark-item"
             label="&mobileBookmarksCmd.label;"
             hidden="true"
             container="true">
         <menupopup id="mobileBookmarksFolderPopup"
 #ifndef XP_MACOSX
                    placespopup="true"
 #endif
                    context="placesContext"
                    onpopupshowing="if (!this.parentNode._placesView)
-                                     new PlacesMenu(event, 'place:folder=MOBILE_BOOKMARKS');"/>
+                                     new PlacesMenu(event, `place:parent=${PlacesUtils.bookmarks.mobileGuid}`);"/>
       </menu>
       <menuseparator id="bookmarksMenuItemsSeparator"/>
       <!-- Bookmarks menu items -->
     </menupopup>
   </menu>
 
             <menu id="tools-menu"
                   label="&toolsMenu.label;"
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -993,18 +993,16 @@ var PlacesMenuDNDHandler = {
   }
 };
 
 /**
  * This object handles the initialization and uninitialization of the bookmarks
  * toolbar.
  */
 var PlacesToolbarHelper = {
-  _place: "place:folder=TOOLBAR",
-
   get _viewElt() {
     return document.getElementById("PlacesToolbar");
   },
 
   init: function PTH_init() {
     let viewElt = this._viewElt;
     if (!viewElt || viewElt._placesView)
       return;
@@ -1025,17 +1023,17 @@ var PlacesToolbarHelper = {
     // don't initialize.  Also, there is no need to initialize the toolbar if
     // customizing, because that will happen when the customization is done.
     let toolbar = this._getParentToolbar(viewElt);
     if (!toolbar || toolbar.collapsed || this._isCustomizing ||
         getComputedStyle(toolbar, "").display == "none") {
       return;
     }
 
-    new PlacesToolbar(this._place);
+    new PlacesToolbar(`place:parent=${PlacesUtils.bookmarks.toolbarGuid}`);
   },
 
   handleEvent(event) {
     switch (event.type) {
       case "toolbarvisibilitychange":
         if (event.target == this._getParentToolbar(this._viewElt))
           this._resetView();
         break;
@@ -1330,17 +1328,17 @@ var BookmarkingUI = {
       document.getElementById("PersonalToolbar").collapsed);
   },
 
   attachPlacesView(event, node) {
     // If the view is already there, bail out early.
     if (node.parentNode._placesView)
       return;
 
-    new PlacesMenu(event, "place:folder=BOOKMARKS_MENU", {
+    new PlacesMenu(event, `place:parent=${PlacesUtils.bookmarks.menuGuid}`, {
       extraClasses: {
         entry: "subviewbutton",
         footer: "panel-subview-footer"
       },
       insertionPoint: ".panel-subview-footer"
     });
   },
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1125,17 +1125,17 @@
           <menu id="BMB_bookmarksToolbar"
                 class="menu-iconic bookmark-item subviewbutton"
                 label="&personalbarCmd.label;"
                 container="true">
             <menupopup id="BMB_bookmarksToolbarPopup"
                        placespopup="true"
                        context="placesContext"
                        onpopupshowing="if (!this.parentNode._placesView)
-                                         new PlacesMenu(event, 'place:folder=TOOLBAR',
+                                         new PlacesMenu(event, `place:parent=${PlacesUtils.bookmarks.toolbarGuid}`,
                                                         PlacesUIUtils.getViewForNode(this.parentNode.parentNode).options);">
               <menuitem id="BMB_viewBookmarksToolbar"
                         class="menuitem-iconic subviewbutton"
                         label-show="&viewBookmarksToolbar.label;"
                         label-hide="&hideBookmarksToolbar.label;"
                         oncommand="BookmarkingUI.toggleBookmarksToolbar();"/>
               <menuseparator/>
               <!-- Bookmarks toolbar items -->
@@ -1144,29 +1144,29 @@
           <menu id="BMB_unsortedBookmarks"
                 class="menu-iconic bookmark-item subviewbutton"
                 label="&bookmarksMenuButton.other.label;"
                 container="true">
             <menupopup id="BMB_unsortedBookmarksPopup"
                        placespopup="true"
                        context="placesContext"
                        onpopupshowing="if (!this.parentNode._placesView)
-                                         new PlacesMenu(event, 'place:folder=UNFILED_BOOKMARKS',
+                                         new PlacesMenu(event, `place:parent=${PlacesUtils.bookmarks.unfiledGuid}`,
                                                         PlacesUIUtils.getViewForNode(this.parentNode.parentNode).options);"/>
           </menu>
           <menu id="BMB_mobileBookmarks"
                 class="menu-iconic bookmark-item subviewbutton"
                 label="&bookmarksMenuButton.mobile.label;"
                 hidden="true"
                 container="true">
             <menupopup id="BMB_mobileBookmarksPopup"
                        placespopup="true"
                        context="placesContext"
                        onpopupshowing="if (!this.parentNode._placesView)
-                                         new PlacesMenu(event, 'place:folder=MOBILE_BOOKMARKS',
+                                         new PlacesMenu(event, `place:parent=${PlacesUtils.bookmarks.mobileGuid}`,
                                                         PlacesUIUtils.getViewForNode(this.parentNode.parentNode).options);"/>
           </menu>
 
           <menuseparator/>
           <!-- Bookmarks menu items will go here -->
           <menuitem id="BMB_bookmarksShowAll"
                     class="subviewbutton panel-subview-footer"
                     label="&showAllBookmarks2.label;"
--- a/browser/components/places/content/bookmarksSidebar.js
+++ b/browser/components/places/content/bookmarksSidebar.js
@@ -16,16 +16,13 @@ function init() {
 }
 
 function searchBookmarks(aSearchString) {
   var tree = document.getElementById("bookmarks-view");
   if (!aSearchString)
     tree.place = tree.place;
   else
     tree.applyFilter(aSearchString,
-                     [PlacesUtils.bookmarksMenuFolderId,
-                      PlacesUtils.unfiledBookmarksFolderId,
-                      PlacesUtils.toolbarFolderId,
-                      PlacesUtils.mobileFolderId]);
+                     PlacesUtils.bookmarks.userContentRoots);
 }
 
 window.addEventListener("SidebarFocused",
                         () => document.getElementById("search-box").focus());
--- a/browser/components/places/content/places.js
+++ b/browser/components/places/content/places.js
@@ -748,20 +748,17 @@ var PlacesSearchBox = {
   },
 
   /**
    * Folders to include when searching.
    */
   _folders: [],
   get folders() {
     if (this._folders.length == 0) {
-      this._folders.push(PlacesUtils.bookmarksMenuFolderId,
-                         PlacesUtils.unfiledBookmarksFolderId,
-                         PlacesUtils.toolbarFolderId,
-                         PlacesUtils.mobileFolderId);
+      this._folders = PlacesUtils.bookmarks.userContentRoots;
     }
     return this._folders;
   },
   set folders(aFolders) {
     this._folders = aFolders;
     return aFolders;
   },
 
@@ -926,20 +923,17 @@ var PlacesQueryBuilder = {
     var filterCollection;
     var folders = [];
     switch (aScope) {
       case "history":
         filterCollection = "history";
         break;
       case "bookmarks":
         filterCollection = "bookmarks";
-        folders.push(PlacesUtils.bookmarksMenuFolderId,
-                     PlacesUtils.toolbarFolderId,
-                     PlacesUtils.unfiledBookmarksFolderId,
-                     PlacesUtils.mobileFolderId);
+        folders = PlacesUtils.bookmarks.userContentRoots;
         break;
       case "downloads":
         filterCollection = "downloads";
         break;
       default:
         throw "Invalid search scope";
     }
 
--- a/browser/components/places/content/tree.xml
+++ b/browser/components/places/content/tree.xml
@@ -87,17 +87,17 @@
               options.resultType == options.RESULTS_AS_TAGS_ROOT ||
               options.resultType == options.RESULTS_AS_ROOTS_QUERY)
             options.resultType = options.RESULTS_AS_URI;
 
           var query = PlacesUtils.history.getNewQuery();
           query.searchTerms = filterString;
 
           if (folderRestrict) {
-            query.setFolders(folderRestrict, folderRestrict.length);
+            query.setParents(folderRestrict, folderRestrict.length);
             options.queryType = options.QUERY_TYPE_BOOKMARKS;
           }
 
           options.includeHidden = !!includeHidden;
 
           this.load(query, options);
         ]]></body>
       </method>
--- a/toolkit/components/places/Database.cpp
+++ b/toolkit/components/places/Database.cpp
@@ -102,22 +102,16 @@
 
 // Places string bundle, contains internationalized bookmark root names.
 #define PLACES_BUNDLE "chrome://places/locale/places.properties"
 
 // Livemarks annotations.
 #define LMANNO_FEEDURI "livemark/feedURI"
 #define LMANNO_SITEURI "livemark/siteURI"
 
-#define ROOT_GUID "root________"
-#define MENU_ROOT_GUID "menu________"
-#define TOOLBAR_ROOT_GUID "toolbar_____"
-#define UNFILED_ROOT_GUID "unfiled_____"
-#define TAGS_ROOT_GUID "tags________"
-#define MOBILE_ROOT_GUID "mobile______"
 // This is no longer used & obsolete except for during migration.
 // Note: it may still be found in older places databases.
 #define MOBILE_ROOT_ANNO "mobile/bookmarksRoot"
 
 // We use a fixed title for the mobile root to avoid marking the database as
 // corrupt if we can't look up the localized title in the string bundle. Sync
 // sets the title to the localized version when it creates the left pane query.
 #define MOBILE_ROOT_TITLE "mobile"
--- a/toolkit/components/places/nsINavHistoryService.idl
+++ b/toolkit/components/places/nsINavHistoryService.idl
@@ -951,26 +951,26 @@ interface nsINavHistoryQuery : nsISuppor
    * are not tagged with any of the given tags.  This attribute is used in
    * conjunction with the 'tags' attribute.
    */
   attribute boolean tagsAreNot;
 
   /**
    * Limit results to items that are in all of the given folders.
    */
-  void getFolders([optional] out unsigned long count,
-                  [retval,array,size_is(count)] out long long folders);
-  readonly attribute unsigned long folderCount;
+  void getParents([optional] out unsigned long aGuidCount,
+                  [retval,array,size_is(aGuidCount)] out string aGuids);
+  readonly attribute unsigned long parentCount;
 
   /**
    * This is not recursive so results will be returned from the first level of
    * that folder.
    */
-  void setFolders([const,array, size_is(folderCount)] in long long folders,
-                  in unsigned long folderCount);
+  void setParents([array, size_is(aGuidCount)] in string aGuids,
+                  in unsigned long aGuidCount);
 
   /**
    * Creates a new query item with the same parameters of this one.
    */
   nsINavHistoryQuery clone();
 };
 
 /**
--- a/toolkit/components/places/nsNavBookmarks.cpp
+++ b/toolkit/components/places/nsNavBookmarks.cpp
@@ -1107,16 +1107,90 @@ nsNavBookmarks::FetchItemInfo(int64_t aI
     _bookmark.grandParentId = -1;
   }
   rv = stmt->GetInt32(12, &_bookmark.syncStatus);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
+
+nsresult
+nsNavBookmarks::FetchItemInfo(const nsCString& aGUID,
+                              BookmarkData& _bookmark)
+{
+  // LEFT JOIN since not all bookmarks have an associated place.
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT b.id, h.url, b.title, b.position, b.fk, b.parent, b.type, "
+           "b.dateAdded, b.lastModified, t.guid, t.parent, "
+           "b.syncStatus "
+    "FROM moz_bookmarks b "
+    "LEFT JOIN moz_bookmarks t ON t.id = b.parent "
+    "LEFT JOIN moz_places h ON h.id = b.fk "
+    "WHERE b.guid = :item_guid"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
+  nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("item_guid"), aGUID);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  _bookmark.guid = aGUID;
+
+  bool hasResult;
+  rv = stmt->ExecuteStep(&hasResult);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!hasResult) {
+    return NS_ERROR_INVALID_ARG;
+  }
+
+  rv = stmt->GetInt64(0, &_bookmark.id);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = stmt->GetUTF8String(1, _bookmark.url);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool isNull;
+  rv = stmt->GetIsNull(2, &isNull);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!isNull) {
+    rv = stmt->GetUTF8String(2, _bookmark.title);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  rv = stmt->GetInt32(3, &_bookmark.position);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->GetInt64(4, &_bookmark.placeId);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->GetInt64(5, &_bookmark.parentId);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->GetInt32(6, &_bookmark.type);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->GetInt64(7, reinterpret_cast<int64_t*>(&_bookmark.dateAdded));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->GetInt64(8, reinterpret_cast<int64_t*>(&_bookmark.lastModified));
+  NS_ENSURE_SUCCESS(rv, rv);
+  // Getting properties of the root would show no parent.
+  rv = stmt->GetIsNull(9, &isNull);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!isNull) {
+    rv = stmt->GetUTF8String(9, _bookmark.parentGuid);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = stmt->GetInt64(10, &_bookmark.grandParentId);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  else {
+    _bookmark.grandParentId = -1;
+  }
+  rv = stmt->GetInt32(11, &_bookmark.syncStatus);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+
 nsresult
 nsNavBookmarks::SetItemDateInternal(enum BookmarkDate aDateType,
                                     int64_t aSyncChangeDelta,
                                     int64_t aItemId,
                                     PRTime aValue)
 {
   aValue = RoundToMilliseconds(aValue);
 
@@ -1495,22 +1569,22 @@ nsNavBookmarks::GetBookmarkURI(int64_t a
   rv = NS_NewURI(_URI, bookmark.url);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 
 nsresult
-nsNavBookmarks::ResultNodeForContainer(int64_t aItemId,
+nsNavBookmarks::ResultNodeForContainer(const nsCString& aGUID,
                                        nsNavHistoryQueryOptions* aOptions,
                                        nsNavHistoryResultNode** aNode)
 {
   BookmarkData bookmark;
-  nsresult rv = FetchItemInfo(aItemId, bookmark);
+  nsresult rv = FetchItemInfo(aGUID, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (bookmark.type == TYPE_FOLDER) { // TYPE_FOLDER
     *aNode = new nsNavHistoryFolderResultNode(bookmark.title,
                                               aOptions,
                                               bookmark.id);
   }
   else {
@@ -2082,19 +2156,19 @@ nsNavBookmarks::OnPageChanged(nsIURI* aU
       nsCOMPtr<nsINavHistoryQuery> query;
       nsCOMPtr<nsINavHistoryQueryOptions> options;
       rv = history->QueryStringToQuery(changeData.bookmark.url,
                                        getter_AddRefs(query),
                                        getter_AddRefs(options));
       NS_ENSURE_SUCCESS(rv, rv);
 
       RefPtr<nsNavHistoryQuery> queryObj = do_QueryObject(query);
-      if (queryObj->Folders().Length() == 1) {
+      if (queryObj->Parents().Length() == 1) {
         // Fetch missing data.
-        rv = FetchItemInfo(queryObj->Folders()[0], changeData.bookmark);
+        rv = FetchItemInfo(queryObj->Parents()[0], changeData.bookmark);
         NS_ENSURE_SUCCESS(rv, rv);
         NotifyItemChanged(changeData);
       }
     }
     else {
       RefPtr< AsyncGetBookmarksForURI<ItemChangeMethod, ItemChangeData> > notifier =
         new AsyncGetBookmarksForURI<ItemChangeMethod, ItemChangeData>(this, &nsNavBookmarks::NotifyItemChanged, changeData);
       notifier->Init();
--- a/toolkit/components/places/nsNavBookmarks.h
+++ b/toolkit/components/places/nsNavBookmarks.h
@@ -116,17 +116,17 @@ public:
   nsresult OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
                    int64_t aSessionId, int64_t aReferringId,
                    uint32_t aTransitionType, const nsACString& aGUID,
                    bool aHidden, uint32_t aVisitCount,
                    uint32_t aTyped, const nsAString& aLastKnownTitle);
 
   nsresult GetBookmarkURI(int64_t aItemId, nsIURI** _URI);
 
-  nsresult ResultNodeForContainer(int64_t aID,
+  nsresult ResultNodeForContainer(const nsCString& aGUID,
                                   nsNavHistoryQueryOptions* aOptions,
                                   nsNavHistoryResultNode** aNode);
 
   // Find all the children of a folder, using the given query and options.
   // For each child, a ResultNode is created and added to |children|.
   // The results are ordered by folder position.
   nsresult QueryFolderChildren(int64_t aFolderId,
                                nsNavHistoryQueryOptions* aOptions,
@@ -172,16 +172,27 @@ public:
    *        Id of the item to fetch information for.
    * @param aBookmark
    *        BookmarkData to store the information.
    */
   nsresult FetchItemInfo(int64_t aItemId,
                          BookmarkData& _bookmark);
 
   /**
+   * Fetches information about the specified GUID from the database.
+   *
+   * @param aGUID
+   *        GUID of the item to fetch information for.
+   * @param aBookmark
+   *        BookmarkData to store the information.
+   */
+  nsresult FetchItemInfo(const nsCString &aGUID,
+                         BookmarkData& _bookmark);
+
+/**
    * Notifies that a bookmark has been visited.
    *
    * @param aItemId
    *        The visited item id.
    * @param aData
    *        Details about the new visit.
    */
   void NotifyItemVisited(const ItemVisitData& aData);
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -186,18 +186,18 @@ NS_INTERFACE_MAP_BEGIN(nsNavHistory)
 NS_INTERFACE_MAP_END
 
 // We don't care about flattening everything
 NS_IMPL_CI_INTERFACE_GETTER(nsNavHistory,
                             nsINavHistoryService)
 
 namespace {
 
-static int64_t GetSimpleBookmarksQueryFolder(const RefPtr<nsNavHistoryQuery>& aQuery,
-                                             const RefPtr<nsNavHistoryQueryOptions>& aOptions);
+static nsCString GetSimpleBookmarksQueryParent(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)
@@ -1036,24 +1036,24 @@ nsNavHistory::ExecuteQuery(nsINavHistory
   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) {
+  nsCString folderGuid = GetSimpleBookmarksQueryParent(query, options);
+  if (!folderGuid.IsEmpty()) {
     // 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;
-    nsresult rv = bookmarks->ResultNodeForContainer(folderId, options,
+    nsresult rv = bookmarks->ResultNodeForContainer(folderGuid, 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);
@@ -1125,17 +1125,17 @@ bool IsOptimizableHistoryQuery(const Ref
     return false;
 
   if (aQuery->DomainIsHost() || !aQuery->Domain().IsEmpty())
     return false;
 
   if (aQuery->AnnotationIsNot() || !aQuery->Annotation().IsEmpty())
     return false;
 
-  if (aQuery->Folders().Length() > 0)
+  if (aQuery->Parents().Length() > 0)
     return false;
 
   if (aQuery->Tags().Length() > 0)
     return false;
 
   if (aQuery->Transitions().Length() > 0)
     return false;
 
@@ -1689,27 +1689,27 @@ PlacesSQLQueryBuilder::SelectAsRoots()
   nsAutoCString mobileString;
 
   if (Preferences::GetBool(MOBILE_BOOKMARKS_PREF, false)) {
     nsAutoCString mobileTitle;
     history->GetStringFromName("MobileBookmarksFolderTitle", mobileTitle);
     mAddParams.Put(NS_LITERAL_CSTRING("MobileBookmarksFolderTitle"), mobileTitle);
 
     mobileString = NS_LITERAL_CSTRING(","
-      "(null, 'place:folder=MOBILE_BOOKMARKS', :MobileBookmarksFolderTitle, null, null, null, "
+      "(null, 'place:parent=" MOBILE_ROOT_GUID "', :MobileBookmarksFolderTitle, null, null, null, "
        "null, null, 0, 0, null, null, null, null, '" MOBILE_BOOKMARKS_VIRTUAL_GUID "', null) ");
   }
 
   mQueryString = NS_LITERAL_CSTRING(
     "SELECT * FROM ("
-        "VALUES(null, 'place:folder=TOOLBAR', :BookmarksToolbarFolderTitle, null, null, null, "
+        "VALUES(null, 'place:parent=" TOOLBAR_ROOT_GUID "', :BookmarksToolbarFolderTitle, null, null, null, "
                "null, null, 0, 0, null, null, null, null, 'toolbar____v', null), "
-              "(null, 'place:folder=BOOKMARKS_MENU', :BookmarksMenuFolderTitle, null, null, null, "
+              "(null, 'place:parent=" MENU_ROOT_GUID "', :BookmarksMenuFolderTitle, null, null, null, "
                "null, null, 0, 0, null, null, null, null, 'menu_______v', null), "
-              "(null, 'place:folder=UNFILED_BOOKMARKS', :OtherBookmarksFolderTitle, null, null, null, "
+              "(null, 'place:parent=" UNFILED_ROOT_GUID "', :OtherBookmarksFolderTitle, null, null, null, "
                "null, null, 0, 0, null, null, null, null, 'unfiled___v', null) ") +
     mobileString + NS_LITERAL_CSTRING(")");
 
   return NS_OK;
 }
 
 nsresult
 PlacesSQLQueryBuilder::SelectAsLeftPane()
@@ -2762,31 +2762,33 @@ nsNavHistory::QueryToSelectClause(const 
   for (uint32_t i = 0; i < transitions.Length(); ++i) {
     nsPrintfCString param(":transition%d_", i);
     clause.Condition("h.id IN (SELECT place_id FROM moz_historyvisits "
                              "WHERE visit_type = ")
           .Param(param.get())
           .Str(")");
   }
 
-  // folders
-  const nsTArray<int64_t>& folders = aQuery->Folders();
-  if (folders.Length() > 0) {
+  // parents
+  const nsTArray<nsCString>& parents = aQuery->Parents();
+  if (parents.Length() > 0) {
     aOptions->SetQueryType(nsNavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS);
     clause.Condition("b.parent IN( "
                        "WITH RECURSIVE parents(id) AS ( "
-                         "VALUES ");
-    for (uint32_t i = 0; i < folders.Length(); ++i) {
-      nsPrintfCString param("(:parent%d_)", i);
+                         "SELECT id FROM moz_bookmarks WHERE GUID IN (");
+
+    for (uint32_t i = 0; i < parents.Length(); ++i) {
+      nsPrintfCString param(":parentguid%d_", i);
       clause.Param(param.get());
-      if (i < folders.Length() - 1) {
+      if (i < parents.Length() - 1) {
         clause.Str(",");
       }
     }
-    clause.Str(          "UNION ALL "
+    clause.Str(          ") "
+                         "UNION ALL "
                          "SELECT b2.id "
                          "FROM moz_bookmarks b2 "
                          "JOIN parents p ON b2.parent = p.id "
                          "WHERE b2.type = 2 "
                        ") "
                        "SELECT id FROM parents "
                      ")");
   }
@@ -2912,21 +2914,21 @@ nsNavHistory::BindQueryClauseParameters(
   // transitions
   const nsTArray<uint32_t>& transitions = aQuery->Transitions();
   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);
   }
 
-  // folders
-  const nsTArray<int64_t>& folders = aQuery->Folders();
-  for (uint32_t i = 0; i < folders.Length(); ++i) {
-    nsPrintfCString paramName("parent%d_", i);
-    rv = statement->BindInt64ByName(paramName, folders[i]);
+  // parents
+  const nsTArray<nsCString>& parents = aQuery->Parents();
+  for (uint32_t i = 0; i < parents.Length(); ++i) {
+    nsPrintfCString paramName("parentguid%d_", i);
+    rv = statement->BindUTF8StringByName(paramName, parents[i]);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 
 // nsNavHistory::ResultsAsList
@@ -3345,31 +3347,29 @@ nsNavHistory::QueryRowToResult(int64_t i
   RefPtr<nsNavHistoryQuery> queryObj = do_QueryObject(query);
   NS_ENSURE_STATE(queryObj);
   RefPtr<nsNavHistoryQueryOptions> optionsObj = do_QueryObject(options);
   NS_ENSURE_STATE(optionsObj);
   // If this failed the query does not parse correctly, let the error pass and
   // handle it later.
   if (NS_SUCCEEDED(rv)) {
     // Check if this is a folder shortcut, so we can take a faster path.
-    int64_t targetFolderId = GetSimpleBookmarksQueryFolder(queryObj, optionsObj);
-    if (targetFolderId) {
+    nsCString targetFolderGuid = GetSimpleBookmarksQueryParent(queryObj, optionsObj);
+    if (!targetFolderGuid.IsEmpty()) {
       nsNavBookmarks *bookmarks = nsNavBookmarks::GetBookmarksService();
       NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
 
-      rv = bookmarks->ResultNodeForContainer(targetFolderId, optionsObj,
+      rv = bookmarks->ResultNodeForContainer(targetFolderGuid, optionsObj,
                                              getter_AddRefs(resultNode));
       // If this failed the shortcut is pointing to nowhere, let the error pass
       // and handle it later.
       if (NS_SUCCEEDED(rv)) {
         // At this point the node is set up like a regular folder node. Here
         // we make the necessary change to make it a folder shortcut.
-        resultNode->GetAsFolder()->mTargetFolderItemId = targetFolderId;
         resultNode->mItemId = itemId;
-        nsAutoCString targetFolderGuid(resultNode->GetAsFolder()->mBookmarkGuid);
         resultNode->mBookmarkGuid = aBookmarkGuid;
         resultNode->GetAsFolder()->mTargetFolderGuid = targetFolderGuid;
 
         // Use the query item title, unless it's empty (in that case use the
         // concrete folder title).
         if (!aTitle.IsEmpty()) {
           resultNode->mTitle = aTitle;
         }
@@ -3624,53 +3624,53 @@ nsNavHistory::GetMonthYear(const PRExplo
     return;
   }
   CopyUTF16toUTF8(monthYear, aResult);
 }
 
 
 namespace {
 
-// GetSimpleBookmarksQueryFolder
+// GetSimpleBookmarksQueryParent
 //
 //    Determines if this is a simple bookmarks query for a
 //    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(const RefPtr<nsNavHistoryQuery>& aQuery,
+static nsCString
+GetSimpleBookmarksQueryParent(const RefPtr<nsNavHistoryQuery>& aQuery,
                               const RefPtr<nsNavHistoryQueryOptions>& aOptions)
 {
-  if (aQuery->Folders().Length() != 1)
-    return 0;
+  if (aQuery->Parents().Length() != 1)
+    return EmptyCString();
 
   bool hasIt;
   if (NS_SUCCEEDED(aQuery->GetHasBeginTime(&hasIt)) && hasIt)
-    return 0;
+    return EmptyCString();
   if (NS_SUCCEEDED(aQuery->GetHasEndTime(&hasIt)) && hasIt)
-    return 0;
+    return EmptyCString();
   if (!aQuery->Domain().IsVoid())
-    return 0;
+    return EmptyCString();
   if (aQuery->Uri())
-    return 0;
+    return EmptyCString();
   if (!aQuery->SearchTerms().IsEmpty())
-    return 0;
+    return EmptyCString();
   if (aQuery->Tags().Length() > 0)
-    return 0;
+    return EmptyCString();
   if (aOptions->MaxResults() > 0)
-    return 0;
+    return EmptyCString();
 
   // Don't care about onlyBookmarked flag, since specifying a bookmark
   // folder is inferring onlyBookmarked.
 
-  return aQuery->Folders()[0];
+  return aQuery->Parents()[0];
 }
 
 
 // ParseSearchTermsFromQuery
 //
 //    Construct an array of search terms from the given query.
 //    Within a query, all the terms are ANDed together.
 //
--- a/toolkit/components/places/nsNavHistory.h
+++ b/toolkit/components/places/nsNavHistory.h
@@ -60,16 +60,23 @@
 
 // The preference we watch to know when the mobile bookmarks folder is filled by
 // sync.
 #define MOBILE_BOOKMARKS_PREF "browser.bookmarks.showMobileBookmarks"
 
 // The guid of the mobile bookmarks virtual query.
 #define MOBILE_BOOKMARKS_VIRTUAL_GUID "mobile____v"
 
+#define ROOT_GUID "root________"
+#define MENU_ROOT_GUID "menu________"
+#define TOOLBAR_ROOT_GUID "toolbar_____"
+#define UNFILED_ROOT_GUID "unfiled_____"
+#define TAGS_ROOT_GUID "tags________"
+#define MOBILE_ROOT_GUID "mobile______"
+
 class nsIAutoCompleteController;
 class nsIEffectiveTLDService;
 class nsIIDNService;
 class nsNavHistory;
 class PlacesDecayFrecencyCallback;
 class PlacesSQLQueryBuilder;
 class QueryKeyValuePair;
 
--- a/toolkit/components/places/nsNavHistoryQuery.cpp
+++ b/toolkit/components/places/nsNavHistoryQuery.cpp
@@ -105,17 +105,17 @@ static void SetOptionsKeyUint32(const ns
 #define QUERYKEY_END_TIME "endTime"
 #define QUERYKEY_END_TIME_REFERENCE "endTimeRef"
 #define QUERYKEY_SEARCH_TERMS "terms"
 #define QUERYKEY_MIN_VISITS "minVisits"
 #define QUERYKEY_MAX_VISITS "maxVisits"
 #define QUERYKEY_ONLY_BOOKMARKED "onlyBookmarked"
 #define QUERYKEY_DOMAIN_IS_HOST "domainIsHost"
 #define QUERYKEY_DOMAIN "domain"
-#define QUERYKEY_FOLDER "folder"
+#define QUERYKEY_PARENT "parent"
 #define QUERYKEY_NOTANNOTATION "!annotation"
 #define QUERYKEY_ANNOTATION "annotation"
 #define QUERYKEY_URI "uri"
 #define QUERYKEY_GROUP "group"
 #define QUERYKEY_SORT "sort"
 #define QUERYKEY_SORTING_ANNOTATION "sortingAnnotation"
 #define QUERYKEY_RESULT_TYPE "type"
 #define QUERYKEY_EXCLUDE_ITEMS "excludeItems"
@@ -150,103 +150,16 @@ inline void AppendInt32(nsACString& str,
 }
 inline void AppendInt64(nsACString& str, int64_t i)
 {
   nsCString tmp;
   tmp.AppendInt(i);
   str.Append(tmp);
 }
 
-namespace PlacesFolderConversion {
-  #define PLACES_ROOT_FOLDER "PLACES_ROOT"
-  #define BOOKMARKS_MENU_FOLDER "BOOKMARKS_MENU"
-  #define TAGS_FOLDER "TAGS"
-  #define UNFILED_BOOKMARKS_FOLDER "UNFILED_BOOKMARKS"
-  #define TOOLBAR_FOLDER "TOOLBAR"
-  #define MOBILE_BOOKMARKS_FOLDER "MOBILE_BOOKMARKS"
-
-  /**
-   * Converts a folder name to a folder id.
-   *
-   * @param aName
-   *        The name of the folder to convert to a folder id.
-   * @returns the folder id if aName is a recognizable name, -1 otherwise.
-   */
-  inline int64_t DecodeFolder(const nsCString &aName)
-  {
-    nsNavBookmarks *bs = nsNavBookmarks::GetBookmarksService();
-    NS_ENSURE_TRUE(bs, false);
-    int64_t folderID = -1;
-
-    if (aName.EqualsLiteral(PLACES_ROOT_FOLDER))
-      (void)bs->GetPlacesRoot(&folderID);
-    else if (aName.EqualsLiteral(BOOKMARKS_MENU_FOLDER))
-      (void)bs->GetBookmarksMenuFolder(&folderID);
-    else if (aName.EqualsLiteral(TAGS_FOLDER))
-      (void)bs->GetTagsFolder(&folderID);
-    else if (aName.EqualsLiteral(UNFILED_BOOKMARKS_FOLDER))
-      (void)bs->GetUnfiledBookmarksFolder(&folderID);
-    else if (aName.EqualsLiteral(TOOLBAR_FOLDER))
-      (void)bs->GetToolbarFolder(&folderID);
-    else if (aName.EqualsLiteral(MOBILE_BOOKMARKS_FOLDER))
-      (void)bs->GetMobileFolder(&folderID);
-
-    return folderID;
-  }
-
-  /**
-   * Converts a folder id to a named constant, or a string representation of the
-   * folder id if there is no named constant for the folder, and appends it to
-   * aQuery.
-   *
-   * @param aQuery
-   *        The string to append the folder string to.  This is generally a
-   *        query string, but could really be anything.
-   * @param aFolderID
-   *        The folder ID to convert to the proper named constant.
-   */
-  inline nsresult AppendFolder(nsCString &aQuery, int64_t aFolderID)
-  {
-    nsNavBookmarks *bs = nsNavBookmarks::GetBookmarksService();
-    NS_ENSURE_STATE(bs);
-    int64_t folderID = -1;
-
-    if (NS_SUCCEEDED(bs->GetPlacesRoot(&folderID)) &&
-        aFolderID == folderID) {
-      aQuery.AppendLiteral(PLACES_ROOT_FOLDER);
-    }
-    else if (NS_SUCCEEDED(bs->GetBookmarksMenuFolder(&folderID)) &&
-             aFolderID == folderID) {
-      aQuery.AppendLiteral(BOOKMARKS_MENU_FOLDER);
-    }
-    else if (NS_SUCCEEDED(bs->GetTagsFolder(&folderID)) &&
-             aFolderID == folderID) {
-      aQuery.AppendLiteral(TAGS_FOLDER);
-    }
-    else if (NS_SUCCEEDED(bs->GetUnfiledBookmarksFolder(&folderID)) &&
-             aFolderID == folderID) {
-      aQuery.AppendLiteral(UNFILED_BOOKMARKS_FOLDER);
-    }
-    else if (NS_SUCCEEDED(bs->GetToolbarFolder(&folderID)) &&
-             aFolderID == folderID) {
-      aQuery.AppendLiteral(TOOLBAR_FOLDER);
-    }
-    else if (NS_SUCCEEDED(bs->GetMobileFolder(&folderID)) &&
-             aFolderID == folderID) {
-      aQuery.AppendLiteral(MOBILE_BOOKMARKS_FOLDER);
-    }
-    else {
-      // It wasn't one of our named constants, so just convert it to a string.
-      aQuery.AppendInt(aFolderID);
-    }
-
-    return NS_OK;
-  }
-} // namespace PlacesFolderConversion
-
 NS_IMETHODIMP
 nsNavHistory::QueryStringToQuery(const nsACString& aQueryString,
                                  nsINavHistoryQuery** _query,
                                  nsINavHistoryQueryOptions** _options)
 {
   NS_ENSURE_ARG_POINTER(_query);
   NS_ENSURE_ARG_POINTER(_options);
 
@@ -381,23 +294,22 @@ nsNavHistory::QueryToQueryString(nsINavH
     }
     const nsCString& annot = query->Annotation();
     nsAutoCString escaped;
     bool success = NS_Escape(annot, escaped, url_XAlphas);
     NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
     queryString.Append(escaped);
   }
 
-  // folders
-  const nsTArray<int64_t>& folders = query->Folders();
-  for (uint32_t i = 0; i < folders.Length(); ++i) {
+  // parents
+  const nsTArray<nsCString>& parents = query->Parents();
+  for (uint32_t i = 0; i < parents.Length(); ++i) {
     AppendAmpersandIfNonempty(queryString);
-    queryString += NS_LITERAL_CSTRING(QUERYKEY_FOLDER "=");
-    nsresult rv = PlacesFolderConversion::AppendFolder(queryString, folders[i]);
-    NS_ENSURE_SUCCESS(rv, rv);
+    queryString += NS_LITERAL_CSTRING(QUERYKEY_PARENT "=");
+    queryString += parents[i];
   }
 
   // tags
   const nsTArray<nsString>& tags = query->Tags();
   for (uint32_t i = 0; i < tags.Length(); ++i) {
     nsAutoCString escapedTag;
     if (!NS_Escape(NS_ConvertUTF16toUTF8(tags[i]), escapedTag, url_XAlphas))
       return NS_ERROR_OUT_OF_MEMORY;
@@ -547,17 +459,17 @@ nsNavHistory::TokensToQuery(const nsTArr
                             nsNavHistoryQuery* aQuery,
                             nsNavHistoryQueryOptions* aOptions)
 {
   nsresult rv;
 
   if (aTokens.Length() == 0)
     return NS_OK;
 
-  nsTArray<int64_t> folders;
+  nsTArray<nsCString> parents;
   nsTArray<nsString> tags;
   nsTArray<uint32_t> transitions;
   for (uint32_t i = 0; i < aTokens.Length(); i ++) {
     const QueryKeyValuePair& kvp = aTokens[i];
 
     // begin time
     if (kvp.key.EqualsLiteral(QUERYKEY_BEGIN_TIME)) {
       SetQueryKeyInt64(kvp.value, aQuery, &nsINavHistoryQuery::SetBeginTime);
@@ -607,30 +519,21 @@ nsNavHistory::TokensToQuery(const nsTArr
 
     // domain string
     } else if (kvp.key.EqualsLiteral(QUERYKEY_DOMAIN)) {
       nsAutoCString unescapedDomain(kvp.value);
       NS_UnescapeURL(unescapedDomain); // modifies input
       rv = aQuery->SetDomain(unescapedDomain);
       NS_ENSURE_SUCCESS(rv, rv);
 
-    // folders
-    } else if (kvp.key.EqualsLiteral(QUERYKEY_FOLDER)) {
-      int64_t folder;
-      if (PR_sscanf(kvp.value.get(), "%lld", &folder) == 1) {
-        NS_ENSURE_TRUE(folders.AppendElement(folder), NS_ERROR_OUT_OF_MEMORY);
-      } else {
-        folder = PlacesFolderConversion::DecodeFolder(kvp.value);
-        if (folder != -1)
-          NS_ENSURE_TRUE(folders.AppendElement(folder), NS_ERROR_OUT_OF_MEMORY);
-        else
-          NS_WARNING("folders value in query is invalid, ignoring");
-      }
+    // parent folders (guids)
+    } else if (kvp.key.EqualsLiteral(QUERYKEY_PARENT)) {
+      NS_ENSURE_TRUE(parents.AppendElement(kvp.value), NS_ERROR_OUT_OF_MEMORY);
 
-    // uri
+     // uri
     } else if (kvp.key.EqualsLiteral(QUERYKEY_URI)) {
       nsAutoCString unescapedUri(kvp.value);
       NS_UnescapeURL(unescapedUri); // modifies input
       nsCOMPtr<nsIURI> uri;
       nsresult rv = NS_NewURI(getter_AddRefs(uri), unescapedUri);
       if (NS_FAILED(rv)) {
         NS_WARNING("Unable to parse URI");
       }
@@ -728,18 +631,20 @@ nsNavHistory::TokensToQuery(const nsTArr
                         &nsINavHistoryQueryOptions::SetAsyncEnabled);
     // unknown key
     } else {
       NS_WARNING("TokensToQueries(), ignoring unknown key: ");
       NS_WARNING(kvp.key.get());
     }
   }
 
-  if (folders.Length() != 0)
-    aQuery->SetFolders(folders.Elements(), folders.Length());
+  if (parents.Length() != 0) {
+    rv = aQuery->SetParents(parents);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   if (tags.Length() > 0) {
     rv = aQuery->SetTags(tags);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (transitions.Length() > 0) {
     rv = aQuery->SetTransitions(transitions);
@@ -794,17 +699,17 @@ nsNavHistoryQuery::nsNavHistoryQuery()
 nsNavHistoryQuery::nsNavHistoryQuery(const nsNavHistoryQuery& aOther)
   : mMinVisits(aOther.mMinVisits), mMaxVisits(aOther.mMaxVisits),
     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),
-    mFolders(aOther.mFolders),
+    mParents(aOther.mParents),
     mTags(aOther.mTags), mTagsAreNot(aOther.mTagsAreNot),
     mTransitions(aOther.mTransitions)
 {
 }
 
 NS_IMETHODIMP nsNavHistoryQuery::GetBeginTime(PRTime *aBeginTime)
 {
   *aBeginTime = mBeginTime;
@@ -1126,47 +1031,49 @@ NS_IMETHODIMP nsNavHistoryQuery::GetTags
 }
 
 NS_IMETHODIMP nsNavHistoryQuery::SetTagsAreNot(bool aTagsAreNot)
 {
   mTagsAreNot = aTagsAreNot;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsNavHistoryQuery::GetFolders(uint32_t *aCount,
-                                            int64_t **aFolders)
+NS_IMETHODIMP nsNavHistoryQuery::GetParents(uint32_t *aGuidCount,
+                                            char ***aGuids)
 {
-  uint32_t count = mFolders.Length();
-  int64_t *folders = nullptr;
+  uint32_t count = mParents.Length();
+  char **guids = nullptr;
   if (count > 0) {
-    folders = static_cast<int64_t*>
-                         (moz_xmalloc(count * sizeof(int64_t)));
-    NS_ENSURE_TRUE(folders, NS_ERROR_OUT_OF_MEMORY);
+    guids = static_cast<char**>
+                       (moz_xmalloc(count * sizeof(char*)));
+    NS_ENSURE_TRUE(guids, NS_ERROR_OUT_OF_MEMORY);
 
     for (uint32_t i = 0; i < count; ++i) {
-      folders[i] = mFolders[i];
+      guids[i] = ToNewCString(mParents[i]);
     }
   }
-  *aCount = count;
-  *aFolders = folders;
+  *aGuidCount = count;
+  *aGuids = guids;
   return NS_OK;
 }
 
-NS_IMETHODIMP nsNavHistoryQuery::GetFolderCount(uint32_t *aCount)
+NS_IMETHODIMP nsNavHistoryQuery::GetParentCount(uint32_t *aGuidCount)
 {
-  *aCount = mFolders.Length();
+  *aGuidCount = mParents.Length();
   return NS_OK;
 }
 
-NS_IMETHODIMP nsNavHistoryQuery::SetFolders(const int64_t *aFolders,
-                                            uint32_t aFolderCount)
+NS_IMETHODIMP nsNavHistoryQuery::SetParents(const char** aGuids,
+                                            uint32_t aGuidCount)
 {
-  if (!mFolders.ReplaceElementsAt(0, mFolders.Length(),
-                                  aFolders, aFolderCount)) {
-    return NS_ERROR_OUT_OF_MEMORY;
+  mParents.Clear();
+  for (size_t i = 0; i < aGuidCount; i++) {
+    if (!mParents.AppendElement(aGuids[i])) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsNavHistoryQuery::GetTransitions(uint32_t* aCount,
                                                 uint32_t** aTransitions)
 {
--- a/toolkit/components/places/nsNavHistoryQuery.h
+++ b/toolkit/components/places/nsNavHistoryQuery.h
@@ -40,17 +40,24 @@ public:
   uint32_t EndTimeReference() { return mEndTimeReference; }
   const nsString& SearchTerms() { return mSearchTerms; }
   bool OnlyBookmarked() { return mOnlyBookmarked; }
   bool DomainIsHost() { return mDomainIsHost; }
   const nsCString& Domain() { return mDomain; }
   nsIURI* Uri() { return mUri; } // NOT AddRef-ed!
   bool AnnotationIsNot() { return mAnnotationIsNot; }
   const nsCString& Annotation() { return mAnnotation; }
-  const nsTArray<int64_t>& Folders() const { return mFolders; }
+  const nsTArray<nsCString>& Parents() { return mParents; }
+  nsresult SetParents(const nsTArray<nsCString>& aParents)
+  {
+    if (!mParents.ReplaceElementsAt(0, mParents.Length(), aParents))
+      return NS_ERROR_OUT_OF_MEMORY;
+    return NS_OK;
+  }
+
   const nsTArray<nsString>& Tags() const { return mTags; }
   nsresult SetTags(const nsTArray<nsString>& aTags)
   {
     if (!mTags.ReplaceElementsAt(0, mTags.Length(), aTags))
       return NS_ERROR_OUT_OF_MEMORY;
     return NS_OK;
   }
   bool TagsAreNot() { return mTagsAreNot; }
@@ -80,17 +87,17 @@ protected:
   uint32_t mEndTimeReference;
   nsString mSearchTerms;
   bool mOnlyBookmarked;
   bool mDomainIsHost;
   nsCString mDomain; // Default is IsVoid, empty string is valid query
   nsCOMPtr<nsIURI> mUri;
   bool mAnnotationIsNot;
   nsCString mAnnotation;
-  nsTArray<int64_t> mFolders;
+  nsTArray<nsCString> mParents;
   nsTArray<nsString> mTags;
   bool mTagsAreNot;
   nsTArray<uint32_t> mTransitions;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryQuery, NS_NAVHISTORYQUERY_IID)
 
 // nsNavHistoryQueryOptions
--- a/toolkit/components/places/nsNavHistoryResult.cpp
+++ b/toolkit/components/places/nsNavHistoryResult.cpp
@@ -94,17 +94,17 @@ getUpdateRequirements(const RefPtr<nsNav
                       bool* aHasSearchTerms)
 {
   // first check if there are search terms
   bool hasSearchTerms = *aHasSearchTerms = !aQuery->SearchTerms().IsEmpty();
 
   bool nonTimeBasedItems = false;
   bool domainBasedItems = false;
 
-  if (aQuery->Folders().Length() > 0 ||
+  if (aQuery->Parents().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
@@ -3213,24 +3213,24 @@ nsNavHistoryFolderResultNode::GetUri(nsA
 
 /**
  * @return the queries that give you this bookmarks folder
  */
 NS_IMETHODIMP
 nsNavHistoryFolderResultNode::GetQuery(nsINavHistoryQuery** _query)
 {
   // get the query object
-  nsCOMPtr<nsINavHistoryQuery> query;
-  nsNavHistory* history = nsNavHistory::GetHistoryService();
-  NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
-  nsresult rv = history->GetNewQuery(getter_AddRefs(query));
-  NS_ENSURE_SUCCESS(rv, rv);
-
+  RefPtr<nsNavHistoryQuery> query = new nsNavHistoryQuery();
+
+  nsTArray<nsCString> parents;
   // query just has the folder ID set and nothing else
-  rv = query->SetFolders(&mTargetFolderItemId, 1);
+  if (!parents.AppendElement(mTargetFolderGuid)) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  nsresult rv = query->SetParents(parents);
   NS_ENSURE_SUCCESS(rv, rv);
 
   query.forget(_query);
   return NS_OK;
 }
 
 
 /**
@@ -3673,17 +3673,17 @@ nsNavHistoryFolderResultNode::OnItemAdde
     nsNavHistory* history = nsNavHistory::GetHistoryService();
     NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
     rv = history->BookmarkIdToResultNode(aItemId, mOptions, getter_AddRefs(node));
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else if (aItemType == nsINavBookmarksService::TYPE_FOLDER) {
     nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
     NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
-    rv = bookmarks->ResultNodeForContainer(aItemId,
+    rv = bookmarks->ResultNodeForContainer(PromiseFlatCString(aGUID),
                                            new nsNavHistoryQueryOptions(),
                                            getter_AddRefs(node));
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else if (aItemType == nsINavBookmarksService::TYPE_SEPARATOR) {
     node = new nsNavHistorySeparatorResultNode();
     node->mItemId = aItemId;
     node->mBookmarkGuid = aGUID;
--- a/toolkit/components/places/tests/queries/test_queryMultipleFolder.js
+++ b/toolkit/components/places/tests/queries/test_queryMultipleFolder.js
@@ -1,58 +1,96 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-add_task(async function test_queryMultipleFolders() {
+var folderIds = [];
+var folderGuids = [];
+var bookmarkGuids = [];
+
+add_task(async function setup() {
   // adding bookmarks in the folders
-  let folderIds = [];
-  let bookmarkIds = [];
   for (let i = 0; i < 3; ++i) {
     let folder = await PlacesUtils.bookmarks.insert({
       parentGuid: PlacesUtils.bookmarks.menuGuid,
       type: PlacesUtils.bookmarks.TYPE_FOLDER,
       title: `Folder${i}`
     });
+    folderGuids.push(folder.guid);
     folderIds.push(await PlacesUtils.promiseItemId(folder.guid));
 
     for (let j = 0; j < 7; ++j) {
       let bm = await PlacesUtils.bookmarks.insert({
         parentGuid: (await PlacesUtils.promiseItemGuid(folderIds[i])),
         url: `http://Bookmark${i}_${j}.com`,
         title: ""
       });
-      bookmarkIds.push(await PlacesUtils.promiseItemId(bm.guid));
+      bookmarkGuids.push(bm.guid);
     }
   }
+});
 
+add_task(async function test_queryMultipleFolders_ids() {
   // using queryStringToQuery
   let query = {}, options = {};
   let maxResults = 20;
   let queryString = `place:${folderIds.map((id) => "folder=" + id).join("&")}&sort=5&maxResults=${maxResults}`;
   PlacesUtils.history.queryStringToQuery(queryString, query, options);
   let rootNode = PlacesUtils.history.executeQuery(query.value, options.value).root;
   rootNode.containerOpen = true;
   let resultLength = rootNode.childCount;
   Assert.equal(resultLength, maxResults);
   for (let i = 0; i < resultLength; ++i) {
     let node = rootNode.getChild(i);
-    Assert.equal(bookmarkIds[i], node.itemId, node.uri);
+    Assert.equal(bookmarkGuids[i], node.bookmarkGuid, node.uri);
   }
   rootNode.containerOpen = false;
 
   // using getNewQuery and getNewQueryOptions
   query = PlacesUtils.history.getNewQuery();
   options = PlacesUtils.history.getNewQueryOptions();
   query.setFolders(folderIds, folderIds.length);
   options.sortingMode = options.SORT_BY_URI_ASCENDING;
   options.maxResults = maxResults;
   rootNode = PlacesUtils.history.executeQuery(query, options).root;
   rootNode.containerOpen = true;
   resultLength = rootNode.childCount;
   Assert.equal(resultLength, maxResults);
   for (let i = 0; i < resultLength; ++i) {
     let node = rootNode.getChild(i);
-    Assert.equal(bookmarkIds[i], node.itemId, node.uri);
+    Assert.equal(bookmarkGuids[i], node.bookmarkGuid, node.uri);
   }
   rootNode.containerOpen = false;
 });
+
+add_task(async function test_queryMultipleFolders_guids() {
+  // using queryStringToQuery
+  let query = {}, options = {};
+  let maxResults = 20;
+  let queryString = `place:${folderGuids.map((guid) => "parent=" + guid).join("&")}&sort=5&maxResults=${maxResults}`;
+  PlacesUtils.history.queryStringToQuery(queryString, query, options);
+  let rootNode = PlacesUtils.history.executeQuery(query.value, options.value).root;
+  rootNode.containerOpen = true;
+  let resultLength = rootNode.childCount;
+  Assert.equal(resultLength, maxResults);
+  for (let i = 0; i < resultLength; ++i) {
+    let node = rootNode.getChild(i);
+    Assert.equal(bookmarkGuids[i], node.bookmarkGuid, node.uri);
+  }
+  rootNode.containerOpen = false;
+
+  // using getNewQuery and getNewQueryOptions
+  query = PlacesUtils.history.getNewQuery();
+  options = PlacesUtils.history.getNewQueryOptions();
+  query.setParents(folderGuids, folderGuids.length);
+  options.sortingMode = options.SORT_BY_URI_ASCENDING;
+  options.maxResults = maxResults;
+  rootNode = PlacesUtils.history.executeQuery(query, options).root;
+  rootNode.containerOpen = true;
+  resultLength = rootNode.childCount;
+  Assert.equal(resultLength, maxResults);
+  for (let i = 0; i < resultLength; ++i) {
+    let node = rootNode.getChild(i);
+    Assert.equal(bookmarkGuids[i], node.bookmarkGuid, node.uri);
+  }
+  rootNode.containerOpen = false;
+});