mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-11 15:03:24 -05:00
Use view for filelist instead of separate table
This commit is contained in:
parent
aa0abc1664
commit
df5b0f779a
124
sqlext/sqlext.c
124
sqlext/sqlext.c
@ -244,6 +244,112 @@ sqlext_daap_unicode_xcollation(void *notused, int llen, const void *left, int rl
|
||||
return rpp;
|
||||
}
|
||||
|
||||
static void
|
||||
sqlext_daap_substring_xfunc(sqlite3_context *pv, int n, sqlite3_value **ppv)
|
||||
{
|
||||
const unsigned char *s1;
|
||||
const unsigned char *s2;
|
||||
int index;
|
||||
|
||||
char *start;
|
||||
char *end;
|
||||
char *result;
|
||||
|
||||
if (n < 2)
|
||||
{
|
||||
sqlite3_result_error(pv, "daap_substring() requires at least 2 parameters", -1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SQLITE_TEXT != sqlite3_value_type(ppv[0]) || SQLITE_TEXT != sqlite3_value_type(ppv[1]))
|
||||
{
|
||||
sqlite3_result_null(pv);
|
||||
return;
|
||||
}
|
||||
|
||||
s1 = sqlite3_value_text(ppv[0]);
|
||||
s2 = sqlite3_value_text(ppv[1]);
|
||||
|
||||
if (n > 2)
|
||||
index = sqlite3_value_int(ppv[2]);
|
||||
else
|
||||
index = 0;
|
||||
|
||||
if (strlen((char *) s1) < index)
|
||||
{
|
||||
sqlite3_result_null(pv);
|
||||
return;
|
||||
}
|
||||
|
||||
start = (char *) s1 + index;
|
||||
end = strstr(start, (char *) s2);
|
||||
|
||||
if (!end)
|
||||
{
|
||||
sqlite3_result_null(pv);
|
||||
return;
|
||||
}
|
||||
|
||||
result = sqlite3_malloc(end - (char *) s1 + 1);
|
||||
if (!result)
|
||||
{
|
||||
sqlite3_result_error_nomem(pv);
|
||||
return;
|
||||
}
|
||||
|
||||
strncpy((char*) result, (char*) s1, end - (char *) s1);
|
||||
*(result + (end - (char *) s1)) = '\0';
|
||||
sqlite3_result_text(pv, (char*) result, -1, SQLITE_TRANSIENT);
|
||||
sqlite3_free(result);
|
||||
}
|
||||
|
||||
static void
|
||||
sqlext_daap_charindex_xfunc(sqlite3_context *pv, int n, sqlite3_value **ppv)
|
||||
{
|
||||
const unsigned char *s1;
|
||||
const unsigned char *s2;
|
||||
int index;
|
||||
|
||||
char *start;
|
||||
char *end;
|
||||
|
||||
if (n < 2)
|
||||
{
|
||||
sqlite3_result_error(pv, "daap_charindex() requires at least 2 parameters", -1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (SQLITE_TEXT != sqlite3_value_type(ppv[0]) || SQLITE_TEXT != sqlite3_value_type(ppv[1]))
|
||||
{
|
||||
sqlite3_result_int(pv, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
s1 = sqlite3_value_text(ppv[0]);
|
||||
s2 = sqlite3_value_text(ppv[1]);
|
||||
|
||||
if (n > 2)
|
||||
index = sqlite3_value_int(ppv[2]);
|
||||
else
|
||||
index = 0;
|
||||
|
||||
if (strlen((char *) s1) < index)
|
||||
{
|
||||
sqlite3_result_int(pv, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
start = (char *) s1 + index;
|
||||
end = strstr(start, (char *) s2);
|
||||
|
||||
if (!end)
|
||||
{
|
||||
sqlite3_result_int(pv, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
sqlite3_result_int(pv, end - (char *) s1);
|
||||
}
|
||||
|
||||
int
|
||||
sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi)
|
||||
@ -269,5 +375,23 @@ sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = sqlite3_create_function(db, "daap_substring", 3, SQLITE_UTF8, NULL, sqlext_daap_substring_xfunc, NULL, NULL);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
if (pzErrMsg)
|
||||
*pzErrMsg = sqlite3_mprintf("Could not create daap_substring function: %s\n", sqlite3_errmsg(db));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = sqlite3_create_function(db, "daap_charindex", 3, SQLITE_UTF8, NULL, sqlext_daap_charindex_xfunc, NULL, NULL);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
if (pzErrMsg)
|
||||
*pzErrMsg = sqlite3_mprintf("Could not create daap_charindex function: %s\n", sqlite3_errmsg(db));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
399
src/db.c
399
src/db.c
@ -324,12 +324,8 @@ db_escape_string(const char *str)
|
||||
void
|
||||
free_fi(struct filelist_info *fi, int content_only)
|
||||
{
|
||||
if (fi->path)
|
||||
free(fi->path);
|
||||
if (fi->name)
|
||||
free(fi->name);
|
||||
if (fi->parentpath)
|
||||
free(fi->parentpath);
|
||||
if (fi->virtual_path)
|
||||
free(fi->virtual_path);
|
||||
|
||||
if (!content_only)
|
||||
free(fi);
|
||||
@ -769,13 +765,9 @@ db_purge_cruft(time_t ref)
|
||||
char *errmsg;
|
||||
int i;
|
||||
int ret;
|
||||
int changes;
|
||||
char *query;
|
||||
char *queries[5] = { NULL, NULL, NULL, NULL, NULL };
|
||||
char *queries_tmpl[5] =
|
||||
char *queries[3] = { NULL, NULL, NULL };
|
||||
char *queries_tmpl[3] =
|
||||
{
|
||||
"DELETE FROM filelist WHERE type = 3 AND path IN (SELECT path FROM files f WHERE f.db_timestamp < %" PRIi64 ");",
|
||||
"DELETE FROM filelist WHERE type = 1 AND path IN (SELECT path FROM playlists p WHERE p.type <> 1 AND p.db_timestamp < %" PRIi64 ");",
|
||||
"DELETE FROM playlistitems WHERE playlistid IN (SELECT id FROM playlists p WHERE p.type <> 1 AND p.db_timestamp < %" PRIi64 ");",
|
||||
"DELETE FROM playlists WHERE type <> 1 AND db_timestamp < %" PRIi64 ";",
|
||||
"DELETE FROM files WHERE db_timestamp < %" PRIi64 ";"
|
||||
@ -812,29 +804,6 @@ db_purge_cruft(time_t ref)
|
||||
DPRINTF(E_DBG, L_DB, "Purged %d rows\n", sqlite3_changes(hdl));
|
||||
}
|
||||
|
||||
// Remove empty directories from filelist table
|
||||
query = "DELETE FROM filelist WHERE type = 2 AND 0 = (SELECT COUNT(path) FROM filelist f WHERE f.parentpath = filelist.path);";
|
||||
|
||||
do
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "Running purge query '%s'\n", query);
|
||||
|
||||
ret = db_exec(query, &errmsg);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Purge query %d error: %s\n", i, errmsg);
|
||||
|
||||
sqlite3_free(errmsg);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
changes = sqlite3_changes(hdl);
|
||||
DPRINTF(E_DBG, L_DB, "Purged %d rows\n", changes);
|
||||
}
|
||||
|
||||
} while (changes > 0);
|
||||
|
||||
purge_fail:
|
||||
for (i = 0; i < (sizeof(queries) / sizeof(queries[0])); i++)
|
||||
{
|
||||
@ -853,7 +822,6 @@ db_purge_all(void)
|
||||
"DELETE FROM playlists WHERE type <> 1;",
|
||||
"DELETE FROM files;",
|
||||
"DELETE FROM groups;",
|
||||
"DELETE FROM filelist;"
|
||||
};
|
||||
char *errmsg;
|
||||
int i;
|
||||
@ -1909,85 +1877,54 @@ db_query_fetch_string_sort(struct query_params *qp, char **string, char **sortst
|
||||
|
||||
/* Filelist */
|
||||
|
||||
static int
|
||||
db_filelist_add(const char *virtual_path, enum filelistitem_type type)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char parentpath[PATH_MAX];
|
||||
char *name;
|
||||
char *query;
|
||||
char *errmsg;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_DB, "Add file to filelist with type %d and virtual path '%s'\n", type, virtual_path);
|
||||
|
||||
strcpy(path, virtual_path);
|
||||
strcpy(parentpath, path);
|
||||
name = strrchr(parentpath, '/');
|
||||
*name = '\0';
|
||||
name++;
|
||||
|
||||
query = sqlite3_mprintf("INSERT INTO filelist (path, name, type, parentpath, disabled) VALUES ('%q', '%q', %d, '%q', %d);",
|
||||
path, name, type, parentpath, 0);
|
||||
DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query);
|
||||
ret = db_exec(query, &errmsg);
|
||||
|
||||
if (ret == SQLITE_CONSTRAINT)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "Path already exists in filelist '%s'\n", path);
|
||||
sqlite3_free(errmsg);
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
}
|
||||
else if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Error '%s' while runnning '%s'\n", errmsg, query);
|
||||
sqlite3_free(errmsg);
|
||||
sqlite3_free(query);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sqlite3_free(query);
|
||||
|
||||
while ((name = strrchr(parentpath, '/')))
|
||||
{
|
||||
strcpy(path, parentpath);
|
||||
*name = '\0';
|
||||
name++;
|
||||
|
||||
query = sqlite3_mprintf("INSERT INTO filelist (path, name, type, parentpath, disabled) VALUES ('%q', '%q', %d, '%q', %d);",
|
||||
path, name, F_DIR, (*parentpath == '\0' ? "/" : parentpath), 0);
|
||||
DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query);
|
||||
ret = db_exec(query, &errmsg);
|
||||
|
||||
if (ret == SQLITE_CONSTRAINT)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "Path already exists in filelist '%s'\n", path);
|
||||
sqlite3_free(errmsg);
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
}
|
||||
else if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Error '%s' while runnning '%s'\n", errmsg, query);
|
||||
sqlite3_free(errmsg);
|
||||
sqlite3_free(query);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sqlite3_free(query);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
db_build_query_filelist(struct query_params *qp, char *parentpath)
|
||||
db_mpd_build_query_filelist(struct query_params *qp, char *parentpath)
|
||||
{
|
||||
char *query;
|
||||
int ret;
|
||||
|
||||
query = sqlite3_mprintf("SELECT * FROM filelist WHERE disabled = 0 AND parentpath = '%q' ORDER BY type, name;", parentpath);
|
||||
/*
|
||||
query = sqlite3_mprintf(
|
||||
"SELECT "
|
||||
" CASE WHEN INSTR(SUBSTR(virtual_path, LENGTH(%Q)+1), '/') = 0 "
|
||||
" THEN "
|
||||
" virtual_path "
|
||||
" ELSE "
|
||||
" SUBSTR(virtual_path, 1, LENGTH(%Q)+INSTR(SUBSTR(virtual_path, LENGTH(%Q)+1), '/')-1) "
|
||||
" END AS path, "
|
||||
" MAX(time_modified), "
|
||||
" CASE WHEN INSTR(SUBSTR(virtual_path, LENGTH(%Q)+1), '/') = 0 "
|
||||
" THEN "
|
||||
" type "
|
||||
" ELSE "
|
||||
" 2 "
|
||||
" END AS ftype, "
|
||||
" disabled "
|
||||
"FROM filelist "
|
||||
"WHERE virtual_path LIKE '%q%%' "
|
||||
"GROUP BY ftype, path "
|
||||
"ORDER BY ftype, path;", parentpath, parentpath, parentpath, parentpath, parentpath);
|
||||
*/
|
||||
query = sqlite3_mprintf(
|
||||
"SELECT "
|
||||
" CASE WHEN daap_charindex(virtual_path, '/', LENGTH(%Q)) = -1 "
|
||||
" THEN "
|
||||
" virtual_path "
|
||||
" ELSE "
|
||||
" daap_substring(virtual_path, '/', LENGTH(%Q)) "
|
||||
" END AS path, "
|
||||
" MAX(time_modified), "
|
||||
" CASE WHEN daap_charindex(virtual_path, '/', LENGTH(%Q)) = -1 "
|
||||
" THEN "
|
||||
" type "
|
||||
" ELSE "
|
||||
" 2 "
|
||||
" END AS ftype "
|
||||
"FROM filelist "
|
||||
"WHERE virtual_path LIKE '%q%%' "
|
||||
"GROUP BY ftype, path "
|
||||
"ORDER BY ftype, path;", parentpath, parentpath, parentpath, parentpath);
|
||||
|
||||
if (!query)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
|
||||
@ -2011,7 +1948,7 @@ db_build_query_filelist(struct query_params *qp, char *parentpath)
|
||||
}
|
||||
|
||||
int
|
||||
db_query_fetch_filelist(struct query_params *qp, struct filelist_info *fi)
|
||||
db_mpd_query_fetch_filelist(struct query_params *qp, struct filelist_info *fi)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -2027,7 +1964,7 @@ db_query_fetch_filelist(struct query_params *qp, struct filelist_info *fi)
|
||||
if (ret == SQLITE_DONE)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "End of query results\n");
|
||||
fi->path = NULL;
|
||||
fi->virtual_path = NULL;
|
||||
return 0;
|
||||
}
|
||||
else if (ret != SQLITE_ROW)
|
||||
@ -2036,93 +1973,13 @@ db_query_fetch_filelist(struct query_params *qp, struct filelist_info *fi)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fi->path = strdup((char *)sqlite3_column_text(qp->stmt, 0));
|
||||
fi->name = strdup((char *)sqlite3_column_text(qp->stmt, 1));
|
||||
fi->virtual_path = strdup((char *)sqlite3_column_text(qp->stmt, 0));
|
||||
fi->time_modified = sqlite3_column_int(qp->stmt, 1);
|
||||
fi->type = sqlite3_column_int(qp->stmt, 2);
|
||||
fi->parentpath = strdup((char *)sqlite3_column_text(qp->stmt, 3));
|
||||
fi->disabled = sqlite3_column_int(qp->stmt, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct filelist_info *
|
||||
db_filelist_fetch_byquery(char *query)
|
||||
{
|
||||
struct filelist_info *fi;
|
||||
sqlite3_stmt *stmt;
|
||||
int ret;
|
||||
|
||||
if (!query)
|
||||
return NULL;
|
||||
|
||||
DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query);
|
||||
|
||||
fi = (struct filelist_info *)malloc(sizeof(struct filelist_info));
|
||||
if (!fi)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Could not allocate struct filelist_info, out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(fi, 0, sizeof(struct filelist_info));
|
||||
|
||||
ret = db_blocking_prepare_v2(query, -1, &stmt, NULL);
|
||||
if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Could not prepare statement: %s\n", sqlite3_errmsg(hdl));
|
||||
|
||||
free(fi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = db_blocking_step(stmt);
|
||||
|
||||
if (ret != SQLITE_ROW)
|
||||
{
|
||||
if (ret == SQLITE_DONE)
|
||||
DPRINTF(E_DBG, L_DB, "No results\n");
|
||||
else
|
||||
DPRINTF(E_LOG, L_DB, "Could not step: %s\n", sqlite3_errmsg(hdl));
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
free(fi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
fi->path = strdup((char *)sqlite3_column_text(stmt, 0));
|
||||
fi->name = strdup((char *)sqlite3_column_text(stmt, 1));
|
||||
fi->type = sqlite3_column_int(stmt, 2);
|
||||
fi->parentpath = strdup((char *)sqlite3_column_text(stmt, 3));
|
||||
fi->disabled = sqlite3_column_int(stmt, 4);
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return fi;
|
||||
}
|
||||
|
||||
struct filelist_info *
|
||||
db_filelist_fetch_bypath(const char *path)
|
||||
{
|
||||
#define Q_TMPL "SELECT f.* FROM filelist f WHERE f.path = %Q;"
|
||||
struct filelist_info *fi;
|
||||
char *query;
|
||||
|
||||
query = sqlite3_mprintf(Q_TMPL, path);
|
||||
if (!query)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fi = db_filelist_fetch_byquery(query);
|
||||
|
||||
sqlite3_free(query);
|
||||
|
||||
return fi;
|
||||
|
||||
#undef Q_TMPL
|
||||
}
|
||||
|
||||
/* Files */
|
||||
int
|
||||
@ -2728,8 +2585,6 @@ db_file_add(struct media_file_info *mfi)
|
||||
|
||||
sqlite3_free(query);
|
||||
|
||||
db_filelist_add(mfi->virtual_path, F_FILE);
|
||||
|
||||
cache_daap_trigger();
|
||||
|
||||
return 0;
|
||||
@ -2821,8 +2676,6 @@ db_file_update(struct media_file_info *mfi)
|
||||
|
||||
sqlite3_free(query);
|
||||
|
||||
db_filelist_add(mfi->virtual_path, F_FILE);
|
||||
|
||||
cache_daap_trigger();
|
||||
|
||||
return 0;
|
||||
@ -3310,8 +3163,6 @@ db_pl_add(char *title, char *path, char *virtual_path, int *id)
|
||||
|
||||
DPRINTF(E_DBG, L_DB, "Added playlist %s (path %s) with id %d\n", title, path, *id);
|
||||
|
||||
db_filelist_add(virtual_path, F_PLAYLIST);
|
||||
|
||||
return 0;
|
||||
|
||||
#undef QDUP_TMPL
|
||||
@ -3353,11 +3204,6 @@ db_pl_update(char *title, char *path, char *virtual_path, int id)
|
||||
|
||||
ret = db_query_run(query, 1, 0);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
db_filelist_add(virtual_path, F_PLAYLIST);
|
||||
}
|
||||
|
||||
return ret;
|
||||
#undef Q_TMPL
|
||||
}
|
||||
@ -3663,12 +3509,11 @@ db_pairing_fetch_byguid(struct pairing_info *pi)
|
||||
void
|
||||
db_spotify_purge(void)
|
||||
{
|
||||
char *queries[4] =
|
||||
char *queries[3] =
|
||||
{
|
||||
"DELETE FROM files WHERE path LIKE 'spotify:%%';",
|
||||
"DELETE FROM playlistitems WHERE filepath LIKE 'spotify:%%';",
|
||||
"DELETE FROM playlists WHERE path LIKE 'spotify:%%';",
|
||||
"DELETE FROM filelist WHERE path LIKE '/spotify:%%';",
|
||||
};
|
||||
int i;
|
||||
int ret;
|
||||
@ -3686,13 +3531,11 @@ db_spotify_purge(void)
|
||||
void
|
||||
db_spotify_pl_delete(int id)
|
||||
{
|
||||
char *queries_tmpl[5] =
|
||||
char *queries_tmpl[3] =
|
||||
{
|
||||
"DELETE FROM filelist WHERE path IN (SELECT virtual_path FROM playlists WHERE id = %d);",
|
||||
"DELETE FROM playlists WHERE id = %d;",
|
||||
"DELETE FROM playlistitems WHERE playlistid = %d;",
|
||||
"DELETE FROM files WHERE path LIKE 'spotify:%%' AND NOT path IN (SELECT filepath FROM playlistitems);",
|
||||
"DELETE FROM filelist WHERE path LIKE 'spotify:%%' AND NOT path IN (SELECT virtual_path FROM FILES WHERE path LIKE 'spotify:%%');",
|
||||
};
|
||||
char *query;
|
||||
int i;
|
||||
@ -4682,14 +4525,16 @@ db_perthread_deinit(void)
|
||||
" path VARCHAR(4096) NOT NULL" \
|
||||
");"
|
||||
|
||||
#define T_FILELIST \
|
||||
"CREATE TABLE IF NOT EXISTS filelist (" \
|
||||
" path VARCHAR(4096) PRIMARY KEY NOT NULL," \
|
||||
" name VARCHAR(255) NOT NULL," \
|
||||
" type INTEGER NOT NULL," \
|
||||
" parentpath VARCHAR(4096) NOT NULL," \
|
||||
" disabled INTEGER DEFAULT 0" \
|
||||
");"
|
||||
#define V_FILELIST \
|
||||
"CREATE VIEW IF NOT EXISTS filelist as" \
|
||||
" SELECT " \
|
||||
" virtual_path, time_modified, 3 as type " \
|
||||
" FROM files WHERE disabled = 0" \
|
||||
" UNION " \
|
||||
" SELECT " \
|
||||
" virtual_path, db_timestamp, 1 as type " \
|
||||
" FROM playlists where disabled = 0 AND type = 0" \
|
||||
";"
|
||||
|
||||
#define TRG_GROUPS_INSERT_FILES \
|
||||
"CREATE TRIGGER update_groups_new_file AFTER INSERT ON files FOR EACH ROW" \
|
||||
@ -4761,7 +4606,7 @@ static const struct db_init_query db_init_table_queries[] =
|
||||
{ T_SPEAKERS, "create table speakers" },
|
||||
{ T_INOTIFY, "create table inotify" },
|
||||
|
||||
{ T_FILELIST, "create table filelist" },
|
||||
{ V_FILELIST, "create view filelist" },
|
||||
|
||||
{ TRG_GROUPS_INSERT_FILES, "create trigger update_groups_new_file" },
|
||||
{ TRG_GROUPS_UPDATE_FILES, "create trigger update_groups_update_file" },
|
||||
@ -4819,11 +4664,14 @@ static const struct db_init_query db_init_table_queries[] =
|
||||
#define I_ALBUM \
|
||||
"CREATE INDEX IF NOT EXISTS idx_album ON files(album, album_sort);"
|
||||
|
||||
#define I_FILELIST \
|
||||
"CREATE INDEX IF NOT EXISTS idx_filelist ON files(disabled, virtual_path, time_modified);"
|
||||
|
||||
#define I_PL_PATH \
|
||||
"CREATE INDEX IF NOT EXISTS idx_pl_path ON playlists(path);"
|
||||
|
||||
#define I_PL_DISABLED \
|
||||
"CREATE INDEX IF NOT EXISTS idx_pl_disabled ON playlists(disabled);"
|
||||
"CREATE INDEX IF NOT EXISTS idx_pl_disabled ON playlists(disabled, type, virtual_path, db_timestamp);"
|
||||
|
||||
#define I_FILEPATH \
|
||||
"CREATE INDEX IF NOT EXISTS idx_filepath ON playlistitems(filepath ASC);"
|
||||
@ -4837,9 +4685,6 @@ static const struct db_init_query db_init_table_queries[] =
|
||||
#define I_PAIRING \
|
||||
"CREATE INDEX IF NOT EXISTS idx_pairingguid ON pairings(guid);"
|
||||
|
||||
#define I_FILELIST \
|
||||
"CREATE INDEX IF NOT EXISTS idx_parentpath_disabled ON filelist(disabled, parentpath, type, name);"
|
||||
|
||||
static const struct db_init_query db_init_index_queries[] =
|
||||
{
|
||||
{ I_RESCAN, "create rescan index" },
|
||||
@ -4854,6 +4699,7 @@ static const struct db_init_query db_init_index_queries[] =
|
||||
{ I_GENRE, "create genre index" },
|
||||
{ I_TITLE, "create title index" },
|
||||
{ I_ALBUM, "create album index" },
|
||||
{ I_FILELIST, "create filelist index" },
|
||||
|
||||
{ I_PL_PATH, "create playlist path index" },
|
||||
{ I_PL_DISABLED, "create playlist state index" },
|
||||
@ -4864,8 +4710,6 @@ static const struct db_init_query db_init_index_queries[] =
|
||||
{ I_GRP_PERSIST, "create groups persistentid index" },
|
||||
|
||||
{ I_PAIRING, "create pairing guid index" },
|
||||
|
||||
{ I_FILELIST, "create filelist index" },
|
||||
};
|
||||
|
||||
static int
|
||||
@ -5800,14 +5644,16 @@ static const struct db_init_query db_upgrade_v1501_queries[] =
|
||||
|
||||
/* Upgrade from schema v15.01 to v16 */
|
||||
|
||||
#define U_V16_CREATE_TBL_FILELIST \
|
||||
"CREATE TABLE IF NOT EXISTS filelist (" \
|
||||
" path VARCHAR(4096) PRIMARY KEY NOT NULL,"\
|
||||
" name VARCHAR(255) NOT NULL," \
|
||||
" type INTEGER NOT NULL," \
|
||||
" parentpath VARCHAR(4096) NOT NULL," \
|
||||
" disabled INTEGER DEFAULT 0" \
|
||||
");"
|
||||
#define U_V16_CREATE_VIEW_FILELIST \
|
||||
"CREATE VIEW IF NOT EXISTS filelist as" \
|
||||
" SELECT " \
|
||||
" virtual_path, time_modified, 3 as type " \
|
||||
" FROM files WHERE disabled = 0" \
|
||||
" UNION " \
|
||||
" SELECT " \
|
||||
" virtual_path, db_timestamp, 1 as type " \
|
||||
" FROM playlists WHERE disabled = 0 AND type = 0" \
|
||||
";"
|
||||
|
||||
#define U_V16_ALTER_TBL_FILES_ADD_COL \
|
||||
"ALTER TABLE files ADD COLUMN virtual_path VARCHAR(4096) DEFAULT NULL;"
|
||||
@ -5824,83 +5670,15 @@ static const struct db_init_query db_upgrade_v1501_queries[] =
|
||||
|
||||
static const struct db_init_query db_upgrade_v16_queries[] =
|
||||
{
|
||||
{ U_V16_CREATE_TBL_FILELIST, "create new table filelist" },
|
||||
{ U_V16_ALTER_TBL_FILES_ADD_COL, "alter table files add column virtual_path" },
|
||||
{ U_V16_ALTER_TBL_PL_ADD_COL, "alter table playlists add column virtual_path" },
|
||||
{ U_V16_CREATE_VIEW_FILELIST, "create new view filelist" },
|
||||
|
||||
{ U_V16_SCVER, "set schema_version to 16" },
|
||||
{ U_V1600_SCVER_MAJOR, "set schema_version_major to 16" },
|
||||
{ U_V1600_SCVER_MINOR, "set schema_version_minor to 00" },
|
||||
};
|
||||
|
||||
static int
|
||||
db_upgrade_v16_filelist_add(const char *virtual_path, int type)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char parentpath[PATH_MAX];
|
||||
char *name;
|
||||
char *query;
|
||||
char *errmsg;
|
||||
int ret;
|
||||
|
||||
strcpy(path, virtual_path);
|
||||
strcpy(parentpath, path);
|
||||
name = strrchr(parentpath, '/');
|
||||
*name = '\0';
|
||||
name++;
|
||||
|
||||
query = sqlite3_mprintf("INSERT INTO filelist (path, name, type, parentpath, disabled) VALUES ('%q', '%q', %d, '%q', %d);", path, name, type, parentpath, 0);
|
||||
DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query);
|
||||
ret = sqlite3_exec(hdl, query, NULL, NULL, &errmsg);
|
||||
|
||||
if (ret == SQLITE_CONSTRAINT)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "Path already exists in filelist '%s'\n", path);
|
||||
sqlite3_free(errmsg);
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
}
|
||||
else if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Error '%s' while runnning '%s'\n", errmsg, query);
|
||||
sqlite3_free(errmsg);
|
||||
sqlite3_free(query);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sqlite3_free(query);
|
||||
|
||||
while ((name = strrchr(parentpath, '/')))
|
||||
{
|
||||
strcpy(path, parentpath);
|
||||
*name = '\0';
|
||||
name++;
|
||||
|
||||
query = sqlite3_mprintf("INSERT INTO filelist (path, name, type, parentpath, disabled) VALUES ('%q', '%q', %d, '%q', %d);", path, name, F_DIR, (*parentpath == '\0' ? "/" : parentpath), 0);
|
||||
DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query);
|
||||
ret = sqlite3_exec(hdl, query, NULL, NULL, &errmsg);
|
||||
|
||||
if (ret == SQLITE_CONSTRAINT)
|
||||
{
|
||||
DPRINTF(E_DBG, L_DB, "Path already exists in filelist '%s'\n", path);
|
||||
sqlite3_free(errmsg);
|
||||
sqlite3_free(query);
|
||||
return 0;
|
||||
}
|
||||
else if (ret != SQLITE_OK)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Error '%s' while runnning '%s'\n", errmsg, query);
|
||||
sqlite3_free(errmsg);
|
||||
sqlite3_free(query);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sqlite3_free(query);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
db_upgrade_v16(void)
|
||||
{
|
||||
@ -5957,17 +5735,6 @@ db_upgrade_v16(void)
|
||||
DPRINTF(E_LOG, L_DB, "Error updating files: %s\n", errmsg);
|
||||
}
|
||||
|
||||
if (data_kind == 0 /* Real file*/
|
||||
|| data_kind == 1 /* URL */
|
||||
|| data_kind == 2 /* Spotify */)
|
||||
{
|
||||
ret = db_upgrade_v16_filelist_add(virtual_path, 3); /* Real file, spotify url, http url */
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Error updating filelist for file %d\n", id);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_free(uquery);
|
||||
sqlite3_free(errmsg);
|
||||
}
|
||||
@ -6013,12 +5780,6 @@ db_upgrade_v16(void)
|
||||
|
||||
sqlite3_free(uquery);
|
||||
sqlite3_free(errmsg);
|
||||
|
||||
ret = db_upgrade_v16_filelist_add(virtual_path, 1); /* Playlists */
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_DB, "Error updating filelist for playlist %d\n", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
11
src/db.h
11
src/db.h
@ -52,7 +52,6 @@ enum filelistitem_type {
|
||||
F_PLAYLIST = 1,
|
||||
F_DIR = 2,
|
||||
F_FILE = 3,
|
||||
F_URL = 4,
|
||||
};
|
||||
|
||||
struct query_params {
|
||||
@ -289,11 +288,9 @@ struct db_media_file_info {
|
||||
#define dbmfi_offsetof(field) offsetof(struct db_media_file_info, field)
|
||||
|
||||
struct filelist_info {
|
||||
char *path;
|
||||
char *name;
|
||||
char *virtual_path;
|
||||
uint32_t time_modified;
|
||||
enum filelistitem_type type;
|
||||
char *parentpath;
|
||||
int disabled;
|
||||
};
|
||||
|
||||
struct watch_info {
|
||||
@ -495,10 +492,10 @@ db_group_persistentid_byid(int id, int64_t *persistentid);
|
||||
|
||||
/* Filelist */
|
||||
int
|
||||
db_build_query_filelist(struct query_params *qp, char *path);
|
||||
db_mpd_build_query_filelist(struct query_params *qp, char *path);
|
||||
|
||||
int
|
||||
db_query_fetch_filelist(struct query_params *qp, struct filelist_info *fi);
|
||||
db_mpd_query_fetch_filelist(struct query_params *qp, struct filelist_info *fi);
|
||||
|
||||
struct filelist_info *
|
||||
db_filelist_fetch_bypath(const char *path);
|
||||
|
19
src/mpd.c
19
src/mpd.c
@ -1685,17 +1685,18 @@ mpd_command_lsinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
struct media_file_info *mfi;
|
||||
int ret;
|
||||
|
||||
if (argc < 2)
|
||||
if (argc < 2 || strlen(argv[1]) == 0
|
||||
|| (strncmp(argv[1], "/", 1) == 0 && strlen(argv[1]) == 1))
|
||||
{
|
||||
ret = snprintf(parent, sizeof(parent), "/");
|
||||
}
|
||||
else if (strncmp(argv[1], "/", 1) == 0)
|
||||
{
|
||||
ret = snprintf(parent, sizeof(parent), "%s", argv[1]);
|
||||
ret = snprintf(parent, sizeof(parent), "%s/", argv[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = snprintf(parent, sizeof(parent), "/%s", argv[1]);
|
||||
ret = snprintf(parent, sizeof(parent), "/%s/", argv[1]);
|
||||
}
|
||||
|
||||
if ((ret < 0) || (ret >= sizeof(parent)))
|
||||
@ -1713,7 +1714,7 @@ mpd_command_lsinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
|
||||
memset(&qp, 0, sizeof(struct query_params));
|
||||
|
||||
ret = db_build_query_filelist(&qp, parent);
|
||||
ret = db_mpd_build_query_filelist(&qp, parent);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MPD, "Could not start query for path '%s'\n", argv[1]);
|
||||
@ -1725,31 +1726,31 @@ mpd_command_lsinfo(struct evbuffer *evbuf, int argc, char **argv, char **errmsg)
|
||||
return ACK_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
while (((ret = db_query_fetch_filelist(&qp, fi)) == 0) && (fi->path))
|
||||
while (((ret = db_mpd_query_fetch_filelist(&qp, fi)) == 0) && (fi->virtual_path))
|
||||
{
|
||||
if (fi->type == F_DIR)
|
||||
{
|
||||
evbuffer_add_printf(evbuf,
|
||||
"directory: %s\n"
|
||||
"Last-Modified: 2014-07-11T14:13:56Z\n", //TODO Send correct last modified timestamp
|
||||
(fi->path + 1));
|
||||
(fi->virtual_path + 1));
|
||||
}
|
||||
else if (fi->type == F_PLAYLIST)
|
||||
{
|
||||
evbuffer_add_printf(evbuf,
|
||||
"playlist: %s\n"
|
||||
"Last-Modified: 2014-07-11T14:13:56Z\n", //TODO Send correct last modified timestamp
|
||||
(fi->path + 1));
|
||||
(fi->virtual_path + 1));
|
||||
}
|
||||
else if (fi->type == F_FILE)
|
||||
{
|
||||
mfi = db_file_fetch_byvirtualpath(fi->path);
|
||||
mfi = db_file_fetch_byvirtualpath(fi->virtual_path);
|
||||
if (mfi)
|
||||
{
|
||||
ret = mpd_add_mediainfo(evbuf, mfi, -1);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_MPD, "Could not add mediainfo for path '%s'\n", fi->path);
|
||||
DPRINTF(E_LOG, L_MPD, "Could not add mediainfo for path '%s'\n", fi->virtual_path);
|
||||
}
|
||||
|
||||
free_mfi(mfi, 0);
|
||||
|
Loading…
Reference in New Issue
Block a user