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)
68 if (incremental_sq == NULL)
69 incremental_sq = sq_create();
70 if (incremental_exec == NULL)
71 incremental_exec = sq_create();
73 for(i=0; i<MAXARGC; i++) {
74 before[i]=malloc(ARGLEN);
75 after[i]=malloc(ARGLEN);
80 /* record the state of a table row before it is changed */
82 void incremental_before(table, qual, argv)
84 EXEC SQL BEGIN DECLARE SECTION;
86 EXEC SQL END DECLARE SECTION;
88 EXEC SQL BEGIN DECLARE SECTION;
90 EXEC SQL END DECLARE SECTION;
99 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, u.last, "
100 "u.first, u.middle, u.status, u.clearid, u.type "
101 "FROM users u WHERE %s", qual);
106 sprintf(stmt_buf, "SELECT m.name, m.vendor FROM machine m "
112 sprintf(stmt_buf, "SELECT c.name, c.description, c.location "
113 "FROM clusters c WHERE %s", qual);
118 strcpy(before[0], argv[0]);
119 strcpy(before[1], argv[1]);
123 strcpy(before[0], argv[0]);
124 strcpy(before[1], argv[1]);
125 strcpy(before[2], argv[2]);
129 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
130 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
131 "fs.createflg, fs.lockertype FROM filesys fs WHERE %s", qual);
134 id = atoi(before[2]);
135 id_to_name(id, MACHINE_TABLE, &name);
136 strcpy(before[2], name);
137 id = atoi(before[7]);
138 id_to_name(id, USERS_TABLE, &name);
139 strcpy(before[7], name);
140 id = atoi(before[8]);
141 id_to_name(id, LIST_TABLE, &name);
142 strcpy(before[8], name);
147 strcpy(before[0], "?");
148 strcpy(before[1], argv[1]);
149 strcpy(before[2], "?");
150 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
151 "WHERE %s AND fs.filsys_id = q.filsys_id", qual);
153 strcpy(before[2], argv[1]);
157 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
158 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
159 "l.description FROM list l WHERE %s", qual);
165 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
166 "grouplist, gid FROM list WHERE list_id = %d", id);
169 id_to_name(id, LIST_TABLE, &name);
170 strcpy(before[0], name);
171 strcpy(before[1], argv[1]);
174 if (!strcmp(before[1], "USER")) {
175 id_to_name(id, USERS_TABLE, &name);
176 EXEC SQL SELECT status INTO :before[9] FROM users
179 } else if (!strcmp(before[1], "LIST")) {
180 id_to_name(id, LIST_TABLE, &name);
181 } else if (!strcmp(before[1], "STRING") || !strcmp(before[1], "KERBEROS")) {
182 id_to_name(id, STRINGS_TABLE, &name);
184 strcpy(before[2], name);
189 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
197 void incremental_clear_before(void)
203 /* add an element to the incremental queue for the changed row */
205 void incremental_after(table, qual, argv)
207 EXEC SQL BEGIN DECLARE SECTION;
209 EXEC SQL END DECLARE SECTION;
215 EXEC SQL BEGIN DECLARE SECTION;
217 EXEC SQL END DECLARE SECTION;
223 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, u.last, "
224 "u.first, u.middle, u.status, u.clearid, u.type "
225 "FROM users u WHERE %s", qual);
230 sprintf(stmt_buf, "SELECT m.name, m.vendor FROM machine m "
236 sprintf(stmt_buf, "SELECT c.name, c.description, c.location "
237 "FROM clusters c WHERE %s", qual);
242 strcpy(after[0], argv[0]);
243 strcpy(after[1], argv[1]);
247 strcpy(after[0], argv[0]);
248 strcpy(after[1], argv[1]);
249 strcpy(after[2], argv[2]);
253 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
254 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
255 "fs.createflg, fs.lockertype FROM filesys fs WHERE %s", qual);
259 id_to_name(id, MACHINE_TABLE, &name);
260 strcpy(after[2], name);
262 id_to_name(id, USERS_TABLE, &name);
263 strcpy(after[7], name);
265 id_to_name(id, LIST_TABLE, &name);
266 strcpy(after[8], name);
271 strcpy(after[0], "?");
272 strcpy(after[1], argv[1]);
273 strcpy(after[2], "?");
274 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
275 "WHERE %s and fs.filsys_id = q.filsys_id and q.type = '%s'",
281 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
282 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
283 "l.description FROM list l WHERE %s", qual);
289 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
290 "grouplist, gid FROM list WHERE list_id = %d", id);
293 id_to_name(id, LIST_TABLE, &name);
294 strcpy(after[0], name);
295 strcpy(after[1], argv[1]);
298 if (!strcmp(after[1], "USER")) {
299 id_to_name(id, USERS_TABLE, &name);
300 EXEC SQL SELECT status INTO :after[9] FROM users
303 } else if (!strcmp(after[1], "LIST")) {
304 id_to_name(id, LIST_TABLE, &name);
305 } else if (!strcmp(after[1], "STRING") || !strcmp(after[1], "KERBEROS")) {
306 id_to_name(id, STRINGS_TABLE, &name);
308 strcpy(after[2], name);
317 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
323 iu = (struct iupdate *) malloc(sizeof(struct iupdate));
324 iu->table = table_name[table];
325 iu->beforec = beforec;
326 iu->before = copy_argv(before, beforec);
328 iu->after = copy_argv(after, afterc);
329 sq_save_data(incremental_sq, iu);
332 sprintf(buffer, "INCREMENTAL(%s, [", table_name[table]);
333 for (i = 0; i < beforec; i++) {
335 strcat(buffer, strtrim(before[0]));
337 strcat(buffer, ", ");
338 strcat(buffer, strtrim(before[i]));
341 strcat(buffer, "], [");
342 for (i = 0; i < afterc; i++) {
344 strcat(buffer, strtrim(after[0]));
346 strcat(buffer, ", ");
347 strcat(buffer, strtrim(after[i]));
350 strcat(buffer, "])");
351 com_err(whoami, 0, buffer);
355 void incremental_clear_after(void)
357 incremental_after(NO_TABLE, NULL, NULL);
361 /* Called when the current transaction is committed to start any queued
362 * incremental updates. This caches the update table the first time it
367 struct inc_cache *next;
368 char *table, *service;
372 void incremental_update(void)
374 static int inited = 0;
375 static struct inc_cache *cache;
377 EXEC SQL BEGIN DECLARE SECTION;
378 char tab[17], serv[17];
379 EXEC SQL END DECLARE SECTION;
385 EXEC SQL DECLARE inc CURSOR FOR SELECT table_name, service FROM incremental;
388 EXEC SQL FETCH inc INTO :tab, :serv;
389 if (sqlca.sqlcode != 0) break;
390 c = (struct inc_cache *)malloc(sizeof(struct inc_cache));
392 c->table = strsave(strtrim(tab));
393 c->service = strsave(strtrim(serv));
397 EXEC SQL COMMIT WORK;
400 while (sq_remove_data(incremental_sq, &iu)) {
401 for (c = cache; c; c = c->next) {
402 if (!strcmp(c->table, iu->table)) {
403 iu->service = c->service;
404 sq_save_data(incremental_exec, iu);
408 if (inc_running == 0)
413 void next_incremental(void)
416 char *argv[MAXARGC * 2 + 4], cafter[3], cbefore[3], prog[BUFSIZ];
420 if (incremental_exec == NULL)
423 if (sq_empty(incremental_exec) ||
424 (inc_running && now - inc_started < INC_TIMEOUT))
428 com_err(whoami, 0, "incremental timeout on pid %d", inc_pid);
430 sq_remove_data(incremental_exec, &iu);
432 sprintf(cbefore, "%d", iu->beforec);
434 sprintf(cafter, "%d", iu->afterc);
436 for (i = 0; i < iu->beforec; i++)
437 argv[4 + i] = iu->before[i];
438 for (i = 0; i < iu->afterc; i++)
439 argv[4 + iu->beforec + i] = iu->after[i];
441 sprintf(prog, "%s/%s.incr", BIN_DIR, iu->service);
443 com_err(whoami, 0, "forking %s", prog);
446 argv[4 + iu->beforec + iu->afterc] = 0;
449 sigaddset(&sigs, SIGCHLD);
450 sigprocmask(SIG_BLOCK, &sigs, NULL);
457 com_err(whoami, 0, "Failed to start incremental update");
463 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
465 free_argv(iu->before, iu->beforec);
466 free_argv(iu->after, iu->afterc);
472 /* Called when the current transaction is aborted to throw away any queued
473 * incremental updates
476 void incremental_flush(void)
480 while (sq_get_data(incremental_sq, &iu)) {
481 free_argv(iu->before, iu->beforec);
482 free_argv(iu->after, iu->afterc);
485 sq_destroy(incremental_sq);
486 incremental_sq = sq_create();
490 char **copy_argv(argv, argc)
494 char **ret = (char **)malloc(sizeof(char *) * argc);
496 ret[argc] = strsave(strtrim(argv[argc]));
500 void free_argv(argv, argc)
509 int table_num(char *name)
513 for(i = num_tables-1; i; i--)
514 if(!strcmp(table_name[i], name)) break;
516 return i; /* 0 = "none" if no match */