diff --git a/src/Instance.cxx b/src/Instance.cxx index 232cd21df..0f7f52e6e 100644 --- a/src/Instance.cxx +++ b/src/Instance.cxx @@ -22,6 +22,7 @@ #include "Partition.hxx" #include "Idle.hxx" #include "Stats.hxx" +#include "util/Error.hxx" #ifdef ENABLE_DATABASE #include "db/DatabaseError.hxx" @@ -76,7 +77,7 @@ Instance::OnDatabaseSongRemoved(const LightSong &song) #ifdef ENABLE_SQLITE /* if the song has a sticker, remove it */ if (sticker_enabled()) - sticker_song_delete(song); + sticker_song_delete(song, IgnoreError()); #endif const auto uri = song.GetURI(); diff --git a/src/command/StickerCommands.cxx b/src/command/StickerCommands.cxx index 088a07a79..f2fad86cc 100644 --- a/src/command/StickerCommands.cxx +++ b/src/command/StickerCommands.cxx @@ -67,9 +67,13 @@ handle_sticker_song(Client &client, ConstBuffer args) if (song == nullptr) return print_error(client, error); - const auto value = sticker_song_get_value(*song, args[3]); + const auto value = sticker_song_get_value(*song, args[3], + error); db->ReturnSong(song); if (value.empty()) { + if (error.IsDefined()) + return print_error(client, error); + command_error(client, ACK_ERROR_NO_EXIST, "no such sticker"); return CommandResult::ERROR; @@ -84,12 +88,13 @@ handle_sticker_song(Client &client, ConstBuffer args) if (song == nullptr) return print_error(client, error); - sticker *sticker = sticker_song_get(*song); + sticker *sticker = sticker_song_get(*song, error); db->ReturnSong(song); if (sticker) { sticker_print(client, *sticker); sticker_free(sticker); - } + } else if (error.IsDefined()) + return print_error(client, error); return CommandResult::OK; /* set song song_id id key */ @@ -98,9 +103,13 @@ handle_sticker_song(Client &client, ConstBuffer args) if (song == nullptr) return print_error(client, error); - bool ret = sticker_song_set_value(*song, args[3], args[4]); + bool ret = sticker_song_set_value(*song, args[3], args[4], + error); db->ReturnSong(song); if (!ret) { + if (error.IsDefined()) + return print_error(client, error); + command_error(client, ACK_ERROR_SYSTEM, "failed to set sticker value"); return CommandResult::ERROR; @@ -115,10 +124,13 @@ handle_sticker_song(Client &client, ConstBuffer args) return print_error(client, error); bool ret = args.size == 3 - ? sticker_song_delete(*song) - : sticker_song_delete_value(*song, args[3]); + ? sticker_song_delete(*song, error) + : sticker_song_delete_value(*song, args[3], error); db->ReturnSong(song); if (!ret) { + if (error.IsDefined()) + return print_error(client, error); + command_error(client, ACK_ERROR_SYSTEM, "no such sticker"); return CommandResult::ERROR; @@ -138,8 +150,12 @@ handle_sticker_song(Client &client, ConstBuffer args) }; success = sticker_song_find(*db, base_uri, data.name, - sticker_song_find_print_cb, &data); + sticker_song_find_print_cb, &data, + error); if (!success) { + if (error.IsDefined()) + return print_error(client, error); + command_error(client, ACK_ERROR_SYSTEM, "failed to set search sticker database"); return CommandResult::ERROR; diff --git a/src/lib/sqlite/Util.hxx b/src/lib/sqlite/Util.hxx index fbc773ed4..abc35835b 100644 --- a/src/lib/sqlite/Util.hxx +++ b/src/lib/sqlite/Util.hxx @@ -21,30 +21,31 @@ #define MPD_SQLITE_UTIL_HXX #include "Domain.hxx" -#include "Log.hxx" +#include "util/Error.hxx" #include #include static void -LogError(sqlite3 *db, const char *msg) +SetError(Error &error, sqlite3 *db, int code, const char *msg) { - FormatError(sqlite_domain, "%s: %s", msg, sqlite3_errmsg(db)); + error.Format(sqlite_domain, code, "%s: %s", + msg, sqlite3_errmsg(db)); } static void -LogError(sqlite3_stmt *stmt, const char *msg) +SetError(Error &error, sqlite3_stmt *stmt, int code, const char *msg) { - LogError(sqlite3_db_handle(stmt), msg); + SetError(error, sqlite3_db_handle(stmt), code, msg); } static bool -Bind(sqlite3_stmt *stmt, unsigned i, const char *value) +Bind(sqlite3_stmt *stmt, unsigned i, const char *value, Error &error) { int result = sqlite3_bind_text(stmt, i, value, -1, nullptr); if (result != SQLITE_OK) { - LogError(stmt, "sqlite3_bind_text() failed"); + SetError(error, stmt, result, "sqlite3_bind_text() failed"); return false; } @@ -53,7 +54,8 @@ Bind(sqlite3_stmt *stmt, unsigned i, const char *value) template static bool -BindAll2(gcc_unused sqlite3_stmt *stmt, gcc_unused unsigned i) +BindAll2(gcc_unused Error &error, gcc_unused sqlite3_stmt *stmt, + gcc_unused unsigned i) { assert(int(i - 1) == sqlite3_bind_parameter_count(stmt)); @@ -62,19 +64,20 @@ BindAll2(gcc_unused sqlite3_stmt *stmt, gcc_unused unsigned i) template static bool -BindAll2(sqlite3_stmt *stmt, unsigned i, const char *value, Args&&... args) +BindAll2(Error &error, sqlite3_stmt *stmt, unsigned i, + const char *value, Args&&... args) { - return Bind(stmt, i, value) && - BindAll2(stmt, i + 1, std::forward(args)...); + return Bind(stmt, i, value, error) && + BindAll2(error, stmt, i + 1, std::forward(args)...); } template static bool -BindAll(sqlite3_stmt *stmt, Args&&... args) +BindAll(Error &error, sqlite3_stmt *stmt, Args&&... args) { assert(int(sizeof...(args)) == sqlite3_bind_parameter_count(stmt)); - return BindAll2(stmt, 1, std::forward(args)...); + return BindAll2(error, stmt, 1, std::forward(args)...); } /** @@ -96,14 +99,14 @@ ExecuteBusy(sqlite3_stmt *stmt) * Wrapper for ExecuteBusy() that returns true on SQLITE_ROW. */ static bool -ExecuteRow(sqlite3_stmt *stmt) +ExecuteRow(sqlite3_stmt *stmt, Error &error) { int result = ExecuteBusy(stmt); if (result == SQLITE_ROW) return true; if (result != SQLITE_DONE) - LogError(sqlite_domain, "sqlite3_step() failed"); + SetError(error, stmt, result, "sqlite3_step() failed"); return false; } @@ -113,11 +116,11 @@ ExecuteRow(sqlite3_stmt *stmt) * SQLITE_DONE as error. */ static bool -ExecuteCommand(sqlite3_stmt *stmt) +ExecuteCommand(sqlite3_stmt *stmt, Error &error) { int result = ExecuteBusy(stmt); if (result != SQLITE_DONE) { - LogError(stmt, "sqlite3_step() failed"); + SetError(error, stmt, result, "sqlite3_step() failed"); return false; } @@ -129,9 +132,9 @@ ExecuteCommand(sqlite3_stmt *stmt) * modified via sqlite3_changes(). Returns -1 on error. */ static inline int -ExecuteChanges(sqlite3_stmt *stmt) +ExecuteChanges(sqlite3_stmt *stmt, Error &error) { - if (!ExecuteCommand(stmt)) + if (!ExecuteCommand(stmt, error)) return -1; return sqlite3_changes(sqlite3_db_handle(stmt)); @@ -143,17 +146,18 @@ ExecuteChanges(sqlite3_stmt *stmt) * occurred. */ static inline bool -ExecuteModified(sqlite3_stmt *stmt) +ExecuteModified(sqlite3_stmt *stmt, Error &error) { - return ExecuteChanges(stmt) > 0; + return ExecuteChanges(stmt, error) > 0; } template static inline bool -ExecuteForEach(sqlite3_stmt *stmt, F &&f) +ExecuteForEach(sqlite3_stmt *stmt, Error &error, F &&f) { while (true) { - switch (ExecuteBusy(stmt)) { + int result = ExecuteBusy(stmt); + switch (result) { case SQLITE_ROW: f(); break; @@ -162,7 +166,7 @@ ExecuteForEach(sqlite3_stmt *stmt, F &&f) return true; default: - LogError(sqlite_domain, "sqlite3_step() failed"); + SetError(error, stmt, result, "sqlite3_step() failed"); return false; } } diff --git a/src/sticker/SongSticker.cxx b/src/sticker/SongSticker.cxx index b0b74b1a6..0b317bf9e 100644 --- a/src/sticker/SongSticker.cxx +++ b/src/sticker/SongSticker.cxx @@ -30,39 +30,41 @@ #include std::string -sticker_song_get_value(const LightSong &song, const char *name) +sticker_song_get_value(const LightSong &song, const char *name, Error &error) { const auto uri = song.GetURI(); - return sticker_load_value("song", uri.c_str(), name); + return sticker_load_value("song", uri.c_str(), name, error); } bool sticker_song_set_value(const LightSong &song, - const char *name, const char *value) + const char *name, const char *value, + Error &error) { const auto uri = song.GetURI(); - return sticker_store_value("song", uri.c_str(), name, value); + return sticker_store_value("song", uri.c_str(), name, value, error); } bool -sticker_song_delete(const LightSong &song) +sticker_song_delete(const LightSong &song, Error &error) { const auto uri = song.GetURI(); - return sticker_delete("song", uri.c_str()); + return sticker_delete("song", uri.c_str(), error); } bool -sticker_song_delete_value(const LightSong &song, const char *name) +sticker_song_delete_value(const LightSong &song, const char *name, + Error &error) { const auto uri = song.GetURI(); - return sticker_delete_value("song", uri.c_str(), name); + return sticker_delete_value("song", uri.c_str(), name, error); } struct sticker * -sticker_song_get(const LightSong &song) +sticker_song_get(const LightSong &song, Error &error) { const auto uri = song.GetURI(); - return sticker_load("song", uri.c_str()); + return sticker_load("song", uri.c_str(), error); } struct sticker_song_find_data { @@ -97,7 +99,8 @@ bool sticker_song_find(const Database &db, const char *base_uri, const char *name, void (*func)(const LightSong &song, const char *value, void *user_data), - void *user_data) + void *user_data, + Error &error) { struct sticker_song_find_data data; data.db = &db; @@ -117,7 +120,8 @@ sticker_song_find(const Database &db, const char *base_uri, const char *name, data.base_uri_length = strlen(data.base_uri); bool success = sticker_find("song", data.base_uri, name, - sticker_song_find_cb, &data); + sticker_song_find_cb, &data, + error); free(allocated); return success; diff --git a/src/sticker/SongSticker.hxx b/src/sticker/SongSticker.hxx index 6e71bc3e4..918046d0e 100644 --- a/src/sticker/SongSticker.hxx +++ b/src/sticker/SongSticker.hxx @@ -27,13 +27,14 @@ struct LightSong; struct sticker; class Database; +class Error; /** * Returns one value from a song's sticker record. */ gcc_pure std::string -sticker_song_get_value(const LightSong &song, const char *name); +sticker_song_get_value(const LightSong &song, const char *name, Error &error); /** * Sets a sticker value in the specified song. Overwrites existing @@ -41,20 +42,22 @@ sticker_song_get_value(const LightSong &song, const char *name); */ bool sticker_song_set_value(const LightSong &song, - const char *name, const char *value); + const char *name, const char *value, + Error &error); /** * Deletes a sticker from the database. All values are deleted. */ bool -sticker_song_delete(const LightSong &song); +sticker_song_delete(const LightSong &song, Error &error); /** * Deletes a sticker value. Does nothing if the sticker did not * exist. */ bool -sticker_song_delete_value(const LightSong &song, const char *name); +sticker_song_delete_value(const LightSong &song, const char *name, + Error &error); /** * Loads the sticker for the specified song. @@ -63,7 +66,7 @@ sticker_song_delete_value(const LightSong &song, const char *name); * @return a sticker object, or NULL on error or if there is no sticker */ sticker * -sticker_song_get(const LightSong &song); +sticker_song_get(const LightSong &song, Error &error); /** * Finds stickers with the specified name below the specified @@ -80,6 +83,7 @@ bool sticker_song_find(const Database &db, const char *base_uri, const char *name, void (*func)(const LightSong &song, const char *value, void *user_data), - void *user_data); + void *user_data, + Error &error); #endif diff --git a/src/sticker/StickerDatabase.cxx b/src/sticker/StickerDatabase.cxx index 69415bd04..70f47d163 100644 --- a/src/sticker/StickerDatabase.cxx +++ b/src/sticker/StickerDatabase.cxx @@ -25,7 +25,6 @@ #include "Idle.hxx" #include "util/Error.hxx" #include "util/Macros.hxx" -#include "Log.hxx" #include #include @@ -157,7 +156,8 @@ sticker_enabled() } std::string -sticker_load_value(const char *type, const char *uri, const char *name) +sticker_load_value(const char *type, const char *uri, const char *name, + Error &error) { sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_GET]; @@ -169,11 +169,11 @@ sticker_load_value(const char *type, const char *uri, const char *name) if (*name == 0) return std::string(); - if (!BindAll(stmt, type, uri, name)) + if (!BindAll(error, stmt, type, uri, name)) return std::string(); std::string value; - if (ExecuteRow(stmt)) + if (ExecuteRow(stmt, error)) value = (const char*)sqlite3_column_text(stmt, 0); sqlite3_reset(stmt); @@ -184,7 +184,8 @@ sticker_load_value(const char *type, const char *uri, const char *name) static bool sticker_list_values(std::map &table, - const char *type, const char *uri) + const char *type, const char *uri, + Error &error) { sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_LIST]; @@ -192,10 +193,10 @@ sticker_list_values(std::map &table, assert(uri != nullptr); assert(sticker_enabled()); - if (!BindAll(stmt, type, uri)) + if (!BindAll(error, stmt, type, uri)) return false; - const bool success = ExecuteForEach(stmt, [stmt, &table](){ + const bool success = ExecuteForEach(stmt, error, [stmt, &table](){ const char *name = (const char *)sqlite3_column_text(stmt, 0); const char *value = (const char *)sqlite3_column_text(stmt, 1); table.insert(std::make_pair(name, value)); @@ -209,7 +210,8 @@ sticker_list_values(std::map &table, static bool sticker_update_value(const char *type, const char *uri, - const char *name, const char *value) + const char *name, const char *value, + Error &error) { sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_UPDATE]; @@ -221,10 +223,10 @@ sticker_update_value(const char *type, const char *uri, assert(sticker_enabled()); - if (!BindAll(stmt, value, type, uri, name)) + if (!BindAll(error, stmt, value, type, uri, name)) return false; - bool modified = ExecuteModified(stmt); + bool modified = ExecuteModified(stmt, error); sqlite3_reset(stmt); sqlite3_clear_bindings(stmt); @@ -236,7 +238,8 @@ sticker_update_value(const char *type, const char *uri, static bool sticker_insert_value(const char *type, const char *uri, - const char *name, const char *value) + const char *name, const char *value, + Error &error) { sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_INSERT]; @@ -248,10 +251,10 @@ sticker_insert_value(const char *type, const char *uri, assert(sticker_enabled()); - if (!BindAll(stmt, type, uri, name, value)) + if (!BindAll(error, stmt, type, uri, name, value)) return false; - bool success = ExecuteCommand(stmt); + bool success = ExecuteCommand(stmt, error); sqlite3_reset(stmt); sqlite3_clear_bindings(stmt); @@ -263,7 +266,8 @@ sticker_insert_value(const char *type, const char *uri, bool sticker_store_value(const char *type, const char *uri, - const char *name, const char *value) + const char *name, const char *value, + Error &error) { assert(sticker_enabled()); assert(type != nullptr); @@ -274,12 +278,12 @@ sticker_store_value(const char *type, const char *uri, if (*name == 0) return false; - return sticker_update_value(type, uri, name, value) || - sticker_insert_value(type, uri, name, value); + return sticker_update_value(type, uri, name, value, error) || + sticker_insert_value(type, uri, name, value, error); } bool -sticker_delete(const char *type, const char *uri) +sticker_delete(const char *type, const char *uri, Error &error) { sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_DELETE]; @@ -287,10 +291,10 @@ sticker_delete(const char *type, const char *uri) assert(type != nullptr); assert(uri != nullptr); - if (!BindAll(stmt, type, uri)) + if (!BindAll(error, stmt, type, uri)) return false; - bool modified = ExecuteModified(stmt); + bool modified = ExecuteModified(stmt, error); sqlite3_reset(stmt); sqlite3_clear_bindings(stmt); @@ -301,7 +305,8 @@ sticker_delete(const char *type, const char *uri) } bool -sticker_delete_value(const char *type, const char *uri, const char *name) +sticker_delete_value(const char *type, const char *uri, const char *name, + Error &error) { sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_DELETE_VALUE]; @@ -309,10 +314,10 @@ sticker_delete_value(const char *type, const char *uri, const char *name) assert(type != nullptr); assert(uri != nullptr); - if (!BindAll(stmt, type, uri, name)) + if (!BindAll(error, stmt, type, uri, name)) return false; - bool modified = ExecuteModified(stmt); + bool modified = ExecuteModified(stmt, error); sqlite3_reset(stmt); sqlite3_clear_bindings(stmt); @@ -349,11 +354,11 @@ sticker_foreach(const sticker &sticker, } struct sticker * -sticker_load(const char *type, const char *uri) +sticker_load(const char *type, const char *uri, Error &error) { sticker s; - if (!sticker_list_values(s.table, type, uri)) + if (!sticker_list_values(s.table, type, uri, error)) return nullptr; if (s.table.empty()) @@ -367,7 +372,8 @@ bool sticker_find(const char *type, const char *base_uri, const char *name, void (*func)(const char *uri, const char *value, void *user_data), - void *user_data) + void *user_data, + Error &error) { sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_FIND]; @@ -379,10 +385,11 @@ sticker_find(const char *type, const char *base_uri, const char *name, if (base_uri == nullptr) base_uri = ""; - if (!BindAll(stmt, type, base_uri, name)) + if (!BindAll(error, stmt, type, base_uri, name)) return false; - const bool success = ExecuteForEach(stmt, [stmt, func, user_data](){ + const bool success = ExecuteForEach(stmt, error, + [stmt, func, user_data](){ func((const char*)sqlite3_column_text(stmt, 0), (const char*)sqlite3_column_text(stmt, 1), user_data); diff --git a/src/sticker/StickerDatabase.hxx b/src/sticker/StickerDatabase.hxx index 949be6ebd..38c7d6f95 100644 --- a/src/sticker/StickerDatabase.hxx +++ b/src/sticker/StickerDatabase.hxx @@ -76,7 +76,8 @@ sticker_enabled(); * empty string if the value doesn't exist. */ std::string -sticker_load_value(const char *type, const char *uri, const char *name); +sticker_load_value(const char *type, const char *uri, const char *name, + Error &error); /** * Sets a sticker value in the specified object. Overwrites existing @@ -84,21 +85,24 @@ sticker_load_value(const char *type, const char *uri, const char *name); */ bool sticker_store_value(const char *type, const char *uri, - const char *name, const char *value); + const char *name, const char *value, + Error &error); /** * Deletes a sticker from the database. All sticker values of the * specified object are deleted. */ bool -sticker_delete(const char *type, const char *uri); +sticker_delete(const char *type, const char *uri, + Error &error); /** * Deletes a sticker value. Fails if no sticker with this name * exists. */ bool -sticker_delete_value(const char *type, const char *uri, const char *name); +sticker_delete_value(const char *type, const char *uri, const char *name, + Error &error); /** * Frees resources held by the sticker object. @@ -140,7 +144,8 @@ sticker_foreach(const sticker &sticker, * @return a sticker object, or nullptr on error or if there is no sticker */ sticker * -sticker_load(const char *type, const char *uri); +sticker_load(const char *type, const char *uri, + Error &error); /** * Finds stickers with the specified name below the specified URI. @@ -156,6 +161,7 @@ bool sticker_find(const char *type, const char *base_uri, const char *name, void (*func)(const char *uri, const char *value, void *user_data), - void *user_data); + void *user_data, + Error &error); #endif