4 * A replacement for Germania's ageing Operservice2
7 * Copyright (C) 2005 Chris Porter.
8 * 99% of the PGSQL handling is stolen from Q9, copyright (C) David Mansell.
11 #include "../core/config.h"
12 #include "../core/error.h"
13 #include "../irc/irc_config.h"
14 #include "../core/events.h"
15 #include "../core/hooks.h"
16 #include "noperserv_psql.h"
22 typedef struct no_asyncquery
{
25 NoQueryHandler handler
;
26 struct no_asyncquery
*next
;
29 no_asyncquery
*queryhead
= NULL
, *querytail
= NULL
;
34 void noperserv_db_handler(int fd
, short revents
);
35 void noperserv_db_status(int hooknum
, void *arg
);
37 int noperserv_connect_db(NoCreateHandler createtables
) {
38 sstring
*dbhost
, *dbusername
, *dbpassword
, *dbdatabase
, *dbport
;
39 char connectstr
[1024];
44 /* stolen from chanserv as I'm lazy */
45 dbhost
= getcopyconfigitem("noperserv", "dbhost", "localhost", HOSTLEN
);
46 dbusername
= getcopyconfigitem("noperserv", "dbusername", "noperserv", 20);
47 dbpassword
= getcopyconfigitem("noperserv", "dbpassword", "moo", 20);
48 dbdatabase
= getcopyconfigitem("noperserv", "dbdatabase", "noperserv", 20);
49 dbport
= getcopyconfigitem("noperserv", "dbport", "3306", 8);
51 if(!dbhost
|| !dbusername
|| !dbpassword
|| !dbdatabase
|| !dbport
) {
52 /* freesstring allows NULL */
54 freesstring(dbusername
);
55 freesstring(dbpassword
);
56 freesstring(dbdatabase
);
61 snprintf(connectstr
, sizeof(connectstr
), "dbname=%s user=%s password=%s", dbdatabase
->content
, dbusername
->content
, dbpassword
->content
);
64 freesstring(dbusername
);
65 freesstring(dbpassword
);
66 freesstring(dbdatabase
);
69 Error("noperserv", ERR_INFO
, "Attempting database connection: %s", connectstr
);
71 /* Blocking connect for now.. */
72 no_dbconn
= PQconnectdb(connectstr
);
74 if (!no_dbconn
|| (PQstatus(no_dbconn
) != CONNECTION_OK
))
82 PQsetnonblocking(no_dbconn
, 1);
84 /* this kicks ass, thanks splidge! */
85 registerhandler(PQsocket(no_dbconn
), POLLIN
, noperserv_db_handler
);
86 registerhook(HOOK_CORE_STATSREQUEST
, noperserv_db_status
);
91 void noperserv_db_handler(int fd
, short revents
) {
95 if(revents
& POLLIN
) {
96 PQconsumeInput(no_dbconn
);
98 if(!PQisBusy(no_dbconn
)) { /* Query is complete */
99 if(queryhead
->handler
)
100 (queryhead
->handler
)(no_dbconn
, queryhead
->tag
);
102 while((res
= PQgetResult(no_dbconn
))) {
103 switch(PQresultStatus(res
)) {
104 case PGRES_TUPLES_OK
:
105 Error("noperserv", ERR_WARNING
, "Unhandled tuples output (query: %s)", queryhead
->query
->content
);
108 case PGRES_NONFATAL_ERROR
:
109 case PGRES_FATAL_ERROR
:
110 Error("noperserv", ERR_WARNING
, "Unhandled error response (query: %s)", queryhead
->query
->content
);
120 /* Free the query and advance */
122 if(queryhead
== querytail
)
125 queryhead
= queryhead
->next
;
127 freesstring(qqp
->query
);
130 if(queryhead
) { /* Submit the next query */
131 PQsendQuery(no_dbconn
, queryhead
->query
->content
);
139 void noperserv_async_query(NoQueryHandler handler
, void *tag
, char *format
, ...) {
148 va_start(va
, format
);
149 len
= vsnprintf(querybuf
, sizeof(querybuf
), format
, va
);
152 qp
= (no_asyncquery
*)malloc(sizeof(no_asyncquery
));
153 qp
->query
= getsstring(querybuf
, len
);
155 qp
->handler
= handler
;
156 qp
->next
= NULL
; /* shove them at the end */
159 querytail
->next
= qp
;
162 querytail
= queryhead
= qp
;
163 PQsendQuery(no_dbconn
, qp
->query
->content
);
168 void noperserv_sync_query(char *format
, ...){
176 va_start(va
, format
);
177 len
= vsnprintf(querybuf
, sizeof(querybuf
), format
, va
);
180 PQclear(PQexec(no_dbconn
, querybuf
));
183 void noperserv_disconnect_db(void) {
184 no_asyncquery
*qqp
= queryhead
, *nqqp
;
189 /* do this first else we may get conflicts */
190 deregisterhandler(PQsocket(no_dbconn
), 0);
192 /* Throw all the queued queries away, beware of data malloc()ed inside the query item.. */
195 freesstring(qqp
->query
);
200 deregisterhook(HOOK_CORE_STATSREQUEST
, noperserv_db_status
);
202 no_dbconn
= NULL
; /* hmm? */
207 /* more stolen code from Q9 */
208 void noperserv_db_status(int hooknum
, void *arg
) {
215 for(qqp
=queryhead
;qqp
;qqp
=qqp
->next
)
218 snprintf(message
, sizeof(message
), "NOServ : %6d database queries queued.",i
);
220 triggerhook(HOOK_CORE_STATSREPLY
, message
);