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"
21 EXEC SQL INCLUDE sqlca;
26 extern char *table_name[];
27 extern int num_tables;
35 EXEC SQL WHENEVER SQLERROR DO dbmserr();
37 /* structures to save before args */
38 static char *before[MAXARGC];
40 static enum tables beforetable;
42 /* structures to save after args */
43 static char *after[MAXARGC];
46 /* structures to save entire sets of incremental changes */
47 struct save_queue *incremental_sq = NULL;
48 struct save_queue *incremental_exec = NULL;
58 void next_incremental(void);
59 char **copy_argv(char **argv, int argc);
60 void free_argv(char **argv, int argc);
61 int table_num(char *table);
63 void incremental_init(void)
68 incremental_sq = sq_create();
69 if (!incremental_exec)
70 incremental_exec = sq_create();
72 for (i = 0; i < MAXARGC; i++)
74 before[i] = xmalloc(MAX_FIELD_WIDTH);
75 after[i] = xmalloc(MAX_FIELD_WIDTH);
80 /* record the state of a table row before it is changed */
82 void incremental_before(enum tables table, char *qual, char **argv)
84 EXEC SQL BEGIN DECLARE SECTION;
86 EXEC SQL END DECLARE SECTION;
95 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, "
96 "u.winconsoleshell, u.last, u.first, u.middle, u.status, "
97 "u.clearid, u.type FROM users u WHERE %s", qual);
102 sprintf(stmt_buf, "SELECT m.name, m.vendor FROM machine m "
108 sprintf(stmt_buf, "SELECT c.name, c.description, c.location "
109 "FROM clusters c WHERE %s", qual);
114 strcpy(before[0], argv[0]);
115 strcpy(before[1], argv[1]);
119 strcpy(before[0], argv[0]);
120 strcpy(before[1], argv[1]);
121 strcpy(before[2], argv[2]);
125 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
126 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
127 "fs.createflg, fs.lockertype FROM filesys fs WHERE %s", qual);
130 id = atoi(before[2]);
131 id_to_name(id, MACHINE_TABLE, &name);
132 strcpy(before[2], name);
133 id = atoi(before[7]);
134 id_to_name(id, USERS_TABLE, &name);
135 strcpy(before[7], name);
136 id = atoi(before[8]);
137 id_to_name(id, LIST_TABLE, &name);
138 strcpy(before[8], name);
143 strcpy(before[0], "?");
144 strcpy(before[1], argv[1]);
145 strcpy(before[2], "?");
146 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
147 "WHERE %s AND fs.filsys_id = q.filsys_id", qual);
149 strcpy(before[2], argv[1]);
153 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
154 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
155 "l.description FROM list l WHERE %s", qual);
161 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
162 "grouplist, gid FROM list WHERE list_id = %d", id);
165 id_to_name(id, LIST_TABLE, &name);
166 strcpy(before[0], name);
167 strcpy(before[1], argv[1]);
170 if (!strcmp(before[1], "USER"))
172 id_to_name(id, USERS_TABLE, &name);
173 EXEC SQL SELECT status INTO :before[9] FROM users
174 WHERE users_id = :id;
177 else if (!strcmp(before[1], "LIST"))
178 id_to_name(id, LIST_TABLE, &name);
179 else if (!strcmp(before[1], "STRING") || !strcmp(before[1], "KERBEROS"))
180 id_to_name(id, STRINGS_TABLE, &name);
181 strcpy(before[2], name);
186 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
194 void incremental_clear_before(void)
200 /* add an element to the incremental queue for the changed row */
202 void incremental_after(enum tables table, char *qual, char **argv)
205 EXEC SQL BEGIN DECLARE SECTION;
207 EXEC SQL END DECLARE SECTION;
213 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, "
214 "u.winconsoleshell, u.last, u.first, u.middle, u.status, "
215 "u.clearid, u.type FROM users u WHERE %s", qual);
220 sprintf(stmt_buf, "SELECT m.name, m.vendor FROM machine m "
226 sprintf(stmt_buf, "SELECT c.name, c.description, c.location "
227 "FROM clusters c WHERE %s", qual);
232 strcpy(after[0], argv[0]);
233 strcpy(after[1], argv[1]);
237 strcpy(after[0], argv[0]);
238 strcpy(after[1], argv[1]);
239 strcpy(after[2], argv[2]);
243 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
244 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
245 "fs.createflg, fs.lockertype FROM filesys fs WHERE %s", qual);
249 id_to_name(id, MACHINE_TABLE, &name);
250 strcpy(after[2], name);
252 id_to_name(id, USERS_TABLE, &name);
253 strcpy(after[7], name);
255 id_to_name(id, LIST_TABLE, &name);
256 strcpy(after[8], name);
261 strcpy(after[0], "?");
262 strcpy(after[1], argv[1]);
263 strcpy(after[2], "?");
264 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
265 "WHERE %s and fs.filsys_id = q.filsys_id and q.type = '%s'",
271 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
272 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
273 "l.description FROM list l WHERE %s", qual);
279 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
280 "grouplist, gid FROM list WHERE list_id = %d", id);
283 id_to_name(id, LIST_TABLE, &name);
284 strcpy(after[0], name);
285 strcpy(after[1], argv[1]);
288 if (!strcmp(after[1], "USER"))
290 id_to_name(id, USERS_TABLE, &name);
291 EXEC SQL SELECT status INTO :after[9] FROM users
292 WHERE users_id = :id;
295 else if (!strcmp(after[1], "LIST"))
296 id_to_name(id, LIST_TABLE, &name);
297 else if (!strcmp(after[1], "STRING") || !strcmp(after[1], "KERBEROS"))
298 id_to_name(id, STRINGS_TABLE, &name);
299 strcpy(after[2], name);
308 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
314 iu = xmalloc(sizeof(struct iupdate));
315 iu->table = table_name[table];
316 iu->beforec = beforec;
317 iu->before = copy_argv(before, beforec);
319 iu->after = copy_argv(after, afterc);
320 sq_save_data(incremental_sq, iu);
323 void incremental_clear_after(void)
325 incremental_after(NO_TABLE, NULL, NULL);
329 /* Called when the current transaction is committed to start any queued
330 * incremental updates. This caches the update table the first time it
335 struct inc_cache *next;
336 char *table, *service;
340 void incremental_update(void)
342 static int inited = 0;
343 static struct inc_cache *cache;
345 EXEC SQL BEGIN DECLARE SECTION;
346 char tab[INCREMENTAL_TABLE_NAME_SIZE], serv[INCREMENTAL_SERVICE_SIZE];
347 EXEC SQL END DECLARE SECTION;
348 struct iupdate *iu, *iu_save;
354 EXEC SQL DECLARE inc CURSOR FOR SELECT table_name, service
359 EXEC SQL FETCH inc INTO :tab, :serv;
362 c = xmalloc(sizeof(struct inc_cache));
364 c->table = xstrdup(strtrim(tab));
365 c->service = xstrdup(strtrim(serv));
369 EXEC SQL COMMIT WORK;
372 while (sq_remove_data(incremental_sq, &iu))
374 for (c = cache; c; c = c->next)
376 if (!strcmp(c->table, iu->table))
378 iu->service = c->service;
379 iu_save = xmalloc(sizeof(struct iupdate));
380 iu_save->service = iu->service;
381 iu_save->table = iu->table;
382 iu_save->beforec = iu->beforec;
383 iu_save->afterc = iu->afterc;
384 iu_save->before = copy_argv(iu->before, iu->beforec);
385 iu_save->after = copy_argv(iu->after, iu->afterc);
386 sq_save_data(incremental_exec, iu_save);
391 free_argv(iu->before, iu->beforec);
392 free_argv(iu->after, iu->afterc);
396 if (inc_running == 0)
400 /* Pro*C 2.2.4 can't cope with the sigset_t below, at least in Solaris 2.6.
401 We add DEFINE=_PROC_ to the proc invocation and then #ifndef that around
402 this function so proc will pass it through without reading it. */
405 void next_incremental(void)
408 char *argv[MAXARGC * 2 + 4], cafter[3], cbefore[3], prog[MAXPATHLEN];
412 if (!incremental_exec)
415 if (sq_empty(incremental_exec) ||
416 (inc_running && now - inc_started < INC_TIMEOUT))
420 com_err(whoami, 0, "incremental timeout on pid %d", inc_pid);
422 sq_remove_data(incremental_exec, &iu);
424 sprintf(cbefore, "%d", iu->beforec);
426 sprintf(cafter, "%d", iu->afterc);
428 for (i = 0; i < iu->beforec; i++)
429 argv[4 + i] = iu->before[i];
430 for (i = 0; i < iu->afterc; i++)
431 argv[4 + iu->beforec + i] = iu->after[i];
433 sprintf(prog, "%s/%s.incr", BIN_DIR, iu->service);
435 argv[4 + iu->beforec + iu->afterc] = 0;
438 sigaddset(&sigs, SIGCHLD);
439 sigprocmask(SIG_BLOCK, &sigs, NULL);
447 com_err(whoami, 0, "Failed to start incremental update");
453 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
455 free_argv(iu->before, iu->beforec);
456 free_argv(iu->after, iu->afterc);
461 /* Called when the current transaction is aborted to throw away any queued
462 * incremental updates
465 void incremental_flush(void)
469 while (sq_get_data(incremental_sq, &iu))
471 free_argv(iu->before, iu->beforec);
472 free_argv(iu->after, iu->afterc);
475 sq_destroy(incremental_sq);
476 incremental_sq = sq_create();
480 char **copy_argv(char **argv, int argc)
482 char **ret = xmalloc(sizeof(char *) * argc);
484 ret[argc] = xstrdup(strtrim(argv[argc]));
488 void free_argv(char **argv, int argc)
495 int table_num(char *name)
499 for (i = num_tables - 1; i; i--)
501 if (!strcmp(table_name[i], name))
505 return i; /* 0 = "none" if no match */