6 * Copyright (C) 1989 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
13 static char *rcsid_increment_dc = "$Header$";
16 #include <mit-copyright.h>
21 #include "mr_server.h"
24 EXEC SQL INCLUDE sqlca;
27 extern char *table_name[];
28 extern int num_tables;
36 EXEC SQL WHENEVER SQLERROR DO dbmserr();
38 /* structures to save before args */
39 static char *before[MAXARGC];
41 static enum tables beforetable;
43 /* structures to save after args */
44 static char *after[MAXARGC];
47 /* structures to save entire sets of incremental changes */
48 struct save_queue *incremental_sq = NULL;
49 struct save_queue *incremental_exec = NULL;
59 void next_incremental(void);
60 char **copy_argv(char **argv, int argc);
61 void free_argv(char **argv, int argc);
62 int table_num(char *table);
64 void incremental_init(void)
69 incremental_sq = sq_create();
70 if (!incremental_exec)
71 incremental_exec = sq_create();
73 for (i = 0; i < MAXARGC; i++)
75 before[i] = malloc(ARGLEN);
76 after[i] = malloc(ARGLEN);
81 /* record the state of a table row before it is changed */
83 void incremental_before(enum tables table, char *qual, char **argv)
85 EXEC SQL BEGIN DECLARE SECTION;
87 EXEC SQL END DECLARE SECTION;
96 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, u.last, "
97 "u.first, u.middle, u.status, u.clearid, u.type "
98 "FROM users u WHERE %s", qual);
103 sprintf(stmt_buf, "SELECT m.name, m.vendor FROM machine m "
109 sprintf(stmt_buf, "SELECT c.name, c.description, c.location "
110 "FROM clusters c WHERE %s", qual);
115 strcpy(before[0], argv[0]);
116 strcpy(before[1], argv[1]);
120 strcpy(before[0], argv[0]);
121 strcpy(before[1], argv[1]);
122 strcpy(before[2], argv[2]);
126 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
127 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
128 "fs.createflg, fs.lockertype FROM filesys fs WHERE %s", qual);
131 id = atoi(before[2]);
132 id_to_name(id, MACHINE_TABLE, &name);
133 strcpy(before[2], name);
134 id = atoi(before[7]);
135 id_to_name(id, USERS_TABLE, &name);
136 strcpy(before[7], name);
137 id = atoi(before[8]);
138 id_to_name(id, LIST_TABLE, &name);
139 strcpy(before[8], name);
144 strcpy(before[0], "?");
145 strcpy(before[1], argv[1]);
146 strcpy(before[2], "?");
147 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
148 "WHERE %s AND fs.filsys_id = q.filsys_id", qual);
150 strcpy(before[2], argv[1]);
154 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
155 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
156 "l.description FROM list l WHERE %s", qual);
162 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
163 "grouplist, gid FROM list WHERE list_id = %d", id);
166 id_to_name(id, LIST_TABLE, &name);
167 strcpy(before[0], name);
168 strcpy(before[1], argv[1]);
171 if (!strcmp(before[1], "USER"))
173 id_to_name(id, USERS_TABLE, &name);
174 EXEC SQL SELECT status INTO :before[9] FROM users
175 WHERE users_id = :id;
178 else if (!strcmp(before[1], "LIST"))
179 id_to_name(id, LIST_TABLE, &name);
180 else if (!strcmp(before[1], "STRING") || !strcmp(before[1], "KERBEROS"))
181 id_to_name(id, STRINGS_TABLE, &name);
182 strcpy(before[2], name);
187 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
195 void incremental_clear_before(void)
201 /* add an element to the incremental queue for the changed row */
203 void incremental_after(enum tables table, char *qual, char **argv)
206 EXEC SQL BEGIN DECLARE SECTION;
208 EXEC SQL END DECLARE SECTION;
214 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, u.last, "
215 "u.first, u.middle, u.status, u.clearid, u.type "
216 "FROM users u WHERE %s", qual);
221 sprintf(stmt_buf, "SELECT m.name, m.vendor FROM machine m "
227 sprintf(stmt_buf, "SELECT c.name, c.description, c.location "
228 "FROM clusters c WHERE %s", qual);
233 strcpy(after[0], argv[0]);
234 strcpy(after[1], argv[1]);
238 strcpy(after[0], argv[0]);
239 strcpy(after[1], argv[1]);
240 strcpy(after[2], argv[2]);
244 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
245 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
246 "fs.createflg, fs.lockertype FROM filesys fs WHERE %s", qual);
250 id_to_name(id, MACHINE_TABLE, &name);
251 strcpy(after[2], name);
253 id_to_name(id, USERS_TABLE, &name);
254 strcpy(after[7], name);
256 id_to_name(id, LIST_TABLE, &name);
257 strcpy(after[8], name);
262 strcpy(after[0], "?");
263 strcpy(after[1], argv[1]);
264 strcpy(after[2], "?");
265 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
266 "WHERE %s and fs.filsys_id = q.filsys_id and q.type = '%s'",
272 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
273 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
274 "l.description FROM list l WHERE %s", qual);
280 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
281 "grouplist, gid FROM list WHERE list_id = %d", id);
284 id_to_name(id, LIST_TABLE, &name);
285 strcpy(after[0], name);
286 strcpy(after[1], argv[1]);
289 if (!strcmp(after[1], "USER"))
291 id_to_name(id, USERS_TABLE, &name);
292 EXEC SQL SELECT status INTO :after[9] FROM users
293 WHERE users_id = :id;
296 else if (!strcmp(after[1], "LIST"))
297 id_to_name(id, LIST_TABLE, &name);
298 else if (!strcmp(after[1], "STRING") || !strcmp(after[1], "KERBEROS"))
299 id_to_name(id, STRINGS_TABLE, &name);
300 strcpy(after[2], name);
309 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
315 iu = malloc(sizeof(struct iupdate));
316 iu->table = table_name[table];
317 iu->beforec = beforec;
318 iu->before = copy_argv(before, beforec);
320 iu->after = copy_argv(after, afterc);
321 sq_save_data(incremental_sq, iu);
324 void incremental_clear_after(void)
326 incremental_after(NO_TABLE, NULL, NULL);
330 /* Called when the current transaction is committed to start any queued
331 * incremental updates. This caches the update table the first time it
336 struct inc_cache *next;
337 char *table, *service;
341 void incremental_update(void)
343 static int inited = 0;
344 static struct inc_cache *cache;
346 EXEC SQL BEGIN DECLARE SECTION;
347 char tab[17], serv[17];
348 EXEC SQL END DECLARE SECTION;
355 EXEC SQL DECLARE inc CURSOR FOR SELECT table_name, service
360 EXEC SQL FETCH inc INTO :tab, :serv;
363 c = malloc(sizeof(struct inc_cache));
365 c->table = strsave(strtrim(tab));
366 c->service = strsave(strtrim(serv));
370 EXEC SQL COMMIT WORK;
373 while (sq_remove_data(incremental_sq, &iu))
375 for (c = cache; c; c = c->next)
377 if (!strcmp(c->table, iu->table))
379 iu->service = c->service;
380 sq_save_data(incremental_exec, iu);
384 if (inc_running == 0)
389 void next_incremental(void)
392 char *argv[MAXARGC * 2 + 4], cafter[3], cbefore[3], prog[BUFSIZ];
396 if (!incremental_exec)
399 if (sq_empty(incremental_exec) ||
400 (inc_running && now - inc_started < INC_TIMEOUT))
404 com_err(whoami, 0, "incremental timeout on pid %d", inc_pid);
406 sq_remove_data(incremental_exec, &iu);
408 sprintf(cbefore, "%d", iu->beforec);
410 sprintf(cafter, "%d", iu->afterc);
412 for (i = 0; i < iu->beforec; i++)
413 argv[4 + i] = iu->before[i];
414 for (i = 0; i < iu->afterc; i++)
415 argv[4 + iu->beforec + i] = iu->after[i];
417 sprintf(prog, "%s/%s.incr", BIN_DIR, iu->service);
419 argv[4 + iu->beforec + iu->afterc] = 0;
422 sigaddset(&sigs, SIGCHLD);
423 sigprocmask(SIG_BLOCK, &sigs, NULL);
431 com_err(whoami, 0, "Failed to start incremental update");
437 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
439 free_argv(iu->before, iu->beforec);
440 free_argv(iu->after, iu->afterc);
445 /* Called when the current transaction is aborted to throw away any queued
446 * incremental updates
449 void incremental_flush(void)
453 while (sq_get_data(incremental_sq, &iu))
455 free_argv(iu->before, iu->beforec);
456 free_argv(iu->after, iu->afterc);
459 sq_destroy(incremental_sq);
460 incremental_sq = sq_create();
464 char **copy_argv(char **argv, int argc)
466 char **ret = malloc(sizeof(char *) * argc);
468 ret[argc] = strsave(strtrim(argv[argc]));
472 void free_argv(char **argv, int argc)
479 int table_num(char *name)
483 for (i = num_tables - 1; i; i--)
485 if (!strcmp(table_name[i], name))
489 return i; /* 0 = "none" if no match */