diff --git a/src/Instance.cxx b/src/Instance.cxx index 0103498ad..986d4dfed 100644 --- a/src/Instance.cxx +++ b/src/Instance.cxx @@ -107,9 +107,9 @@ Instance::OnDatabaseSongRemoved(const char *uri) noexcept #ifdef ENABLE_SQLITE /* if the song has a sticker, remove it */ - if (sticker_enabled()) { + if (HasStickerDatabase()) { try { - sticker_song_delete(uri); + sticker_song_delete(*sticker_database, uri); } catch (...) { } } diff --git a/src/Instance.hxx b/src/Instance.hxx index f3c772931..78e9ffb09 100644 --- a/src/Instance.hxx +++ b/src/Instance.hxx @@ -53,6 +53,7 @@ class ClientList; struct Partition; class StateFile; class RemoteTagCache; +class StickerDatabase; /** * A utility class which, when used as the first base class, ensures @@ -125,6 +126,10 @@ struct Instance final StateFile *state_file = nullptr; +#ifdef ENABLE_SQLITE + std::unique_ptr sticker_database; +#endif + Instance(); ~Instance() noexcept; @@ -166,6 +171,12 @@ struct Instance final const Database &GetDatabaseOrThrow() const; #endif +#ifdef ENABLE_SQLITE + bool HasStickerDatabase() noexcept { + return sticker_database != nullptr; + } +#endif + void BeginShutdownUpdate() noexcept; #ifdef ENABLE_CURL diff --git a/src/Main.cxx b/src/Main.cxx index 9a2919d79..52367b029 100644 --- a/src/Main.cxx +++ b/src/Main.cxx @@ -237,23 +237,23 @@ InitDatabaseAndStorage(const ConfigData &config) #endif +#ifdef ENABLE_SQLITE + /** * Configure and initialize the sticker subsystem. */ -static void -glue_sticker_init(const ConfigData &config) +static std::unique_ptr +LoadStickerDatabase(const ConfigData &config) { -#ifdef ENABLE_SQLITE auto sticker_file = config.GetPath(ConfigOption::STICKER_FILE); if (sticker_file.IsNull()) - return; + return nullptr; - sticker_global_init(std::move(sticker_file)); -#else - (void)config; -#endif + return std::make_unique(std::move(sticker_file)); } +#endif + static void glue_state_file_init(const ConfigData &raw_config) { @@ -513,7 +513,9 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config) const bool create_db = InitDatabaseAndStorage(raw_config); #endif - glue_sticker_init(raw_config); +#ifdef ENABLE_SQLITE + instance->sticker_database = LoadStickerDatabase(raw_config); +#endif command_init(); @@ -625,10 +627,6 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config) } #endif -#ifdef ENABLE_SQLITE - sticker_global_finish(); -#endif - return EXIT_SUCCESS; } diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx index 23c3589e0..ade7a9436 100644 --- a/src/command/AllCommands.cxx +++ b/src/command/AllCommands.cxx @@ -38,6 +38,7 @@ #include "Permission.hxx" #include "tag/Type.h" #include "Partition.hxx" +#include "Instance.hxx" #include "client/Client.hxx" #include "client/Response.hxx" #include "util/Macros.hxx" @@ -216,7 +217,7 @@ command_available(gcc_unused const Partition &partition, { #ifdef ENABLE_SQLITE if (StringIsEqual(cmd->cmd, "sticker")) - return sticker_enabled(); + return partition.instance.HasStickerDatabase(); #endif #ifdef ENABLE_NEIGHBOR_PLUGINS diff --git a/src/command/StickerCommands.cxx b/src/command/StickerCommands.cxx index 940a96943..fe3d8821c 100644 --- a/src/command/StickerCommands.cxx +++ b/src/command/StickerCommands.cxx @@ -28,6 +28,7 @@ #include "client/Client.hxx" #include "client/Response.hxx" #include "Partition.hxx" +#include "Instance.hxx" #include "util/StringAPI.hxx" #include "util/ScopeExit.hxx" @@ -50,7 +51,9 @@ sticker_song_find_print_cb(const LightSong &song, const char *value, } static CommandResult -handle_sticker_song(Response &r, Partition &partition, Request args) +handle_sticker_song(Response &r, Partition &partition, + StickerDatabase &sticker_database, + Request args) { const Database &db = partition.GetDatabaseOrThrow(); @@ -62,7 +65,8 @@ handle_sticker_song(Response &r, Partition &partition, Request args) assert(song != nullptr); AtScopeExit(&db, song) { db.ReturnSong(song); }; - const auto value = sticker_song_get_value(*song, args[3]); + const auto value = sticker_song_get_value(sticker_database, + *song, args[3]); if (value.empty()) { r.Error(ACK_ERROR_NO_EXIST, "no such sticker"); return CommandResult::ERROR; @@ -77,7 +81,7 @@ handle_sticker_song(Response &r, Partition &partition, Request args) assert(song != nullptr); AtScopeExit(&db, song) { db.ReturnSong(song); }; - const auto sticker = sticker_song_get(*song); + const auto sticker = sticker_song_get(sticker_database, *song); sticker_print(r, sticker); return CommandResult::OK; @@ -87,7 +91,8 @@ handle_sticker_song(Response &r, Partition &partition, Request args) assert(song != nullptr); AtScopeExit(&db, song) { db.ReturnSong(song); }; - sticker_song_set_value(*song, args[3], args[4]); + sticker_song_set_value(sticker_database, *song, + args[3], args[4]); return CommandResult::OK; /* delete song song_id [key] */ } else if ((args.size == 3 || args.size == 4) && @@ -97,8 +102,9 @@ handle_sticker_song(Response &r, Partition &partition, Request args) AtScopeExit(&db, song) { db.ReturnSong(song); }; bool ret = args.size == 3 - ? sticker_song_delete(*song) - : sticker_song_delete_value(*song, args[3]); + ? sticker_song_delete(sticker_database, *song) + : sticker_song_delete_value(sticker_database, *song, + args[3]); if (!ret) { r.Error(ACK_ERROR_NO_EXIST, "no such sticker"); return CommandResult::ERROR; @@ -138,7 +144,7 @@ handle_sticker_song(Response &r, Partition &partition, Request args) args[3], }; - sticker_song_find(db, base_uri, data.name, + sticker_song_find(sticker_database, db, base_uri, data.name, op, value, sticker_song_find_print_cb, &data); @@ -154,13 +160,18 @@ handle_sticker(Client &client, Request args, Response &r) { assert(args.size >= 3); - if (!sticker_enabled()) { + auto &instance = client.GetInstance(); + if (!instance.HasStickerDatabase()) { r.Error(ACK_ERROR_UNKNOWN, "sticker database is disabled"); return CommandResult::ERROR; } + auto &sticker_database = *instance.sticker_database; + if (StringIsEqual(args[1], "song")) - return handle_sticker_song(r, client.GetPartition(), args); + return handle_sticker_song(r, client.GetPartition(), + sticker_database, + args); else { r.Error(ACK_ERROR_ARG, "unknown sticker domain"); return CommandResult::ERROR; diff --git a/src/sticker/Database.cxx b/src/sticker/Database.cxx index 5e5f341c5..302ba3e3f 100644 --- a/src/sticker/Database.cxx +++ b/src/sticker/Database.cxx @@ -41,6 +41,7 @@ enum sticker_sql { STICKER_SQL_FIND_VALUE, STICKER_SQL_FIND_LT, STICKER_SQL_FIND_GT, + STICKER_SQL_COUNT }; static const char *const sticker_sql[] = { @@ -80,11 +81,7 @@ static const char sticker_sql_create[] = " sticker_value ON sticker(type, uri, name);" ""; -static sqlite3 *sticker_db; -static sqlite3_stmt *sticker_stmt[ARRAY_SIZE(sticker_sql)]; - -void -sticker_global_init(Path path) +StickerDatabase::StickerDatabase(Path path) { assert(!path.IsNull()); @@ -92,20 +89,20 @@ sticker_global_init(Path path) /* open/create the sqlite database */ - ret = sqlite3_open(path.c_str(), &sticker_db); + ret = sqlite3_open(path.c_str(), &db); if (ret != SQLITE_OK) { const std::string utf8 = path.ToUTF8(); - throw SqliteError(sticker_db, ret, + throw SqliteError(db, ret, ("Failed to open sqlite database '" + utf8 + "'").c_str()); } /* create the table and index */ - ret = sqlite3_exec(sticker_db, sticker_sql_create, + ret = sqlite3_exec(db, sticker_sql_create, nullptr, nullptr, nullptr); if (ret != SQLITE_OK) - throw SqliteError(sticker_db, ret, + throw SqliteError(db, ret, "Failed to create sticker table"); /* prepare the statements we're going to use */ @@ -113,38 +110,28 @@ sticker_global_init(Path path) for (unsigned i = 0; i < ARRAY_SIZE(sticker_sql); ++i) { assert(sticker_sql[i] != nullptr); - sticker_stmt[i] = Prepare(sticker_db, sticker_sql[i]); + stmt[i] = Prepare(db, sticker_sql[i]); } } -void -sticker_global_finish() noexcept +StickerDatabase::~StickerDatabase() noexcept { - if (sticker_db == nullptr) - /* not configured */ - return; + assert(db != nullptr); - for (unsigned i = 0; i < ARRAY_SIZE(sticker_stmt); ++i) { - assert(sticker_stmt[i] != nullptr); + for (unsigned i = 0; i < ARRAY_SIZE(stmt); ++i) { + assert(stmt[i] != nullptr); - sqlite3_finalize(sticker_stmt[i]); + sqlite3_finalize(stmt[i]); } - sqlite3_close(sticker_db); -} - -bool -sticker_enabled() noexcept -{ - return sticker_db != nullptr; + sqlite3_close(db); } std::string -sticker_load_value(const char *type, const char *uri, const char *name) +StickerDatabase::LoadValue(const char *type, const char *uri, const char *name) { - sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_GET]; + sqlite3_stmt *const s = stmt[STICKER_SQL_GET]; - assert(sticker_enabled()); assert(type != nullptr); assert(uri != nullptr); assert(name != nullptr); @@ -152,49 +139,48 @@ sticker_load_value(const char *type, const char *uri, const char *name) if (StringIsEmpty(name)) return std::string(); - BindAll(stmt, type, uri, name); + BindAll(s, type, uri, name); - AtScopeExit(stmt) { - sqlite3_reset(stmt); - sqlite3_clear_bindings(stmt); + AtScopeExit(s) { + sqlite3_reset(s); + sqlite3_clear_bindings(s); }; std::string value; - if (ExecuteRow(stmt)) - value = (const char*)sqlite3_column_text(stmt, 0); + if (ExecuteRow(s)) + value = (const char*)sqlite3_column_text(s, 0); return value; } -static void -sticker_list_values(std::map &table, - const char *type, const char *uri) +void +StickerDatabase::ListValues(std::map &table, + const char *type, const char *uri) { - sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_LIST]; + sqlite3_stmt *const s = stmt[STICKER_SQL_LIST]; assert(type != nullptr); assert(uri != nullptr); - assert(sticker_enabled()); - BindAll(stmt, type, uri); + BindAll(s, type, uri); - AtScopeExit(stmt) { - sqlite3_reset(stmt); - sqlite3_clear_bindings(stmt); + AtScopeExit(s) { + sqlite3_reset(s); + sqlite3_clear_bindings(s); }; - ExecuteForEach(stmt, [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)); - }); + ExecuteForEach(s, [s, &table](){ + const char *name = (const char *)sqlite3_column_text(s, 0); + const char *value = (const char *)sqlite3_column_text(s, 1); + table.insert(std::make_pair(name, value)); + }); } -static bool -sticker_update_value(const char *type, const char *uri, - const char *name, const char *value) +bool +StickerDatabase::UpdateValue(const char *type, const char *uri, + const char *name, const char *value) { - sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_UPDATE]; + sqlite3_stmt *const s = stmt[STICKER_SQL_UPDATE]; assert(type != nullptr); assert(uri != nullptr); @@ -202,27 +188,25 @@ sticker_update_value(const char *type, const char *uri, assert(*name != 0); assert(value != nullptr); - assert(sticker_enabled()); + BindAll(s, value, type, uri, name); - BindAll(stmt, value, type, uri, name); - - AtScopeExit(stmt) { - sqlite3_reset(stmt); - sqlite3_clear_bindings(stmt); + AtScopeExit(s) { + sqlite3_reset(s); + sqlite3_clear_bindings(s); }; - bool modified = ExecuteModified(stmt); + bool modified = ExecuteModified(s); if (modified) idle_add(IDLE_STICKER); return modified; } -static void -sticker_insert_value(const char *type, const char *uri, - const char *name, const char *value) +void +StickerDatabase::InsertValue(const char *type, const char *uri, + const char *name, const char *value) { - sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_INSERT]; + sqlite3_stmt *const s = stmt[STICKER_SQL_INSERT]; assert(type != nullptr); assert(uri != nullptr); @@ -230,24 +214,21 @@ sticker_insert_value(const char *type, const char *uri, assert(*name != 0); assert(value != nullptr); - assert(sticker_enabled()); + BindAll(s, type, uri, name, value); - BindAll(stmt, type, uri, name, value); - - AtScopeExit(stmt) { - sqlite3_reset(stmt); - sqlite3_clear_bindings(stmt); + AtScopeExit(s) { + sqlite3_reset(s); + sqlite3_clear_bindings(s); }; - ExecuteCommand(stmt); + ExecuteCommand(s); idle_add(IDLE_STICKER); } void -sticker_store_value(const char *type, const char *uri, - const char *name, const char *value) +StickerDatabase::StoreValue(const char *type, const char *uri, + const char *name, const char *value) { - assert(sticker_enabled()); assert(type != nullptr); assert(uri != nullptr); assert(name != nullptr); @@ -256,67 +237,67 @@ sticker_store_value(const char *type, const char *uri, if (StringIsEmpty(name)) return; - if (!sticker_update_value(type, uri, name, value)) - sticker_insert_value(type, uri, name, value); + if (!UpdateValue(type, uri, name, value)) + InsertValue(type, uri, name, value); } bool -sticker_delete(const char *type, const char *uri) +StickerDatabase::Delete(const char *type, const char *uri) { - sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_DELETE]; + sqlite3_stmt *const s = stmt[STICKER_SQL_DELETE]; - assert(sticker_enabled()); assert(type != nullptr); assert(uri != nullptr); - BindAll(stmt, type, uri); + BindAll(s, type, uri); - AtScopeExit(stmt) { - sqlite3_reset(stmt); - sqlite3_clear_bindings(stmt); + AtScopeExit(s) { + sqlite3_reset(s); + sqlite3_clear_bindings(s); }; - bool modified = ExecuteModified(stmt); + bool modified = ExecuteModified(s); if (modified) idle_add(IDLE_STICKER); return modified; } bool -sticker_delete_value(const char *type, const char *uri, const char *name) +StickerDatabase::DeleteValue(const char *type, const char *uri, + const char *name) { - sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_DELETE_VALUE]; + sqlite3_stmt *const s = stmt[STICKER_SQL_DELETE_VALUE]; - assert(sticker_enabled()); assert(type != nullptr); assert(uri != nullptr); - BindAll(stmt, type, uri, name); + BindAll(s, type, uri, name); - AtScopeExit(stmt) { - sqlite3_reset(stmt); - sqlite3_clear_bindings(stmt); + AtScopeExit(s) { + sqlite3_reset(s); + sqlite3_clear_bindings(s); }; - bool modified = ExecuteModified(stmt); + bool modified = ExecuteModified(s); if (modified) idle_add(IDLE_STICKER); return modified; } Sticker -sticker_load(const char *type, const char *uri) +StickerDatabase::Load(const char *type, const char *uri) { Sticker s; - sticker_list_values(s.table, type, uri); + ListValues(s.table, type, uri); return s; } -static sqlite3_stmt * -BindFind(const char *type, const char *base_uri, const char *name, - StickerOperator op, const char *value) +sqlite3_stmt * +StickerDatabase::BindFind(const char *type, const char *base_uri, + const char *name, + StickerOperator op, const char *value) { assert(type != nullptr); assert(name != nullptr); @@ -326,23 +307,23 @@ BindFind(const char *type, const char *base_uri, const char *name, switch (op) { case StickerOperator::EXISTS: - BindAll(sticker_stmt[STICKER_SQL_FIND], type, base_uri, name); - return sticker_stmt[STICKER_SQL_FIND]; + BindAll(stmt[STICKER_SQL_FIND], type, base_uri, name); + return stmt[STICKER_SQL_FIND]; case StickerOperator::EQUALS: - BindAll(sticker_stmt[STICKER_SQL_FIND_VALUE], + BindAll(stmt[STICKER_SQL_FIND_VALUE], type, base_uri, name, value); - return sticker_stmt[STICKER_SQL_FIND_VALUE]; + return stmt[STICKER_SQL_FIND_VALUE]; case StickerOperator::LESS_THAN: - BindAll(sticker_stmt[STICKER_SQL_FIND_LT], + BindAll(stmt[STICKER_SQL_FIND_LT], type, base_uri, name, value); - return sticker_stmt[STICKER_SQL_FIND_LT]; + return stmt[STICKER_SQL_FIND_LT]; case StickerOperator::GREATER_THAN: - BindAll(sticker_stmt[STICKER_SQL_FIND_GT], + BindAll(stmt[STICKER_SQL_FIND_GT], type, base_uri, name, value); - return sticker_stmt[STICKER_SQL_FIND_GT]; + return stmt[STICKER_SQL_FIND_GT]; } assert(false); @@ -350,26 +331,25 @@ BindFind(const char *type, const char *base_uri, const char *name, } void -sticker_find(const char *type, const char *base_uri, const char *name, - StickerOperator op, const char *value, - void (*func)(const char *uri, const char *value, - void *user_data), - void *user_data) +StickerDatabase::Find(const char *type, const char *base_uri, const char *name, + StickerOperator op, const char *value, + void (*func)(const char *uri, const char *value, + void *user_data), + void *user_data) { assert(func != nullptr); - assert(sticker_enabled()); - sqlite3_stmt *const stmt = BindFind(type, base_uri, name, op, value); - assert(stmt != nullptr); + sqlite3_stmt *const s = BindFind(type, base_uri, name, op, value); + assert(s != nullptr); - AtScopeExit(stmt) { - sqlite3_reset(stmt); - sqlite3_clear_bindings(stmt); + AtScopeExit(s) { + sqlite3_reset(s); + sqlite3_clear_bindings(s); }; - ExecuteForEach(stmt, [stmt, func, user_data](){ - func((const char*)sqlite3_column_text(stmt, 0), - (const char*)sqlite3_column_text(stmt, 1), + ExecuteForEach(s, [s, func, user_data](){ + func((const char*)sqlite3_column_text(s, 0), + (const char*)sqlite3_column_text(s, 1), user_data); }); } diff --git a/src/sticker/Database.hxx b/src/sticker/Database.hxx index dbaac8080..efc94b3ca 100644 --- a/src/sticker/Database.hxx +++ b/src/sticker/Database.hxx @@ -45,96 +45,116 @@ #include "Match.hxx" #include "util/Compiler.h" +#include + +#include #include class Path; struct Sticker; -/** - * Opens the sticker database. - * - * Throws std::runtime_error on error. - */ -void -sticker_global_init(Path path); +class StickerDatabase { + enum SQL { + SQL_GET, + SQL_LIST, + SQL_UPDATE, + SQL_INSERT, + SQL_DELETE, + SQL_DELETE_VALUE, + SQL_FIND, + SQL_FIND_VALUE, + SQL_FIND_LT, + SQL_FIND_GT, -/** - * Close the sticker database. - */ -void -sticker_global_finish() noexcept; + SQL_COUNT + }; -/** - * Returns true if the sticker database is configured and available. - */ -gcc_const -bool -sticker_enabled() noexcept; + sqlite3 *db; + sqlite3_stmt *stmt[SQL_COUNT]; -/** - * Returns one value from an object's sticker record. Returns an - * empty string if the value doesn't exist. - * - * Throws #SqliteError on error. - */ -std::string -sticker_load_value(const char *type, const char *uri, const char *name); +public: + /** + * Opens the sticker database. + * + * Throws on error. + */ + StickerDatabase(Path path); + ~StickerDatabase() noexcept; -/** - * Sets a sticker value in the specified object. Overwrites existing - * values. - * - * Throws #SqliteError on error. - */ -void -sticker_store_value(const char *type, const char *uri, - const char *name, const char *value); + /** + * Returns one value from an object's sticker record. Returns an + * empty string if the value doesn't exist. + * + * Throws #SqliteError on error. + */ + std::string LoadValue(const char *type, const char *uri, + const char *name); -/** - * Deletes a sticker from the database. All sticker values of the - * specified object are deleted. - * - * Throws #SqliteError on error. - */ -bool -sticker_delete(const char *type, const char *uri); + /** + * Sets a sticker value in the specified object. Overwrites existing + * values. + * + * Throws #SqliteError on error. + */ + void StoreValue(const char *type, const char *uri, + const char *name, const char *value); -/** - * Deletes a sticker value. Fails if no sticker with this name - * exists. - * - * Throws #SqliteError on error. - */ -bool -sticker_delete_value(const char *type, const char *uri, const char *name); + /** + * Deletes a sticker from the database. All sticker values of the + * specified object are deleted. + * + * Throws #SqliteError on error. + */ + bool Delete(const char *type, const char *uri); -/** - * Loads the sticker for the specified resource. - * - * Throws #SqliteError on error. - * - * @param type the resource type, e.g. "song" - * @param uri the URI of the resource, e.g. the song path - * @return a sticker object - */ -Sticker -sticker_load(const char *type, const char *uri); + /** + * Deletes a sticker value. Fails if no sticker with this name + * exists. + * + * Throws #SqliteError on error. + */ + bool DeleteValue(const char *type, const char *uri, const char *name); -/** - * Finds stickers with the specified name below the specified URI. - * - * @param type the resource type, e.g. "song" - * @param base_uri the URI prefix of the resources, or nullptr if all - * resources should be searched - * @param name the name of the sticker - * @param op the comparison operator - * @param value the operand - */ -void -sticker_find(const char *type, const char *base_uri, const char *name, - StickerOperator op, const char *value, - void (*func)(const char *uri, const char *value, - void *user_data), - void *user_data); + /** + * Loads the sticker for the specified resource. + * + * Throws #SqliteError on error. + * + * @param type the resource type, e.g. "song" + * @param uri the URI of the resource, e.g. the song path + * @return a sticker object + */ + Sticker Load(const char *type, const char *uri); + + /** + * Finds stickers with the specified name below the specified URI. + * + * @param type the resource type, e.g. "song" + * @param base_uri the URI prefix of the resources, or nullptr if all + * resources should be searched + * @param name the name of the sticker + * @param op the comparison operator + * @param value the operand + */ + void Find(const char *type, const char *base_uri, const char *name, + StickerOperator op, const char *value, + void (*func)(const char *uri, const char *value, + void *user_data), + void *user_data); + +private: + void ListValues(std::map &table, + const char *type, const char *uri); + + bool UpdateValue(const char *type, const char *uri, + const char *name, const char *value); + + void InsertValue(const char *type, const char *uri, + const char *name, const char *value); + + sqlite3_stmt *BindFind(const char *type, const char *base_uri, + const char *name, + StickerOperator op, const char *value); +}; #endif diff --git a/src/sticker/SongSticker.cxx b/src/sticker/SongSticker.cxx index 1c43f4d04..5b4683672 100644 --- a/src/sticker/SongSticker.cxx +++ b/src/sticker/SongSticker.cxx @@ -29,44 +29,47 @@ #include std::string -sticker_song_get_value(const LightSong &song, const char *name) +sticker_song_get_value(StickerDatabase &db, + const LightSong &song, const char *name) { const auto uri = song.GetURI(); - return sticker_load_value("song", uri.c_str(), name); + return db.LoadValue("song", uri.c_str(), name); } void -sticker_song_set_value(const LightSong &song, +sticker_song_set_value(StickerDatabase &db, + const LightSong &song, const char *name, const char *value) { const auto uri = song.GetURI(); - sticker_store_value("song", uri.c_str(), name, value); + db.StoreValue("song", uri.c_str(), name, value); } bool -sticker_song_delete(const char *uri) +sticker_song_delete(StickerDatabase &db, const char *uri) { - return sticker_delete("song", uri); + return db.Delete("song", uri); } bool -sticker_song_delete(const LightSong &song) +sticker_song_delete(StickerDatabase &db, const LightSong &song) { - return sticker_song_delete(song.GetURI().c_str()); + return sticker_song_delete(db, song.GetURI().c_str()); } bool -sticker_song_delete_value(const LightSong &song, const char *name) +sticker_song_delete_value(StickerDatabase &db, + const LightSong &song, const char *name) { const auto uri = song.GetURI(); - return sticker_delete_value("song", uri.c_str(), name); + return db.DeleteValue("song", uri.c_str(), name); } Sticker -sticker_song_get(const LightSong &song) +sticker_song_get(StickerDatabase &db, const LightSong &song) { const auto uri = song.GetURI(); - return sticker_load("song", uri.c_str()); + return db.Load("song", uri.c_str()); } namespace { @@ -101,7 +104,8 @@ sticker_song_find_cb(const char *uri, const char *value, void *user_data) } void -sticker_song_find(const Database &db, const char *base_uri, const char *name, +sticker_song_find(StickerDatabase &sticker_database, const Database &db, + const char *base_uri, const char *name, StickerOperator op, const char *value, void (*func)(const LightSong &song, const char *value, void *user_data), @@ -126,6 +130,6 @@ sticker_song_find(const Database &db, const char *base_uri, const char *name, data.base_uri_length = strlen(data.base_uri); - sticker_find("song", data.base_uri, name, op, value, - sticker_song_find_cb, &data); + sticker_database.Find("song", data.base_uri, name, op, value, + sticker_song_find_cb, &data); } diff --git a/src/sticker/SongSticker.hxx b/src/sticker/SongSticker.hxx index 28f3eca7c..ed76e9c4c 100644 --- a/src/sticker/SongSticker.hxx +++ b/src/sticker/SongSticker.hxx @@ -27,6 +27,7 @@ struct LightSong; struct Sticker; class Database; +class StickerDatabase; /** * Returns one value from a song's sticker record. @@ -34,7 +35,8 @@ class Database; * Throws #SqliteError on error. */ std::string -sticker_song_get_value(const LightSong &song, const char *name); +sticker_song_get_value(StickerDatabase &db, + const LightSong &song, const char *name); /** * Sets a sticker value in the specified song. Overwrites existing @@ -43,7 +45,8 @@ sticker_song_get_value(const LightSong &song, const char *name); * Throws #SqliteError on error. */ void -sticker_song_set_value(const LightSong &song, +sticker_song_set_value(StickerDatabase &db, + const LightSong &song, const char *name, const char *value); /** @@ -52,10 +55,10 @@ sticker_song_set_value(const LightSong &song, * Throws #SqliteError on error. */ bool -sticker_song_delete(const char *uri); +sticker_song_delete(StickerDatabase &db, const char *uri); bool -sticker_song_delete(const LightSong &song); +sticker_song_delete(StickerDatabase &db, const LightSong &song); /** * Deletes a sticker value. Does nothing if the sticker did not @@ -64,7 +67,8 @@ sticker_song_delete(const LightSong &song); * Throws #SqliteError on error. */ bool -sticker_song_delete_value(const LightSong &song, const char *name); +sticker_song_delete_value(StickerDatabase &db, + const LightSong &song, const char *name); /** * Loads the sticker for the specified song. @@ -75,7 +79,7 @@ sticker_song_delete_value(const LightSong &song, const char *name); * @return a sticker object */ Sticker -sticker_song_get(const LightSong &song); +sticker_song_get(StickerDatabase &db, const LightSong &song); /** * Finds stickers with the specified name below the specified @@ -89,7 +93,8 @@ sticker_song_get(const LightSong &song); * @param name the name of the sticker */ void -sticker_song_find(const Database &db, const char *base_uri, const char *name, +sticker_song_find(StickerDatabase &sticker_database, const Database &db, + const char *base_uri, const char *name, StickerOperator op, const char *value, void (*func)(const LightSong &song, const char *value, void *user_data),