10 #ifndef __USE_POSIX199309
11 #define __USE_POSIX199309
16 #include "../core/config.h"
17 #include "../core/error.h"
18 #include "../core/events.h"
19 #include "../core/hooks.h"
20 #include "../lib/version.h"
21 #include "../lib/strlfunc.h"
22 #include "../core/nsmalloc.h"
23 #include "../core/schedule.h"
25 #define BUILDING_DBAPI
26 #include "../dbapi/dbapi.h"
32 static int dbconnected
= 0;
33 static struct sqlite3
*conn
;
34 static SQLiteModuleIdentifier modid
;
37 sqlite3_stmt
*statement
;
38 SQLiteQueryHandler handler
;
41 struct sqlitequeue
*next
;
44 static struct sqlitequeue
*head
, *tail
;
46 static void *processsched
;
49 #define SYNC_MODE "OFF"
51 static void sqlitequeueprocessor(void *arg
);
52 static void dbstatus(int hooknum
, void *arg
);
58 dbfile
= getcopyconfigitem("sqlite", "file", "newserv.db", 100);
61 Error("sqlite", ERR_ERROR
, "Unable to get config settings.");
65 processsched
= schedulerecurring(time(NULL
), 0, 1, &sqlitequeueprocessor
, NULL
);
67 Error("sqlite", ERR_ERROR
, "Unable to schedule query processor.");
73 if(sqlite3_initialize() != SQLITE_OK
) {
74 Error("sqlite", ERR_ERROR
, "Unable to initialise sqlite");
77 sqlite3_config(SQLITE_CONFIG_SINGLETHREAD
);
81 rc
= sqlite3_open(dbfile
->content
, &conn
);
85 Error("sqlite", ERR_ERROR
, "Unable to connect to database: %s", sqlite3_errmsg(conn
));
86 deleteschedule(processsched
, &sqlitequeueprocessor
, NULL
);
92 sqliteasyncqueryf(0, NULL
, NULL
, 0, "PRAGMA synchronous=" SYNC_MODE
";");
93 registerhook(HOOK_CORE_STATSREQUEST
, dbstatus
);
97 struct sqlitequeue
*q
, *nq
;
99 if(sqliteconnected()) {
100 deregisterhook(HOOK_CORE_STATSREQUEST
, dbstatus
);
101 deleteschedule(processsched
, &sqlitequeueprocessor
, NULL
);
103 /* we assume every module that's being unloaded
104 * has us as a dependency and will have cleaned up
105 * their queries by using freeid..
109 sqlite3_finalize(q
->statement
);
110 nsfree(POOL_SQLITE
, q
);
123 nscheckfreeall(POOL_SQLITE
);
126 /* busy processing is done externally as that varies depending on what you are... */
127 static void processstatement(int rc
, sqlite3_stmt
*s
, SQLiteQueryHandler handler
, void *tag
, char *querybuf
) {
128 if(handler
) { /* the handler deals with the cleanup */
131 if((rc
!= SQLITE_ROW
) && (rc
!= SQLITE_DONE
)) {
132 Error("sqlite", ERR_WARNING
, "SQL error %d: %s (query: %s)", rc
, sqlite3_errmsg(conn
), querybuf
);
137 r
= (SQLiteResult
*)nsmalloc(POOL_SQLITE
, sizeof(SQLiteResult
));
140 if(rc
== SQLITE_ROW
) {
142 } else if(rc
== SQLITE_DONE
) {
147 if(rc
== SQLITE_ROW
) {
148 Error("sqlite", ERR_WARNING
, "Unhandled data from query: %s", querybuf
);
149 } else if(rc
!= SQLITE_DONE
) {
150 Error("sqlite", ERR_WARNING
, "SQL error %d: %s (query: %s)", rc
, sqlite3_errmsg(conn
), querybuf
);
156 static void pushqueue(sqlite3_stmt
*s
, int identifier
, SQLiteQueryHandler handler
, void *tag
) {
157 struct sqlitequeue
*q
= (struct sqlitequeue
*)nsmalloc(POOL_SQLITE
, sizeof(struct sqlitequeue
));
159 q
->identifier
= identifier
;
160 q
->handler
= handler
;
174 static struct sqlitequeue
*peekqueue(void) {
178 /* a weird pop that doesn't return the value */
179 static void popqueue(void) {
180 struct sqlitequeue
*q
;
192 nsfree(POOL_SQLITE
, q
);
197 void sqliteasyncqueryf(int identifier
, SQLiteQueryHandler handler
, void *tag
, int flags
, char *format
, ...) {
204 if(!sqliteconnected())
207 va_start(va
, format
);
208 len
= vsnprintf(querybuf
, sizeof(querybuf
), format
, va
);
211 rc
= sqlite3_prepare(conn
, querybuf
, -1, &s
, NULL
);
212 if(rc
!= SQLITE_OK
) {
213 if(flags
!= DB_CREATE
)
214 Error("sqlite", ERR_WARNING
, "SQL error %d: %s (query: %s)", rc
, sqlite3_errmsg(conn
), querybuf
);
220 if(head
) { /* stuff already queued */
221 pushqueue(s
, identifier
, handler
, tag
);
225 rc
= sqlite3_step(s
);
226 if(rc
== SQLITE_BUSY
) {
227 pushqueue(s
, identifier
, handler
, tag
);
231 processstatement(rc
, s
, handler
, tag
, querybuf
);
234 int sqliteconnected(void) {
238 size_t sqliteescapestring(char *buf
, char *src
, unsigned int len
) {
242 for(p
=src
,d
=buf
,i
=0;i
<len
;i
++,p
++) {
252 SQLiteResult
*sqlitegetresult(SQLiteConn
*r
) {
256 int sqlitefetchrow(SQLiteResult
*r
) {
260 if(!r
|| !r
->r
|| r
->final
)
263 if(r
->first
) { /* we've extracted the first row already */
270 rc
= sqlite3_step(r
->r
);
271 if(rc
!= SQLITE_BUSY
)
274 v
= rand() % 50 + 50;
275 t
.tv_nsec
= v
* 1000000;
276 Error("sqlite", ERR_WARNING
, "SQLite is busy, retrying in %fs...", (double)v
/ 1000);
280 if(rc
== SQLITE_DONE
) {
285 if(rc
!= SQLITE_ROW
) {
286 Error("sqlite", ERR_WARNING
, "SQL error %d: %s", rc
, sqlite3_errmsg(conn
));
294 void sqliteclear(SQLiteResult
*r
) {
299 sqlite3_finalize(r
->r
);
301 nsfree(POOL_SQLITE
, r
);
304 int sqlitequerysuccessful(SQLiteResult
*r
) {
311 struct sqlitetableloader
{
312 SQLiteQueryHandler init
, data
, fini
;
317 static void loadtablerows(SQLiteConn
*c
, void *tag
) {
318 struct sqlitetableloader
*t
= (struct sqlitetableloader
*)tag
;
320 if(!c
) { /* pqsql doesnt call the handlers so we don't either */
321 nsfree(POOL_SQLITE
, t
);
325 /* the handlers do all the checking and cleanup */
327 (t
->init
)(NULL
, t
->tag
);
329 (t
->data
)(c
, t
->tag
);
332 (t
->fini
)(NULL
, t
->tag
);
334 nsfree(POOL_SQLITE
, t
);
337 static void loadtablecount(SQLiteConn
*c
, void *tag
) {
338 struct sqlitetableloader
*t
= (struct sqlitetableloader
*)tag
;
339 SQLiteResult
*r
= NULL
;
341 if(!c
) { /* unloaded */
342 nsfree(POOL_SQLITE
, t
);
346 if(!(r
= sqlitegetresult(c
)) || !sqlitefetchrow(r
)) {
347 Error("sqlite", ERR_ERROR
, "Error getting row count for %s.", t
->tablename
);
348 nsfree(POOL_SQLITE
, t
);
355 Error("sqlite", ERR_INFO
, "Found %s entries in table %s, loading...", (char *)sqlite3_column_text(r
->r
, 0), t
->tablename
);
358 sqliteasyncqueryf(0, loadtablerows
, t
, 0, "SELECT * FROM %s", t
->tablename
);
361 void sqliteloadtable(char *tablename
, SQLiteQueryHandler init
, SQLiteQueryHandler data
, SQLiteQueryHandler fini
, void *tag
) {
362 struct sqlitetableloader
*t
;
365 if(!sqliteconnected())
368 len
= strlen(tablename
);
370 t
= (struct sqlitetableloader
*)nsmalloc(POOL_SQLITE
, sizeof(struct sqlitetableloader
) + len
+ 1);
371 memcpy(t
->tablename
, tablename
, len
+ 1);
377 sqliteasyncqueryf(0, loadtablecount
, t
, 0, "SELECT COUNT(*) FROM %s", tablename
);
380 void sqliteattach(char *schema
) {
381 sqliteasyncqueryf(0, NULL
, NULL
, 0, "ATTACH DATABASE '%s.db' AS %s", schema
, schema
);
382 sqliteasyncqueryf(0, NULL
, NULL
, 0, "PRAGMA %s.synchronous=" SYNC_MODE
, schema
);
385 void sqlitedetach(char *schema
) {
386 sqliteasyncqueryf(0, NULL
, NULL
, 0, "DETACH DATABASE %s", schema
);
389 int sqlitegetid(void) {
397 void sqlitefreeid(int id
) {
398 struct sqlitequeue
*q
, *pq
;
402 for(pq
=NULL
,q
=head
;q
;) {
403 if(q
->identifier
== id
) {
413 sqlite3_finalize(q
->statement
);
415 q
->handler(NULL
, q
->tag
);
416 nsfree(POOL_SQLITE
, q
);
431 static void sqlitequeueprocessor(void *arg
) {
432 struct sqlitequeue
*q
= peekqueue();
435 int rc
= sqlite3_step(q
->statement
);
436 if(rc
== SQLITE_BUSY
)
439 processstatement(rc
, q
->statement
, q
->handler
, q
->tag
, "??");
446 static void dbstatus(int hooknum
, void *arg
) {
450 snprintf(message
, sizeof(message
), "SQLite : %6d queries queued.", queuesize
);
451 triggerhook(HOOK_CORE_STATSREPLY
, message
);