mirror of
https://github.com/owntone/owntone-server.git
synced 2025-02-26 12:59:19 -05:00
make sqlite3 thread-safer(?) by using a thread pool
This commit is contained in:
parent
d53e2f83e4
commit
8e9d759e05
@ -340,7 +340,8 @@ char *db_error_list[] = {
|
|||||||
"Invalid playlist id: %d",
|
"Invalid playlist id: %d",
|
||||||
"Invalid song id: %d",
|
"Invalid song id: %d",
|
||||||
"Parse error: %s",
|
"Parse error: %s",
|
||||||
"No backend database support for type: %s"
|
"No backend database support for type: %s",
|
||||||
|
"Could not initialize thread pool"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Globals */
|
/* Globals */
|
||||||
|
@ -207,7 +207,7 @@ extern void db_dispose_playlist(M3UFILE *pm3u);
|
|||||||
#define DB_E_INVALID_SONGID 0x07 /**< bad song id */
|
#define DB_E_INVALID_SONGID 0x07 /**< bad song id */
|
||||||
#define DB_E_PARSE 0x08 /**< could not parse result */
|
#define DB_E_PARSE 0x08 /**< could not parse result */
|
||||||
#define DB_E_BADPROVIDER 0x09 /**< requested db backend not there */
|
#define DB_E_BADPROVIDER 0x09 /**< requested db backend not there */
|
||||||
|
#define DB_E_PROC 0x0A /**< could not start threadpool */
|
||||||
/* describes the individual database handlers */
|
/* describes the individual database handlers */
|
||||||
typedef struct tag_dbinfo {
|
typedef struct tag_dbinfo {
|
||||||
char *handler_name;
|
char *handler_name;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* $Id$
|
* $Id$
|
||||||
* sqlite2-specific db implementation
|
* sqlite3-specific db implementation
|
||||||
*
|
*
|
||||||
* Copyright (C) 2005 Ron Pedde (ron@pedde.com)
|
* Copyright (C) 2005 Ron Pedde (ron@pedde.com)
|
||||||
*
|
*
|
||||||
@ -56,36 +56,171 @@
|
|||||||
# define FALSE 0
|
# define FALSE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DB_SQLITE3_JOB_DONE 0
|
||||||
|
#define DB_SQLITE3_JOB_NOP 1
|
||||||
|
#define DB_SQLITE3_JOB_OPEN 2
|
||||||
|
#define DB_SQLITE3_JOB_CLOSE 3
|
||||||
|
#define DB_SQLITE3_JOB_EXEC 4
|
||||||
|
#define DB_SQLITE3_JOB_CHANGES 5
|
||||||
|
#define DB_SQLITE3_JOB_EBEGIN 6
|
||||||
|
#define DB_SQLITE3_JOB_EFETCH 7
|
||||||
|
#define DB_SQLITE3_JOB_ESTEP 8
|
||||||
|
#define DB_SQLITE3_JOB_FINALIZE 9
|
||||||
|
#define DB_SQLITE3_JOB_ROWID 10
|
||||||
|
#define DB_SQLITE3_JOB_QUIT 99
|
||||||
|
|
||||||
|
|
||||||
/* Globals */
|
/* Globals */
|
||||||
static sqlite3 *db_sqlite3_songs; /**< Database that holds the mp3 info */
|
static pthread_mutex_t _db_sqlite3_mutex = PTHREAD_MUTEX_INITIALIZER; /**< sqlite not reentrant */
|
||||||
static pthread_mutex_t db_sqlite3_mutex = PTHREAD_MUTEX_INITIALIZER; /**< sqlite not reentrant */
|
static sqlite3_stmt *_db_sqlite3_stmt;
|
||||||
static sqlite3_stmt *db_sqlite3_stmt;
|
|
||||||
static int db_sqlite3_reload=0;
|
static int db_sqlite3_reload=0;
|
||||||
static char *db_sqlite3_enum_query=NULL;
|
static char *_db_sqlite3_enum_query=NULL;
|
||||||
static char **db_sqlite3_row = NULL;
|
static char **_db_sqlite3_row = NULL;
|
||||||
|
|
||||||
static char db_sqlite3_path[PATH_MAX + 1];
|
static char db_sqlite3_path[PATH_MAX + 1];
|
||||||
|
static pthread_t _db_sqlite3_tid;
|
||||||
|
static pthread_cond_t _db_sqlite3_start = PTHREAD_COND_INITIALIZER;
|
||||||
|
static pthread_cond_t _db_sqlite3_done = PTHREAD_COND_INITIALIZER;
|
||||||
|
static pthread_mutex_t _db_sqlite3_mutex_job = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
/* Job info */
|
||||||
|
static volatile int _db_sqlite3_job = DB_SQLITE3_JOB_DONE;
|
||||||
|
static sqlite3 *_db_sqlite3_songs; /**< Database that holds the mp3 info */
|
||||||
|
static int _db_sqlite3_err;
|
||||||
|
static char *_db_sqlite3_perr=NULL;
|
||||||
|
static char *_db_sqlite3_query;
|
||||||
|
|
||||||
#define DB_SQLITE3_VERSION 9
|
#define DB_SQLITE3_VERSION 9
|
||||||
|
|
||||||
|
|
||||||
/* Forwards */
|
/* Forwards */
|
||||||
void db_sqlite3_lock(void);
|
void _db_sqlite3_lock(void);
|
||||||
void db_sqlite3_unlock(void);
|
void _db_sqlite3_unlock(void);
|
||||||
extern char *db_sqlite3_initial1;
|
extern char *db_sqlite3_initial1;
|
||||||
extern char *db_sqlite3_initial2;
|
extern char *db_sqlite3_initial2;
|
||||||
int db_sqlite3_enum_begin_helper(char **pe);
|
int _db_sqlite3_enum_begin_helper(char **pe);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* throw a job at the worker thread.
|
||||||
|
*
|
||||||
|
* @param pe error buffer
|
||||||
|
* @param job job (DB_SQLITE3_JOB_*)
|
||||||
|
* @returns DB_E_SUCCESS on success, DB_E_* otherwise
|
||||||
|
*/
|
||||||
|
int _db_sqlite3_start_job(int job) {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
DPRINTF(E_SPAM,L_DB,"About to submit job (%d).. waiting for mutex\n",job);
|
||||||
|
if((err=pthread_mutex_lock(&_db_sqlite3_mutex_job))) {
|
||||||
|
DPRINTF(E_FATAL,L_DB,"cannot lock sqlite job lock: %s\n",strerror(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we'll assume that all the other stuff is set correctly */
|
||||||
|
_db_sqlite3_job = job;
|
||||||
|
|
||||||
|
pthread_cond_signal(&_db_sqlite3_start);
|
||||||
|
|
||||||
|
DPRINTF(E_SPAM,L_DB,"Submitting sqlite job type: %d\n",job);
|
||||||
|
/* now wait for the job to be done */
|
||||||
|
while(_db_sqlite3_job != DB_SQLITE3_JOB_DONE) {
|
||||||
|
pthread_cond_wait(&_db_sqlite3_done,&_db_sqlite3_mutex_job);
|
||||||
|
}
|
||||||
|
DPRINTF(E_SPAM,L_DB,"Job done: status %d, unlocking mutex\n",_db_sqlite3_err);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&_db_sqlite3_mutex_job);
|
||||||
|
return _db_sqlite3_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* worker thread main loop. since sqlite3 is picky about only
|
||||||
|
* using handles from the thread that opened, I'm going to make
|
||||||
|
* a single worker thread pool to handle all db stuff from one
|
||||||
|
* thread.
|
||||||
|
*/
|
||||||
|
void *_db_sqlite3_threadproc(void *arg) {
|
||||||
|
int err;
|
||||||
|
char *perr;
|
||||||
|
const char *ptail;
|
||||||
|
int cols;
|
||||||
|
int idx;
|
||||||
|
static int done=0;
|
||||||
|
|
||||||
|
/* we'll just sit on the "start" cond */
|
||||||
|
|
||||||
|
DPRINTF(E_INF,L_DB,"sqlite3 worker: starting\n");
|
||||||
|
if((err=pthread_mutex_lock(&_db_sqlite3_mutex_job))) {
|
||||||
|
DPRINTF(E_FATAL,L_DB,"cannot lock sqlite job lock: %s\n",strerror(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!done) {
|
||||||
|
while(_db_sqlite3_job == DB_SQLITE3_JOB_DONE) {
|
||||||
|
DPRINTF(E_SPAM,L_DB,"sqlite3 worker: about to cond_wait...\n");
|
||||||
|
pthread_cond_wait(&_db_sqlite3_start, &_db_sqlite3_mutex_job);
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF(E_SPAM,L_DB,"sqlite3 worker: Found job type %d\n",_db_sqlite3_job);
|
||||||
|
_db_sqlite3_err = SQLITE_OK;
|
||||||
|
|
||||||
|
/* case takes up too much horizontal space */
|
||||||
|
if(_db_sqlite3_job == DB_SQLITE3_JOB_OPEN) {
|
||||||
|
err=sqlite3_open(db_sqlite3_path,&_db_sqlite3_songs);
|
||||||
|
if(err == SQLITE_OK) {
|
||||||
|
sqlite3_busy_timeout(_db_sqlite3_songs,30000);
|
||||||
|
}
|
||||||
|
} else if(_db_sqlite3_job == DB_SQLITE3_JOB_CLOSE) {
|
||||||
|
err=sqlite3_close(_db_sqlite3_songs);
|
||||||
|
} else if(_db_sqlite3_job == DB_SQLITE3_JOB_EXEC) {
|
||||||
|
err = sqlite3_exec(_db_sqlite3_songs,_db_sqlite3_query,NULL,NULL,&perr);
|
||||||
|
} else if(_db_sqlite3_job == DB_SQLITE3_JOB_CHANGES) {
|
||||||
|
err = sqlite3_changes(_db_sqlite3_songs);
|
||||||
|
} else if(_db_sqlite3_job == DB_SQLITE3_JOB_EBEGIN) {
|
||||||
|
err=sqlite3_prepare(_db_sqlite3_songs,_db_sqlite3_enum_query,0,
|
||||||
|
&_db_sqlite3_stmt,&ptail);
|
||||||
|
} else if(_db_sqlite3_job == DB_SQLITE3_JOB_ESTEP) {
|
||||||
|
err=sqlite3_step(_db_sqlite3_stmt);
|
||||||
|
} else if(_db_sqlite3_job == DB_SQLITE3_JOB_EFETCH) {
|
||||||
|
cols = sqlite3_column_count(_db_sqlite3_stmt);
|
||||||
|
if(!_db_sqlite3_row) {
|
||||||
|
/* alloc space */
|
||||||
|
_db_sqlite3_row = (char**)malloc((sizeof(char*)) * cols);
|
||||||
|
if(!_db_sqlite3_row)
|
||||||
|
DPRINTF(E_FATAL,L_DB,"Malloc error\n");
|
||||||
|
}
|
||||||
|
for(idx=0; idx < cols; idx++) {
|
||||||
|
_db_sqlite3_row[idx] = (char*)sqlite3_column_text(_db_sqlite3_stmt,idx);
|
||||||
|
DPRINTF(E_SPAM,L_DB,"Fetched %s\n",_db_sqlite3_row[idx]);
|
||||||
|
}
|
||||||
|
err = SQLITE_OK;
|
||||||
|
} else if(_db_sqlite3_job == DB_SQLITE3_JOB_FINALIZE) {
|
||||||
|
err = sqlite3_finalize(_db_sqlite3_stmt);
|
||||||
|
} else if(_db_sqlite3_job == DB_SQLITE3_JOB_ROWID) {
|
||||||
|
err = (int)sqlite3_last_insert_rowid(_db_sqlite3_songs);
|
||||||
|
} else if(_db_sqlite3_job == DB_SQLITE3_JOB_QUIT) {
|
||||||
|
done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_db_sqlite3_err = err;
|
||||||
|
DPRINTF(E_SPAM,L_DB,"sqlite3 worker: finished job with %d\n",err);
|
||||||
|
|
||||||
|
/* hand it back to the client */
|
||||||
|
|
||||||
|
_db_sqlite3_job = DB_SQLITE3_JOB_DONE;
|
||||||
|
pthread_cond_signal(&_db_sqlite3_done);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&_db_sqlite3_mutex_job);
|
||||||
|
DPRINTF(E_INF,L_DB,"sqlite3 worker exiting\n");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lock the db_mutex
|
* lock the db_mutex
|
||||||
*/
|
*/
|
||||||
void db_sqlite3_lock(void) {
|
void _db_sqlite3_lock(void) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if((err=pthread_mutex_lock(&db_sqlite3_mutex))) {
|
if((err=pthread_mutex_lock(&_db_sqlite3_mutex))) {
|
||||||
DPRINTF(E_FATAL,L_DB,"cannot lock sqlite lock: %s\n",strerror(err));
|
DPRINTF(E_FATAL,L_DB,"cannot lock sqlite lock: %s\n",strerror(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,10 +228,10 @@ void db_sqlite3_lock(void) {
|
|||||||
/**
|
/**
|
||||||
* unlock the db_mutex
|
* unlock the db_mutex
|
||||||
*/
|
*/
|
||||||
void db_sqlite3_unlock(void) {
|
void _db_sqlite3_unlock(void) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if((err=pthread_mutex_unlock(&db_sqlite3_mutex))) {
|
if((err=pthread_mutex_unlock(&_db_sqlite3_mutex))) {
|
||||||
DPRINTF(E_FATAL,L_DB,"cannot unlock sqlite3 lock: %s\n",strerror(err));
|
DPRINTF(E_FATAL,L_DB,"cannot unlock sqlite3 lock: %s\n",strerror(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,20 +262,28 @@ void db_sqlite3_vmfree(char *query) {
|
|||||||
int db_sqlite3_open(char **pe, char *dsn) {
|
int db_sqlite3_open(char **pe, char *dsn) {
|
||||||
int ver;
|
int ver;
|
||||||
int err;
|
int err;
|
||||||
|
char *perr;
|
||||||
|
|
||||||
snprintf(db_sqlite3_path,sizeof(db_sqlite3_path),"%s/songs3.db",dsn);
|
snprintf(db_sqlite3_path,sizeof(db_sqlite3_path),"%s/songs3.db",dsn);
|
||||||
|
|
||||||
db_sqlite3_lock();
|
_db_sqlite3_lock();
|
||||||
if(sqlite3_open(db_sqlite3_path,&db_sqlite3_songs) != SQLITE_OK) {
|
|
||||||
db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_songs));
|
if((err=pthread_create(&_db_sqlite3_tid,NULL,
|
||||||
DPRINTF(E_LOG,L_DB,"db_sqlite3_open: %s (%s)\n",*pe,
|
_db_sqlite3_threadproc,NULL))) {
|
||||||
db_sqlite3_path);
|
DPRINTF(E_LOG,L_DB,"Could not spawn thread: %s\n",strerror(err));
|
||||||
db_sqlite3_unlock();
|
return DB_E_PROC;
|
||||||
return DB_E_SQL_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_busy_timeout(db_sqlite3_songs,30000); /* 30 seconds */
|
if(_db_sqlite3_start_job(DB_SQLITE3_JOB_OPEN) != SQLITE_OK) {
|
||||||
db_sqlite3_unlock();
|
perr = _db_sqlite3_perr;
|
||||||
|
db_get_error(pe,DB_E_SQL_ERROR,perr);
|
||||||
|
DPRINTF(E_LOG,L_DB,"db_sqlite3_open: %s (%s)\n",*pe,
|
||||||
|
db_sqlite3_path);
|
||||||
|
_db_sqlite3_unlock();
|
||||||
|
sqlite3_free(perr);
|
||||||
|
return DB_E_SQL_ERROR;
|
||||||
|
}
|
||||||
|
_db_sqlite3_unlock();
|
||||||
|
|
||||||
err = db_sql_fetch_int(pe,&ver,"select value from config where "
|
err = db_sql_fetch_int(pe,&ver,"select value from config where "
|
||||||
"term='version'");
|
"term='version'");
|
||||||
@ -163,9 +306,11 @@ int db_sqlite3_open(char **pe, char *dsn) {
|
|||||||
* close the database
|
* close the database
|
||||||
*/
|
*/
|
||||||
int db_sqlite3_close(void) {
|
int db_sqlite3_close(void) {
|
||||||
db_sqlite3_lock();
|
_db_sqlite3_lock();
|
||||||
sqlite3_close(db_sqlite3_songs);
|
_db_sqlite3_start_job(DB_SQLITE3_JOB_CLOSE);
|
||||||
db_sqlite3_unlock();
|
_db_sqlite3_start_job(DB_SQLITE3_JOB_QUIT);
|
||||||
|
pthread_join(_db_sqlite3_tid,NULL);
|
||||||
|
_db_sqlite3_unlock();
|
||||||
return DB_E_SUCCESS;
|
return DB_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,32 +326,33 @@ int db_sqlite3_close(void) {
|
|||||||
*/
|
*/
|
||||||
int db_sqlite3_exec(char **pe, int loglevel, char *fmt, ...) {
|
int db_sqlite3_exec(char **pe, int loglevel, char *fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char *query;
|
|
||||||
int err;
|
int err;
|
||||||
char *perr;
|
char *perr;
|
||||||
|
|
||||||
db_sqlite3_lock();
|
_db_sqlite3_lock();
|
||||||
|
|
||||||
va_start(ap,fmt);
|
va_start(ap,fmt);
|
||||||
query=sqlite3_vmprintf(fmt,ap);
|
_db_sqlite3_query=sqlite3_vmprintf(fmt,ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
DPRINTF(E_DBG,L_DB,"Executing: %s\n",query);
|
DPRINTF(E_DBG,L_DB,"Executing: %s\n",_db_sqlite3_query);
|
||||||
|
|
||||||
|
err=_db_sqlite3_start_job(DB_SQLITE3_JOB_EXEC);
|
||||||
|
perr = _db_sqlite3_perr;
|
||||||
|
|
||||||
err=sqlite3_exec(db_sqlite3_songs,query,NULL,NULL,&perr);
|
|
||||||
if(err != SQLITE_OK) {
|
if(err != SQLITE_OK) {
|
||||||
db_get_error(pe,DB_E_SQL_ERROR,perr);
|
db_get_error(pe,DB_E_SQL_ERROR,perr);
|
||||||
|
|
||||||
DPRINTF(loglevel == E_FATAL ? E_LOG : loglevel,L_DB,"Query: %s\n",
|
DPRINTF(loglevel == E_FATAL ? E_LOG : loglevel,L_DB,"Query: %s\n",
|
||||||
query);
|
_db_sqlite3_query);
|
||||||
DPRINTF(loglevel,L_DB,"Error: %s\n",perr);
|
DPRINTF(loglevel,L_DB,"Error: %s\n",perr);
|
||||||
sqlite3_free(perr);
|
sqlite3_free(perr);
|
||||||
} else {
|
} else {
|
||||||
DPRINTF(E_DBG,L_DB,"Rows: %d\n",sqlite3_changes(db_sqlite3_songs));
|
DPRINTF(E_DBG,L_DB,"Rows: %d\n",_db_sqlite3_start_job(DB_SQLITE3_JOB_CHANGES));
|
||||||
}
|
}
|
||||||
sqlite3_free(query);
|
sqlite3_free(_db_sqlite3_query);
|
||||||
|
|
||||||
db_sqlite3_unlock();
|
_db_sqlite3_unlock();
|
||||||
|
|
||||||
if(err != SQLITE_OK)
|
if(err != SQLITE_OK)
|
||||||
return DB_E_SQL_ERROR;
|
return DB_E_SQL_ERROR;
|
||||||
@ -219,38 +365,39 @@ int db_sqlite3_exec(char **pe, int loglevel, char *fmt, ...) {
|
|||||||
int db_sqlite3_enum_begin(char **pe, char *fmt, ...) {
|
int db_sqlite3_enum_begin(char **pe, char *fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
db_sqlite3_lock();
|
_db_sqlite3_lock();
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
db_sqlite3_enum_query = sqlite3_vmprintf(fmt,ap);
|
_db_sqlite3_enum_query = sqlite3_vmprintf(fmt,ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
return db_sqlite3_enum_begin_helper(pe);
|
DPRINTF(E_SPAM,L_DB,"Starting enum_begin: %s\n",_db_sqlite3_enum_query);
|
||||||
|
return _db_sqlite3_enum_begin_helper(pe);
|
||||||
}
|
}
|
||||||
|
|
||||||
int db_sqlite3_enum_begin_helper(char **pe) {
|
int _db_sqlite3_enum_begin_helper(char **pe) {
|
||||||
int err;
|
int err;
|
||||||
const char *ptail;
|
|
||||||
|
|
||||||
if(!db_sqlite3_enum_query)
|
if(!_db_sqlite3_enum_query)
|
||||||
*((int*)NULL) = 1;
|
*((int*)NULL) = 1;
|
||||||
|
|
||||||
|
|
||||||
DPRINTF(E_DBG,L_DB,"Executing: %s\n",db_sqlite3_enum_query);
|
DPRINTF(E_DBG,L_DB,"Executing: %s\n",_db_sqlite3_enum_query);
|
||||||
err=sqlite3_prepare(db_sqlite3_songs,db_sqlite3_enum_query,0,
|
err=_db_sqlite3_start_job(DB_SQLITE3_JOB_EBEGIN);
|
||||||
&db_sqlite3_stmt,&ptail);
|
|
||||||
|
|
||||||
if(err != SQLITE_OK) {
|
if(err != SQLITE_OK) {
|
||||||
db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_songs));
|
DPRINTF(E_SPAM,L_DB,"Error: %s, enum exiting\n",_db_sqlite3_perr);
|
||||||
db_sqlite3_unlock();
|
db_get_error(pe,DB_E_SQL_ERROR,_db_sqlite3_perr);
|
||||||
sqlite3_free(db_sqlite3_enum_query);
|
sqlite3_free(_db_sqlite3_perr);
|
||||||
db_sqlite3_enum_query=NULL;
|
sqlite3_free(_db_sqlite3_enum_query);
|
||||||
|
_db_sqlite3_enum_query = NULL;
|
||||||
|
_db_sqlite3_unlock();
|
||||||
return DB_E_SQL_ERROR;
|
return DB_E_SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* otherwise, we leave the db locked while we walk through the enums */
|
/* otherwise, we leave the db locked while we walk through the enums */
|
||||||
if(db_sqlite3_row)
|
if(_db_sqlite3_row)
|
||||||
free(db_sqlite3_row);
|
free(_db_sqlite3_row);
|
||||||
db_sqlite3_row=NULL;
|
_db_sqlite3_row=NULL;
|
||||||
|
|
||||||
return DB_E_SUCCESS;
|
return DB_E_SUCCESS;
|
||||||
|
|
||||||
@ -270,15 +417,15 @@ int db_sqlite3_enum_begin_helper(char **pe) {
|
|||||||
*/
|
*/
|
||||||
int db_sqlite3_enum_fetch(char **pe, SQL_ROW *pr) {
|
int db_sqlite3_enum_fetch(char **pe, SQL_ROW *pr) {
|
||||||
int err;
|
int err;
|
||||||
int cols;
|
|
||||||
int idx;
|
|
||||||
int counter=10;
|
int counter=10;
|
||||||
|
|
||||||
if(!db_sqlite3_enum_query)
|
DPRINTF(E_SPAM,L_DB,"Fetching row for %s\n",_db_sqlite3_enum_query);
|
||||||
|
|
||||||
|
if(!_db_sqlite3_enum_query)
|
||||||
*((int*)NULL) = 1;
|
*((int*)NULL) = 1;
|
||||||
|
|
||||||
while(counter--) {
|
while(counter--) {
|
||||||
err=sqlite3_step(db_sqlite3_stmt);
|
err=_db_sqlite3_start_job(DB_SQLITE3_JOB_ESTEP);
|
||||||
if(err != SQLITE_BUSY)
|
if(err != SQLITE_BUSY)
|
||||||
break;
|
break;
|
||||||
usleep(100);
|
usleep(100);
|
||||||
@ -286,36 +433,25 @@ int db_sqlite3_enum_fetch(char **pe, SQL_ROW *pr) {
|
|||||||
|
|
||||||
if(err == SQLITE_DONE) {
|
if(err == SQLITE_DONE) {
|
||||||
*pr = NULL;
|
*pr = NULL;
|
||||||
if(db_sqlite3_row)
|
if(_db_sqlite3_row)
|
||||||
free(db_sqlite3_row);
|
free(_db_sqlite3_row);
|
||||||
db_sqlite3_row = NULL;
|
_db_sqlite3_row = NULL;
|
||||||
return DB_E_SUCCESS;
|
return DB_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(err == SQLITE_ROW) {
|
if(err == SQLITE_ROW) {
|
||||||
cols = sqlite3_column_count(db_sqlite3_stmt);
|
err = _db_sqlite3_start_job(DB_SQLITE3_JOB_EFETCH);
|
||||||
|
*pr = _db_sqlite3_row;
|
||||||
if(!db_sqlite3_row) {
|
|
||||||
/* gotta alloc space */
|
|
||||||
db_sqlite3_row = (char**)malloc((sizeof(char*)) * cols);
|
|
||||||
if(!db_sqlite3_row)
|
|
||||||
DPRINTF(E_FATAL,L_DB,"Malloc error\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
for(idx=0; idx < cols; idx++) {
|
|
||||||
db_sqlite3_row[idx] = (char*) sqlite3_column_text(db_sqlite3_stmt,idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
*pr = db_sqlite3_row;
|
|
||||||
return DB_E_SUCCESS;
|
return DB_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(db_sqlite3_row)
|
if(_db_sqlite3_row)
|
||||||
free(db_sqlite3_row);
|
free(_db_sqlite3_row);
|
||||||
db_sqlite3_row = NULL;
|
_db_sqlite3_row = NULL;
|
||||||
|
|
||||||
db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_songs));
|
db_get_error(pe,DB_E_SQL_ERROR,_db_sqlite3_perr);
|
||||||
sqlite3_finalize(db_sqlite3_stmt);
|
sqlite3_free(_db_sqlite3_perr);
|
||||||
|
_db_sqlite3_start_job(DB_SQLITE3_JOB_FINALIZE);
|
||||||
|
|
||||||
return DB_E_SQL_ERROR;
|
return DB_E_SQL_ERROR;
|
||||||
}
|
}
|
||||||
@ -325,24 +461,30 @@ int db_sqlite3_enum_fetch(char **pe, SQL_ROW *pr) {
|
|||||||
*/
|
*/
|
||||||
int db_sqlite3_enum_end(char **pe) {
|
int db_sqlite3_enum_end(char **pe) {
|
||||||
int err;
|
int err;
|
||||||
|
char *perr;
|
||||||
|
|
||||||
if(!db_sqlite3_enum_query)
|
DPRINTF(E_SPAM,L_DB,"Finishing enum for %s\n",_db_sqlite3_enum_query);
|
||||||
|
|
||||||
|
if(!_db_sqlite3_enum_query)
|
||||||
*((int*)NULL) = 1;
|
*((int*)NULL) = 1;
|
||||||
|
|
||||||
if(db_sqlite3_row)
|
if(_db_sqlite3_row)
|
||||||
free(db_sqlite3_row);
|
free(_db_sqlite3_row);
|
||||||
db_sqlite3_row = NULL;
|
_db_sqlite3_row = NULL;
|
||||||
sqlite3_free(db_sqlite3_enum_query);
|
sqlite3_free(_db_sqlite3_enum_query);
|
||||||
db_sqlite3_enum_query = NULL;
|
_db_sqlite3_enum_query = NULL;
|
||||||
|
|
||||||
err = sqlite3_finalize(db_sqlite3_stmt);
|
err = _db_sqlite3_start_job(DB_SQLITE3_JOB_FINALIZE);
|
||||||
if(err != SQLITE_OK) {
|
if(err != SQLITE_OK) {
|
||||||
db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_songs));
|
perr = _db_sqlite3_perr;
|
||||||
db_sqlite3_unlock();
|
db_get_error(pe,DB_E_SQL_ERROR,perr);
|
||||||
|
DPRINTF(E_LOG,L_DB,"Error in enum_end: %s\n",perr);
|
||||||
|
sqlite3_free(perr);
|
||||||
|
_db_sqlite3_unlock();
|
||||||
return DB_E_SQL_ERROR;
|
return DB_E_SQL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
db_sqlite3_unlock();
|
_db_sqlite3_unlock();
|
||||||
return DB_E_SUCCESS;
|
return DB_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +492,7 @@ int db_sqlite3_enum_end(char **pe) {
|
|||||||
* restart the enumeration
|
* restart the enumeration
|
||||||
*/
|
*/
|
||||||
int db_sqlite3_enum_restart(char **pe) {
|
int db_sqlite3_enum_restart(char **pe) {
|
||||||
return db_sqlite3_enum_begin_helper(pe);
|
return _db_sqlite3_enum_begin_helper(pe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -445,9 +587,9 @@ int db_sqlite3_event(int event_type) {
|
|||||||
int db_sqlite3_insert_id(void) {
|
int db_sqlite3_insert_id(void) {
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
db_sqlite3_lock();
|
_db_sqlite3_lock();
|
||||||
result = (int)sqlite3_last_insert_rowid(db_sqlite3_songs);
|
result=_db_sqlite3_start_job(DB_SQLITE3_JOB_ROWID);
|
||||||
db_sqlite3_unlock();
|
_db_sqlite3_unlock();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
34
src/db-sql.c
34
src/db-sql.c
@ -144,7 +144,7 @@ int db_sql_fetch_row(char **pe, SQL_ROW *row, char *fmt, ...) {
|
|||||||
db_sql_vmfree_fn(query);
|
db_sql_vmfree_fn(query);
|
||||||
|
|
||||||
if(err != DB_E_SUCCESS) {
|
if(err != DB_E_SUCCESS) {
|
||||||
DPRINTF(E_SPAM,L_DB,"Error: enum_begin failed: %s\n",*pe);
|
DPRINTF(E_SPAM,L_DB,"Error: enum_begin failed: %s\n",(pe) ? *pe : "?");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,6 +881,8 @@ int db_sql_update_playlists(char **pe) {
|
|||||||
pinfo[index].plid=strdup(STR(row[0]));
|
pinfo[index].plid=strdup(STR(row[0]));
|
||||||
pinfo[index].type=strdup(STR(row[1]));
|
pinfo[index].type=strdup(STR(row[1]));
|
||||||
pinfo[index].clause=strdup(STR(row[2]));
|
pinfo[index].clause=strdup(STR(row[2]));
|
||||||
|
DPRINTF(E_SPAM,L_DB,"Found playlist %s: type %s, clause %s\n",pinfo[index].plid,
|
||||||
|
pinfo[index].type,pinfo[index].clause);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
db_sql_enum_end_fn(pe);
|
db_sql_enum_end_fn(pe);
|
||||||
@ -944,13 +946,13 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
|||||||
|
|
||||||
switch(pinfo->query_type) {
|
switch(pinfo->query_type) {
|
||||||
case queryTypeItems:
|
case queryTypeItems:
|
||||||
strcpy(query_select,"SELECT * FROM songs ");
|
strcpy(query_select,"select * from songs ");
|
||||||
strcpy(query_count,"SELECT COUNT(*) FROM songs ");
|
strcpy(query_count,"select count (*) from songs ");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case queryTypePlaylists:
|
case queryTypePlaylists:
|
||||||
strcpy(query_select,"SELECT * FROM playlists ");
|
strcpy(query_select,"select * from playlists ");
|
||||||
strcpy(query_count,"SELECT COUNT (*) FROM playlists ");
|
strcpy(query_count,"select count (*) from playlists ");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case queryTypePlaylistItems: /* Figure out if it's smart or dull */
|
case queryTypePlaylistItems: /* Figure out if it's smart or dull */
|
||||||
@ -985,12 +987,12 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
|||||||
return DB_E_PARSE;
|
return DB_E_PARSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(query_select,"SELECT * FROM songs ");
|
sprintf(query_select,"select * from songs ");
|
||||||
sprintf(query_count,"SELECT COUNT(id) FROM songs ");
|
sprintf(query_count,"select count(id) from songs ");
|
||||||
sprintf(query_rest,"WHERE (%s)",where_clause);
|
sprintf(query_rest,"where (%s)",where_clause);
|
||||||
free(where_clause);
|
free(where_clause);
|
||||||
} else {
|
} else {
|
||||||
sprintf(query_count,"SELECT COUNT(id) FROM songs ");
|
sprintf(query_count,"select count(id) from songs ");
|
||||||
|
|
||||||
/* We need to fix playlist queries to stop
|
/* We need to fix playlist queries to stop
|
||||||
* pulling the whole song db... the performance
|
* pulling the whole song db... the performance
|
||||||
@ -1048,9 +1050,9 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
|||||||
/* Apply the query/filter */
|
/* Apply the query/filter */
|
||||||
if(pinfo->whereclause) {
|
if(pinfo->whereclause) {
|
||||||
if(have_clause)
|
if(have_clause)
|
||||||
strcat(query_rest," AND ");
|
strcat(query_rest," and ");
|
||||||
else
|
else
|
||||||
strcpy(query_rest," WHERE ");
|
strcpy(query_rest," where ");
|
||||||
|
|
||||||
strcat(query_rest,"(");
|
strcat(query_rest,"(");
|
||||||
strcat(query_rest,pinfo->whereclause);
|
strcat(query_rest,pinfo->whereclause);
|
||||||
@ -1081,17 +1083,17 @@ int db_sql_enum_start(char **pe, DBQUERYINFO *pinfo) {
|
|||||||
/* Apply any index */
|
/* Apply any index */
|
||||||
switch(pinfo->index_type) {
|
switch(pinfo->index_type) {
|
||||||
case indexTypeFirst:
|
case indexTypeFirst:
|
||||||
sprintf(scratch," LIMIT %d",pinfo->index_high);
|
sprintf(scratch," limit %d",pinfo->index_high);
|
||||||
break;
|
break;
|
||||||
case indexTypeLast:
|
case indexTypeLast:
|
||||||
if(pinfo->index_low >= results) {
|
if(pinfo->index_low >= results) {
|
||||||
sprintf(scratch," LIMIT %d",pinfo->index_low); /* unnecessary */
|
sprintf(scratch," limit %d",pinfo->index_low); /* unnecessary */
|
||||||
} else {
|
} else {
|
||||||
sprintf(scratch," LIMIT %d OFFSET %d",pinfo->index_low, results-pinfo->index_low);
|
sprintf(scratch," limit %d offset %d",pinfo->index_low, results-pinfo->index_low);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case indexTypeSub:
|
case indexTypeSub:
|
||||||
sprintf(scratch," LIMIT %d OFFSET %d",pinfo->index_high - pinfo->index_low,
|
sprintf(scratch," limit %d offset %d",pinfo->index_high - pinfo->index_low,
|
||||||
pinfo->index_low);
|
pinfo->index_low);
|
||||||
break;
|
break;
|
||||||
case indexTypeNone:
|
case indexTypeNone:
|
||||||
@ -1745,7 +1747,7 @@ int db_sql_get_count(char **pe, int *count, CountType_t type) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
err=db_sql_fetch_int(pe,count,"SELECT COUNT(*) FROM '%q'", table);
|
err=db_sql_fetch_int(pe,count,"select count(*) FROM %q", table);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ int main(int argc, char *argv[]) {
|
|||||||
char txtrecord[255];
|
char txtrecord[255];
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
char *perr;
|
char *perr=NULL;
|
||||||
|
|
||||||
config.use_mdns=1;
|
config.use_mdns=1;
|
||||||
err_setlevel(1);
|
err_setlevel(1);
|
||||||
@ -393,8 +393,8 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
end_time=(int) time(NULL);
|
end_time=(int) time(NULL);
|
||||||
|
|
||||||
db_get_song_count(&perr,&song_count);
|
err=db_get_song_count(&perr,&song_count);
|
||||||
if(perr) {
|
if(err != DB_E_SUCCESS) {
|
||||||
DPRINTF(E_FATAL,L_MISC,"Error getting song count: %s\n",perr);
|
DPRINTF(E_FATAL,L_MISC,"Error getting song count: %s\n",perr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user