Show error dialog for failed SQL queries
This commit is contained in:
@@ -217,6 +217,8 @@ Application::Application(QObject *parent)
|
||||
collection()->Init();
|
||||
tag_reader_client();
|
||||
|
||||
QObject::connect(database(), &Database::Error, this, &Application::ErrorAdded);
|
||||
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "taskmanager.h"
|
||||
#include "database.h"
|
||||
#include "application.h"
|
||||
#include "sqlquery.h"
|
||||
#include "scopedtransaction.h"
|
||||
|
||||
const char *Database::kDatabaseFilename = "strawberry.db";
|
||||
@@ -167,14 +168,14 @@ QSqlDatabase Database::Connect() {
|
||||
else qLog(Fatal) << "Unable to enable FTS3 tokenizer";
|
||||
}
|
||||
#endif
|
||||
QSqlQuery get_fts_tokenizer(db);
|
||||
SqlQuery get_fts_tokenizer(db);
|
||||
get_fts_tokenizer.prepare("SELECT fts3_tokenizer(:name)");
|
||||
get_fts_tokenizer.bindValue(":name", "unicode61");
|
||||
get_fts_tokenizer.BindValue(":name", "unicode61");
|
||||
if (get_fts_tokenizer.exec() && get_fts_tokenizer.next()) {
|
||||
QSqlQuery set_fts_tokenizer(db);
|
||||
SqlQuery set_fts_tokenizer(db);
|
||||
set_fts_tokenizer.prepare("SELECT fts3_tokenizer(:name, :pointer)");
|
||||
set_fts_tokenizer.bindValue(":name", "unicode");
|
||||
set_fts_tokenizer.bindValue(":pointer", get_fts_tokenizer.value(0));
|
||||
set_fts_tokenizer.BindValue(":name", "unicode");
|
||||
set_fts_tokenizer.BindValue(":pointer", get_fts_tokenizer.value(0));
|
||||
if (!set_fts_tokenizer.exec()) {
|
||||
qLog(Warning) << "Couldn't register FTS3 tokenizer : " << set_fts_tokenizer.lastError();
|
||||
}
|
||||
@@ -192,11 +193,11 @@ QSqlDatabase Database::Connect() {
|
||||
if (!injected_database_name_.isNull()) filename = injected_database_name_;
|
||||
|
||||
// Attach the db
|
||||
QSqlQuery q(db);
|
||||
SqlQuery q(db);
|
||||
q.prepare("ATTACH DATABASE :filename AS :alias");
|
||||
q.bindValue(":filename", filename);
|
||||
q.bindValue(":alias", key);
|
||||
if (!q.exec()) {
|
||||
q.BindValue(":filename", filename);
|
||||
q.BindValue(":alias", key);
|
||||
if (!q.Exec()) {
|
||||
qFatal("Couldn't attach external database '%s'", key.toLatin1().constData());
|
||||
}
|
||||
}
|
||||
@@ -212,9 +213,9 @@ QSqlDatabase Database::Connect() {
|
||||
continue;
|
||||
}
|
||||
// Find out if there are any tables in this database
|
||||
QSqlQuery q(db);
|
||||
SqlQuery q(db);
|
||||
q.prepare(QString("SELECT ROWID FROM %1.sqlite_master WHERE type='table'").arg(key));
|
||||
if (!q.exec() || !q.next()) {
|
||||
if (!q.Exec() || !q.next()) {
|
||||
q.finish();
|
||||
ExecSchemaCommandsFromFile(db, attached_databases_[key].schema_, 0);
|
||||
}
|
||||
@@ -249,9 +250,12 @@ int Database::SchemaVersion(QSqlDatabase *db) {
|
||||
// Get the database's schema version
|
||||
int schema_version = 0;
|
||||
{
|
||||
QSqlQuery q("SELECT version FROM schema_version", *db);
|
||||
if (q.next()) schema_version = q.value(0).toInt();
|
||||
// Implicit invocation of ~QSqlQuery() when leaving the scope to release any remaining database locks!
|
||||
SqlQuery q(*db);
|
||||
q.prepare("SELECT version FROM schema_version");
|
||||
if (q.Exec() && q.next()) {
|
||||
schema_version = q.value(0).toInt();
|
||||
}
|
||||
// Implicit invocation of ~SqlQuery() when leaving the scope to release any remaining database locks!
|
||||
}
|
||||
return schema_version;
|
||||
|
||||
@@ -287,10 +291,10 @@ void Database::RecreateAttachedDb(const QString &database_name) {
|
||||
{
|
||||
QSqlDatabase db(Connect());
|
||||
|
||||
QSqlQuery q(db);
|
||||
SqlQuery q(db);
|
||||
q.prepare("DETACH DATABASE :alias");
|
||||
q.bindValue(":alias", database_name);
|
||||
if (!q.exec()) {
|
||||
q.BindValue(":alias", database_name);
|
||||
if (!q.Exec()) {
|
||||
qLog(Warning) << "Failed to detach database" << database_name;
|
||||
return;
|
||||
}
|
||||
@@ -317,11 +321,11 @@ void Database::AttachDatabaseOnDbConnection(const QString &database_name, const
|
||||
AttachDatabase(database_name, database);
|
||||
|
||||
// Attach the db
|
||||
QSqlQuery q(db);
|
||||
SqlQuery q(db);
|
||||
q.prepare("ATTACH DATABASE :filename AS :alias");
|
||||
q.bindValue(":filename", database.filename_);
|
||||
q.bindValue(":alias", database_name);
|
||||
if (!q.exec()) {
|
||||
q.BindValue(":filename", database.filename_);
|
||||
q.BindValue(":alias", database_name);
|
||||
if (!q.Exec()) {
|
||||
qFatal("Couldn't attach external database '%s'", database_name.toLatin1().constData());
|
||||
}
|
||||
|
||||
@@ -333,10 +337,10 @@ void Database::DetachDatabase(const QString &database_name) {
|
||||
{
|
||||
QSqlDatabase db(Connect());
|
||||
|
||||
QSqlQuery q(db);
|
||||
SqlQuery q(db);
|
||||
q.prepare("DETACH DATABASE :alias");
|
||||
q.bindValue(":alias", database_name);
|
||||
if (!q.exec()) {
|
||||
q.BindValue(":alias", database_name);
|
||||
if (!q.Exec()) {
|
||||
qLog(Warning) << "Failed to detach database" << database_name;
|
||||
return;
|
||||
}
|
||||
@@ -363,12 +367,13 @@ void Database::UpdateDatabaseSchema(int version, QSqlDatabase &db) {
|
||||
|
||||
void Database::UrlEncodeFilenameColumn(const QString &table, QSqlDatabase &db) {
|
||||
|
||||
QSqlQuery select(db);
|
||||
SqlQuery select(db);
|
||||
select.prepare(QString("SELECT ROWID, filename FROM %1").arg(table));
|
||||
QSqlQuery update(db);
|
||||
SqlQuery update(db);
|
||||
update.prepare(QString("UPDATE %1 SET filename=:filename WHERE ROWID=:id").arg(table));
|
||||
select.exec();
|
||||
if (CheckErrors(select)) return;
|
||||
if (!select.Exec()) {
|
||||
ReportErrors(select);
|
||||
}
|
||||
|
||||
while (select.next()) {
|
||||
const int rowid = select.value(0).toInt();
|
||||
@@ -380,10 +385,11 @@ void Database::UrlEncodeFilenameColumn(const QString &table, QSqlDatabase &db) {
|
||||
|
||||
const QUrl url = QUrl::fromLocalFile(filename);
|
||||
|
||||
update.bindValue(":filename", url.toEncoded());
|
||||
update.bindValue(":id", rowid);
|
||||
update.exec();
|
||||
CheckErrors(update);
|
||||
update.BindValue(":filename", url.toEncoded());
|
||||
update.BindValue(":id", rowid);
|
||||
if (!update.Exec()) {
|
||||
ReportErrors(update);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -437,20 +443,27 @@ void Database::ExecSongTablesCommands(QSqlDatabase &db, const QStringList &song_
|
||||
qLog(Info) << "Updating" << table << "for" << kMagicAllSongsTables;
|
||||
QString new_command(command);
|
||||
new_command.replace(kMagicAllSongsTables, table);
|
||||
QSqlQuery query(db.exec(new_command));
|
||||
if (CheckErrors(query))
|
||||
SqlQuery query(db);
|
||||
query.prepare(new_command);
|
||||
if (!query.Exec()) {
|
||||
ReportErrors(query);
|
||||
qFatal("Unable to update music collection database");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
QSqlQuery query(db.exec(command));
|
||||
if (CheckErrors(query)) qFatal("Unable to update music collection database");
|
||||
SqlQuery query(db);
|
||||
query.prepare(command);
|
||||
if (!query.Exec()) {
|
||||
ReportErrors(query);
|
||||
qFatal("Unable to update music collection database");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QStringList Database::SongsTables(QSqlDatabase &db, int schema_version) const {
|
||||
QStringList Database::SongsTables(QSqlDatabase &db, const int schema_version) {
|
||||
|
||||
Q_UNUSED(schema_version);
|
||||
|
||||
@@ -464,14 +477,17 @@ QStringList Database::SongsTables(QSqlDatabase &db, int schema_version) const {
|
||||
// look for the tables in attached dbs
|
||||
QStringList keys = attached_databases_.keys();
|
||||
for (const QString &key : keys) {
|
||||
QSqlQuery q(db);
|
||||
SqlQuery q(db);
|
||||
q.prepare(QString("SELECT NAME FROM %1.sqlite_master WHERE type='table' AND name='songs' OR name LIKE '%songs'").arg(key));
|
||||
if (q.exec()) {
|
||||
if (q.Exec()) {
|
||||
while (q.next()) {
|
||||
QString tab_name = key + "." + q.value(0).toString();
|
||||
ret << tab_name;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ReportErrors(q);
|
||||
}
|
||||
}
|
||||
|
||||
ret << "playlist_items";
|
||||
@@ -480,44 +496,49 @@ QStringList Database::SongsTables(QSqlDatabase &db, int schema_version) const {
|
||||
|
||||
}
|
||||
|
||||
bool Database::CheckErrors(const QSqlQuery &query) {
|
||||
void Database::ReportErrors(const SqlQuery &query) {
|
||||
|
||||
QSqlError last_error = query.lastError();
|
||||
if (last_error.isValid()) {
|
||||
qLog(Error) << "db error: " << last_error;
|
||||
qLog(Error) << "faulty query: " << query.lastQuery();
|
||||
qLog(Error) << "bound values: " << query.boundValues();
|
||||
|
||||
return true;
|
||||
const QSqlError sql_error = query.lastError();
|
||||
if (sql_error.isValid()) {
|
||||
qLog(Error) << "Unable to execute SQL query: " << sql_error;
|
||||
qLog(Error) << "Failed query: " << query.LastQuery();
|
||||
QString error;
|
||||
error += "Unable to execute SQL query: " + sql_error.text() + "<br />";
|
||||
error += "Failed query: " + query.LastQuery();
|
||||
emit Error(error);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool Database::IntegrityCheck(const QSqlDatabase &db) {
|
||||
|
||||
qLog(Debug) << "Starting database integrity check";
|
||||
int task_id = app_->task_manager()->StartTask(tr("Integrity check"));
|
||||
const int task_id = app_->task_manager()->StartTask(tr("Integrity check"));
|
||||
|
||||
bool ok = false;
|
||||
bool error_reported = false;
|
||||
// Ask for 10 error messages at most.
|
||||
QSqlQuery q(QString("PRAGMA integrity_check(10)"), db);
|
||||
while (q.next()) {
|
||||
QString message = q.value(0).toString();
|
||||
SqlQuery q(db);
|
||||
q.prepare("PRAGMA integrity_check(10)");
|
||||
if (q.Exec()) {
|
||||
while (q.next()) {
|
||||
QString message = q.value(0).toString();
|
||||
|
||||
// If no errors are found, a single row with the value "ok" is returned
|
||||
if (message == "ok") {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (!error_reported) { app_->AddError(tr("Database corruption detected.")); }
|
||||
app_->AddError("Database: " + message);
|
||||
error_reported = true;
|
||||
// If no errors are found, a single row with the value "ok" is returned
|
||||
if (message == "ok") {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (!error_reported) { app_->AddError(tr("Database corruption detected.")); }
|
||||
app_->AddError("Database: " + message);
|
||||
error_reported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ReportErrors(q);
|
||||
}
|
||||
|
||||
app_->task_manager()->SetTaskFinished(task_id);
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
# include <QRecursiveMutex>
|
||||
#endif
|
||||
|
||||
#include "sqlquery.h"
|
||||
|
||||
class QThread;
|
||||
class Application;
|
||||
|
||||
@@ -65,7 +67,7 @@ class Database : public QObject {
|
||||
void ExitAsync();
|
||||
QSqlDatabase Connect();
|
||||
void Close();
|
||||
static bool CheckErrors(const QSqlQuery &query);
|
||||
void ReportErrors(const SqlQuery &query);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QRecursiveMutex *Mutex() { return &mutex_; }
|
||||
@@ -85,7 +87,8 @@ class Database : public QObject {
|
||||
|
||||
signals:
|
||||
void ExitFinished();
|
||||
void Error(QString message);
|
||||
void Error(QString error);
|
||||
void Errors(QStringList errors);
|
||||
|
||||
private slots:
|
||||
void Exit();
|
||||
@@ -98,11 +101,11 @@ class Database : public QObject {
|
||||
void UpdateMainSchema(QSqlDatabase *db);
|
||||
|
||||
void ExecSchemaCommandsFromFile(QSqlDatabase &db, const QString &filename, int schema_version, bool in_transaction = false);
|
||||
static void ExecSongTablesCommands(QSqlDatabase &db, const QStringList &song_tables, const QStringList &commands);
|
||||
void ExecSongTablesCommands(QSqlDatabase &db, const QStringList &song_tables, const QStringList &commands);
|
||||
|
||||
void UpdateDatabaseSchema(int version, QSqlDatabase &db);
|
||||
static void UrlEncodeFilenameColumn(const QString &table, QSqlDatabase &db);
|
||||
QStringList SongsTables(QSqlDatabase &db, int schema_version) const;
|
||||
void UrlEncodeFilenameColumn(const QString &table, QSqlDatabase &db);
|
||||
QStringList SongsTables(QSqlDatabase &db, const int schema_version);
|
||||
bool IntegrityCheck(const QSqlDatabase &db);
|
||||
void BackupFile(const QString &filename);
|
||||
static bool OpenDatabase(const QString &filename, sqlite3 **connection);
|
||||
|
||||
@@ -607,6 +607,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
||||
QObject::connect(ui_->track_slider, &TrackSlider::Next, app_->player(), &Player::Next);
|
||||
|
||||
// Collection connections
|
||||
QObject::connect(app_->collection(), &SCollection::Error, this, &MainWindow::ShowErrorDialog);
|
||||
QObject::connect(collection_view_->view(), &CollectionView::AddToPlaylistSignal, this, &MainWindow::AddToPlaylist);
|
||||
QObject::connect(collection_view_->view(), &CollectionView::ShowConfigDialog, this, &MainWindow::ShowCollectionConfig);
|
||||
QObject::connect(collection_view_->view(), &CollectionView::Error, this, &MainWindow::ShowErrorDialog);
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#include "utilities.h"
|
||||
#include "song.h"
|
||||
#include "application.h"
|
||||
#include "sqlquery.h"
|
||||
#include "mpris_common.h"
|
||||
#include "collection/sqlrow.h"
|
||||
#include "tagreadermessages.pb.h"
|
||||
@@ -1369,7 +1370,7 @@ bool Song::MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle) {
|
||||
|
||||
}
|
||||
|
||||
void Song::BindToQuery(QSqlQuery *query) const {
|
||||
void Song::BindToQuery(SqlQuery *query) const {
|
||||
|
||||
#define strval(x) ((x).isNull() ? "" : (x))
|
||||
#define intval(x) ((x) <= 0 ? -1 : (x))
|
||||
@@ -1377,63 +1378,63 @@ void Song::BindToQuery(QSqlQuery *query) const {
|
||||
|
||||
// Remember to bind these in the same order as kBindSpec
|
||||
|
||||
query->bindValue(":title", strval(d->title_));
|
||||
query->bindValue(":album", strval(d->album_));
|
||||
query->bindValue(":artist", strval(d->artist_));
|
||||
query->bindValue(":albumartist", strval(d->albumartist_));
|
||||
query->bindValue(":track", intval(d->track_));
|
||||
query->bindValue(":disc", intval(d->disc_));
|
||||
query->bindValue(":year", intval(d->year_));
|
||||
query->bindValue(":originalyear", intval(d->originalyear_));
|
||||
query->bindValue(":genre", strval(d->genre_));
|
||||
query->bindValue(":compilation", d->compilation_ ? 1 : 0);
|
||||
query->bindValue(":composer", strval(d->composer_));
|
||||
query->bindValue(":performer", strval(d->performer_));
|
||||
query->bindValue(":grouping", strval(d->grouping_));
|
||||
query->bindValue(":comment", strval(d->comment_));
|
||||
query->bindValue(":lyrics", strval(d->lyrics_));
|
||||
query->BindValue(":title", strval(d->title_));
|
||||
query->BindValue(":album", strval(d->album_));
|
||||
query->BindValue(":artist", strval(d->artist_));
|
||||
query->BindValue(":albumartist", strval(d->albumartist_));
|
||||
query->BindValue(":track", intval(d->track_));
|
||||
query->BindValue(":disc", intval(d->disc_));
|
||||
query->BindValue(":year", intval(d->year_));
|
||||
query->BindValue(":originalyear", intval(d->originalyear_));
|
||||
query->BindValue(":genre", strval(d->genre_));
|
||||
query->BindValue(":compilation", d->compilation_ ? 1 : 0);
|
||||
query->BindValue(":composer", strval(d->composer_));
|
||||
query->BindValue(":performer", strval(d->performer_));
|
||||
query->BindValue(":grouping", strval(d->grouping_));
|
||||
query->BindValue(":comment", strval(d->comment_));
|
||||
query->BindValue(":lyrics", strval(d->lyrics_));
|
||||
|
||||
query->bindValue(":artist_id", strval(d->artist_id_));
|
||||
query->bindValue(":album_id", strval(d->album_id_));
|
||||
query->bindValue(":song_id", strval(d->song_id_));
|
||||
query->BindValue(":artist_id", strval(d->artist_id_));
|
||||
query->BindValue(":album_id", strval(d->album_id_));
|
||||
query->BindValue(":song_id", strval(d->song_id_));
|
||||
|
||||
query->bindValue(":beginning", d->beginning_);
|
||||
query->bindValue(":length", intval(length_nanosec()));
|
||||
query->BindValue(":beginning", d->beginning_);
|
||||
query->BindValue(":length", intval(length_nanosec()));
|
||||
|
||||
query->bindValue(":bitrate", intval(d->bitrate_));
|
||||
query->bindValue(":samplerate", intval(d->samplerate_));
|
||||
query->bindValue(":bitdepth", intval(d->bitdepth_));
|
||||
query->BindValue(":bitrate", intval(d->bitrate_));
|
||||
query->BindValue(":samplerate", intval(d->samplerate_));
|
||||
query->BindValue(":bitdepth", intval(d->bitdepth_));
|
||||
|
||||
query->bindValue(":source", d->source_);
|
||||
query->bindValue(":directory_id", notnullintval(d->directory_id_));
|
||||
query->bindValue(":url", d->url_.toString(QUrl::FullyEncoded));
|
||||
query->bindValue(":filetype", d->filetype_);
|
||||
query->bindValue(":filesize", notnullintval(d->filesize_));
|
||||
query->bindValue(":mtime", notnullintval(d->mtime_));
|
||||
query->bindValue(":ctime", notnullintval(d->ctime_));
|
||||
query->bindValue(":unavailable", d->unavailable_ ? 1 : 0);
|
||||
query->BindValue(":source", d->source_);
|
||||
query->BindValue(":directory_id", notnullintval(d->directory_id_));
|
||||
query->BindValue(":url", d->url_.toString(QUrl::FullyEncoded));
|
||||
query->BindValue(":filetype", d->filetype_);
|
||||
query->BindValue(":filesize", notnullintval(d->filesize_));
|
||||
query->BindValue(":mtime", notnullintval(d->mtime_));
|
||||
query->BindValue(":ctime", notnullintval(d->ctime_));
|
||||
query->BindValue(":unavailable", d->unavailable_ ? 1 : 0);
|
||||
|
||||
query->bindValue(":fingerprint", strval(d->fingerprint_));
|
||||
query->BindValue(":fingerprint", strval(d->fingerprint_));
|
||||
|
||||
query->bindValue(":playcount", d->playcount_);
|
||||
query->bindValue(":skipcount", d->skipcount_);
|
||||
query->bindValue(":lastplayed", intval(d->lastplayed_));
|
||||
query->bindValue(":lastseen", intval(d->lastseen_));
|
||||
query->BindValue(":playcount", d->playcount_);
|
||||
query->BindValue(":skipcount", d->skipcount_);
|
||||
query->BindValue(":lastplayed", intval(d->lastplayed_));
|
||||
query->BindValue(":lastseen", intval(d->lastseen_));
|
||||
|
||||
query->bindValue(":compilation_detected", d->compilation_detected_ ? 1 : 0);
|
||||
query->bindValue(":compilation_on", d->compilation_on_ ? 1 : 0);
|
||||
query->bindValue(":compilation_off", d->compilation_off_ ? 1 : 0);
|
||||
query->bindValue(":compilation_effective", is_compilation() ? 1 : 0);
|
||||
query->BindValue(":compilation_detected", d->compilation_detected_ ? 1 : 0);
|
||||
query->BindValue(":compilation_on", d->compilation_on_ ? 1 : 0);
|
||||
query->BindValue(":compilation_off", d->compilation_off_ ? 1 : 0);
|
||||
query->BindValue(":compilation_effective", is_compilation() ? 1 : 0);
|
||||
|
||||
query->bindValue(":art_automatic", d->art_automatic_.isValid() ? d->art_automatic_.toString(QUrl::FullyEncoded) : "");
|
||||
query->bindValue(":art_manual", d->art_manual_.isValid() ? d->art_manual_.toString(QUrl::FullyEncoded) : "");
|
||||
query->BindValue(":art_automatic", d->art_automatic_.isValid() ? d->art_automatic_.toString(QUrl::FullyEncoded) : "");
|
||||
query->BindValue(":art_manual", d->art_manual_.isValid() ? d->art_manual_.toString(QUrl::FullyEncoded) : "");
|
||||
|
||||
query->bindValue(":effective_albumartist", strval(this->effective_albumartist()));
|
||||
query->bindValue(":effective_originalyear", intval(this->effective_originalyear()));
|
||||
query->BindValue(":effective_albumartist", strval(this->effective_albumartist()));
|
||||
query->BindValue(":effective_originalyear", intval(this->effective_originalyear()));
|
||||
|
||||
query->bindValue(":cue_path", d->cue_path_);
|
||||
query->BindValue(":cue_path", d->cue_path_);
|
||||
|
||||
query->bindValue(":rating", intval(d->rating_));
|
||||
query->BindValue(":rating", intval(d->rating_));
|
||||
|
||||
#undef intval
|
||||
#undef notnullintval
|
||||
@@ -1441,17 +1442,17 @@ void Song::BindToQuery(QSqlQuery *query) const {
|
||||
|
||||
}
|
||||
|
||||
void Song::BindToFtsQuery(QSqlQuery *query) const {
|
||||
void Song::BindToFtsQuery(SqlQuery *query) const {
|
||||
|
||||
query->bindValue(":ftstitle", d->title_);
|
||||
query->bindValue(":ftsalbum", d->album_);
|
||||
query->bindValue(":ftsartist", d->artist_);
|
||||
query->bindValue(":ftsalbumartist", d->albumartist_);
|
||||
query->bindValue(":ftscomposer", d->composer_);
|
||||
query->bindValue(":ftsperformer", d->performer_);
|
||||
query->bindValue(":ftsgrouping", d->grouping_);
|
||||
query->bindValue(":ftsgenre", d->genre_);
|
||||
query->bindValue(":ftscomment", d->comment_);
|
||||
query->BindValue(":ftstitle", d->title_);
|
||||
query->BindValue(":ftsalbum", d->album_);
|
||||
query->BindValue(":ftsartist", d->artist_);
|
||||
query->BindValue(":ftsalbumartist", d->albumartist_);
|
||||
query->BindValue(":ftscomposer", d->composer_);
|
||||
query->BindValue(":ftsperformer", d->performer_);
|
||||
query->BindValue(":ftsgrouping", d->grouping_);
|
||||
query->BindValue(":ftsgenre", d->genre_);
|
||||
query->BindValue(":ftscomment", d->comment_);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include <QImage>
|
||||
#include <QIcon>
|
||||
|
||||
class QSqlQuery;
|
||||
class SqlQuery;
|
||||
|
||||
namespace Engine {
|
||||
struct SimpleMetaBundle;
|
||||
@@ -185,8 +185,8 @@ class Song {
|
||||
void MergeUserSetData(const Song &other);
|
||||
|
||||
// Save
|
||||
void BindToQuery(QSqlQuery *query) const;
|
||||
void BindToFtsQuery(QSqlQuery *query) const;
|
||||
void BindToQuery(SqlQuery *query) const;
|
||||
void BindToFtsQuery(SqlQuery *query) const;
|
||||
void ToXesam(QVariantMap *map) const;
|
||||
void ToProtobuf(spb::tagreader::SongMetadata *pb) const;
|
||||
|
||||
|
||||
66
src/core/sqlquery.cpp
Normal file
66
src/core/sqlquery.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* Copyright 2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Strawberry is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QSqlQuery>
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QVariantList>
|
||||
|
||||
#include "sqlquery.h"
|
||||
|
||||
void SqlQuery::BindValue(const QString &placeholder, const QVariant &value) {
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
bound_values_.insert(placeholder, value);
|
||||
#endif
|
||||
|
||||
bindValue(placeholder, value);
|
||||
|
||||
}
|
||||
|
||||
bool SqlQuery::Exec() {
|
||||
|
||||
bool success = exec();
|
||||
last_query_ = executedQuery();
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
for (QMap<QString, QVariant>::const_iterator it = bound_values_.begin(); it != bound_values_.end(); ++it) {
|
||||
last_query_.replace(it.key(), it.value().toString());
|
||||
}
|
||||
bound_values_.clear();
|
||||
#else
|
||||
QMapIterator<QString, QVariant> it(boundValues());
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
last_query_.replace(it.key(), it.value().toString());
|
||||
}
|
||||
#endif
|
||||
|
||||
return success;
|
||||
|
||||
}
|
||||
|
||||
QString SqlQuery::LastQuery() const {
|
||||
|
||||
return last_query_;
|
||||
|
||||
}
|
||||
48
src/core/sqlquery.h
Normal file
48
src/core/sqlquery.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* Copyright 2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Strawberry is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SQLQUERY_H
|
||||
#define SQLQUERY_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
|
||||
class SqlQuery : public QSqlQuery {
|
||||
|
||||
public:
|
||||
explicit SqlQuery(QSqlDatabase db) : QSqlQuery(db) {}
|
||||
|
||||
void BindValue(const QString &placeholder, const QVariant &value);
|
||||
bool Exec();
|
||||
QString LastQuery() const;
|
||||
|
||||
private:
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
QMap<QString, QVariant> bound_values_;
|
||||
#endif
|
||||
QString last_query_;
|
||||
|
||||
};
|
||||
|
||||
#endif // SQLQUERY_H
|
||||
Reference in New Issue
Block a user