From aa2dad48bddccc0d30c1d9010aaa4c846cdc9591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Mon, 18 Jul 2011 23:36:54 +0200 Subject: [PATCH] metadb: Add support for schema upgrades --- Makefile | 2 + {metadb => resources/metadb}/001.sql | 42 +----- src/main.c | 3 + src/metadata.c | 194 +++++++++++++++++++++++---- src/metadata.h | 2 + 5 files changed, 179 insertions(+), 64 deletions(-) rename {metadb => resources/metadb}/001.sql (72%) diff --git a/Makefile b/Makefile index 2984d1aba8..b07f6d9a3e 100644 --- a/Makefile +++ b/Makefile @@ -74,6 +74,8 @@ endif SRCS-${CONFIG_EMU_THREAD_SPECIFICS} += src/arch/emu_thread_specifics.c +BUNDLES += resources/metadb + # # Misc support # diff --git a/metadb/001.sql b/resources/metadb/001.sql similarity index 72% rename from metadb/001.sql rename to resources/metadb/001.sql index 007665b2d1..f0b638bc37 100644 --- a/metadb/001.sql +++ b/resources/metadb/001.sql @@ -1,18 +1,3 @@ - -PRAGMA foreign_keys = ON; - -BEGIN; - -DROP TABLE itemtype; -DROP TABLE item; -DROP TABLE stream; -DROP TABLE audioitem; -DROP TABLE videoitem; -DROP TABLE artist; -DROP TABLE album; - -DROP INDEX item_url_idx; - CREATE TABLE itemtype ( id INTEGER PRIMARY KEY, name TEXT NOT NULL @@ -83,30 +68,5 @@ CREATE TABLE stream ( codec TEXT, mediatype TEXT ); -CREATE INDEX stream_item_id_idx ON stream(item_id); - - -COMMIT; - - - - -INSERT INTO item (url) values ('foo'); - -BEGIN; -INSERT OR IGNORE INTO item(url, contenttype, playcount) VALUES('bar3', 5,1); -UPDATE item SET playcount = playcount + (1 - changes()) WHERE url = 'bar3'; -COMMIT; - - -INSERT INTO item(url, contenttype) VALUES('video', 5); -INSERT INTO item(url, contenttype) VALUES('audio', 4); - -INSERT INTO videoitem values (1, 1337); - -INSERT INTO audioitem values (2, 1, 1); - -insert into album (title) values ('dark side of the moon'); -insert into artist (title) values ('pink floyd'); - +CREATE INDEX stream_item_id_idx ON stream(item_id); diff --git a/src/main.c b/src/main.c index 1143d6076b..077ac0a59a 100644 --- a/src/main.c +++ b/src/main.c @@ -352,6 +352,9 @@ main(int argc, char **argv) /* Initialize htsmsg_store() */ htsmsg_store_init(); + /* Metadata init */ + metadb_init(); + /* Initialize keyring */ keyring_init(); diff --git a/src/metadata.c b/src/metadata.c index 3d4842ffd7..bc53207007 100644 --- a/src/metadata.c +++ b/src/metadata.c @@ -9,6 +9,10 @@ #include "api/lastfm.h" #include "metadata.h" +#include "fileaccess/fileaccess.h" + +// If not set to true by metadb_init() no metadb actions will occur +static int metadb_valid; /** * @@ -213,10 +217,167 @@ one_statement(sqlite3 *db, const char *sql) } +/** + * + */ +static int +db_get_int_from_query(sqlite3 *db, const char *query, int *v) +{ + int rc; + int64_t rval = -1; + sqlite3_stmt *stmt; + + rc = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if(rc) + return -1; + + rc = sqlite3_step(stmt); + + if(rc == SQLITE_ROW) { + *v = sqlite3_column_int(stmt, 0); + rval = 0; + } else { + rval = -1; + } + + sqlite3_finalize(stmt); + return rval; +} + + + +static int +begin(sqlite3 *db) +{ + return one_statement(db, "BEGIN;"); +} + + +static int +commit(sqlite3 *db) +{ + return one_statement(db, "COMMIT;"); +} + +static int +rollback(sqlite3 *db) +{ + return one_statement(db, "ROLLBACK;"); +} +#define METADB_SCHEMA_DIR "bundle://resources/metadb" +/** + * + */ +static void +metadb_upgrade(sqlite3 *db) +{ + int ver, tgtver = 0; + char path[256]; + char buf[256]; + if(db_get_int_from_query(db, "pragma user_version", &ver)) { + TRACE(TRACE_ERROR, "METADB", "Unable to query db version"); + return; + } + + fa_dir_t *fd; + fa_dir_entry_t *fde; + + fd = fa_scandir(METADB_SCHEMA_DIR, buf, sizeof(buf)); + + if(fd == NULL) { + TRACE(TRACE_ERROR, "METADB", + "Unable to scan schema dir %s -- %s", METADB_SCHEMA_DIR , buf); + return; + } + + TAILQ_FOREACH(fde, &fd->fd_entries, fde_link) { + if(fde->fde_type != CONTENT_FILE || strchr(fde->fde_filename, '~')) + continue; + tgtver = MAX(tgtver, atoi(fde->fde_filename)); + } + + fa_dir_free(fd); + + while(1) { + + if(ver == tgtver) { + TRACE(TRACE_DEBUG, "METADB", "At current version %d", ver); + metadb_valid = 1; + return; + } + + ver++; + snprintf(path, sizeof(path), METADB_SCHEMA_DIR"/%03d.sql", ver); + + struct fa_stat fs; + char *sql = fa_quickload(path, &fs, NULL, buf, sizeof(buf)); + if(sql == NULL) { + TRACE(TRACE_ERROR, "METADB", + "Unable to upgrade db schema to version %d using %s -- %s", + ver, path, buf); + return; + } + + begin(db); + snprintf(buf, sizeof(buf), "PRAGMA user_version=%d", ver); + if(one_statement(db, buf)) { + free(sql); + break; + } + + const char *s = sql; + + while(strchr(s, ';') != NULL) { + sqlite3_stmt *stmt; + + int rc = sqlite3_prepare_v2(db, s, -1, &stmt, &s); + if(rc != SQLITE_OK) { + TRACE(TRACE_ERROR, "METADB", + "Unable to prepare statement in upgrade %d\n%s", ver, s); + goto fail; + } + + rc = sqlite3_step(stmt); + if(rc != SQLITE_DONE) { + TRACE(TRACE_ERROR, "METADB", + "Unable to execute statement error %d\n%s", rc, + sqlite3_sql(stmt)); + goto fail; + } + sqlite3_finalize(stmt); + } + + commit(db); + TRACE(TRACE_INFO, "METADB", "Upgraded to version %d", ver); + free(sql); + } + fail: + rollback(db); +} + + +/** + * + */ +void +metadb_init(void) +{ + sqlite3 *db; + + db = metadb_get(); + metadb_upgrade(db); + metadb_close(db); +} + + + +/** + * + */ void * metadb_get(void) { @@ -236,8 +397,6 @@ metadb_get(void) return NULL; } - sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_FKEY, 1, NULL); - rc = sqlite3_exec(db, "PRAGMA synchronous = normal;", NULL, NULL, &errmsg); if(rc) { TRACE(TRACE_ERROR, @@ -267,6 +426,9 @@ metadb_playcount_incr(void *db, const char *url) int rc; sqlite3_stmt *stmt; + if(!metadb_valid) + return; + rc = sqlite3_prepare_v2(db, "UPDATE item SET playcount=playcount+1 WHERE URL=?1;", -1, &stmt, NULL); @@ -283,26 +445,6 @@ metadb_playcount_incr(void *db, const char *url) -static int -begin(sqlite3 *db) -{ - return one_statement(db, "BEGIN;"); -} - - -static int -commit(sqlite3 *db) -{ - return one_statement(db, "COMMIT;"); -} - - -static int -rollback(sqlite3 *db) -{ - return one_statement(db, "ROLLBACK;"); -} - /** * @@ -682,6 +824,9 @@ metadb_metadata_write(void *db, const char *url, time_t mtime, int rc; sqlite3_stmt *stmt; + if(!metadb_valid) + return; + if(begin(db)) return; @@ -866,7 +1011,7 @@ metadb_metadata_get_streams(sqlite3 *db, metadata_t *md, int64_t item_id) /** - * Perhaps this should be merged into one SELECT + * */ metadata_t * metadb_metadata_get(void *db, const char *url, time_t mtime) @@ -874,6 +1019,9 @@ metadb_metadata_get(void *db, const char *url, time_t mtime) int rc; sqlite3_stmt *sel; + if(!metadb_valid) + return NULL; + if(begin(db)) return NULL; diff --git a/src/metadata.h b/src/metadata.h index bc66d90d23..e8a6fd3af7 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -98,6 +98,8 @@ void metadata_to_proptree(const metadata_t *md, struct prop *proproot, +void metadb_init(void); + void *metadb_get(void); void metadb_close(void *db);