]> andersk Git - moira.git/blame - server/increment.pc
First cut of mailman support.
[moira.git] / server / increment.pc
CommitLineData
7ac48069 1/* $Id$
32cfe906 2 *
7ac48069 3 * Deal with incremental updates
5eaef520 4 *
7ac48069 5 * Copyright (C) 1989-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
32cfe906 8 */
9
32cfe906 10#include <mit-copyright.h>
32cfe906 11#include "mr_server.h"
03c05291 12#include "query.h"
13#include "qrtn.h"
7ac48069 14
15#include <signal.h>
85330553 16#include <stdio.h>
7ac48069 17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
20
45bf7573 21EXEC SQL INCLUDE sqlca;
32cfe906 22
7ac48069 23RCSID("$Header$");
24
32cfe906 25extern char *whoami;
03c05291 26extern char *table_name[];
27extern int num_tables;
32cfe906 28
29int inc_pid = 0;
30int inc_running = 0;
31time_t inc_started;
32
33#define MAXARGC 15
34
03c05291 35EXEC SQL WHENEVER SQLERROR DO dbmserr();
45bf7573 36
066fdd26 37EXEC SQL BEGIN DECLARE SECTION;
32cfe906 38/* structures to save before args */
32cfe906 39static char *before[MAXARGC];
32cfe906 40static int beforec;
03c05291 41static enum tables beforetable;
32cfe906 42
43/* structures to save after args */
32cfe906 44static char *after[MAXARGC];
32cfe906 45static int afterc;
066fdd26 46EXEC SQL END DECLARE SECTION;
32cfe906 47
48/* structures to save entire sets of incremental changes */
49struct save_queue *incremental_sq = NULL;
50struct save_queue *incremental_exec = NULL;
51struct iupdate {
5eaef520 52 char *table;
53 int beforec;
54 char **before;
55 int afterc;
56 char **after;
57 char *service;
32cfe906 58};
59
03c05291 60void next_incremental(void);
fc053494 61char **copy_argv(char **argv, int argc);
03c05291 62void free_argv(char **argv, int argc);
63int table_num(char *table);
32cfe906 64
03c05291 65void incremental_init(void)
32cfe906 66{
5eaef520 67 int i;
32cfe906 68
5eaef520 69 if (!incremental_sq)
70 incremental_sq = sq_create();
71 if (!incremental_exec)
72 incremental_exec = sq_create();
03c05291 73
5eaef520 74 for (i = 0; i < MAXARGC; i++)
75 {
e688520a 76 before[i] = xmalloc(MAX_FIELD_WIDTH);
77 after[i] = xmalloc(MAX_FIELD_WIDTH);
03c05291 78 }
32cfe906 79}
80
81
03c05291 82/* record the state of a table row before it is changed */
83
5eaef520 84void incremental_before(enum tables table, char *qual, char **argv)
32cfe906 85{
5eaef520 86 EXEC SQL BEGIN DECLARE SECTION;
87 int id;
88 EXEC SQL END DECLARE SECTION;
89
88acd4d3 90 char *name, *name2;
5eaef520 91
92 beforetable = table;
93
94 switch (table)
95 {
96 case USERS_TABLE:
d6759517 97 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, "
98 "u.winconsoleshell, u.last, u.first, u.middle, u.status, "
88acd4d3 99 "u.clearid, u.type, u.users_id FROM users u WHERE %s", qual);
5eaef520 100 dosql(before);
88acd4d3 101 beforec = 11;
5eaef520 102 break;
103 case MACHINE_TABLE:
88acd4d3 104 sprintf(stmt_buf, "SELECT m.name, m.vendor, m.mach_id FROM machine m "
5eaef520 105 "WHERE %s", qual);
106 dosql(before);
88acd4d3 107 beforec = 3;
5eaef520 108 break;
e688520a 109 case CLUSTERS_TABLE:
88acd4d3 110 sprintf(stmt_buf, "SELECT c.name, c.description, c.location, "
111 "c.clu_id FROM clusters c WHERE %s", qual);
5eaef520 112 dosql(before);
88acd4d3 113 beforec = 4;
5eaef520 114 break;
bb5c9457 115 case CONTAINERS_TABLE:
116 sprintf(stmt_buf, "SELECT c.name, c.description, c.location, c.contact, "
73155abd 117 "c.acl_type, c.acl_id, c.cnt_id, c.list_id FROM containers c "
118 "WHERE %s", qual);
bb5c9457 119 dosql(before);
73155abd 120 beforec = 8;
429aec78 121 name = xmalloc(0);
122 id = atoi(before[5]);
123 if (!strncmp(before[4], "USER", 4))
124 {
125 id_to_name(id, USERS_TABLE, &name);
126 strcpy(before[5], name);
127 }
128 else if (!strncmp(before[4], "LIST", 4))
129 {
130 id_to_name(id, LIST_TABLE, &name);
131 strcpy(before[5], name);
132 }
133 else if (!strncmp(before[4], "KERBEROS", 8))
134 {
135 id_to_name(id, STRINGS_TABLE, &name);
136 strcpy(before[5], name);
137 }
73155abd 138 id = atoi(before[7]);
139 id_to_name(id, LIST_TABLE, &name);
140 strcpy(before[7], name);
bb5c9457 141 break;
5eaef520 142 case MCMAP_TABLE:
143 strcpy(before[0], argv[0]);
144 strcpy(before[1], argv[1]);
145 beforec = 2;
146 break;
b227bf97 147 case MCNTMAP_TABLE:
148 strcpy(before[0], argv[0]);
149 strcpy(before[1], argv[1]);
150 name_to_id(before[0], MACHINE_TABLE, &id);
151 sprintf(before[2], "%d", id);
152 name_to_id(before[1], CONTAINERS_TABLE, &id);
153 sprintf(before[3], "%d", id);
73155abd 154 name = xmalloc(0);
155 EXEC SQL SELECT list_id INTO :before[4] FROM containers
156 WHERE cnt_id = :id;
157 id = atoi(before[4]);
158 id_to_name(id, LIST_TABLE, &name);
159 strcpy(before[4], name);
160 beforec = 5;
b227bf97 161 break;
5eaef520 162 case SVC_TABLE:
163 strcpy(before[0], argv[0]);
164 strcpy(before[1], argv[1]);
165 strcpy(before[2], argv[2]);
166 beforec = 3;
167 break;
168 case FILESYS_TABLE:
169 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
170 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
88acd4d3 171 "fs.createflg, fs.lockertype, fs.filsys_id FROM filesys fs "
172 "WHERE %s", qual);
5eaef520 173 dosql(before);
88acd4d3 174 name = xmalloc(0);
5eaef520 175 id = atoi(before[2]);
176 id_to_name(id, MACHINE_TABLE, &name);
177 strcpy(before[2], name);
178 id = atoi(before[7]);
179 id_to_name(id, USERS_TABLE, &name);
180 strcpy(before[7], name);
181 id = atoi(before[8]);
182 id_to_name(id, LIST_TABLE, &name);
183 strcpy(before[8], name);
184 free(name);
88acd4d3 185 beforec = 12;
5eaef520 186 break;
187 case QUOTA_TABLE:
188 strcpy(before[0], "?");
189 strcpy(before[1], argv[1]);
190 strcpy(before[2], "?");
191 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
192 "WHERE %s AND fs.filsys_id = q.filsys_id", qual);
193 dosql(&(before[3]));
194 strcpy(before[2], argv[1]);
195 beforec = 5;
196 break;
197 case LIST_TABLE:
198 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
199 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
8e3761a2 200 "l.description, l.list_id, l.mailman, l.mailman_id "
201 "FROM list l WHERE %s", qual);
5eaef520 202 dosql(before);
8e3761a2 203 name = xmalloc(0);
204 id = atoi(before[12]);
205 id_to_name(id, MACHINE_TABLE, &name);
206 strcpy(before[12], name);
207 free(name);
208 beforec = 13;
5eaef520 209 break;
210 case IMEMBERS_TABLE:
211 id = (int) argv[0];
212 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
213 "grouplist, gid FROM list WHERE list_id = %d", id);
214 dosql(&(before[3]));
88acd4d3 215 name = xmalloc(0);
5eaef520 216 id_to_name(id, LIST_TABLE, &name);
88acd4d3 217 name2 = xmalloc(0);
5eaef520 218 strcpy(before[0], name);
219 strcpy(before[1], argv[1]);
220 id = (int) argv[2];
88acd4d3 221 beforec = 10;
5eaef520 222 if (!strcmp(before[1], "USER"))
223 {
88acd4d3 224 id_to_name(id, USERS_TABLE, &name2);
225 EXEC SQL SELECT status, users_id INTO :before[9], :before[11]
226 FROM users WHERE users_id = :id;
227 EXEC SQL SELECT list_id INTO :before[10] FROM list
228 WHERE name = :name;
229 beforec = 12;
5eaef520 230 }
231 else if (!strcmp(before[1], "LIST"))
88acd4d3 232 {
233 id_to_name(id, LIST_TABLE, &name2);
234 EXEC SQL SELECT list_id INTO :before[9] FROM list
235 WHERE name = :name;
236 sprintf(before[10], "%d", id);
237 beforec = 11;
238 }
5eaef520 239 else if (!strcmp(before[1], "STRING") || !strcmp(before[1], "KERBEROS"))
88acd4d3 240 {
241 id_to_name(id, STRINGS_TABLE, &name2);
242 EXEC SQL SELECT list_id INTO :before[9] FROM list
243 WHERE name = :name;
244 }
5f7b0741 245 else if (!strcmp(before[1], "MACHINE"))
246 {
247 id_to_name(id, MACHINE_TABLE, &name2);
53a1afb6 248 EXEC SQL SELECT list_id INTO :before[9] FROM list
5f7b0741 249 WHERE name = :name;
53a1afb6 250 sprintf(before[10], "%d", id);
251 beforec = 11;
5f7b0741 252 }
88acd4d3 253 strcpy(before[2], name2);
5eaef520 254 free(name);
88acd4d3 255 free(name2);
5eaef520 256 break;
257 default:
03c05291 258 /*
259 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
260 table_name[table]);
261 */
5eaef520 262 break;
263 }
a313cad2 264}
32cfe906 265
266
03c05291 267void incremental_clear_before(void)
32cfe906 268{
5eaef520 269 beforec = 0;
32cfe906 270}
271
32cfe906 272
03c05291 273/* add an element to the incremental queue for the changed row */
32cfe906 274
5eaef520 275void incremental_after(enum tables table, char *qual, char **argv)
a313cad2 276{
88acd4d3 277 char *name, *name2;
5eaef520 278 EXEC SQL BEGIN DECLARE SECTION;
73155abd 279 int id;
5eaef520 280 EXEC SQL END DECLARE SECTION;
281 struct iupdate *iu;
282
283 switch (table)
284 {
285 case USERS_TABLE:
d6759517 286 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, "
287 "u.winconsoleshell, u.last, u.first, u.middle, u.status, "
88acd4d3 288 "u.clearid, u.type, u.users_id FROM users u WHERE %s", qual);
5eaef520 289 dosql(after);
88acd4d3 290 afterc = 11;
5eaef520 291 break;
292 case MACHINE_TABLE:
88acd4d3 293 sprintf(stmt_buf, "SELECT m.name, m.vendor, m.mach_id FROM machine m "
5eaef520 294 "WHERE %s", qual);
295 dosql(after);
88acd4d3 296 afterc = 3;
5eaef520 297 break;
e688520a 298 case CLUSTERS_TABLE:
88acd4d3 299 sprintf(stmt_buf, "SELECT c.name, c.description, c.location, "
300 "c.clu_id FROM clusters c WHERE %s", qual);
5eaef520 301 dosql(after);
88acd4d3 302 afterc = 4;
5eaef520 303 break;
bb5c9457 304 case CONTAINERS_TABLE:
305 sprintf(stmt_buf, "SELECT c.name, c.description, c.location, c.contact, "
73155abd 306 "c.acl_type, c.acl_id, c.cnt_id, c.list_id FROM containers c "
307 "WHERE %s", qual);
bb5c9457 308 dosql(after);
73155abd 309 afterc = 8;
429aec78 310 name = xmalloc(0);
311 id = atoi(after[5]);
312 if (!strncmp(after[4], "USER", 4))
313 {
314 id_to_name(id, USERS_TABLE, &name);
315 strcpy(after[5], name);
316 }
317 else if (!strncmp(after[4], "LIST", 4))
318 {
319 id_to_name(id, LIST_TABLE, &name);
320 strcpy(after[5], name);
321 }
322 else if (!strncmp(after[4], "KERBEROS", 8))
323 {
324 id_to_name(id, STRINGS_TABLE, &name);
325 strcpy(after[5], name);
326 }
73155abd 327 id = atoi(after[7]);
328 id_to_name(id, LIST_TABLE, &name);
329 strcpy(after[7], name);
bb5c9457 330 break;
5eaef520 331 case MCMAP_TABLE:
332 strcpy(after[0], argv[0]);
333 strcpy(after[1], argv[1]);
334 afterc = 2;
335 break;
b227bf97 336 case MCNTMAP_TABLE:
337 strcpy(after[0], argv[0]);
338 strcpy(after[1], argv[1]);
339 name_to_id(after[0], MACHINE_TABLE, &id);
340 sprintf(after[2], "%d", id);
341 name_to_id(after[1], CONTAINERS_TABLE, &id);
342 sprintf(after[3], "%d", id);
73155abd 343 name = xmalloc(0);
344 EXEC SQL SELECT list_id INTO :after[4] FROM containers
345 WHERE cnt_id = :id;
346 id = atoi(after[4]);
347 id_to_name(id, LIST_TABLE, &name);
348 strcpy(after[4], name);
349 afterc = 5;
b227bf97 350 break;
5eaef520 351 case SVC_TABLE:
352 strcpy(after[0], argv[0]);
353 strcpy(after[1], argv[1]);
354 strcpy(after[2], argv[2]);
355 afterc = 3;
356 break;
357 case FILESYS_TABLE:
358 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
359 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
88acd4d3 360 "fs.createflg, fs.lockertype, fs.filsys_id FROM filesys fs "
361 "WHERE %s", qual);
5eaef520 362 dosql(after);
88acd4d3 363 name = xmalloc(0);
5eaef520 364 id = atoi(after[2]);
365 id_to_name(id, MACHINE_TABLE, &name);
366 strcpy(after[2], name);
367 id = atoi(after[7]);
368 id_to_name(id, USERS_TABLE, &name);
369 strcpy(after[7], name);
370 id = atoi(after[8]);
371 id_to_name(id, LIST_TABLE, &name);
372 strcpy(after[8], name);
373 free(name);
88acd4d3 374 afterc = 12;
5eaef520 375 break;
376 case QUOTA_TABLE:
377 strcpy(after[0], "?");
378 strcpy(after[1], argv[1]);
379 strcpy(after[2], "?");
380 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
381 "WHERE %s and fs.filsys_id = q.filsys_id and q.type = '%s'",
382 qual, argv[1]);
383 dosql(&(after[3]));
384 afterc = 5;
385 break;
386 case LIST_TABLE:
387 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
388 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
8e3761a2 389 "l.description, l.list_id, l.mailman, l.mailman_id "
390 "FROM list l WHERE %s", qual);
5eaef520 391 dosql(after);
8e3761a2 392 name = xmalloc(0);
393 id = atoi(after[12]);
394 id_to_name(id, MACHINE_TABLE, &name);
395 strcpy(after[12], name);
396 free(name);
397 afterc = 13;
5eaef520 398 break;
399 case IMEMBERS_TABLE:
400 id = (int) argv[0];
401 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
402 "grouplist, gid FROM list WHERE list_id = %d", id);
403 dosql(&(after[3]));
88acd4d3 404 name = xmalloc(0);
5eaef520 405 id_to_name(id, LIST_TABLE, &name);
88acd4d3 406 name2 = xmalloc(0);
5eaef520 407 strcpy(after[0], name);
408 strcpy(after[1], argv[1]);
409 id = (int) argv[2];
88acd4d3 410 afterc = 10;
5eaef520 411 if (!strcmp(after[1], "USER"))
412 {
88acd4d3 413 id_to_name(id, USERS_TABLE, &name2);
414 EXEC SQL SELECT status, users_id INTO :after[9], :after[11]
415 FROM users WHERE users_id = :id;
416 EXEC SQL SELECT list_id INTO :after[10] FROM list
417 WHERE name = :name;
418 afterc = 12;
32cfe906 419 }
5eaef520 420 else if (!strcmp(after[1], "LIST"))
88acd4d3 421 {
422 id_to_name(id, LIST_TABLE, &name2);
423 EXEC SQL SELECT list_id INTO :after[9] FROM list
424 WHERE name = :name;
425 sprintf(after[10], "%d", id);
426 afterc = 11;
427 }
5eaef520 428 else if (!strcmp(after[1], "STRING") || !strcmp(after[1], "KERBEROS"))
88acd4d3 429 {
430 id_to_name(id, STRINGS_TABLE, &name2);
431 EXEC SQL SELECT list_id INTO :after[9] FROM list
432 WHERE name = :name;
433 }
5f7b0741 434 else if (!strcmp(after[1], "MACHINE"))
435 {
436 id_to_name(id, MACHINE_TABLE, &name2);
53a1afb6 437 EXEC SQL SELECT list_id INTO :after[9] FROM list
5f7b0741 438 WHERE name = :name;
53a1afb6 439 sprintf(after[10], "%d", id);
440 afterc = 11;
5f7b0741 441 }
88acd4d3 442 strcpy(after[2], name2);
5eaef520 443 free(name);
88acd4d3 444 free(name2);
5eaef520 445 break;
446 case NO_TABLE:
447 afterc = 0;
448 table = beforetable;
449 break;
450 default:
03c05291 451 /*
452 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
453 table_name[table]);
454 */
5eaef520 455 break;
32cfe906 456 }
5eaef520 457
e688520a 458 iu = xmalloc(sizeof(struct iupdate));
5eaef520 459 iu->table = table_name[table];
460 iu->beforec = beforec;
fc053494 461 iu->before = copy_argv(before, beforec);
5eaef520 462 iu->afterc = afterc;
fc053494 463 iu->after = copy_argv(after, afterc);
5eaef520 464 sq_save_data(incremental_sq, iu);
a313cad2 465}
32cfe906 466
03c05291 467void incremental_clear_after(void)
468{
5eaef520 469 incremental_after(NO_TABLE, NULL, NULL);
03c05291 470}
471
32cfe906 472
473/* Called when the current transaction is committed to start any queued
474 * incremental updates. This caches the update table the first time it
475 * is called.
476 */
477
478struct inc_cache {
5eaef520 479 struct inc_cache *next;
480 char *table, *service;
32cfe906 481};
482
483
03c05291 484void incremental_update(void)
32cfe906 485{
5eaef520 486 static int inited = 0;
487 static struct inc_cache *cache;
488 struct inc_cache *c;
489 EXEC SQL BEGIN DECLARE SECTION;
e688520a 490 char tab[INCREMENTAL_TABLE_NAME_SIZE], serv[INCREMENTAL_SERVICE_SIZE];
5eaef520 491 EXEC SQL END DECLARE SECTION;
772c26b3 492 struct iupdate *iu, *iu_save;
5eaef520 493
494 if (!inited)
495 {
496 inited++;
497
498 EXEC SQL DECLARE inc CURSOR FOR SELECT table_name, service
499 FROM incremental;
500 EXEC SQL OPEN inc;
501 while (1)
502 {
503 EXEC SQL FETCH inc INTO :tab, :serv;
504 if (sqlca.sqlcode)
505 break;
e688520a 506 c = xmalloc(sizeof(struct inc_cache));
5eaef520 507 c->next = cache;
e688520a 508 c->table = xstrdup(strtrim(tab));
509 c->service = xstrdup(strtrim(serv));
5eaef520 510 cache = c;
32cfe906 511 }
5eaef520 512 EXEC SQL CLOSE inc;
513 EXEC SQL COMMIT WORK;
32cfe906 514 }
515
5eaef520 516 while (sq_remove_data(incremental_sq, &iu))
517 {
518 for (c = cache; c; c = c->next)
519 {
520 if (!strcmp(c->table, iu->table))
521 {
522 iu->service = c->service;
772c26b3 523 iu_save = xmalloc(sizeof(struct iupdate));
524 iu_save->service = iu->service;
525 iu_save->table = iu->table;
526 iu_save->beforec = iu->beforec;
527 iu_save->afterc = iu->afterc;
528 iu_save->before = copy_argv(iu->before, iu->beforec);
529 iu_save->after = copy_argv(iu->after, iu->afterc);
530 sq_save_data(incremental_exec, iu_save);
32cfe906 531 }
532 }
e688520a 533 if (!c)
534 {
535 free_argv(iu->before, iu->beforec);
536 free_argv(iu->after, iu->afterc);
537 free(iu);
538 }
32cfe906 539 }
5eaef520 540 if (inc_running == 0)
541 next_incremental();
32cfe906 542}
543
f18a32ee 544/* Pro*C 2.2.4 can't cope with the sigset_t below, at least in Solaris 2.6.
545 We add DEFINE=_PROC_ to the proc invocation and then #ifndef that around
546 this function so proc will pass it through without reading it. */
32cfe906 547
f18a32ee 548#ifndef _PROC_
03c05291 549void next_incremental(void)
32cfe906 550{
5eaef520 551 struct iupdate *iu;
e688520a 552 char *argv[MAXARGC * 2 + 4], cafter[3], cbefore[3], prog[MAXPATHLEN];
5eaef520 553 int i;
554 sigset_t sigs;
555
556 if (!incremental_exec)
557 incremental_init();
558
559 if (sq_empty(incremental_exec) ||
560 (inc_running && now - inc_started < INC_TIMEOUT))
561 return;
562
563 if (inc_running)
564 com_err(whoami, 0, "incremental timeout on pid %d", inc_pid);
565
566 sq_remove_data(incremental_exec, &iu);
567 argv[1] = iu->table;
568 sprintf(cbefore, "%d", iu->beforec);
569 argv[2] = cbefore;
570 sprintf(cafter, "%d", iu->afterc);
571 argv[3] = cafter;
572 for (i = 0; i < iu->beforec; i++)
573 argv[4 + i] = iu->before[i];
574 for (i = 0; i < iu->afterc; i++)
575 argv[4 + iu->beforec + i] = iu->after[i];
576
577 sprintf(prog, "%s/%s.incr", BIN_DIR, iu->service);
578 argv[0] = prog;
579 argv[4 + iu->beforec + iu->afterc] = 0;
580
581 sigemptyset(&sigs);
582 sigaddset(&sigs, SIGCHLD);
583 sigprocmask(SIG_BLOCK, &sigs, NULL);
584 inc_pid = vfork();
585 switch (inc_pid)
586 {
32cfe906 587 case 0:
5eaef520 588 execv(prog, argv);
589 _exit(1);
32cfe906 590 case -1:
5eaef520 591 com_err(whoami, 0, "Failed to start incremental update");
592 break;
32cfe906 593 default:
5eaef520 594 inc_running = 1;
595 inc_started = now;
32cfe906 596 }
5eaef520 597 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
32cfe906 598
5eaef520 599 free_argv(iu->before, iu->beforec);
600 free_argv(iu->after, iu->afterc);
601 free(iu);
32cfe906 602}
f18a32ee 603#endif
32cfe906 604
605/* Called when the current transaction is aborted to throw away any queued
606 * incremental updates
607 */
608
03c05291 609void incremental_flush(void)
32cfe906 610{
5eaef520 611 struct iupdate *iu;
32cfe906 612
5eaef520 613 while (sq_get_data(incremental_sq, &iu))
614 {
615 free_argv(iu->before, iu->beforec);
616 free_argv(iu->after, iu->afterc);
617 free(iu);
32cfe906 618 }
5eaef520 619 sq_destroy(incremental_sq);
620 incremental_sq = sq_create();
32cfe906 621}
622
623
fc053494 624char **copy_argv(char **argv, int argc)
625{
626 char **ret = xmalloc(sizeof(char *) * argc);
627 while (--argc >= 0)
628 ret[argc] = xstrdup(strtrim(argv[argc]));
629 return ret;
630}
631
5eaef520 632void free_argv(char **argv, int argc)
32cfe906 633{
5eaef520 634 while (--argc >= 0)
635 free(argv[argc]);
636 free(argv);
32cfe906 637}
03c05291 638
639int table_num(char *name)
640{
641 int i;
642
5eaef520 643 for (i = num_tables - 1; i; i--)
644 {
645 if (!strcmp(table_name[i], name))
646 break;
647 }
03c05291 648
649 return i; /* 0 = "none" if no match */
650}
This page took 0.226947 seconds and 5 git commands to generate.