Make CollectionQuery subclass QSqlQuery, don't copy QSqlQuery
This commit is contained in:
parent
0c4edc4d17
commit
5a58ac2845
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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]; }
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue