3 * Deal with incremental updates
5 * Copyright (C) 1989-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
10 #include <mit-copyright.h>
11 #include "mr_server.h"
20 EXEC SQL INCLUDE sqlca;
25 extern char *table_name[];
26 extern int num_tables;
34 EXEC SQL WHENEVER SQLERROR DO dbmserr();
36 /* structures to save before args */
37 static char *before[MAXARGC];
39 static enum tables beforetable;
41 /* structures to save after args */
42 static char *after[MAXARGC];
45 /* structures to save entire sets of incremental changes */
46 struct save_queue *incremental_sq = NULL;
47 struct save_queue *incremental_exec = NULL;
57 void next_incremental(void);
58 char **copy_argv(char **argv, int argc);
59 void free_argv(char **argv, int argc);
60 int table_num(char *table);
62 void incremental_init(void)
67 incremental_sq = sq_create();
68 if (!incremental_exec)
69 incremental_exec = sq_create();
71 for (i = 0; i < MAXARGC; i++)
73 before[i] = malloc(ARGLEN);
74 after[i] = malloc(ARGLEN);
79 /* record the state of a table row before it is changed */
81 void incremental_before(enum tables table, char *qual, char **argv)
83 EXEC SQL BEGIN DECLARE SECTION;
85 EXEC SQL END DECLARE SECTION;
94 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, u.last, "
95 "u.first, u.middle, u.status, u.clearid, u.type "
96 "FROM users u WHERE %s", qual);
101 sprintf(stmt_buf, "SELECT m.name, m.vendor FROM machine m "
107 sprintf(stmt_buf, "SELECT c.name, c.description, c.location "
108 "FROM clusters c WHERE %s", qual);
113 strcpy(before[0], argv[0]);
114 strcpy(before[1], argv[1]);
118 strcpy(before[0], argv[0]);
119 strcpy(before[1], argv[1]);
120 strcpy(before[2], argv[2]);
124 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
125 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
126 "fs.createflg, fs.lockertype FROM filesys fs WHERE %s", qual);
129 id = atoi(before[2]);
130 id_to_name(id, MACHINE_TABLE, &name);
131 strcpy(before[2], name);
132 id = atoi(before[7]);
133 id_to_name(id, USERS_TABLE, &name);
134 strcpy(before[7], name);
135 id = atoi(before[8]);
136 id_to_name(id, LIST_TABLE, &name);
137 strcpy(before[8], name);
142 strcpy(before[0], "?");
143 strcpy(before[1], argv[1]);
144 strcpy(before[2], "?");
145 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
146 "WHERE %s AND fs.filsys_id = q.filsys_id", qual);
148 strcpy(before[2], argv[1]);
152 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
153 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
154 "l.description FROM list l WHERE %s", qual);
160 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
161 "grouplist, gid FROM list WHERE list_id = %d", id);
164 id_to_name(id, LIST_TABLE, &name);
165 strcpy(before[0], name);
166 strcpy(before[1], argv[1]);
169 if (!strcmp(before[1], "USER"))
171 id_to_name(id, USERS_TABLE, &name);
172 EXEC SQL SELECT status INTO :before[9] FROM users
173 WHERE users_id = :id;
176 else if (!strcmp(before[1], "LIST"))
177 id_to_name(id, LIST_TABLE, &name);
178 else if (!strcmp(before[1], "STRING") || !strcmp(before[1], "KERBEROS"))
179 id_to_name(id, STRINGS_TABLE, &name);
180 strcpy(before[2], name);
185 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
193 void incremental_clear_before(void)
199 /* add an element to the incremental queue for the changed row */
201 void incremental_after(enum tables table, char *qual, char **argv)
204 EXEC SQL BEGIN DECLARE SECTION;
206 EXEC SQL END DECLARE SECTION;
212 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, u.last, "
213 "u.first, u.middle, u.status, u.clearid, u.type "
214 "FROM users u WHERE %s", qual);
219 sprintf(stmt_buf, "SELECT m.name, m.vendor FROM machine m "
225 sprintf(stmt_buf, "SELECT c.name, c.description, c.location "
226 "FROM clusters c WHERE %s", qual);
231 strcpy(after[0], argv[0]);
232 strcpy(after[1], argv[1]);
236 strcpy(after[0], argv[0]);
237 strcpy(after[1], argv[1]);
238 strcpy(after[2], argv[2]);
242 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
243 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
244 "fs.createflg, fs.lockertype FROM filesys fs WHERE %s", qual);
248 id_to_name(id, MACHINE_TABLE, &name);
249 strcpy(after[2], name);
251 id_to_name(id, USERS_TABLE, &name);
252 strcpy(after[7], name);
254 id_to_name(id, LIST_TABLE, &name);
255 strcpy(after[8], name);
260 strcpy(after[0], "?");
261 strcpy(after[1], argv[1]);
262 strcpy(after[2], "?");
263 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
264 "WHERE %s and fs.filsys_id = q.filsys_id and q.type = '%s'",
270 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
271 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
272 "l.description FROM list l WHERE %s", qual);
278 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
279 "grouplist, gid FROM list WHERE list_id = %d", id);
282 id_to_name(id, LIST_TABLE, &name);
283 strcpy(after[0], name);
284 strcpy(after[1], argv[1]);
287 if (!strcmp(after[1], "USER"))
289 id_to_name(id, USERS_TABLE, &name);
290 EXEC SQL SELECT status INTO :after[9] FROM users
291 WHERE users_id = :id;
294 else if (!strcmp(after[1], "LIST"))
295 id_to_name(id, LIST_TABLE, &name);
296 else if (!strcmp(after[1], "STRING") || !strcmp(after[1], "KERBEROS"))
297 id_to_name(id, STRINGS_TABLE, &name);
298 strcpy(after[2], name);
307 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
313 iu = malloc(sizeof(struct iupdate));
314 iu->table = table_name[table];
315 iu->beforec = beforec;
316 iu->before = copy_argv(before, beforec);
318 iu->after = copy_argv(after, afterc);
319 sq_save_data(incremental_sq, iu);
322 void incremental_clear_after(void)
324 incremental_after(NO_TABLE, NULL, NULL);
328 /* Called when the current transaction is committed to start any queued
329 * incremental updates. This caches the update table the first time it
334 struct inc_cache *next;
335 char *table, *service;
339 void incremental_update(void)
341 static int inited = 0;
342 static struct inc_cache *cache;
344 EXEC SQL BEGIN DECLARE SECTION;
345 char tab[17], serv[17];
346 EXEC SQL END DECLARE SECTION;
353 EXEC SQL DECLARE inc CURSOR FOR SELECT table_name, service
358 EXEC SQL FETCH inc INTO :tab, :serv;
361 c = malloc(sizeof(struct inc_cache));
363 c->table = strdup(strtrim(tab));
364 c->service = strdup(strtrim(serv));
368 EXEC SQL COMMIT WORK;
371 while (sq_remove_data(incremental_sq, &iu))
373 for (c = cache; c; c = c->next)
375 if (!strcmp(c->table, iu->table))
377 iu->service = c->service;
378 sq_save_data(incremental_exec, iu);
382 if (inc_running == 0)
387 void next_incremental(void)
390 char *argv[MAXARGC * 2 + 4], cafter[3], cbefore[3], prog[BUFSIZ];
394 if (!incremental_exec)
397 if (sq_empty(incremental_exec) ||
398 (inc_running && now - inc_started < INC_TIMEOUT))
402 com_err(whoami, 0, "incremental timeout on pid %d", inc_pid);
404 sq_remove_data(incremental_exec, &iu);
406 sprintf(cbefore, "%d", iu->beforec);
408 sprintf(cafter, "%d", iu->afterc);
410 for (i = 0; i < iu->beforec; i++)
411 argv[4 + i] = iu->before[i];
412 for (i = 0; i < iu->afterc; i++)
413 argv[4 + iu->beforec + i] = iu->after[i];
415 sprintf(prog, "%s/%s.incr", BIN_DIR, iu->service);
417 argv[4 + iu->beforec + iu->afterc] = 0;
420 sigaddset(&sigs, SIGCHLD);
421 sigprocmask(SIG_BLOCK, &sigs, NULL);
429 com_err(whoami, 0, "Failed to start incremental update");
435 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
437 free_argv(iu->before, iu->beforec);
438 free_argv(iu->after, iu->afterc);
443 /* Called when the current transaction is aborted to throw away any queued
444 * incremental updates
447 void incremental_flush(void)
451 while (sq_get_data(incremental_sq, &iu))
453 free_argv(iu->before, iu->beforec);
454 free_argv(iu->after, iu->afterc);
457 sq_destroy(incremental_sq);
458 incremental_sq = sq_create();
462 char **copy_argv(char **argv, int argc)
464 char **ret = malloc(sizeof(char *) * argc);
466 ret[argc] = strdup(strtrim(argv[argc]));
470 void free_argv(char **argv, int argc)
477 int table_num(char *name)
481 for (i = num_tables - 1; i; i--)
483 if (!strcmp(table_name[i], name))
487 return i; /* 0 = "none" if no match */