@@ -458,30 +458,35 @@ void BaseTrackCache::filterAndSort(const QSet<TrackId>& trackIds,
458458 buildIndex ();
459459 }
460460
461+ // The id string we need for our QSqlQuery
461462 QStringList idStrings;
463+ // The id set we need for removing/adding dirty tracks
464+ QSet<TrackId> ids;
462465 // TODO(rryan) consider making this the data passed in and a separate
463466 // QVector for output
464467 QSet<TrackId> dirtyTracks;
465- for (const auto & trackId: trackIds) {
468+ for (const auto & trackId : trackIds) {
466469 idStrings << trackId.toString ();
470+ ids << trackId;
467471 if (m_dirtyTracks.contains (trackId)) {
468472 dirtyTracks.insert (trackId);
469473 }
470474 }
471475
472- QStringList queryFragments;
473- if (!extraFilter.isNull () && extraFilter != " " ) {
474- queryFragments << QString (" (%1)" ).arg (extraFilter);
475- }
476- if (idStrings.size () > 0 ) {
477- queryFragments << QString (" %1 in (%2)" )
478- .arg (m_idColumn, idStrings.join (" ," ));
476+ // Note: don't use the extraFilter for m_pQueryParser->parseQuery(), just
477+ // append it to searchQuery if not empty and let the parser construct
478+ // a SQL query from it.
479+ // The issue with the extraFilter is that the parser is assuming the input
480+ // is a SQL string and creates a SqlNode from it, and the issue with that is
481+ // that SqlNode::match(TrackPointer) always returns true -- which leads to
482+ // false positive matches when we iterate over the dirty tracks below.
483+ QString searchPlusExtraFilter = searchQuery;
484+ if (!extraFilter.isEmpty ()) {
485+ searchPlusExtraFilter += ' ' ;
486+ searchPlusExtraFilter += extraFilter;
479487 }
480-
481488 const std::unique_ptr<QueryNode> pQuery =
482- m_pQueryParser->parseQuery (
483- searchQuery,
484- queryFragments.join (" AND " ));
489+ m_pQueryParser->parseQuery (searchPlusExtraFilter, QString ());
485490
486491 QString filter = pQuery->toSql ();
487492 if (!filter.isEmpty ()) {
@@ -539,18 +544,20 @@ void BaseTrackCache::filterAndSort(const QSet<TrackId>& trackIds,
539544 }
540545
541546 for (TrackId trackId : std::as_const (dirtyTracks)) {
542- // Only get the track if it is in the cache. Tracks that
543- // are not cached in memory cannot be dirty.
547+ // Only get the track if it is in the cache.
548+ // Tracks that are not cached in memory cannot be dirty.
544549 // Bypass getCachedTrack() to not invalidate m_recentTrackId
545550 TrackPointer pTrack = GlobalTrackCacheLocker ().lookupTrackById (trackId);
546551 if (!pTrack) {
547552 continue ;
548553 }
549554
550- // The track should be in the result set if the search is empty or the
551- // track matches the search.
552- bool shouldBeInResultSet = searchQuery.isEmpty () ||
553- pQuery->match (pTrack);
555+ // The track should be in the result set if
556+ // the search and extra filter are empty
557+ // or
558+ // the track matches the search and ids (if not empty) contains its id
559+ bool shouldBeInResultSet = searchPlusExtraFilter.isEmpty () ||
560+ ((ids.isEmpty () || ids.contains (trackId)) && pQuery->match (pTrack));
554561
555562 // If the track is in this result set.
556563 bool isInResultSet = trackToIndex->contains (trackId);
0 commit comments