* Implement and use new sql_get_int_field() function to simplify getting integers from the database.

This commit is contained in:
Justin Maggard 2009-11-02 19:21:38 +00:00
parent 9712e90bdd
commit 58ecfd6380
8 changed files with 144 additions and 148 deletions

View File

@ -124,19 +124,13 @@ int
inotify_create_watches(int fd) inotify_create_watches(int fd)
{ {
FILE * max_watches; FILE * max_watches;
unsigned int num_watches = 0, watch_limit = 8192; unsigned int num_watches, watch_limit = 8192;
char **result; char **result;
int i, rows = 0; int i, rows = 0;
struct media_dir_s * media_path; 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 ) 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;
if( rows )
{
num_watches = strtoul(result[1], NULL, 10);
}
sqlite3_free_table(result);
}
max_watches = fopen("/proc/sys/fs/inotify/max_user_watches", "r"); max_watches = fopen("/proc/sys/fs/inotify/max_user_watches", "r");
if( max_watches ) if( max_watches )
@ -499,7 +493,6 @@ inotify_remove_file(const char * path)
{ {
char * sql; char * sql;
char **result; char **result;
char **result2;
char * art_cache; char * art_cache;
sqlite_int64 detailID = 0; sqlite_int64 detailID = 0;
int i, rows, children, ret = 1; int i, rows, children, ret = 1;
@ -525,13 +518,21 @@ inotify_remove_file(const char * path)
{ {
for( i=1; i < rows; i++ ) for( i=1; i < rows; i++ )
{ {
free(sql); children = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", result[i]);
asprintf(&sql, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", result[i]); if( children < 0 )
if( sql_get_table(db, sql, &result2, NULL, NULL) == SQLITE_OK ) continue;
if( children < 2 )
{ {
children = atoi(result2[1]); free(sql);
sqlite3_free_table(result2); asprintf(&sql, "DELETE from DETAILS where ID ="
if( children < 2 ) " (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); free(sql);
asprintf(&sql, "DELETE from DETAILS where ID =" asprintf(&sql, "DELETE from DETAILS where ID ="
@ -540,23 +541,6 @@ inotify_remove_file(const char * path)
free(sql); free(sql);
asprintf(&sql, "DELETE from OBJECTS where OBJECT_ID = '%s'", result[i]); asprintf(&sql, "DELETE from OBJECTS where OBJECT_ID = '%s'", result[i]);
sql_exec(db, sql); 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);
}
} }
} }
} }

View File

@ -694,55 +694,45 @@ main(int argc, char * * argv)
} }
else else
{ {
char **result;
int rows;
sqlite3_busy_timeout(db, 5000); 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 = sql_get_int_field(db, "SELECT UPDATE_ID from SETTINGS");
{
updateID = atoi(result[1]);
}
sqlite3_free_table(result);
} }
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");
{
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
} }
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 && if( sqlite3_threadsafe() && sqlite3_libversion_number() >= 3005001 &&
GETFLAG(INOTIFY_MASK) && pthread_create(&inotify_thread, NULL, start_inotify, NULL) ) GETFLAG(INOTIFY_MASK) && pthread_create(&inotify_thread, NULL, start_inotify, NULL) )

View File

