From 43c234e6662ad0e562738e3517b139c9e38b4370 Mon Sep 17 00:00:00 2001 From: Ron Pedde Date: Sat, 13 Oct 2007 22:03:52 +0000 Subject: [PATCH] Add per-thread db handles to guard against SQLITE_MISUSE --- src/db-sql-sqlite2.c | 54 ++++++++++++++++++++++++++++++--------- src/db-sql-sqlite3.c | 60 ++++++++++++++++++++++++++++++++------------ src/plugins/rsp.c | 2 +- 3 files changed, 87 insertions(+), 29 deletions(-) diff --git a/src/db-sql-sqlite2.c b/src/db-sql-sqlite2.c index ad6419a8..a34f9965 100644 --- a/src/db-sql-sqlite2.c +++ b/src/db-sql-sqlite2.c @@ -62,11 +62,11 @@ /* Globals */ -static sqlite *db_sqlite2_songs; /**< Database that holds the mp3 info */ static pthread_mutex_t db_sqlite2_mutex = PTHREAD_MUTEX_INITIALIZER; /**< sqlite not reentrant */ static sqlite_vm *db_sqlite2_pvm; static int db_sqlite2_reload=0; static char *db_sqlite2_enum_query; +static pthread_key_t db_sqlite2_key; static char db_sqlite2_path[PATH_MAX + 1]; @@ -80,6 +80,38 @@ extern char *db_sqlite2_initial1; extern char *db_sqlite2_initial2; int db_sqlite2_enum_begin_helper(char **pe); +/** + * get (or create) the db handle + */ +sqlite *db_sqlite2_handle(void) { + sqlite *pdb = NULL; + char *perr; + char *pe = NULL; + + pdb = (sqlite *)pthread_getspecific(db_sqlite2_key); + if(pdb == NULL) { /* don't have a handle yet */ + if((pdb = sqlite_open(db_sqlite2_path,0666,&perr)) == NULL) { + db_get_error(&pe,DB_E_SQL_ERROR,perr); + DPRINTF(E_FATAL,L_DB,"db_sqlite2_open: %s (%s)\n",perr, + db_sqlite2_path); + sqlite_freemem(perr); + db_sqlite2_unlock(); + return NULL; + } + sqlite_busy_timeout(pdb,30000); /* 30 seconds */ + pthread_setspecific(db_sqlite2_key,(void*)pdb); + } + + return pdb; +} + +/** + * free a thread-specific db handle + */ +void db_sqlite2_freedb(sqlite *pdb) { + sqlite_close(pdb); +} + /** * lock the db_mutex */ @@ -130,15 +162,17 @@ void db_sqlite2_vmfree(char *query) { * @returns DB_E_SUCCESS on success */ int db_sqlite2_open(char **pe, char *dsn) { + sqlite *pdb; char *perr; int ver; int err; + pthread_key_create(&db_sqlite2_key, (void*)db_sqlite2_freedb); snprintf(db_sqlite2_path,sizeof(db_sqlite2_path),"%s/songs.db",dsn); db_sqlite2_lock(); - db_sqlite2_songs=sqlite_open(db_sqlite2_path,0666,&perr); - if(!db_sqlite2_songs) { + pdb=sqlite_open(db_sqlite2_path,0666,&perr); + if(!pdb) { db_get_error(pe,DB_E_SQL_ERROR,perr); DPRINTF(E_LOG,L_DB,"db_sqlite2_open: %s (%s)\n",perr, db_sqlite2_path); @@ -146,8 +180,7 @@ int db_sqlite2_open(char **pe, char *dsn) { db_sqlite2_unlock(); return DB_E_SQL_ERROR; } - - sqlite_busy_timeout(db_sqlite2_songs,30000); /* 30 seconds */ + sqlite_close(pdb); db_sqlite2_unlock(); err = db_sql_fetch_int(pe,&ver,"select value from config where " @@ -176,9 +209,6 @@ int db_sqlite2_open(char **pe, char *dsn) { * close the database */ int db_sqlite2_close(void) { - db_sqlite2_lock(); - sqlite_close(db_sqlite2_songs); - db_sqlite2_unlock(); return DB_E_SUCCESS; } @@ -205,7 +235,7 @@ int db_sqlite2_exec(char **pe, int loglevel, char *fmt, ...) { DPRINTF(E_DBG,L_DB,"Executing: %s\n",query); db_sqlite2_lock(); - err=sqlite_exec(db_sqlite2_songs,query,NULL,NULL,&perr); + err=sqlite_exec(db_sqlite2_handle(),query,NULL,NULL,&perr); if(err != SQLITE_OK) { db_get_error(pe,DB_E_SQL_ERROR,perr); @@ -214,7 +244,7 @@ int db_sqlite2_exec(char **pe, int loglevel, char *fmt, ...) { DPRINTF(loglevel,L_DB,"Error: %s\n",perr); sqlite_freemem(perr); } else { - DPRINTF(E_DBG,L_DB,"Rows: %d\n",sqlite_changes(db_sqlite2_songs)); + DPRINTF(E_DBG,L_DB,"Rows: %d\n",sqlite_changes(db_sqlite2_handle())); } sqlite_freemem(query); @@ -246,7 +276,7 @@ int db_sqlite2_enum_begin_helper(char **pe) { DPRINTF(E_DBG,L_DB,"Executing: %s\n",db_sqlite2_enum_query); - err=sqlite_compile(db_sqlite2_songs,db_sqlite2_enum_query, + err=sqlite_compile(db_sqlite2_handle(),db_sqlite2_enum_query, &ptail,&db_sqlite2_pvm,&perr); if(err != SQLITE_OK) { @@ -430,7 +460,7 @@ int db_sqlite2_event(int event_type) { */ int db_sqlite2_insert_id(void) { - return sqlite_last_insert_rowid(db_sqlite2_songs); + return sqlite_last_insert_rowid(db_sqlite2_handle()); } diff --git a/src/db-sql-sqlite3.c b/src/db-sql-sqlite3.c index e05484d3..fb459295 100644 --- a/src/db-sql-sqlite3.c +++ b/src/db-sql-sqlite3.c @@ -62,7 +62,6 @@ /* 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 sqlite3_stmt *db_sqlite3_stmt; static const char *db_sqlite3_ptail; @@ -70,7 +69,7 @@ static int db_sqlite3_finalized; static int db_sqlite3_reload=0; static char *db_sqlite3_enum_query=NULL; static char **db_sqlite3_row = NULL; - +static pthread_key_t db_sqlite3_key; static char db_sqlite3_path[PATH_MAX + 1]; #define DB_SQLITE3_VERSION 13 @@ -85,6 +84,36 @@ int db_sqlite3_enum_begin_helper(char **pe); +/** + * get (or create) the db handle + */ +sqlite3 *db_sqlite3_handle(void) { + sqlite3 *pdb = NULL; + char *pe = NULL; + + pdb = (sqlite3*)pthread_getspecific(db_sqlite3_key); + if(pdb == NULL) { /* don't have a handle yet */ + DPRINTF(E_DBG,L_DB,"Creating new db handle\n"); + if(sqlite3_open(db_sqlite3_path,&pdb) != SQLITE_OK) { + db_get_error(&pe,DB_E_SQL_ERROR,sqlite3_errmsg(pdb)); + DPRINTF(E_FATAL,L_DB,"db_sqlite3_open: %s (%s)\n",pe,db_sqlite3_path); + db_sqlite3_unlock(); + return NULL; + } + sqlite3_busy_timeout(pdb,30000); /* 30 seconds */ + pthread_setspecific(db_sqlite3_key,(void*)pdb); + } + + return pdb; +} + +/** + * free a thread-specific db handle + */ +void db_sqlite3_freedb(sqlite3 *pdb) { + sqlite3_close(pdb); +} + /** * lock the db_mutex */ @@ -133,19 +162,20 @@ void db_sqlite3_vmfree(char *query) { int db_sqlite3_open(char **pe, char *dsn) { int ver; int err; + sqlite3 *pdb; + pthread_key_create(&db_sqlite3_key, (void*)db_sqlite3_freedb); snprintf(db_sqlite3_path,sizeof(db_sqlite3_path),"%s/songs3.db",dsn); 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(sqlite3_open(db_sqlite3_path,&pdb) != SQLITE_OK) { + db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(pdb)); DPRINTF(E_LOG,L_DB,"db_sqlite3_open: %s (%s)\n",pe ? *pe : "Unknown", db_sqlite3_path); db_sqlite3_unlock(); return DB_E_SQL_ERROR; } - - sqlite3_busy_timeout(db_sqlite3_songs,30000); /* 30 seconds */ + sqlite3_close(pdb); db_sqlite3_unlock(); err = db_sql_fetch_int(pe,&ver,"select value from config where " @@ -171,9 +201,7 @@ int db_sqlite3_open(char **pe, char *dsn) { * close the database */ int db_sqlite3_close(void) { - db_sqlite3_lock(); - sqlite3_close(db_sqlite3_songs); - db_sqlite3_unlock(); + /* this doens't actually make much sense, as the closes get done by the threads */ return DB_E_SUCCESS; } @@ -201,7 +229,7 @@ int db_sqlite3_exec(char **pe, int loglevel, char *fmt, ...) { DPRINTF(E_DBG,L_DB,"Executing: %s\n",query); - err=sqlite3_exec(db_sqlite3_songs,query,NULL,NULL,&perr); + err=sqlite3_exec(db_sqlite3_handle(),query,NULL,NULL,&perr); if(err != SQLITE_OK) { db_get_error(pe,DB_E_SQL_ERROR,perr); @@ -210,7 +238,7 @@ int db_sqlite3_exec(char **pe, int loglevel, char *fmt, ...) { DPRINTF(loglevel,L_DB,"Error: %s\n",perr); sqlite3_free(perr); } else { - DPRINTF(E_DBG,L_DB,"Rows: %d\n",sqlite3_changes(db_sqlite3_songs)); + DPRINTF(E_DBG,L_DB,"Rows: %d\n",sqlite3_changes(db_sqlite3_handle())); } sqlite3_free(query); @@ -243,11 +271,11 @@ int db_sqlite3_enum_begin_helper(char **pe) { *((int*)NULL) = 1; DPRINTF(E_DBG,L_DB,"Executing: %s\n",db_sqlite3_enum_query); - err=sqlite3_prepare(db_sqlite3_songs,db_sqlite3_enum_query,-1, + err=sqlite3_prepare(db_sqlite3_handle(),db_sqlite3_enum_query,-1, &db_sqlite3_stmt,&db_sqlite3_ptail); if(err != SQLITE_OK) { - db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_songs)); + db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_handle())); sqlite3_free(db_sqlite3_enum_query); db_sqlite3_enum_query=NULL; db_sqlite3_unlock(); @@ -325,7 +353,7 @@ int db_sqlite3_enum_fetch(char **pe, SQL_ROW *pr) { free(db_sqlite3_row); 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,sqlite3_errmsg(db_sqlite3_handle())); DPRINTF(E_SPAM,L_DB,"Finalizing statement: %08X\n",db_sqlite3_stmt); sqlite3_finalize(db_sqlite3_stmt); db_sqlite3_finalized=1; @@ -352,7 +380,7 @@ int db_sqlite3_enum_end(char **pe) { DPRINTF(E_SPAM,L_DB,"Finalizing statement: %08X\n",db_sqlite3_stmt); err = sqlite3_finalize(db_sqlite3_stmt); if(err != SQLITE_OK) { - db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_songs)); + db_get_error(pe,DB_E_SQL_ERROR,sqlite3_errmsg(db_sqlite3_handle())); db_sqlite3_unlock(); return DB_E_SQL_ERROR; } @@ -472,7 +500,7 @@ int db_sqlite3_insert_id(void) { int result; db_sqlite3_lock(); - result = (int)sqlite3_last_insert_rowid(db_sqlite3_songs); + result = (int)sqlite3_last_insert_rowid(db_sqlite3_handle()); db_sqlite3_unlock(); return result; diff --git a/src/plugins/rsp.c b/src/plugins/rsp.c index 5166dacf..4854251d 100644 --- a/src/plugins/rsp.c +++ b/src/plugins/rsp.c @@ -273,7 +273,7 @@ void rsp_info(WS_CONNINFO *pwsc, PRIVINFO *ppi) { /* info block */ xml_push(pxml,"info"); - xml_output(pxml,"count","%d",pi_db_count()); + xml_output(pxml,"count","%d",pi_db_count_items(COUNT_SONGS)); xml_output(pxml,"rsp-version","%s",RSP_VERSION); xml_output(pxml,"server-version","%s",pi_server_ver());