1 /*
2  * Copyright (c) 2010 William Pitcock <nenolod@atheme.org>
3  * Rights to this code are as documented in doc/LICENSE.
4  *
5  * Platform-agnostic database backend layer.
6  */
7 
8 #include "atheme.h"
9 
10 database_module_t *db_mod = NULL;
11 mowgli_patricia_t *db_types = NULL;
12 
13 database_handle_t *
db_open(const char * filename,database_transaction_t txn)14 db_open(const char *filename, database_transaction_t txn)
15 {
16 	return_val_if_fail(db_mod != NULL, NULL);
17 	return_val_if_fail(db_mod->db_open != NULL, NULL);
18 
19 	return db_mod->db_open(filename, txn);
20 }
21 
22 void
db_close(database_handle_t * db)23 db_close(database_handle_t *db)
24 {
25 	return_if_fail(db_mod != NULL);
26 	return_if_fail(db_mod->db_close != NULL);
27 
28 	return db_mod->db_close(db);
29 }
30 
31 void
db_parse(database_handle_t * db)32 db_parse(database_handle_t *db)
33 {
34 	return_if_fail(db_mod != NULL);
35 	return_if_fail(db_mod->db_parse != NULL);
36 
37 	return db_mod->db_parse(db);
38 }
39 
40 bool
db_read_next_row(database_handle_t * db)41 db_read_next_row(database_handle_t *db)
42 {
43 	return_val_if_fail(db != NULL, NULL);
44 	return_val_if_fail(db->vt != NULL, NULL);
45 	return_val_if_fail(db->vt->read_next_row != NULL, NULL);
46 
47 	return db->vt->read_next_row(db);
48 }
49 
50 const char *
db_read_word(database_handle_t * db)51 db_read_word(database_handle_t *db)
52 {
53 	return_val_if_fail(db != NULL, NULL);
54 	return_val_if_fail(db->vt != NULL, NULL);
55 	return_val_if_fail(db->vt->read_word != NULL, NULL);
56 
57 	return db->vt->read_word(db);
58 }
59 
60 const char *
db_read_str(database_handle_t * db)61 db_read_str(database_handle_t *db)
62 {
63 	return_val_if_fail(db != NULL, NULL);
64 	return_val_if_fail(db->vt != NULL, NULL);
65 	return_val_if_fail(db->vt->read_str != NULL, NULL);
66 
67 	return db->vt->read_str(db);
68 }
69 
70 bool
db_read_int(database_handle_t * db,int * r)71 db_read_int(database_handle_t *db, int *r)
72 {
73 	return_val_if_fail(db != NULL, false);
74 	return_val_if_fail(db->vt != NULL, false);
75 	return_val_if_fail(db->vt->read_int != NULL, false);
76 
77 	return db->vt->read_int(db, r);
78 }
79 
80 bool
db_read_uint(database_handle_t * db,unsigned int * r)81 db_read_uint(database_handle_t *db, unsigned int *r)
82 {
83 	return_val_if_fail(db != NULL, false);
84 	return_val_if_fail(db->vt != NULL, false);
85 	return_val_if_fail(db->vt->read_uint != NULL, false);
86 
87 	return db->vt->read_uint(db, r);
88 }
89 
90 bool
db_read_time(database_handle_t * db,time_t * r)91 db_read_time(database_handle_t *db, time_t *r)
92 {
93 	return_val_if_fail(db != NULL, false);
94 	return_val_if_fail(db->vt != NULL, false);
95 	return_val_if_fail(db->vt->read_time != NULL, false);
96 
97 	return db->vt->read_time(db, r);
98 }
99 
100 const char *
db_sread_word(database_handle_t * db)101 db_sread_word(database_handle_t *db)
102 {
103 	const char *w = db_read_word(db);
104 	if (!w)
105 	{
106 		slog(LG_ERROR, "db-sread-word: needed word at file %s line %d token %d", db->file, db->line, db->token);
107 		slog(LG_ERROR, "db-sread-word: exiting to avoid data loss");
108 		exit(EXIT_FAILURE);
109 	}
110 	return w;
111 }
112 
113 const char *
db_sread_str(database_handle_t * db)114 db_sread_str(database_handle_t *db)
115 {
116 	const char *w = db_read_str(db);
117 	if (!w)
118 	{
119 		slog(LG_ERROR, "db-sread-multiword: needed multiword at file %s line %d token %d", db->file, db->line, db->token);
120 		slog(LG_ERROR, "db-sread-multiword: exiting to avoid data loss");
121 		exit(EXIT_FAILURE);
122 	}
123 	return w;
124 }
125 
126 int
db_sread_int(database_handle_t * db)127 db_sread_int(database_handle_t *db)
128 {
129 	int r;
130 	bool ok = db_read_int(db, &r);
131 
132 	if (!ok)
133 	{
134 		slog(LG_ERROR, "db-read-int: needed int at file %s line %d token %d", db->file, db->line, db->token);
135 		slog(LG_ERROR, "db-read-int: exiting to avoid data loss");
136 		exit(EXIT_FAILURE);
137 	}
138 	return r;
139 }
140 
141 unsigned int
db_sread_uint(database_handle_t * db)142 db_sread_uint(database_handle_t *db)
143 {
144 	unsigned int r;
145 	bool ok = db_read_uint(db, &r);
146 
147 	if (!ok)
148 	{
149 		slog(LG_ERROR, "db-read-uint: needed int at file %s line %d token %d", db->file, db->line, db->token);
150 		slog(LG_ERROR, "db-read-uint: exiting to avoid data loss");
151 		exit(EXIT_FAILURE);
152 	}
153 	return r;
154 }
155 
156 time_t
db_sread_time(database_handle_t * db)157 db_sread_time(database_handle_t *db)
158 {
159 	time_t r;
160 	bool ok = db_read_time(db, &r);
161 
162 	if (!ok)
163 	{
164 		slog(LG_ERROR, "db-read-time: needed int at file %s line %d token %d", db->file, db->line, db->token);
165 		slog(LG_ERROR, "db-read-time: exiting to avoid data loss");
166 		exit(EXIT_FAILURE);
167 	}
168 	return r;
169 }
170 
171 bool
db_start_row(database_handle_t * db,const char * type)172 db_start_row(database_handle_t *db, const char *type)
173 {
174 	return_val_if_fail(db != NULL, false);
175 	return_val_if_fail(db->vt != NULL, false);
176 	return_val_if_fail(db->vt->start_row != NULL, false);
177 
178 	return db->vt->start_row(db, type);
179 }
180 
181 bool
db_write_word(database_handle_t * db,const char * word)182 db_write_word(database_handle_t *db, const char *word)
183 {
184 	return_val_if_fail(db != NULL, false);
185 	return_val_if_fail(db->vt != NULL, false);
186 	return_val_if_fail(db->vt->write_word != NULL, false);
187 
188 	return db->vt->write_word(db, word);
189 }
190 
191 bool
db_write_str(database_handle_t * db,const char * str)192 db_write_str(database_handle_t *db, const char *str)
193 {
194 	return_val_if_fail(db != NULL, false);
195 	return_val_if_fail(db->vt != NULL, false);
196 	return_val_if_fail(db->vt->write_str != NULL, false);
197 
198 	return db->vt->write_str(db, str);
199 }
200 
201 bool
db_write_int(database_handle_t * db,int num)202 db_write_int(database_handle_t *db, int num)
203 {
204 	return_val_if_fail(db != NULL, false);
205 	return_val_if_fail(db->vt != NULL, false);
206 	return_val_if_fail(db->vt->write_int != NULL, false);
207 
208 	return db->vt->write_int(db, num);
209 }
210 
211 bool
db_write_uint(database_handle_t * db,unsigned int num)212 db_write_uint(database_handle_t *db, unsigned int num)
213 {
214 	return_val_if_fail(db != NULL, false);
215 	return_val_if_fail(db->vt != NULL, false);
216 	return_val_if_fail(db->vt->write_uint != NULL, false);
217 
218 	return db->vt->write_uint(db, num);
219 }
220 
221 bool
db_write_time(database_handle_t * db,time_t tm)222 db_write_time(database_handle_t *db, time_t tm)
223 {
224 	return_val_if_fail(db != NULL, false);
225 	return_val_if_fail(db->vt != NULL, false);
226 	return_val_if_fail(db->vt->write_time != NULL, false);
227 
228 	return db->vt->write_time(db, tm);
229 }
230 
231 bool
db_commit_row(database_handle_t * db)232 db_commit_row(database_handle_t *db)
233 {
234 	return_val_if_fail(db != NULL, false);
235 	return_val_if_fail(db->vt != NULL, false);
236 	return_val_if_fail(db->vt->commit_row != NULL, false);
237 
238 	return db->vt->commit_row(db);
239 }
240 
241 void
db_register_type_handler(const char * type,database_handler_f fun)242 db_register_type_handler(const char *type, database_handler_f fun)
243 {
244 	return_if_fail(db_types != NULL);
245 	return_if_fail(type != NULL);
246 	return_if_fail(fun != NULL);
247 
248 	mowgli_patricia_add(db_types, type, fun);
249 }
250 
251 void
db_unregister_type_handler(const char * type)252 db_unregister_type_handler(const char *type)
253 {
254 	return_if_fail(db_types != NULL);
255 	return_if_fail(type != NULL);
256 
257 	mowgli_patricia_delete(db_types, type);
258 }
259 
260 void
db_process(database_handle_t * db,const char * type)261 db_process(database_handle_t *db, const char *type)
262 {
263 	database_handler_f fun;
264 
265 	return_if_fail(db_types != NULL);
266 	return_if_fail(db != NULL);
267 	return_if_fail(type != NULL);
268 
269 	fun = mowgli_patricia_retrieve(db_types, type);
270 
271 	if (!fun)
272 	{
273 		fun = mowgli_patricia_retrieve(db_types, "???");
274 	}
275 
276 	fun(db, type);
277 }
278 
279 bool
db_write_format(database_handle_t * db,const char * fmt,...)280 db_write_format(database_handle_t *db, const char *fmt, ...)
281 {
282 	va_list va;
283 	char buf[BUFSIZE];
284 
285 	va_start(va, fmt);
286 	vsnprintf(buf, BUFSIZE, fmt, va);
287 	va_end(va);
288 
289 	return db_write_word(db, buf);
290 }
291 
292 void
db_init(void)293 db_init(void)
294 {
295 	db_types = mowgli_patricia_create(strcasecanon);
296 
297 	if (db_types == NULL)
298 	{
299 		slog(LG_ERROR, "db_init(): object allocator failure");
300 		exit(EXIT_FAILURE);
301 	}
302 }
303