10 #define __USE_POSIX199309
13 #include "../core/config.h"
14 #include "../core/error.h"
15 #include "../core/events.h"
16 #include "../core/hooks.h"
17 #include "../lib/version.h"
18 #include "../lib/strlfunc.h"
19 #include "../core/nsmalloc.h"
20 #include "../core/schedule.h"
22 #define BUILDING_DBAPI
23 #include "../dbapi/dbapi.h"
29 static int dbconnected
= 0;
30 static struct sqlite3
*conn
;
31 static SQLiteModuleIdentifier modid
;
34 sqlite3_stmt
*statement
;
35 SQLiteQueryHandler handler
;
38 struct sqlitequeue
*next
;
41 static struct sqlitequeue
*head
, *tail
;
43 static void *processsched
;
46 #define SYNC_MODE "OFF"
48 static void sqlitequeueprocessor(void *arg
);
49 static void dbstatus(int hooknum
, void *arg
);
55 dbfile
= getcopyconfigitem("sqlite", "file", "newserv.db", 100);
58 Error("sqlite", ERR_ERROR
, "Unable to get config settings.");
62 processsched
= schedulerecurring(time(NULL
), 0, 1, &sqlitequeueprocessor
, NULL
);
64 Error("sqlite", ERR_ERROR
, "Unable to schedule query processor.");
70 if(sqlite3_initialize() != SQLITE_OK
) {
71 Error("sqlite", ERR_ERROR
, "Unable to initialise sqlite");
74 sqlite3_config(SQLITE_CONFIG_SINGLETHREAD
);
78 rc
= sqlite3_open(dbfile
->content
, &conn
);
82 Error("sqlite", ERR_ERROR
, "Unable to connect to database: %s", sqlite3_errmsg(conn
));
83 deleteschedule(processsched
, &sqlitequeueprocessor
, NULL
);
89 sqliteasyncqueryf(0, NULL
, NULL
, 0, "PRAGMA synchronous=" SYNC_MODE
";");
90 registerhook(HOOK_CORE_STATSREQUEST
, dbstatus
);
94 struct sqlitequeue
*q
, *nq
;
96 if(sqliteconnected()) {
97 deregisterhook(HOOK_CORE_STATSREQUEST
, dbstatus
);
98 deleteschedule(processsched
, &sqlitequeueprocessor
, NULL
);
100 /* we assume every module that's being unloaded
101 * has us as a dependency and will have cleaned up
102 * their queries by using freeid..
106 sqlite3_finalize(q
->statement
);
107 nsfree(POOL_SQLITE
, q
);
120 nscheckfreeall(POOL_SQLITE
);
123 /* busy processing is done externally as that varies depending on what you are... */
124 static void processstatement(int rc
, sqlite3_stmt
*s
, SQLiteQueryHandler handler
, void *tag
, char *querybuf
) {
125 if(handler
) { /* the handler deals with the cleanup */
128 if((rc
!= SQLITE_ROW
) && (rc
!= SQLITE_DONE
)) {
129 Error("sqlite", ERR_WARNING
, "SQL error %d: %s (query: %s)", rc
, sqlite3_errmsg(conn
), querybuf
);
134 r
= (SQLiteResult
*)nsmalloc(POOL_SQLITE
, sizeof(SQLiteResult
));
137 if(rc
== SQLITE_ROW
) {
139 } else if(rc
== SQLITE_DONE
) {
144 if(rc
== SQLITE_ROW
) {
145 Error("sqlite", ERR_WARNING
, "Unhandled data from query: %s", querybuf
);
146 } else if(rc
!= SQLITE_DONE
) {
147 Error("sqlite", ERR_WARNING
, "SQL error %d: %s (query: %s)", rc
, sqlite3_errmsg(conn
), querybuf
);
153 static void pushqueue(sqlite3_stmt
*s
, int identifier
, SQLiteQueryHandler handler
, void *tag
) {
154 struct sqlitequeue
*q
= (struct sqlitequeue
*)nsmalloc(POOL_SQLITE
, sizeof(struct sqlitequeue
));
156 q
->identifier
= identifier
;
157 q
->handler
= handler
;
171 static struct sqlitequeue
*peekqueue(void) {
175 /* a weird pop that doesn't return the value */
176 static void popqueue(void) {
177 struct sqlitequeue
*q
;
189 nsfree(POOL_SQLITE
, q
);
194 void sqliteasyncqueryf(int identifier
, SQLiteQueryHandler handler
, void *tag
, int flags
, char *format
, ...) {
201 if(!sqliteconnected())
204 va_start(va
, format
);
205 len
= vsnprintf(querybuf
, sizeof(querybuf
), format
, va
);
208 rc
= sqlite3_prepare(conn
, querybuf
, -1, &s
, NULL
);
209 if(rc
!= SQLITE_OK
) {
210 if(flags
!= DB_CREATE
)
211 Error("sqlite", ERR_WARNING
, "SQL error %d: %s (query: %s)", rc
, sqlite3_errmsg(conn
), querybuf
);
217 if(head
) { /* stuff already queued */
218 pushqueue(s
, identifier
, handler
, tag
);
222 rc
= sqlite3_step(s
);
223 if(rc
== SQLITE_BUSY
) {
224 pushqueue(s
, identifier
, handler
, tag
);
228 processstatement(rc
, s
, handler
, tag
, querybuf
);
231 int sqliteconnected(void) {
235 size_t sqliteescapestring(char *buf
, char *src
, unsigned int len
) {
239 for(p
=src
,d
=buf
,i
=0;i
<len
;i
++,p
++) {
249 SQLiteResult
*sqlitegetresult(SQLiteConn
*r
) {
253 int sqlitefetchrow(SQLiteResult
*r
) {
257 if(!r
|| !r
->r
|| r
->final
)
260 if(r
->first
) { /* we've extracted the first row already */
267 rc
= sqlite3_step(r
->r
);
268 if(rc
!= SQLITE_BUSY
)
271 v
= rand() % 50 + 50;
272 t
.tv_nsec
= v
* 1000000;
273 Error("sqlite", ERR_WARNING
, "SQLite is busy, retrying in %fs...", (double)v
/ 1000);
277 if(rc
== SQLITE_DONE
) {
282 if(rc
!= SQLITE_ROW
) {
283 Error("sqlite", ERR_WARNING
, "SQL error %d: %s", rc
, sqlite3_errmsg(conn
));
291 void sqliteclear(SQLiteResult
*r
) {
296 sqlite3_finalize(r
->r
);
298 nsfree(POOL_SQLITE
, r
);
301 int sqlitequerysuccessful(SQLiteResult
*r
) {
308 struct sqlitetableloader
{
309 SQLiteQueryHandler init
, data
, fini
;
314 static void loadtablerows(SQLiteConn
*c
, void *tag
) {
315 struct sqlitetableloader
*t
= (struct sqlitetableloader
*)tag
;
317 if(!c
) { /* pqsql doesnt call the handlers so we don't either */
318 nsfree(POOL_SQLITE
, t
);
322 /* the handlers do all the checking and cleanup */
324 (t
->init
)(NULL
, t
->tag
);
326 (t
->data
)(c
, t
->tag
);
329 (t
->fini
)(NULL
, t
->tag
);
331 nsfree(POOL_SQLITE
, t
);
334 static void loadtablecount(SQLiteConn
*c
, void *tag
) {
335 struct sqlitetableloader
*t
= (struct sqlitetableloader
*)tag
;
336 SQLiteResult
*r
= NULL
;
338 if(!c
) { /* unloaded */
339 nsfree(POOL_SQLITE
, t
);
343 if(!(r
= sqlitegetresult(c
)) || !sqlitefetchrow(r
)) {
344 Error("sqlite", ERR_ERROR
, "Error getting row count for %s.", t
->tablename
);
345 nsfree(POOL_SQLITE
, t
);
352 Error("sqlite", ERR_INFO
, "Found %s entries in table %s, loading...", (char *)sqlite3_column_text(r
->r
, 0), t
->tablename
);
355 sqliteasyncqueryf(0, loadtablerows
, t
, 0, "SELECT * FROM %s", t
->tablename
);
358 void sqliteloadtable(char *tablename
, SQLiteQueryHandler init
, SQLiteQueryHandler data
, SQLiteQueryHandler fini
, void *tag
) {
359 struct sqlitetableloader
*t
;
362 if(!sqliteconnected())
365 len
= strlen(tablename
);
367 t
= (struct sqlitetableloader
*)nsmalloc(POOL_SQLITE
, sizeof(struct sqlitetableloader
) + len
+ 1);
368 memcpy(t
->tablename
, tablename
, len
+ 1);
374 sqliteasyncqueryf(0, loadtablecount
, t
, 0, "SELECT COUNT(*) FROM %s", tablename
);
377 void sqliteattach(char *schema
) {
378 sqliteasyncqueryf(0, NULL
, NULL
, 0, "ATTACH DATABASE '%s.db' AS %s", schema
, schema
);
379 sqliteasyncqueryf(0, NULL
, NULL
, 0, "PRAGMA %s.synchronous=" SYNC_MODE
, schema
);
382 void sqlitedetach(char *schema
) {
383 sqliteasyncqueryf(0, NULL
, NULL
, 0, "DETACH DATABASE %s", schema
);
386 int sqlitegetid(void) {
394 void sqlitefreeid(int id
) {
395 struct sqlitequeue
*q
, *pq
;
399 for(pq
=NULL
,q
=head
;q
;) {
400 if(q
->identifier
== id
) {
410 sqlite3_finalize(q
->statement
);
412 q
->handler(NULL
, q
->tag
);
413 nsfree(POOL_SQLITE
, q
);
428 static void sqlitequeueprocessor(void *arg
) {
429 struct sqlitequeue
*q
= peekqueue();
432 int rc
= sqlite3_step(q
->statement
);
433 if(rc
== SQLITE_BUSY
)
436 processstatement(rc
, q
->statement
, q
->handler
, q
->tag
, "??");
443 static void dbstatus(int hooknum
, void *arg
) {
447 snprintf(message
, sizeof(message
), "SQLite : %6d queries queued.", queuesize
);
448 triggerhook(HOOK_CORE_STATSREPLY
, message
);