From 58ecfd63807e45a78ea57d41674e72788beac7a3 Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Mon, 2 Nov 2009 19:21:38 +0000 Subject: [PATCH] * Implement and use new sql_get_int_field() function to simplify getting integers from the database. --- inotify.c | 50 +++++++++++-------------------- minidlna.c | 76 +++++++++++++++++++++--------------------------- scanner.c | 14 ++++----- sql.c | 60 ++++++++++++++++++++++++++++++++++++++ sql.h | 3 ++ tivo_commands.c | 35 ++++++++-------------- upnpglobalvars.h | 4 +-- upnpsoap.c | 50 ++++++++----------------------- 8 files changed, 144 insertions(+), 148 deletions(-) diff --git a/inotify.c b/inotify.c index 72fec04..8be0e80 100644 --- a/inotify.c +++ b/inotify.c @@ -124,19 +124,13 @@ int inotify_create_watches(int fd) { FILE * max_watches; - unsigned int num_watches = 0, watch_limit = 8192; + unsigned int num_watches, watch_limit = 8192; char **result; int i, rows = 0; struct media_dir_s * media_path; - if( sql_get_table(db, "SELECT count(*) from DETAILS where SIZE is NULL and PATH is not NULL", &result, &rows, NULL) == SQLITE_OK ) - { - if( rows ) - { - num_watches = strtoul(result[1], NULL, 10); - } - sqlite3_free_table(result); - } + i = sql_get_int_field(db, "SELECT count(*) from DETAILS where SIZE is NULL and PATH is not NULL"); + num_watches = (i < 0) ? 0 : i; max_watches = fopen("/proc/sys/fs/inotify/max_user_watches", "r"); if( max_watches ) @@ -499,7 +493,6 @@ inotify_remove_file(const char * path) { char * sql; char **result; - char **result2; char * art_cache; sqlite_int64 detailID = 0; int i, rows, children, ret = 1; @@ -525,13 +518,21 @@ inotify_remove_file(const char * path) { for( i=1; i < rows; i++ ) { - free(sql); - asprintf(&sql, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", result[i]); - if( sql_get_table(db, sql, &result2, NULL, NULL) == SQLITE_OK ) + children = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", result[i]); + if( children < 0 ) + continue; + if( children < 2 ) { - children = atoi(result2[1]); - sqlite3_free_table(result2); - if( children < 2 ) + free(sql); + asprintf(&sql, "DELETE from DETAILS where ID =" + " (SELECT DETAIL_ID from OBJECTS where OBJECT_ID = '%s')", result[i]); + sql_exec(db, sql); + free(sql); + asprintf(&sql, "DELETE from OBJECTS where OBJECT_ID = '%s'", result[i]); + sql_exec(db, sql); + + *rindex(result[i], '$') = '\0'; + if( sql_get_int_field("SELECT count(*) from OBJECTS where PARENT_ID = '%s'", result[i]) == 0 ) { free(sql); asprintf(&sql, "DELETE from DETAILS where ID =" @@ -540,23 +541,6 @@ inotify_remove_file(const char * path) free(sql); asprintf(&sql, "DELETE from OBJECTS where OBJECT_ID = '%s'", result[i]); sql_exec(db, sql); - free(sql); - *rindex(result[i], '$') = '\0'; - asprintf(&sql, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", result[i]); - if( sql_get_table(db, sql, &result2, NULL, NULL) == SQLITE_OK ) - { - if( atoi(result2[1]) == 0 ) - { - free(sql); - asprintf(&sql, "DELETE from DETAILS where ID =" - " (SELECT DETAIL_ID from OBJECTS where OBJECT_ID = '%s')", result[i]); - sql_exec(db, sql); - free(sql); - asprintf(&sql, "DELETE from OBJECTS where OBJECT_ID = '%s'", result[i]); - sql_exec(db, sql); - } - sqlite3_free_table(result2); - } } } } diff --git a/minidlna.c b/minidlna.c index 8b361aa..7cbc182 100644 --- a/minidlna.c +++ b/minidlna.c @@ -694,55 +694,45 @@ main(int argc, char * * argv) } else { - char **result; - int rows; sqlite3_busy_timeout(db, 5000); - if( !new_db && (sql_get_table(db, "SELECT UPDATE_ID from SETTINGS", &result, &rows, 0) == SQLITE_OK) ) + if( !new_db ) { - if( rows ) - { - updateID = atoi(result[1]); - } - sqlite3_free_table(result); + updateID = sql_get_int_field(db, "SELECT UPDATE_ID from SETTINGS"); } - if( sql_get_table(db, "pragma user_version", &result, &rows, 0) == SQLITE_OK ) + if( sql_get_int_field(db, "pragma user_version") != DB_VERSION ) { - if( atoi(result[1]) != DB_VERSION ) + if( new_db ) { - if( new_db ) - { - DPRINTF(E_WARN, L_GENERAL, "Creating new database...\n"); - } - else - { - DPRINTF(E_WARN, L_GENERAL, "Database version mismatch; need to recreate...\n"); - } - sqlite3_close(db); - unlink(DB_PATH "/files.db"); - system("rm -rf " DB_PATH "/art_cache"); - sqlite3_open(DB_PATH "/files.db", &db); - sqlite3_busy_timeout(db, 5000); - if( CreateDatabase() != 0 ) - { - DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to create sqlite database! Exiting...\n"); - } -#if USE_FORK - scanning = 1; - sqlite3_close(db); - scanner_pid = fork(); - sqlite3_open(DB_PATH "/files.db", &db); - sqlite3_busy_timeout(db, 5000); - if( !scanner_pid ) // child (scanner) process - { - start_scanner(); - sqlite3_close(db); - exit(EXIT_SUCCESS); - } -#else - start_scanner(); -#endif + DPRINTF(E_WARN, L_GENERAL, "Creating new database...\n"); } - sqlite3_free_table(result); + else + { + DPRINTF(E_WARN, L_GENERAL, "Database version mismatch; need to recreate...\n"); + } + sqlite3_close(db); + unlink(DB_PATH "/files.db"); + system("rm -rf " DB_PATH "/art_cache"); + sqlite3_open(DB_PATH "/files.db", &db); + sqlite3_busy_timeout(db, 5000); + if( CreateDatabase() != 0 ) + { + DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to create sqlite database! Exiting...\n"); + } +#if USE_FORK + scanning = 1; + sqlite3_close(db); + scanner_pid = fork(); + sqlite3_open(DB_PATH "/files.db", &db); + sqlite3_busy_timeout(db, 5000); + if( !scanner_pid ) // child (scanner) process + { + start_scanner(); + sqlite3_close(db); + exit(EXIT_SUCCESS); + } +#else + start_scanner(); +#endif } if( sqlite3_threadsafe() && sqlite3_libversion_number() >= 3005001 && GETFLAG(INOTIFY_MASK) && pthread_create(&inotify_thread, NULL, start_inotify, NULL) ) diff --git a/scanner.c b/scanner.c index 88f92ee..5c1e0d4 100644 --- a/scanner.c +++ b/scanner.c @@ -429,16 +429,11 @@ insert_directory(const char * name, const char * path, const char * base, const { if( strcmp(id_buf, last_found) == 0 ) break; - sql = sqlite3_mprintf("SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", id_buf); - if( (sql_get_table(db, sql, &result, NULL, NULL) == SQLITE_OK) && atoi(result[1]) ) + if( sql_get_int_field(db, "SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", id_buf) > 0 ) { - sqlite3_free_table(result); - sqlite3_free(sql); strcpy(last_found, id_buf); break; } - sqlite3_free_table(result); - sqlite3_free(sql); /* Does not exist. Need to create, and may need to create parents also */ sql = sqlite3_mprintf("SELECT DETAIL_ID from OBJECTS where OBJECT_ID = '%s'", refID); if( (sql_get_table(db, sql, &result, &rows, NULL) == SQLITE_OK) && rows ) @@ -578,7 +573,7 @@ CreateDatabase(void) "1$14", "1", "Folders", "2", "0", "Video", "2$8", "2", "All Video", - "2$15", "2", "Folders", + VIDEO_DIR_ID, "2", "Folders", "3", "0", "Pictures", "3$11", "3", "All Pictures", "3$12", "3", "Date Taken", @@ -646,11 +641,12 @@ CreateDatabase(void) if( ret != SQLITE_OK ) goto sql_failed; ret = sql_exec(db, "CREATE TABLE SETTINGS (" - "UPDATE_ID INTEGER PRIMARY KEY DEFAULT 0" + "UPDATE_ID INTEGER PRIMARY KEY DEFAULT 0, " + "FLAGS INTEGER DEFAULT 0" ")"); if( ret != SQLITE_OK ) goto sql_failed; - ret = sql_exec(db, "INSERT into SETTINGS values (0)"); + ret = sql_exec(db, "INSERT into SETTINGS values (0, 0)"); if( ret != SQLITE_OK ) goto sql_failed; for( i=0; containers[i]; i=i+3 ) diff --git a/sql.c b/sql.c index 375f8cd..e15b86e 100644 --- a/sql.c +++ b/sql.c @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include #include "sql.h" #include "log.h" @@ -53,3 +54,62 @@ sql_get_table(sqlite3 *db, const char *sql, char ***pazResult, int *pnRow, int * return ret; } +int +sql_get_int_field(sqlite3 *db, const char *fmt, ...) +{ + va_list ap; + int counter, result; + char *sql; + int ret; + sqlite3_stmt *stmt; + + va_start(ap, fmt); + + sql = sqlite3_vmprintf(fmt, ap); + + //DPRINTF(E_DEBUG, L_DB_SQL, "sql: %s\n", sql); + + switch (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL)) + { + case SQLITE_OK: + break; + default: + DPRINTF(E_ERROR, L_DB_SQL, "prepare failed: %s\n", sqlite3_errmsg(db)); + sqlite3_free(sql); + return -1; + } + sqlite3_free(sql); + + for (counter = 0; + ((result = sqlite3_step(stmt)) == SQLITE_BUSY || result == SQLITE_LOCKED) && counter < 2; + counter++) { + /* While SQLITE_BUSY has a built in timeout, + SQLITE_LOCKED does not, so sleep */ + if (result == SQLITE_LOCKED) + sleep(1); + } + + switch (result) + { + case SQLITE_DONE: + /* no rows returned */ + ret = 0; + break; + case SQLITE_ROW: + if (sqlite3_column_type(stmt, 0) == SQLITE_NULL) + { + ret = 0; + break; + } + ret = sqlite3_column_int(stmt, 0); + break; + default: + DPRINTF(E_WARN, L_DB_SQL, "%s: step failed: %s\n", __func__, sqlite3_errmsg(db)); + ret = -1; + break; + } + + sqlite3_finalize(stmt); + return ret; +} + diff --git a/sql.h b/sql.h index a69e49a..e067eb7 100644 --- a/sql.h +++ b/sql.h @@ -18,4 +18,7 @@ sql_exec(sqlite3 * db, const char * sql); int sql_get_table(sqlite3 *db, const char *zSql, char ***pazResult, int *pnRow, int *pnColumn); +int +sql_get_int_field(sqlite3 *db, const char *fmt, ...); + #endif diff --git a/tivo_commands.c b/tivo_commands.c index 0eb9cc1..d53e70b 100644 --- a/tivo_commands.c +++ b/tivo_commands.c @@ -111,9 +111,7 @@ int callback(void *args, int argc, char **argv, char **azColName) *bitrate = argv[6], *sampleFrequency = argv[7], *artist = argv[8], *album = argv[9], *genre = argv[10], *comment = argv[11], *date = argv[12], *resolution = argv[13], *mime = argv[14], *path = argv[15]; char str_buf[4096]; - char **result; - int flags = 0; - int ret = 0; + int ret = 0, flags = 0, count; if( strncmp(class, "item", 4) == 0 ) { @@ -256,19 +254,18 @@ int callback(void *args, int argc, char **argv, char **azColName) { /* Determine the number of children */ #ifdef __sparc__ /* Adding filters on large containers can take a long time on slow processors */ - sprintf(str_buf, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", id); + count = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", id); #else - sprintf(str_buf, "SELECT count(*) from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID) where PARENT_ID = '%s' and " - " (MIME in ('image/jpeg', 'audio/mpeg', 'video/mpeg', 'video/x-tivo-mpeg')" - " or CLASS glob 'container*')", id); + count = sql_get_int_field(db, "SELECT count(*) from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID) where PARENT_ID = '%s' and " + " (MIME in ('image/jpeg', 'audio/mpeg', 'video/mpeg', 'video/x-tivo-mpeg')" + " or CLASS glob 'container*')", id); #endif - ret = sql_get_table(db, str_buf, &result, NULL, NULL); ret = sprintf(str_buf, "" "
" "x-container/folder" "x-container/folder" "%s" - "%s" + "%d" "
" "" "" @@ -276,8 +273,7 @@ int callback(void *args, int argc, char **argv, char **azColName) "x-tivo-container/folder" "" "", - unescape_tag(title), result[1], id); - sqlite3_free_table(result); + unescape_tag(title), count, id); } memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); passed_args->size += ret; @@ -568,18 +564,11 @@ SendContainer(struct upnphttp * h, const char * objectID, int itemStart, int ite args.start = itemStart+anchorOffset; sqlite3Prng.isInit = 0; - asprintf(&sql, "SELECT count(distinct DETAIL_ID) " - "from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)" - " where %s and (%s)", - which, myfilter); - DPRINTF(E_DEBUG, L_TIVO, "Count SQL: %s\n", sql); - ret = sql_get_table(db, sql, &result, NULL, NULL); - if( ret == SQLITE_OK ) - { - totalMatches = atoi(result[1]); - sqlite3_free_table(result); - } - free(sql); + ret = sql_get_int_field(db, "SELECT count(distinct DETAIL_ID) " + "from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)" + " where %s and (%s)", + which, myfilter); + totalMatches = (ret > 0) ? ret : 0; sql = sqlite3_mprintf("SELECT o.OBJECT_ID, o.CLASS, o.DETAIL_ID, d.SIZE, d.TITLE," " d.DURATION, d.BITRATE, d.SAMPLERATE, d.ARTIST, d.ALBUM," diff --git a/upnpglobalvars.h b/upnpglobalvars.h index aa70218..f65c5a0 100644 --- a/upnpglobalvars.h +++ b/upnpglobalvars.h @@ -21,11 +21,11 @@ #include -#define MINIDLNA_VERSION "1.0.16-pre7" +#define MINIDLNA_VERSION "1.0.16" #define CLIENT_CACHE_SLOTS 20 #define USE_FORK 1 -#define DB_VERSION 3 +#define DB_VERSION 4 #if 0 // Add these once the newer ffmpeg libs that can detect WMAPRO are more widely used "http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=01;DLNA.ORG_CI=0," diff --git a/upnpsoap.c b/upnpsoap.c index 60460e8..f9af030 100644 --- a/upnpsoap.c +++ b/upnpsoap.c @@ -30,6 +30,7 @@ #include "upnpreplyparse.h" #include "getifaddr.h" +#include "scanner.h" #include "utils.h" #include "sql.h" #include "log.h" @@ -532,7 +533,6 @@ callback(void *args, int argc, char **argv, char **azColName) char dlna_buf[96]; char ext[5]; char str_buf[512]; - char **result; int children, ret = 0; /* Make sure we have at least 4KB left of allocated memory to finish the response. */ @@ -777,15 +777,8 @@ callback(void *args, int argc, char **argv, char **azColName) passed_args->size += ret; if( passed_args->filter & FILTER_CHILDCOUNT ) { - sprintf(str_buf, "SELECT count(*) from OBJECTS where PARENT_ID = '%s';", id); - ret = sql_get_table(db, str_buf, &result, NULL, NULL); - if( ret == SQLITE_OK ) { - children = atoi(result[1]); - sqlite3_free_table(result); - } - else { - children = 0; - } + ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s';", id); + children = (ret > 0) ? ret : 0; ret = sprintf(str_buf, "childCount=\"%d\"", children); memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); passed_args->size += ret; @@ -860,10 +853,9 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) char str_buf[512]; char *zErrMsg = 0; char *sql, *ptr; - char **result; int ret; struct Response args; - int totalMatches = 0; + int totalMatches; struct NameValueParserData data; *resp = '\0'; @@ -924,7 +916,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) if( strcmp(ObjectId, "16") == 0 ) ObjectId = strdup("3$16"); else if( strcmp(ObjectId, "15") == 0 ) - ObjectId = strdup("2$15"); + ObjectId = strdup(VIDEO_DIR_ID); else ObjectId = strdup(ObjectId); } @@ -950,12 +942,8 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) } else { - sprintf(str_buf, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", ObjectId); - ret = sql_get_table(db, str_buf, &result, NULL, NULL); - if( ret == SQLITE_OK ) { - totalMatches = atoi(result[1]); - sqlite3_free_table(result); - } + ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", ObjectId); + totalMatches = (ret > 0) ? ret : 0; #ifdef __sparc__ /* Sorting takes too long on slow processors with very large containers */ ret = 0; if( totalMatches < 10000 ) @@ -984,15 +972,8 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) /* Does the object even exist? */ if( !totalMatches ) { - ret = 0; - sql = sqlite3_mprintf("SELECT count(*) from OBJECTS where OBJECT_ID = '%q'", ObjectId); - if( sql_get_table(db, sql, &result, NULL, NULL) == SQLITE_OK ) - { - ret = atoi(result[1]); - sqlite3_free_table(result); - } - sqlite3_free(sql); - if( !ret ) + ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", ObjectId); + if( ret <= 0 ) { SoapError(h, 701, "No such object error"); goto browse_error; @@ -1184,16 +1165,9 @@ SearchContentDirectory(struct upnphttp * h, const char * action) /* Does the object even exist? */ if( !totalMatches ) { - ret = 0; - sql = sqlite3_mprintf("SELECT count(*) from OBJECTS where OBJECT_ID = '%q'", - !strcmp(ContainerID, "*")?"0":ContainerID); - if( sql_get_table(db, sql, &result, NULL, NULL) == SQLITE_OK ) - { - ret = atoi(result[1]); - sqlite3_free_table(result); - } - sqlite3_free(sql); - if( !ret ) + ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where OBJECT_ID = '%q'", + !strcmp(ContainerID, "*")?"0":ContainerID); + if( ret <= 0 ) { SoapError(h, 710, "No such container"); goto search_error;