@ -429,16 +429,11 @@ insert_directory(const char * name, const char * path, const char * base, const
{ {
if( strcmp(id_buf, last_found) == 0 ) if( strcmp(id_buf, last_found) == 0 )
break; break;
sql = sqlite3_mprintf("SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", id_buf); if( sql_get_int_field(db, "SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", id_buf) > 0 )
if( (sql_get_table(db, sql, &result, NULL, NULL) == SQLITE_OK) && atoi(result[1]) )
{ {
sqlite3_free_table(result);
sqlite3_free(sql);
strcpy(last_found, id_buf); strcpy(last_found, id_buf);
break; break;
} }
sqlite3_free_table(result);
sqlite3_free(sql);
/* Does not exist. Need to create, and may need to create parents also */ /* 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); 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 ) if( (sql_get_table(db, sql, &result, &rows, NULL) == SQLITE_OK) && rows )
@ -578,7 +573,7 @@ CreateDatabase(void)
"1$14", "1", "Folders", "1$14", "1", "Folders",
"2", "0", "Video", "2", "0", "Video",
"2$8", "2", "All Video", "2$8", "2", "All Video",
"2$15", "2", "Folders", VIDEO_DIR_ID, "2", "Folders",
"3", "0", "Pictures", "3", "0", "Pictures",
"3$11", "3", "All Pictures", "3$11", "3", "All Pictures",
"3$12", "3", "Date Taken", "3$12", "3", "Date Taken",
@ -646,11 +641,12 @@ CreateDatabase(void)
if( ret != SQLITE_OK ) if( ret != SQLITE_OK )
goto sql_failed; goto sql_failed;
ret = sql_exec(db, "CREATE TABLE SETTINGS (" 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 ) if( ret != SQLITE_OK )
goto sql_failed; 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 ) if( ret != SQLITE_OK )
goto sql_failed; goto sql_failed;
for( i=0; containers[i]; i=i+3 ) for( i=0; containers[i]; i=i+3 )

60
sql.c
View File

@ -16,6 +16,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include "sql.h" #include "sql.h"
#include "log.h" #include "log.h"
@ -53,3 +54,62 @@ sql_get_table(sqlite3 *db, const char *sql, char ***pazResult, int *pnRow, int *
return ret; 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;
}

3
sql.h
View File

@ -18,4 +18,7 @@ sql_exec(sqlite3 * db, const char * sql);
int int
sql_get_table(sqlite3 *db, const char *zSql, char ***pazResult, int *pnRow, int *pnColumn); 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 #endif

View File

@ -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], *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]; *comment = argv[11], *date = argv[12], *resolution = argv[13], *mime = argv[14], *path = argv[15];
char str_buf[4096]; char str_buf[4096];
char **result; int ret = 0, flags = 0, count;
int flags = 0;
int ret = 0;
if( strncmp(class, "item", 4) == 0 ) 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 */ /* Determine the number of children */
#ifdef __sparc__ /* Adding filters on large containers can take a long time on slow processors */ #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 #else
sprintf(str_buf, "SELECT count(*) from OBJECTS o left join DETAILS d on (d.ID = o.DETAIL_ID) where PARENT_ID = '%s' and " 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')" " (MIME in ('image/jpeg', 'audio/mpeg', 'video/mpeg', 'video/x-tivo-mpeg')"
" or CLASS glob 'container*')", id); " or CLASS glob 'container*')", id);
#endif #endif
ret = sql_get_table(db, str_buf, &result, NULL, NULL);
ret = sprintf(str_buf, "<Item>" ret = sprintf(str_buf, "<Item>"
"<Details>" "<Details>"
"<ContentType>x-container/folder</ContentType>" "<ContentType>x-container/folder</ContentType>"
"<SourceFormat>x-container/folder</SourceFormat>" "<SourceFormat>x-container/folder</SourceFormat>"
"<Title>%s</Title>" "<Title>%s</Title>"
"<TotalItems>%s</TotalItems>" "<TotalItems>%d</TotalItems>"
"</Details>" "</Details>"
"<Links>" "<Links>"
"<Content>" "<Content>"
@ -276,8 +273,7 @@ int callback(void *args, int argc, char **argv, char **azColName)
"<ContentType>x-tivo-container/folder</ContentType>" "<ContentType>x-tivo-container/folder</ContentType>"
"</Content>" "</Content>"
"</Links>", "</Links>",
unescape_tag(title), result[1], id); unescape_tag(title), count, id);
sqlite3_free_table(result);
} }
memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
passed_args->size += ret; passed_args->size += ret;
@ -568,18 +564,11 @@ SendContainer(struct upnphttp * h, const char * objectID, int itemStart, int ite
args.start = itemStart+anchorOffset; args.start = itemStart+anchorOffset;
sqlite3Prng.isInit = 0; sqlite3Prng.isInit = 0;
asprintf(&sql, "SELECT count(distinct DETAIL_ID) " ret = sql_get_int_field(db, "SELECT count(distinct DETAIL_ID) "
"from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)" "from OBJECTS o left join DETAILS d on (o.DETAIL_ID = d.ID)"
" where %s and (%s)", " where %s and (%s)",
which, myfilter); which, myfilter);
DPRINTF(E_DEBUG, L_TIVO, "Count SQL: %s\n", sql); totalMatches = (ret > 0) ? ret : 0;
ret = sql_get_table(db, sql, &result, NULL, NULL);
if( ret == SQLITE_OK )
{
totalMatches = atoi(result[1]);
sqlite3_free_table(result);
}
free(sql);
sql = sqlite3_mprintf("SELECT o.OBJECT_ID, o.CLASS, o.DETAIL_ID, d.SIZE, d.TITLE," 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," " d.DURATION, d.BITRATE, d.SAMPLERATE, d.ARTIST, d.ALBUM,"

View File

@ -21,11 +21,11 @@
#include <sqlite3.h> #include <sqlite3.h>
#define MINIDLNA_VERSION "1.0.16-pre7" #define MINIDLNA_VERSION "1.0.16"
#define CLIENT_CACHE_SLOTS 20 #define CLIENT_CACHE_SLOTS 20
#define USE_FORK 1 #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 #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," "http-get:*:video/x-ms-wmv:DLNA.ORG_PN=WMVHIGH_PRO;DLNA.ORG_OP=01;DLNA.ORG_CI=0,"

View File

@ -30,6 +30,7 @@
#include "upnpreplyparse.h" #include "upnpreplyparse.h"
#include "getifaddr.h" #include "getifaddr.h"
#include "scanner.h"
#include "utils.h" #include "utils.h"
#include "sql.h" #include "sql.h"
#include "log.h" #include "log.h"
@ -532,7 +533,6 @@ callback(void *args, int argc, char **argv, char **azColName)
char dlna_buf[96]; char dlna_buf[96];
char ext[5]; char ext[5];
char str_buf[512]; char str_buf[512];
char **result;
int children, ret = 0; int children, ret = 0;
/* Make sure we have at least 4KB left of allocated memory to finish the response. */ /* 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; passed_args->size += ret;
if( passed_args->filter & FILTER_CHILDCOUNT ) if( passed_args->filter & FILTER_CHILDCOUNT )
{ {
sprintf(str_buf, "SELECT count(*) from OBJECTS where PARENT_ID = '%s';", id); ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s';", id);
ret = sql_get_table(db, str_buf, &result, NULL, NULL); children = (ret > 0) ? ret : 0;
if( ret == SQLITE_OK ) {
children = atoi(result[1]);
sqlite3_free_table(result);
}
else {
children = 0;
}
ret = sprintf(str_buf, "childCount=\"%d\"", children); ret = sprintf(str_buf, "childCount=\"%d\"", children);
memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1); memcpy(passed_args->resp+passed_args->size, &str_buf, ret+1);
passed_args->size += ret; passed_args->size += ret;
@ -860,10 +853,9 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
char str_buf[512]; char str_buf[512];
char *zErrMsg = 0; char *zErrMsg = 0;
char *sql, *ptr; char *sql, *ptr;
char **result;
int ret; int ret;
struct Response args; struct Response args;
int totalMatches = 0; int totalMatches;
struct NameValueParserData data; struct NameValueParserData data;
*resp = '\0'; *resp = '\0';
@ -924,7 +916,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
if( strcmp(ObjectId, "16") == 0 ) if( strcmp(ObjectId, "16") == 0 )
ObjectId = strdup("3$16"); ObjectId = strdup("3$16");
else if( strcmp(ObjectId, "15") == 0 ) else if( strcmp(ObjectId, "15") == 0 )
ObjectId = strdup("2$15"); ObjectId = strdup(VIDEO_DIR_ID);
else else
ObjectId = strdup(ObjectId); ObjectId = strdup(ObjectId);
} }
@ -950,12 +942,8 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
} }
else else
{ {
sprintf(str_buf, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", ObjectId); ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", ObjectId);
ret = sql_get_table(db, str_buf, &result, NULL, NULL); totalMatches = (ret > 0) ? ret : 0;
if( ret == SQLITE_OK ) {
totalMatches = atoi(result[1]);
sqlite3_free_table(result);
}
#ifdef __sparc__ /* Sorting takes too long on slow processors with very large containers */ #ifdef __sparc__ /* Sorting takes too long on slow processors with very large containers */
ret = 0; ret = 0;
if( totalMatches < 10000 ) if( totalMatches < 10000 )
@ -984,15 +972,8 @@ BrowseContentDirectory(struct upnphttp * h, const char * action)
/* Does the object even exist? */ /* Does the object even exist? */
if( !totalMatches ) if( !totalMatches )
{ {
ret = 0; ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where OBJECT_ID = '%s'", ObjectId);
sql = sqlite3_mprintf("SELECT count(*) from OBJECTS where OBJECT_ID = '%q'", ObjectId); if( ret <= 0 )
if( sql_get_table(db, sql, &result, NULL, NULL) == SQLITE_OK )
{
ret = atoi(result[1]);
sqlite3_free_table(result);
}
sqlite3_free(sql);
if( !ret )
{ {
SoapError(h, 701, "No such object error"); SoapError(h, 701, "No such object error");
goto browse_error; goto browse_error;
@ -1184,16 +1165,9 @@ SearchContentDirectory(struct upnphttp * h, const char * action)
/* Does the object even exist? */ /* Does the object even exist? */
if( !totalMatches ) if( !totalMatches )
{ {
ret = 0; ret = sql_get_int_field(db, "SELECT count(*) from OBJECTS where OBJECT_ID = '%q'",
sql = sqlite3_mprintf("SELECT count(*) from OBJECTS where OBJECT_ID = '%q'", !strcmp(ContainerID, "*")?"0":ContainerID);
!strcmp(ContainerID, "*")?"0":ContainerID); if( ret <= 0 )
if( sql_get_table(db, sql, &result, NULL, NULL) == SQLITE_OK )
{
ret = atoi(result[1]);
sqlite3_free_table(result);
}
sqlite3_free(sql);
if( !ret )
{ {
SoapError(h, 710, "No such container"); SoapError(h, 710, "No such container");
goto search_error; goto search_error;