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
;
45 #define SYNC_MODE "OFF"
47 static void sqlitequeueprocessor(void *arg
);
48 static void dbstatus(int hooknum
, void *arg
);
54 dbfile
= getcopyconfigitem("sqlite", "file", "newserv.db", 100);
57 Error("sqlite", ERR_ERROR
, "Unable to get config settings.");
61 processsched
= schedulerecurring(time(NULL
), 0, 1, &sqlitequeueprocessor
, NULL
);
63 Error("sqlite", ERR_ERROR
, "Unable to schedule query processor.");
68 rc
= sqlite3_open(dbfile
->content
, &conn
);
72 Error("sqlite", ERR_ERROR
, "Unable to connect to database: %s", sqlite3_errmsg(conn
));
73 deleteschedule(processsched
, &sqlitequeueprocessor
, NULL
);
79 sqliteasyncqueryf(0, NULL
, NULL
, 0, "PRAGMA synchronous=" SYNC_MODE
";");
80 registerhook(HOOK_CORE_STATSREQUEST
, dbstatus
);
84 struct sqlitequeue
*q
, *nq
;
85 if(!sqliteconnected())
88 deregisterhook(HOOK_CORE_STATSREQUEST
, dbstatus
);
89 deleteschedule(processsched
, &sqlitequeueprocessor
, NULL
);
91 /* we assume every module that's being unloaded
92 * has us as a dependency and will have cleaned up
93 * their queries by using freeid..
97 sqlite3_finalize(q
->statement
);
98 nsfree(POOL_SQLITE
, q
);
104 nscheckfreeall(POOL_SQLITE
);
107 /* busy processing is done externally as that varies depending on what you are... */
108 static void processstatement(int rc
, sqlite3_stmt
*s
, SQLiteQueryHandler handler
, void *tag
, char *querybuf
) {
109 if(handler
) { /* the handler deals with the cleanup */
112 if((rc
!= SQLITE_ROW
) && (rc
!= SQLITE_DONE
)) {
113 Error("sqlite", ERR_WARNING
, "SQL error %d: %s (query: %s)", rc
, sqlite3_errmsg(conn
), querybuf
);
118 r
= (SQLiteResult
*)nsmalloc(POOL_SQLITE
, sizeof(SQLiteResult
));
121 if(rc
== SQLITE_ROW
) {
123 } else if(rc
== SQLITE_DONE
) {
128 if(rc
== SQLITE_ROW
) {
129 Error("sqlite", ERR_WARNING
, "Unhandled data from query: %s", querybuf
);
130 } else if(rc
!= SQLITE_DONE
) {
131 Error("sqlite", ERR_WARNING
, "SQL error %d: %s (query: %s)", rc
, sqlite3_errmsg(conn
), querybuf
);
137 static void pushqueue(sqlite3_stmt
*s
, int identifier
, SQLiteQueryHandler handler
, void *tag
) {
138 struct sqlitequeue
*q
= (struct sqlitequeue
*)nsmalloc(POOL_SQLITE
, sizeof(struct sqlitequeue
));
140 q
->identifier
= identifier
;
141 q
->handler
= handler
;
155 static struct sqlitequeue
*peekqueue(void) {
159 /* a weird pop that doesn't return the value */
160 static void popqueue(void) {
161 struct sqlitequeue
*q
;
173 nsfree(POOL_SQLITE
, q
);
178 void sqliteasyncqueryf(int identifier
, SQLiteQueryHandler handler
, void *tag
, int flags
, char *format
, ...) {
185 if(!sqliteconnected())
188 va_start(va
, format
);
189 len
= vsnprintf(querybuf
, sizeof(querybuf
), format
, va
);
192 rc
= sqlite3_prepare(conn
, querybuf
, -1, &s
, NULL
);
193 if(rc
!= SQLITE_OK
) {
194 if(flags
!= DB_CREATE
)
195 Error("sqlite", ERR_WARNING
, "SQL error %d: %s (query: %s)", rc
, sqlite3_errmsg(conn
), querybuf
);
201 if(head
) { /* stuff already queued */
202 pushqueue(s
, identifier
, handler
, tag
);
206 rc
= sqlite3_step(s
);
207 if(rc
== SQLITE_BUSY
) {
208 pushqueue(s
, identifier
, handler
, tag
);
212 processstatement(rc
, s
, handler
, tag
, querybuf
);
215 int sqliteconnected(void) {
219 void sqliteescapestring(char *buf
, char *src
, unsigned int len
) {
223 for(p
=src
,i
=0;i
<len
;i
++,p
++) {
231 SQLiteResult
*sqlitegetresult(SQLiteConn
*r
) {
235 int sqlitefetchrow(SQLiteResult
*r
) {
239 if(!r
|| !r
->r
|| r
->final
)
242 if(r
->first
) { /* we've extracted the first row already */
249 rc
= sqlite3_step(r
->r
);
250 if(rc
!= SQLITE_BUSY
)
253 v
= rand() % 50 + 50;
254 t
.tv_nsec
= v
* 1000000;
255 Error("sqlite", ERR_WARNING
, "SQLite is busy, retrying in %fs...", (double)v
/ 1000);
259 if(rc
== SQLITE_DONE
) {
264 if(rc
!= SQLITE_ROW
) {
265 Error("sqlite", ERR_WARNING
, "SQL error %d: %s", rc
, sqlite3_errmsg(conn
));
273 void sqliteclear(SQLiteResult
*r
) {
278 sqlite3_finalize(r
->r
);
280 nsfree(POOL_SQLITE
, r
);
283 int sqlitequerysuccessful(SQLiteResult
*r
) {
290 struct sqlitetableloader
{
291 SQLiteQueryHandler init
, data
, fini
;
295 static void loadtablerows(SQLiteConn
*c
, void *tag
) {
296 struct sqlitetableloader
*t
= (struct sqlitetableloader
*)tag
;
298 if(!c
) { /* pqsql doesnt call the handlers so we don't either */
299 nsfree(POOL_SQLITE
, t
);
303 /* the handlers do all the checking and cleanup */
312 nsfree(POOL_SQLITE
, t
);
315 static void loadtablecount(SQLiteConn
*c
, void *tag
) {
316 struct sqlitetableloader
*t
= (struct sqlitetableloader
*)tag
;
317 SQLiteResult
*r
= NULL
;
319 if(!c
) { /* unloaded */
320 nsfree(POOL_SQLITE
, t
);
324 if(!(r
= sqlitegetresult(c
)) || !sqlitefetchrow(r
)) {
325 Error("sqlite", ERR_ERROR
, "Error getting row count for %s.", t
->tablename
);
326 nsfree(POOL_SQLITE
, t
);
333 Error("sqlite", ERR_INFO
, "Found %s entries in table %s, loading...", (char *)sqlite3_column_text(r
->r
, 0), t
->tablename
);
336 sqliteasyncqueryf(0, loadtablerows
, t
, 0, "SELECT * FROM %s", t
->tablename
);
339 void sqliteloadtable(char *tablename
, SQLiteQueryHandler init
, SQLiteQueryHandler data
, SQLiteQueryHandler fini
) {
340 struct sqlitetableloader
*t
;
343 if(!sqliteconnected())
346 len
= strlen(tablename
);
348 t
= (struct sqlitetableloader
*)nsmalloc(POOL_SQLITE
, sizeof(struct sqlitetableloader
) + len
+ 1);
349 memcpy(t
->tablename
, tablename
, len
+ 1);
354 sqliteasyncqueryf(0, loadtablecount
, t
, 0, "SELECT COUNT(*) FROM %s", tablename
);
357 void sqliteattach(char *schema
) {
358 sqliteasyncqueryf(0, NULL
, NULL
, 0, "ATTACH DATABASE '%s.db' AS %s", schema
, schema
);
359 sqliteasyncqueryf(0, NULL
, NULL
, 0, "PRAGMA %s.synchronous=" SYNC_MODE
, schema
);
362 void sqlitedetach(char *schema
) {
363 sqliteasyncqueryf(0, NULL
, NULL
, 0, "DETACH DATABASE %s", schema
);
366 int sqlitegetid(void) {
374 void sqlitefreeid(int id
) {
375 struct sqlitequeue
*q
, *pq
;
379 for(pq
=NULL
,q
=head
;q
;) {
380 if(q
->identifier
== id
) {
390 sqlite3_finalize(q
->statement
);
392 q
->handler(NULL
, q
->tag
);
393 nsfree(POOL_SQLITE
, q
);
408 static void sqlitequeueprocessor(void *arg
) {
409 struct sqlitequeue
*q
= peekqueue();
412 int rc
= sqlite3_step(q
->statement
);
413 if(rc
== SQLITE_BUSY
)
416 processstatement(rc
, q
->statement
, q
->handler
, q
->tag
, "??");
423 static void dbstatus(int hooknum
, void *arg
) {
427 snprintf(message
, sizeof(message
), "SQLite : %6d queries queued.", queuesize
);
428 triggerhook(HOOK_CORE_STATSREPLY
, message
);