From 6bdcda1524f9943d8e0cc24214d747b77670d42e Mon Sep 17 00:00:00 2001 From: chme Date: Fri, 13 Apr 2018 16:29:06 +0200 Subject: [PATCH] [db/filescanner] Upgrade database to v19.08 and support limit/order by in smart playlist files --- src/db.c | 62 ++++++++++++++++++++++++++----- src/db.h | 4 ++ src/db_init.c | 4 +- src/db_init.h | 2 +- src/db_upgrade.c | 24 ++++++++++++ src/library/filescanner_smartpl.c | 11 ++++-- 6 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/db.c b/src/db.c index 2fa4f2bd..4b1b0734 100644 --- a/src/db.c +++ b/src/db.c @@ -178,6 +178,8 @@ static const struct col_type_map pli_cols_map[] = { pli_offsetof(virtual_path), DB_TYPE_STRING }, { pli_offsetof(parent_id), DB_TYPE_INT }, { pli_offsetof(directory_id), DB_TYPE_INT }, + { pli_offsetof(query_orderby),DB_TYPE_STRING }, + { pli_offsetof(query_limit), DB_TYPE_INT }, /* items is computed on the fly */ }; @@ -268,6 +270,8 @@ static const ssize_t dbpli_cols_map[] = dbpli_offsetof(virtual_path), dbpli_offsetof(parent_id), dbpli_offsetof(directory_id), + dbpli_offsetof(query_orderby), + dbpli_offsetof(query_limit), /* items is computed on the fly */ }; @@ -1584,18 +1588,54 @@ db_build_query_plitems_plain(struct query_params *qp) } static char * -db_build_query_plitems_smart(struct query_params *qp, char *smartpl_query) +db_build_query_plitems_smart(struct query_params *qp, struct playlist_info *pli) { struct query_clause *qc; char *count; char *query; + bool free_orderby = false; + + if (pli->query_limit > 0) + { + if (qp->idx_type == I_SUB) + { + if (pli->query_limit > qp->offset + qp->limit) + qp->limit = pli->query_limit; + } + else if (qp->idx_type == I_NONE) + { + qp->idx_type = I_SUB; + qp->limit = pli->query_limit; + qp->offset = 0; + } + else + { + DPRINTF(E_WARN, L_DB, "Cannot append limit from smart playlist '%s' to query\n", pli->path); + } + } + + if (pli->query_orderby) + { + if (!qp->orderby && qp->sort == S_NONE) + { + qp->orderby = strdup(pli->query_orderby); + free_orderby = true; + } + else + DPRINTF(E_WARN, L_DB, "Cannot append order by from smart playlist '%s' to query\n", pli->path); + } qc = db_build_query_clause(qp); + if (free_orderby) + { + free(qp->orderby); + qp->orderby = NULL; + } if (!qc) return NULL; - count = sqlite3_mprintf("SELECT COUNT(*) FROM files f %s AND %s;", qc->where, smartpl_query); - query = sqlite3_mprintf("SELECT f.* FROM files f %s AND %s %s %s;", qc->where, smartpl_query, qc->order, qc->index); + count = sqlite3_mprintf("SELECT COUNT(*) FROM files f %s AND %s LIMIT %d;", qc->where, pli->query, pli->query_limit); + 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); @@ -1622,7 +1662,7 @@ db_build_query_plitems(struct query_params *qp) { case PL_SPECIAL: case PL_SMART: - query = db_build_query_plitems_smart(qp, pli->query); + query = db_build_query_plitems_smart(qp, pli); break; case PL_PLAIN: @@ -3376,8 +3416,9 @@ int db_pl_add(struct playlist_info *pli, int *id) { #define QDUP_TMPL "SELECT COUNT(*) FROM playlists p WHERE p.title = TRIM(%Q) AND p.path = '%q';" -#define QADD_TMPL "INSERT INTO playlists (title, type, query, db_timestamp, disabled, path, idx, special_id, parent_id, virtual_path, directory_id)" \ - " VALUES (TRIM(%Q), %d, '%q', %" PRIi64 ", %d, '%q', %d, %d, %d, '%q', %d);" +#define QADD_TMPL "INSERT INTO playlists (title, type, query, db_timestamp, disabled, path, idx, special_id, " \ + " parent_id, virtual_path, directory_id, query_orderby, query_limit)" \ + " VALUES (TRIM(%Q), %d, '%q', %" PRIi64 ", %d, '%q', %d, %d, %d, '%q', %d, %Q, %d);" char *query; char *errmsg; int ret; @@ -3403,7 +3444,8 @@ db_pl_add(struct playlist_info *pli, int *id) /* Add */ query = sqlite3_mprintf(QADD_TMPL, pli->title, pli->type, pli->query, (int64_t)time(NULL), pli->disabled, STR(pli->path), - pli->index, pli->special_id, pli->parent_id, pli->virtual_path, pli->directory_id); + pli->index, pli->special_id, pli->parent_id, pli->virtual_path, pli->directory_id, + pli->query_orderby, pli->query_limit); if (!query) { @@ -3468,14 +3510,16 @@ int db_pl_update(struct playlist_info *pli) { #define Q_TMPL "UPDATE playlists SET title = TRIM(%Q), type = %d, query = '%q', db_timestamp = %" PRIi64 ", disabled = %d, " \ - " path = '%q', idx = %d, special_id = %d, parent_id = %d, virtual_path = '%q', directory_id = %d " \ + " path = '%q', idx = %d, special_id = %d, parent_id = %d, virtual_path = '%q', directory_id = %d, " \ + " query_orderby = %Q, query_limit = %d " \ " WHERE id = %d;" char *query; int ret; query = sqlite3_mprintf(Q_TMPL, pli->title, pli->type, pli->query, (int64_t)time(NULL), pli->disabled, STR(pli->path), - pli->index, pli->special_id, pli->parent_id, pli->virtual_path, pli->directory_id, pli->id); + pli->index, pli->special_id, pli->parent_id, pli->virtual_path, pli->directory_id, + pli->query_orderby, pli->query_limit, pli->id); ret = db_query_run(query, 1, 0); diff --git a/src/db.h b/src/db.h index 379ba9e9..6de25475 100644 --- a/src/db.h +++ b/src/db.h @@ -247,6 +247,8 @@ struct playlist_info { char *virtual_path; /* virtual path of underlying playlist */ uint32_t parent_id; /* Id of parent playlist if the playlist is nested */ uint32_t directory_id; /* Id of directory */ + char *query_orderby; /* order by clause if it is a smart playlist */ + uint32_t query_limit; /* limit if it is a smart playlist */ }; #define pli_offsetof(field) offsetof(struct playlist_info, field) @@ -266,6 +268,8 @@ struct db_playlist_info { char *virtual_path; char *parent_id; char *directory_id; + char *query_orderby; + char *query_limit; }; #define dbpli_offsetof(field) offsetof(struct db_playlist_info, field) diff --git a/src/db_init.c b/src/db_init.c index 7c12e0b0..5c6b48b9 100644 --- a/src/db_init.c +++ b/src/db_init.c @@ -109,7 +109,9 @@ " special_id INTEGER DEFAULT 0," \ " virtual_path VARCHAR(4096)," \ " parent_id INTEGER DEFAULT 0," \ - " directory_id INTEGER DEFAULT 0" \ + " directory_id INTEGER DEFAULT 0," \ + " query_orderby VARCHAR(1024)," \ + " query_limit INTEGER DEFAULT 0" \ ");" #define T_PLITEMS \ diff --git a/src/db_init.h b/src/db_init.h index 0c37f83a..ce430015 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 19 -#define SCHEMA_VERSION_MINOR 07 +#define SCHEMA_VERSION_MINOR 8 int db_init_indices(sqlite3 *hdl); diff --git a/src/db_upgrade.c b/src/db_upgrade.c index 857d59c7..9c815841 100644 --- a/src/db_upgrade.c +++ b/src/db_upgrade.c @@ -1634,6 +1634,23 @@ static const struct db_upgrade_query db_upgrade_V1907_queries[] = }; +#define U_V1908_ALTER_PL_ADD_ORDERBY \ + "ALTER TABLE playlists ADD COLUMN query_orderby VARCHAR(1024);" +#define U_V1908_ALTER_PL_ADD_LIMIT \ + "ALTER TABLE playlists ADD COLUMN query_limit INTEGER DEFAULT 0;" + +#define U_V1908_SCVER_MINOR \ + "UPDATE admin SET value = '08' WHERE key = 'schema_version_minor';" + +static const struct db_upgrade_query db_upgrade_v1908_queries[] = + { + { U_V1908_ALTER_PL_ADD_ORDERBY, "alter table playlists add column query_orderby" }, + { U_V1908_ALTER_PL_ADD_LIMIT, "alter table playlists add column query_limit" }, + + { U_V1908_SCVER_MINOR, "set schema_version_minor to 08" }, + }; + + int db_upgrade(sqlite3 *hdl, int db_ver) { @@ -1793,6 +1810,13 @@ db_upgrade(sqlite3 *hdl, int db_ver) if (ret < 0) return -1; + /* FALLTHROUGH */ + + case 1907: + ret = db_generic_upgrade(hdl, db_upgrade_v1908_queries, ARRAY_SIZE(db_upgrade_v1908_queries)); + if (ret < 0) + return -1; + break; default: diff --git a/src/library/filescanner_smartpl.c b/src/library/filescanner_smartpl.c index aa344f28..841593e4 100644 --- a/src/library/filescanner_smartpl.c +++ b/src/library/filescanner_smartpl.c @@ -80,14 +80,17 @@ scan_smartpl(const char *file, time_t mtime, int dir_id) return; } - if (pli->title) - free(pli->title); + free(pli->title); pli->title = strdup(smartpl.title); - if (pli->query) - free(pli->query); + free(pli->query); pli->query = strdup(smartpl.query_where); + free(pli->query_orderby); + pli->query_orderby = safe_strdup(smartpl.order_by); + + pli->query_limit = smartpl.limit; + free_smartpl(&smartpl, 1); if (pli->id)