From 689d1ce3dd850e50e3f0bea2e50ea6528584a040 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Sun, 24 Jan 2021 01:14:56 +0100 Subject: [PATCH 1/6] [db] Refactor queue_item functions - Use prepared statements - Add qi_mfi_map that defines mapping between mfi, dbmfi and qi - Use qi_cols_map/qi_mfi_map for iteration (avoid duplicating field references) - Stick to "qi" as name for a queue_item in db.c (more similar to mfi/pli/gri) - Some renaming and other minor stuff in db.c's queue code --- src/db.c | 579 ++++++++++++++++++++++++-------------- src/db.h | 14 +- src/httpd_jsonapi.c | 2 +- src/library/filescanner.c | 44 +-- src/player.c | 2 +- src/spotify_webapi.c | 6 +- 6 files changed, 382 insertions(+), 265 deletions(-) diff --git a/src/db.c b/src/db.c index cb1f1172..b6b058f1 100644 --- a/src/db.c +++ b/src/db.c @@ -112,16 +112,26 @@ struct db_statements sqlite3_stmt *playlists_insert; sqlite3_stmt *playlists_update; + + sqlite3_stmt *queue_items_insert; + sqlite3_stmt *queue_items_update; }; struct col_type_map { char *name; - size_t offset; + ssize_t offset; short type; enum fixup_type fixup; short flag; }; +struct qi_mfi_map +{ + ssize_t qi_offset; + ssize_t mfi_offset; + ssize_t dbmfi_offset; +}; + struct fixup_ctx { const struct col_type_map *map; @@ -129,7 +139,7 @@ struct fixup_ctx void *data; struct media_file_info *mfi; struct playlist_info *pli; - struct db_queue_item *queue_item; + struct db_queue_item *qi; }; struct query_clause { @@ -248,11 +258,12 @@ static const struct col_type_map pli_cols_map[] = /* This list must be kept in sync with * - the order of the columns in the queue table * - the type and name of the fields in struct db_queue_item + * - with qi_mfi_map */ static const struct col_type_map qi_cols_map[] = { { "id", qi_offsetof(id), DB_TYPE_INT, DB_FIXUP_STANDARD, DB_FLAG_NO_BIND }, - { "file_id", qi_offsetof(id), DB_TYPE_INT }, + { "file_id", qi_offsetof(file_id), DB_TYPE_INT }, { "pos", qi_offsetof(pos), DB_TYPE_INT }, { "shuffle_pos", qi_offsetof(shuffle_pos), DB_TYPE_INT }, { "data_kind", qi_offsetof(data_kind), DB_TYPE_INT }, @@ -405,6 +416,43 @@ static const ssize_t dbgri_cols_map[] = dbgri_offsetof(seek), }; +/* This list must be kept in sync with + * - qi_cols_map + */ +static const struct qi_mfi_map qi_mfi_map[] = + { + { qi_offsetof(id), -1, -1 }, + { qi_offsetof(file_id), mfi_offsetof(id), dbmfi_offsetof(id) }, + { qi_offsetof(pos), -1, -1 }, + { qi_offsetof(shuffle_pos), -1, -1 }, + { qi_offsetof(data_kind), mfi_offsetof(data_kind), dbmfi_offsetof(data_kind) }, + { qi_offsetof(media_kind), mfi_offsetof(media_kind), dbmfi_offsetof(media_kind) }, + { qi_offsetof(song_length), mfi_offsetof(song_length), dbmfi_offsetof(song_length) }, + { qi_offsetof(path), mfi_offsetof(path), dbmfi_offsetof(path) }, + { qi_offsetof(virtual_path), mfi_offsetof(virtual_path), dbmfi_offsetof(virtual_path) }, + { qi_offsetof(title), mfi_offsetof(title), dbmfi_offsetof(title) }, + { qi_offsetof(artist), mfi_offsetof(artist), dbmfi_offsetof(artist) }, + { qi_offsetof(album_artist), mfi_offsetof(album_artist), dbmfi_offsetof(album_artist) }, + { qi_offsetof(album), mfi_offsetof(album), dbmfi_offsetof(album) }, + { qi_offsetof(genre), mfi_offsetof(genre), dbmfi_offsetof(genre) }, + { qi_offsetof(songalbumid), mfi_offsetof(songalbumid), dbmfi_offsetof(songalbumid) }, + { qi_offsetof(time_modified), mfi_offsetof(time_modified), dbmfi_offsetof(time_modified) }, + { qi_offsetof(artist_sort), mfi_offsetof(artist_sort), dbmfi_offsetof(artist_sort) }, + { qi_offsetof(album_sort), mfi_offsetof(album_sort), dbmfi_offsetof(album_sort) }, + { qi_offsetof(album_artist_sort), mfi_offsetof(album_artist_sort), dbmfi_offsetof(album_artist_sort) }, + { qi_offsetof(year), mfi_offsetof(year), dbmfi_offsetof(year) }, + { qi_offsetof(track), mfi_offsetof(track), dbmfi_offsetof(track) }, + { qi_offsetof(disc), mfi_offsetof(disc), dbmfi_offsetof(disc) }, + { qi_offsetof(artwork_url), -1, -1 }, + { qi_offsetof(queue_version), -1, -1 }, + { qi_offsetof(composer), mfi_offsetof(composer), dbmfi_offsetof(composer) }, + { qi_offsetof(songartistid), mfi_offsetof(songartistid), dbmfi_offsetof(songartistid) }, + { qi_offsetof(type), mfi_offsetof(type), dbmfi_offsetof(type) }, + { qi_offsetof(bitrate), mfi_offsetof(bitrate), dbmfi_offsetof(bitrate) }, + { qi_offsetof(samplerate), mfi_offsetof(samplerate), dbmfi_offsetof(samplerate) }, + { qi_offsetof(channels), mfi_offsetof(channels), dbmfi_offsetof(channels) }, + }; + /* This list must be kept in sync with * - the order of the columns in the inotify table * - the name and type of the fields in struct watch_info @@ -719,29 +767,73 @@ free_query_params(struct query_params *qp, int content_only) } void -free_queue_item(struct db_queue_item *queue_item, int content_only) +free_queue_item(struct db_queue_item *qi, int content_only) { - if (!queue_item) + if (!qi) return; - free(queue_item->path); - free(queue_item->virtual_path); - free(queue_item->title); - free(queue_item->artist); - free(queue_item->album_artist); - free(queue_item->composer); - free(queue_item->album); - free(queue_item->genre); - free(queue_item->artist_sort); - free(queue_item->album_sort); - free(queue_item->album_artist_sort); - free(queue_item->artwork_url); - free(queue_item->type); + free(qi->path); + free(qi->virtual_path); + free(qi->title); + free(qi->artist); + free(qi->album_artist); + free(qi->composer); + free(qi->album); + free(qi->genre); + free(qi->artist_sort); + free(qi->album_sort); + free(qi->album_artist_sort); + free(qi->artwork_url); + free(qi->type); if (!content_only) - free(queue_item); + free(qi); else - memset(queue_item, 0, sizeof(struct db_queue_item)); + memset(qi, 0, sizeof(struct db_queue_item)); +} + +// Utility function for stepping through mfi/pli/qi structs and setting the +// values from some source, which could be another struct. Some examples: +// - src is a dbmfi, dst is a qi, dst_type is DB_TYPE_INT, caller wants to own +// qi so must_strdup is true, dbmfi has strings so parse_integers is true +// - src is a **char, dst is a qi, dst_type is DB_TYPE_STRING, src_offset is 0 +// because src is not a struct, caller wants to strdup the string so +// must_strdup is true +static inline void +struct_set(void *dst_struct, ssize_t dst_offset, int dst_type, const void *src_struct, ssize_t src_offset, bool must_strdup, bool parse_integers) +{ + char *srcstr; + uint32_t srcu32val; + int64_t srci64val; + char **dstptr; + + srcstr = *(char **)(src_struct + src_offset); + + switch (dst_type) + { + case DB_TYPE_STRING: + dstptr = (char **)(dst_struct + dst_offset); + *dstptr = must_strdup ? safe_strdup(srcstr) : srcstr; + break; + + case DB_TYPE_INT: + if (parse_integers) + safe_atou32(srcstr, &srcu32val); + else + srcu32val = *(uint32_t *)(src_struct + src_offset); + + memcpy(dst_struct + dst_offset, &srcu32val, sizeof(srcu32val)); + break; + + case DB_TYPE_INT64: + if (parse_integers) + safe_atoi64(srcstr, &srci64val); + else + srci64val = *(int64_t *)(src_struct + src_offset); + + memcpy(dst_struct + dst_offset, &srci64val, sizeof(srci64val)); + break; + } } static void @@ -902,8 +994,8 @@ fixup_defaults(char **tag, enum fixup_type fixup, struct fixup_ctx *ctx) } else if (ctx->pli && ctx->pli->path) *tag = strdup(ctx->pli->path); - else if (ctx->queue_item && ctx->queue_item->path) - *tag = strdup(ctx->queue_item->path); + else if (ctx->qi && ctx->qi->path) + *tag = strdup(ctx->qi->path); else *tag = strdup(CFG_NAME_UNKNOWN_TITLE); break; @@ -950,8 +1042,8 @@ fixup_defaults(char **tag, enum fixup_type fixup, struct fixup_ctx *ctx) *tag = strdup(ca); // If ca is empty string then the artist will not be shown in artist view else if (ctx->mfi && ctx->mfi->artist) *tag = strdup(ctx->mfi->artist); - else if (ctx->queue_item && ctx->queue_item->artist) - *tag = strdup(ctx->queue_item->artist); + else if (ctx->qi && ctx->qi->artist) + *tag = strdup(ctx->qi->artist); else *tag = strdup(CFG_NAME_UNKNOWN_ARTIST); break; @@ -970,8 +1062,8 @@ fixup_defaults(char **tag, enum fixup_type fixup, struct fixup_ctx *ctx) ctx->mfi->media_kind = MEDIA_KIND_MUSIC; else if (ctx->pli && !ctx->pli->media_kind) ctx->pli->media_kind = MEDIA_KIND_MUSIC; - else if (ctx->queue_item && !ctx->queue_item->media_kind) - ctx->queue_item->media_kind = MEDIA_KIND_MUSIC; + else if (ctx->qi && !ctx->qi->media_kind) + ctx->qi->media_kind = MEDIA_KIND_MUSIC; break; @@ -1022,22 +1114,22 @@ fixup_sort_tags(char **tag, enum fixup_type fixup, struct fixup_ctx *ctx) case DB_FIXUP_ARTIST_SORT: if (ctx->mfi) sort_tag_create(tag, ctx->mfi->artist); - else if (ctx->queue_item) - sort_tag_create(tag, ctx->queue_item->artist); + else if (ctx->qi) + sort_tag_create(tag, ctx->qi->artist); break; case DB_FIXUP_ALBUM_SORT: if (ctx->mfi) sort_tag_create(tag, ctx->mfi->album); - else if (ctx->queue_item) - sort_tag_create(tag, ctx->queue_item->album); + else if (ctx->qi) + sort_tag_create(tag, ctx->qi->album); break; case DB_FIXUP_ALBUM_ARTIST_SORT: if (ctx->mfi) sort_tag_create(tag, ctx->mfi->album_artist); - else if (ctx->queue_item) - sort_tag_create(tag, ctx->queue_item->album_artist); + else if (ctx->qi) + sort_tag_create(tag, ctx->qi->album_artist); break; case DB_FIXUP_COMPOSER_SORT: @@ -1103,11 +1195,11 @@ fixup_tags_pli(struct playlist_info *pli) } static void -fixup_tags_queue_item(struct db_queue_item *queue_item) +fixup_tags_qi(struct db_queue_item *qi) { struct fixup_ctx ctx = { 0 }; - ctx.data = queue_item; - ctx.queue_item = queue_item; + ctx.data = qi; + ctx.qi = qi; ctx.map = qi_cols_map; ctx.map_size = ARRAY_SIZE(qi_cols_map); @@ -1171,6 +1263,12 @@ bind_pli(sqlite3_stmt *stmt, struct playlist_info *pli) return bind_generic(stmt, pli, pli_cols_map, ARRAY_SIZE(pli_cols_map), pli->id); } +static int +bind_qi(sqlite3_stmt *stmt, struct db_queue_item *qi) +{ + return bind_generic(stmt, qi, qi_cols_map, ARRAY_SIZE(qi_cols_map), qi->id); +} + /* Unlock notification support */ static void unlock_notify_cb(void **args, int nargs) @@ -4664,7 +4762,7 @@ queue_transaction_begin() * * This function must be called after modifying the queue. * - * @param retval 'retval' == 0, if modifying the queue was successful or 'retval' < 0 if an error occurred + * @param retval 'retval' >= 0, if modifying the queue was successful or 'retval' < 0 if an error occurred * @param queue_version The new queue version, for the pending modifications */ static void @@ -4672,7 +4770,7 @@ queue_transaction_end(int retval, int queue_version) { int ret; - if (retval != 0) + if (retval < 0) goto error; ret = db_admin_setint(DB_ADMIN_QUEUE_VERSION, queue_version); @@ -4691,116 +4789,139 @@ static int queue_reshuffle(uint32_t item_id, int queue_version); static int -queue_add_file(struct db_media_file_info *dbmfi, int pos, int shuffle_pos, int queue_version) +queue_item_add(struct db_queue_item *qi) { -#define Q_TMPL "INSERT INTO queue " \ - "(id, file_id, song_length, data_kind, media_kind, " \ - "pos, shuffle_pos, path, virtual_path, title, " \ - "artist, composer, album_artist, album, genre, songalbumid, songartistid," \ - "time_modified, artist_sort, album_sort, album_artist_sort, year, " \ - "type, bitrate, samplerate, channels, " \ - "track, disc, queue_version)" \ - "VALUES" \ - "(NULL, %s, %s, %s, %s, " \ - "%d, %d, %Q, %Q, %Q, " \ - "%Q, %Q, %Q, %Q, %Q, %s, %s," \ - "%s, %Q, %Q, %Q, %s, " \ - "%Q, %s, %s, %s, " \ - "%s, %s, %d);" - - char *query; int ret; - query = sqlite3_mprintf(Q_TMPL, - dbmfi->id, dbmfi->song_length, dbmfi->data_kind, dbmfi->media_kind, - pos, shuffle_pos, dbmfi->path, dbmfi->virtual_path, dbmfi->title, - dbmfi->artist, dbmfi->composer, dbmfi->album_artist, dbmfi->album, dbmfi->genre, dbmfi->songalbumid, dbmfi->songartistid, - dbmfi->time_modified, dbmfi->artist_sort, dbmfi->album_sort, dbmfi->album_artist_sort, dbmfi->year, - dbmfi->type, dbmfi->bitrate, dbmfi->samplerate, dbmfi->channels, - dbmfi->track, dbmfi->disc, queue_version); - ret = db_query_run(query, 1, 0); + fixup_tags_qi(qi); + + ret = bind_qi(db_statements.queue_items_insert, qi); + if (ret < 0) + return -1; + + // Do not update events here, only caller knows if more items will be added + ret = db_statement_run(db_statements.queue_items_insert, 0); + if (ret < 0) + return -1; + + ret = (int)sqlite3_last_insert_rowid(hdl); + if (ret == 0) + { + DPRINTF(E_LOG, L_DB, "Successful queue item insert but no last_insert_rowid!\n"); + return -1; + } return ret; - -#undef Q_TMPL } static int -queue_add_item(struct db_queue_item *item, int pos, int shuffle_pos, int queue_version) +queue_item_add_from_file(struct db_media_file_info *dbmfi, int pos, int shuffle_pos, int queue_version) { -#define Q_TMPL "INSERT INTO queue " \ - "(id, file_id, song_length, data_kind, media_kind, " \ - "pos, shuffle_pos, path, virtual_path, title, " \ - "artist, composer, album_artist, album, genre, songalbumid, songartistid, " \ - "time_modified, artist_sort, album_sort, album_artist_sort, year, " \ - "type, bitrate, samplerate, channels, " \ - "track, disc, artwork_url, queue_version)" \ - "VALUES" \ - "(NULL, %d, %d, %d, %d, " \ - "%d, %d, %Q, %Q, %Q, " \ - "%Q, %Q, %Q, %Q, %Q, %" PRIi64 ", %" PRIi64 "," \ - "%d, %Q, %Q, %Q, %d, " \ - "%Q, %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", " \ - "%d, %d, %Q, %d);" - - char *query; + struct db_queue_item qi; int ret; - query = sqlite3_mprintf(Q_TMPL, - item->file_id, item->song_length, item->data_kind, item->media_kind, - pos, shuffle_pos, item->path, item->virtual_path, item->title, - item->artist, item->composer, item->album_artist, item->album, item->genre, item->songalbumid, item->songartistid, - item->time_modified, item->artist_sort, item->album_sort, item->album_artist_sort, item->year, - item->type, item->bitrate, item->samplerate, item->channels, - item->track, item->disc, item->artwork_url, queue_version); - ret = db_query_run(query, 1, 0); + // No allocations, just the struct content is copied + db_queue_item_from_dbmfi(&qi, dbmfi); + + // No tag fixup, we can't touch the strings in qi, plus must assume dbmfi has proper tags + + qi.pos = pos; + qi.shuffle_pos = shuffle_pos; + qi.queue_version = queue_version; + + ret = bind_qi(db_statements.queue_items_insert, &qi); + if (ret < 0) + return -1; + + // Do not update events here, only caller knows if more items will be added + ret = db_statement_run(db_statements.queue_items_insert, 0); + if (ret < 0) + return -1; + + ret = (int)sqlite3_last_insert_rowid(hdl); + if (ret == 0) + { + DPRINTF(E_LOG, L_DB, "Successful queue item insert but no last_insert_rowid!\n"); + return -1; + } return ret; - -#undef Q_TMPL } -int -db_queue_update_item(struct db_queue_item *qi) +static int +queue_item_update(struct db_queue_item *qi) { -#define Q_TMPL "UPDATE queue SET " \ - "file_id = %d, song_length = %d, data_kind = %d, media_kind = %d, " \ - "pos = %d, shuffle_pos = %d, path = '%q', virtual_path = %Q, " \ - "title = %Q, artist = %Q, album_artist = %Q, album = %Q, " \ - "composer = %Q, " \ - "genre = %Q, time_modified = %d, " \ - "songalbumid = %" PRIi64 ", songartistid = %" PRIi64 ", " \ - "artist_sort = %Q, album_sort = %Q, album_artist_sort = %Q, " \ - "year = %d, track = %d, disc = %d, artwork_url = %Q, " \ - "queue_version = %d " \ - "WHERE id = %d;" - - int queue_version; - char *query; int ret; - fixup_tags_queue_item(qi); + fixup_tags_qi(qi); + + ret = bind_qi(db_statements.queue_items_update, qi); + if (ret < 0) + return -1; + + // Do not update events here, only caller knows if more items will be updated + ret = db_statement_run(db_statements.queue_items_update, 0); + if (ret < 0) + return -1; + + return qi->id; +} + +void +db_queue_item_from_mfi(struct db_queue_item *qi, struct media_file_info *mfi) +{ + int i; + + memset(qi, 0, sizeof(struct db_queue_item)); + + for (i = 0; i < ARRAY_SIZE(qi_mfi_map); i++) + { + if (qi_mfi_map[i].mfi_offset < 0) + continue; + + struct_set(qi, qi_cols_map[i].offset, qi_cols_map[i].type, mfi, qi_mfi_map[i].mfi_offset, true, false); + } + + if (!qi->file_id) + qi->file_id = DB_MEDIA_FILE_NON_PERSISTENT_ID; +} + +void +db_queue_item_from_dbmfi(struct db_queue_item *qi, struct db_media_file_info *dbmfi) +{ + int i; + + memset(qi, 0, sizeof(struct db_queue_item)); + + for (i = 0; i < ARRAY_SIZE(qi_mfi_map); i++) + { + if (qi_mfi_map[i].dbmfi_offset < 0) + continue; + + struct_set(qi, qi_cols_map[i].offset, qi_cols_map[i].type, dbmfi, qi_mfi_map[i].dbmfi_offset, false, true); + } + + if (!qi->file_id) + qi->file_id = DB_MEDIA_FILE_NON_PERSISTENT_ID; +} + + +int +db_queue_item_update(struct db_queue_item *qi) +{ + int queue_version; + int ret; queue_version = queue_transaction_begin(); - query = sqlite3_mprintf(Q_TMPL, - qi->file_id, qi->song_length, qi->data_kind, qi->media_kind, - qi->pos, qi->shuffle_pos, qi->path, qi->virtual_path, - qi->title, qi->artist, qi->album_artist, qi->album, - qi->composer, - qi->genre, qi->time_modified, - qi->songalbumid, qi->songartistid, - qi->artist_sort, qi->album_sort, qi->album_artist_sort, - qi->year, qi->track, qi->disc, qi->artwork_url, queue_version, - qi->id); + qi->queue_version = queue_version; - ret = db_query_run(query, 1, 0); + ret = queue_item_update(qi); - /* MPD changes playlist version when metadata changes */ + // MPD changes playlist version when metadata changes, also makes LISTENER_QUEUE queue_transaction_end(ret, queue_version); return ret; -#undef Q_TMPL } /* @@ -4888,25 +5009,26 @@ db_queue_add_end(struct db_queue_add_info *queue_add_info, char reshuffle, uint3 } int -db_queue_add_item(struct db_queue_add_info *queue_add_info, struct db_queue_item *item) +db_queue_add_next(struct db_queue_add_info *queue_add_info, struct db_queue_item *qi) { int ret; - fixup_tags_queue_item(item); - ret = queue_add_item(item, queue_add_info->pos, queue_add_info->shuffle_pos, queue_add_info->queue_version); - if (ret == 0) - { - queue_add_info->pos++; - queue_add_info->shuffle_pos++; - queue_add_info->count++; + qi->pos = queue_add_info->pos; + qi->shuffle_pos = queue_add_info->shuffle_pos; + qi->queue_version = queue_add_info->queue_version; - if (queue_add_info->new_item_id == 0) - queue_add_info->new_item_id = (int) sqlite3_last_insert_rowid(hdl); - } + ret = queue_item_add(qi); + if (ret < 0) + return ret; + + queue_add_info->pos++; + queue_add_info->shuffle_pos++; + queue_add_info->count++; + + if (queue_add_info->new_item_id == 0) + queue_add_info->new_item_id = ret; return ret; - -#undef Q_TMPL } /* @@ -4980,7 +5102,7 @@ db_queue_add_by_query(struct query_params *qp, char reshuffle, uint32_t item_id, while (((ret = db_query_fetch_file(qp, &dbmfi)) == 0) && (dbmfi.id)) { - ret = queue_add_file(&dbmfi, pos, queue_count, queue_version); + ret = queue_item_add_from_file(&dbmfi, pos, queue_count, queue_version); if (ret < 0) { @@ -4988,10 +5110,10 @@ db_queue_add_by_query(struct query_params *qp, char reshuffle, uint32_t item_id, break; } - DPRINTF(E_DBG, L_DB, "Added song id %s (%s) to queue\n", dbmfi.id, dbmfi.title); + DPRINTF(E_DBG, L_DB, "Added song id %s (%s) to queue with item id %d\n", dbmfi.id, dbmfi.title, ret); if (new_item_id && *new_item_id == 0) - *new_item_id = (int) sqlite3_last_insert_rowid(hdl); + *new_item_id = ret; if (count) (*count)++; @@ -5133,11 +5255,16 @@ strdup_if(char *str, int cond) } static int -queue_enum_fetch(struct query_params *qp, struct db_queue_item *queue_item, int keep_item) +queue_enum_fetch(struct query_params *qp, struct db_queue_item *qi, int must_strdup) { + const void *srcptr; + const char *str; + int32_t i32; + int64_t i64; int ret; + int i; - memset(queue_item, 0, sizeof(struct db_queue_item)); + memset(qi, 0, sizeof(struct db_queue_item)); if (!qp->stmt) { @@ -5157,36 +5284,32 @@ queue_enum_fetch(struct query_params *qp, struct db_queue_item *queue_item, int return -1; } - queue_item->id = (uint32_t)sqlite3_column_int(qp->stmt, 0); - queue_item->file_id = (uint32_t)sqlite3_column_int(qp->stmt, 1); - queue_item->pos = (uint32_t)sqlite3_column_int(qp->stmt, 2); - queue_item->shuffle_pos = (uint32_t)sqlite3_column_int(qp->stmt, 3); - queue_item->data_kind = sqlite3_column_int(qp->stmt, 4); - queue_item->media_kind = sqlite3_column_int(qp->stmt, 5); - queue_item->song_length = (uint32_t)sqlite3_column_int(qp->stmt, 6); - queue_item->path = strdup_if((char *)sqlite3_column_text(qp->stmt, 7), keep_item); - queue_item->virtual_path = strdup_if((char *)sqlite3_column_text(qp->stmt, 8), keep_item); - queue_item->title = strdup_if((char *)sqlite3_column_text(qp->stmt, 9), keep_item); - queue_item->artist = strdup_if((char *)sqlite3_column_text(qp->stmt, 10), keep_item); - queue_item->album_artist = strdup_if((char *)sqlite3_column_text(qp->stmt, 11), keep_item); - queue_item->album = strdup_if((char *)sqlite3_column_text(qp->stmt, 12), keep_item); - queue_item->genre = strdup_if((char *)sqlite3_column_text(qp->stmt, 13), keep_item); - queue_item->songalbumid = sqlite3_column_int64(qp->stmt, 14); - queue_item->time_modified = sqlite3_column_int(qp->stmt, 15); - queue_item->artist_sort = strdup_if((char *)sqlite3_column_text(qp->stmt, 16), keep_item); - queue_item->album_sort = strdup_if((char *)sqlite3_column_text(qp->stmt, 17), keep_item); - queue_item->album_artist_sort = strdup_if((char *)sqlite3_column_text(qp->stmt, 18), keep_item); - queue_item->year = sqlite3_column_int(qp->stmt, 19); - queue_item->track = sqlite3_column_int(qp->stmt, 20); - queue_item->disc = sqlite3_column_int(qp->stmt, 21); - queue_item->artwork_url = strdup_if((char *)sqlite3_column_text(qp->stmt, 22), keep_item); - queue_item->queue_version = sqlite3_column_int(qp->stmt, 23); - queue_item->composer = strdup_if((char *)sqlite3_column_text(qp->stmt, 24), keep_item); - queue_item->songartistid = sqlite3_column_int64(qp->stmt, 25); - queue_item->type = strdup_if((char *)sqlite3_column_text(qp->stmt, 26), keep_item); - queue_item->bitrate = sqlite3_column_int(qp->stmt, 27); - queue_item->samplerate = sqlite3_column_int(qp->stmt, 28); - queue_item->channels = sqlite3_column_int(qp->stmt, 29); + for (i = 0; i < ARRAY_SIZE(qi_cols_map); i++) + { + switch (qi_cols_map[i].type) + { + case DB_TYPE_STRING: + str = (const char *)sqlite3_column_text(qp->stmt, i); + srcptr = &str; + break; + + case DB_TYPE_INT: + i32 = sqlite3_column_int(qp->stmt, i); + srcptr = &i32; + break; + + case DB_TYPE_INT64: + i64 = sqlite3_column_int64(qp->stmt, i); + srcptr = &i64; + break; + + default: + DPRINTF(E_LOG, L_DB, "BUG! Unknown data type (%d) in queue_enum_fetch()\n", qi_cols_map[i].type); + return -1; + } + + struct_set(qi, qi_cols_map[i].offset, qi_cols_map[i].type, srcptr, 0, must_strdup, false); + } return 0; } @@ -5214,9 +5337,9 @@ db_queue_enum_end(struct query_params *qp) } int -db_queue_enum_fetch(struct query_params *qp, struct db_queue_item *queue_item) +db_queue_enum_fetch(struct query_params *qp, struct db_queue_item *qi) { - return queue_enum_fetch(qp, queue_item, 0); + return queue_enum_fetch(qp, qi, 0); } int @@ -5244,7 +5367,7 @@ db_queue_get_pos(uint32_t item_id, char shuffle) } static int -queue_fetch_byitemid(uint32_t item_id, struct db_queue_item *queue_item, int with_metadata) +queue_fetch_byitemid(uint32_t item_id, struct db_queue_item *qi, int with_metadata) { struct query_params qp; int ret; @@ -5259,7 +5382,7 @@ queue_fetch_byitemid(uint32_t item_id, struct db_queue_item *queue_item, int wit return -1; } - ret = queue_enum_fetch(&qp, queue_item, with_metadata); + ret = queue_enum_fetch(&qp, qi, with_metadata); db_query_end(&qp); sqlite3_free(qp.filter); return ret; @@ -5268,46 +5391,46 @@ queue_fetch_byitemid(uint32_t item_id, struct db_queue_item *queue_item, int wit struct db_queue_item * db_queue_fetch_byitemid(uint32_t item_id) { - struct db_queue_item *queue_item; + struct db_queue_item *qi; int ret; - queue_item = calloc(1, sizeof(struct db_queue_item)); - if (!queue_item) + qi = calloc(1, sizeof(struct db_queue_item)); + if (!qi) { DPRINTF(E_LOG, L_DB, "Out of memory for queue_item\n"); return NULL; } db_transaction_begin(); - ret = queue_fetch_byitemid(item_id, queue_item, 1); + ret = queue_fetch_byitemid(item_id, qi, 1); db_transaction_end(); if (ret < 0) { - free_queue_item(queue_item, 0); + free_queue_item(qi, 0); DPRINTF(E_LOG, L_DB, "Error fetching queue item by item id\n"); return NULL; } - else if (queue_item->id == 0) + else if (qi->id == 0) { // No item found - free_queue_item(queue_item, 0); + free_queue_item(qi, 0); return NULL; } - return queue_item; + return qi; } struct db_queue_item * db_queue_fetch_byfileid(uint32_t file_id) { - struct db_queue_item *queue_item; + struct db_queue_item *qi; struct query_params qp; int ret; memset(&qp, 0, sizeof(struct query_params)); - queue_item = calloc(1, sizeof(struct db_queue_item)); - if (!queue_item) + qi = calloc(1, sizeof(struct db_queue_item)); + if (!qi) { DPRINTF(E_LOG, L_DB, "Out of memory for queue_item\n"); return NULL; @@ -5322,34 +5445,34 @@ db_queue_fetch_byfileid(uint32_t file_id) { sqlite3_free(qp.filter); db_transaction_end(); - free_queue_item(queue_item, 0); + free_queue_item(qi, 0); DPRINTF(E_LOG, L_DB, "Error fetching queue item by file id\n"); return NULL; } - ret = queue_enum_fetch(&qp, queue_item, 1); + ret = queue_enum_fetch(&qp, qi, 1); db_query_end(&qp); sqlite3_free(qp.filter); db_transaction_end(); if (ret < 0) { - free_queue_item(queue_item, 0); + free_queue_item(qi, 0); DPRINTF(E_LOG, L_DB, "Error fetching queue item by file id\n"); return NULL; } - else if (queue_item->id == 0) + else if (qi->id == 0) { // No item found - free_queue_item(queue_item, 0); + free_queue_item(qi, 0); return NULL; } - return queue_item; + return qi; } static int -queue_fetch_bypos(uint32_t pos, char shuffle, struct db_queue_item *queue_item, int with_metadata) +queue_fetch_bypos(uint32_t pos, char shuffle, struct db_queue_item *qi, int with_metadata) { struct query_params qp; int ret; @@ -5367,7 +5490,7 @@ queue_fetch_bypos(uint32_t pos, char shuffle, struct db_queue_item *queue_item, return -1; } - ret = queue_enum_fetch(&qp, queue_item, with_metadata); + ret = queue_enum_fetch(&qp, qi, with_metadata); db_query_end(&qp); sqlite3_free(qp.filter); return ret; @@ -5376,38 +5499,38 @@ queue_fetch_bypos(uint32_t pos, char shuffle, struct db_queue_item *queue_item, struct db_queue_item * db_queue_fetch_bypos(uint32_t pos, char shuffle) { - struct db_queue_item *queue_item; + struct db_queue_item *qi; int ret; - queue_item = calloc(1, sizeof(struct db_queue_item)); - if (!queue_item) + qi = calloc(1, sizeof(struct db_queue_item)); + if (!qi) { DPRINTF(E_LOG, L_MAIN, "Out of memory for queue_item\n"); return NULL; } db_transaction_begin(); - ret = queue_fetch_bypos(pos, shuffle, queue_item, 1); + ret = queue_fetch_bypos(pos, shuffle, qi, 1); db_transaction_end(); if (ret < 0) { - free_queue_item(queue_item, 0); + free_queue_item(qi, 0); DPRINTF(E_LOG, L_DB, "Error fetching queue item by pos id\n"); return NULL; } - else if (queue_item->id == 0) + else if (qi->id == 0) { // No item found - free_queue_item(queue_item, 0); + free_queue_item(qi, 0); return NULL; } - return queue_item; + return qi; } static int -queue_fetch_byposrelativetoitem(int pos, uint32_t item_id, char shuffle, struct db_queue_item *queue_item, int with_metadata) +queue_fetch_byposrelativetoitem(int pos, uint32_t item_id, char shuffle, struct db_queue_item *qi, int with_metadata) { int pos_absolute; int ret; @@ -5424,12 +5547,12 @@ queue_fetch_byposrelativetoitem(int pos, uint32_t item_id, char shuffle, struct pos_absolute += pos; - ret = queue_fetch_bypos(pos_absolute, shuffle, queue_item, with_metadata); + ret = queue_fetch_bypos(pos_absolute, shuffle, qi, with_metadata); if (ret < 0) DPRINTF(E_LOG, L_DB, "Error fetching item by pos: pos (%d) relative to item with id (%d)\n", pos, item_id); else - DPRINTF(E_DBG, L_DB, "Fetch by pos: fetched item (id=%d, pos=%d, file-id=%d)\n", queue_item->id, queue_item->pos, queue_item->file_id); + DPRINTF(E_DBG, L_DB, "Fetch by pos: fetched item (id=%d, pos=%d, file-id=%d)\n", qi->id, qi->pos, qi->file_id); return ret; } @@ -5437,13 +5560,13 @@ queue_fetch_byposrelativetoitem(int pos, uint32_t item_id, char shuffle, struct struct db_queue_item * db_queue_fetch_byposrelativetoitem(int pos, uint32_t item_id, char shuffle) { - struct db_queue_item *queue_item; + struct db_queue_item *qi; int ret; DPRINTF(E_DBG, L_DB, "Fetch by pos: pos (%d) relative to item with id (%d)\n", pos, item_id); - queue_item = calloc(1, sizeof(struct db_queue_item)); - if (!queue_item) + qi = calloc(1, sizeof(struct db_queue_item)); + if (!qi) { DPRINTF(E_LOG, L_MAIN, "Out of memory for queue_item\n"); return NULL; @@ -5451,26 +5574,26 @@ db_queue_fetch_byposrelativetoitem(int pos, uint32_t item_id, char shuffle) db_transaction_begin(); - ret = queue_fetch_byposrelativetoitem(pos, item_id, shuffle, queue_item, 1); + ret = queue_fetch_byposrelativetoitem(pos, item_id, shuffle, qi, 1); db_transaction_end(); if (ret < 0) { - free_queue_item(queue_item, 0); + free_queue_item(qi, 0); DPRINTF(E_LOG, L_DB, "Error fetching queue item by pos relative to item id\n"); return NULL; } - else if (queue_item->id == 0) + else if (qi->id == 0) { // No item found - free_queue_item(queue_item, 0); + free_queue_item(qi, 0); return NULL; } - DPRINTF(E_DBG, L_DB, "Fetch by pos: fetched item (id=%d, pos=%d, file-id=%d)\n", queue_item->id, queue_item->pos, queue_item->file_id); + DPRINTF(E_DBG, L_DB, "Fetch by pos: fetched item (id=%d, pos=%d, file-id=%d)\n", qi->id, qi->pos, qi->file_id); - return queue_item; + return qi; } struct db_queue_item * @@ -5604,13 +5727,13 @@ db_queue_clear(uint32_t keep_item_id) } static int -queue_delete_item(struct db_queue_item *queue_item, int queue_version) +queue_delete_item(struct db_queue_item *qi, int queue_version) { char *query; int ret; // Remove item with the given item_id - query = sqlite3_mprintf("DELETE FROM queue where id = %d;", queue_item->id); + query = sqlite3_mprintf("DELETE FROM queue where id = %d;", qi->id); ret = db_query_run(query, 1, 0); if (ret < 0) { @@ -5618,7 +5741,7 @@ queue_delete_item(struct db_queue_item *queue_item, int queue_version) } // Update pos for all items after the item with given item_id - query = sqlite3_mprintf("UPDATE queue SET pos = pos - 1, queue_version = %d WHERE pos > %d;", queue_version, queue_item->pos); + query = sqlite3_mprintf("UPDATE queue SET pos = pos - 1, queue_version = %d WHERE pos > %d;", queue_version, qi->pos); ret = db_query_run(query, 1, 0); if (ret < 0) { @@ -5626,7 +5749,7 @@ queue_delete_item(struct db_queue_item *queue_item, int queue_version) } // Update shuffle_pos for all items after the item with given item_id - query = sqlite3_mprintf("UPDATE queue SET shuffle_pos = shuffle_pos - 1, queue_version = %d WHERE shuffle_pos > %d;", queue_version, queue_item->shuffle_pos); + query = sqlite3_mprintf("UPDATE queue SET shuffle_pos = shuffle_pos - 1, queue_version = %d WHERE shuffle_pos > %d;", queue_version, qi->shuffle_pos); ret = db_query_run(query, 1, 0); if (ret < 0) { @@ -6759,6 +6882,9 @@ db_open(void) int synchronous; int mmap_size; + if (!db_path) + return -1; + ret = sqlite3_open(db_path, &hdl); if (ret != SQLITE_OK) { @@ -6951,8 +7077,12 @@ db_statements_prepare(void) db_statements.playlists_insert = db_statements_prepare_insert(pli_cols_map, ARRAY_SIZE(pli_cols_map), "playlists"); db_statements.playlists_update = db_statements_prepare_update(pli_cols_map, ARRAY_SIZE(pli_cols_map), "playlists"); + db_statements.queue_items_insert = db_statements_prepare_insert(qi_cols_map, ARRAY_SIZE(qi_cols_map), "queue"); + db_statements.queue_items_update = db_statements_prepare_update(qi_cols_map, ARRAY_SIZE(qi_cols_map), "queue"); + if ( !db_statements.files_insert || !db_statements.files_update || !db_statements.files_ping || !db_statements.playlists_insert || !db_statements.playlists_update + || !db_statements.queue_items_insert || !db_statements.queue_items_update ) return -1; @@ -7196,7 +7326,9 @@ db_init(void) uint32_t files; uint32_t pls; int ret; + int i; + // Consistency checks if (ARRAY_SIZE(dbmfi_cols_map) != ARRAY_SIZE(mfi_cols_map)) { DPRINTF(E_FATAL, L_DB, "BUG: mfi column maps are not in sync\n"); @@ -7209,6 +7341,21 @@ db_init(void) return -1; } + if (ARRAY_SIZE(qi_cols_map) != ARRAY_SIZE(qi_mfi_map)) + { + DPRINTF(E_FATAL, L_DB, "BUG: queue_item column maps are not in sync\n"); + return -1; + } + + for (i = 0; i < ARRAY_SIZE(qi_cols_map); i++) + { + if (qi_cols_map[i].offset == qi_mfi_map[i].qi_offset) + continue; + + DPRINTF(E_FATAL, L_DB, "BUG: queue_item offset maps are not in sync (at %d)\n", i); + return -1; + } + db_path = cfg_getstr(cfg_getsec(cfg, "general"), "db_path"); db_rating_updates = cfg_getbool(cfg_getsec(cfg, "library"), "rating_updates"); diff --git a/src/db.h b/src/db.h index 755aab20..aa4ae5ba 100644 --- a/src/db.h +++ b/src/db.h @@ -543,7 +543,7 @@ void free_query_params(struct query_params *qp, int content_only); void -free_queue_item(struct db_queue_item *queue_item, int content_only); +free_queue_item(struct db_queue_item *qi, int content_only); /* Maintenance and DB hygiene */ void @@ -816,8 +816,14 @@ int db_speaker_get(struct output_device *device, uint64_t id); /* Queue */ +void +db_queue_item_from_mfi(struct db_queue_item *qi, struct media_file_info *mfi); // Use free_queue_item(qi, 0) to free + +void +db_queue_item_from_dbmfi(struct db_queue_item *qi, struct db_media_file_info *dbmfi); // Do not free qi content + int -db_queue_update_item(struct db_queue_item *queue_item); +db_queue_item_update(struct db_queue_item *qi); int db_queue_add_by_queryafteritemid(struct query_params *qp, uint32_t item_id); @@ -838,7 +844,7 @@ int db_queue_add_end(struct db_queue_add_info *queue_add_info, char reshuffle, uint32_t item_id, int ret); int -db_queue_add_item(struct db_queue_add_info *queue_add_info, struct db_queue_item *item); +db_queue_add_next(struct db_queue_add_info *queue_add_info, struct db_queue_item *qi); int db_queue_enum_start(struct query_params *qp); @@ -847,7 +853,7 @@ void db_queue_enum_end(struct query_params *qp); int -db_queue_enum_fetch(struct query_params *qp, struct db_queue_item *queue_item); +db_queue_enum_fetch(struct query_params *qp, struct db_queue_item *qi); struct db_queue_item * db_queue_fetch_byitemid(uint32_t item_id); diff --git a/src/httpd_jsonapi.c b/src/httpd_jsonapi.c index 4f81d7fa..a5232c26 100644 --- a/src/httpd_jsonapi.c +++ b/src/httpd_jsonapi.c @@ -2607,7 +2607,7 @@ jsonapi_reply_queue_tracks_update(struct httpd_request *hreq) return ret; if (is_changed) - db_queue_update_item(queue_item); + db_queue_item_update(queue_item); return HTTP_NOCONTENT; } diff --git a/src/library/filescanner.c b/src/library/filescanner.c index 86f047cf..07edd5fc 100644 --- a/src/library/filescanner.c +++ b/src/library/filescanner.c @@ -1742,47 +1742,11 @@ filescanner_fullrescan() return 0; } -static void -map_media_file_to_queue_item(struct db_queue_item *queue_item, struct media_file_info *mfi) -{ - memset(queue_item, 0, sizeof(struct db_queue_item)); - - if (mfi->id) - queue_item->file_id = mfi->id; - else - queue_item->file_id = DB_MEDIA_FILE_NON_PERSISTENT_ID; - - queue_item->title = safe_strdup(mfi->title); - queue_item->artist = safe_strdup(mfi->artist); - queue_item->album_artist = safe_strdup(mfi->album_artist); - queue_item->album = safe_strdup(mfi->album); - queue_item->genre = safe_strdup(mfi->genre); - queue_item->artist_sort = safe_strdup(mfi->artist_sort); - queue_item->album_artist_sort = safe_strdup(mfi->album_artist_sort); - queue_item->album_sort = safe_strdup(mfi->album_sort); - queue_item->path = safe_strdup(mfi->path); - queue_item->virtual_path = safe_strdup(mfi->virtual_path); - queue_item->data_kind = mfi->data_kind; - queue_item->media_kind = mfi->media_kind; - queue_item->song_length = mfi->song_length; - queue_item->seek = mfi->seek; - queue_item->songalbumid = mfi->songalbumid; - queue_item->time_modified = mfi->time_modified; - queue_item->year = mfi->year; - queue_item->track = mfi->track; - queue_item->disc = mfi->disc; - //queue_item->artwork_url - queue_item->type = safe_strdup(mfi->type); - queue_item->channels = mfi->channels; - queue_item->samplerate = mfi->samplerate; - queue_item->bitrate = mfi->bitrate; -} - static int queue_item_stream_add(const char *path, int position, char reshuffle, uint32_t item_id, int *count, int *new_item_id) { struct media_file_info mfi; - struct db_queue_item item; + struct db_queue_item qi; struct db_queue_add_info queue_add_info; int ret; @@ -1790,12 +1754,12 @@ queue_item_stream_add(const char *path, int position, char reshuffle, uint32_t i scan_metadata_stream(&mfi, path); - map_media_file_to_queue_item(&item, &mfi); + db_queue_item_from_mfi(&qi, &mfi); ret = db_queue_add_start(&queue_add_info, position); if (ret == 0) { - ret = db_queue_add_item(&queue_add_info, &item); + ret = db_queue_add_next(&queue_add_info, &qi); ret = db_queue_add_end(&queue_add_info, reshuffle, item_id, ret); if (ret == 0) { @@ -1806,7 +1770,7 @@ queue_item_stream_add(const char *path, int position, char reshuffle, uint32_t i } } - free_queue_item(&item, 1); + free_queue_item(&qi, 1); free_mfi(&mfi, 1); return 0; diff --git a/src/player.c b/src/player.c index 2be6a76c..a110e9c4 100644 --- a/src/player.c +++ b/src/player.c @@ -601,7 +601,7 @@ metadata_update_queue_cb(void *arg) if (metadata->len_ms) queue_item->song_length = metadata->len_ms; - ret = db_queue_update_item(queue_item); + ret = db_queue_item_update(queue_item); if (ret < 0) DPRINTF(E_LOG, L_PLAYER, "Database error while updating queue with new metadata\n"); } diff --git a/src/spotify_webapi.c b/src/spotify_webapi.c index c417f7be..9e02c6f0 100644 --- a/src/spotify_webapi.c +++ b/src/spotify_webapi.c @@ -1080,7 +1080,7 @@ queue_add_track(const char *uri, int position, char reshuffle, uint32_t item_id, ret = db_queue_add_start(&queue_add_info, position); if (ret == 0) { - ret = db_queue_add_item(&queue_add_info, &item); + ret = db_queue_add_next(&queue_add_info, &item); ret = db_queue_add_end(&queue_add_info, reshuffle, item_id, ret); if (ret == 0) { @@ -1122,7 +1122,7 @@ queue_add_album_tracks(json_object *item, int index, int total, enum spotify_req map_track_to_queueitem(&queue_item, &track, ¶m->album); - ret = db_queue_add_item(¶m->queue_add_info, &queue_item); + ret = db_queue_add_next(¶m->queue_add_info, &queue_item); free_queue_item(&queue_item, 1); @@ -1236,7 +1236,7 @@ queue_add_playlist_tracks(json_object *item, int index, int total, enum spotify_ map_track_to_queueitem(&queue_item, &track, NULL); - ret = db_queue_add_item(queue_add_info, &queue_item); + ret = db_queue_add_next(queue_add_info, &queue_item); free_queue_item(&queue_item, 1); From 1fa1d9091b26223e0627de00753300bec6a5c9f1 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Sun, 24 Jan 2021 23:42:43 +0100 Subject: [PATCH 2/6] [db] Consolidate setting struct fields from database queries --- src/db.c | 277 ++++++++++++++++++------------------------------------- 1 file changed, 90 insertions(+), 187 deletions(-) diff --git a/src/db.c b/src/db.c index b6b058f1..4ca205dd 100644 --- a/src/db.c +++ b/src/db.c @@ -56,10 +56,6 @@ // Inotify cookies are uint32_t #define INOTIFY_FAKE_COOKIE ((int64_t)1 << 32) -#define DB_TYPE_INT 1 -#define DB_TYPE_INT64 2 -#define DB_TYPE_STRING 3 - // Flags that the field will not be bound to prepared statements, which is relevant if the field has no // matching column, or if the the column value is set automatically by the db, e.g. by a trigger #define DB_FLAG_NO_BIND (1 << 0) @@ -75,6 +71,12 @@ enum group_type { G_ARTISTS = 2, }; +enum field_type { + DB_TYPE_INT, + DB_TYPE_INT64, + DB_TYPE_STRING, +}; + enum fixup_type { DB_FIXUP_STANDARD = 0, DB_FIXUP_NO_SANITIZE, @@ -120,7 +122,7 @@ struct db_statements struct col_type_map { char *name; ssize_t offset; - short type; + enum field_type type; enum fixup_type fixup; short flag; }; @@ -800,38 +802,92 @@ free_queue_item(struct db_queue_item *qi, int content_only) // because src is not a struct, caller wants to strdup the string so // must_strdup is true static inline void -struct_set(void *dst_struct, ssize_t dst_offset, int dst_type, const void *src_struct, ssize_t src_offset, bool must_strdup, bool parse_integers) +struct_field_set_str(void *dst, const void *src, bool must_strdup) +{ + char *srcstr; + char **dstptr; + + srcstr = *(char **)(src); + dstptr = (char **)(dst); + *dstptr = must_strdup ? safe_strdup(srcstr) : srcstr; +} + +static inline void +struct_field_set_uint32(void *dst, const void *src, bool parse_integers) { char *srcstr; uint32_t srcu32val; - int64_t srci64val; - char **dstptr; - srcstr = *(char **)(src_struct + src_offset); + if (parse_integers) + { + srcstr = *(char **)(src); + safe_atou32(srcstr, &srcu32val); + } + else + srcu32val = *(uint32_t *)(src); + + memcpy(dst, &srcu32val, sizeof(srcu32val)); +} + +static inline void +struct_field_set_int64(void *dst, const void *src, bool parse_integers) +{ + char *srcstr; + int64_t srci64val; + + if (parse_integers) + { + srcstr = *(char **)(src); + safe_atoi64(srcstr, &srci64val); + } + else + srci64val = *(int64_t *)(src); + + memcpy(dst, &srci64val, sizeof(srci64val)); +} + +static void +struct_field_from_field(void *dst_struct, ssize_t dst_offset, enum field_type dst_type, const void *src_struct, ssize_t src_offset, bool must_strdup, bool parse_integers) +{ + switch (dst_type) + { + case DB_TYPE_STRING: + struct_field_set_str(dst_struct + dst_offset, src_struct + src_offset, must_strdup); + break; + + case DB_TYPE_INT: + struct_field_set_uint32(dst_struct + dst_offset, src_struct + src_offset, parse_integers); + break; + + case DB_TYPE_INT64: + struct_field_set_int64(dst_struct + dst_offset, src_struct + src_offset, parse_integers); + break; + } +} + +static void +struct_field_from_statement(void *dst_struct, ssize_t dst_offset, enum field_type dst_type, sqlite3_stmt *stmt, int col, bool must_strdup, bool parse_integers) +{ + const char *str; + uint32_t u32; + int64_t i64; switch (dst_type) { case DB_TYPE_STRING: - dstptr = (char **)(dst_struct + dst_offset); - *dstptr = must_strdup ? safe_strdup(srcstr) : srcstr; + str = (const char *)sqlite3_column_text(stmt, col); + struct_field_set_str(dst_struct + dst_offset, &str, must_strdup); break; case DB_TYPE_INT: - if (parse_integers) - safe_atou32(srcstr, &srcu32val); - else - srcu32val = *(uint32_t *)(src_struct + src_offset); - - memcpy(dst_struct + dst_offset, &srcu32val, sizeof(srcu32val)); + u32 = (uint32_t)sqlite3_column_int64(stmt, col); // _int64() because _int() wouldn't be enough for uint32 + // TODO add a check that we aren't truncating int64 !=0 to uint32 == 0? + struct_field_set_uint32(dst_struct + dst_offset, &u32, parse_integers); break; case DB_TYPE_INT64: - if (parse_integers) - safe_atoi64(srcstr, &srci64val); - else - srci64val = *(int64_t *)(src_struct + src_offset); - - memcpy(dst_struct + dst_offset, &srci64val, sizeof(srci64val)); + i64 = sqlite3_column_int64(stmt, col); + struct_field_set_int64(dst_struct + dst_offset, &i64, parse_integers); break; } } @@ -3011,11 +3067,6 @@ db_file_fetch_byquery(char *query) struct media_file_info *mfi; sqlite3_stmt *stmt; int ncols; - char *cval; - uint32_t *ival; - uint64_t *i64val; - char **strval; - uint64_t disabled; int i; int ret; @@ -3068,41 +3119,7 @@ db_file_fetch_byquery(char *query) for (i = 0; i < ARRAY_SIZE(mfi_cols_map); i++) { - switch (mfi_cols_map[i].type) - { - case DB_TYPE_INT: - ival = (uint32_t *) ((char *)mfi + mfi_cols_map[i].offset); - - if (mfi_cols_map[i].offset == mfi_offsetof(disabled)) - { - disabled = sqlite3_column_int64(stmt, i); - *ival = (disabled != 0); - } - else - *ival = sqlite3_column_int(stmt, i); - break; - - case DB_TYPE_INT64: - i64val = (uint64_t *) ((char *)mfi + mfi_cols_map[i].offset); - - *i64val = sqlite3_column_int64(stmt, i); - break; - - case DB_TYPE_STRING: - strval = (char **) ((char *)mfi + mfi_cols_map[i].offset); - - cval = (char *)sqlite3_column_text(stmt, i); - if (cval) - *strval = strdup(cval); - break; - - default: - DPRINTF(E_LOG, L_DB, "BUG: Unknown type %d in mfi column map\n", mfi_cols_map[i].type); - - free_mfi(mfi, 0); - sqlite3_finalize(stmt); - return NULL; - } + struct_field_from_statement(mfi, mfi_cols_map[i].offset, mfi_cols_map[i].type, stmt, i, true, false); } #ifdef DB_PROFILE @@ -3464,10 +3481,6 @@ db_pl_fetch_byquery(const char *query) struct playlist_info *pli; sqlite3_stmt *stmt; int ncols; - char *cval; - uint32_t *ival; - char **strval; - uint64_t disabled; int i; int ret; @@ -3518,35 +3531,7 @@ db_pl_fetch_byquery(const char *query) for (i = 0; i < ARRAY_SIZE(pli_cols_map); i++) { - switch (pli_cols_map[i].type) - { - case DB_TYPE_INT: - ival = (uint32_t *) ((char *)pli + pli_cols_map[i].offset); - - if (pli_cols_map[i].offset == pli_offsetof(disabled)) - { - disabled = sqlite3_column_int64(stmt, i); - *ival = (disabled != 0); - } - else - *ival = sqlite3_column_int(stmt, i); - break; - - case DB_TYPE_STRING: - strval = (char **) ((char *)pli + pli_cols_map[i].offset); - - cval = (char *)sqlite3_column_text(stmt, i); - if (cval) - *strval = strdup(cval); - break; - - default: - DPRINTF(E_LOG, L_DB, "BUG: Unknown type %d in pli column map\n", pli_cols_map[i].type); - - sqlite3_finalize(stmt); - free_pli(pli, 0); - return NULL; - } + struct_field_from_statement(pli, pli_cols_map[i].offset, pli_cols_map[i].type, stmt, i, true, false); } ret = db_blocking_step(stmt); @@ -4556,10 +4541,6 @@ admin_get(void *value, const char *key, short type) #define Q_TMPL "SELECT value FROM admin a WHERE a.key = '%q';" char *query; sqlite3_stmt *stmt; - char *cval; - int32_t *ival; - int64_t *i64val; - char **strval; int ret; CHECK_NULL(L_DB, query = sqlite3_mprintf(Q_TMPL, key)); @@ -4588,35 +4569,7 @@ admin_get(void *value, const char *key, short type) return -1; } - switch (type) - { - case DB_TYPE_INT: - ival = (int32_t *) value; - - *ival = sqlite3_column_int(stmt, 0); - break; - - case DB_TYPE_INT64: - i64val = (int64_t *) value; - - *i64val = sqlite3_column_int64(stmt, 0); - break; - - case DB_TYPE_STRING: - strval = (char **) value; - - cval = (char *)sqlite3_column_text(stmt, 0); - if (cval) - *strval = strdup(cval); - break; - - default: - DPRINTF(E_LOG, L_DB, "BUG: Unknown type %d in admin_set\n", type); - - sqlite3_finalize(stmt); - sqlite3_free(query); - return -1; - } + struct_field_from_statement(value, 0, type, stmt, 0, true, false); #ifdef DB_PROFILE while (db_blocking_step(stmt) == SQLITE_ROW) @@ -4879,7 +4832,7 @@ db_queue_item_from_mfi(struct db_queue_item *qi, struct media_file_info *mfi) if (qi_mfi_map[i].mfi_offset < 0) continue; - struct_set(qi, qi_cols_map[i].offset, qi_cols_map[i].type, mfi, qi_mfi_map[i].mfi_offset, true, false); + struct_field_from_field(qi, qi_cols_map[i].offset, qi_cols_map[i].type, mfi, qi_mfi_map[i].mfi_offset, true, false); } if (!qi->file_id) @@ -4898,7 +4851,7 @@ db_queue_item_from_dbmfi(struct db_queue_item *qi, struct db_media_file_info *db if (qi_mfi_map[i].dbmfi_offset < 0) continue; - struct_set(qi, qi_cols_map[i].offset, qi_cols_map[i].type, dbmfi, qi_mfi_map[i].dbmfi_offset, false, true); + struct_field_from_field(qi, qi_cols_map[i].offset, qi_cols_map[i].type, dbmfi, qi_mfi_map[i].dbmfi_offset, false, true); } if (!qi->file_id) @@ -5257,10 +5210,6 @@ strdup_if(char *str, int cond) static int queue_enum_fetch(struct query_params *qp, struct db_queue_item *qi, int must_strdup) { - const void *srcptr; - const char *str; - int32_t i32; - int64_t i64; int ret; int i; @@ -5286,29 +5235,7 @@ queue_enum_fetch(struct query_params *qp, struct db_queue_item *qi, int must_str for (i = 0; i < ARRAY_SIZE(qi_cols_map); i++) { - switch (qi_cols_map[i].type) - { - case DB_TYPE_STRING: - str = (const char *)sqlite3_column_text(qp->stmt, i); - srcptr = &str; - break; - - case DB_TYPE_INT: - i32 = sqlite3_column_int(qp->stmt, i); - srcptr = &i32; - break; - - case DB_TYPE_INT64: - i64 = sqlite3_column_int64(qp->stmt, i); - srcptr = &i64; - break; - - default: - DPRINTF(E_LOG, L_DB, "BUG! Unknown data type (%d) in queue_enum_fetch()\n", qi_cols_map[i].type); - return -1; - } - - struct_set(qi, qi_cols_map[i].offset, qi_cols_map[i].type, srcptr, 0, must_strdup, false); + struct_field_from_statement(qi, qi_cols_map[i].offset, qi_cols_map[i].type, qp->stmt, i, must_strdup, false); } return 0; @@ -6274,9 +6201,6 @@ static int db_watch_get_byquery(struct watch_info *wi, char *query) { sqlite3_stmt *stmt; - char **strval; - char *cval; - uint32_t *ival; int64_t cookie; int ncols; int i; @@ -6314,33 +6238,12 @@ db_watch_get_byquery(struct watch_info *wi, char *query) for (i = 0; i < ARRAY_SIZE(wi_cols_map); i++) { - switch (wi_cols_map[i].type) + struct_field_from_statement(wi, wi_cols_map[i].offset, wi_cols_map[i].type, stmt, i, true, false); + + if (wi_cols_map[i].offset == wi_offsetof(cookie)) { - case DB_TYPE_INT: - ival = (uint32_t *) ((char *)wi + wi_cols_map[i].offset); - - if (wi_cols_map[i].offset == wi_offsetof(cookie)) - { - cookie = sqlite3_column_int64(stmt, i); - *ival = (cookie == INOTIFY_FAKE_COOKIE) ? 0 : cookie; - } - else - *ival = sqlite3_column_int(stmt, i); - break; - - case DB_TYPE_STRING: - strval = (char **) ((char *)wi + wi_cols_map[i].offset); - - cval = (char *)sqlite3_column_text(stmt, i); - if (cval) - *strval = strdup(cval); - break; - - default: - DPRINTF(E_LOG, L_DB, "BUG: Unknown type %d in wi column map\n", wi_cols_map[i].type); - sqlite3_finalize(stmt); - sqlite3_free(query); - return -1; + cookie = sqlite3_column_int64(stmt, i); + wi->cookie = (cookie == INOTIFY_FAKE_COOKIE) ? 0 : cookie; } } From b6163c9d341ee7d7e43d9d3b3357d1533af3cf9c Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Mon, 25 Jan 2021 20:39:45 +0100 Subject: [PATCH 3/6] [db] Fix bug in bind_generic, input to sqlite3_bind_int64 should be int64_t --- src/db.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db.c b/src/db.c index 4ca205dd..fae19bdd 100644 --- a/src/db.c +++ b/src/db.c @@ -1285,7 +1285,7 @@ bind_generic(sqlite3_stmt *stmt, void *data, const struct col_type_map *map, siz break; case DB_TYPE_INT64: - sqlite3_bind_int64(stmt, n, *((uint64_t *)ptr)); + sqlite3_bind_int64(stmt, n, *((int64_t *)ptr)); break; case DB_TYPE_STRING: From 79b4a070b0884d2844aff1541224c6da0bfe8d76 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Mon, 25 Jan 2021 23:21:49 +0100 Subject: [PATCH 4/6] [db] Change type of "disabled" to int64 Before the value in the db was not read straight into mfi->disabled and pli->disabled, instead it was evaluated as != 0, so the ->disabled field would just be true or false. This was also necessary when INOTIFY_FAKE_COOKIE (1 << 32) was written to the DB, because it could not fit in the uint32 of mfi->disabled/pli->disabled. I consider this juggling poor practice, so with this change it is read straight in and out, always as a int64. --- src/db.c | 13 +++++-------- src/db.h | 6 +++--- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/db.c b/src/db.c index fae19bdd..79209e6c 100644 --- a/src/db.c +++ b/src/db.c @@ -207,7 +207,7 @@ static const struct col_type_map mfi_cols_map[] = { "time_modified", mfi_offsetof(time_modified), DB_TYPE_INT, DB_FIXUP_TIME_MODIFIED }, { "time_played", mfi_offsetof(time_played), DB_TYPE_INT, DB_FIXUP_STANDARD, DB_FLAG_NO_ZERO }, { "time_skipped", mfi_offsetof(time_skipped), DB_TYPE_INT, DB_FIXUP_STANDARD, DB_FLAG_NO_ZERO }, - { "disabled", mfi_offsetof(disabled), DB_TYPE_INT }, + { "disabled", mfi_offsetof(disabled), DB_TYPE_INT64 }, { "sample_count", mfi_offsetof(sample_count), DB_TYPE_INT64 }, { "codectype", mfi_offsetof(codectype), DB_TYPE_STRING, DB_FIXUP_CODECTYPE }, { "idx", mfi_offsetof(idx), DB_TYPE_INT }, @@ -240,7 +240,7 @@ static const struct col_type_map pli_cols_map[] = { "type", pli_offsetof(type), DB_TYPE_INT }, { "query", pli_offsetof(query), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE }, { "db_timestamp", pli_offsetof(db_timestamp), DB_TYPE_INT }, - { "disabled", pli_offsetof(disabled), DB_TYPE_INT }, + { "disabled", pli_offsetof(disabled), DB_TYPE_INT64 }, { "path", pli_offsetof(path), DB_TYPE_STRING, DB_FIXUP_NO_SANITIZE }, { "idx", pli_offsetof(index), DB_TYPE_INT }, { "special_id", pli_offsetof(special_id), DB_TYPE_INT }, @@ -881,7 +881,6 @@ struct_field_from_statement(void *dst_struct, ssize_t dst_offset, enum field_typ case DB_TYPE_INT: u32 = (uint32_t)sqlite3_column_int64(stmt, col); // _int64() because _int() wouldn't be enough for uint32 - // TODO add a check that we aren't truncating int64 !=0 to uint32 == 0? struct_field_set_uint32(dst_struct + dst_offset, &u32, parse_integers); break; @@ -4104,7 +4103,6 @@ db_directory_enum_start(struct directory_enum *de) int db_directory_enum_fetch(struct directory_enum *de, struct directory_info *di) { - uint64_t disabled; int ret; memset(di, 0, sizeof(struct directory_info)); @@ -4130,8 +4128,7 @@ db_directory_enum_fetch(struct directory_enum *de, struct directory_info *di) di->id = sqlite3_column_int(de->stmt, 0); di->virtual_path = (char *)sqlite3_column_text(de->stmt, 1); di->db_timestamp = sqlite3_column_int(de->stmt, 2); - disabled = sqlite3_column_int64(de->stmt, 3); - di->disabled = (disabled != 0); + di->disabled = sqlite3_column_int64(de->stmt, 3); di->parent_id = sqlite3_column_int(de->stmt, 4); di->path = (char *)sqlite3_column_text(de->stmt, 5); @@ -4152,7 +4149,7 @@ static int db_directory_add(struct directory_info *di, int *id) { #define QADD_TMPL "INSERT INTO directories (virtual_path, db_timestamp, disabled, parent_id, path)" \ - " VALUES (TRIM(%Q), %d, %d, %d, TRIM(%Q));" + " VALUES (TRIM(%Q), %d, %" PRIi64 ", %d, TRIM(%Q));" char *query; char *errmsg; @@ -4206,7 +4203,7 @@ db_directory_add(struct directory_info *di, int *id) static int db_directory_update(struct directory_info *di) { -#define QADD_TMPL "UPDATE directories SET virtual_path = TRIM(%Q), db_timestamp = %d, disabled = %d, parent_id = %d, path = TRIM(%Q)" \ +#define QADD_TMPL "UPDATE directories SET virtual_path = TRIM(%Q), db_timestamp = %d, disabled = %" PRIi64 ", parent_id = %d, path = TRIM(%Q)" \ " WHERE id = %d;" char *query; char *errmsg; diff --git a/src/db.h b/src/db.h index aa4ae5ba..3c6df0da 100644 --- a/src/db.h +++ b/src/db.h @@ -197,7 +197,7 @@ struct media_file_info { uint32_t time_played; uint32_t time_skipped; - uint32_t disabled; + int64_t disabled; // Long because it stores up to INOTIFY_FAKE_COOKIE uint64_t sample_count; //TODO [unused] sample count is never set and therefor always 0 char *codectype; /* song.codectype, 4 chars max (32 bits) */ @@ -247,7 +247,7 @@ struct playlist_info { enum pl_type type; /* see PL_ types */ char *query; /* where clause if type 1 (MSPS) */ uint32_t db_timestamp; /* time last updated */ - uint32_t disabled; + int64_t disabled; /* long because it stores up to INOTIFY_FAKE_COOKIE */ char *path; /* path of underlying playlist */ uint32_t index; /* index of playlist for paths with multiple playlists */ uint32_t special_id; /* iTunes identifies certain 'special' playlists with special meaning */ @@ -439,7 +439,7 @@ struct directory_info { char *virtual_path; char *path; uint32_t db_timestamp; - uint32_t disabled; + int64_t disabled; uint32_t parent_id; }; From bd91a238ec67dc752af5c06d98f4e63d0af3986b Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Sun, 31 Jan 2021 10:27:23 +0100 Subject: [PATCH 5/6] [db] Upgrade schema to 21.06, change default of query_limit to 0 --- src/db.c | 7 ++-- src/db.h | 2 +- src/db_init.c | 2 +- src/db_init.h | 2 +- src/db_upgrade.c | 55 +++++++++++++++++++++++++++++++ src/library/filescanner_smartpl.c | 2 +- 6 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/db.c b/src/db.c index 79209e6c..e6a420d6 100644 --- a/src/db.c +++ b/src/db.c @@ -1849,7 +1849,10 @@ db_build_query_clause(struct query_params *qp) switch (qp->idx_type) { case I_FIRST: - qc->index = sqlite3_mprintf("LIMIT %d", qp->limit); + if (qp->limit) + qc->index = sqlite3_mprintf("LIMIT %d", qp->limit); + else + qc->index = sqlite3_mprintf(""); break; case I_LAST: @@ -2004,7 +2007,7 @@ db_build_query_plitems_smart(struct query_params *qp, struct playlist_info *pli) if (!qc) return NULL; - count = sqlite3_mprintf("SELECT COUNT(*) FROM files f %s AND %s LIMIT %d;", qc->where, pli->query, pli->query_limit); + count = sqlite3_mprintf("SELECT COUNT(*) FROM files f %s AND %s LIMIT %d;", qc->where, pli->query, pli->query_limit ? pli->query_limit : -1); query = sqlite3_mprintf("SELECT f.* FROM files f %s AND %s %s %s;", qc->where, pli->query, qc->order, qc->index); db_free_query_clause(qc); diff --git a/src/db.h b/src/db.h index 3c6df0da..f23f3097 100644 --- a/src/db.h +++ b/src/db.h @@ -255,7 +255,7 @@ struct playlist_info { uint32_t parent_id; /* Id of parent playlist if the playlist is nested */ uint32_t directory_id; /* Id of directory */ char *query_order; /* order by clause, used by e.g. a smart playlists */ - int32_t query_limit; /* limit, used by e.g. smart playlists */ + uint32_t query_limit; /* limit, used by e.g. smart playlists */ uint32_t media_kind; char *artwork_url; /* optional artwork */ uint32_t items; /* number of items (mimc) */ diff --git a/src/db_init.c b/src/db_init.c index 45626ea3..5e358c7a 100644 --- a/src/db_init.c +++ b/src/db_init.c @@ -114,7 +114,7 @@ " parent_id INTEGER DEFAULT 0," \ " directory_id INTEGER DEFAULT 0," \ " query_order VARCHAR(1024)," \ - " query_limit INTEGER DEFAULT -1," \ + " query_limit INTEGER DEFAULT 0," \ " media_kind INTEGER DEFAULT 1," \ " artwork_url VARCHAR(4096) DEFAULT NULL" \ ");" diff --git a/src/db_init.h b/src/db_init.h index a28463d2..d200860e 100644 --- a/src/db_init.h +++ b/src/db_init.h @@ -26,7 +26,7 @@ * is a major upgrade. In other words minor version upgrades permit downgrading * forked-daapd after the database was upgraded. */ #define SCHEMA_VERSION_MAJOR 21 -#define SCHEMA_VERSION_MINOR 05 +#define SCHEMA_VERSION_MINOR 06 int db_init_indices(sqlite3 *hdl); diff --git a/src/db_upgrade.c b/src/db_upgrade.c index de84ab79..a68e2999 100644 --- a/src/db_upgrade.c +++ b/src/db_upgrade.c @@ -1074,6 +1074,49 @@ static const struct db_upgrade_query db_upgrade_v2105_queries[] = }; +/* ---------------------------- 21.05 -> 21.06 ------------------------------ */ + +// Reload table, required for changing the default of query_limit from -1 to 0 +#define U_V2106_NEW_PLAYLISTS_TABLE \ + "CREATE TABLE new_playlists (" \ + " id INTEGER PRIMARY KEY NOT NULL," \ + " title VARCHAR(255) NOT NULL COLLATE DAAP," \ + " type INTEGER NOT NULL," \ + " query VARCHAR(1024)," \ + " db_timestamp INTEGER NOT NULL," \ + " disabled INTEGER DEFAULT 0," \ + " path VARCHAR(4096)," \ + " idx INTEGER NOT NULL," \ + " special_id INTEGER DEFAULT 0," \ + " virtual_path VARCHAR(4096)," \ + " parent_id INTEGER DEFAULT 0," \ + " directory_id INTEGER DEFAULT 0," \ + " query_order VARCHAR(1024)," \ + " query_limit INTEGER DEFAULT 0," \ + " media_kind INTEGER DEFAULT 1," \ + " artwork_url VARCHAR(4096) DEFAULT NULL" \ + ");" + +static int +db_upgrade_v2106(sqlite3 *hdl) +{ + return db_table_upgrade(hdl, "playlists", U_V2106_NEW_PLAYLISTS_TABLE); +} + +// Previously, query_limit had multiple defaults: -1, 0 and UINT32_MAX +#define U_v2106_UPDATE_PLAYLISTS_QUERY_LIMIT \ + "UPDATE playlists SET query_limit = 0 WHERE query_limit = -1 OR query_limit = 4294967295;" +#define U_v2106_SCVER_MINOR \ + "UPDATE admin SET value = '06' WHERE key = 'schema_version_minor';" + +static const struct db_upgrade_query db_upgrade_v2106_queries[] = + { + { U_v2106_UPDATE_PLAYLISTS_QUERY_LIMIT, "update table playlists query_limit default" }, + + { U_v2106_SCVER_MINOR, "set schema_version_minor to 06" }, + }; + + int db_upgrade(sqlite3 *hdl, int db_ver) { @@ -1257,6 +1300,18 @@ db_upgrade(sqlite3 *hdl, int db_ver) if (ret < 0) return -1; + /* FALLTHROUGH */ + + case 2105: + ret = db_upgrade_v2106(hdl); + if (ret < 0) + return -1; + + ret = db_generic_upgrade(hdl, db_upgrade_v2106_queries, ARRAY_SIZE(db_upgrade_v2106_queries)); + if (ret < 0) + return -1; + + /* Last case statement is the only one that ends with a break statement! */ break; diff --git a/src/library/filescanner_smartpl.c b/src/library/filescanner_smartpl.c index 34d5f4b9..09501299 100644 --- a/src/library/filescanner_smartpl.c +++ b/src/library/filescanner_smartpl.c @@ -73,7 +73,7 @@ scan_smartpl(const char *file, time_t mtime, int dir_id) swap_pointers(&pli->title, &smartpl.title); swap_pointers(&pli->query, &smartpl.query_where); swap_pointers(&pli->query_order, &smartpl.order); - pli->query_limit = smartpl.limit; + pli->query_limit = (smartpl.limit > 0) ? smartpl.limit : 0; free_smartpl(&smartpl, 1); From 13be7999cb08240114440461540760fdf9e6eaec Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Sun, 31 Jan 2021 10:37:16 +0100 Subject: [PATCH 6/6] [db] Add some headers in db_upgrade.c for easier navigation --- src/db_upgrade.c | 56 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/src/db_upgrade.c b/src/db_upgrade.c index a68e2999..efd4c87d 100644 --- a/src/db_upgrade.c +++ b/src/db_upgrade.c @@ -262,7 +262,8 @@ db_table_upgrade(sqlite3 *hdl, const char *name, const char *newtablequery) return -1; } -/* Upgrade from schema v17.00 to v18.00 */ +/* ---------------------------- 17.00 -> 18.00 ------------------------------ */ + /* Change playlist type enumeration and recreate filelist view (include smart * playlists in view) */ @@ -300,7 +301,7 @@ static const struct db_upgrade_query db_upgrade_v18_queries[] = { U_V18_SCVER_MINOR, "set schema_version_minor to 00" }, }; -/* Upgrade from schema v18.00 to v18.01 */ +/* ---------------------------- 18.00 -> 18.01 ------------------------------ */ /* Change virtual_path for playlists: remove file extension */ @@ -326,7 +327,7 @@ static const struct db_upgrade_query db_upgrade_v1801_queries[] = { U_V1801_SCVER_MINOR, "set schema_version_minor to 01" }, }; -/* Upgrade from schema v18.01 to v19.00 */ +/* ---------------------------- 18.01 -> 19.00 ------------------------------ */ /* Replace 'filelist' view with new table 'directories' */ @@ -601,7 +602,7 @@ db_upgrade_v19(sqlite3 *hdl) return 0; } -/* Upgrade from schema v19.00 to v19.01 */ +/* ---------------------------- 19.00 -> 19.01 ------------------------------ */ /* Create new table queue for persistent playqueue */ @@ -648,7 +649,7 @@ static const struct db_upgrade_query db_upgrade_v1901_queries[] = { U_V1901_SCVER_MINOR, "set schema_version_minor to 01" }, }; -/* Upgrade from schema v19.01 to v19.02 */ +/* ---------------------------- 19.01 -> 19.02 ------------------------------ */ /* Set key column as primary key in the admin table */ @@ -690,6 +691,8 @@ static const struct db_upgrade_query db_upgrade_v1902_queries[] = }; +/* ---------------------------- 19.02 -> 19.03 ------------------------------ */ + #define U_V1903_ALTER_QUEUE_ADD_ARTWORKURL \ "ALTER TABLE queue ADD COLUMN artwork_url VARCHAR(4096) DEFAULT NULL;" @@ -707,6 +710,8 @@ static const struct db_upgrade_query db_upgrade_v1903_queries[] = }; +/* ---------------------------- 19.03 -> 19.04 ------------------------------ */ + #define U_V1904_ALTER_SPEAKERS_ADD_AUTHKEY \ "ALTER TABLE speakers ADD COLUMN auth_key VARCHAR(2048) DEFAULT NULL;" @@ -724,6 +729,8 @@ static const struct db_upgrade_query db_upgrade_v1904_queries[] = }; +/* ---------------------------- 19.04 -> 19.05 ------------------------------ */ + #define U_V1905_SCVER_MINOR \ "UPDATE admin SET value = '05' WHERE key = 'schema_version_minor';" @@ -734,6 +741,8 @@ static const struct db_upgrade_query db_upgrade_v1905_queries[] = }; +/* ---------------------------- 19.05 -> 19.06 ------------------------------ */ + #define U_V1906_DROP_TABLE_QUEUE \ "DROP TABLE queue;" @@ -784,6 +793,8 @@ static const struct db_upgrade_query db_upgrade_V1906_queries[] = }; +/* ---------------------------- 19.06 -> 19.07 ------------------------------ */ + #define U_V1907_SCVER_MINOR \ "UPDATE admin SET value = '07' WHERE key = 'schema_version_minor';" @@ -794,6 +805,8 @@ static const struct db_upgrade_query db_upgrade_V1907_queries[] = }; +/* ---------------------------- 19.07 -> 19.08 ------------------------------ */ + #define U_V1908_ALTER_PL_ADD_ORDER \ "ALTER TABLE playlists ADD COLUMN query_order VARCHAR(1024);" #define U_V1908_ALTER_PL_ADD_LIMIT \ @@ -811,6 +824,8 @@ static const struct db_upgrade_query db_upgrade_v1908_queries[] = }; +/* ---------------------------- 19.08 -> 19.09 ------------------------------ */ + #define U_V1909_ALTER_FILES_ADD_SKIP_COUNT \ "ALTER TABLE files ADD COLUMN skip_count INTEGER DEFAULT 0;" #define U_V1909_ALTER_FILES_ADD_TIME_SKIPPED \ @@ -828,6 +843,8 @@ static const struct db_upgrade_query db_upgrade_v1909_queries[] = }; +/* ---------------------------- 19.09 -> 19.10 ------------------------------ */ + // Clean up after bug in commit fde0a281 (schema 19.09) #define U_V1910_CLEANUP_TIME_SKIPPED \ "UPDATE files SET time_skipped = 0 WHERE time_skipped > 2000000000;" @@ -843,6 +860,8 @@ static const struct db_upgrade_query db_upgrade_v1910_queries[] = }; +/* ---------------------------- 19.10 -> 19.11 ------------------------------ */ + #define U_v1911_ALTER_QUEUE_ADD_COMPOSER \ "ALTER TABLE queue ADD COLUMN composer VARCHAR(1024) DEFAULT NULL;" @@ -860,6 +879,8 @@ static const struct db_upgrade_query db_upgrade_v1911_queries[] = }; +/* ---------------------------- 19.11 -> 19.12 ------------------------------ */ + #define U_V1912_ALTER_DIRECTORIES_ADD_PATH \ "ALTER TABLE directories ADD COLUMN path VARCHAR(4096) DEFAULT NULL;" @@ -881,6 +902,8 @@ static const struct db_upgrade_query db_upgrade_v1912_queries[] = }; +/* ---------------------------- 19.12 -> 20.00 ------------------------------ */ + #define U_V20_NEW_FILES_TABLE \ "CREATE TABLE new_files (" \ " id INTEGER PRIMARY KEY NOT NULL," \ @@ -972,6 +995,9 @@ static const struct db_upgrade_query db_upgrade_v2000_queries[] = { U_V2000_SCVER_MINOR, "set schema_version_minor to 00" }, }; + +/* ---------------------------- 20.00 -> 20.01 ------------------------------ */ + #define U_V2001_ALTER_QUEUE_ADD_SONGARTISTID \ "ALTER TABLE queue ADD COLUMN songartistid INTEGER NOT NULL default 0;" #define U_V2001_SCVER_MINOR \ @@ -983,6 +1009,9 @@ static const struct db_upgrade_query db_upgrade_v2001_queries[] = { U_V2001_SCVER_MINOR, "set schema_version_minor to 01" }, }; + +/* ---------------------------- 20.01 -> 21.00 ------------------------------ */ + #define U_V2100_SCVER_MAJOR \ "UPDATE admin SET value = '21' WHERE key = 'schema_version_major';" #define U_V2100_SCVER_MINOR \ @@ -995,6 +1024,9 @@ static const struct db_upgrade_query db_upgrade_v2100_queries[] = { U_V2100_SCVER_MINOR, "set schema_version_minor to 00" }, }; + +/* ---------------------------- 21.00 -> 21.01 ------------------------------ */ + #define U_v2101_ALTER_QUEUE_ADD_TYPE \ "ALTER TABLE queue ADD COLUMN type VARCHAR(8) DEFAULT NULL;" #define U_v2101_ALTER_QUEUE_ADD_BITRATE \ @@ -1020,6 +1052,9 @@ static const struct db_upgrade_query db_upgrade_v2101_queries[] = { U_v2101_SCVER_MINOR, "set schema_version_minor to 01" }, }; + +/* ---------------------------- 21.01 -> 21.02 ------------------------------ */ + // This column added because Apple Music makes a DAAP request for playlists // that has a query condition on extended-media-kind. We set the default value // to 1 to signify music. @@ -1036,6 +1071,9 @@ static const struct db_upgrade_query db_upgrade_v2102_queries[] = { U_v2102_SCVER_MINOR, "set schema_version_minor to 02" }, }; + +/* ---------------------------- 21.02 -> 21.03 ------------------------------ */ + #define U_V2103_SCVER_MAJOR \ "UPDATE admin SET value = '21' WHERE key = 'schema_version_major';" #define U_V2103_SCVER_MINOR \ @@ -1048,6 +1086,9 @@ static const struct db_upgrade_query db_upgrade_v2103_queries[] = { U_V2103_SCVER_MINOR, "set schema_version_minor to 03" }, }; + +/* ---------------------------- 21.03 -> 21.04 ------------------------------ */ + #define U_v2104_ALTER_PLAYLISTS_ADD_ARTWORK_URL \ "ALTER TABLE playlists ADD COLUMN artwork_url VARCHAR(4096) DEFAULT NULL;" #define U_v2104_SCVER_MINOR \ @@ -1060,6 +1101,9 @@ static const struct db_upgrade_query db_upgrade_v2104_queries[] = { U_v2104_SCVER_MINOR, "set schema_version_minor to 04" }, }; + +/* ---------------------------- 21.04 -> 21.05 ------------------------------ */ + // Previously, the auth_key contained the public key twice #define U_v2105_UPDATE_SPEAKERS_AUTH_KEY \ "UPDATE speakers SET auth_key = SUBSTR(auth_key, LENGTH(auth_key) - 128 + 1, LENGTH(auth_key) + 1) WHERE LENGTH(auth_key) = 128 + 64;" @@ -1117,6 +1161,8 @@ static const struct db_upgrade_query db_upgrade_v2106_queries[] = }; +/* -------------------------- Main upgrade handler -------------------------- */ + int db_upgrade(sqlite3 *hdl, int db_ver) {