ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/databases.c
Revision: 3389
Committed: Fri Apr 25 14:12:15 2014 UTC (9 years, 10 months ago) by michael
Content type: text/x-csrc
File size: 9571 byte(s)
Log Message:
- Imported ircservices-5.1.24

File Contents

# Content
1 /* Database core routines.
2 *
3 * IRC Services is copyright (c) 1996-2009 Andrew Church.
4 * E-mail: <achurch@achurch.org>
5 * Parts written by Andrew Kempe and others.
6 * This program is free but copyrighted software; see the file GPL.txt for
7 * details.
8 */
9
10 #include "services.h"
11 #include "databases.h"
12 #include "encrypt.h"
13 #include "modules.h"
14
15 /*************************************************************************/
16
17 /* List of registered tables */
18 typedef struct dbtablenode_ DBTableNode;
19 struct dbtablenode_ {
20 DBTableNode *next, *prev;
21 DBTable *table;
22 const Module *owner; /* Which module registered this table? */
23 int loaded; /* Has this table been loaded? */
24 };
25 static DBTableNode *tables = NULL;
26
27 /* Currently active database module */
28 static DBModule *dbmodule = NULL;
29
30
31 /* Local routines: */
32 static int do_unload_module(const Module *module);
33
34 /*************************************************************************/
35 /*************************************************************************/
36
37 /* Initialization/cleanup routines. */
38
39 int database_init(int ac, char **av)
40 {
41 if (!add_callback(NULL, "unload module", do_unload_module)) {
42 log("database_init: add_callback() failed");
43 return 0;
44 }
45 return 1;
46 }
47
48 /************************************/
49
50 void database_cleanup(void)
51 {
52 remove_callback(NULL, "unload module", do_unload_module);
53 }
54
55 /************************************/
56
57 /* Check for tables that the module forgot to unload. */
58
59 static int do_unload_module(const Module *module)
60 {
61 DBTableNode *t, *t2;
62
63 LIST_FOREACH_SAFE (t, tables, t2) {
64 if (t->owner == module) {
65 log("database: Module `%s' forgot to unregister table `%s'",
66 get_module_name(module), t->table->name);
67 unregister_dbtable(t->table);
68 }
69 }
70 return 0;
71 }
72
73 /*************************************************************************/
74
75 /* Register a new database table. Returns nonzero on success, zero on
76 * error.
77 */
78
79 int _register_dbtable(DBTable *table, const Module *caller)
80 {
81 DBTableNode *t;
82
83 /* Sanity checks on parameter */
84 if (!table) {
85 log("BUG: register_dbtable() with NULL table!");
86 return 0;
87 }
88 if (!table->name) {
89 log("BUG: register_dbtable(): table->name is NULL!");
90 return 0;
91 }
92 if (!table->fields || !table->newrec || !table->freerec
93 || !table->insert || !table->first || !table->next
94 ) {
95 log("BUG: register_dbtable(%s): table->%s is NULL!", table->name,
96 !table->fields ? "fields" :
97 !table->newrec ? "newrec" :
98 !table->freerec ? "freerec" :
99 !table->insert ? "insert" :
100 !table->first ? "first" :
101 !table->next ? "next" :
102 "???");
103 return 0;
104 }
105
106 /* Sanity check: make sure it's not already registered */
107 LIST_FOREACH (t, tables) {
108 if (t->table == table) {
109 log("BUG: register_dbtable(%s): table already registered!",
110 table->name);
111 break;
112 }
113 }
114
115 /* Allocate and append to list (make sure to preserve order, since
116 * later tables may depend on earlier ones); if a database module is
117 * available, load the table ammediately*/
118 t = smalloc(sizeof(*t));
119 t->table = table;
120 t->owner = caller;
121 t->loaded = 0;
122 LIST_APPEND(t, tables);
123 if (dbmodule)
124 t->loaded = (*dbmodule->load_table)(t->table);
125
126 return 1;
127 }
128
129 /*************************************************************************/
130
131 /* Unregister a database table. Does nothing if the table was not
132 * registered in the first place.
133 */
134
135 void unregister_dbtable(DBTable *table)
136 {
137 DBTableNode *t;
138
139 if (!table) {
140 log("BUG: unregister_dbtable() with NULL table!");
141 return;
142 }
143 /* Sanity check: make sure it was registered first */
144 LIST_FOREACH (t, tables) {
145 if (t->table == table) {
146 LIST_REMOVE(t, tables);
147 free(t);
148 break;
149 }
150 }
151 }
152
153 /*************************************************************************/
154
155 /* Save all registered database tables to permanent storage. Returns 1 if
156 * all tables were successfully saved or no tables are registered, 0 if
157 * some tables were successfully saved (but some were not), or -1 if no
158 * tables were successfully saved.
159 */
160
161 int save_all_dbtables(void)
162 {
163 DBTableNode *t;
164 int some_saved = 0;
165 int some_failed = 0;
166
167 if (!tables)
168 return 1;
169 if (!dbmodule) {
170 log("save_all_dbtables(): No database module registered!");
171 return -1;
172 }
173 LIST_FOREACH (t, tables) {
174 if ((*dbmodule->save_table)(t->table)) {
175 some_saved = 1;
176 } else {
177 log("save_all_dbtables(): Failed to save table `%s'",
178 t->table->name);
179 some_failed = 1;
180 }
181 }
182 return some_saved - some_failed;
183 }
184
185 /*************************************************************************/
186 /*************************************************************************/
187
188 /* Register a database module. Returns nonzero on success, zero on error.
189 * On success, all registered tables which have not already been loaded
190 * will be loaded from permanent storage. Only one database module can be
191 * registered.
192 */
193
194 int register_dbmodule(DBModule *module)
195 {
196 DBTableNode *t;
197
198 if (!module) {
199 log("BUG: register_dbmodule() with NULL module!");
200 return 0;
201 }
202 if (!module->load_table || !module->save_table) {
203 log("BUG: register_dbmodule(): module->%s is NULL!",
204 !module->load_table ? "load_table" : "save_table");
205 return 0;
206 }
207 if (dbmodule) {
208 if (module == dbmodule)
209 log("BUG: register_dbmodule(): attempt to re-register module!");
210 else
211 log("register_dbmodule(): a database module is already registered");
212 return 0;
213 }
214
215 dbmodule = module;
216 LIST_FOREACH (t, tables) {
217 if (!t->loaded)
218 t->loaded = (*dbmodule->load_table)(t->table);
219 }
220 return 1;
221 }
222
223 /*************************************************************************/
224
225 /* Unregister a database module. Does nothing if the module was not
226 * registered in the first place.
227 */
228
229 void unregister_dbmodule(DBModule *module)
230 {
231 if (!module) {
232 log("BUG: unregister_dbmodule() with NULL module!");
233 return;
234 }
235 if (dbmodule == module)
236 dbmodule = NULL;
237 }
238
239 /*************************************************************************/
240
241 /* Read a value from a database field. The value buffer is assumed to be
242 * large enough to hold the retrieved value.
243 */
244
245 void get_dbfield(const void *record, const DBField *field, void *buffer)
246 {
247 int size;
248
249 if (!record || !field || !buffer) {
250 log("BUG: get_dbfield(): %s is NULL!",
251 !record ? "record" : !field ? "field" : "buffer");
252 return;
253 }
254 if (field->get) {
255 (*field->get)(record, buffer);
256 return;
257 }
258 switch (field->type) {
259 case DBTYPE_INT8: size = 1; break;
260 case DBTYPE_UINT8: size = 1; break;
261 case DBTYPE_INT16: size = 2; break;
262 case DBTYPE_UINT16: size = 2; break;
263 case DBTYPE_INT32: size = 4; break;
264 case DBTYPE_UINT32: size = 4; break;
265 case DBTYPE_TIME: size = sizeof(time_t); break;
266 case DBTYPE_STRING: size = sizeof(char *); break;
267 case DBTYPE_BUFFER: size = field->length; break;
268 case DBTYPE_PASSWORD: size = sizeof(Password); break;
269 default:
270 log("BUG: bad field type %d in get_dbfield()", field->type);
271 return;
272 }
273 if (!size) {
274 return;
275 }
276 memcpy(buffer, (const uint8 *)record + field->offset, size);
277 }
278
279 /*************************************************************************/
280
281 /* Store a value to a database field. */
282
283 void put_dbfield(void *record, const DBField *field, const void *value)
284 {
285 int size;
286
287 if (!record || !field || !value) {
288 log("BUG: get_dbfield(): %s is NULL!",
289 !record ? "record" : !field ? "field" : "value");
290 return;
291 }
292 if (field->put) {
293 (*field->put)(record, value);
294 return;
295 }
296 switch (field->type) {
297 case DBTYPE_INT8: size = 1; break;
298 case DBTYPE_UINT8: size = 1; break;
299 case DBTYPE_INT16: size = 2; break;
300 case DBTYPE_UINT16: size = 2; break;
301 case DBTYPE_INT32: size = 4; break;
302 case DBTYPE_UINT32: size = 4; break;
303 case DBTYPE_TIME: size = sizeof(time_t); break;
304 case DBTYPE_STRING: size = sizeof(char *); break;
305 case DBTYPE_BUFFER: size = field->length; break;
306 case DBTYPE_PASSWORD: size = sizeof(Password); break;
307 default:
308 log("BUG: bad field type %d in get_dbfield()", field->type);
309 return;
310 }
311 if (!size) {
312 return;
313 }
314 memcpy((uint8 *)record + field->offset, value, size);
315 }
316
317 /*************************************************************************/
318
319 /*
320 * Local variables:
321 * c-file-style: "stroustrup"
322 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
323 * indent-tabs-mode: nil
324 * End:
325 *
326 * vim: expandtab shiftwidth=4:
327 */