Make CollectionQuery subclass QSqlQuery, don't copy QSqlQuery

This commit is contained in:
Jonas Kvinge 2021-04-10 03:20:25 +02:00
parent 0c4edc4d17
commit 5a58ac2845
11 changed files with 187 additions and 115 deletions

View File

@ -612,12 +612,14 @@ void CollectionBackend::MarkSongsUnavailable(const SongList &songs, const bool u
QStringList CollectionBackend::GetAll(const QString &column, const QueryOptions &opt) {
CollectionQuery query(opt);
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
CollectionQuery query(db, songs_table_, fts_table_, opt);
query.SetColumnSpec("DISTINCT " + column);
query.AddCompilationRequirement(false);
QMutexLocker l(db_->Mutex());
if (!ExecQuery(&query)) return QStringList();
if (!query.Exec()) return QStringList();
QStringList ret;
while (query.Next()) {
@ -634,24 +636,24 @@ QStringList CollectionBackend::GetAllArtists(const QueryOptions &opt) {
QStringList CollectionBackend::GetAllArtistsWithAlbums(const QueryOptions &opt) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
// Albums with 'albumartist' field set:
CollectionQuery query(opt);
CollectionQuery query(db, songs_table_, fts_table_, opt);
query.SetColumnSpec("DISTINCT albumartist");
query.AddCompilationRequirement(false);
query.AddWhere("album", "", "!=");
// Albums with no 'albumartist' (extract 'artist'):
CollectionQuery query2(opt);
CollectionQuery query2(db, songs_table_, fts_table_, opt);
query2.SetColumnSpec("DISTINCT artist");
query2.AddCompilationRequirement(false);
query2.AddWhere("album", "", "!=");
query2.AddWhere("albumartist", "", "=");
{
QMutexLocker l(db_->Mutex());
if (!ExecQuery(&query) || !ExecQuery(&query2)) {
return QStringList();
}
if (!query.Exec() || !query2.Exec()) {
return QStringList();
}
QSet<QString> artists;
@ -677,28 +679,40 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbumsByArtist(const QString
SongList CollectionBackend::GetArtistSongs(const QString &effective_albumartist, const QueryOptions &opt) {
CollectionQuery query(opt);
QSqlDatabase db(db_->Connect());
QMutexLocker l(db_->Mutex());
CollectionQuery query(db, songs_table_, fts_table_, opt);
query.AddCompilationRequirement(false);
query.AddWhere("effective_albumartist", effective_albumartist);
return ExecCollectionQuery(&query);
}
SongList CollectionBackend::GetAlbumSongs(const QString &effective_albumartist, const QString &album, const QueryOptions &opt) {
CollectionQuery query(opt);
QSqlDatabase db(db_->Connect());
QMutexLocker l(db_->Mutex());
CollectionQuery query(db, songs_table_, fts_table_, opt);
query.AddCompilationRequirement(false);
query.AddWhere("effective_albumartist", effective_albumartist);
query.AddWhere("album", album);
return ExecCollectionQuery(&query);
}
SongList CollectionBackend::GetSongsByAlbum(const QString &album, const QueryOptions &opt) {
CollectionQuery query(opt);
QSqlDatabase db(db_->Connect());
QMutexLocker l(db_->Mutex());
CollectionQuery query(db, songs_table_, fts_table_, opt);
query.AddCompilationRequirement(false);
query.AddWhere("album", album);
return ExecCollectionQuery(&query);
}
@ -706,8 +720,8 @@ SongList CollectionBackend::GetSongsByAlbum(const QString &album, const QueryOpt
SongList CollectionBackend::ExecCollectionQuery(CollectionQuery *query) {
query->SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
QMutexLocker l(db_->Mutex());
if (!ExecQuery(query)) return SongList();
if (!query->Exec()) return SongList();
SongList ret;
while (query->Next()) {
@ -720,12 +734,15 @@ SongList CollectionBackend::ExecCollectionQuery(CollectionQuery *query) {
}
Song CollectionBackend::GetSongById(const int id) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
return GetSongById(id, db);
}
SongList CollectionBackend::GetSongsById(const QList<int> &ids) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
@ -735,13 +752,16 @@ SongList CollectionBackend::GetSongsById(const QList<int> &ids) {
}
return GetSongsById(str_ids, db);
}
SongList CollectionBackend::GetSongsById(const QStringList &ids) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
return GetSongsById(ids, db);
}
SongList CollectionBackend::GetSongsByForeignId(const QStringList &ids, const QString &table, const QString &column) {
@ -769,9 +789,11 @@ SongList CollectionBackend::GetSongsByForeignId(const QStringList &ids, const QS
}
Song CollectionBackend::GetSongById(const int id, QSqlDatabase &db) {
SongList list = GetSongsById(QStringList() << QString::number(id), db);
if (list.isEmpty()) return Song();
return list.first();
}
SongList CollectionBackend::GetSongsById(const QStringList &ids, QSqlDatabase &db) {
@ -897,13 +919,15 @@ CollectionBackend::AlbumList CollectionBackend::GetCompilationAlbums(const Query
SongList CollectionBackend::GetCompilationSongs(const QString &album, const QueryOptions &opt) {
CollectionQuery query(opt);
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
CollectionQuery query(db, songs_table_, fts_table_, opt);
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
query.AddCompilationRequirement(true);
query.AddWhere("album", album);
QMutexLocker l(db_->Mutex());
if (!ExecQuery(&query)) return SongList();
if (!query.Exec()) return SongList();
SongList ret;
while (query.Next()) {
@ -1022,7 +1046,10 @@ void CollectionBackend::UpdateCompilations(QSqlQuery &find_song, QSqlQuery &upda
CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist, const bool compilation_required, const QueryOptions &opt) {
CollectionQuery query(opt);
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
CollectionQuery query(db, songs_table_, fts_table_, opt);
query.SetColumnSpec("url, effective_albumartist, album, compilation_effective, art_automatic, art_manual, filetype, cue_path");
query.SetOrderBy("effective_albumartist, album, url");
@ -1034,10 +1061,7 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist,
query.AddWhere("effective_albumartist", artist);
}
{
QMutexLocker l(db_->Mutex());
if (!ExecQuery(&query)) return AlbumList();
}
if (!query.Exec()) return AlbumList();
QMap<QString, Album> albums;
while (query.Next()) {
@ -1100,19 +1124,21 @@ CollectionBackend::AlbumList CollectionBackend::GetAlbums(const QString &artist,
CollectionBackend::Album CollectionBackend::GetAlbumArt(const QString &effective_albumartist, const QString &album) {
QMutexLocker l(db_->Mutex());
QSqlDatabase db(db_->Connect());
Album ret;
ret.album = album;
ret.album_artist = effective_albumartist;
CollectionQuery query = CollectionQuery(QueryOptions());
CollectionQuery query(db, songs_table_, fts_table_, QueryOptions());
query.SetColumnSpec("art_automatic, art_manual, url");
if (!effective_albumartist.isEmpty()) {
query.AddWhere("effective_albumartist", effective_albumartist);
}
query.AddWhere("album", album);
QMutexLocker l(db_->Mutex());
if (!ExecQuery(&query)) return ret;
if (!query.Exec()) return ret;
if (query.Next()) {
ret.art_automatic = QUrl::fromEncoded(query.Value(0).toByteArray());
@ -1136,12 +1162,12 @@ void CollectionBackend::UpdateManualAlbumArt(const QString &effective_albumartis
QSqlDatabase db(db_->Connect());
// Get the songs before they're updated
CollectionQuery query;
CollectionQuery query(db, songs_table_, fts_table_);
query.SetColumnSpec("ROWID, " + Song::kColumnSpec);
query.AddWhere("effective_albumartist", effective_albumartist);
query.AddWhere("album", album);
if (!ExecQuery(&query)) return;
if (!query.Exec()) return;
SongList deleted_songs;
while (query.Next()) {
@ -1167,7 +1193,7 @@ void CollectionBackend::UpdateManualAlbumArt(const QString &effective_albumartis
db_->CheckErrors(q);
// Now get the updated songs
if (!ExecQuery(&query)) return;
if (!query.Exec()) return;
SongList added_songs;
while (query.Next()) {
@ -1195,12 +1221,12 @@ void CollectionBackend::UpdateAutomaticAlbumArt(const QString &effective_albumar
QSqlDatabase db(db_->Connect());
// Get the songs before they're updated
CollectionQuery query;
CollectionQuery query(db, songs_table_, fts_table_);
query.SetColumnSpec("ROWID, " + Song::kColumnSpec);
query.AddWhere("effective_albumartist", effective_albumartist);
query.AddWhere("album", album);
if (!ExecQuery(&query)) return;
if (!query.Exec()) return;
SongList deleted_songs;
while (query.Next()) {
@ -1222,7 +1248,7 @@ void CollectionBackend::UpdateAutomaticAlbumArt(const QString &effective_albumar
db_->CheckErrors(q);
// Now get the updated songs
if (!ExecQuery(&query)) return;
if (!query.Exec()) return;
SongList added_songs;
while (query.Next()) {
@ -1246,12 +1272,12 @@ void CollectionBackend::ForceCompilation(const QString &album, const QList<QStri
for (const QString &artist : artists) {
// Get the songs before they're updated
CollectionQuery query;
CollectionQuery query(db, songs_table_, fts_table_);
query.SetColumnSpec("ROWID, " + Song::kColumnSpec);
query.AddWhere("album", album);
if (!artist.isEmpty()) query.AddWhere("artist", artist);
if (!ExecQuery(&query)) return;
if (!query.Exec()) return;
while (query.Next()) {
Song song(source_);
@ -1274,7 +1300,7 @@ void CollectionBackend::ForceCompilation(const QString &album, const QList<QStri
db_->CheckErrors(q);
// Now get the updated songs
if (!ExecQuery(&query)) return;
if (!query.Exec()) return;
while (query.Next()) {
Song song(source_);
@ -1290,10 +1316,6 @@ void CollectionBackend::ForceCompilation(const QString &album, const QList<QStri
}
bool CollectionBackend::ExecQuery(CollectionQuery *q) {
return !db_->CheckErrors(q->Exec(db_->Connect(), songs_table_, fts_table_));
}
void CollectionBackend::IncrementPlayCount(const int id) {
if (id == -1) return;

View File

@ -71,6 +71,9 @@ class CollectionBackendInterface : public QObject {
typedef QList<Album> AlbumList;
virtual QString songs_table() const = 0;
virtual QString fts_table() const = 0;
virtual Database *db() const = 0;
// Get a list of directories in the collection. Emits DirectoriesDiscovered.
virtual void LoadDirectoriesAsync() = 0;
@ -111,8 +114,6 @@ class CollectionBackendInterface : public QObject {
virtual void AddDirectory(const QString &path) = 0;
virtual void RemoveDirectory(const Directory &dir) = 0;
virtual bool ExecQuery(CollectionQuery *q) = 0;
};
class CollectionBackend : public CollectionBackendInterface {
@ -127,9 +128,10 @@ class CollectionBackend : public CollectionBackendInterface {
void ExitAsync();
Database *db() const { return db_; }
Database *db() const override { return db_; }
QString songs_table() const override { return songs_table_; }
QString fts_table() const override { return fts_table_; }
QString dirs_table() const { return dirs_table_; }
QString subdirs_table() const { return subdirs_table_; }
@ -174,7 +176,6 @@ class CollectionBackend : public CollectionBackendInterface {
void AddDirectory(const QString &path) override;
void RemoveDirectory(const Directory &dir) override;
bool ExecQuery(CollectionQuery *q) override;
SongList ExecCollectionQuery(CollectionQuery *query);
void IncrementPlayCountAsync(const int id);

View File

@ -815,14 +815,20 @@ QVariant CollectionModel::data(const CollectionItem *item, const int role) const
}
bool CollectionModel::HasCompilations(const CollectionQuery &query) {
bool CollectionModel::HasCompilations(const QSqlDatabase &db, const CollectionQuery &query) {
CollectionQuery q = query;
CollectionQuery q(db, backend_->songs_table(), backend_->fts_table(), query_options_);
q.SetColumnSpec(query.column_spec());
q.SetOrderBy(query.order_by());
q.SetWhereClauses(query.where_clauses());
q.SetBoundValues(query.bound_values());
q.SetIncludeUnavailable(query.include_unavailable());
q.SetDuplicatesOnly(query.duplicates_only());
q.AddCompilationRequirement(true);
q.SetLimit(1);
QMutexLocker l(backend_->db()->Mutex());
if (!backend_->ExecQuery(&q)) return false;
if (!q.Exec()) return false;
return q.Next();
@ -837,33 +843,39 @@ CollectionModel::QueryResult CollectionModel::RunQuery(CollectionItem *parent) {
GroupBy child_type = child_level >= 3 ? GroupBy_None : group_by_[child_level];
// Initialize the query. child_type says what type of thing we want (artists, songs, etc.)
CollectionQuery q(query_options_);
InitQuery(child_type, &q);
// Walk up through the item's parents adding filters as necessary
CollectionItem *p = parent;
while (p && p->type == CollectionItem::Type_Container) {
FilterQuery(group_by_[p->container_level], p, &q);
p = p->parent;
}
{
QMutexLocker l(backend_->db()->Mutex());
QSqlDatabase db(backend_->db()->Connect());
// Artists GroupBy is special - we don't want compilation albums appearing
if (IsArtistGroupBy(child_type)) {
// Add the special Various artists node
if (show_various_artists_ && HasCompilations(q)) {
result.create_va = true;
CollectionQuery q(db, backend_->songs_table(), backend_->fts_table(), query_options_);
InitQuery(child_type, &q);
// Walk up through the item's parents adding filters as necessary
CollectionItem *p = parent;
while (p && p->type == CollectionItem::Type_Container) {
FilterQuery(group_by_[p->container_level], p, &q);
p = p->parent;
}
// Don't show compilations again outside the Various artists node
q.AddCompilationRequirement(false);
}
// Artists GroupBy is special - we don't want compilation albums appearing
if (IsArtistGroupBy(child_type)) {
// Add the special Various artists node
if (show_various_artists_ && HasCompilations(db, q)) {
result.create_va = true;
}
// Execute the query
QMutexLocker l(backend_->db()->Mutex());
if (backend_->ExecQuery(&q)) {
while (q.Next()) {
result.rows << SqlRow(q);
// Don't show compilations again outside the Various artists node
q.AddCompilationRequirement(false);
}
// Execute the query
if (q.Exec()) {
while (q.Next()) {
result.rows << SqlRow(q);
}
}
}
if (QThread::currentThread() != thread() && QThread::currentThread() != backend_->thread()) {

View File

@ -239,7 +239,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
QueryResult RunQuery(CollectionItem *parent);
void PostQuery(CollectionItem *parent, const QueryResult &result, const bool signal);
bool HasCompilations(const CollectionQuery &query);
bool HasCompilations(const QSqlDatabase &db, const CollectionQuery &query);
void BeginReset();

View File

@ -31,14 +31,23 @@
#include <QRegularExpression>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include "core/logging.h"
#include "core/song.h"
#include "collectionquery.h"
#include "core/song.h"
QueryOptions::QueryOptions() : max_age_(-1), query_mode_(QueryMode_All) {}
CollectionQuery::CollectionQuery(const QueryOptions &options)
: include_unavailable_(false), join_with_fts_(false), limit_(-1) {
CollectionQuery::CollectionQuery(const QSqlDatabase &db, const QString &songs_table, const QString &fts_table, const QueryOptions &options) :
QSqlQuery(db),
songs_table_(songs_table),
fts_table_(fts_table),
include_unavailable_(false),
join_with_fts_(false),
duplicates_only_(false),
limit_(-1) {
if (!options.filter().isEmpty()) {
// We need to munge the filter text a little bit to get it to work as expected with sqlite's FTS5:
@ -98,7 +107,7 @@ CollectionQuery::CollectionQuery(const QueryOptions &options)
bound_values_ << cutoff;
}
// TODO: Currently you cannot use any QueryMode other than All and fts at the same time.
// TODO: Currently you cannot use any QueryMode other than All and FTS at the same time.
// Joining songs, duplicated_songs and songs_fts all together takes a huge amount of time.
// The query takes about 20 seconds on my machine then. Why?
// Untagged mode could work with additional filtering but I'm disabling it just to be consistent
@ -123,7 +132,7 @@ QString CollectionQuery::GetInnerQuery() {
void CollectionQuery::AddWhere(const QString &column, const QVariant &value, const QString &op) {
// ignore 'literal' for IN
// Ignore 'literal' for IN
if (!op.compare("IN", Qt::CaseInsensitive)) {
QStringList final;
for (const QString &single_value : value.toStringList()) {
@ -168,7 +177,7 @@ void CollectionQuery::AddWhereArtist(const QVariant &value) {
}
void CollectionQuery::AddCompilationRequirement(bool compilation) {
void CollectionQuery::AddCompilationRequirement(const bool compilation) {
// The unary + is added to prevent sqlite from using the index idx_comp_artist.
// When joining with fts, sqlite 3.8 has a tendency to use this index and thereby nesting the tables in an order which gives very poor performance
@ -176,15 +185,15 @@ void CollectionQuery::AddCompilationRequirement(bool compilation) {
}
QSqlQuery CollectionQuery::Exec(QSqlDatabase db, const QString &songs_table, const QString &fts_table) {
bool CollectionQuery::Exec() {
QString sql;
if (join_with_fts_) {
sql = QString("SELECT %1 FROM %2 INNER JOIN %3 AS fts ON %2.ROWID = fts.ROWID").arg(column_spec_, songs_table, fts_table);
sql = QString("SELECT %1 FROM %2 INNER JOIN %3 AS fts ON %2.ROWID = fts.ROWID").arg(column_spec_, songs_table_, fts_table_);
}
else {
sql = QString("SELECT %1 FROM %2 %3").arg(column_spec_, songs_table, GetInnerQuery());
sql = QString("SELECT %1 FROM %2 %3").arg(column_spec_, songs_table_, GetInnerQuery());
}
QStringList where_clauses(where_clauses_);
@ -198,31 +207,40 @@ QSqlQuery CollectionQuery::Exec(QSqlDatabase db, const QString &songs_table, con
if (limit_ != -1) sql += " LIMIT " + QString::number(limit_);
sql.replace("%songs_table", songs_table);
sql.replace("%fts_table_noprefix", fts_table.section('.', -1, -1));
sql.replace("%fts_table", fts_table);
sql.replace("%songs_table", songs_table_);
sql.replace("%fts_table_noprefix", fts_table_.section('.', -1, -1));
sql.replace("%fts_table", fts_table_);
query_ = QSqlQuery(db);
query_.prepare(sql);
prepare(sql);
// Bind values
for (const QVariant &value : bound_values_) {
query_.addBindValue(value);
addBindValue(value);
}
query_.exec();
return query_;
const bool result = exec();
if (!result) {
QSqlError last_error = lastError();
if (last_error.isValid()) {
qLog(Error) << "DB error: " << last_error;
qLog(Error) << "Faulty query: " << lastQuery();
qLog(Error) << "Bound values: " << boundValues();
}
}
return result;
}
bool CollectionQuery::Next() { return query_.next(); }
bool CollectionQuery::Next() { return next(); }
QVariant CollectionQuery::Value(int column) const { return query_.value(column); }
QVariant CollectionQuery::Value(const int column) const { return value(column); }
bool QueryOptions::Matches(const Song &song) const {
if (max_age_ != -1) {
const uint cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - max_age_;
const qint64 cutoff = QDateTime::currentDateTime().toSecsSinceEpoch() - max_age_;
if (song.ctime() <= cutoff) return false;
}

View File

@ -39,7 +39,7 @@ struct QueryOptions {
// - use the all songs table
// - use the duplicated songs view; by duplicated we mean those songs for which the (artist, album, title) tuple is found more than once in the songs table
// - use the untagged songs view; by untagged we mean those for which at least one of the (artist, album, title) tags is empty
// Please note that additional filtering based on fts table (the filter attribute) won't work in Duplicates and Untagged modes.
// Please note that additional filtering based on FTS table (the filter attribute) won't work in Duplicates and Untagged modes.
enum QueryMode {
QueryMode_All,
QueryMode_Duplicates,
@ -71,12 +71,13 @@ struct QueryOptions {
QueryMode query_mode_;
};
class CollectionQuery {
class CollectionQuery : public QSqlQuery {
public:
explicit CollectionQuery(const QueryOptions &options = QueryOptions());
explicit CollectionQuery(const QSqlDatabase &db, const QString &songs_table, const QString &fts_table, const QueryOptions &options = QueryOptions());
// Sets contents of SELECT clause on the query (list of columns to get).
void SetColumnSpec(const QString &spec) { column_spec_ = spec; }
// Sets an ORDER BY clause on the query.
void SetOrderBy(const QString &order_by) { order_by_ = order_by; }
@ -85,29 +86,42 @@ class CollectionQuery {
void AddWhere(const QString &column, const QVariant &value, const QString &op = "=");
void AddWhereArtist(const QVariant &value);
void AddCompilationRequirement(bool compilation);
void SetLimit(int limit) { limit_ = limit; }
void SetIncludeUnavailable(bool include_unavailable) { include_unavailable_ = include_unavailable; }
void SetWhereClauses(const QStringList &where_clauses) { where_clauses_ = where_clauses; }
void SetBoundValues(const QVariantList &bound_values) { bound_values_ = bound_values; }
void SetDuplicatesOnly(const bool duplicates_only) { duplicates_only_ = duplicates_only; }
void SetIncludeUnavailable(const bool include_unavailable) { include_unavailable_ = include_unavailable; }
void SetLimit(const int limit) { limit_ = limit; }
void AddCompilationRequirement(const bool compilation);
QSqlQuery Exec(QSqlDatabase db, const QString &songs_table, const QString &fts_table);
bool Exec();
bool Next();
QVariant Value(int column) const;
QVariant Value(const int column) const;
operator const QSqlQuery &() const { return query_; }
QString column_spec() const { return column_spec_; }
QString order_by() const { return order_by_; }
QStringList where_clauses() const { return where_clauses_; }
QVariantList bound_values() const { return bound_values_; }
bool include_unavailable() const { return include_unavailable_; }
bool join_with_fts() const { return join_with_fts_; }
bool duplicates_only() const { return duplicates_only_; }
int limit() const { return limit_; }
private:
QString GetInnerQuery();
bool include_unavailable_;
bool join_with_fts_;
QSqlDatabase db_;
QString songs_table_;
QString fts_table_;
QString column_spec_;
QString order_by_;
QStringList where_clauses_;
QVariantList bound_values_;
int limit_;
bool duplicates_only_;
QSqlQuery query_;
bool include_unavailable_;
bool join_with_fts_;
bool duplicates_only_;
int limit_;
};
#endif // COLLECTIONQUERY_H

View File

@ -30,8 +30,6 @@
SqlRow::SqlRow(const QSqlQuery &query) { Init(query); }
SqlRow::SqlRow(const CollectionQuery &query) { Init(query); }
void SqlRow::Init(const QSqlQuery &query) {
int rows = query.record().count();

View File

@ -32,9 +32,7 @@ class CollectionQuery;
class SqlRow {
public:
// WARNING: Implicit construction from QSqlQuery and CollectionQuery.
SqlRow(const QSqlQuery &query);
SqlRow(const CollectionQuery &query);
const QVariant &value(int i) const { return columns_[i]; }

View File

@ -249,8 +249,11 @@ QVariant ContextAlbumsModel::data(const CollectionItem *item, int role) const {
ContextAlbumsModel::QueryResult ContextAlbumsModel::RunQuery(CollectionItem *parent) {
QMutexLocker l(backend_->db()->Mutex());
QSqlDatabase db(backend_->db()->Connect());
QueryResult result;
CollectionQuery q(query_options_);
CollectionQuery q(db, backend_->songs_table(), backend_->fts_table(), query_options_);
q.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
// Walk up through the item's parents adding filters as necessary
@ -263,9 +266,7 @@ ContextAlbumsModel::QueryResult ContextAlbumsModel::RunQuery(CollectionItem *par
}
// Execute the query
QMutexLocker l(backend_->db()->Mutex());
if (!backend_->ExecQuery(&q)) return result;
if (!q.Exec()) return result;
while (q.Next()) {
result.rows << SqlRow(q);

View File

@ -52,6 +52,7 @@
#include "song.h"
#include "songloader.h"
#include "tagreaderclient.h"
#include "database.h"
#include "engine/enginetype.h"
#include "engine/enginebase.h"
#include "collection/collectionbackend.h"
@ -222,11 +223,14 @@ SongLoader::Result SongLoader::LoadLocal(const QString &filename) {
// Search in the database.
QUrl url = QUrl::fromLocalFile(filename);
CollectionQuery query;
QMutexLocker l(collection_->db()->Mutex());
QSqlDatabase db(collection_->db()->Connect());
CollectionQuery query(db, collection_->songs_table(), collection_->fts_table());
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
query.AddWhere("url", url.toEncoded());
if (collection_->ExecQuery(&query) && query.Next()) {
if (query.Exec() && query.Next()) {
// We may have many results when the file has many sections
do {
Song song(Song::Source_Collection);

View File

@ -70,6 +70,7 @@
#include "core/utilities.h"
#include "core/imageutils.h"
#include "core/tagreaderclient.h"
#include "core/database.h"
#include "widgets/forcescrollperpixel.h"
#include "widgets/qsearchfield.h"
#include "collection/sqlrow.h"
@ -888,7 +889,10 @@ SongList AlbumCoverManager::GetSongsInAlbum(const QModelIndex &idx) const {
SongList ret;
CollectionQuery q;
QMutexLocker l(collection_backend_->db()->Mutex());
QSqlDatabase db(collection_backend_->db()->Connect());
CollectionQuery q(db, collection_backend_->songs_table(), collection_backend_->fts_table());
q.SetColumnSpec("ROWID," + Song::kColumnSpec);
q.AddWhere("album", idx.data(Role_Album).toString());
q.SetOrderBy("disc, track, title");
@ -900,7 +904,7 @@ SongList AlbumCoverManager::GetSongsInAlbum(const QModelIndex &idx) const {
q.AddCompilationRequirement(albumartist.isEmpty());
if (!collection_backend_->ExecQuery(&q)) return ret;
if (!q.Exec()) return ret;
while (q.Next()) {
Song song;