From 5111b3ed301a95f6b4cbf7734f9579733f5bdc93 Mon Sep 17 00:00:00 2001 From: casey langen Date: Fri, 1 Dec 2017 00:31:54 -0800 Subject: [PATCH] SQL WHERE IN(...) does not preserve order, meaning certain playlist operations could result in jumbled track orders. This fixes that by eating some extra memory temporarily. --- src/core/library/LocalSimpleDataProvider.cpp | 22 +++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/core/library/LocalSimpleDataProvider.cpp b/src/core/library/LocalSimpleDataProvider.cpp index 59f4d96d0..3b8ff9b7c 100644 --- a/src/core/library/LocalSimpleDataProvider.cpp +++ b/src/core/library/LocalSimpleDataProvider.cpp @@ -91,7 +91,7 @@ class ExternalIdListToTrackListQuery : public TrackListQueryBase { protected: virtual bool OnRun(musik::core::db::Connection& db) { - std::string sql = "SELECT id FROM tracks WHERE external_id IN("; + std::string sql = "SELECT id, external_id FROM tracks WHERE external_id IN("; for (size_t i = 0; i < externalIdCount; i++) { sql += (i == 0) ? "?" : ",?"; } @@ -103,10 +103,26 @@ class ExternalIdListToTrackListQuery : public TrackListQueryBase { query.BindText(i, externalIds[i]); } - this->result = std::make_shared(this->library); + /* gotta eat up some memory to preserve the input order. map the + external id to the id so we can ensure we return the list in the + same order it was requested. this is faster than executing one + query per ID (we do this because WHERE IN() does not preserve input + ordering... */ + struct Record { int64_t id; std::string externalId; }; + std::map records; while (query.Step() == Row) { - result->Add(query.ColumnInt64(0)); + records[query.ColumnText(1)] = query.ColumnInt64(0); + } + + /* order the output here... */ + this->result = std::make_shared(this->library); + auto end = records.end(); + for (size_t i = 0; i < externalIdCount; i++) { + auto r = records.find(externalIds[i]); + if (r != end) { + this->result->Add(r->second); + } } return true;